diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index 4d05c69cc..8a4ed0607 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -136,7 +136,8 @@ public class App extends Application { final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( getApplicationContext()); final String key = getApplicationContext().getString(R.string.recaptcha_cookies_key); - downloader.setCookies(prefs.getString(key, "")); + downloader.setCookie(ReCaptchaActivity.RECAPTCHA_COOKIES_KEY, prefs.getString(key, "")); + downloader.updateYoutubeRestrictedModeCookies(getApplicationContext()); } private void configureRxJavaErrorHandler() { diff --git a/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java b/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java index ed517f160..95d3c2b7c 100644 --- a/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java +++ b/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java @@ -1,7 +1,8 @@ package org.schabi.newpipe; +import android.content.Context; import android.os.Build; -import android.text.TextUtils; +import android.preference.PreferenceManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -10,6 +11,8 @@ 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.util.CookieUtils; +import org.schabi.newpipe.util.InfoCache; import org.schabi.newpipe.util.TLSSocketFactoryCompat; import java.io.IOException; @@ -20,6 +23,7 @@ import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -40,9 +44,13 @@ import static org.schabi.newpipe.MainActivity.DEBUG; public final class DownloaderImpl extends Downloader { public static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:68.0) Gecko/20100101 Firefox/68.0"; + public static final String YOUTUBE_RESTRICTED_MODE_COOKIE_KEY + = "youtube_restricted_mode_key"; + public static final String YOUTUBE_RESTRICTED_MODE_COOKIE = "PREF=f2=8000000"; + public static final String YOUTUBE_DOMAIN = "youtube.com"; private static DownloaderImpl instance; - private String mCookies; + private Map mCookies; private OkHttpClient client; private DownloaderImpl(final OkHttpClient.Builder builder) { @@ -54,6 +62,7 @@ public final class DownloaderImpl extends Downloader { // .cache(new Cache(new File(context.getExternalCacheDir(), "okhttp"), // 16 * 1024 * 1024)) .build(); + this.mCookies = new HashMap<>(); } /** @@ -121,12 +130,50 @@ public final class DownloaderImpl extends Downloader { } } - public String getCookies() { - return mCookies; + public String getCookies(final String url) { + List resultCookies = new ArrayList<>(); + if (url.contains(YOUTUBE_DOMAIN)) { + String youtubeCookie = getCookie(YOUTUBE_RESTRICTED_MODE_COOKIE_KEY); + if (youtubeCookie != null) { + resultCookies.add(youtubeCookie); + } + } + // Recaptcha cookie is always added TODO: not sure if this is necessary + String recaptchaCookie = getCookie(ReCaptchaActivity.RECAPTCHA_COOKIES_KEY); + if (recaptchaCookie != null) { + resultCookies.add(recaptchaCookie); + } + return CookieUtils.concatCookies(resultCookies); } - public void setCookies(final String cookies) { - mCookies = cookies; + public String getCookie(final String key) { + return mCookies.get(key); + } + + public void setCookie(final String key, final String cookie) { + mCookies.put(key, cookie); + } + + public void removeCookie(final String key) { + mCookies.remove(key); + } + + public void updateYoutubeRestrictedModeCookies(final Context context) { + String restrictedModeEnabledKey = + context.getString(R.string.youtube_restricted_mode_enabled); + boolean restrictedModeEnabled = PreferenceManager.getDefaultSharedPreferences(context) + .getBoolean(restrictedModeEnabledKey, false); + updateYoutubeRestrictedModeCookies(restrictedModeEnabled); + } + + public void updateYoutubeRestrictedModeCookies(final boolean youtubeRestrictedModeEnabled) { + if (youtubeRestrictedModeEnabled) { + setCookie(YOUTUBE_RESTRICTED_MODE_COOKIE_KEY, + YOUTUBE_RESTRICTED_MODE_COOKIE); + } else { + removeCookie(YOUTUBE_RESTRICTED_MODE_COOKIE_KEY); + } + InfoCache.getInstance().clearCache(); } /** @@ -152,8 +199,9 @@ public final class DownloaderImpl extends Downloader { .method("GET", null).url(siteUrl) .addHeader("User-Agent", USER_AGENT); - if (!TextUtils.isEmpty(mCookies)) { - requestBuilder.addHeader("Cookie", mCookies); + String cookies = getCookies(siteUrl); + if (!cookies.isEmpty()) { + requestBuilder.addHeader("Cookie", cookies); } final okhttp3.Request request = requestBuilder.build(); @@ -192,8 +240,9 @@ public final class DownloaderImpl extends Downloader { .method(httpMethod, requestBody).url(url) .addHeader("User-Agent", USER_AGENT); - if (!TextUtils.isEmpty(mCookies)) { - requestBuilder.addHeader("Cookie", mCookies); + String cookies = getCookies(url); + if (!cookies.isEmpty()) { + requestBuilder.addHeader("Cookie", cookies); } for (Map.Entry> pair : headers.entrySet()) { diff --git a/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java b/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java index 49fb6b179..40ea4fd58 100644 --- a/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java +++ b/app/src/main/java/org/schabi/newpipe/ReCaptchaActivity.java @@ -51,6 +51,7 @@ public class ReCaptchaActivity extends AppCompatActivity { public static final String RECAPTCHA_URL_EXTRA = "recaptcha_url_extra"; public static final String TAG = ReCaptchaActivity.class.toString(); public static final String YT_URL = "https://www.youtube.com"; + public static final String RECAPTCHA_COOKIES_KEY = "recaptcha_cookies"; private WebView webView; private String foundCookies = ""; @@ -168,7 +169,7 @@ public class ReCaptchaActivity extends AppCompatActivity { prefs.edit().putString(key, foundCookies).apply(); // give cookies to Downloader class - DownloaderImpl.getInstance().setCookies(foundCookies); + DownloaderImpl.getInstance().setCookie(RECAPTCHA_COOKIES_KEY, foundCookies); setResult(RESULT_OK); } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java index 52c1afb93..000318ae2 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java @@ -2,6 +2,7 @@ package org.schabi.newpipe.fragments; import android.content.Context; import android.os.Bundle; +import android.preference.PreferenceManager; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; @@ -45,6 +46,9 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte private boolean hasTabsChanged = false; + private boolean previousYoutubeRestrictedModeEnabled; + private String youtubeRestrictedModeEnabledKey; + /*////////////////////////////////////////////////////////////////////////// // Fragment's LifeCycle //////////////////////////////////////////////////////////////////////////*/ @@ -53,7 +57,6 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); - tabsManager = TabsManager.getManager(activity); tabsManager.setSavedTabsListener(() -> { if (DEBUG) { @@ -66,6 +69,11 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte hasTabsChanged = true; } }); + + youtubeRestrictedModeEnabledKey = getString(R.string.youtube_restricted_mode_enabled); + previousYoutubeRestrictedModeEnabled = + PreferenceManager.getDefaultSharedPreferences(getContext()) + .getBoolean(youtubeRestrictedModeEnabledKey, false); } @Override @@ -92,7 +100,13 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte public void onResume() { super.onResume(); - if (hasTabsChanged) { + boolean youtubeRestrictedModeEnabled = + PreferenceManager.getDefaultSharedPreferences(getContext()) + .getBoolean(youtubeRestrictedModeEnabledKey, false); + if (previousYoutubeRestrictedModeEnabled != youtubeRestrictedModeEnabled) { + previousYoutubeRestrictedModeEnabled = youtubeRestrictedModeEnabled; + setupTabs(); + } else if (hasTabsChanged) { setupTabs(); } } diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java index bc2765387..b0bb30aa7 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java @@ -2,6 +2,7 @@ package org.schabi.newpipe.settings; import android.app.Activity; import android.app.AlertDialog; +import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; @@ -17,6 +18,7 @@ import androidx.preference.Preference; import com.nononsenseapps.filepicker.Utils; import com.nostra13.universalimageloader.core.ImageLoader; +import org.schabi.newpipe.DownloaderImpl; import org.schabi.newpipe.NewPipeDatabase; import org.schabi.newpipe.R; import org.schabi.newpipe.extractor.NewPipe; @@ -56,6 +58,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment { private File newpipeSettings; private String thumbnailLoadToggleKey; + private String youtubeRestrictedModeEnabledKey; private Localization initialSelectedLocalization; private ContentCountry initialSelectedContentCountry; @@ -65,6 +68,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment { public void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); thumbnailLoadToggleKey = getString(R.string.download_thumbnail_key); + youtubeRestrictedModeEnabledKey = getString(R.string.youtube_restricted_mode_enabled); initialSelectedLocalization = org.schabi.newpipe.util.Localization .getPreferredLocalization(requireContext()); @@ -86,6 +90,15 @@ public class ContentSettingsFragment extends BasePreferenceFragment { Toast.LENGTH_SHORT).show(); } + if (preference.getKey().equals(youtubeRestrictedModeEnabledKey)) { + Context context = getContext(); + if (context != null) { + DownloaderImpl.getInstance().updateYoutubeRestrictedModeCookies(context); + } else { + Log.w(TAG, "onPreferenceTreeClick: null context"); + } + } + return super.onPreferenceTreeClick(preference); } diff --git a/app/src/main/java/org/schabi/newpipe/util/CookieUtils.java b/app/src/main/java/org/schabi/newpipe/util/CookieUtils.java new file mode 100644 index 000000000..4575e7017 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/util/CookieUtils.java @@ -0,0 +1,25 @@ +package org.schabi.newpipe.util; + +import org.jsoup.helper.StringUtil; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +public final class CookieUtils { + private CookieUtils() { + } + + public static String concatCookies(final Collection cookieStrings) { + Set cookieSet = new HashSet<>(); + for (String cookies : cookieStrings) { + cookieSet.addAll(splitCookies(cookies)); + } + return StringUtil.join(cookieSet, "; ").trim(); + } + + public static Set splitCookies(final String cookies) { + return new HashSet<>(Arrays.asList(cookies.split("; *"))); + } +} diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index a95404925..926bb9a17 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -170,6 +170,7 @@ peertube_instance_list content_country show_age_restricted_content + youtube_restricted_mode_enabled use_tor enable_search_history enable_watch_history diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4ec48f8bd..3b7bc8a4a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -137,6 +137,7 @@ Content Age restricted content Show age restricted video. Future changes are possible from the settings. + YouTube restricted mode This video is age restricted.\n\nIf you want to view it, enable \"Age restricted content\" in the settings. Live Downloads diff --git a/app/src/main/res/xml/content_settings.xml b/app/src/main/res/xml/content_settings.xml index e2fbc081d..bf9c3d115 100644 --- a/app/src/main/res/xml/content_settings.xml +++ b/app/src/main/res/xml/content_settings.xml @@ -51,6 +51,12 @@ android:key="@string/show_age_restricted_content" android:title="@string/show_age_restricted_content_title"/> + +