[Youtube] Add _ITEMS constants and improve code style

Move thumbnail id exctraction code to getThumbnailUrlFromId
Add test for "My mix" detection to service tests
Use ITEM_COUNT_UNKNOWN everywhere instead of -1 and add some tests
This commit is contained in:
Xiang Rong Lin 2020-03-17 14:04:46 +01:00 committed by XiangRongLin
parent df38b1926c
commit 822cf307f7
5 changed files with 55 additions and 38 deletions

View File

@ -1,6 +1,8 @@
package org.schabi.newpipe.extractor.services.media_ccc.extractors.infoItems;
import com.grack.nanojson.JsonObject;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
@ -23,7 +25,7 @@ public class MediaCCCConferenceInfoItemExtractor implements ChannelInfoItemExtra
@Override
public long getStreamCount() {
return -1;
return ListExtractor.ITEM_COUNT_UNKNOWN;
}
@Override

View File

@ -2,6 +2,7 @@ package org.schabi.newpipe.extractor.services.youtube.extractors;
import com.grack.nanojson.JsonObject;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelLinkHandlerFactory;
@ -86,7 +87,7 @@ public class YoutubeChannelInfoItemExtractor implements ChannelInfoItemExtractor
try {
if (!channelInfoItem.has("videoCountText")) {
// Video count is not available, channel probably has no public uploads.
return -1;
return ListExtractor.ITEM_COUNT_UNKNOWN;
}
return Long.parseLong(Utils.removeNonDigitCharacters(getTextFromObject(

View File

@ -7,6 +7,8 @@ import com.grack.nanojson.JsonObject;
import java.io.IOException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.downloader.Downloader;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
@ -23,6 +25,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
*/
public class YoutubeMixPlaylistExtractor extends PlaylistExtractor {
private final static String CONTENTS = "contents";
private final static String RESPONSE = "response";
private final static String PLAYLIST = "playlist";
@ -41,44 +44,25 @@ public class YoutubeMixPlaylistExtractor extends PlaylistExtractor {
final String url = getUrl() + "&pbj=1";
final JsonArray ajaxJson = getJsonResponse(url, getExtractorLocalization());
JsonObject initialData = ajaxJson.getObject(3).getObject(RESPONSE);
try {
playlistData = initialData.getObject(CONTENTS).getObject(TWO_COLUMNS_WATCH_NEXT_RESULTS)
.getObject(PLAYLIST).getObject(PLAYLIST);
} catch (NullPointerException e) {
throw new ExtractionException(e);
}
playlistData = initialData.getObject(CONTENTS).getObject(TWO_COLUMN_WATCH_NEXT_RESULTS)
.getObject(PLAYLIST).getObject(PLAYLIST);
}
@Nonnull
@Override
public String getName() throws ParsingException {
try {
final String name = playlistData.getString("title");
if (name != null) {
return name;
} else {
return "";
}
} catch (Exception e) {
throw new ParsingException("Could not get playlist name", e);
final String name = playlistData.getString("title");
if (name == null) {
throw new ParsingException("Could not get playlist name");
}
return name;
}
@Override
public String getThumbnailUrl() throws ParsingException {
try {
final String playlistId = playlistData.getString("playlistId");
final String videoId;
if (playlistId.startsWith("RDMM")) {
videoId = playlistId.substring(4);
} else {
videoId = playlistId.substring(2);
}
if (videoId.isEmpty()) {
throw new ParsingException("");
}
return getThumbnailUrlFromId(videoId);
return getThumbnailUrlFromId(playlistId);
} catch (Exception e) {
throw new ParsingException("Could not get playlist thumbnail", e);
}
@ -97,20 +81,20 @@ public class YoutubeMixPlaylistExtractor extends PlaylistExtractor {
@Override
public String getUploaderName() {
//Youtube mix are auto-generated
return "";
//Youtube mix are auto-generated by YouTube
return "YouTube";
}
@Override
public String getUploaderAvatarUrl() {
//Youtube mix are auto-generated
//Youtube mix are auto-generated by YouTube
return "";
}
@Override
public long getStreamCount() {
// Auto-generated playlist always start with 25 videos and are endless
return 25;
return ListExtractor.ITEM_COUNT_INFINITE;
}
@Nonnull
@ -135,7 +119,7 @@ public class YoutubeMixPlaylistExtractor extends PlaylistExtractor {
@Override
public InfoItemsPage<StreamInfoItem> getPage(final String pageUrl)
throws ExtractionException, IOException {
throws ExtractionException, IOException {
if (pageUrl == null || pageUrl.isEmpty()) {
throw new ExtractionException(
new IllegalArgumentException("Page url is empty or null"));
@ -145,7 +129,7 @@ public class YoutubeMixPlaylistExtractor extends PlaylistExtractor {
final JsonArray ajaxJson = getJsonResponse(pageUrl, getExtractorLocalization());
playlistData =
ajaxJson.getObject(3).getObject(RESPONSE).getObject(CONTENTS)
.getObject(TWO_COLUMNS_WATCH_NEXT_RESULTS).getObject(PLAYLIST)
.getObject(TWO_COLUMN_WATCH_NEXT_RESULTS).getObject(PLAYLIST)
.getObject(PLAYLIST);
final JsonArray streams = playlistData.getArray(CONTENTS);
//Because continuation requests are created with the last video of previous request as start
@ -155,8 +139,8 @@ public class YoutubeMixPlaylistExtractor extends PlaylistExtractor {
}
private void collectStreamsFrom(
@Nonnull StreamInfoItemsCollector collector,
@Nullable JsonArray streams) {
@Nonnull StreamInfoItemsCollector collector,
@Nullable JsonArray streams) {
collector.reset();
if (streams == null) {
@ -176,7 +160,16 @@ public class YoutubeMixPlaylistExtractor extends PlaylistExtractor {
}
}
private String getThumbnailUrlFromId(String videoId) {
private String getThumbnailUrlFromId(String playlistId) throws ParsingException {
final String videoId;
if (playlistId.startsWith("RDMM")) {
videoId = playlistId.substring(4);
} else {
videoId = playlistId.substring(2);
}
if (videoId.isEmpty()) {
throw new ParsingException("videoId is empty");
}
return "https://i.ytimg.com/vi/" + videoId + "/hqdefault.jpg";
}
}

View File

@ -93,6 +93,11 @@ public class YoutubeMixPlaylistExtractorTest {
public void getStreamCount() throws Exception {
assertEquals(ListExtractor.ITEM_COUNT_INFINITE, extractor.getStreamCount());
}
@Test
public void getStreamCount() throws Exception {
assertEquals(ListExtractor.ITEM_COUNT_INFINITE, extractor.getStreamCount());
}
}
public static class MixWithIndex {
@ -165,6 +170,11 @@ public class YoutubeMixPlaylistExtractorTest {
public void getStreamCount() {
assertEquals(ListExtractor.ITEM_COUNT_INFINITE, extractor.getStreamCount());
}
@Test
public void getStreamCount() throws Exception {
assertEquals(ListExtractor.ITEM_COUNT_INFINITE, extractor.getStreamCount());
}
}
public static class MyMix {
@ -319,5 +329,10 @@ public class YoutubeMixPlaylistExtractorTest {
public void getStreamCount() throws Exception {
assertEquals(ListExtractor.ITEM_COUNT_INFINITE, extractor.getStreamCount());
}
@Test
public void getStreamCount() throws Exception {
assertEquals(ListExtractor.ITEM_COUNT_INFINITE, extractor.getStreamCount());
}
}
}

View File

@ -75,7 +75,13 @@ public class YoutubeServiceTest {
assertTrue(extractor instanceof YoutubeMixPlaylistExtractor);
extractor = YouTube.getPlaylistExtractor(
"https://www.youtube.com/watch?v=" + videoId + "&list=RD" + videoId);
"https://www.youtube.com/watch?v=" + videoId + "&list=RDMM" + videoId);
assertTrue(extractor instanceof YoutubeMixPlaylistExtractor);
final String mixVideoId = "qHtzO49SDmk";
extractor = YouTube.getPlaylistExtractor(
"https://www.youtube.com/watch?v=" + mixVideoId + "&list=RD" + videoId);
assertTrue(extractor instanceof YoutubeMixPlaylistExtractor);
}
}