Merge branch 'dev' into bandcamp
This commit is contained in:
commit
e062c8cb0d
|
@ -1,6 +1,9 @@
|
||||||
name: CI
|
name: CI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
schedule:
|
||||||
|
# once per day
|
||||||
|
- cron: 0 0 * * *
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- dev
|
- dev
|
||||||
|
@ -25,5 +28,11 @@ jobs:
|
||||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
|
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
|
||||||
restore-keys: ${{ runner.os }}-gradle
|
restore-keys: ${{ runner.os }}-gradle
|
||||||
|
|
||||||
|
# See gradle file for difference between downloaders
|
||||||
- name: Build and run Tests
|
- name: Build and run Tests
|
||||||
run: ./gradlew check --stacktrace -Ddownloader=MOCK
|
run: |
|
||||||
|
if [[ $GITHUB_EVENT_NAME == 'schedule' ]]; then
|
||||||
|
./gradlew check --stacktrace -Ddownloader=REAL
|
||||||
|
else
|
||||||
|
./gradlew check --stacktrace -Ddownloader=MOCK
|
||||||
|
fi
|
||||||
|
|
|
@ -11,7 +11,7 @@ NewPipe Extractor is available at JitPack's Maven repo.
|
||||||
If you're using Gradle, you could add NewPipe Extractor as a dependency with the following steps:
|
If you're using Gradle, you could add NewPipe Extractor as a dependency with the following steps:
|
||||||
|
|
||||||
1. Add `maven { url 'https://jitpack.io' }` to the `repositories` in your `build.gradle`.
|
1. Add `maven { url 'https://jitpack.io' }` to the `repositories` in your `build.gradle`.
|
||||||
2. Add `implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.20.8'`the `dependencies` in your `build.gradle`. Replace `v0.20.8` with the latest release.
|
2. Add `implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.20.10'`the `dependencies` in your `build.gradle`. Replace `v0.20.10` with the latest release.
|
||||||
|
|
||||||
**Note:** To use NewPipe Extractor in projects with a `minSdkVersion` below 26, [API desugaring](https://developer.android.com/studio/write/java8-support#library-desugaring) is required.
|
**Note:** To use NewPipe Extractor in projects with a `minSdkVersion` below 26, [API desugaring](https://developer.android.com/studio/write/java8-support#library-desugaring) is required.
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ allprojects {
|
||||||
sourceCompatibility = 1.8
|
sourceCompatibility = 1.8
|
||||||
targetCompatibility = 1.8
|
targetCompatibility = 1.8
|
||||||
|
|
||||||
version 'v0.20.8'
|
version 'v0.20.10'
|
||||||
group 'com.github.TeamNewPipe'
|
group 'com.github.TeamNewPipe'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
|
|
@ -15,6 +15,6 @@ dependencies {
|
||||||
implementation 'org.nibor.autolink:autolink:0.10.0'
|
implementation 'org.nibor.autolink:autolink:0.10.0'
|
||||||
|
|
||||||
testImplementation 'junit:junit:4.13.1'
|
testImplementation 'junit:junit:4.13.1'
|
||||||
testImplementation "com.squareup.okhttp3:okhttp:3.12.11"
|
testImplementation "com.squareup.okhttp3:okhttp:3.12.13"
|
||||||
testImplementation 'com.google.code.gson:gson:2.8.6'
|
testImplementation 'com.google.code.gson:gson:2.8.6'
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ public class CommentsInfo extends ListInfo<CommentsInfoItem> {
|
||||||
return getInfo(serviceByUrl.getCommentsExtractor(url));
|
return getInfo(serviceByUrl.getCommentsExtractor(url));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CommentsInfo getInfo(CommentsExtractor commentsExtractor) throws IOException, ExtractionException {
|
public static CommentsInfo getInfo(CommentsExtractor commentsExtractor) throws IOException, ExtractionException {
|
||||||
// for services which do not have a comments extractor
|
// for services which do not have a comments extractor
|
||||||
if (null == commentsExtractor) {
|
if (null == commentsExtractor) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -17,6 +17,7 @@ public class CommentsInfoItem extends InfoItem {
|
||||||
private DateWrapper uploadDate;
|
private DateWrapper uploadDate;
|
||||||
private int likeCount;
|
private int likeCount;
|
||||||
private boolean heartedByUploader;
|
private boolean heartedByUploader;
|
||||||
|
private boolean pinned;
|
||||||
|
|
||||||
public CommentsInfoItem(int serviceId, String url, String name) {
|
public CommentsInfoItem(int serviceId, String url, String name) {
|
||||||
super(InfoType.COMMENT, serviceId, url, name);
|
super(InfoType.COMMENT, serviceId, url, name);
|
||||||
|
@ -91,7 +92,15 @@ public class CommentsInfoItem extends InfoItem {
|
||||||
this.heartedByUploader = isHeartedByUploader;
|
this.heartedByUploader = isHeartedByUploader;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getHeartedByUploader() {
|
public boolean isHeartedByUploader() {
|
||||||
return this.heartedByUploader;
|
return this.heartedByUploader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isPinned() {
|
||||||
|
return pinned;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPinned(boolean pinned) {
|
||||||
|
this.pinned = pinned;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ public interface CommentsInfoItemExtractor extends InfoItemExtractor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the like count of the comment, or -1 if it's unavailable
|
* Return the like count of the comment, or -1 if it's unavailable
|
||||||
|
*
|
||||||
* @see StreamExtractor#getLikeCount()
|
* @see StreamExtractor#getLikeCount()
|
||||||
*/
|
*/
|
||||||
int getLikeCount() throws ParsingException;
|
int getLikeCount() throws ParsingException;
|
||||||
|
@ -22,12 +23,14 @@ public interface CommentsInfoItemExtractor extends InfoItemExtractor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The upload date given by the service, unmodified
|
* The upload date given by the service, unmodified
|
||||||
|
*
|
||||||
* @see StreamExtractor#getTextualUploadDate()
|
* @see StreamExtractor#getTextualUploadDate()
|
||||||
*/
|
*/
|
||||||
String getTextualUploadDate() throws ParsingException;
|
String getTextualUploadDate() throws ParsingException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The upload date wrapped with DateWrapper class
|
* The upload date wrapped with DateWrapper class
|
||||||
|
*
|
||||||
* @see StreamExtractor#getUploadDate()
|
* @see StreamExtractor#getUploadDate()
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -44,5 +47,10 @@ public interface CommentsInfoItemExtractor extends InfoItemExtractor {
|
||||||
/**
|
/**
|
||||||
* Whether the comment has been hearted by the uploader
|
* Whether the comment has been hearted by the uploader
|
||||||
*/
|
*/
|
||||||
boolean getHeartedByUploader() throws ParsingException;
|
boolean isHeartedByUploader() throws ParsingException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the comment is pinned
|
||||||
|
*/
|
||||||
|
boolean isPinned() throws ParsingException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,13 @@ public class CommentsInfoItemsCollector extends InfoItemsCollector<CommentsInfoI
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
resultItem.setHeartedByUploader(extractor.getHeartedByUploader());
|
resultItem.setHeartedByUploader(extractor.isHeartedByUploader());
|
||||||
|
} catch (Exception e) {
|
||||||
|
addError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
resultItem.setPinned(extractor.isPinned());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
addError(e);
|
addError(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||||
|
|
||||||
public class KioskList {
|
public class KioskList {
|
||||||
|
|
||||||
public interface KioskExtractorFactory {
|
public interface KioskExtractorFactory {
|
||||||
|
@ -70,7 +72,7 @@ public class KioskList {
|
||||||
|
|
||||||
public KioskExtractor getDefaultKioskExtractor(Page nextPage, Localization localization)
|
public KioskExtractor getDefaultKioskExtractor(Page nextPage, Localization localization)
|
||||||
throws ExtractionException, IOException {
|
throws ExtractionException, IOException {
|
||||||
if (defaultKiosk != null && !defaultKiosk.equals("")) {
|
if (!isNullOrEmpty(defaultKiosk)) {
|
||||||
return getExtractorById(defaultKiosk, nextPage, localization);
|
return getExtractorById(defaultKiosk, nextPage, localization);
|
||||||
} else {
|
} else {
|
||||||
if (!kioskList.isEmpty()) {
|
if (!kioskList.isEmpty()) {
|
||||||
|
|
|
@ -50,6 +50,9 @@ public abstract class LinkHandlerFactory {
|
||||||
* @return a {@link LinkHandler} complete with information
|
* @return a {@link LinkHandler} complete with information
|
||||||
*/
|
*/
|
||||||
public LinkHandler fromUrl(final String url) throws ParsingException {
|
public LinkHandler fromUrl(final String url) throws ParsingException {
|
||||||
|
if (Utils.isNullOrEmpty(url)) {
|
||||||
|
throw new IllegalArgumentException("The url is null or empty");
|
||||||
|
}
|
||||||
final String polishedUrl = Utils.followGoogleRedirectIfNeeded(url);
|
final String polishedUrl = Utils.followGoogleRedirectIfNeeded(url);
|
||||||
final String baseUrl = Utils.getBaseUrl(polishedUrl);
|
final String baseUrl = Utils.getBaseUrl(polishedUrl);
|
||||||
return fromUrl(polishedUrl, baseUrl);
|
return fromUrl(polishedUrl, baseUrl);
|
||||||
|
|
|
@ -5,6 +5,8 @@ import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
||||||
|
|
||||||
public abstract class SearchQueryHandlerFactory extends ListLinkHandlerFactory {
|
public abstract class SearchQueryHandlerFactory extends ListLinkHandlerFactory {
|
||||||
|
|
||||||
///////////////////////////////////
|
///////////////////////////////////
|
||||||
|
@ -12,7 +14,7 @@ public abstract class SearchQueryHandlerFactory extends ListLinkHandlerFactory {
|
||||||
///////////////////////////////////
|
///////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract String getUrl(String querry, List<String> contentFilter, String sortFilter) throws ParsingException;
|
public abstract String getUrl(String query, List<String> contentFilter, String sortFilter) throws ParsingException;
|
||||||
|
|
||||||
public String getSearchString(String url) {
|
public String getSearchString(String url) {
|
||||||
return "";
|
return "";
|
||||||
|
@ -28,14 +30,14 @@ public abstract class SearchQueryHandlerFactory extends ListLinkHandlerFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SearchQueryHandler fromQuery(String querry,
|
public SearchQueryHandler fromQuery(String query,
|
||||||
List<String> contentFilter,
|
List<String> contentFilter,
|
||||||
String sortFilter) throws ParsingException {
|
String sortFilter) throws ParsingException {
|
||||||
return new SearchQueryHandler(super.fromQuery(querry, contentFilter, sortFilter));
|
return new SearchQueryHandler(super.fromQuery(query, contentFilter, sortFilter));
|
||||||
}
|
}
|
||||||
|
|
||||||
public SearchQueryHandler fromQuery(String querry) throws ParsingException {
|
public SearchQueryHandler fromQuery(String query) throws ParsingException {
|
||||||
return fromQuery(querry, new ArrayList<String>(0), "");
|
return fromQuery(query, new ArrayList<String>(0), EMPTY_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,6 +7,8 @@ import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.UTF_8;
|
||||||
|
|
||||||
public class MediaCCCSearchQueryHandlerFactory extends SearchQueryHandlerFactory {
|
public class MediaCCCSearchQueryHandlerFactory extends SearchQueryHandlerFactory {
|
||||||
public static final String ALL = "all";
|
public static final String ALL = "all";
|
||||||
public static final String CONFERENCES = "conferences";
|
public static final String CONFERENCES = "conferences";
|
||||||
|
@ -31,7 +33,7 @@ public class MediaCCCSearchQueryHandlerFactory extends SearchQueryHandlerFactory
|
||||||
final String sortFilter) throws ParsingException {
|
final String sortFilter) throws ParsingException {
|
||||||
try {
|
try {
|
||||||
return "https://media.ccc.de/public/events/search?q="
|
return "https://media.ccc.de/public/events/search?q="
|
||||||
+ URLEncoder.encode(query, "UTF-8");
|
+ URLEncoder.encode(query, UTF_8);
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
throw new ParsingException("Could not create search string with query: " + query, e);
|
throw new ParsingException("Could not create search string with query: " + query, e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.extractor.services.peertube.extractors;
|
package org.schabi.newpipe.extractor.services.peertube.extractors;
|
||||||
|
|
||||||
import com.grack.nanojson.JsonObject;
|
import com.grack.nanojson.JsonObject;
|
||||||
|
|
||||||
import org.jsoup.Jsoup;
|
import org.jsoup.Jsoup;
|
||||||
import org.jsoup.nodes.Document;
|
import org.jsoup.nodes.Document;
|
||||||
import org.schabi.newpipe.extractor.ServiceList;
|
import org.schabi.newpipe.extractor.ServiceList;
|
||||||
|
@ -13,6 +12,8 @@ import org.schabi.newpipe.extractor.utils.JsonUtils;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
||||||
|
|
||||||
public class PeertubeCommentsInfoItemExtractor implements CommentsInfoItemExtractor {
|
public class PeertubeCommentsInfoItemExtractor implements CommentsInfoItemExtractor {
|
||||||
private final JsonObject item;
|
private final JsonObject item;
|
||||||
private final String url;
|
private final String url;
|
||||||
|
@ -68,7 +69,7 @@ public class PeertubeCommentsInfoItemExtractor implements CommentsInfoItemExtrac
|
||||||
final Document doc = Jsoup.parse(htmlText);
|
final Document doc = Jsoup.parse(htmlText);
|
||||||
return doc.body().text();
|
return doc.body().text();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return htmlText.replaceAll("(?s)<[^>]*>(\\s*<[^>]*>)*", "");
|
return htmlText.replaceAll("(?s)<[^>]*>(\\s*<[^>]*>)*", EMPTY_STRING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +90,12 @@ public class PeertubeCommentsInfoItemExtractor implements CommentsInfoItemExtrac
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getHeartedByUploader() throws ParsingException {
|
public boolean isHeartedByUploader() throws ParsingException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPinned() throws ParsingException {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,15 +18,7 @@ import org.schabi.newpipe.extractor.localization.DateWrapper;
|
||||||
import org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper;
|
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.PeertubeSearchQueryHandlerFactory;
|
||||||
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeStreamLinkHandlerFactory;
|
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeStreamLinkHandlerFactory;
|
||||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
import org.schabi.newpipe.extractor.stream.*;
|
||||||
import org.schabi.newpipe.extractor.stream.Description;
|
|
||||||
import org.schabi.newpipe.extractor.stream.Stream;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamSegment;
|
|
||||||
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.utils.JsonUtils;
|
import org.schabi.newpipe.extractor.utils.JsonUtils;
|
||||||
import org.schabi.newpipe.extractor.utils.Utils;
|
import org.schabi.newpipe.extractor.utils.Utils;
|
||||||
|
|
||||||
|
@ -40,6 +32,8 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.UTF_8;
|
||||||
|
|
||||||
public class PeertubeStreamExtractor extends StreamExtractor {
|
public class PeertubeStreamExtractor extends StreamExtractor {
|
||||||
private final String baseUrl;
|
private final String baseUrl;
|
||||||
private JsonObject json;
|
private JsonObject json;
|
||||||
|
@ -322,7 +316,7 @@ public class PeertubeStreamExtractor extends StreamExtractor {
|
||||||
params.append("start=0&count=8&sort=-createdAt");
|
params.append("start=0&count=8&sort=-createdAt");
|
||||||
for (final String tag : tags) {
|
for (final String tag : tags) {
|
||||||
params.append("&tagsOneOf=");
|
params.append("&tagsOneOf=");
|
||||||
params.append(URLEncoder.encode(tag, "UTF-8"));
|
params.append(URLEncoder.encode(tag, UTF_8));
|
||||||
}
|
}
|
||||||
return url + "?" + params.toString();
|
return url + "?" + params.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,10 @@ import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.UTF_8;
|
||||||
|
|
||||||
public class PeertubeSearchQueryHandlerFactory extends SearchQueryHandlerFactory {
|
public class PeertubeSearchQueryHandlerFactory extends SearchQueryHandlerFactory {
|
||||||
|
|
||||||
public static final String CHARSET_UTF_8 = "UTF-8";
|
|
||||||
public static final String VIDEOS = "videos";
|
public static final String VIDEOS = "videos";
|
||||||
public static final String SEPIA_VIDEOS = "sepia_videos"; // sepia is the global index
|
public static final String SEPIA_VIDEOS = "sepia_videos"; // sepia is the global index
|
||||||
public static final String SEPIA_BASE_URL = "https://sepiasearch.org";
|
public static final String SEPIA_BASE_URL = "https://sepiasearch.org";
|
||||||
|
@ -35,7 +36,7 @@ public class PeertubeSearchQueryHandlerFactory extends SearchQueryHandlerFactory
|
||||||
public String getUrl(String searchString, List<String> contentFilters, String sortFilter, String baseUrl) throws ParsingException {
|
public String getUrl(String searchString, List<String> contentFilters, String sortFilter, String baseUrl) throws ParsingException {
|
||||||
try {
|
try {
|
||||||
final String url = baseUrl + SEARCH_ENDPOINT
|
final String url = baseUrl + SEARCH_ENDPOINT
|
||||||
+ "?search=" + URLEncoder.encode(searchString, CHARSET_UTF_8);
|
+ "?search=" + URLEncoder.encode(searchString, UTF_8);
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
|
|
@ -37,9 +37,7 @@ import java.util.List;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
|
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
|
||||||
import static org.schabi.newpipe.extractor.utils.JsonUtils.EMPTY_STRING;
|
import static org.schabi.newpipe.extractor.utils.Utils.*;
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.replaceHttpWithHttps;
|
|
||||||
|
|
||||||
public class SoundcloudParsingHelper {
|
public class SoundcloudParsingHelper {
|
||||||
private static final String HARDCODED_CLIENT_ID = "H2c34Q0E7hftqnuDHGsk88DbNqhYpgMm"; // Updated on 24/06/20
|
private static final String HARDCODED_CLIENT_ID = "H2c34Q0E7hftqnuDHGsk88DbNqhYpgMm"; // Updated on 24/06/20
|
||||||
|
@ -117,7 +115,7 @@ public class SoundcloudParsingHelper {
|
||||||
*/
|
*/
|
||||||
public static JsonObject resolveFor(Downloader downloader, String url) throws IOException, ExtractionException {
|
public static JsonObject resolveFor(Downloader downloader, String url) throws IOException, ExtractionException {
|
||||||
String apiUrl = "https://api-v2.soundcloud.com/resolve"
|
String apiUrl = "https://api-v2.soundcloud.com/resolve"
|
||||||
+ "?url=" + URLEncoder.encode(url, "UTF-8")
|
+ "?url=" + URLEncoder.encode(url, UTF_8)
|
||||||
+ "&client_id=" + clientId();
|
+ "&client_id=" + clientId();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -136,7 +134,7 @@ public class SoundcloudParsingHelper {
|
||||||
public static String resolveUrlWithEmbedPlayer(String apiUrl) throws IOException, ReCaptchaException, ParsingException {
|
public static String resolveUrlWithEmbedPlayer(String apiUrl) throws IOException, ReCaptchaException, ParsingException {
|
||||||
|
|
||||||
String response = NewPipe.getDownloader().get("https://w.soundcloud.com/player/?url="
|
String response = NewPipe.getDownloader().get("https://w.soundcloud.com/player/?url="
|
||||||
+ URLEncoder.encode(apiUrl, "UTF-8"), SoundCloud.getLocalization()).responseBody();
|
+ URLEncoder.encode(apiUrl, UTF_8), SoundCloud.getLocalization()).responseBody();
|
||||||
|
|
||||||
return Jsoup.parse(response).select("link[rel=\"canonical\"]").first().attr("abs:href");
|
return Jsoup.parse(response).select("link[rel=\"canonical\"]").first().attr("abs:href");
|
||||||
}
|
}
|
||||||
|
@ -148,17 +146,17 @@ public class SoundcloudParsingHelper {
|
||||||
*/
|
*/
|
||||||
public static String resolveIdWithEmbedPlayer(String urlString) throws IOException, ReCaptchaException, ParsingException {
|
public static String resolveIdWithEmbedPlayer(String urlString) throws IOException, ReCaptchaException, ParsingException {
|
||||||
// Remove the tailing slash from URLs due to issues with the SoundCloud API
|
// Remove the tailing slash from URLs due to issues with the SoundCloud API
|
||||||
if (urlString.charAt(urlString.length() -1) == '/') urlString = urlString.substring(0, urlString.length()-1);
|
if (urlString.charAt(urlString.length() - 1) == '/') urlString = urlString.substring(0, urlString.length() - 1);
|
||||||
|
|
||||||
URL url;
|
URL url;
|
||||||
try {
|
try {
|
||||||
url = Utils.stringToURL(urlString);
|
url = Utils.stringToURL(urlString);
|
||||||
} catch (MalformedURLException e){
|
} catch (MalformedURLException e) {
|
||||||
throw new IllegalArgumentException("The given URL is not valid");
|
throw new IllegalArgumentException("The given URL is not valid");
|
||||||
}
|
}
|
||||||
|
|
||||||
String response = NewPipe.getDownloader().get("https://w.soundcloud.com/player/?url="
|
String response = NewPipe.getDownloader().get("https://w.soundcloud.com/player/?url="
|
||||||
+ URLEncoder.encode(url.toString(), "UTF-8"), SoundCloud.getLocalization()).responseBody();
|
+ URLEncoder.encode(url.toString(), UTF_8), SoundCloud.getLocalization()).responseBody();
|
||||||
// handle playlists / sets different and get playlist id via uir field in JSON
|
// handle playlists / sets different and get playlist id via uir field in JSON
|
||||||
if (url.getPath().contains("/sets/") && !url.getPath().endsWith("/sets"))
|
if (url.getPath().contains("/sets/") && !url.getPath().endsWith("/sets"))
|
||||||
return Parser.matchGroup1("\"uri\":\\s*\"https:\\/\\/api\\.soundcloud\\.com\\/playlists\\/((\\d)*?)\"", response);
|
return Parser.matchGroup1("\"uri\":\\s*\"https:\\/\\/api\\.soundcloud\\.com\\/playlists\\/((\\d)*?)\"", response);
|
||||||
|
@ -240,10 +238,14 @@ public class SoundcloudParsingHelper {
|
||||||
* @return the next streams url, empty if don't have
|
* @return the next streams url, empty if don't have
|
||||||
*/
|
*/
|
||||||
public static String getStreamsFromApi(StreamInfoItemsCollector collector, String apiUrl, boolean charts) throws IOException, ReCaptchaException, ParsingException {
|
public static String getStreamsFromApi(StreamInfoItemsCollector collector, String apiUrl, boolean charts) throws IOException, ReCaptchaException, ParsingException {
|
||||||
String response = NewPipe.getDownloader().get(apiUrl, SoundCloud.getLocalization()).responseBody();
|
final Response response = NewPipe.getDownloader().get(apiUrl, SoundCloud.getLocalization());
|
||||||
|
if (response.responseCode() >= 400) {
|
||||||
|
throw new IOException("Could not get streams from API, HTTP " + response.responseCode());
|
||||||
|
}
|
||||||
|
|
||||||
JsonObject responseObject;
|
JsonObject responseObject;
|
||||||
try {
|
try {
|
||||||
responseObject = JsonParser.object().from(response);
|
responseObject = JsonParser.object().from(response.responseBody());
|
||||||
} catch (JsonParserException e) {
|
} catch (JsonParserException e) {
|
||||||
throw new ParsingException("Could not parse json response", e);
|
throw new ParsingException("Could not parse json response", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package org.schabi.newpipe.extractor.services.soundcloud.extractors;
|
||||||
import com.grack.nanojson.JsonObject;
|
import com.grack.nanojson.JsonObject;
|
||||||
import com.grack.nanojson.JsonParser;
|
import com.grack.nanojson.JsonParser;
|
||||||
import com.grack.nanojson.JsonParserException;
|
import com.grack.nanojson.JsonParserException;
|
||||||
|
|
||||||
import org.schabi.newpipe.extractor.Page;
|
import org.schabi.newpipe.extractor.Page;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
|
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
|
||||||
|
@ -15,11 +14,10 @@ import org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.utils.JsonUtils.EMPTY_STRING;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
|
|
@ -3,7 +3,7 @@ package org.schabi.newpipe.extractor.services.soundcloud.extractors;
|
||||||
import com.grack.nanojson.JsonObject;
|
import com.grack.nanojson.JsonObject;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor;
|
import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.utils.JsonUtils.EMPTY_STRING;
|
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.replaceHttpWithHttps;
|
import static org.schabi.newpipe.extractor.utils.Utils.replaceHttpWithHttps;
|
||||||
|
|
||||||
public class SoundcloudChannelInfoItemExtractor implements ChannelInfoItemExtractor {
|
public class SoundcloudChannelInfoItemExtractor implements ChannelInfoItemExtractor {
|
||||||
|
|
|
@ -6,13 +6,13 @@ import org.schabi.newpipe.extractor.downloader.Downloader;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.extractor.kiosk.KioskExtractor;
|
import org.schabi.newpipe.extractor.kiosk.KioskExtractor;
|
||||||
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
|
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
|
||||||
|
import org.schabi.newpipe.extractor.localization.ContentCountry;
|
||||||
import org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper;
|
import org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
|
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||||
|
@ -61,10 +61,20 @@ public class SoundcloudChartsExtractor extends KioskExtractor<StreamInfoItem> {
|
||||||
apiUrl += "&kind=trending";
|
apiUrl += "&kind=trending";
|
||||||
}
|
}
|
||||||
|
|
||||||
final String contentCountry = SoundCloud.getContentCountry().getCountryCode();
|
final ContentCountry contentCountry = SoundCloud.getContentCountry();
|
||||||
apiUrl += "®ion=soundcloud:regions:" + contentCountry;
|
String apiUrlWithRegion = null;
|
||||||
|
if (getService().getSupportedCountries().contains(contentCountry)) {
|
||||||
|
apiUrlWithRegion = apiUrl + "®ion=soundcloud:regions:" + contentCountry.getCountryCode();
|
||||||
|
}
|
||||||
|
|
||||||
final String nextPageUrl = SoundcloudParsingHelper.getStreamsFromApi(collector, apiUrl, true);
|
String nextPageUrl;
|
||||||
|
try {
|
||||||
|
nextPageUrl = SoundcloudParsingHelper.getStreamsFromApi(collector, apiUrlWithRegion == null ? apiUrl : apiUrlWithRegion, true);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Request to other region may be geo-restricted. See https://github.com/TeamNewPipe/NewPipeExtractor/issues/537
|
||||||
|
// we retry without the specified region.
|
||||||
|
nextPageUrl = SoundcloudParsingHelper.getStreamsFromApi(collector, apiUrl, true);
|
||||||
|
}
|
||||||
|
|
||||||
return new InfoItemsPage<>(collector, new Page(nextPageUrl));
|
return new InfoItemsPage<>(collector, new Page(nextPageUrl));
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,12 @@ public class SoundcloudCommentsInfoItemExtractor implements CommentsInfoItemExtr
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getHeartedByUploader() throws ParsingException {
|
public boolean isHeartedByUploader() throws ParsingException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPinned() throws ParsingException {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import com.grack.nanojson.JsonObject;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItemExtractor;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItemExtractor;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.utils.JsonUtils.EMPTY_STRING;
|
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.replaceHttpWithHttps;
|
import static org.schabi.newpipe.extractor.utils.Utils.replaceHttpWithHttps;
|
||||||
|
|
||||||
public class SoundcloudPlaylistInfoItemExtractor implements PlaylistInfoItemExtractor {
|
public class SoundcloudPlaylistInfoItemExtractor implements PlaylistInfoItemExtractor {
|
||||||
|
|
|
@ -4,13 +4,7 @@ import com.grack.nanojson.JsonArray;
|
||||||
import com.grack.nanojson.JsonObject;
|
import com.grack.nanojson.JsonObject;
|
||||||
import com.grack.nanojson.JsonParser;
|
import com.grack.nanojson.JsonParser;
|
||||||
import com.grack.nanojson.JsonParserException;
|
import com.grack.nanojson.JsonParserException;
|
||||||
|
import org.schabi.newpipe.extractor.*;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
|
||||||
import org.schabi.newpipe.extractor.InfoItemExtractor;
|
|
||||||
import org.schabi.newpipe.extractor.InfoItemsCollector;
|
|
||||||
import org.schabi.newpipe.extractor.MetaInfo;
|
|
||||||
import org.schabi.newpipe.extractor.Page;
|
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
|
||||||
import org.schabi.newpipe.extractor.downloader.Downloader;
|
import org.schabi.newpipe.extractor.downloader.Downloader;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
|
@ -19,6 +13,7 @@ import org.schabi.newpipe.extractor.search.InfoItemsSearchCollector;
|
||||||
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
||||||
import org.schabi.newpipe.extractor.utils.Parser;
|
import org.schabi.newpipe.extractor.utils.Parser;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
|
@ -26,10 +21,8 @@ import java.net.URL;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.services.soundcloud.linkHandler.SoundcloudSearchQueryHandlerFactory.ITEMS_PER_PAGE;
|
import static org.schabi.newpipe.extractor.services.soundcloud.linkHandler.SoundcloudSearchQueryHandlerFactory.ITEMS_PER_PAGE;
|
||||||
import static org.schabi.newpipe.extractor.utils.JsonUtils.EMPTY_STRING;
|
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||||
|
|
||||||
public class SoundcloudSearchExtractor extends SearchExtractor {
|
public class SoundcloudSearchExtractor extends SearchExtractor {
|
||||||
|
@ -50,7 +43,7 @@ public class SoundcloudSearchExtractor extends SearchExtractor {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public List<MetaInfo> getMetaInfo() {
|
public List<MetaInfo> getMetaInfo() {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
|
|
@ -4,7 +4,6 @@ import com.grack.nanojson.JsonArray;
|
||||||
import com.grack.nanojson.JsonObject;
|
import com.grack.nanojson.JsonObject;
|
||||||
import com.grack.nanojson.JsonParser;
|
import com.grack.nanojson.JsonParser;
|
||||||
import com.grack.nanojson.JsonParserException;
|
import com.grack.nanojson.JsonParserException;
|
||||||
|
|
||||||
import org.schabi.newpipe.extractor.MediaFormat;
|
import org.schabi.newpipe.extractor.MediaFormat;
|
||||||
import org.schabi.newpipe.extractor.MetaInfo;
|
import org.schabi.newpipe.extractor.MetaInfo;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
@ -17,15 +16,10 @@ import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
|
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
|
||||||
import org.schabi.newpipe.extractor.localization.DateWrapper;
|
import org.schabi.newpipe.extractor.localization.DateWrapper;
|
||||||
import org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper;
|
import org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper;
|
||||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
import org.schabi.newpipe.extractor.stream.*;
|
||||||
import org.schabi.newpipe.extractor.stream.Description;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamSegment;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
|
||||||
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
|
|
||||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
|
@ -34,11 +28,7 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import static org.schabi.newpipe.extractor.utils.Utils.*;
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.utils.JsonUtils.EMPTY_STRING;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
|
||||||
|
|
||||||
public class SoundcloudStreamExtractor extends StreamExtractor {
|
public class SoundcloudStreamExtractor extends StreamExtractor {
|
||||||
private JsonObject track;
|
private JsonObject track;
|
||||||
|
@ -60,7 +50,7 @@ public class SoundcloudStreamExtractor extends StreamExtractor {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return track.getInt("id") + "";
|
return track.getInt("id") + EMPTY_STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
|
@ -73,8 +63,8 @@ public class SoundcloudStreamExtractor extends StreamExtractor {
|
||||||
@Override
|
@Override
|
||||||
public String getTextualUploadDate() {
|
public String getTextualUploadDate() {
|
||||||
return track.getString("created_at")
|
return track.getString("created_at")
|
||||||
.replace("T"," ")
|
.replace("T", " ")
|
||||||
.replace("Z", "");
|
.replace("Z", EMPTY_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
|
@ -232,7 +222,7 @@ public class SoundcloudStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
private static String urlEncode(String value) {
|
private static String urlEncode(String value) {
|
||||||
try {
|
try {
|
||||||
return URLEncoder.encode(value, "UTF-8");
|
return URLEncoder.encode(value, UTF_8);
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.utils.JsonUtils.EMPTY_STRING;
|
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.replaceHttpWithHttps;
|
import static org.schabi.newpipe.extractor.utils.Utils.replaceHttpWithHttps;
|
||||||
|
|
||||||
public class SoundcloudStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
public class SoundcloudStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
||||||
|
|
|
@ -17,9 +17,9 @@ import java.net.URLEncoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class SoundcloudSuggestionExtractor extends SuggestionExtractor {
|
import static org.schabi.newpipe.extractor.utils.Utils.UTF_8;
|
||||||
|
|
||||||
public static final String CHARSET_UTF_8 = "UTF-8";
|
public class SoundcloudSuggestionExtractor extends SuggestionExtractor {
|
||||||
|
|
||||||
public SoundcloudSuggestionExtractor(StreamingService service) {
|
public SoundcloudSuggestionExtractor(StreamingService service) {
|
||||||
super(service);
|
super(service);
|
||||||
|
@ -32,7 +32,7 @@ public class SoundcloudSuggestionExtractor extends SuggestionExtractor {
|
||||||
Downloader dl = NewPipe.getDownloader();
|
Downloader dl = NewPipe.getDownloader();
|
||||||
|
|
||||||
String url = "https://api-v2.soundcloud.com/search/queries"
|
String url = "https://api-v2.soundcloud.com/search/queries"
|
||||||
+ "?q=" + URLEncoder.encode(query, CHARSET_UTF_8)
|
+ "?q=" + URLEncoder.encode(query, UTF_8)
|
||||||
+ "&client_id=" + SoundcloudParsingHelper.clientId()
|
+ "&client_id=" + SoundcloudParsingHelper.clientId()
|
||||||
+ "&limit=10";
|
+ "&limit=10";
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,9 @@ import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.UTF_8;
|
||||||
|
|
||||||
public class SoundcloudSearchQueryHandlerFactory extends SearchQueryHandlerFactory {
|
public class SoundcloudSearchQueryHandlerFactory extends SearchQueryHandlerFactory {
|
||||||
public static final String CHARSET_UTF_8 = "UTF-8";
|
|
||||||
|
|
||||||
public static final String TRACKS = "tracks";
|
public static final String TRACKS = "tracks";
|
||||||
public static final String USERS = "users";
|
public static final String USERS = "users";
|
||||||
|
@ -43,7 +44,7 @@ public class SoundcloudSearchQueryHandlerFactory extends SearchQueryHandlerFacto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return url + "?q=" + URLEncoder.encode(id, CHARSET_UTF_8)
|
return url + "?q=" + URLEncoder.encode(id, UTF_8)
|
||||||
+ "&client_id=" + SoundcloudParsingHelper.clientId()
|
+ "&client_id=" + SoundcloudParsingHelper.clientId()
|
||||||
+ "&limit=" + ITEMS_PER_PAGE
|
+ "&limit=" + ITEMS_PER_PAGE
|
||||||
+ "&offset=0";
|
+ "&offset=0";
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
package org.schabi.newpipe.extractor.services.youtube;
|
package org.schabi.newpipe.extractor.services.youtube;
|
||||||
|
|
||||||
import com.grack.nanojson.*;
|
import com.grack.nanojson.*;
|
||||||
import com.grack.nanojson.JsonArray;
|
|
||||||
import com.grack.nanojson.JsonObject;
|
|
||||||
import com.grack.nanojson.JsonParser;
|
|
||||||
import com.grack.nanojson.JsonParserException;
|
|
||||||
import com.grack.nanojson.JsonWriter;
|
|
||||||
|
|
||||||
import org.jsoup.Jsoup;
|
|
||||||
import org.jsoup.nodes.Document;
|
|
||||||
import org.schabi.newpipe.extractor.MetaInfo;
|
import org.schabi.newpipe.extractor.MetaInfo;
|
||||||
import org.schabi.newpipe.extractor.Page;
|
import org.schabi.newpipe.extractor.Page;
|
||||||
import org.schabi.newpipe.extractor.downloader.Response;
|
import org.schabi.newpipe.extractor.downloader.Response;
|
||||||
|
@ -21,27 +13,27 @@ import org.schabi.newpipe.extractor.stream.Description;
|
||||||
import org.schabi.newpipe.extractor.utils.Parser;
|
import org.schabi.newpipe.extractor.utils.Parser;
|
||||||
import org.schabi.newpipe.extractor.utils.Utils;
|
import org.schabi.newpipe.extractor.utils.Utils;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
import java.time.format.DateTimeParseException;
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.NewPipe.getDownloader;
|
import static org.schabi.newpipe.extractor.NewPipe.getDownloader;
|
||||||
import static org.schabi.newpipe.extractor.utils.JsonUtils.EMPTY_STRING;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.*;
|
import static org.schabi.newpipe.extractor.utils.Utils.*;
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.HTTP;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.HTTPS;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.join;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Created by Christian Schabesberger on 02.03.16.
|
* Created by Christian Schabesberger on 02.03.16.
|
||||||
|
@ -111,7 +103,7 @@ public class YoutubeParsingHelper {
|
||||||
return host.equalsIgnoreCase("invidio.us")
|
return host.equalsIgnoreCase("invidio.us")
|
||||||
|| host.equalsIgnoreCase("dev.invidio.us")
|
|| host.equalsIgnoreCase("dev.invidio.us")
|
||||||
|| host.equalsIgnoreCase("www.invidio.us")
|
|| host.equalsIgnoreCase("www.invidio.us")
|
||||||
|| host.equalsIgnoreCase("vid.encryptionin.space")
|
|| host.equalsIgnoreCase("redirect.invidious.io")
|
||||||
|| host.equalsIgnoreCase("invidious.snopyta.org")
|
|| host.equalsIgnoreCase("invidious.snopyta.org")
|
||||||
|| host.equalsIgnoreCase("yewtu.be")
|
|| host.equalsIgnoreCase("yewtu.be")
|
||||||
|| host.equalsIgnoreCase("tube.connect.cafe")
|
|| host.equalsIgnoreCase("tube.connect.cafe")
|
||||||
|
@ -122,11 +114,16 @@ public class YoutubeParsingHelper {
|
||||||
|| host.equalsIgnoreCase("invidious.xyz")
|
|| host.equalsIgnoreCase("invidious.xyz")
|
||||||
|| host.equalsIgnoreCase("vid.mint.lgbt")
|
|| host.equalsIgnoreCase("vid.mint.lgbt")
|
||||||
|| host.equalsIgnoreCase("invidiou.site")
|
|| host.equalsIgnoreCase("invidiou.site")
|
||||||
|| host.equalsIgnoreCase("invidious.fdn.fr");
|
|| host.equalsIgnoreCase("invidious.fdn.fr")
|
||||||
|
|| host.equalsIgnoreCase("invidious.048596.xyz")
|
||||||
|
|| host.equalsIgnoreCase("invidious.zee.li")
|
||||||
|
|| host.equalsIgnoreCase("vid.puffyan.us")
|
||||||
|
|| host.equalsIgnoreCase("ytprivate.com");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the duration string of the video expecting ":" or "." as separators
|
* Parses the duration string of the video expecting ":" or "." as separators
|
||||||
|
*
|
||||||
* @return the duration in seconds
|
* @return the duration in seconds
|
||||||
* @throws ParsingException when more than 3 separators are found
|
* @throws ParsingException when more than 3 separators are found
|
||||||
*/
|
*/
|
||||||
|
@ -196,6 +193,7 @@ public class YoutubeParsingHelper {
|
||||||
/**
|
/**
|
||||||
* Checks if the given playlist id is a YouTube Mix (auto-generated playlist)
|
* Checks if the given playlist id is a YouTube Mix (auto-generated playlist)
|
||||||
* Ids from a YouTube Mix start with "RD"
|
* Ids from a YouTube Mix start with "RD"
|
||||||
|
*
|
||||||
* @param playlistId
|
* @param playlistId
|
||||||
* @return Whether given id belongs to a YouTube Mix
|
* @return Whether given id belongs to a YouTube Mix
|
||||||
*/
|
*/
|
||||||
|
@ -206,15 +204,18 @@ public class YoutubeParsingHelper {
|
||||||
/**
|
/**
|
||||||
* Checks if the given playlist id is a YouTube Music Mix (auto-generated playlist)
|
* Checks if the given playlist id is a YouTube Music Mix (auto-generated playlist)
|
||||||
* Ids from a YouTube Music Mix start with "RDAMVM" or "RDCLAK"
|
* Ids from a YouTube Music Mix start with "RDAMVM" or "RDCLAK"
|
||||||
|
*
|
||||||
* @param playlistId
|
* @param playlistId
|
||||||
* @return Whether given id belongs to a YouTube Music Mix
|
* @return Whether given id belongs to a YouTube Music Mix
|
||||||
*/
|
*/
|
||||||
public static boolean isYoutubeMusicMixId(final String playlistId) {
|
public static boolean isYoutubeMusicMixId(final String playlistId) {
|
||||||
return playlistId.startsWith("RDAMVM") || playlistId.startsWith("RDCLAK");
|
return playlistId.startsWith("RDAMVM") || playlistId.startsWith("RDCLAK");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the given playlist id is a YouTube Channel Mix (auto-generated playlist)
|
* Checks if the given playlist id is a YouTube Channel Mix (auto-generated playlist)
|
||||||
* Ids from a YouTube channel Mix start with "RDCM"
|
* Ids from a YouTube channel Mix start with "RDCM"
|
||||||
|
*
|
||||||
* @return Whether given id belongs to a YouTube Channel Mix
|
* @return Whether given id belongs to a YouTube Channel Mix
|
||||||
*/
|
*/
|
||||||
public static boolean isYoutubeChannelMixId(final String playlistId) {
|
public static boolean isYoutubeChannelMixId(final String playlistId) {
|
||||||
|
@ -223,6 +224,7 @@ public class YoutubeParsingHelper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the video id from the playlist id for Mixes.
|
* Extracts the video id from the playlist id for Mixes.
|
||||||
|
*
|
||||||
* @throws ParsingException If the playlistId is a Channel Mix or not a mix.
|
* @throws ParsingException If the playlistId is a Channel Mix or not a mix.
|
||||||
*/
|
*/
|
||||||
public static String extractVideoIdFromMixId(final String playlistId) throws ParsingException {
|
public static String extractVideoIdFromMixId(final String playlistId) throws ParsingException {
|
||||||
|
@ -314,7 +316,8 @@ public class YoutubeParsingHelper {
|
||||||
clientVersion = contextClientVersion;
|
clientVersion = contextClientVersion;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (Parser.RegexException ignored) { }
|
} catch (Parser.RegexException ignored) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNullOrEmpty(clientVersion) && !isNullOrEmpty(shortClientVersion)) {
|
if (!isNullOrEmpty(clientVersion) && !isNullOrEmpty(shortClientVersion)) {
|
||||||
|
@ -326,7 +329,8 @@ public class YoutubeParsingHelper {
|
||||||
} catch (Parser.RegexException e) {
|
} catch (Parser.RegexException e) {
|
||||||
try {
|
try {
|
||||||
key = Parser.matchGroup1("innertubeApiKey\":\"([0-9a-zA-Z_-]+?)\"", html);
|
key = Parser.matchGroup1("innertubeApiKey\":\"([0-9a-zA-Z_-]+?)\"", html);
|
||||||
} catch (Parser.RegexException ignored) { }
|
} catch (Parser.RegexException ignored) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,7 +362,7 @@ public class YoutubeParsingHelper {
|
||||||
*
|
*
|
||||||
* Quick-and-dirty solution to reset global state in between test classes.
|
* Quick-and-dirty solution to reset global state in between test classes.
|
||||||
*/
|
*/
|
||||||
static void resetClientVersionAndKey() {
|
public static void resetClientVersionAndKey() {
|
||||||
clientVersion = null;
|
clientVersion = null;
|
||||||
key = null;
|
key = null;
|
||||||
}
|
}
|
||||||
|
@ -393,7 +397,7 @@ public class YoutubeParsingHelper {
|
||||||
.end()
|
.end()
|
||||||
.value("query", "test")
|
.value("query", "test")
|
||||||
.value("params", "Eg-KAQwIARAAGAAgACgAMABqChAEEAUQAxAKEAk%3D")
|
.value("params", "Eg-KAQwIARAAGAAgACgAMABqChAEEAUQAxAKEAk%3D")
|
||||||
.end().done().getBytes("UTF-8");
|
.end().done().getBytes(UTF_8);
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
final Map<String, List<String>> headers = new HashMap<>();
|
final Map<String, List<String>> headers = new HashMap<>();
|
||||||
|
@ -438,10 +442,17 @@ public class YoutubeParsingHelper {
|
||||||
return youtubeMusicKeys = new String[]{key, clientName, clientVersion};
|
return youtubeMusicKeys = new String[]{key, clientName, clientVersion};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static String getUrlFromNavigationEndpoint(JsonObject navigationEndpoint) throws ParsingException {
|
public static String getUrlFromNavigationEndpoint(JsonObject navigationEndpoint) throws ParsingException {
|
||||||
if (navigationEndpoint.has("urlEndpoint")) {
|
if (navigationEndpoint.has("urlEndpoint")) {
|
||||||
String internUrl = navigationEndpoint.getObject("urlEndpoint").getString("url");
|
String internUrl = navigationEndpoint.getObject("urlEndpoint").getString("url");
|
||||||
|
if (internUrl.startsWith("https://www.youtube.com/redirect?")) {
|
||||||
|
// remove https://www.youtube.com part to fall in the next if block
|
||||||
|
internUrl = internUrl.substring(23);
|
||||||
|
}
|
||||||
|
|
||||||
if (internUrl.startsWith("/redirect?")) {
|
if (internUrl.startsWith("/redirect?")) {
|
||||||
// q parameter can be the first parameter
|
// q parameter can be the first parameter
|
||||||
internUrl = internUrl.substring(10);
|
internUrl = internUrl.substring(10);
|
||||||
|
@ -450,7 +461,7 @@ public class YoutubeParsingHelper {
|
||||||
if (param.split("=")[0].equals("q")) {
|
if (param.split("=")[0].equals("q")) {
|
||||||
String url;
|
String url;
|
||||||
try {
|
try {
|
||||||
url = URLDecoder.decode(param.split("=")[1], "UTF-8");
|
url = URLDecoder.decode(param.split("=")[1], UTF_8);
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -459,6 +470,8 @@ public class YoutubeParsingHelper {
|
||||||
}
|
}
|
||||||
} else if (internUrl.startsWith("http")) {
|
} else if (internUrl.startsWith("http")) {
|
||||||
return internUrl;
|
return internUrl;
|
||||||
|
} else if (internUrl.startsWith("/channel") || internUrl.startsWith("/user") || internUrl.startsWith("/watch")) {
|
||||||
|
return "https://www.youtube.com" + internUrl;
|
||||||
}
|
}
|
||||||
} else if (navigationEndpoint.has("browseEndpoint")) {
|
} else if (navigationEndpoint.has("browseEndpoint")) {
|
||||||
final JsonObject browseEndpoint = navigationEndpoint.getObject("browseEndpoint");
|
final JsonObject browseEndpoint = navigationEndpoint.getObject("browseEndpoint");
|
||||||
|
@ -496,6 +509,7 @@ public class YoutubeParsingHelper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the text from a JSON object that has either a simpleText or a runs array.
|
* Get the text from a JSON object that has either a simpleText or a runs array.
|
||||||
|
*
|
||||||
* @param textObject JSON object to get the text from
|
* @param textObject JSON object to get the text from
|
||||||
* @param html whether to return HTML, by parsing the navigationEndpoint
|
* @param html whether to return HTML, by parsing the navigationEndpoint
|
||||||
* @return text in the JSON object or {@code null}
|
* @return text in the JSON object or {@code null}
|
||||||
|
@ -723,7 +737,7 @@ public class YoutubeParsingHelper {
|
||||||
|
|
||||||
final String title = YoutubeParsingHelper.getTextFromObject(clarificationRenderer.getObject("contentTitle"));
|
final String title = YoutubeParsingHelper.getTextFromObject(clarificationRenderer.getObject("contentTitle"));
|
||||||
final String text = YoutubeParsingHelper.getTextFromObject(clarificationRenderer.getObject("text"));
|
final String text = YoutubeParsingHelper.getTextFromObject(clarificationRenderer.getObject("text"));
|
||||||
if (title == null || text == null) {
|
if (title == null || text == null) {
|
||||||
throw new ParsingException("Could not extract clarification renderer content");
|
throw new ParsingException("Could not extract clarification renderer content");
|
||||||
}
|
}
|
||||||
metaInfo.setTitle(title);
|
metaInfo.setTitle(title);
|
||||||
|
@ -767,6 +781,7 @@ public class YoutubeParsingHelper {
|
||||||
/**
|
/**
|
||||||
* Sometimes, YouTube provides URLs which use Google's cache. They look like
|
* Sometimes, YouTube provides URLs which use Google's cache. They look like
|
||||||
* {@code https://webcache.googleusercontent.com/search?q=cache:CACHED_URL}
|
* {@code https://webcache.googleusercontent.com/search?q=cache:CACHED_URL}
|
||||||
|
*
|
||||||
* @param url the URL which might refer to the Google's webcache
|
* @param url the URL which might refer to the Google's webcache
|
||||||
* @return the URL which is referring to the original site
|
* @return the URL which is referring to the original site
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -20,10 +20,8 @@ import org.schabi.newpipe.extractor.utils.Utils;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.fixThumbnailUrl;
|
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.*;
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getJsonResponse;
|
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getTextFromObject;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.JsonUtils.EMPTY_STRING;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -230,9 +228,9 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
|
||||||
.getArray("contents").getObject(0).getObject("itemSectionRenderer")
|
.getArray("contents").getObject(0).getObject("itemSectionRenderer")
|
||||||
.getArray("contents").getObject(0).getObject("gridRenderer");
|
.getArray("contents").getObject(0).getObject("gridRenderer");
|
||||||
|
|
||||||
collectStreamsFrom(collector, gridRenderer.getArray("items"));
|
final JsonObject continuation = collectStreamsFrom(collector, gridRenderer.getArray("items"));
|
||||||
|
|
||||||
nextPage = getNextPageFrom(gridRenderer.getArray("continuations"));
|
nextPage = getNextPageFrom(continuation);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new InfoItemsPage<>(collector, nextPage);
|
return new InfoItemsPage<>(collector, nextPage);
|
||||||
|
@ -252,36 +250,47 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
|
||||||
final JsonArray ajaxJson = getJsonResponse(page.getUrl(), getExtractorLocalization());
|
final JsonArray ajaxJson = getJsonResponse(page.getUrl(), getExtractorLocalization());
|
||||||
|
|
||||||
JsonObject sectionListContinuation = ajaxJson.getObject(1).getObject("response")
|
JsonObject sectionListContinuation = ajaxJson.getObject(1).getObject("response")
|
||||||
.getObject("continuationContents").getObject("gridContinuation");
|
.getArray("onResponseReceivedActions").getObject(0).getObject("appendContinuationItemsAction");
|
||||||
|
|
||||||
collectStreamsFrom(collector, sectionListContinuation.getArray("items"));
|
final JsonObject continuation = collectStreamsFrom(collector, sectionListContinuation.getArray("continuationItems"));
|
||||||
|
|
||||||
return new InfoItemsPage<>(collector, getNextPageFrom(sectionListContinuation.getArray("continuations")));
|
return new InfoItemsPage<>(collector, getNextPageFrom(continuation));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Page getNextPageFrom(final JsonArray continuations) {
|
private Page getNextPageFrom(final JsonObject continuations) {
|
||||||
if (isNullOrEmpty(continuations)) {
|
if (isNullOrEmpty(continuations)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final JsonObject nextContinuationData = continuations.getObject(0).getObject("nextContinuationData");
|
final JsonObject continuationEndpoint = continuations.getObject("continuationEndpoint");
|
||||||
final String continuation = nextContinuationData.getString("continuation");
|
final String continuation = continuationEndpoint.getObject("continuationCommand").getString("token");
|
||||||
final String clickTrackingParams = nextContinuationData.getString("clickTrackingParams");
|
final String clickTrackingParams = continuationEndpoint.getString("clickTrackingParams");
|
||||||
return new Page("https://www.youtube.com/browse_ajax?ctoken=" + continuation
|
return new Page("https://www.youtube.com/browse_ajax?ctoken=" + continuation
|
||||||
+ "&continuation=" + continuation + "&itct=" + clickTrackingParams);
|
+ "&continuation=" + continuation + "&itct=" + clickTrackingParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void collectStreamsFrom(StreamInfoItemsCollector collector, JsonArray videos) throws ParsingException {
|
/**
|
||||||
|
* Collect streams from an array of items
|
||||||
|
*
|
||||||
|
* @param collector the collector where videos will be commited
|
||||||
|
* @param videos the array to get videos from
|
||||||
|
* @return the continuation object
|
||||||
|
* @throws ParsingException if an error happened while extracting
|
||||||
|
*/
|
||||||
|
private JsonObject collectStreamsFrom(StreamInfoItemsCollector collector, JsonArray videos) throws ParsingException {
|
||||||
collector.reset();
|
collector.reset();
|
||||||
|
|
||||||
final String uploaderName = getName();
|
final String uploaderName = getName();
|
||||||
final String uploaderUrl = getUrl();
|
final String uploaderUrl = getUrl();
|
||||||
final TimeAgoParser timeAgoParser = getTimeAgoParser();
|
final TimeAgoParser timeAgoParser = getTimeAgoParser();
|
||||||
|
|
||||||
for (Object video : videos) {
|
JsonObject continuation = null;
|
||||||
if (((JsonObject) video).has("gridVideoRenderer")) {
|
|
||||||
|
for (Object object : videos) {
|
||||||
|
final JsonObject video = (JsonObject) object;
|
||||||
|
if (video.has("gridVideoRenderer")) {
|
||||||
collector.commit(new YoutubeStreamInfoItemExtractor(
|
collector.commit(new YoutubeStreamInfoItemExtractor(
|
||||||
((JsonObject) video).getObject("gridVideoRenderer"), timeAgoParser) {
|
video.getObject("gridVideoRenderer"), timeAgoParser) {
|
||||||
@Override
|
@Override
|
||||||
public String getUploaderName() {
|
public String getUploaderName() {
|
||||||
return uploaderName;
|
return uploaderName;
|
||||||
|
@ -292,8 +301,12 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
|
||||||
return uploaderUrl;
|
return uploaderUrl;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else if (video.has("continuationItemRenderer")) {
|
||||||
|
continuation = video.getObject("continuationItemRenderer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return continuation;
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonObject getVideoTab() throws ParsingException {
|
private JsonObject getVideoTab() throws ParsingException {
|
||||||
|
|
|
@ -3,7 +3,6 @@ package org.schabi.newpipe.extractor.services.youtube.extractors;
|
||||||
import com.grack.nanojson.JsonArray;
|
import com.grack.nanojson.JsonArray;
|
||||||
import com.grack.nanojson.JsonObject;
|
import com.grack.nanojson.JsonObject;
|
||||||
import com.grack.nanojson.JsonParser;
|
import com.grack.nanojson.JsonParser;
|
||||||
|
|
||||||
import org.schabi.newpipe.extractor.Page;
|
import org.schabi.newpipe.extractor.Page;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
import org.schabi.newpipe.extractor.comments.CommentsExtractor;
|
import org.schabi.newpipe.extractor.comments.CommentsExtractor;
|
||||||
|
@ -19,6 +18,7 @@ import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
|
||||||
import org.schabi.newpipe.extractor.utils.JsonUtils;
|
import org.schabi.newpipe.extractor.utils.JsonUtils;
|
||||||
import org.schabi.newpipe.extractor.utils.Parser;
|
import org.schabi.newpipe.extractor.utils.Parser;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
|
@ -27,9 +27,8 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.UTF_8;
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||||
|
|
||||||
public class YoutubeCommentsExtractor extends CommentsExtractor {
|
public class YoutubeCommentsExtractor extends CommentsExtractor {
|
||||||
|
@ -152,9 +151,9 @@ public class YoutubeCommentsExtractor extends CommentsExtractor {
|
||||||
first = false;
|
first = false;
|
||||||
else
|
else
|
||||||
result.append("&");
|
result.append("&");
|
||||||
result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
|
result.append(URLEncoder.encode(entry.getKey(), UTF_8));
|
||||||
result.append("=");
|
result.append("=");
|
||||||
result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
|
result.append(URLEncoder.encode(entry.getValue(), UTF_8));
|
||||||
}
|
}
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package org.schabi.newpipe.extractor.services.youtube.extractors;
|
||||||
|
|
||||||
import com.grack.nanojson.JsonArray;
|
import com.grack.nanojson.JsonArray;
|
||||||
import com.grack.nanojson.JsonObject;
|
import com.grack.nanojson.JsonObject;
|
||||||
|
|
||||||
import org.schabi.newpipe.extractor.comments.CommentsInfoItemExtractor;
|
import org.schabi.newpipe.extractor.comments.CommentsInfoItemExtractor;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.localization.DateWrapper;
|
import org.schabi.newpipe.extractor.localization.DateWrapper;
|
||||||
|
@ -13,6 +12,7 @@ import org.schabi.newpipe.extractor.utils.Utils;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getTextFromObject;
|
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getTextFromObject;
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
||||||
|
|
||||||
public class YoutubeCommentsInfoItemExtractor implements CommentsInfoItemExtractor {
|
public class YoutubeCommentsInfoItemExtractor implements CommentsInfoItemExtractor {
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ public class YoutubeCommentsInfoItemExtractor implements CommentsInfoItemExtract
|
||||||
try {
|
try {
|
||||||
return getTextFromObject(JsonUtils.getObject(json, "authorText"));
|
return getTextFromObject(JsonUtils.getObject(json, "authorText"));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return "";
|
return EMPTY_STRING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ public class YoutubeCommentsInfoItemExtractor implements CommentsInfoItemExtract
|
||||||
if (contentText.isEmpty()) {
|
if (contentText.isEmpty()) {
|
||||||
// completely empty comments as described in
|
// completely empty comments as described in
|
||||||
// https://github.com/TeamNewPipe/NewPipeExtractor/issues/380#issuecomment-668808584
|
// https://github.com/TeamNewPipe/NewPipeExtractor/issues/380#issuecomment-668808584
|
||||||
return "";
|
return EMPTY_STRING;
|
||||||
}
|
}
|
||||||
final String commentText = getTextFromObject(contentText);
|
final String commentText = getTextFromObject(contentText);
|
||||||
// youtube adds U+FEFF in some comments. eg. https://www.youtube.com/watch?v=Nj4F63E59io<feff>
|
// youtube adds U+FEFF in some comments. eg. https://www.youtube.com/watch?v=Nj4F63E59io<feff>
|
||||||
|
@ -116,16 +116,21 @@ public class YoutubeCommentsInfoItemExtractor implements CommentsInfoItemExtract
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getHeartedByUploader() throws ParsingException {
|
public boolean isHeartedByUploader() throws ParsingException {
|
||||||
return json.has("creatorHeart");
|
return json.has("creatorHeart");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPinned() {
|
||||||
|
return json.has("pinnedCommentBadge");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUploaderName() throws ParsingException {
|
public String getUploaderName() throws ParsingException {
|
||||||
try {
|
try {
|
||||||
return getTextFromObject(JsonUtils.getObject(json, "authorText"));
|
return getTextFromObject(JsonUtils.getObject(json, "authorText"));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return "";
|
return EMPTY_STRING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +139,7 @@ public class YoutubeCommentsInfoItemExtractor implements CommentsInfoItemExtract
|
||||||
try {
|
try {
|
||||||
return "https://youtube.com/channel/" + JsonUtils.getString(json, "authorEndpoint.browseEndpoint.browseId");
|
return "https://youtube.com/channel/" + JsonUtils.getString(json, "authorEndpoint.browseEndpoint.browseId");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return "";
|
return EMPTY_STRING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
package org.schabi.newpipe.extractor.services.youtube.extractors;
|
package org.schabi.newpipe.extractor.services.youtube.extractors;
|
||||||
|
|
||||||
import com.grack.nanojson.JsonArray;
|
import com.grack.nanojson.*;
|
||||||
import com.grack.nanojson.JsonObject;
|
|
||||||
import com.grack.nanojson.JsonParser;
|
|
||||||
import com.grack.nanojson.JsonParserException;
|
|
||||||
import com.grack.nanojson.JsonWriter;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.MetaInfo;
|
import org.schabi.newpipe.extractor.MetaInfo;
|
||||||
import org.schabi.newpipe.extractor.Page;
|
import org.schabi.newpipe.extractor.Page;
|
||||||
|
@ -20,27 +15,20 @@ import org.schabi.newpipe.extractor.localization.TimeAgoParser;
|
||||||
import org.schabi.newpipe.extractor.search.InfoItemsSearchCollector;
|
import org.schabi.newpipe.extractor.search.InfoItemsSearchCollector;
|
||||||
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
|
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubePlaylistLinkHandlerFactory;
|
|
||||||
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory;
|
|
||||||
import org.schabi.newpipe.extractor.utils.JsonUtils;
|
import org.schabi.newpipe.extractor.utils.JsonUtils;
|
||||||
|
import org.schabi.newpipe.extractor.utils.Parser;
|
||||||
import org.schabi.newpipe.extractor.utils.Utils;
|
import org.schabi.newpipe.extractor.utils.Utils;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.*;
|
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.*;
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.MUSIC_ALBUMS;
|
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.*;
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.MUSIC_ARTISTS;
|
import static org.schabi.newpipe.extractor.utils.Utils.*;
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.MUSIC_PLAYLISTS;
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.MUSIC_SONGS;
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.MUSIC_VIDEOS;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.JsonUtils.EMPTY_STRING;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
|
||||||
|
|
||||||
public class YoutubeMusicSearchExtractor extends SearchExtractor {
|
public class YoutubeMusicSearchExtractor extends SearchExtractor {
|
||||||
private JsonObject initialData;
|
private JsonObject initialData;
|
||||||
|
@ -105,7 +93,7 @@ public class YoutubeMusicSearchExtractor extends SearchExtractor {
|
||||||
.end()
|
.end()
|
||||||
.value("query", getSearchString())
|
.value("query", getSearchString())
|
||||||
.value("params", params)
|
.value("params", params)
|
||||||
.end().done().getBytes("UTF-8");
|
.end().done().getBytes(UTF_8);
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
final Map<String, List<String>> headers = new HashMap<>();
|
final Map<String, List<String>> headers = new HashMap<>();
|
||||||
|
@ -229,7 +217,7 @@ public class YoutubeMusicSearchExtractor extends SearchExtractor {
|
||||||
.value("enableSafetyMode", false)
|
.value("enableSafetyMode", false)
|
||||||
.end()
|
.end()
|
||||||
.end()
|
.end()
|
||||||
.end().done().getBytes("UTF-8");
|
.end().done().getBytes(UTF_8);
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
final Map<String, List<String>> headers = new HashMap<>();
|
final Map<String, List<String>> headers = new HashMap<>();
|
||||||
|
@ -365,7 +353,12 @@ public class YoutubeMusicSearchExtractor extends SearchExtractor {
|
||||||
.getObject(descriptionElements.size() - 3)
|
.getObject(descriptionElements.size() - 3)
|
||||||
.getString("text");
|
.getString("text");
|
||||||
if (!isNullOrEmpty(viewCount)) {
|
if (!isNullOrEmpty(viewCount)) {
|
||||||
return Utils.mixedNumberWordToLong(viewCount);
|
try {
|
||||||
|
return Utils.mixedNumberWordToLong(viewCount);
|
||||||
|
} catch (final Parser.RegexException e) {
|
||||||
|
// probably viewCount == "No views" or similar
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw new ParsingException("Could not get view count");
|
throw new ParsingException("Could not get view count");
|
||||||
}
|
}
|
||||||
|
@ -421,10 +414,15 @@ public class YoutubeMusicSearchExtractor extends SearchExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getSubscriberCount() throws ParsingException {
|
public long getSubscriberCount() throws ParsingException {
|
||||||
final String viewCount = getTextFromObject(info.getArray("flexColumns").getObject(2)
|
final String subscriberCount = getTextFromObject(info.getArray("flexColumns").getObject(2)
|
||||||
.getObject("musicResponsiveListItemFlexColumnRenderer").getObject("text"));
|
.getObject("musicResponsiveListItemFlexColumnRenderer").getObject("text"));
|
||||||
if (!isNullOrEmpty(viewCount)) {
|
if (!isNullOrEmpty(subscriberCount)) {
|
||||||
return Utils.mixedNumberWordToLong(viewCount);
|
try {
|
||||||
|
return Utils.mixedNumberWordToLong(subscriberCount);
|
||||||
|
} catch (final Parser.RegexException ignored) {
|
||||||
|
// probably subscriberCount == "No subscribers" or similar
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw new ParsingException("Could not get subscriber count");
|
throw new ParsingException("Could not get subscriber count");
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ public class YoutubePlaylistExtractor extends PlaylistExtractor {
|
||||||
@Override
|
@Override
|
||||||
public String getName() throws ParsingException {
|
public String getName() throws ParsingException {
|
||||||
final String name = getTextFromObject(playlistInfo.getObject("title"));
|
final String name = getTextFromObject(playlistInfo.getObject("title"));
|
||||||
if (name != null && !name.isEmpty()) return name;
|
if (!isNullOrEmpty(name)) return name;
|
||||||
|
|
||||||
return initialData.getObject("microformat").getObject("microformatDataRenderer").getString("title");
|
return initialData.getObject("microformat").getObject("microformatDataRenderer").getString("title");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
package org.schabi.newpipe.extractor.services.youtube.extractors;
|
package org.schabi.newpipe.extractor.services.youtube.extractors;
|
||||||
|
|
||||||
import com.grack.nanojson.JsonArray;
|
import com.grack.nanojson.*;
|
||||||
import com.grack.nanojson.JsonObject;
|
|
||||||
import com.grack.nanojson.JsonParser;
|
|
||||||
import com.grack.nanojson.JsonParserException;
|
|
||||||
import com.grack.nanojson.JsonWriter;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.MetaInfo;
|
import org.schabi.newpipe.extractor.MetaInfo;
|
||||||
import org.schabi.newpipe.extractor.Page;
|
import org.schabi.newpipe.extractor.Page;
|
||||||
|
@ -20,16 +15,15 @@ import org.schabi.newpipe.extractor.search.SearchExtractor;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
|
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
|
||||||
import org.schabi.newpipe.extractor.utils.JsonUtils;
|
import org.schabi.newpipe.extractor.utils.JsonUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getClientVersion;
|
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.*;
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getJsonResponse;
|
import static org.schabi.newpipe.extractor.utils.Utils.UTF_8;
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getKey;
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getTextFromObject;
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getValidJsonResponseBody;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -171,7 +165,7 @@ public class YoutubeSearchExtractor extends SearchExtractor {
|
||||||
.object("user").end()
|
.object("user").end()
|
||||||
.end()
|
.end()
|
||||||
.value("continuation", page.getId())
|
.value("continuation", page.getId())
|
||||||
.end().done().getBytes("UTF-8");
|
.end().done().getBytes(UTF_8);
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
final Map<String, List<String>> headers = new HashMap<>();
|
final Map<String, List<String>> headers = new HashMap<>();
|
||||||
|
|
|
@ -4,7 +4,6 @@ import com.grack.nanojson.JsonArray;
|
||||||
import com.grack.nanojson.JsonObject;
|
import com.grack.nanojson.JsonObject;
|
||||||
import com.grack.nanojson.JsonParser;
|
import com.grack.nanojson.JsonParser;
|
||||||
import com.grack.nanojson.JsonParserException;
|
import com.grack.nanojson.JsonParserException;
|
||||||
|
|
||||||
import org.jsoup.Jsoup;
|
import org.jsoup.Jsoup;
|
||||||
import org.jsoup.nodes.Document;
|
import org.jsoup.nodes.Document;
|
||||||
import org.jsoup.nodes.Element;
|
import org.jsoup.nodes.Element;
|
||||||
|
@ -29,17 +28,7 @@ import org.schabi.newpipe.extractor.localization.TimeAgoPatternsManager;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.ItagItem;
|
import org.schabi.newpipe.extractor.services.youtube.ItagItem;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
|
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelLinkHandlerFactory;
|
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelLinkHandlerFactory;
|
||||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
import org.schabi.newpipe.extractor.stream.*;
|
||||||
import org.schabi.newpipe.extractor.stream.Description;
|
|
||||||
import org.schabi.newpipe.extractor.stream.Frameset;
|
|
||||||
import org.schabi.newpipe.extractor.stream.Stream;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamSegment;
|
|
||||||
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.utils.Parser;
|
import org.schabi.newpipe.extractor.utils.Parser;
|
||||||
import org.schabi.newpipe.extractor.utils.Utils;
|
import org.schabi.newpipe.extractor.utils.Utils;
|
||||||
|
|
||||||
|
@ -47,26 +36,13 @@ import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.util.*;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.fixThumbnailUrl;
|
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.*;
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getJsonResponse;
|
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getTextFromObject;
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getUrlFromNavigationEndpoint;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.JsonUtils.EMPTY_STRING;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -102,17 +78,21 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////*/
|
/*//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Nullable private static String cachedDeobfuscationCode = null;
|
@Nullable
|
||||||
@Nullable private String playerJsUrl = null;
|
private static String cachedDeobfuscationCode = null;
|
||||||
|
@Nullable
|
||||||
|
private String playerJsUrl = null;
|
||||||
|
|
||||||
private JsonArray initialAjaxJson;
|
private JsonArray initialAjaxJson;
|
||||||
private JsonObject initialData;
|
private JsonObject initialData;
|
||||||
@Nonnull private final Map<String, String> videoInfoPage = new HashMap<>();
|
@Nonnull
|
||||||
|
private final Map<String, String> videoInfoPage = new HashMap<>();
|
||||||
private JsonObject playerResponse;
|
private JsonObject playerResponse;
|
||||||
private JsonObject videoPrimaryInfoRenderer;
|
private JsonObject videoPrimaryInfoRenderer;
|
||||||
private JsonObject videoSecondaryInfoRenderer;
|
private JsonObject videoSecondaryInfoRenderer;
|
||||||
private int ageLimit = -1;
|
private int ageLimit = -1;
|
||||||
@Nullable private List<SubtitlesStream> subtitles = null;
|
@Nullable
|
||||||
|
private List<SubtitlesStream> subtitles = null;
|
||||||
|
|
||||||
public YoutubeStreamExtractor(StreamingService service, LinkHandler linkHandler) {
|
public YoutubeStreamExtractor(StreamingService service, LinkHandler linkHandler) {
|
||||||
super(service, linkHandler);
|
super(service, linkHandler);
|
||||||
|
@ -224,7 +204,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public Description getDescription() {
|
public Description getDescription() throws ParsingException {
|
||||||
assertPageFetched();
|
assertPageFetched();
|
||||||
// description with more info on links
|
// description with more info on links
|
||||||
try {
|
try {
|
||||||
|
@ -234,8 +214,15 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
// age-restricted videos cause a ParsingException here
|
// age-restricted videos cause a ParsingException here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String description = playerResponse.getObject("videoDetails").getString("shortDescription");
|
||||||
|
if (description == null) {
|
||||||
|
final JsonObject descriptionObject = playerResponse.getObject("microformat")
|
||||||
|
.getObject("playerMicroformatRenderer").getObject("description");
|
||||||
|
description = getTextFromObject(descriptionObject);
|
||||||
|
}
|
||||||
|
|
||||||
// raw non-html description
|
// raw non-html description
|
||||||
return new Description(playerResponse.getObject("videoDetails").getString("shortDescription"), Description.PLAIN_TEXT);
|
return new Description(description, Description.PLAIN_TEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -780,8 +767,6 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private String getDeobfuscationFuncName(final String playerCode) throws DeobfuscateException {
|
private String getDeobfuscationFuncName(final String playerCode) throws DeobfuscateException {
|
||||||
Parser.RegexException exception = null;
|
Parser.RegexException exception = null;
|
||||||
for (final String regex : REGEXES) {
|
for (final String regex : REGEXES) {
|
||||||
|
@ -1079,8 +1064,10 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
// Search for correct panel containing the data
|
// Search for correct panel containing the data
|
||||||
for (int i = 0; i < panels.size(); i++) {
|
for (int i = 0; i < panels.size(); i++) {
|
||||||
if (panels.getObject(i).getObject("engagementPanelSectionListRenderer")
|
final String panelIdentifier = panels.getObject(i).getObject("engagementPanelSectionListRenderer")
|
||||||
.getString("panelIdentifier").equals("engagement-panel-macro-markers")) {
|
.getString("panelIdentifier");
|
||||||
|
if (panelIdentifier.equals("engagement-panel-macro-markers-description-chapters")
|
||||||
|
|| panelIdentifier.equals("engagement-panel-macro-markers")) {
|
||||||
segmentsArray = panels.getObject(i).getObject("engagementPanelSectionListRenderer")
|
segmentsArray = panels.getObject(i).getObject("engagementPanelSectionListRenderer")
|
||||||
.getObject("content").getObject("macroMarkersListRenderer").getArray("contents");
|
.getObject("content").getObject("macroMarkersListRenderer").getArray("contents");
|
||||||
break;
|
break;
|
||||||
|
@ -1129,6 +1116,6 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
public List<MetaInfo> getMetaInfo() throws ParsingException {
|
public List<MetaInfo> getMetaInfo() throws ParsingException {
|
||||||
return YoutubeParsingHelper.getMetaInfo(
|
return YoutubeParsingHelper.getMetaInfo(
|
||||||
initialData.getObject("contents").getObject("twoColumnWatchNextResults")
|
initialData.getObject("contents").getObject("twoColumnWatchNextResults")
|
||||||
.getObject("results").getObject("results").getArray("contents"));
|
.getObject("results").getObject("results").getArray("contents"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,8 @@ import java.time.OffsetDateTime;
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.fixThumbnailUrl;
|
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.*;
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getTextFromObject;
|
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getUrlFromNavigationEndpoint;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.JsonUtils.EMPTY_STRING;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -15,6 +15,8 @@ import java.net.URLEncoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.UTF_8;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Created by Christian Schabesberger on 28.09.16.
|
* Created by Christian Schabesberger on 28.09.16.
|
||||||
*
|
*
|
||||||
|
@ -37,8 +39,6 @@ import java.util.List;
|
||||||
|
|
||||||
public class YoutubeSuggestionExtractor extends SuggestionExtractor {
|
public class YoutubeSuggestionExtractor extends SuggestionExtractor {
|
||||||
|
|
||||||
public static final String CHARSET_UTF_8 = "UTF-8";
|
|
||||||
|
|
||||||
public YoutubeSuggestionExtractor(StreamingService service) {
|
public YoutubeSuggestionExtractor(StreamingService service) {
|
||||||
super(service);
|
super(service);
|
||||||
}
|
}
|
||||||
|
@ -52,8 +52,8 @@ public class YoutubeSuggestionExtractor extends SuggestionExtractor {
|
||||||
+ "?client=" + "youtube" //"firefox" for JSON, 'toolbar' for xml
|
+ "?client=" + "youtube" //"firefox" for JSON, 'toolbar' for xml
|
||||||
+ "&jsonp=" + "JP"
|
+ "&jsonp=" + "JP"
|
||||||
+ "&ds=" + "yt"
|
+ "&ds=" + "yt"
|
||||||
+ "&gl=" + URLEncoder.encode(getExtractorContentCountry().getCountryCode(), CHARSET_UTF_8)
|
+ "&gl=" + URLEncoder.encode(getExtractorContentCountry().getCountryCode(), UTF_8)
|
||||||
+ "&q=" + URLEncoder.encode(query, CHARSET_UTF_8);
|
+ "&q=" + URLEncoder.encode(query, UTF_8);
|
||||||
|
|
||||||
String response = dl.get(url, getExtractorLocalization()).responseBody();
|
String response = dl.get(url, getExtractorLocalization()).responseBody();
|
||||||
// trim JSONP part "JP(...)"
|
// trim JSONP part "JP(...)"
|
||||||
|
|
|
@ -69,7 +69,15 @@ public class YoutubeTrendingExtractor extends KioskExtractor<StreamInfoItem> {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getName() throws ParsingException {
|
public String getName() throws ParsingException {
|
||||||
String name = getTextFromObject(initialData.getObject("header").getObject("feedTabbedHeaderRenderer").getObject("title"));
|
final JsonObject header = initialData.getObject("header");
|
||||||
|
JsonObject title = null;
|
||||||
|
if (header.has("feedTabbedHeaderRenderer")) {
|
||||||
|
title = header.getObject("feedTabbedHeaderRenderer").getObject("title");
|
||||||
|
} else if (header.has("c4TabbedHeaderRenderer")) {
|
||||||
|
title = header.getObject("c4TabbedHeaderRenderer").getObject("title");
|
||||||
|
}
|
||||||
|
|
||||||
|
String name = getTextFromObject(title);
|
||||||
if (!isNullOrEmpty(name)) {
|
if (!isNullOrEmpty(name)) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,9 @@ import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.UTF_8;
|
||||||
|
|
||||||
public class YoutubeSearchQueryHandlerFactory extends SearchQueryHandlerFactory {
|
public class YoutubeSearchQueryHandlerFactory extends SearchQueryHandlerFactory {
|
||||||
public static final String CHARSET_UTF_8 = "UTF-8";
|
|
||||||
|
|
||||||
public static final String ALL = "all";
|
public static final String ALL = "all";
|
||||||
public static final String VIDEOS = "videos";
|
public static final String VIDEOS = "videos";
|
||||||
|
@ -37,21 +38,21 @@ public class YoutubeSearchQueryHandlerFactory extends SearchQueryHandlerFactory
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case VIDEOS:
|
case VIDEOS:
|
||||||
return SEARCH_URL + URLEncoder.encode(searchString, CHARSET_UTF_8) + "&sp=EgIQAQ%253D%253D";
|
return SEARCH_URL + URLEncoder.encode(searchString, UTF_8) + "&sp=EgIQAQ%253D%253D";
|
||||||
case CHANNELS:
|
case CHANNELS:
|
||||||
return SEARCH_URL + URLEncoder.encode(searchString, CHARSET_UTF_8) + "&sp=EgIQAg%253D%253D";
|
return SEARCH_URL + URLEncoder.encode(searchString, UTF_8) + "&sp=EgIQAg%253D%253D";
|
||||||
case PLAYLISTS:
|
case PLAYLISTS:
|
||||||
return SEARCH_URL + URLEncoder.encode(searchString, CHARSET_UTF_8) + "&sp=EgIQAw%253D%253D";
|
return SEARCH_URL + URLEncoder.encode(searchString, UTF_8) + "&sp=EgIQAw%253D%253D";
|
||||||
case MUSIC_SONGS:
|
case MUSIC_SONGS:
|
||||||
case MUSIC_VIDEOS:
|
case MUSIC_VIDEOS:
|
||||||
case MUSIC_ALBUMS:
|
case MUSIC_ALBUMS:
|
||||||
case MUSIC_PLAYLISTS:
|
case MUSIC_PLAYLISTS:
|
||||||
case MUSIC_ARTISTS:
|
case MUSIC_ARTISTS:
|
||||||
return MUSIC_SEARCH_URL + URLEncoder.encode(searchString, CHARSET_UTF_8);
|
return MUSIC_SEARCH_URL + URLEncoder.encode(searchString, UTF_8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SEARCH_URL + URLEncoder.encode(searchString, CHARSET_UTF_8);
|
return SEARCH_URL + URLEncoder.encode(searchString, UTF_8);
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
throw new ParsingException("Could not encode query", e);
|
throw new ParsingException("Could not encode query", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class YoutubeStreamLinkHandlerFactory extends LinkHandlerFactory {
|
public class YoutubeStreamLinkHandlerFactory extends LinkHandlerFactory {
|
||||||
|
|
||||||
private static final Pattern YOUTUBE_VIDEO_ID_REGEX_PATTERN = Pattern.compile("([a-zA-Z0-9_-]{11})");
|
private static final Pattern YOUTUBE_VIDEO_ID_REGEX_PATTERN = Pattern.compile("^([a-zA-Z0-9_-]{11})");
|
||||||
private static final YoutubeStreamLinkHandlerFactory instance = new YoutubeStreamLinkHandlerFactory();
|
private static final YoutubeStreamLinkHandlerFactory instance = new YoutubeStreamLinkHandlerFactory();
|
||||||
|
|
||||||
private YoutubeStreamLinkHandlerFactory() {
|
private YoutubeStreamLinkHandlerFactory() {
|
||||||
|
@ -183,10 +183,10 @@ public class YoutubeStreamLinkHandlerFactory extends LinkHandlerFactory {
|
||||||
// there is no break-statement here on purpose so the next code-block gets also run for hooktube
|
// there is no break-statement here on purpose so the next code-block gets also run for hooktube
|
||||||
}
|
}
|
||||||
|
|
||||||
case "WWW.INVIDIO.US":
|
|
||||||
case "DEV.INVIDIO.US":
|
|
||||||
case "INVIDIO.US":
|
case "INVIDIO.US":
|
||||||
case "VID.ENCRYPTIONIN.SPACE":
|
case "DEV.INVIDIO.US":
|
||||||
|
case "WWW.INVIDIO.US":
|
||||||
|
case "REDIRECT.INVIDIOUS.IO":
|
||||||
case "INVIDIOUS.SNOPYTA.ORG":
|
case "INVIDIOUS.SNOPYTA.ORG":
|
||||||
case "YEWTU.BE":
|
case "YEWTU.BE":
|
||||||
case "TUBE.CONNECT.CAFE":
|
case "TUBE.CONNECT.CAFE":
|
||||||
|
@ -197,7 +197,11 @@ public class YoutubeStreamLinkHandlerFactory extends LinkHandlerFactory {
|
||||||
case "INVIDIOUS.XYZ":
|
case "INVIDIOUS.XYZ":
|
||||||
case "VID.MINT.LGBT":
|
case "VID.MINT.LGBT":
|
||||||
case "INVIDIOU.SITE":
|
case "INVIDIOU.SITE":
|
||||||
case "INVIDIOUS.FDN.FR": { // code-block for hooktube.com and Invidious instances
|
case "INVIDIOUS.FDN.FR":
|
||||||
|
case "INVIDIOUS.048596.XYZ":
|
||||||
|
case "INVIDIOUS.ZEE.LI":
|
||||||
|
case "VID.PUFFYAN.US":
|
||||||
|
case "YTPRIVATE.COM": { // code-block for hooktube.com and Invidious instances
|
||||||
if (path.equals("watch")) {
|
if (path.equals("watch")) {
|
||||||
String viewQueryValue = Utils.getQueryValue(url, "v");
|
String viewQueryValue = Utils.getQueryValue(url, "v");
|
||||||
if (viewQueryValue != null) {
|
if (viewQueryValue != null) {
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
package org.schabi.newpipe.extractor.stream;
|
package org.schabi.newpipe.extractor.stream;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
||||||
|
|
||||||
public class Description implements Serializable {
|
public class Description implements Serializable {
|
||||||
|
|
||||||
public static final int HTML = 1;
|
public static final int HTML = 1;
|
||||||
public static final int MARKDOWN = 2;
|
public static final int MARKDOWN = 2;
|
||||||
public static final int PLAIN_TEXT = 3;
|
public static final int PLAIN_TEXT = 3;
|
||||||
public static final Description emptyDescription = new Description("", PLAIN_TEXT);
|
public static final Description emptyDescription = new Description(EMPTY_STRING, PLAIN_TEXT);
|
||||||
|
|
||||||
private String content;
|
private String content;
|
||||||
private int type;
|
private int type;
|
||||||
|
@ -28,4 +31,17 @@ public class Description implements Serializable {
|
||||||
public int getType() {
|
public int getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Description that = (Description) o;
|
||||||
|
return type == that.type && Objects.equals(content, that.content);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(content, type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ public class StreamInfo extends Info {
|
||||||
return getInfo(service.getStreamExtractor(url));
|
return getInfo(service.getStreamExtractor(url));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static StreamInfo getInfo(StreamExtractor extractor) throws ExtractionException, IOException {
|
public static StreamInfo getInfo(StreamExtractor extractor) throws ExtractionException, IOException {
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
StreamInfo streamInfo;
|
StreamInfo streamInfo;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -13,7 +13,6 @@ import java.util.List;
|
||||||
public class JsonUtils {
|
public class JsonUtils {
|
||||||
public static final JsonObject EMPTY_OBJECT = new JsonObject();
|
public static final JsonObject EMPTY_OBJECT = new JsonObject();
|
||||||
public static final JsonArray EMPTY_ARRAY = new JsonArray();
|
public static final JsonArray EMPTY_ARRAY = new JsonArray();
|
||||||
public static final String EMPTY_STRING = "";
|
|
||||||
|
|
||||||
private JsonUtils() {
|
private JsonUtils() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.UTF_8;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Created by Christian Schabesberger on 02.02.16.
|
* Created by Christian Schabesberger on 02.02.16.
|
||||||
*
|
*
|
||||||
|
@ -69,9 +71,9 @@ public class Parser {
|
||||||
} else {
|
} else {
|
||||||
// only pass input to exception message when it is not too long
|
// only pass input to exception message when it is not too long
|
||||||
if (input.length() > 1024) {
|
if (input.length() > 1024) {
|
||||||
throw new RegexException("failed to find pattern \"" + pat.pattern());
|
throw new RegexException("failed to find pattern \"" + pat.pattern() + "\"");
|
||||||
} else {
|
} else {
|
||||||
throw new RegexException("failed to find pattern \"" + pat.pattern() + " inside of " + input + "\"");
|
throw new RegexException("failed to find pattern \"" + pat.pattern() + "\" inside of \"" + input + "\"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,7 +89,7 @@ public class Parser {
|
||||||
for (String arg : input.split("&")) {
|
for (String arg : input.split("&")) {
|
||||||
String[] splitArg = arg.split("=");
|
String[] splitArg = arg.split("=");
|
||||||
if (splitArg.length > 1) {
|
if (splitArg.length > 1) {
|
||||||
map.put(splitArg[0], URLDecoder.decode(splitArg[1], "UTF-8"));
|
map.put(splitArg[0], URLDecoder.decode(splitArg[1], UTF_8));
|
||||||
} else {
|
} else {
|
||||||
map.put(splitArg[0], "");
|
map.put(splitArg[0], "");
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,16 +6,14 @@ import java.io.UnsupportedEncodingException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class Utils {
|
public class Utils {
|
||||||
|
|
||||||
public static final String HTTP = "http://";
|
public static final String HTTP = "http://";
|
||||||
public static final String HTTPS = "https://";
|
public static final String HTTPS = "https://";
|
||||||
|
public static final String UTF_8 = "UTF-8";
|
||||||
|
public static final String EMPTY_STRING = "";
|
||||||
|
|
||||||
private Utils() {
|
private Utils() {
|
||||||
//no instance
|
//no instance
|
||||||
|
@ -117,7 +115,7 @@ public class Utils {
|
||||||
|
|
||||||
String query;
|
String query;
|
||||||
try {
|
try {
|
||||||
query = URLDecoder.decode(params[0], "UTF-8");
|
query = URLDecoder.decode(params[0], UTF_8);
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
System.err.println("Cannot decode string with UTF-8. using the string without decoding");
|
System.err.println("Cannot decode string with UTF-8. using the string without decoding");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -126,7 +124,7 @@ public class Utils {
|
||||||
|
|
||||||
if (query.equals(parameterName)) {
|
if (query.equals(parameterName)) {
|
||||||
try {
|
try {
|
||||||
return URLDecoder.decode(params[1], "UTF-8");
|
return URLDecoder.decode(params[1], UTF_8);
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
System.err.println("Cannot decode string with UTF-8. using the string without decoding");
|
System.err.println("Cannot decode string with UTF-8. using the string without decoding");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -200,6 +198,7 @@ public class Utils {
|
||||||
/**
|
/**
|
||||||
* If the provided url is a Google search redirect, then the actual url is extracted from the
|
* If the provided url is a Google search redirect, then the actual url is extracted from the
|
||||||
* {@code url=} query value and returned, otherwise the original url is returned.
|
* {@code url=} query value and returned, otherwise the original url is returned.
|
||||||
|
*
|
||||||
* @param url the url which can possibly be a Google search redirect
|
* @param url the url which can possibly be a Google search redirect
|
||||||
* @return an url with no Google search redirects
|
* @return an url with no Google search redirects
|
||||||
*/
|
*/
|
||||||
|
@ -208,7 +207,7 @@ public class Utils {
|
||||||
try {
|
try {
|
||||||
final URL decoded = Utils.stringToURL(url);
|
final URL decoded = Utils.stringToURL(url);
|
||||||
if (decoded.getHost().contains("google") && decoded.getPath().equals("/url")) {
|
if (decoded.getHost().contains("google") && decoded.getPath().equals("/url")) {
|
||||||
return URLDecoder.decode(Parser.matchGroup1("&url=([^&]+)(?:&|$)", url), "UTF-8");
|
return URLDecoder.decode(Parser.matchGroup1("&url=([^&]+)(?:&|$)", url), UTF_8);
|
||||||
}
|
}
|
||||||
} catch (final Exception ignored) {
|
} catch (final Exception ignored) {
|
||||||
}
|
}
|
||||||
|
@ -231,12 +230,12 @@ public class Utils {
|
||||||
return map == null || map.isEmpty();
|
return map == null || map.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isWhitespace(final int c){
|
public static boolean isWhitespace(final int c) {
|
||||||
return c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r';
|
return c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r';
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isBlank(final String string) {
|
public static boolean isBlank(final String string) {
|
||||||
if (string == null || string.isEmpty()) {
|
if (isNullOrEmpty(string)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,10 +262,10 @@ public class Utils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String join(final String delimiter, final String mapJoin,
|
public static String join(final String delimiter, final String mapJoin,
|
||||||
final Map<? extends CharSequence, ? extends CharSequence> elements) {
|
final Map<? extends CharSequence, ? extends CharSequence> elements) {
|
||||||
final List<String> list = new LinkedList<>();
|
final List<String> list = new LinkedList<>();
|
||||||
for (final Map.Entry<? extends CharSequence, ? extends CharSequence> entry : elements
|
for (final Map.Entry<? extends CharSequence, ? extends CharSequence> entry : elements
|
||||||
.entrySet()) {
|
.entrySet()) {
|
||||||
list.add(entry.getKey() + mapJoin + entry.getValue());
|
list.add(entry.getKey() + mapJoin + entry.getValue());
|
||||||
}
|
}
|
||||||
return join(delimiter, list);
|
return join(delimiter, list);
|
||||||
|
|
|
@ -26,16 +26,13 @@ public class MediaCCCRecentListExtractorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore("TODO fix")
|
|
||||||
public void testStreamList() throws Exception {
|
public void testStreamList() throws Exception {
|
||||||
final List<StreamInfoItem> items = extractor.getInitialPage().getItems();
|
final List<StreamInfoItem> items = extractor.getInitialPage().getItems();
|
||||||
assertEquals(100, items.size());
|
assertEquals(100, items.size());
|
||||||
for (final StreamInfoItem item: items) {
|
for (final StreamInfoItem item: items) {
|
||||||
assertFalse(isNullOrEmpty(item.getName()));
|
assertFalse(isNullOrEmpty(item.getName()));
|
||||||
assertTrue(item.getDuration() > 0);
|
assertTrue(item.getDuration() > 0);
|
||||||
assertTrue(isNullOrEmpty(item.getUploaderName())); // we do not get the uploader name
|
|
||||||
assertTrue(item.getUploadDate().offsetDateTime().isBefore(OffsetDateTime.now()));
|
assertTrue(item.getUploadDate().offsetDateTime().isBefore(OffsetDateTime.now()));
|
||||||
assertTrue(item.getUploadDate().offsetDateTime().isAfter(OffsetDateTime.now().minusYears(1)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,6 @@ public class PeertubeAccountExtractorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore("TODO fix")
|
|
||||||
public void testSubscriberCount() throws ParsingException {
|
public void testSubscriberCount() throws ParsingException {
|
||||||
assertTrue("Wrong subscriber count", extractor.getSubscriberCount() >= 500);
|
assertTrue("Wrong subscriber count", extractor.getSubscriberCount() >= 500);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import org.junit.BeforeClass;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
||||||
|
import org.schabi.newpipe.extractor.ExtractorAsserts;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubePlaylistExtractor;
|
import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubePlaylistExtractor;
|
||||||
|
@ -51,9 +52,8 @@ public class PeertubePlaylistExtractorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore("TODO fix")
|
|
||||||
public void testGetStreamCount() throws ParsingException {
|
public void testGetStreamCount() throws ParsingException {
|
||||||
assertEquals(35, extractor.getStreamCount());
|
ExtractorAsserts.assertAtLeast(39, extractor.getStreamCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -62,7 +62,6 @@ public class PeertubePlaylistExtractorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore("TODO fix")
|
|
||||||
public void testGetSubChannelName() throws ParsingException {
|
public void testGetSubChannelName() throws ParsingException {
|
||||||
assertEquals("SHOCKING !", extractor.getSubChannelName());
|
assertEquals("SHOCKING !", extractor.getSubChannelName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,13 +94,6 @@ public class PeertubeStreamExtractorTest {
|
||||||
@Override public Locale expectedLanguageInfo() { return Locale.forLanguageTag("en"); }
|
@Override public Locale expectedLanguageInfo() { return Locale.forLanguageTag("en"); }
|
||||||
@Override public List<String> expectedTags() { return Arrays.asList("framasoft", "peertube"); }
|
@Override public List<String> expectedTags() { return Arrays.asList("framasoft", "peertube"); }
|
||||||
@Override public int expectedStreamSegmentsCount() { return 0; }
|
@Override public int expectedStreamSegmentsCount() { return 0; }
|
||||||
|
|
||||||
@Override
|
|
||||||
@Test
|
|
||||||
@Ignore("TODO fix")
|
|
||||||
public void testSubChannelName() throws Exception {
|
|
||||||
super.testSubChannelName();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("TODO fix")
|
@Ignore("TODO fix")
|
||||||
|
|
|
@ -42,7 +42,6 @@ public class SoundcloudPlaylistExtractorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore("TODO fix")
|
|
||||||
public void testName() {
|
public void testName() {
|
||||||
assertEquals("THE PERFECT LUV TAPE®️", extractor.getName());
|
assertEquals("THE PERFECT LUV TAPE®️", extractor.getName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ public class SoundcloudStreamLinkHandlerFactoryTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
@Ignore("TODO fix")
|
|
||||||
public void getIdWithNullAsUrl() throws ParsingException {
|
public void getIdWithNullAsUrl() throws ParsingException {
|
||||||
linkHandler.fromUrl(null).getId();
|
linkHandler.fromUrl(null).getId();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import static java.util.Collections.singletonList;
|
||||||
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
|
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
|
||||||
import static org.schabi.newpipe.extractor.services.DefaultTests.assertNoDuplicatedItems;
|
import static org.schabi.newpipe.extractor.services.DefaultTests.assertNoDuplicatedItems;
|
||||||
import static org.schabi.newpipe.extractor.services.soundcloud.linkHandler.SoundcloudSearchQueryHandlerFactory.*;
|
import static org.schabi.newpipe.extractor.services.soundcloud.linkHandler.SoundcloudSearchQueryHandlerFactory.*;
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.UTF_8;
|
||||||
|
|
||||||
public class SoundcloudSearchExtractorTest {
|
public class SoundcloudSearchExtractorTest {
|
||||||
|
|
||||||
|
@ -33,6 +34,7 @@ public class SoundcloudSearchExtractorTest {
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
@Override public SearchExtractor extractor() { return extractor; }
|
@Override public SearchExtractor extractor() { return extractor; }
|
||||||
@Override public StreamingService expectedService() { return SoundCloud; }
|
@Override public StreamingService expectedService() { return SoundCloud; }
|
||||||
@Override public String expectedName() { return QUERY; }
|
@Override public String expectedName() { return QUERY; }
|
||||||
|
@ -41,6 +43,7 @@ public class SoundcloudSearchExtractorTest {
|
||||||
@Override public String expectedOriginalUrlContains() { return "soundcloud.com/search?q=" + urlEncode(QUERY); }
|
@Override public String expectedOriginalUrlContains() { return "soundcloud.com/search?q=" + urlEncode(QUERY); }
|
||||||
@Override public String expectedSearchString() { return QUERY; }
|
@Override public String expectedSearchString() { return QUERY; }
|
||||||
@Nullable @Override public String expectedSearchSuggestion() { return null; }
|
@Nullable @Override public String expectedSearchSuggestion() { return null; }
|
||||||
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Tracks extends DefaultSearchExtractorTest {
|
public static class Tracks extends DefaultSearchExtractorTest {
|
||||||
|
@ -54,6 +57,7 @@ public class SoundcloudSearchExtractorTest {
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
@Override public SearchExtractor extractor() { return extractor; }
|
@Override public SearchExtractor extractor() { return extractor; }
|
||||||
@Override public StreamingService expectedService() { return SoundCloud; }
|
@Override public StreamingService expectedService() { return SoundCloud; }
|
||||||
@Override public String expectedName() { return QUERY; }
|
@Override public String expectedName() { return QUERY; }
|
||||||
|
@ -62,8 +66,8 @@ public class SoundcloudSearchExtractorTest {
|
||||||
@Override public String expectedOriginalUrlContains() { return "soundcloud.com/search/tracks?q=" + urlEncode(QUERY); }
|
@Override public String expectedOriginalUrlContains() { return "soundcloud.com/search/tracks?q=" + urlEncode(QUERY); }
|
||||||
@Override public String expectedSearchString() { return QUERY; }
|
@Override public String expectedSearchString() { return QUERY; }
|
||||||
@Nullable @Override public String expectedSearchSuggestion() { return null; }
|
@Nullable @Override public String expectedSearchSuggestion() { return null; }
|
||||||
|
|
||||||
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.STREAM; }
|
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.STREAM; }
|
||||||
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Users extends DefaultSearchExtractorTest {
|
public static class Users extends DefaultSearchExtractorTest {
|
||||||
|
@ -77,6 +81,7 @@ public class SoundcloudSearchExtractorTest {
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
@Override public SearchExtractor extractor() { return extractor; }
|
@Override public SearchExtractor extractor() { return extractor; }
|
||||||
@Override public StreamingService expectedService() { return SoundCloud; }
|
@Override public StreamingService expectedService() { return SoundCloud; }
|
||||||
@Override public String expectedName() { return QUERY; }
|
@Override public String expectedName() { return QUERY; }
|
||||||
|
@ -85,8 +90,8 @@ public class SoundcloudSearchExtractorTest {
|
||||||
@Override public String expectedOriginalUrlContains() { return "soundcloud.com/search/users?q=" + urlEncode(QUERY); }
|
@Override public String expectedOriginalUrlContains() { return "soundcloud.com/search/users?q=" + urlEncode(QUERY); }
|
||||||
@Override public String expectedSearchString() { return QUERY; }
|
@Override public String expectedSearchString() { return QUERY; }
|
||||||
@Nullable @Override public String expectedSearchSuggestion() { return null; }
|
@Nullable @Override public String expectedSearchSuggestion() { return null; }
|
||||||
|
|
||||||
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.CHANNEL; }
|
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.CHANNEL; }
|
||||||
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Playlists extends DefaultSearchExtractorTest {
|
public static class Playlists extends DefaultSearchExtractorTest {
|
||||||
|
@ -100,6 +105,7 @@ public class SoundcloudSearchExtractorTest {
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
@Override public SearchExtractor extractor() { return extractor; }
|
@Override public SearchExtractor extractor() { return extractor; }
|
||||||
@Override public StreamingService expectedService() { return SoundCloud; }
|
@Override public StreamingService expectedService() { return SoundCloud; }
|
||||||
@Override public String expectedName() { return QUERY; }
|
@Override public String expectedName() { return QUERY; }
|
||||||
|
@ -108,13 +114,12 @@ public class SoundcloudSearchExtractorTest {
|
||||||
@Override public String expectedOriginalUrlContains() { return "soundcloud.com/search/playlists?q=" + urlEncode(QUERY); }
|
@Override public String expectedOriginalUrlContains() { return "soundcloud.com/search/playlists?q=" + urlEncode(QUERY); }
|
||||||
@Override public String expectedSearchString() { return QUERY; }
|
@Override public String expectedSearchString() { return QUERY; }
|
||||||
@Nullable @Override public String expectedSearchSuggestion() { return null; }
|
@Nullable @Override public String expectedSearchSuggestion() { return null; }
|
||||||
|
|
||||||
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.PLAYLIST; }
|
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.PLAYLIST; }
|
||||||
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class PagingTest {
|
public static class PagingTest {
|
||||||
@Test
|
@Test
|
||||||
@Ignore("TODO fix")
|
|
||||||
public void duplicatedItemsCheck() throws Exception {
|
public void duplicatedItemsCheck() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
NewPipe.init(DownloaderTestImpl.getInstance());
|
||||||
final SearchExtractor extractor = SoundCloud.getSearchExtractor("cirque du soleil", singletonList(TRACKS), "");
|
final SearchExtractor extractor = SoundCloud.getSearchExtractor("cirque du soleil", singletonList(TRACKS), "");
|
||||||
|
@ -129,7 +134,7 @@ public class SoundcloudSearchExtractorTest {
|
||||||
|
|
||||||
private static String urlEncode(String value) {
|
private static String urlEncode(String value) {
|
||||||
try {
|
try {
|
||||||
return URLEncoder.encode(value, CHARSET_UTF_8);
|
return URLEncoder.encode(value, UTF_8);
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ public class SoundcloudSearchQHTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore("TODO fix")
|
|
||||||
public void testRegularValues() throws Exception {
|
public void testRegularValues() throws Exception {
|
||||||
assertEquals("https://api-v2.soundcloud.com/search?q=asdf&limit=10&offset=0",
|
assertEquals("https://api-v2.soundcloud.com/search?q=asdf&limit=10&offset=0",
|
||||||
removeClientId(SoundCloud.getSearchQHFactory().fromQuery("asdf").getUrl()));
|
removeClientId(SoundCloud.getSearchQHFactory().fromQuery("asdf").getUrl()));
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.schabi.newpipe.extractor.services.youtube;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.schabi.newpipe.downloader.DownloaderFactory;
|
||||||
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
|
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
|
||||||
|
@ -12,21 +13,29 @@ import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.services.BaseChannelExtractorTest;
|
import org.schabi.newpipe.extractor.services.BaseChannelExtractorTest;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeChannelExtractor;
|
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeChannelExtractor;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import java.io.IOException;
|
||||||
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertEmpty;
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl;
|
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl;
|
||||||
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
import static org.schabi.newpipe.extractor.services.DefaultTests.*;
|
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestGetPageInNewExtractor;
|
||||||
|
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestMoreItems;
|
||||||
|
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestRelatedItems;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for {@link ChannelExtractor}
|
* Test for {@link ChannelExtractor}
|
||||||
*/
|
*/
|
||||||
public class YoutubeChannelExtractorTest {
|
public class YoutubeChannelExtractorTest {
|
||||||
|
|
||||||
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/channel/";
|
||||||
|
|
||||||
public static class NotAvailable {
|
public static class NotAvailable {
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() {
|
public static void setUp() throws IOException {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "notAvailable"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = ContentNotAvailableException.class)
|
@Test(expected = ContentNotAvailableException.class)
|
||||||
|
@ -46,8 +55,9 @@ public class YoutubeChannelExtractorTest {
|
||||||
|
|
||||||
public static class NotSupported {
|
public static class NotSupported {
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() {
|
public static void setUp() throws IOException {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "notSupported"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = ContentNotSupportedException.class)
|
@Test(expected = ContentNotSupportedException.class)
|
||||||
|
@ -63,7 +73,8 @@ public class YoutubeChannelExtractorTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "gronkh"));
|
||||||
extractor = (YoutubeChannelExtractor) YouTube
|
extractor = (YoutubeChannelExtractor) YouTube
|
||||||
.getChannelExtractor("http://www.youtube.com/user/Gronkh");
|
.getChannelExtractor("http://www.youtube.com/user/Gronkh");
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
|
@ -116,8 +127,8 @@ public class YoutubeChannelExtractorTest {
|
||||||
// ChannelExtractor
|
// ChannelExtractor
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
@Ignore("TODO fix, character ü makes problems")
|
||||||
@Test
|
@Test
|
||||||
@Ignore("TODO fix")
|
|
||||||
public void testDescription() throws Exception {
|
public void testDescription() throws Exception {
|
||||||
assertTrue(extractor.getDescription().contains("Zart im Schmelz und süffig im Abgang. Ungebremster Spieltrieb"));
|
assertTrue(extractor.getDescription().contains("Zart im Schmelz und süffig im Abgang. Ungebremster Spieltrieb"));
|
||||||
}
|
}
|
||||||
|
@ -154,7 +165,8 @@ public class YoutubeChannelExtractorTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "VSauce"));
|
||||||
extractor = (YoutubeChannelExtractor) YouTube
|
extractor = (YoutubeChannelExtractor) YouTube
|
||||||
.getChannelExtractor("https://www.youtube.com/user/Vsauce");
|
.getChannelExtractor("https://www.youtube.com/user/Vsauce");
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
|
@ -245,22 +257,13 @@ public class YoutubeChannelExtractorTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "kurzgesagt"));
|
||||||
extractor = (YoutubeChannelExtractor) YouTube
|
extractor = (YoutubeChannelExtractor) YouTube
|
||||||
.getChannelExtractor("https://www.youtube.com/channel/UCsXVk37bltHxD1rDPwtNM8Q");
|
.getChannelExtractor("https://www.youtube.com/channel/UCsXVk37bltHxD1rDPwtNM8Q");
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Additional Testing
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetPageInNewExtractor() throws Exception {
|
|
||||||
final ChannelExtractor newExtractor = YouTube.getChannelExtractor(extractor.getUrl());
|
|
||||||
defaultTestGetPageInNewExtractor(extractor, newExtractor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Extractor
|
// Extractor
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
@ -342,12 +345,33 @@ public class YoutubeChannelExtractorTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class KurzgesagtAdditional {
|
||||||
|
|
||||||
|
private static YoutubeChannelExtractor extractor;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUp() throws Exception {
|
||||||
|
// Test is not deterministic, mocks can't be used
|
||||||
|
NewPipe.init(DownloaderTestImpl.getInstance());
|
||||||
|
extractor = (YoutubeChannelExtractor) YouTube
|
||||||
|
.getChannelExtractor("https://www.youtube.com/channel/UCsXVk37bltHxD1rDPwtNM8Q");
|
||||||
|
extractor.fetchPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetPageInNewExtractor() throws Exception {
|
||||||
|
final ChannelExtractor newExtractor = YouTube.getChannelExtractor(extractor.getUrl());
|
||||||
|
defaultTestGetPageInNewExtractor(extractor, newExtractor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class CaptainDisillusion implements BaseChannelExtractorTest {
|
public static class CaptainDisillusion implements BaseChannelExtractorTest {
|
||||||
private static YoutubeChannelExtractor extractor;
|
private static YoutubeChannelExtractor extractor;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "captainDisillusion"));
|
||||||
extractor = (YoutubeChannelExtractor) YouTube
|
extractor = (YoutubeChannelExtractor) YouTube
|
||||||
.getChannelExtractor("https://www.youtube.com/user/CaptainDisillusion/videos");
|
.getChannelExtractor("https://www.youtube.com/user/CaptainDisillusion/videos");
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
|
@ -436,7 +460,8 @@ public class YoutubeChannelExtractorTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "random"));
|
||||||
extractor = (YoutubeChannelExtractor) YouTube
|
extractor = (YoutubeChannelExtractor) YouTube
|
||||||
.getChannelExtractor("https://www.youtube.com/channel/UCUaQMQS9lY5lit3vurpXQ6w");
|
.getChannelExtractor("https://www.youtube.com/channel/UCUaQMQS9lY5lit3vurpXQ6w");
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package org.schabi.newpipe.extractor.services.youtube;
|
package org.schabi.newpipe.extractor.services.youtube;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
import org.schabi.newpipe.downloader.DownloaderFactory;
|
||||||
import org.schabi.newpipe.extractor.ListExtractor;
|
import org.schabi.newpipe.extractor.ListExtractor;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
|
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
|
||||||
|
@ -23,14 +22,15 @@ import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestRela
|
||||||
/**
|
/**
|
||||||
* A class that tests multiple channels and ranges of "time ago".
|
* A class that tests multiple channels and ranges of "time ago".
|
||||||
*/
|
*/
|
||||||
@Ignore("Should be ran manually from time to time, as it's too time consuming.")
|
|
||||||
public class YoutubeChannelLocalizationTest {
|
public class YoutubeChannelLocalizationTest {
|
||||||
private static final boolean DEBUG = true;
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/channel/";
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAllSupportedLocalizations() throws Exception {
|
public void testAllSupportedLocalizations() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "localization"));
|
||||||
|
|
||||||
testLocalizationsFor("https://www.youtube.com/user/NBCNews");
|
testLocalizationsFor("https://www.youtube.com/user/NBCNews");
|
||||||
testLocalizationsFor("https://www.youtube.com/channel/UCcmpeVbSSQlZRvHfdC-CRwg/videos");
|
testLocalizationsFor("https://www.youtube.com/channel/UCcmpeVbSSQlZRvHfdC-CRwg/videos");
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package org.schabi.newpipe.extractor.services.youtube;
|
package org.schabi.newpipe.extractor.services.youtube;
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
import org.schabi.newpipe.downloader.DownloaderFactory;
|
||||||
import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage;
|
import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.Page;
|
import org.schabi.newpipe.extractor.Page;
|
||||||
|
@ -16,10 +17,15 @@ import org.schabi.newpipe.extractor.utils.Utils;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
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 static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
|
|
||||||
public class YoutubeCommentsExtractorTest {
|
public class YoutubeCommentsExtractorTest {
|
||||||
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/comments/";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test a "normal" YouTube
|
* Test a "normal" YouTube
|
||||||
*/
|
*/
|
||||||
|
@ -30,7 +36,8 @@ public class YoutubeCommentsExtractorTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "thomas"));
|
||||||
extractor = (YoutubeCommentsExtractor) YouTube
|
extractor = (YoutubeCommentsExtractor) YouTube
|
||||||
.getCommentsExtractor(url);
|
.getCommentsExtractor(url);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
|
@ -117,13 +124,15 @@ public class YoutubeCommentsExtractorTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "empty"));
|
||||||
extractor = (YoutubeCommentsExtractor) YouTube
|
extractor = (YoutubeCommentsExtractor) YouTube
|
||||||
.getCommentsExtractor(url);
|
.getCommentsExtractor(url);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore("TODO fix")
|
||||||
public void testGetCommentsAllData() throws IOException, ExtractionException {
|
public void testGetCommentsAllData() throws IOException, ExtractionException {
|
||||||
final InfoItemsPage<CommentsInfoItem> comments = extractor.getInitialPage();
|
final InfoItemsPage<CommentsInfoItem> comments = extractor.getInitialPage();
|
||||||
|
|
||||||
|
@ -155,7 +164,8 @@ public class YoutubeCommentsExtractorTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "hearted"));
|
||||||
extractor = (YoutubeCommentsExtractor) YouTube
|
extractor = (YoutubeCommentsExtractor) YouTube
|
||||||
.getCommentsExtractor(url);
|
.getCommentsExtractor(url);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
|
@ -181,7 +191,7 @@ public class YoutubeCommentsExtractorTest {
|
||||||
assertFalse(Utils.isBlank(c.getUrl()));
|
assertFalse(Utils.isBlank(c.getUrl()));
|
||||||
assertFalse(c.getLikeCount() < 0);
|
assertFalse(c.getLikeCount() < 0);
|
||||||
assertFalse(Utils.isBlank(c.getCommentText()));
|
assertFalse(Utils.isBlank(c.getCommentText()));
|
||||||
if (c.getHeartedByUploader()) {
|
if (c.isHeartedByUploader()) {
|
||||||
heartedByUploader = true;
|
heartedByUploader = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,4 +199,41 @@ public class YoutubeCommentsExtractorTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Pinned {
|
||||||
|
private final static String url = "https://www.youtube.com/watch?v=bjFtFMilb34";
|
||||||
|
private static YoutubeCommentsExtractor extractor;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUp() throws Exception {
|
||||||
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "pinned"));
|
||||||
|
extractor = (YoutubeCommentsExtractor) YouTube
|
||||||
|
.getCommentsExtractor(url);
|
||||||
|
extractor.fetchPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCommentsAllData() throws IOException, ExtractionException {
|
||||||
|
final InfoItemsPage<CommentsInfoItem> comments = extractor.getInitialPage();
|
||||||
|
|
||||||
|
DefaultTests.defaultTestListOfItems(YouTube, comments.getItems(), comments.getErrors());
|
||||||
|
|
||||||
|
for (CommentsInfoItem c : comments.getItems()) {
|
||||||
|
assertFalse(Utils.isBlank(c.getUploaderUrl()));
|
||||||
|
assertFalse(Utils.isBlank(c.getUploaderName()));
|
||||||
|
assertFalse(Utils.isBlank(c.getUploaderAvatarUrl()));
|
||||||
|
assertFalse(Utils.isBlank(c.getCommentId()));
|
||||||
|
assertFalse(Utils.isBlank(c.getName()));
|
||||||
|
assertFalse(Utils.isBlank(c.getTextualUploadDate()));
|
||||||
|
assertNotNull(c.getUploadDate());
|
||||||
|
assertFalse(Utils.isBlank(c.getThumbnailUrl()));
|
||||||
|
assertFalse(Utils.isBlank(c.getUrl()));
|
||||||
|
assertFalse(c.getLikeCount() < 0);
|
||||||
|
assertFalse(Utils.isBlank(c.getCommentText()));
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue("First comment isn't pinned", comments.getItems().get(0).isPinned());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,24 +2,29 @@ package org.schabi.newpipe.extractor.services.youtube;
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
import org.schabi.newpipe.downloader.DownloaderFactory;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.services.BaseListExtractorTest;
|
import org.schabi.newpipe.extractor.services.BaseListExtractorTest;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeFeedExtractor;
|
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeFeedExtractor;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
import static org.schabi.newpipe.extractor.services.DefaultTests.assertNoMoreItems;
|
import static org.schabi.newpipe.extractor.services.DefaultTests.assertNoMoreItems;
|
||||||
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestRelatedItems;
|
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestRelatedItems;
|
||||||
|
|
||||||
public class YoutubeFeedExtractorTest {
|
public class YoutubeFeedExtractorTest {
|
||||||
|
|
||||||
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/feed/";
|
||||||
|
|
||||||
public static class Kurzgesagt implements BaseListExtractorTest {
|
public static class Kurzgesagt implements BaseListExtractorTest {
|
||||||
private static YoutubeFeedExtractor extractor;
|
private static YoutubeFeedExtractor extractor;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH));
|
||||||
extractor = (YoutubeFeedExtractor) YouTube
|
extractor = (YoutubeFeedExtractor) YouTube
|
||||||
.getFeedExtractor("https://www.youtube.com/user/Kurzgesagt");
|
.getFeedExtractor("https://www.youtube.com/user/Kurzgesagt");
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
|
|
|
@ -2,7 +2,7 @@ package org.schabi.newpipe.extractor.services.youtube;
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
import org.schabi.newpipe.downloader.DownloaderFactory;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.services.BaseListExtractorTest;
|
import org.schabi.newpipe.extractor.services.BaseListExtractorTest;
|
||||||
|
@ -14,12 +14,16 @@ import static org.schabi.newpipe.extractor.services.DefaultTests.assertNoMoreIte
|
||||||
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestRelatedItems;
|
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestRelatedItems;
|
||||||
|
|
||||||
public class YoutubeKioskExtractorTest {
|
public class YoutubeKioskExtractorTest {
|
||||||
|
|
||||||
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/kiosk/";
|
||||||
|
|
||||||
public static class Trending implements BaseListExtractorTest {
|
public static class Trending implements BaseListExtractorTest {
|
||||||
private static YoutubeTrendingExtractor extractor;
|
private static YoutubeTrendingExtractor extractor;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "trending"));
|
||||||
extractor = (YoutubeTrendingExtractor) YouTube.getKioskList().getDefaultKioskExtractor();
|
extractor = (YoutubeTrendingExtractor) YouTube.getKioskList().getDefaultKioskExtractor();
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
package org.schabi.newpipe.extractor.services.youtube;
|
package org.schabi.newpipe.extractor.services.youtube;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import org.hamcrest.MatcherAssert;
|
import org.hamcrest.MatcherAssert;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -26,6 +20,12 @@ import org.schabi.newpipe.extractor.services.youtube.YoutubeMixPlaylistExtractor
|
||||||
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeMixPlaylistExtractor;
|
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeMixPlaylistExtractor;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.containsString;
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
import static org.hamcrest.CoreMatchers.startsWith;
|
import static org.hamcrest.CoreMatchers.startsWith;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
@ -43,7 +43,7 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
private static final String VIDEO_ID = "_AzeUSL9lZc";
|
private static final String VIDEO_ID = "_AzeUSL9lZc";
|
||||||
private static final String VIDEO_TITLE =
|
private static final String VIDEO_TITLE =
|
||||||
"Most Beautiful And Emotional Piano: Anime Music Shigatsu wa Kimi no Uso OST IMO";
|
"Most Beautiful And Emotional Piano: Anime Music Shigatsu wa Kimi no Uso OST IMO";
|
||||||
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/mix/";
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/mix/";
|
||||||
private static final Map<String, String> dummyCookie
|
private static final Map<String, String> dummyCookie
|
||||||
= Collections.singletonMap(YoutubeMixPlaylistExtractor.COOKIE_NAME, "whatever");
|
= Collections.singletonMap(YoutubeMixPlaylistExtractor.COOKIE_NAME, "whatever");
|
||||||
|
|
||||||
|
@ -134,9 +134,9 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
YoutubeParsingHelper.resetClientVersionAndKey();
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "mixWithIndex"));
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "mixWithIndex"));
|
||||||
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
||||||
.getPlaylistExtractor(
|
.getPlaylistExtractor(
|
||||||
"https://www.youtube.com/watch?v=" + VIDEO_ID_NUMBER_13 + "&list=RD"
|
"https://www.youtube.com/watch?v=" + VIDEO_ID_NUMBER_13 + "&list=RD"
|
||||||
+ VIDEO_ID + INDEX);
|
+ VIDEO_ID + INDEX);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,8 +165,8 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
@Test
|
@Test
|
||||||
public void getPage() throws Exception {
|
public void getPage() throws Exception {
|
||||||
final InfoItemsPage<StreamInfoItem> streams = extractor.getPage(
|
final InfoItemsPage<StreamInfoItem> streams = extractor.getPage(
|
||||||
new Page("https://www.youtube.com/watch?v=" + VIDEO_ID_NUMBER_13 + "&list=RD"
|
new Page("https://www.youtube.com/watch?v=" + VIDEO_ID_NUMBER_13 + "&list=RD"
|
||||||
+ VIDEO_ID + INDEX + PBJ, dummyCookie));
|
+ VIDEO_ID + INDEX + PBJ, dummyCookie));
|
||||||
assertFalse(streams.getItems().isEmpty());
|
assertFalse(streams.getItems().isEmpty());
|
||||||
assertTrue(streams.hasNextPage());
|
assertTrue(streams.hasNextPage());
|
||||||
}
|
}
|
||||||
|
@ -204,9 +204,9 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
YoutubeParsingHelper.resetClientVersionAndKey();
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "myMix"));
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "myMix"));
|
||||||
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
||||||
.getPlaylistExtractor(
|
.getPlaylistExtractor(
|
||||||
"https://www.youtube.com/watch?v=" + VIDEO_ID + "&list=RDMM"
|
"https://www.youtube.com/watch?v=" + VIDEO_ID + "&list=RDMM"
|
||||||
+ VIDEO_ID);
|
+ VIDEO_ID);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,11 +238,12 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
@Test
|
@Test
|
||||||
public void getPage() throws Exception {
|
public void getPage() throws Exception {
|
||||||
final InfoItemsPage<StreamInfoItem> streams =
|
final InfoItemsPage<StreamInfoItem> streams =
|
||||||
extractor.getPage(new Page("https://www.youtube.com/watch?v=" + VIDEO_ID
|
extractor.getPage(new Page("https://www.youtube.com/watch?v=" + VIDEO_ID
|
||||||
+ "&list=RDMM" + VIDEO_ID + PBJ, dummyCookie));
|
+ "&list=RDMM" + VIDEO_ID + PBJ, dummyCookie));
|
||||||
assertFalse(streams.getItems().isEmpty());
|
assertFalse(streams.getItems().isEmpty());
|
||||||
assertTrue(streams.hasNextPage());
|
assertTrue(streams.hasNextPage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getContinuations() throws Exception {
|
public void getContinuations() throws Exception {
|
||||||
InfoItemsPage<StreamInfoItem> streams = extractor.getInitialPage();
|
InfoItemsPage<StreamInfoItem> streams = extractor.getInitialPage();
|
||||||
|
@ -290,8 +291,8 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
@Test(expected = ExtractionException.class)
|
@Test(expected = ExtractionException.class)
|
||||||
public void invalidVideoId() throws Exception {
|
public void invalidVideoId() throws Exception {
|
||||||
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
||||||
.getPlaylistExtractor(
|
.getPlaylistExtractor(
|
||||||
"https://www.youtube.com/watch?v=" + "abcde" + "&list=RD" + "abcde");
|
"https://www.youtube.com/watch?v=" + "abcde" + "&list=RD" + "abcde");
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
extractor.getName();
|
extractor.getName();
|
||||||
}
|
}
|
||||||
|
@ -309,9 +310,9 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
YoutubeParsingHelper.resetClientVersionAndKey();
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "channelMix"));
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "channelMix"));
|
||||||
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
||||||
.getPlaylistExtractor(
|
.getPlaylistExtractor(
|
||||||
"https://www.youtube.com/watch?v=" + VIDEO_ID_OF_CHANNEL
|
"https://www.youtube.com/watch?v=" + VIDEO_ID_OF_CHANNEL
|
||||||
+ "&list=RDCM" + CHANNEL_ID);
|
+ "&list=RDCM" + CHANNEL_ID);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,8 +340,8 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
@Test
|
@Test
|
||||||
public void getPage() throws Exception {
|
public void getPage() throws Exception {
|
||||||
final InfoItemsPage<StreamInfoItem> streams = extractor.getPage(
|
final InfoItemsPage<StreamInfoItem> streams = extractor.getPage(
|
||||||
new Page("https://www.youtube.com/watch?v=" + VIDEO_ID_OF_CHANNEL
|
new Page("https://www.youtube.com/watch?v=" + VIDEO_ID_OF_CHANNEL
|
||||||
+ "&list=RDCM" + CHANNEL_ID + PBJ, dummyCookie));
|
+ "&list=RDCM" + CHANNEL_ID + PBJ, dummyCookie));
|
||||||
assertFalse(streams.getItems().isEmpty());
|
assertFalse(streams.getItems().isEmpty());
|
||||||
assertTrue(streams.hasNextPage());
|
assertTrue(streams.hasNextPage());
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package org.schabi.newpipe.extractor.services.youtube;
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
import org.schabi.newpipe.downloader.DownloaderFactory;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
|
@ -13,9 +13,13 @@ import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class YoutubeParsingHelperTest {
|
public class YoutubeParsingHelperTest {
|
||||||
|
|
||||||
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/";
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() {
|
public static void setUp() throws IOException {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "youtubeParsingHelper"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -6,10 +6,9 @@ import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.Suite;
|
import org.junit.runners.Suite;
|
||||||
import org.junit.runners.Suite.SuiteClasses;
|
import org.junit.runners.Suite.SuiteClasses;
|
||||||
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
import org.schabi.newpipe.downloader.DownloaderFactory;
|
||||||
import org.schabi.newpipe.extractor.ListExtractor;
|
import org.schabi.newpipe.extractor.ListExtractor;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
|
||||||
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
|
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistExtractor;
|
import org.schabi.newpipe.extractor.playlist.PlaylistExtractor;
|
||||||
|
@ -22,13 +21,18 @@ import org.schabi.newpipe.extractor.services.youtube.YoutubePlaylistExtractorTes
|
||||||
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubePlaylistExtractor;
|
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubePlaylistExtractor;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import static junit.framework.TestCase.assertFalse;
|
import static junit.framework.TestCase.assertFalse;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl;
|
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl;
|
||||||
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
import static org.schabi.newpipe.extractor.services.DefaultTests.*;
|
import static org.schabi.newpipe.extractor.services.DefaultTests.assertNoMoreItems;
|
||||||
|
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestGetPageInNewExtractor;
|
||||||
|
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestListOfItems;
|
||||||
|
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestMoreItems;
|
||||||
|
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestRelatedItems;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for {@link YoutubePlaylistExtractor}
|
* Test for {@link YoutubePlaylistExtractor}
|
||||||
|
@ -38,10 +42,13 @@ import static org.schabi.newpipe.extractor.services.DefaultTests.*;
|
||||||
LearningPlaylist.class, ContinuationsTests.class})
|
LearningPlaylist.class, ContinuationsTests.class})
|
||||||
public class YoutubePlaylistExtractorTest {
|
public class YoutubePlaylistExtractorTest {
|
||||||
|
|
||||||
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/playlist/";
|
||||||
|
|
||||||
public static class NotAvailable {
|
public static class NotAvailable {
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() {
|
public static void setUp() throws IOException {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "notAvailable"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = ContentNotAvailableException.class)
|
@Test(expected = ContentNotAvailableException.class)
|
||||||
|
@ -65,7 +72,8 @@ public class YoutubePlaylistExtractorTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "TimelessPopHits"));
|
||||||
extractor = (YoutubePlaylistExtractor) YouTube
|
extractor = (YoutubePlaylistExtractor) YouTube
|
||||||
.getPlaylistExtractor("http://www.youtube.com/watch?v=lp-EO5I60KA&list=PLMC9KNkIncKtPzgY-5rmhvj7fax8fdxoj");
|
.getPlaylistExtractor("http://www.youtube.com/watch?v=lp-EO5I60KA&list=PLMC9KNkIncKtPzgY-5rmhvj7fax8fdxoj");
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
|
@ -162,7 +170,8 @@ public class YoutubePlaylistExtractorTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "huge"));
|
||||||
extractor = (YoutubePlaylistExtractor) YouTube
|
extractor = (YoutubePlaylistExtractor) YouTube
|
||||||
.getPlaylistExtractor("https://www.youtube.com/watch?v=8SbUC-UaAxE&list=PLWwAypAcFRgKAIIFqBr9oy-ZYZnixa_Fj");
|
.getPlaylistExtractor("https://www.youtube.com/watch?v=8SbUC-UaAxE&list=PLWwAypAcFRgKAIIFqBr9oy-ZYZnixa_Fj");
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
|
@ -274,7 +283,8 @@ public class YoutubePlaylistExtractorTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "learning"));
|
||||||
extractor = (YoutubePlaylistExtractor) YouTube
|
extractor = (YoutubePlaylistExtractor) YouTube
|
||||||
.getPlaylistExtractor("https://www.youtube.com/playlist?list=PL8dPuuaLjXtOAKed_MxxWBNaPno5h3Zs8");
|
.getPlaylistExtractor("https://www.youtube.com/playlist?list=PL8dPuuaLjXtOAKed_MxxWBNaPno5h3Zs8");
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
|
@ -370,8 +380,9 @@ public class YoutubePlaylistExtractorTest {
|
||||||
public static class ContinuationsTests {
|
public static class ContinuationsTests {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() {
|
public static void setUp() throws IOException {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "continuations"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -42,6 +42,8 @@ public class YoutubeStreamLinkHandlerFactoryTest {
|
||||||
invalidUrls.add("https://www.youtube.com/watch?v=jZViOEv90d");
|
invalidUrls.add("https://www.youtube.com/watch?v=jZViOEv90d");
|
||||||
invalidUrls.add("https://www.youtube.com/watchjZViOEv90d");
|
invalidUrls.add("https://www.youtube.com/watchjZViOEv90d");
|
||||||
invalidUrls.add("https://www.youtube.com/");
|
invalidUrls.add("https://www.youtube.com/");
|
||||||
|
invalidUrls.add("https://www.youtube.com/channel/UCBR8-60-B28hp2BmDPdntcQ");
|
||||||
|
invalidUrls.add("https://invidio.us/channel/UCBR8-60-B28hp2BmDPdntcQ");
|
||||||
for (String invalidUrl : invalidUrls) {
|
for (String invalidUrl : invalidUrls) {
|
||||||
Throwable exception = null;
|
Throwable exception = null;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -12,25 +12,25 @@ import org.schabi.newpipe.extractor.subscription.SubscriptionItem;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
import static org.schabi.newpipe.FileUtils.resolveTestResource;
|
import static org.schabi.newpipe.FileUtils.resolveTestResource;
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.UTF_8;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for {@link YoutubeSubscriptionExtractor}
|
* Test for {@link YoutubeSubscriptionExtractor}
|
||||||
*/
|
*/
|
||||||
public class YoutubeSubscriptionExtractorTest {
|
public class YoutubeSubscriptionExtractorTest {
|
||||||
|
|
||||||
|
|
||||||
private static YoutubeSubscriptionExtractor subscriptionExtractor;
|
private static YoutubeSubscriptionExtractor subscriptionExtractor;
|
||||||
private static LinkHandlerFactory urlHandler;
|
private static LinkHandlerFactory urlHandler;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setupClass() {
|
public static void setupClass() {
|
||||||
|
//Doesn't make network requests
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
NewPipe.init(DownloaderTestImpl.getInstance());
|
||||||
subscriptionExtractor = new YoutubeSubscriptionExtractor(ServiceList.YouTube);
|
subscriptionExtractor = new YoutubeSubscriptionExtractor(ServiceList.YouTube);
|
||||||
urlHandler = ServiceList.YouTube.getChannelLHFactory();
|
urlHandler = ServiceList.YouTube.getChannelLHFactory();
|
||||||
|
@ -53,7 +53,7 @@ public class YoutubeSubscriptionExtractorTest {
|
||||||
@Test
|
@Test
|
||||||
public void testEmptySourceException() throws Exception {
|
public void testEmptySourceException() throws Exception {
|
||||||
final List<SubscriptionItem> items = subscriptionExtractor.fromInputStream(
|
final List<SubscriptionItem> items = subscriptionExtractor.fromInputStream(
|
||||||
new ByteArrayInputStream("[]".getBytes(StandardCharsets.UTF_8)));
|
new ByteArrayInputStream("[]".getBytes(UTF_8)));
|
||||||
assertTrue(items.isEmpty());
|
assertTrue(items.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ public class YoutubeSubscriptionExtractorTest {
|
||||||
public void testSubscriptionWithEmptyTitleInSource() throws Exception {
|
public void testSubscriptionWithEmptyTitleInSource() throws Exception {
|
||||||
final String source = "[{\"snippet\":{\"resourceId\":{\"channelId\":\"UCEOXxzW2vU0P-0THehuIIeg\"}}}]";
|
final String source = "[{\"snippet\":{\"resourceId\":{\"channelId\":\"UCEOXxzW2vU0P-0THehuIIeg\"}}}]";
|
||||||
final List<SubscriptionItem> items = subscriptionExtractor.fromInputStream(
|
final List<SubscriptionItem> items = subscriptionExtractor.fromInputStream(
|
||||||
new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8)));
|
new ByteArrayInputStream(source.getBytes(UTF_8)));
|
||||||
|
|
||||||
assertEquals(1, items.size());
|
assertEquals(1, items.size());
|
||||||
assertEquals(ServiceList.YouTube.getServiceId(), items.get(0).getServiceId());
|
assertEquals(ServiceList.YouTube.getServiceId(), items.get(0).getServiceId());
|
||||||
|
@ -74,7 +74,7 @@ public class YoutubeSubscriptionExtractorTest {
|
||||||
final String source = "[{\"snippet\":{\"resourceId\":{\"channelId\":\"gibberish\"},\"title\":\"name1\"}}," +
|
final String source = "[{\"snippet\":{\"resourceId\":{\"channelId\":\"gibberish\"},\"title\":\"name1\"}}," +
|
||||||
"{\"snippet\":{\"resourceId\":{\"channelId\":\"UCEOXxzW2vU0P-0THehuIIeg\"},\"title\":\"name2\"}}]";
|
"{\"snippet\":{\"resourceId\":{\"channelId\":\"UCEOXxzW2vU0P-0THehuIIeg\"},\"title\":\"name2\"}}]";
|
||||||
final List<SubscriptionItem> items = subscriptionExtractor.fromInputStream(
|
final List<SubscriptionItem> items = subscriptionExtractor.fromInputStream(
|
||||||
new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8)));
|
new ByteArrayInputStream(source.getBytes(UTF_8)));
|
||||||
|
|
||||||
assertEquals(1, items.size());
|
assertEquals(1, items.size());
|
||||||
assertEquals(ServiceList.YouTube.getServiceId(), items.get(0).getServiceId());
|
assertEquals(ServiceList.YouTube.getServiceId(), items.get(0).getServiceId());
|
||||||
|
@ -98,7 +98,7 @@ public class YoutubeSubscriptionExtractorTest {
|
||||||
|
|
||||||
for (String invalidContent : invalidList) {
|
for (String invalidContent : invalidList) {
|
||||||
try {
|
try {
|
||||||
byte[] bytes = invalidContent.getBytes(StandardCharsets.UTF_8);
|
byte[] bytes = invalidContent.getBytes(UTF_8);
|
||||||
subscriptionExtractor.fromInputStream(new ByteArrayInputStream(bytes));
|
subscriptionExtractor.fromInputStream(new ByteArrayInputStream(bytes));
|
||||||
fail("Extracting from \"" + invalidContent + "\" didn't throw an exception");
|
fail("Extracting from \"" + invalidContent + "\" didn't throw an exception");
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
|
|
|
@ -22,7 +22,7 @@ package org.schabi.newpipe.extractor.services.youtube;
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
import org.schabi.newpipe.downloader.DownloaderFactory;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.extractor.localization.Localization;
|
import org.schabi.newpipe.extractor.localization.Localization;
|
||||||
|
@ -37,11 +37,15 @@ import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
* Test for {@link SuggestionExtractor}
|
* Test for {@link SuggestionExtractor}
|
||||||
*/
|
*/
|
||||||
public class YoutubeSuggestionExtractorTest {
|
public class YoutubeSuggestionExtractorTest {
|
||||||
|
|
||||||
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/suggestions/";
|
||||||
|
|
||||||
private static SuggestionExtractor suggestionExtractor;
|
private static SuggestionExtractor suggestionExtractor;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance(), new Localization("de", "DE"));
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + ""), new Localization("de", "DE"));
|
||||||
suggestionExtractor = YouTube.getSuggestionExtractor();
|
suggestionExtractor = YouTube.getSuggestionExtractor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ package org.schabi.newpipe.extractor.services.youtube;
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
import org.schabi.newpipe.downloader.DownloaderFactory;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
import org.schabi.newpipe.extractor.kiosk.KioskInfo;
|
import org.schabi.newpipe.extractor.kiosk.KioskInfo;
|
||||||
|
@ -36,14 +36,17 @@ import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
* Test for {@link KioskInfo}
|
* Test for {@link KioskInfo}
|
||||||
*/
|
*/
|
||||||
public class YoutubeTrendingKioskInfoTest {
|
public class YoutubeTrendingKioskInfoTest {
|
||||||
|
|
||||||
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "kiosk";
|
||||||
|
|
||||||
static KioskInfo kioskInfo;
|
static KioskInfo kioskInfo;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp()
|
public static void setUp()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
StreamingService service = YouTube;
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH));
|
||||||
LinkHandlerFactory LinkHandlerFactory = service.getKioskList().getListLinkHandlerFactoryByType("Trending");
|
LinkHandlerFactory LinkHandlerFactory = ((StreamingService) YouTube).getKioskList().getListLinkHandlerFactoryByType("Trending");
|
||||||
|
|
||||||
kioskInfo = KioskInfo.getInfo(YouTube, LinkHandlerFactory.fromId("Trending").getUrl());
|
kioskInfo = KioskInfo.getInfo(YouTube, LinkHandlerFactory.fromId("Trending").getUrl());
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,14 @@ import org.schabi.newpipe.extractor.search.SearchExtractor;
|
||||||
import org.schabi.newpipe.extractor.services.DefaultSearchExtractorTest;
|
import org.schabi.newpipe.extractor.services.DefaultSearchExtractorTest;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory;
|
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
|
|
||||||
|
// Doesn't work with mocks. Makes request with different `dataToSend` i think
|
||||||
public class YoutubeMusicSearchExtractorTest {
|
public class YoutubeMusicSearchExtractorTest {
|
||||||
public static class MusicSongs extends DefaultSearchExtractorTest {
|
public static class MusicSongs extends DefaultSearchExtractorTest {
|
||||||
private static SearchExtractor extractor;
|
private static SearchExtractor extractor;
|
||||||
|
|
|
@ -1,24 +1,26 @@
|
||||||
package org.schabi.newpipe.extractor.services.youtube.search;
|
package org.schabi.newpipe.extractor.services.youtube.search;
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
import org.schabi.newpipe.downloader.DownloaderFactory;
|
||||||
import org.schabi.newpipe.extractor.*;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
|
import org.schabi.newpipe.extractor.ListExtractor;
|
||||||
|
import org.schabi.newpipe.extractor.MetaInfo;
|
||||||
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
||||||
import org.schabi.newpipe.extractor.services.DefaultSearchExtractorTest;
|
import org.schabi.newpipe.extractor.services.DefaultSearchExtractorTest;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.YoutubeService;
|
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
|
||||||
import org.schabi.newpipe.extractor.stream.Description;
|
import org.schabi.newpipe.extractor.stream.Description;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static junit.framework.TestCase.assertFalse;
|
import static junit.framework.TestCase.assertFalse;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -29,15 +31,20 @@ import static org.schabi.newpipe.extractor.services.DefaultTests.assertNoDuplica
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.CHANNELS;
|
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.CHANNELS;
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.PLAYLISTS;
|
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.PLAYLISTS;
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.VIDEOS;
|
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.VIDEOS;
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
||||||
|
|
||||||
public class YoutubeSearchExtractorTest {
|
public class YoutubeSearchExtractorTest {
|
||||||
|
|
||||||
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/search/";
|
||||||
|
|
||||||
public static class All extends DefaultSearchExtractorTest {
|
public static class All extends DefaultSearchExtractorTest {
|
||||||
private static SearchExtractor extractor;
|
private static SearchExtractor extractor;
|
||||||
private static final String QUERY = "test";
|
private static final String QUERY = "test";
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "all"));
|
||||||
extractor = YouTube.getSearchExtractor(QUERY);
|
extractor = YouTube.getSearchExtractor(QUERY);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
@ -58,7 +65,8 @@ public class YoutubeSearchExtractorTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "channel"));
|
||||||
extractor = YouTube.getSearchExtractor(QUERY, singletonList(CHANNELS), "");
|
extractor = YouTube.getSearchExtractor(QUERY, singletonList(CHANNELS), "");
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
@ -81,7 +89,8 @@ public class YoutubeSearchExtractorTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "playlist"));
|
||||||
extractor = YouTube.getSearchExtractor(QUERY, singletonList(PLAYLISTS), "");
|
extractor = YouTube.getSearchExtractor(QUERY, singletonList(PLAYLISTS), "");
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
@ -104,7 +113,8 @@ public class YoutubeSearchExtractorTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "videos"));
|
||||||
extractor = YouTube.getSearchExtractor(QUERY, singletonList(VIDEOS), "");
|
extractor = YouTube.getSearchExtractor(QUERY, singletonList(VIDEOS), "");
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
@ -128,7 +138,8 @@ public class YoutubeSearchExtractorTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "suggestions"));
|
||||||
extractor = YouTube.getSearchExtractor(QUERY, singletonList(VIDEOS), "");
|
extractor = YouTube.getSearchExtractor(QUERY, singletonList(VIDEOS), "");
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
@ -151,7 +162,8 @@ public class YoutubeSearchExtractorTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "corrected"));
|
||||||
extractor = YouTube.getSearchExtractor(QUERY, singletonList(VIDEOS), "");
|
extractor = YouTube.getSearchExtractor(QUERY, singletonList(VIDEOS), "");
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
@ -174,7 +186,8 @@ public class YoutubeSearchExtractorTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "random"));
|
||||||
extractor = YouTube.getSearchExtractor(QUERY);
|
extractor = YouTube.getSearchExtractor(QUERY);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
@ -208,7 +221,8 @@ public class YoutubeSearchExtractorTest {
|
||||||
public static class PagingTest {
|
public static class PagingTest {
|
||||||
@Test
|
@Test
|
||||||
public void duplicatedItemsCheck() throws Exception {
|
public void duplicatedItemsCheck() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "paging"));
|
||||||
final SearchExtractor extractor = YouTube.getSearchExtractor("cirque du soleil", singletonList(VIDEOS), "");
|
final SearchExtractor extractor = YouTube.getSearchExtractor("cirque du soleil", singletonList(VIDEOS), "");
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
|
|
||||||
|
@ -219,14 +233,14 @@ public class YoutubeSearchExtractorTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("TODO fix")
|
|
||||||
public static class MetaInfoTest extends DefaultSearchExtractorTest {
|
public static class MetaInfoTest extends DefaultSearchExtractorTest {
|
||||||
private static SearchExtractor extractor;
|
private static SearchExtractor extractor;
|
||||||
private static final String QUERY = "Covid";
|
private static final String QUERY = "Covid";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void clarificationTest() throws Exception {
|
public void clarificationTest() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "metaInfo"));
|
||||||
extractor = YouTube.getSearchExtractor(QUERY, singletonList(VIDEOS), "");
|
extractor = YouTube.getSearchExtractor(QUERY, singletonList(VIDEOS), "");
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import static java.util.Arrays.asList;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.*;
|
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.*;
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
||||||
|
|
||||||
public class YoutubeSearchQHTest {
|
public class YoutubeSearchQHTest {
|
||||||
|
|
||||||
|
@ -19,37 +20,37 @@ public class YoutubeSearchQHTest {
|
||||||
assertEquals("https://www.youtube.com/results?search_query=G%C3%BCl%C3%BCm", YouTube.getSearchQHFactory().fromQuery("Gülüm").getUrl());
|
assertEquals("https://www.youtube.com/results?search_query=G%C3%BCl%C3%BCm", YouTube.getSearchQHFactory().fromQuery("Gülüm").getUrl());
|
||||||
assertEquals("https://www.youtube.com/results?search_query=%3Fj%24%29H%C2%A7B", YouTube.getSearchQHFactory().fromQuery("?j$)H§B").getUrl());
|
assertEquals("https://www.youtube.com/results?search_query=%3Fj%24%29H%C2%A7B", YouTube.getSearchQHFactory().fromQuery("?j$)H§B").getUrl());
|
||||||
|
|
||||||
assertEquals("https://music.youtube.com/search?q=asdf", YouTube.getSearchQHFactory().fromQuery("asdf", asList(new String[]{MUSIC_SONGS}), "").getUrl());
|
assertEquals("https://music.youtube.com/search?q=asdf", YouTube.getSearchQHFactory().fromQuery("asdf", asList(new String[]{MUSIC_SONGS}), EMPTY_STRING).getUrl());
|
||||||
assertEquals("https://music.youtube.com/search?q=hans", YouTube.getSearchQHFactory().fromQuery("hans", asList(new String[]{MUSIC_SONGS}), "").getUrl());
|
assertEquals("https://music.youtube.com/search?q=hans", YouTube.getSearchQHFactory().fromQuery("hans", asList(new String[]{MUSIC_SONGS}), EMPTY_STRING).getUrl());
|
||||||
assertEquals("https://music.youtube.com/search?q=Poifj%26jaijf", YouTube.getSearchQHFactory().fromQuery("Poifj&jaijf", asList(new String[]{MUSIC_SONGS}), "").getUrl());
|
assertEquals("https://music.youtube.com/search?q=Poifj%26jaijf", YouTube.getSearchQHFactory().fromQuery("Poifj&jaijf", asList(new String[]{MUSIC_SONGS}), EMPTY_STRING).getUrl());
|
||||||
assertEquals("https://music.youtube.com/search?q=G%C3%BCl%C3%BCm", YouTube.getSearchQHFactory().fromQuery("Gülüm", asList(new String[]{MUSIC_SONGS}), "").getUrl());
|
assertEquals("https://music.youtube.com/search?q=G%C3%BCl%C3%BCm", YouTube.getSearchQHFactory().fromQuery("Gülüm", asList(new String[]{MUSIC_SONGS}), EMPTY_STRING).getUrl());
|
||||||
assertEquals("https://music.youtube.com/search?q=%3Fj%24%29H%C2%A7B", YouTube.getSearchQHFactory().fromQuery("?j$)H§B", asList(new String[]{MUSIC_SONGS}), "").getUrl());
|
assertEquals("https://music.youtube.com/search?q=%3Fj%24%29H%C2%A7B", YouTube.getSearchQHFactory().fromQuery("?j$)H§B", asList(new String[]{MUSIC_SONGS}), EMPTY_STRING).getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetContentFilter() throws Exception {
|
public void testGetContentFilter() throws Exception {
|
||||||
assertEquals(VIDEOS, YouTube.getSearchQHFactory()
|
assertEquals(VIDEOS, YouTube.getSearchQHFactory()
|
||||||
.fromQuery("", asList(new String[]{VIDEOS}), "").getContentFilters().get(0));
|
.fromQuery(EMPTY_STRING, asList(new String[]{VIDEOS}), EMPTY_STRING).getContentFilters().get(0));
|
||||||
assertEquals(CHANNELS, YouTube.getSearchQHFactory()
|
assertEquals(CHANNELS, YouTube.getSearchQHFactory()
|
||||||
.fromQuery("asdf", asList(new String[]{CHANNELS}), "").getContentFilters().get(0));
|
.fromQuery("asdf", asList(new String[]{CHANNELS}), EMPTY_STRING).getContentFilters().get(0));
|
||||||
|
|
||||||
assertEquals(MUSIC_SONGS, YouTube.getSearchQHFactory()
|
assertEquals(MUSIC_SONGS, YouTube.getSearchQHFactory()
|
||||||
.fromQuery("asdf", asList(new String[]{MUSIC_SONGS}), "").getContentFilters().get(0));
|
.fromQuery("asdf", asList(new String[]{MUSIC_SONGS}), EMPTY_STRING).getContentFilters().get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWithContentfilter() throws Exception {
|
public void testWithContentfilter() throws Exception {
|
||||||
assertEquals("https://www.youtube.com/results?search_query=asdf&sp=EgIQAQ%253D%253D", YouTube.getSearchQHFactory()
|
assertEquals("https://www.youtube.com/results?search_query=asdf&sp=EgIQAQ%253D%253D", YouTube.getSearchQHFactory()
|
||||||
.fromQuery("asdf", asList(new String[]{VIDEOS}), "").getUrl());
|
.fromQuery("asdf", asList(new String[]{VIDEOS}), EMPTY_STRING).getUrl());
|
||||||
assertEquals("https://www.youtube.com/results?search_query=asdf&sp=EgIQAg%253D%253D", YouTube.getSearchQHFactory()
|
assertEquals("https://www.youtube.com/results?search_query=asdf&sp=EgIQAg%253D%253D", YouTube.getSearchQHFactory()
|
||||||
.fromQuery("asdf", asList(new String[]{CHANNELS}), "").getUrl());
|
.fromQuery("asdf", asList(new String[]{CHANNELS}), EMPTY_STRING).getUrl());
|
||||||
assertEquals("https://www.youtube.com/results?search_query=asdf&sp=EgIQAw%253D%253D", YouTube.getSearchQHFactory()
|
assertEquals("https://www.youtube.com/results?search_query=asdf&sp=EgIQAw%253D%253D", YouTube.getSearchQHFactory()
|
||||||
.fromQuery("asdf", asList(new String[]{PLAYLISTS}), "").getUrl());
|
.fromQuery("asdf", asList(new String[]{PLAYLISTS}), EMPTY_STRING).getUrl());
|
||||||
assertEquals("https://www.youtube.com/results?search_query=asdf", YouTube.getSearchQHFactory()
|
assertEquals("https://www.youtube.com/results?search_query=asdf", YouTube.getSearchQHFactory()
|
||||||
.fromQuery("asdf", asList(new String[]{"fjiijie"}), "").getUrl());
|
.fromQuery("asdf", asList(new String[]{"fjiijie"}), EMPTY_STRING).getUrl());
|
||||||
|
|
||||||
assertEquals("https://music.youtube.com/search?q=asdf", YouTube.getSearchQHFactory()
|
assertEquals("https://music.youtube.com/search?q=asdf", YouTube.getSearchQHFactory()
|
||||||
.fromQuery("asdf", asList(new String[]{MUSIC_SONGS}), "").getUrl());
|
.fromQuery("asdf", asList(new String[]{MUSIC_SONGS}), EMPTY_STRING).getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package org.schabi.newpipe.extractor.services.youtube.stream;
|
package org.schabi.newpipe.extractor.services.youtube.stream;
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
import org.schabi.newpipe.downloader.DownloaderFactory;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest;
|
import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest;
|
||||||
|
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
|
|
||||||
|
@ -16,6 +17,7 @@ import javax.annotation.Nullable;
|
||||||
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
|
|
||||||
public class YoutubeStreamExtractorAgeRestrictedTest extends DefaultStreamExtractorTest {
|
public class YoutubeStreamExtractorAgeRestrictedTest extends DefaultStreamExtractorTest {
|
||||||
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/stream/";
|
||||||
private static final String ID = "MmBeUZqv1QA";
|
private static final String ID = "MmBeUZqv1QA";
|
||||||
private static final int TIMESTAMP = 196;
|
private static final int TIMESTAMP = 196;
|
||||||
private static final String URL = YoutubeStreamExtractorDefaultTest.BASE_URL + ID + "&t=" + TIMESTAMP;
|
private static final String URL = YoutubeStreamExtractorDefaultTest.BASE_URL + ID + "&t=" + TIMESTAMP;
|
||||||
|
@ -23,7 +25,8 @@ public class YoutubeStreamExtractorAgeRestrictedTest extends DefaultStreamExtrac
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "ageRestricted"));
|
||||||
extractor = YouTube.getStreamExtractor(URL);
|
extractor = YouTube.getStreamExtractor(URL);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,11 @@ package org.schabi.newpipe.extractor.services.youtube.stream;
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.schabi.newpipe.downloader.DownloaderFactory;
|
||||||
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest;
|
import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest;
|
||||||
|
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory;
|
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
|
@ -21,14 +21,17 @@ import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
/**
|
/**
|
||||||
* Test for {@link YoutubeStreamLinkHandlerFactory}
|
* Test for {@link YoutubeStreamLinkHandlerFactory}
|
||||||
*/
|
*/
|
||||||
|
@Ignore("Video is not available anymore")
|
||||||
public class YoutubeStreamExtractorControversialTest extends DefaultStreamExtractorTest {
|
public class YoutubeStreamExtractorControversialTest extends DefaultStreamExtractorTest {
|
||||||
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/stream/";
|
||||||
private static final String ID = "T4XJQO3qol8";
|
private static final String ID = "T4XJQO3qol8";
|
||||||
private static final String URL = YoutubeStreamExtractorDefaultTest.BASE_URL + ID;
|
private static final String URL = YoutubeStreamExtractorDefaultTest.BASE_URL + ID;
|
||||||
private static StreamExtractor extractor;
|
private static StreamExtractor extractor;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "controversial"));
|
||||||
extractor = YouTube.getStreamExtractor(URL);
|
extractor = YouTube.getStreamExtractor(URL);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
@ -53,11 +56,4 @@ public class YoutubeStreamExtractorControversialTest extends DefaultStreamExtrac
|
||||||
@Nullable @Override public String expectedTextualUploadDate() { return "2010-09-09"; }
|
@Nullable @Override public String expectedTextualUploadDate() { return "2010-09-09"; }
|
||||||
@Override public long expectedLikeCountAtLeast() { return 13300; }
|
@Override public long expectedLikeCountAtLeast() { return 13300; }
|
||||||
@Override public long expectedDislikeCountAtLeast() { return 2600; }
|
@Override public long expectedDislikeCountAtLeast() { return 2600; }
|
||||||
|
|
||||||
@Override
|
|
||||||
@Test
|
|
||||||
@Ignore("TODO fix")
|
|
||||||
public void testErrorMessage() throws Exception {
|
|
||||||
super.testErrorMessage();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,29 +3,31 @@ package org.schabi.newpipe.extractor.services.youtube.stream;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
import org.schabi.newpipe.downloader.DownloaderFactory;
|
||||||
import org.schabi.newpipe.extractor.MetaInfo;
|
import org.schabi.newpipe.extractor.MetaInfo;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
|
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest;
|
import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest;
|
||||||
|
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
|
||||||
import org.schabi.newpipe.extractor.stream.Description;
|
import org.schabi.newpipe.extractor.stream.Description;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamSegment;
|
import org.schabi.newpipe.extractor.stream.StreamSegment;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.*;
|
|
||||||
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Created by Christian Schabesberger on 30.12.15.
|
* Created by Christian Schabesberger on 30.12.15.
|
||||||
|
@ -47,12 +49,14 @@ import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
public class YoutubeStreamExtractorDefaultTest {
|
public class YoutubeStreamExtractorDefaultTest {
|
||||||
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/stream/";
|
||||||
static final String BASE_URL = "https://www.youtube.com/watch?v=";
|
static final String BASE_URL = "https://www.youtube.com/watch?v=";
|
||||||
|
|
||||||
public static class NotAvailable {
|
public static class NotAvailable {
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() {
|
public static void setUp() throws IOException {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "notAvailable"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = ContentNotAvailableException.class)
|
@Test(expected = ContentNotAvailableException.class)
|
||||||
|
@ -78,11 +82,13 @@ public class YoutubeStreamExtractorDefaultTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "pewdiwpie"));
|
||||||
extractor = YouTube.getStreamExtractor(URL);
|
extractor = YouTube.getStreamExtractor(URL);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
@Override public StreamExtractor extractor() { return extractor; }
|
@Override public StreamExtractor extractor() { return extractor; }
|
||||||
@Override public StreamingService expectedService() { return YouTube; }
|
@Override public StreamingService expectedService() { return YouTube; }
|
||||||
@Override public String expectedName() { return "Marzia & Felix - Wedding 19.08.2019"; }
|
@Override public String expectedName() { return "Marzia & Felix - Wedding 19.08.2019"; }
|
||||||
|
@ -105,9 +111,9 @@ public class YoutubeStreamExtractorDefaultTest {
|
||||||
@Override public long expectedLikeCountAtLeast() { return 5212900; }
|
@Override public long expectedLikeCountAtLeast() { return 5212900; }
|
||||||
@Override public long expectedDislikeCountAtLeast() { return 30600; }
|
@Override public long expectedDislikeCountAtLeast() { return 30600; }
|
||||||
@Override public int expectedStreamSegmentsCount() { return 0; }
|
@Override public int expectedStreamSegmentsCount() { return 0; }
|
||||||
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("TODO fix")
|
|
||||||
public static class DescriptionTestUnboxing extends DefaultStreamExtractorTest {
|
public static class DescriptionTestUnboxing extends DefaultStreamExtractorTest {
|
||||||
private static final String ID = "cV5TjZCJkuA";
|
private static final String ID = "cV5TjZCJkuA";
|
||||||
private static final String URL = BASE_URL + ID;
|
private static final String URL = BASE_URL + ID;
|
||||||
|
@ -115,11 +121,13 @@ public class YoutubeStreamExtractorDefaultTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "unboxing"));
|
||||||
extractor = YouTube.getStreamExtractor(URL);
|
extractor = YouTube.getStreamExtractor(URL);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
@Override public StreamExtractor extractor() { return extractor; }
|
@Override public StreamExtractor extractor() { return extractor; }
|
||||||
@Override public StreamingService expectedService() { return YouTube; }
|
@Override public StreamingService expectedService() { return YouTube; }
|
||||||
@Override public String expectedName() { return "This Smartphone Changes Everything..."; }
|
@Override public String expectedName() { return "This Smartphone Changes Everything..."; }
|
||||||
|
@ -142,6 +150,14 @@ public class YoutubeStreamExtractorDefaultTest {
|
||||||
@Nullable @Override public String expectedTextualUploadDate() { return "2018-06-19"; }
|
@Nullable @Override public String expectedTextualUploadDate() { return "2018-06-19"; }
|
||||||
@Override public long expectedLikeCountAtLeast() { return 340100; }
|
@Override public long expectedLikeCountAtLeast() { return 340100; }
|
||||||
@Override public long expectedDislikeCountAtLeast() { return 18700; }
|
@Override public long expectedDislikeCountAtLeast() { return 18700; }
|
||||||
|
// @formatter:on
|
||||||
|
@Override
|
||||||
|
@Test
|
||||||
|
@Ignore("TODO fix")
|
||||||
|
public void testDescription() throws Exception {
|
||||||
|
super.testDescription();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("TODO fix")
|
@Ignore("TODO fix")
|
||||||
|
@ -153,11 +169,13 @@ public class YoutubeStreamExtractorDefaultTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "ratingsDisabled"));
|
||||||
extractor = YouTube.getStreamExtractor(URL);
|
extractor = YouTube.getStreamExtractor(URL);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
@Override public StreamExtractor extractor() { return extractor; }
|
@Override public StreamExtractor extractor() { return extractor; }
|
||||||
@Override public StreamingService expectedService() { return YouTube; }
|
@Override public StreamingService expectedService() { return YouTube; }
|
||||||
@Override public String expectedName() { return "AlphaOmegaSin Fanboy Logic: Likes/Dislikes Disabled = Point Invalid Lol wtf?"; }
|
@Override public String expectedName() { return "AlphaOmegaSin Fanboy Logic: Likes/Dislikes Disabled = Point Invalid Lol wtf?"; }
|
||||||
|
@ -176,6 +194,7 @@ public class YoutubeStreamExtractorDefaultTest {
|
||||||
@Nullable @Override public String expectedTextualUploadDate() { return "2019-01-02"; }
|
@Nullable @Override public String expectedTextualUploadDate() { return "2019-01-02"; }
|
||||||
@Override public long expectedLikeCountAtLeast() { return -1; }
|
@Override public long expectedLikeCountAtLeast() { return -1; }
|
||||||
@Override public long expectedDislikeCountAtLeast() { return -1; }
|
@Override public long expectedDislikeCountAtLeast() { return -1; }
|
||||||
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class StreamSegmentsTestOstCollection extends DefaultStreamExtractorTest {
|
public static class StreamSegmentsTestOstCollection extends DefaultStreamExtractorTest {
|
||||||
|
@ -186,11 +205,13 @@ public class YoutubeStreamExtractorDefaultTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "streamSegmentsOstCollection"));
|
||||||
extractor = YouTube.getStreamExtractor(URL);
|
extractor = YouTube.getStreamExtractor(URL);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
@Override public StreamExtractor extractor() { return extractor; }
|
@Override public StreamExtractor extractor() { return extractor; }
|
||||||
@Override public StreamingService expectedService() { return YouTube; }
|
@Override public StreamingService expectedService() { return YouTube; }
|
||||||
@Override public String expectedName() { return "1 Hour - Most Epic Anime Mix - Battle Anime OST"; }
|
@Override public String expectedName() { return "1 Hour - Most Epic Anime Mix - Battle Anime OST"; }
|
||||||
|
@ -221,6 +242,7 @@ public class YoutubeStreamExtractorDefaultTest {
|
||||||
assertEquals(BASE_URL + ID + "?t=589", segment.getUrl());
|
assertEquals(BASE_URL + ID + "?t=589", segment.getUrl());
|
||||||
assertNotNull(segment.getPreviewUrl());
|
assertNotNull(segment.getPreviewUrl());
|
||||||
}
|
}
|
||||||
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class StreamSegmentsTestMaiLab extends DefaultStreamExtractorTest {
|
public static class StreamSegmentsTestMaiLab extends DefaultStreamExtractorTest {
|
||||||
|
@ -231,11 +253,13 @@ public class YoutubeStreamExtractorDefaultTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "streamSegmentsMaiLab"));
|
||||||
extractor = YouTube.getStreamExtractor(URL);
|
extractor = YouTube.getStreamExtractor(URL);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
@Override public StreamExtractor extractor() { return extractor; }
|
@Override public StreamExtractor extractor() { return extractor; }
|
||||||
@Override public StreamingService expectedService() { return YouTube; }
|
@Override public StreamingService expectedService() { return YouTube; }
|
||||||
@Override public String expectedName() { return "Vitamin D wissenschaftlich gepr\u00fcft"; }
|
@Override public String expectedName() { return "Vitamin D wissenschaftlich gepr\u00fcft"; }
|
||||||
|
@ -246,9 +270,7 @@ public class YoutubeStreamExtractorDefaultTest {
|
||||||
@Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; }
|
@Override public StreamType expectedStreamType() { return StreamType.VIDEO_STREAM; }
|
||||||
@Override public String expectedUploaderName() { return "maiLab"; }
|
@Override public String expectedUploaderName() { return "maiLab"; }
|
||||||
@Override public String expectedUploaderUrl() { return "https://www.youtube.com/channel/UCyHDQ5C6z1NDmJ4g6SerW8g"; }
|
@Override public String expectedUploaderUrl() { return "https://www.youtube.com/channel/UCyHDQ5C6z1NDmJ4g6SerW8g"; }
|
||||||
@Override public List<String> expectedDescriptionContains() {
|
@Override public List<String> expectedDescriptionContains() {return Arrays.asList("Vitamin", "2:44", "Was ist Vitamin D?");}
|
||||||
return Arrays.asList("Vitamin", "2:44", "Was ist Vitamin D?");
|
|
||||||
}
|
|
||||||
@Override public long expectedLength() { return 1010; }
|
@Override public long expectedLength() { return 1010; }
|
||||||
@Override public long expectedViewCountAtLeast() { return 815500; }
|
@Override public long expectedViewCountAtLeast() { return 815500; }
|
||||||
@Nullable @Override public String expectedUploadDate() { return "2020-11-18 00:00:00.000"; }
|
@Nullable @Override public String expectedUploadDate() { return "2020-11-18 00:00:00.000"; }
|
||||||
|
@ -256,10 +278,10 @@ public class YoutubeStreamExtractorDefaultTest {
|
||||||
@Override public long expectedLikeCountAtLeast() { return 48500; }
|
@Override public long expectedLikeCountAtLeast() { return 48500; }
|
||||||
@Override public long expectedDislikeCountAtLeast() { return 20000; }
|
@Override public long expectedDislikeCountAtLeast() { return 20000; }
|
||||||
@Override public boolean expectedHasSubtitles() { return true; }
|
@Override public boolean expectedHasSubtitles() { return true; }
|
||||||
|
|
||||||
@Override public int expectedStreamSegmentsCount() { return 7; }
|
@Override public int expectedStreamSegmentsCount() { return 7; }
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore("TODO fix")
|
|
||||||
public void testStreamSegment() throws Exception {
|
public void testStreamSegment() throws Exception {
|
||||||
final StreamSegment segment = extractor.getStreamSegments().get(1);
|
final StreamSegment segment = extractor.getStreamSegments().get(1);
|
||||||
assertEquals(164, segment.getStartTimeSeconds());
|
assertEquals(164, segment.getStartTimeSeconds());
|
||||||
|
@ -267,9 +289,15 @@ public class YoutubeStreamExtractorDefaultTest {
|
||||||
assertEquals(BASE_URL + ID + "?t=164", segment.getUrl());
|
assertEquals(BASE_URL + ID + "?t=164", segment.getUrl());
|
||||||
assertNotNull(segment.getPreviewUrl());
|
assertNotNull(segment.getPreviewUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Test
|
||||||
|
@Ignore("encoding problem")
|
||||||
|
public void testName() throws Exception {
|
||||||
|
super.testName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("TODO fix")
|
|
||||||
public static class PublicBroadcasterTest extends DefaultStreamExtractorTest {
|
public static class PublicBroadcasterTest extends DefaultStreamExtractorTest {
|
||||||
private static final String ID = "q6fgbYWsMgw";
|
private static final String ID = "q6fgbYWsMgw";
|
||||||
private static final int TIMESTAMP = 0;
|
private static final int TIMESTAMP = 0;
|
||||||
|
@ -278,11 +306,13 @@ public class YoutubeStreamExtractorDefaultTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "publicBroadcast"));
|
||||||
extractor = YouTube.getStreamExtractor(URL);
|
extractor = YouTube.getStreamExtractor(URL);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
@Override public StreamExtractor extractor() { return extractor; }
|
@Override public StreamExtractor extractor() { return extractor; }
|
||||||
@Override public StreamingService expectedService() { return YouTube; }
|
@Override public StreamingService expectedService() { return YouTube; }
|
||||||
@Override public String expectedName() { return "Was verbirgt sich am tiefsten Punkt des Ozeans?"; }
|
@Override public String expectedName() { return "Was verbirgt sich am tiefsten Punkt des Ozeans?"; }
|
||||||
|
@ -303,12 +333,27 @@ public class YoutubeStreamExtractorDefaultTest {
|
||||||
@Override public long expectedDislikeCountAtLeast() { return 500; }
|
@Override public long expectedDislikeCountAtLeast() { return 500; }
|
||||||
@Override public List<MetaInfo> expectedMetaInfo() throws MalformedURLException {
|
@Override public List<MetaInfo> expectedMetaInfo() throws MalformedURLException {
|
||||||
return Collections.singletonList(new MetaInfo(
|
return Collections.singletonList(new MetaInfo(
|
||||||
"",
|
EMPTY_STRING,
|
||||||
new Description("Funk is a German public broadcast service.", Description.PLAIN_TEXT),
|
new Description("Funk is a German public broadcast service.", Description.PLAIN_TEXT),
|
||||||
Collections.singletonList(new URL("https://de.wikipedia.org/wiki/Funk_(Medienangebot)?wprov=yicw1")),
|
Collections.singletonList(new URL("https://de.wikipedia.org/wiki/Funk_(Medienangebot)?wprov=yicw1")),
|
||||||
Collections.singletonList("Wikipedia (German)")
|
Collections.singletonList("Wikipedia (German)")
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
// @formatter:on
|
||||||
|
@Override
|
||||||
|
@Ignore("TODO fix")
|
||||||
|
@Test
|
||||||
|
public void testUploaderName() throws Exception {
|
||||||
|
super.testUploaderName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Ignore("TODO fix")
|
||||||
|
@Test
|
||||||
|
public void testMetaInfo() throws Exception {
|
||||||
|
super.testMetaInfo();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package org.schabi.newpipe.extractor.services.youtube.stream;
|
package org.schabi.newpipe.extractor.services.youtube.stream;
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
import org.schabi.newpipe.downloader.DownloaderFactory;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest;
|
import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest;
|
||||||
|
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
|
|
||||||
|
@ -16,6 +17,7 @@ import javax.annotation.Nullable;
|
||||||
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
|
|
||||||
public class YoutubeStreamExtractorLivestreamTest extends DefaultStreamExtractorTest {
|
public class YoutubeStreamExtractorLivestreamTest extends DefaultStreamExtractorTest {
|
||||||
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/stream/";
|
||||||
private static final String ID = "5qap5aO4i9A";
|
private static final String ID = "5qap5aO4i9A";
|
||||||
private static final int TIMESTAMP = 1737;
|
private static final int TIMESTAMP = 1737;
|
||||||
private static final String URL = YoutubeStreamExtractorDefaultTest.BASE_URL + ID + "&t=" + TIMESTAMP;
|
private static final String URL = YoutubeStreamExtractorDefaultTest.BASE_URL + ID + "&t=" + TIMESTAMP;
|
||||||
|
@ -23,7 +25,8 @@ public class YoutubeStreamExtractorLivestreamTest extends DefaultStreamExtractor
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "live"));
|
||||||
extractor = YouTube.getStreamExtractor(URL);
|
extractor = YouTube.getStreamExtractor(URL);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package org.schabi.newpipe.extractor.services.youtube.stream;
|
package org.schabi.newpipe.extractor.services.youtube.stream;
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.schabi.newpipe.downloader.DownloaderTestImpl;
|
import org.schabi.newpipe.downloader.DownloaderFactory;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest;
|
import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest;
|
||||||
|
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
|
|
||||||
|
@ -16,13 +17,15 @@ import javax.annotation.Nullable;
|
||||||
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
|
|
||||||
public class YoutubeStreamExtractorUnlistedTest extends DefaultStreamExtractorTest {
|
public class YoutubeStreamExtractorUnlistedTest extends DefaultStreamExtractorTest {
|
||||||
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/stream/";
|
||||||
static final String ID = "udsB8KnIJTg";
|
static final String ID = "udsB8KnIJTg";
|
||||||
static final String URL = YoutubeStreamExtractorDefaultTest.BASE_URL + ID;
|
static final String URL = YoutubeStreamExtractorDefaultTest.BASE_URL + ID;
|
||||||
private static StreamExtractor extractor;
|
private static StreamExtractor extractor;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance());
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "unlisted"));
|
||||||
extractor = YouTube.getStreamExtractor(URL);
|
extractor = YouTube.getStreamExtractor(URL);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,69 @@
|
||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"httpMethod": "GET",
|
||||||
|
"url": "https://www.youtube.com/channel/DOESNT-EXIST/videos?pbj\u003d1\u0026view\u003d0\u0026flow\u003dgrid",
|
||||||
|
"headers": {
|
||||||
|
"Accept-Language": [
|
||||||
|
"en-GB, en;q\u003d0.9"
|
||||||
|
],
|
||||||
|
"X-YouTube-Client-Name": [
|
||||||
|
"1"
|
||||||
|
],
|
||||||
|
"X-YouTube-Client-Version": [
|
||||||
|
"2.20200214.04.00"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"localization": {
|
||||||
|
"languageCode": "en",
|
||||||
|
"countryCode": "GB"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"responseCode": 404,
|
||||||
|
"responseMessage": "",
|
||||||
|
"responseHeaders": {
|
||||||
|
"alt-svc": [
|
||||||
|
"h3-29\u003d\":443\"; ma\u003d2592000,h3-T051\u003d\":443\"; ma\u003d2592000,h3-Q050\u003d\":443\"; ma\u003d2592000,h3-Q046\u003d\":443\"; ma\u003d2592000,h3-Q043\u003d\":443\"; ma\u003d2592000,quic\u003d\":443\"; ma\u003d2592000; v\u003d\"46,43\""
|
||||||
|
],
|
||||||
|
"cache-control": [
|
||||||
|
"no-cache, no-store, max-age\u003d0, must-revalidate"
|
||||||
|
],
|
||||||
|
"content-type": [
|
||||||
|
"text/html; charset\u003dutf-8"
|
||||||
|
],
|
||||||
|
"date": [
|
||||||
|
"Sat, 13 Feb 2021 19:13:39 GMT"
|
||||||
|
],
|
||||||
|
"expires": [
|
||||||
|
"Mon, 01 Jan 1990 00:00:00 GMT"
|
||||||
|
],
|
||||||
|
"p3p": [
|
||||||
|
"CP\u003d\"This is not a P3P policy! See http://support.google.com/accounts/answer/151657?hl\u003den-GB for more info.\""
|
||||||
|
],
|
||||||
|
"pragma": [
|
||||||
|
"no-cache"
|
||||||
|
],
|
||||||
|
"server": [
|
||||||
|
"ESF"
|
||||||
|
],
|
||||||
|
"set-cookie": [
|
||||||
|
"YSC\u003dbFLZyqvSsDQ; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
|
||||||
|
"VISITOR_INFO1_LIVE\u003dYgNWpn3F6Ww; Domain\u003d.youtube.com; Expires\u003dThu, 12-Aug-2021 19:13:39 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone"
|
||||||
|
],
|
||||||
|
"strict-transport-security": [
|
||||||
|
"max-age\u003d31536000"
|
||||||
|
],
|
||||||
|
"x-content-type-options": [
|
||||||
|
"nosniff"
|
||||||
|
],
|
||||||
|
"x-frame-options": [
|
||||||
|
"SAMEORIGIN"
|
||||||
|
],
|
||||||
|
"x-xss-protection": [
|
||||||
|
"0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"responseBody": "\u003chtml lang\u003d\"en-GB\" dir\u003d\"ltr\"\u003e\u003chead\u003e\u003ctitle\u003e404 Not Found\u003c/title\u003e\u003cstyle nonce\u003d\"AkiRKVBSwx7zy61zR/BBpg\"\u003e*{margin:0;padding:0;border:0}html,body{height:100%;}\u003c/style\u003e\u003clink rel\u003d\"shortcut icon\" href\u003d\"https://www.youtube.com/img/favicon.ico\" type\u003d\"image/x-icon\"\u003e\u003clink rel\u003d\"icon\" href\u003d\"https://www.youtube.com/img/favicon_32.png\" sizes\u003d\"32x32\"\u003e\u003clink rel\u003d\"icon\" href\u003d\"https://www.youtube.com/img/favicon_48.png\" sizes\u003d\"48x48\"\u003e\u003clink rel\u003d\"icon\" href\u003d\"https://www.youtube.com/img/favicon_96.png\" sizes\u003d\"96x96\"\u003e\u003clink rel\u003d\"icon\" href\u003d\"https://www.youtube.com/img/favicon_144.png\" sizes\u003d\"144x144\"\u003e\u003c/head\u003e\u003cbody\u003e\u003ciframe style\u003d\"display:block;border:0;\" src\u003d\"/error?src\u003d404\u0026amp;ifr\u003d1\u0026amp;error\u003d\" width\u003d\"100%\" height\u003d\"100%\" frameborder\u003d\"\\\" scrolling\u003d\"no\"\u003e\u003c/iframe\u003e\u003c/body\u003e\u003c/html\u003e",
|
||||||
|
"latestUrl": "https://www.youtube.com/channel/DOESNT-EXIST/videos?pbj\u003d1\u0026view\u003d0\u0026flow\u003dgrid"
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue