From f9e9b80ba221fa6ff31527d0b5eccae0c8173954 Mon Sep 17 00:00:00 2001
From: FongMi
Date: Fri, 28 Mar 2025 15:46:52 +0800
Subject: [PATCH] Clean code
---
app/build.gradle | 2 +-
.../com/github/catvod/bean/uvod/Data.java | 168 ------------
.../com/github/catvod/debug/MainActivity.java | 4 +-
.../java/com/github/catvod/spider/AList.java | 3 +-
.../java/com/github/catvod/spider/AppXY.java | 112 --------
.../java/com/github/catvod/spider/Dm84.java | 179 ------------
.../java/com/github/catvod/spider/Doll.java | 108 --------
.../java/com/github/catvod/spider/JSDemo.java | 54 ----
.../java/com/github/catvod/spider/Kugou.java | 97 -------
.../java/com/github/catvod/spider/Living.java | 256 ------------------
.../java/com/github/catvod/spider/PTT.java | 2 +-
.../java/com/github/catvod/spider/Uvod.java | 189 -------------
.../java/com/github/catvod/spider/XPath.java | 10 +-
.../com/github/catvod/spider/XPathFilter.java | 6 +-
.../com/github/catvod/spider/XPathMac.java | 8 +-
.../github/catvod/spider/XPathMacFilter.java | 6 +-
.../java/com/github/catvod/spider/Xb6v.java | 244 -----------------
.../java/com/github/catvod/spider/YHDM.java | 3 -
.../java/com/github/catvod/spider/Ysj.java | 166 ------------
.../com/github/catvod/utils/LZString.java | 220 ---------------
.../java/com/github/catvod/utils/Util.java | 4 -
jar/custom_spider.jar | Bin 328430 -> 311056 bytes
jar/custom_spider.jar.md5 | 2 +-
23 files changed, 23 insertions(+), 1820 deletions(-)
delete mode 100644 app/src/main/java/com/github/catvod/bean/uvod/Data.java
delete mode 100644 app/src/main/java/com/github/catvod/spider/AppXY.java
delete mode 100644 app/src/main/java/com/github/catvod/spider/Dm84.java
delete mode 100644 app/src/main/java/com/github/catvod/spider/Doll.java
delete mode 100644 app/src/main/java/com/github/catvod/spider/JSDemo.java
delete mode 100644 app/src/main/java/com/github/catvod/spider/Kugou.java
delete mode 100644 app/src/main/java/com/github/catvod/spider/Living.java
delete mode 100644 app/src/main/java/com/github/catvod/spider/Uvod.java
delete mode 100644 app/src/main/java/com/github/catvod/spider/Xb6v.java
delete mode 100644 app/src/main/java/com/github/catvod/spider/Ysj.java
delete mode 100644 app/src/main/java/com/github/catvod/utils/LZString.java
diff --git a/app/build.gradle b/app/build.gradle
index 1dc43b5f..e9cf110f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -42,7 +42,7 @@ android {
dependencies {
implementation 'com.squareup.okhttp3:okhttp:' + okhttpVersion
implementation 'com.github.thegrizzlylabs:sardine-android:0.9'
- implementation 'wang.harlon.quickjs:wrapper-android:2.4.4'
+ implementation 'wang.harlon.quickjs:wrapper-android:2.4.5'
implementation 'com.google.code.gson:gson:2.11.0'
implementation 'cn.wanghaomiao:JsoupXpath:2.5.1'
implementation 'com.orhanobut:logger:2.2.0'
diff --git a/app/src/main/java/com/github/catvod/bean/uvod/Data.java b/app/src/main/java/com/github/catvod/bean/uvod/Data.java
deleted file mode 100644
index bd94323f..00000000
--- a/app/src/main/java/com/github/catvod/bean/uvod/Data.java
+++ /dev/null
@@ -1,168 +0,0 @@
-package com.github.catvod.bean.uvod;
-
-import android.text.TextUtils;
-
-import com.github.catvod.bean.Vod;
-import com.google.gson.Gson;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-import com.google.gson.annotations.SerializedName;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public class Data {
-
- @SerializedName("video_fragment_list")
- private List videoFragmentList;
- @SerializedName(value = "video_latest_list", alternate = {"video_list"})
- private List videolatestlist;
- @SerializedName(value = "video", alternate = {"video_soruce"})
- private Video video;
-
- public static Data objectFrom(String str) {
- JsonObject jsonObject = JsonParser.parseString(str).getAsJsonObject();
- if (jsonObject.has("data")) return new Gson().fromJson(jsonObject.get("data"), Data.class);
- return new Data();
- }
-
- public List getVideoFragmentList() {
- return videoFragmentList == null ? Collections.emptyList() : videoFragmentList;
- }
-
- public List getVideoLatest() {
- return videolatestlist == null ? Collections.emptyList() : videolatestlist;
- }
-
- public Video getVideo() {
- return video == null ? new Video() : video;
- }
-
- public List getList() {
- List list = new ArrayList<>();
- for (Data.VideoLatest video : getVideoLatest()) list.add(video.vod());
- return list;
- }
-
- public static class VideoLatest {
-
- @SerializedName("id")
- private String id;
- @SerializedName("title")
- private String title;
- @SerializedName("pic")
- private String pic;
- @SerializedName("state")
- private String state;
- @SerializedName("last_fragment_symbol")
- private String lastfragment;
- @SerializedName("year")
- private String year;
-
- public String getId() {
- return TextUtils.isEmpty(id) ? "" : id;
- }
-
- public String getTitle() {
- return TextUtils.isEmpty(title) ? "" : title;
- }
-
- public String getPic() {
- return TextUtils.isEmpty(pic) ? "" : pic;
- }
-
- public String getState() {
- return TextUtils.isEmpty(state) ? "" : state;
- }
-
- public String getLastFragment() {
- return TextUtils.isEmpty(lastfragment) ? "" : lastfragment;
- }
-
- public String getYear() {
- return TextUtils.isEmpty(year) ? "" : year;
- }
-
- public Vod vod() {
- return new Vod(getId(), getTitle(), getPic(), getState() + getLastFragment());
- }
- }
-
- public static class Video {
-
- @SerializedName("year")
- private String year;
- @SerializedName("region")
- private String region;
- @SerializedName("starring")
- private String starring;
- @SerializedName("state")
- private String state;
- @SerializedName("description")
- private String description;
- @SerializedName("director")
- private String director;
- @SerializedName("language")
- private String language;
- @SerializedName("url")
- private String url;
-
- public String getYear() {
- return TextUtils.isEmpty(year) ? "" : year;
- }
-
- public String getRegion() {
- return TextUtils.isEmpty(region) ? "" : region;
- }
-
- public String getStarring() {
- return TextUtils.isEmpty(starring) ? "" : starring;
- }
-
- public String getDescription() {
- return TextUtils.isEmpty(description) ? "" : description;
- }
-
- public String getState() {
- return TextUtils.isEmpty(state) ? "" : state;
- }
-
- public String getDirector() {
- return TextUtils.isEmpty(director) ? "" : director;
- }
-
- public String getLanguage() {
- return TextUtils.isEmpty(language) ? "" : language;
- }
-
- public String getUrl() {
- return TextUtils.isEmpty(url) ? "" : url;
- }
- }
-
- public static class VideoFragmentList {
-
- @SerializedName("id")
- private String id;
- @SerializedName("symbol")
- private String symbol;
- @SerializedName("qualities")
- private List qualities;
-
- public String getId() {
- return TextUtils.isEmpty(id) ? "" : id;
- }
-
- public String getSymbol() {
- return TextUtils.isEmpty(symbol) ? "" : symbol;
- }
-
- public List getQualities() {
- if (qualities == null || qualities.isEmpty()) return Collections.emptyList();
- Collections.sort(qualities, Collections.reverseOrder());
- return qualities;
- }
-
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/github/catvod/debug/MainActivity.java b/app/src/main/java/com/github/catvod/debug/MainActivity.java
index ba9bdffe..e394b18f 100644
--- a/app/src/main/java/com/github/catvod/debug/MainActivity.java
+++ b/app/src/main/java/com/github/catvod/debug/MainActivity.java
@@ -7,7 +7,7 @@ import android.widget.Button;
import com.github.catvod.R;
import com.github.catvod.crawler.Spider;
import com.github.catvod.spider.Init;
-import com.github.catvod.spider.Uvod;
+import com.github.catvod.spider.PTT;
import com.orhanobut.logger.AndroidLogAdapter;
import com.orhanobut.logger.Logger;
@@ -46,7 +46,7 @@ public class MainActivity extends Activity {
private void initSpider() {
try {
Init.init(getApplicationContext());
- spider = new Uvod();
+ spider = new PTT();
spider.init(this, "");
} catch (Throwable e) {
e.printStackTrace();
diff --git a/app/src/main/java/com/github/catvod/spider/AList.java b/app/src/main/java/com/github/catvod/spider/AList.java
index 413f1987..f5264612 100644
--- a/app/src/main/java/com/github/catvod/spider/AList.java
+++ b/app/src/main/java/com/github/catvod/spider/AList.java
@@ -122,14 +122,13 @@ public class AList extends Spider {
String path = id.substring(0, id.lastIndexOf("/"));
String name = path.substring(path.lastIndexOf("/") + 1);
Drive drive = getDrive(key);
- List- parents = getList(path, false);
- Sorter.sort("name", "asc", parents);
Vod vod = new Vod();
vod.setVodPlayFrom(key);
vod.setVodId(id);
vod.setVodName(name);
vod.setVodPic(vodPic);
List playUrls = new ArrayList<>();
+ List
- parents = getList(path, false);
for (Item item : parents) if (item.isMedia(drive.isNew())) playUrls.add(item.getName() + "$" + item.getVodId(path) + findSubs(path, parents));
vod.setVodPlayUrl(TextUtils.join("#", playUrls));
return Result.string(vod);
diff --git a/app/src/main/java/com/github/catvod/spider/AppXY.java b/app/src/main/java/com/github/catvod/spider/AppXY.java
deleted file mode 100644
index d081f81b..00000000
--- a/app/src/main/java/com/github/catvod/spider/AppXY.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package com.github.catvod.spider;
-
-import android.content.Context;
-import android.text.TextUtils;
-
-import com.github.catvod.bean.Class;
-import com.github.catvod.bean.Result;
-import com.github.catvod.bean.Vod;
-import com.github.catvod.crawler.Spider;
-import com.github.catvod.net.OkHttp;
-import com.github.catvod.utils.Crypto;
-
-import org.json.JSONArray;
-import org.json.JSONObject;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author leospring
- * 星牙短剧
- */
-public class AppXY extends Spider {
-
- private String auth;
-
- private Map getHeader() {
- Map map = new HashMap<>();
- map.put("User-Agent", "okhttp/4.10.0");
- if (!TextUtils.isEmpty(auth)) map.put("Authorization", auth);
- return map;
- }
-
- @Override
- public void init(Context context, String extend) throws Exception {
- String s = System.currentTimeMillis() + "";
- Map map = new HashMap<>();
- map.put("device", Crypto.md5(s));
- map.put("install_first_open", "true");
- map.put("first_install_time", s);
- map.put("last_update_time", s);
- auth = new JSONObject(OkHttp.post("https://app.whjzjx.cn/v1/account/login", map, getHeader()).getBody()).optJSONObject("data").optString("token");
- }
-
- @Override
- public String homeContent(boolean filter) throws Exception {
- ArrayList classes = new ArrayList<>();
- JSONArray array = new JSONObject(OkHttp.string("https://app.whjzjx.cn/cloud/v2/theater/classes", getHeader())).optJSONObject("data").optJSONArray("list");
- for (int i = 0; i < array.length(); ++i) {
- JSONObject object = array.optJSONObject(i);
- if (!object.optString("show_type").contains("Bookstore")) {
- classes.add(new Class(object.optString("id"), object.optString("class_name")));
- }
- }
- return Result.string(classes, new ArrayList<>());
- }
-
- @Override
- public String categoryContent(String tid, String pg, boolean filter, HashMap extend) throws Exception {
- List videos = new ArrayList<>();
- String class2Id = extend.get("class2_id");
- if (class2Id == null) class2Id = "0";
- JSONArray array = new JSONObject(OkHttp.string(("https://app.whjzjx.cn/cloud/v2/theater/home_page?theater_class_id=" + tid + "&class2_ids=" + class2Id + "&type=1&page_num=" + pg + "&page_size=24"), getHeader())).optJSONObject("data").optJSONArray("list");
- for (int v = 0; v < array.length(); ++v) {
- JSONObject object = array.optJSONObject(v).optJSONObject("theater");
- videos.add(new Vod(object.optString("id"), object.optString("title"), object.optString("cover_url"), object.optString("total") + "集"));
- }
- return Result.string(videos);
- }
-
- @Override
- public String detailContent(List ids) throws Exception {
- Vod vod = new Vod();
- JSONObject object = new JSONObject(OkHttp.string(("https://app.whjzjx.cn/v2/theater_parent/detail?theater_parent_id=" + ids.get(0)), getHeader())).optJSONObject("data");
- vod.setVodId(ids.get(0));
- vod.setVodName(object.optString("title"));
- vod.setVodPic(object.optString("cover_url"));
- vod.setTypeName(object.optJSONArray("desc_tags").join(",").replace("\"", ""));
- vod.setVodContent(object.optString("introduction"));
- ArrayList playUrls = new ArrayList<>();
- ArrayList playFrom = new ArrayList<>();
- playFrom.add("leospring");
- JSONArray array = object.optJSONArray("theaters");
- ArrayList urlNames = new ArrayList<>();
- for (int i = 0; i < array.length(); ++i) {
- object = array.optJSONObject(i);
- urlNames.add(object.optString("num") + "$" + object.optString("son_video_url"));
- }
- playUrls.add(TextUtils.join("#", urlNames));
- vod.setVodPlayFrom(TextUtils.join("$$$", playFrom));
- vod.setVodPlayUrl(TextUtils.join("$$$", playUrls));
- return Result.string(vod);
- }
-
- @Override
- public String playerContent(String flag, String id, List flags) throws Exception {
- return Result.get().url(id).toString();
- }
-
- @Override
- public String searchContent(String key, boolean quick) throws Exception {
- List list = new ArrayList<>();
- JSONArray array = new JSONObject(OkHttp.post("https://app.whjzjx.cn/v3/search", new JSONObject().put("text", key).toString(), getHeader()).getBody()).optJSONObject("data").optJSONObject("theater").optJSONArray("search_data");
- for (int i = 0; i < array.length(); ++i) {
- JSONObject object = array.optJSONObject(i);
- list.add(new Vod(object.optString("id"), object.optString("title"), object.optString("cover_url"), object.optString("score_str")));
- }
- return Result.string(list);
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/github/catvod/spider/Dm84.java b/app/src/main/java/com/github/catvod/spider/Dm84.java
deleted file mode 100644
index b8831c3f..00000000
--- a/app/src/main/java/com/github/catvod/spider/Dm84.java
+++ /dev/null
@@ -1,179 +0,0 @@
-package com.github.catvod.spider;
-
-import android.text.TextUtils;
-
-import com.github.catvod.bean.Class;
-import com.github.catvod.bean.Filter;
-import com.github.catvod.bean.Result;
-import com.github.catvod.bean.Vod;
-import com.github.catvod.crawler.Spider;
-import com.github.catvod.net.OkHttp;
-import com.github.catvod.utils.Util;
-
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.select.Elements;
-
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author FongMi
- */
-public class Dm84 extends Spider {
-
- private static final String siteUrl = "https://dm84.tv";
-
- private HashMap getHeaders() {
- HashMap headers = new HashMap<>();
- headers.put("User-Agent", Util.CHROME);
- headers.put("Accept", Util.ACCEPT);
- return headers;
- }
-
- private Filter getFilter(String name, String key, List texts) {
- List values = new ArrayList<>();
- for (String text : texts) {
- if (text.isEmpty()) continue;
- String n = text.replace("按", "");
- String v = key.equals("by") ? replaceBy(text) : text;
- values.add(new Filter.Value(n, v));
- }
- return new Filter(key, name, values);
- }
-
- private String replaceBy(String text) {
- return text.replace("按时间", "time").replace("按人气", "hits").replace("按评分", "score");
- }
-
- @Override
- public String homeContent(boolean filter) {
- List list = new ArrayList<>();
- List classes = new ArrayList<>();
- LinkedHashMap> filters = new LinkedHashMap<>();
- Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeaders()));
- for (Element element : doc.select("ul.nav_row > li > a")) {
- if (element.attr("href").startsWith("/list")) {
- String id = element.attr("href").split("-")[1].substring(0, 1);
- String name = element.text().substring(0, 2);
- classes.add(new Class(id, name));
- }
- }
- for (Class item : classes) {
- doc = Jsoup.parse(OkHttp.string(siteUrl + "/list-" + item.getTypeId() + ".html", getHeaders()));
- Elements elements = doc.select("ul.list_filter > li > div");
- List array = new ArrayList<>();
- array.add(getFilter("類型", "type", elements.get(0).select("a").eachText()));
- array.add(getFilter("時間", "year", elements.get(1).select("a").eachText()));
- array.add(getFilter("排序", "by", elements.get(2).select("a").eachText()));
- filters.put(item.getTypeId(), array);
- }
- for (Element element : doc.select("div.item")) {
- String img = element.select("a.cover").attr("data-bg");
- String url = element.select("a.title").attr("href");
- String name = element.select("a.title").text();
- String remark = element.select("span.desc").text();
- String id = url.split("/")[2];
- list.add(new Vod(id, name, img, remark));
- }
- return Result.string(classes, list, filters);
- }
-
- @Override
- public String categoryContent(String tid, String pg, boolean filter, HashMap extend) {
- List list = new ArrayList<>();
- if (extend.get("type") == null) extend.put("type", "");
- if (extend.get("year") == null) extend.put("year", "");
- if (extend.get("by") == null) extend.put("by", "time");
- String by = extend.get("by");
- String type = URLEncoder.encode(extend.get("type"));
- String year = extend.get("year");
- String target = siteUrl + String.format("/show-%s--%s-%s--%s-%s.html", tid, by, type, year, pg);
- Document doc = Jsoup.parse(OkHttp.string(target, getHeaders()));
- for (Element element : doc.select("div.item")) {
- String img = element.select("a.cover").attr("data-bg");
- String url = element.select("a.title").attr("href");
- String name = element.select("a.title").text();
- String remark = element.select("span.desc").text();
- String id = url.split("/")[2];
- list.add(new Vod(id, name, img, remark));
- }
- return Result.string(list);
- }
-
- @Override
- public String detailContent(List ids) {
- Document doc = Jsoup.parse(OkHttp.string(siteUrl.concat("/v/").concat(ids.get(0)), getHeaders()));
- String name = doc.select("h1.v_title").text();
- String remarks = doc.select("p.v_desc > span.desc").text();
- String img = doc.select("meta[property=og:image]").attr("content");
- String area = doc.select("meta[name=og:video:area]").attr("content");
- String type = doc.select("meta[name=og:video:class]").attr("content");
- String actor = doc.select("meta[name=og:video:actor]").attr("content");
- String content = doc.select("meta[property=og:description]").attr("content");
- String year = doc.select("meta[name=og:video:release_date]").attr("content");
- String director = doc.select("meta[name=og:video:director]").attr("content");
-
- Vod vod = new Vod();
- vod.setVodId(ids.get(0));
- vod.setVodPic(img);
- vod.setVodYear(year);
- vod.setVodName(name);
- vod.setVodArea(area);
- vod.setVodActor(actor);
- vod.setVodRemarks(remarks);
- vod.setVodContent(content);
- vod.setVodDirector(director);
- vod.setTypeName(type);
-
- Map sites = new LinkedHashMap<>();
- Elements sources = doc.select("ul.tab_control > li");
- Elements sourceList = doc.select("ul.play_list");
- for (int i = 0; i < sources.size(); i++) {
- Element source = sources.get(i);
- String sourceName = source.text();
- Elements playList = sourceList.get(i).select("a");
- List vodItems = new ArrayList<>();
- for (int j = 0; j < playList.size(); j++) {
- Element e = playList.get(j);
- vodItems.add(e.text() + "$" + e.attr("href"));
- }
- if (vodItems.size() > 0) {
- sites.put(sourceName, TextUtils.join("#", vodItems));
- }
- }
- if (sites.size() > 0) {
- vod.setVodPlayFrom(TextUtils.join("$$$", sites.keySet()));
- vod.setVodPlayUrl(TextUtils.join("$$$", sites.values()));
- }
- return Result.string(vod);
- }
-
- @Override
- public String searchContent(String key, boolean quick) {
- List list = new ArrayList<>();
- String target = siteUrl.concat("/s----------.html?wd=").concat(key);
- Document doc = Jsoup.parse(OkHttp.string(target, getHeaders()));
- for (Element element : doc.select("div.item")) {
- String img = element.select("a.cover").attr("data-bg");
- String url = element.select("a.title").attr("href");
- String name = element.select("a.title").text();
- String remark = element.select("span.desc").text();
- String id = url.split("/")[2];
- list.add(new Vod(id, name, img, remark));
- }
- return Result.string(list);
- }
-
- @Override
- public String playerContent(String flag, String id, List vipFlags) {
- Document doc = Jsoup.parse(OkHttp.string(siteUrl.concat(id), getHeaders()));
- String url = doc.select("iframe").attr("src");
- return Result.get().url(url).parse().header(getHeaders()).string();
- }
-}
diff --git a/app/src/main/java/com/github/catvod/spider/Doll.java b/app/src/main/java/com/github/catvod/spider/Doll.java
deleted file mode 100644
index a68f4c5f..00000000
--- a/app/src/main/java/com/github/catvod/spider/Doll.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package com.github.catvod.spider;
-
-import com.github.catvod.bean.Class;
-import com.github.catvod.bean.Result;
-import com.github.catvod.bean.Vod;
-import com.github.catvod.crawler.Spider;
-import com.github.catvod.net.OkHttp;
-
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-public class Doll extends Spider {
-
- private final String url = "https://hongkongdollvideo.com/";
-
- @Override
- public String homeContent(boolean filter) throws Exception {
- List classes = new ArrayList<>();
- List list = new ArrayList<>();
- Document doc = Jsoup.parse(OkHttp.string(url));
- for (Element a : doc.select("ul.menu").get(0).select("li > a")) {
- String typeName = a.text();
- String typeId = a.attr("href");
- if (typeId.contains(url)) classes.add(new Class(typeId.replace(url, ""), typeName));
- }
- for (Element div : doc.select("div.video-item")) {
- String id = div.select("a.video-title").attr("href").replace(url, "");
- String name = div.select("a.video-title").text();
- String pic = div.select("div.thumb > a > img").attr("data-src");
- String remark = div.select("div.date").text();
- list.add(new Vod(id, name, pic, remark));
- }
- return Result.string(classes, list);
- }
-
- @Override
- public String categoryContent(String tid, String pg, boolean filter, HashMap extend) throws Exception {
- List list = new ArrayList<>();
- String target = pg.equals("1") ? url + tid : url + tid + "/" + pg + ".html";
- Document doc = Jsoup.parse(OkHttp.string(target));
- for (Element div : doc.select("div.video-item")) {
- String id = div.select("a.video-title").attr("href").replace(url, "");
- String name = div.select("a.video-title").text();
- String pic = div.select("div.thumb > a > img").attr("data-src");
- String remark = div.select("div.date").text();
- list.add(new Vod(id, name, pic, remark));
- }
- return Result.string(list);
- }
-
- @Override
- public String detailContent(List ids) throws Exception {
- String html = OkHttp.string(url + ids.get(0));
- Document doc = Jsoup.parse(html);
- String pic = doc.select("meta[property=og:image]").attr("content");
- String name = doc.select("meta[property=og:title]").attr("content");
- Vod vod = new Vod();
- vod.setVodId(ids.get(0));
- vod.setVodPic(pic);
- vod.setVodName(name);
- vod.setVodPlayFrom("玩偶姐姐");
- vod.setVodPlayUrl("播放$" + url + ids.get(0));
- return Result.string(vod);
- }
-
- @Override
- public String playerContent(String flag, String id, List vipFlags) throws Exception {
- return Result.get().url(id).parse().click("document.getElementById('player-wrapper').click()").string();
- }
-
- @Override
- public boolean manualVideoCheck() throws Exception {
- return true;
- }
-
- @Override
- public boolean isVideoFormat(String url) throws Exception {
- return !url.contains("afcdn.net") && url.contains(".m3u8");
- }
-
- @Override
- public String searchContent(String key, boolean quick) throws Exception {
- return searchContent("search/" + key);
- }
-
- @Override
- public String searchContent(String key, boolean quick, String pg) throws Exception {
- return searchContent("search/" + key + "/" + pg + ".html");
- }
-
- private String searchContent(String query) {
- List list = new ArrayList<>();
- Document doc = Jsoup.parse(OkHttp.string(url + query));
- for (Element div : doc.select("div.video-item")) {
- String id = div.select("a.video-title").attr("href").replace(url, "");
- String name = div.select("a.video-title").text();
- String pic = div.select("div.thumb > a > img").attr("data-src");
- String remark = div.select("div.date").text();
- list.add(new Vod(id, name, pic, remark));
- }
- return Result.string(list);
- }
-}
diff --git a/app/src/main/java/com/github/catvod/spider/JSDemo.java b/app/src/main/java/com/github/catvod/spider/JSDemo.java
deleted file mode 100644
index e2b8acda..00000000
--- a/app/src/main/java/com/github/catvod/spider/JSDemo.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.github.catvod.spider;
-
-import android.content.Context;
-
-import com.github.catvod.crawler.Spider;
-import com.whl.quickjs.android.QuickJSLoader;
-import com.whl.quickjs.wrapper.QuickJSContext;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-
-public class JSDemo extends Spider {
-
- private ExecutorService executor;
- private QuickJSContext ctx;
-
- private void submit(Runnable runnable) {
- executor.submit(runnable);
- }
-
- private Future submit(Callable callable) {
- return executor.submit(callable);
- }
-
- private void initJS() {
- if (ctx != null) return;
- ctx = QuickJSContext.create();
- QuickJSLoader.initConsoleLog(ctx);
- }
-
- @Override
- public void init(Context context, String extend) {
- this.executor = Executors.newSingleThreadExecutor();
- submit(this::initJS);
- }
-
- @Override
- public String homeContent(boolean filter) throws Exception {
- return submit(() -> {
- ctx.evaluate("var text = 'homeContent';");
- return ctx.getGlobalObject().getString("text");
- }).get();
- }
-
- @Override
- public void destroy() {
- submit(() -> {
- executor.shutdownNow();
- ctx.destroy();
- });
- }
-}
diff --git a/app/src/main/java/com/github/catvod/spider/Kugou.java b/app/src/main/java/com/github/catvod/spider/Kugou.java
deleted file mode 100644
index 5fbfcb86..00000000
--- a/app/src/main/java/com/github/catvod/spider/Kugou.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.github.catvod.spider;
-
-import android.text.TextUtils;
-
-import com.github.catvod.bean.Class;
-import com.github.catvod.bean.Result;
-import com.github.catvod.bean.Vod;
-import com.github.catvod.crawler.Spider;
-import com.github.catvod.net.OkHttp;
-import com.github.catvod.utils.Util;
-
-import org.json.JSONArray;
-import org.json.JSONObject;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.select.Elements;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author Qile
- */
-public class Kugou extends Spider {
-
- private Map getHeader() {
- Map header = new HashMap<>();
- header.put("User-Agent", Util.CHROME);
- return header;
- }
-
- @Override
- public String homeContent(boolean filter) throws Exception {
- List classes = new ArrayList<>();
- List list = new ArrayList<>();
- List typeIds = Arrays.asList("6666|0", "33162|1", "4681|2");
- List typeNames = Arrays.asList("热门榜单", "特色音乐榜", "全球榜");
- for (int i = 0; i < typeIds.size(); i++) classes.add(new Class(typeIds.get(i), typeNames.get(i)));
- return Result.string(classes, list);
- }
-
- @Override
- public String categoryContent(String tid, String pg, boolean filter, HashMap extend) throws Exception {
- HashMap ext = new HashMap<>();
- if (extend != null && extend.size() > 0) ext.putAll(extend);
- String[] item = tid.split("\\|");
- String id = item[0];
- String digit = item[1];
- int digitValue = Integer.parseInt(digit);
- String cateId = ext.get("cateId") == null ? id : ext.get("cateId");
- String cateUrl = String.format("https://www.kugou.com/yy/rank/home/1-%s.html?from=rank", cateId);
- Document doc = Jsoup.parse(OkHttp.string(cateUrl, getHeader()));
- Elements lis = doc.select(".pc_rank_sidebar").eq(digitValue).select("ul li a");
- JSONArray videos = new JSONArray();
- for (Element li : lis) {
- String vid = li.attr("href");
- String name = li.attr("title");
- JSONObject vod = new JSONObject().put("vod_id", vid).put("vod_name", name);
- videos.put(vod);
- }
- JSONObject result = new JSONObject().put("total", lis.size()).put("pagecount", 1).put("list", videos);
- return result.toString();
- }
-
- @Override
- public String detailContent(List ids) throws Exception {
- Document doc = Jsoup.parse(OkHttp.string(ids.get(0), getHeader()));
- Elements playlist = doc.select(".pc_temp_songlist ul li");
- List vodItems = new ArrayList<>();
- for (int j = 0; j < playlist.size(); j++) {
- Element a = playlist.get(j);
- String href = a.select("a.pc_temp_songname").attr("href");
- String text = a.select("a.pc_temp_songname").text();
- vodItems.add(text + "$" + href);
- }
- String title = doc.select(".pc_temp_title h3").text();
- String remark = doc.select(".rank_update").text();
- String vod_play_from = "Qile";
- String vod_play_url = TextUtils.join("#", vodItems);
- Vod vod = new Vod();
- vod.setVodId(ids.get(0));
- vod.setVodName(title);
- vod.setVodRemarks(remark);
- vod.setVodPlayFrom(vod_play_from);
- vod.setVodPlayUrl(vod_play_url);
- return Result.string(vod);
- }
-
- @Override
- public String playerContent(String flag, String id, List vipFlags) throws Exception {
- return Result.get().url(id).parse().header(getHeader()).string();
- }
-}
diff --git a/app/src/main/java/com/github/catvod/spider/Living.java b/app/src/main/java/com/github/catvod/spider/Living.java
deleted file mode 100644
index d64ea199..00000000
--- a/app/src/main/java/com/github/catvod/spider/Living.java
+++ /dev/null
@@ -1,256 +0,0 @@
-package com.github.catvod.spider;
-
-import android.content.Context;
-import android.text.TextUtils;
-import android.util.Base64;
-
-import com.github.catvod.bean.Class;
-import com.github.catvod.bean.Filter;
-import com.github.catvod.bean.Result;
-import com.github.catvod.bean.Vod;
-import com.github.catvod.crawler.Spider;
-import com.github.catvod.net.OkHttp;
-import com.github.catvod.utils.Crypto;
-import com.github.catvod.utils.LZString;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * @author leospring
- * 聚合直播
- */
-public class Living extends Spider {
-
- private String host = "https://lemonlive.deno.dev";
- private String cookie;
-
- @Override
- public void init(Context context, String extend) throws Exception {
- if (!TextUtils.isEmpty(extend)) {
- host = extend;
- }
- }
-
- @Override
- public String homeContent(boolean filter) throws Exception {
- List classList = new ArrayList<>();
- LinkedHashMap> filters = new LinkedHashMap<>();
-
- classList.add(new Class("huya", "虎牙"));
- classList.add(new Class("douyu", "斗鱼"));
- classList.add(new Class("douyin", "抖音"));
- classList.add(new Class("bilibili", "哔哩哔哩"));
- classList.add(new Class("cc", "网易CC"));
-
- List huyaFilterList = new ArrayList<>();
- List huyaVals = new ArrayList<>();
- huyaVals.add(new Filter.Value("网游", "1"));
- huyaVals.add(new Filter.Value("手游", "3"));
- huyaVals.add(new Filter.Value("娱乐", "8"));
- huyaVals.add(new Filter.Value("单机", "2"));
- huyaFilterList.add(new Filter("type", "分类", huyaVals));
- filters.put("huya", huyaFilterList);
-
- List douyuFilterList = new ArrayList<>();
- List douyuVals = new ArrayList<>();
- douyuVals.add(new Filter.Value("网游竞技", "PCgame"));
- douyuVals.add(new Filter.Value("单机热游", "djry"));
- douyuVals.add(new Filter.Value("手游休闲", "syxx"));
- douyuVals.add(new Filter.Value("娱乐天地", "yl"));
- douyuVals.add(new Filter.Value("颜值", "yz"));
- douyuVals.add(new Filter.Value("科技文化", "kjwh"));
- douyuVals.add(new Filter.Value("语言互动", "yp"));
- douyuFilterList.add(new Filter("type", "分类", douyuVals));
- filters.put("douyu", douyuFilterList);
-
- List douyinFilterList = new ArrayList<>();
- List douyinVals = new ArrayList<>();
- douyinVals.add(new Filter.Value("竞技游戏", "2"));
- douyinVals.add(new Filter.Value("射击游戏", "1"));
- douyinVals.add(new Filter.Value("单机游戏", "3"));
- douyinVals.add(new Filter.Value("棋牌游戏", "4"));
- douyinVals.add(new Filter.Value("休闲益智", "5"));
- douyinVals.add(new Filter.Value("角色扮演", "6"));
- douyinVals.add(new Filter.Value("策略卡牌", "7"));
- douyinVals.add(new Filter.Value("娱乐天地", "10000"));
- douyinVals.add(new Filter.Value("科技文化", "10001"));
- douyinFilterList.add(new Filter("type", "分类", douyinVals));
- filters.put("douyin", douyinFilterList);
-
- List biliFilterList = new ArrayList<>();
- List biliVals = new ArrayList<>();
- biliVals.add(new Filter.Value("网游", "2"));
- biliVals.add(new Filter.Value("手游", "3"));
- biliVals.add(new Filter.Value("单机游戏", "6"));
- biliVals.add(new Filter.Value("娱乐", "1"));
- biliVals.add(new Filter.Value("电台", "5"));
- biliVals.add(new Filter.Value("虚拟主播", "9"));
- biliVals.add(new Filter.Value("聊天室", "14"));
- biliVals.add(new Filter.Value("生活", "10"));
- biliVals.add(new Filter.Value("知识", "11"));
- biliVals.add(new Filter.Value("赛事", "13"));
- biliVals.add(new Filter.Value("互动玩法", "15"));
- biliFilterList.add(new Filter("type", "分类", biliVals));
- filters.put("bilibili", biliFilterList);
-
- List ccFilterList = new ArrayList<>();
- List ccVals = new ArrayList<>();
- ccVals.add(new Filter.Value("网游", "1"));
- ccVals.add(new Filter.Value("手游", "2"));
- ccVals.add(new Filter.Value("竞技", "4"));
- ccVals.add(new Filter.Value("综艺", "5"));
- ccFilterList.add(new Filter("type", "分类", ccVals));
- filters.put("cc", ccFilterList);
- return Result.string(classList, filters);
- }
-
- @Override
- public String categoryContent(String tid, String pg, boolean filter, HashMap extend) throws Exception {
- if (!tid.contains("_")) {
- String url = host + "/api/" + tid + "/getCategories";
- JSONObject json = request(url);
- String type = extend.get("type");
- if (TextUtils.isEmpty(type)) type = json.optJSONArray("data").optJSONObject(0).optString("id");
- List vodList = new ArrayList<>();
- for (int i = 0; i < json.optJSONArray("data").length(); i++) {
- JSONObject data = json.optJSONArray("data").optJSONObject(i);
- if (type.equals(data.optString("id"))) {
- for (int j = 0; j < data.optJSONArray("list").length(); j++) {
- JSONObject item = data.optJSONArray("list").optJSONObject(j);
- vodList.add(new Vod(tid + "_" + item.optString("cid"), item.optString("name"), item.optString("pic"), data.optString("name"), true));
- }
- }
- }
- return Result.string(vodList);
- } else {
- String[] split = tid.split("_");
- String url = host + "/api/" + split[0] + "/getCategoryRooms?id=" + split[1] + "&pid=" + (split[0].equals("bilibili") ? "2" : "1") + "&page=" + pg;
- if (!TextUtils.isEmpty(cookie)) {
- url = url + "&cookie=" + URLDecoder.decode(cookie, "UTF-8");
- }
- JSONObject json = request(url);
- if (!TextUtils.isEmpty(json.optJSONObject("data").optString("cookie"))) {
- cookie = json.optJSONObject("data").optString("cookie");
- }
- List vodList = new ArrayList<>();
- for (int i = 0; i < json.optJSONObject("data").optJSONArray("list").length(); i++) {
- JSONObject data = json.optJSONObject("data").optJSONArray("list").optJSONObject(i);
- vodList.add(new Vod(split[0] + "_" + data.optString("roomId"), data.optString("title"), data.optString("cover"), data.optString("nickname")));
- }
- return Result.string(vodList);
- }
- }
-
- @Override
- public String detailContent(List ids) throws Exception {
- String[] split = ids.get(0).split("_");
- String url = host + "/api/" + split[0] + "/getRoomDetail?id=" + split[1];
- JSONObject json = request(url).optJSONObject("data");
- Vod vod = new Vod();
- vod.setVodId(json.optString("roomId"));
- vod.setVodName(json.optString("title"));
- vod.setVodArea(json.optString("online"));
- vod.setVodDirector(json.optString("siteId"));
- vod.setVodActor(json.optString("nickname"));
- vod.setVodPic(json.optString("cover"));
- vod.setVodContent(json.optString("url"));
- vod.setTypeName(json.optString("category"));
- JSONObject info = json.optJSONObject("info");
- String params = "";
- if (info != null) {
- params = getHuyaParam(info.optString("name"), info.optString("code"));
- }
- List fromList = new ArrayList<>();
- List playList = new ArrayList<>();
- for (int i = 0; i < json.optJSONArray("stream").length(); i++) {
- JSONObject data = json.optJSONArray("stream").optJSONObject(i);
- fromList.add(data.optString("name"));
- List nameUrls = new ArrayList<>();
- for (int j = 0; j < data.optJSONArray("lines").length(); j++) {
- JSONObject urls = data.optJSONArray("lines").optJSONObject(j);
- String playUrl = urls.optString("url") + params;
- nameUrls.add(urls.optString("name") + "$" + playUrl);
- }
- playList.add(TextUtils.join("#", nameUrls));
- }
- vod.setVodPlayFrom(TextUtils.join("$$$", fromList));
- vod.setVodPlayUrl(TextUtils.join("$$$", playList));
- return Result.string(vod);
- }
-
- @Override
- public String playerContent(String flag, String id, List vipFlags) throws Exception {
- if (!id.startsWith("http")) id = "https:" + id;
- return Result.get().url(id).toString();
- }
-
- @Override
- public String searchContent(String key, boolean quick) throws Exception {
- return searchContent(key, quick, "1");
- }
-
- @Override
- public String searchContent(String key, boolean quick, String pg) throws Exception {
- List vodList = new ArrayList<>();
- vodList.addAll(searchWithSite("huya", key, pg));
- vodList.addAll(searchWithSite("douyu", key, pg));
- vodList.addAll(searchWithSite("douyin", key, pg));
- vodList.addAll(searchWithSite("bilibili", key, pg));
- return Result.string(vodList);
- }
-
- private String getSiteNameByEn(String en) {
- return Objects.equals(en, "huya") ? "虎牙"
- : Objects.equals(en, "douyu") ? "斗鱼"
- : Objects.equals(en, "douyin") ? "抖音"
- : Objects.equals(en, "bilibili") ? "哔哩哔哩"
- : Objects.equals(en, "cc") ? "网易CC" : "";
- }
-
- private List searchWithSite(String site, String key, String pg) {
- try {
- List vodList = new ArrayList<>();
- String url = host + "/api/" + site + "/searchRooms?page=" + pg + "&kw=" + key;
- JSONArray jsonArray = request(url).optJSONObject("data").optJSONArray("list");
- for (int i = 0; i < jsonArray.length(); i++) {
- JSONObject item = jsonArray.getJSONObject(i);
- vodList.add(new Vod(site + "_" + item.optString("roomId"), item.optString("nickname"), item.optString("cover"), getSiteNameByEn(site) + "/" + item.optString("category") + "/" + item.optString("title"), false));
- }
- return vodList;
- } catch (Exception ignored) {
- return Collections.emptyList();
- }
- }
-
- private String getHuyaParam(String name, String code) throws UnsupportedEncodingException {
- String N = "1063681129617";
- long currentTimeMillis = System.currentTimeMillis();
- String i = String.valueOf(currentTimeMillis % 10000000000L * 1000 + (long) (Math.random() * 4294967295L));
- String r = code.split("fs=")[1].split("&")[0];
- String s = Long.toHexString((currentTimeMillis / 1000) | 21600);
- String f = String.valueOf(currentTimeMillis + Long.parseLong(N));
- String fmPart = code.split("fm=")[1].split("&")[0];
- String c = new String(Base64.decode(URLDecoder.decode(fmPart, "UTF-8"), Base64.NO_WRAP)).split("_")[0];
- String u = Crypto.md5(f + "|tars_mp|102");
- return String.format("&wsSecret=%s&uuid=%s&wsTime=%s&uid=%s&seqid=%s&fs=%s&ctype=tars_mp&t=102&ver=1&sv=2401310321", Crypto.md5(c + "_" + N + "_" + name + "_" + u + "_" + s), i, s, N, f, r);
- }
-
- private JSONObject request(String url) throws JSONException {
- HashMap map = new HashMap<>();
- map.put("sec-fetch-site", "same-origin");
- String str = OkHttp.string(url, map);
- String result = LZString.decompressFromBase64(str.replaceAll(" ", ""));
- return new JSONObject(result);
- }
-}
diff --git a/app/src/main/java/com/github/catvod/spider/PTT.java b/app/src/main/java/com/github/catvod/spider/PTT.java
index 3704181b..35b7614b 100644
--- a/app/src/main/java/com/github/catvod/spider/PTT.java
+++ b/app/src/main/java/com/github/catvod/spider/PTT.java
@@ -27,7 +27,7 @@ import java.util.regex.Pattern;
public class PTT extends Spider {
- private String url = "https://ptt.red/";
+ private final String url = "https://ptt.red/";
private String extend;
private Map getHeader() {
diff --git a/app/src/main/java/com/github/catvod/spider/Uvod.java b/app/src/main/java/com/github/catvod/spider/Uvod.java
deleted file mode 100644
index 503ff5bc..00000000
--- a/app/src/main/java/com/github/catvod/spider/Uvod.java
+++ /dev/null
@@ -1,189 +0,0 @@
-package com.github.catvod.spider;
-
-import android.content.Context;
-
-import com.github.catvod.bean.Class;
-import com.github.catvod.bean.Result;
-import com.github.catvod.bean.Vod;
-import com.github.catvod.bean.uvod.Data;
-import com.github.catvod.crawler.Spider;
-import com.github.catvod.net.OkHttp;
-import com.github.catvod.utils.Crypto;
-import com.github.catvod.utils.Util;
-
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author Qile
- * @date 2024/11/15
- */
-public class Uvod extends Spider {
-
- private static String siteUrl = "https://api-h5.uvod.tv";
- private static final String latest = siteUrl + "/video/latest";
- private static final String list = siteUrl + "/video/list";
- private static final String detail = siteUrl + "/video/info";
- private static final String play = siteUrl + "/video/source";
- private static final String publicKeyPem = "-----BEGIN PUBLIC KEY-----\n" + "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeBQWotWOpsuPn3PAA+bcmM8YD\n" + "fEOzPz7hb/vItV43vBJV2FcM72Hdcv3DccIFuEV9LQ8vcmuetld98eksja9vQ1Ol\n" + "8rTnjpTpMbd4HedevSuIhWidJdMAOJKDE3AgGFcQvQePs80uXY2JhTLkRn2ICmDR\n" + "/fb32OwWY3QGOvLcuQIDAQAB\n" + "-----END PUBLIC KEY-----";
- private static final String privateKeyPem = "-----BEGIN PRIVATE KEY-----\n" + "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJ4FBai1Y6my4+fc\n" + "8AD5tyYzxgN8Q7M/PuFv+8i1Xje8ElXYVwzvYd1y/cNxwgW4RX0tDy9ya562V33x\n" + "6SyNr29DU6XytOeOlOkxt3gd5169K4iFaJ0l0wA4koMTcCAYVxC9B4+zzS5djYmF\n" + "MuRGfYgKYNH99vfY7BZjdAY68ty5AgMBAAECgYB1rbvHJj5wVF7Rf4Hk2BMDCi9+\n" + "zP4F8SW88Y6KrDbcPt1QvOonIea56jb9ZCxf4hkt3W6foRBwg86oZo2FtoZcpCJ+\n" + "rFqUM2/wyV4CuzlL0+rNNSq7bga7d7UVld4hQYOCffSMifyF5rCFNH1py/4Dvswm\n" + "pi5qljf+dPLSlxXl2QJBAMzPJ/QPAwcf5K5nngQtbZCD3nqDFpRixXH4aUAIZcDz\n" + "S1RNsHrT61mEwZ/thQC2BUJTQNpGOfgh5Ecd1MnURwsCQQDFhAFfmvK7svkygoKX\n" + "t55ARNZy9nmme0StMOfdb4Q2UdJjfw8+zQNtKFOM7VhB7ijHcfFuGsE7UeXBe20n\n" + "g/XLAkEAv9SoT2hgJaQxxUk4MCF8pgddstJlq8Z3uTA7JMa4x+kZfXTm/6TOo6I8\n" + "2VbXZLsYYe8op0lvsoHMFvBSBljV0QJBAKhxyoYRa98dZB5qZRskciaXTlge0WJk\n" + "kA4vvh3/o757izRlQMgrKTfng1GVfIZFqKtnBiIDWTXQw2N9cnqXtH8CQAx+CD5t\n" + "l1iT0cMdjvlMg2two3SnpOjpo7gALgumIDHAmsUWhocLtcrnJI032VQSUkNnLq9z\n" + "EIfmHDz0TPVNHBQ=\n" + "-----END PRIVATE KEY-----";
-
- private Map getHeader(String url) {
- String[] item = url.split("\\|");
- String URL = item[0];
- String tid = item.length > 1 ? item[1] : "";
- String pg = item.length > 2 ? item[2] : "";
- String quality = item.length > 3 ? item[3] : "";
- String hm = String.valueOf(System.currentTimeMillis());
- String text = "";
- if (URL.equals(latest)) {
- text = String.format("-parent_category_id=101-%s", hm);
- } else if (URL.equals(list)) {
- if (pg != null && !pg.isEmpty()) {
- text = String.format("-page=%s&pagesize=42&parent_category_id=%s&sort_type=asc-%s", pg, tid, hm);
- } else {
- text = String.format("-keyword=%s&need_fragment=1&page=1&pagesize=42&sort_type=asc-%s", URLEncoder.encode(tid).toLowerCase(), hm);
- }
- } else if (URL.equals(detail)) {
- text = String.format("-id=%s-%s", tid, hm);
- } else if (URL.equals(play)) {
- text = String.format("-quality=%s&video_fragment_id=%s&video_id=%s-%s", quality, pg, tid, hm);
- }
- String sign = Crypto.md5(text);
- Map header = new HashMap<>();
- header.put("User-Agent", Util.CHROME);
- header.put("referer", "https://www.uvod.tv/");
- header.put("origin", "https://www.uvod.tv");
- header.put("content-type", "application/json");
- header.put("accept", "*/*");
- header.put("x-signature", sign);
- header.put("x-timestamp", hm);
- header.put("x-token", "");
- return header;
- }
-
- private Map playHeader() {
- Map header = new HashMap<>();
- header.put("User-Agent", Util.CHROME);
- header.put("referer", "https://www.uvod.tv/");
- header.put("origin", "https://www.uvod.tv");
- return header;
- }
-
- @Override
- public void init(Context context, String extend) throws Exception {
- if (!extend.isEmpty()) siteUrl = extend;
- }
-
- private String encrypt(String data) throws Exception {
- String aesKey = Crypto.randomKey(32);
- String aesEncryptedData = Crypto.aesEncrypt(data, aesKey, "abcdefghijklmnop");
- String rsaEncryptedKey = Crypto.rsaEncrypt(aesKey, publicKeyPem);
- return aesEncryptedData + "." + rsaEncryptedKey;
- }
-
- private String decrypt(String encryptedData) throws Exception {
- encryptedData = encryptedData.replaceAll("\\s", "");
- String[] parts = encryptedData.split("\\.");
- if (parts.length != 2) return null;
- String rsaEncryptedKey = parts[1];
- String decryptedKey = Crypto.rsaDecrypt(rsaEncryptedKey, privateKeyPem);
- String aesEncryptedData = parts[0];
- return Crypto.CBC(aesEncryptedData, decryptedKey, "abcdefghijklmnop");
- }
-
- @Override
- public String homeContent(boolean filter) throws Exception {
- List classes = new ArrayList<>();
- List typeIds = Arrays.asList("101", "100", "106", "102", "103", "104", "105");
- List typeNames = Arrays.asList("电视剧", "电影", "粤台专区", "综艺", "动漫", "体育", "纪录片");
- for (int i = 0; i < typeIds.size(); i++) classes.add(new Class(typeIds.get(i), typeNames.get(i)));
- String param = "{\"parent_category_id\":101}";
- String encryptData = encrypt(param);
- String content = OkHttp.post(latest, encryptData, getHeader(latest)).getBody();
- String decryptData = decrypt(content);
- Data data = Data.objectFrom(decryptData);
- return Result.string(classes, data.getList());
- }
-
- @Override
- public String categoryContent(String tid, String pg, boolean filter, HashMap extend) throws Exception {
- String param = String.format("{\"parent_category_id\":\"%s\",\"category_id\":null,\"language\":null,\"year\":null,\"region\":null,\"state\":null,\"keyword\":\"\",\"paid\":null,\"page\":%s,\"pagesize\":42,\"sort_field\":\"\",\"sort_type\":\"asc\"}", tid, pg);
- String encryptData = encrypt(param);
- String content = OkHttp.post(list, encryptData, getHeader(list + "|" + tid + "|" + pg)).getBody();
- String decryptData = decrypt(content);
- Data data = Data.objectFrom(decryptData);
- return Result.string(data.getList());
- }
-
- @Override
- public String detailContent(List ids) throws Exception {
- String param = String.format("{\"id\":\"%s\"}", ids.get(0));
- String encryptData = encrypt(param);
- String content = OkHttp.post(detail, encryptData, getHeader(detail + "|" + ids.get(0))).getBody();
- String decryptData = decrypt(content);
- Data data = Data.objectFrom(decryptData);
- StringBuilder vod_play_url = new StringBuilder();
- List videoFragmentList = data.getVideoFragmentList();
- for (int j = 0; j < videoFragmentList.size(); j++) {
- Data.VideoFragmentList videoList = videoFragmentList.get(j);
- String name = videoList.getSymbol();
- String nid = videoList.getId();
- List Qualities = videoList.getQualities();
- nid = ids.get(0) + "|" + nid + "|" + Qualities;
- vod_play_url.append(name).append("$").append(nid);
- boolean notLastEpisode = j < videoFragmentList.size() - 1;
- vod_play_url.append(notLastEpisode ? "#" : "$$$");
- }
- Data.Video video = data.getVideo();
- Vod vod = new Vod();
- vod.setVodId(ids.get(0));
- vod.setVodYear(video.getYear());
- vod.setVodArea(video.getRegion());
- vod.setVodActor(video.getStarring());
- vod.setVodRemarks(video.getState());
- vod.setVodContent(video.getDescription());
- vod.setVodDirector(video.getDirector());
- vod.setTypeName(video.getLanguage());
- vod.setVodPlayFrom("Qile");
- vod.setVodPlayUrl(vod_play_url.toString());
- return Result.string(vod);
- }
-
- @Override
- public String searchContent(String key, boolean quick) throws Exception {
- String param = String.format("{\"parent_category_id\":null,\"category_id\":null,\"language\":null,\"year\":null,\"region\":null,\"state\":null,\"keyword\":\"%s\",\"paid\":null,\"page\":1,\"pagesize\":42,\"sort_field\":\"\",\"sort_type\":\"asc\",\"need_fragment\":1}", key);
- String encryptData = encrypt(param);
- String content = OkHttp.post(list, encryptData, getHeader(list + "|" + key)).getBody();
- String decryptData = decrypt(content);
- Data data = Data.objectFrom(decryptData);
- return Result.string(data.getList());
- }
-
- @Override
- public String playerContent(String flag, String id, List vipFlags) throws Exception {
- String[] item = id.split("\\|");
- String tid = item[0];
- String nid = item[1];
- String[] quality = item[2].replaceAll("[\\[\\]]", "").replace(" ", "").split(",");
- List url = new ArrayList<>();
- for (String s : quality) {
- if (s.equals("4")) url.add("1080p");
- else if (s.equals("3")) url.add("720p");
- else if (s.equals("2")) url.add("480p");
- else if (s.equals("1")) url.add("360p");
- else url.add(s.trim());
- String param = String.format("{\"video_id\":\"%s\",\"video_fragment_id\":%s,\"quality\":%s,\"seek\":null}", tid, nid, s.trim());
- String encryptData = encrypt(param);
- String content = OkHttp.post(play, encryptData, getHeader(play + "|" + tid + "|" + nid + "|" + s.trim())).getBody();
- String decryptData = decrypt(content);
- Data data = Data.objectFrom(decryptData);
- url.add(data.getVideo().getUrl());
- }
- return Result.get().url(url).header(playHeader()).string();
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/github/catvod/spider/XPath.java b/app/src/main/java/com/github/catvod/spider/XPath.java
index e843b1ab..26eb1b74 100644
--- a/app/src/main/java/com/github/catvod/spider/XPath.java
+++ b/app/src/main/java/com/github/catvod/spider/XPath.java
@@ -41,7 +41,7 @@ public class XPath extends Spider {
fetchRule();
List list = new ArrayList<>();
List classes = new ArrayList<>();
- if (rule.getCateManual().size() > 0) {
+ if (!rule.getCateManual().isEmpty()) {
Set keys = rule.getCateManual().keySet();
for (String k : keys) {
classes.add(new Class(rule.getCateManual().get(k), k));
@@ -49,7 +49,7 @@ public class XPath extends Spider {
}
String webUrl = rule.getHomeUrl();
JXDocument doc = JXDocument.create(fetch(webUrl));
- if (rule.getCateManual().size() == 0) {
+ if (rule.getCateManual().isEmpty()) {
List navNodes = doc.selN(rule.getCateNode());
for (int i = 0; i < navNodes.size(); i++) {
String name = navNodes.get(i).selOne(rule.getCateName()).asString().trim();
@@ -220,7 +220,7 @@ public class XPath extends Spider {
vodItems.add(name + "$" + id);
}
// 排除播放列表為空的播放源
- if (vodItems.size() == 0 && playFrom.size() > i) {
+ if (vodItems.isEmpty() && playFrom.size() > i) {
playFrom.set(i, "");
}
playList.add(TextUtils.join("#", vodItems));
@@ -246,8 +246,8 @@ public class XPath extends Spider {
String webUrl = rule.getPlayUrl().isEmpty() ? id : rule.getPlayUrl().replace("{playUrl}", id);
SpiderDebug.log(webUrl);
HashMap headers = new HashMap<>();
- if (rule.getPlayUa().length() > 0) headers.put("User-Agent", rule.getPlayUa());
- if (rule.getPlayReferer().length() > 0) headers.put("Referer", rule.getPlayReferer());
+ if (!rule.getPlayUa().isEmpty()) headers.put("User-Agent", rule.getPlayUa());
+ if (!rule.getPlayReferer().isEmpty()) headers.put("Referer", rule.getPlayReferer());
return Result.get().parse().url(webUrl).header(headers).string();
}
diff --git a/app/src/main/java/com/github/catvod/spider/XPathFilter.java b/app/src/main/java/com/github/catvod/spider/XPathFilter.java
index 604166c4..387b99bb 100644
--- a/app/src/main/java/com/github/catvod/spider/XPathFilter.java
+++ b/app/src/main/java/com/github/catvod/spider/XPathFilter.java
@@ -1,5 +1,7 @@
package com.github.catvod.spider;
+import android.text.TextUtils;
+
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.regex.Matcher;
@@ -15,10 +17,10 @@ public class XPathFilter extends XPath {
@Override
protected String categoryUrl(String tid, String pg, boolean filter, HashMap extend) {
String cateUrl = rule.getCateUrl();
- if (filter && extend != null && extend.size() > 0) {
+ if (filter && extend != null && !extend.isEmpty()) {
for (String key : extend.keySet()) {
String value = extend.get(key);
- if (value.length() > 0) {
+ if (!TextUtils.isEmpty(value)) {
cateUrl = cateUrl.replace("{" + key + "}", URLEncoder.encode(value));
}
}
diff --git a/app/src/main/java/com/github/catvod/spider/XPathMac.java b/app/src/main/java/com/github/catvod/spider/XPathMac.java
index 729f1248..0154b52c 100644
--- a/app/src/main/java/com/github/catvod/spider/XPathMac.java
+++ b/app/src/main/java/com/github/catvod/spider/XPathMac.java
@@ -68,7 +68,7 @@ public class XPathMac extends XPath {
@Override
public String homeContent(boolean filter) {
String result = super.homeContent(filter);
- if (result.length() > 0 && playerConfigJs.length() > 0) { // 嘗試通過playerConfigJs獲取展示和flag匹配關系
+ if (!result.isEmpty() && !playerConfigJs.isEmpty()) { // 嘗試通過playerConfigJs獲取展示和flag匹配關系
String webContent = fetch(playerConfigJs);
Matcher matcher = Pattern.compile(playerConfigJsRegex).matcher(webContent);
if (matcher.find()) {
@@ -94,7 +94,7 @@ public class XPathMac extends XPath {
@Override
public String detailContent(List ids) {
String result = super.detailContent(ids);
- if (decodeVipFlag && result.length() > 0) {
+ if (decodeVipFlag && !result.isEmpty()) {
try {
JSONObject jsonObject = new JSONObject(result);
String[] playFrom = jsonObject.optJSONArray("list").getJSONObject(0).optString("vod_play_from").split("\\$\\$\\$");
@@ -181,8 +181,8 @@ public class XPathMac extends XPath {
result.put("playUrl", "");
result.put("url", videoUrl);
HashMap headers = new HashMap<>();
- if (rule.getPlayUa().length() > 0) headers.put("User-Agent", rule.getPlayUa());
- if (rule.getPlayReferer().length() > 0) headers.put("Referer", rule.getPlayReferer());
+ if (!rule.getPlayUa().isEmpty()) headers.put("User-Agent", rule.getPlayUa());
+ if (!rule.getPlayReferer().isEmpty()) headers.put("Referer", rule.getPlayReferer());
result.put("header", new Gson().toJson(headers));
return result.toString();
} catch (Exception e) {
diff --git a/app/src/main/java/com/github/catvod/spider/XPathMacFilter.java b/app/src/main/java/com/github/catvod/spider/XPathMacFilter.java
index 435f11c9..78f9ecc8 100644
--- a/app/src/main/java/com/github/catvod/spider/XPathMacFilter.java
+++ b/app/src/main/java/com/github/catvod/spider/XPathMacFilter.java
@@ -1,5 +1,7 @@
package com.github.catvod.spider;
+import android.text.TextUtils;
+
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.regex.Matcher;
@@ -10,10 +12,10 @@ public class XPathMacFilter extends XPathMac {
@Override
protected String categoryUrl(String tid, String pg, boolean filter, HashMap extend) {
String cateUrl = rule.getCateUrl();
- if (filter && extend != null && extend.size() > 0) {
+ if (filter && extend != null && !extend.isEmpty()) {
for (String key : extend.keySet()) {
String value = extend.get(key);
- if (value.length() > 0) {
+ if (!TextUtils.isEmpty(value)) {
cateUrl = cateUrl.replace("{" + key + "}", URLEncoder.encode(value));
}
}
diff --git a/app/src/main/java/com/github/catvod/spider/Xb6v.java b/app/src/main/java/com/github/catvod/spider/Xb6v.java
deleted file mode 100644
index 778e6f05..00000000
--- a/app/src/main/java/com/github/catvod/spider/Xb6v.java
+++ /dev/null
@@ -1,244 +0,0 @@
-package com.github.catvod.spider;
-
-import android.text.TextUtils;
-
-import com.github.catvod.bean.Class;
-import com.github.catvod.bean.Filter;
-import com.github.catvod.bean.Result;
-import com.github.catvod.bean.Vod;
-import com.github.catvod.crawler.Spider;
-import com.github.catvod.net.OkHttp;
-import com.github.catvod.utils.Util;
-
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.select.Elements;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import okhttp3.FormBody;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
-
-/**
- * @author zhixc
- * 新版6V电影网
- */
-public class Xb6v extends Spider {
-
- private final String siteUrl = "https://www.xb6v.com";
- private String nextSearchUrlPrefix;
- private String nextSearchUrlSuffix;
-
- private Map getHeader() {
- Map header = new HashMap<>();
- header.put("User-Agent", Util.CHROME);
- header.put("Referer", siteUrl + "/");
- return header;
- }
-
- private Map getDetailHeader() {
- Map header = new HashMap<>();
- header.put("User-Agent", Util.CHROME);
- return header;
- }
-
- @Override
- public String homeContent(boolean filter) throws Exception {
- List classes = new ArrayList<>();
- String html = OkHttp.string(siteUrl, getHeader());
- Document doc = Jsoup.parse(html);
- Elements elements = doc.select("#menus > li > a");
- LinkedHashMap> filters = new LinkedHashMap<>();
- for (int i = 0; i < elements.size(); i++) {
- if (i < 2 || i == elements.size() - 1) continue;
- Element e = elements.get(i);
- String typeId = e.attr("href");
- String typeName = e.text();
- if (typeName.equals("电视剧")) {
- List values = new ArrayList<>();
- values.add(new Filter.Value("不限", ""));
- for (Element a : e.nextElementSibling().select("a")) {
- values.add(new Filter.Value(a.text(), a.attr("href").replaceAll(typeId, "")));
- }
- List filterList = new ArrayList<>();
- filterList.add(new Filter("cateId", "类型", values));
- filters.put(typeId, filterList);
- }
- classes.add(new Class(typeId, typeName));
- }
- return Result.string(classes, parseVodListFromDoc(doc), filters);
- }
-
- private List parseVodListFromDoc(String html) {
- return parseVodListFromDoc(Jsoup.parse(html));
- }
-
- private List parseVodListFromDoc(Document doc) {
- Elements items = doc.select("#post_container .post_hover");
- List list = new ArrayList<>();
- for (Element item : items) {
- Element element = item.select("[class=zoom]").get(0);
- String vodId = element.attr("href");
- String name = element.attr("title").replaceAll("?[^>]+>", "");
- String pic = element.select("img").attr("src");
- String remark = item.select("[rel=category tag]").text();
- list.add(new Vod(vodId, name, pic, remark));
- }
- return list;
- }
-
- @Override
- public String categoryContent(String tid, String pg, boolean filter, HashMap extend) throws Exception {
- String cateId = extend.get("cateId") == null ? "" : extend.get("cateId");
- String cateUrl = siteUrl + tid + cateId;
- if (!pg.equals("1")) cateUrl += "index_" + pg + ".html";
- String html = OkHttp.string(cateUrl, getHeader());
- Document doc = Jsoup.parse(html);
- String href = doc.select(".pagination > a").last().attr("href");
- int page = Integer.parseInt(pg);
- int count = Integer.parseInt(getStrByRegex(Pattern.compile("index_(.*?).html"), href));
- int limit = 18;
- Elements items = doc.select("#post_container .post_hover");
- int total = page == count ? (page - 1) * limit + items.size() : count * limit;
- return Result.get().vod(parseVodListFromDoc(doc)).page(page, count, limit, total).string();
- }
-
- @Override
- public String detailContent(List ids) throws Exception {
- String vodId = ids.get(0);
- String detailUrl = siteUrl + vodId;
- String html = OkHttp.string(detailUrl, getDetailHeader());
- Document doc = Jsoup.parse(html);
- Elements sourceList = doc.select("#post_content");
-
- String circuitName = "磁力线路";
- Map playMap = new LinkedHashMap<>();
- int i = 0;
- for (Element source : sourceList) {
- Elements aList = source.select("table a");
- List vodItems = new ArrayList<>();
- for (Element a : aList) {
- String episodeUrl = a.attr("href");
- String episodeName = a.text();
- if (!episodeUrl.toLowerCase().startsWith("magnet")) continue;
- vodItems.add(episodeName + "$" + episodeUrl);
- }
- if (vodItems.size() > 0) {
- i++;
- playMap.put(circuitName + i, TextUtils.join("#", vodItems));
- }
- }
-
- String partHTML = doc.select(".context").html();
- String name = doc.select(".article_container > h1").text();
- String pic = doc.select("#post_content img").attr("src");
- String typeName = getStrByRegex(Pattern.compile("◎类 别 (.*?)
"), partHTML);
- if (typeName.equals("")) typeName = doc.select("[rel=category tag]").text();
- String year = getStrByRegex(Pattern.compile("◎年 代 (.*?)
"), partHTML);
- if (year.equals("")) year = getStrByRegex(Pattern.compile("首播:(.*?)
"), partHTML);
- String area = getStrByRegex(Pattern.compile("◎产 地 (.*?)
"), partHTML);
- if (area.equals("")) area = getStrByRegex(Pattern.compile("地区:(.*?)
"), partHTML);
- String remark = getStrByRegex(Pattern.compile("◎上映日期 (.*?)
"), partHTML);
- String actor = getActorOrDirector(Pattern.compile("◎演 员 (.*?)
"), partHTML);
- if (actor.equals("")) actor = getActorOrDirector(Pattern.compile("◎主 演 (.*?)"), partHTML);
- if (actor.equals("")) actor = getActorOrDirector(Pattern.compile("主演:(.*?)
"), partHTML);
- String director = getActorOrDirector(Pattern.compile("◎导 演 (.*?)
"), partHTML);
- if (director.equals("")) director = getActorOrDirector(Pattern.compile("导演:(.*?)
"), partHTML);
- String description = getDescription(Pattern.compile("◎简 介(.*?)
", Pattern.CASE_INSENSITIVE | Pattern.DOTALL), partHTML);
- if (description.equals("")) description = getDescription(Pattern.compile("简介(.*?)", Pattern.CASE_INSENSITIVE | Pattern.DOTALL), partHTML);
-
- Vod vod = new Vod();
- vod.setVodId(ids.get(0));
- vod.setVodName(name);
- vod.setVodPic(pic);
- vod.setTypeName(typeName);
- vod.setVodYear(year);
- vod.setVodArea(area);
- vod.setVodRemarks(remark);
- vod.setVodActor(actor);
- vod.setVodDirector(director);
- vod.setVodContent(description);
- vod.setVodPlayFrom(TextUtils.join("$$$", playMap.keySet()));
- vod.setVodPlayUrl(TextUtils.join("$$$", playMap.values()));
-
- return Result.string(vod);
- }
-
- private String getStrByRegex(Pattern pattern, String str) {
- Matcher matcher = pattern.matcher(str);
- if (matcher.find()) return matcher.group(1).trim();
- return "";
- }
-
- private String getActorOrDirector(Pattern pattern, String str) {
- return getStrByRegex(pattern, str)
- .replaceAll("
", "")
- .replaceAll(" ", "")
- .replaceAll("&", "")
- .replaceAll("middot;", "・")
- .replaceAll(" ", ",")
- .replaceAll(" ", ",")
- .replaceAll(" ", "");
- }
-
- private String getDescription(Pattern pattern, String str) {
- return getStrByRegex(pattern, str)
- .replaceAll("?[^>]+>", "")
- .replaceAll("\n", "")
- .replaceAll("&", "")
- .replaceAll("middot;", "・")
- .replaceAll("ldquo;", "【")
- .replaceAll("rdquo;", "】")
- .replaceAll(" ", "");
- }
-
- @Override
- public String searchContent(String key, boolean quick) throws Exception {
- return searchContent(key, quick, "1");
- }
-
- @Override
- public String searchContent(String key, boolean quick, String pg) throws Exception {
- String searchUrl = siteUrl + "/e/search/index.php";
- if (pg.equals("1")) {
- RequestBody formBody = new FormBody.Builder()
- .add("show", "title")
- .add("tempid", "1")
- .add("tbname", "article")
- .add("mid", "1")
- .add("dopost", "search")
- .add("submit", "")
- .addEncoded("keyboard", key)
- .build();
- Request request = new Request.Builder().url(searchUrl)
- .addHeader("User-Agent", Util.CHROME)
- .addHeader("Origin", siteUrl)
- .addHeader("Referer", siteUrl + "/")
- .post(formBody)
- .build();
- Response response = OkHttp.newCall(request);
- String[] split = String.valueOf(response.request().url()).split("\\?searchid=");
- nextSearchUrlPrefix = split[0] + "index.php?page=";
- nextSearchUrlSuffix = "&searchid=" + split[1];
- return Result.string(parseVodListFromDoc(response.body().string()));
- } else {
- int page = Integer.parseInt(pg) - 1;
- searchUrl = nextSearchUrlPrefix + page + nextSearchUrlSuffix;
- return Result.string(parseVodListFromDoc(OkHttp.string(searchUrl, getHeader())));
- }
- }
-
- @Override
- public String playerContent(String flag, String id, List vipFlags) throws Exception {
- return Result.get().url(id).string();
- }
-}
diff --git a/app/src/main/java/com/github/catvod/spider/YHDM.java b/app/src/main/java/com/github/catvod/spider/YHDM.java
index 770cff89..a633da48 100644
--- a/app/src/main/java/com/github/catvod/spider/YHDM.java
+++ b/app/src/main/java/com/github/catvod/spider/YHDM.java
@@ -91,7 +91,6 @@ public class YHDM extends Spider {
Document doc = Jsoup.parse(OkHttp.string(detailUrl, getHeader()));
Elements sources = doc.select(".myui-content__list.sort-list");
Elements circuits = doc.select("a[href^=#playlist]");
-
StringBuilder vod_play_url = new StringBuilder();
StringBuilder vod_play_from = new StringBuilder();
for (int i = 0; i < circuits.size(); i++) {
@@ -113,7 +112,6 @@ public class YHDM extends Spider {
String year = matcher(text, "年份:(.*?)更新");
String remark = matcher(text, "更新:(.*?)简介");
String brief = doc.select(".col-pd.text-collapse .data").text();
-
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodArea(area);
@@ -164,7 +162,6 @@ public class YHDM extends Spider {
String key = "57A891D97E332A9D";
String iv = matcher(content1, "bt_token = \"(.*?)\"");
String realUrl = Crypto.CBC(playUrl, key, iv);
- if (realUrl == null) return Result.get().url(siteUrl + id).parse().string();
return Result.get().url(realUrl).string();
}
diff --git a/app/src/main/java/com/github/catvod/spider/Ysj.java b/app/src/main/java/com/github/catvod/spider/Ysj.java
deleted file mode 100644
index 3f6fb202..00000000
--- a/app/src/main/java/com/github/catvod/spider/Ysj.java
+++ /dev/null
@@ -1,166 +0,0 @@
-package com.github.catvod.spider;
-
-import android.text.TextUtils;
-
-import com.github.catvod.bean.Class;
-import com.github.catvod.bean.Filter;
-import com.github.catvod.bean.Result;
-import com.github.catvod.bean.Vod;
-import com.github.catvod.crawler.Spider;
-import com.github.catvod.net.OkHttp;
-import com.github.catvod.utils.Util;
-
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.select.Elements;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-public class Ysj extends Spider {
-
- private static final String siteUrl = "https://www.dmmiku.com";
- private static final String cateUrl = "https://www.dmmiku.com/index.php/vod/show";
- private static final String homeUrl = "https://www.dmmiku.com/index.php/vod/show/id/20.html";
- private static final String detailUrl = "https://www.dmmiku.com/index.php/vod/detail/id/";
- private static final String searchUrl = "https://www.dmmiku.com/index.php/vod/search.html";
- private static final String playUrl = "/index.php/vod/play/id/";
-
- private HashMap getHeaders() {
- HashMap headers = new HashMap<>();
- headers.put("User-Agent", Util.CHROME);
- return headers;
- }
-
- private Filter getFilter(String name, String key, List texts) {
- List values = new ArrayList<>();
- for (String text : texts) {
- if (text.isEmpty()) continue;
- values.add(new Filter.Value(text, text.replace("全部", "")));
- }
- return new Filter(key, name, values);
- }
-
- @Override
- public String homeContent(boolean filter) {
- List list = new ArrayList<>();
- List classes = new ArrayList<>();
- List array = new ArrayList<>();
- LinkedHashMap> filters = new LinkedHashMap<>();
- Document doc = Jsoup.parse(OkHttp.string(homeUrl, getHeaders()));
- array.add(getFilter("地區", "area", doc.select("div#hl03").select("a").eachText()));
- array.add(getFilter("年份", "year", doc.select("div#hl04").select("a").eachText()));
- array.add(getFilter("語言", "lang", doc.select("div#hl05").select("a").eachText()));
- array.add(getFilter("字母", "letter", doc.select("div#hl06").select("a").eachText()));
- for (Element element : doc.select("div#hl02").select("a")) {
- String typeId = element.attr("href").split("/")[5];
- typeId = typeId.contains(".html") ? "" : typeId;
- String typeName = element.text().replace("BD", "");
- classes.add(new Class(typeId, typeName));
- filters.put(typeId, array);
- }
- for (Element element : doc.select("li.vodlist_item")) {
- String id = element.select("a").attr("href").split("/")[5];
- String name = element.select("a").attr("title");
- String pic = siteUrl + element.select("a").attr("data-original");
- String remark = element.select("span.pic_text").text();
- list.add(new Vod(id, name, pic, remark));
- }
- return Result.string(classes, list, filters);
- }
-
- @Override
- public String categoryContent(String tid, String pg, boolean filter, HashMap extend) {
- StringBuilder sb = new StringBuilder(cateUrl);
- if (extend.containsKey("area")) sb.append("/area/").append(extend.get("area"));
- if (tid.length() > 0) sb.append("/class/").append(tid);
- sb.append("/id/20");
- if (extend.containsKey("lang")) sb.append("/lang/").append(extend.get("lang"));
- if (extend.containsKey("letter")) sb.append("/letter/").append(extend.get("letter"));
- if (extend.containsKey("year")) sb.append("/year/").append(extend.get("year"));
- if (!pg.equals("1")) sb.append("/page/").append(pg);
- sb.append(".html");
- Document doc = Jsoup.parse(OkHttp.string(sb.toString(), getHeaders()));
- List list = new ArrayList<>();
- for (Element element : doc.select("li.vodlist_item")) {
- String id = element.select("a").attr("href").split("/")[5];
- String name = element.select("a").attr("title");
- String pic = siteUrl + element.select("a").attr("data-original");
- String remark = element.select("span.pic_text").text();
- list.add(new Vod(id, name, pic, remark));
- }
- return Result.string(list);
- }
-
- @Override
- public String detailContent(List ids) {
- Document doc = Jsoup.parse(OkHttp.string(detailUrl.concat(ids.get(0)), getHeaders()));
- String name = doc.select("h2.title").text();
- String pic = siteUrl + doc.select("a.vodlist_thumb").attr("data-original");
- String year = doc.select("li.data").get(0).select("a").get(0).text();
- String area = doc.select("li.data").get(0).select("a").get(1).text();
- String type = doc.select("li.data").get(0).select("a").get(2).text();
- String actor = doc.select("li.data").get(2).text().replace("主演:", "");
- String director = doc.select("li.data").get(3).text().replace("导演:", "");
- String content = doc.select("div.content_desc > span").text();
-
- Vod vod = new Vod();
- vod.setVodId(ids.get(0));
- vod.setVodPic(pic);
- vod.setVodYear(year);
- vod.setVodName(name);
- vod.setVodArea(area);
- vod.setVodActor(actor);
- vod.setVodContent(content);
- vod.setVodDirector(director);
- vod.setTypeName(type);
-
- Map sites = new LinkedHashMap<>();
- Elements sources = doc.select("div.play_source_tab > a");
- Elements sourceList = doc.select("ul.content_playlist");
- for (int i = 0; i < sources.size(); i++) {
- Element source = sources.get(i);
- String sourceName = source.attr("alt");
- Elements playList = sourceList.get(i).select("a");
- List vodItems = new ArrayList<>();
- for (int j = 0; j < playList.size(); j++) {
- Element e = playList.get(j);
- String href = e.attr("href").replace(playUrl, "");
- vodItems.add(e.text() + "$" + href);
- }
- if (vodItems.size() > 0) {
- sites.put(sourceName, TextUtils.join("#", vodItems));
- }
- }
- if (sites.size() > 0) {
- vod.setVodPlayFrom(TextUtils.join("$$$", sites.keySet()));
- vod.setVodPlayUrl(TextUtils.join("$$$", sites.values()));
- }
- return Result.string(vod);
- }
-
- @Override
- public String searchContent(String key, boolean quick) {
- List list = new ArrayList<>();
- String target = searchUrl.concat("?wd=").concat(key).concat("&submit=");
- Document doc = Jsoup.parse(OkHttp.string(target, getHeaders()));
- if (doc.html().contains("很抱歉,暂无相关视频")) return Result.string(list);
- for (Element element : doc.select("li.searchlist_item")) {
- String id = element.select("a").attr("href").split("/")[5];
- String name = element.select("a").attr("title");
- String pic = siteUrl + element.select("a").attr("data-original");
- String remark = element.select("span.pic_text").text();
- list.add(new Vod(id, name, pic, remark));
- }
- return Result.string(list);
- }
-
- @Override
- public String playerContent(String flag, String id, List vipFlags) {
- return Result.get().url(siteUrl + playUrl + id).parse().header(getHeaders()).string();
- }
-}
diff --git a/app/src/main/java/com/github/catvod/utils/LZString.java b/app/src/main/java/com/github/catvod/utils/LZString.java
deleted file mode 100644
index fdc76b97..00000000
--- a/app/src/main/java/com/github/catvod/utils/LZString.java
+++ /dev/null
@@ -1,220 +0,0 @@
-package com.github.catvod.utils;
-
-/*
- * LZString4Java By Rufus Huang
- * https://github.com/rufushuang/lz-string4java
- * MIT License
- *
- * Port from original JavaScript version by pieroxy
- * https://github.com/pieroxy/lz-string
- */
-
-import android.text.TextUtils;
-
-import java.util.*;
-
-public class LZString {
-
- private static final char[] keyStrBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();
- private static final Map> baseReverseDic = new HashMap<>();
-
- private static char getBaseValue(char[] alphabet, Character character) {
- Map map = baseReverseDic.get(alphabet);
- if (map == null) {
- map = new HashMap<>();
- baseReverseDic.put(alphabet, map);
- for (int i = 0; i < alphabet.length; i++) {
- map.put(alphabet[i], i);
- }
- }
- return (char) map.get(character).intValue();
- }
-
- public static String decompressFromBase64(final String inputStr) {
- if (TextUtils.isEmpty(inputStr)) return "";
- return _decompress(inputStr.length(), 32, new DecompressFunctionWrapper() {
- @Override
- public char doFunc(int index) {
- return getBaseValue(keyStrBase64, inputStr.charAt(index));
- }
- });
- }
-
- private static abstract class DecompressFunctionWrapper {
- public abstract char doFunc(int i);
- }
-
- protected static class DecData {
- public char val;
- public int position;
- public int index;
- }
-
- public static String f(int i) {
- return String.valueOf((char) i);
- }
-
- private static String _decompress(int length, int resetValue, DecompressFunctionWrapper getNextValue) {
- List dictionary = new ArrayList<>();
- int enlargeIn = 4;
- int dictSize = 4;
- int numBits = 3;
- String entry;
- StringBuilder result = new StringBuilder();
- String w;
- int bits, resb;
- int maxpower, power;
- String c = null;
- DecData data = new DecData();
- data.val = getNextValue.doFunc(0);
- data.position = resetValue;
- data.index = 1;
-
- for (int i = 0; i < 3; i += 1) {
- dictionary.add(i, f(i));
- }
-
- bits = 0;
- maxpower = powerOf2(2);
- power = 1;
- while (power != maxpower) {
- resb = data.val & data.position;
- data.position >>= 1;
- if (data.position == 0) {
- data.position = resetValue;
- data.val = getNextValue.doFunc(data.index++);
- }
- bits |= (resb > 0 ? 1 : 0) * power;
- power <<= 1;
- }
-
- switch (bits) {
- case 0:
- maxpower = powerOf2(8);
- power = 1;
- while (power != maxpower) {
- resb = data.val & data.position;
- data.position >>= 1;
- if (data.position == 0) {
- data.position = resetValue;
- data.val = getNextValue.doFunc(data.index++);
- }
- bits |= (resb > 0 ? 1 : 0) * power;
- power <<= 1;
- }
- c = f(bits);
- break;
- case 1:
- bits = 0;
- maxpower = powerOf2(16);
- power = 1;
- while (power != maxpower) {
- resb = data.val & data.position;
- data.position >>= 1;
- if (data.position == 0) {
- data.position = resetValue;
- data.val = getNextValue.doFunc(data.index++);
- }
- bits |= (resb > 0 ? 1 : 0) * power;
- power <<= 1;
- }
- c = f(bits);
- break;
- case 2:
- return "";
- }
- dictionary.add(3, c);
- w = c;
- result.append(w);
- while (true) {
- if (data.index > length) {
- return "";
- }
- bits = 0;
- maxpower = powerOf2(numBits);
- power = 1;
- while (power != maxpower) {
- resb = data.val & data.position;
- data.position >>= 1;
- if (data.position == 0) {
- data.position = resetValue;
- data.val = getNextValue.doFunc(data.index++);
- }
- bits |= (resb > 0 ? 1 : 0) * power;
- power <<= 1;
- }
- int cc;
- switch (cc = bits) {
- case 0:
- maxpower = powerOf2(8);
- power = 1;
- while (power != maxpower) {
- resb = data.val & data.position;
- data.position >>= 1;
- if (data.position == 0) {
- data.position = resetValue;
- data.val = getNextValue.doFunc(data.index++);
- }
- bits |= (resb > 0 ? 1 : 0) * power;
- power <<= 1;
- }
- dictionary.add(dictSize++, f(bits));
- cc = dictSize - 1;
- enlargeIn--;
- break;
- case 1:
- bits = 0;
- maxpower = powerOf2(16);
- power = 1;
- while (power != maxpower) {
- resb = data.val & data.position;
- data.position >>= 1;
- if (data.position == 0) {
- data.position = resetValue;
- data.val = getNextValue.doFunc(data.index++);
- }
- bits |= (resb > 0 ? 1 : 0) * power;
- power <<= 1;
- }
- dictionary.add(dictSize++, f(bits));
- cc = dictSize - 1;
- enlargeIn--;
- break;
- case 2:
- return result.toString();
- }
-
- if (enlargeIn == 0) {
- enlargeIn = powerOf2(numBits);
- numBits++;
- }
-
- if (cc < dictionary.size() && dictionary.get(cc) != null) {
- entry = dictionary.get(cc);
- } else {
- if (cc == dictSize) {
- entry = w + w.charAt(0);
- } else {
- return null;
- }
- }
- result.append(entry);
-
- // Add w+entry[0] to the dictionary.
- dictionary.add(dictSize++, w + entry.charAt(0));
- enlargeIn--;
-
- w = entry;
-
- if (enlargeIn == 0) {
- enlargeIn = powerOf2(numBits);
- numBits++;
- }
- }
- }
-
- private static int powerOf2(int power) {
- return 1 << power;
- }
-}
-
diff --git a/app/src/main/java/com/github/catvod/utils/Util.java b/app/src/main/java/com/github/catvod/utils/Util.java
index 15d70d55..b59f81dc 100644
--- a/app/src/main/java/com/github/catvod/utils/Util.java
+++ b/app/src/main/java/com/github/catvod/utils/Util.java
@@ -13,9 +13,6 @@ import android.webkit.WebViewClient;
import com.github.catvod.spider.Init;
-import java.io.File;
-import java.io.FileInputStream;
-import java.security.MessageDigest;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
@@ -26,7 +23,6 @@ public class Util {
public static final Pattern RULE = Pattern.compile("http((?!http).){12,}?\\.(m3u8|mp4|mkv|flv|mp3|m4a|aac)\\?.*|http((?!http).){12,}\\.(m3u8|mp4|mkv|flv|mp3|m4a|aac)|http((?!http).)*?video/tos*");
public static final Pattern THUNDER = Pattern.compile("(magnet|thunder|ed2k):.*");
public static final String CHROME = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36";
- public static final String ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
public static final List MEDIA = Arrays.asList("mp4", "mkv", "wmv", "flv", "avi", "iso", "mpg", "ts", "mp3", "aac", "flac", "m4a", "ape", "ogg");
public static final List SUB = Arrays.asList("srt", "ass", "ssa", "vtt");
diff --git a/jar/custom_spider.jar b/jar/custom_spider.jar
index 6ed82a173bdcb355a91350b21749b5c6e968b59e..c9df1bf0258e01d39cbce3529b1f0b5707700ecd 100644
GIT binary patch
literal 311056
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