diff --git a/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java b/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java index 2982f0e1..a59b0a0b 100644 --- a/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java +++ b/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java @@ -19,6 +19,7 @@ import com.github.tvbox.osc.util.AES; import com.github.tvbox.osc.util.AdBlocker; import com.github.tvbox.osc.util.DefaultConfig; import com.github.tvbox.osc.util.HawkConfig; +import com.github.tvbox.osc.util.LOG; import com.github.tvbox.osc.util.MD5; import com.github.tvbox.osc.util.VideoParseRuler; import com.google.gson.Gson; @@ -58,6 +59,7 @@ public class ApiConfig { private List liveChannelGroupList; private List parseBeanList; private List vipParseFlags; + private Map myHosts; private List ijkCodes; private String spider = null; public String wallpaper = ""; @@ -491,6 +493,17 @@ public class ApiConfig { } } } + myHosts = new HashMap<>(); + if (infoJson.has("hosts")) { + JsonArray hostsArray = infoJson.getAsJsonArray("hosts"); + for (int i = 0; i < hostsArray.size(); i++) { + String entry = hostsArray.get(i).getAsString(); + String[] parts = entry.split("=", 2); // 只分割一次,防止 value 里有 = + if (parts.length == 2) { + myHosts.put(parts[0], parts[1]); + } + } + } String defaultIJKADS="{\"ijk\":[{\"options\":[{\"name\":\"opensles\",\"category\":4,\"value\":\"0\"},{\"name\":\"framedrop\",\"category\":4,\"value\":\"1\"},{\"name\":\"soundtouch\",\"category\":4,\"value\":\"1\"},{\"name\":\"start-on-prepared\",\"category\":4,\"value\":\"1\"},{\"name\":\"http-detect-rangeupport\",\"category\":1,\"value\":\"0\"},{\"name\":\"fflags\",\"category\":1,\"value\":\"fastseek\"},{\"name\":\"skip_loop_filter\",\"category\":2,\"value\":\"48\"},{\"name\":\"reconnect\",\"category\":4,\"value\":\"1\"},{\"name\":\"enable-accurate-seek\",\"category\":4,\"value\":\"0\"},{\"name\":\"mediacodec\",\"category\":4,\"value\":\"0\"},{\"name\":\"mediacodec-all-videos\",\"category\":4,\"value\":\"0\"},{\"name\":\"mediacodec-auto-rotate\",\"category\":4,\"value\":\"0\"},{\"name\":\"mediacodec-handle-resolution-change\",\"category\":4,\"value\":\"0\"},{\"name\":\"mediacodec-hevc\",\"category\":4,\"value\":\"0\"},{\"name\":\"max-buffer-size\",\"category\":4,\"value\":\"15728640\"}],\"group\":\"软解码\"},{\"options\":[{\"name\":\"opensles\",\"category\":4,\"value\":\"0\"},{\"name\":\"framedrop\",\"category\":4,\"value\":\"1\"},{\"name\":\"soundtouch\",\"category\":4,\"value\":\"1\"},{\"name\":\"start-on-prepared\",\"category\":4,\"value\":\"1\"},{\"name\":\"http-detect-rangeupport\",\"category\":1,\"value\":\"0\"},{\"name\":\"fflags\",\"category\":1,\"value\":\"fastseek\"},{\"name\":\"skip_loop_filter\",\"category\":2,\"value\":\"48\"},{\"name\":\"reconnect\",\"category\":4,\"value\":\"1\"},{\"name\":\"enable-accurate-seek\",\"category\":4,\"value\":\"0\"},{\"name\":\"mediacodec\",\"category\":4,\"value\":\"1\"},{\"name\":\"mediacodec-all-videos\",\"category\":4,\"value\":\"1\"},{\"name\":\"mediacodec-auto-rotate\",\"category\":4,\"value\":\"1\"},{\"name\":\"mediacodec-handle-resolution-change\",\"category\":4,\"value\":\"1\"},{\"name\":\"mediacodec-hevc\",\"category\":4,\"value\":\"1\"},{\"name\":\"max-buffer-size\",\"category\":4,\"value\":\"15728640\"}],\"group\":\"硬解码\"}],\"ads\":[\"mimg.0c1q0l.cn\",\"www.googletagmanager.com\",\"www.google-analytics.com\",\"mc.usihnbcq.cn\",\"mg.g1mm3d.cn\",\"mscs.svaeuzh.cn\",\"cnzz.hhttm.top\",\"tp.vinuxhome.com\",\"cnzz.mmstat.com\",\"www.baihuillq.com\",\"s23.cnzz.com\",\"z3.cnzz.com\",\"c.cnzz.com\",\"stj.v1vo.top\",\"z12.cnzz.com\",\"img.mosflower.cn\",\"tips.gamevvip.com\",\"ehwe.yhdtns.com\",\"xdn.cqqc3.com\",\"www.jixunkyy.cn\",\"sp.chemacid.cn\",\"hm.baidu.com\",\"s9.cnzz.com\",\"z6.cnzz.com\",\"um.cavuc.com\",\"mav.mavuz.com\",\"wofwk.aoidf3.com\",\"z5.cnzz.com\",\"xc.hubeijieshikj.cn\",\"tj.tianwenhu.com\",\"xg.gars57.cn\",\"k.jinxiuzhilv.com\",\"cdn.bootcss.com\",\"ppl.xunzhuo123.com\",\"xomk.jiangjunmh.top\",\"img.xunzhuo123.com\",\"z1.cnzz.com\",\"s13.cnzz.com\",\"xg.huataisangao.cn\",\"z7.cnzz.com\",\"xg.huataisangao.cn\",\"z2.cnzz.com\",\"s96.cnzz.com\",\"q11.cnzz.com\",\"thy.dacedsfa.cn\",\"xg.whsbpw.cn\",\"s19.cnzz.com\",\"z8.cnzz.com\",\"s4.cnzz.com\",\"f5w.as12df.top\",\"ae01.alicdn.com\",\"www.92424.cn\",\"k.wudejia.com\",\"vivovip.mmszxc.top\",\"qiu.xixiqiu.com\",\"cdnjs.hnfenxun.com\",\"cms.qdwght.com\"]}"; JsonObject defaultJson=new Gson().fromJson(defaultIJKADS, JsonObject.class); @@ -708,4 +721,8 @@ public class ApiConfig { } return content; } + + public Map getMyHost() { + return myHosts; + } } diff --git a/app/src/main/java/com/github/tvbox/osc/player/IjkMediaPlayer.java b/app/src/main/java/com/github/tvbox/osc/player/IjkMediaPlayer.java index fa0f8e5b..5b44b9d5 100644 --- a/app/src/main/java/com/github/tvbox/osc/player/IjkMediaPlayer.java +++ b/app/src/main/java/com/github/tvbox/osc/player/IjkMediaPlayer.java @@ -7,6 +7,7 @@ import com.github.tvbox.osc.api.ApiConfig; import com.github.tvbox.osc.bean.IJKCode; import com.github.tvbox.osc.util.FileUtils; import com.github.tvbox.osc.util.HawkConfig; +import com.github.tvbox.osc.util.LOG; import com.github.tvbox.osc.util.MD5; import com.orhanobut.hawk.Hawk; @@ -48,9 +49,8 @@ public class IjkMediaPlayer extends IjkPlayer { } } } + mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-fps", 60); - // 在每个数据包之后启用 I/O 上下文的刷新 -// mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_FORMAT, "flush_packets", 1); // 设置视频流格式 mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", tv.danmaku.ijk.media.player.IjkMediaPlayer.SDL_FCC_RV32); @@ -59,6 +59,19 @@ public class IjkMediaPlayer extends IjkPlayer { mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_clear", 1); mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_timeout", -1); + + mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_FORMAT,"safe",0); + + if(Hawk.get(HawkConfig.PLAYER_IS_LIVE)){ + LOG.i("type-直播"); + mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", 0); +// mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_FORMAT, "fflags", "nobuffer"); // 减少协议层缓冲 + }else{ + LOG.i("type-点播"); + mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max_cached_duration", 100); + mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_FORMAT, "infbuf", 0); + mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_PLAYER, "min-frames", 5); + } } @Override @@ -159,4 +172,4 @@ public class IjkMediaPlayer extends IjkPlayer { mMediaPlayer.setOnTimedTextListener(listener); } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/github/tvbox/osc/ui/activity/LivePlayActivity.java b/app/src/main/java/com/github/tvbox/osc/ui/activity/LivePlayActivity.java index fa32e556..bfcb931b 100644 --- a/app/src/main/java/com/github/tvbox/osc/ui/activity/LivePlayActivity.java +++ b/app/src/main/java/com/github/tvbox/osc/ui/activity/LivePlayActivity.java @@ -371,6 +371,7 @@ public class LivePlayActivity extends BaseActivity { initSettingItemView(); initLiveChannelList(); initLiveSettingGroupList(); + Hawk.put(HawkConfig.PLAYER_IS_LIVE,true); } //获取EPG并存储 // 百川epg DIYP epg 51zmt epg ------- 自建EPG格式输出格式请参考 51zmt private List epgdata = new ArrayList<>(); diff --git a/app/src/main/java/com/github/tvbox/osc/ui/activity/PlayActivity.java b/app/src/main/java/com/github/tvbox/osc/ui/activity/PlayActivity.java index 83b4f5bd..a06a42c3 100644 --- a/app/src/main/java/com/github/tvbox/osc/ui/activity/PlayActivity.java +++ b/app/src/main/java/com/github/tvbox/osc/ui/activity/PlayActivity.java @@ -131,6 +131,7 @@ public class PlayActivity extends BaseActivity { initView(); initViewModel(); initData(); + Hawk.put(HawkConfig.PLAYER_IS_LIVE,false); } public long getSavedProgress(String url) { diff --git a/app/src/main/java/com/github/tvbox/osc/ui/fragment/PlayFragment.java b/app/src/main/java/com/github/tvbox/osc/ui/fragment/PlayFragment.java index 49354a30..b3bf33f0 100644 --- a/app/src/main/java/com/github/tvbox/osc/ui/fragment/PlayFragment.java +++ b/app/src/main/java/com/github/tvbox/osc/ui/fragment/PlayFragment.java @@ -140,6 +140,7 @@ public class PlayFragment extends BaseLazyFragment { initView(); initViewModel(); initData(); + Hawk.put(HawkConfig.PLAYER_IS_LIVE,false); } public long getSavedProgress(String url) { diff --git a/app/src/main/java/com/github/tvbox/osc/util/HawkConfig.java b/app/src/main/java/com/github/tvbox/osc/util/HawkConfig.java index 3cc484da..b4d8308c 100644 --- a/app/src/main/java/com/github/tvbox/osc/util/HawkConfig.java +++ b/app/src/main/java/com/github/tvbox/osc/util/HawkConfig.java @@ -39,5 +39,6 @@ public class HawkConfig { public static final String NOW_DATE = "now_date"; //当前日期 public static final String REMOTE_TVBOX = "remote_tvbox_host"; public static final String IJK_CACHE_PLAY = "ijk_cache_play"; + public static final String PLAYER_IS_LIVE = "player_is_live"; public static boolean hotVodDelete; } diff --git a/app/src/main/java/com/github/tvbox/osc/util/OkGoHelper.java b/app/src/main/java/com/github/tvbox/osc/util/OkGoHelper.java index 307b9a52..513ccce6 100644 --- a/app/src/main/java/com/github/tvbox/osc/util/OkGoHelper.java +++ b/app/src/main/java/com/github/tvbox/osc/util/OkGoHelper.java @@ -2,6 +2,9 @@ package com.github.tvbox.osc.util; import android.graphics.Bitmap; +import androidx.annotation.NonNull; + +import com.github.tvbox.osc.api.ApiConfig; import com.github.tvbox.osc.base.App; import com.github.tvbox.osc.picasso.MyOkhttpDownLoader; import com.github.tvbox.osc.util.SSL.SSLSocketFactoryCompat; @@ -13,8 +16,13 @@ import com.orhanobut.hawk.Hawk; import com.squareup.picasso.Picasso; import java.io.File; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.security.cert.CertificateException; import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -24,6 +32,7 @@ import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.X509TrustManager; import okhttp3.Cache; +import okhttp3.Dns; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.dnsoverhttps.DnsOverHttps; @@ -56,7 +65,8 @@ public class OkGoHelper { } catch (Throwable th) { th.printStackTrace(); } - builder.dns(dnsOverHttps); + + builder.dns(new CustomDns()); ExoMediaSourceHelper.getInstance(App.getInstance()).setOkClient(builder.build()); } @@ -65,6 +75,9 @@ public class OkGoHelper { public static ArrayList dnsHttpsList = new ArrayList<>(); + public static boolean is_doh = false; + public static Map myHosts = null; + public static String getDohUrl(int type) { switch (type) { @@ -112,9 +125,37 @@ public class OkGoHelper { builder.cache(new Cache(new File(App.getInstance().getCacheDir().getAbsolutePath(), "dohcache"), 100 * 1024 * 1024)); OkHttpClient dohClient = builder.build(); String dohUrl = getDohUrl(Hawk.get(HawkConfig.DOH_URL, 0)); - dnsOverHttps = new DnsOverHttps.Builder().client(dohClient).url(dohUrl.isEmpty() ? null : HttpUrl.get(dohUrl)).build(); + if(!dohUrl.isEmpty())is_doh=true; + dnsOverHttps = new DnsOverHttps.Builder() + .client(dohClient) + .url(dohUrl.isEmpty()?null:HttpUrl.get(dohUrl)) + .build(); } + // 自定义 DNS 解析器,优先使用 DoH,失败时降级到系统 DNS + static class CustomDns implements Dns { + @NonNull + @Override + public List lookup(@NonNull String hostname) throws UnknownHostException { + if(myHosts==null){ + LOG.i("echo-exo-setHOSTS"); + myHosts= ApiConfig.get().getMyHost(); + } + if (is_doh && !hostname.equals("127.0.0.1")) { + if (!myHosts.isEmpty() && myHosts.containsKey(hostname)) { + return dnsOverHttps.lookup(Objects.requireNonNull(myHosts.get(hostname))); + }else { + return dnsOverHttps.lookup(hostname); + } + }else { + if (!myHosts.isEmpty() && myHosts.containsKey(hostname)) { + return Dns.SYSTEM.lookup(Objects.requireNonNull(myHosts.get(hostname))); + }else { + return Dns.SYSTEM.lookup(hostname); + } + } + } + } static OkHttpClient defaultClient = null; static OkHttpClient noRedirectClient = null; @@ -149,7 +190,7 @@ public class OkGoHelper { builder.writeTimeout(DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS); builder.connectTimeout(DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS); - builder.dns(dnsOverHttps); + if(dnsOverHttps!=null)builder.dns(dnsOverHttps); try { setOkHttpSsl(builder); } catch (Throwable th) { diff --git a/player/src/main/java/xyz/doikki/videoplayer/exo/ExoMediaPlayer.java b/player/src/main/java/xyz/doikki/videoplayer/exo/ExoMediaPlayer.java index 8fbba0b2..a5bc6538 100644 --- a/player/src/main/java/xyz/doikki/videoplayer/exo/ExoMediaPlayer.java +++ b/player/src/main/java/xyz/doikki/videoplayer/exo/ExoMediaPlayer.java @@ -54,24 +54,7 @@ public class ExoMediaPlayer extends AbstractPlayer implements Player.Listener { public ExoMediaPlayer(Context context) { mAppContext = context.getApplicationContext(); - // 初始化 ExoMediaSourceHelper 实例 mMediaSourceHelper = ExoMediaSourceHelper.getInstance(context); - // 构造自定义的 OkHttpClient,加入自定义 DNS 逻辑: - // 当请求的域名以 "cache.ott" 开头时,使用 "base-v4-free-mghy.e.cdn.chinamobile.com" 解析 - OkHttpClient customOkHttpClient = new OkHttpClient.Builder() - .dns(new Dns() { - @Override - public List lookup(@NonNull String hostname) throws UnknownHostException { - if (hostname.matches("^cache\\.ott\\..*\\.cmvideo\\.cn$")) { - // 这里将 hostname 强制解析为目标域名 - return Dns.SYSTEM.lookup("base-v4-free-mghy.e.cdn.chinamobile.com"); - } - return Dns.SYSTEM.lookup(hostname); - } - }) - .build(); - // 注入自定义 OkHttpClient 到 ExoMediaSourceHelper 中 - mMediaSourceHelper.setOkClient(customOkHttpClient); } @Override