Skip to content

Commit 0e4e6a9

Browse files
authored
Merge pull request #1022 from AudricV/yt_support-live-urls
[YouTube] Support live URLs
2 parents c589a2c + ba24976 commit 0e4e6a9

2 files changed

Lines changed: 72 additions & 67 deletions

File tree

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/linkHandler/YoutubeStreamLinkHandlerFactory.java

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
/*
2+
* Created by Christian Schabesberger on 02.02.16.
3+
*
4+
* Copyright (C) Christian Schabesberger 2018 <chris.schabesberger@mailbox.org>
5+
* YoutubeStreamLinkHandlerFactory.java is part of NewPipe Extractor.
6+
*
7+
* NewPipe Extractor is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* NewPipe Extractor is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with NewPipe Extractor. If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
121
package org.schabi.newpipe.extractor.services.youtube.linkHandler;
222

323
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isHooktubeURL;
@@ -15,41 +35,21 @@
1535
import java.net.URI;
1636
import java.net.URISyntaxException;
1737
import java.net.URL;
18-
import java.util.Arrays;
1938
import java.util.List;
2039
import java.util.regex.Matcher;
2140
import java.util.regex.Pattern;
2241

42+
import javax.annotation.Nonnull;
2343
import javax.annotation.Nullable;
2444

25-
/*
26-
* Created by Christian Schabesberger on 02.02.16.
27-
*
28-
* Copyright (C) Christian Schabesberger 2018 <chris.schabesberger@mailbox.org>
29-
* YoutubeStreamLinkHandlerFactory.java is part of NewPipe.
30-
*
31-
* NewPipe is free software: you can redistribute it and/or modify
32-
* it under the terms of the GNU General Public License as published by
33-
* the Free Software Foundation, either version 3 of the License, or
34-
* (at your option) any later version.
35-
*
36-
* NewPipe is distributed in the hope that it will be useful,
37-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
38-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39-
* GNU General Public License for more details.
40-
*
41-
* You should have received a copy of the GNU General Public License
42-
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
43-
*/
44-
4545
public final class YoutubeStreamLinkHandlerFactory extends LinkHandlerFactory {
4646

4747
private static final Pattern YOUTUBE_VIDEO_ID_REGEX_PATTERN
4848
= Pattern.compile("^([a-zA-Z0-9_-]{11})");
4949
private static final YoutubeStreamLinkHandlerFactory INSTANCE
5050
= new YoutubeStreamLinkHandlerFactory();
5151
private static final List<String> SUBPATHS
52-
= Arrays.asList("embed/", "shorts/", "watch/", "v/", "w/");
52+
= List.of("embed/", "live/", "shorts/", "watch/", "v/", "w/");
5353

5454
private YoutubeStreamLinkHandlerFactory() {
5555
}
@@ -67,21 +67,24 @@ private static String extractId(@Nullable final String id) {
6767
return null;
6868
}
6969

70+
@Nonnull
7071
private static String assertIsId(@Nullable final String id) throws ParsingException {
7172
final String extractedId = extractId(id);
7273
if (extractedId != null) {
7374
return extractedId;
7475
} else {
75-
throw new ParsingException("The given string is not a Youtube-Video-ID");
76+
throw new ParsingException("The given string is not a YouTube video ID");
7677
}
7778
}
7879

80+
@Nonnull
7981
@Override
8082
public String getUrl(final String id) {
8183
return "https://www.youtube.com/watch?v=" + id;
8284
}
8385

8486
@SuppressWarnings("AvoidNestedBlocks")
87+
@Nonnull
8588
@Override
8689
public String getId(final String theUrlString)
8790
throws ParsingException, IllegalArgumentException {
@@ -124,14 +127,14 @@ public String getId(final String theUrlString)
124127
if (!Utils.isHTTP(url) || !(isYoutubeURL(url) || isYoutubeServiceURL(url)
125128
|| isHooktubeURL(url) || isInvidiousURL(url) || isY2ubeURL(url))) {
126129
if (host.equalsIgnoreCase("googleads.g.doubleclick.net")) {
127-
throw new FoundAdException("Error found ad: " + urlString);
130+
throw new FoundAdException("Error: found ad: " + urlString);
128131
}
129132

130-
throw new ParsingException("The url is not a Youtube-URL");
133+
throw new ParsingException("The URL is not a YouTube URL");
131134
}
132135

133136
if (YoutubePlaylistLinkHandlerFactory.getInstance().acceptUrl(urlString)) {
134-
throw new ParsingException("Error no suitable url: " + urlString);
137+
throw new ParsingException("Error: no suitable URL: " + urlString);
135138
}
136139

137140
// Using uppercase instead of lowercase, because toLowercase replaces some unicode
@@ -154,9 +157,9 @@ public String getId(final String theUrlString)
154157

155158
final URL decodedURL;
156159
try {
157-
decodedURL = Utils.stringToURL("http://www.youtube.com" + uQueryValue);
160+
decodedURL = Utils.stringToURL("https://www.youtube.com" + uQueryValue);
158161
} catch (final MalformedURLException e) {
159-
throw new ParsingException("Error no suitable url: " + urlString);
162+
throw new ParsingException("Error: no suitable URL: " + urlString);
160163
}
161164

162165
final String viewQueryValue = Utils.getQueryValue(decodedURL, "v");
@@ -231,7 +234,7 @@ public String getId(final String theUrlString)
231234
}
232235
}
233236

