Skip to content

Commit fbb9a86

Browse files
authored
Merge branch 'dev' into yt-webm-opus
2 parents 12008fc + 8ab48c6 commit fbb9a86

4 files changed

Lines changed: 137 additions & 25 deletions

File tree

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeChannelExtractor.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ public String getUrl() throws ParsingException {
8282
@Nonnull
8383
@Override
8484
public String getId() throws ParsingException {
85+
try {
86+
return doc.select("meta[itemprop=\"channelId\"]").first().attr("content");
87+
} catch (Exception ignored) {}
88+
89+
// fallback method; does not work with channels that have no "Subscribe" button (e.g. EminemVEVO)
8590
try {
8691
Element element = doc.getElementsByClass("yt-uix-subscription-button").first();
8792
if (element == null) element = doc.getElementsByClass("yt-uix-subscription-preferences-button").first();
@@ -135,11 +140,12 @@ public String getFeedUrl() throws ParsingException {
135140

136141
@Override
137142
public long getSubscriberCount() throws ParsingException {
138-
final String el = doc.select("span[class*=\"yt-subscription-button-subscriber-count\"]")
139-
.first().attr("title");
143+
144+
final Element el = doc.select("span[class*=\"yt-subscription-button-subscriber-count\"]").first();
140145
if (el != null) {
146+
String elTitle = el.attr("title");
141147
try {
142-
return Utils.mixedNumberWordToLong(el);
148+
return Utils.mixedNumberWordToLong(elTitle);
143149
} catch (NumberFormatException e) {
144150
throw new ParsingException("Could not get subscriber count", e);
145151
}

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeChannelInfoItemExtractor.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,25 @@ public String getName() throws ParsingException {
5656

5757
@Override
5858
public String getUrl() throws ParsingException {
59-
String buttonTrackingUrl = el.select("button[class*=\"yt-uix-button\"]").first()
60-
.attr("abs:data-href");
59+
try {
60+
String buttonTrackingUrl = el.select("button[class*=\"yt-uix-button\"]").first()
61+
.attr("abs:data-href");
6162

62-
Pattern channelIdPattern = Pattern.compile("(?:.*?)\\%252Fchannel\\%252F([A-Za-z0-9\\-\\_]+)(?:.*)");
63-
Matcher match = channelIdPattern.matcher(buttonTrackingUrl);
63+
Pattern channelIdPattern = Pattern.compile("(?:.*?)\\%252Fchannel\\%252F([A-Za-z0-9\\-\\_]+)(?:.*)");
64+
Matcher match = channelIdPattern.matcher(buttonTrackingUrl);
6465

65-
if (match.matches()) {
66-
return YoutubeChannelExtractor.CHANNEL_URL_BASE + match.group(1);
67-
} else {
68-
// fallback method just in case youtube changes things; it should never run and tests will fail
69-
// provides an url with "/user/NAME", that is inconsistent with stream and channel extractor
66+
if (match.matches()) {
67+
return YoutubeChannelExtractor.CHANNEL_URL_BASE + match.group(1);
68+
}
69+
} catch(Exception ignored) {}
70+
71+
// fallback method for channels without "Subscribe" button (or just in case yt changes things)
72+
// provides an url with "/user/NAME", inconsistent with stream and channel extractor: tests will fail
73+
try {
7074
return el.select("a[class*=\"yt-uix-tile-link\"]").first()
7175
.attr("abs:href");
76+
} catch (Exception e) {
77+
throw new ParsingException("Could not get channel url", e);
7278
}
7379
}
7480

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -575,21 +575,26 @@ public StreamInfoItemsCollector getRelatedStreams() throws IOException, Extracti
575575
*/
576576
@Override
577577
public String getErrorMessage() {
578-
String errorMessage = doc.select("h1[id=\"unavailable-message\"]").first().text();
579578
StringBuilder errorReason;
579+
Element errorElement = doc.select("h1[id=\"unavailable-message\"]").first();
580580

581-
if (errorMessage == null || errorMessage.isEmpty()) {
581+
if (errorElement == null) {
582582
errorReason = null;
583-
} else if (errorMessage.contains("GEMA")) {
584-
// Gema sometimes blocks youtube music content in germany:
585-
// https://www.gema.de/en/
586-
// Detailed description:
587-
// https://en.wikipedia.org/wiki/GEMA_%28German_organization%29
588-
errorReason = new StringBuilder("GEMA");
589583
} else {
590-
errorReason = new StringBuilder(errorMessage);
591-
errorReason.append(" ");
592-
errorReason.append(doc.select("[id=\"unavailable-submessage\"]").first().text());
584+
String errorMessage = errorElement.text();
585+
if (errorMessage == null || errorMessage.isEmpty()) {
586+
errorReason = null;
587+
} else if (errorMessage.contains("GEMA")) {
588+
// Gema sometimes blocks youtube music content in germany:
589+
// https://www.gema.de/en/
590+
// Detailed description:
591+
// https://en.wikipedia.org/wiki/GEMA_%28German_organization%29
592+
errorReason = new StringBuilder("GEMA");
593+
} else {
594+
errorReason = new StringBuilder(errorMessage);
595+
errorReason.append(" ");
596+
errorReason.append(doc.select("[id=\"unavailable-submessage\"]").first().text());
597+
}
593598
}
594599

595600
return errorReason != null ? errorReason.toString() : null;

extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeChannelExtractorTest.java

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,100 @@ public void testSubscriberCount() throws Exception {
392392
}
393393
}
394394

395+
// this channel has no "Subscribe" button
396+
public static class EminemVEVO implements BaseChannelExtractorTest {
397+
private static YoutubeChannelExtractor extractor;
398+
399+
@BeforeClass
400+
public static void setUp() throws Exception {
401+
NewPipe.init(Downloader.getInstance(), new Localization("GB", "en"));
402+
extractor = (YoutubeChannelExtractor) YouTube
403+
.getChannelExtractor("https://www.youtube.com/user/EminemVEVO/");
404+
extractor.fetchPage();
405+
}
406+
407+
/*//////////////////////////////////////////////////////////////////////////
408+
// Extractor
409+
//////////////////////////////////////////////////////////////////////////*/
410+
411+
@Test
412+
public void testServiceId() {
413+
assertEquals(YouTube.getServiceId(), extractor.getServiceId());
414+
}
415+
416+
@Test
417+
public void testName() throws Exception {
418+
assertEquals("EminemVEVO", extractor.getName());
419+
}
420+
421+
@Test
422+
public void testId() throws Exception {
423+
assertEquals("UC20vb-R_px4CguHzzBPhoyQ", extractor.getId());
424+
}
425+
426+
@Test
427+
public void testUrl() throws ParsingException {
428+
assertEquals("https://www.youtube.com/channel/UC20vb-R_px4CguHzzBPhoyQ", extractor.getUrl());
429+
}
430+
431+
@Test
432+
public void testOriginalUrl() throws ParsingException {
433+
assertEquals("https://www.youtube.com/user/EminemVEVO/", extractor.getOriginalUrl());
434+
}
435+
436+
/*//////////////////////////////////////////////////////////////////////////
437+
// ListExtractor
438+
//////////////////////////////////////////////////////////////////////////*/
439+
440+
@Test
441+
public void testRelatedItems() throws Exception {
442+
defaultTestRelatedItems(extractor, YouTube.getServiceId());
443+
}
444+
445+
@Test
446+
public void testMoreRelatedItems() throws Exception {
447+
defaultTestMoreItems(extractor, YouTube.getServiceId());
448+
}
449+
450+
/*//////////////////////////////////////////////////////////////////////////
451+
// ChannelExtractor
452+
//////////////////////////////////////////////////////////////////////////*/
453+
454+
@Test
455+
public void testDescription() throws Exception {
456+
final String description = extractor.getDescription();
457+
assertTrue(description, description.contains("Eminem on Vevo"));
458+
}
459+
460+
@Test
461+
public void testAvatarUrl() throws Exception {
462+
String avatarUrl = extractor.getAvatarUrl();
463+
assertIsSecureUrl(avatarUrl);
464+
assertTrue(avatarUrl, avatarUrl.contains("yt3"));
465+
}
466+
467+
@Test
468+
public void testBannerUrl() throws Exception {
469+
String bannerUrl = extractor.getBannerUrl();
470+
assertIsSecureUrl(bannerUrl);
471+
assertTrue(bannerUrl, bannerUrl.contains("yt3"));
472+
}
473+
474+
@Test
475+
public void testFeedUrl() throws Exception {
476+
assertEquals("https://www.youtube.com/feeds/videos.xml?channel_id=UC20vb-R_px4CguHzzBPhoyQ", extractor.getFeedUrl());
477+
}
478+
479+
@Test
480+
public void testSubscriberCount() throws Exception {
481+
// there is no "Subscribe" button
482+
long subscribers = extractor.getSubscriberCount();
483+
assertEquals("Wrong subscriber count", -1, subscribers);
484+
}
485+
}
486+
487+
488+
395489
public static class RandomChannel implements BaseChannelExtractorTest {
396490
private static YoutubeChannelExtractor extractor;
397491

@@ -483,8 +577,9 @@ public void testFeedUrl() throws Exception {
483577

484578
@Test
485579
public void testSubscriberCount() throws Exception {
486-
assertTrue("Wrong subscriber count", extractor.getSubscriberCount() >= 50);
580+
long subscribers = extractor.getSubscriberCount();
581+
assertTrue("Wrong subscriber count: " + subscribers, subscribers >= 50);
487582
}
488583
}
489-
};
584+
}
490585

0 commit comments

Comments
 (0)