Skip to content

Commit d4186d1

Browse files
authored
Merge pull request #580 from TeamNewPipe/accountTerminated
Add AccountTerminatedException for terminated channels
2 parents 89e0514 + fa444c8 commit d4186d1

16 files changed

Lines changed: 715 additions & 27 deletions

File tree

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package org.schabi.newpipe.extractor.exceptions;
2+
3+
public class AccountTerminatedException extends ContentNotAvailableException {
4+
5+
private Reason reason = Reason.UNKNOWN;
6+
7+
public AccountTerminatedException(final String message) {
8+
super(message);
9+
}
10+
11+
public AccountTerminatedException(final String message, final Reason reason) {
12+
super(message);
13+
this.reason = reason;
14+
}
15+
16+
public AccountTerminatedException(final String message, final Throwable cause) {
17+
super(message, cause);
18+
}
19+
20+
/**
21+
* The reason for the violation. There should also be more info in the exception's message.
22+
*/
23+
public Reason getReason() {
24+
return reason;
25+
}
26+
27+
public enum Reason {
28+
UNKNOWN,
29+
VIOLATION
30+
}
31+
}

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@
1010
import org.schabi.newpipe.extractor.MetaInfo;
1111
import org.schabi.newpipe.extractor.Page;
1212
import org.schabi.newpipe.extractor.downloader.Response;
13-
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
14-
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
15-
import org.schabi.newpipe.extractor.exceptions.ParsingException;
16-
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
13+
import org.schabi.newpipe.extractor.exceptions.*;
1714
import org.schabi.newpipe.extractor.localization.Localization;
1815
import org.schabi.newpipe.extractor.stream.Description;
1916
import org.schabi.newpipe.extractor.utils.JsonUtils;
@@ -762,6 +759,23 @@ public static void defaultAlertsCheck(final JsonObject initialData) throws Parsi
762759
final String alertText = getTextFromObject(alertRenderer.getObject("text"));
763760
final String alertType = alertRenderer.getString("type", EMPTY_STRING);
764761
if (alertType.equalsIgnoreCase("ERROR")) {
762+
if (alertText != null && alertText.contains("This account has been terminated")) {
763+
if (alertText.contains("violation") || alertText.contains("violating")
764+
|| alertText.contains("infringement")) {
765+
// possible error messages:
766+
// "This account has been terminated for a violation of YouTube's Terms of Service."
767+
// "This account has been terminated due to multiple or severe violations of YouTube's policy prohibiting hate speech."
768+
// "This account has been terminated due to multiple or severe violations of YouTube's policy prohibiting content designed to harass, bully or threaten."
769+
// "This account has been terminated due to multiple or severe violations of YouTube's policy against spam, deceptive practices and misleading content or other Terms of Service violations."
770+
// "This account has been terminated due to multiple or severe violations of YouTube's policy on nudity or sexual content."
771+
// "This account has been terminated for violating YouTube's Community Guidelines."
772+
// "This account has been terminated because we received multiple third-party claims of copyright infringement regarding material that the user posted."
773+
// "This account has been terminated because it is linked to an account that received multiple third-party claims of copyright infringement."
774+
throw new AccountTerminatedException(alertText, AccountTerminatedException.Reason.VIOLATION);
775+
} else {
776+
throw new AccountTerminatedException(alertText);
777+
}
778+
}
765779
throw new ContentNotAvailableException("Got error: \"" + alertText + "\"");
766780
}
767781
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.schabi.newpipe.extractor.StreamingService;
1010
import org.schabi.newpipe.extractor.downloader.Downloader;
1111
import org.schabi.newpipe.extractor.downloader.Response;
12+
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
1213
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
1314
import org.schabi.newpipe.extractor.feed.FeedExtractor;
1415
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
@@ -33,6 +34,9 @@ public void onFetchPage(@Nonnull Downloader downloader) throws IOException, Extr
3334
final String feedUrl = YoutubeParsingHelper.getFeedUrlFrom(channelIdOrUser);
3435

