add proxy settings

This commit is contained in:
dfokin 2025-10-08 20:00:33 +03:00
parent 965eea2124
commit 6cc3153730
13 changed files with 233 additions and 16 deletions

View File

@ -26,7 +26,8 @@ class DebugApp : App() {
override fun getDownloader(): Downloader {
val downloader = DownloaderImpl.init(
OkHttpClient.Builder()
.addNetworkInterceptor(StethoInterceptor())
.addNetworkInterceptor(StethoInterceptor()),
this
)
setCookiesToDownloader(downloader)
return downloader

View File

@ -131,7 +131,7 @@ public class App extends Application {
}
protected Downloader getDownloader() {
final DownloaderImpl downloader = DownloaderImpl.init(null);
final DownloaderImpl downloader = DownloaderImpl.init(null, this);
setCookiesToDownloader(downloader);
return downloader;
}

View File

@ -11,6 +11,7 @@ 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 org.schabi.newpipe.settings.ProxyManager;
import org.schabi.newpipe.util.InfoCache;
import java.io.IOException;
@ -52,11 +53,18 @@ public final class DownloaderImpl extends Downloader {
* It's recommended to call exactly once in the entire lifetime of the application.
*
* @param builder if null, default builder will be used
* @param context the context to use
* @return a new instance of {@link DownloaderImpl}
*/
public static DownloaderImpl init(@Nullable final OkHttpClient.Builder builder) {
instance = new DownloaderImpl(
builder != null ? builder : new OkHttpClient.Builder());
public static DownloaderImpl init(@Nullable final OkHttpClient.Builder builder,
final Context context) {
final OkHttpClient.Builder builderToUse = builder != null ? builder
: new OkHttpClient.Builder();
final ProxyManager proxyManager = new ProxyManager(context);
if (proxyManager.isProxyEnabled()) {
builderToUse.proxy(proxyManager.getProxy());
}
instance = new DownloaderImpl(builderToUse);
return instance;
}

View File

@ -22,6 +22,7 @@ import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isWebEmbeddedPlayerStreamingUrl;
import static java.lang.Math.min;
import android.content.Context;
import android.net.Uri;
import androidx.annotation.NonNull;
@ -47,6 +48,7 @@ import com.google.common.collect.Sets;
import com.google.common.net.HttpHeaders;
import org.schabi.newpipe.DownloaderImpl;
import org.schabi.newpipe.settings.ProxyManager;
import java.io.IOException;
import java.io.InputStream;
@ -56,6 +58,7 @@ import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.NoRouteToHostException;
import java.net.Proxy;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
@ -86,6 +89,7 @@ public final class YoutubeHttpDataSource extends BaseDataSource implements HttpD
*/
public static final class Factory implements HttpDataSource.Factory {
private final Context context;
private final RequestProperties defaultRequestProperties;
@Nullable
@ -102,8 +106,10 @@ public final class YoutubeHttpDataSource extends BaseDataSource implements HttpD
/**
* Creates an instance.
* @param context the context to use
*/
public Factory() {
public Factory(final Context context) {
this.context = context;
defaultRequestProperties = new RequestProperties();
connectTimeoutMs = DEFAULT_CONNECT_TIMEOUT_MILLIS;
readTimeoutMs = DEFAULT_READ_TIMEOUT_MILLIS;
@ -222,7 +228,6 @@ public final class YoutubeHttpDataSource extends BaseDataSource implements HttpD
* <p>The default is {@code null}.
*
* <p>See {@link DataSource#addTransferListener(TransferListener)}.
*
* @param transferListenerToUse The listener that will be used.
* @return This factory.
*/
@ -249,6 +254,7 @@ public final class YoutubeHttpDataSource extends BaseDataSource implements HttpD
@Override
public YoutubeHttpDataSource createDataSource() {
final YoutubeHttpDataSource dataSource = new YoutubeHttpDataSource(
context,
connectTimeoutMs,
readTimeoutMs,
allowCrossProtocolRedirects,
@ -274,6 +280,7 @@ public final class YoutubeHttpDataSource extends BaseDataSource implements HttpD
private static final String YOUTUBE_BASE_URL = "https://www.youtube.com";
private static final byte[] POST_BODY = new byte[] {0x78, 0};
private final Context context;
private final boolean allowCrossProtocolRedirects;
private final boolean rangeParameterEnabled;
private final boolean rnParameterEnabled;
@ -301,7 +308,8 @@ public final class YoutubeHttpDataSource extends BaseDataSource implements HttpD
private long requestNumber;
@SuppressWarnings("checkstyle:ParameterNumber")
private YoutubeHttpDataSource(final int connectTimeoutMillis,
private YoutubeHttpDataSource(final Context context,
final int connectTimeoutMillis,
final int readTimeoutMillis,
final boolean allowCrossProtocolRedirects,
final boolean rangeParameterEnabled,
@ -310,6 +318,7 @@ public final class YoutubeHttpDataSource extends BaseDataSource implements HttpD
@Nullable final Predicate<String> contentTypePredicate,
final boolean keepPostFor302Redirects) {
super(true);
this.context = context;
this.connectTimeoutMillis = connectTimeoutMillis;
this.readTimeoutMillis = readTimeoutMillis;
this.allowCrossProtocolRedirects = allowCrossProtocolRedirects;
@ -716,6 +725,11 @@ public final class YoutubeHttpDataSource extends BaseDataSource implements HttpD
* @return an {@link HttpURLConnection} created with the {@code url}
*/
private HttpURLConnection openConnection(@NonNull final URL url) throws IOException {
final ProxyManager proxyManager = new ProxyManager(context);
final Proxy proxy = proxyManager.getProxy();
if (proxy != null) {
return (HttpURLConnection) url.openConnection(proxy);
}
return (HttpURLConnection) url.openConnection();
}
@ -1014,4 +1028,3 @@ public final class YoutubeHttpDataSource extends BaseDataSource implements HttpD
}
}
}

View File

@ -95,11 +95,11 @@ public class PlayerDataSource {
// YouTube-specific data source factories use getYoutubeHttpDataSourceFactory()
ytHlsCacheDataSourceFactory = new CacheFactory(context, transferListener, cache,
getYoutubeHttpDataSourceFactory(false, false));
getYoutubeHttpDataSourceFactory(context, false, false));
ytDashCacheDataSourceFactory = new CacheFactory(context, transferListener, cache,
getYoutubeHttpDataSourceFactory(true, true));
getYoutubeHttpDataSourceFactory(context, true, true));
ytProgressiveDashCacheDataSourceFactory = new CacheFactory(context, transferListener, cache,
getYoutubeHttpDataSourceFactory(false, true));
getYoutubeHttpDataSourceFactory(context, false, true));
// set the maximum size to manifest creators
YoutubeProgressiveDashManifestCreator.getCache().setMaximumSize(MAX_MANIFEST_CACHE_SIZE);
@ -191,9 +191,10 @@ public class PlayerDataSource {
}
private static YoutubeHttpDataSource.Factory getYoutubeHttpDataSourceFactory(
final Context context,
final boolean rangeParameterEnabled,
final boolean rnParameterEnabled) {
return new YoutubeHttpDataSource.Factory()
return new YoutubeHttpDataSource.Factory(context)
.setRangeParameterEnabled(rangeParameterEnabled)
.setRnParameterEnabled(rnParameterEnabled);
}

View File

@ -0,0 +1,79 @@
package org.schabi.newpipe.settings;
import android.content.Context;
import android.content.SharedPreferences;
import androidx.preference.PreferenceManager;
import java.net.InetSocketAddress;
import java.net.Proxy;
/**
* A class to manage proxy settings.
*/
public class ProxyManager {
private final SharedPreferences sharedPreferences;
/**
* Creates a new ProxyManager.
* @param context the context to use
*/
public ProxyManager(final Context context) {
this.sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
}
/**
* Checks if the proxy is enabled.
* @return true if the proxy is enabled, false otherwise
*/
public boolean isProxyEnabled() {
return sharedPreferences.getBoolean("use_proxy", false);
}
/**
* Gets the proxy host.
* @return the proxy host
*/
public String getProxyHost() {
return sharedPreferences.getString("proxy_host", "127.0.0.1");
}
/**
* Gets the proxy port.
* @return the proxy port
*/
public int getProxyPort() {
final String portString = sharedPreferences.getString("proxy_port", "1080");
try {
return Integer.parseInt(portString);
} catch (final NumberFormatException e) {
return 1080;
}
}
/**
* Gets the proxy type.
* @return the proxy type
*/
public Proxy.Type getProxyType() {
final String type = sharedPreferences.getString("proxy_type", "SOCKS");
if ("SOCKS".equals(type)) {
return Proxy.Type.SOCKS;
} else {
return Proxy.Type.HTTP;
}
}
/**
* Gets the proxy.
* @return the proxy, or null if the proxy is not enabled
*/
public Proxy getProxy() {
if (!isProxyEnabled()) {
return null;
}
return new Proxy(getProxyType(), new InetSocketAddress(getProxyHost(), getProxyPort()));
}
}

View File

@ -0,0 +1,26 @@
package org.schabi.newpipe.settings;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.preference.ListPreference;
import org.schabi.newpipe.R;
/**
* A fragment that displays proxy settings.
*/
public class ProxySettingsFragment extends BasePreferenceFragment {
@Override
public void onCreatePreferences(@Nullable final Bundle savedInstanceState,
@Nullable final String rootKey) {
addPreferencesFromResource(R.xml.proxy_settings);
final ListPreference proxyTypePreference = findPreference("proxy_type");
if (proxyTypePreference != null) {
proxyTypePreference.setSummaryProvider(
ListPreference.SimpleSummaryProvider.getInstance());
}
}
}

View File

@ -23,6 +23,7 @@ import com.squareup.picasso.Transformation;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.Image;
import org.schabi.newpipe.settings.ProxyManager;
import java.io.File;
import java.io.IOException;
@ -49,12 +50,17 @@ public final class PicassoHelper {
public static void init(final Context context) {
picassoCache = new LruCache(10 * 1024 * 1024);
picassoDownloaderClient = new OkHttpClient.Builder()
final ProxyManager proxyManager = new ProxyManager(context);
final OkHttpClient.Builder builder = new OkHttpClient.Builder()
.cache(new okhttp3.Cache(new File(context.getExternalCacheDir(), "picasso"),
50L * 1024L * 1024L))
// this should already be the default timeout in OkHttp3, but just to be sure...
.callTimeout(15, TimeUnit.SECONDS)
.build();
.callTimeout(15, TimeUnit.SECONDS);
if (proxyManager.isProxyEnabled()) {
builder.proxy(proxyManager.getProxy());
}
picassoDownloaderClient = builder.build();
picassoInstance = new Picasso.Builder(context)
.memoryCache(picassoCache) // memory cache

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_search"
android:icon="@drawable/ic_search"
android:title="@string/search"
app:showAsAction="ifRoom" />
</menu>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="proxy_settings_title">Настройки прокси</string>
<string name="use_proxy">Использовать прокси</string>
<string name="use_proxy_summary">Перенаправлять трафик через прокси</string>
<string name="proxy_host">Хост прокси</string>
<string name="proxy_host_summary">Имя хоста или IP-адрес прокси</string>
<string name="proxy_port">Порт прокси</string>
<string name="proxy_port_summary">Номер порта прокси</string>
<string name="proxy_port_dialog_message">Введите номер порта прокси</string>
</resources>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="proxy_settings_title">Proxy Settings</string>
<string name="use_proxy">Use proxy</string>
<string name="use_proxy_summary">Redirect traffic through a proxy</string>
<string name="proxy_host">Proxy host</string>
<string name="proxy_host_summary">Hostname or IP address of the proxy</string>
<string name="proxy_port">Proxy port</string>
<string name="proxy_port_summary">Port number of the proxy</string>
<string name="proxy_port_dialog_message">Enter the proxy port number</string>
<string name="proxy_type">Proxy type</string>
<string-array name="proxy_type_entries">
<item>HTTP</item>
<item>SOCKS</item>
</string-array>
<string-array name="proxy_type_values">
<item>HTTP</item>
<item>SOCKS</item>
</string-array>
</resources>

View File

@ -16,6 +16,12 @@
android:title="@string/settings_category_downloads_title"
app:iconSpaceReserved="false" />
<PreferenceScreen
android:fragment="org.schabi.newpipe.settings.ProxySettingsFragment"
android:icon="@drawable/ic_cloud_download"
android:title="@string/proxy_settings_title"
app:iconSpaceReserved="false" />
<PreferenceScreen
android:fragment="org.schabi.newpipe.settings.AppearanceSettingsFragment"
android:icon="@drawable/ic_palette"

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:title="@string/proxy_settings_title">
<SwitchPreferenceCompat
app:key="use_proxy"
app:title="@string/use_proxy"
app:summary="@string/use_proxy_summary"
app:defaultValue="false" />
<ListPreference
app:key="proxy_type"
app:title="@string/proxy_type"
app:summary="%s"
app:entries="@array/proxy_type_entries"
app:entryValues="@array/proxy_type_values"
app:defaultValue="HTTP"
app:dependency="use_proxy" />
<EditTextPreference
app:key="proxy_host"
app:title="@string/proxy_host"
app:summary="@string/proxy_host_summary"
app:defaultValue="127.0.0.1"
app:dependency="use_proxy" />
<EditTextPreference
app:key="proxy_port"
app:title="@string/proxy_port"
app:summary="@string/proxy_port_summary"
app:defaultValue="1080"
app:dependency="use_proxy"
app:dialogMessage="@string/proxy_port_dialog_message"
android:inputType="number" />
</PreferenceScreen>