diff --git a/app/src/main/java/com/github/catvod/bean/jianpian/Data.java b/app/src/main/java/com/github/catvod/bean/jianpian/Data.java new file mode 100644 index 0000000..311ca27 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/jianpian/Data.java @@ -0,0 +1,179 @@ +package com.github.catvod.bean.jianpian; + +import android.text.TextUtils; + +import com.github.catvod.bean.Vod; +import com.github.catvod.utils.Util; +import com.google.gson.annotations.SerializedName; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Data { + + @SerializedName("jump_id") + private String jumpId; + @SerializedName("id") + private String id; + @SerializedName(value = "thumbnail", alternate = "path") + private String thumbnail; + @SerializedName("title") + private String title; + @SerializedName("mask") + private String mask; + @SerializedName("description") + private String description; + @SerializedName("playlist") + private Value playlist; + @SerializedName("year") + private String year; + @SerializedName("area") + private String area; + @SerializedName("types") + private List types; + @SerializedName("actors") + private List actors; + @SerializedName("directors") + private List directors; + @SerializedName("source_list_source") + private List source; + @SerializedName("dataList") + private List dataList; + + public String getJumpId() { + return TextUtils.isEmpty(jumpId) ? "" : jumpId; + } + + public String getId() { + return TextUtils.isEmpty(id) ? "" : id; + } + + public String getThumbnail() { + return TextUtils.isEmpty(thumbnail) ? "" : "http://img1.vbwus.com" + thumbnail; + } + + public String getTitle() { + return TextUtils.isEmpty(title) ? "" : title; + } + + public String getMask() { + return TextUtils.isEmpty(mask) ? getPlaylist() : mask; + } + + public String getDescription() { + return TextUtils.isEmpty(description) ? "" : description.replace(" ", ""); + } + + public String getPlaylist() { + return playlist == null ? "" : playlist.getTitle(); + } + + public String getYear() { + return year == null ? "" : year; + } + + public String getArea() { + return area == null ? "" : area; + } + + public String getTypes() { + return types == null ? "" : getValues(types, false); + } + + public String getActors() { + return actors == null ? "" : getValues(actors, true); + } + + public String getDirectors() { + return directors == null ? "" : getValues(directors, true); + } + + public List getSource() { + return source == null ? Collections.emptyList() : source; + } + + public List getDataList() { + return dataList == null ? Collections.emptyList() : dataList; + } + + public Vod homeVod() { + return new Vod(getJumpId(), getTitle(), getThumbnail()); + } + + public Vod vod() { + return new Vod(getId(), getTitle(), getThumbnail(), getMask()); + } + + public String getValues(List items, boolean link) { + StringBuilder sb = new StringBuilder(); + for (Value value : items) sb.append(value.getValue(link)).append(" "); + return Util.substring(sb.toString()); + } + + public static class Value { + + @SerializedName(value = "title", alternate = "name") + private String title; + + private String getTitle() { + return TextUtils.isEmpty(title) ? "" : title; + } + + private String getLink() { + return String.format("[a=cr:{\"id\":\"%s\",\"name\":\"%s\"}/]%s[/a]", getTitle() + "/{pg}", getTitle(), getTitle()); + } + + public String getValue(boolean link) { + return link ? getLink() : getTitle(); + } + } + + public static class SourceListSource { + + @SerializedName("name") + private String name; + @SerializedName("source_list") + private List list; + + public String getName() { + return TextUtils.isEmpty(name) ? "" : name; + } + + public List getList() { + return list == null ? Collections.emptyList() : list; + } + } + + public static class SourceList { + + @SerializedName("source_name") + private String name; + @SerializedName("url") + private String url; + + public String getName() { + return TextUtils.isEmpty(name) ? "" : name; + } + + public String getUrl() { + return TextUtils.isEmpty(url) ? "" : url.replaceAll("ftp", "tvbox-xg:ftp"); + } + } + + public String getVodFrom() { + List items = new ArrayList<>(); + for (SourceListSource source : getSource()) items.add(source.getName()); + return TextUtils.join("$$$", items); + } + + public String getVodUrl() { + List items = new ArrayList<>(); + for (SourceListSource source : getSource()) { + List urls = new ArrayList<>(); + for (SourceList item : source.getList()) urls.add(item.getName() + "$" + item.getUrl()); + items.add(TextUtils.join("#", urls)); + } + return TextUtils.join("$$$", items); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/catvod/bean/jianpian/Detail.java b/app/src/main/java/com/github/catvod/bean/jianpian/Detail.java new file mode 100644 index 0000000..4ba05a1 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/jianpian/Detail.java @@ -0,0 +1,18 @@ +package com.github.catvod.bean.jianpian; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +public class Detail { + + @SerializedName("data") + private Data data; + + public static Detail objectFrom(String str) { + return new Gson().fromJson(str, Detail.class); + } + + public Data getData() { + return data == null ? new Data() : data; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/catvod/bean/jianpian/Resp.java b/app/src/main/java/com/github/catvod/bean/jianpian/Resp.java new file mode 100644 index 0000000..ef88c8b --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/jianpian/Resp.java @@ -0,0 +1,21 @@ +package com.github.catvod.bean.jianpian; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +import java.util.Collections; +import java.util.List; + +public class Resp { + + @SerializedName("data") + private List data; + + public static Resp objectFrom(String str) { + return new Gson().fromJson(str, Resp.class); + } + + public List getData() { + return data == null ? Collections.emptyList() : data; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/catvod/bean/jianpian/Search.java b/app/src/main/java/com/github/catvod/bean/jianpian/Search.java new file mode 100644 index 0000000..80679d0 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/jianpian/Search.java @@ -0,0 +1,52 @@ +package com.github.catvod.bean.jianpian; + +import android.text.TextUtils; + +import com.github.catvod.bean.Vod; +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +import java.util.Collections; +import java.util.List; + +public class Search { + + @SerializedName("data") + private List data; + @SerializedName("id") + private String id; + @SerializedName(value = "thumbnail", alternate = "path") + private String thumbnail; + @SerializedName("title") + private String title; + @SerializedName("mask") + private String mask; + + public static Search objectFrom(String str) { + return new Gson().fromJson(str, Search.class); + } + + public String getId() { + return TextUtils.isEmpty(id) ? "" : id; + } + + public String getThumbnail() { + return TextUtils.isEmpty(thumbnail) ? "" : "http://img1.vbwus.com" + thumbnail; + } + + public String getTitle() { + return TextUtils.isEmpty(title) ? "" : title; + } + + public String getMask() { + return TextUtils.isEmpty(mask) ? "" : mask; + } + + public Vod vod() { + return new Vod(getId(), getTitle(), getThumbnail(), getMask()); + } + + public List getData() { + return data == null ? Collections.emptyList() : data; + } +} diff --git a/app/src/main/java/com/github/catvod/spider/Jianpian.java b/app/src/main/java/com/github/catvod/spider/Jianpian.java new file mode 100644 index 0000000..753f523 --- /dev/null +++ b/app/src/main/java/com/github/catvod/spider/Jianpian.java @@ -0,0 +1,123 @@ +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.jianpian.Data; +import com.github.catvod.bean.jianpian.Detail; +import com.github.catvod.bean.jianpian.Resp; +import com.github.catvod.bean.jianpian.Search; +import com.github.catvod.crawler.Spider; +import com.github.catvod.net.OkHttp; +import com.google.gson.JsonParser; + +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Qile + */ +public class Jianpian extends Spider { + + private final String siteUrl = "http://api.ubj83.com"; + private String extend; + + private Map getHeader() { + Map headers = new HashMap<>(); + headers.put("user-agent", "Mozilla/5.0 (Linux; Android 11; Redmi K30 Pro Zoom Edition Build/RKQ1.200826.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/90.0.4430.210 Mobile Safari/537.36;webank/h5face;webank/1.0;netType:NETWORK_WIFI;appVersion:416;packageName:com.jp3.xg3"); + headers.put("accept", "application/json, text/plain, */*"); + headers.put("x-requested-with", "com.jp3.xg3"); + return headers; + } + + @Override + public void init(Context context, String extend) throws Exception { + this.extend = extend; + } + + @Override + public String homeContent(boolean filter) throws Exception { + List classes = new ArrayList<>(); + List typeIds = Arrays.asList("1", "2", "3", "4", "50", "99"); + List typeNames = Arrays.asList("電影", "電視劇", "動漫", "綜藝", "紀錄片", "Netflix"); + for (int i = 0; i < typeIds.size(); i++) classes.add(new Class(typeIds.get(i), typeNames.get(i))); + return Result.string(classes, JsonParser.parseString(OkHttp.string(extend))); + } + + @Override + public String homeVideoContent() { + List list = new ArrayList<>(); + String url = siteUrl + "/api/slide/list?pos_id=88"; + Resp resp = Resp.objectFrom(OkHttp.string(url, getHeader())); + for (Data data : resp.getData()) list.add(data.homeVod()); + return Result.string(list); + } + + @Override + public String categoryContent(String tid, String pg, boolean filter, HashMap extend) throws Exception { + if (tid.endsWith("/{pg}")) return searchContent(tid.split("/")[0], pg); + if (tid.equals("50") || tid.equals("99") || tid.equals("111")) { + List list = new ArrayList<>(); + String url = siteUrl + String.format("/api/dyTag/list?category_id=%s&page=%s", tid, pg); + Resp resp = Resp.objectFrom(OkHttp.string(url, getHeader())); + for (Data data : resp.getData()) for (Data dataList : data.getDataList()) list.add(dataList.vod()); + return Result.get().page().vod(list).string(); + } else { + List list = new ArrayList<>(); + HashMap ext = new HashMap<>(); + if (extend != null && !extend.isEmpty()) ext.putAll(extend); + String area = ext.get("area") == null ? "0" : ext.get("area"); + String year = ext.get("year") == null ? "0" : ext.get("year"); + String by = ext.get("by") == null ? "updata" : ext.get("by"); + String url = siteUrl + String.format("/api/crumb/list?fcate_pid=%s&area=%s&year=%s&type=0&sort=%s&page=%s&category_id=", tid, area, year, by, pg); + Resp resp = Resp.objectFrom(OkHttp.string(url, getHeader())); + for (Data data : resp.getData()) list.add(data.vod()); + return Result.string(list); + } + } + + @Override + public String detailContent(List ids) throws Exception { + String url = siteUrl + "/api/video/detailv2?id=" + ids.get(0); + Data data = Detail.objectFrom(OkHttp.string(url, getHeader())).getData(); + Vod vod = data.vod(); + vod.setVodPlayFrom(data.getVodFrom()); + vod.setVodYear(data.getYear()); + vod.setVodArea(data.getArea()); + vod.setTypeName(data.getTypes()); + vod.setVodActor(data.getActors()); + vod.setVodPlayUrl(data.getVodUrl()); + vod.setVodDirector(data.getDirectors()); + vod.setVodContent(data.getDescription()); + return Result.string(vod); + } + + @Override + public String playerContent(String flag, String id, List vipFlags) throws Exception { + return Result.get().url(id).header(getHeader()).string(); + } + + @Override + public String searchContent(String key, boolean quick) throws Exception { + return searchContent(key, "1"); + } + + @Override + public String searchContent(String key, boolean quick, String pg) throws Exception { + return searchContent(key, pg); + } + + public String searchContent(String key, String pg) throws Exception { + List list = new ArrayList<>(); + String url = siteUrl + String.format("/api/v2/search/videoV2?key=%s&category_id=88&page=%s&pageSize=20", URLEncoder.encode(key), pg); + Search search = Search.objectFrom(OkHttp.string(url, getHeader())); + for (Search data : search.getData()) list.add(data.vod()); + return Result.string(list); + } +} \ No newline at end of file diff --git a/jar/custom_spider.jar b/jar/custom_spider.jar index c260718..76d0e4e 100644 Binary files a/jar/custom_spider.jar and b/jar/custom_spider.jar differ diff --git a/jar/custom_spider.jar.md5 b/jar/custom_spider.jar.md5 index 77ac1e5..d510fb4 100644 --- a/jar/custom_spider.jar.md5 +++ b/jar/custom_spider.jar.md5 @@ -1 +1 @@ -796d0367c1378d9397c2aa967715c636 +eaaa2de0f1e4946be155e3130ef4fdf3 diff --git a/json/jianpian.json b/json/jianpian.json new file mode 100644 index 0000000..b2c5201 --- /dev/null +++ b/json/jianpian.json @@ -0,0 +1,426 @@ +{ + "1": [ + { + "key": "area", + "name": "地區", + "init": "1", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "国产", + "v": "1" + }, + { + "n": "中国香港", + "v": "3" + }, + { + "n": "中国台湾", + "v": "6" + }, + { + "n": "美国", + "v": "5" + }, + { + "n": "韩国", + "v": "18" + }, + { + "n": "日本", + "v": "2" + } + ] + }, + { + "key": "year", + "name": "年份", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "2025", + "v": "107" + }, + { + "n": "2024", + "v": "119" + }, + { + "n": "2023", + "v": "153" + }, + { + "n": "2022", + "v": "101" + }, + { + "n": "2021", + "v": "118" + }, + { + "n": "2020", + "v": "16" + }, + { + "n": "2019", + "v": "7" + }, + { + "n": "2018", + "v": "2" + }, + { + "n": "2017", + "v": "3" + }, + { + "n": "2016", + "v": "22" + } + ] + }, + { + "key": "by", + "name": "排序", + "init": "updata", + "value": [ + { + "n": "热门", + "v": "hot" + }, + { + "n": "更新", + "v": "updata" + }, + { + "n": "评分", + "v": "rating" + } + ] + } + ], + "2": [ + { + "key": "area", + "name": "地區", + "init": "1", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "国产", + "v": "1" + }, + { + "n": "中国香港", + "v": "3" + }, + { + "n": "中国台湾", + "v": "6" + }, + { + "n": "美国", + "v": "5" + }, + { + "n": "韩国", + "v": "18" + }, + { + "n": "日本", + "v": "2" + } + ] + }, + { + "key": "year", + "name": "年份", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "2025", + "v": "107" + }, + { + "n": "2024", + "v": "119" + }, + { + "n": "2023", + "v": "153" + }, + { + "n": "2022", + "v": "101" + }, + { + "n": "2021", + "v": "118" + }, + { + "n": "2020", + "v": "16" + }, + { + "n": "2019", + "v": "7" + }, + { + "n": "2018", + "v": "2" + }, + { + "n": "2017", + "v": "3" + }, + { + "n": "2016", + "v": "22" + } + ] + }, + { + "key": "by", + "name": "排序", + "init": "updata", + "value": [ + { + "n": "热门", + "v": "hot" + }, + { + "n": "更新", + "v": "updata" + }, + { + "n": "评分", + "v": "rating" + } + ] + } + ], + "3": [ + { + "key": "area", + "name": "地區", + "init": "1", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "国产", + "v": "1" + }, + { + "n": "中国香港", + "v": "3" + }, + { + "n": "中国台湾", + "v": "6" + }, + { + "n": "美国", + "v": "5" + }, + { + "n": "韩国", + "v": "18" + }, + { + "n": "日本", + "v": "2" + } + ] + }, + { + "key": "year", + "name": "年份", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "2025", + "v": "107" + }, + { + "n": "2024", + "v": "119" + }, + { + "n": "2023", + "v": "153" + }, + { + "n": "2022", + "v": "101" + }, + { + "n": "2021", + "v": "118" + }, + { + "n": "2020", + "v": "16" + }, + { + "n": "2019", + "v": "7" + }, + { + "n": "2018", + "v": "2" + }, + { + "n": "2017", + "v": "3" + }, + { + "n": "2016", + "v": "22" + } + ] + }, + { + "key": "by", + "name": "排序", + "init": "updata", + "value": [ + { + "n": "热门", + "v": "hot" + }, + { + "n": "更新", + "v": "updata" + }, + { + "n": "评分", + "v": "rating" + } + ] + } + ], + "4": [ + { + "key": "area", + "name": "地區", + "init": "1", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "国产", + "v": "1" + }, + { + "n": "中国香港", + "v": "3" + }, + { + "n": "中国台湾", + "v": "6" + }, + { + "n": "美国", + "v": "5" + }, + { + "n": "韩国", + "v": "18" + }, + { + "n": "日本", + "v": "2" + } + ] + }, + { + "key": "year", + "name": "年份", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "2025", + "v": "107" + }, + { + "n": "2024", + "v": "119" + }, + { + "n": "2023", + "v": "153" + }, + { + "n": "2022", + "v": "101" + }, + { + "n": "2021", + "v": "118" + }, + { + "n": "2020", + "v": "16" + }, + { + "n": "2019", + "v": "7" + }, + { + "n": "2018", + "v": "2" + }, + { + "n": "2017", + "v": "3" + }, + { + "n": "2016", + "v": "22" + } + ] + }, + { + "key": "by", + "name": "排序", + "init": "updata", + "value": [ + { + "n": "热门", + "v": "hot" + }, + { + "n": "更新", + "v": "updata" + }, + { + "n": "评分", + "v": "rating" + } + ] + } + ] +} \ No newline at end of file