|
1 | | -package org.schabi.newpipe.extractor.services.youtube.extractors; |
2 | | - |
3 | 1 | /* |
4 | 2 | * Created by Christian Schabesberger on 12.08.17. |
5 | 3 | * |
6 | 4 | * Copyright (C) Christian Schabesberger 2018 <chris.schabesberger@mailbox.org> |
7 | | - * YoutubeTrendingExtractor.java is part of NewPipe. |
| 5 | + * YoutubeTrendingExtractor.java is part of NewPipe Extractor. |
8 | 6 | * |
9 | | - * NewPipe is free software: you can redistribute it and/or modify |
| 7 | + * NewPipe Extractor is free software: you can redistribute it and/or modify |
10 | 8 | * it under the terms of the GNU General Public License as published by |
11 | 9 | * the Free Software Foundation, either version 3 of the License, or |
12 | 10 | * (at your option) any later version. |
13 | 11 | * |
14 | | - * NewPipe is distributed in the hope that it will be useful, |
| 12 | + * NewPipe Extractor is distributed in the hope that it will be useful, |
15 | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | 15 | * GNU General Public License for more details. |
18 | 16 | * |
19 | 17 | * You should have received a copy of the GNU General Public License |
20 | | - * along with NewPipe. If not, see <http://www.gnu.org/licenses/>. |
| 18 | + * along with NewPipe Extractor. If not, see <https://www.gnu.org/licenses/>. |
21 | 19 | */ |
22 | 20 |
|
23 | | -import com.grack.nanojson.JsonArray; |
| 21 | +package org.schabi.newpipe.extractor.services.youtube.extractors; |
| 22 | + |
24 | 23 | import com.grack.nanojson.JsonObject; |
25 | 24 | import com.grack.nanojson.JsonWriter; |
26 | 25 |
|
@@ -92,25 +91,66 @@ public String getName() throws ParsingException { |
92 | 91 |
|
93 | 92 | @Nonnull |
94 | 93 | @Override |
95 | | - public InfoItemsPage<StreamInfoItem> getInitialPage() { |
| 94 | + public InfoItemsPage<StreamInfoItem> getInitialPage() throws ParsingException { |
96 | 95 | final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); |
97 | 96 | final TimeAgoParser timeAgoParser = getTimeAgoParser(); |
98 | | - final JsonArray itemSectionRenderers = initialData.getObject("contents") |
99 | | - .getObject("twoColumnBrowseResultsRenderer").getArray("tabs").getObject(0) |
100 | | - .getObject("tabRenderer").getObject("content").getObject("sectionListRenderer") |
101 | | - .getArray("contents"); |
102 | | - |
103 | | - for (final Object itemSectionRenderer : itemSectionRenderers) { |
104 | | - final JsonObject expandedShelfContentsRenderer = ((JsonObject) itemSectionRenderer) |
105 | | - .getObject("itemSectionRenderer").getArray("contents").getObject(0) |
106 | | - .getObject("shelfRenderer").getObject("content") |
107 | | - .getObject("expandedShelfContentsRenderer"); |
108 | | - for (final Object ul : expandedShelfContentsRenderer.getArray("items")) { |
109 | | - final JsonObject videoInfo = ((JsonObject) ul).getObject("videoRenderer"); |
110 | | - collector.commit(new YoutubeStreamInfoItemExtractor(videoInfo, timeAgoParser)); |
111 | | - } |
| 97 | + final JsonObject tabContent = getTrendingTabContent(); |
| 98 | + |
| 99 | + if (tabContent.has("richGridRenderer")) { |
| 100 | + tabContent.getObject("richGridRenderer") |
| 101 | + .getArray("contents") |
| 102 | + .stream() |
| 103 | + .filter(JsonObject.class::isInstance) |
| 104 | + .map(JsonObject.class::cast) |
| 105 | + // Filter Trending shorts and Recently trending sections |
| 106 | + .filter(content -> content.has("richItemRenderer")) |
| 107 | + .map(content -> content.getObject("richItemRenderer") |
| 108 | + .getObject("content") |
| 109 | + .getObject("videoRenderer")) |
| 110 | + .forEachOrdered(videoRenderer -> collector.commit( |
| 111 | + new YoutubeStreamInfoItemExtractor(videoRenderer, timeAgoParser))); |
| 112 | + } else if (tabContent.has("sectionListRenderer")) { |
| 113 | + tabContent.getObject("sectionListRenderer") |
| 114 | + .getArray("contents") |
| 115 | + .stream() |
| 116 | + .filter(JsonObject.class::isInstance) |
| 117 | + .map(JsonObject.class::cast) |
| 118 | + .flatMap(content -> content.getObject("itemSectionRenderer") |
| 119 | + .getArray("contents") |
| 120 | + .stream()) |
| 121 | + .filter(JsonObject.class::isInstance) |
| 122 | + .map(JsonObject.class::cast) |
| 123 | + .map(content -> content.getObject("shelfRenderer")) |
| 124 | + // Filter Trending shorts and Recently trending sections which have a title, |
| 125 | + // contrary to normal trends |
| 126 | + .filter(shelfRenderer -> !shelfRenderer.has("title")) |
| 127 | + .flatMap(shelfRenderer -> shelfRenderer.getObject("content") |
| 128 | + .getObject("expandedShelfContentsRenderer") |
| 129 | + .getArray("items") |
| 130 | + .stream()) |
| 131 | + .filter(JsonObject.class::isInstance) |
| 132 | + .map(JsonObject.class::cast) |
| 133 | + .map(item -> item.getObject("videoRenderer")) |
| 134 | + .forEachOrdered(videoRenderer -> collector.commit( |
| 135 | + new YoutubeStreamInfoItemExtractor(videoRenderer, timeAgoParser))); |
112 | 136 | } |
113 | 137 |
|
114 | 138 | return new InfoItemsPage<>(collector, null); |
115 | 139 | } |
| 140 | + |
| 141 | + private JsonObject getTrendingTabContent() throws ParsingException { |
| 142 | + return initialData.getObject("contents") |
| 143 | + .getObject("twoColumnBrowseResultsRenderer") |
| 144 | + .getArray("tabs") |
| 145 | + .stream() |
| 146 | + .filter(JsonObject.class::isInstance) |
| 147 | + .map(JsonObject.class::cast) |
| 148 | + .map(tab -> tab.getObject("tabRenderer")) |
| 149 | + .filter(tabRenderer -> tabRenderer.getBoolean("selected")) |
| 150 | + .filter(tabRenderer -> tabRenderer.has("content")) |
| 151 | + // There should be at most one tab selected |
| 152 | + .findFirst() |
| 153 | + .orElseThrow(() -> new ParsingException("Could not get \"Now\" trending tab")) |
| 154 | + .getObject("content"); |
| 155 | + } |
116 | 156 | } |
0 commit comments