From 2f7c0e57820ac6993bbf1fd5a5c9ddb376b8132a Mon Sep 17 00:00:00 2001 From: FongMi Date: Tue, 23 May 2023 11:29:35 +0800 Subject: [PATCH] [leanback] add player setting --- app/src/leanback/AndroidManifest.xml | 5 + .../tv/ui/activity/SettingActivity.java | 6 + .../tv/ui/activity/SettingPlayerActivity.java | 73 ++++++++++++ .../android/tv/ui/custom/dialog/UaDialog.java | 97 ++++++++++++++++ .../res/layout/activity_setting_player.xml | 104 ++++++++++++++++++ app/src/leanback/res/layout/dialog_ua.xml | 81 ++++++++++++++ .../fongmi/android/tv/impl/UaCallback.java | 6 + .../com/fongmi/android/tv/player/ExoUtil.java | 16 ++- .../com/fongmi/android/tv/player/Players.java | 11 +- .../com/fongmi/android/tv/utils/Prefers.java | 24 ++++ app/src/main/res/values-zh-rCN/strings.xml | 10 ++ app/src/main/res/values-zh-rTW/strings.xml | 10 ++ app/src/main/res/values/strings.xml | 10 ++ .../ijk/media/player/ui/IjkVideoView.java | 9 +- .../tv/danmaku/ijk/media/player/ui/Utils.java | 16 --- 15 files changed, 453 insertions(+), 25 deletions(-) create mode 100644 app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingPlayerActivity.java create mode 100644 app/src/leanback/java/com/fongmi/android/tv/ui/custom/dialog/UaDialog.java create mode 100644 app/src/leanback/res/layout/activity_setting_player.xml create mode 100644 app/src/leanback/res/layout/dialog_ua.xml create mode 100644 app/src/main/java/com/fongmi/android/tv/impl/UaCallback.java diff --git a/app/src/leanback/AndroidManifest.xml b/app/src/leanback/AndroidManifest.xml index 8ec608c1d8..e7f602b8bb 100644 --- a/app/src/leanback/AndroidManifest.xml +++ b/app/src/leanback/AndroidManifest.xml @@ -80,5 +80,10 @@ android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" android:screenOrientation="sensorLandscape" /> + + \ No newline at end of file diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingActivity.java index 3ff2840d2d..208eb52c4d 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingActivity.java @@ -109,6 +109,7 @@ protected void initEvent() { mBinding.vodHistory.setOnClickListener(this::onVodHistory); mBinding.version.setOnLongClickListener(this::onVersionDev); mBinding.liveHistory.setOnClickListener(this::onLiveHistory); + mBinding.player.setOnLongClickListener(this::onPlayerSetting); mBinding.wallDefault.setOnClickListener(this::setWallDefault); mBinding.wallRefresh.setOnClickListener(this::setWallRefresh); mBinding.quality.setOnClickListener(this::setQuality); @@ -231,6 +232,11 @@ private void onLiveHistory(View view) { HistoryDialog.create(this).type(type = 1).show(); } + private boolean onPlayerSetting(View view) { + SettingPlayerActivity.start(this); + return true; + } + private void onVersion(View view) { Updater.get().force().release().start(); } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingPlayerActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingPlayerActivity.java new file mode 100644 index 0000000000..fc35e628e7 --- /dev/null +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingPlayerActivity.java @@ -0,0 +1,73 @@ +package com.fongmi.android.tv.ui.activity; + +import android.app.Activity; +import android.content.Intent; +import android.view.View; + +import androidx.viewbinding.ViewBinding; + +import com.fongmi.android.tv.R; +import com.fongmi.android.tv.databinding.ActivitySettingPlayerBinding; +import com.fongmi.android.tv.impl.UaCallback; +import com.fongmi.android.tv.player.ExoUtil; +import com.fongmi.android.tv.ui.base.BaseActivity; +import com.fongmi.android.tv.ui.custom.dialog.UaDialog; +import com.fongmi.android.tv.utils.Prefers; +import com.fongmi.android.tv.utils.ResUtil; + +public class SettingPlayerActivity extends BaseActivity implements UaCallback { + + private ActivitySettingPlayerBinding mBinding; + private String[] http; + + public static void start(Activity activity) { + activity.startActivity(new Intent(activity, SettingPlayerActivity.class)); + } + + private String getSwitch(boolean value) { + return getString(value ? R.string.setting_on : R.string.setting_off); + } + + @Override + protected ViewBinding getBinding() { + return mBinding = ActivitySettingPlayerBinding.inflate(getLayoutInflater()); + } + + @Override + protected void initView() { + mBinding.uaText.setText(Prefers.getUa()); + mBinding.tunnelText.setText(getSwitch(Prefers.isTunnel())); + mBinding.httpText.setText((http = ResUtil.getStringArray(R.array.select_player_http))[Prefers.getHttp()]); + mBinding.tunnel.setVisibility(Prefers.getPlayer() == 0 ? View.VISIBLE : View.GONE); + mBinding.http.setVisibility(Prefers.getPlayer() == 0 ? View.VISIBLE : View.GONE); + } + + @Override + protected void initEvent() { + mBinding.ua.setOnClickListener(this::onUa); + mBinding.http.setOnClickListener(this::setHttp); + mBinding.tunnel.setOnClickListener(this::setTunnel); + } + + private void onUa(View view) { + UaDialog.create(this).show(); + } + + private void setHttp(View view) { + int index = Prefers.getHttp(); + Prefers.putHttp(index = index == http.length - 1 ? 0 : ++index); + mBinding.httpText.setText(http[index]); + ExoUtil.reset(); + } + + private void setTunnel(View view) { + Prefers.putTunnel(!Prefers.isTunnel()); + mBinding.tunnelText.setText(getSwitch(Prefers.isTunnel())); + } + + @Override + public void setUa(String ua) { + mBinding.uaText.setText(ua); + Prefers.putUa(ua); + } +} diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/custom/dialog/UaDialog.java b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/dialog/UaDialog.java new file mode 100644 index 0000000000..33711a2087 --- /dev/null +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/dialog/UaDialog.java @@ -0,0 +1,97 @@ +package com.fongmi.android.tv.ui.custom.dialog; + +import android.content.DialogInterface; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.WindowManager; +import android.view.inputmethod.EditorInfo; + +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.FragmentActivity; + +import com.fongmi.android.tv.R; +import com.fongmi.android.tv.databinding.DialogUaBinding; +import com.fongmi.android.tv.event.ServerEvent; +import com.fongmi.android.tv.impl.UaCallback; +import com.fongmi.android.tv.server.Server; +import com.fongmi.android.tv.utils.Prefers; +import com.fongmi.android.tv.utils.QRCode; +import com.fongmi.android.tv.utils.ResUtil; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +public class UaDialog implements DialogInterface.OnDismissListener { + + private final DialogUaBinding binding; + private final UaCallback callback; + private final AlertDialog dialog; + + public static UaDialog create(FragmentActivity activity) { + return new UaDialog(activity); + } + + public UaDialog(FragmentActivity activity) { + this.callback = (UaCallback) activity; + this.binding = DialogUaBinding.inflate(LayoutInflater.from(activity)); + this.dialog = new MaterialAlertDialogBuilder(activity).setView(binding.getRoot()).create(); + } + + public void show() { + initDialog(); + initView(); + initEvent(); + } + + private void initDialog() { + WindowManager.LayoutParams params = dialog.getWindow().getAttributes(); + params.width = (int) (ResUtil.getScreenWidth() * 0.55f); + dialog.getWindow().setAttributes(params); + dialog.getWindow().setDimAmount(0); + dialog.setOnDismissListener(this); + dialog.show(); + } + + private void initView() { + String ua = Prefers.getUa(); + String address = Server.get().getAddress(); + binding.text.setText(ua); + binding.code.setImageBitmap(QRCode.getBitmap(address, 200, 0)); + binding.text.setSelection(TextUtils.isEmpty(ua) ? 0 : ua.length()); + binding.info.setText(ResUtil.getString(R.string.push_info, address).replace(",", "\n")); + } + + private void initEvent() { + EventBus.getDefault().register(this); + binding.positive.setOnClickListener(this::onPositive); + binding.negative.setOnClickListener(this::onNegative); + binding.text.setOnEditorActionListener((textView, actionId, event) -> { + if (actionId == EditorInfo.IME_ACTION_DONE) binding.positive.performClick(); + return true; + }); + } + + private void onPositive(View view) { + callback.setUa(binding.text.getText().toString().trim()); + dialog.dismiss(); + } + + private void onNegative(View view) { + dialog.dismiss(); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onServerEvent(ServerEvent event) { + if (event.getType() != ServerEvent.Type.API) return; + binding.text.setText(event.getText()); + binding.positive.performClick(); + } + + @Override + public void onDismiss(DialogInterface dialogInterface) { + EventBus.getDefault().unregister(this); + } +} diff --git a/app/src/leanback/res/layout/activity_setting_player.xml b/app/src/leanback/res/layout/activity_setting_player.xml new file mode 100644 index 0000000000..0e34b2213e --- /dev/null +++ b/app/src/leanback/res/layout/activity_setting_player.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/leanback/res/layout/dialog_ua.xml b/app/src/leanback/res/layout/dialog_ua.xml new file mode 100644 index 0000000000..41aa733594 --- /dev/null +++ b/app/src/leanback/res/layout/dialog_ua.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/fongmi/android/tv/impl/UaCallback.java b/app/src/main/java/com/fongmi/android/tv/impl/UaCallback.java new file mode 100644 index 0000000000..66150efb34 --- /dev/null +++ b/app/src/main/java/com/fongmi/android/tv/impl/UaCallback.java @@ -0,0 +1,6 @@ +package com.fongmi.android.tv.impl; + +public interface UaCallback { + + void setUa(String ua); +} diff --git a/app/src/main/java/com/fongmi/android/tv/player/ExoUtil.java b/app/src/main/java/com/fongmi/android/tv/player/ExoUtil.java index 7e2ac60bf0..310a736660 100644 --- a/app/src/main/java/com/fongmi/android/tv/player/ExoUtil.java +++ b/app/src/main/java/com/fongmi/android/tv/player/ExoUtil.java @@ -12,6 +12,7 @@ import androidx.media3.database.StandaloneDatabaseProvider; import androidx.media3.datasource.DataSource; import androidx.media3.datasource.DefaultDataSource; +import androidx.media3.datasource.DefaultHttpDataSource; import androidx.media3.datasource.HttpDataSource; import androidx.media3.datasource.cache.Cache; import androidx.media3.datasource.cache.CacheDataSource; @@ -39,7 +40,6 @@ import com.fongmi.android.tv.bean.Sub; import com.fongmi.android.tv.utils.FileUtil; import com.fongmi.android.tv.utils.Prefers; -import com.fongmi.android.tv.utils.Sniffer; import com.github.catvod.net.OkHttp; import com.google.common.net.HttpHeaders; @@ -64,7 +64,7 @@ public static LoadControl buildLoadControl() { public static TrackSelector buildTrackSelector() { DefaultTrackSelector trackSelector = new DefaultTrackSelector(App.get()); - trackSelector.setParameters(trackSelector.buildUponParameters().setPreferredTextLanguage("zh")); + trackSelector.setParameters(trackSelector.buildUponParameters().setPreferredTextLanguage("zh").setTunnelingEnabled(Prefers.isTunnel())); return trackSelector; } @@ -122,12 +122,11 @@ private static synchronized ExtractorsFactory getExtractorsFactory() { } private static synchronized HttpDataSource.Factory getHttpDataSourceFactory() { - if (httpDataSourceFactory == null) httpDataSourceFactory = new OkHttpDataSource.Factory((Call.Factory) OkHttp.client()); + if (httpDataSourceFactory == null) httpDataSourceFactory = Prefers.getHttp() == 0 ? new DefaultHttpDataSource.Factory().setAllowCrossProtocolRedirects(true) : new OkHttpDataSource.Factory((Call.Factory) OkHttp.client()); return httpDataSourceFactory; } private static synchronized DataSource.Factory getDataSourceFactory(Map headers) { - if (!headers.containsKey(HttpHeaders.USER_AGENT)) headers.put(HttpHeaders.USER_AGENT, Sniffer.CHROME); if (dataSourceFactory == null) dataSourceFactory = buildReadOnlyCacheDataSource(new DefaultDataSource.Factory(App.get(), getHttpDataSourceFactory()), getCache()); httpDataSourceFactory.setDefaultRequestProperties(headers); return dataSourceFactory; @@ -146,4 +145,13 @@ private static synchronized Cache getCache() { if (cache == null) cache = new SimpleCache(FileUtil.getCacheDir("player"), new NoOpCacheEvictor(), getDatabase()); return cache; } + + public static void reset() { + if (cache != null) cache.release(); + httpDataSourceFactory = null; + dataSourceFactory = null; + extractorsFactory = null; + database = null; + cache = null; + } } diff --git a/app/src/main/java/com/fongmi/android/tv/player/Players.java b/app/src/main/java/com/fongmi/android/tv/player/Players.java index bb03a84e95..3c45a52da5 100644 --- a/app/src/main/java/com/fongmi/android/tv/player/Players.java +++ b/app/src/main/java/com/fongmi/android/tv/player/Players.java @@ -24,6 +24,7 @@ import com.fongmi.android.tv.utils.ResUtil; import com.github.catvod.crawler.SpiderDebug; import com.google.common.collect.ImmutableList; +import com.google.common.net.HttpHeaders; import java.util.Formatter; import java.util.List; @@ -327,8 +328,14 @@ private void stopParse() { if (parseJob != null) parseJob.stop(); } + private Map checkHeaders(Map headers) { + if (Prefers.getUa().isEmpty() || headers.containsKey(HttpHeaders.USER_AGENT) || headers.containsKey(HttpHeaders.USER_AGENT.toLowerCase())) return headers; + headers.put(HttpHeaders.USER_AGENT, Prefers.getUa()); + return headers; + } + private void setMediaSource(Result result) { - SpiderDebug.log(errorCode + "," + result.getRealUrl() + "," + result.getHeaders()); + SpiderDebug.log(errorCode + "," + result.getRealUrl() + "," + checkHeaders(result.getHeaders())); if (isIjk()) ijkPlayer.setMediaSource(result.getRealUrl(), result.getHeaders()); if (isExo()) exoPlayer.setMediaSource(ExoUtil.getSource(result, errorCode)); if (isExo()) exoPlayer.prepare(); @@ -336,7 +343,7 @@ private void setMediaSource(Result result) { } private void setMediaSource(Map headers, String url) { - SpiderDebug.log(errorCode + "," + url + "," + headers); + SpiderDebug.log(errorCode + "," + url + "," + checkHeaders(headers)); if (isIjk()) ijkPlayer.setMediaSource(url, headers); if (isExo()) exoPlayer.setMediaSource(ExoUtil.getSource(headers, url, errorCode)); if (isExo()) exoPlayer.prepare(); diff --git a/app/src/main/java/com/fongmi/android/tv/utils/Prefers.java b/app/src/main/java/com/fongmi/android/tv/utils/Prefers.java index aefb53ba9e..fd3b1cf934 100644 --- a/app/src/main/java/com/fongmi/android/tv/utils/Prefers.java +++ b/app/src/main/java/com/fongmi/android/tv/utils/Prefers.java @@ -203,6 +203,30 @@ public static void putUpdate(boolean update) { put("update", update); } + public static String getUa() { + return getString("ua", Sniffer.CHROME); + } + + public static void putUa(String ua) { + put("ua", ua); + } + + public static boolean isTunnel() { + return getBoolean("exo_tunnel"); + } + + public static void putTunnel(boolean tunnel) { + put("exo_tunnel", tunnel); + } + + public static int getHttp() { + return getInt("exo_http", 1); + } + + public static void putHttp(int http) { + put("exo_http", http); + } + public static float getThumbnail() { return 0.3f * getQuality() + 0.4f; } diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index fc3d359d50..6966a4eb0a 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -61,6 +61,9 @@ 直播 壁纸 播放器 + User Agent + Tunnel Mode + Http Source 解码方式 渲染方式 缩放比例 @@ -70,6 +73,8 @@ 缓存 版本 权限 + + 关键字… @@ -120,6 +125,11 @@ IJK + + 预设 + OkHttp + + diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 5132ecb6fb..deb6e3462c 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -61,6 +61,9 @@ 直播 壁紙 播放器 + User Agent + Tunnel Mode + Http Source 解碼方式 渲染方式 縮放比例 @@ -70,6 +73,8 @@ 暫存 版本 權限 + + 關鍵字… @@ -120,6 +125,11 @@ IJK + + 預設 + OkHttp + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bc0e194508..a8efbafb62 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -61,6 +61,9 @@ Live Wallpaper Player + User Agent + Tunnel Mode + Http Source Decode Render Scale @@ -70,6 +73,8 @@ Cache Version Permission + OFF + ON Keywords… @@ -120,6 +125,11 @@ IJK + + Default + OkHttp + + Surface Texture diff --git a/ijkplayer/src/main/java/tv/danmaku/ijk/media/player/ui/IjkVideoView.java b/ijkplayer/src/main/java/tv/danmaku/ijk/media/player/ui/IjkVideoView.java index 773302c81b..fd98d49802 100644 --- a/ijkplayer/src/main/java/tv/danmaku/ijk/media/player/ui/IjkVideoView.java +++ b/ijkplayer/src/main/java/tv/danmaku/ijk/media/player/ui/IjkVideoView.java @@ -14,6 +14,7 @@ import androidx.annotation.NonNull; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -187,9 +188,11 @@ private void openVideo(Uri uri, Map headers) { } private void fixUserAgent(Map headers) { - if (!headers.containsKey(Utils.USER_AGENT)) headers.put(Utils.USER_AGENT, Utils.CHROME); - mPlayer.setOption(format, "user_agent", headers.get(Utils.USER_AGENT)); - headers.remove(Utils.USER_AGENT); + for (String key : Arrays.asList(Utils.USER_AGENT, Utils.USER_AGENT.toLowerCase())) { + if (!headers.containsKey(key)) continue; + mPlayer.setOption(format, "user_agent", headers.get(key)); + headers.remove(key); + } } private void bindSurfaceHolder(IMediaPlayer mp, IRenderView.ISurfaceHolder holder) { diff --git a/ijkplayer/src/main/java/tv/danmaku/ijk/media/player/ui/Utils.java b/ijkplayer/src/main/java/tv/danmaku/ijk/media/player/ui/Utils.java index 22d7a72338..4a1ad61ec2 100644 --- a/ijkplayer/src/main/java/tv/danmaku/ijk/media/player/ui/Utils.java +++ b/ijkplayer/src/main/java/tv/danmaku/ijk/media/player/ui/Utils.java @@ -1,29 +1,13 @@ package tv.danmaku.ijk.media.player.ui; import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.os.Build; import android.util.DisplayMetrics; public class Utils { public static final String USER_AGENT = "User-Agent"; - public static final String CHROME = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"; public static float dp2px(Context context, float dpValue) { return Math.round((dpValue * context.getResources().getDisplayMetrics().densityDpi) / DisplayMetrics.DENSITY_DEFAULT); } - - public static String getUserAgent(Context context) { - String versionName; - try { - String packageName = context.getPackageName(); - PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0); - versionName = info.versionName; - } catch (PackageManager.NameNotFoundException e) { - versionName = "?"; - } - return context.getPackageName() + "/" + versionName + " (Linux;Android " + Build.VERSION.RELEASE + ") " + "IjkPlayerLib/0.8.9"; - } }