diff --git a/app/build.gradle b/app/build.gradle index e49f0f8abc..0e26aa5eab 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,8 +13,8 @@ android { minSdk 21 //noinspection ExpiredTargetSdkVersion targetSdk 28 - versionCode 247 - versionName "2.4.7" + versionCode 250 + versionName "2.5.0" javaCompileOptions { annotationProcessorOptions { arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] @@ -149,7 +149,7 @@ dependencies { implementation(ext: 'aar', name: 'dlna-dmr-release', group: 'fongmi', version: 'release') leanbackImplementation 'androidx.leanback:leanback:1.2.0-alpha04' leanbackImplementation 'com.github.hedzr:android-file-chooser:v1.2.0-final' - leanbackImplementation 'me.jessyan:autosize:1.2.1' + leanbackImplementation 'com.github.JessYanCoding:AndroidAutoSize:1.2.1' mobileImplementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' mobileImplementation 'com.google.android.flexbox:flexbox:3.0.0' mobileImplementation('com.journeyapps:zxing-android-embedded:4.3.0') { transitive = false } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/CollectActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/CollectActivity.java index 3c2d735a55..f9317116e5 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/CollectActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/CollectActivity.java @@ -35,8 +35,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; public class CollectActivity extends BaseActivity { @@ -127,7 +125,7 @@ private void setSite() { private void search() { mAdapter.add(Collect.all()); mBinding.pager.getAdapter().notifyDataSetChanged(); - mExecutor = new PauseExecutor(Constant.THREAD_POOL, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); + mExecutor = new PauseExecutor(Constant.THREAD_POOL); mBinding.result.setText(getString(R.string.collect_result, getKeyword())); for (Site site : mSites) mExecutor.execute(() -> search(site)); } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/fragment/VodFragment.java b/app/src/leanback/java/com/fongmi/android/tv/ui/fragment/VodFragment.java index c9e950fbf5..2159c87e60 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/fragment/VodFragment.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/fragment/VodFragment.java @@ -281,7 +281,9 @@ public boolean goRoot() { @Override public void onItemClick(Vod item) { - if (item.isFolder()) { + if (item.isAction()) { + mViewModel.action(getKey(), item.getAction()); + } else if (item.isFolder()) { mPages.add(Page.get(item, mBinding.recycler.getSelectedPosition())); mBinding.recycler.setMoveTop(false); getVideo(item.getVodId(), "1"); diff --git a/app/src/main/java/com/fongmi/android/tv/App.java b/app/src/main/java/com/fongmi/android/tv/App.java index 51e7bdba69..951496cd04 100644 --- a/app/src/main/java/com/fongmi/android/tv/App.java +++ b/app/src/main/java/com/fongmi/android/tv/App.java @@ -41,7 +41,7 @@ public class App extends Application { public App() { instance = this; - executor = Executors.newFixedThreadPool(Constant.THREAD_POOL * 2); + executor = Executors.newFixedThreadPool(Constant.THREAD_POOL); handler = HandlerCompat.createAsync(Looper.getMainLooper()); gson = new Gson(); } diff --git a/app/src/main/java/com/fongmi/android/tv/Constant.java b/app/src/main/java/com/fongmi/android/tv/Constant.java index b080b95338..8b8981226a 100644 --- a/app/src/main/java/com/fongmi/android/tv/Constant.java +++ b/app/src/main/java/com/fongmi/android/tv/Constant.java @@ -28,5 +28,5 @@ public class Constant { //传送超時時間 public static final int TIMEOUT_TRANSMIT = 60 * 1000; //搜尋線程數量 - public static final int THREAD_POOL = 5; + public static final int THREAD_POOL = 10; } diff --git a/app/src/main/java/com/fongmi/android/tv/bean/Sub.java b/app/src/main/java/com/fongmi/android/tv/bean/Sub.java index 8a664d07f8..e8a6e0e284 100644 --- a/app/src/main/java/com/fongmi/android/tv/bean/Sub.java +++ b/app/src/main/java/com/fongmi/android/tv/bean/Sub.java @@ -31,7 +31,7 @@ public static Sub from(String path) { if (path.startsWith("http")) { return http(path); } else { - return file(Path.utf8(Path.local(path))); + return file(Path.local(path)); } } diff --git a/app/src/main/java/com/fongmi/android/tv/bean/Vod.java b/app/src/main/java/com/fongmi/android/tv/bean/Vod.java index 65b0dbfde9..efc8eccbbd 100644 --- a/app/src/main/java/com/fongmi/android/tv/bean/Vod.java +++ b/app/src/main/java/com/fongmi/android/tv/bean/Vod.java @@ -73,6 +73,9 @@ public class Vod implements Parcelable { @SerializedName("vod_tag") private String vodTag; + @SerializedName("action") + private String action; + @SerializedName("cate") private Cate cate; @@ -167,6 +170,10 @@ public String getVodTag() { return TextUtils.isEmpty(vodTag) ? "" : vodTag; } + public String getAction() { + return TextUtils.isEmpty(action) ? "" : action; + } + public Cate getCate() { return cate; } @@ -231,6 +238,10 @@ public boolean isFolder() { return "folder".equals(getVodTag()) || getCate() != null; } + public boolean isAction() { + return !getAction().isEmpty(); + } + public boolean isManga() { return "manga".equals(getVodTag()); } @@ -303,6 +314,7 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeString(this.vodPlayFrom); dest.writeString(this.vodPlayUrl); dest.writeString(this.vodTag); + dest.writeString(this.action); dest.writeInt(this.land); dest.writeInt(this.circle); dest.writeFloat(this.ratio); @@ -326,6 +338,7 @@ protected Vod(Parcel in) { this.vodPlayFrom = in.readString(); this.vodPlayUrl = in.readString(); this.vodTag = in.readString(); + this.action = in.readString(); this.land = in.readInt(); this.circle = in.readInt(); this.ratio = in.readFloat(); diff --git a/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java b/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java index 7735a981c1..56c31a6edd 100644 --- a/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java +++ b/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java @@ -47,6 +47,7 @@ public class SiteViewModel extends ViewModel { public MutableLiveData result; public MutableLiveData player; public MutableLiveData search; + public MutableLiveData action; public MutableLiveData danmaku; public MutableLiveData download; private ExecutorService executor; @@ -57,6 +58,7 @@ public SiteViewModel() { this.result = new MutableLiveData<>(); this.player = new MutableLiveData<>(); this.search = new MutableLiveData<>(); + this.action = new MutableLiveData<>(); this.download = new MutableLiveData<>(); } @@ -207,6 +209,15 @@ public void download(String key, String flag, String id) { executePlayer(download, key, flag, id); } + public void action(String key, String action) { + execute(this.action, () -> { + Site site = VodConfig.get().getSite(key); + if (site.getType() == 3) return Result.fromJson(site.recent().spider().action(action)); + if (site.getType() == 4) return Result.fromJson(OkHttp.string(action)); + return Result.empty(); + }); + } + public void searchContent(Site site, String keyword, boolean quick) throws Throwable { if (site.getType() == 3) { String searchContent = site.spider().searchContent(Trans.t2s(keyword), quick); 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 0edb9f97d8..26c151cd68 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 @@ -194,6 +194,7 @@ public Map getHeaders() { public void setSub(Sub sub) { this.sub = sub; if (isIjk()) return; + setPosition(getPosition()); setMediaSource(); } diff --git a/app/src/main/java/com/fongmi/android/tv/player/Source.java b/app/src/main/java/com/fongmi/android/tv/player/Source.java index 2cfdbec130..fe7094f38c 100644 --- a/app/src/main/java/com/fongmi/android/tv/player/Source.java +++ b/app/src/main/java/com/fongmi/android/tv/player/Source.java @@ -68,7 +68,7 @@ private void addCallable(Iterator iterator, List public void parse(List flags) throws Exception { for (Flag flag : flags) { - ExecutorService executor = Executors.newFixedThreadPool(Constant.THREAD_POOL * 2); + ExecutorService executor = Executors.newFixedThreadPool(Constant.THREAD_POOL); List>> items = new ArrayList<>(); Iterator iterator = flag.getEpisodes().iterator(); while (iterator.hasNext()) addCallable(iterator, items); diff --git a/app/src/main/java/com/fongmi/android/tv/utils/PauseExecutor.java b/app/src/main/java/com/fongmi/android/tv/utils/PauseExecutor.java index e46c8e1526..4ea7931b4a 100644 --- a/app/src/main/java/com/fongmi/android/tv/utils/PauseExecutor.java +++ b/app/src/main/java/com/fongmi/android/tv/utils/PauseExecutor.java @@ -1,6 +1,6 @@ package com.fongmi.android.tv.utils; -import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; @@ -12,12 +12,14 @@ public class PauseExecutor extends ThreadPoolExecutor { private final Condition condition; private boolean isPaused; - public PauseExecutor(int corePoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) { - super(corePoolSize, corePoolSize, keepAliveTime, unit, workQueue); + public PauseExecutor(int corePoolSize) { + super(corePoolSize, corePoolSize, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); pauseLock = new ReentrantLock(); condition = pauseLock.newCondition(); } + + @Override protected void beforeExecute(Thread t, Runnable r) { super.beforeExecute(t, r); pauseLock.lock(); diff --git a/app/src/main/java/com/fongmi/android/tv/utils/Traffic.java b/app/src/main/java/com/fongmi/android/tv/utils/Traffic.java index 0213f7cd13..a95644d6d7 100644 --- a/app/src/main/java/com/fongmi/android/tv/utils/Traffic.java +++ b/app/src/main/java/com/fongmi/android/tv/utils/Traffic.java @@ -13,8 +13,8 @@ public class Traffic { private static final DecimalFormat format = new DecimalFormat("#.0"); private static final String UNIT_KB = " KB/s"; private static final String UNIT_MB = " MB/s"; - private static long lastTotalRxBytes = 0; - private static long lastTimeStamp = 0; + private static long lastTotalRxBytes; + private static long lastTimeStamp; public static void setSpeed(TextView view) { if (unsupported()) return; @@ -27,8 +27,8 @@ private static boolean unsupported() { } private static String getSpeed() { - long nowTotalRxBytes = TrafficStats.getTotalRxBytes() / 1024; long nowTimeStamp = System.currentTimeMillis(); + long nowTotalRxBytes = TrafficStats.getTotalRxBytes() / 1024; long speed = (nowTotalRxBytes - lastTotalRxBytes) * 1000 / Math.max(nowTimeStamp - lastTimeStamp, 1); lastTimeStamp = nowTimeStamp; lastTotalRxBytes = nowTotalRxBytes; diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/CollectActivity.java b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/CollectActivity.java index c9439911f5..01d4a9edbb 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/CollectActivity.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/CollectActivity.java @@ -51,8 +51,6 @@ import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; import okhttp3.Call; import okhttp3.Response; @@ -192,7 +190,7 @@ private void search() { mBinding.view.setVisibility(View.VISIBLE); mBinding.result.setVisibility(View.VISIBLE); if (mExecutor != null) mExecutor.shutdownNow(); - mExecutor = new PauseExecutor(Constant.THREAD_POOL * 2, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); + mExecutor = new PauseExecutor(Constant.THREAD_POOL * 2); String keyword = mBinding.keyword.getText().toString().trim(); for (Site site : mSites) mExecutor.execute(() -> search(site, keyword)); App.post(() -> mRecordAdapter.add(keyword), 250); diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/TypeFragment.java b/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/TypeFragment.java index 5c94785a0a..768f41b264 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/TypeFragment.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/TypeFragment.java @@ -228,7 +228,9 @@ public void onLoadMore(String page) { @Override public void onItemClick(Vod item) { - if (item.isFolder()) { + if (item.isAction()) { + mViewModel.action(getKey(), item.getAction()); + } else if (item.isFolder()) { mPages.add(Page.get(item, findPosition())); getVideo(item.getVodId(), "1"); } else { diff --git a/catvod/src/main/java/com/github/catvod/crawler/Spider.java b/catvod/src/main/java/com/github/catvod/crawler/Spider.java index 147b03624d..a5ff9cd6dc 100644 --- a/catvod/src/main/java/com/github/catvod/crawler/Spider.java +++ b/catvod/src/main/java/com/github/catvod/crawler/Spider.java @@ -64,6 +64,10 @@ public Object[] proxyLocal(Map params) throws Exception { return null; } + public String action(String action) throws Exception { + return null; + } + public void destroy() { } diff --git a/catvod/src/main/java/com/github/catvod/utils/Path.java b/catvod/src/main/java/com/github/catvod/utils/Path.java index 7ced5cb5c7..c414ffce81 100644 --- a/catvod/src/main/java/com/github/catvod/utils/Path.java +++ b/catvod/src/main/java/com/github/catvod/utils/Path.java @@ -201,10 +201,6 @@ public static File write(File file, byte[] data) { } } - public static File utf8(File file) { - return write(cache(file.getName()), Util.utf8(readToByte(file))); - } - public static void move(File in, File out) { copy(in, out); clear(in); diff --git a/catvod/src/main/java/com/github/catvod/utils/Util.java b/catvod/src/main/java/com/github/catvod/utils/Util.java index 9d7c862542..0220732c13 100644 --- a/catvod/src/main/java/com/github/catvod/utils/Util.java +++ b/catvod/src/main/java/com/github/catvod/utils/Util.java @@ -8,8 +8,6 @@ import com.github.catvod.Init; -import org.mozilla.universalchardet.UniversalDetector; - import java.io.File; import java.io.FileInputStream; import java.math.BigInteger; @@ -17,7 +15,6 @@ import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; -import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Enumeration; @@ -68,17 +65,6 @@ public static boolean equals(String name, String md5) { return md5(Path.jar(name)).equalsIgnoreCase(md5); } - public static byte[] utf8(byte[] bytes) { - try { - UniversalDetector detector = new UniversalDetector(null); - detector.handleData(bytes, 0, bytes.length); - detector.dataEnd(); - return new String(bytes, detector.getDetectedCharset()).getBytes(StandardCharsets.UTF_8); - } catch (Exception e) { - return bytes; - } - } - public static String md5(String src) { try { if (TextUtils.isEmpty(src)) return ""; diff --git a/pyramid/src/main/java/com/undcover/freedom/pyramid/Spider.java b/pyramid/src/main/java/com/undcover/freedom/pyramid/Spider.java index fd037a30dd..6f0871042f 100644 --- a/pyramid/src/main/java/com/undcover/freedom/pyramid/Spider.java +++ b/pyramid/src/main/java/com/undcover/freedom/pyramid/Spider.java @@ -103,6 +103,11 @@ public Object[] proxyLocal(Map params) { return result; } + @Override + public String action(String action) { + return app.callAttr("action", obj, action).toString(); + } + @Override public void destroy() { app.callAttr("destroy", obj); diff --git a/pyramid/src/main/python/app.py b/pyramid/src/main/python/app.py index 499dfcd494..d09ff81455 100644 --- a/pyramid/src/main/python/app.py +++ b/pyramid/src/main/python/app.py @@ -100,6 +100,12 @@ def destroy(ru): ru.destroy() +def action(ru, action): + result = ru.action(action) + formatJo = json.dumps(result, ensure_ascii=False) + return formatJo + + def run(): pass diff --git a/pyramid/src/main/python/base/spider.py b/pyramid/src/main/python/base/spider.py index e08e06da99..cf719a9943 100644 --- a/pyramid/src/main/python/base/spider.py +++ b/pyramid/src/main/python/base/spider.py @@ -57,6 +57,9 @@ def isVideoFormat(self, url): def manualVideoCheck(self): pass + def action(self, action): + pass + def destroy(self): pass diff --git a/pyramid/src/main/python/runner.py b/pyramid/src/main/python/runner.py index 5538221686..16cd739dae 100644 --- a/pyramid/src/main/python/runner.py +++ b/pyramid/src/main/python/runner.py @@ -41,5 +41,8 @@ def isVideoFormat(self, url): def manualVideoCheck(self): return self.spider.manualVideoCheck() + def action(self, action): + return self.spider.action(action) + def destroy(self): - return self.spider.destroy() + self.spider.destroy() diff --git a/pyramid/src/main/python/trigger.py b/pyramid/src/main/python/trigger.py index 87fbf8fe3d..419bfb5cf8 100644 --- a/pyramid/src/main/python/trigger.py +++ b/pyramid/src/main/python/trigger.py @@ -39,6 +39,10 @@ def isVideoFormat(sp_obj, url): def manualVideoCheck(sp_obj): return sp_obj.manualVideoCheck() + @staticmethod + def action(sp_obj, action): + return sp_obj.action(action) + @staticmethod def destroy(sp_obj): - return sp_obj.destroy() + sp_obj.destroy() diff --git a/quickjs/src/main/java/com/fongmi/quickjs/crawler/Spider.java b/quickjs/src/main/java/com/fongmi/quickjs/crawler/Spider.java index a27840da4c..22db32db4b 100644 --- a/quickjs/src/main/java/com/fongmi/quickjs/crawler/Spider.java +++ b/quickjs/src/main/java/com/fongmi/quickjs/crawler/Spider.java @@ -124,6 +124,11 @@ public Object[] proxyLocal(Map params) throws Exception { else return submit(() -> proxy1(params)).get(); } + @Override + public String action(String action) throws Exception { + return (String) call("action", action); + } + @Override public void destroy() { try { diff --git a/quickjs/src/main/java/com/fongmi/quickjs/method/Async.java b/quickjs/src/main/java/com/fongmi/quickjs/method/Async.java index c74b2859b8..534ec4109a 100644 --- a/quickjs/src/main/java/com/fongmi/quickjs/method/Async.java +++ b/quickjs/src/main/java/com/fongmi/quickjs/method/Async.java @@ -24,6 +24,7 @@ private CompletableFuture call(JSObject object, String name, Object[] ar Object result = function.call(args); if (result instanceof JSObject) then(result); else future.complete(result); + function.release(); return future; } @@ -36,6 +37,7 @@ private void then(Object result) { JSObject promise = (JSObject) result; JSFunction then = promise.getJSFunction("then"); if (then != null) then.call(callback); + if (then != null) then.release(); } private final JSCallFunction callback = new JSCallFunction() { diff --git a/youtube/src/main/java/com/github/kiulian/downloader/model/videos/formats/Itag.java b/youtube/src/main/java/com/github/kiulian/downloader/model/videos/formats/Itag.java index 7ce0617d48..12d53bb617 100644 --- a/youtube/src/main/java/com/github/kiulian/downloader/model/videos/formats/Itag.java +++ b/youtube/src/main/java/com/github/kiulian/downloader/model/videos/formats/Itag.java @@ -103,6 +103,9 @@ public void setId(int id) { i250(AudioQuality.low), i251(AudioQuality.medium), + // audio mp4 acc + i327(AudioQuality.medium), + // Dash webm hdr video i330(VideoQuality.tiny), i331(VideoQuality.small), @@ -113,6 +116,9 @@ public void setId(int id) { i336(VideoQuality.hd1440), i337(VideoQuality.hd2160), + // audio webm opus + i338(AudioQuality.medium), + // av01 video only formats i394(VideoQuality.tiny), i395(VideoQuality.small), @@ -122,7 +128,8 @@ public void setId(int id) { i399(VideoQuality.hd1080), i400(VideoQuality.hd1440), i401(VideoQuality.hd2160), - i402(VideoQuality.hd2880p); + i402(VideoQuality.hd2880p), + i571(VideoQuality.ultrahighres); protected int id; private VideoQuality videoQuality; diff --git a/youtube/src/main/java/com/github/kiulian/downloader/model/videos/quality/VideoQuality.java b/youtube/src/main/java/com/github/kiulian/downloader/model/videos/quality/VideoQuality.java index 906a4dc8e6..2a1893aef3 100644 --- a/youtube/src/main/java/com/github/kiulian/downloader/model/videos/quality/VideoQuality.java +++ b/youtube/src/main/java/com/github/kiulian/downloader/model/videos/quality/VideoQuality.java @@ -13,7 +13,8 @@ public enum VideoQuality { hd1440(7), hd2160(8), hd2880p(9), - highres(10); // 3072p + highres(10), // 3072p + ultrahighres(11); // 4320p private final Integer order;