diff --git a/app/src/main/java/com/github/catvod/crawler/JarLoader.java b/app/src/main/java/com/github/catvod/crawler/JarLoader.java index a57834c9..8d45365e 100644 --- a/app/src/main/java/com/github/catvod/crawler/JarLoader.java +++ b/app/src/main/java/com/github/catvod/crawler/JarLoader.java @@ -1,9 +1,6 @@ package com.github.catvod.crawler; import android.content.Context; -import android.os.Handler; -import android.os.Looper; -import android.os.NetworkOnMainThreadException; import android.util.Log; @@ -17,21 +14,11 @@ import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; import dalvik.system.DexClassLoader; import okhttp3.Response; @@ -71,177 +58,66 @@ public class JarLoader { } private boolean loadClassLoader(String jar, String key) { - final String TAG = "JarLoader"; if (classLoaders.containsKey(key)){ - Log.i(TAG, "loadClassLoader jar缓存: " + key); + Log.i("JarLoader", "echo-loadClassLoader jar缓存: " + key); return true; } - final File jarFile = new File(jar); - final AtomicBoolean success = new AtomicBoolean(false); - DexClassLoader classLoader; - // 1. 前置校验 - if (!validateJarFile(jarFile, TAG)) return false; - // 2. 准备缓存目录 - File cacheDir = prepareCacheDir(TAG); - if (cacheDir == null) return false; - classLoader = createDexClassLoader(jarFile, cacheDir, TAG); - if (classLoader == null) return false; - int retryCount = 0; - final int maxRetries = 2; // 减少重试次数,增加超时检测 - final long retryInterval = 200; // 增加重试间隔 - while (retryCount < maxRetries && !success.get()) { - try { - Class initClass = classLoader.loadClass("com.github.catvod.spider.Init"); - Method initMethod = initClass.getMethod("init", Context.class); - // 4.2 异步执行初始化(解决主线程网络问题) - executeInitInBackground(initMethod, success, TAG); - // 4.3 处理初始化结果 - if (success.get()) { - handlePostInit(classLoader, key, TAG); - classLoaders.put(key, classLoader); - Log.i(TAG, "JAR加载成功: " + jar); - return true; - } - } catch (ClassNotFoundException e) { - Log.w(TAG, "Init类未找到,重试: " + (++retryCount) + "/" + maxRetries); - sleep(retryInterval); - } catch (Exception e) { - Log.w(TAG, "Init类 加载失败"); - break; - } - } - - // 5. 清理资源 - cleanupResources(classLoader, TAG); - return false; - } - - - // ------------------- 辅助方法 ------------------- - private boolean validateJarFile(File jarFile, String tag) { - if (!jarFile.exists() || !jarFile.isFile() || jarFile.length() == 0) { - Log.e(tag, "JAR文件无效: " + jarFile); - return false; - } - return true; - } - - private File prepareCacheDir(String tag) { - File cacheDir = new File(App.getInstance().getCacheDir(), "catvod_csp"); - try { - if (!cacheDir.exists() && !cacheDir.mkdirs()) { - Log.e(tag, "目录创建失败: " + cacheDir); - return null; - } - return cacheDir; - } catch (SecurityException e) { - Log.e(tag, "目录访问拒绝: " + e.getMessage()); - return null; - } - } - - private DexClassLoader createDexClassLoader(File jarFile, File cacheDir, String tag) { - try { - return new DexClassLoader( - jarFile.getAbsolutePath(), - cacheDir.getAbsolutePath(), - null, - App.getInstance().getClassLoader() - ); - } catch (Exception e) { - Log.e(tag, "类加载器创建失败", e); - return null; - } - } - - private void executeInitInBackground(Method initMethod, AtomicBoolean successFlag, String tag) { - final CountDownLatch latch = new CountDownLatch(1); - final Throwable[] exceptionHolder = {null}; - - Executors.newSingleThreadExecutor().execute(() -> { - try { - initMethod.invoke(null, App.getInstance()); - successFlag.set(true); - } catch (InvocationTargetException e) { - exceptionHolder[0] = e.getTargetException(); - } catch (Exception e) { - exceptionHolder[0] = e; - } finally { - latch.countDown(); - } - }); - + boolean success = false; try { - if (!latch.await(6, TimeUnit.SECONDS)) { - Log.e(tag, "初始化超时"); - throw new TimeoutException("初始化未在6秒内完成"); - } - } catch (InterruptedException e) { - Log.e(tag, "线程中断", e); - Thread.currentThread().interrupt(); - } catch (TimeoutException e) { - throw new RuntimeException(e); - } - - if (exceptionHolder[0] != null) { - handleInitException(exceptionHolder[0], tag); - } - } - - private void handlePostInit(ClassLoader loader, String key, String tag) { - // 主线程处理后续操作 - new Handler(Looper.getMainLooper()).post(() -> { - try { - Class proxyClass = loader.loadClass("com.github.catvod.spider.Proxy"); - Method method = proxyClass.getMethod("proxy", Map.class); - proxyMethods.put(key, method); - Log.d(tag, "代理方法加载成功"); - } catch (Exception e) { - Log.w(tag, "代理功能未启用: " + e.getMessage()); - } - }); - } - - private void handleInitException(Throwable t, String tag) { - StringWriter sw = new StringWriter(); - t.printStackTrace(new PrintWriter(sw)); - - Log.e(tag, "初始化失败: \n" + - "类型: " + t.getClass().getName() + "\n" + - "信息: " + (t.getMessage() != null ? t.getMessage() : "无详细消息") + "\n" + - "堆栈: \n" + sw.toString()); - - if (t instanceof NetworkOnMainThreadException) { - Log.w(tag, "建议: 第三方JAR包含主线程网络操作,请更新实现或联系开发者"); - } - } + File cacheDir = new File(App.getInstance().getCacheDir().getAbsolutePath() + "/catvod_csp"); + if (!cacheDir.exists()) + cacheDir.mkdirs(); + final DexClassLoader classLoader = new DexClassLoader(jar, cacheDir.getAbsolutePath(), null, App.getInstance().getClassLoader()); + int count = 0; + do { + try { + final Class classInit = classLoader.loadClass("com.github.catvod.spider.Init"); + if (classInit != null) { + final Method initMethod = classInit.getMethod("init", Context.class); + // 在子线程中调用 init 方法,避免网络请求在主线程中执行 + Thread initThread = new Thread(new Runnable() { + @Override + public void run() { + try { + initMethod.invoke(null, App.getInstance()); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + initThread.start(); + initThread.join(); + Log.i("JarLoader", "echo-自定义爬虫代码加载成功!"); + success = true; + try { + Class proxy = classLoader.loadClass("com.github.catvod.spider.Proxy"); + Method proxyMethod = proxy.getMethod("proxy", Map.class); + proxyMethods.put(key, proxyMethod); + } catch (Throwable th) { + // 可以记录错误日志 + th.printStackTrace(); + } + break; + } + Thread.sleep(200); + } catch (Throwable th) { + th.printStackTrace(); + } + count++; + } while (count < 2); - private void cleanupResources(DexClassLoader loader, String tag) { - if (loader != null) { - try { - Field pathList = Objects.requireNonNull(loader.getClass().getSuperclass()).getDeclaredField("pathList"); - pathList.setAccessible(true); - Object dexPathList = pathList.get(loader); - assert dexPathList != null; - Field dexElements = dexPathList.getClass().getDeclaredField("dexElements"); - dexElements.setAccessible(true); - dexElements.set(dexPathList, new Object[0]); - } catch (Exception e) { - Log.w(tag, "资源清理失败", e); + if (success) { + classLoaders.put(key, classLoader); } + } catch (Throwable th) { + th.printStackTrace(); } - } - - private void sleep(long millis) { - try { - Thread.sleep(millis); - } catch (InterruptedException ignored) { - } + return success; } private DexClassLoader loadJarInternal(String jar, String md5, String key) { if (classLoaders.containsKey(key)){ - Log.i("JarLoader", "loadJarInternal jar缓存: " + key); + Log.i("JarLoader", "echo-loadJarInternal jar缓存: " + key); return classLoaders.get(key); } File cache = new File(App.getInstance().getFilesDir().getAbsolutePath() + "/" + key + ".jar"); @@ -280,7 +156,7 @@ public class JarLoader { public Spider getSpider(String key, String cls, String ext, String jar) { if (spiders.containsKey(key)) { - Log.i("JarLoader", "getSpider spider缓存: " + key); + Log.i("JarLoader", "echo-getSpider spider缓存: " + key); return spiders.get(key); } String clsKey = cls.replace("csp_", ""); 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 1e426507..5e4cecda 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 @@ -262,6 +262,7 @@ public class ApiConfig { public void onSuccess(Response response) { try { String json = response.body(); + LOG.i("echo-ConfigJson"+json); parseJson(apiUrl, json); FileUtils.saveCache(cache,json); callback.success(); @@ -406,8 +407,6 @@ public class ApiConfig { } private void parseJson(String apiUrl, String jsonStr) { - LOG.i("echo-parseJson"+jsonStr); - JsonObject infoJson = gson.fromJson(jsonStr, JsonObject.class); // spider spider = DefaultConfig.safeJsonString(infoJson, "spider", ""); diff --git a/app/src/main/java/com/github/tvbox/osc/ui/activity/SearchActivity.java b/app/src/main/java/com/github/tvbox/osc/ui/activity/SearchActivity.java index 45fdaa6f..704f8541 100644 --- a/app/src/main/java/com/github/tvbox/osc/ui/activity/SearchActivity.java +++ b/app/src/main/java/com/github/tvbox/osc/ui/activity/SearchActivity.java @@ -103,24 +103,6 @@ public class SearchActivity extends BaseActivity { isSearchBack = false; } - /* - * 禁止软键盘 - * @param activity Activity - */ - public static void disableKeyboard(Activity activity) { - hasKeyBoard = false; - activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - } - - /* - * 启用软键盘 - * @param activity Activity - */ - public static void enableKeyboard(Activity activity) { - hasKeyBoard = true; - activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - } - public void openSystemKeyBoard() { InputMethodManager imm = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(this.getCurrentFocus(), InputMethodManager.SHOW_FORCED); @@ -256,8 +238,8 @@ public class SearchActivity extends BaseActivity { @Override public void onClick(View v) { FastClickCheckUtil.check(v); - etSearch.setText(""); initData(); + etSearch.setText(""); } }); @@ -273,6 +255,10 @@ public class SearchActivity extends BaseActivity { bundle.putString("title", wd); jumpActivity(FastSearchActivity.class, bundle); } else { + InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + imm.hideSoftInputFromWindow(etSearch.getWindowToken(), 0); + } search(wd); } } else { diff --git a/app/src/main/java/com/github/tvbox/osc/viewmodel/SourceViewModel.java b/app/src/main/java/com/github/tvbox/osc/viewmodel/SourceViewModel.java index 3c7c9448..7f851bab 100644 --- a/app/src/main/java/com/github/tvbox/osc/viewmodel/SourceViewModel.java +++ b/app/src/main/java/com/github/tvbox/osc/viewmodel/SourceViewModel.java @@ -318,7 +318,7 @@ public class SourceViewModel extends ViewModel { } // categoryContent public void getList(MovieSort.SortData sortData, int page) { - LOG.i("getList:"); + LOG.i("echo-getList:"); SourceBean homeSourceBean = ApiConfig.get().getHomeSourceBean(); int type = homeSourceBean.getType(); if (type == 3) { @@ -373,11 +373,13 @@ public class SourceViewModel extends ViewModel { }); }else if (type == 4) { String ext= ""; + String extend=homeSourceBean.getExt(); + extend=getFixUrl(extend); + if(URLEncoder.encode(extend).length()>1000)extend=""; if (sortData.filterSelect != null && sortData.filterSelect.size() > 0) { try { String selectExt = new JSONObject(sortData.filterSelect).toString(); ext = Base64.encodeToString(selectExt.getBytes("UTF-8"), Base64.DEFAULT | Base64.NO_WRAP); - LOG.i(ext); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } @@ -391,6 +393,7 @@ public class SourceViewModel extends ViewModel { .params("t", sortData.id) .params("pg", page) .params("ext", ext) + .params("extend", extend) .execute(new AbsCallback() { @Override public String convertResponse(okhttp3.Response response) throws Throwable { @@ -404,7 +407,7 @@ public class SourceViewModel extends ViewModel { @Override public void onSuccess(Response response) { String json = response.body(); - LOG.i(json); + LOG.i("echo-list:"+json); json(listResult, json, homeSourceBean.getKey()); } @@ -564,10 +567,14 @@ public class SourceViewModel extends ViewModel { } }); } else if (type == 0 || type == 1|| type == 4) { + String extend=sourceBean.getExt(); + extend=getFixUrl(extend); + if(URLEncoder.encode(extend).length()>1000)extend=""; OkGo.get(sourceBean.getApi()) .tag("detail") .params("ac", type == 0 ? "videolist" : "detail") .params("ids", id) + .params("extend", extend) .execute(new AbsCallback() { @Override @@ -652,10 +659,14 @@ public class SourceViewModel extends ViewModel { } }); }else if (type == 4) { + String extend=sourceBean.getExt(); + extend=getFixUrl(extend); + if(URLEncoder.encode(extend).length()>1000)extend=""; OkGo.get(sourceBean.getApi()) .params("wd", wd) .params("ac" ,"detail") .params("quick" ,"false") + .params("extend" ,extend) .tag("search") .execute(new AbsCallback() { @Override @@ -730,10 +741,14 @@ public class SourceViewModel extends ViewModel { } }); }else if (type == 4) { + String extend=sourceBean.getExt(); + extend=getFixUrl(extend); + if(URLEncoder.encode(extend).length()>1000)extend=""; OkGo.get(sourceBean.getApi()) .params("wd", wd) .params("ac" ,"detail") .params("quick" ,"true") + .params("extend" ,extend) .tag("search") .execute(new AbsCallback() { @Override