diff --git a/MyVideoTube b/MyVideoTube index 3a6240ee1..545f6d1d2 160000 --- a/MyVideoTube +++ b/MyVideoTube @@ -1 +1 @@ -Subproject commit 3a6240ee11232f4fdea3ce88b9681e75c7bd5d68 +Subproject commit 545f6d1d2240d5f0a2c5909f99398b57bc1104ad diff --git a/SharedUtils b/SharedUtils index bb45ca575..01eaf49c4 160000 --- a/SharedUtils +++ b/SharedUtils @@ -1 +1 @@ -Subproject commit bb45ca575228dab0909f81f434793ed553379c67 +Subproject commit 01eaf49c4c58a83d0e99eb7f8d360c702efe0a7e diff --git a/browser/src/main/java/com/liskovsoft/browser/WebViewController.java b/browser/src/main/java/com/liskovsoft/browser/WebViewController.java index 79d01efe2..0f835df80 100644 --- a/browser/src/main/java/com/liskovsoft/browser/WebViewController.java +++ b/browser/src/main/java/com/liskovsoft/browser/WebViewController.java @@ -13,10 +13,7 @@ import android.webkit.ValueCallback; import android.webkit.WebChromeClient; import android.webkit.WebChromeClient.FileChooserParams; -import android.webkit.WebResourceRequest; -import android.webkit.WebResourceResponse; import android.webkit.WebView; -import android.webkit.WebViewClient; import java.util.Map; @@ -108,14 +105,20 @@ Tab openTab(String url, Tab parent, boolean setActive, boolean shouldCaptureThumbnails(); // My Custom Methods - + void setListener(Controller.EventListener listener); + void onControllerStart(); + void onSaveControllerState(Bundle state); + void onRestoreControllerState(Bundle state); + void setDefaultUrl(Uri url); + void setDefaultHeaders(Map headers); - Map getDefaultHeaders(); + + Map getDefaultHeaders(); // End My Custom Methods } diff --git a/common/src/main/res/values/languages.xml b/common/src/main/res/values/languages.xml index 3b5fe66f7..32a9c9b24 100644 --- a/common/src/main/res/values/languages.xml +++ b/common/src/main/res/values/languages.xml @@ -10,6 +10,7 @@ Arabic|ar Hebrew|he Spanish|es + Português Brasileiro|pt_BR Français|fr Nederlands|nl Czech|cs diff --git a/exoplayeractivity/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/player/ExoPlayerBaseFragment.java b/exoplayeractivity/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/player/ExoPlayerBaseFragment.java index 6167895e4..8835474f6 100644 --- a/exoplayeractivity/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/player/ExoPlayerBaseFragment.java +++ b/exoplayeractivity/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/player/ExoPlayerBaseFragment.java @@ -2,14 +2,14 @@ import android.content.Context; import android.content.Intent; -import android.net.Uri; import android.os.Bundle; import android.os.Handler; -import android.view.KeyEvent; import android.view.View; import android.widget.TextView; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; + import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.SimpleExoPlayer; @@ -21,7 +21,6 @@ import com.liskovsoft.sharedutils.dialogs.CombinedChoiceSelectorDialog; import com.liskovsoft.sharedutils.dialogs.SingleChoiceSelectorDialog; import com.liskovsoft.sharedutils.helpers.Helpers; -import com.liskovsoft.sharedutils.helpers.KeyHelpers; import com.liskovsoft.sharedutils.mylogger.Log; import com.liskovsoft.smartyoutubetv.flavors.exoplayer.player.dialogs.afr.AfrDialogSource; import com.liskovsoft.smartyoutubetv.flavors.exoplayer.player.dialogs.restrictcodec.RestrictFormatDialogSource; @@ -90,7 +89,6 @@ public abstract class ExoPlayerBaseFragment extends PlayerCoreFragment { private PlayerStateManager mStateManager; private VideoZoomManager mVideoZoomManager; private List mListeners; - private List mRestore; private boolean mIsAfrApplying; private boolean mPlaybackStopped; diff --git a/exoplayeractivity/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/player/dialogs/speed/SpeedDialogSource.java b/exoplayeractivity/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/player/dialogs/speed/SpeedDialogSource.java index aa0d29c73..3764ea755 100644 --- a/exoplayeractivity/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/player/dialogs/speed/SpeedDialogSource.java +++ b/exoplayeractivity/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/player/dialogs/speed/SpeedDialogSource.java @@ -1,6 +1,7 @@ package com.liskovsoft.smartyoutubetv.flavors.exoplayer.player.dialogs.speed; import android.content.Context; + import com.google.android.exoplayer2.SimpleExoPlayer; import com.liskovsoft.exoplayeractivity.R; import com.liskovsoft.sharedutils.dialogs.GenericSelectorDialog.CombinedDialogSource; @@ -12,31 +13,29 @@ public class SpeedDialogSource implements CombinedDialogSource { private final Context mContext; - private final SimpleExoPlayer mPlayer; - private final ArrayList mItems; - private final ExoPreferences mPrefs; + private final List mItems; public SpeedDialogSource(ExoPlayerFragment playerFragment) { mContext = playerFragment.getActivity(); - mPlayer = playerFragment.getPlayer(); - mPrefs = ExoPreferences.instance(mContext); + SimpleExoPlayer player = playerFragment.getPlayer(); + ExoPreferences preferences = ExoPreferences.instance(mContext); mItems = new ArrayList<>(); - mItems.add(new SaveSpeedDialogItem(mContext.getString(R.string.checkbox_save_speed), mPrefs)); - mItems.add(new SpeedDialogItem("0.25", "0.25", mPlayer, mPrefs)); - mItems.add(new SpeedDialogItem("0.5", "0.5", mPlayer, mPrefs)); - mItems.add(new SpeedDialogItem("0.75", "0.75", mPlayer, mPrefs)); - mItems.add(new SpeedDialogItem(mContext.getString(R.string.normal), "1.0", mPlayer, mPrefs)); - mItems.add(new SpeedDialogItem("1.25", "1.25", mPlayer, mPrefs)); - mItems.add(new SpeedDialogItem("1.5", "1.5", mPlayer, mPrefs)); - mItems.add(new SpeedDialogItem("1.75", "1.75", mPlayer, mPrefs)); - mItems.add(new SpeedDialogItem("2", "2.0", mPlayer, mPrefs)); - mItems.add(new SpeedDialogItem("2.25", "2.25", mPlayer, mPrefs)); - mItems.add(new SpeedDialogItem("2.5", "2.5", mPlayer, mPrefs)); - mItems.add(new SpeedDialogItem("2.75", "2.75", mPlayer, mPrefs)); - - if (mPlayer != null) { - SpeedDialogItem.sCurrentSpeed = String.valueOf(mPlayer.getPlaybackParameters().speed); + mItems.add(new SaveSpeedDialogItem(mContext.getString(R.string.checkbox_save_speed), preferences)); + mItems.add(new SpeedDialogItem("0.25", "0.25", player, preferences)); + mItems.add(new SpeedDialogItem("0.5", "0.5", player, preferences)); + mItems.add(new SpeedDialogItem("0.75", "0.75", player, preferences)); + mItems.add(new SpeedDialogItem(mContext.getString(R.string.normal), "1.0", player, preferences)); + mItems.add(new SpeedDialogItem("1.25", "1.25", player, preferences)); + mItems.add(new SpeedDialogItem("1.5", "1.5", player, preferences)); + mItems.add(new SpeedDialogItem("1.75", "1.75", player, preferences)); + mItems.add(new SpeedDialogItem("2", "2.0", player, preferences)); + mItems.add(new SpeedDialogItem("2.25", "2.25", player, preferences)); + mItems.add(new SpeedDialogItem("2.5", "2.5", player, preferences)); + mItems.add(new SpeedDialogItem("2.75", "2.75", player, preferences)); + + if (player != null) { + SpeedDialogItem.sCurrentSpeed = String.valueOf(player.getPlaybackParameters().speed); } } diff --git a/smartyoutubetv/build.gradle b/smartyoutubetv/build.gradle index 50ee21c1d..db1e10d66 100644 --- a/smartyoutubetv/build.gradle +++ b/smartyoutubetv/build.gradle @@ -38,8 +38,8 @@ android { minSdkVersion project.properties.minSdkVersion targetSdkVersion project.properties.targetSdkVersion applicationId "com.liskovsoft.videomanager" - versionCode 1142 - versionName "6.17.562" + versionCode 1149 + versionName "6.17.569" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" buildConfigField "long", "TIMESTAMP", System.currentTimeMillis() + "L" @@ -88,6 +88,10 @@ android { orig { matchingFallbacks = ['lite'] } + experiments { + matchingFallbacks = ['lite'] + applicationIdSuffix ".experiments" + } // Vtesting { // matchingFallbacks = ['lite'] // applicationIdSuffix ".testing" @@ -170,6 +174,9 @@ android { orig { java.srcDirs('src/commonSrc/crashHandler/java') } + experiments { + java.srcDirs('src/commonSrc/crashHandler/java') + } // Vtesting { // java.srcDirs = commonDirs // } @@ -220,6 +227,7 @@ dependencies { // ATV INSTALL_FAILED_CONFLICTING_PROVIDER fix origImplementation project(path: ':leanbackassistant') + experimentsImplementation project(path: ':leanbackassistant') implementation project(path: ':common') diff --git a/smartyoutubetv/src/experiments/AndroidManifest.xml b/smartyoutubetv/src/experiments/AndroidManifest.xml new file mode 100644 index 000000000..60ce1b8c7 --- /dev/null +++ b/smartyoutubetv/src/experiments/AndroidManifest.xml @@ -0,0 +1,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/smartyoutubetv/src/experiments/assets/service.properties b/smartyoutubetv/src/experiments/assets/service.properties new file mode 100644 index 000000000..4e65542a8 --- /dev/null +++ b/smartyoutubetv/src/experiments/assets/service.properties @@ -0,0 +1,9 @@ +# avoid resume playback after app exit +main_page_persistent = true +main_page_url = https://www.youtube.com/tv +music_page_url = https://www.youtube.com/tv#/surface?c=FEtopics¶ms=-gIFbXVzaWM%253D&resume +subscriptions_page_url = https://www.youtube.com/tv#/surface?c=FEsubscriptions +history_page_url = https://www.youtube.com/tv#/surface?c=FEmy_youtube +watch_later_page_url = https://www.youtube.com/tv#/surface?c=FEmy_youtube¶ms=cAc%253D&resume +stable_urls.github = https://github.com/yuliskov/SmartYouTubeTV/releases/download/experiments/smartyoutubetv.json +beta_urls.github = https://github.com/yuliskov/SmartYouTubeTV/releases/download/experiments/smartyoutubetv.json \ No newline at end of file diff --git a/smartyoutubetv/src/experiments/java/com/liskovsoft/smartyoutubetv/misc/appstatewatcher/AppStateWatcher.java b/smartyoutubetv/src/experiments/java/com/liskovsoft/smartyoutubetv/misc/appstatewatcher/AppStateWatcher.java new file mode 100644 index 000000000..edddd5ac0 --- /dev/null +++ b/smartyoutubetv/src/experiments/java/com/liskovsoft/smartyoutubetv/misc/appstatewatcher/AppStateWatcher.java @@ -0,0 +1,31 @@ +package com.liskovsoft.smartyoutubetv.misc.appstatewatcher; + +import com.liskovsoft.smartyoutubetv.flavors.common.FragmentManagerActivity; +import com.liskovsoft.smartyoutubetv.misc.appstatewatcher.handlers.ATVChannelsHandler; +import com.liskovsoft.smartyoutubetv.misc.appstatewatcher.handlers.ATVYouTubeBridgeHandler; +import com.liskovsoft.smartyoutubetv.misc.appstatewatcher.handlers.AdBlockPermissionsHandler; +import com.liskovsoft.smartyoutubetv.misc.appstatewatcher.handlers.AmazonYouTubeBridgeHandler; +import com.liskovsoft.smartyoutubetv.misc.appstatewatcher.handlers.ApkUpdaterHandler; +import com.liskovsoft.smartyoutubetv.misc.appstatewatcher.handlers.BackupAndRestoreHandler; +import com.liskovsoft.smartyoutubetv.misc.appstatewatcher.handlers.CacheCleanHandler; +import com.liskovsoft.smartyoutubetv.misc.appstatewatcher.handlers.LoadingCheckHandler; + +public class AppStateWatcher extends AppStateWatcherBase { + public AppStateWatcher(FragmentManagerActivity context) { + super(context); + + addHandler(new AdBlockPermissionsHandler(context, this)); + + addHandler(new ApkUpdaterHandler(context, this)); + + addHandler(new LoadingCheckHandler(context)); + + addHandler(new CacheCleanHandler(context)); + + addHandler(new BackupAndRestoreHandler(context, this)); + + // update recommendations + addHandler(new ATVChannelsHandler(context)); + } + +} diff --git a/smartyoutubetv/src/experiments/java/com/liskovsoft/smartyoutubetv/misc/appstatewatcher/handlers/ATVChannelsHandler.java b/smartyoutubetv/src/experiments/java/com/liskovsoft/smartyoutubetv/misc/appstatewatcher/handlers/ATVChannelsHandler.java new file mode 100644 index 000000000..c61a217b8 --- /dev/null +++ b/smartyoutubetv/src/experiments/java/com/liskovsoft/smartyoutubetv/misc/appstatewatcher/handlers/ATVChannelsHandler.java @@ -0,0 +1,23 @@ +package com.liskovsoft.smartyoutubetv.misc.appstatewatcher.handlers; + +import android.app.Activity; +import android.content.Intent; +import com.liskovsoft.leanbackassistant.channels.RunOnInstallReceiver; +import com.liskovsoft.sharedutils.helpers.Helpers; +import com.liskovsoft.smartyoutubetv.misc.appstatewatcher.AppStateWatcherBase.StateHandler; + +public class ATVChannelsHandler extends StateHandler { + private final Activity mContext; + + public ATVChannelsHandler(Activity context) { + mContext = context; + } + + @Override + public void onLoad() { + if (Helpers.isATVChannelsSupported(mContext) || Helpers.isATVRecommendationsSupported(mContext)) { + Intent intent = new Intent(mContext, RunOnInstallReceiver.class); + mContext.sendBroadcast(intent); + } + } +} diff --git a/smartyoutubetv/src/experiments/java/com/liskovsoft/smartyoutubetv/misc/appstatewatcher/handlers/AdBlockPermissionsHandler.java b/smartyoutubetv/src/experiments/java/com/liskovsoft/smartyoutubetv/misc/appstatewatcher/handlers/AdBlockPermissionsHandler.java new file mode 100644 index 000000000..7749eddaf --- /dev/null +++ b/smartyoutubetv/src/experiments/java/com/liskovsoft/smartyoutubetv/misc/appstatewatcher/handlers/AdBlockPermissionsHandler.java @@ -0,0 +1,56 @@ +package com.liskovsoft.smartyoutubetv.misc.appstatewatcher.handlers; + +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import com.liskovsoft.sharedutils.dialogs.YesNoDialog; +import com.liskovsoft.smartyoutubetv.CommonApplication; +import com.liskovsoft.smartyoutubetv.R; +import com.liskovsoft.smartyoutubetv.misc.appstatewatcher.AppStateWatcherBase; +import com.liskovsoft.smartyoutubetv.misc.appstatewatcher.AppStateWatcherBase.StateHandler; +import com.liskovsoft.smartyoutubetv.prefs.SmartPreferences; + +public class AdBlockPermissionsHandler extends StateHandler implements OnClickListener { + private final SmartPreferences mPrefs; + private final Context mContext; + private final AppStateWatcherBase mAppStateWatcher; + + public AdBlockPermissionsHandler(Context context, AppStateWatcherBase appStateWatcher) { + mAppStateWatcher = appStateWatcher; + mPrefs = CommonApplication.getPreferences(); + mContext = context; + } + + @Override + public void onInit() { + mAppStateWatcher.addRunAfterLock(this::runDialog); + } + + private void runDialog() { + boolean undefined = SmartPreferences.AD_BLOCK_UNDEFINED.equals(mPrefs.getAdBlockStatus()); + if (undefined) { + showPermissionsDialog(); + } + } + + private void showPermissionsDialog() { + mAppStateWatcher.setLock(true); + YesNoDialog.create(mContext, R.string.ad_blocking_permissions, this, R.style.AppDialog); + } + + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + //Yes button clicked + mPrefs.setAdBlockStatus(SmartPreferences.AD_BLOCK_ENABLED); + break; + + case DialogInterface.BUTTON_NEGATIVE: + //No button clicked + mPrefs.setAdBlockStatus(SmartPreferences.AD_BLOCK_DISABLED); + break; + } + mAppStateWatcher.setLock(false); + } +} diff --git a/smartyoutubetv/src/experiments/res/mipmap-nodpi/ic_banner_main.png b/smartyoutubetv/src/experiments/res/mipmap-nodpi/ic_banner_main.png new file mode 100644 index 000000000..04baba373 Binary files /dev/null and b/smartyoutubetv/src/experiments/res/mipmap-nodpi/ic_banner_main.png differ diff --git a/smartyoutubetv/src/experiments/res/mipmap-nodpi/ic_launcher_main.png b/smartyoutubetv/src/experiments/res/mipmap-nodpi/ic_launcher_main.png new file mode 100644 index 000000000..56630ab15 Binary files /dev/null and b/smartyoutubetv/src/experiments/res/mipmap-nodpi/ic_launcher_main.png differ diff --git a/smartyoutubetv/src/experiments/res/values/strings.xml b/smartyoutubetv/src/experiments/res/values/strings.xml new file mode 100644 index 000000000..554ac81ad --- /dev/null +++ b/smartyoutubetv/src/experiments/res/values/strings.xml @@ -0,0 +1,3 @@ + + Experiments YouTube TV + diff --git a/smartyoutubetv/src/experiments/res/xml/smart_preferences.xml b/smartyoutubetv/src/experiments/res/xml/smart_preferences.xml new file mode 100644 index 000000000..ee3a31f25 --- /dev/null +++ b/smartyoutubetv/src/experiments/res/xml/smart_preferences.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/smartyoutubetv/src/experiments/res/xml/whisperplay.xml b/smartyoutubetv/src/experiments/res/xml/whisperplay.xml new file mode 100644 index 000000000..82840c9cf --- /dev/null +++ b/smartyoutubetv/src/experiments/res/xml/whisperplay.xml @@ -0,0 +1,9 @@ + + + + + YouTube + android.intent.action.MAIN + + + \ No newline at end of file diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/bootstrap/dialogtweaks/TweaksDialogSource.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/bootstrap/dialogtweaks/TweaksDialogSource.java index 255a7a83f..1f4655498 100644 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/bootstrap/dialogtweaks/TweaksDialogSource.java +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/bootstrap/dialogtweaks/TweaksDialogSource.java @@ -51,8 +51,8 @@ public TweaksDialogSource(Context context) { mItems = new ArrayList<>(); //mItems.add(new UseNewUIDialogItem(mContext)); mItems.add(new SaveSelectionDialogItem(mContext)); - mItems.add(new UpdateCheckDialogItem(mContext)); - mItems.add(new BetaUpdateCheckDialogItem(mContext)); + //mItems.add(new UpdateCheckDialogItem(mContext)); + //mItems.add(new BetaUpdateCheckDialogItem(mContext)); //mItems.add(new EndCardsDialogItem(mContext)); mItems.add(new LogToFileDialogItem(mContext)); //mItems.add(new UnplayableVideoFixDialogItem(mContext)); diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/interceptors/HistoryInterceptor.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/interceptors/HistoryInterceptor.java index 2cac156a5..7371b4d43 100644 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/interceptors/HistoryInterceptor.java +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/interceptors/HistoryInterceptor.java @@ -1,8 +1,8 @@ package com.liskovsoft.smartyoutubetv.flavors.exoplayer.interceptors; import android.content.Context; -import android.os.Handler; import android.webkit.WebResourceResponse; + import com.liskovsoft.sharedutils.mylogger.Log; import com.liskovsoft.smartyoutubetv.CommonApplication; import com.liskovsoft.smartyoutubetv.interceptors.RequestInterceptor; @@ -11,15 +11,13 @@ public class HistoryInterceptor extends RequestInterceptor { private static final String TAG = HistoryInterceptor.class.getSimpleName(); - private final Context mContext; private final YouTubeHistoryUpdater mTracker; private float mPosition; private String mUrl; public HistoryInterceptor(Context context) { super(context); - mContext = context; - mTracker = new YouTubeHistoryUpdater(mContext); + mTracker = new YouTubeHistoryUpdater(context); } @Override diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/interceptors/NewVideoInterceptor.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/interceptors/NewVideoInterceptor.java deleted file mode 100644 index a07c6b85d..000000000 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/interceptors/NewVideoInterceptor.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.liskovsoft.smartyoutubetv.flavors.exoplayer.interceptors; - -import android.content.Context; -import android.webkit.WebResourceResponse; -import com.liskovsoft.smartyoutubetv.interceptors.RequestInterceptor; - -public class NewVideoInterceptor extends RequestInterceptor { - private final Context mContext; - private boolean mIsNewVideo; - - public NewVideoInterceptor(Context context) { - super(context); - mContext = context; - } - - @Override - public boolean test(String url) { - return true; - } - - @Override - public WebResourceResponse intercept(String url) { - mIsNewVideo = true; - return null; - } - - public boolean isNewVideo() { - return mIsNewVideo; - } - - public void reset() { - mIsNewVideo = false; - } -} diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/youtubeinfoparser/misc/DecipherUtils.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/youtubeinfoparser/misc/DecipherUtils.java index c54a29c23..88092c09e 100644 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/youtubeinfoparser/misc/DecipherUtils.java +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/youtubeinfoparser/misc/DecipherUtils.java @@ -12,17 +12,16 @@ */ public class DecipherUtils { // Don't remove var part! It is used inside the decipher function. - private static final String decipherPattern = - "var [_$A-Za-z]{2}=\\{.*\\n.*\\n.*\\nfunction [_$A-Za-z]{2}\\(a\\)\\{.*a\\.split\\(\"\"\\).*;return a\\.join\\(\"\"\\)\\}"; + private static final Pattern DECIPHER_PATTERN = Pattern.compile( + "var [_$A-Za-z]{2}=\\{.*\\n.*\\n.*\\nfunction [_$A-Za-z]{2}\\(a\\)\\{.*a\\.split\\(\"\"\\).*;return a\\.join\\(\"\"\\)\\}"); + private static final Pattern FUNCTION_PATTERN = Pattern.compile("function [_$A-Za-z]{2}"); public static String extractDecipherCode(InputStream is) { Scanner scanner = new Scanner(is); - Pattern regex = Pattern.compile(decipherPattern); - String jsCode = scanner.findWithinHorizon(regex, 0); + String jsCode = scanner.findWithinHorizon(DECIPHER_PATTERN, 0); if (jsCode == null) { return null; } - String cleaned = jsCode.replaceFirst("function [_$A-Za-z]{2}", "function decipherSignature"); - return cleaned; + return FUNCTION_PATTERN.matcher(jsCode).replaceFirst("function decipherSignature"); } } diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/youtubeinfoparser/mpd/OtfSegmentParser.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/youtubeinfoparser/mpd/OtfSegmentParser.java index d31c274fa..34e0a865c 100644 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/youtubeinfoparser/mpd/OtfSegmentParser.java +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/youtubeinfoparser/mpd/OtfSegmentParser.java @@ -2,7 +2,6 @@ import com.liskovsoft.sharedutils.mylogger.Log; import com.liskovsoft.sharedutils.okhttp.OkHttpHelpers; -import okhttp3.Response; import java.io.BufferedReader; import java.io.IOException; @@ -13,8 +12,12 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import okhttp3.Response; + public class OtfSegmentParser { private static final String TAG = OtfSegmentParser.class.getSimpleName(); + private static final Pattern SEGMENT_PATTERN = Pattern.compile("Segment-Durations-Ms: (.*)"); + private static final Pattern DIGIT_PATTERN = Pattern.compile("\\d+"); private final boolean mCached; private List mCachedSegments; private boolean mAlreadyParsed; @@ -77,12 +80,10 @@ private List parseInt(Reader stream) { BufferedReader bufferedReader = new BufferedReader(stream); - Pattern segmentPattern = Pattern.compile("Segment-Durations-Ms: (.*)"); - try { String currentLine; while ((currentLine = bufferedReader.readLine()) != null) { - Matcher segmentPatternMatcher = segmentPattern.matcher(currentLine); + Matcher segmentPatternMatcher = SEGMENT_PATTERN.matcher(currentLine); if (segmentPatternMatcher.matches()) { result = splitToSegments(segmentPatternMatcher.group(1)); break; @@ -107,10 +108,8 @@ private List splitToSegments(String rawString) { if (rawString != null) { String[] split = rawString.split(","); // Sample to match: '5120(r=192)' or '5120' - Pattern segmentPattern = Pattern.compile("\\d+"); - for (String item : split) { - Matcher segmentPatternMatcher = segmentPattern.matcher(item); + Matcher segmentPatternMatcher = DIGIT_PATTERN.matcher(item); int findNum = 0; OtfSegment segment = new OtfSegment(); diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/youtubeinfoparser/mpd/SimpleMPDBuilder.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/youtubeinfoparser/mpd/SimpleMPDBuilder.java index 6d6bd564c..b20d11886 100644 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/youtubeinfoparser/mpd/SimpleMPDBuilder.java +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/youtubeinfoparser/mpd/SimpleMPDBuilder.java @@ -1,17 +1,19 @@ package com.liskovsoft.smartyoutubetv.flavors.exoplayer.youtubeinfoparser.mpd; import android.util.Xml; + import com.liskovsoft.sharedutils.helpers.FileHelpers; +import com.liskovsoft.sharedutils.helpers.Helpers; import com.liskovsoft.sharedutils.mylogger.Log; import com.liskovsoft.smartyoutubetv.flavors.exoplayer.youtubeinfoparser.misc.ITag; -import com.liskovsoft.smartyoutubetv.flavors.exoplayer.youtubeinfoparser.mpd.OtfSegmentParser.OtfSegment; -import com.liskovsoft.smartyoutubetv.flavors.exoplayer.youtubeinfoparser.parsers.JsonInfoParser.Subtitle; -import com.liskovsoft.smartyoutubetv.flavors.exoplayer.youtubeinfoparser.parsers.YouTubeMediaParser.GenericInfo; -import com.liskovsoft.smartyoutubetv.flavors.exoplayer.youtubeinfoparser.parsers.JsonInfoParser.MediaItem; import com.liskovsoft.smartyoutubetv.flavors.exoplayer.youtubeinfoparser.misc.MediaItemComparator; import com.liskovsoft.smartyoutubetv.flavors.exoplayer.youtubeinfoparser.misc.MediaItemUtils; import com.liskovsoft.smartyoutubetv.flavors.exoplayer.youtubeinfoparser.misc.SimpleYouTubeGenericInfo; -import com.liskovsoft.sharedutils.helpers.Helpers; +import com.liskovsoft.smartyoutubetv.flavors.exoplayer.youtubeinfoparser.mpd.OtfSegmentParser.OtfSegment; +import com.liskovsoft.smartyoutubetv.flavors.exoplayer.youtubeinfoparser.parsers.JsonInfoParser.MediaItem; +import com.liskovsoft.smartyoutubetv.flavors.exoplayer.youtubeinfoparser.parsers.JsonInfoParser.Subtitle; +import com.liskovsoft.smartyoutubetv.flavors.exoplayer.youtubeinfoparser.parsers.YouTubeMediaParser.GenericInfo; + import org.xmlpull.v1.XmlSerializer; import java.io.IOException; @@ -35,6 +37,7 @@ public class SimpleMPDBuilder implements MPDBuilder { private static final String NULL_INDEX_RANGE = "0-0"; private static final String NULL_CONTENT_LENGTH = "0"; private static final String TAG = SimpleMPDBuilder.class.getSimpleName(); + private static final Pattern CODECS_PATTERN = Pattern.compile(".*codecs=\\\"(.*)\\\""); private final GenericInfo mInfo; private final boolean mVLCFix; private XmlSerializer mXmlSerializer; @@ -299,7 +302,7 @@ private void writeMediaListPrologue(String id, String mimeType) { attribute("", "value", "main"); endTag("", "Role"); } - + private void writeMediaListPrologue(Subtitle sub) { String id = String.valueOf(mId++); @@ -374,7 +377,7 @@ private String extractMimeType(MediaItem item) { String codecs = extractCodecs(item); if (codecs.startsWith("vorbis") || - codecs.startsWith("opus")) { + codecs.startsWith("opus")) { return MIME_WEBM_AUDIO; } @@ -432,7 +435,7 @@ private void writeMediaItemTag(MediaItem item) { } else if (item.getSegmentUrlList() != null) { writeSegmentList(item); } else if (item.getIndex() != null && - !item.getIndex().equals(NULL_INDEX_RANGE)) { // json format fix: index is null + !item.getIndex().equals(NULL_INDEX_RANGE)) { // json format fix: index is null writeSegmentBase(item); } @@ -528,8 +531,7 @@ private XmlSerializer text(String url) { private String extractCodecs(MediaItem item) { // input example: video/mp4;+codecs="avc1.640033" - Pattern pattern = Pattern.compile(".*codecs=\\\"(.*)\\\""); - Matcher matcher = pattern.matcher(item.getType()); + Matcher matcher = CODECS_PATTERN.matcher(item.getType()); matcher.find(); return matcher.group(1); } @@ -541,6 +543,7 @@ private String extractCodecs(MediaItem item) { * "http://example.com?dur=544.99&key=val&key2=val2" *
* "http://example.com/dur/544.99/key/val/key2/val2" + * * @return duration as string */ private String extractDurationFromTrack() { @@ -627,7 +630,7 @@ private boolean isLive() { private boolean isLiveMedia(MediaItem item) { boolean isLive = item.getUrl().contains("live=1") || - item.getUrl().contains("yt_live_broadcast"); + item.getUrl().contains("yt_live_broadcast"); return isLive; } @@ -665,7 +668,7 @@ private void writeOtfSegmentTemplateOld(MediaItem item) { endTag("", "SegmentTemplate"); } - + private void writeOtfSegmentTemplate(MediaItem item) { // // diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/youtubeinfoparser/parsers/ParserUtils.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/youtubeinfoparser/parsers/ParserUtils.java index b3afcc585..6246accbf 100644 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/youtubeinfoparser/parsers/ParserUtils.java +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/flavors/exoplayer/youtubeinfoparser/parsers/ParserUtils.java @@ -1,6 +1,7 @@ package com.liskovsoft.smartyoutubetv.flavors.exoplayer.youtubeinfoparser.parsers; import android.net.Uri; + import com.google.gson.JsonArray; import com.google.gson.JsonSyntaxException; import com.jayway.jsonpath.Configuration; @@ -15,9 +16,18 @@ import java.io.InputStream; -public class ParserUtils { +public final class ParserUtils { + private static final String TAG = ParserUtils.class.getSimpleName(); + private static final Configuration JSON_PATH_CONFIGURATION = Configuration.builder() + .mappingProvider(new GsonMappingProvider()) + .jsonProvider(new GsonJsonProvider()) + .build(); + + private ParserUtils() { + } + public static String extractParam(String queryParam, String content) { Uri videoInfo = parseUri(content); String value = videoInfo.getQueryParameter(queryParam); @@ -52,19 +62,13 @@ public static DocumentContext createJsonInfoParser(T jsonInfo) { throw new IllegalStateException("Can't create parser. jsonInfo == null"); } - Configuration conf = Configuration - .builder() - .mappingProvider(new GsonMappingProvider()) - .jsonProvider(new GsonJsonProvider()) - .build(); - DocumentContext jsonPath; try { if (jsonInfo instanceof InputStream) { - jsonPath = JsonPath.using(conf).parse((InputStream) jsonInfo, "UTF-8"); + jsonPath = JsonPath.using(JSON_PATH_CONFIGURATION).parse((InputStream) jsonInfo); } else if (jsonInfo instanceof String) { - jsonPath = JsonPath.using(conf).parse((String) jsonInfo); + jsonPath = JsonPath.using(JSON_PATH_CONFIGURATION).parse((String) jsonInfo); } else { throw new IllegalStateException("Can't create parser. Unknown input type: " + jsonInfo.getClass().getSimpleName()); } @@ -110,8 +114,8 @@ private static T extractType(String jsonPath, DocumentContext parser) { return result; } - - public static void delete(String jsonPath, DocumentContext parser) { + + public static void delete(JsonPath jsonPath, DocumentContext parser) { try { parser.delete(jsonPath); } catch (PathNotFoundException e) { // NOTE: exception isn't thrown in some cases @@ -120,7 +124,7 @@ public static void delete(String jsonPath, DocumentContext parser) { } } - public static boolean exists(String jsonPath, DocumentContext parser) { + public static boolean exists(JsonPath jsonPath, DocumentContext parser) { boolean result; try { diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/FileExtensionInterceptor.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/FileExtensionInterceptor.java new file mode 100644 index 000000000..acb807d2f --- /dev/null +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/FileExtensionInterceptor.java @@ -0,0 +1,35 @@ +package com.liskovsoft.smartyoutubetv.interceptors; + +import android.content.Context; +import android.webkit.MimeTypeMap; +import android.webkit.WebResourceResponse; + +/** + * The {@link FileExtensionInterceptor} class represent request interceptor by file extensions. + *

+ * Attention! This class cannot be used in {@link RequestInterceptorProcessor} list, because + * return {@code null} as processing result. + */ +public class FileExtensionInterceptor extends RequestInterceptor { + + public FileExtensionInterceptor(Context context) { + super(context); + } + + @Override + public boolean test(String url) { + String ext = MimeTypeMap.getFileExtensionFromUrl(url); + if (ext.isEmpty()) { + return false; + } + return ext.equals("jpg") + || ext.equals("png") + || ext.equals("ico") + || ext.equals("ttf"); + } + + @Override + public WebResourceResponse intercept(String url) { + return null; + } +} diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/RequestInterceptorProcessor.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/RequestInterceptorProcessor.java index 63c59bac5..366db2a94 100644 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/RequestInterceptorProcessor.java +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/RequestInterceptorProcessor.java @@ -17,8 +17,10 @@ public class RequestInterceptorProcessor { private static final String TAG = RequestInterceptorProcessor.class.getSimpleName(); private final List mInterceptors; + private final FileExtensionInterceptor mFileExtensionInterceptor; public RequestInterceptorProcessor(Context context) { + mFileExtensionInterceptor = new FileExtensionInterceptor(context); mInterceptors = new ArrayList<>(); mInterceptors.add(new AdAwayInterceptor(context)); mInterceptors.add(new BrowseInterceptor(context)); // impact performance @@ -38,8 +40,11 @@ public WebResourceResponse process(String url) { Log.d(TAG, "Intercepting url: " + url); WebResourceResponse result = null; - - for (RequestInterceptor interceptor : mInterceptors) { + if (mFileExtensionInterceptor.test(url)) { + return null; + } + for (int i = 0; i < mInterceptors.size(); i++) { + RequestInterceptor interceptor = mInterceptors.get(i); if (interceptor.test(url)) { result = interceptor.intercept(url); diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/ads/AdAwayInterceptor.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/ads/AdAwayInterceptor.java index 9b32dd217..704ac39f0 100644 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/ads/AdAwayInterceptor.java +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/ads/AdAwayInterceptor.java @@ -2,6 +2,7 @@ import android.content.Context; import android.webkit.WebResourceResponse; + import com.liskovsoft.sharedutils.mylogger.Log; import com.liskovsoft.smartyoutubetv.CommonApplication; import com.liskovsoft.smartyoutubetv.interceptors.RequestInterceptor; @@ -29,11 +30,10 @@ public AdAwayInterceptor(Context context) { @Override public boolean test(String url) { - if (mClient.isAd(url)) { - return mAdBlockEnabled; - } else { - return false; + if (mAdBlockEnabled) { + return mClient.isAd(url); } + return false; } @Override diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/ads/BrowseInterceptor.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/ads/BrowseInterceptor.java index 5601d218d..f4e834afb 100644 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/ads/BrowseInterceptor.java +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/ads/BrowseInterceptor.java @@ -3,11 +3,12 @@ import android.content.Context; import android.webkit.WebResourceResponse; +import com.liskovsoft.m3uparser.core.utils.Strings; import com.liskovsoft.sharedutils.helpers.AssetHelper; -import com.liskovsoft.sharedutils.helpers.Helpers; import com.liskovsoft.sharedutils.mylogger.Log; import com.liskovsoft.smartyoutubetv.CommonApplication; import com.liskovsoft.smartyoutubetv.interceptors.RequestInterceptor; +import com.liskovsoft.smartyoutubetv.interceptors.ads.contentfilter.ReplacingInputStream; import com.liskovsoft.smartyoutubetv.misc.SmartUtils; import com.liskovsoft.smartyoutubetv.misc.UserAgentManager; import com.liskovsoft.smartyoutubetv.prefs.SmartPreferences; @@ -36,6 +37,7 @@ public class BrowseInterceptor extends RequestInterceptor { private boolean mIsXWalk; private boolean mIsAdBlockEnabled; private boolean mIsEnableVideoMenu; + private boolean mIsCompatibleSettings; public BrowseInterceptor(Context context) { super(context); @@ -44,6 +46,7 @@ public BrowseInterceptor(Context context) { mIsXWalk = SmartUtils.isXWalk(mContext); mIsAdBlockEnabled = mPrefs.isAdBlockEnabled(); mIsEnableVideoMenu = mPrefs.getEnableVideoMenu(); + mIsCompatibleSettings = mIsEnableVideoMenu || (mIsAdBlockEnabled && !mIsXWalk); initHeaders(); } @@ -57,7 +60,7 @@ private void initHeaders() { @Override public boolean test(String url) { - return url != null && url.contains(BROWSE_URL); + return mIsCompatibleSettings && (url != null && url.contains(BROWSE_URL)); } @Override @@ -82,7 +85,7 @@ private WebResourceResponse filterBannerData(String url) { String postData = mPrefs.getPostData(); - if (postData == null) { + if (Strings.isNullOrEmpty(postData)) { Log.e(TAG, "Post body is empty! Skipping url: " + url); return null; } @@ -97,34 +100,16 @@ private WebResourceResponse filterBannerData(String url) { InputStream urlData = postJsonData(url, postData, mHeaders); - WebResourceResponse response = null; - - if (Log.getLogType().equals(Log.LOG_TYPE_FILE) && urlData != null) { - String content = Helpers.toString(urlData); - Log.d(TAG, "Url: " + url + ". Post Data: " + postData + ". Response: " + content); - urlData = Helpers.toStream(content); - } - - if (urlData != null) { - Log.d(TAG, "Searching and removing tv masthead section..."); - JsonBrowseParser browseParser = JsonBrowseParser.parse(urlData); - - if (browseParser.removeMastHead()) { - Log.d(TAG, "Success. TV masthead has been removed."); - } else { - if (Log.getLogType().equals(Log.LOG_TYPE_FILE)) { - Log.d(TAG, "Oops. Response doesn't contain MustHead section. Url: " + url + ". Post Data: " + postData + ". Response: " + Helpers.toString(browseParser.toStream())); - } else { - Log.d(TAG, "Oops. Response doesn't contain MustHead section. Url: " + url + ". Post Data: " + postData); - } - } - - response = createResponse("application/json", null, browseParser.toStream()); - } else { + if (urlData == null) { Log.e(TAG, "Error. Response in empty. Url: " + url + ". Post Data: " + postData); + return null; } - return response; + Log.d(TAG, "Searching and removing tv masthead section..."); + + ReplacingInputStream replacingInputStream = new ReplacingInputStream(urlData, "tvMastheadRenderer", "broken-tvMastheadRend"); + + return createResponse("application/json", null, replacingInputStream); } private WebResourceResponse filterLongPressVideoMenu(String url) { diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/ads/JsonBrowseParser.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/ads/JsonBrowseParser.java index 81756d8c0..894e10ff5 100644 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/ads/JsonBrowseParser.java +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/ads/JsonBrowseParser.java @@ -1,6 +1,7 @@ package com.liskovsoft.smartyoutubetv.interceptors.ads; import com.jayway.jsonpath.DocumentContext; +import com.jayway.jsonpath.JsonPath; import com.liskovsoft.sharedutils.helpers.Helpers; import com.liskovsoft.smartyoutubetv.flavors.exoplayer.youtubeinfoparser.parsers.ParserUtils; @@ -9,7 +10,7 @@ public class JsonBrowseParser { // All objects with property 'tvMastheadRenderer' // ex: https://github.com/json-path/JsonPath - private static final String TV_MASTHEAD_SECTION_ANY = "$..[?(@.tvMastheadRenderer)]"; + private static final JsonPath TV_MASTHEAD_SECTION_ANY = JsonPath.compile("$..[?(@.tvMastheadRenderer)]"); private final DocumentContext mParser; diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/ads/contentfilter/ReplacingInputStream.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/ads/contentfilter/ReplacingInputStream.java index 257c1a681..7f699a8e3 100644 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/ads/contentfilter/ReplacingInputStream.java +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/ads/contentfilter/ReplacingInputStream.java @@ -1,142 +1,63 @@ package com.liskovsoft.smartyoutubetv.interceptors.ads.contentfilter; -import androidx.core.util.Pair; -import com.liskovsoft.sharedutils.mylogger.Log; -import java.io.*; -import java.util.*; - -class ReplacingInputStream extends FilterInputStream { - private static final String TAG = ReplacingInputStream.class.getSimpleName(); - private LinkedList mInQueue = new LinkedList<>(); - private LinkedList mOutQueue = new LinkedList<>(); - private static String DEFAULT_ENCODING = "UTF-8"; - private final List mPairs; - - static class ReplacePair extends Pair { - public boolean matchFound; - - public ReplacePair(String first, String second) { - super(first, second); - } - } - - protected ReplacingInputStream(InputStream in, List pairs) { - super(in); - mPairs = pairs; - } - - private boolean isMatchFound() throws UnsupportedEncodingException { - Iterator inIter = mInQueue.iterator(); - - int maxLength = findMaxSearchLength(); - boolean matchFound = false; - - for (int i = 0; i < maxLength; i++) { - if (!inIter.hasNext()) { - break; - } - - Integer next = inIter.next(); - - for (ReplacePair pair : mPairs) { - if (i < pair.first.getBytes(DEFAULT_ENCODING).length && (pair.matchFound || i == 0)) { // NOTE: it's buggy because of different strings length - pair.matchFound = pair.first.getBytes(DEFAULT_ENCODING)[i] == next; - - if (pair.matchFound && (pair.first.getBytes(DEFAULT_ENCODING).length - 1) == i) { - matchFound = true; - break; - } - } - } - } - - return matchFound; - } - - private void readAhead() throws IOException { - // Work up some look-ahead. - int maxLength = findMaxSearchLength(); - while (mInQueue.size() < maxLength) { - int next = super.read(); - mInQueue.offer(next); - if (next == -1) { - break; - } - } - } - - private int findMaxSearchLength() throws UnsupportedEncodingException { - int length = 0; - - for (Pair pair : mPairs) { - if (pair.first.getBytes(DEFAULT_ENCODING).length > length) { - length = pair.first.getBytes(DEFAULT_ENCODING).length; - } - } - - return length; - } - - private int findMatchedSearchLength() throws UnsupportedEncodingException { - int length = 0; - - for (ReplacePair pair : mPairs) { - if (pair.matchFound) { - length = pair.first.getBytes(DEFAULT_ENCODING).length; - break; - } - } - - return length; - } - - private byte[] findReplacement() throws UnsupportedEncodingException { - byte[] result = null; - - for (ReplacePair pair : mPairs) { - if (pair.matchFound) { - result = pair.second.getBytes(DEFAULT_ENCODING); - break; - } - } - - return result; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +/** + * Simple FilterInputStream that can replace occurrances of bytes with something else. + */ +public class ReplacingInputStream extends FilterInputStream { + + // while matching, this is where the bytes go. + int[] buf = null; + int matchedIndex = 0; + int unbufferIndex = 0; + int replacedIndex = 0; + + private final byte[] pattern; + private final byte[] replacement; + private State state = State.NOT_MATCHED; + + // simple state machine for keeping track of what we are doing + private enum State { + NOT_MATCHED, + MATCHING, + REPLACING, + UNBUFFER } - @Override - public int read() throws IOException { - // Next byte already determined. - if (mOutQueue.isEmpty()) { - readAhead(); - - if (isMatchFound()) { - int matchedLength = findMatchedSearchLength(); - - for (int i = 0; i < matchedLength; i++) { - mInQueue.remove(); - } - - byte[] replacement = findReplacement(); - - for (byte b : replacement) { - mOutQueue.offer((int) b); - } - } else { - mOutQueue.add(mInQueue.remove()); - } - } - - return mOutQueue.remove(); + /** + * Replace occurances of pattern in the input. Note: input is assumed to be UTF-8 encoded. If not the case use byte[] based pattern and replacement. + * + * @param in input + * @param pattern pattern to replace. + * @param replacement the replacement or null + */ + public ReplacingInputStream(InputStream in, String pattern, String replacement) { + this(in, pattern.getBytes(StandardCharsets.UTF_8), replacement == null ? null : replacement.getBytes(StandardCharsets.UTF_8)); } - @Override - public int read(byte[] b) throws IOException { - return read(b, 0, b.length); + /** + * Replace occurances of pattern in the input. + * + * @param in input + * @param pattern pattern to replace + * @param replacement the replacement or null + */ + public ReplacingInputStream(InputStream in, byte[] pattern, byte[] replacement) { + super(in); + this.pattern = pattern; + this.replacement = replacement; + // we will never match more than the pattern length + buf = new int[pattern.length]; } @Override public int read(byte[] b, int off, int len) throws IOException { + // copy of parent logic; we need to call our own read() instead of super.read(), which delegates instead of calling our read if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { @@ -149,19 +70,108 @@ public int read(byte[] b, int off, int len) throws IOException { if (c == -1) { return -1; } - b[off] = (byte)c; + b[off] = (byte) c; int i = 1; try { - for (; i < len ; i++) { + for (; i < len; i++) { c = read(); if (c == -1) { break; } - b[off + i] = (byte)c; + b[off + i] = (byte) c; } } catch (IOException ee) { } return i; + } -} + + @Override + public int read(byte[] b) throws IOException { + // call our own read + return read(b, 0, b.length); + } + + @Override + public int read() throws IOException { + // use a simple state machine to figure out what we are doing + int next; + switch (state) { + case NOT_MATCHED: + // we are not currently matching, replacing, or unbuffering + next = super.read(); + if (pattern[0] == next) { + // clear whatever was there + buf = new int[pattern.length]; // clear whatever was there + // make sure we start at 0 + matchedIndex = 0; + + buf[matchedIndex++] = next; + if (pattern.length == 1) { + // edgecase when the pattern length is 1 we go straight to replacing + state = State.REPLACING; + // reset replace counter + replacedIndex = 0; + } else { + // pattern of length 1 + state = State.MATCHING; + } + // recurse to continue matching + return read(); + } else { + return next; + } + case MATCHING: + // the previous bytes matched part of the pattern + next = super.read(); + if (pattern[matchedIndex] == next) { + buf[matchedIndex++] = next; + if (matchedIndex == pattern.length) { + // we've found a full match! + if (replacement == null || replacement.length == 0) { + // the replacement is empty, go straight to NOT_MATCHED + state = State.NOT_MATCHED; + matchedIndex = 0; + } else { + // start replacing + state = State.REPLACING; + replacedIndex = 0; + } + } + } else { + // mismatch -> unbuffer + buf[matchedIndex++] = next; + state = State.UNBUFFER; + unbufferIndex = 0; + } + return read(); + case REPLACING: + // we've fully matched the pattern and are returning bytes from the replacement + next = replacement[replacedIndex++]; + if (replacedIndex == replacement.length) { + state = State.NOT_MATCHED; + replacedIndex = 0; + } + return next; + case UNBUFFER: + // we partially matched the pattern before encountering a non matching byte + // we need to serve up the buffered bytes before we go back to NOT_MATCHED + next = buf[unbufferIndex++]; + if (unbufferIndex == matchedIndex) { + state = State.NOT_MATCHED; + matchedIndex = 0; + } + return next; + + default: + throw new IllegalStateException("no such state " + state); + } + } + + @Override + public String toString() { + return state.name() + " " + matchedIndex + " " + replacedIndex + " " + unbufferIndex; + } + +} \ No newline at end of file diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/scripts/LegacyMainScriptManagerInterceptor.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/scripts/LegacyMainScriptManagerInterceptor.java index ca3897adc..d85d4260c 100644 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/scripts/LegacyMainScriptManagerInterceptor.java +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/scripts/LegacyMainScriptManagerInterceptor.java @@ -1,15 +1,20 @@ package com.liskovsoft.smartyoutubetv.interceptors.scripts; import android.content.Context; + import com.liskovsoft.sharedutils.helpers.Helpers; +import java.util.regex.Pattern; + +import static java.util.regex.Pattern.compile; + /** - * Legacy devices + * Legacy devices */ public class LegacyMainScriptManagerInterceptor extends MainScriptManagerInterceptor { - private static final String[] BASE_SCRIPT_REGEX = {"youtube.com/s/_/kabuki_legacy/_/js/.*/m=base$"}; - private static final String[] MAIN_SCRIPT_REGEX = {"youtube.com/s/_/kabuki_legacy/_/js/.*/m=main$"}; - private static final String[] MAIN_STYLE_REGEX = {"youtube.com/s/_/kabuki_legacy/_/ss/.*"}; + private static final Pattern[] BASE_SCRIPT_REGEX = {compile("youtube.com/s/_/kabuki_legacy/_/js/.*/m=base$")}; + private static final Pattern[] MAIN_SCRIPT_REGEX = {compile("youtube.com/s/_/kabuki_legacy/_/js/.*/m=main$")}; + private static final Pattern[] MAIN_STYLE_REGEX = {compile("youtube.com/s/_/kabuki_legacy/_/ss/.*")}; public LegacyMainScriptManagerInterceptor(Context context) { super(context); diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/scripts/ScriptManagerInterceptor.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/scripts/ScriptManagerInterceptor.java index cb77b22b9..b40bfbdc4 100644 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/scripts/ScriptManagerInterceptor.java +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/interceptors/scripts/ScriptManagerInterceptor.java @@ -13,6 +13,7 @@ import com.liskovsoft.smartyoutubetv.webscripts.ScriptManager; import java.io.InputStream; +import java.util.BitSet; import okhttp3.Response; import okhttp3.ResponseBody; @@ -22,6 +23,13 @@ public abstract class ScriptManagerInterceptor extends RequestInterceptor { private final ScriptManager mManager; private final ContentFilter mFilter; private boolean mFirstScriptDone; + private final BitSet mState = new BitSet(4); + private final static BitSet DONE_STATE = new BitSet(4); + private boolean mIsScriptsLoad = false; + + static { + DONE_STATE.set(1, 5); + } public ScriptManagerInterceptor(Context context) { super(context); @@ -32,6 +40,9 @@ public ScriptManagerInterceptor(Context context) { @Override public boolean test(String url) { + if (mIsScriptsLoad) { + return false; + } if (isFirstScript(url)) { return true; } @@ -69,6 +80,7 @@ public WebResourceResponse intercept(String url) { mFirstScriptDone = true; result = mFilter.filterFirstScript(result); } else if (isSecondScript(url)) { + syncState(4); result = mFilter.filterSecondScript(result); } else if (isLastScript(url)) { if (!mFirstScriptDone) { @@ -87,6 +99,7 @@ public WebResourceResponse intercept(String url) { @Nullable private InputStream applyInit(InputStream result) { + syncState(1); Log.d(TAG, "Begin onInitScripts"); InputStream onInitScripts = mManager.getOnInitScripts(); Log.d(TAG, "End onInitScripts"); @@ -96,6 +109,7 @@ private InputStream applyInit(InputStream result) { @Nullable private InputStream applyLoad(InputStream result) { + syncState(2); Log.d(TAG, "Begin onLoadScript"); InputStream onLoadScripts = mManager.getOnLoadScripts(); Log.d(TAG, "End onLoadScript"); @@ -105,6 +119,7 @@ private InputStream applyLoad(InputStream result) { @Nullable private InputStream applyStyles(InputStream result) { + syncState(3); Log.d(TAG, "Begin onStyles"); InputStream styles = mManager.getStyles(); Log.d(TAG, "End onStyles"); @@ -112,6 +127,13 @@ private InputStream applyStyles(InputStream result) { return result; } + private void syncState(int state) { + mState.set(state); + if (DONE_STATE.equals(mState)) { + mIsScriptsLoad = true; + } + } + protected abstract boolean isFirstScript(String url); protected abstract boolean isSecondScript(String url); diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/misc/keyhandler/BrowserKeyTranslator.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/misc/keyhandler/BrowserKeyTranslator.java index 333fb4497..a32b01268 100644 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/misc/keyhandler/BrowserKeyTranslator.java +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/misc/keyhandler/BrowserKeyTranslator.java @@ -1,13 +1,28 @@ package com.liskovsoft.smartyoutubetv.misc.keyhandler; import android.view.KeyEvent; + import com.liskovsoft.smartyoutubetv.CommonApplication; import com.liskovsoft.smartyoutubetv.keytranslator.KeyTranslator; +import java.util.Collections; import java.util.HashMap; import java.util.Map; public class BrowserKeyTranslator extends KeyTranslator { + + private static Map KEY_MAPPING = new HashMap<>(); + + static { + KEY_MAPPING.put(KeyEvent.KEYCODE_BUTTON_B, KeyEvent.KEYCODE_ESCAPE); + KEY_MAPPING.put(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_ESCAPE); + KEY_MAPPING.put(KeyEvent.KEYCODE_MENU, KeyEvent.KEYCODE_G); // menu to guide + KEY_MAPPING.put(KeyEvent.KEYCODE_NUMPAD_ENTER, KeyEvent.KEYCODE_ENTER); + KEY_MAPPING.put(KeyEvent.KEYCODE_BUTTON_A, KeyEvent.KEYCODE_ENTER); + KEY_MAPPING.put(KeyEvent.KEYCODE_BUTTON_Y, KeyEvent.KEYCODE_SEARCH); + KEY_MAPPING = Collections.unmodifiableMap(KEY_MAPPING); + } + public static KeyTranslator create() { if (CommonApplication.getPreferences().getAltPlayerMappingEnabled()) { return new AltMediaBrowserKeyTranslator(); @@ -18,14 +33,6 @@ public static KeyTranslator create() { @Override protected Map getKeyMapping() { - Map keyMapping = new HashMap<>(); - keyMapping.put(KeyEvent.KEYCODE_BUTTON_B, KeyEvent.KEYCODE_ESCAPE); - keyMapping.put(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_ESCAPE); - keyMapping.put(KeyEvent.KEYCODE_MENU, KeyEvent.KEYCODE_G); // menu to guide - keyMapping.put(KeyEvent.KEYCODE_NUMPAD_ENTER, KeyEvent.KEYCODE_ENTER); - keyMapping.put(KeyEvent.KEYCODE_BUTTON_A, KeyEvent.KEYCODE_ENTER); - keyMapping.put(KeyEvent.KEYCODE_BUTTON_Y, KeyEvent.KEYCODE_SEARCH); - - return keyMapping; + return KEY_MAPPING; } } diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/misc/keyhandler/MediaBrowserKeyTranslator.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/misc/keyhandler/MediaBrowserKeyTranslator.java index 3297d486f..b0bac1596 100644 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/misc/keyhandler/MediaBrowserKeyTranslator.java +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/misc/keyhandler/MediaBrowserKeyTranslator.java @@ -1,12 +1,42 @@ package com.liskovsoft.smartyoutubetv.misc.keyhandler; import android.view.KeyEvent; + import com.liskovsoft.smartyoutubetv.misc.SmartUtils; +import java.util.Collections; +import java.util.HashMap; import java.util.Map; public class MediaBrowserKeyTranslator extends BrowserKeyTranslator { private static final String KEY_PRESS_MESSAGE = "key_press_message"; + private Map keyMapping; + + public MediaBrowserKeyTranslator() { + Map superkeyMapping = super.getKeyMapping(); + keyMapping = new HashMap<>(superkeyMapping); + // triggerEvent($('#watch'), 'keydown', 228); + // triggerEvent($('.scrubber'), 'keydown', 228); + + // FF + // triggerEvent($$('.focused'), 'keydown', 228); + + // P/P + // triggerEvent($$('.focused'), 'keyup', 179); + + // test + //keyMapping.put(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_MEDIA_PLAY); + + // disable media keys + keyMapping.put(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, KeyEvent.KEYCODE_UNKNOWN); + keyMapping.put(KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_UNKNOWN); + keyMapping.put(KeyEvent.KEYCODE_MEDIA_STOP, KeyEvent.KEYCODE_UNKNOWN); + keyMapping.put(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, KeyEvent.KEYCODE_UNKNOWN); + keyMapping.put(KeyEvent.KEYCODE_MEDIA_REWIND, KeyEvent.KEYCODE_UNKNOWN); + keyMapping.put(KeyEvent.KEYCODE_MEDIA_NEXT, KeyEvent.KEYCODE_UNKNOWN); + keyMapping.put(KeyEvent.KEYCODE_MEDIA_PREVIOUS, KeyEvent.KEYCODE_UNKNOWN); + keyMapping = Collections.unmodifiableMap(keyMapping); + } @Override public KeyEvent doTranslateKeys(KeyEvent event) { @@ -43,29 +73,6 @@ private void sendMessage(String keyCode, KeyEvent event) { @Override protected Map getKeyMapping() { - Map keyMapping = super.getKeyMapping(); - - // triggerEvent($('#watch'), 'keydown', 228); - // triggerEvent($('.scrubber'), 'keydown', 228); - - // FF - // triggerEvent($$('.focused'), 'keydown', 228); - - // P/P - // triggerEvent($$('.focused'), 'keyup', 179); - - // test - //keyMapping.put(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_MEDIA_PLAY); - - // disable media keys - keyMapping.put(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, KeyEvent.KEYCODE_UNKNOWN); - keyMapping.put(KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_UNKNOWN); - keyMapping.put(KeyEvent.KEYCODE_MEDIA_STOP, KeyEvent.KEYCODE_UNKNOWN); - keyMapping.put(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, KeyEvent.KEYCODE_UNKNOWN); - keyMapping.put(KeyEvent.KEYCODE_MEDIA_REWIND, KeyEvent.KEYCODE_UNKNOWN); - keyMapping.put(KeyEvent.KEYCODE_MEDIA_NEXT, KeyEvent.KEYCODE_UNKNOWN); - keyMapping.put(KeyEvent.KEYCODE_MEDIA_PREVIOUS, KeyEvent.KEYCODE_UNKNOWN); - return keyMapping; } } diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/misc/myquerystring/MyPathQueryString.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/misc/myquerystring/MyPathQueryString.java index da0024397..30f52191a 100644 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/misc/myquerystring/MyPathQueryString.java +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/misc/myquerystring/MyPathQueryString.java @@ -1,6 +1,7 @@ package com.liskovsoft.smartyoutubetv.misc.myquerystring; import androidx.annotation.NonNull; + import com.liskovsoft.sharedutils.helpers.Helpers; import java.util.regex.Matcher; @@ -11,6 +12,8 @@ * Regex: \/key\/([^\/]*) */ public class MyPathQueryString implements MyQueryString { + private static final Pattern VALIDATION_PATTERN_1 = Pattern.compile("^[^&=]*$"); + private static final Pattern VALIDATION_PATTERN_2 = Pattern.compile("\\/[^\\/]+\\/[^\\/]+"); private String mUrl; public MyPathQueryString(String url) { @@ -108,7 +111,7 @@ public boolean isValid() { return false; } - return Helpers.matchAll(mUrl, "^[^&=]*$", "\\/[^\\/]+\\/[^\\/]+"); + return Helpers.matchAll(mUrl, VALIDATION_PATTERN_1, VALIDATION_PATTERN_2); } @Override diff --git a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/misc/youtubeutils/YouTubeHistoryUpdater.java b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/misc/youtubeutils/YouTubeHistoryUpdater.java index 5934708d5..ca140e9d2 100644 --- a/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/misc/youtubeutils/YouTubeHistoryUpdater.java +++ b/smartyoutubetv/src/main/java/com/liskovsoft/smartyoutubetv/misc/youtubeutils/YouTubeHistoryUpdater.java @@ -1,27 +1,27 @@ package com.liskovsoft.smartyoutubetv.misc.youtubeutils; import android.content.Context; + import com.liskovsoft.sharedutils.mylogger.Log; import com.liskovsoft.sharedutils.okhttp.OkHttpHelpers; import com.liskovsoft.smartyoutubetv.misc.HeaderManager; import com.liskovsoft.smartyoutubetv.misc.myquerystring.MyQueryString; import com.liskovsoft.smartyoutubetv.misc.myquerystring.MyQueryStringFactory; -import okhttp3.Response; import java.util.HashMap; +import okhttp3.Response; + public class YouTubeHistoryUpdater { private static final String TAG = YouTubeHistoryUpdater.class.getSimpleName(); private static final String LEN = "len"; private static final String CMT = "cmt"; private static final String ST = "st"; private static final String ET = "et"; - private final Context mContext; private final HeaderManager mManager; public YouTubeHistoryUpdater(Context context) { - mContext = context; - mManager = new HeaderManager(mContext); + mManager = new HeaderManager(context); } public void sync(String trackingUrl, float position, float length) { diff --git a/smartyoutubetv/src/main/res/mipmap-nodpi/ic_banner_main_new.png b/smartyoutubetv/src/main/res/mipmap-nodpi/ic_banner_main_new.png deleted file mode 100644 index 9bf9a38d4..000000000 Binary files a/smartyoutubetv/src/main/res/mipmap-nodpi/ic_banner_main_new.png and /dev/null differ diff --git a/smartyoutubetv/src/main/res/mipmap-nodpi/ic_banner_main_old1.png b/smartyoutubetv/src/main/res/mipmap-nodpi/ic_banner_main_old1.png deleted file mode 100644 index 9d3ccd493..000000000 Binary files a/smartyoutubetv/src/main/res/mipmap-nodpi/ic_banner_main_old1.png and /dev/null differ diff --git a/smartyoutubetv/src/main/res/mipmap-nodpi/ic_launcher_main_old1.png b/smartyoutubetv/src/main/res/mipmap-nodpi/ic_launcher_main_old1.png deleted file mode 100644 index 0d8111e1c..000000000 Binary files a/smartyoutubetv/src/main/res/mipmap-nodpi/ic_launcher_main_old1.png and /dev/null differ diff --git a/smartyoutubetv/src/orig/java/com/liskovsoft/smartyoutubetv/misc/appstatewatcher/AppStateWatcher.java b/smartyoutubetv/src/orig/java/com/liskovsoft/smartyoutubetv/misc/appstatewatcher/AppStateWatcher.java index f9ff649a6..677441588 100644 --- a/smartyoutubetv/src/orig/java/com/liskovsoft/smartyoutubetv/misc/appstatewatcher/AppStateWatcher.java +++ b/smartyoutubetv/src/orig/java/com/liskovsoft/smartyoutubetv/misc/appstatewatcher/AppStateWatcher.java @@ -8,7 +8,6 @@ import com.liskovsoft.smartyoutubetv.misc.appstatewatcher.handlers.ApkUpdaterHandler; import com.liskovsoft.smartyoutubetv.misc.appstatewatcher.handlers.BackupAndRestoreHandler; import com.liskovsoft.smartyoutubetv.misc.appstatewatcher.handlers.CacheCleanHandler; -import com.liskovsoft.smartyoutubetv.misc.appstatewatcher.handlers.ForceNewUIHandler; import com.liskovsoft.smartyoutubetv.misc.appstatewatcher.handlers.LoadingCheckHandler; public class AppStateWatcher extends AppStateWatcherBase { diff --git a/smartyoutubetv/src/test/java/com/liskovsoft/smartyoutubetv/interceptors/ads/contentfilter/ReplacingInputStreamTest.java b/smartyoutubetv/src/test/java/com/liskovsoft/smartyoutubetv/interceptors/ads/contentfilter/ReplacingInputStreamTest.java index a44563842..7d331277e 100644 --- a/smartyoutubetv/src/test/java/com/liskovsoft/smartyoutubetv/interceptors/ads/contentfilter/ReplacingInputStreamTest.java +++ b/smartyoutubetv/src/test/java/com/liskovsoft/smartyoutubetv/interceptors/ads/contentfilter/ReplacingInputStreamTest.java @@ -2,7 +2,7 @@ import com.liskovsoft.sharedutils.TestHelpers; import com.liskovsoft.sharedutils.helpers.Helpers; -import com.liskovsoft.smartyoutubetv.interceptors.ads.contentfilter.ReplacingInputStream.ReplacePair; + import org.junit.Before; import org.junit.Test; @@ -22,7 +22,7 @@ public void setUp() { @Test public void replacementTest() { - InputStream ris = new ReplacingInputStream(mMainJSOrigin, new ReplacePair("tvMastheadRenderer", "tvMastheadRendererOld")); + InputStream ris = new ReplacingInputStream(mMainJSOrigin, "tvMastheadRenderer".getBytes(), "tvMastheadRendererOld".getBytes()); assertEquals(TestHelpers.unescapeJavaString(Helpers.toString(mMainJSResult)), TestHelpers.unescapeJavaString(Helpers.toString(ris))); } } \ No newline at end of file