234-
throw new ParsingException("Error no suitable url: " + urlString);
237+
throw new ParsingException("Error: no suitable URL: " + urlString);
235238
}
236239

237240
@Override
@@ -246,7 +249,8 @@ public boolean onAcceptUrl(final String url) throws FoundAdException {
246249
}
247250
}
248251

249-
private String getIdFromSubpathsInPath(final String path) throws ParsingException {
252+
@Nullable
253+
private String getIdFromSubpathsInPath(@Nonnull final String path) throws ParsingException {
250254
for (final String subpath : SUBPATHS) {
251255
if (path.startsWith(subpath)) {
252256
final String id = path.substring(subpath.length());

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

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@
1111
import org.schabi.newpipe.extractor.exceptions.ParsingException;
1212
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory;
1313

14-
import java.util.ArrayList;
15-
import java.util.List;
16-
17-
import static org.junit.jupiter.api.Assertions.*;
14+
import static org.junit.jupiter.api.Assertions.assertEquals;
15+
import static org.junit.jupiter.api.Assertions.assertThrows;
16+
import static org.junit.jupiter.api.Assertions.assertTrue;
1817

1918
/**
2019
* Test for {@link YoutubeStreamLinkHandlerFactory}
2120
*/
21+
@SuppressWarnings("HttpUrlsUsage")
2222
public class YoutubeStreamLinkHandlerFactoryTest {
2323
private static YoutubeStreamLinkHandlerFactory linkHandler;
2424

@@ -53,25 +53,25 @@ void getIdForInvalidUrls(final String invalidUrl) {
5353

5454
@ParameterizedTest
5555
@ValueSource(strings = {
56-
"https://www.youtube.com/watch?v=jZViOEv90dI",
57-
"https://www.youtube.com/watch?v=jZViOEv90dI&t=100",
58-
"https://WWW.YouTube.com/watch?v=jZViOEv90dI&t=100",
59-
"HTTPS://www.youtube.com/watch?v=jZViOEv90dI&t=100",
60-
"https://youtu.be/jZViOEv90dI?t=9s",
61-
"HTTPS://Youtu.be/jZViOEv90dI?t=9s",
62-
"https://www.youtube.com/embed/jZViOEv90dI",
63-
"https://www.youtube-nocookie.com/embed/jZViOEv90dI",
64-
"http://www.youtube.com/watch?v=jZViOEv90dI",
65-
"http://youtube.com/watch?v=jZViOEv90dI",
66-
"http://youtu.be/jZViOEv90dI?t=9s",
67-
"http://www.youtube.com/embed/jZViOEv90dI",
68-
"http://www.Youtube.com/embed/jZViOEv90dI",
69-
"http://www.youtube-nocookie.com/embed/jZViOEv90dI",
70-
"vnd.youtube://www.youtube.com/watch?v=jZViOEv90dI",
71-
"vnd.youtube:jZViOEv90dI"
56+
"https://www.youtube.com/watch?v=9Dpqou5cI08",
57+
"https://www.youtube.com/watch?v=9Dpqou5cI08&t=100",
58+
"https://WWW.YouTube.com/watch?v=9Dpqou5cI08&t=100",
59+
"HTTPS://www.youtube.com/watch?v=9Dpqou5cI08&t=100",
60+
"https://youtu.be/9Dpqou5cI08?t=9s",
61+
"HTTPS://Youtu.be/9Dpqou5cI08?t=9s",
62+
"https://www.youtube.com/embed/9Dpqou5cI08",
63+
"https://www.youtube-nocookie.com/embed/9Dpqou5cI08",
64+
"http://www.youtube.com/watch?v=9Dpqou5cI08",
65+
"http://youtube.com/watch?v=9Dpqou5cI08",
66+
"http://youtu.be/9Dpqou5cI08?t=9s",
67+
"http://www.youtube.com/embed/9Dpqou5cI08",
68+
"http://www.Youtube.com/embed/9Dpqou5cI08",
69+
"http://www.youtube-nocookie.com/embed/9Dpqou5cI08",
70+
"vnd.youtube://www.youtube.com/watch?v=9Dpqou5cI08",
71+
"vnd.youtube:9Dpqou5cI08"
7272
})
73-
void getId_jZViOEv90dI_fromYt(final String url) throws Exception {
74-
assertEquals("jZViOEv90dI", linkHandler.fromUrl(url).getId());
73+
void getId_9Dpqou5cI08_fromYt(final String url) throws Exception {
74+
assertEquals("9Dpqou5cI08", linkHandler.fromUrl(url).getId());
7575
}
7676

7777
@ParameterizedTest
@@ -117,27 +117,28 @@ void getId_diverse_fromYt(final String expectedId, final String url) throws Exce
117117

118118
@ParameterizedTest
119119
@ValueSource(strings = {
120-
"https://www.youtube.com/watch?v=jZViOEv90dI",
121-
"https://www.youtube.com/watch?v=jZViOEv90dI&t=100",
122-
"https://WWW.YouTube.com/watch?v=jZViOEv90dI&t=100",
123-
"HTTPS://www.youtube.com/watch?v=jZViOEv90dI&t=100",
124-
"https://youtu.be/jZViOEv90dI?t=9s",
125-
"https://www.youtube.com/embed/jZViOEv90dI",
126-
"https://www.youtube-nocookie.com/embed/jZViOEv90dI",
127-
"http://www.youtube.com/watch?v=jZViOEv90dI",
128-
"http://youtu.be/jZViOEv90dI?t=9s",
129-
"http://www.youtube.com/embed/jZViOEv90dI",
130-
"http://www.youtube-nocookie.com/embed/jZViOEv90dI",
120+
"https://www.youtube.com/watch?v=9Dpqou5cI08",
121+
"https://www.youtube.com/watch?v=9Dpqou5cI08&t=100",
122+
"https://WWW.YouTube.com/watch?v=9Dpqou5cI08&t=100",
123+
"HTTPS://www.youtube.com/watch?v=9Dpqou5cI08&t=100",
124+
"https://youtu.be/9Dpqou5cI08?t=9s",
125+
"https://www.youtube.com/embed/9Dpqou5cI08",
126+
"https://www.youtube-nocookie.com/embed/9Dpqou5cI08",
127+
"http://www.youtube.com/watch?v=9Dpqou5cI08",
128+
"http://youtu.be/9Dpqou5cI08?t=9s",
129+
"http://www.youtube.com/embed/9Dpqou5cI08",
130+
"http://www.youtube-nocookie.com/embed/9Dpqou5cI08",
131131
"http://www.youtube.com/attribution_link?a=JdfC0C9V6ZI&u=%2Fwatch%3Fv%3DEhxJLojIE_o%26feature%3Dshare",
132-
"vnd.youtube://www.youtube.com/watch?v=jZViOEv90dI",
133-
"vnd.youtube:jZViOEv90dI",
134-
"vnd.youtube.launch:jZViOEv90dI",
132+
"vnd.youtube://www.youtube.com/watch?v=9Dpqou5cI08",
133+
"vnd.youtube:9Dpqou5cI08",
134+
"vnd.youtube.launch:9Dpqou5cI08",
135135
"https://music.youtube.com/watch?v=O0EDx9WAelc",
136136
"https://www.youtube.com/shorts/IOS2fqxwYbA",
137137
"http://www.youtube.com/shorts/IOS2fqxwYbA",
138138
"http://www.youtube.com/v/IOS2fqxwYbA",
139139
"https://www.youtube.com/w/IOS2fqxwYbA",
140-
"https://www.youtube.com/watch/IOS2fqxwYbA"
140+
"https://www.youtube.com/watch/IOS2fqxwYbA",
141+
"https://www.youtube.com/live/rUxyKA_-grg"
141142
})
142143
void acceptYtUrl(final String url) throws ParsingException {
143144
assertTrue(linkHandler.acceptUrl(url));

0 commit comments

Comments
 (0)