3536
final Response response = downloader.get(feedUrl);
37+
if (response.responseCode() == 404) {
38+
throw new ContentNotAvailableException("Could not get feed: 404 - not found");
39+
}
3640
document = Jsoup.parse(response.responseBody());
3741
}
3842

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

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.schabi.newpipe.downloader.DownloaderTestImpl;
77
import org.schabi.newpipe.extractor.NewPipe;
88
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
9+
import org.schabi.newpipe.extractor.exceptions.AccountTerminatedException;
910
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
1011
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
1112
import org.schabi.newpipe.extractor.exceptions.ParsingException;
@@ -50,6 +51,90 @@ public void nonExistentFetch() throws Exception {
5051
YouTube.getChannelExtractor("https://www.youtube.com/channel/DOESNT-EXIST");
5152
extractor.fetchPage();
5253
}
54+
55+
@Test(expected = AccountTerminatedException.class)
56+
public void accountTerminatedTOSFetch() throws Exception {
57+
// "This account has been terminated for a violation of YouTube's Terms of Service."
58+
final ChannelExtractor extractor =
59+
YouTube.getChannelExtractor("https://www.youtube.com/channel/UCTGjY2I-ZUGnwVoWAGRd7XQ");
60+
try {
61+
extractor.fetchPage();
62+
} catch (AccountTerminatedException e) {
63+
assertEquals(e.getReason(), AccountTerminatedException.Reason.VIOLATION);
64+
throw e;
65+
}
66+
}
67+
68+
@Test(expected = AccountTerminatedException.class)
69+
public void accountTerminatedCommunityFetch() throws Exception {
70+
// "This account has been terminated for violating YouTube's Community Guidelines."
71+
final ChannelExtractor extractor =
72+
YouTube.getChannelExtractor("https://www.youtube.com/channel/UC0AuOxCr9TZ0TtEgL1zpIgA");
73+
try {
74+
extractor.fetchPage();
75+
} catch (AccountTerminatedException e) {
76+
assertEquals(e.getReason(), AccountTerminatedException.Reason.VIOLATION);
77+
throw e;
78+
}
79+
}
80+
81+
@Test(expected = AccountTerminatedException.class)
82+
public void accountTerminatedHateFetch() throws Exception {
83+
// "This account has been terminated due to multiple or severe violations
84+
// of YouTube's policy prohibiting hate speech."
85+
final ChannelExtractor extractor =
86+
YouTube.getChannelExtractor("https://www.youtube.com/channel/UCPWXIOPK-9myzek6jHR5yrg");
87+
try {
88+
extractor.fetchPage();
89+
} catch (AccountTerminatedException e) {
90+
assertEquals(e.getReason(), AccountTerminatedException.Reason.VIOLATION);
91+
throw e;
92+
}
93+
}
94+
95+
@Test(expected = AccountTerminatedException.class)
96+
public void accountTerminatedBullyFetch() throws Exception {
97+
// "This account has been terminated due to multiple or severe violations
98+
// of YouTube's policy prohibiting content designed to harass, bully or threaten."
99+
final ChannelExtractor extractor =
100+
YouTube.getChannelExtractor("https://youtube.com/channel/UCB1o7_gbFp2PLsamWxFenBg");
101+
try {
102+
extractor.fetchPage();
103+
} catch (AccountTerminatedException e) {
104+
assertEquals(e.getReason(), AccountTerminatedException.Reason.VIOLATION);
105+
throw e;
106+
}
107+
}
108+
109+
@Test(expected = AccountTerminatedException.class)
110+
public void accountTerminatedSpamFetch() throws Exception {
111+
// "This account has been terminated due to multiple or severe violations
112+
// of YouTube's policy against spam, deceptive practices and misleading content
113+
// or other Terms of Service violations."
114+
final ChannelExtractor extractor =
115+
YouTube.getChannelExtractor("https://www.youtube.com/channel/UCoaO4U_p7G7AwalqSbGCZOA");
116+
try {
117+
extractor.fetchPage();
118+
} catch (AccountTerminatedException e) {
119+
assertEquals(e.getReason(), AccountTerminatedException.Reason.VIOLATION);
120+
throw e;
121+
}
122+
}
123+
124+
@Test(expected = AccountTerminatedException.class)
125+
public void accountTerminatedCopyrightFetch() throws Exception {
126+
// "This account has been terminated because we received multiple third-party claims
127+
// of copyright infringement regarding material that the user posted."
128+
final ChannelExtractor extractor =
129+
YouTube.getChannelExtractor("https://www.youtube.com/channel/UCpExuV8qJMfCaSQNL1YG6bQ");
130+
try {
131+
extractor.fetchPage();
132+
} catch (AccountTerminatedException e) {
133+
assertEquals(e.getReason(), AccountTerminatedException.Reason.VIOLATION);
134+
throw e;
135+
}
136+
}
137+
53138
}
54139

55140
public static class NotSupported {

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
import org.junit.Test;
55
import org.schabi.newpipe.downloader.DownloaderFactory;
66
import org.schabi.newpipe.extractor.NewPipe;
7+
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
78
import org.schabi.newpipe.extractor.exceptions.ParsingException;
89
import org.schabi.newpipe.extractor.services.BaseListExtractorTest;
910
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeFeedExtractor;
1011

12+
import java.io.IOException;
1113
import java.util.Random;
1214

1315
import static org.junit.Assert.assertEquals;
@@ -77,4 +79,20 @@ public void testMoreRelatedItems() throws Exception {
7779
assertNoMoreItems(extractor);
7880
}
7981
}
82+
83+
public static class NotAvailable {
84+
85+
@BeforeClass
86+
public static void setUp() throws IOException {
87+
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "notAvailable/"));
88+
}
89+
90+
@Test(expected = ContentNotAvailableException.class)
91+
public void AccountTerminatedFetch() throws Exception {
92+
YoutubeFeedExtractor extractor = (YoutubeFeedExtractor) YouTube
93+
.getFeedExtractor("https://www.youtube.com/channel/UCTGjY2I-ZUGnwVoWAGRd7XQ");
94+
extractor.fetchPage();
95+
}
96+
97+
}
8098
}

extractor/src/test/resources/org/schabi/newpipe/extractor/services/youtube/extractor/channel/notAvailable/generated_mock_0.json

Lines changed: 7 additions & 4 deletions
Large diffs are not rendered by default.

extractor/src/test/resources/org/schabi/newpipe/extractor/services/youtube/extractor/channel/notAvailable/generated_mock_1.json

Lines changed: 9 additions & 6 deletions
Large diffs are not rendered by default.

extractor/src/test/resources/org/schabi/newpipe/extractor/services/youtube/extractor/channel/notAvailable/generated_mock_2.json

Lines changed: 17 additions & 7 deletions
Large diffs are not rendered by default.

extractor/src/test/resources/org/schabi/newpipe/extractor/services/youtube/extractor/channel/notAvailable/generated_mock_3.json

Lines changed: 81 additions & 0 deletions
Large diffs are not rendered by default.

extractor/src/test/resources/org/schabi/newpipe/extractor/services/youtube/extractor/channel/notAvailable/generated_mock_4.json

Lines changed: 81 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)