diff --git a/app/src/main/java/com/github/catvod/spider/TgSearch123.java b/app/src/main/java/com/github/catvod/spider/TgSearch123.java new file mode 100644 index 00000000..ab5af97f --- /dev/null +++ b/app/src/main/java/com/github/catvod/spider/TgSearch123.java @@ -0,0 +1,258 @@ +package com.github.catvod.spider; + +import android.content.Context; +import android.text.TextUtils; +import com.github.catvod.bean.Result; +import com.github.catvod.bean.Vod; +import com.github.catvod.net.OkHttp; +import com.github.catvod.net.OkResult; +import com.github.catvod.utils.Json; +import com.github.catvod.utils.Util; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import java.util.*; + +public class TgSearch123 extends Cloud { + private static final String KEY_API_URLS = "api_urls"; + private static final String KEY_DOMAIN_MAP = "siteurl"; + private static final String KEY_SOURCES = "sources"; + private static final int DEFAULT_PAGE_SIZE = 10; + + private List apiUrls = new ArrayList<>(); + private Map domainMap = new HashMap() {{ + put("alipan", "阿里"); + put("aliyundrive", "阿里"); + put("quark", "夸克"); + put("115cdn", "115"); + put("baidu.com", "百度"); + put("uc", "UC"); + put("189.cn", "天翼"); + put("139.com", "移动"); + put("123", "123盘"); + }}; + private Set sources = new HashSet<>(); + private String[] extInfos = null; + + @Override + public synchronized void init(Context context, String extend) throws Exception { + super.init(context, extend); + + this.apiUrls.clear(); + + if (!TextUtils.isEmpty(extend)) { + try { + if (extend.contains("###")) { + String[] infos = extend.split("###"); + this.extInfos = infos; + + if (infos.length > 0 && !TextUtils.isEmpty(infos[0])) { + processExtendConfig(infos[0]); + } + } else { + this.extInfos = new String[]{extend}; + processExtendConfig(extend); + } + } catch (Exception e) { + } + } + this.extInfos = null; // 重置,避免内存泄漏 + } + + private void processExtendConfig(String config) { + try { + // 检查是否为HTTP URL + if (isValidUrl(config)) { + if (!this.apiUrls.contains(config)) { + this.apiUrls.add(config); + } + return; + } + + // 尝试JSON格式解析 + JsonObject ext = Json.safeObject(config); + + // 处理API URLs配置 + processApiUrls(ext); + + // 处理域名映射配置 + processDomainMap(ext); + + // 处理来源过滤配置 + processSources(ext, true); + } catch (Exception e) { + // 可以添加日志记录 + } + } + + private void processApiUrls(JsonObject config) { + if (config.has(KEY_API_URLS) && config.get(KEY_API_URLS).isJsonArray()) { + JsonArray urlsArray = config.getAsJsonArray(KEY_API_URLS); + for (JsonElement element : urlsArray) { + if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) { + String url = element.getAsString(); + if (isValidUrl(url) && !this.apiUrls.contains(url)) { + this.apiUrls.add(url); + } + } + } + } + } + + private void processDomainMap(JsonObject config) { + if (config.has(KEY_DOMAIN_MAP) && config.get(KEY_DOMAIN_MAP).isJsonObject()) { + JsonObject customDomains = config.getAsJsonObject(KEY_DOMAIN_MAP); + for (Map.Entry entry : customDomains.entrySet()) { + if (entry == null || entry.getValue() == null) continue; + + String domain = entry.getKey(); + String sourceName = ""; + try { + sourceName = entry.getValue().getAsString(); + } catch (Exception e) { + continue; + } + + if (!TextUtils.isEmpty(domain) && !TextUtils.isEmpty(sourceName) && !domainMap.containsKey(domain)) { + domainMap.put(domain, sourceName); + } + } + } + } + + private void processSources(JsonObject config, boolean clearExisting) { + if (config.has(KEY_SOURCES) && config.get(KEY_SOURCES).isJsonArray()) { + if (clearExisting) { + this.sources.clear(); + } + + JsonArray sourcesArray = config.getAsJsonArray(KEY_SOURCES); + for (JsonElement element : sourcesArray) { + if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) { + String source = element.getAsString(); + if (!TextUtils.isEmpty(source) && !sources.contains(source)) { + sources.add(source); + } + } + } + } + } + + private boolean isValidUrl(String url) { + return !TextUtils.isEmpty(url) && (url.startsWith("http://") || url.startsWith("https://")); + } + + + private Map getHeader() { + Map header = new HashMap<>(); + header.put("User-Agent", Util.CHROME); + return header; + } + + @Override + public String searchContent(String key, boolean quick) throws Exception { + if (key == null || key.trim().isEmpty()) { + return Result.error("关键词不能为空"); + } + + return performSearch(key, 1, DEFAULT_PAGE_SIZE); + } + + private String performSearch(String key, int page, int pageSize) throws Exception { + List list = new ArrayList<>(); + int total = 0; + + Map params = new HashMap<>(); + params.put("kw", key); + params.put("page", String.valueOf(page)); + params.put("size", String.valueOf(pageSize)); + + for (String apiUrl : apiUrls) { + if (!isValidUrl(apiUrl)) continue; + + try { + OkResult result = OkHttp.get(apiUrl, params, getHeader()); + if (result.getCode() == 500 || TextUtils.isEmpty(result.getBody())) continue; + + JsonObject jsonObject = Json.safeObject(result.getBody()); + if (!jsonObject.has("code") || jsonObject.get("code").getAsInt() != 0 || !jsonObject.has("data")) + continue; + + JsonObject data = jsonObject.getAsJsonObject("data"); + + total = data.has("total") && !data.get("total").isJsonNull() ? data.get("total").getAsInt() : 0; + + // 直接检查merged_by_type字段,无需三重判断 + if (!data.has("merged_by_type") || !data.get("merged_by_type").isJsonObject()) continue; + + JsonObject mergedByType = data.getAsJsonObject("merged_by_type"); + + for (Map.Entry categoryEntry : mergedByType.entrySet()) { + if (!categoryEntry.getValue().isJsonArray()) continue; + + JsonArray items = categoryEntry.getValue().getAsJsonArray(); + + for (JsonElement item : items) { + if (!item.isJsonObject()) continue; + + JsonObject entry = item.getAsJsonObject(); + + String vodUrl = entry.has("url") && !entry.get("url").isJsonNull() ? entry.get("url").getAsString() : ""; + if (TextUtils.isEmpty(vodUrl)) continue; + + // 获取来源信息并映射 + String originalSource = entry.has("source") && !entry.get("source").isJsonNull() ? entry.get("source").getAsString() : "未知来源"; + String sourceName = mapSource(vodUrl, originalSource); + + // 获取标题 + String title = entry.has("note") && !entry.get("note").isJsonNull() ? entry.get("note").getAsString() : "未命名资源"; + + // 获取图片 + String pic = getFirstImage(entry); + + // 简化VodPlayBuilder的使用 + Vod vod = new Vod(vodUrl, title, pic, sourceName + " (" + originalSource + ")"); + // 由于只有一个播放源,直接设置播放信息 + vod.setVodPlayFrom(sourceName); + vod.setVodPlayUrl("播放源$" + vodUrl); + + // 来源过滤 + if (sources.isEmpty() || sources.contains(sourceName)) { + list.add(vod); + } + } + } + + int pageCount = total > 0 && pageSize > 0 ? (total + pageSize - 1) / pageSize : 1; + return Result.string(page, pageCount, pageSize, total, list); + } catch (Exception e) { + // 出错时继续尝试下一个API + continue; + } + } + + return Result.error("无法连接到任何搜索API"); + } + + // 提取来源映射逻辑为单独方法 + private String mapSource(String vodUrl, String originalSource) { + for (Map.Entry domainEntry : domainMap.entrySet()) { + if (vodUrl.contains(domainEntry.getKey())) { + return domainEntry.getValue(); + } + } + return originalSource; + } + + // 提取图片获取逻辑为单独方法 + private String getFirstImage(JsonObject entry) { + if (entry.has("images") && !entry.get("images").isJsonNull() && entry.get("images").isJsonArray()) { + JsonArray images = entry.getAsJsonArray("images"); + if (images.size() > 0 && !images.get(0).isJsonNull() && images.get(0).isJsonPrimitive()) { + return images.get(0).getAsString(); + } + } + return ""; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/catvod/spider/TgSearch139.java b/app/src/main/java/com/github/catvod/spider/TgSearch139.java new file mode 100644 index 00000000..135f741f --- /dev/null +++ b/app/src/main/java/com/github/catvod/spider/TgSearch139.java @@ -0,0 +1,258 @@ +package com.github.catvod.spider; + +import android.content.Context; +import android.text.TextUtils; +import com.github.catvod.bean.Result; +import com.github.catvod.bean.Vod; +import com.github.catvod.net.OkHttp; +import com.github.catvod.net.OkResult; +import com.github.catvod.utils.Json; +import com.github.catvod.utils.Util; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import java.util.*; + +public class TgSearch139 extends Cloud { + private static final String KEY_API_URLS = "api_urls"; + private static final String KEY_DOMAIN_MAP = "siteurl"; + private static final String KEY_SOURCES = "sources"; + private static final int DEFAULT_PAGE_SIZE = 10; + + private List apiUrls = new ArrayList<>(); + private Map domainMap = new HashMap() {{ + put("alipan", "阿里"); + put("aliyundrive", "阿里"); + put("quark", "夸克"); + put("115cdn", "115"); + put("baidu.com", "百度"); + put("uc", "UC"); + put("189.cn", "天翼"); + put("139.com", "移动"); + put("123", "123盘"); + }}; + private Set sources = new HashSet<>(); + private String[] extInfos = null; + + @Override + public synchronized void init(Context context, String extend) throws Exception { + super.init(context, extend); + + this.apiUrls.clear(); + + if (!TextUtils.isEmpty(extend)) { + try { + if (extend.contains("###")) { + String[] infos = extend.split("###"); + this.extInfos = infos; + + if (infos.length > 0 && !TextUtils.isEmpty(infos[0])) { + processExtendConfig(infos[0]); + } + } else { + this.extInfos = new String[]{extend}; + processExtendConfig(extend); + } + } catch (Exception e) { + } + } + this.extInfos = null; // 重置,避免内存泄漏 + } + + private void processExtendConfig(String config) { + try { + // 检查是否为HTTP URL + if (isValidUrl(config)) { + if (!this.apiUrls.contains(config)) { + this.apiUrls.add(config); + } + return; + } + + // 尝试JSON格式解析 + JsonObject ext = Json.safeObject(config); + + // 处理API URLs配置 + processApiUrls(ext); + + // 处理域名映射配置 + processDomainMap(ext); + + // 处理来源过滤配置 + processSources(ext, true); + } catch (Exception e) { + // 可以添加日志记录 + } + } + + private void processApiUrls(JsonObject config) { + if (config.has(KEY_API_URLS) && config.get(KEY_API_URLS).isJsonArray()) { + JsonArray urlsArray = config.getAsJsonArray(KEY_API_URLS); + for (JsonElement element : urlsArray) { + if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) { + String url = element.getAsString(); + if (isValidUrl(url) && !this.apiUrls.contains(url)) { + this.apiUrls.add(url); + } + } + } + } + } + + private void processDomainMap(JsonObject config) { + if (config.has(KEY_DOMAIN_MAP) && config.get(KEY_DOMAIN_MAP).isJsonObject()) { + JsonObject customDomains = config.getAsJsonObject(KEY_DOMAIN_MAP); + for (Map.Entry entry : customDomains.entrySet()) { + if (entry == null || entry.getValue() == null) continue; + + String domain = entry.getKey(); + String sourceName = ""; + try { + sourceName = entry.getValue().getAsString(); + } catch (Exception e) { + continue; + } + + if (!TextUtils.isEmpty(domain) && !TextUtils.isEmpty(sourceName) && !domainMap.containsKey(domain)) { + domainMap.put(domain, sourceName); + } + } + } + } + + private void processSources(JsonObject config, boolean clearExisting) { + if (config.has(KEY_SOURCES) && config.get(KEY_SOURCES).isJsonArray()) { + if (clearExisting) { + this.sources.clear(); + } + + JsonArray sourcesArray = config.getAsJsonArray(KEY_SOURCES); + for (JsonElement element : sourcesArray) { + if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) { + String source = element.getAsString(); + if (!TextUtils.isEmpty(source) && !sources.contains(source)) { + sources.add(source); + } + } + } + } + } + + private boolean isValidUrl(String url) { + return !TextUtils.isEmpty(url) && (url.startsWith("http://") || url.startsWith("https://")); + } + + + private Map getHeader() { + Map header = new HashMap<>(); + header.put("User-Agent", Util.CHROME); + return header; + } + + @Override + public String searchContent(String key, boolean quick) throws Exception { + if (key == null || key.trim().isEmpty()) { + return Result.error("关键词不能为空"); + } + + return performSearch(key, 1, DEFAULT_PAGE_SIZE); + } + + private String performSearch(String key, int page, int pageSize) throws Exception { + List list = new ArrayList<>(); + int total = 0; + + Map params = new HashMap<>(); + params.put("kw", key); + params.put("page", String.valueOf(page)); + params.put("size", String.valueOf(pageSize)); + + for (String apiUrl : apiUrls) { + if (!isValidUrl(apiUrl)) continue; + + try { + OkResult result = OkHttp.get(apiUrl, params, getHeader()); + if (result.getCode() == 500 || TextUtils.isEmpty(result.getBody())) continue; + + JsonObject jsonObject = Json.safeObject(result.getBody()); + if (!jsonObject.has("code") || jsonObject.get("code").getAsInt() != 0 || !jsonObject.has("data")) + continue; + + JsonObject data = jsonObject.getAsJsonObject("data"); + + total = data.has("total") && !data.get("total").isJsonNull() ? data.get("total").getAsInt() : 0; + + // 直接检查merged_by_type字段,无需三重判断 + if (!data.has("merged_by_type") || !data.get("merged_by_type").isJsonObject()) continue; + + JsonObject mergedByType = data.getAsJsonObject("merged_by_type"); + + for (Map.Entry categoryEntry : mergedByType.entrySet()) { + if (!categoryEntry.getValue().isJsonArray()) continue; + + JsonArray items = categoryEntry.getValue().getAsJsonArray(); + + for (JsonElement item : items) { + if (!item.isJsonObject()) continue; + + JsonObject entry = item.getAsJsonObject(); + + String vodUrl = entry.has("url") && !entry.get("url").isJsonNull() ? entry.get("url").getAsString() : ""; + if (TextUtils.isEmpty(vodUrl)) continue; + + // 获取来源信息并映射 + String originalSource = entry.has("source") && !entry.get("source").isJsonNull() ? entry.get("source").getAsString() : "未知来源"; + String sourceName = mapSource(vodUrl, originalSource); + + // 获取标题 + String title = entry.has("note") && !entry.get("note").isJsonNull() ? entry.get("note").getAsString() : "未命名资源"; + + // 获取图片 + String pic = getFirstImage(entry); + + // 简化VodPlayBuilder的使用 + Vod vod = new Vod(vodUrl, title, pic, sourceName + " (" + originalSource + ")"); + // 由于只有一个播放源,直接设置播放信息 + vod.setVodPlayFrom(sourceName); + vod.setVodPlayUrl("播放源$" + vodUrl); + + // 来源过滤 + if (sources.isEmpty() || sources.contains(sourceName)) { + list.add(vod); + } + } + } + + int pageCount = total > 0 && pageSize > 0 ? (total + pageSize - 1) / pageSize : 1; + return Result.string(page, pageCount, pageSize, total, list); + } catch (Exception e) { + // 出错时继续尝试下一个API + continue; + } + } + + return Result.error("无法连接到任何搜索API"); + } + + // 提取来源映射逻辑为单独方法 + private String mapSource(String vodUrl, String originalSource) { + for (Map.Entry domainEntry : domainMap.entrySet()) { + if (vodUrl.contains(domainEntry.getKey())) { + return domainEntry.getValue(); + } + } + return originalSource; + } + + // 提取图片获取逻辑为单独方法 + private String getFirstImage(JsonObject entry) { + if (entry.has("images") && !entry.get("images").isJsonNull() && entry.get("images").isJsonArray()) { + JsonArray images = entry.getAsJsonArray("images"); + if (images.size() > 0 && !images.get(0).isJsonNull() && images.get(0).isJsonPrimitive()) { + return images.get(0).getAsString(); + } + } + return ""; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/catvod/spider/TgSearch189.java b/app/src/main/java/com/github/catvod/spider/TgSearch189.java new file mode 100644 index 00000000..2d225f15 --- /dev/null +++ b/app/src/main/java/com/github/catvod/spider/TgSearch189.java @@ -0,0 +1,258 @@ +package com.github.catvod.spider; + +import android.content.Context; +import android.text.TextUtils; +import com.github.catvod.bean.Result; +import com.github.catvod.bean.Vod; +import com.github.catvod.net.OkHttp; +import com.github.catvod.net.OkResult; +import com.github.catvod.utils.Json; +import com.github.catvod.utils.Util; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import java.util.*; + +public class TgSearch189 extends Cloud { + private static final String KEY_API_URLS = "api_urls"; + private static final String KEY_DOMAIN_MAP = "siteurl"; + private static final String KEY_SOURCES = "sources"; + private static final int DEFAULT_PAGE_SIZE = 10; + + private List apiUrls = new ArrayList<>(); + private Map domainMap = new HashMap() {{ + put("alipan", "阿里"); + put("aliyundrive", "阿里"); + put("quark", "夸克"); + put("115cdn", "115"); + put("baidu.com", "百度"); + put("uc", "UC"); + put("189.cn", "天翼"); + put("139.com", "移动"); + put("123", "123盘"); + }}; + private Set sources = new HashSet<>(); + private String[] extInfos = null; + + @Override + public synchronized void init(Context context, String extend) throws Exception { + super.init(context, extend); + + this.apiUrls.clear(); + + if (!TextUtils.isEmpty(extend)) { + try { + if (extend.contains("###")) { + String[] infos = extend.split("###"); + this.extInfos = infos; + + if (infos.length > 0 && !TextUtils.isEmpty(infos[0])) { + processExtendConfig(infos[0]); + } + } else { + this.extInfos = new String[]{extend}; + processExtendConfig(extend); + } + } catch (Exception e) { + } + } + this.extInfos = null; // 重置,避免内存泄漏 + } + + private void processExtendConfig(String config) { + try { + // 检查是否为HTTP URL + if (isValidUrl(config)) { + if (!this.apiUrls.contains(config)) { + this.apiUrls.add(config); + } + return; + } + + // 尝试JSON格式解析 + JsonObject ext = Json.safeObject(config); + + // 处理API URLs配置 + processApiUrls(ext); + + // 处理域名映射配置 + processDomainMap(ext); + + // 处理来源过滤配置 + processSources(ext, true); + } catch (Exception e) { + // 可以添加日志记录 + } + } + + private void processApiUrls(JsonObject config) { + if (config.has(KEY_API_URLS) && config.get(KEY_API_URLS).isJsonArray()) { + JsonArray urlsArray = config.getAsJsonArray(KEY_API_URLS); + for (JsonElement element : urlsArray) { + if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) { + String url = element.getAsString(); + if (isValidUrl(url) && !this.apiUrls.contains(url)) { + this.apiUrls.add(url); + } + } + } + } + } + + private void processDomainMap(JsonObject config) { + if (config.has(KEY_DOMAIN_MAP) && config.get(KEY_DOMAIN_MAP).isJsonObject()) { + JsonObject customDomains = config.getAsJsonObject(KEY_DOMAIN_MAP); + for (Map.Entry entry : customDomains.entrySet()) { + if (entry == null || entry.getValue() == null) continue; + + String domain = entry.getKey(); + String sourceName = ""; + try { + sourceName = entry.getValue().getAsString(); + } catch (Exception e) { + continue; + } + + if (!TextUtils.isEmpty(domain) && !TextUtils.isEmpty(sourceName) && !domainMap.containsKey(domain)) { + domainMap.put(domain, sourceName); + } + } + } + } + + private void processSources(JsonObject config, boolean clearExisting) { + if (config.has(KEY_SOURCES) && config.get(KEY_SOURCES).isJsonArray()) { + if (clearExisting) { + this.sources.clear(); + } + + JsonArray sourcesArray = config.getAsJsonArray(KEY_SOURCES); + for (JsonElement element : sourcesArray) { + if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) { + String source = element.getAsString(); + if (!TextUtils.isEmpty(source) && !sources.contains(source)) { + sources.add(source); + } + } + } + } + } + + private boolean isValidUrl(String url) { + return !TextUtils.isEmpty(url) && (url.startsWith("http://") || url.startsWith("https://")); + } + + + private Map getHeader() { + Map header = new HashMap<>(); + header.put("User-Agent", Util.CHROME); + return header; + } + + @Override + public String searchContent(String key, boolean quick) throws Exception { + if (key == null || key.trim().isEmpty()) { + return Result.error("关键词不能为空"); + } + + return performSearch(key, 1, DEFAULT_PAGE_SIZE); + } + + private String performSearch(String key, int page, int pageSize) throws Exception { + List list = new ArrayList<>(); + int total = 0; + + Map params = new HashMap<>(); + params.put("kw", key); + params.put("page", String.valueOf(page)); + params.put("size", String.valueOf(pageSize)); + + for (String apiUrl : apiUrls) { + if (!isValidUrl(apiUrl)) continue; + + try { + OkResult result = OkHttp.get(apiUrl, params, getHeader()); + if (result.getCode() == 500 || TextUtils.isEmpty(result.getBody())) continue; + + JsonObject jsonObject = Json.safeObject(result.getBody()); + if (!jsonObject.has("code") || jsonObject.get("code").getAsInt() != 0 || !jsonObject.has("data")) + continue; + + JsonObject data = jsonObject.getAsJsonObject("data"); + + total = data.has("total") && !data.get("total").isJsonNull() ? data.get("total").getAsInt() : 0; + + // 直接检查merged_by_type字段,无需三重判断 + if (!data.has("merged_by_type") || !data.get("merged_by_type").isJsonObject()) continue; + + JsonObject mergedByType = data.getAsJsonObject("merged_by_type"); + + for (Map.Entry categoryEntry : mergedByType.entrySet()) { + if (!categoryEntry.getValue().isJsonArray()) continue; + + JsonArray items = categoryEntry.getValue().getAsJsonArray(); + + for (JsonElement item : items) { + if (!item.isJsonObject()) continue; + + JsonObject entry = item.getAsJsonObject(); + + String vodUrl = entry.has("url") && !entry.get("url").isJsonNull() ? entry.get("url").getAsString() : ""; + if (TextUtils.isEmpty(vodUrl)) continue; + + // 获取来源信息并映射 + String originalSource = entry.has("source") && !entry.get("source").isJsonNull() ? entry.get("source").getAsString() : "未知来源"; + String sourceName = mapSource(vodUrl, originalSource); + + // 获取标题 + String title = entry.has("note") && !entry.get("note").isJsonNull() ? entry.get("note").getAsString() : "未命名资源"; + + // 获取图片 + String pic = getFirstImage(entry); + + // 简化VodPlayBuilder的使用 + Vod vod = new Vod(vodUrl, title, pic, sourceName + " (" + originalSource + ")"); + // 由于只有一个播放源,直接设置播放信息 + vod.setVodPlayFrom(sourceName); + vod.setVodPlayUrl("播放源$" + vodUrl); + + // 来源过滤 + if (sources.isEmpty() || sources.contains(sourceName)) { + list.add(vod); + } + } + } + + int pageCount = total > 0 && pageSize > 0 ? (total + pageSize - 1) / pageSize : 1; + return Result.string(page, pageCount, pageSize, total, list); + } catch (Exception e) { + // 出错时继续尝试下一个API + continue; + } + } + + return Result.error("无法连接到任何搜索API"); + } + + // 提取来源映射逻辑为单独方法 + private String mapSource(String vodUrl, String originalSource) { + for (Map.Entry domainEntry : domainMap.entrySet()) { + if (vodUrl.contains(domainEntry.getKey())) { + return domainEntry.getValue(); + } + } + return originalSource; + } + + // 提取图片获取逻辑为单独方法 + private String getFirstImage(JsonObject entry) { + if (entry.has("images") && !entry.get("images").isJsonNull() && entry.get("images").isJsonArray()) { + JsonArray images = entry.getAsJsonArray("images"); + if (images.size() > 0 && !images.get(0).isJsonNull() && images.get(0).isJsonPrimitive()) { + return images.get(0).getAsString(); + } + } + return ""; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/catvod/spider/TgSearchQuark.java b/app/src/main/java/com/github/catvod/spider/TgSearchQuark.java new file mode 100644 index 00000000..f9f1494b --- /dev/null +++ b/app/src/main/java/com/github/catvod/spider/TgSearchQuark.java @@ -0,0 +1,258 @@ +package com.github.catvod.spider; + +import android.content.Context; +import android.text.TextUtils; +import com.github.catvod.bean.Result; +import com.github.catvod.bean.Vod; +import com.github.catvod.net.OkHttp; +import com.github.catvod.net.OkResult; +import com.github.catvod.utils.Json; +import com.github.catvod.utils.Util; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import java.util.*; + +public class TgSearchQuark extends Cloud { + private static final String KEY_API_URLS = "api_urls"; + private static final String KEY_DOMAIN_MAP = "siteurl"; + private static final String KEY_SOURCES = "sources"; + private static final int DEFAULT_PAGE_SIZE = 10; + + private List apiUrls = new ArrayList<>(); + private Map domainMap = new HashMap() {{ + put("alipan", "阿里"); + put("aliyundrive", "阿里"); + put("quark", "夸克"); + put("115cdn", "115"); + put("baidu.com", "百度"); + put("uc", "UC"); + put("189.cn", "天翼"); + put("139.com", "移动"); + put("123", "123盘"); + }}; + private Set sources = new HashSet<>(); + private String[] extInfos = null; + + @Override + public synchronized void init(Context context, String extend) throws Exception { + super.init(context, extend); + + this.apiUrls.clear(); + + if (!TextUtils.isEmpty(extend)) { + try { + if (extend.contains("###")) { + String[] infos = extend.split("###"); + this.extInfos = infos; + + if (infos.length > 0 && !TextUtils.isEmpty(infos[0])) { + processExtendConfig(infos[0]); + } + } else { + this.extInfos = new String[]{extend}; + processExtendConfig(extend); + } + } catch (Exception e) { + } + } + this.extInfos = null; // 重置,避免内存泄漏 + } + + private void processExtendConfig(String config) { + try { + // 检查是否为HTTP URL + if (isValidUrl(config)) { + if (!this.apiUrls.contains(config)) { + this.apiUrls.add(config); + } + return; + } + + // 尝试JSON格式解析 + JsonObject ext = Json.safeObject(config); + + // 处理API URLs配置 + processApiUrls(ext); + + // 处理域名映射配置 + processDomainMap(ext); + + // 处理来源过滤配置 + processSources(ext, true); + } catch (Exception e) { + // 可以添加日志记录 + } + } + + private void processApiUrls(JsonObject config) { + if (config.has(KEY_API_URLS) && config.get(KEY_API_URLS).isJsonArray()) { + JsonArray urlsArray = config.getAsJsonArray(KEY_API_URLS); + for (JsonElement element : urlsArray) { + if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) { + String url = element.getAsString(); + if (isValidUrl(url) && !this.apiUrls.contains(url)) { + this.apiUrls.add(url); + } + } + } + } + } + + private void processDomainMap(JsonObject config) { + if (config.has(KEY_DOMAIN_MAP) && config.get(KEY_DOMAIN_MAP).isJsonObject()) { + JsonObject customDomains = config.getAsJsonObject(KEY_DOMAIN_MAP); + for (Map.Entry entry : customDomains.entrySet()) { + if (entry == null || entry.getValue() == null) continue; + + String domain = entry.getKey(); + String sourceName = ""; + try { + sourceName = entry.getValue().getAsString(); + } catch (Exception e) { + continue; + } + + if (!TextUtils.isEmpty(domain) && !TextUtils.isEmpty(sourceName) && !domainMap.containsKey(domain)) { + domainMap.put(domain, sourceName); + } + } + } + } + + private void processSources(JsonObject config, boolean clearExisting) { + if (config.has(KEY_SOURCES) && config.get(KEY_SOURCES).isJsonArray()) { + if (clearExisting) { + this.sources.clear(); + } + + JsonArray sourcesArray = config.getAsJsonArray(KEY_SOURCES); + for (JsonElement element : sourcesArray) { + if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) { + String source = element.getAsString(); + if (!TextUtils.isEmpty(source) && !sources.contains(source)) { + sources.add(source); + } + } + } + } + } + + private boolean isValidUrl(String url) { + return !TextUtils.isEmpty(url) && (url.startsWith("http://") || url.startsWith("https://")); + } + + + private Map getHeader() { + Map header = new HashMap<>(); + header.put("User-Agent", Util.CHROME); + return header; + } + + @Override + public String searchContent(String key, boolean quick) throws Exception { + if (key == null || key.trim().isEmpty()) { + return Result.error("关键词不能为空"); + } + + return performSearch(key, 1, DEFAULT_PAGE_SIZE); + } + + private String performSearch(String key, int page, int pageSize) throws Exception { + List list = new ArrayList<>(); + int total = 0; + + Map params = new HashMap<>(); + params.put("kw", key); + params.put("page", String.valueOf(page)); + params.put("size", String.valueOf(pageSize)); + + for (String apiUrl : apiUrls) { + if (!isValidUrl(apiUrl)) continue; + + try { + OkResult result = OkHttp.get(apiUrl, params, getHeader()); + if (result.getCode() == 500 || TextUtils.isEmpty(result.getBody())) continue; + + JsonObject jsonObject = Json.safeObject(result.getBody()); + if (!jsonObject.has("code") || jsonObject.get("code").getAsInt() != 0 || !jsonObject.has("data")) + continue; + + JsonObject data = jsonObject.getAsJsonObject("data"); + + total = data.has("total") && !data.get("total").isJsonNull() ? data.get("total").getAsInt() : 0; + + // 直接检查merged_by_type字段,无需三重判断 + if (!data.has("merged_by_type") || !data.get("merged_by_type").isJsonObject()) continue; + + JsonObject mergedByType = data.getAsJsonObject("merged_by_type"); + + for (Map.Entry categoryEntry : mergedByType.entrySet()) { + if (!categoryEntry.getValue().isJsonArray()) continue; + + JsonArray items = categoryEntry.getValue().getAsJsonArray(); + + for (JsonElement item : items) { + if (!item.isJsonObject()) continue; + + JsonObject entry = item.getAsJsonObject(); + + String vodUrl = entry.has("url") && !entry.get("url").isJsonNull() ? entry.get("url").getAsString() : ""; + if (TextUtils.isEmpty(vodUrl)) continue; + + // 获取来源信息并映射 + String originalSource = entry.has("source") && !entry.get("source").isJsonNull() ? entry.get("source").getAsString() : "未知来源"; + String sourceName = mapSource(vodUrl, originalSource); + + // 获取标题 + String title = entry.has("note") && !entry.get("note").isJsonNull() ? entry.get("note").getAsString() : "未命名资源"; + + // 获取图片 + String pic = getFirstImage(entry); + + // 简化VodPlayBuilder的使用 + Vod vod = new Vod(vodUrl, title, pic, sourceName + " (" + originalSource + ")"); + // 由于只有一个播放源,直接设置播放信息 + vod.setVodPlayFrom(sourceName); + vod.setVodPlayUrl("播放源$" + vodUrl); + + // 来源过滤 + if (sources.isEmpty() || sources.contains(sourceName)) { + list.add(vod); + } + } + } + + int pageCount = total > 0 && pageSize > 0 ? (total + pageSize - 1) / pageSize : 1; + return Result.string(page, pageCount, pageSize, total, list); + } catch (Exception e) { + // 出错时继续尝试下一个API + continue; + } + } + + return Result.error("无法连接到任何搜索API"); + } + + // 提取来源映射逻辑为单独方法 + private String mapSource(String vodUrl, String originalSource) { + for (Map.Entry domainEntry : domainMap.entrySet()) { + if (vodUrl.contains(domainEntry.getKey())) { + return domainEntry.getValue(); + } + } + return originalSource; + } + + // 提取图片获取逻辑为单独方法 + private String getFirstImage(JsonObject entry) { + if (entry.has("images") && !entry.get("images").isJsonNull() && entry.get("images").isJsonArray()) { + JsonArray images = entry.getAsJsonArray("images"); + if (images.size() > 0 && !images.get(0).isJsonNull() && images.get(0).isJsonPrimitive()) { + return images.get(0).getAsString(); + } + } + return ""; + } +} \ No newline at end of file diff --git a/app/src/test/java/QuarkTest.java b/app/src/test/java/QuarkTest.java index 3e2773c5..3a4cfe0e 100644 --- a/app/src/test/java/QuarkTest.java +++ b/app/src/test/java/QuarkTest.java @@ -28,7 +28,7 @@ public class QuarkTest { Init.init(mockContext); spider = new Quark(); // spider.init(mockContext, "b-user-id=89ede34e-0efc-e1dd-c997-f16aaa792d0c; _UP_A4A_11_=wb9661c6dfb642f88f73d8e0c7edd398; b-user-id=89ede34e-0efc-e1dd-c997-f16aaa792d0c; ctoken=wla6p3EUOLyn1FSB8IKp1SEW; grey-id=5583e32b-39df-4bf0-f39f-1adf83f604a2; grey-id.sig=p8ReBIMG2BeZu1sYvsuOAZxYbx-MVrsfKEiCv87MsTM; isQuark=true; isQuark.sig=hUgqObykqFom5Y09bll94T1sS9abT1X-4Df_lzgl8nM; _UP_F7E_8D_=ZkyvVHnrBLp1A1NFJIjWi0PwKLOVbxJPcg0RzQPI6KmBtV6ZMgPh38l93pgubgHDQqhaZ2Sfc0qv%2BRantbfg1mWGAUpRMP4RqXP78Wvu%2FCfvkWWGc5NhCTV71tGOIGgDBR3%2Bu6%2Fjj44KlE5biSNDOWW7Bigcz27lvOTidzNw8s%2FWtKAIxWbnCzZn4%2FJMBUub1SIMcW89g57k4mfPmDlCgpZKzxwl6beSfdtZ4RUWXmZOn5v5NkxVKhU4wR0Pq7NklczEGdRq2nIAcu7v22Uw2o%2FxMY0xBdeC9Korm5%2FNHnxl6K%2Bd6FXSoT9a3XIMQO359auZPiZWzrNlZe%2BqnOahXcx7KAhQIRqSOapSmL4ygJor4r5isJhRuDoXy7vJAVuH%2FRDtEJJ8rZTq0BdC23Bz%2B0MrsdgbK%2BiW; _UP_D_=pc; __wpkreporterwid_=3d3f74a7-99b7-4916-3f78-911fc2eb9d87; tfstk=fIoZNxjnbhKwPOu0TWZ4LsaRqirTcudSSmNbnxD0C5VgClMm8xMyB-GsnSu4tjpOflAOmSD-9PNiGl120XrgkVNb1SrqHbJBN3tSBAEYoQOWVUUg9qZ8n1bGGkD3CqGYINKSBABhjnXgp3_Vywz6gSc0Syj3BWf0mr2DLW24eZfiiovEKWefj1q0swq3E82iNEMinMy7SLrcpA4Fh3z_ZAViCfih3PbtdW5N_DuU77AaTijmYRkL2Wq54ENoy5a7ZXxCbok33XzS7QSZgxD-oyoVsdGotql0p2dVu7umC4nLStbiLmParc4FELHrI-c0u2dPVRrs8zoZWKCnIbNZrlHfUCMUz2z8KyXVSlgSFmUojh58OzeqTzgwaGll4YCYKwctDV5coP2LL79eKHxpNTXHmre1kZU32JPWCR_AkP2LL79eLZQY-WeUNdw1.; __pus=2051c82285199d8be553be41dd5a2100AAQ+mmv35G4FDDZ5x+3Mhe2OMbNgweQ1ODbW8zDt9YuP1LQVqHUuAAz9KWLsPjpNtim0AVGHusN4MCosTmbq/khM; __kp=e6604120-6051-11ef-bfe4-c31b6cdd0766; __kps=AATcZArVgS76EPn0FMaV4HEj; __ktd=sii/iz4ePzEaoVirXul7QQ==; __uid=AATcZArVgS76EPn0FMaV4HEj; __itrace_wid=5829b95d-dac1-48d3-bfd5-f60cd9462786; __puus=7da0b96cb710fa1b376934485f977e05AATp/q8/QupT7IiBR1GWqZhxlIRT677smMvoHlLxQA0Lk6CkP0YJBOTl+p9DZgzlMz6w4hPXPgWsokukk8PW7ZfhFfPmv8tKMgLpCGLW+tk57luhNghmSdTeVPkAF59STtyCPBEtiNzNAd/zZJ6qILJDi5ywEBAAAg+gOyWHoLHNUR+QxeHRuQa8g5WWA95J8jebIlrr8rCvI1vjTbtiYktT"); - spider.init(mockContext, "_UP_A4A_11_=wb9681fbaed6454a8112f31e53b5c0be; __pus=45beefa93e8775c9211487d0c8ddd2b1AASCmV5S7LY0dfX90N3p4wU/G4f/oS0gZK6cpxZMZiDtXt9s7KiSs3tVZOXnIDel69C9KaQ61IQlnLYH2rS4NGjO; __kp=fe663a90-68d5-11ef-8b23-e77b0eaa352c; __kps=AAT32Fob+vq66znO5UHSHAPi; __ktd=39oXE+BT53YlFgUfFVq9kw==; __uid=AAT32Fob+vq66znO5UHSHAPi; xlly_s=1; b-user-id=91d551ad-db9e-f092-2b42-aa4db35b8ed0; isg=BNXVFRgkH_dXwTuJ8PizGl2W5NGP0onkjXrhLld60cybrvegHyMutYcsfLIYrqGc; tfstk=fNlSqGqmrgj57RpyCwL4hfk8bfFCODOw9waKS2CPJ7F-JWib0zWyEJ-IhDn42_P82ZEQ7caRpHf8M9aTxuFEUuzKc2nJry8uwiCY7PzLvzeLHsUUP6Ud9WQoncuOabJuT6NutWKwbCRZz4V39rUtZ-SukyUWT_U8JbtmmvxwbCR2eZFBVhkeml_RcyqYyzEdwENYSyFdv_nLD-UT7gFKvWLbHy4G2aCLJoUYJoEL9WnKkjXR5y97q4TY2O9qutVEyo1soja-eT0zc6CKGxw7XBrf96hbPqfsiZf6LlHg4RrtDI57OqUIcRkWf_iIJVDLhXsJzcnxdDUmnH6Qfv3rIj2RJT3jOuwtw-_9SVg8JDeInh1aP7kbCbMk-i3-buMTZ2764qwshR4YHw68aAuZtRhJNGq4IyibQYt1NcIzH1r_KcBClRfQll8Xl9Xh_6YQJFIaDQy8ozw2lEs-K8U0ll8Xl9X3er477ETf2vf..; __puus=514ad4334da84f912529719d557085b2AASV1aKJKLRXGjvHRfwQJ5gupjOzlxgeAImozKKYdppZduMrKS7Q5+3hUZZ0f6zk7YpAGu7p0GVPYojTpZdhvnamXzCBLryM3ULhlqkw9yR6oVeTr3b1MituYgqfeFM4jHi4ASNiLk22pCNKteAtD6aowAM0K1ZFVc7j7xlpxLEgS1CoNSttupAb56Zf+ruuTkDPsjZPiRW1S4yM/kduA247"); + spider.init(mockContext, "_UP_28A_52_=386;_UP_BT_=html5;_UP_F7E_8D_=0z44HdIBxZZTFH3p1NV%2FwWJIkAWBTYaH20RoPCksvMmyhI6XxrMIHoi8gAqVoKf%2Bfw0hw4mmmcFLHpvA%2Fhicy1HUTu2LBlCP6GF%2FnM%2Bm0IJoj1BQdak3tm1o3OeN1OV9dQAEQ0UDfWTXDik4ZZxmO5Iwvj6IsFkb5GPrrCl5M87ivs0EP%2FjAQTQimMgEdat62Byd22%2BZGM703ymU3s8N9B3XRdiyy8E7vOTidzNw8s%2FWtKAIxWbnCzZn4%2FJMBUubLuroBmVIB9UVOMEdD6uzZJXMxBnUatpyAHLu79tlMNqP8TGNMQXXgvSqK5ufzR58ZeivnehV0qE%2FWt1yDEDt%2BfWrmT4mVs6zZWXvqpzmoV3MeygIUCEakh2GAn6rsLT1b2ZsrSkQkrM6F8u7yQFbh%2F0Q7RCSfK2U6tAXQttwc%2FtDK7HYGyvolg%3D%3D;_UP_6D1_64_=069;_UP_A4A_11_=wb9cc1693e1d486b8b2ac58e4839d64e;_UP_D_=mobilectoken=4IUaeDKAfn3pV-MKaWfg_GHG;__pus=76f683009a07bdd1c1a7c04f05838d4bAASVSWCD2jiL0GI43jmIC5x50sk6Tgbh4UtXFf/vqOUyaX8Aory/bsGsGCTl68Lo7sJPpZpBJdif81oItfZizhzH;__kp=d8da7a20-7522-11f0-8e98-7daef001221f;__kps=AATcZArVgS76EPn0FMaV4HEj;__ktd=sii/iz4ePzEaoVirXul7QQ==;__uid=AATcZArVgS76EPn0FMaV4HEj;__puus=b4617d4cdadeb05679ed39be924d99d8AATp/q8/QupT7IiBR1GWqZhx6c42nqKQR/5g49EMGJ5TE742htjk9EkPPibrpvSh8/N8ybuC/Wc4BP1YbLBb5ZFEEOPrmFBTCZtKVEh5HcqkSL6T6LoyeKfvGe32k9HckqoPn9MxbAThhpRlbHg8QgH8OwxLHp0V2cAYcsGY72XN2ZPL7JzZyOAwmSsJwpX9B0+LYNvco+Ixucn5KaaCTKND"); Server.get().start(); } @@ -41,7 +41,7 @@ public class QuarkTest { @org.junit.Test public void detailContent() throws Exception { - String content = spider.detailContent(Arrays.asList("https://pan.quark.cn/s/38c5e16d71f7")); + String content = spider.detailContent(Arrays.asList("https://pan.quark.cn/s/469c2acf8640")); System.out.println("detailContent--" + content); JsonObject map = Json.safeObject(content); Gson gson = new GsonBuilder().setPrettyPrinting().create(); @@ -52,7 +52,7 @@ public class QuarkTest { @org.junit.Test public void playerContent() throws Exception { - String content = spider.playerContent("普画","41ea9a50cbdd4e50b019bcd78687ebc1++22fc6fa8350d22e0eaecc49035368e81++38c5e16d71f7++WFcYTmRhjJpKTui56aleYdzBZi9R203GERBVzYNxDxI=",new ArrayList<>()); + String content = spider.playerContent("quark原画","a04522f504a742db8ebaf69e3b7f50d6++cf35e6096b5be563ed747a4538ceab60++469c2acf8640++lbhatsGLyszqGYVHwO+DJPeyRkwbsCr7JzcoZhPVYBI=",new ArrayList<>()); System.out.println("playerContent--" + content); JsonObject map = Json.safeObject(content); Gson gson = new GsonBuilder().setPrettyPrinting().create(); diff --git a/json/index.json b/json/index.json index 96453ff1..d62f727f 100644 --- a/json/index.json +++ b/json/index.json @@ -101,32 +101,23 @@ "searchable": 1, "changeable": 1, "ext": {} - },{ - "key": "TgSearch", - "name": "TgSearch|Pan", + }, { + "key": "TgSearchQuark", + "name": "☁TgSearchQuark┃网盘", "type": 3, - "api": "csp_TgSearch", + "api": "csp_TgSearchQuark", "searchable": 1, - "changeable": 1, - "ext": {} - }, - { - "key": "TgQuarkSearch", - "name": "TgQuarkSearch|Pan", - "type": 3, - "api": "csp_TgQuarkSearch", - "searchable": 1, - "changeable": 1, - "ext": {} - }, - { - "key": "Tg189Search", - "name": "Tg189Search|Pan", - "type": 3, - "api": "csp_Tg189Search", - "searchable": 1, - "changeable": 1, - "ext": {} + "filterable": 0, + "ext": { + "api_urls": [ + "https://psweb.banye.tech:7777/api/search", + "https://so.566987.xyz/api/search", + "http://152.69.222.142:8088/api/search" + ], + "sources": [ + "夸克" + ] + } }, { "key": "TgSearchBaidu", @@ -142,7 +133,60 @@ "http://152.69.222.142:8088/api/search" ], "sources": [ - "夸克", "百度","123盘","天翼","移动" + "百度" + ] + } + }, + { + "key": "TgSearch123", + "name": "☁TgSearch123┃网盘", + "type": 3, + "api": "csp_TgSearch123", + "searchable": 1, + "filterable": 0, + "ext": { + "api_urls": [ + "https://psweb.banye.tech:7777/api/search", + "https://so.566987.xyz/api/search", + "http://152.69.222.142:8088/api/search" + ], + "sources": [ + "123盘" + ] + } + }, + { + "key": "TgSearch189", + "name": "☁TgSearch189┃网盘", + "type": 3, + "api": "csp_TgSearch189", + "searchable": 1, + "filterable": 0, + "ext": { + "api_urls": [ + "https://psweb.banye.tech:7777/api/search", + "https://so.566987.xyz/api/search", + "http://152.69.222.142:8088/api/search" + ], + "sources": [ + "天翼" + ] + } + },{ + "key": "TgSearch139", + "name": "☁TgSearch139┃网盘", + "type": 3, + "api": "csp_TgSearch139", + "searchable": 1, + "filterable": 0, + "ext": { + "api_urls": [ + "https://psweb.banye.tech:7777/api/search", + "https://so.566987.xyz/api/search", + "http://152.69.222.142:8088/api/search" + ], + "sources": [ + "移动" ] } },