Merge pull request #2713 from mauriciocolli/compatibility-extractor
Use new Localization and Downloader implementations from extractor
This commit is contained in:
commit
a8e326ceea
|
@ -62,7 +62,7 @@ dependencies {
|
||||||
exclude module: 'support-annotations'
|
exclude module: 'support-annotations'
|
||||||
})
|
})
|
||||||
|
|
||||||
implementation 'com.github.teamnewpipe:NewPipeExtractor:v0.17.4'
|
implementation 'com.github.TeamNewPipe:NewPipeExtractor:5c420340ceb39'
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
testImplementation 'org.mockito:mockito-core:2.23.0'
|
testImplementation 'org.mockito:mockito-core:2.23.0'
|
||||||
|
|
||||||
|
@ -94,6 +94,7 @@ dependencies {
|
||||||
implementation 'io.reactivex.rxjava2:rxjava:2.2.2'
|
implementation 'io.reactivex.rxjava2:rxjava:2.2.2'
|
||||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
|
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
|
||||||
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
|
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
|
||||||
|
implementation 'org.ocpsoft.prettytime:prettytime:4.0.1.Final'
|
||||||
|
|
||||||
implementation "androidx.room:room-runtime:${roomDbLibVersion}"
|
implementation "androidx.room:room-runtime:${roomDbLibVersion}"
|
||||||
implementation "androidx.room:room-rxjava2:${roomDbLibVersion}"
|
implementation "androidx.room:room-rxjava2:${roomDbLibVersion}"
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
#}
|
#}
|
||||||
|
|
||||||
-dontobfuscate
|
-dontobfuscate
|
||||||
|
-keep class org.schabi.newpipe.extractor.timeago.patterns.** { *; }
|
||||||
|
-keep class org.ocpsoft.prettytime.i18n.** { *; }
|
||||||
|
|
||||||
-keep class org.mozilla.javascript.** { *; }
|
-keep class org.mozilla.javascript.** { *; }
|
||||||
|
|
||||||
-keep class org.mozilla.classfile.ClassFileWriter
|
-keep class org.mozilla.classfile.ClassFileWriter
|
||||||
|
|
|
@ -15,7 +15,7 @@ import com.squareup.leakcanary.LeakCanary;
|
||||||
import com.squareup.leakcanary.LeakDirectoryProvider;
|
import com.squareup.leakcanary.LeakDirectoryProvider;
|
||||||
import com.squareup.leakcanary.RefWatcher;
|
import com.squareup.leakcanary.RefWatcher;
|
||||||
|
|
||||||
import org.schabi.newpipe.extractor.Downloader;
|
import org.schabi.newpipe.extractor.downloader.Downloader;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -39,7 +39,7 @@ public class DebugApp extends App {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Downloader getDownloader() {
|
protected Downloader getDownloader() {
|
||||||
return org.schabi.newpipe.Downloader.init(new OkHttpClient.Builder()
|
return DownloaderImpl.init(new OkHttpClient.Builder()
|
||||||
.addNetworkInterceptor(new StethoInterceptor()));
|
.addNetworkInterceptor(new StethoInterceptor()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,13 +21,14 @@ import org.acra.config.ACRAConfiguration;
|
||||||
import org.acra.config.ACRAConfigurationException;
|
import org.acra.config.ACRAConfigurationException;
|
||||||
import org.acra.config.ConfigurationBuilder;
|
import org.acra.config.ConfigurationBuilder;
|
||||||
import org.acra.sender.ReportSenderFactory;
|
import org.acra.sender.ReportSenderFactory;
|
||||||
import org.schabi.newpipe.extractor.Downloader;
|
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
import org.schabi.newpipe.extractor.downloader.Downloader;
|
||||||
import org.schabi.newpipe.report.AcraReportSenderFactory;
|
import org.schabi.newpipe.report.AcraReportSenderFactory;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.settings.SettingsActivity;
|
import org.schabi.newpipe.settings.SettingsActivity;
|
||||||
import org.schabi.newpipe.util.ExtractorHelper;
|
import org.schabi.newpipe.util.ExtractorHelper;
|
||||||
|
import org.schabi.newpipe.util.Localization;
|
||||||
import org.schabi.newpipe.util.StateSaver;
|
import org.schabi.newpipe.util.StateSaver;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -95,7 +96,10 @@ public class App extends Application {
|
||||||
SettingsActivity.initSettings(this);
|
SettingsActivity.initSettings(this);
|
||||||
|
|
||||||
NewPipe.init(getDownloader(),
|
NewPipe.init(getDownloader(),
|
||||||
org.schabi.newpipe.util.Localization.getPreferredExtractorLocal(this));
|
Localization.getPreferredLocalization(this),
|
||||||
|
Localization.getPreferredContentCountry(this));
|
||||||
|
Localization.init();
|
||||||
|
|
||||||
StateSaver.init(this);
|
StateSaver.init(this);
|
||||||
initNotificationChannel();
|
initNotificationChannel();
|
||||||
|
|
||||||
|
@ -109,7 +113,7 @@ public class App extends Application {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Downloader getDownloader() {
|
protected Downloader getDownloader() {
|
||||||
return org.schabi.newpipe.Downloader.init(null);
|
return DownloaderImpl.init(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void configureRxJavaErrorHandler() {
|
private void configureRxJavaErrorHandler() {
|
||||||
|
|
|
@ -1,296 +0,0 @@
|
||||||
package org.schabi.newpipe;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.extractor.DownloadRequest;
|
|
||||||
import org.schabi.newpipe.extractor.DownloadResponse;
|
|
||||||
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
|
||||||
import org.schabi.newpipe.extractor.utils.Localization;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import okhttp3.MediaType;
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
import okhttp3.Request;
|
|
||||||
import okhttp3.RequestBody;
|
|
||||||
import okhttp3.Response;
|
|
||||||
import okhttp3.ResponseBody;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Created by Christian Schabesberger on 28.01.16.
|
|
||||||
*
|
|
||||||
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
|
||||||
* Downloader.java is part of NewPipe.
|
|
||||||
*
|
|
||||||
* NewPipe is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* NewPipe is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class Downloader implements org.schabi.newpipe.extractor.Downloader {
|
|
||||||
public static final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0";
|
|
||||||
|
|
||||||
private static Downloader instance;
|
|
||||||
private String mCookies;
|
|
||||||
private final OkHttpClient client;
|
|
||||||
|
|
||||||
private Downloader(OkHttpClient.Builder builder) {
|
|
||||||
this.client = builder
|
|
||||||
.readTimeout(30, TimeUnit.SECONDS)
|
|
||||||
//.cache(new Cache(new File(context.getExternalCacheDir(), "okhttp"), 16 * 1024 * 1024))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* It's recommended to call exactly once in the entire lifetime of the application.
|
|
||||||
*
|
|
||||||
* @param builder if null, default builder will be used
|
|
||||||
*/
|
|
||||||
public static Downloader init(@Nullable OkHttpClient.Builder builder) {
|
|
||||||
return instance = new Downloader(builder != null ? builder : new OkHttpClient.Builder());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Downloader getInstance() {
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCookies() {
|
|
||||||
return mCookies;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCookies(String cookies) {
|
|
||||||
mCookies = cookies;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the size of the content that the url is pointing by firing a HEAD request.
|
|
||||||
*
|
|
||||||
* @param url an url pointing to the content
|
|
||||||
* @return the size of the content, in bytes
|
|
||||||
*/
|
|
||||||
public long getContentLength(String url) throws IOException {
|
|
||||||
Response response = null;
|
|
||||||
try {
|
|
||||||
final Request request = new Request.Builder()
|
|
||||||
.head().url(url)
|
|
||||||
.addHeader("User-Agent", USER_AGENT)
|
|
||||||
.build();
|
|
||||||
response = client.newCall(request).execute();
|
|
||||||
|
|
||||||
String contentLength = response.header("Content-Length");
|
|
||||||
return contentLength == null ? -1 : Long.parseLong(contentLength);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
throw new IOException("Invalid content length", e);
|
|
||||||
} finally {
|
|
||||||
if (response != null) {
|
|
||||||
response.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Download the text file at the supplied URL as in download(String),
|
|
||||||
* but set the HTTP header field "Accept-Language" to the supplied string.
|
|
||||||
*
|
|
||||||
* @param siteUrl the URL of the text file to return the contents of
|
|
||||||
* @param localization the language and country (usually a 2-character code) to set
|
|
||||||
* @return the contents of the specified text file
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String download(String siteUrl, Localization localization) throws IOException, ReCaptchaException {
|
|
||||||
Map<String, String> requestProperties = new HashMap<>();
|
|
||||||
requestProperties.put("Accept-Language", localization.getLanguage());
|
|
||||||
return download(siteUrl, requestProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Download the text file at the supplied URL as in download(String),
|
|
||||||
* but set the HTTP headers included in the customProperties map.
|
|
||||||
*
|
|
||||||
* @param siteUrl the URL of the text file to return the contents of
|
|
||||||
* @param customProperties set request header properties
|
|
||||||
* @return the contents of the specified text file
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String download(String siteUrl, Map<String, String> customProperties) throws IOException, ReCaptchaException {
|
|
||||||
return getBody(siteUrl, customProperties).string();
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream stream(String siteUrl) throws IOException {
|
|
||||||
try {
|
|
||||||
return getBody(siteUrl, Collections.emptyMap()).byteStream();
|
|
||||||
} catch (ReCaptchaException e) {
|
|
||||||
throw new IOException(e.getMessage(), e.getCause());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ResponseBody getBody(String siteUrl, Map<String, String> customProperties) throws IOException, ReCaptchaException {
|
|
||||||
final Request.Builder requestBuilder = new Request.Builder()
|
|
||||||
.method("GET", null).url(siteUrl);
|
|
||||||
|
|
||||||
for (Map.Entry<String, String> header : customProperties.entrySet()) {
|
|
||||||
requestBuilder.addHeader(header.getKey(), header.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!customProperties.containsKey("User-Agent")) {
|
|
||||||
requestBuilder.header("User-Agent", USER_AGENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(mCookies)) {
|
|
||||||
requestBuilder.addHeader("Cookie", mCookies);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Request request = requestBuilder.build();
|
|
||||||
final Response response = client.newCall(request).execute();
|
|
||||||
final ResponseBody body = response.body();
|
|
||||||
|
|
||||||
if (response.code() == 429) {
|
|
||||||
throw new ReCaptchaException("reCaptcha Challenge requested", siteUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (body == null) {
|
|
||||||
response.close();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Download (via HTTP) the text file located at the supplied URL, and return its contents.
|
|
||||||
* Primarily intended for downloading web pages.
|
|
||||||
*
|
|
||||||
* @param siteUrl the URL of the text file to download
|
|
||||||
* @return the contents of the specified text file
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String download(String siteUrl) throws IOException, ReCaptchaException {
|
|
||||||
return download(siteUrl, Collections.emptyMap());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DownloadResponse get(String siteUrl, DownloadRequest request) throws IOException, ReCaptchaException {
|
|
||||||
final Request.Builder requestBuilder = new Request.Builder()
|
|
||||||
.method("GET", null).url(siteUrl);
|
|
||||||
|
|
||||||
Map<String, List<String>> requestHeaders = request.getRequestHeaders();
|
|
||||||
// set custom headers in request
|
|
||||||
for (Map.Entry<String, List<String>> pair : requestHeaders.entrySet()) {
|
|
||||||
for(String value : pair.getValue()){
|
|
||||||
requestBuilder.addHeader(pair.getKey(), value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!requestHeaders.containsKey("User-Agent")) {
|
|
||||||
requestBuilder.header("User-Agent", USER_AGENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(mCookies)) {
|
|
||||||
requestBuilder.addHeader("Cookie", mCookies);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Request okRequest = requestBuilder.build();
|
|
||||||
final Response response = client.newCall(okRequest).execute();
|
|
||||||
final ResponseBody body = response.body();
|
|
||||||
|
|
||||||
if (response.code() == 429) {
|
|
||||||
throw new ReCaptchaException("reCaptcha Challenge requested", siteUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (body == null) {
|
|
||||||
response.close();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DownloadResponse(response.code(), body.string(), response.headers().toMultimap());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DownloadResponse get(String siteUrl) throws IOException, ReCaptchaException {
|
|
||||||
return get(siteUrl, DownloadRequest.emptyRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DownloadResponse post(String siteUrl, DownloadRequest request) throws IOException, ReCaptchaException {
|
|
||||||
|
|
||||||
Map<String, List<String>> requestHeaders = request.getRequestHeaders();
|
|
||||||
if(null == requestHeaders.get("Content-Type") || requestHeaders.get("Content-Type").isEmpty()){
|
|
||||||
// content type header is required. maybe throw an exception here
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String contentType = requestHeaders.get("Content-Type").get(0);
|
|
||||||
|
|
||||||
RequestBody okRequestBody = null;
|
|
||||||
if (null != request.getRequestBody()) {
|
|
||||||
okRequestBody = RequestBody.create(MediaType.parse(contentType), request.getRequestBody());
|
|
||||||
}
|
|
||||||
final Request.Builder requestBuilder = new Request.Builder()
|
|
||||||
.method("POST", okRequestBody).url(siteUrl);
|
|
||||||
|
|
||||||
// set custom headers in request
|
|
||||||
for (Map.Entry<String, List<String>> pair : requestHeaders.entrySet()) {
|
|
||||||
for(String value : pair.getValue()){
|
|
||||||
requestBuilder.addHeader(pair.getKey(), value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!requestHeaders.containsKey("User-Agent")) {
|
|
||||||
requestBuilder.header("User-Agent", USER_AGENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(mCookies)) {
|
|
||||||
requestBuilder.addHeader("Cookie", mCookies);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Request okRequest = requestBuilder.build();
|
|
||||||
final Response response = client.newCall(okRequest).execute();
|
|
||||||
final ResponseBody body = response.body();
|
|
||||||
|
|
||||||
if (response.code() == 429) {
|
|
||||||
throw new ReCaptchaException("reCaptcha Challenge requested", siteUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (body == null) {
|
|
||||||
response.close();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DownloadResponse(response.code(), body.string(), response.headers().toMultimap());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DownloadResponse head(String siteUrl) throws IOException, ReCaptchaException {
|
|
||||||
final Request request = new Request.Builder()
|
|
||||||
.head().url(siteUrl)
|
|
||||||
.addHeader("User-Agent", USER_AGENT)
|
|
||||||
.build();
|
|
||||||
final Response response = client.newCall(request).execute();
|
|
||||||
|
|
||||||
if (response.code() == 429) {
|
|
||||||
throw new ReCaptchaException("reCaptcha Challenge requested", siteUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DownloadResponse(response.code(), null, response.headers().toMultimap());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,156 @@
|
||||||
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.extractor.downloader.Downloader;
|
||||||
|
import org.schabi.newpipe.extractor.downloader.Request;
|
||||||
|
import org.schabi.newpipe.extractor.downloader.Response;
|
||||||
|
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
|
|
||||||
|
public class DownloaderImpl extends Downloader {
|
||||||
|
public static final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0";
|
||||||
|
|
||||||
|
private static DownloaderImpl instance;
|
||||||
|
private String mCookies;
|
||||||
|
private OkHttpClient client;
|
||||||
|
|
||||||
|
private DownloaderImpl(OkHttpClient.Builder builder) {
|
||||||
|
this.client = builder
|
||||||
|
.readTimeout(30, TimeUnit.SECONDS)
|
||||||
|
//.cache(new Cache(new File(context.getExternalCacheDir(), "okhttp"), 16 * 1024 * 1024))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It's recommended to call exactly once in the entire lifetime of the application.
|
||||||
|
*
|
||||||
|
* @param builder if null, default builder will be used
|
||||||
|
*/
|
||||||
|
public static DownloaderImpl init(@Nullable OkHttpClient.Builder builder) {
|
||||||
|
return instance = new DownloaderImpl(builder != null ? builder : new OkHttpClient.Builder());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DownloaderImpl getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCookies() {
|
||||||
|
return mCookies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCookies(String cookies) {
|
||||||
|
mCookies = cookies;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the size of the content that the url is pointing by firing a HEAD request.
|
||||||
|
*
|
||||||
|
* @param url an url pointing to the content
|
||||||
|
* @return the size of the content, in bytes
|
||||||
|
*/
|
||||||
|
public long getContentLength(String url) throws IOException {
|
||||||
|
try {
|
||||||
|
final Response response = head(url);
|
||||||
|
return Long.parseLong(response.getHeader("Content-Length"));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new IOException("Invalid content length", e);
|
||||||
|
} catch (ReCaptchaException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream stream(String siteUrl) throws IOException {
|
||||||
|
try {
|
||||||
|
final okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder()
|
||||||
|
.method("GET", null).url(siteUrl)
|
||||||
|
.addHeader("User-Agent", USER_AGENT);
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(mCookies)) {
|
||||||
|
requestBuilder.addHeader("Cookie", mCookies);
|
||||||
|
}
|
||||||
|
|
||||||
|
final okhttp3.Request request = requestBuilder.build();
|
||||||
|
final okhttp3.Response response = client.newCall(request).execute();
|
||||||
|
final ResponseBody body = response.body();
|
||||||
|
|
||||||
|
if (response.code() == 429) {
|
||||||
|
throw new ReCaptchaException("reCaptcha Challenge requested", siteUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body == null) {
|
||||||
|
response.close();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return body.byteStream();
|
||||||
|
} catch (ReCaptchaException e) {
|
||||||
|
throw new IOException(e.getMessage(), e.getCause());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response execute(@Nonnull Request request) throws IOException, ReCaptchaException {
|
||||||
|
final String httpMethod = request.httpMethod();
|
||||||
|
final String url = request.url();
|
||||||
|
final Map<String, List<String>> headers = request.headers();
|
||||||
|
final byte[] dataToSend = request.dataToSend();
|
||||||
|
|
||||||
|
RequestBody requestBody = null;
|
||||||
|
if (dataToSend != null) {
|
||||||
|
requestBody = RequestBody.create(null, dataToSend);
|
||||||
|
}
|
||||||
|
|
||||||
|
final okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder()
|
||||||
|
.method(httpMethod, requestBody).url(url)
|
||||||
|
.addHeader("User-Agent", USER_AGENT);
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(mCookies)) {
|
||||||
|
requestBuilder.addHeader("Cookie", mCookies);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<String, List<String>> pair : headers.entrySet()) {
|
||||||
|
final String headerName = pair.getKey();
|
||||||
|
final List<String> headerValueList = pair.getValue();
|
||||||
|
|
||||||
|
if (headerValueList.size() > 1) {
|
||||||
|
requestBuilder.removeHeader(headerName);
|
||||||
|
for (String headerValue : headerValueList) {
|
||||||
|
requestBuilder.addHeader(headerName, headerValue);
|
||||||
|
}
|
||||||
|
} else if (headerValueList.size() == 1) {
|
||||||
|
requestBuilder.header(headerName, headerValueList.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
final okhttp3.Response response = client.newCall(requestBuilder.build()).execute();
|
||||||
|
|
||||||
|
if (response.code() == 429) {
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
throw new ReCaptchaException("reCaptcha Challenge requested", url);
|
||||||
|
}
|
||||||
|
|
||||||
|
final ResponseBody body = response.body();
|
||||||
|
String responseBodyToReturn = null;
|
||||||
|
|
||||||
|
if (body != null) {
|
||||||
|
responseBodyToReturn = body.string();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Response(response.code(), response.message(), response.headers().toMultimap(), responseBodyToReturn);
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,7 +40,7 @@ public class ImageDownloader extends BaseImageDownloader {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {
|
protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {
|
||||||
final Downloader downloader = (Downloader) NewPipe.getDownloader();
|
final DownloaderImpl downloader = (DownloaderImpl) NewPipe.getDownloader();
|
||||||
return downloader.stream(imageUri);
|
return downloader.stream(imageUri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
||||||
// find cookies : s_gl & goojf and Add cookies to Downloader
|
// find cookies : s_gl & goojf and Add cookies to Downloader
|
||||||
if (find_access_cookies(cookies)) {
|
if (find_access_cookies(cookies)) {
|
||||||
// Give cookies to Downloader class
|
// Give cookies to Downloader class
|
||||||
Downloader.getInstance().setCookies(mCookies);
|
DownloaderImpl.getInstance().setCookies(mCookies);
|
||||||
|
|
||||||
// Closing activity and return to parent
|
// Closing activity and return to parent
|
||||||
setResult(RESULT_OK);
|
setResult(RESULT_OK);
|
||||||
|
|
|
@ -40,12 +40,12 @@ import org.schabi.newpipe.MainActivity;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.MediaFormat;
|
import org.schabi.newpipe.extractor.MediaFormat;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
import org.schabi.newpipe.extractor.localization.Localization;
|
||||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||||
import org.schabi.newpipe.extractor.stream.Stream;
|
import org.schabi.newpipe.extractor.stream.Stream;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
|
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
|
||||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||||
import org.schabi.newpipe.extractor.utils.Localization;
|
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.settings.NewPipeSettings;
|
import org.schabi.newpipe.settings.NewPipeSettings;
|
||||||
|
@ -488,35 +488,24 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getSubtitleIndexBy(List<SubtitlesStream> streams) {
|
private int getSubtitleIndexBy(List<SubtitlesStream> streams) {
|
||||||
Localization loc = NewPipe.getPreferredLocalization();
|
final Localization preferredLocalization = NewPipe.getPreferredLocalization();
|
||||||
|
|
||||||
|
int candidate = 0;
|
||||||
for (int i = 0; i < streams.size(); i++) {
|
for (int i = 0; i < streams.size(); i++) {
|
||||||
Locale streamLocale = streams.get(i).getLocale();
|
final Locale streamLocale = streams.get(i).getLocale();
|
||||||
String tag = streamLocale.getLanguage().concat("-").concat(streamLocale.getCountry());
|
|
||||||
if (tag.equalsIgnoreCase(loc.getLanguage())) {
|
final boolean languageEquals = streamLocale.getLanguage() != null && preferredLocalization.getLanguageCode() != null &&
|
||||||
return i;
|
streamLocale.getLanguage().equals(new Locale(preferredLocalization.getLanguageCode()).getLanguage());
|
||||||
|
final boolean countryEquals = streamLocale.getCountry() != null && streamLocale.getCountry().equals(preferredLocalization.getCountryCode());
|
||||||
|
|
||||||
|
if (languageEquals) {
|
||||||
|
if (countryEquals) return i;
|
||||||
|
|
||||||
|
candidate = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback
|
return candidate;
|
||||||
// 1st loop match country & language
|
|
||||||
// 2nd loop match language only
|
|
||||||
int index = loc.getLanguage().indexOf("-");
|
|
||||||
String lang = index > 0 ? loc.getLanguage().substring(0, index) : loc.getLanguage();
|
|
||||||
|
|
||||||
for (int j = 0; j < 2; j++) {
|
|
||||||
for (int i = 0; i < streams.size(); i++) {
|
|
||||||
Locale streamLocale = streams.get(i).getLocale();
|
|
||||||
|
|
||||||
if (streamLocale.getLanguage().equalsIgnoreCase(lang)) {
|
|
||||||
if (j > 0 || streamLocale.getCountry().equalsIgnoreCase(loc.getCountry())) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StoredDirectoryHelper mainStorageAudio = null;
|
StoredDirectoryHelper mainStorageAudio = null;
|
||||||
|
|
|
@ -1067,7 +1067,13 @@ public class VideoDetailFragment
|
||||||
uploaderThumb.setImageDrawable(ContextCompat.getDrawable(activity, R.drawable.buddy));
|
uploaderThumb.setImageDrawable(ContextCompat.getDrawable(activity, R.drawable.buddy));
|
||||||
|
|
||||||
if (info.getViewCount() >= 0) {
|
if (info.getViewCount() >= 0) {
|
||||||
|
if (info.getStreamType().equals(StreamType.AUDIO_LIVE_STREAM)) {
|
||||||
|
videoCountView.setText(Localization.listeningCount(activity, info.getViewCount()));
|
||||||
|
} else if (info.getStreamType().equals(StreamType.LIVE_STREAM)) {
|
||||||
|
videoCountView.setText(Localization.watchingCount(activity, info.getViewCount()));
|
||||||
|
} else {
|
||||||
videoCountView.setText(Localization.localizeViewCount(activity, info.getViewCount()));
|
videoCountView.setText(Localization.localizeViewCount(activity, info.getViewCount()));
|
||||||
|
}
|
||||||
videoCountView.setVisibility(View.VISIBLE);
|
videoCountView.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
videoCountView.setVisibility(View.GONE);
|
videoCountView.setVisibility(View.GONE);
|
||||||
|
@ -1120,9 +1126,15 @@ public class VideoDetailFragment
|
||||||
videoTitleToggleArrow.setVisibility(View.VISIBLE);
|
videoTitleToggleArrow.setVisibility(View.VISIBLE);
|
||||||
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
|
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
|
||||||
videoDescriptionRootLayout.setVisibility(View.GONE);
|
videoDescriptionRootLayout.setVisibility(View.GONE);
|
||||||
if (!TextUtils.isEmpty(info.getUploadDate())) {
|
|
||||||
videoUploadDateView.setText(Localization.localizeDate(activity, info.getUploadDate()));
|
if (info.getUploadDate() != null) {
|
||||||
|
videoUploadDateView.setText(Localization.localizeUploadDate(activity, info.getUploadDate().date().getTime()));
|
||||||
|
videoUploadDateView.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
videoUploadDateView.setText(null);
|
||||||
|
videoUploadDateView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareDescription(info.getDescription());
|
prepareDescription(info.getDescription());
|
||||||
updateProgressInfo(info);
|
updateProgressInfo(info);
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.util.CommentTextOnTouchListener;
|
import org.schabi.newpipe.util.CommentTextOnTouchListener;
|
||||||
import org.schabi.newpipe.util.ImageDisplayConstants;
|
import org.schabi.newpipe.util.ImageDisplayConstants;
|
||||||
|
import org.schabi.newpipe.util.Localization;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
@ -101,10 +102,17 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
|
||||||
ellipsize();
|
ellipsize();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null != item.getLikeCount()) {
|
if (item.getLikeCount() >= 0) {
|
||||||
itemLikesCountView.setText(String.valueOf(item.getLikeCount()));
|
itemLikesCountView.setText(String.valueOf(item.getLikeCount()));
|
||||||
|
} else {
|
||||||
|
itemLikesCountView.setText("-");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.getPublishedTime() != null) {
|
||||||
|
itemPublishedTime.setText(Localization.relativeTime(item.getPublishedTime().date()));
|
||||||
|
} else {
|
||||||
|
itemPublishedTime.setText(item.getTextualPublishedTime());
|
||||||
}
|
}
|
||||||
itemPublishedTime.setText(item.getPublishedTime());
|
|
||||||
|
|
||||||
itemView.setOnClickListener(view -> {
|
itemView.setOnClickListener(view -> {
|
||||||
toggleEllipsize();
|
toggleEllipsize();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.schabi.newpipe.info_list.holder;
|
package org.schabi.newpipe.info_list.holder;
|
||||||
|
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
@ -7,10 +8,13 @@ import android.widget.TextView;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.MainActivity.DEBUG;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Created by Christian Schabesberger on 01.08.16.
|
* Created by Christian Schabesberger on 01.08.16.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -53,15 +57,38 @@ public class StreamInfoItemHolder extends StreamMiniInfoItemHolder {
|
||||||
private String getStreamInfoDetailLine(final StreamInfoItem infoItem) {
|
private String getStreamInfoDetailLine(final StreamInfoItem infoItem) {
|
||||||
String viewsAndDate = "";
|
String viewsAndDate = "";
|
||||||
if (infoItem.getViewCount() >= 0) {
|
if (infoItem.getViewCount() >= 0) {
|
||||||
|
if (infoItem.getStreamType().equals(StreamType.AUDIO_LIVE_STREAM)) {
|
||||||
|
viewsAndDate = Localization.listeningCount(itemBuilder.getContext(), infoItem.getViewCount());
|
||||||
|
} else if (infoItem.getStreamType().equals(StreamType.LIVE_STREAM)) {
|
||||||
|
viewsAndDate = Localization.watchingCount(itemBuilder.getContext(), infoItem.getViewCount());
|
||||||
|
} else {
|
||||||
viewsAndDate = Localization.shortViewCount(itemBuilder.getContext(), infoItem.getViewCount());
|
viewsAndDate = Localization.shortViewCount(itemBuilder.getContext(), infoItem.getViewCount());
|
||||||
}
|
}
|
||||||
if (!TextUtils.isEmpty(infoItem.getUploadDate())) {
|
}
|
||||||
|
|
||||||
|
final String uploadDate = getFormattedRelativeUploadDate(infoItem);
|
||||||
|
if (!TextUtils.isEmpty(uploadDate)) {
|
||||||
if (viewsAndDate.isEmpty()) {
|
if (viewsAndDate.isEmpty()) {
|
||||||
viewsAndDate = infoItem.getUploadDate();
|
return uploadDate;
|
||||||
} else {
|
|
||||||
viewsAndDate += " • " + infoItem.getUploadDate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Localization.concatenateStrings(viewsAndDate, uploadDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
return viewsAndDate;
|
return viewsAndDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getFormattedRelativeUploadDate(final StreamInfoItem infoItem) {
|
||||||
|
if (infoItem.getUploadDate() != null) {
|
||||||
|
String formattedRelativeTime = Localization.relativeTime(infoItem.getUploadDate().date());
|
||||||
|
|
||||||
|
if (DEBUG && PreferenceManager.getDefaultSharedPreferences(itemBuilder.getContext())
|
||||||
|
.getBoolean(itemBuilder.getContext().getString(R.string.show_original_time_ago_key), false)) {
|
||||||
|
formattedRelativeTime += " (" + infoItem.getTextualUploadDate() + ")";
|
||||||
|
}
|
||||||
|
return formattedRelativeTime;
|
||||||
|
} else {
|
||||||
|
return infoItem.getTextualUploadDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ import com.nostra13.universalimageloader.core.assist.FailReason;
|
||||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
||||||
|
|
||||||
import org.schabi.newpipe.BuildConfig;
|
import org.schabi.newpipe.BuildConfig;
|
||||||
import org.schabi.newpipe.Downloader;
|
import org.schabi.newpipe.DownloaderImpl;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
|
@ -209,7 +209,7 @@ public abstract class BasePlayer implements
|
||||||
this.progressUpdateReactor = new SerialDisposable();
|
this.progressUpdateReactor = new SerialDisposable();
|
||||||
this.databaseUpdateReactor = new CompositeDisposable();
|
this.databaseUpdateReactor = new CompositeDisposable();
|
||||||
|
|
||||||
final String userAgent = Downloader.USER_AGENT;
|
final String userAgent = DownloaderImpl.USER_AGENT;
|
||||||
final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter.Builder(context).build();
|
final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter.Builder(context).build();
|
||||||
this.dataSource = new PlayerDataSource(context, userAgent, bandwidthMeter);
|
this.dataSource = new PlayerDataSource(context, userAgent, bandwidthMeter);
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@ import com.nononsenseapps.filepicker.Utils;
|
||||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.localization.ContentCountry;
|
||||||
import org.schabi.newpipe.extractor.utils.Localization;
|
import org.schabi.newpipe.extractor.localization.Localization;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
||||||
|
@ -53,10 +53,16 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
||||||
|
|
||||||
private String thumbnailLoadToggleKey;
|
private String thumbnailLoadToggleKey;
|
||||||
|
|
||||||
|
private Localization initialSelectedLocalization;
|
||||||
|
private ContentCountry initialSelectedContentCountry;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
thumbnailLoadToggleKey = getString(R.string.download_thumbnail_key);
|
thumbnailLoadToggleKey = getString(R.string.download_thumbnail_key);
|
||||||
|
|
||||||
|
initialSelectedLocalization = org.schabi.newpipe.util.Localization.getPreferredLocalization(requireContext());
|
||||||
|
initialSelectedContentCountry = org.schabi.newpipe.util.Localization.getPreferredContentCountry(requireContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -108,20 +114,21 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
||||||
startActivityForResult(i, REQUEST_EXPORT_PATH);
|
startActivityForResult(i, REQUEST_EXPORT_PATH);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Preference setPreferredLanguage = findPreference(getString(R.string.content_language_key));
|
@Override
|
||||||
setPreferredLanguage.setOnPreferenceChangeListener((Preference p, Object newLanguage) -> {
|
public void onDestroy() {
|
||||||
Localization oldLocal = org.schabi.newpipe.util.Localization.getPreferredExtractorLocal(getActivity());
|
super.onDestroy();
|
||||||
NewPipe.setLocalization(new Localization(oldLocal.getCountry(), (String) newLanguage));
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
Preference setPreferredCountry = findPreference(getString(R.string.content_country_key));
|
final Localization selectedLocalization = org.schabi.newpipe.util.Localization
|
||||||
setPreferredCountry.setOnPreferenceChangeListener((Preference p, Object newCountry) -> {
|
.getPreferredLocalization(requireContext());
|
||||||
Localization oldLocal = org.schabi.newpipe.util.Localization.getPreferredExtractorLocal(getActivity());
|
final ContentCountry selectedContentCountry = org.schabi.newpipe.util.Localization
|
||||||
NewPipe.setLocalization(new Localization((String) newCountry, oldLocal.getLanguage()));
|
.getPreferredContentCountry(requireContext());
|
||||||
return true;
|
|
||||||
});
|
if (!selectedLocalization.equals(initialSelectedLocalization)
|
||||||
|
|| !selectedContentCountry.equals(initialSelectedContentCountry)) {
|
||||||
|
Toast.makeText(requireContext(), R.string.localization_changes_requires_app_restart, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -32,7 +32,7 @@ import org.schabi.newpipe.extractor.Info;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
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.SuggestionExtractor;
|
import org.schabi.newpipe.extractor.suggestion.SuggestionExtractor;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
||||||
import org.schabi.newpipe.extractor.comments.CommentsInfo;
|
import org.schabi.newpipe.extractor.comments.CommentsInfo;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
|
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
|
||||||
|
|
|
@ -2,24 +2,26 @@ package org.schabi.newpipe.util;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.PluralsRes;
|
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import org.ocpsoft.prettytime.PrettyTime;
|
||||||
|
import org.ocpsoft.prettytime.units.Decade;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.extractor.localization.ContentCountry;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.PluralsRes;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Created by chschtsch on 12/29/15.
|
* Created by chschtsch on 12/29/15.
|
||||||
*
|
*
|
||||||
|
@ -42,11 +44,16 @@ import java.util.Locale;
|
||||||
|
|
||||||
public class Localization {
|
public class Localization {
|
||||||
|
|
||||||
public final static String DOT_SEPARATOR = " • ";
|
private static PrettyTime prettyTime;
|
||||||
|
private static final String DOT_SEPARATOR = " • ";
|
||||||
|
|
||||||
private Localization() {
|
private Localization() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
initPrettyTime();
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static String concatenateStrings(final String... strings) {
|
public static String concatenateStrings(final String... strings) {
|
||||||
return concatenateStrings(Arrays.asList(strings));
|
return concatenateStrings(Arrays.asList(strings));
|
||||||
|
@ -69,16 +76,18 @@ public class Localization {
|
||||||
return stringBuilder.toString();
|
return stringBuilder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static org.schabi.newpipe.extractor.utils.Localization getPreferredExtractorLocal(Context context) {
|
public static org.schabi.newpipe.extractor.localization.Localization getPreferredLocalization(final Context context) {
|
||||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
final String contentLanguage = PreferenceManager
|
||||||
|
.getDefaultSharedPreferences(context)
|
||||||
|
.getString(context.getString(R.string.content_language_key), context.getString(R.string.default_language_value));
|
||||||
|
return org.schabi.newpipe.extractor.localization.Localization.fromLocalizationCode(contentLanguage);
|
||||||
|
}
|
||||||
|
|
||||||
String languageCode = sp.getString(context.getString(R.string.content_language_key),
|
public static ContentCountry getPreferredContentCountry(final Context context) {
|
||||||
context.getString(R.string.default_language_value));
|
final String contentCountry = PreferenceManager
|
||||||
|
.getDefaultSharedPreferences(context)
|
||||||
String countryCode = sp.getString(context.getString(R.string.content_country_key),
|
.getString(context.getString(R.string.content_country_key), context.getString(R.string.default_country_value));
|
||||||
context.getString(R.string.default_country_value));
|
return new ContentCountry(contentCountry);
|
||||||
|
|
||||||
return new org.schabi.newpipe.extractor.utils.Localization(countryCode, languageCode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Locale getPreferredLocale(Context context) {
|
public static Locale getPreferredLocale(Context context) {
|
||||||
|
@ -106,27 +115,12 @@ public class Localization {
|
||||||
return nf.format(number);
|
return nf.format(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String formatDate(Context context, String date) {
|
public static String formatDate(Date date) {
|
||||||
Locale locale = getPreferredLocale(context);
|
return DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault()).format(date);
|
||||||
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
|
|
||||||
Date datum = null;
|
|
||||||
try {
|
|
||||||
datum = formatter.parse(date);
|
|
||||||
} catch (ParseException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
|
public static String localizeUploadDate(Context context, Date date) {
|
||||||
|
return context.getString(R.string.upload_date_text, formatDate(date));
|
||||||
return df.format(datum);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String localizeDate(Context context, String date) {
|
|
||||||
Resources res = context.getResources();
|
|
||||||
String dateString = res.getString(R.string.upload_date_text);
|
|
||||||
|
|
||||||
String formattedDate = formatDate(context, date);
|
|
||||||
return String.format(dateString, formattedDate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String localizeViewCount(Context context, long viewCount) {
|
public static String localizeViewCount(Context context, long viewCount) {
|
||||||
|
@ -153,6 +147,14 @@ public class Localization {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String listeningCount(Context context, long listeningCount) {
|
||||||
|
return getQuantity(context, R.plurals.listening, R.string.no_one_listening, listeningCount, shortCount(context, listeningCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String watchingCount(Context context, long watchingCount) {
|
||||||
|
return getQuantity(context, R.plurals.watching, R.string.no_one_watching, watchingCount, shortCount(context, watchingCount));
|
||||||
|
}
|
||||||
|
|
||||||
public static String shortViewCount(Context context, long viewCount) {
|
public static String shortViewCount(Context context, long viewCount) {
|
||||||
return getQuantity(context, R.plurals.views, R.string.no_views, viewCount, shortCount(context, viewCount));
|
return getQuantity(context, R.plurals.views, R.string.no_views, viewCount, shortCount(context, viewCount));
|
||||||
}
|
}
|
||||||
|
@ -192,4 +194,26 @@ public class Localization {
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Pretty Time
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private static void initPrettyTime() {
|
||||||
|
prettyTime = new PrettyTime(Locale.getDefault());
|
||||||
|
// Do not use decades as YouTube doesn't either.
|
||||||
|
prettyTime.removeUnit(Decade.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PrettyTime getPrettyTime() {
|
||||||
|
// If pretty time's Locale is different, init again with the new one.
|
||||||
|
if (!prettyTime.getLocale().equals(Locale.getDefault())) {
|
||||||
|
initPrettyTime();
|
||||||
|
}
|
||||||
|
return prettyTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String relativeTime(Calendar calendarTime) {
|
||||||
|
return getPrettyTime().formatUnrounded(calendarTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import android.widget.ImageView;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.schabi.newpipe.Downloader;
|
import org.schabi.newpipe.DownloaderImpl;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||||
import org.schabi.newpipe.extractor.stream.Stream;
|
import org.schabi.newpipe.extractor.stream.Stream;
|
||||||
|
@ -182,7 +182,7 @@ public class StreamItemAdapter<T extends Stream, U extends Stream> extends BaseA
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final long contentLength = Downloader.getInstance().getContentLength(stream.getUrl());
|
final long contentLength = DownloaderImpl.getInstance().getContentLength(stream.getUrl());
|
||||||
streamsWrapper.setSize(stream, contentLength);
|
streamsWrapper.setSize(stream, contentLength);
|
||||||
hasChanged = true;
|
hasChanged = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.schabi.newpipe.Downloader;
|
import org.schabi.newpipe.DownloaderImpl;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
@ -212,7 +212,7 @@ public class DownloadMission extends Mission {
|
||||||
HttpURLConnection openConnection(String url, int threadId, long rangeStart, long rangeEnd) throws IOException {
|
HttpURLConnection openConnection(String url, int threadId, long rangeStart, long rangeEnd) throws IOException {
|
||||||
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||||
conn.setInstanceFollowRedirects(true);
|
conn.setInstanceFollowRedirects(true);
|
||||||
conn.setRequestProperty("User-Agent", Downloader.USER_AGENT);
|
conn.setRequestProperty("User-Agent", DownloaderImpl.USER_AGENT);
|
||||||
conn.setRequestProperty("Accept", "*/*");
|
conn.setRequestProperty("Accept", "*/*");
|
||||||
|
|
||||||
// BUG workaround: switching between networks can freeze the download forever
|
// BUG workaround: switching between networks can freeze the download forever
|
||||||
|
|
|
@ -111,8 +111,8 @@
|
||||||
<!-- DEBUG ONLY -->
|
<!-- DEBUG ONLY -->
|
||||||
<string name="debug_pref_screen_key" translatable="false">debug_pref_screen_key</string>
|
<string name="debug_pref_screen_key" translatable="false">debug_pref_screen_key</string>
|
||||||
<string name="allow_heap_dumping_key" translatable="false">allow_heap_dumping_key</string>
|
<string name="allow_heap_dumping_key" translatable="false">allow_heap_dumping_key</string>
|
||||||
|
|
||||||
<string name="allow_disposed_exceptions_key" translatable="false">allow_disposed_exceptions_key</string>
|
<string name="allow_disposed_exceptions_key" translatable="false">allow_disposed_exceptions_key</string>
|
||||||
|
<string name="show_original_time_ago_key" translatable="false">show_original_time_ago_text_key</string>
|
||||||
|
|
||||||
<!-- THEMES -->
|
<!-- THEMES -->
|
||||||
<string name="theme_key" translatable="false">theme</string>
|
<string name="theme_key" translatable="false">theme</string>
|
||||||
|
|
|
@ -263,6 +263,19 @@
|
||||||
<item quantity="one">%s view</item>
|
<item quantity="one">%s view</item>
|
||||||
<item quantity="other">%s views</item>
|
<item quantity="other">%s views</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
|
||||||
|
<string name="no_one_watching">No one is watching</string>
|
||||||
|
<plurals name="watching">
|
||||||
|
<item quantity="one">%s watching</item>
|
||||||
|
<item quantity="other">%s watching</item>
|
||||||
|
</plurals>
|
||||||
|
|
||||||
|
<string name="no_one_listening">No one is listening</string>
|
||||||
|
<plurals name="listening">
|
||||||
|
<item quantity="one">%s listener</item>
|
||||||
|
<item quantity="other">%s listeners</item>
|
||||||
|
</plurals>
|
||||||
|
|
||||||
<string name="no_videos">No videos</string>
|
<string name="no_videos">No videos</string>
|
||||||
<plurals name="videos">
|
<plurals name="videos">
|
||||||
<item quantity="one">%s video</item>
|
<item quantity="one">%s video</item>
|
||||||
|
@ -380,6 +393,8 @@
|
||||||
<string name="override_current_data">This will override your current setup.</string>
|
<string name="override_current_data">This will override your current setup.</string>
|
||||||
<string name="import_settings">Do you want to also import settings?</string>
|
<string name="import_settings">Do you want to also import settings?</string>
|
||||||
<string name="error_unable_to_load_comments">Could not load comments</string>
|
<string name="error_unable_to_load_comments">Could not load comments</string>
|
||||||
|
<string name="localization_changes_requires_app_restart">Localization changes will not take effect until the app is restarted</string>
|
||||||
|
|
||||||
<!-- Kiosk Names -->
|
<!-- Kiosk Names -->
|
||||||
<string name="kiosk">Kiosk</string>
|
<string name="kiosk">Kiosk</string>
|
||||||
<string name="trending">Trending</string>
|
<string name="trending">Trending</string>
|
||||||
|
@ -443,6 +458,10 @@
|
||||||
<string name="enable_leak_canary_summary">Memory leak monitoring may cause the app to become unresponsive when heap dumping</string>
|
<string name="enable_leak_canary_summary">Memory leak monitoring may cause the app to become unresponsive when heap dumping</string>
|
||||||
<string name="enable_disposed_exceptions_title">Report out-of-lifecycle errors</string>
|
<string name="enable_disposed_exceptions_title">Report out-of-lifecycle errors</string>
|
||||||
<string name="enable_disposed_exceptions_summary">Force reporting of undeliverable Rx exceptions outside of fragment or activity lifecycle after disposal</string>
|
<string name="enable_disposed_exceptions_summary">Force reporting of undeliverable Rx exceptions outside of fragment or activity lifecycle after disposal</string>
|
||||||
|
|
||||||
|
<string name="show_original_time_ago_title" translatable="false">Show original time ago on items</string>
|
||||||
|
<string name="show_original_time_ago_summary" translatable="false">Original texts from services will be visible in stream items</string>
|
||||||
|
|
||||||
<!-- Subscriptions import/export -->
|
<!-- Subscriptions import/export -->
|
||||||
<string name="import_export_title">Import/export</string>
|
<string name="import_export_title">Import/export</string>
|
||||||
<string name="import_title">Import</string>
|
<string name="import_title">Import</string>
|
||||||
|
|
|
@ -3,15 +3,6 @@
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:title="@string/content">
|
android:title="@string/content">
|
||||||
<ListPreference
|
|
||||||
app:iconSpaceReserved="false"
|
|
||||||
android:defaultValue="@string/default_country_value"
|
|
||||||
android:entries="@array/country_names"
|
|
||||||
android:entryValues="@array/country_codes"
|
|
||||||
android:key="@string/content_country_key"
|
|
||||||
android:summary="%s"
|
|
||||||
android:title="@string/default_content_country_title"/>
|
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
app:iconSpaceReserved="false"
|
app:iconSpaceReserved="false"
|
||||||
android:defaultValue="@string/default_language_value"
|
android:defaultValue="@string/default_language_value"
|
||||||
|
@ -21,6 +12,15 @@
|
||||||
android:summary="%s"
|
android:summary="%s"
|
||||||
android:title="@string/content_language_title"/>
|
android:title="@string/content_language_title"/>
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
android:defaultValue="@string/default_country_value"
|
||||||
|
android:entries="@array/country_names"
|
||||||
|
android:entryValues="@array/country_codes"
|
||||||
|
android:key="@string/content_country_key"
|
||||||
|
android:summary="%s"
|
||||||
|
android:title="@string/default_content_country_title"/>
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
app:iconSpaceReserved="false"
|
app:iconSpaceReserved="false"
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
|
|
|
@ -18,4 +18,11 @@
|
||||||
android:key="@string/allow_disposed_exceptions_key"
|
android:key="@string/allow_disposed_exceptions_key"
|
||||||
android:title="@string/enable_disposed_exceptions_title"
|
android:title="@string/enable_disposed_exceptions_title"
|
||||||
android:summary="@string/enable_disposed_exceptions_summary"/>
|
android:summary="@string/enable_disposed_exceptions_summary"/>
|
||||||
|
|
||||||
|
<SwitchPreference
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="@string/show_original_time_ago_key"
|
||||||
|
android:title="@string/show_original_time_ago_title"
|
||||||
|
android:summary="@string/show_original_time_ago_summary"/>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
Loading…
Reference in New Issue