[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:
parent
df38b1926c
commit
822cf307f7
5 changed files with 55 additions and 38 deletions
|
@ -1,6 +1,8 @@
|
||||||
package org.schabi.newpipe.extractor.services.media_ccc.extractors.infoItems;
|
package org.schabi.newpipe.extractor.services.media_ccc.extractors.infoItems;
|
||||||
|
|
||||||
import com.grack.nanojson.JsonObject;
|
import com.grack.nanojson.JsonObject;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.extractor.ListExtractor;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor;
|
import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
|
|
||||||
|
@ -23,7 +25,7 @@ public class MediaCCCConferenceInfoItemExtractor implements ChannelInfoItemExtra
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getStreamCount() {
|
public long getStreamCount() {
|
||||||
return -1;
|
return ListExtractor.ITEM_COUNT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -2,6 +2,7 @@ package org.schabi.newpipe.extractor.services.youtube.extractors;
|
||||||
|
|
||||||
import com.grack.nanojson.JsonObject;
|
import com.grack.nanojson.JsonObject;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.extractor.ListExtractor;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor;
|
import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelLinkHandlerFactory;
|
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelLinkHandlerFactory;
|
||||||
|
@ -86,7 +87,7 @@ public class YoutubeChannelInfoItemExtractor implements ChannelInfoItemExtractor
|
||||||
try {
|
try {
|
||||||
if (!channelInfoItem.has("videoCountText")) {
|
if (!channelInfoItem.has("videoCountText")) {
|
||||||
// Video count is not available, channel probably has no public uploads.
|
// Video count is not available, channel probably has no public uploads.
|
||||||
return -1;
|
return ListExtractor.ITEM_COUNT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Long.parseLong(Utils.removeNonDigitCharacters(getTextFromObject(
|
return Long.parseLong(Utils.removeNonDigitCharacters(getTextFromObject(
|
||||||
|
|
|
@ -7,6 +7,8 @@ import com.grack.nanojson.JsonObject;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.extractor.ListExtractor;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
import org.schabi.newpipe.extractor.downloader.Downloader;
|
import org.schabi.newpipe.extractor.downloader.Downloader;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
|
@ -23,6 +25,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
|
||||||
*/
|
*/
|
||||||
public class YoutubeMixPlaylistExtractor extends PlaylistExtractor {
|
public class YoutubeMixPlaylistExtractor extends PlaylistExtractor {
|
||||||
|
|
||||||
|
|
||||||
private final static String CONTENTS = "contents";
|
private final static String CONTENTS = "contents";
|
||||||
private final static String RESPONSE = "response";
|
private final static String RESPONSE = "response";
|
||||||
private final static String PLAYLIST = "playlist";
|
private final static String PLAYLIST = "playlist";
|
||||||
|
@ -41,44 +44,25 @@ public class YoutubeMixPlaylistExtractor extends PlaylistExtractor {
|
||||||
final String url = getUrl() + "&pbj=1";
|
final String url = getUrl() + "&pbj=1";
|
||||||
final JsonArray ajaxJson = getJsonResponse(url, getExtractorLocalization());
|
final JsonArray ajaxJson = getJsonResponse(url, getExtractorLocalization());
|
||||||
JsonObject initialData = ajaxJson.getObject(3).getObject(RESPONSE);
|
JsonObject initialData = ajaxJson.getObject(3).getObject(RESPONSE);
|
||||||
try {
|
playlistData = initialData.getObject(CONTENTS).getObject(TWO_COLUMN_WATCH_NEXT_RESULTS)
|
||||||
playlistData = initialData.getObject(CONTENTS).getObject(TWO_COLUMNS_WATCH_NEXT_RESULTS)
|
.getObject(PLAYLIST).getObject(PLAYLIST);
|
||||||
.getObject(PLAYLIST).getObject(PLAYLIST);
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
throw new ExtractionException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getName() throws ParsingException {
|
public String getName() throws ParsingException {
|
||||||
try {
|
final String name = playlistData.getString("title");
|
||||||
final String name = playlistData.getString("title");
|
if (name == null) {
|
||||||
if (name != null) {
|
throw new ParsingException("Could not get playlist name");
|
||||||
return name;
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ParsingException("Could not get playlist name", e);
|
|
||||||
}
|
}
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getThumbnailUrl() throws ParsingException {
|
public String getThumbnailUrl() throws ParsingException {
|
||||||
try {
|
try {
|
||||||
final String playlistId = playlistData.getString("playlistId");
|
final String playlistId = playlistData.getString("playlistId");
|
||||||
final String videoId;
|
return getThumbnailUrlFromId(playlistId);
|
||||||
if (playlistId.startsWith("RDMM")) {
|
|
||||||
videoId = playlistId.substring(4);
|
|
||||||
} else {
|
|
||||||
videoId = playlistId.substring(2);
|
|
||||||
}
|
|
||||||
if (videoId.isEmpty()) {
|
|
||||||
throw new ParsingException("");
|
|
||||||
}
|
|
||||||
return getThumbnailUrlFromId(videoId);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ParsingException("Could not get playlist thumbnail", e);
|
throw new ParsingException("Could not get playlist thumbnail", e);
|
||||||
}
|
}
|
||||||
|
@ -97,20 +81,20 @@ public class YoutubeMixPlaylistExtractor extends PlaylistExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUploaderName() {
|
public String getUploaderName() {
|
||||||
//Youtube mix are auto-generated
|
//Youtube mix are auto-generated by YouTube
|
||||||
return "";
|
return "YouTube";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUploaderAvatarUrl() {
|
public String getUploaderAvatarUrl() {
|
||||||
//Youtube mix are auto-generated
|
//Youtube mix are auto-generated by YouTube
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getStreamCount() {
|
public long getStreamCount() {
|
||||||
// Auto-generated playlist always start with 25 videos and are endless
|
// Auto-generated playlist always start with 25 videos and are endless
|
||||||
return 25;
|
return ListExtractor.ITEM_COUNT_INFINITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
|
@ -135,7 +119,7 @@ public class YoutubeMixPlaylistExtractor extends PlaylistExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InfoItemsPage<StreamInfoItem> getPage(final String pageUrl)
|
public InfoItemsPage<StreamInfoItem> getPage(final String pageUrl)
|
||||||
throws ExtractionException, IOException {
|
throws ExtractionException, IOException {
|
||||||
if (pageUrl == null || pageUrl.isEmpty()) {
|
if (pageUrl == null || pageUrl.isEmpty()) {
|
||||||
throw new ExtractionException(
|
throw new ExtractionException(
|
||||||
new IllegalArgumentException("Page url is empty or null"));
|
new IllegalArgumentException("Page url is empty or null"));
|
||||||
|
@ -145,7 +129,7 @@ public class YoutubeMixPlaylistExtractor extends PlaylistExtractor {
|
||||||
final JsonArray ajaxJson = getJsonResponse(pageUrl, getExtractorLocalization());
|
final JsonArray ajaxJson = getJsonResponse(pageUrl, getExtractorLocalization());
|
||||||
playlistData =
|
playlistData =
|
||||||
ajaxJson.getObject(3).getObject(RESPONSE).getObject(CONTENTS)
|
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);
|
.getObject(PLAYLIST);
|
||||||
final JsonArray streams = playlistData.getArray(CONTENTS);
|
final JsonArray streams = playlistData.getArray(CONTENTS);
|
||||||
//Because continuation requests are created with the last video of previous request as start
|
//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(
|
private void collectStreamsFrom(
|
||||||
@Nonnull StreamInfoItemsCollector collector,
|
@Nonnull StreamInfoItemsCollector collector,
|
||||||
@Nullable JsonArray streams) {
|
@Nullable JsonArray streams) {
|
||||||
collector.reset();
|
collector.reset();
|
||||||
|
|
||||||
if (streams == null) {
|
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";
|
return "https://i.ytimg.com/vi/" + videoId + "/hqdefault.jpg";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,11 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
public void getStreamCount() throws Exception {
|
public void getStreamCount() throws Exception {
|
||||||
assertEquals(ListExtractor.ITEM_COUNT_INFINITE, extractor.getStreamCount());
|
assertEquals(ListExtractor.ITEM_COUNT_INFINITE, extractor.getStreamCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getStreamCount() throws Exception {
|
||||||
|
assertEquals(ListExtractor.ITEM_COUNT_INFINITE, extractor.getStreamCount());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MixWithIndex {
|
public static class MixWithIndex {
|
||||||
|
@ -165,6 +170,11 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
public void getStreamCount() {
|
public void getStreamCount() {
|
||||||
assertEquals(ListExtractor.ITEM_COUNT_INFINITE, extractor.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 {
|
public static class MyMix {
|
||||||
|
@ -319,5 +329,10 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
public void getStreamCount() throws Exception {
|
public void getStreamCount() throws Exception {
|
||||||
assertEquals(ListExtractor.ITEM_COUNT_INFINITE, extractor.getStreamCount());
|
assertEquals(ListExtractor.ITEM_COUNT_INFINITE, extractor.getStreamCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getStreamCount() throws Exception {
|
||||||
|
assertEquals(ListExtractor.ITEM_COUNT_INFINITE, extractor.getStreamCount());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -75,7 +75,13 @@ public class YoutubeServiceTest {
|
||||||
assertTrue(extractor instanceof YoutubeMixPlaylistExtractor);
|
assertTrue(extractor instanceof YoutubeMixPlaylistExtractor);
|
||||||
|
|
||||||
extractor = YouTube.getPlaylistExtractor(
|
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);
|
assertTrue(extractor instanceof YoutubeMixPlaylistExtractor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue