From 1d7a86e664717d09e33371bc87c289903b19feb2 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 9 Apr 2020 13:51:47 +0200 Subject: [PATCH 01/30] [Test] Add base classes for stream extractor tests Refactor all stream extractor tests to use new base class. Remove check if upload date is in the past: this does not have to hold true: youtube premieres turn up in search results even though they are in the future --- .../newpipe/extractor/ExtractorAsserts.java | 14 +- .../services/BaseStreamExtractorTest.java | 24 ++ .../services/DefaultStreamExtractorTest.java | 286 +++++++++++++++ .../extractor/services/DefaultTests.java | 4 +- .../MediaCCCStreamExtractorTest.java | 214 +++++------ .../PeertubeStreamExtractorDefaultTest.java | 180 ---------- .../peertube/PeertubeStreamExtractorTest.java | 165 +++++++++ .../PeertubeTrendingExtractorTest.java | 4 +- .../SoundcloudChartsExtractorTest.java | 2 +- .../SoundcloudStreamExtractorDefaultTest.java | 163 --------- .../SoundcloudStreamExtractorTest.java | 81 +++++ ...utubeStreamExtractorAgeRestrictedTest.java | 157 ++------- ...utubeStreamExtractorControversialTest.java | 138 ++------ .../YoutubeStreamExtractorDefaultTest.java | 333 ++++++------------ .../YoutubeStreamExtractorLivestreamTest.java | 155 ++------ .../YoutubeStreamExtractorUnlistedTest.java | 169 ++------- 16 files changed, 883 insertions(+), 1206 deletions(-) create mode 100644 extractor/src/test/java/org/schabi/newpipe/extractor/services/BaseStreamExtractorTest.java create mode 100644 extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java delete mode 100644 extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorDefaultTest.java create mode 100644 extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java delete mode 100644 extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudStreamExtractorDefaultTest.java create mode 100644 extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudStreamExtractorTest.java diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/ExtractorAsserts.java b/extractor/src/test/java/org/schabi/newpipe/extractor/ExtractorAsserts.java index 1006f7b34..a0a887d7d 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/ExtractorAsserts.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/ExtractorAsserts.java @@ -1,12 +1,16 @@ package org.schabi.newpipe.extractor; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.net.MalformedURLException; import java.net.URL; import java.util.List; -import static org.junit.Assert.*; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; public class ExtractorAsserts { public static void assertEmptyErrors(String message, List errors) { @@ -56,4 +60,8 @@ public class ExtractorAsserts { assertTrue(message, stringToCheck.isEmpty()); } } + + public static void assertAtLeast(long expected, long actual) { + assertTrue(actual + " is not at least " + expected, actual >= expected); + } } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/BaseStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/BaseStreamExtractorTest.java new file mode 100644 index 000000000..fb555a033 --- /dev/null +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/BaseStreamExtractorTest.java @@ -0,0 +1,24 @@ +package org.schabi.newpipe.extractor.services; + +public interface BaseStreamExtractorTest extends BaseExtractorTest { + void testStreamType() throws Exception; + void testUploaderName() throws Exception; + void testUploaderUrl() throws Exception; + void testUploaderAvatarUrl() throws Exception; + void testThumbnailUrl() throws Exception; + void testDescription() throws Exception; + void testLength() throws Exception; + void testTimestamp() throws Exception; + void testViewCount() throws Exception; + void testUploadDate() throws Exception; + void testTextualUploadDate() throws Exception; + void testLikeCount() throws Exception; + void testDislikeCount() throws Exception; + void testRelatedStreams() throws Exception; + void testAgeLimit() throws Exception; + void testErrorMessage() throws Exception; + void testAudioStreams() throws Exception; + void testVideoStreams() throws Exception; + void testSubtitles() throws Exception; + void testFrames() throws Exception; +} diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java new file mode 100644 index 000000000..406177f7e --- /dev/null +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java @@ -0,0 +1,286 @@ +package org.schabi.newpipe.extractor.services; + +import org.junit.Test; +import org.schabi.newpipe.extractor.MediaFormat; +import org.schabi.newpipe.extractor.localization.DateWrapper; +import org.schabi.newpipe.extractor.stream.AudioStream; +import org.schabi.newpipe.extractor.stream.Description; +import org.schabi.newpipe.extractor.stream.Frameset; +import org.schabi.newpipe.extractor.stream.StreamExtractor; +import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector; +import org.schabi.newpipe.extractor.stream.StreamType; +import org.schabi.newpipe.extractor.stream.SubtitlesStream; +import org.schabi.newpipe.extractor.stream.VideoStream; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.List; +import java.util.TimeZone; + +import javax.annotation.Nullable; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.schabi.newpipe.extractor.ExtractorAsserts.assertAtLeast; +import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl; +import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsValidUrl; +import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestListOfItems; + +/** + * Test for {@link StreamExtractor} + */ +public abstract class DefaultStreamExtractorTest extends DefaultExtractorTest + implements BaseStreamExtractorTest { + + public abstract StreamType expectedStreamType(); + public abstract String expectedUploaderName(); + public abstract String expectedUploaderUrl(); + public abstract List expectedDescriptionContains(); // e.g. for full links + public abstract long expectedLength(); + public long expectedTimestamp() { return 0; }; // default: there is no timestamp + public abstract long expectedViewCountAtLeast(); + @Nullable public abstract String expectedUploadDate(); // format: "yyyy-MM-dd HH:mm:ss.SSS" + @Nullable public abstract String expectedTextualUploadDate(); + public abstract long expectedLikeCountAtLeast(); // return -1 if ratings are disabled + public abstract long expectedDislikeCountAtLeast(); // return -1 if ratings are disabled + public boolean expectedHasRelatedStreams() { return true; } // default: there are related videos + public int expectedAgeLimit() { return StreamExtractor.NO_AGE_LIMIT; } // default: no limit + @Nullable public String expectedErrorMessage() { return null; } // default: no error message + public boolean expectedHasVideoStreams() { return true; } // default: there are video streams + public boolean expectedHasAudioStreams() { return true; } // default: there are audio streams + public boolean expectedHasSubtitles() { return true; } // default: there are subtitles streams + public boolean expectedHasFrames() { return true; } // default: there are frames + + @Test + @Override + public void testStreamType() throws Exception { + assertEquals(expectedStreamType(), extractor().getStreamType()); + } + + @Test + @Override + public void testUploaderName() throws Exception { + assertEquals(expectedUploaderName(), extractor().getUploaderName()); + } + + @Test + @Override + public void testUploaderUrl() throws Exception { + final String uploaderUrl = extractor().getUploaderUrl(); + assertIsSecureUrl(uploaderUrl); + assertEquals(expectedUploaderUrl(), uploaderUrl); + } + + @Test + @Override + public void testUploaderAvatarUrl() throws Exception { + assertIsSecureUrl(extractor().getUploaderAvatarUrl()); + } + + @Test + @Override + public void testThumbnailUrl() throws Exception { + assertIsSecureUrl(extractor().getThumbnailUrl()); + } + + @Test + @Override + public void testDescription() throws Exception { + final Description description = extractor().getDescription(); + assertNotNull(description); + assertFalse("description is empty", description.getContent().isEmpty()); + + for (String s : expectedDescriptionContains()) { + assertThat(description.getContent(), containsString(s)); + } + } + + @Test + @Override + public void testLength() throws Exception { + assertEquals(expectedLength(), extractor().getLength()); + } + + @Test + @Override + public void testTimestamp() throws Exception { + assertEquals(expectedTimestamp(), extractor().getTimeStamp()); + } + + @Test + @Override + public void testViewCount() throws Exception { + assertAtLeast(expectedViewCountAtLeast(), extractor().getViewCount()); + } + + @Test + @Override + public void testUploadDate() throws Exception { + final DateWrapper dateWrapper = extractor().getUploadDate(); + + if (expectedUploadDate() == null) { + assertNull(dateWrapper); + } else { + assertNotNull(dateWrapper); + + final Calendar expectedDate = Calendar.getInstance(); + final Calendar actualDate = dateWrapper.date(); + expectedDate.setTimeZone(TimeZone.getTimeZone("GMT")); + actualDate.setTimeZone(TimeZone.getTimeZone("GMT")); + + final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S"); + expectedDate.setTime(sdf.parse(expectedUploadDate())); + assertEquals(expectedDate, actualDate); + } + } + + @Test + @Override + public void testTextualUploadDate() throws Exception { + assertEquals(expectedTextualUploadDate(), extractor().getTextualUploadDate()); + } + + @Test + @Override + public void testLikeCount() throws Exception { + if (expectedLikeCountAtLeast() == -1) { + assertEquals(-1, extractor().getLikeCount()); + } else { + assertAtLeast(expectedLikeCountAtLeast(), extractor().getLikeCount()); + } + } + + @Test + @Override + public void testDislikeCount() throws Exception { + if (expectedDislikeCountAtLeast() == -1) { + assertEquals(-1, extractor().getDislikeCount()); + } else { + assertAtLeast(expectedDislikeCountAtLeast(), extractor().getDislikeCount()); + } + } + + @Test + @Override + public void testRelatedStreams() throws Exception { + final StreamInfoItemsCollector relatedStreams = extractor().getRelatedStreams(); + + if (expectedHasRelatedStreams()) { + defaultTestListOfItems(extractor().getService(), relatedStreams.getItems(), + relatedStreams.getErrors()); + } else { + assertNull(relatedStreams); + } + } + + @Test + @Override + public void testAgeLimit() throws Exception { + assertEquals(expectedAgeLimit(), extractor().getAgeLimit()); + } + + @Test + @Override + public void testErrorMessage() throws Exception { + assertEquals(expectedErrorMessage(), extractor().getErrorMessage()); + } + + @Test + @Override + public void testVideoStreams() throws Exception { + List videoStreams = extractor().getVideoStreams(); + final List videoOnlyStreams = extractor().getVideoOnlyStreams(); + assertNotNull(videoStreams); + assertNotNull(videoOnlyStreams); + videoStreams.addAll(videoOnlyStreams); + + if (expectedHasVideoStreams()) { + assertFalse(videoStreams.isEmpty()); + + for (VideoStream stream : videoStreams) { + assertIsSecureUrl(stream.getUrl()); + assertFalse(stream.getResolution().isEmpty()); + + int formatId = stream.getFormatId(); + assertTrue("format id does not fit a video stream: " + formatId, + 0 <= formatId && formatId < 0x100); + } + } else { + assertTrue(videoStreams.isEmpty()); + } + } + + @Test + @Override + public void testAudioStreams() throws Exception { + final List audioStreams = extractor().getAudioStreams(); + assertNotNull(audioStreams); + + if (expectedHasAudioStreams()) { + assertFalse(audioStreams.isEmpty()); + + for (AudioStream stream : audioStreams) { + assertIsSecureUrl(stream.getUrl()); + + int formatId = stream.getFormatId(); + assertTrue("format id does not fit an audio stream: " + formatId, + 0x100 <= formatId && formatId < 0x1000); + } + } else { + assertTrue(audioStreams.isEmpty()); + } + } + + @Test + @Override + public void testSubtitles() throws Exception { + List subtitles = extractor().getSubtitlesDefault(); + assertNotNull(subtitles); + + if (expectedHasSubtitles()) { + assertFalse(subtitles.isEmpty()); + + for (SubtitlesStream stream : subtitles) { + assertIsSecureUrl(stream.getUrl()); + + int formatId = stream.getFormatId(); + assertTrue("format id does not fit an audio stream: " + formatId, + 0x1000 <= formatId && formatId < 0x10000); + } + } else { + assertTrue(subtitles.isEmpty()); + + MediaFormat[] formats = {MediaFormat.VTT, MediaFormat.TTML, MediaFormat.TRANSCRIPT1, + MediaFormat.TRANSCRIPT2, MediaFormat.TRANSCRIPT3, MediaFormat.SRT}; + for (MediaFormat format : formats) { + subtitles = extractor().getSubtitles(format); + assertNotNull(subtitles); + assertTrue(subtitles.isEmpty()); + } + } + } + + @Test + @Override + public void testFrames() throws Exception { + final List frames = extractor().getFrames(); + assertNotNull(frames); + + if (expectedHasFrames()) { + assertFalse(frames.isEmpty()); + for (final Frameset f : frames) { + for (final String url : f.getUrls()) { + assertIsValidUrl(url); + assertIsSecureUrl(url); + } + } + } else { + assertTrue(frames.isEmpty()); + } + } +} diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultTests.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultTests.java index a335b0eca..d2b9ca4ae 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultTests.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultTests.java @@ -10,7 +10,6 @@ import org.schabi.newpipe.extractor.localization.DateWrapper; import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem; -import java.util.Calendar; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -42,7 +41,7 @@ public final class DefaultTests { StreamInfoItem streamInfoItem = (StreamInfoItem) item; assertNotEmpty("Uploader name not set: " + item, streamInfoItem.getUploaderName()); -// assertNotEmpty("Uploader url not set: " + item, streamInfoItem.getUploaderUrl()); + // assertNotEmpty("Uploader url not set: " + item, streamInfoItem.getUploaderUrl()); final String uploaderUrl = streamInfoItem.getUploaderUrl(); if (!isNullOrEmpty(uploaderUrl)) { assertIsSecureUrl(uploaderUrl); @@ -54,7 +53,6 @@ public final class DefaultTests { if (!isNullOrEmpty(streamInfoItem.getTextualUploadDate())) { final DateWrapper uploadDate = streamInfoItem.getUploadDate(); assertNotNull("No parsed upload date", uploadDate); - assertTrue("Upload date not in the past", uploadDate.date().before(Calendar.getInstance())); } } else if (item instanceof ChannelInfoItem) { diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCStreamExtractorTest.java index 95c882290..6a4c4c0e2 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCStreamExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCStreamExtractorTest.java @@ -1,204 +1,148 @@ package org.schabi.newpipe.extractor.services.media_ccc; -import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.schabi.newpipe.DownloaderTestImpl; import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.exceptions.ParsingException; +import org.schabi.newpipe.extractor.StreamingService; +import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest; import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCStreamExtractor; -import org.schabi.newpipe.extractor.stream.AudioStream; -import org.schabi.newpipe.extractor.stream.VideoStream; +import org.schabi.newpipe.extractor.stream.StreamExtractor; +import org.schabi.newpipe.extractor.stream.StreamType; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; +import java.util.Arrays; import java.util.List; -import static java.util.Objects.requireNonNull; +import javax.annotation.Nullable; + import static junit.framework.TestCase.assertEquals; -import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl; import static org.schabi.newpipe.extractor.ServiceList.MediaCCC; /** * Test {@link MediaCCCStreamExtractor} */ public class MediaCCCStreamExtractorTest { - public static class Gpn18Tmux { - private static MediaCCCStreamExtractor extractor; + private static final String BASE_URL = "https://media.ccc.de/v/"; + + public static class Gpn18Tmux extends DefaultStreamExtractorTest { + private static final String ID = "gpn18-105-tmux-warum-ein-schwarzes-fenster-am-bildschirm-reicht"; + private static final String URL = BASE_URL + ID; + private static StreamExtractor extractor; @BeforeClass - public static void setUpClass() throws Exception { + public static void setUp() throws Exception { NewPipe.init(DownloaderTestImpl.getInstance()); - - extractor = (MediaCCCStreamExtractor) MediaCCC.getStreamExtractor("https://media.ccc.de/v/gpn18-105-tmux-warum-ein-schwarzes-fenster-am-bildschirm-reicht"); + extractor = MediaCCC.getStreamExtractor(URL); extractor.fetchPage(); } - @Test - public void testServiceId() throws Exception { - assertEquals(2, extractor.getServiceId()); - } + @Override public StreamExtractor extractor() { return extractor; } + @Override public StreamingService expectedService() { return MediaCCC; } + @Override public String expectedName() { return "tmux - Warum ein schwarzes Fenster am Bildschirm reicht"; } + @Override public String expectedId() { return ID; } + @Override public String expectedUrlContains() { return URL; } + @Override public String expectedOriginalUrlContains() { return URL; } - @Test - public void testName() throws Exception { - assertEquals("tmux - Warum ein schwarzes Fenster am Bildschirm reicht", extractor.getName()); - } + @Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; } + @Override public String expectedUploaderName() { return "gpn18"; } + @Override public String expectedUploaderUrl() { return "https://media.ccc.de/c/gpn18"; } + @Override public List expectedDescriptionContains() { return Arrays.asList("SSH-Sessions", "\"Terminal Multiplexer\""); } + @Override public long expectedLength() { return 3097; } + @Override public long expectedViewCountAtLeast() { return 2380; } + @Nullable @Override public String expectedUploadDate() { return "2018-05-11 00:00:00.000"; } + @Nullable @Override public String expectedTextualUploadDate() { return "2018-05-11T02:00:00.000+02:00"; } + @Override public long expectedLikeCountAtLeast() { return -1; } + @Override public long expectedDislikeCountAtLeast() { return -1; } + @Override public boolean expectedHasSubtitles() { return false; } + @Override public boolean expectedHasFrames() { return false; } + @Override @Test - public void testId() throws Exception { - assertEquals("gpn18-105-tmux-warum-ein-schwarzes-fenster-am-bildschirm-reicht", extractor.getId()); - } - - @Test - public void testUrl() throws Exception { - assertIsSecureUrl(extractor.getUrl()); - assertEquals("https://media.ccc.de/public/events/gpn18-105-tmux-warum-ein-schwarzes-fenster-am-bildschirm-reicht", extractor.getUrl()); - } - - @Test - public void testOriginalUrl() throws Exception { - assertIsSecureUrl(extractor.getOriginalUrl()); - assertEquals("https://media.ccc.de/v/gpn18-105-tmux-warum-ein-schwarzes-fenster-am-bildschirm-reicht", extractor.getOriginalUrl()); - } - - @Test - public void testThumbnail() throws Exception { - assertIsSecureUrl(extractor.getThumbnailUrl()); + public void testThumbnailUrl() throws Exception { + super.testThumbnailUrl(); assertEquals("https://static.media.ccc.de/media/events/gpn/gpn18/105-hd.jpg", extractor.getThumbnailUrl()); } - @Test - public void testUploaderName() throws Exception { - assertEquals("gpn18", extractor.getUploaderName()); - } - - @Test - public void testUploaderUrl() throws Exception { - assertIsSecureUrl(extractor.getUploaderUrl()); - assertEquals("https://media.ccc.de/public/conferences/gpn18", extractor.getUploaderUrl()); - } - + @Override @Test public void testUploaderAvatarUrl() throws Exception { - assertIsSecureUrl(extractor.getUploaderAvatarUrl()); + super.testUploaderAvatarUrl(); assertEquals("https://static.media.ccc.de/media/events/gpn/gpn18/logo.png", extractor.getUploaderAvatarUrl()); } + @Override @Test public void testVideoStreams() throws Exception { - List videoStreamList = extractor.getVideoStreams(); - assertEquals(4, videoStreamList.size()); - for (VideoStream stream : videoStreamList) { - assertIsSecureUrl(stream.getUrl()); - } + super.testVideoStreams(); + assertEquals(4, extractor.getVideoStreams().size()); } + @Override @Test public void testAudioStreams() throws Exception { - List audioStreamList = extractor.getAudioStreams(); - assertEquals(2, audioStreamList.size()); - for (AudioStream stream : audioStreamList) { - assertIsSecureUrl(stream.getUrl()); - } - } - - @Test - public void testGetTextualUploadDate() throws ParsingException { - Assert.assertEquals("2018-05-11T02:00:00.000+02:00", extractor.getTextualUploadDate()); - } - - @Test - public void testGetUploadDate() throws ParsingException, ParseException { - final Calendar instance = Calendar.getInstance(); - instance.setTime(new SimpleDateFormat("yyyy-MM-dd").parse("2018-05-11")); - assertEquals(instance, requireNonNull(extractor.getUploadDate()).date()); + super.testAudioStreams(); + assertEquals(2, extractor.getAudioStreams().size()); } } - public static class _36c3PrivacyMessaging { - private static MediaCCCStreamExtractor extractor; + public static class _36c3PrivacyMessaging extends DefaultStreamExtractorTest { + private static final String ID = "36c3-10565-what_s_left_for_private_messaging"; + private static final String URL = BASE_URL + ID; + private static StreamExtractor extractor; @BeforeClass - public static void setUpClass() throws Exception { + public static void setUp() throws Exception { NewPipe.init(DownloaderTestImpl.getInstance()); - extractor = (MediaCCCStreamExtractor) MediaCCC.getStreamExtractor("https://media.ccc.de/v/36c3-10565-what_s_left_for_private_messaging"); + extractor = MediaCCC.getStreamExtractor(URL); extractor.fetchPage(); } - @Test - public void testName() throws Exception { - assertEquals("What's left for private messaging?", extractor.getName()); - } + @Override public StreamExtractor extractor() { return extractor; } + @Override public StreamingService expectedService() { return MediaCCC; } + @Override public String expectedName() { return "What's left for private messaging?"; } + @Override public String expectedId() { return ID; } + @Override public String expectedUrlContains() { return URL; } + @Override public String expectedOriginalUrlContains() { return URL; } - @Test - public void testId() throws Exception { - assertEquals("36c3-10565-what_s_left_for_private_messaging", extractor.getId()); - } + @Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; } + @Override public String expectedUploaderName() { return "36c3"; } + @Override public String expectedUploaderUrl() { return "https://media.ccc.de/c/36c3"; } + @Override public List expectedDescriptionContains() { return Arrays.asList("WhatsApp", "Signal"); } + @Override public long expectedLength() { return 3603; } + @Override public long expectedViewCountAtLeast() { return 2380; } + @Nullable @Override public String expectedUploadDate() { return "2020-01-11 00:00:00.000"; } + @Nullable @Override public String expectedTextualUploadDate() { return "2020-01-11T01:00:00.000+01:00"; } + @Override public long expectedLikeCountAtLeast() { return -1; } + @Override public long expectedDislikeCountAtLeast() { return -1; } + @Override public boolean expectedHasSubtitles() { return false; } + @Override public boolean expectedHasFrames() { return false; } + @Override @Test - public void testUrl() throws Exception { - assertIsSecureUrl(extractor.getUrl()); - assertEquals("https://media.ccc.de/public/events/36c3-10565-what_s_left_for_private_messaging", extractor.getUrl()); - } - - @Test - public void testOriginalUrl() throws Exception { - assertIsSecureUrl(extractor.getOriginalUrl()); - assertEquals("https://media.ccc.de/v/36c3-10565-what_s_left_for_private_messaging", extractor.getOriginalUrl()); - } - - @Test - public void testThumbnail() throws Exception { - assertIsSecureUrl(extractor.getThumbnailUrl()); + public void testThumbnailUrl() throws Exception { + super.testThumbnailUrl(); assertEquals("https://static.media.ccc.de/media/congress/2019/10565-hd.jpg", extractor.getThumbnailUrl()); } - @Test - public void testUploaderName() throws Exception { - assertEquals("36c3", extractor.getUploaderName()); - } - - @Test - public void testUploaderUrl() throws Exception { - assertIsSecureUrl(extractor.getUploaderUrl()); - assertEquals("https://media.ccc.de/public/conferences/36c3", extractor.getUploaderUrl()); - } - + @Override @Test public void testUploaderAvatarUrl() throws Exception { - assertIsSecureUrl(extractor.getUploaderAvatarUrl()); + super.testUploaderAvatarUrl(); assertEquals("https://static.media.ccc.de/media/congress/2019/logo.png", extractor.getUploaderAvatarUrl()); } + @Override @Test public void testVideoStreams() throws Exception { - List videoStreamList = extractor.getVideoStreams(); - assertEquals(8, videoStreamList.size()); - for (VideoStream stream : videoStreamList) { - assertIsSecureUrl(stream.getUrl()); - } + super.testVideoStreams(); + assertEquals(8, extractor.getVideoStreams().size()); } + @Override @Test public void testAudioStreams() throws Exception { - List audioStreamList = extractor.getAudioStreams(); - assertEquals(2, audioStreamList.size()); - for (AudioStream stream : audioStreamList) { - assertIsSecureUrl(stream.getUrl()); - } - } - - @Test - public void testGetTextualUploadDate() throws ParsingException { - Assert.assertEquals("2020-01-11T01:00:00.000+01:00", extractor.getTextualUploadDate()); - } - - @Test - public void testGetUploadDate() throws ParsingException, ParseException { - final Calendar instance = Calendar.getInstance(); - instance.setTime(new SimpleDateFormat("yyyy-MM-dd").parse("2020-01-11")); - assertEquals(instance, requireNonNull(extractor.getUploadDate()).date()); + super.testAudioStreams(); + assertEquals(2, extractor.getAudioStreams().size()); } } } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorDefaultTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorDefaultTest.java deleted file mode 100644 index c3d8c7169..000000000 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorDefaultTest.java +++ /dev/null @@ -1,180 +0,0 @@ -package org.schabi.newpipe.extractor.services.peertube; - -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; -import org.schabi.newpipe.DownloaderTestImpl; -import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.exceptions.ExtractionException; -import org.schabi.newpipe.extractor.exceptions.ParsingException; -import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeStreamExtractor; -import org.schabi.newpipe.extractor.stream.StreamExtractor; -import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector; -import org.schabi.newpipe.extractor.stream.StreamType; - -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Locale; -import java.util.TimeZone; - -import static java.util.Objects.requireNonNull; -import static org.junit.Assert.*; -import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl; -import static org.schabi.newpipe.extractor.ServiceList.PeerTube; - -/** - * Test for {@link StreamExtractor} - */ -public class PeertubeStreamExtractorDefaultTest { - private static PeertubeStreamExtractor extractor; - private static final String expectedLargeDescription = "**[Want to help to translate this video?](https://weblate.framasoft.org/projects/what-is-peertube-video/)**\r\n\r\n**Take back the control of your videos! [#JoinPeertube](https://joinpeertube.org)**\r\n*A decentralized video hosting network, based on free/libre software!*\r\n\r\n**Animation Produced by:** [LILA](https://libreart.info) - [ZeMarmot Team](https://film.zemarmot.net)\r\n*Directed by* Aryeom\r\n*Assistant* Jehan\r\n**Licence**: [CC-By-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)\r\n\r\n**Sponsored by** [Framasoft](https://framasoft.org)\r\n\r\n**Music**: [Red Step Forward](http://play.dogmazic.net/song.php?song_id=52491) - CC-By Ken Bushima\r\n\r\n**Movie Clip**: [Caminades 3: Llamigos](http://www.caminandes.com/) CC-By Blender Institute\r\n\r\n**Video sources**: https://gitlab.gnome.org/Jehan/what-is-peertube/"; - private static final String expectedSmallDescription = "https://www.kickstarter.com/projects/1587081065/nothing-to-hide-the-documentary"; - - @BeforeClass - public static void setUp() throws Exception { - NewPipe.init(DownloaderTestImpl.getInstance()); - // setting instance might break test when running in parallel - PeerTube.setInstance(new PeertubeInstance("https://framatube.org", "FramaTube")); - extractor = (PeertubeStreamExtractor) PeerTube.getStreamExtractor("https://framatube.org/videos/watch/9c9de5e8-0a1e-484a-b099-e80766180a6d"); - extractor.fetchPage(); - } - - @Test - public void testGetUploadDate() throws ParsingException, ParseException { - final Calendar instance = Calendar.getInstance(); - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S'Z'"); - sdf.setTimeZone(TimeZone.getTimeZone("GMT")); - instance.setTime(sdf.parse("2018-10-01T10:52:46.396Z")); - assertEquals(instance, requireNonNull(extractor.getUploadDate()).date()); - - } - - @Test - public void testGetInvalidTimeStamp() throws ParsingException { - assertTrue(extractor.getTimeStamp() + "", - extractor.getTimeStamp() <= 0); - } - - @Test - public void testGetTitle() throws ParsingException { - assertEquals("What is PeerTube?", extractor.getName()); - } - - @Test - public void testGetLargeDescription() throws ParsingException { - assertEquals(expectedLargeDescription, extractor.getDescription().getContent()); - } - - @Test - public void testGetEmptyDescription() throws Exception { - PeertubeStreamExtractor extractorEmpty = (PeertubeStreamExtractor) PeerTube.getStreamExtractor("https://framatube.org/api/v1/videos/d5907aad-2252-4207-89ec-a4b687b9337d"); - extractorEmpty.fetchPage(); - assertEquals("", extractorEmpty.getDescription().getContent()); - } - - @Test - public void testGetSmallDescription() throws Exception { - PeerTube.setInstance(new PeertubeInstance("https://peertube.cpy.re", "PeerTube test server")); - PeertubeStreamExtractor extractorSmall = (PeertubeStreamExtractor) PeerTube.getStreamExtractor("https://peertube.cpy.re/videos/watch/d2a5ec78-5f85-4090-8ec5-dc1102e022ea"); - extractorSmall.fetchPage(); - assertEquals(expectedSmallDescription, extractorSmall.getDescription().getContent()); - } - - @Test - public void testGetUploaderName() throws ParsingException { - assertEquals("Framasoft", extractor.getUploaderName()); - } - - @Test - public void testGetUploaderUrl() throws ParsingException { - assertIsSecureUrl(extractor.getUploaderUrl()); - assertEquals("https://framatube.org/api/v1/accounts/framasoft@framatube.org", extractor.getUploaderUrl()); - } - - @Test - public void testGetUploaderAvatarUrl() throws ParsingException { - assertIsSecureUrl(extractor.getUploaderAvatarUrl()); - } - - @Test - public void testGetSubChannelName() throws ParsingException { - assertEquals("Les vidéos de Framasoft", extractor.getSubChannelName()); - } - - @Test - public void testGetSubChannelUrl() throws ParsingException { - assertIsSecureUrl(extractor.getSubChannelUrl()); - assertEquals("https://framatube.org/video-channels/bf54d359-cfad-4935-9d45-9d6be93f63e8", extractor.getSubChannelUrl()); - } - - @Test - public void testGetSubChannelAvatarUrl() throws ParsingException { - assertIsSecureUrl(extractor.getSubChannelAvatarUrl()); - } - - @Test - public void testGetLength() throws ParsingException { - assertEquals(113, extractor.getLength()); - } - - @Test - public void testGetViewCount() throws ParsingException { - assertTrue(Long.toString(extractor.getViewCount()), - extractor.getViewCount() > 10); - } - - @Test - public void testGetThumbnailUrl() throws ParsingException { - assertIsSecureUrl(extractor.getThumbnailUrl()); - } - - @Test - public void testGetVideoStreams() throws IOException, ExtractionException { - assertFalse(extractor.getVideoStreams().isEmpty()); - } - - @Test - public void testStreamType() throws ParsingException { - assertTrue(extractor.getStreamType() == StreamType.VIDEO_STREAM); - } - - @Ignore - @Test - public void testGetRelatedVideos() throws ExtractionException, IOException { - StreamInfoItemsCollector relatedVideos = extractor.getRelatedStreams(); - assertFalse(relatedVideos.getItems().isEmpty()); - assertTrue(relatedVideos.getErrors().isEmpty()); - } - - @Test - public void testGetSubtitlesListDefault() throws IOException, ExtractionException { - assertFalse(extractor.getSubtitlesDefault().isEmpty()); - } - - @Test - public void testGetSubtitlesList() throws IOException, ExtractionException { - assertFalse(extractor.getSubtitlesDefault().isEmpty()); - } - - @Test - public void testGetAgeLimit() throws ExtractionException, IOException { - assertEquals(0, extractor.getAgeLimit()); - PeertubeStreamExtractor ageLimit = (PeertubeStreamExtractor) PeerTube.getStreamExtractor("https://nocensoring.net/videos/embed/dbd8e5e1-c527-49b6-b70c-89101dbb9c08"); - ageLimit.fetchPage(); - assertEquals(18, ageLimit.getAgeLimit()); - } - - @Test - public void testGetSupportInformation() throws ExtractionException, IOException { - PeertubeStreamExtractor supportInfoExtractor = (PeertubeStreamExtractor) PeerTube.getStreamExtractor("https://framatube.org/videos/watch/ee408ec8-07cd-4e35-b884-fb681a4b9d37"); - supportInfoExtractor.fetchPage(); - assertEquals("https://utip.io/chatsceptique", supportInfoExtractor.getSupportInfo()); - } - - @Test - public void testGetLanguageInformation() throws ParsingException { - assertEquals(new Locale("en"), extractor.getLanguageInfo()); - } -} diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java new file mode 100644 index 000000000..bddb75bd4 --- /dev/null +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java @@ -0,0 +1,165 @@ +package org.schabi.newpipe.extractor.services.peertube; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.schabi.newpipe.DownloaderTestImpl; +import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.StreamingService; +import org.schabi.newpipe.extractor.exceptions.ExtractionException; +import org.schabi.newpipe.extractor.exceptions.ParsingException; +import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest; +import org.schabi.newpipe.extractor.stream.StreamExtractor; +import org.schabi.newpipe.extractor.stream.StreamType; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +import javax.annotation.Nullable; + +import static org.junit.Assert.assertEquals; +import static org.schabi.newpipe.extractor.ServiceList.PeerTube; + +public class PeertubeStreamExtractorTest { + private static final String BASE_URL = "/videos/watch/"; + + public static class WhatIsPeertube extends DefaultStreamExtractorTest { + private static final String ID = "9c9de5e8-0a1e-484a-b099-e80766180a6d"; + private static final String INSTANCE = "https://framatube.org"; + private static final String URL = INSTANCE + BASE_URL + ID; + private static StreamExtractor extractor; + + @BeforeClass + public static void setUp() throws Exception { + NewPipe.init(DownloaderTestImpl.getInstance()); + // setting instance might break test when running in parallel (!) + PeerTube.setInstance(new PeertubeInstance(INSTANCE, "FramaTube")); + extractor = PeerTube.getStreamExtractor(URL); + extractor.fetchPage(); + } + + @Test + public void testGetLanguageInformation() throws ParsingException { + assertEquals(new Locale("en"), extractor.getLanguageInfo()); + } + + @Override public StreamExtractor extractor() { return extractor; } + @Override public StreamingService expectedService() { return PeerTube; } + @Override public String expectedName() { return "What is PeerTube?"; } + @Override public String expectedId() { return ID; } + @Override public String expectedUrlContains() { return BASE_URL + ID; } + @Override public String expectedOriginalUrlContains() { return URL; } + + @Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; } + @Override public String expectedUploaderName() { return "Framasoft"; } + @Override public String expectedUploaderUrl() { return "https://framatube.org/accounts/framasoft"; } + @Override public List expectedDescriptionContains() { // CRLF line ending + return Arrays.asList("**[Want to help to translate this video?](https://weblate.framasoft.org/projects/what-is-peertube-video/)**\r\n" + + "\r\n" + + "**Take back the control of your videos! [#JoinPeertube](https://joinpeertube.org)**\r\n" + + "*A decentralized video hosting network, based on free/libre software!*\r\n" + + "\r\n" + + "**Animation Produced by:** [LILA](https://libreart.info) - [ZeMarmot Team](https://film.zemarmot.net)\r\n" + + "*Directed by* Aryeom\r\n" + + "*Assistant* Jehan\r\n" + + "**Licence**: [CC-By-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)\r\n" + + "\r\n" + + "**Sponsored by** [Framasoft](https://framasoft.org)\r\n" + + "\r\n" + + "**Music**: [Red Step Forward](http://play.dogmazic.net/song.php?song_id=52491) - CC-By Ken Bushima\r\n" + + "\r\n" + + "**Movie Clip**: [Caminades 3: Llamigos](http://www.caminandes.com/) CC-By Blender Institute\r\n" + + "\r\n" + + "**Video sources**: https://gitlab.gnome.org/Jehan/what-is-peertube/"); + } + @Override public long expectedLength() { return 113; } + @Override public long expectedViewCountAtLeast() { return 38600; } + @Nullable @Override public String expectedUploadDate() { return "2018-10-01 12:52:46.396"; } // GMT (!) + @Nullable @Override public String expectedTextualUploadDate() { return "2018-10-01T10:52:46.396Z"; } + @Override public long expectedLikeCountAtLeast() { return 120; } + @Override public long expectedDislikeCountAtLeast() { return 0; } + @Override public boolean expectedHasAudioStreams() { return false; } + @Override public boolean expectedHasFrames() { return false; } + + } + + public static class AgeRestricted extends DefaultStreamExtractorTest { + private static final String ID = "0d501633-f2d9-4476-87c6-71f1c02402a4"; + private static final String INSTANCE = "https://peertube.co.uk"; + private static final String URL = INSTANCE + BASE_URL + ID; + private static StreamExtractor extractor; + + @BeforeClass + public static void setUp() throws Exception { + NewPipe.init(DownloaderTestImpl.getInstance());; + // setting instance might break test when running in parallel (!) + PeerTube.setInstance(new PeertubeInstance(INSTANCE)); + extractor = PeerTube.getStreamExtractor(URL); + extractor.fetchPage(); + } + + @Override public StreamExtractor extractor() { return extractor; } + @Override public StreamingService expectedService() { return PeerTube; } + @Override public String expectedName() { return "A DPR Combatant Describes how Orders are Given through Russian Officers"; } + @Override public String expectedId() { return ID; } + @Override public String expectedUrlContains() { return BASE_URL + ID; } + @Override public String expectedOriginalUrlContains() { return URL; } + + @Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; } + @Override public String expectedUploaderName() { return "Tomas Berezovskiy"; } + @Override public String expectedUploaderUrl() { return "https://peertube.iriseden.eu/accounts/tomas_berezovskiy"; } + @Override public List expectedDescriptionContains() { // LF line ending + return Arrays.asList("https://en.informnapalm.org/dpr-combatant-describes-orders-given-russian-officers/ " + + " The InformNapalm team received another video of a separatist prisoner of war telling about his " + + "activities in `Dontesk People’s Republic’ (DPR) structures. The video is old, as the interrogation" + + " date is September, but it is the situation described is still relevant and interesting today. In " + + "this recording the combatant re-tells how he came to be recruited into the DPR forces, and how " + + "they are operating under Russian military command. He expresses remorse for his stupidity. Perhaps" + + " he is just saying what he thinks his interrogator wants to hear, perhaps he is speaking from a " + + "new understanding?\n" + + "\n" + + "The video contains a lot of cut and paste (stitching) in places where intelligence data or valuable" + + " information has been deleted because it cannot be shared publically. We trust you will understand " + + "this necessity."); + } + @Override public long expectedLength() { return 512; } + @Override public long expectedViewCountAtLeast() { return 7; } + @Nullable @Override public String expectedUploadDate() { return "2019-10-22 08:16:48.982"; } // GMT (!) + @Nullable @Override public String expectedTextualUploadDate() { return "2019-10-22T06:16:48.982Z"; } + @Override public long expectedLikeCountAtLeast() { return 3; } + @Override public long expectedDislikeCountAtLeast() { return 0; } + @Override public int expectedAgeLimit() { return 18; } + @Override public boolean expectedHasAudioStreams() { return false; } + @Override public boolean expectedHasSubtitles() { return false; } + @Override public boolean expectedHasFrames() { return false; } + } + + + @BeforeClass + public static void setUp() throws Exception { + NewPipe.init(DownloaderTestImpl.getInstance()); + PeerTube.setInstance(new PeertubeInstance("https://peertube.cpy.re", "PeerTube test server")); + } + + @Test + public void testGetEmptyDescription() throws Exception { + StreamExtractor extractorEmpty = PeerTube.getStreamExtractor("https://framatube.org/api/v1/videos/d5907aad-2252-4207-89ec-a4b687b9337d"); + extractorEmpty.fetchPage(); + assertEquals("", extractorEmpty.getDescription().getContent()); + } + + @Test + public void testGetSmallDescription() throws Exception { + StreamExtractor extractorSmall = PeerTube.getStreamExtractor("https://peertube.cpy.re/videos/watch/d2a5ec78-5f85-4090-8ec5-dc1102e022ea"); + extractorSmall.fetchPage(); + assertEquals("https://www.kickstarter.com/projects/1587081065/nothing-to-hide-the-documentary", extractorSmall.getDescription().getContent()); + } + + @Test + public void testGetSupportInformation() throws ExtractionException, IOException { + StreamExtractor supportInfoExtractor = PeerTube.getStreamExtractor("https://framatube.org/videos/watch/ee408ec8-07cd-4e35-b884-fb681a4b9d37"); + supportInfoExtractor.fetchPage(); + assertEquals("https://utip.io/chatsceptique", supportInfoExtractor.getSupportInfo()); + } +} diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeTrendingExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeTrendingExtractorTest.java index 60f72f9d1..924dbbc1f 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeTrendingExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeTrendingExtractorTest.java @@ -8,8 +8,8 @@ import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.services.BaseListExtractorTest; import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeTrendingExtractor; -import static org.junit.Assert.*; -import static org.schabi.newpipe.extractor.ServiceList.*; +import static org.junit.Assert.assertEquals; +import static org.schabi.newpipe.extractor.ServiceList.PeerTube; import static org.schabi.newpipe.extractor.services.DefaultTests.*; public class PeertubeTrendingExtractorTest { diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudChartsExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudChartsExtractorTest.java index 8abfb4d3f..54c48431b 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudChartsExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudChartsExtractorTest.java @@ -8,7 +8,7 @@ import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.services.BaseListExtractorTest; import org.schabi.newpipe.extractor.services.soundcloud.extractors.SoundcloudChartsExtractor; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import static org.schabi.newpipe.extractor.ServiceList.SoundCloud; import static org.schabi.newpipe.extractor.services.DefaultTests.*; diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudStreamExtractorDefaultTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudStreamExtractorDefaultTest.java deleted file mode 100644 index 794a1a6b6..000000000 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudStreamExtractorDefaultTest.java +++ /dev/null @@ -1,163 +0,0 @@ -package org.schabi.newpipe.extractor.services.soundcloud; - -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.schabi.newpipe.DownloaderTestImpl; -import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException; -import org.schabi.newpipe.extractor.exceptions.ExtractionException; -import org.schabi.newpipe.extractor.exceptions.ParsingException; -import org.schabi.newpipe.extractor.services.soundcloud.extractors.SoundcloudStreamExtractor; -import org.schabi.newpipe.extractor.stream.StreamExtractor; -import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector; -import org.schabi.newpipe.extractor.stream.StreamType; - -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.TimeZone; - -import static java.util.Objects.requireNonNull; -import static org.junit.Assert.*; -import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl; -import static org.schabi.newpipe.extractor.ServiceList.SoundCloud; - -/** - * Test for {@link StreamExtractor} - */ -public class SoundcloudStreamExtractorDefaultTest { - - public static class LilUziVertDoWhatIWant { - private static SoundcloudStreamExtractor extractor; - - @BeforeClass - public static void setUp() throws Exception { - NewPipe.init(DownloaderTestImpl.getInstance()); - extractor = (SoundcloudStreamExtractor) SoundCloud.getStreamExtractor("https://soundcloud.com/liluzivert/do-what-i-want-produced-by-maaly-raw-don-cannon"); - extractor.fetchPage(); - } - - @Test - public void testGetInvalidTimeStamp() throws ParsingException { - assertTrue(extractor.getTimeStamp() + "", - extractor.getTimeStamp() <= 0); - } - - @Test - public void testGetValidTimeStamp() throws IOException, ExtractionException { - StreamExtractor extractor = SoundCloud.getStreamExtractor("https://soundcloud.com/liluzivert/do-what-i-want-produced-by-maaly-raw-don-cannon#t=69"); - assertEquals("69", extractor.getTimeStamp() + ""); - } - - @Test - public void testGetTitle() throws ParsingException { - assertEquals("Do What I Want [Produced By Maaly Raw + Don Cannon]", extractor.getName()); - } - - @Test - public void testGetDescription() throws ParsingException { - assertEquals("The Perfect LUV Tape®️", extractor.getDescription().getContent()); - } - - @Test - public void testGetUploaderName() throws ParsingException { - assertEquals("Lil Uzi Vert", extractor.getUploaderName()); - } - - @Test - public void testGetLength() throws ParsingException { - assertEquals(175, extractor.getLength()); - } - - @Test - public void testGetViewCount() throws ParsingException { - assertTrue(Long.toString(extractor.getViewCount()), - extractor.getViewCount() > 44227978); - } - - @Test - public void testGetTextualUploadDate() throws ParsingException { - Assert.assertEquals("2016-07-31 18:18:07", extractor.getTextualUploadDate()); - } - - @Test - public void testGetUploadDate() throws ParsingException, ParseException { - final Calendar instance = Calendar.getInstance(); - SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss +0000"); - sdf.setTimeZone(TimeZone.getTimeZone("GMT")); - instance.setTime(sdf.parse("2016/07/31 18:18:07 +0000")); - assertEquals(instance, requireNonNull(extractor.getUploadDate()).date()); - } - - @Test - public void testGetUploaderUrl() throws ParsingException { - assertIsSecureUrl(extractor.getUploaderUrl()); - assertEquals("https://soundcloud.com/liluzivert", extractor.getUploaderUrl()); - } - - @Test - public void testGetThumbnailUrl() throws ParsingException { - assertIsSecureUrl(extractor.getThumbnailUrl()); - } - - @Test - public void testGetUploaderAvatarUrl() throws ParsingException { - assertIsSecureUrl(extractor.getUploaderAvatarUrl()); - } - - @Test - public void testGetAudioStreams() throws IOException, ExtractionException { - assertFalse(extractor.getAudioStreams().isEmpty()); - } - - @Test - public void testStreamType() throws ParsingException { - assertTrue(extractor.getStreamType() == StreamType.AUDIO_STREAM); - } - - @Test - public void testGetRelatedVideos() throws ExtractionException, IOException { - StreamInfoItemsCollector relatedVideos = extractor.getRelatedStreams(); - assertFalse(relatedVideos.getItems().isEmpty()); - assertTrue(relatedVideos.getErrors().isEmpty()); - } - - @Test - public void testGetSubtitlesListDefault() throws IOException, ExtractionException { - // Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null - assertTrue(extractor.getSubtitlesDefault().isEmpty()); - } - - @Test - public void testGetSubtitlesList() throws IOException, ExtractionException { - // Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null - assertTrue(extractor.getSubtitlesDefault().isEmpty()); - } - } - - public static class ContentNotSupported { - @BeforeClass - public static void setUp() { - NewPipe.init(DownloaderTestImpl.getInstance()); - } - - @Test(expected = ContentNotSupportedException.class) - public void hlsAudioStream() throws Exception { - final StreamExtractor extractor = - SoundCloud.getStreamExtractor("https://soundcloud.com/dualipa/cool"); - extractor.fetchPage(); - extractor.getAudioStreams(); - } - - @Test(expected = ContentNotSupportedException.class) - public void bothHlsAndOpusAudioStreams() throws Exception { - final StreamExtractor extractor = - SoundCloud.getStreamExtractor("https://soundcloud.com/lil-baby-4pf/no-sucker"); - extractor.fetchPage(); - extractor.getAudioStreams(); - } - } -} - diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudStreamExtractorTest.java new file mode 100644 index 000000000..28c8d0b23 --- /dev/null +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/soundcloud/SoundcloudStreamExtractorTest.java @@ -0,0 +1,81 @@ +package org.schabi.newpipe.extractor.services.soundcloud; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.schabi.newpipe.DownloaderTestImpl; +import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.StreamingService; +import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException; +import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest; +import org.schabi.newpipe.extractor.stream.StreamExtractor; +import org.schabi.newpipe.extractor.stream.StreamType; + +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Nullable; + +import static org.schabi.newpipe.extractor.ServiceList.SoundCloud; + +public class SoundcloudStreamExtractorTest { + + public static class LilUziVertDoWhatIWant extends DefaultStreamExtractorTest { + private static final String ID = "do-what-i-want-produced-by-maaly-raw-don-cannon"; + private static final String UPLOADER = "https://soundcloud.com/liluzivert"; + private static final int TIMESTAMP = 69; + private static final String URL = UPLOADER + "/" + ID + "#t=" + TIMESTAMP; + private static StreamExtractor extractor; + + @BeforeClass + public static void setUp() throws Exception { + NewPipe.init(DownloaderTestImpl.getInstance()); + extractor = SoundCloud.getStreamExtractor(URL); + extractor.fetchPage(); + } + + @Override public StreamExtractor extractor() { return extractor; } + @Override public StreamingService expectedService() { return SoundCloud; } + @Override public String expectedName() { return "Do What I Want [Produced By Maaly Raw + Don Cannon]"; } + @Override public String expectedId() { return "276206960"; } + @Override public String expectedUrlContains() { return UPLOADER + "/" + ID; } + @Override public String expectedOriginalUrlContains() { return URL; } + + @Override public StreamType expectedStreamType() { return StreamType.AUDIO_STREAM; } + @Override public String expectedUploaderName() { return "Lil Uzi Vert"; } + @Override public String expectedUploaderUrl() { return UPLOADER; } + @Override public List expectedDescriptionContains() { return Arrays.asList("The Perfect LUV Tape®"); } + @Override public long expectedLength() { return 175; } + @Override public long expectedTimestamp() { return TIMESTAMP; } + @Override public long expectedViewCountAtLeast() { return 75413600; } + @Nullable @Override public String expectedUploadDate() { return "2016-07-31 18:18:07.000"; } + @Nullable @Override public String expectedTextualUploadDate() { return "2016-07-31 18:18:07"; } + @Override public long expectedLikeCountAtLeast() { return -1; } + @Override public long expectedDislikeCountAtLeast() { return -1; } + @Override public boolean expectedHasVideoStreams() { return false; } + @Override public boolean expectedHasSubtitles() { return false; } + @Override public boolean expectedHasFrames() { return false; } + } + + public static class ContentNotSupported { + @BeforeClass + public static void setUp() { + NewPipe.init(DownloaderTestImpl.getInstance()); + } + + @Test(expected = ContentNotSupportedException.class) + public void hlsAudioStream() throws Exception { + final StreamExtractor extractor = + SoundCloud.getStreamExtractor("https://soundcloud.com/dualipa/cool"); + extractor.fetchPage(); + extractor.getAudioStreams(); + } + + @Test(expected = ContentNotSupportedException.class) + public void bothHlsAndOpusAudioStreams() throws Exception { + final StreamExtractor extractor = + SoundCloud.getStreamExtractor("https://soundcloud.com/lil-baby-4pf/no-sucker"); + extractor.fetchPage(); + extractor.getAudioStreams(); + } + } +} diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java index 95c8aeb43..6844ca2e9 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java @@ -1,144 +1,53 @@ package org.schabi.newpipe.extractor.services.youtube.stream; import org.junit.BeforeClass; -import org.junit.Test; import org.schabi.newpipe.DownloaderTestImpl; -import org.schabi.newpipe.extractor.MediaFormat; import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.exceptions.ExtractionException; -import org.schabi.newpipe.extractor.exceptions.ParsingException; -import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; -import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory; +import org.schabi.newpipe.extractor.StreamingService; +import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest; import org.schabi.newpipe.extractor.stream.StreamExtractor; -import org.schabi.newpipe.extractor.stream.VideoStream; +import org.schabi.newpipe.extractor.stream.StreamType; -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; +import java.util.Arrays; import java.util.List; -import static java.util.Objects.requireNonNull; -import static org.junit.Assert.*; -import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl; +import javax.annotation.Nullable; + import static org.schabi.newpipe.extractor.ServiceList.YouTube; -/** - * Test for {@link YoutubeStreamLinkHandlerFactory} - */ -public class YoutubeStreamExtractorAgeRestrictedTest { - public static final String HTTPS = "https://"; - private static YoutubeStreamExtractor extractor; +public class YoutubeStreamExtractorAgeRestrictedTest extends DefaultStreamExtractorTest { + private static final String ID = "MmBeUZqv1QA"; + private static final int TIMESTAMP = 196; + private static final String URL = YoutubeStreamExtractorDefaultTest.BASE_URL + ID + "&t=" + TIMESTAMP; + private static StreamExtractor extractor; @BeforeClass public static void setUp() throws Exception { NewPipe.init(DownloaderTestImpl.getInstance()); - extractor = (YoutubeStreamExtractor) YouTube - .getStreamExtractor("https://www.youtube.com/watch?v=MmBeUZqv1QA"); + extractor = YouTube.getStreamExtractor(URL); extractor.fetchPage(); } - @Test - public void testGetInvalidTimeStamp() throws ParsingException { - assertTrue(extractor.getTimeStamp() + "", extractor.getTimeStamp() <= 0); - } + @Override public StreamExtractor extractor() { return extractor; } + @Override public StreamingService expectedService() { return YouTube; } + @Override public String expectedName() { return "FINGERING PORNSTARS @ AVN Expo 2017 In Las Vegas!"; } + @Override public String expectedId() { return ID; } + @Override public String expectedUrlContains() { return YoutubeStreamExtractorDefaultTest.BASE_URL + ID; } + @Override public String expectedOriginalUrlContains() { return URL; } - @Test - public void testGetValidTimeStamp() throws IOException, ExtractionException { - StreamExtractor extractor = YouTube.getStreamExtractor("https://youtu.be/FmG385_uUys?t=174"); - assertEquals(extractor.getTimeStamp() + "", "174"); - extractor = YouTube.getStreamExtractor("https://youtube.com/embed/FmG385_uUys?start=174"); - assertEquals(extractor.getTimeStamp() + "", "174"); - } - - @Test - public void testGetAgeLimit() throws ParsingException { - assertEquals(18, extractor.getAgeLimit()); - } - - @Test - public void testGetName() throws ParsingException { - assertNotNull("name is null", extractor.getName()); - assertFalse("name is empty", extractor.getName().isEmpty()); - } - - @Test - public void testGetDescription() throws ParsingException { - assertNotNull(extractor.getDescription()); - assertFalse(extractor.getDescription().getContent().isEmpty()); - } - - @Test - public void testGetUploaderName() throws ParsingException { - assertNotNull(extractor.getUploaderName()); - assertFalse(extractor.getUploaderName().isEmpty()); - } - - @Test - public void testGetLength() throws ParsingException { - assertEquals(1790, extractor.getLength()); - } - - @Test - public void testGetViews() throws ParsingException { - assertTrue(extractor.getViewCount() > 0); - } - - @Test - public void testGetTextualUploadDate() throws ParsingException { - assertEquals("2017-01-25", extractor.getTextualUploadDate()); - } - - @Test - public void testGetUploadDate() throws ParsingException, ParseException { - final Calendar instance = Calendar.getInstance(); - instance.setTime(new SimpleDateFormat("yyyy-MM-dd").parse("2017-01-25")); - assertEquals(instance, requireNonNull(extractor.getUploadDate()).date()); - } - - @Test - public void testGetThumbnailUrl() throws ParsingException { - assertIsSecureUrl(extractor.getThumbnailUrl()); - } - - @Test - public void testGetUploaderAvatarUrl() throws ParsingException { - assertIsSecureUrl(extractor.getUploaderAvatarUrl()); - } - - @Test - public void testGetAudioStreams() throws IOException, ExtractionException { - // audio streams are not always necessary - assertFalse(extractor.getAudioStreams().isEmpty()); - } - - @Test - public void testGetVideoStreams() throws IOException, ExtractionException { - List streams = new ArrayList<>(); - streams.addAll(extractor.getVideoStreams()); - streams.addAll(extractor.getVideoOnlyStreams()); - - assertTrue(Integer.toString(streams.size()), streams.size() > 0); - for (VideoStream s : streams) { - assertTrue(s.getUrl(), - s.getUrl().contains(HTTPS)); - assertTrue(s.resolution.length() > 0); - assertTrue(Integer.toString(s.getFormatId()), - 0 <= s.getFormatId() && s.getFormatId() <= 0x100); - } - } - - - @Test - public void testGetSubtitlesListDefault() throws IOException, ExtractionException { - // Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null - assertTrue(extractor.getSubtitlesDefault().isEmpty()); - } - - @Test - public void testGetSubtitlesList() throws IOException, ExtractionException { - // Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null - assertTrue(extractor.getSubtitles(MediaFormat.TTML).isEmpty()); - } + @Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; } + @Override public String expectedUploaderName() { return "EpicFiveTV"; } + @Override public String expectedUploaderUrl() { return "https://www.youtube.com/channel/UCuPUHlLP5POZphOIrjrNxiw"; } + @Override public List expectedDescriptionContains() { return Arrays.asList("http://instagram.com/Ruben_Sole", "AVN"); } + @Override public long expectedLength() { return 1790; } + @Override public long expectedTimestamp() { return TIMESTAMP; } + @Override public long expectedViewCountAtLeast() { return 28500000; } + @Nullable @Override public String expectedUploadDate() { return "2017-01-25 00:00:00.000"; } + @Nullable @Override public String expectedTextualUploadDate() { return "2017-01-25"; } + @Override public long expectedLikeCountAtLeast() { return 149000; } + @Override public long expectedDislikeCountAtLeast() { return 38000; } + @Override public boolean expectedHasRelatedStreams() { return false; } // no related videos (!) + @Override public int expectedAgeLimit() { return 18; } + @Nullable @Override public String expectedErrorMessage() { return "Sign in to confirm your age"; } + @Override public boolean expectedHasSubtitles() { return false; } } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorControversialTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorControversialTest.java index 915f42ae1..a090460a5 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorControversialTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorControversialTest.java @@ -1,134 +1,54 @@ package org.schabi.newpipe.extractor.services.youtube.stream; import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; import org.schabi.newpipe.DownloaderTestImpl; -import org.schabi.newpipe.extractor.MediaFormat; import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.exceptions.ExtractionException; -import org.schabi.newpipe.extractor.exceptions.ParsingException; -import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; +import org.schabi.newpipe.extractor.StreamingService; +import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest; import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory; import org.schabi.newpipe.extractor.stream.StreamExtractor; -import org.schabi.newpipe.extractor.stream.VideoStream; +import org.schabi.newpipe.extractor.stream.StreamType; -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; +import java.util.Arrays; import java.util.List; -import static java.util.Objects.requireNonNull; -import static org.junit.Assert.*; -import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl; +import javax.annotation.Nullable; + import static org.schabi.newpipe.extractor.ServiceList.YouTube; /** * Test for {@link YoutubeStreamLinkHandlerFactory} */ -public class YoutubeStreamExtractorControversialTest { - private static YoutubeStreamExtractor extractor; +public class YoutubeStreamExtractorControversialTest extends DefaultStreamExtractorTest { + private static final String ID = "T4XJQO3qol8"; + private static final String URL = YoutubeStreamExtractorDefaultTest.BASE_URL + ID; + private static StreamExtractor extractor; @BeforeClass public static void setUp() throws Exception { NewPipe.init(DownloaderTestImpl.getInstance()); - extractor = (YoutubeStreamExtractor) YouTube - .getStreamExtractor("https://www.youtube.com/watch?v=T4XJQO3qol8"); + extractor = YouTube.getStreamExtractor(URL); extractor.fetchPage(); } - @Test - public void testGetInvalidTimeStamp() throws ParsingException { - assertTrue(extractor.getTimeStamp() + "", extractor.getTimeStamp() <= 0); - } + @Override public StreamExtractor extractor() { return extractor; } + @Override public StreamingService expectedService() { return YouTube; } + @Override public String expectedName() { return "Burning Everyone's Koran"; } + @Override public String expectedId() { return ID; } + @Override public String expectedUrlContains() { return URL; } + @Override public String expectedOriginalUrlContains() { return URL; } - @Test - public void testGetValidTimeStamp() throws IOException, ExtractionException { - StreamExtractor extractor = YouTube.getStreamExtractor("https://youtu.be/FmG385_uUys?t=174"); - assertEquals(extractor.getTimeStamp() + "", "174"); - } - - @Test - @Ignore - public void testGetAgeLimit() throws ParsingException { - assertEquals(18, extractor.getAgeLimit()); - } - - @Test - public void testGetName() throws ParsingException { - assertNotNull("name is null", extractor.getName()); - assertFalse("name is empty", extractor.getName().isEmpty()); - } - - @Test - public void testGetDescription() throws ParsingException { - assertNotNull(extractor.getDescription()); - assertFalse(extractor.getDescription().getContent().isEmpty()); - } - - @Test - public void testGetUploaderName() throws ParsingException { - assertNotNull(extractor.getUploaderName()); - assertFalse(extractor.getUploaderName().isEmpty()); - } - - @Test - public void testGetLength() throws ParsingException { - assertEquals(219, extractor.getLength()); - } - - @Test - public void testGetViews() throws ParsingException { - assertTrue(extractor.getViewCount() > 0); - } - - @Test - public void testGetTextualUploadDate() throws ParsingException { - assertEquals("2010-09-09", extractor.getTextualUploadDate()); - } - - @Test - public void testGetUploadDate() throws ParsingException, ParseException { - final Calendar instance = Calendar.getInstance(); - instance.setTime(new SimpleDateFormat("yyyy-MM-dd").parse("2010-09-09")); - assertEquals(instance, requireNonNull(extractor.getUploadDate()).date()); - } - - @Test - public void testGetThumbnailUrl() throws ParsingException { - assertIsSecureUrl(extractor.getThumbnailUrl()); - } - - @Test - public void testGetUploaderAvatarUrl() throws ParsingException { - assertIsSecureUrl(extractor.getUploaderAvatarUrl()); - } - - @Test - public void testGetAudioStreams() throws IOException, ExtractionException { - // audio streams are not always necessary - assertFalse(extractor.getAudioStreams().isEmpty()); - } - - @Test - public void testGetVideoStreams() throws IOException, ExtractionException { - List streams = new ArrayList<>(); - streams.addAll(extractor.getVideoStreams()); - streams.addAll(extractor.getVideoOnlyStreams()); - assertTrue(streams.size() > 0); - } - - @Test - public void testGetSubtitlesListDefault() throws IOException, ExtractionException { - // Video (/view?v=T4XJQO3qol8) set in the setUp() method has at least auto-generated (English) captions - assertFalse(extractor.getSubtitlesDefault().isEmpty()); - } - - @Test - public void testGetSubtitlesList() throws IOException, ExtractionException { - // Video (/view?v=T4XJQO3qol8) set in the setUp() method has at least auto-generated (English) captions - assertFalse(extractor.getSubtitles(MediaFormat.TTML).isEmpty()); + @Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; } + @Override public String expectedUploaderName() { return "Amazing Atheist"; } + @Override public String expectedUploaderUrl() { return "https://www.youtube.com/channel/UCjNxszyFPasDdRoD9J6X-sw"; } + @Override public List expectedDescriptionContains() { + return Arrays.asList("http://www.huffingtonpost.com/2010/09/09/obama-gma-interview-quran_n_710282.html", + "freedom"); } + @Override public long expectedLength() { return 219; } + @Override public long expectedViewCountAtLeast() { return 285000; } + @Nullable @Override public String expectedUploadDate() { return "2010-09-09 00:00:00.000"; } + @Nullable @Override public String expectedTextualUploadDate() { return "2010-09-09"; } + @Override public long expectedLikeCountAtLeast() { return 13300; } + @Override public long expectedDislikeCountAtLeast() { return 2600; } } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java index 0d36fd9a8..49369831b 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java @@ -1,35 +1,22 @@ package org.schabi.newpipe.extractor.services.youtube.stream; -import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.schabi.newpipe.DownloaderTestImpl; -import org.schabi.newpipe.extractor.ExtractorAsserts; -import org.schabi.newpipe.extractor.MediaFormat; import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException; -import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ParsingException; -import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; -import org.schabi.newpipe.extractor.stream.Frameset; +import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest; import org.schabi.newpipe.extractor.stream.StreamExtractor; -import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector; import org.schabi.newpipe.extractor.stream.StreamType; -import org.schabi.newpipe.extractor.stream.VideoStream; -import org.schabi.newpipe.extractor.utils.Utils; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; +import java.util.Arrays; import java.util.List; -import static java.util.Objects.requireNonNull; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import javax.annotation.Nullable; + import static org.junit.Assert.fail; -import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl; import static org.schabi.newpipe.extractor.ServiceList.YouTube; /* @@ -51,11 +38,8 @@ import static org.schabi.newpipe.extractor.ServiceList.YouTube; * You should have received a copy of the GNU General Public License * along with NewPipe. If not, see . */ - -/** - * Test for {@link StreamExtractor} - */ public class YoutubeStreamExtractorDefaultTest { + static final String BASE_URL = "https://www.youtube.com/watch?v="; public static class NotAvailable { @BeforeClass @@ -66,266 +50,163 @@ public class YoutubeStreamExtractorDefaultTest { @Test(expected = ContentNotAvailableException.class) public void nonExistentFetch() throws Exception { final StreamExtractor extractor = - YouTube.getStreamExtractor("https://www.youtube.com/watch?v=don-t-exist"); + YouTube.getStreamExtractor(BASE_URL + "don-t-exist"); extractor.fetchPage(); } @Test(expected = ParsingException.class) public void invalidId() throws Exception { final StreamExtractor extractor = - YouTube.getStreamExtractor("https://www.youtube.com/watch?v=INVALID_ID_INVALID_ID"); + YouTube.getStreamExtractor(BASE_URL + "INVALID_ID_INVALID_ID"); extractor.fetchPage(); } } - /** - * Test for {@link StreamExtractor} - */ - public static class AdeleHello { - private static YoutubeStreamExtractor extractor; + public static class AdeleHello extends DefaultStreamExtractorTest { + private static final String ID = "YQHsXMglC9A"; + private static final String URL = BASE_URL + ID; + private static StreamExtractor extractor; @BeforeClass public static void setUp() throws Exception { NewPipe.init(DownloaderTestImpl.getInstance()); - extractor = (YoutubeStreamExtractor) YouTube - .getStreamExtractor("https://www.youtube.com/watch?v=YQHsXMglC9A"); + extractor = YouTube.getStreamExtractor(URL); extractor.fetchPage(); } @Test - public void testGetInvalidTimeStamp() throws ParsingException { - assertTrue(extractor.getTimeStamp() + "", - extractor.getTimeStamp() <= 0); - } - - @Test - public void testGetValidTimeStamp() throws ExtractionException { - StreamExtractor extractor = YouTube.getStreamExtractor("https://youtu.be/FmG385_uUys?t=174"); - assertEquals(extractor.getTimeStamp() + "", "174"); - } - - @Test - public void testGetTitle() throws ParsingException { - assertFalse(extractor.getName().isEmpty()); - } - - @Test - public void testGetDescription() throws ParsingException { - assertNotNull(extractor.getDescription()); - assertFalse(extractor.getDescription().getContent().isEmpty()); - } - - @Test - public void testGetFullLinksInDescription() throws ParsingException { - assertTrue(extractor.getDescription().getContent().contains("http://adele.com")); - } - - @Test - public void testGetUploaderName() throws ParsingException { - assertNotNull(extractor.getUploaderName()); - assertFalse(extractor.getUploaderName().isEmpty()); - } - - - @Test - public void testGetLength() throws ParsingException { - assertEquals(367, extractor.getLength()); - } - - @Test - public void testGetViewCount() throws ParsingException { - Long count = extractor.getViewCount(); - assertTrue(Long.toString(count), count >= /* specific to that video */ 1220025784); - } - - @Test - public void testGetTextualUploadDate() throws ParsingException { - Assert.assertEquals("2015-10-22", extractor.getTextualUploadDate()); - } - - @Test - public void testGetUploadDate() throws ParsingException, ParseException { - final Calendar instance = Calendar.getInstance(); - instance.setTime(new SimpleDateFormat("yyyy-MM-dd").parse("2015-10-22")); - assertEquals(instance, requireNonNull(extractor.getUploadDate()).date()); - } - - @Test - public void testGetUploaderUrl() throws ParsingException { - String url = extractor.getUploaderUrl(); + @Override + public void testUploaderUrl() throws ParsingException { + String url = extractor().getUploaderUrl(); if (!url.equals("https://www.youtube.com/channel/UCsRM0YB_dabtEPGPTKo-gcw") && !url.equals("https://www.youtube.com/channel/UComP_epzeKzvBX156r6pm1Q")) { fail("Uploader url is neither the music channel one nor the Vevo one"); } } - @Test - public void testGetThumbnailUrl() throws ParsingException { - assertIsSecureUrl(extractor.getThumbnailUrl()); - } + @Override public StreamExtractor extractor() { return extractor; } + @Override public StreamingService expectedService() { return YouTube; } + @Override public String expectedName() { return "Adele - Hello"; } + @Override public String expectedId() { return ID; } + @Override public String expectedUrlContains() { return URL; } + @Override public String expectedOriginalUrlContains() { return URL; } - @Test - public void testGetUploaderAvatarUrl() throws ParsingException { - assertIsSecureUrl(extractor.getUploaderAvatarUrl()); - } - - @Test - public void testGetAudioStreams() throws ExtractionException { - assertFalse(extractor.getAudioStreams().isEmpty()); - } - - @Test - public void testGetVideoStreams() throws ExtractionException { - for (VideoStream s : extractor.getVideoStreams()) { - assertIsSecureUrl(s.url); - assertTrue(s.resolution.length() > 0); - assertTrue(Integer.toString(s.getFormatId()), - 0 <= s.getFormatId() && s.getFormatId() <= 0x100); - } - } - - @Test - public void testStreamType() throws ParsingException { - assertTrue(extractor.getStreamType() == StreamType.VIDEO_STREAM); - } - - @Test - public void testGetDashMpd() throws ParsingException { - // we dont expect this particular video to have a DASH file. For this purpouse we use a different test class. - assertTrue(extractor.getDashMpdUrl(), - extractor.getDashMpdUrl() != null && extractor.getDashMpdUrl().isEmpty()); - } - - @Test - public void testGetRelatedVideos() throws ExtractionException { - StreamInfoItemsCollector relatedVideos = extractor.getRelatedStreams(); - Utils.printErrors(relatedVideos.getErrors()); - assertFalse(relatedVideos.getItems().isEmpty()); - assertTrue(relatedVideos.getErrors().isEmpty()); - } - - @Test - public void testGetSubtitlesListDefault() { - // Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null - assertTrue(extractor.getSubtitlesDefault().isEmpty()); - } - - @Test - public void testGetSubtitlesList() { - // Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null - assertTrue(extractor.getSubtitles(MediaFormat.TTML).isEmpty()); - } - - @Test - public void testGetLikeCount() throws ParsingException { - long likeCount = extractor.getLikeCount(); - assertTrue("" + likeCount, likeCount >= 15000000); - } - - @Test - public void testGetDislikeCount() throws ParsingException { - long dislikeCount = extractor.getDislikeCount(); - assertTrue("" + dislikeCount, dislikeCount >= 818000); - } + @Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; } + @Override public String expectedUploaderName() { return "Adele"; } + @Override public String expectedUploaderUrl() { return null; } // overridden above + @Override public List expectedDescriptionContains() { return Arrays.asList("http://adele.com", "https://www.facebook.com/Adele"); } + @Override public long expectedLength() { return 367; } + @Override public long expectedViewCountAtLeast() { return 1220025784; } + @Nullable @Override public String expectedUploadDate() { return "2015-10-22 00:00:00.000"; } + @Nullable @Override public String expectedTextualUploadDate() { return "2015-10-22"; } + @Override public long expectedLikeCountAtLeast() { return 15289000; } + @Override public long expectedDislikeCountAtLeast() { return 826000; } + @Override public boolean expectedHasSubtitles() { return false; } } - public static class DescriptionTestPewdiepie { - private static YoutubeStreamExtractor extractor; + public static class DescriptionTestPewdiepie extends DefaultStreamExtractorTest { + private static final String ID = "fBc4Q_htqPg"; + private static final int TIMESTAMP = 17; + private static final String URL = BASE_URL + ID + "&t=" + TIMESTAMP; + private static StreamExtractor extractor; @BeforeClass public static void setUp() throws Exception { NewPipe.init(DownloaderTestImpl.getInstance()); - extractor = (YoutubeStreamExtractor) YouTube - .getStreamExtractor("https://www.youtube.com/watch?v=fBc4Q_htqPg"); + extractor = YouTube.getStreamExtractor(URL); extractor.fetchPage(); } - @Test - public void testGetDescription() throws ParsingException { - assertNotNull(extractor.getDescription()); - assertFalse(extractor.getDescription().getContent().isEmpty()); - } + @Override public StreamExtractor extractor() { return extractor; } + @Override public StreamingService expectedService() { return YouTube; } + @Override public String expectedName() { return "Dr. Phil DESTROYS spoiled brat!!!! . -- Dr Phil #7"; } + @Override public String expectedId() { return ID; } + @Override public String expectedUrlContains() { return BASE_URL + ID; } + @Override public String expectedOriginalUrlContains() { return URL; } - @Test - public void testGetFullLinksInDescription() throws ParsingException { - assertTrue(extractor.getDescription().getContent().contains("https://www.reddit.com/r/PewdiepieSubmissions/")); - assertTrue(extractor.getDescription().getContent().contains("https://www.youtube.com/channel/UC3e8EMTOn4g6ZSKggHTnNng")); - assertTrue(extractor.getDescription().getContent().contains("https://usa.clutchchairz.com/product/pewdiepie-edition-throttle-series/")); + @Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; } + @Override public String expectedUploaderName() { return "PewDiePie"; } + @Override public String expectedUploaderUrl() { return "https://www.youtube.com/channel/UC-lHJZR3Gqxm24_Vd_AJ5Yw"; } + @Override public List expectedDescriptionContains() { + return Arrays.asList("https://www.reddit.com/r/PewdiepieSubmissions/", + "https://www.youtube.com/channel/UC3e8EMTOn4g6ZSKggHTnNng", + "https://usa.clutchchairz.com/product/pewdiepie-edition-throttle-series/"); } + @Override public long expectedLength() { return 1165; } + @Override public long expectedTimestamp() { return TIMESTAMP; } + @Override public long expectedViewCountAtLeast() { return 26682500; } + @Nullable @Override public String expectedUploadDate() { return "2018-09-12 00:00:00.000"; } + @Nullable @Override public String expectedTextualUploadDate() { return "2018-09-12"; } + @Override public long expectedLikeCountAtLeast() { return 1166000; } + @Override public long expectedDislikeCountAtLeast() { return 16900; } } - public static class DescriptionTestUnboxing { - private static YoutubeStreamExtractor extractor; + public static class DescriptionTestUnboxing extends DefaultStreamExtractorTest { + private static final String ID = "cV5TjZCJkuA"; + private static final String URL = BASE_URL + ID; + private static StreamExtractor extractor; @BeforeClass public static void setUp() throws Exception { NewPipe.init(DownloaderTestImpl.getInstance()); - extractor = (YoutubeStreamExtractor) YouTube - .getStreamExtractor("https://www.youtube.com/watch?v=cV5TjZCJkuA"); + extractor = YouTube.getStreamExtractor(URL); extractor.fetchPage(); } - @Test - public void testGetDescription() throws ParsingException { - assertNotNull(extractor.getDescription()); - assertFalse(extractor.getDescription().getContent().isEmpty()); - } + @Override public StreamExtractor extractor() { return extractor; } + @Override public StreamingService expectedService() { return YouTube; } + @Override public String expectedName() { return "This Smartphone Changes Everything..."; } + @Override public String expectedId() { return ID; } + @Override public String expectedUrlContains() { return URL; } + @Override public String expectedOriginalUrlContains() { return URL; } - @Test - public void testGetFullLinksInDescription() throws ParsingException { - final String description = extractor.getDescription().getContent(); - assertTrue(description.contains("https://www.youtube.com/watch?v=X7FLCHVXpsA&list=PL7u4lWXQ3wfI_7PgX0C-VTiwLeu0S4v34")); - assertTrue(description.contains("https://www.youtube.com/watch?v=Lqv6G0pDNnw&list=PL7u4lWXQ3wfI_7PgX0C-VTiwLeu0S4v34")); - assertTrue(description.contains("https://www.youtube.com/watch?v=XxaRBPyrnBU&list=PL7u4lWXQ3wfI_7PgX0C-VTiwLeu0S4v34")); - assertTrue(description.contains("https://www.youtube.com/watch?v=U-9tUEOFKNU&list=PL7u4lWXQ3wfI_7PgX0C-VTiwLeu0S4v34")); + @Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; } + @Override public String expectedUploaderName() { return "Unbox Therapy"; } + @Override public String expectedUploaderUrl() { return "https://www.youtube.com/channel/UCsTcErHg8oDvUnTzoqsYeNw"; } + @Override public List expectedDescriptionContains() { + return Arrays.asList("https://www.youtube.com/watch?v=X7FLCHVXpsA&list=PL7u4lWXQ3wfI_7PgX0C-VTiwLeu0S4v34", + "https://www.youtube.com/watch?v=Lqv6G0pDNnw&list=PL7u4lWXQ3wfI_7PgX0C-VTiwLeu0S4v34", + "https://www.youtube.com/watch?v=XxaRBPyrnBU&list=PL7u4lWXQ3wfI_7PgX0C-VTiwLeu0S4v34", + "https://www.youtube.com/watch?v=U-9tUEOFKNU&list=PL7u4lWXQ3wfI_7PgX0C-VTiwLeu0S4v34"); } + @Override public long expectedLength() { return 434; } + @Override public long expectedViewCountAtLeast() { return 21229200; } + @Nullable @Override public String expectedUploadDate() { return "2018-06-19 00:00:00.000"; } + @Nullable @Override public String expectedTextualUploadDate() { return "2018-06-19"; } + @Override public long expectedLikeCountAtLeast() { return 340100; } + @Override public long expectedDislikeCountAtLeast() { return 18700; } } - public static class RatingsDisabledTest { - private static YoutubeStreamExtractor extractor; + public static class RatingsDisabledTest extends DefaultStreamExtractorTest { + private static final String ID = "HRKu0cvrr_o"; + private static final int TIMESTAMP = 17; + private static final String URL = BASE_URL + ID + "&t=" + TIMESTAMP; + private static StreamExtractor extractor; @BeforeClass public static void setUp() throws Exception { NewPipe.init(DownloaderTestImpl.getInstance()); - extractor = (YoutubeStreamExtractor) YouTube - .getStreamExtractor("https://www.youtube.com/watch?v=HRKu0cvrr_o"); + extractor = YouTube.getStreamExtractor(URL); extractor.fetchPage(); } - @Test - public void testGetLikeCount() throws ParsingException { - assertEquals(-1, extractor.getLikeCount()); - } + @Override public StreamExtractor extractor() { return extractor; } + @Override public StreamingService expectedService() { return YouTube; } + @Override public String expectedName() { return "AlphaOmegaSin Fanboy Logic: Likes/Dislikes Disabled = Point Invalid Lol wtf?"; } + @Override public String expectedId() { return ID; } + @Override public String expectedUrlContains() { return BASE_URL + ID; } + @Override public String expectedOriginalUrlContains() { return URL; } - @Test - public void testGetDislikeCount() throws ParsingException { - assertEquals(-1, extractor.getDislikeCount()); - } - - } - - public static class FramesTest { - private static YoutubeStreamExtractor extractor; - - @BeforeClass - public static void setUp() throws Exception { - NewPipe.init(DownloaderTestImpl.getInstance()); - extractor = (YoutubeStreamExtractor) YouTube - .getStreamExtractor("https://www.youtube.com/watch?v=HoK9shIJ2xQ"); - extractor.fetchPage(); - } - - @Test - public void testGetFrames() throws ExtractionException { - final List frames = extractor.getFrames(); - assertNotNull(frames); - assertFalse(frames.isEmpty()); - for (final Frameset f : frames) { - for (final String url : f.getUrls()) { - ExtractorAsserts.assertIsValidUrl(url); - ExtractorAsserts.assertIsSecureUrl(url); - } - } - } + @Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; } + @Override public String expectedUploaderName() { return "YouTuber PrinceOfFALLEN"; } + @Override public String expectedUploaderUrl() { return "https://www.youtube.com/channel/UCQT2yul0lr6Ie9qNQNmw-sg"; } + @Override public List expectedDescriptionContains() { return Arrays.asList("dislikes", "Alpha", "wrong"); } + @Override public long expectedLength() { return 84; } + @Override public long expectedTimestamp() { return TIMESTAMP; } + @Override public long expectedViewCountAtLeast() { return 190; } + @Nullable @Override public String expectedUploadDate() { return "2019-01-02 00:00:00.000"; } + @Nullable @Override public String expectedTextualUploadDate() { return "2019-01-02"; } + @Override public long expectedLikeCountAtLeast() { return -1; } + @Override public long expectedDislikeCountAtLeast() { return -1; } } } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorLivestreamTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorLivestreamTest.java index 0e17fe8d8..6a675487a 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorLivestreamTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorLivestreamTest.java @@ -1,139 +1,54 @@ package org.schabi.newpipe.extractor.services.youtube.stream; import org.junit.BeforeClass; -import org.junit.Test; import org.schabi.newpipe.DownloaderTestImpl; -import org.schabi.newpipe.extractor.MediaFormat; import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.exceptions.ExtractionException; -import org.schabi.newpipe.extractor.exceptions.ParsingException; -import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; -import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector; +import org.schabi.newpipe.extractor.StreamingService; +import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest; +import org.schabi.newpipe.extractor.stream.StreamExtractor; import org.schabi.newpipe.extractor.stream.StreamType; -import org.schabi.newpipe.extractor.stream.VideoStream; -import org.schabi.newpipe.extractor.utils.Utils; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Nullable; + import static org.schabi.newpipe.extractor.ServiceList.YouTube; -public class YoutubeStreamExtractorLivestreamTest { - private static YoutubeStreamExtractor extractor; +public class YoutubeStreamExtractorLivestreamTest extends DefaultStreamExtractorTest { + private static final String ID = "5qap5aO4i9A"; + private static final int TIMESTAMP = 1737; + private static final String URL = YoutubeStreamExtractorDefaultTest.BASE_URL + ID + "&t=" + TIMESTAMP; + private static StreamExtractor extractor; @BeforeClass public static void setUp() throws Exception { NewPipe.init(DownloaderTestImpl.getInstance()); - extractor = (YoutubeStreamExtractor) YouTube - .getStreamExtractor("https://www.youtube.com/watch?v=5qap5aO4i9A"); + extractor = YouTube.getStreamExtractor(URL); extractor.fetchPage(); } - @Test - public void testGetInvalidTimeStamp() throws ParsingException { - assertTrue(extractor.getTimeStamp() + "", - extractor.getTimeStamp() <= 0); - } + @Override public StreamExtractor extractor() { return extractor; } + @Override public StreamingService expectedService() { return YouTube; } + @Override public String expectedName() { return "lofi hip hop radio - beats to relax/study to"; } + @Override public String expectedId() { return ID; } + @Override public String expectedUrlContains() { return YoutubeStreamExtractorDefaultTest.BASE_URL + ID; } + @Override public String expectedOriginalUrlContains() { return URL; } - @Test - public void testGetTitle() throws ParsingException { - assertFalse(extractor.getName().isEmpty()); - } - - @Test - public void testGetDescription() throws ParsingException { - assertNotNull(extractor.getDescription()); - assertFalse(extractor.getDescription().getContent().isEmpty()); - } - - @Test - public void testGetFullLinksInDescription() throws ParsingException { - assertTrue(extractor.getDescription().getContent().contains("https://bit.ly/chilledcow-playlists")); - } - - @Test - public void testGetUploaderName() throws ParsingException { - assertNotNull(extractor.getUploaderName()); - assertFalse(extractor.getUploaderName().isEmpty()); - } - - - @Test - public void testGetLength() throws ParsingException { - assertEquals(0, extractor.getLength()); - } - - @Test - public void testGetViewCount() throws ParsingException { - long count = extractor.getViewCount(); - assertTrue(Long.toString(count), count > -1); - } - - @Test - public void testGetUploadDate() throws ParsingException { - assertNull(extractor.getUploadDate()); - assertNull(extractor.getTextualUploadDate()); - } - - @Test - public void testGetUploaderUrl() throws ParsingException { - assertEquals("https://www.youtube.com/channel/UCSJ4gkVC6NrvII8umztf0Ow", extractor.getUploaderUrl()); - } - - @Test - public void testGetThumbnailUrl() throws ParsingException { - assertIsSecureUrl(extractor.getThumbnailUrl()); - } - - @Test - public void testGetUploaderAvatarUrl() throws ParsingException { - assertIsSecureUrl(extractor.getUploaderAvatarUrl()); - } - - @Test - public void testGetAudioStreams() throws ExtractionException { - assertFalse(extractor.getAudioStreams().isEmpty()); - } - - @Test - public void testGetVideoStreams() throws ExtractionException { - for (VideoStream s : extractor.getVideoStreams()) { - assertIsSecureUrl(s.url); - assertTrue(s.resolution.length() > 0); - assertTrue(Integer.toString(s.getFormatId()), - 0 <= s.getFormatId() && s.getFormatId() <= 0x100); - } - } - - @Test - public void testStreamType() throws ParsingException { - assertSame(extractor.getStreamType(), StreamType.LIVE_STREAM); - } - - @Test - public void testGetDashMpd() throws ParsingException { - assertTrue(extractor.getDashMpdUrl().startsWith("https://manifest.googlevideo.com/api/manifest/dash/")); - } - - @Test - public void testGetRelatedVideos() throws ExtractionException { - StreamInfoItemsCollector relatedVideos = extractor.getRelatedStreams(); - Utils.printErrors(relatedVideos.getErrors()); - assertFalse(relatedVideos.getItems().isEmpty()); - assertTrue(relatedVideos.getErrors().isEmpty()); - } - - @Test - public void testGetSubtitlesListDefault() { - assertTrue(extractor.getSubtitlesDefault().isEmpty()); - } - - @Test - public void testGetSubtitlesList() { - assertTrue(extractor.getSubtitles(MediaFormat.TTML).isEmpty()); + @Override public StreamType expectedStreamType() { return StreamType.LIVE_STREAM; } + @Override public String expectedUploaderName() { return "ChilledCow"; } + @Override public String expectedUploaderUrl() { return "https://www.youtube.com/channel/UCSJ4gkVC6NrvII8umztf0Ow"; } + @Override public List expectedDescriptionContains() { + return Arrays.asList("https://bit.ly/chilledcow-playlists", + "https://bit.ly/chilledcow-submissions"); } + @Override public long expectedLength() { return 0; } + @Override public long expectedTimestamp() { return TIMESTAMP; } + @Override public long expectedViewCountAtLeast() { return 0; } + @Nullable @Override public String expectedUploadDate() { return null; } + @Nullable @Override public String expectedTextualUploadDate() { return null; } + @Override public long expectedLikeCountAtLeast() { return 825000; } + @Override public long expectedDislikeCountAtLeast() { return 15600; } + @Override public boolean expectedHasSubtitles() { return false; } + @Override public boolean expectedHasFrames() { return false; } } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorUnlistedTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorUnlistedTest.java index 49a851f4f..22b537ddd 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorUnlistedTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorUnlistedTest.java @@ -1,161 +1,50 @@ package org.schabi.newpipe.extractor.services.youtube.stream; -import org.junit.Assert; import org.junit.BeforeClass; -import org.junit.Test; import org.schabi.newpipe.DownloaderTestImpl; -import org.schabi.newpipe.extractor.MediaFormat; import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.exceptions.ExtractionException; -import org.schabi.newpipe.extractor.exceptions.ParsingException; -import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; -import org.schabi.newpipe.extractor.stream.AudioStream; -import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector; +import org.schabi.newpipe.extractor.StreamingService; +import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest; +import org.schabi.newpipe.extractor.stream.StreamExtractor; import org.schabi.newpipe.extractor.stream.StreamType; -import org.schabi.newpipe.extractor.stream.VideoStream; -import org.schabi.newpipe.extractor.utils.Utils; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; +import java.util.Arrays; import java.util.List; -import static org.junit.Assert.*; -import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl; +import javax.annotation.Nullable; + import static org.schabi.newpipe.extractor.ServiceList.YouTube; -public class YoutubeStreamExtractorUnlistedTest { - private static YoutubeStreamExtractor extractor; +public class YoutubeStreamExtractorUnlistedTest extends DefaultStreamExtractorTest { + static final String ID = "udsB8KnIJTg"; + static final String URL = YoutubeStreamExtractorDefaultTest.BASE_URL + ID; + private static StreamExtractor extractor; @BeforeClass public static void setUp() throws Exception { NewPipe.init(DownloaderTestImpl.getInstance()); - extractor = (YoutubeStreamExtractor) YouTube - .getStreamExtractor("https://www.youtube.com/watch?v=udsB8KnIJTg"); + extractor = YouTube.getStreamExtractor(URL); extractor.fetchPage(); } - @Test - public void testGetInvalidTimeStamp() throws ParsingException { - assertTrue(extractor.getTimeStamp() + "", - extractor.getTimeStamp() <= 0); - } + @Override public StreamExtractor extractor() { return extractor; } + @Override public StreamingService expectedService() { return YouTube; } + @Override public String expectedName() { return "Praise the Casual: Ein Neuling trifft Dark Souls - Folge 5"; } + @Override public String expectedId() { return ID; } + @Override public String expectedUrlContains() { return URL; } + @Override public String expectedOriginalUrlContains() { return URL; } - @Test - public void testGetTitle() throws ParsingException { - assertFalse(extractor.getName().isEmpty()); - } - - @Test - public void testGetDescription() throws ParsingException { - assertNotNull(extractor.getDescription()); - assertFalse(extractor.getDescription().getContent().isEmpty()); - } - - @Test - public void testGetFullLinksInDescription() throws ParsingException { - assertTrue(extractor.getDescription().getContent().contains("https://www.youtube.com/user/Roccowschiptune")); - } - - @Test - public void testGetUploaderName() throws ParsingException { - assertNotNull(extractor.getUploaderName()); - assertFalse(extractor.getUploaderName().isEmpty()); - } - - - @Test - public void testGetLength() throws ParsingException { - assertEquals(2488, extractor.getLength()); - } - - @Test - public void testGetViewCount() throws ParsingException { - long count = extractor.getViewCount(); - assertTrue(Long.toString(count), count >= /* specific to that video */ 1225); - } - - @Test - public void testGetTextualUploadDate() throws ParsingException { - Assert.assertEquals("2017-09-22", extractor.getTextualUploadDate()); - } - - @Test - public void testGetUploadDate() throws ParsingException, ParseException { - final Calendar instance = Calendar.getInstance(); - instance.setTime(new SimpleDateFormat("yyyy-MM-dd").parse("2017-09-22")); - assertNotNull(extractor.getUploadDate()); - assertEquals(instance, extractor.getUploadDate().date()); - } - - @Test - public void testGetUploaderUrl() throws ParsingException { - assertEquals("https://www.youtube.com/channel/UCPysfiuOv4VKBeXFFPhKXyw", extractor.getUploaderUrl()); - } - - @Test - public void testGetThumbnailUrl() throws ParsingException { - assertIsSecureUrl(extractor.getThumbnailUrl()); - } - - @Test - public void testGetUploaderAvatarUrl() throws ParsingException { - assertIsSecureUrl(extractor.getUploaderAvatarUrl()); - } - - @Test - public void testGetAudioStreams() throws ExtractionException { - List audioStreams = extractor.getAudioStreams(); - assertFalse(audioStreams.isEmpty()); - for (AudioStream s : audioStreams) { - assertIsSecureUrl(s.url); - assertTrue(Integer.toString(s.getFormatId()), - 0x100 <= s.getFormatId() && s.getFormatId() < 0x1000); - } - } - - @Test - public void testGetVideoStreams() throws ExtractionException { - for (VideoStream s : extractor.getVideoStreams()) { - assertIsSecureUrl(s.url); - assertTrue(s.resolution.length() > 0); - assertTrue(Integer.toString(s.getFormatId()), - 0 <= s.getFormatId() && s.getFormatId() < 0x100); - } - } - - @Test - public void testStreamType() throws ParsingException { - assertSame(StreamType.VIDEO_STREAM, extractor.getStreamType()); - } - - @Test - public void testGetRelatedVideos() throws ExtractionException { - StreamInfoItemsCollector relatedVideos = extractor.getRelatedStreams(); - Utils.printErrors(relatedVideos.getErrors()); - assertFalse(relatedVideos.getItems().isEmpty()); - assertTrue(relatedVideos.getErrors().isEmpty()); - } - - @Test - public void testGetSubtitlesListDefault() { - assertFalse(extractor.getSubtitlesDefault().isEmpty()); - } - - @Test - public void testGetSubtitlesList() { - assertFalse(extractor.getSubtitles(MediaFormat.TTML).isEmpty()); - } - - @Test - public void testGetLikeCount() throws ParsingException { - long likeCount = extractor.getLikeCount(); - assertTrue("" + likeCount, likeCount >= 96); - } - - @Test - public void testGetDislikeCount() throws ParsingException { - long dislikeCount = extractor.getDislikeCount(); - assertTrue("" + dislikeCount, dislikeCount >= 0); + @Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; } + @Override public String expectedUploaderName() { return "Hooked"; } + @Override public String expectedUploaderUrl() { return "https://www.youtube.com/channel/UCPysfiuOv4VKBeXFFPhKXyw"; } + @Override public List expectedDescriptionContains() { + return Arrays.asList("https://www.youtube.com/user/Roccowschiptune", + "https://www.facebook.com/HookedMagazinDE"); } + @Override public long expectedLength() { return 2488; } + @Override public long expectedViewCountAtLeast() { return 1500; } + @Nullable @Override public String expectedUploadDate() { return "2017-09-22 00:00:00.000"; } + @Nullable @Override public String expectedTextualUploadDate() { return "2017-09-22"; } + @Override public long expectedLikeCountAtLeast() { return 110; } + @Override public long expectedDislikeCountAtLeast() { return 0; } } From 7fb867c1662457c51d6579f2803c913f356126bf Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 9 Apr 2020 14:11:42 +0200 Subject: [PATCH 02/30] [YouTube] Fix error message obtaining when there is none --- .../services/youtube/extractors/YoutubeStreamExtractor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java index 8364246c2..08e43d6fd 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java @@ -606,7 +606,7 @@ public class YoutubeStreamExtractor extends StreamExtractor { try { return getTextFromObject(initialAjaxJson.getObject(2).getObject("playerResponse").getObject("playabilityStatus") .getObject("errorScreen").getObject("playerErrorMessageRenderer").getObject("reason")); - } catch (ParsingException e) { + } catch (Exception e) { return null; } } From 7cd410f3fc304a9eb620fa28ba39f938e4565c2b Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 9 Apr 2020 14:45:33 +0200 Subject: [PATCH 03/30] [YouTube] Return 0 when there is no timestamp, not -2, as per javadoc --- .../youtube/extractors/YoutubeStreamExtractor.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java index 08e43d6fd..bdaf4cadd 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java @@ -253,7 +253,14 @@ public class YoutubeStreamExtractor extends StreamExtractor { */ @Override public long getTimeStamp() throws ParsingException { - return getTimestampSeconds("((#|&|\\?)(t|start)=\\d{0,3}h?\\d{0,3}m?\\d{1,3}s?)"); + long timestamp = getTimestampSeconds("((#|&|\\?)t=\\d{0,3}h?\\d{0,3}m?\\d{1,3}s?)"); + + if (timestamp == -2) { + // regex for timestamp was not found + return 0; + } else { + return timestamp; + } } @Override From 072bae321fdf9cca340d154d02b388623fadcc8a Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 9 Apr 2020 15:52:42 +0200 Subject: [PATCH 04/30] [YouTube] Fix frame extraction for livestreams Use saved playerResponse instead of parsing json every time --- .../youtube/extractors/YoutubeStreamExtractor.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java index bdaf4cadd..b2b5e4c44 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java @@ -1006,12 +1006,18 @@ public class YoutubeStreamExtractor extends StreamExtractor { @Override public List getFrames() throws ExtractionException { try { - JsonObject jo = initialAjaxJson.getObject(2).getObject("player"); - final String resp = jo.getObject("args").getString("player_response"); - jo = JsonParser.object().from(resp); - final String[] spec = jo.getObject("storyboards").getObject("playerStoryboardSpecRenderer").getString("spec").split("\\|"); + final JsonObject storyboards = playerResponse.getObject("storyboards"); + final JsonObject storyboardsRenderer; + if (storyboards.has("playerLiveStoryboardSpecRenderer")) { + storyboardsRenderer = storyboards.getObject("playerLiveStoryboardSpecRenderer"); + } else { + storyboardsRenderer = storyboards.getObject("playerStoryboardSpecRenderer"); + } + + final String[] spec = storyboardsRenderer.getString("spec").split("\\|"); final String url = spec[0]; final ArrayList result = new ArrayList<>(spec.length - 1); + for (int i = 1; i < spec.length; ++i) { final String[] parts = spec[i].split("#"); if (parts.length != 8) { From 3b2cfb4ca2e9fbe9457e2a4551d97f7fa8bc6fec Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 9 Apr 2020 18:15:34 +0200 Subject: [PATCH 05/30] [SoundCloud] Return empty video stream list instead of null Also replace every instance of `return new ArrayList<>();` with `return Collections.emptyList();` --- .../media_ccc/extractors/MediaCCCStreamExtractor.java | 4 ++-- .../soundcloud/extractors/SoundcloudStreamExtractor.java | 6 +++--- .../services/youtube/extractors/YoutubeStreamExtractor.java | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java index 042c5cd18..18aa97086 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java @@ -277,8 +277,8 @@ public class MediaCCCStreamExtractor extends StreamExtractor { @Nonnull @Override - public List getTags() { - return new ArrayList<>(); + public List getTags() throws ParsingException { + return Collections.emptyList(); } @Nonnull diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java index d909acfc6..0eaf1d9d8 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java @@ -235,12 +235,12 @@ public class SoundcloudStreamExtractor extends StreamExtractor { @Override public List getVideoStreams() throws IOException, ExtractionException { - return null; + return Collections.emptyList(); } @Override public List getVideoOnlyStreams() throws IOException, ExtractionException { - return null; + return Collections.emptyList(); } @Override @@ -304,7 +304,7 @@ public class SoundcloudStreamExtractor extends StreamExtractor { @Nonnull @Override public List getTags() throws ParsingException { - return new ArrayList<>(); + return Collections.emptyList(); } @Nonnull diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java index b2b5e4c44..f49812fc6 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java @@ -1087,7 +1087,7 @@ public class YoutubeStreamExtractor extends StreamExtractor { @Nonnull @Override public List getTags() { - return new ArrayList<>(); + return Collections.emptyList(); } @Nonnull From 4349be13af66aaf9af4c244d53cce1702b3a0782 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 9 Apr 2020 18:18:43 +0200 Subject: [PATCH 06/30] [PeerTube] Return empty audio stream list instead of null --- .../extractors/PeertubeStreamExtractor.java | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamExtractor.java index 4fda78275..74d646bf0 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamExtractor.java @@ -41,7 +41,7 @@ import javax.annotation.Nonnull; public class PeertubeStreamExtractor extends StreamExtractor { private final String baseUrl; private JsonObject json; - private List subtitles = new ArrayList<>(); + private final List subtitles = new ArrayList<>(); public PeertubeStreamExtractor(final StreamingService service, final LinkHandler linkHandler) throws ParsingException { super(service, linkHandler); @@ -64,11 +64,13 @@ public class PeertubeStreamExtractor extends StreamExtractor { return new DateWrapper(PeertubeParsingHelper.parseDateFrom(textualUploadDate)); } + @Nonnull @Override public String getThumbnailUrl() throws ParsingException { return baseUrl + JsonUtils.getString(json, "previewPath"); } + @Nonnull @Override public Description getDescription() throws ParsingException { String text; @@ -127,6 +129,7 @@ public class PeertubeStreamExtractor extends StreamExtractor { return json.getLong("dislikes"); } + @Nonnull @Override public String getUploaderUrl() throws ParsingException { final String name = JsonUtils.getString(json, "account.name"); @@ -134,11 +137,13 @@ public class PeertubeStreamExtractor extends StreamExtractor { return getService().getChannelLHFactory().fromId("accounts/" + name + "@" + host, baseUrl).getUrl(); } + @Nonnull @Override public String getUploaderName() throws ParsingException { return JsonUtils.getString(json, "account.displayName"); } + @Nonnull @Override public String getUploaderAvatarUrl() { String value; @@ -150,6 +155,7 @@ public class PeertubeStreamExtractor extends StreamExtractor { return baseUrl + value; } + @Nonnull @Override public String getSubChannelUrl() throws ParsingException { return JsonUtils.getString(json, "channel.url"); @@ -173,11 +179,13 @@ public class PeertubeStreamExtractor extends StreamExtractor { return baseUrl + value; } + @Nonnull @Override public String getDashMpdUrl() { return ""; } + @Nonnull @Override public String getHlsUrl() { return ""; @@ -185,7 +193,7 @@ public class PeertubeStreamExtractor extends StreamExtractor { @Override public List getAudioStreams() { - return null; + return Collections.emptyList(); } @Override @@ -220,11 +228,13 @@ public class PeertubeStreamExtractor extends StreamExtractor { return Collections.emptyList(); } + @Nonnull @Override public List getSubtitlesDefault() { return subtitles; } + @Nonnull @Override public List getSubtitles(final MediaFormat format) { final List filteredSubs = new ArrayList<>(); @@ -256,6 +266,7 @@ public class PeertubeStreamExtractor extends StreamExtractor { return collector; } + @Nonnull @Override public List getTags() { try { @@ -370,31 +381,37 @@ public class PeertubeStreamExtractor extends StreamExtractor { } } + @Nonnull @Override public String getName() throws ParsingException { return JsonUtils.getString(json, "name"); } + @Nonnull @Override public String getOriginalUrl() throws ParsingException { return baseUrl + "/videos/watch/" + getId(); } + @Nonnull @Override public String getHost() throws ParsingException { return JsonUtils.getString(json, "account.host"); } + @Nonnull @Override public String getPrivacy() throws ParsingException { return JsonUtils.getString(json, "privacy.label"); } + @Nonnull @Override public String getCategory() throws ParsingException { return JsonUtils.getString(json, "category.label"); } + @Nonnull @Override public String getLicence() throws ParsingException { return JsonUtils.getString(json, "licence.label"); From 7ae3cb6d07cea6abb71d9c69eb2b1b276e5b795f Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 9 Apr 2020 19:46:20 +0200 Subject: [PATCH 07/30] [PeerTube] Fix link handler inconsistency providing API links --- .../extractors/PeertubeAccountExtractor.java | 17 ++++++++------- .../extractors/PeertubeChannelExtractor.java | 17 ++++++++------- .../extractors/PeertubeStreamExtractor.java | 21 ++++++++++--------- .../PeertubeChannelLinkHandlerFactory.java | 7 +++---- .../PeertubeStreamLinkHandlerFactory.java | 5 +++-- .../PeertubeAccountExtractorTest.java | 10 ++++----- .../PeertubeChannelExtractorTest.java | 8 +++---- .../peertube/PeertubeStreamExtractorTest.java | 4 ++-- 8 files changed, 46 insertions(+), 43 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeAccountExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeAccountExtractor.java index 49978e889..aaf645d8f 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeAccountExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeAccountExtractor.java @@ -13,6 +13,7 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler; import org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper; +import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeChannelLinkHandlerFactory; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector; import org.schabi.newpipe.extractor.utils.JsonUtils; @@ -20,6 +21,8 @@ import org.schabi.newpipe.extractor.utils.Utils; import java.io.IOException; +import javax.annotation.Nonnull; + import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.COUNT_KEY; import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.ITEMS_PER_PAGE; import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.START_KEY; @@ -85,10 +88,11 @@ public class PeertubeAccountExtractor extends ChannelExtractor { return ""; } + @Nonnull @Override public InfoItemsPage getInitialPage() throws IOException, ExtractionException { - final String pageUrl = getUrl() + "/videos?" + START_KEY + "=0&" + COUNT_KEY + "=" + ITEMS_PER_PAGE; - return getPage(new Page(pageUrl)); + return getPage(new Page( + getUrl() + "/videos?" + START_KEY + "=0&" + COUNT_KEY + "=" + ITEMS_PER_PAGE)); } @Override @@ -123,7 +127,8 @@ public class PeertubeAccountExtractor extends ChannelExtractor { @Override public void onFetchPage(final Downloader downloader) throws IOException, ExtractionException { - final Response response = downloader.get(getUrl()); + final Response response = downloader.get( + baseUrl + PeertubeChannelLinkHandlerFactory.API_ENDPOINT + getId()); if (response != null && response.responseBody() != null) { setInitialData(response.responseBody()); } else { @@ -140,13 +145,9 @@ public class PeertubeAccountExtractor extends ChannelExtractor { if (json == null) throw new ExtractionException("Unable to extract PeerTube account data"); } + @Nonnull @Override public String getName() throws ParsingException { return JsonUtils.getString(json, "displayName"); } - - @Override - public String getOriginalUrl() throws ParsingException { - return baseUrl + "/" + getId(); - } } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeChannelExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeChannelExtractor.java index e6cc66b6a..432433cdc 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeChannelExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeChannelExtractor.java @@ -13,6 +13,7 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler; import org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper; +import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeChannelLinkHandlerFactory; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector; import org.schabi.newpipe.extractor.utils.JsonUtils; @@ -20,6 +21,8 @@ import org.schabi.newpipe.extractor.utils.Utils; import java.io.IOException; +import javax.annotation.Nonnull; + import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.COUNT_KEY; import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.ITEMS_PER_PAGE; import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.START_KEY; @@ -92,10 +95,11 @@ public class PeertubeChannelExtractor extends ChannelExtractor { return baseUrl + value; } + @Nonnull @Override public InfoItemsPage getInitialPage() throws IOException, ExtractionException { - final String pageUrl = getUrl() + "/videos?" + START_KEY + "=0&" + COUNT_KEY + "=" + ITEMS_PER_PAGE; - return getPage(new Page(pageUrl)); + return getPage(new Page( + getUrl() + "/videos?" + START_KEY + "=0&" + COUNT_KEY + "=" + ITEMS_PER_PAGE)); } @Override @@ -130,7 +134,8 @@ public class PeertubeChannelExtractor extends ChannelExtractor { @Override public void onFetchPage(final Downloader downloader) throws IOException, ExtractionException { - final Response response = downloader.get(getUrl()); + final Response response = downloader.get( + baseUrl + PeertubeChannelLinkHandlerFactory.API_ENDPOINT + getId()); if (response != null && response.responseBody() != null) { setInitialData(response.responseBody()); } else { @@ -147,13 +152,9 @@ public class PeertubeChannelExtractor extends ChannelExtractor { if (json == null) throw new ExtractionException("Unable to extract PeerTube channel data"); } + @Nonnull @Override public String getName() throws ParsingException { return JsonUtils.getString(json, "displayName"); } - - @Override - public String getOriginalUrl() throws ParsingException { - return baseUrl + "/" + getId(); - } } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamExtractor.java index 74d646bf0..b67daca13 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamExtractor.java @@ -17,6 +17,7 @@ import org.schabi.newpipe.extractor.linkhandler.LinkHandler; import org.schabi.newpipe.extractor.localization.DateWrapper; import org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper; import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearchQueryHandlerFactory; +import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeStreamLinkHandlerFactory; import org.schabi.newpipe.extractor.stream.AudioStream; import org.schabi.newpipe.extractor.stream.Description; import org.schabi.newpipe.extractor.stream.Stream; @@ -83,7 +84,9 @@ public class PeertubeStreamExtractor extends StreamExtractor { //if description is shortened, get full description final Downloader dl = NewPipe.getDownloader(); try { - final Response response = dl.get(getUrl() + "/description"); + final Response response = dl.get(baseUrl + + PeertubeStreamLinkHandlerFactory.VIDEO_API_ENDPOINT + + getId() + "/description"); final JsonObject jsonObject = JsonParser.object().from(response.responseBody()); text = JsonUtils.getString(jsonObject, "description"); } catch (ReCaptchaException | IOException | JsonParserException e) { @@ -338,7 +341,7 @@ public class PeertubeStreamExtractor extends StreamExtractor { @Override public void onFetchPage(final Downloader downloader) throws IOException, ExtractionException { - final Response response = downloader.get(getUrl()); + final Response response = downloader.get(baseUrl + PeertubeStreamLinkHandlerFactory.VIDEO_API_ENDPOINT + getId()); if (response != null && response.responseBody() != null) { setInitialData(response.responseBody()); } else { @@ -354,14 +357,18 @@ public class PeertubeStreamExtractor extends StreamExtractor { } catch (JsonParserException e) { throw new ExtractionException("Unable to extract PeerTube stream data", e); } - if (json == null) throw new ExtractionException("Unable to extract PeerTube stream data"); + if (json == null) { + throw new ExtractionException("Unable to extract PeerTube stream data"); + } PeertubeParsingHelper.validate(json); } private void loadSubtitles() { if (subtitles.isEmpty()) { try { - final Response response = getDownloader().get(getUrl() + "/captions"); + final Response response = getDownloader().get(baseUrl + + PeertubeStreamLinkHandlerFactory.VIDEO_API_ENDPOINT + + getId() + "/captions"); final JsonObject captionsJson = JsonParser.object().from(response.responseBody()); final JsonArray captions = JsonUtils.getArray(captionsJson, "data"); for (final Object c : captions) { @@ -387,12 +394,6 @@ public class PeertubeStreamExtractor extends StreamExtractor { return JsonUtils.getString(json, "name"); } - @Nonnull - @Override - public String getOriginalUrl() throws ParsingException { - return baseUrl + "/videos/watch/" + getId(); - } - @Nonnull @Override public String getHost() throws ParsingException { diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeChannelLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeChannelLinkHandlerFactory.java index ef81ca4b0..2903c2959 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeChannelLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeChannelLinkHandlerFactory.java @@ -11,7 +11,7 @@ public class PeertubeChannelLinkHandlerFactory extends ListLinkHandlerFactory { private static final PeertubeChannelLinkHandlerFactory instance = new PeertubeChannelLinkHandlerFactory(); private static final String ID_PATTERN = "(accounts|video-channels)/([^/?&#]*)"; - private static final String API_ENDPOINT = "/api/v1/"; + public static final String API_ENDPOINT = "/api/v1/"; public static PeertubeChannelLinkHandlerFactory getInstance() { return instance; @@ -31,12 +31,11 @@ public class PeertubeChannelLinkHandlerFactory extends ListLinkHandlerFactory { @Override public String getUrl(String id, List contentFilter, String sortFilter, String baseUrl) throws ParsingException { - if (id.matches(ID_PATTERN)) { - return baseUrl + API_ENDPOINT + id; + return baseUrl + "/" + id; } else { // This is needed for compatibility with older versions were we didn't support video channels yet - return baseUrl + API_ENDPOINT + "accounts/" + id; + return baseUrl + "/accounts/" + id; } } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeStreamLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeStreamLinkHandlerFactory.java index d3f369fcc..3e16b5096 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeStreamLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeStreamLinkHandlerFactory.java @@ -10,7 +10,8 @@ public class PeertubeStreamLinkHandlerFactory extends LinkHandlerFactory { private static final PeertubeStreamLinkHandlerFactory instance = new PeertubeStreamLinkHandlerFactory(); private static final String ID_PATTERN = "/videos/(watch/|embed/)?([^/?&#]*)"; - private static final String VIDEO_ENDPOINT = "/api/v1/videos/"; + public static final String VIDEO_API_ENDPOINT = "/api/v1/videos/"; + private static final String VIDEO_PATH = "/videos/watch/"; private PeertubeStreamLinkHandlerFactory() { } @@ -27,7 +28,7 @@ public class PeertubeStreamLinkHandlerFactory extends LinkHandlerFactory { @Override public String getUrl(String id, String baseUrl) { - return baseUrl + VIDEO_ENDPOINT + id; + return baseUrl + VIDEO_PATH + id; } @Override diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeAccountExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeAccountExtractorTest.java index fd944f49d..1c315ff12 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeAccountExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeAccountExtractorTest.java @@ -28,7 +28,7 @@ public class PeertubeAccountExtractorTest { // setting instance might break test when running in parallel PeerTube.setInstance(new PeertubeInstance("https://peertube.mastodon.host", "PeerTube on Mastodon.host")); extractor = (PeertubeAccountExtractor) PeerTube - .getChannelExtractor("https://peertube.mastodon.host/api/v1/accounts/kde"); + .getChannelExtractor("https://peertube.mastodon.host/accounts/kde"); extractor.fetchPage(); } @@ -53,7 +53,7 @@ public class PeertubeAccountExtractorTest { @Test public void testUrl() throws ParsingException { - assertEquals("https://peertube.mastodon.host/api/v1/accounts/kde", extractor.getUrl()); + assertEquals("https://peertube.mastodon.host/accounts/kde", extractor.getUrl()); } @Test @@ -115,7 +115,7 @@ public class PeertubeAccountExtractorTest { // setting instance might break test when running in parallel PeerTube.setInstance(new PeertubeInstance("https://peertube.mastodon.host", "PeerTube on Mastodon.host")); extractor = (PeertubeAccountExtractor) PeerTube - .getChannelExtractor("https://peertube.mastodon.host/accounts/booteille"); + .getChannelExtractor("https://peertube.mastodon.host/api/v1/accounts/booteille"); extractor.fetchPage(); } @@ -150,12 +150,12 @@ public class PeertubeAccountExtractorTest { @Test public void testUrl() throws ParsingException { - assertEquals("https://peertube.mastodon.host/api/v1/accounts/booteille", extractor.getUrl()); + assertEquals("https://peertube.mastodon.host/accounts/booteille", extractor.getUrl()); } @Test public void testOriginalUrl() throws ParsingException { - assertEquals("https://peertube.mastodon.host/accounts/booteille", extractor.getOriginalUrl()); + assertEquals("https://peertube.mastodon.host/api/v1/accounts/booteille", extractor.getOriginalUrl()); } /*////////////////////////////////////////////////////////////////////////// diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeChannelExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeChannelExtractorTest.java index 010dbd7b4..68ae7673a 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeChannelExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeChannelExtractorTest.java @@ -53,7 +53,7 @@ public class PeertubeChannelExtractorTest { @Test public void testUrl() throws ParsingException { - assertEquals("https://peertube.mastodon.host/api/v1/video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa", extractor.getUrl()); + assertEquals("https://peertube.mastodon.host/video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa", extractor.getUrl()); } @Test @@ -130,7 +130,7 @@ public class PeertubeChannelExtractorTest { // setting instance might break test when running in parallel PeerTube.setInstance(new PeertubeInstance("https://peertube.mastodon.host", "PeerTube on Mastodon.host")); extractor = (PeertubeChannelExtractor) PeerTube - .getChannelExtractor("https://peertube.mastodon.host/video-channels/35080089-79b6-45fc-96ac-37e4d46a4457"); + .getChannelExtractor("https://peertube.mastodon.host/api/v1/video-channels/35080089-79b6-45fc-96ac-37e4d46a4457"); extractor.fetchPage(); } @@ -165,12 +165,12 @@ public class PeertubeChannelExtractorTest { @Test public void testUrl() throws ParsingException { - assertEquals("https://peertube.mastodon.host/api/v1/video-channels/35080089-79b6-45fc-96ac-37e4d46a4457", extractor.getUrl()); + assertEquals("https://peertube.mastodon.host/video-channels/35080089-79b6-45fc-96ac-37e4d46a4457", extractor.getUrl()); } @Test public void testOriginalUrl() throws ParsingException { - assertEquals("https://peertube.mastodon.host/video-channels/35080089-79b6-45fc-96ac-37e4d46a4457", extractor.getOriginalUrl()); + assertEquals("https://peertube.mastodon.host/api/v1/video-channels/35080089-79b6-45fc-96ac-37e4d46a4457", extractor.getOriginalUrl()); } /*////////////////////////////////////////////////////////////////////////// diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java index bddb75bd4..1ecfc7263 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java @@ -53,7 +53,7 @@ public class PeertubeStreamExtractorTest { @Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; } @Override public String expectedUploaderName() { return "Framasoft"; } - @Override public String expectedUploaderUrl() { return "https://framatube.org/accounts/framasoft"; } + @Override public String expectedUploaderUrl() { return "https://framatube.org/accounts/framasoft@framatube.org"; } @Override public List expectedDescriptionContains() { // CRLF line ending return Arrays.asList("**[Want to help to translate this video?](https://weblate.framasoft.org/projects/what-is-peertube-video/)**\r\n" + "\r\n" @@ -108,7 +108,7 @@ public class PeertubeStreamExtractorTest { @Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; } @Override public String expectedUploaderName() { return "Tomas Berezovskiy"; } - @Override public String expectedUploaderUrl() { return "https://peertube.iriseden.eu/accounts/tomas_berezovskiy"; } + @Override public String expectedUploaderUrl() { return "https://peertube.co.uk/accounts/tomas_berezovskiy@peertube.iriseden.eu"; } @Override public List expectedDescriptionContains() { // LF line ending return Arrays.asList("https://en.informnapalm.org/dpr-combatant-describes-orders-given-russian-officers/ " + " The InformNapalm team received another video of a separatist prisoner of war telling about his " From aeeae87641f8ca41e62b985ad20f0cf1ed565aa6 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 9 Apr 2020 20:02:41 +0200 Subject: [PATCH 08/30] [PeerTube] Parse timestamp from url (previously unimplemented) --- .../extractors/PeertubeStreamExtractor.java | 13 ++++++++++--- .../peertube/PeertubeStreamExtractorTest.java | 9 ++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamExtractor.java index b67daca13..7e1861f76 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamExtractor.java @@ -112,9 +112,16 @@ public class PeertubeStreamExtractor extends StreamExtractor { } @Override - public long getTimeStamp() { - //TODO fetch timestamp from url if present; - return 0; + public long getTimeStamp() throws ParsingException { + long timestamp = + getTimestampSeconds("((#|&|\\?)start=\\d{0,3}h?\\d{0,3}m?\\d{1,3}s?)"); + + if (timestamp == -2) { + // regex for timestamp was not found + return 0; + } else { + return timestamp; + } } @Override diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java index 1ecfc7263..f78b96e13 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java @@ -27,7 +27,9 @@ public class PeertubeStreamExtractorTest { public static class WhatIsPeertube extends DefaultStreamExtractorTest { private static final String ID = "9c9de5e8-0a1e-484a-b099-e80766180a6d"; private static final String INSTANCE = "https://framatube.org"; - private static final String URL = INSTANCE + BASE_URL + ID; + private static final int TIMESTAMP_MINUTE = 1; + private static final int TIMESTAMP_SECOND = 21; + private static final String URL = INSTANCE + BASE_URL + ID + "?start=" + TIMESTAMP_MINUTE + "m" + TIMESTAMP_SECOND + "s"; private static StreamExtractor extractor; @BeforeClass @@ -48,7 +50,7 @@ public class PeertubeStreamExtractorTest { @Override public StreamingService expectedService() { return PeerTube; } @Override public String expectedName() { return "What is PeerTube?"; } @Override public String expectedId() { return ID; } - @Override public String expectedUrlContains() { return BASE_URL + ID; } + @Override public String expectedUrlContains() { return INSTANCE + BASE_URL + ID; } @Override public String expectedOriginalUrlContains() { return URL; } @Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; } @@ -74,6 +76,7 @@ public class PeertubeStreamExtractorTest { + "**Video sources**: https://gitlab.gnome.org/Jehan/what-is-peertube/"); } @Override public long expectedLength() { return 113; } + @Override public long expectedTimestamp() { return TIMESTAMP_MINUTE*60 + TIMESTAMP_SECOND; } @Override public long expectedViewCountAtLeast() { return 38600; } @Nullable @Override public String expectedUploadDate() { return "2018-10-01 12:52:46.396"; } // GMT (!) @Nullable @Override public String expectedTextualUploadDate() { return "2018-10-01T10:52:46.396Z"; } @@ -103,7 +106,7 @@ public class PeertubeStreamExtractorTest { @Override public StreamingService expectedService() { return PeerTube; } @Override public String expectedName() { return "A DPR Combatant Describes how Orders are Given through Russian Officers"; } @Override public String expectedId() { return ID; } - @Override public String expectedUrlContains() { return BASE_URL + ID; } + @Override public String expectedUrlContains() { return URL; } @Override public String expectedOriginalUrlContains() { return URL; } @Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; } From b461da792f375a8527587ff13ff8a6ed8c6f43b4 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 9 Apr 2020 20:25:22 +0200 Subject: [PATCH 09/30] [MediaCCC] Fix link handler inconsistency providing API links --- .../MediaCCCConferenceExtractor.java | 12 +++------ .../extractors/MediaCCCStreamExtractor.java | 27 +++++++++++-------- .../MediaCCCConferenceLinkHandlerFactory.java | 20 ++++++++------ .../MediaCCCStreamLinkHandlerFactory.java | 7 +++-- .../MediaCCCConferenceExtractorTest.java | 4 +-- 5 files changed, 39 insertions(+), 31 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCConferenceExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCConferenceExtractor.java index 7d39eacb9..5a7256a9a 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCConferenceExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCConferenceExtractor.java @@ -13,6 +13,7 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler; import org.schabi.newpipe.extractor.services.media_ccc.extractors.infoItems.MediaCCCStreamInfoItemExtractor; +import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCConferenceLinkHandlerFactory; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector; @@ -87,10 +88,11 @@ public class MediaCCCConferenceExtractor extends ChannelExtractor { @Override public void onFetchPage(@Nonnull final Downloader downloader) throws IOException, ExtractionException { + final String conferenceUrl = MediaCCCConferenceLinkHandlerFactory.CONFERENCE_API_ENDPOINT + getId(); try { - conferenceData = JsonParser.object().from(downloader.get(getUrl()).responseBody()); + conferenceData = JsonParser.object().from(downloader.get(conferenceUrl).responseBody()); } catch (JsonParserException jpe) { - throw new ExtractionException("Could not parse json returnd by url: " + getUrl()); + throw new ExtractionException("Could not parse json returnd by url: " + conferenceUrl); } } @@ -99,10 +101,4 @@ public class MediaCCCConferenceExtractor extends ChannelExtractor { public String getName() throws ParsingException { return conferenceData.getString("title"); } - - @Nonnull - @Override - public String getOriginalUrl() { - return "https://media.ccc.de/c/" + conferenceData.getString("acronym"); - } } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java index 18aa97086..6512f092a 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java @@ -19,6 +19,8 @@ import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector; import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.extractor.stream.SubtitlesStream; import org.schabi.newpipe.extractor.stream.VideoStream; +import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCConferenceLinkHandlerFactory; +import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCStreamLinkHandlerFactory; import java.io.IOException; import java.util.ArrayList; @@ -93,7 +95,7 @@ public class MediaCCCStreamExtractor extends StreamExtractor { @Nonnull @Override public String getUploaderUrl() { - return data.getString("conference_url"); + return MediaCCCConferenceLinkHandlerFactory.CONFERENCE_PATH + getUploaderName(); } @Nonnull @@ -111,25 +113,25 @@ public class MediaCCCStreamExtractor extends StreamExtractor { @Nonnull @Override - public String getSubChannelUrl() throws ParsingException { + public String getSubChannelUrl() { return ""; } @Nonnull @Override - public String getSubChannelName() throws ParsingException { + public String getSubChannelName() { return ""; } @Nonnull @Override - public String getSubChannelAvatarUrl() throws ParsingException { + public String getSubChannelAvatarUrl() { return ""; } @Nonnull @Override - public String getDashMpdUrl() throws ParsingException { + public String getDashMpdUrl() { return ""; } @@ -227,14 +229,13 @@ public class MediaCCCStreamExtractor extends StreamExtractor { @Override public void onFetchPage(@Nonnull final Downloader downloader) throws IOException, ExtractionException { + final String videoUrl = MediaCCCStreamLinkHandlerFactory.VIDEO_API_ENDPOINT + getId(); try { - data = JsonParser.object().from( - downloader.get(getLinkHandler().getUrl()).responseBody()); + data = JsonParser.object().from(downloader.get(videoUrl).responseBody()); conferenceData = JsonParser.object() - .from(downloader.get(getUploaderUrl()).responseBody()); + .from(downloader.get(data.getString("conference_url")).responseBody()); } catch (JsonParserException jpe) { - throw new ExtractionException("Could not parse json returned by url: " - + getLinkHandler().getUrl(), jpe); + throw new ExtractionException("Could not parse json returned by url: " + videoUrl, jpe); } } @@ -250,21 +251,25 @@ public class MediaCCCStreamExtractor extends StreamExtractor { return data.getString("frontend_link"); } + @Nonnull @Override public String getHost() { return ""; } + @Nonnull @Override public String getPrivacy() { return ""; } + @Nonnull @Override public String getCategory() { return ""; } + @Nonnull @Override public String getLicence() { return ""; @@ -277,7 +282,7 @@ public class MediaCCCStreamExtractor extends StreamExtractor { @Nonnull @Override - public List getTags() throws ParsingException { + public List getTags() { return Collections.emptyList(); } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCConferenceLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCConferenceLinkHandlerFactory.java index 5dc903d88..57591ae1c 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCConferenceLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCConferenceLinkHandlerFactory.java @@ -7,19 +7,23 @@ import org.schabi.newpipe.extractor.utils.Parser; import java.util.List; public class MediaCCCConferenceLinkHandlerFactory extends ListLinkHandlerFactory { + public static final String CONFERENCE_API_ENDPOINT = "https://api.media.ccc.de/public/conferences/"; + public static final String CONFERENCE_PATH = "https://media.ccc.de/c/"; + @Override - public String getUrl(final String id, final List contentFilter, final String sortFilter) - throws ParsingException { - return "https://media.ccc.de/public/conferences/" + id; + public String getUrl(final String id, final List contentFilter, + final String sortFilter) throws ParsingException { + return CONFERENCE_PATH + id; } @Override public String getId(final String url) throws ParsingException { - if (url.startsWith("https://media.ccc.de/public/conferences/") - || url.startsWith("https://api.media.ccc.de/public/conferences/")) { - return url.replaceFirst("https://(api\\.)?media\\.ccc\\.de/public/conferences/", ""); - } else if (url.startsWith("https://media.ccc.de/c/")) { - return Parser.matchGroup1("https://media.ccc.de/c/([^?#]*)", url); + if (url.startsWith(CONFERENCE_API_ENDPOINT)) { + return url.replace(CONFERENCE_API_ENDPOINT, ""); + } else if (url.startsWith("https://media.ccc.de/public/conferences/")) { + return url.replace("https://media.ccc.de/public/conferences/", ""); + } else if (url.startsWith(CONFERENCE_PATH)) { + return Parser.matchGroup1(CONFERENCE_PATH + "([^?#]*)", url); } else if (url.startsWith("https://media.ccc.de/b/")) { return Parser.matchGroup1("https://media.ccc.de/b/([^?#]*)", url); } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCStreamLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCStreamLinkHandlerFactory.java index a335abf86..d7ecdc3c2 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCStreamLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCStreamLinkHandlerFactory.java @@ -8,6 +8,9 @@ import java.net.MalformedURLException; import java.net.URL; public class MediaCCCStreamLinkHandlerFactory extends LinkHandlerFactory { + public static final String VIDEO_API_ENDPOINT = "https://api.media.ccc.de/public/events/"; + private static final String VIDEO_PATH = "https://media.ccc.de/v/"; + @Override public String getId(final String urlString) throws ParsingException { if (urlString.startsWith("https://media.ccc.de/public/events/") @@ -15,7 +18,7 @@ public class MediaCCCStreamLinkHandlerFactory extends LinkHandlerFactory { return urlString.substring(35); //remove …/public/events part } - if (urlString.startsWith("https://api.media.ccc.de/public/events/") + if (urlString.startsWith(VIDEO_API_ENDPOINT) && !urlString.contains("?q=")) { return urlString.substring(39); //remove api…/public/events part } @@ -42,7 +45,7 @@ public class MediaCCCStreamLinkHandlerFactory extends LinkHandlerFactory { @Override public String getUrl(final String id) throws ParsingException { - return "https://media.ccc.de/public/events/" + id; + return VIDEO_PATH + id; } @Override diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCConferenceExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCConferenceExtractorTest.java index 98b6203c9..f189497df 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCConferenceExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCConferenceExtractorTest.java @@ -31,7 +31,7 @@ public class MediaCCCConferenceExtractorTest { @Test public void testGetUrl() throws Exception { - assertEquals("https://media.ccc.de/public/conferences/froscon2017", extractor.getUrl()); + assertEquals("https://media.ccc.de/c/froscon2017", extractor.getUrl()); } @Test @@ -67,7 +67,7 @@ public class MediaCCCConferenceExtractorTest { @Test public void testGetUrl() throws Exception { - assertEquals("https://media.ccc.de/public/conferences/oscal19", extractor.getUrl()); + assertEquals("https://media.ccc.de/c/oscal19", extractor.getUrl()); } @Test From 3b2a1829d466e0f1b3d0b6c5a43de49bfde5a287 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 9 Apr 2020 21:28:13 +0200 Subject: [PATCH 10/30] [MediaCCC] Extract tags --- .../media_ccc/extractors/MediaCCCStreamExtractor.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java index 6512f092a..2fbeb1add 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java @@ -24,6 +24,7 @@ import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCStrea import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -282,8 +283,8 @@ public class MediaCCCStreamExtractor extends StreamExtractor { @Nonnull @Override - public List getTags() { - return Collections.emptyList(); + public List getTags() throws ParsingException { + return Arrays.asList(data.getArray("tags").toArray(new String[0])); } @Nonnull From 492db83ccff20a71a24aaab94e8968be3d4fffcd Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 9 Apr 2020 21:33:28 +0200 Subject: [PATCH 11/30] [MediaCCC] Return null instead of empty items collector As per the documentation in the base getRelatedStreams() --- .../services/media_ccc/extractors/MediaCCCStreamExtractor.java | 2 +- .../services/media_ccc/MediaCCCStreamExtractorTest.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java index 2fbeb1add..193f044da 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java @@ -219,7 +219,7 @@ public class MediaCCCStreamExtractor extends StreamExtractor { @Override public StreamInfoItemsCollector getRelatedStreams() { - return new StreamInfoItemsCollector(getServiceId()); + return null; } @Override diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCStreamExtractorTest.java index 6a4c4c0e2..14111304b 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCStreamExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCStreamExtractorTest.java @@ -53,6 +53,7 @@ public class MediaCCCStreamExtractorTest { @Nullable @Override public String expectedTextualUploadDate() { return "2018-05-11T02:00:00.000+02:00"; } @Override public long expectedLikeCountAtLeast() { return -1; } @Override public long expectedDislikeCountAtLeast() { return -1; } + @Override public boolean expectedHasRelatedStreams() { return false; } @Override public boolean expectedHasSubtitles() { return false; } @Override public boolean expectedHasFrames() { return false; } @@ -114,6 +115,7 @@ public class MediaCCCStreamExtractorTest { @Nullable @Override public String expectedTextualUploadDate() { return "2020-01-11T01:00:00.000+01:00"; } @Override public long expectedLikeCountAtLeast() { return -1; } @Override public long expectedDislikeCountAtLeast() { return -1; } + @Override public boolean expectedHasRelatedStreams() { return false; } @Override public boolean expectedHasSubtitles() { return false; } @Override public boolean expectedHasFrames() { return false; } From d130fd79c31338293134f8416500f135fc57a63a Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 11 Apr 2020 15:52:59 +0200 Subject: [PATCH 12/30] [PeerTube] Prepend "accounts/" to channel id for backward compatibility --- .../extractors/PeertubeAccountExtractor.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeAccountExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeAccountExtractor.java index aaf645d8f..9f04ffc27 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeAccountExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeAccountExtractor.java @@ -126,9 +126,15 @@ public class PeertubeAccountExtractor extends ChannelExtractor { } @Override - public void onFetchPage(final Downloader downloader) throws IOException, ExtractionException { - final Response response = downloader.get( - baseUrl + PeertubeChannelLinkHandlerFactory.API_ENDPOINT + getId()); + public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException { + String accountUrl = baseUrl + PeertubeChannelLinkHandlerFactory.API_ENDPOINT; + if (getId().contains("accounts/")) { + accountUrl += getId(); + } else { + accountUrl += "accounts/" + getId(); + } + + final Response response = downloader.get(accountUrl); if (response != null && response.responseBody() != null) { setInitialData(response.responseBody()); } else { From 0c980b2d648b7eb72fa22482a390114da1d3f5ae Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 11 Apr 2020 15:53:40 +0200 Subject: [PATCH 13/30] [PeerTube] Improve channel and stream link handler tests --- ...PeertubeChannelLinkHandlerFactoryTest.java | 34 ++++++++++++++----- .../PeertubeStreamLinkHandlerFactoryTest.java | 28 ++++++++++++--- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeChannelLinkHandlerFactoryTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeChannelLinkHandlerFactoryTest.java index d47dc6f64..6696ad631 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeChannelLinkHandlerFactoryTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeChannelLinkHandlerFactoryTest.java @@ -28,20 +28,36 @@ public class PeertubeChannelLinkHandlerFactoryTest { @Test public void acceptUrlTest() throws ParsingException { assertTrue(linkHandler.acceptUrl("https://peertube.mastodon.host/accounts/kranti@videos.squat.net")); - assertTrue(linkHandler.acceptUrl("https://peertube.mastodon.host/video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa")); + assertTrue(linkHandler.acceptUrl("https://peertube.mastodon.host/video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa/videos")); + assertTrue(linkHandler.acceptUrl("https://peertube.mastodon.host/api/v1/accounts/kranti@videos.squat.net/videos")); + assertTrue(linkHandler.acceptUrl("https://peertube.mastodon.host/api/v1/video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa")); } @Test - public void getIdFromUrl() throws ParsingException { - assertEquals("accounts/kranti@videos.squat.net", linkHandler.fromUrl("https://peertube.mastodon.host/accounts/kranti@videos.squat.net").getId()); - assertEquals("accounts/kranti@videos.squat.net", linkHandler.fromUrl("https://peertube.mastodon.host/accounts/kranti@videos.squat.net/videos").getId()); - assertEquals("video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa", linkHandler.fromUrl("https://peertube.mastodon.host/video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa/videos").getId()); + public void getId() throws ParsingException { + assertEquals("accounts/kranti@videos.squat.net", + linkHandler.fromUrl("https://peertube.mastodon.host/accounts/kranti@videos.squat.net").getId()); + assertEquals("accounts/kranti@videos.squat.net", + linkHandler.fromUrl("https://peertube.mastodon.host/accounts/kranti@videos.squat.net/videos").getId()); + assertEquals("video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa", + linkHandler.fromUrl("https://peertube.mastodon.host/video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa/videos").getId()); + assertEquals("accounts/kranti@videos.squat.net", + linkHandler.fromUrl("https://peertube.mastodon.host/api/v1/accounts/kranti@videos.squat.net").getId()); + assertEquals("accounts/kranti@videos.squat.net", + linkHandler.fromUrl("https://peertube.mastodon.host/api/v1/accounts/kranti@videos.squat.net/videos").getId()); + assertEquals("video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa", + linkHandler.fromUrl("https://peertube.mastodon.host/api/v1/video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa").getId()); } @Test - public void getUrlFromId() throws ParsingException { - assertEquals("https://peertube.mastodon.host/api/v1/video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa", linkHandler.fromId("video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa").getUrl()); - assertEquals("https://peertube.mastodon.host/api/v1/accounts/kranti@videos.squat.net", linkHandler.fromId("accounts/kranti@videos.squat.net").getUrl()); - assertEquals("https://peertube.mastodon.host/api/v1/accounts/kranti@videos.squat.net", linkHandler.fromId("kranti@videos.squat.net").getUrl()); + public void getUrl() throws ParsingException { + assertEquals("https://peertube.mastodon.host/video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa", + linkHandler.fromId("video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa").getUrl()); + assertEquals("https://peertube.mastodon.host/accounts/kranti@videos.squat.net", + linkHandler.fromId("accounts/kranti@videos.squat.net").getUrl()); + assertEquals("https://peertube.mastodon.host/accounts/kranti@videos.squat.net", + linkHandler.fromId("kranti@videos.squat.net").getUrl()); + assertEquals("https://peertube.mastodon.host/video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa", + linkHandler.fromUrl("https://peertube.mastodon.host/api/v1/video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa").getUrl()); } } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamLinkHandlerFactoryTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamLinkHandlerFactoryTest.java index f217b8e3a..e60db3ba9 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamLinkHandlerFactoryTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamLinkHandlerFactoryTest.java @@ -9,6 +9,7 @@ import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeStream import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.schabi.newpipe.extractor.ServiceList.PeerTube; /** * Test for {@link PeertubeStreamLinkHandlerFactory} @@ -17,16 +18,34 @@ public class PeertubeStreamLinkHandlerFactoryTest { private static PeertubeStreamLinkHandlerFactory linkHandler; @BeforeClass - public static void setUp() throws Exception { + public static void setUp() { + PeerTube.setInstance(new PeertubeInstance("https://peertube.mastodon.host", "PeerTube on Mastodon.host")); linkHandler = PeertubeStreamLinkHandlerFactory.getInstance(); NewPipe.init(DownloaderTestImpl.getInstance()); } @Test public void getId() throws Exception { - assertEquals("986aac60-1263-4f73-9ce5-36b18225cb60", linkHandler.fromUrl("https://peertube.mastodon.host/videos/watch/986aac60-1263-4f73-9ce5-36b18225cb60").getId()); - assertEquals("986aac60-1263-4f73-9ce5-36b18225cb60", linkHandler.fromUrl("https://peertube.mastodon.host/videos/watch/986aac60-1263-4f73-9ce5-36b18225cb60?fsdafs=fsafa").getId()); - assertEquals("9c9de5e8-0a1e-484a-b099-e80766180a6d", linkHandler.fromUrl("https://framatube.org/videos/embed/9c9de5e8-0a1e-484a-b099-e80766180a6d").getId()); + assertEquals("986aac60-1263-4f73-9ce5-36b18225cb60", + linkHandler.fromUrl("https://peertube.mastodon.host/videos/watch/986aac60-1263-4f73-9ce5-36b18225cb60").getId()); + assertEquals("986aac60-1263-4f73-9ce5-36b18225cb60", + linkHandler.fromUrl("https://peertube.mastodon.host/videos/watch/986aac60-1263-4f73-9ce5-36b18225cb60?fsdafs=fsafa").getId()); + assertEquals("9c9de5e8-0a1e-484a-b099-e80766180a6d", + linkHandler.fromUrl("https://framatube.org/videos/embed/9c9de5e8-0a1e-484a-b099-e80766180a6d").getId()); + assertEquals("986aac60-1263-4f73-9ce5-36b18225cb60", + linkHandler.fromUrl("https://peertube.mastodon.host/api/v1/videos/watch/986aac60-1263-4f73-9ce5-36b18225cb60").getId()); + assertEquals("986aac60-1263-4f73-9ce5-36b18225cb60", + linkHandler.fromUrl("https://peertube.mastodon.host/api/v1/videos/watch/986aac60-1263-4f73-9ce5-36b18225cb60?fsdafs=fsafa").getId()); + } + + @Test + public void getUrl() throws Exception { + assertEquals("https://peertube.mastodon.host/videos/watch/986aac60-1263-4f73-9ce5-36b18225cb60", + linkHandler.fromId("986aac60-1263-4f73-9ce5-36b18225cb60").getUrl()); + assertEquals("https://peertube.mastodon.host/videos/watch/986aac60-1263-4f73-9ce5-36b18225cb60", + linkHandler.fromUrl("https://peertube.mastodon.host/api/v1/videos/watch/986aac60-1263-4f73-9ce5-36b18225cb60").getUrl()); + assertEquals("https://peertube.mastodon.host/videos/watch/986aac60-1263-4f73-9ce5-36b18225cb60", + linkHandler.fromUrl("https://peertube.mastodon.host/videos/embed/986aac60-1263-4f73-9ce5-36b18225cb60").getUrl()); } @@ -35,5 +54,6 @@ public class PeertubeStreamLinkHandlerFactoryTest { assertTrue(linkHandler.acceptUrl("https://peertube.mastodon.host/videos/watch/986aac60-1263-4f73-9ce5-36b18225cb60")); assertTrue(linkHandler.acceptUrl("https://peertube.mastodon.host/videos/watch/986aac60-1263-4f73-9ce5-36b18225cb60?fsdafs=fsafa")); assertTrue(linkHandler.acceptUrl("https://framatube.org/videos/embed/9c9de5e8-0a1e-484a-b099-e80766180a6d")); + assertTrue(linkHandler.acceptUrl("https://peertube.mastodon.host/api/v1/videos/watch/986aac60-1263-4f73-9ce5-36b18225cb60?fsdafs=fsafa")); } } \ No newline at end of file From 07a90d116a0059a027f158f59b5fe9d2720f361f Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 11 Apr 2020 16:57:31 +0200 Subject: [PATCH 14/30] [MediaCCC] Use regex to parse stream and conference urls --- .../MediaCCCConferenceLinkHandlerFactory.java | 18 +++------ .../MediaCCCStreamLinkHandlerFactory.java | 40 +++---------------- 2 files changed, 10 insertions(+), 48 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCConferenceLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCConferenceLinkHandlerFactory.java index 57591ae1c..e5e9b158f 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCConferenceLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCConferenceLinkHandlerFactory.java @@ -9,32 +9,24 @@ import java.util.List; public class MediaCCCConferenceLinkHandlerFactory extends ListLinkHandlerFactory { public static final String CONFERENCE_API_ENDPOINT = "https://api.media.ccc.de/public/conferences/"; public static final String CONFERENCE_PATH = "https://media.ccc.de/c/"; + private static final String ID_PATTERN = "(?:(?:(?:api\\.)?media\\.ccc\\.de/public/conferences/)|(?:media\\.ccc\\.de/[bc]/))([^/?&#]*)"; @Override - public String getUrl(final String id, final List contentFilter, + public String getUrl(final String id, + final List contentFilter, final String sortFilter) throws ParsingException { return CONFERENCE_PATH + id; } @Override public String getId(final String url) throws ParsingException { - if (url.startsWith(CONFERENCE_API_ENDPOINT)) { - return url.replace(CONFERENCE_API_ENDPOINT, ""); - } else if (url.startsWith("https://media.ccc.de/public/conferences/")) { - return url.replace("https://media.ccc.de/public/conferences/", ""); - } else if (url.startsWith(CONFERENCE_PATH)) { - return Parser.matchGroup1(CONFERENCE_PATH + "([^?#]*)", url); - } else if (url.startsWith("https://media.ccc.de/b/")) { - return Parser.matchGroup1("https://media.ccc.de/b/([^?#]*)", url); - } - throw new ParsingException("Could not get id from url: " + url); + return Parser.matchGroup1(ID_PATTERN, url); } @Override public boolean onAcceptUrl(final String url) { try { - getId(url); - return true; + return getId(url) != null; } catch (ParsingException e) { return false; } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCStreamLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCStreamLinkHandlerFactory.java index d7ecdc3c2..fa9ac4829 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCStreamLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/linkHandler/MediaCCCStreamLinkHandlerFactory.java @@ -2,45 +2,16 @@ package org.schabi.newpipe.extractor.services.media_ccc.linkHandler; import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory; -import org.schabi.newpipe.extractor.utils.Utils; - -import java.net.MalformedURLException; -import java.net.URL; +import org.schabi.newpipe.extractor.utils.Parser; public class MediaCCCStreamLinkHandlerFactory extends LinkHandlerFactory { public static final String VIDEO_API_ENDPOINT = "https://api.media.ccc.de/public/events/"; private static final String VIDEO_PATH = "https://media.ccc.de/v/"; + private static final String ID_PATTERN = "(?:(?:(?:api\\.)?media\\.ccc\\.de/public/events/)|(?:media\\.ccc\\.de/v/))([^/?&#]*)"; @Override - public String getId(final String urlString) throws ParsingException { - if (urlString.startsWith("https://media.ccc.de/public/events/") - && !urlString.contains("?q=")) { - return urlString.substring(35); //remove …/public/events part - } - - if (urlString.startsWith(VIDEO_API_ENDPOINT) - && !urlString.contains("?q=")) { - return urlString.substring(39); //remove api…/public/events part - } - - URL url; - try { - url = Utils.stringToURL(urlString); - } catch (MalformedURLException e) { - throw new IllegalArgumentException("The given URL is not valid"); - } - - String path = url.getPath(); - // remove leading "/" of URL-path if URL-path is given - if (!path.isEmpty()) { - path = path.substring(1); - } - - if (path.startsWith("v/")) { - return path.substring(2); - } - - throw new ParsingException("Could not get id from url: " + url); + public String getId(final String url) throws ParsingException { + return Parser.matchGroup1(ID_PATTERN, url); } @Override @@ -51,8 +22,7 @@ public class MediaCCCStreamLinkHandlerFactory extends LinkHandlerFactory { @Override public boolean onAcceptUrl(final String url) { try { - getId(url); - return true; + return getId(url) != null; } catch (ParsingException e) { return false; } From af5b8b1915a5ca4d7a79341e550ca64eda5e94e4 Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 11 Apr 2020 16:57:56 +0200 Subject: [PATCH 15/30] [MediaCCC] Add tests for stream and conference link handlers --- ...iaCCCConferenceLinkHandlerFactoryTest.java | 42 +++++++++++++++++++ .../MediaCCCStreamLinkHandlerFactoryTest.java | 42 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCConferenceLinkHandlerFactoryTest.java create mode 100644 extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCStreamLinkHandlerFactoryTest.java diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCConferenceLinkHandlerFactoryTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCConferenceLinkHandlerFactoryTest.java new file mode 100644 index 000000000..945bbc35e --- /dev/null +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCConferenceLinkHandlerFactoryTest.java @@ -0,0 +1,42 @@ +package org.schabi.newpipe.extractor.services.media_ccc; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.schabi.newpipe.DownloaderTestImpl; +import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.exceptions.ParsingException; +import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCConferenceLinkHandlerFactory; + +import static org.junit.Assert.assertEquals; + +public class MediaCCCConferenceLinkHandlerFactoryTest { + private static MediaCCCConferenceLinkHandlerFactory linkHandler; + + @BeforeClass + public static void setUp() { + linkHandler = new MediaCCCConferenceLinkHandlerFactory(); + NewPipe.init(DownloaderTestImpl.getInstance()); + } + + @Test + public void getId() throws ParsingException { + assertEquals("jh20", + linkHandler.fromUrl("https://media.ccc.de/c/jh20#278").getId()); + assertEquals("jh20", + linkHandler.fromUrl("https://media.ccc.de/b/jh20?a=b").getId()); + assertEquals("jh20", + linkHandler.fromUrl("https://api.media.ccc.de/public/conferences/jh20&a=b&b=c").getId()); + } + + @Test + public void getUrl() throws ParsingException { + assertEquals("https://media.ccc.de/c/jh20", + linkHandler.fromUrl("https://media.ccc.de/c/jh20#278").getUrl()); + assertEquals("https://media.ccc.de/c/jh20", + linkHandler.fromUrl("https://media.ccc.de/b/jh20?a=b").getUrl()); + assertEquals("https://media.ccc.de/c/jh20", + linkHandler.fromUrl("https://api.media.ccc.de/public/conferences/jh20&a=b&b=c").getUrl()); + assertEquals("https://media.ccc.de/c/jh20", + linkHandler.fromId("jh20").getUrl()); + } +} diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCStreamLinkHandlerFactoryTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCStreamLinkHandlerFactoryTest.java new file mode 100644 index 000000000..79228ae60 --- /dev/null +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCStreamLinkHandlerFactoryTest.java @@ -0,0 +1,42 @@ +package org.schabi.newpipe.extractor.services.media_ccc; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.schabi.newpipe.DownloaderTestImpl; +import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.exceptions.ParsingException; +import org.schabi.newpipe.extractor.services.media_ccc.linkHandler.MediaCCCStreamLinkHandlerFactory; + +import static org.junit.Assert.assertEquals; + +public class MediaCCCStreamLinkHandlerFactoryTest { + private static MediaCCCStreamLinkHandlerFactory linkHandler; + + @BeforeClass + public static void setUp() { + linkHandler = new MediaCCCStreamLinkHandlerFactory(); + NewPipe.init(DownloaderTestImpl.getInstance()); + } + + @Test + public void getId() throws ParsingException { + assertEquals("jhremote20-3001-abschlusspraesentation_jugend_hackt_remote_2020", + linkHandler.fromUrl("https://media.ccc.de/v/jhremote20-3001-abschlusspraesentation_jugend_hackt_remote_2020").getId()); + assertEquals("jhremote20-3001-abschlusspraesentation_jugend_hackt_remote_2020", + linkHandler.fromUrl("https://media.ccc.de/v/jhremote20-3001-abschlusspraesentation_jugend_hackt_remote_2020?a=b").getId()); + assertEquals("jhremote20-3001-abschlusspraesentation_jugend_hackt_remote_2020", + linkHandler.fromUrl("https://media.ccc.de/v/jhremote20-3001-abschlusspraesentation_jugend_hackt_remote_2020#3").getId()); + assertEquals("jhremote20-3001-abschlusspraesentation_jugend_hackt_remote_2020", + linkHandler.fromUrl("https://api.media.ccc.de/public/events/jhremote20-3001-abschlusspraesentation_jugend_hackt_remote_2020&a=b").getId()); + } + + @Test + public void getUrl() throws ParsingException { + assertEquals("https://media.ccc.de/v/jhremote20-3001-abschlusspraesentation_jugend_hackt_remote_2020", + linkHandler.fromUrl("https://media.ccc.de/v/jhremote20-3001-abschlusspraesentation_jugend_hackt_remote_2020").getUrl()); + assertEquals("https://media.ccc.de/v/jhremote20-3001-abschlusspraesentation_jugend_hackt_remote_2020", + linkHandler.fromUrl("https://api.media.ccc.de/public/events/jhremote20-3001-abschlusspraesentation_jugend_hackt_remote_2020?b=a&a=b").getUrl()); + assertEquals("https://media.ccc.de/v/jhremote20-3001-abschlusspraesentation_jugend_hackt_remote_2020", + linkHandler.fromId("jhremote20-3001-abschlusspraesentation_jugend_hackt_remote_2020").getUrl()); + } +} From fcb9b6f855ddd5345a6cefcc9b82a0f5138719dd Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 11 Apr 2020 17:17:14 +0200 Subject: [PATCH 16/30] [MediaCCC] Use final when possible, ide refactorings Refactorings on `throws` clause --- .../media_ccc/extractors/MediaCCCConferenceExtractor.java | 4 ++-- .../media_ccc/extractors/MediaCCCStreamExtractor.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCConferenceExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCConferenceExtractor.java index 5a7256a9a..77ea3ad1c 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCConferenceExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCConferenceExtractor.java @@ -72,8 +72,8 @@ public class MediaCCCConferenceExtractor extends ChannelExtractor { @Nonnull @Override public InfoItemsPage getInitialPage() { - StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); - JsonArray events = conferenceData.getArray("events"); + final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); + final JsonArray events = conferenceData.getArray("events"); for (int i = 0; i < events.size(); i++) { collector.commit(new MediaCCCStreamInfoItemExtractor(events.getObject(i))); } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java index 193f044da..cb5e10111 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java @@ -283,7 +283,7 @@ public class MediaCCCStreamExtractor extends StreamExtractor { @Nonnull @Override - public List getTags() throws ParsingException { + public List getTags() { return Arrays.asList(data.getArray("tags").toArray(new String[0])); } From 06430c4749295309727f72c6ac18f036f22bdc19 Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 11 Apr 2020 17:17:47 +0200 Subject: [PATCH 17/30] [PeerTube] Use final when possible, ide refactorings --- .../extractors/PeertubeStreamInfoItemExtractor.java | 6 +++--- .../linkHandler/PeertubeChannelLinkHandlerFactory.java | 3 +-- .../linkHandler/PeertubeStreamLinkHandlerFactory.java | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamInfoItemExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamInfoItemExtractor.java index edb72c164..489f5fe0c 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamInfoItemExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamInfoItemExtractor.java @@ -27,8 +27,7 @@ public class PeertubeStreamInfoItemExtractor implements StreamInfoItemExtractor @Override public String getThumbnailUrl() throws ParsingException { - final String value = JsonUtils.getString(item, "thumbnailPath"); - return baseUrl + value; + return baseUrl + JsonUtils.getString(item, "thumbnailPath"); } @Override @@ -51,7 +50,8 @@ public class PeertubeStreamInfoItemExtractor implements StreamInfoItemExtractor final String name = JsonUtils.getString(item, "account.name"); final String host = JsonUtils.getString(item, "account.host"); - return ServiceList.PeerTube.getChannelLHFactory().fromId("accounts/" + name + "@" + host, baseUrl).getUrl(); + return ServiceList.PeerTube.getChannelLHFactory() + .fromId("accounts/" + name + "@" + host, baseUrl).getUrl(); } @Override diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeChannelLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeChannelLinkHandlerFactory.java index 2903c2959..9134c14e5 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeChannelLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeChannelLinkHandlerFactory.java @@ -24,8 +24,7 @@ public class PeertubeChannelLinkHandlerFactory extends ListLinkHandlerFactory { @Override public String getUrl(String id, List contentFilters, String searchFilter) throws ParsingException { - String baseUrl = ServiceList.PeerTube.getBaseUrl(); - return getUrl(id, contentFilters, searchFilter, baseUrl); + return getUrl(id, contentFilters, searchFilter, ServiceList.PeerTube.getBaseUrl()); } @Override diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeStreamLinkHandlerFactory.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeStreamLinkHandlerFactory.java index 3e16b5096..16b3fed3f 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeStreamLinkHandlerFactory.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/linkHandler/PeertubeStreamLinkHandlerFactory.java @@ -22,8 +22,7 @@ public class PeertubeStreamLinkHandlerFactory extends LinkHandlerFactory { @Override public String getUrl(String id) { - String baseUrl = ServiceList.PeerTube.getBaseUrl(); - return getUrl(id, baseUrl); + return getUrl(id, ServiceList.PeerTube.getBaseUrl()); } @Override From 55bc01d1ce48404d6cb11cc419685696ba02eac5 Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 11 Apr 2020 17:18:05 +0200 Subject: [PATCH 18/30] [SoundCloud] Use final when possible, ide refactorings --- .../extractors/SoundcloudStreamExtractor.java | 82 ++++++++++--------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java index 0eaf1d9d8..c545ea805 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java @@ -68,8 +68,10 @@ public class SoundcloudStreamExtractor extends StreamExtractor { @Nonnull @Override - public String getTextualUploadDate() throws ParsingException { - return track.getString("created_at").replace("T"," ").replace("Z", ""); + public String getTextualUploadDate() { + return track.getString("created_at") + .replace("T"," ") + .replace("Z", ""); } @Nonnull @@ -85,10 +87,10 @@ public class SoundcloudStreamExtractor extends StreamExtractor { if (artworkUrl.isEmpty()) { artworkUrl = track.getObject("user").getString("avatar_url", EMPTY_STRING); } - String artworkUrlBetterResolution = artworkUrl.replace("large.jpg", "crop.jpg"); - return artworkUrlBetterResolution; + return artworkUrl.replace("large.jpg", "crop.jpg"); } + @Nonnull @Override public Description getDescription() { return new Description(track.getString("description"), Description.PLAIN_TEXT); @@ -144,19 +146,19 @@ public class SoundcloudStreamExtractor extends StreamExtractor { @Nonnull @Override - public String getSubChannelUrl() throws ParsingException { + public String getSubChannelUrl() { return ""; } @Nonnull @Override - public String getSubChannelName() throws ParsingException { + public String getSubChannelName() { return ""; } @Nonnull @Override - public String getSubChannelAvatarUrl() throws ParsingException { + public String getSubChannelAvatarUrl() { return ""; } @@ -168,14 +170,14 @@ public class SoundcloudStreamExtractor extends StreamExtractor { @Nonnull @Override - public String getHlsUrl() throws ParsingException { + public String getHlsUrl() { return ""; } @Override public List getAudioStreams() throws IOException, ExtractionException { List audioStreams = new ArrayList<>(); - Downloader dl = NewPipe.getDownloader(); + final Downloader dl = NewPipe.getDownloader(); // Streams can be streamable and downloadable - or explicitly not. // For playing the track, it is only necessary to have a streamable track. @@ -183,12 +185,12 @@ public class SoundcloudStreamExtractor extends StreamExtractor { if (!track.getBoolean("streamable")) return audioStreams; try { - JsonArray transcodings = track.getObject("media").getArray("transcodings"); + final JsonArray transcodings = track.getObject("media").getArray("transcodings"); // get information about what stream formats are available for (Object transcoding : transcodings) { - JsonObject t = (JsonObject) transcoding; + final JsonObject t = (JsonObject) transcoding; String url = t.getString("url"); if (!isNullOrEmpty(url)) { @@ -200,7 +202,7 @@ public class SoundcloudStreamExtractor extends StreamExtractor { // This url points to the endpoint which generates a unique and short living url to the stream. // TODO: move this to a separate method to generate valid urls when needed (e.g. resuming a paused stream) url += "?client_id=" + SoundcloudParsingHelper.clientId(); - String res = dl.get(url).responseBody(); + final String res = dl.get(url).responseBody(); try { JsonObject mp3UrlObject = JsonParser.object().from(res); @@ -234,24 +236,24 @@ public class SoundcloudStreamExtractor extends StreamExtractor { } @Override - public List getVideoStreams() throws IOException, ExtractionException { + public List getVideoStreams() { return Collections.emptyList(); } @Override - public List getVideoOnlyStreams() throws IOException, ExtractionException { + public List getVideoOnlyStreams() { return Collections.emptyList(); } @Override @Nonnull - public List getSubtitlesDefault() throws IOException, ExtractionException { + public List getSubtitlesDefault() { return Collections.emptyList(); } @Override @Nonnull - public List getSubtitles(MediaFormat format) throws IOException, ExtractionException { + public List getSubtitles(MediaFormat format) { return Collections.emptyList(); } @@ -262,10 +264,10 @@ public class SoundcloudStreamExtractor extends StreamExtractor { @Override public StreamInfoItemsCollector getRelatedStreams() throws IOException, ExtractionException { - StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); + final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); - String apiUrl = "https://api-v2.soundcloud.com/tracks/" + urlEncode(getId()) + "/related" - + "?client_id=" + urlEncode(SoundcloudParsingHelper.clientId()); + final String apiUrl = "https://api-v2.soundcloud.com/tracks/" + urlEncode(getId()) + + "/related?client_id=" + urlEncode(SoundcloudParsingHelper.clientId()); SoundcloudParsingHelper.getStreamsFromApi(collector, apiUrl); return collector; @@ -276,40 +278,44 @@ public class SoundcloudStreamExtractor extends StreamExtractor { return null; } + @Nonnull @Override - public String getHost() throws ParsingException { + public String getHost() { + return ""; + } + + @Nonnull + @Override + public String getPrivacy() { + return ""; + } + + @Nonnull + @Override + public String getCategory() { + return ""; + } + + @Nonnull + @Override + public String getLicence() { return ""; } @Override - public String getPrivacy() throws ParsingException { - return ""; - } - - @Override - public String getCategory() throws ParsingException { - return ""; - } - - @Override - public String getLicence() throws ParsingException { - return ""; - } - - @Override - public Locale getLanguageInfo() throws ParsingException { + public Locale getLanguageInfo() { return null; } @Nonnull @Override - public List getTags() throws ParsingException { + public List getTags() { return Collections.emptyList(); } @Nonnull @Override - public String getSupportInfo() throws ParsingException { + public String getSupportInfo() { return ""; } } From 3191bd6c703e1a410a03b50c2d0e4cbe7b30d7b8 Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 11 Apr 2020 17:18:17 +0200 Subject: [PATCH 19/30] [YouTube] Use final when possible --- .../services/youtube/extractors/YoutubeStreamExtractor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java index f49812fc6..d4d618b56 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java @@ -253,7 +253,8 @@ public class YoutubeStreamExtractor extends StreamExtractor { */ @Override public long getTimeStamp() throws ParsingException { - long timestamp = getTimestampSeconds("((#|&|\\?)t=\\d{0,3}h?\\d{0,3}m?\\d{1,3}s?)"); + final long timestamp = + getTimestampSeconds("((#|&|\\?)t=\\d{0,3}h?\\d{0,3}m?\\d{1,3}s?)"); if (timestamp == -2) { // regex for timestamp was not found From 68d23defba04e3db08462d8268903ec23056fd5f Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 11 Apr 2020 17:26:31 +0200 Subject: [PATCH 20/30] [YouTube] Do not catch every exception on getErrorMessage @B0pol suggestion --- .../youtube/extractors/YoutubeStreamExtractor.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java index d4d618b56..8ae88c392 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java @@ -612,10 +612,11 @@ public class YoutubeStreamExtractor extends StreamExtractor { @Override public String getErrorMessage() { try { - return getTextFromObject(initialAjaxJson.getObject(2).getObject("playerResponse").getObject("playabilityStatus") - .getObject("errorScreen").getObject("playerErrorMessageRenderer").getObject("reason")); - } catch (Exception e) { - return null; + return getTextFromObject(initialAjaxJson.getObject(2).getObject("playerResponse") + .getObject("playabilityStatus").getObject("errorScreen") + .getObject("playerErrorMessageRenderer").getObject("reason")); + } catch (ParsingException | NullPointerException e) { + return null; // no error message } } From 8dc3f28618d38c692f3abee1ae612e54ac1de3ee Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 11 Apr 2020 17:42:15 +0200 Subject: [PATCH 21/30] [PeerTube] Test one channel url with api and one without --- .../services/peertube/PeertubeChannelExtractorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeChannelExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeChannelExtractorTest.java index 68ae7673a..f9e686c82 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeChannelExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeChannelExtractorTest.java @@ -28,7 +28,7 @@ public class PeertubeChannelExtractorTest { // setting instance might break test when running in parallel PeerTube.setInstance(new PeertubeInstance("https://peertube.mastodon.host", "PeerTube on Mastodon.host")); extractor = (PeertubeChannelExtractor) PeerTube - .getChannelExtractor("https://peertube.mastodon.host/api/v1/video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa"); + .getChannelExtractor("https://peertube.mastodon.host/video-channels/7682d9f2-07be-4622-862e-93ec812e2ffa"); extractor.fetchPage(); } From a4097d8d0119cfc71a3b969aa117df924af60e3d Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 11 Apr 2020 17:43:26 +0200 Subject: [PATCH 22/30] [MediaCCC] Return empty list of video-only streams instead of null --- .../services/media_ccc/extractors/MediaCCCStreamExtractor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java index cb5e10111..92a049c55 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java @@ -197,7 +197,7 @@ public class MediaCCCStreamExtractor extends StreamExtractor { @Override public List getVideoOnlyStreams() { - return null; + return Collections.emptyList(); } @Nonnull From a087b092b401977bd58b279a3f285549db0e2160 Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 16 May 2020 16:07:25 +0200 Subject: [PATCH 23/30] [Test] Improve code style and add final --- .../services/DefaultStreamExtractorTest.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java index 406177f7e..fc2ebf435 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java @@ -95,7 +95,7 @@ public abstract class DefaultStreamExtractorTest extends DefaultExtractorTest videoStreams = extractor().getVideoStreams(); + final List videoStreams = extractor().getVideoStreams(); final List videoOnlyStreams = extractor().getVideoOnlyStreams(); assertNotNull(videoStreams); assertNotNull(videoOnlyStreams); @@ -202,11 +202,11 @@ public abstract class DefaultStreamExtractorTest extends DefaultExtractorTest subtitles = extractor().getSubtitlesDefault(); + final List subtitles = extractor().getSubtitlesDefault(); assertNotNull(subtitles); if (expectedHasSubtitles()) { assertFalse(subtitles.isEmpty()); - for (SubtitlesStream stream : subtitles) { + for (final SubtitlesStream stream : subtitles) { assertIsSecureUrl(stream.getUrl()); - int formatId = stream.getFormatId(); - assertTrue("format id does not fit an audio stream: " + formatId, + final int formatId = stream.getFormatId(); + assertTrue("format id does not fit a subtitles stream: " + formatId, 0x1000 <= formatId && formatId < 0x10000); } } else { assertTrue(subtitles.isEmpty()); - MediaFormat[] formats = {MediaFormat.VTT, MediaFormat.TTML, MediaFormat.TRANSCRIPT1, - MediaFormat.TRANSCRIPT2, MediaFormat.TRANSCRIPT3, MediaFormat.SRT}; - for (MediaFormat format : formats) { - subtitles = extractor().getSubtitles(format); - assertNotNull(subtitles); - assertTrue(subtitles.isEmpty()); + final MediaFormat[] formats = {MediaFormat.VTT, MediaFormat.TTML, MediaFormat.SRT, + MediaFormat.TRANSCRIPT1, MediaFormat.TRANSCRIPT2, MediaFormat.TRANSCRIPT3}; + for (final MediaFormat format : formats) { + final List formatSubtitles = extractor().getSubtitles(format); + assertNotNull(formatSubtitles); + assertTrue(formatSubtitles.isEmpty()); } } } From 6127826571a9041cc9d9d264ac97239249f2aff9 Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 16 May 2020 20:07:12 +0200 Subject: [PATCH 24/30] [Test] Add stream metadata tests --- .../newpipe/extractor/ExtractorAsserts.java | 17 ++++++ .../services/BaseStreamExtractorTest.java | 7 +++ .../services/DefaultStreamExtractorTest.java | 54 ++++++++++++++++++- .../MediaCCCStreamExtractorTest.java | 2 + .../peertube/PeertubeStreamExtractorTest.java | 13 ++++- 5 files changed, 91 insertions(+), 2 deletions(-) diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/ExtractorAsserts.java b/extractor/src/test/java/org/schabi/newpipe/extractor/ExtractorAsserts.java index a0a887d7d..69e10b0ed 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/ExtractorAsserts.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/ExtractorAsserts.java @@ -2,6 +2,8 @@ package org.schabi.newpipe.extractor; import java.net.MalformedURLException; import java.net.URL; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import javax.annotation.Nonnull; @@ -10,6 +12,7 @@ import javax.annotation.Nullable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; public class ExtractorAsserts { @@ -64,4 +67,18 @@ public class ExtractorAsserts { public static void assertAtLeast(long expected, long actual) { assertTrue(actual + " is not at least " + expected, actual >= expected); } + + // this assumes that sorting a and b in-place is not an issue, so it's only intended for tests + public static void assertEqualsOrderIndependent(List expected, List actual) { + if (expected == null) { + assertNull(actual); + return; + } else { + assertNotNull(actual); + } + + Collections.sort(expected); + Collections.sort(actual); + assertEquals(expected, actual); + } } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/BaseStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/BaseStreamExtractorTest.java index fb555a033..6f3dc813a 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/BaseStreamExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/BaseStreamExtractorTest.java @@ -21,4 +21,11 @@ public interface BaseStreamExtractorTest extends BaseExtractorTest { void testVideoStreams() throws Exception; void testSubtitles() throws Exception; void testFrames() throws Exception; + void testHost() throws Exception; + void testPrivacy() throws Exception; + void testCategory() throws Exception; + void testLicence() throws Exception; + void testLanguageInfo() throws Exception; + void testTags() throws Exception; + void testSupportInfo() throws Exception; } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java index fc2ebf435..29d9b15da 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java @@ -14,7 +14,9 @@ import org.schabi.newpipe.extractor.stream.VideoStream; import java.text.SimpleDateFormat; import java.util.Calendar; +import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.TimeZone; import javax.annotation.Nullable; @@ -27,6 +29,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.schabi.newpipe.extractor.ExtractorAsserts.assertAtLeast; +import static org.schabi.newpipe.extractor.ExtractorAsserts.assertEqualsOrderIndependent; import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl; import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsValidUrl; import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestListOfItems; @@ -42,7 +45,7 @@ public abstract class DefaultStreamExtractorTest extends DefaultExtractorTest expectedDescriptionContains(); // e.g. for full links public abstract long expectedLength(); - public long expectedTimestamp() { return 0; }; // default: there is no timestamp + public long expectedTimestamp() { return 0; } // default: there is no timestamp public abstract long expectedViewCountAtLeast(); @Nullable public abstract String expectedUploadDate(); // format: "yyyy-MM-dd HH:mm:ss.SSS" @Nullable public abstract String expectedTextualUploadDate(); @@ -55,6 +58,13 @@ public abstract class DefaultStreamExtractorTest extends DefaultExtractorTest expectedTags() { return Collections.emptyList(); } // default: no tags + public String expectedSupportInfo() { return ""; } // default: no support info available @Test @Override @@ -283,4 +293,46 @@ public abstract class DefaultStreamExtractorTest extends DefaultExtractorTest expectedTags() { return Arrays.asList("gpn18", "105"); } @Override @Test @@ -118,6 +119,7 @@ public class MediaCCCStreamExtractorTest { @Override public boolean expectedHasRelatedStreams() { return false; } @Override public boolean expectedHasSubtitles() { return false; } @Override public boolean expectedHasFrames() { return false; } + @Override public List expectedTags() { return Arrays.asList("36c3", "10565", "2019", "Security", "Main"); } @Override @Test diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java index f78b96e13..40b198713 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java @@ -84,7 +84,12 @@ public class PeertubeStreamExtractorTest { @Override public long expectedDislikeCountAtLeast() { return 0; } @Override public boolean expectedHasAudioStreams() { return false; } @Override public boolean expectedHasFrames() { return false; } - + @Override public String expectedHost() { return "framatube.org"; } + @Override public String expectedPrivacy() { return "Public"; } + @Override public String expectedCategory() { return "Science & Technology"; } + @Override public String expectedLicence() { return "Attribution - Share Alike"; } + @Override public Locale expectedLanguageInfo() { return Locale.forLanguageTag("en"); } + @Override public List expectedTags() { return Arrays.asList("framasoft", "peertube"); } } public static class AgeRestricted extends DefaultStreamExtractorTest { @@ -136,6 +141,12 @@ public class PeertubeStreamExtractorTest { @Override public boolean expectedHasAudioStreams() { return false; } @Override public boolean expectedHasSubtitles() { return false; } @Override public boolean expectedHasFrames() { return false; } + @Override public String expectedHost() { return "peertube.iriseden.eu"; } + @Override public String expectedPrivacy() { return "Public"; } + @Override public String expectedCategory() { return "News & Politics"; } + @Override public String expectedLicence() { return "Attribution - Share Alike"; } + @Override public Locale expectedLanguageInfo() { return Locale.forLanguageTag("ru"); } + @Override public List expectedTags() { return Arrays.asList("ДНР", "ЛНР", "Кремль", "Новороссия", "ФСБ"); } } From 8ce711f40fe3667a9184da513a794d83c098985d Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 16 May 2020 20:27:58 +0200 Subject: [PATCH 25/30] [Test] Add sub channel name, url and thumbnail tests --- .../services/BaseStreamExtractorTest.java | 3 ++ .../services/DefaultStreamExtractorTest.java | 32 +++++++++++++++++++ .../peertube/PeertubeStreamExtractorTest.java | 4 +++ 3 files changed, 39 insertions(+) diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/BaseStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/BaseStreamExtractorTest.java index 6f3dc813a..fe7abc677 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/BaseStreamExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/BaseStreamExtractorTest.java @@ -5,6 +5,9 @@ public interface BaseStreamExtractorTest extends BaseExtractorTest { void testUploaderName() throws Exception; void testUploaderUrl() throws Exception; void testUploaderAvatarUrl() throws Exception; + void testSubChannelName() throws Exception; + void testSubChannelUrl() throws Exception; + void testSubChannelAvatarUrl() throws Exception; void testThumbnailUrl() throws Exception; void testDescription() throws Exception; void testLength() throws Exception; diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java index 29d9b15da..860dfd48d 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java @@ -43,6 +43,8 @@ public abstract class DefaultStreamExtractorTest extends DefaultExtractorTest expectedDescriptionContains(); // e.g. for full links public abstract long expectedLength(); public long expectedTimestamp() { return 0; } // default: there is no timestamp @@ -92,6 +94,36 @@ public abstract class DefaultStreamExtractorTest extends DefaultExtractorTest expectedDescriptionContains() { // CRLF line ending return Arrays.asList("**[Want to help to translate this video?](https://weblate.framasoft.org/projects/what-is-peertube-video/)**\r\n" + "\r\n" @@ -117,6 +119,8 @@ public class PeertubeStreamExtractorTest { @Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; } @Override public String expectedUploaderName() { return "Tomas Berezovskiy"; } @Override public String expectedUploaderUrl() { return "https://peertube.co.uk/accounts/tomas_berezovskiy@peertube.iriseden.eu"; } + @Override public String expectedSubChannelName() { return "smm.expx3"; } + @Override public String expectedSubChannelUrl() { return "https://peertube.iriseden.eu/video-channels/smm.expx3"; } @Override public List expectedDescriptionContains() { // LF line ending return Arrays.asList("https://en.informnapalm.org/dpr-combatant-describes-orders-given-russian-officers/ " + " The InformNapalm team received another video of a separatist prisoner of war telling about his " From d0b14644bb9937d73137a4b8c0121a13defe9b56 Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 16 May 2020 21:14:10 +0200 Subject: [PATCH 26/30] [YouTube/MediaCCC] Consider dates as GMT and not as local --- .../services/media_ccc/extractors/MediaCCCParsingHelper.java | 5 ++++- .../extractor/services/youtube/YoutubeParsingHelper.java | 4 +++- .../extractor/services/DefaultStreamExtractorTest.java | 3 +-- .../services/peertube/PeertubeStreamExtractorTest.java | 4 ++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCParsingHelper.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCParsingHelper.java index 9e5baaf9c..dfdceeadc 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCParsingHelper.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCParsingHelper.java @@ -6,6 +6,7 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; +import java.util.TimeZone; public final class MediaCCCParsingHelper { private MediaCCCParsingHelper() { } @@ -13,7 +14,9 @@ public final class MediaCCCParsingHelper { public static Calendar parseDateFrom(final String textualUploadDate) throws ParsingException { Date date; try { - date = new SimpleDateFormat("yyyy-MM-dd").parse(textualUploadDate); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + sdf.setTimeZone(TimeZone.getTimeZone("GMT")); + date = sdf.parse(textualUploadDate); } catch (ParseException e) { throw new ParsingException("Could not parse date: \"" + textualUploadDate + "\"", e); } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java index af10efa22..cefab49d5 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java @@ -185,7 +185,9 @@ public class YoutubeParsingHelper { public static Calendar parseDateFrom(String textualUploadDate) throws ParsingException { Date date; try { - date = new SimpleDateFormat("yyyy-MM-dd").parse(textualUploadDate); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + sdf.setTimeZone(TimeZone.getTimeZone("GMT")); + date = sdf.parse(textualUploadDate); } catch (ParseException e) { throw new ParsingException("Could not parse date: \"" + textualUploadDate + "\"", e); } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java index 860dfd48d..81d9dced3 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java @@ -172,10 +172,9 @@ public abstract class DefaultStreamExtractorTest extends DefaultExtractorTest Date: Sun, 14 Jun 2020 10:41:13 +0200 Subject: [PATCH 27/30] [Test] Add stream dash mpd url test --- .../services/BaseStreamExtractorTest.java | 1 + .../services/DefaultStreamExtractorTest.java | 15 ++++++++++++++- .../YoutubeStreamExtractorLivestreamTest.java | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/BaseStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/BaseStreamExtractorTest.java index fe7abc677..40356cebf 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/BaseStreamExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/BaseStreamExtractorTest.java @@ -23,6 +23,7 @@ public interface BaseStreamExtractorTest extends BaseExtractorTest { void testAudioStreams() throws Exception; void testVideoStreams() throws Exception; void testSubtitles() throws Exception; + void testGetDashMpdUrl() throws Exception; void testFrames() throws Exception; void testHost() throws Exception; void testPrivacy() throws Exception; diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java index 81d9dced3..8ab642d93 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java @@ -22,11 +22,11 @@ import java.util.TimeZone; import javax.annotation.Nullable; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.schabi.newpipe.extractor.ExtractorAsserts.assertAtLeast; import static org.schabi.newpipe.extractor.ExtractorAsserts.assertEqualsOrderIndependent; @@ -59,6 +59,7 @@ public abstract class DefaultStreamExtractorTest extends DefaultExtractorTest Date: Sun, 14 Jun 2020 19:51:54 +0200 Subject: [PATCH 28/30] [PeerTube] Change age restricted video in tests The old one wasn't available anymore --- .../peertube/PeertubeStreamExtractorTest.java | 51 ++++++++----------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java index 8b9550b81..f8c729571 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/peertube/PeertubeStreamExtractorTest.java @@ -95,9 +95,9 @@ public class PeertubeStreamExtractorTest { } public static class AgeRestricted extends DefaultStreamExtractorTest { - private static final String ID = "0d501633-f2d9-4476-87c6-71f1c02402a4"; - private static final String INSTANCE = "https://peertube.co.uk"; - private static final String URL = INSTANCE + BASE_URL + ID; + private static final String ID = "dbd8e5e1-c527-49b6-b70c-89101dbb9c08"; + private static final String INSTANCE = "https://nocensoring.net"; + private static final String URL = INSTANCE + "/videos/embed/" + ID; private static StreamExtractor extractor; @BeforeClass @@ -111,46 +111,35 @@ public class PeertubeStreamExtractorTest { @Override public StreamExtractor extractor() { return extractor; } @Override public StreamingService expectedService() { return PeerTube; } - @Override public String expectedName() { return "A DPR Combatant Describes how Orders are Given through Russian Officers"; } + @Override public String expectedName() { return "Covid-19 ? [Court-métrage]"; } @Override public String expectedId() { return ID; } - @Override public String expectedUrlContains() { return URL; } + @Override public String expectedUrlContains() { return INSTANCE + BASE_URL + ID; } @Override public String expectedOriginalUrlContains() { return URL; } @Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; } - @Override public String expectedUploaderName() { return "Tomas Berezovskiy"; } - @Override public String expectedUploaderUrl() { return "https://peertube.co.uk/accounts/tomas_berezovskiy@peertube.iriseden.eu"; } - @Override public String expectedSubChannelName() { return "smm.expx3"; } - @Override public String expectedSubChannelUrl() { return "https://peertube.iriseden.eu/video-channels/smm.expx3"; } + @Override public String expectedUploaderName() { return "Résilience humaine"; } + @Override public String expectedUploaderUrl() { return "https://nocensoring.net/accounts/gmt@nocensoring.net"; } + @Override public String expectedSubChannelName() { return "SYSTEM FAILURE Quel à-venir ?"; } + @Override public String expectedSubChannelUrl() { return "https://nocensoring.net/video-channels/systemfailure_quel"; } @Override public List expectedDescriptionContains() { // LF line ending - return Arrays.asList("https://en.informnapalm.org/dpr-combatant-describes-orders-given-russian-officers/ " - + " The InformNapalm team received another video of a separatist prisoner of war telling about his " - + "activities in `Dontesk People’s Republic’ (DPR) structures. The video is old, as the interrogation" - + " date is September, but it is the situation described is still relevant and interesting today. In " - + "this recording the combatant re-tells how he came to be recruited into the DPR forces, and how " - + "they are operating under Russian military command. He expresses remorse for his stupidity. Perhaps" - + " he is just saying what he thinks his interrogator wants to hear, perhaps he is speaking from a " - + "new understanding?\n" - + "\n" - + "The video contains a lot of cut and paste (stitching) in places where intelligence data or valuable" - + " information has been deleted because it cannot be shared publically. We trust you will understand " - + "this necessity."); + return Arrays.asList("2020, le monde est frappé par une pandémie, beaucoup d'humains sont confinés.", + "System Failure Quel à-venir ? - Covid-19 / 2020"); } - @Override public long expectedLength() { return 512; } - @Override public long expectedViewCountAtLeast() { return 7; } - @Nullable @Override public String expectedUploadDate() { return "2019-10-22 06:16:48.982"; } - @Nullable @Override public String expectedTextualUploadDate() { return "2019-10-22T06:16:48.982Z"; } - @Override public long expectedLikeCountAtLeast() { return 3; } + @Override public long expectedLength() { return 667; } + @Override public long expectedViewCountAtLeast() { return 138; } + @Nullable @Override public String expectedUploadDate() { return "2020-05-14 17:24:35.580"; } + @Nullable @Override public String expectedTextualUploadDate() { return "2020-05-14T17:24:35.580Z"; } + @Override public long expectedLikeCountAtLeast() { return 1; } @Override public long expectedDislikeCountAtLeast() { return 0; } @Override public int expectedAgeLimit() { return 18; } @Override public boolean expectedHasAudioStreams() { return false; } @Override public boolean expectedHasSubtitles() { return false; } @Override public boolean expectedHasFrames() { return false; } - @Override public String expectedHost() { return "peertube.iriseden.eu"; } + @Override public String expectedHost() { return "nocensoring.net"; } @Override public String expectedPrivacy() { return "Public"; } - @Override public String expectedCategory() { return "News & Politics"; } - @Override public String expectedLicence() { return "Attribution - Share Alike"; } - @Override public Locale expectedLanguageInfo() { return Locale.forLanguageTag("ru"); } - @Override public List expectedTags() { return Arrays.asList("ДНР", "ЛНР", "Кремль", "Новороссия", "ФСБ"); } + @Override public String expectedCategory() { return "Art"; } + @Override public String expectedLicence() { return "Attribution"; } + @Override public List expectedTags() { return Arrays.asList("Covid-19", "Gérôme-Mary trebor", "Horreur et beauté", "court-métrage", "nue artistique"); } } From f11fe87688beb27a051608c4f0facb2d8214b6d1 Mon Sep 17 00:00:00 2001 From: Stypox Date: Fri, 14 Aug 2020 11:09:29 +0200 Subject: [PATCH 29/30] [YouTube] Replace outdated PewDiePie video test with another one The old video was made private, and this video (wedding) is probably never going to be removed. --- .../YoutubeStreamExtractorDefaultTest.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java index 49369831b..6a3aa4f28 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java @@ -105,7 +105,7 @@ public class YoutubeStreamExtractorDefaultTest { } public static class DescriptionTestPewdiepie extends DefaultStreamExtractorTest { - private static final String ID = "fBc4Q_htqPg"; + private static final String ID = "7PIMiDcwNvc"; private static final int TIMESTAMP = 17; private static final String URL = BASE_URL + ID + "&t=" + TIMESTAMP; private static StreamExtractor extractor; @@ -119,7 +119,7 @@ public class YoutubeStreamExtractorDefaultTest { @Override public StreamExtractor extractor() { return extractor; } @Override public StreamingService expectedService() { return YouTube; } - @Override public String expectedName() { return "Dr. Phil DESTROYS spoiled brat!!!! . -- Dr Phil #7"; } + @Override public String expectedName() { return "Marzia & Felix - Wedding 19.08.2019"; } @Override public String expectedId() { return ID; } @Override public String expectedUrlContains() { return BASE_URL + ID; } @Override public String expectedOriginalUrlContains() { return URL; } @@ -128,17 +128,16 @@ public class YoutubeStreamExtractorDefaultTest { @Override public String expectedUploaderName() { return "PewDiePie"; } @Override public String expectedUploaderUrl() { return "https://www.youtube.com/channel/UC-lHJZR3Gqxm24_Vd_AJ5Yw"; } @Override public List expectedDescriptionContains() { - return Arrays.asList("https://www.reddit.com/r/PewdiepieSubmissions/", - "https://www.youtube.com/channel/UC3e8EMTOn4g6ZSKggHTnNng", - "https://usa.clutchchairz.com/product/pewdiepie-edition-throttle-series/"); + return Arrays.asList("https://www.youtube.com/channel/UC7l23W7gFi4Uho6WSzckZRA", + "https://www.handcraftpictures.com/"); } - @Override public long expectedLength() { return 1165; } + @Override public long expectedLength() { return 381; } @Override public long expectedTimestamp() { return TIMESTAMP; } @Override public long expectedViewCountAtLeast() { return 26682500; } - @Nullable @Override public String expectedUploadDate() { return "2018-09-12 00:00:00.000"; } - @Nullable @Override public String expectedTextualUploadDate() { return "2018-09-12"; } - @Override public long expectedLikeCountAtLeast() { return 1166000; } - @Override public long expectedDislikeCountAtLeast() { return 16900; } + @Nullable @Override public String expectedUploadDate() { return "2019-08-24 00:00:00.000"; } + @Nullable @Override public String expectedTextualUploadDate() { return "2019-08-24"; } + @Override public long expectedLikeCountAtLeast() { return 5212900; } + @Override public long expectedDislikeCountAtLeast() { return 30600; } } public static class DescriptionTestUnboxing extends DefaultStreamExtractorTest { From 57e7994c9e46d068ba53cb320c91c22ec24f76de Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 24 Oct 2020 21:17:58 +0200 Subject: [PATCH 30/30] Add some missing finals, nullables and comments --- .../extractors/MediaCCCParsingHelper.java | 4 ++-- .../extractors/MediaCCCStreamExtractor.java | 2 ++ .../extractors/PeertubeAccountExtractor.java | 6 +++-- .../extractors/PeertubeStreamExtractor.java | 22 ++++++++++++------- .../extractors/SoundcloudStreamExtractor.java | 2 ++ .../youtube/YoutubeParsingHelper.java | 4 ++-- .../extractors/YoutubeStreamExtractor.java | 5 ++++- .../extractor/stream/StreamExtractor.java | 1 + .../services/DefaultStreamExtractorTest.java | 3 +++ 9 files changed, 34 insertions(+), 15 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCParsingHelper.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCParsingHelper.java index dfdceeadc..14ca5c52c 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCParsingHelper.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCParsingHelper.java @@ -12,9 +12,9 @@ public final class MediaCCCParsingHelper { private MediaCCCParsingHelper() { } public static Calendar parseDateFrom(final String textualUploadDate) throws ParsingException { - Date date; + final Date date; try { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); date = sdf.parse(textualUploadDate); } catch (ParseException e) { diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java index 92a049c55..96b1a5cc7 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Locale; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class MediaCCCStreamExtractor extends StreamExtractor { private JsonObject data; @@ -217,6 +218,7 @@ public class MediaCCCStreamExtractor extends StreamExtractor { return StreamType.VIDEO_STREAM; } + @Nullable @Override public StreamInfoItemsCollector getRelatedStreams() { return null; diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeAccountExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeAccountExtractor.java index 9f04ffc27..b41bf2057 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeAccountExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeAccountExtractor.java @@ -96,7 +96,8 @@ public class PeertubeAccountExtractor extends ChannelExtractor { } @Override - public InfoItemsPage getPage(final Page page) throws IOException, ExtractionException { + public InfoItemsPage getPage(final Page page) + throws IOException, ExtractionException { if (page == null || isNullOrEmpty(page.getUrl())) { throw new IllegalArgumentException("Page doesn't contain an URL"); } @@ -126,7 +127,8 @@ public class PeertubeAccountExtractor extends ChannelExtractor { } @Override - public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException { + public void onFetchPage(@Nonnull final Downloader downloader) + throws IOException, ExtractionException { String accountUrl = baseUrl + PeertubeChannelLinkHandlerFactory.API_ENDPOINT; if (getId().contains("accounts/")) { accountUrl += getId(); diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamExtractor.java index 7e1861f76..fa02d473a 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamExtractor.java @@ -38,6 +38,7 @@ import java.util.List; import java.util.Locale; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class PeertubeStreamExtractor extends StreamExtractor { private final String baseUrl; @@ -113,7 +114,7 @@ public class PeertubeStreamExtractor extends StreamExtractor { @Override public long getTimeStamp() throws ParsingException { - long timestamp = + final long timestamp = getTimestampSeconds("((#|&|\\?)start=\\d{0,3}h?\\d{0,3}m?\\d{1,3}s?)"); if (timestamp == -2) { @@ -261,19 +262,24 @@ public class PeertubeStreamExtractor extends StreamExtractor { return StreamType.VIDEO_STREAM; } + @Nullable @Override public StreamInfoItemsCollector getRelatedStreams() throws IOException, ExtractionException { - final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); final List tags = getTags(); final String apiUrl; - if (!tags.isEmpty()) { - apiUrl = getRelatedStreamsUrl(tags); - - } else { + if (tags.isEmpty()) { apiUrl = getUploaderUrl() + "/videos?start=0&count=8"; + } else { + apiUrl = getRelatedStreamsUrl(tags); + } + + if (Utils.isBlank(apiUrl)) { + return null; + } else { + final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); + getStreamsFromApi(collector, apiUrl); + return collector; } - if (!Utils.isBlank(apiUrl)) getStreamsFromApi(collector, apiUrl); - return collector; } @Nonnull diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java index c545ea805..bc1d59026 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java @@ -33,6 +33,7 @@ import java.util.List; import java.util.Locale; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import static org.schabi.newpipe.extractor.utils.JsonUtils.EMPTY_STRING; import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; @@ -262,6 +263,7 @@ public class SoundcloudStreamExtractor extends StreamExtractor { return StreamType.AUDIO_STREAM; } + @Nullable @Override public StreamInfoItemsCollector getRelatedStreams() throws IOException, ExtractionException { final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java index cefab49d5..ac7db9855 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java @@ -183,9 +183,9 @@ public class YoutubeParsingHelper { } public static Calendar parseDateFrom(String textualUploadDate) throws ParsingException { - Date date; + final Date date; try { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); date = sdf.parse(textualUploadDate); } catch (ParseException e) { diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java index 8ae88c392..0077a163e 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java @@ -576,11 +576,14 @@ public class YoutubeStreamExtractor extends StreamExtractor { } } + @Nullable @Override public StreamInfoItemsCollector getRelatedStreams() throws ExtractionException { assertPageFetched(); - if (getAgeLimit() != NO_AGE_LIMIT) return null; + if (getAgeLimit() != NO_AGE_LIMIT) { + return null; + } try { final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamExtractor.java index f48bb913f..4e109bbab 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamExtractor.java @@ -321,6 +321,7 @@ public abstract class StreamExtractor extends Extractor { * @throws IOException * @throws ExtractionException */ + @Nullable public abstract StreamInfoItemsCollector getRelatedStreams() throws IOException, ExtractionException; /** diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java index 8ab642d93..a70b38a8a 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultStreamExtractorTest.java @@ -249,6 +249,7 @@ public abstract class DefaultStreamExtractorTest extends DefaultExtractorTest