Merge remote-tracking branch 'origin/main'
# Conflicts: # build.gradle # gradle/wrapper/gradle-wrapper.properties
This commit is contained in:
commit
c45f58cf10
|
|
@ -6,12 +6,18 @@ plugins {
|
|||
android {
|
||||
namespace 'com.github.catvod'
|
||||
|
||||
compileSdk 35
|
||||
compileSdk {
|
||||
version = release(36)
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.github.catvod.demo"
|
||||
minSdk 21
|
||||
targetSdk 35
|
||||
targetSdk 36
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
|
@ -28,8 +34,8 @@ android {
|
|||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
configurations.configureEach {
|
||||
|
|
@ -42,10 +48,9 @@ android {
|
|||
dependencies {
|
||||
implementation 'com.squareup.okhttp3:okhttp:' + okhttpVersion
|
||||
implementation 'com.github.thegrizzlylabs:sardine-android:0.9'
|
||||
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 'wang.harlon.quickjs:wrapper-android:3.2.3'
|
||||
implementation 'com.google.code.gson:gson:2.13.2'
|
||||
implementation 'com.hierynomus:smbj:0.14.0'
|
||||
implementation 'com.orhanobut:logger:2.2.0'
|
||||
implementation 'org.jsoup:jsoup:1.18.3'
|
||||
implementation 'org.jsoup:jsoup:1.21.2'
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
android:usesCleartextTraffic="true">
|
||||
|
||||
<activity
|
||||
android:name=".debug.MainActivity"
|
||||
android:name=".MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,142 @@
|
|||
package com.github.catvod;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.databinding.ActivityMainBinding;
|
||||
import com.github.catvod.spider.Init;
|
||||
import com.github.catvod.spider.PTT;
|
||||
import com.github.catvod.spider.Proxy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.orhanobut.logger.AndroidLogAdapter;
|
||||
import com.orhanobut.logger.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class MainActivity extends Activity {
|
||||
|
||||
private ActivityMainBinding binding;
|
||||
private ExecutorService executor;
|
||||
private Spider spider;
|
||||
private Gson gson;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
Logger.addLogAdapter(new AndroidLogAdapter());
|
||||
executor = Executors.newCachedThreadPool();
|
||||
executor.execute(this::initSpider);
|
||||
spider = new PTT();
|
||||
initView();
|
||||
initEvent();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
}
|
||||
|
||||
private void initEvent() {
|
||||
binding.home.setOnClickListener(view -> executor.execute(this::homeContent));
|
||||
binding.homeVideo.setOnClickListener(view -> executor.execute(this::homeVideoContent));
|
||||
binding.category.setOnClickListener(view -> executor.execute(this::categoryContent));
|
||||
binding.detail.setOnClickListener(view -> executor.execute(this::detailContent));
|
||||
binding.player.setOnClickListener(view -> executor.execute(this::playerContent));
|
||||
binding.search.setOnClickListener(view -> executor.execute(this::searchContent));
|
||||
binding.live.setOnClickListener(view -> executor.execute(this::liveContent));
|
||||
binding.proxy.setOnClickListener(view -> executor.execute(this::proxy));
|
||||
}
|
||||
|
||||
private void initSpider() {
|
||||
try {
|
||||
Init.init(getApplicationContext());
|
||||
spider.init(this, "");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void homeContent() {
|
||||
try {
|
||||
String result = gson.toJson(JsonParser.parseString(spider.homeContent(true)));
|
||||
Init.post(() -> binding.result.setText(result));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void homeVideoContent() {
|
||||
try {
|
||||
String result = gson.toJson(JsonParser.parseString(spider.homeVideoContent()));
|
||||
Init.post(() -> binding.result.setText(result));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void categoryContent() {
|
||||
try {
|
||||
HashMap<String, String> extend = new HashMap<>();
|
||||
extend.put("c", "19");
|
||||
extend.put("year", "2024");
|
||||
String result = gson.toJson(JsonParser.parseString(spider.categoryContent("3", "2", true, extend)));
|
||||
Init.post(() -> binding.result.setText(result));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void detailContent() {
|
||||
try {
|
||||
String result = gson.toJson(JsonParser.parseString(spider.detailContent(List.of("78702"))));
|
||||
Init.post(() -> binding.result.setText(result));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void playerContent() {
|
||||
try {
|
||||
String result = gson.toJson(JsonParser.parseString(spider.playerContent("", "382044/1/78", new ArrayList<>())));
|
||||
Init.post(() -> binding.result.setText(result));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void searchContent() {
|
||||
try {
|
||||
String result = gson.toJson(JsonParser.parseString(spider.searchContent("我的人间烟火", false)));
|
||||
Init.post(() -> binding.result.setText(result));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void liveContent() {
|
||||
try {
|
||||
String result = gson.toJson(JsonParser.parseString(spider.liveContent("")));
|
||||
Init.post(() -> binding.result.setText(result));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void proxy() {
|
||||
try {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
Logger.t("liveContent").d(Proxy.proxy(params));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -111,6 +111,10 @@ public class Item {
|
|||
}
|
||||
|
||||
public String getVodId(String id) {
|
||||
return id + "/" + getName();
|
||||
}
|
||||
|
||||
public String getVodPath(String id) {
|
||||
return id + getPath() + "/" + getName();
|
||||
}
|
||||
|
||||
|
|
@ -127,6 +131,6 @@ public class Item {
|
|||
}
|
||||
|
||||
public Vod getVod(Drive drive) {
|
||||
return new Vod(getVodId(drive.getName()), getName(), getPic(), drive.getName(), isFolder());
|
||||
return new Vod(getVodPath(drive.getName()), getName(), getPic(), drive.getName(), isFolder());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,16 @@ 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(value = "jump_id", alternate = "id")
|
||||
@SerializedName("jump_id")
|
||||
private String jumpId;
|
||||
@SerializedName("id")
|
||||
private String id;
|
||||
@SerializedName(value = "thumbnail", alternate = "path")
|
||||
private String thumbnail;
|
||||
@SerializedName("title")
|
||||
|
|
@ -24,24 +27,30 @@ public class Data {
|
|||
@SerializedName("playlist")
|
||||
private Value playlist;
|
||||
@SerializedName("year")
|
||||
private Value year;
|
||||
private String year;
|
||||
@SerializedName("area")
|
||||
private Value area;
|
||||
private String area;
|
||||
@SerializedName("types")
|
||||
private List<Value> types;
|
||||
@SerializedName("actors")
|
||||
private List<Value> actors;
|
||||
@SerializedName("directors")
|
||||
private List<Value> directors;
|
||||
@SerializedName("btbo_downlist")
|
||||
private List<BtboDown> btboDownlist;
|
||||
@SerializedName("source_list_source")
|
||||
private List<SourceListSource> source;
|
||||
@SerializedName("dataList")
|
||||
private List<Data> dataList;
|
||||
|
||||
public String getJumpId() {
|
||||
return TextUtils.isEmpty(jumpId) ? "" : jumpId;
|
||||
}
|
||||
|
||||
public String getThumbnail() {
|
||||
return TextUtils.isEmpty(thumbnail) ? "" : thumbnail + "@Referer=www.jianpianapp.com@User-Agent=jianpian-version362";
|
||||
public String getId() {
|
||||
return TextUtils.isEmpty(id) ? "" : id;
|
||||
}
|
||||
|
||||
public String getThumbnail(String imgDomain) {
|
||||
return TextUtils.isEmpty(thumbnail) ? "" : "http://" + imgDomain + thumbnail;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
|
|
@ -61,11 +70,11 @@ public class Data {
|
|||
}
|
||||
|
||||
public String getYear() {
|
||||
return year == null ? "" : year.getTitle();
|
||||
return year == null ? "" : year;
|
||||
}
|
||||
|
||||
public String getArea() {
|
||||
return area == null ? "" : area.getTitle();
|
||||
return area == null ? "" : area;
|
||||
}
|
||||
|
||||
public String getTypes() {
|
||||
|
|
@ -80,12 +89,20 @@ public class Data {
|
|||
return directors == null ? "" : getValues(directors, true);
|
||||
}
|
||||
|
||||
public List<BtboDown> getBtboDownlist() {
|
||||
return btboDownlist == null ? Collections.emptyList() : btboDownlist;
|
||||
public List<SourceListSource> getSource() {
|
||||
return source == null ? Collections.emptyList() : source;
|
||||
}
|
||||
|
||||
public Vod vod() {
|
||||
return new Vod(getJumpId(), getTitle(), getThumbnail(), getMask());
|
||||
public List<Data> getDataList() {
|
||||
return dataList == null ? Collections.emptyList() : dataList;
|
||||
}
|
||||
|
||||
public Vod homeVod(String imgDomain) {
|
||||
return new Vod(getJumpId(), getTitle(), getThumbnail(imgDomain));
|
||||
}
|
||||
|
||||
public Vod vod(String imgDomain) {
|
||||
return new Vod(getId(), getTitle(), getThumbnail(imgDomain), getMask());
|
||||
}
|
||||
|
||||
public String getValues(List<Value> items, boolean link) {
|
||||
|
|
@ -94,12 +111,6 @@ public class Data {
|
|||
return Util.substring(sb.toString());
|
||||
}
|
||||
|
||||
public String getPlayUrl() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (BtboDown value : getBtboDownlist()) sb.append(value.getVal()).append("#");
|
||||
return Util.substring(sb.toString());
|
||||
}
|
||||
|
||||
public static class Value {
|
||||
|
||||
@SerializedName(value = "title", alternate = "name")
|
||||
|
|
@ -118,13 +129,51 @@ public class Data {
|
|||
}
|
||||
}
|
||||
|
||||
public static class BtboDown {
|
||||
public static class SourceListSource {
|
||||
|
||||
@SerializedName("val")
|
||||
private String val;
|
||||
@SerializedName("name")
|
||||
private String name;
|
||||
@SerializedName("source_list")
|
||||
private List<SourceList> list;
|
||||
|
||||
public String getVal() {
|
||||
return TextUtils.isEmpty(val) ? "" : val.replaceAll("ftp", "tvbox-xg:ftp");
|
||||
public String getName() {
|
||||
return TextUtils.isEmpty(name) ? "" : name;
|
||||
}
|
||||
|
||||
public List<SourceList> 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<String> items = new ArrayList<>();
|
||||
for (SourceListSource source : getSource()) items.add(source.getName());
|
||||
return TextUtils.join("$$$", items);
|
||||
}
|
||||
|
||||
public String getVodUrl() {
|
||||
List<String> items = new ArrayList<>();
|
||||
for (SourceListSource source : getSource()) {
|
||||
List<String> urls = new ArrayList<>();
|
||||
for (SourceList item : source.getList()) urls.add(item.getName() + "$" + item.getUrl());
|
||||
items.add(TextUtils.join("#", urls));
|
||||
}
|
||||
return TextUtils.join("$$$", items);
|
||||
}
|
||||
}
|
||||
|
|
@ -15,4 +15,4 @@ public class Detail {
|
|||
public Data getData() {
|
||||
return data == null ? new Data() : data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,4 +18,4 @@ public class Resp {
|
|||
public List<Data> getData() {
|
||||
return data == null ? Collections.emptyList() : data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Search> 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(String imgDomain) {
|
||||
return TextUtils.isEmpty(thumbnail) ? "" : "http://" + imgDomain + thumbnail;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return TextUtils.isEmpty(title) ? "" : title;
|
||||
}
|
||||
|
||||
public String getMask() {
|
||||
return TextUtils.isEmpty(mask) ? "" : mask;
|
||||
}
|
||||
|
||||
public Vod vod(String imgDomain) {
|
||||
return new Vod(getId(), getTitle(), getThumbnail(imgDomain), getMask());
|
||||
}
|
||||
|
||||
public List<Search> getData() {
|
||||
return data == null ? Collections.emptyList() : data;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
package com.github.catvod.bean.mqitv;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Config {
|
||||
|
||||
@SerializedName("name")
|
||||
private String name;
|
||||
@SerializedName("url")
|
||||
private String url;
|
||||
|
||||
private List<User> users;
|
||||
private List<Data> data;
|
||||
private Uri uri;
|
||||
|
||||
public static List<Config> arrayFrom(String str) {
|
||||
Type listType = new TypeToken<List<Config>>() {}.getType();
|
||||
return new Gson().fromJson(str, listType);
|
||||
}
|
||||
|
||||
public Config(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name == null ? "" : name;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url == null ? "" : url;
|
||||
}
|
||||
|
||||
public List<User> getUsers() {
|
||||
return users = users == null ? new ArrayList<>() : users;
|
||||
}
|
||||
|
||||
public List<Data> getData() {
|
||||
return data = data == null ? Data.objectFrom(OkHttp.string(getApi(), 3000)).getData() : data;
|
||||
}
|
||||
|
||||
public Uri getUri() {
|
||||
return uri = uri == null ? Uri.parse(getUrl()) : uri;
|
||||
}
|
||||
|
||||
public String getApi() {
|
||||
return getUrl() + "/api/post?item=itv_traffic";
|
||||
}
|
||||
|
||||
public String getPlayUrl(String port, String playing) {
|
||||
return "http://" + getUri().getHost() + ":" + port + "/" + playing.replace(":/", "");
|
||||
}
|
||||
|
||||
public void loadUser() {
|
||||
Pattern userPattern = Pattern.compile(".*?([0-9a-zA-Z]{11,}).*", Pattern.CASE_INSENSITIVE);
|
||||
Pattern macPattern = Pattern.compile(".*?(([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}).*", Pattern.CASE_INSENSITIVE);
|
||||
for (Data item : getData()) {
|
||||
for (String userIp : item.getStat().getUserIpList()) {
|
||||
if (getUsers().size() >= 5) continue;
|
||||
Matcher userMatcher = userPattern.matcher(userIp);
|
||||
Matcher macMatcher = macPattern.matcher(userIp);
|
||||
String user = userMatcher.matches() ? userMatcher.group(1) : "";
|
||||
String mac = macMatcher.matches() ? macMatcher.group(1) : "";
|
||||
if (!user.isEmpty() && !mac.isEmpty()) {
|
||||
User u = new User(user, mac).getToken(getUrl());
|
||||
if (!u.getToken().isEmpty()) getUsers().add(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
if (getUsers().isEmpty()) loadUser();
|
||||
return getUsers().isEmpty() ? new User("", "") : getUsers().get(ThreadLocalRandom.current().nextInt(getUsers().size()));
|
||||
}
|
||||
|
||||
public String getAuth(String id, String token) {
|
||||
String data = OkHttp.string(getUrl() + "/ualive?cid=" + id + "&token=" + token);
|
||||
Matcher matcher = Pattern.compile("\"Reason\":\"(.*?)\"", Pattern.CASE_INSENSITIVE).matcher(data);
|
||||
if (matcher.find()) return matcher.group(1);
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getM3U8(String id, String token, String port) {
|
||||
String base = "http://" + getUri().getHost() + ":" + port + "/";
|
||||
String m3u8 = OkHttp.string(base + id + ".m3u8?token=" + token);
|
||||
if (m3u8.isEmpty() || m3u8.contains("\"Reason\"")) return "";
|
||||
String[] lines = m3u8.split("\\r?\\n");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String line : lines) {
|
||||
if (!line.startsWith("#") && !line.startsWith("http")) line = base + line;
|
||||
sb.append(line).append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.data.clear();
|
||||
this.users.clear();
|
||||
this.data = null;
|
||||
this.users = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof Config)) return false;
|
||||
Config it = (Config) obj;
|
||||
return getUrl().equals(it.getUrl());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package com.github.catvod.bean.mqitv;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Data {
|
||||
|
||||
@SerializedName("data")
|
||||
private List<Data> data;
|
||||
@SerializedName("id")
|
||||
private String id;
|
||||
@SerializedName("name")
|
||||
private String name;
|
||||
@SerializedName("playing")
|
||||
private String playing;
|
||||
@SerializedName("port")
|
||||
private String port;
|
||||
@SerializedName("stat")
|
||||
private Stat stat;
|
||||
|
||||
public static Data objectFrom(String str) {
|
||||
try {
|
||||
Data data = new Gson().fromJson(str, Data.class);
|
||||
return data == null ? new Data() : data;
|
||||
} catch (Exception e) {
|
||||
return new Data();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Data> getData() {
|
||||
return data == null ? Collections.emptyList() : data;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id == null ? "" : id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name == null ? "" : name;
|
||||
}
|
||||
|
||||
public String getPort() {
|
||||
return port == null ? "" : port;
|
||||
}
|
||||
|
||||
public String getPlaying() {
|
||||
return playing == null ? "" : playing;
|
||||
}
|
||||
|
||||
public Stat getStat() {
|
||||
return stat == null ? new Stat() : stat;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.github.catvod.bean.mqitv;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Stat {
|
||||
|
||||
@SerializedName("UserIpList")
|
||||
private List<String> userIpList;
|
||||
|
||||
public List<String> getUserIpList() {
|
||||
return userIpList == null ? Collections.emptyList() : userIpList;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.github.catvod.bean.mqitv;
|
||||
|
||||
import com.github.catvod.net.OkHttp;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class User {
|
||||
|
||||
private String id;
|
||||
private String mac;
|
||||
private String token;
|
||||
|
||||
public User(String id, String mac) {
|
||||
this.id = id;
|
||||
this.mac = mac;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getMac() {
|
||||
return mac;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token == null ? "" : token;
|
||||
}
|
||||
|
||||
public User getToken(String url) {
|
||||
String result = OkHttp.string(String.format(Locale.getDefault(), "%s/HSAndroidLogin.ecgi?ty=json&net_account=%s&mac_address1=%s&_=%d", url, getId(), getMac(), System.currentTimeMillis()));
|
||||
Pattern pattern = Pattern.compile("\"Token\"\\s*:\\s*\"(.*?)\"", Pattern.CASE_INSENSITIVE);
|
||||
Matcher matcher = pattern.matcher(result);
|
||||
token = matcher.find() ? matcher.group(1) : "";
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,695 +0,0 @@
|
|||
package com.github.catvod.bean.xpath;
|
||||
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Rule {
|
||||
/**
|
||||
* user-agent
|
||||
*/
|
||||
private String ua;
|
||||
/**
|
||||
* 取得分類和首頁推薦的Url
|
||||
*/
|
||||
private String homeUrl;
|
||||
/**
|
||||
* 分類節點 xpath
|
||||
*/
|
||||
private String cateNode;
|
||||
/**
|
||||
* 分類節點名 xpath
|
||||
*/
|
||||
private String cateName;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern cateNameR;
|
||||
/**
|
||||
* 分類節點 id xpath
|
||||
*/
|
||||
private String cateId;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern cateIdR;
|
||||
/**
|
||||
* 手動指定分類如果有則不從 homeUrl 中獲取分類
|
||||
*/
|
||||
private final LinkedHashMap<String, String> cateManual = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* 篩選
|
||||
*/
|
||||
private JSONObject filter;
|
||||
|
||||
/**
|
||||
* 更新推薦影片節點 xpath
|
||||
*/
|
||||
private String homeVodNode;
|
||||
/**
|
||||
* 更新推薦影片名稱 xpath
|
||||
*/
|
||||
private String homeVodName;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern homeVodNameR;
|
||||
/**
|
||||
* 更新推薦影片 id xpath
|
||||
*/
|
||||
private String homeVodId;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern homeVodIdR;
|
||||
/**
|
||||
* 更新推薦影片圖片 xpath
|
||||
*/
|
||||
private String homeVodImg;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern homeVodImgR;
|
||||
/**
|
||||
* 更新推薦影片簡介 xpath
|
||||
*/
|
||||
private String homeVodMark;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern homeVodMarkR;
|
||||
/**
|
||||
* 分類頁地址
|
||||
*/
|
||||
private String cateUrl;
|
||||
/**
|
||||
* 分類頁影片節點 xpath
|
||||
*/
|
||||
private String cateVodNode;
|
||||
/**
|
||||
* 分類頁影片名稱 xpath
|
||||
*/
|
||||
private String cateVodName;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern cateVodNameR;
|
||||
/**
|
||||
* 分類頁影片影片id xpath
|
||||
*/
|
||||
private String cateVodId;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern cateVodIdR;
|
||||
/**
|
||||
* 分類頁影片影片圖片 xpath
|
||||
*/
|
||||
private String cateVodImg;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern cateVodImgR;
|
||||
/**
|
||||
* 分類頁影片影片簡介 xpath
|
||||
*/
|
||||
private String cateVodMark;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern cateVodMarkR;
|
||||
|
||||
/**
|
||||
* 詳情頁面
|
||||
*/
|
||||
private String dtUrl;
|
||||
/**
|
||||
* 詳情節點 xpath
|
||||
*/
|
||||
private String dtNode;
|
||||
/**
|
||||
* 詳情影片 xpath
|
||||
*/
|
||||
private String dtName;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern dtNameR;
|
||||
/**
|
||||
* 詳情影片圖片 xpath
|
||||
*/
|
||||
private String dtImg;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern dtImgR;
|
||||
/**
|
||||
* 詳情影片分類 xpath
|
||||
*/
|
||||
private String dtCate;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern dtCateR;
|
||||
/**
|
||||
* 詳情影片年份 xpath
|
||||
*/
|
||||
private String dtYear;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern dtYearR;
|
||||
/**
|
||||
* 詳情影片地區 xpath
|
||||
*/
|
||||
private String dtArea;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern dtAreaR;
|
||||
/**
|
||||
* 詳情影片簡介 xpath
|
||||
*/
|
||||
private String dtMark;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern dtMarkR;
|
||||
/**
|
||||
* 詳情演員 xpath
|
||||
*/
|
||||
private String dtActor;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern dtActorR;
|
||||
/**
|
||||
* 詳情導演 xpath
|
||||
*/
|
||||
private String dtDirector;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern dtDirectorR;
|
||||
/**
|
||||
* 詳情說明 xpath
|
||||
*/
|
||||
private String dtDesc;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern dtDescR;
|
||||
|
||||
/**
|
||||
* 詳情播放來源節點
|
||||
*/
|
||||
private String dtFromNode;
|
||||
/**
|
||||
* 詳情播放來源名稱 xpath
|
||||
*/
|
||||
private String dtFromName;
|
||||
/**
|
||||
* 詳情
|
||||
*/
|
||||
private Pattern dtFromNameR;
|
||||
/**
|
||||
* 詳情播放地址列表節點 xpath
|
||||
*/
|
||||
private String dtUrlNode;
|
||||
/**
|
||||
* 詳情播放地址節點 xpath
|
||||
*/
|
||||
private String dtUrlSubNode;
|
||||
/**
|
||||
* 詳情播放地址id xpath
|
||||
*/
|
||||
private String dtUrlId;
|
||||
/**
|
||||
* 詳情
|
||||
*/
|
||||
private Pattern dtUrlIdR;
|
||||
/**
|
||||
* 詳情播放地址名稱 xpath
|
||||
*/
|
||||
private String dtUrlName;
|
||||
/**
|
||||
* 詳情
|
||||
*/
|
||||
private Pattern dtUrlNameR;
|
||||
/**
|
||||
* 播放頁面url
|
||||
*/
|
||||
private String playUrl;
|
||||
/**
|
||||
* 播放解析調用ua
|
||||
*/
|
||||
private String playUa;
|
||||
/**
|
||||
* 播放解析調用referer
|
||||
*/
|
||||
private String playReferer;
|
||||
|
||||
/**
|
||||
* 搜尋頁地址
|
||||
*/
|
||||
private String searchUrl;
|
||||
|
||||
/**
|
||||
* 搜尋頁影片節點 xpath
|
||||
*/
|
||||
private String scVodNode;
|
||||
/**
|
||||
* 搜尋頁影片名稱 xpath
|
||||
*/
|
||||
private String scVodName;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern scVodNameR;
|
||||
/**
|
||||
* 搜尋頁影片id xpath
|
||||
*/
|
||||
private String scVodId;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern scVodIdR;
|
||||
/**
|
||||
* 搜尋頁影片圖片 xpath
|
||||
*/
|
||||
private String scVodImg;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern scVodImgR;
|
||||
/**
|
||||
* 搜尋頁影片簡介 xpath
|
||||
*/
|
||||
private String scVodMark;
|
||||
/**
|
||||
* 正則對取到的數據進行二次處理
|
||||
*/
|
||||
private Pattern scVodMarkR;
|
||||
|
||||
private static Pattern getPattern(JSONObject json, String key) {
|
||||
String v = json.optString(key).trim();
|
||||
if (v.isEmpty())
|
||||
return null;
|
||||
else {
|
||||
try {
|
||||
return Pattern.compile(v);
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String doReplaceRegex(Pattern pattern, String src) {
|
||||
if (pattern == null)
|
||||
return src;
|
||||
try {
|
||||
Matcher matcher = pattern.matcher(src);
|
||||
if (matcher.find()) {
|
||||
return matcher.group(1).trim();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
return src;
|
||||
}
|
||||
|
||||
public static Rule fromJson(String json) {
|
||||
try {
|
||||
JSONObject jsonObj = new JSONObject(json);
|
||||
Rule rule = new Rule();
|
||||
rule.ua = jsonObj.optString("ua");
|
||||
rule.homeUrl = jsonObj.optString("homeUrl").trim();
|
||||
rule.cateNode = jsonObj.optString("cateNode").trim();
|
||||
rule.cateName = jsonObj.optString("cateName").trim();
|
||||
rule.cateNameR = getPattern(jsonObj, "cateNameR");
|
||||
rule.cateId = jsonObj.optString("cateId").trim();
|
||||
rule.cateIdR = getPattern(jsonObj, "cateIdR");
|
||||
JSONObject navs = jsonObj.optJSONObject("cateManual");
|
||||
if (navs != null) {
|
||||
Iterator<String> keys = navs.keys();
|
||||
while (keys.hasNext()) {
|
||||
String name = keys.next();
|
||||
rule.cateManual.put(name.trim(), navs.getString(name).trim());
|
||||
}
|
||||
}
|
||||
rule.filter = jsonObj.optJSONObject("filter");
|
||||
rule.homeVodNode = jsonObj.optString("homeVodNode").trim();
|
||||
rule.homeVodName = jsonObj.optString("homeVodName").trim();
|
||||
rule.homeVodNameR = getPattern(jsonObj, "homeVodNameR");
|
||||
rule.homeVodId = jsonObj.optString("homeVodId").trim();
|
||||
rule.homeVodIdR = getPattern(jsonObj, "homeVodIdR");
|
||||
rule.homeVodImg = jsonObj.optString("homeVodImg").trim();
|
||||
rule.homeVodImgR = getPattern(jsonObj, "homeVodImgR");
|
||||
rule.homeVodMark = jsonObj.optString("homeVodMark").trim();
|
||||
rule.homeVodMarkR = getPattern(jsonObj, "homeVodMarkR");
|
||||
rule.cateUrl = jsonObj.optString("cateUrl").trim();
|
||||
rule.cateVodNode = jsonObj.optString("cateVodNode").trim();
|
||||
rule.cateVodName = jsonObj.optString("cateVodName").trim();
|
||||
rule.cateVodNameR = getPattern(jsonObj, "cateVodNameR");
|
||||
rule.cateVodId = jsonObj.optString("cateVodId").trim();
|
||||
rule.cateVodIdR = getPattern(jsonObj, "cateVodIdR");
|
||||
rule.cateVodImg = jsonObj.optString("cateVodImg").trim();
|
||||
rule.cateVodImgR = getPattern(jsonObj, "cateVodImgR");
|
||||
rule.cateVodMark = jsonObj.optString("cateVodMark").trim();
|
||||
rule.cateVodMarkR = getPattern(jsonObj, "cateVodMarkR");
|
||||
rule.dtUrl = jsonObj.optString("dtUrl");
|
||||
rule.dtNode = jsonObj.optString("dtNode");
|
||||
rule.dtName = jsonObj.optString("dtName");
|
||||
rule.dtNameR = getPattern(jsonObj, "dtNameR");
|
||||
rule.dtImg = jsonObj.optString("dtImg");
|
||||
rule.dtImgR = getPattern(jsonObj, "dtImgR");
|
||||
rule.dtCate = jsonObj.optString("dtCate");
|
||||
rule.dtCateR = getPattern(jsonObj, "dtCateR");
|
||||
rule.dtYear = jsonObj.optString("dtYear");
|
||||
rule.dtYearR = getPattern(jsonObj, "dtYearR");
|
||||
rule.dtArea = jsonObj.optString("dtArea");
|
||||
rule.dtAreaR = getPattern(jsonObj, "dtAreaR");
|
||||
rule.dtMark = jsonObj.optString("dtMark");
|
||||
rule.dtMarkR = getPattern(jsonObj, "dtMarkR");
|
||||
rule.dtActor = jsonObj.optString("dtActor");
|
||||
rule.dtActorR = getPattern(jsonObj, "dtActorR");
|
||||
rule.dtDirector = jsonObj.optString("dtDirector");
|
||||
rule.dtDirectorR = getPattern(jsonObj, "dtDirectorR");
|
||||
rule.dtDesc = jsonObj.optString("dtDesc");
|
||||
rule.dtDescR = getPattern(jsonObj, "dtDescR");
|
||||
rule.dtFromNode = jsonObj.optString("dtFromNode");
|
||||
rule.dtFromName = jsonObj.optString("dtFromName");
|
||||
rule.dtFromNameR = getPattern(jsonObj, "dtFromNameR");
|
||||
rule.dtUrlNode = jsonObj.optString("dtUrlNode");
|
||||
rule.dtUrlSubNode = jsonObj.optString("dtUrlSubNode");
|
||||
rule.dtUrlId = jsonObj.optString("dtUrlId");
|
||||
rule.dtUrlIdR = getPattern(jsonObj, "dtUrlIdR");
|
||||
rule.dtUrlName = jsonObj.optString("dtUrlName");
|
||||
rule.dtUrlNameR = getPattern(jsonObj, "dtUrlNameR");
|
||||
rule.playUrl = jsonObj.optString("playUrl");
|
||||
rule.playUa = jsonObj.optString("playUa");
|
||||
rule.playReferer = jsonObj.optString("playReferer");
|
||||
rule.searchUrl = jsonObj.optString("searchUrl");
|
||||
rule.scVodNode = jsonObj.optString("scVodNode").trim();
|
||||
rule.scVodName = jsonObj.optString("scVodName").trim();
|
||||
rule.scVodNameR = getPattern(jsonObj, "scVodNameR");
|
||||
rule.scVodId = jsonObj.optString("scVodId").trim();
|
||||
rule.scVodIdR = getPattern(jsonObj, "scVodIdR");
|
||||
rule.scVodImg = jsonObj.optString("scVodImg").trim();
|
||||
rule.scVodImgR = getPattern(jsonObj, "scVodImgR");
|
||||
rule.scVodMark = jsonObj.optString("scVodMark").trim();
|
||||
rule.scVodMarkR = getPattern(jsonObj, "scVodMarkR");
|
||||
return rule;
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getUa() {
|
||||
return ua;
|
||||
}
|
||||
|
||||
public String getHomeUrl() {
|
||||
return homeUrl;
|
||||
}
|
||||
|
||||
public String getCateNode() {
|
||||
return cateNode;
|
||||
}
|
||||
|
||||
public String getCateName() {
|
||||
return cateName;
|
||||
}
|
||||
|
||||
public String getCateNameR(String src) {
|
||||
return doReplaceRegex(cateNameR, src);
|
||||
}
|
||||
|
||||
public String getCateId() {
|
||||
return cateId;
|
||||
}
|
||||
|
||||
public String getCateIdR(String src) {
|
||||
return doReplaceRegex(cateIdR, src);
|
||||
}
|
||||
|
||||
public LinkedHashMap<String, String> getCateManual() {
|
||||
return cateManual;
|
||||
}
|
||||
|
||||
public JSONObject getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
public String getHomeVodNode() {
|
||||
return homeVodNode;
|
||||
}
|
||||
|
||||
public String getHomeVodName() {
|
||||
return homeVodName;
|
||||
}
|
||||
|
||||
public String getHomeVodNameR(String src) {
|
||||
return doReplaceRegex(homeVodNameR, src);
|
||||
}
|
||||
|
||||
public String getHomeVodId() {
|
||||
return homeVodId;
|
||||
}
|
||||
|
||||
public String getHomeVodIdR(String src) {
|
||||
return doReplaceRegex(homeVodIdR, src);
|
||||
}
|
||||
|
||||
public String getHomeVodImg() {
|
||||
return homeVodImg;
|
||||
}
|
||||
|
||||
public String getHomeVodImgR(String src) {
|
||||
return doReplaceRegex(homeVodImgR, src);
|
||||
}
|
||||
|
||||
public String getHomeVodMark() {
|
||||
return homeVodMark;
|
||||
}
|
||||
|
||||
public String getHomeVodMarkR(String src) {
|
||||
return doReplaceRegex(homeVodMarkR, src);
|
||||
}
|
||||
|
||||
public String getCateUrl() {
|
||||
return cateUrl;
|
||||
}
|
||||
|
||||
public String getCateVodNode() {
|
||||
return cateVodNode;
|
||||
}
|
||||
|
||||
public String getCateVodName() {
|
||||
return cateVodName;
|
||||
}
|
||||
|
||||
public String getCateVodNameR(String src) {
|
||||
return doReplaceRegex(cateVodNameR, src);
|
||||
}
|
||||
|
||||
public String getCateVodId() {
|
||||
return cateVodId;
|
||||
}
|
||||
|
||||
public String getCateVodIdR(String src) {
|
||||
return doReplaceRegex(cateVodIdR, src);
|
||||
}
|
||||
|
||||
public String getCateVodImg() {
|
||||
return cateVodImg;
|
||||
}
|
||||
|
||||
public String getCateVodImgR(String src) {
|
||||
return doReplaceRegex(cateVodImgR, src);
|
||||
}
|
||||
|
||||
public String getCateVodMark() {
|
||||
return cateVodMark;
|
||||
}
|
||||
|
||||
public String getCateVodMarkR(String src) {
|
||||
return doReplaceRegex(cateVodNameR, src);
|
||||
}
|
||||
|
||||
public String getDetailUrl() {
|
||||
return dtUrl;
|
||||
}
|
||||
|
||||
public String getDetailNode() {
|
||||
return dtNode;
|
||||
}
|
||||
|
||||
public String getDetailName() {
|
||||
return dtName;
|
||||
}
|
||||
|
||||
public String getDetailNameR(String src) {
|
||||
return doReplaceRegex(dtNameR, src);
|
||||
}
|
||||
|
||||
public String getDetailImg() {
|
||||
return dtImg;
|
||||
}
|
||||
|
||||
public String getDetailImgR(String src) {
|
||||
return doReplaceRegex(dtImgR, src);
|
||||
}
|
||||
|
||||
public String getDetailCate() {
|
||||
return dtCate;
|
||||
}
|
||||
|
||||
public String getDetailCateR(String src) {
|
||||
return doReplaceRegex(dtCateR, src);
|
||||
}
|
||||
|
||||
public String getDetailYear() {
|
||||
return dtYear;
|
||||
}
|
||||
|
||||
public String getDetailYearR(String src) {
|
||||
return doReplaceRegex(dtYearR, src);
|
||||
}
|
||||
|
||||
public String getDetailArea() {
|
||||
return dtArea;
|
||||
}
|
||||
|
||||
public String getDetailAreaR(String src) {
|
||||
return doReplaceRegex(dtAreaR, src);
|
||||
}
|
||||
|
||||
public String getDetailMark() {
|
||||
return dtMark;
|
||||
}
|
||||
|
||||
public String getDetailMarkR(String src) {
|
||||
return doReplaceRegex(dtMarkR, src);
|
||||
}
|
||||
|
||||
public String getDetailActor() {
|
||||
return dtActor;
|
||||
}
|
||||
|
||||
public String getDetailActorR(String src) {
|
||||
return doReplaceRegex(dtActorR, src);
|
||||
}
|
||||
|
||||
public String getDetailDirector() {
|
||||
return dtDirector;
|
||||
}
|
||||
|
||||
public String getDetailDirectorR(String src) {
|
||||
return doReplaceRegex(dtDirectorR, src);
|
||||
}
|
||||
|
||||
public String getDetailDesc() {
|
||||
return dtDesc;
|
||||
}
|
||||
|
||||
public String getDetailDescR(String src) {
|
||||
return doReplaceRegex(dtDescR, src);
|
||||
}
|
||||
|
||||
public String getDetailFromNode() {
|
||||
return dtFromNode;
|
||||
}
|
||||
|
||||
public String getDetailFromName() {
|
||||
return dtFromName;
|
||||
}
|
||||
|
||||
public String getDetailFromNameR(String src) {
|
||||
return doReplaceRegex(dtFromNameR, src);
|
||||
}
|
||||
|
||||
public String getDetailUrlNode() {
|
||||
return dtUrlNode;
|
||||
}
|
||||
|
||||
public String getDetailUrlSubNode() {
|
||||
return dtUrlSubNode;
|
||||
}
|
||||
|
||||
public String getDetailUrlId() {
|
||||
return dtUrlId;
|
||||
}
|
||||
|
||||
public String getDetailUrlIdR(String src) {
|
||||
return doReplaceRegex(dtUrlIdR, src);
|
||||
}
|
||||
|
||||
public String getDetailUrlName() {
|
||||
return dtUrlName;
|
||||
}
|
||||
|
||||
public String getDetailUrlNameR(String src) {
|
||||
return doReplaceRegex(dtUrlNameR, src);
|
||||
}
|
||||
|
||||
public String getPlayUrl() {
|
||||
return playUrl;
|
||||
}
|
||||
|
||||
public String getPlayUa() {
|
||||
return playUa;
|
||||
}
|
||||
|
||||
public String getPlayReferer() {
|
||||
return playReferer;
|
||||
}
|
||||
|
||||
public String getSearchUrl() {
|
||||
return searchUrl;
|
||||
}
|
||||
|
||||
public String getSearchVodNode() {
|
||||
return scVodNode;
|
||||
}
|
||||
|
||||
public String getSearchVodName() {
|
||||
return scVodName;
|
||||
}
|
||||
|
||||
public String getSearchVodNameR(String src) {
|
||||
return doReplaceRegex(scVodNameR, src);
|
||||
}
|
||||
|
||||
public String getSearchVodId() {
|
||||
return scVodId;
|
||||
}
|
||||
|
||||
public String getSearchVodIdR(String src) {
|
||||
return doReplaceRegex(scVodIdR, src);
|
||||
}
|
||||
|
||||
public String getSearchVodImg() {
|
||||
return scVodImg;
|
||||
}
|
||||
|
||||
public String getSearchVodImgR(String src) {
|
||||
return doReplaceRegex(scVodImgR, src);
|
||||
}
|
||||
|
||||
public String getSearchVodMark() {
|
||||
return scVodMark;
|
||||
}
|
||||
|
||||
public String getSearchVodMarkR(String src) {
|
||||
return doReplaceRegex(scVodMarkR, src);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
package com.github.catvod.debug;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
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.PTT;
|
||||
import com.orhanobut.logger.AndroidLogAdapter;
|
||||
import com.orhanobut.logger.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class MainActivity extends Activity {
|
||||
|
||||
private ExecutorService executor;
|
||||
private Spider spider;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
Button homeContent = findViewById(R.id.homeContent);
|
||||
Button homeVideoContent = findViewById(R.id.homeVideoContent);
|
||||
Button categoryContent = findViewById(R.id.categoryContent);
|
||||
Button detailContent = findViewById(R.id.detailContent);
|
||||
Button playerContent = findViewById(R.id.playerContent);
|
||||
Button searchContent = findViewById(R.id.searchContent);
|
||||
homeContent.setOnClickListener(view -> executor.execute(this::homeContent));
|
||||
homeVideoContent.setOnClickListener(view -> executor.execute(this::homeVideoContent));
|
||||
categoryContent.setOnClickListener(view -> executor.execute(this::categoryContent));
|
||||
detailContent.setOnClickListener(view -> executor.execute(this::detailContent));
|
||||
playerContent.setOnClickListener(view -> executor.execute(this::playerContent));
|
||||
searchContent.setOnClickListener(view -> executor.execute(this::searchContent));
|
||||
Logger.addLogAdapter(new AndroidLogAdapter());
|
||||
executor = Executors.newCachedThreadPool();
|
||||
executor.execute(this::initSpider);
|
||||
}
|
||||
|
||||
private void initSpider() {
|
||||
try {
|
||||
Init.init(getApplicationContext());
|
||||
spider = new PTT();
|
||||
spider.init(this, "");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void homeContent() {
|
||||
try {
|
||||
Logger.t("homeContent").d(spider.homeContent(true));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void homeVideoContent() {
|
||||
try {
|
||||
Logger.t("homeVideoContent").d(spider.homeVideoContent());
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void categoryContent() {
|
||||
try {
|
||||
HashMap<String, String> extend = new HashMap<>();
|
||||
extend.put("c", "19");
|
||||
extend.put("year", "2024");
|
||||
Logger.t("categoryContent").d(spider.categoryContent("3", "2", true, extend));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void detailContent() {
|
||||
try {
|
||||
Logger.t("detailContent").d(spider.detailContent(Arrays.asList("78702")));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void playerContent() {
|
||||
try {
|
||||
Logger.t("playerContent").d(spider.playerContent("", "382044/1/78", new ArrayList<>()));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void searchContent() {
|
||||
try {
|
||||
Logger.t("searchContent").d(spider.searchContent("我的人间烟火", false));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.github.catvod.js;
|
||||
|
||||
import com.github.catvod.js.utils.Parser;
|
||||
import com.github.catvod.js.utils.JSUtil;
|
||||
import com.github.catvod.js.utils.Parser;
|
||||
import com.whl.quickjs.wrapper.JSArray;
|
||||
import com.whl.quickjs.wrapper.JSMethod;
|
||||
import com.whl.quickjs.wrapper.QuickJSContext;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import okhttp3.Response;
|
|||
|
||||
public class OkHttp {
|
||||
|
||||
private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(15);
|
||||
|
||||
public static final String POST = "POST";
|
||||
public static final String GET = "GET";
|
||||
|
||||
|
|
@ -37,28 +39,28 @@ public class OkHttp {
|
|||
return Loader.INSTANCE;
|
||||
}
|
||||
|
||||
public static Response newCall(Request request) throws IOException {
|
||||
return client().newCall(request).execute();
|
||||
}
|
||||
|
||||
public static Response newCall(String url) throws IOException {
|
||||
return client().newCall(new Request.Builder().url(url).build()).execute();
|
||||
}
|
||||
|
||||
public static Response newCall(String url, Map<String, String> header) throws IOException {
|
||||
return client().newCall(new Request.Builder().url(url).headers(Headers.of(header)).build()).execute();
|
||||
}
|
||||
|
||||
public static String string(String url) {
|
||||
return string(url, null);
|
||||
}
|
||||
|
||||
public static String string(String url, long timeout) {
|
||||
return string(url, null, null, timeout);
|
||||
}
|
||||
|
||||
public static String string(String url, Map<String, String> header) {
|
||||
return string(url, null, header);
|
||||
}
|
||||
|
||||
public static String string(String url, Map<String, String> params, Map<String, String> header) {
|
||||
return url.startsWith("http") ? new OkRequest(GET, url, params, header).execute(client()).getBody() : "";
|
||||
return new OkRequest(GET, url, params, header).execute(client()).getBody();
|
||||
}
|
||||
|
||||
public static String string(String url, Map<String, String> params, Map<String, String> header, long timeout) {
|
||||
return new OkRequest(GET, url, params, header).execute(client(timeout)).getBody();
|
||||
}
|
||||
|
||||
public static String post(String url, Map<String, String> params) {
|
||||
|
|
@ -94,7 +96,11 @@ public class OkHttp {
|
|||
}
|
||||
|
||||
private static OkHttpClient.Builder getBuilder() {
|
||||
return new OkHttpClient.Builder().dns(safeDns()).connectTimeout(30, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS).hostnameVerifier((hostname, session) -> true).sslSocketFactory(getSSLContext().getSocketFactory(), trustAllCertificates());
|
||||
return new OkHttpClient.Builder().dns(safeDns()).connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS).readTimeout(TIMEOUT, TimeUnit.MILLISECONDS).writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS).hostnameVerifier((hostname, session) -> true).sslSocketFactory(getSSLContext().getSocketFactory(), trustAllCertificates());
|
||||
}
|
||||
|
||||
private static OkHttpClient client(long timeout) {
|
||||
return client().newBuilder().connectTimeout(timeout, TimeUnit.MILLISECONDS).readTimeout(timeout, TimeUnit.MILLISECONDS).writeTimeout(timeout, TimeUnit.MILLISECONDS).build();
|
||||
}
|
||||
|
||||
private static OkHttpClient client() {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.github.catvod.net;
|
|||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.utils.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
@ -37,10 +38,10 @@ class OkRequest {
|
|||
this.method = method;
|
||||
this.params = params;
|
||||
this.header = header;
|
||||
getInstance();
|
||||
this.buildRequest();
|
||||
}
|
||||
|
||||
private void getInstance() {
|
||||
private void buildRequest() {
|
||||
Request.Builder builder = new Request.Builder();
|
||||
if (method.equals(OkHttp.GET) && params != null) setParams();
|
||||
if (method.equals(OkHttp.POST)) builder.post(getRequestBody());
|
||||
|
|
@ -62,10 +63,10 @@ class OkRequest {
|
|||
}
|
||||
|
||||
public OkResult execute(OkHttpClient client) {
|
||||
try {
|
||||
Response response = client.newCall(request).execute();
|
||||
return new OkResult(response.code(), response.body().string(), response.headers().toMultimap());
|
||||
try (Response res = client.newCall(request).execute()) {
|
||||
return new OkResult(res.code(), res.body().string(), res.headers().toMultimap());
|
||||
} catch (IOException e) {
|
||||
SpiderDebug.log(e);
|
||||
return new OkResult();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,6 @@ import com.github.catvod.net.OkHttp;
|
|||
import com.github.catvod.utils.Util;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
|
@ -270,29 +267,6 @@ public class AList extends Spider {
|
|||
|
||||
@Override
|
||||
public List<Vod> call() {
|
||||
List<Vod> alist = alist();
|
||||
return !alist.isEmpty() ? alist : xiaoya();
|
||||
}
|
||||
|
||||
private List<Vod> xiaoya() {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(drive.searchApi(keyword)));
|
||||
for (Element a : doc.select("ul > a")) {
|
||||
String[] splits = a.text().split("#");
|
||||
if (!splits[0].contains("/")) continue;
|
||||
int index = splits[0].lastIndexOf("/");
|
||||
boolean file = Util.isMedia(splits[0]);
|
||||
Item item = new Item();
|
||||
item.setType(file ? 0 : 1);
|
||||
item.setThumb(splits.length > 3 ? splits[4] : "");
|
||||
item.setPath("/" + splits[0].substring(0, index));
|
||||
item.setName(splits[0].substring(index + 1));
|
||||
list.add(item.getVod(drive));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private List<Vod> alist() {
|
||||
try {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
String response = post(drive, drive.searchApi(), drive.params(keyword));
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ public class Bili extends Spider {
|
|||
String dan = "https://api.bilibili.com/x/v1/dm/list.so?oid=".concat(cid);
|
||||
for (int i = 0; i < acceptDesc.length; i++) {
|
||||
url.add(acceptDesc[i]);
|
||||
url.add(Proxy.getUrl() + "?do=bili" + "&aid=" + aid + "&cid=" + cid + "&qn=" + acceptQuality[i] + "&type=mpd");
|
||||
url.add("proxy://do=bili" + "&aid=" + aid + "&cid=" + cid + "&qn=" + acceptQuality[i] + "&type=mpd");
|
||||
}
|
||||
return Result.get().url(url).danmaku(Arrays.asList(Danmaku.create().name("B站").url(dan))).dash().header(getHeader()).string();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,138 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
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.json.JSONObject;
|
||||
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.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class Hanime extends Spider {
|
||||
|
||||
private static final String siteUrl = "https://hanime1.me";
|
||||
|
||||
private HashMap<String, String> getHeaders() {
|
||||
HashMap<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", Util.CHROME);
|
||||
return headers;
|
||||
}
|
||||
|
||||
private Filter getFilter(String name, String key, List<String> texts) {
|
||||
List<Filter.Value> values = new ArrayList<>();
|
||||
if (!key.equals("by")) values.add(new Filter.Value("全部", ""));
|
||||
for (String text : texts) {
|
||||
if (text.isEmpty()) continue;
|
||||
values.add(new Filter.Value(text));
|
||||
}
|
||||
return new Filter(key, name, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
List<Class> classes = new ArrayList<>();
|
||||
LinkedHashMap<String, List<Filter>> filters = new LinkedHashMap<>();
|
||||
Document doc1 = Jsoup.parse(OkHttp.string(siteUrl.concat("/search?genre=裏番"), getHeaders()));
|
||||
List<String> sorts = doc1.select("div.hentai-sort-options-wrapper").eachText();
|
||||
List<String> years = doc1.getElementById("year").select("option").eachAttr("value");
|
||||
Document doc2 = Jsoup.parse(OkHttp.string(siteUrl, getHeaders()));
|
||||
for (Element element : doc2.select("a.nav-item")) {
|
||||
String text = element.text();
|
||||
if (text.equals("新番預告") || text.equals("H漫畫")) continue;
|
||||
classes.add(new Class(text));
|
||||
List<Filter> array = new ArrayList<>();
|
||||
array.add(getFilter("排序", "by", sorts));
|
||||
array.add(getFilter("年份", "year", years));
|
||||
filters.put(text, array);
|
||||
}
|
||||
for (Element element : doc2.select("a")) {
|
||||
if (element.attr("href").contains("watch")) {
|
||||
String pic = element.select("div > img").attr("src");
|
||||
String url = element.attr("href");
|
||||
String name = element.select("div > div").text();
|
||||
String id = url.split("=")[1];
|
||||
if (name.contains("smart_display") || name.isEmpty()) continue;
|
||||
list.add(new Vod(id, name, pic));
|
||||
}
|
||||
}
|
||||
return Result.string(classes, list, filters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
if (extend.get("by") == null) extend.put("by", "最新上市");
|
||||
if (extend.get("year") == null) extend.put("year", "");
|
||||
String target = siteUrl.concat("/search?genre=").concat(tid).concat("&page=").concat(pg).concat("&sort=").concat(extend.get("by")).concat("&year=").concat(extend.get("year"));
|
||||
Document doc = Jsoup.parse(OkHttp.string(target, getHeaders()));
|
||||
for (Element element : doc.select("div.col-xs-6")) {
|
||||
String pic = element.select("img").get(1).attr("src");
|
||||
String url = element.select("a.overlay").attr("href");
|
||||
String name = element.select("div.card-mobile-title").text();
|
||||
String id = url.split("=")[1];
|
||||
list.add(new Vod(id, name, pic));
|
||||
}
|
||||
if (list.isEmpty()) {
|
||||
for (Element element : doc.select("a")) {
|
||||
if (element.attr("href").contains("watch")) {
|
||||
String pic = element.select("div > img").attr("src");
|
||||
String url = element.attr("href");
|
||||
String name = element.select("div > div").text();
|
||||
String id = url.split("=")[1];
|
||||
if (name.contains("smart_display")) continue;
|
||||
list.add(new Vod(id, name, pic));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl.concat("/watch?v=").concat(ids.get(0)), getHeaders()));
|
||||
String name = doc.getElementById("shareBtn-title").text();
|
||||
JSONObject json = new JSONObject(doc.select("script[type=application/ld+json]").html().trim());
|
||||
String content = json.optString("description");
|
||||
String pic = json.optJSONArray("thumbnailUrl").optString(0);
|
||||
String url = json.optString("contentUrl");;
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId(ids.get(0));
|
||||
vod.setVodPic(pic);
|
||||
vod.setVodName(name);
|
||||
vod.setVodContent(content);
|
||||
vod.setVodPlayFrom("Hanime1");
|
||||
vod.setVodPlayUrl("播放$" + url);
|
||||
return Result.string(vod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
String target = siteUrl.concat("/search?query=").concat(key).concat("&genre=&sort=&year=&month=&duration=");
|
||||
Document doc = Jsoup.parse(OkHttp.string(target, getHeaders()));
|
||||
for (Element element : doc.select("div.col-xs-6")) {
|
||||
String pic = element.select("img").get(1).attr("src");
|
||||
String url = element.select("a.overlay").attr("href");
|
||||
String name = element.select("div.card-mobile-title").text();
|
||||
String id = url.split("=")[1];
|
||||
list.add(new Vod(id, name, pic));
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
|
||||
return Result.get().url(id).header(getHeaders()).string();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,17 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
|
|
@ -20,6 +19,7 @@ public class Init {
|
|||
|
||||
private final ExecutorService executor;
|
||||
private final Handler handler;
|
||||
private Activity activity;
|
||||
private Application app;
|
||||
|
||||
private static class Loader {
|
||||
|
|
@ -39,52 +39,68 @@ public class Init {
|
|||
return get().app;
|
||||
}
|
||||
|
||||
public static Activity activity() {
|
||||
return get().activity;
|
||||
}
|
||||
|
||||
private void setActivity(Activity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
public static void init(Context context) {
|
||||
get().app = ((Application) context);
|
||||
SpiderDebug.log("自定義爬蟲代碼載入成功!");
|
||||
registerActivityLifecycleCallbacks();
|
||||
Proxy.init();
|
||||
}
|
||||
|
||||
public static void execute(Runnable runnable) {
|
||||
get().executor.execute(runnable);
|
||||
}
|
||||
|
||||
public static void run(Runnable runnable) {
|
||||
public static void post(Runnable runnable) {
|
||||
get().handler.post(runnable);
|
||||
}
|
||||
|
||||
public static void run(Runnable runnable, int delay) {
|
||||
public static void post(Runnable runnable, int delay) {
|
||||
get().handler.postDelayed(runnable, delay);
|
||||
}
|
||||
|
||||
public static void checkPermission() {
|
||||
try {
|
||||
Activity activity = Init.getActivity();
|
||||
if (activity == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return;
|
||||
if (activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) return;
|
||||
activity.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 9999);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static Activity getActivity() throws Exception {
|
||||
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
|
||||
Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null);
|
||||
Field activitiesField = activityThreadClass.getDeclaredField("mActivities");
|
||||
activitiesField.setAccessible(true);
|
||||
Map<?, ?> activities = (Map<?, ?>) activitiesField.get(activityThread);
|
||||
for (Object activityRecord : activities.values()) {
|
||||
Class<?> activityRecordClass = activityRecord.getClass();
|
||||
Field pausedField = activityRecordClass.getDeclaredField("paused");
|
||||
pausedField.setAccessible(true);
|
||||
if (!pausedField.getBoolean(activityRecord)) {
|
||||
Field activityField = activityRecordClass.getDeclaredField("activity");
|
||||
activityField.setAccessible(true);
|
||||
Activity activity = (Activity) activityField.get(activityRecord);
|
||||
SpiderDebug.log(activity.getComponentName().getClassName());
|
||||
return activity;
|
||||
private static void registerActivityLifecycleCallbacks() {
|
||||
get().app.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
|
||||
@Override
|
||||
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
|
||||
if (activity != activity()) get().setActivity(activity);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@Override
|
||||
public void onActivityStarted(@NonNull Activity activity) {
|
||||
if (activity != activity()) get().setActivity(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResumed(@NonNull Activity activity) {
|
||||
if (activity != activity()) get().setActivity(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPaused(@NonNull Activity activity) {
|
||||
if (activity == activity()) get().setActivity(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStopped(@NonNull Activity activity) {
|
||||
if (activity == activity()) get().setActivity(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityDestroyed(@NonNull Activity activity) {
|
||||
if (activity == activity()) get().setActivity(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,114 +1,138 @@
|
|||
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.crawler.Spider;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Json;
|
||||
|
||||
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://api2.rinhome.com";
|
||||
private String extend;
|
||||
|
||||
private Map<String, String> getHeader() {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", "jianpian-android/360");
|
||||
headers.put("JPAUTH", "y261ow7kF2dtzlxh1GS9EB8nbTxNmaK/QQIAjctlKiEv");
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
this.extend = extend;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) throws Exception {
|
||||
List<Class> classes = new ArrayList<>();
|
||||
List<String> typeIds = Arrays.asList("0", "1", "2", "3", "4");
|
||||
List<String> 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, Json.parse(OkHttp.string(extend)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeVideoContent() {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
String url = siteUrl + "/api/slide/list?code=unknown9039b6856c3a3306&pos_id=888&channel=wandoujia";
|
||||
Resp resp = Resp.objectFrom(OkHttp.string(url, getHeader()));
|
||||
for (Data data : resp.getData()) list.add(data.vod());
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
|
||||
if (tid.endsWith("/{pg}")) return searchContent(tid.split("/")[0], pg);
|
||||
List<Vod> list = new ArrayList<>();
|
||||
HashMap<String, String> ext = new HashMap<>();
|
||||
if (extend != null && extend.size() > 0) ext.putAll(extend);
|
||||
String cateId = ext.get("cateId") == null ? tid : ext.get("cateId");
|
||||
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 ? "hot" : ext.get("by");
|
||||
String url = siteUrl + String.format("/api/crumb/list?area=%s&category_id=%s&page=%s&type=0&limit=24&sort=%s&year=%s", area, cateId, pg, by, year);
|
||||
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<String> ids) throws Exception {
|
||||
String url = siteUrl + "/api/node/detail?channel=wandoujia&token=&id=" + ids.get(0);
|
||||
Data data = Detail.objectFrom(OkHttp.string(url, getHeader())).getData();
|
||||
Vod vod = data.vod();
|
||||
vod.setVodPlayFrom("Jianpian");
|
||||
vod.setVodYear(data.getYear());
|
||||
vod.setVodArea(data.getArea());
|
||||
vod.setTypeName(data.getTypes());
|
||||
vod.setVodActor(data.getActors());
|
||||
vod.setVodPlayUrl(data.getPlayUrl());
|
||||
vod.setVodDirector(data.getDirectors());
|
||||
vod.setVodContent(data.getDescription());
|
||||
return Result.string(vod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> 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<Vod> list = new ArrayList<>();
|
||||
String url = siteUrl + "/api/video/search?page=" + pg + "&key=" + URLEncoder.encode(key);
|
||||
Resp resp = Resp.objectFrom(OkHttp.string(url, getHeader()));
|
||||
for (Data data : resp.getData()) list.add(data.vod());
|
||||
return Result.string(list);
|
||||
}
|
||||
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.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
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 String siteUrl = "https://ev5356.970xw.com";
|
||||
private String imgDomain;
|
||||
private String extend;
|
||||
|
||||
private Map<String, String> getHeader() {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Linux; Android 9; V2196A Build/PQ3A.190705.08211809; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/91.0.4472.114 Mobile Safari/537.36;webank/h5face;webank/1.0;netType:NETWORK_WIFI;appVersion:416;packageName:com.jp3.xg3");
|
||||
headers.put("Referer", siteUrl);
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
this.extend = extend;
|
||||
JsonObject domains = new Gson().fromJson(OkHttp.string("https://dns.alidns.com/resolve?name=swrdsfeiujo25sw.cc&type=TXT"), JsonObject.class);
|
||||
String parts = domains.getAsJsonArray("Answer").get(0).getAsJsonObject().get("data").getAsString();
|
||||
parts = parts.replace("\"", "");
|
||||
String[] domain = parts.split(",");
|
||||
for (String d : domain) {
|
||||
siteUrl = "https://wangerniu." + d;
|
||||
String json = OkHttp.string(siteUrl + "/api/appAuthConfig");
|
||||
if (!json.isEmpty()) {
|
||||
JsonObject root = new Gson().fromJson(json, JsonObject.class);
|
||||
imgDomain = root.getAsJsonObject("data").get("imgDomain").getAsString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) throws Exception {
|
||||
List<Class> classes = new ArrayList<>();
|
||||
List<String> typeIds = Arrays.asList("1", "2", "3", "4", "50", "99");
|
||||
List<String> 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<Vod> 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(imgDomain));
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
|
||||
if (tid.endsWith("/{pg}")) return searchContent(tid.split("/")[0], pg);
|
||||
if (tid.equals("50") || tid.equals("99") || tid.equals("111")) {
|
||||
List<Vod> 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(imgDomain));
|
||||
return Result.get().page().vod(list).string();
|
||||
} else {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
HashMap<String, String> 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(imgDomain));
|
||||
return Result.string(list);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> 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(imgDomain);
|
||||
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<String> 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<Vod> 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(imgDomain));
|
||||
return Result.string(list);
|
||||
}
|
||||
}
|
||||
|
|
@ -104,7 +104,7 @@ public class Local extends Spider {
|
|||
Vod vod = new Vod();
|
||||
vod.setVodId(file.getAbsolutePath());
|
||||
vod.setVodName(file.getName());
|
||||
vod.setVodPic(file.isFile() ? Proxy.getUrl() + "?do=local&path=" + Base64.encodeToString(file.getAbsolutePath().getBytes(), Base64.DEFAULT | Base64.URL_SAFE) : Image.FOLDER);
|
||||
vod.setVodPic(file.isFile() ? "proxy://do=local&path=" + Base64.encodeToString(file.getAbsolutePath().getBytes(), Base64.DEFAULT | Base64.URL_SAFE) : Image.FOLDER);
|
||||
vod.setVodRemarks(format.format(file.lastModified()));
|
||||
vod.setVodTag(file.isDirectory() ? "folder" : "file");
|
||||
return vod;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.github.catvod.bean.mqitv.Config;
|
||||
import com.github.catvod.bean.mqitv.Data;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class MQiTV extends Spider {
|
||||
|
||||
private static List<Config> configs;
|
||||
|
||||
public static List<Config> getConfigs() {
|
||||
return configs = configs == null ? new ArrayList<>() : configs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
configs = Config.arrayFrom(extend);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String liveContent(String url) throws Exception {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Config config : getConfigs()) {
|
||||
if (config.getData().isEmpty()) continue;
|
||||
sb.append(config.getName()).append(",#genre#").append("\n");
|
||||
boolean hasPort = config.getUri().getPort() != -1;
|
||||
for (Data item : config.getData()) {
|
||||
String port = hasPort ? item.getPort() : "5003";
|
||||
String proxy = "proxy://do=mqitv&id=" + item.getId() + "&ip=" + config.getUrl() + "&playing=" + item.getPlaying() + "&port=" + port + "&type=m3u8";
|
||||
sb.append(item.getName()).append(",").append(proxy).append("\n");
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static Config getConfig(String ip) {
|
||||
Config config = new Config(ip);
|
||||
int index = getConfigs().indexOf(config);
|
||||
if (index != -1) return getConfigs().get(index);
|
||||
else getConfigs().add(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
public static Object[] proxy(Map<String, String> params) {
|
||||
String ip = params.get("ip");
|
||||
String port = params.get("port");
|
||||
String playing = params.get("playing");
|
||||
if (port == null) port = "5003";
|
||||
Config config = getConfig(ip);
|
||||
String token = config.getUser().getToken();
|
||||
if (token.isEmpty()) {
|
||||
return get302(config.getPlayUrl(port, playing));
|
||||
} else {
|
||||
String id = params.get("id");
|
||||
String auth = config.getAuth(id, token);
|
||||
if (!"OK".equals(auth)) config.clear();
|
||||
if (!"OK".equals(auth)) return proxy(params);
|
||||
String m3u8 = config.getM3U8(id, token, port);
|
||||
return m3u8.isEmpty() ? get302(config.getPlayUrl(port, playing)) : get200(m3u8);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object[] get302(String location) {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("Location", location);
|
||||
Object[] result = new Object[4];
|
||||
result[0] = 302;
|
||||
result[1] = "text/plain";
|
||||
result[2] = new ByteArrayInputStream("302 Found".getBytes());
|
||||
result[3] = header;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Object[] get200(String m3u8) {
|
||||
Object[] result = new Object[3];
|
||||
result[0] = 200;
|
||||
result[1] = "application/vnd.apple.mpegurl";
|
||||
result[2] = new ByteArrayInputStream(m3u8.getBytes());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -42,7 +42,6 @@ public class Market extends Spider {
|
|||
public void init(Context context, String extend) throws Exception {
|
||||
if (extend.startsWith("http")) extend = OkHttp.string(extend);
|
||||
datas = Data.arrayFrom(extend);
|
||||
Init.checkPermission();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -63,7 +62,7 @@ public class Market extends Spider {
|
|||
try {
|
||||
if (isBusy()) return "";
|
||||
setBusy(true);
|
||||
Init.run(this::setDialog, 500);
|
||||
Init.post(this::setDialog, 500);
|
||||
Response response = OkHttp.newCall(action);
|
||||
File file = Path.create(new File(Path.download(), Uri.parse(action).getLastPathSegment()));
|
||||
download(file, response.body().byteStream(), Double.parseDouble(response.header("Content-Length", "1")));
|
||||
|
|
@ -71,6 +70,7 @@ public class Market extends Spider {
|
|||
if (file.getName().endsWith(".apk")) FileUtil.openFile(file);
|
||||
else Result.notify("下載完成");
|
||||
checkCopy(action);
|
||||
response.close();
|
||||
dismiss();
|
||||
return "";
|
||||
} catch (Exception e) {
|
||||
|
|
@ -80,8 +80,7 @@ public class Market extends Spider {
|
|||
}
|
||||
|
||||
private void download(File file, InputStream is, double length) throws Exception {
|
||||
FileOutputStream os = new FileOutputStream(file);
|
||||
try (BufferedInputStream input = new BufferedInputStream(is)) {
|
||||
try (BufferedInputStream input = new BufferedInputStream(is); FileOutputStream os = new FileOutputStream(file)) {
|
||||
byte[] buffer = new byte[4096];
|
||||
int readBytes;
|
||||
long totalBytes = 0;
|
||||
|
|
@ -104,9 +103,9 @@ public class Market extends Spider {
|
|||
}
|
||||
|
||||
private void setDialog() {
|
||||
Init.run(() -> {
|
||||
Init.post(() -> {
|
||||
try {
|
||||
dialog = new ProgressDialog(Init.getActivity());
|
||||
dialog = new ProgressDialog(Init.activity());
|
||||
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||
dialog.setCancelable(false);
|
||||
if (isBusy()) dialog.show();
|
||||
|
|
@ -117,7 +116,7 @@ public class Market extends Spider {
|
|||
}
|
||||
|
||||
private void dismiss() {
|
||||
Init.run(() -> {
|
||||
Init.post(() -> {
|
||||
try {
|
||||
setBusy(false);
|
||||
if (dialog != null) dialog.dismiss();
|
||||
|
|
@ -128,7 +127,7 @@ public class Market extends Spider {
|
|||
}
|
||||
|
||||
private void setProgress(int value) {
|
||||
Init.run(() -> {
|
||||
Init.post(() -> {
|
||||
try {
|
||||
if (dialog != null) dialog.setProgress(value);
|
||||
} catch (Exception e) {
|
||||
|
|
|
|||
|
|
@ -1,20 +1,24 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
public class Proxy extends Spider {
|
||||
public class Proxy {
|
||||
|
||||
private static int port = -1;
|
||||
private static Method method;
|
||||
private static int port;
|
||||
|
||||
public static Object[] proxy(Map<String, String> params) throws Exception {
|
||||
switch (params.get("do")) {
|
||||
case "ck":
|
||||
return new Object[]{200, "text/plain; charset=utf-8", new ByteArrayInputStream("ok".getBytes("UTF-8"))};
|
||||
return new Object[]{200, "text/plain; charset=utf-8", new ByteArrayInputStream("ok".getBytes(StandardCharsets.UTF_8))};
|
||||
case "mqitv":
|
||||
return MQiTV.proxy(params);
|
||||
case "bili":
|
||||
return Bili.proxy(params);
|
||||
case "webdav":
|
||||
|
|
@ -26,27 +30,41 @@ public class Proxy extends Spider {
|
|||
}
|
||||
}
|
||||
|
||||
static void adjustPort() {
|
||||
if (Proxy.port > 0) return;
|
||||
int port = 9978;
|
||||
while (port < 10000) {
|
||||
String resp = OkHttp.string("http://127.0.0.1:" + port + "/proxy?do=ck", null);
|
||||
if (resp.equals("ok")) {
|
||||
SpiderDebug.log("Found local server port " + port);
|
||||
Proxy.port = port;
|
||||
break;
|
||||
}
|
||||
port++;
|
||||
public static void init() {
|
||||
try {
|
||||
Class<?> clz = Class.forName("com.github.catvod.Proxy");
|
||||
port = (int) clz.getMethod("getPort").invoke(null);
|
||||
method = clz.getMethod("getUrl", boolean.class);
|
||||
SpiderDebug.log("本地代理端口:" + port);
|
||||
} catch (Throwable e) {
|
||||
findPort();
|
||||
}
|
||||
}
|
||||
|
||||
public static int getPort() {
|
||||
adjustPort();
|
||||
return port;
|
||||
}
|
||||
|
||||
public static String getUrl() {
|
||||
adjustPort();
|
||||
return "http://127.0.0.1:" + port + "/proxy";
|
||||
return getUrl(true);
|
||||
}
|
||||
|
||||
public static String getUrl(boolean local) {
|
||||
try {
|
||||
return (String) method.invoke(null, local);
|
||||
} catch (Throwable e) {
|
||||
return "http://127.0.0.1:" + port + "/proxy";
|
||||
}
|
||||
}
|
||||
|
||||
private static void findPort() {
|
||||
if (port > 0) return;
|
||||
for (int p = 8964; p < 9999; p++) {
|
||||
if ("ok".equals(OkHttp.string("http://127.0.0.1:" + p + "/proxy?do=ck", null))) {
|
||||
SpiderDebug.log("本地代理端口:" + p);
|
||||
port = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ public class Push extends Spider {
|
|||
vod.setVodId(url);
|
||||
vod.setVodPic(Image.PUSH);
|
||||
vod.setTypeName("FongMi");
|
||||
vod.setVodName(url.startsWith("file://") ? new File(url).getName() : url);
|
||||
vod.setVodName(url.startsWith("file://") ? new File(url).getName() : "");
|
||||
if (url.contains("://") && url.contains("#")) url = url.replace("#", "***");
|
||||
if (Util.isThunder(url)) {
|
||||
vod.setVodPlayUrl(url);
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ public class WebDAV extends Spider {
|
|||
}
|
||||
|
||||
private String getProxyUrl(String url) {
|
||||
return Proxy.getUrl() + "?do=webdav&url=" + url;
|
||||
return "proxy://do=webdav&url=" + url;
|
||||
}
|
||||
|
||||
public static Object[] vod(Map<String, String> params) throws IOException {
|
||||
|
|
|
|||
|
|
@ -1,345 +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.bean.xpath.Rule;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Util;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.seimicrawler.xpath.JXDocument;
|
||||
import org.seimicrawler.xpath.JXNode;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class XPath extends Spider {
|
||||
|
||||
private HashMap<String, String> getHeaders() {
|
||||
HashMap<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", rule.getUa().isEmpty() ? Util.CHROME : rule.getUa());
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) {
|
||||
this.ext = extend;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) {
|
||||
fetchRule();
|
||||
List<Vod> list = new ArrayList<>();
|
||||
List<Class> classes = new ArrayList<>();
|
||||
if (!rule.getCateManual().isEmpty()) {
|
||||
Set<String> keys = rule.getCateManual().keySet();
|
||||
for (String k : keys) {
|
||||
classes.add(new Class(rule.getCateManual().get(k), k));
|
||||
}
|
||||
}
|
||||
String webUrl = rule.getHomeUrl();
|
||||
JXDocument doc = JXDocument.create(fetch(webUrl));
|
||||
if (rule.getCateManual().isEmpty()) {
|
||||
List<JXNode> navNodes = doc.selN(rule.getCateNode());
|
||||
for (int i = 0; i < navNodes.size(); i++) {
|
||||
String name = navNodes.get(i).selOne(rule.getCateName()).asString().trim();
|
||||
name = rule.getCateNameR(name);
|
||||
String id = navNodes.get(i).selOne(rule.getCateId()).asString().trim();
|
||||
id = rule.getCateIdR(id);
|
||||
classes.add(new Class(id, name));
|
||||
}
|
||||
}
|
||||
if (!rule.getHomeVodNode().isEmpty()) {
|
||||
List<JXNode> vodNodes = doc.selN(rule.getHomeVodNode());
|
||||
for (int i = 0; i < vodNodes.size(); i++) {
|
||||
String name = vodNodes.get(i).selOne(rule.getHomeVodName()).asString().trim();
|
||||
name = rule.getHomeVodNameR(name);
|
||||
String id = vodNodes.get(i).selOne(rule.getHomeVodId()).asString().trim();
|
||||
id = rule.getHomeVodIdR(id);
|
||||
String pic = vodNodes.get(i).selOne(rule.getHomeVodImg()).asString().trim();
|
||||
pic = rule.getHomeVodImgR(pic);
|
||||
pic = Util.fixUrl(webUrl, pic);
|
||||
String mark = "";
|
||||
if (!rule.getHomeVodMark().isEmpty()) {
|
||||
try {
|
||||
mark = vodNodes.get(i).selOne(rule.getHomeVodMark()).asString().trim();
|
||||
mark = rule.getHomeVodMarkR(mark);
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
list.add(new Vod(id, name, pic, mark));
|
||||
}
|
||||
}
|
||||
return Result.string(classes, list, rule.getFilter());
|
||||
}
|
||||
|
||||
protected String categoryUrl(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
return rule.getCateUrl().replace("{cateId}", tid).replace("{catePg}", pg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
fetchRule();
|
||||
List<Vod> list = new ArrayList<>();
|
||||
String webUrl = categoryUrl(tid, pg, filter, extend);
|
||||
JXDocument doc = JXDocument.create(fetch(webUrl));
|
||||
List<JXNode> vodNodes = doc.selN(rule.getCateVodNode());
|
||||
for (int i = 0; i < vodNodes.size(); i++) {
|
||||
String name = vodNodes.get(i).selOne(rule.getCateVodName()).asString().trim();
|
||||
name = rule.getCateVodNameR(name);
|
||||
String id = vodNodes.get(i).selOne(rule.getCateVodId()).asString().trim();
|
||||
id = rule.getCateVodIdR(id);
|
||||
String pic = vodNodes.get(i).selOne(rule.getCateVodImg()).asString().trim();
|
||||
pic = rule.getCateVodImgR(pic);
|
||||
pic = Util.fixUrl(webUrl, pic);
|
||||
String mark = "";
|
||||
if (!rule.getCateVodMark().isEmpty()) {
|
||||
try {
|
||||
mark = vodNodes.get(i).selOne(rule.getCateVodMark()).asString().trim();
|
||||
mark = rule.getCateVodMarkR(mark);
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
list.add(new Vod(id, name, pic, mark));
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) {
|
||||
fetchRule();
|
||||
String webUrl = rule.getDetailUrl().replace("{vid}", ids.get(0));
|
||||
String webContent = fetch(webUrl);
|
||||
JXDocument doc = JXDocument.create(webContent);
|
||||
JXNode vodNode = doc.selNOne(rule.getDetailNode());
|
||||
String cover = "", title = "", desc = "", category = "", area = "", year = "", remark = "", director = "", actor = "";
|
||||
title = vodNode.selOne(rule.getDetailName()).asString().trim();
|
||||
title = rule.getDetailNameR(title);
|
||||
cover = vodNode.selOne(rule.getDetailImg()).asString().trim();
|
||||
cover = rule.getDetailImgR(cover);
|
||||
cover = Util.fixUrl(webUrl, cover);
|
||||
if (!rule.getDetailCate().isEmpty()) {
|
||||
try {
|
||||
category = vodNode.selOne(rule.getDetailCate()).asString().trim();
|
||||
category = rule.getDetailCateR(category);
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
if (!rule.getDetailYear().isEmpty()) {
|
||||
try {
|
||||
year = vodNode.selOne(rule.getDetailYear()).asString().trim();
|
||||
year = rule.getDetailYearR(year);
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
if (!rule.getDetailArea().isEmpty()) {
|
||||
try {
|
||||
area = vodNode.selOne(rule.getDetailArea()).asString().trim();
|
||||
area = rule.getDetailAreaR(area);
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
if (!rule.getDetailMark().isEmpty()) {
|
||||
try {
|
||||
remark = vodNode.selOne(rule.getDetailMark()).asString().trim();
|
||||
remark = rule.getDetailMarkR(remark);
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
if (!rule.getDetailActor().isEmpty()) {
|
||||
try {
|
||||
actor = vodNode.selOne(rule.getDetailActor()).asString().trim();
|
||||
actor = rule.getDetailActorR(actor);
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
if (!rule.getDetailDirector().isEmpty()) {
|
||||
try {
|
||||
director = vodNode.selOne(rule.getDetailDirector()).asString().trim();
|
||||
director = rule.getDetailDirectorR(director);
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
if (!rule.getDetailDesc().isEmpty()) {
|
||||
try {
|
||||
desc = vodNode.selOne(rule.getDetailDesc()).asString().trim();
|
||||
desc = rule.getDetailDescR(desc);
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId(ids.get(0));
|
||||
vod.setVodName(title);
|
||||
vod.setVodPic(cover);
|
||||
vod.setTypeName(category);
|
||||
vod.setVodYear(year);
|
||||
vod.setVodArea(area);
|
||||
vod.setVodRemarks(remark);
|
||||
vod.setVodActor(actor);
|
||||
vod.setVodDirector(director);
|
||||
vod.setVodContent(desc);
|
||||
|
||||
ArrayList<String> playFrom = new ArrayList<>();
|
||||
List<JXNode> fromNodes = doc.selN(rule.getDetailFromNode());
|
||||
for (int i = 0; i < fromNodes.size(); i++) {
|
||||
String name = fromNodes.get(i).selOne(rule.getDetailFromName()).asString().trim();
|
||||
name = rule.getDetailFromNameR(name);
|
||||
playFrom.add(name);
|
||||
}
|
||||
|
||||
ArrayList<String> playList = new ArrayList<>();
|
||||
List<JXNode> urlListNodes = doc.selN(rule.getDetailUrlNode());
|
||||
for (int i = 0; i < urlListNodes.size(); i++) {
|
||||
List<JXNode> urlNodes = urlListNodes.get(i).sel(rule.getDetailUrlSubNode());
|
||||
List<String> vodItems = new ArrayList<>();
|
||||
for (int j = 0; j < urlNodes.size(); j++) {
|
||||
String name = urlNodes.get(j).selOne(rule.getDetailUrlName()).asString().trim();
|
||||
name = rule.getDetailUrlNameR(name);
|
||||
String id = urlNodes.get(j).selOne(rule.getDetailUrlId()).asString().trim();
|
||||
id = rule.getDetailUrlIdR(id);
|
||||
vodItems.add(name + "$" + id);
|
||||
}
|
||||
// 排除播放列表為空的播放源
|
||||
if (vodItems.isEmpty() && playFrom.size() > i) {
|
||||
playFrom.set(i, "");
|
||||
}
|
||||
playList.add(TextUtils.join("#", vodItems));
|
||||
}
|
||||
// 排除播放列表為空的播放源
|
||||
for (int i = playFrom.size() - 1; i >= 0; i--) {
|
||||
if (playFrom.get(i).isEmpty()) playFrom.remove(i);
|
||||
}
|
||||
for (int i = playList.size() - 1; i >= 0; i--) {
|
||||
if (playList.get(i).isEmpty()) playList.remove(i);
|
||||
}
|
||||
for (int i = playList.size() - 1; i >= 0; i--) {
|
||||
if (i >= playFrom.size()) playList.remove(i);
|
||||
}
|
||||
vod.setVodPlayFrom(TextUtils.join("$$$", playFrom));
|
||||
vod.setVodPlayUrl(TextUtils.join("$$$", playList));
|
||||
return Result.string(vod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) {
|
||||
fetchRule();
|
||||
String webUrl = rule.getPlayUrl().isEmpty() ? id : rule.getPlayUrl().replace("{playUrl}", id);
|
||||
SpiderDebug.log(webUrl);
|
||||
HashMap<String, String> headers = new HashMap<>();
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
fetchRule();
|
||||
if (rule.getSearchUrl().isEmpty()) return "";
|
||||
String webUrl = rule.getSearchUrl().replace("{wd}", URLEncoder.encode(key));
|
||||
String webContent = fetch(webUrl);
|
||||
List<Vod> list = new ArrayList<>();
|
||||
if (rule.getSearchVodNode().startsWith("json:")) {
|
||||
String[] node = rule.getSearchVodNode().substring(5).split(">");
|
||||
JSONObject data = new JSONObject(webContent);
|
||||
for (int i = 0; i < node.length; i++) {
|
||||
if (i == node.length - 1) {
|
||||
JSONArray vodArray = data.getJSONArray(node[i]);
|
||||
for (int j = 0; j < vodArray.length(); j++) {
|
||||
JSONObject vod = vodArray.getJSONObject(j);
|
||||
String name = vod.optString(rule.getSearchVodName()).trim();
|
||||
name = rule.getSearchVodNameR(name);
|
||||
String id = vod.optString(rule.getSearchVodId()).trim();
|
||||
id = rule.getSearchVodIdR(id);
|
||||
String pic = vod.optString(rule.getSearchVodImg()).trim();
|
||||
pic = rule.getSearchVodImgR(pic);
|
||||
pic = Util.fixUrl(webUrl, pic);
|
||||
String mark = vod.optString(rule.getSearchVodMark()).trim();
|
||||
mark = rule.getSearchVodMarkR(mark);
|
||||
list.add(new Vod(id, name, pic, mark));
|
||||
}
|
||||
} else {
|
||||
data = data.getJSONObject(node[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
JXDocument doc = JXDocument.create(webContent);
|
||||
List<JXNode> vodNodes = doc.selN(rule.getSearchVodNode());
|
||||
for (int i = 0; i < vodNodes.size(); i++) {
|
||||
String name = vodNodes.get(i).selOne(rule.getSearchVodName()).asString().trim();
|
||||
name = rule.getSearchVodNameR(name);
|
||||
String id = vodNodes.get(i).selOne(rule.getSearchVodId()).asString().trim();
|
||||
id = rule.getSearchVodIdR(id);
|
||||
String pic = vodNodes.get(i).selOne(rule.getSearchVodImg()).asString().trim();
|
||||
pic = rule.getSearchVodImgR(pic);
|
||||
pic = Util.fixUrl(webUrl, pic);
|
||||
String mark = "";
|
||||
if (!rule.getCateVodMark().isEmpty()) {
|
||||
try {
|
||||
mark = vodNodes.get(i).selOne(rule.getSearchVodMark()).asString().trim();
|
||||
mark = rule.getSearchVodMarkR(mark);
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
list.add(new Vod(id, name, pic, mark));
|
||||
}
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean manualVideoCheck() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVideoFormat(String url) {
|
||||
return Util.isVideoFormat(url);
|
||||
}
|
||||
|
||||
protected String ext = null;
|
||||
protected Rule rule = null;
|
||||
|
||||
protected void fetchRule() {
|
||||
if (rule == null) {
|
||||
if (ext != null) {
|
||||
if (ext.startsWith("http")) {
|
||||
String json = OkHttp.string(ext, null);
|
||||
rule = Rule.fromJson(json);
|
||||
loadRuleExt(json);
|
||||
} else {
|
||||
rule = Rule.fromJson(ext);
|
||||
loadRuleExt(ext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void loadRuleExt(String json) {
|
||||
}
|
||||
|
||||
protected String fetch(String webUrl) {
|
||||
SpiderDebug.log(webUrl);
|
||||
return OkHttp.string(webUrl, getHeaders());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class XPathFilter extends XPath {
|
||||
|
||||
@Override
|
||||
protected void loadRuleExt(String json) {
|
||||
super.loadRuleExt(json);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String categoryUrl(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
String cateUrl = rule.getCateUrl();
|
||||
if (filter && extend != null && !extend.isEmpty()) {
|
||||
for (String key : extend.keySet()) {
|
||||
String value = extend.get(key);
|
||||
if (!TextUtils.isEmpty(value)) {
|
||||
cateUrl = cateUrl.replace("{" + key + "}", URLEncoder.encode(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
cateUrl = cateUrl.replace("{cateId}", tid).replace("{catePg}", pg);
|
||||
Matcher m = Pattern.compile("\\{(.*?)\\}").matcher(cateUrl);
|
||||
while (m.find()) {
|
||||
String n = m.group(0).replace("{", "").replace("}", "");
|
||||
cateUrl = cateUrl.replace(m.group(0), "").replace("/" + n + "/", "");
|
||||
}
|
||||
return cateUrl;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,196 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLDecoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class XPathMac extends XPath {
|
||||
|
||||
// 嘗試分析直連
|
||||
private boolean decodePlayUrl;
|
||||
// 嘗試匹配官源標識以調用應用配置中的解析列表
|
||||
private boolean decodeVipFlag;
|
||||
// 播放器配置js
|
||||
private String playerConfigJs = "";
|
||||
// 播放器配置js取值正則
|
||||
private String playerConfigJsRegex = "[\\W|\\S|.]*?MacPlayerConfig.player_list[\\W|\\S|.]*?=([\\W|\\S|.]*?),MacPlayerConfig.downer_list";
|
||||
// 站點里播放源對應的真實官源
|
||||
private final HashMap<String, String> show2VipFlag = new HashMap<>();
|
||||
|
||||
/**
|
||||
* mac cms 直連和官源調用應用內播放列表支持
|
||||
*
|
||||
* @param context
|
||||
* @param extend
|
||||
*/
|
||||
public void init(Context context, String extend) {
|
||||
super.init(context, extend);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadRuleExt(String json) {
|
||||
try {
|
||||
JSONObject jsonObj = new JSONObject(json);
|
||||
decodePlayUrl = jsonObj.optBoolean("dcPlayUrl", false);
|
||||
decodeVipFlag = jsonObj.optBoolean("dcVipFlag", false);
|
||||
JSONObject dcShow2Vip = jsonObj.optJSONObject("dcShow2Vip");
|
||||
if (dcShow2Vip != null) {
|
||||
Iterator<String> keys = dcShow2Vip.keys();
|
||||
while (keys.hasNext()) {
|
||||
String name = keys.next();
|
||||
show2VipFlag.put(name.trim(), dcShow2Vip.getString(name).trim());
|
||||
}
|
||||
}
|
||||
playerConfigJs = jsonObj.optString("pCfgJs").trim();
|
||||
playerConfigJsRegex = jsonObj.optString("pCfgJsR", playerConfigJsRegex).trim();
|
||||
} catch (JSONException e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) {
|
||||
String result = super.homeContent(filter);
|
||||
if (!result.isEmpty() && !playerConfigJs.isEmpty()) { // 嘗試通過playerConfigJs獲取展示和flag匹配關系
|
||||
String webContent = fetch(playerConfigJs);
|
||||
Matcher matcher = Pattern.compile(playerConfigJsRegex).matcher(webContent);
|
||||
if (matcher.find()) {
|
||||
try {
|
||||
JSONObject jsonObject = new JSONObject(matcher.group(1));
|
||||
Iterator<String> keys = jsonObject.keys();
|
||||
while (keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
JSONObject keyObj = jsonObject.optJSONObject(key);
|
||||
if (keyObj == null) continue;
|
||||
String show = keyObj.optString("show").trim();
|
||||
if (show.isEmpty()) continue;
|
||||
show2VipFlag.put(show, key);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) {
|
||||
String result = super.detailContent(ids);
|
||||
if (decodeVipFlag && !result.isEmpty()) {
|
||||
try {
|
||||
JSONObject jsonObject = new JSONObject(result);
|
||||
String[] playFrom = jsonObject.optJSONArray("list").getJSONObject(0).optString("vod_play_from").split("\\$\\$\\$");
|
||||
if (playFrom.length > 0) {
|
||||
for (int i = 0; i < playFrom.length; i++) {
|
||||
if (show2VipFlag.containsKey(playFrom[i])) {
|
||||
playFrom[i] = show2VipFlag.get(playFrom[i]);
|
||||
}
|
||||
}
|
||||
jsonObject.optJSONArray("list").getJSONObject(0).put("vod_play_from", TextUtils.join("$$$", playFrom));
|
||||
result = jsonObject.toString();
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
SpiderDebug.log(th);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) {
|
||||
fetchRule();
|
||||
String webUrl = rule.getPlayUrl().isEmpty() ? id : rule.getPlayUrl().replace("{playUrl}", id);
|
||||
String videoUrl = null;
|
||||
// 嘗試分析直連
|
||||
if (decodePlayUrl) {
|
||||
try {
|
||||
Document doc = Jsoup.parse(fetch(webUrl));
|
||||
Elements allScript = doc.select("script");
|
||||
for (int i = 0; i < allScript.size(); i++) {
|
||||
String scContent = allScript.get(i).html().trim();
|
||||
if (scContent.startsWith("var player_")) {
|
||||
int start = scContent.indexOf('{');
|
||||
int end = scContent.lastIndexOf('}') + 1;
|
||||
String json = scContent.substring(start, end);
|
||||
JSONObject player = new JSONObject(json);
|
||||
String videoUrlTmp = player.getString("url");
|
||||
if (player.has("encrypt")) {
|
||||
int encrypt = player.getInt("encrypt");
|
||||
if (encrypt == 1) {
|
||||
videoUrlTmp = URLDecoder.decode(videoUrlTmp);
|
||||
} else if (encrypt == 2) {
|
||||
videoUrlTmp = new String(Base64.decode(videoUrlTmp, Base64.DEFAULT));
|
||||
videoUrlTmp = URLDecoder.decode(videoUrlTmp);
|
||||
}
|
||||
}
|
||||
videoUrl = videoUrlTmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
if (videoUrl != null) {
|
||||
// 適配2.0.6的調用應用內解析列表的支持, 需要配合直連分析和匹配官源解析一起使用,參考cjt影視和極品直連
|
||||
if (decodeVipFlag && Util.isVip(videoUrl)) { // 使用jx:1
|
||||
try {
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("parse", 1);
|
||||
result.put("jx", "1");
|
||||
result.put("url", videoUrl);
|
||||
return result.toString();
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
} else if (decodeVipFlag && vipFlags.contains(flag)) { // 是否使用應用內解析列表解析官源
|
||||
try {
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("parse", 1);
|
||||
result.put("playUrl", "");
|
||||
result.put("url", videoUrl);
|
||||
result.put("header", "");
|
||||
return result.toString();
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
// 如果是視頻直連 直接返回免解
|
||||
else if (isVideoFormat(videoUrl)) {
|
||||
try {
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("parse", 0);
|
||||
result.put("playUrl", "");
|
||||
result.put("url", videoUrl);
|
||||
HashMap<String, String> headers = new HashMap<>();
|
||||
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) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 上述都失敗了就按默認模式走
|
||||
return super.playerContent(flag, id, vipFlags);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class XPathMacFilter extends XPathMac {
|
||||
|
||||
@Override
|
||||
protected String categoryUrl(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
String cateUrl = rule.getCateUrl();
|
||||
if (filter && extend != null && !extend.isEmpty()) {
|
||||
for (String key : extend.keySet()) {
|
||||
String value = extend.get(key);
|
||||
if (!TextUtils.isEmpty(value)) {
|
||||
cateUrl = cateUrl.replace("{" + key + "}", URLEncoder.encode(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
cateUrl = cateUrl.replace("{cateId}", tid).replace("{catePg}", pg);
|
||||
Matcher m = Pattern.compile("\\{(.*?)\\}").matcher(cateUrl);
|
||||
while (m.find()) {
|
||||
String n = m.group(0).replace("{", "").replace("}", "");
|
||||
cateUrl = cateUrl.replace(m.group(0), "").replace("/" + n + "/", "");
|
||||
}
|
||||
return cateUrl;
|
||||
}
|
||||
}
|
||||
|
|
@ -53,9 +53,7 @@ public class YHDM extends Spider {
|
|||
List<Class> classes = new ArrayList<>();
|
||||
List<String> typeIds = Arrays.asList("guochandongman", "ribendongman", "dongmandianying", "omeidongman");
|
||||
List<String> typeNames = Arrays.asList("国产动漫", "日本动漫", "动漫电影", "欧美动漫");
|
||||
for (int i = 0; i < typeIds.size(); i++)
|
||||
classes.add(new Class(typeIds.get(i), typeNames.get(i)));
|
||||
|
||||
for (int i = 0; i < typeIds.size(); i++) classes.add(new Class(typeIds.get(i), typeNames.get(i)));
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeader()));
|
||||
List<Vod> list = new ArrayList<>();
|
||||
for (Element li : doc.select(".stui-vodlist.clearfix .myui-vodlist__box")) {
|
||||
|
|
|
|||
|
|
@ -12,13 +12,14 @@ import android.content.res.XmlResourceParser;
|
|||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.text.TextUtils;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.File;
|
||||
|
|
@ -57,16 +58,16 @@ public class FileProvider extends ContentProvider {
|
|||
synchronized (sCache) {
|
||||
sCache.remove(authority);
|
||||
}
|
||||
mStrategy = getPathStrategy(context, authority, 0);
|
||||
mStrategy = getPathStrategy(context, authority);
|
||||
}
|
||||
|
||||
public static Uri getUriForFile(Context context, String authority, File file) {
|
||||
final PathStrategy strategy = getPathStrategy(context, authority, 0);
|
||||
final PathStrategy strategy = getPathStrategy(context, authority);
|
||||
return strategy.getUriForFile(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||
public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||
final File file = mStrategy.getFileForUri(uri);
|
||||
String displayName = uri.getQueryParameter(DISPLAYNAME_FIELD);
|
||||
if (projection == null) {
|
||||
|
|
@ -92,7 +93,7 @@ public class FileProvider extends ContentProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getType(Uri uri) {
|
||||
public String getType(@NonNull Uri uri) {
|
||||
final File file = mStrategy.getFileForUri(uri);
|
||||
final int lastDot = file.getName().lastIndexOf('.');
|
||||
if (lastDot >= 0) {
|
||||
|
|
@ -106,38 +107,36 @@ public class FileProvider extends ContentProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Uri insert(Uri uri, ContentValues values) {
|
||||
public Uri insert(@NonNull Uri uri, ContentValues values) {
|
||||
throw new UnsupportedOperationException("No external inserts");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
||||
public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
||||
throw new UnsupportedOperationException("No external updates");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
||||
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
|
||||
final File file = mStrategy.getFileForUri(uri);
|
||||
return file.delete() ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
|
||||
public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException {
|
||||
final File file = mStrategy.getFileForUri(uri);
|
||||
final int fileMode = modeToMode(mode);
|
||||
return ParcelFileDescriptor.open(file, fileMode);
|
||||
}
|
||||
|
||||
private static PathStrategy getPathStrategy(Context context, String authority, int resourceId) {
|
||||
private static PathStrategy getPathStrategy(Context context, String authority) {
|
||||
PathStrategy strat;
|
||||
synchronized (sCache) {
|
||||
strat = sCache.get(authority);
|
||||
if (strat == null) {
|
||||
try {
|
||||
strat = parsePathStrategy(context, authority, resourceId);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException("Failed to parse " + META_DATA_FILE_PROVIDER_PATHS + " meta-data", e);
|
||||
} catch (XmlPullParserException e) {
|
||||
strat = parsePathStrategy(context, authority);
|
||||
} catch (IOException | XmlPullParserException e) {
|
||||
throw new IllegalArgumentException("Failed to parse " + META_DATA_FILE_PROVIDER_PATHS + " meta-data", e);
|
||||
}
|
||||
sCache.put(authority, strat);
|
||||
|
|
@ -146,14 +145,10 @@ public class FileProvider extends ContentProvider {
|
|||
return strat;
|
||||
}
|
||||
|
||||
static XmlResourceParser getFileProviderPathsMetaData(Context context, String authority, ProviderInfo info, int resourceId) {
|
||||
static XmlResourceParser getFileProviderPathsMetaData(Context context, String authority, ProviderInfo info) {
|
||||
if (info == null) {
|
||||
throw new IllegalArgumentException("Couldn't find meta-data for provider with authority " + authority);
|
||||
}
|
||||
if (info.metaData == null && resourceId != 0) {
|
||||
info.metaData = new Bundle(1);
|
||||
info.metaData.putInt(META_DATA_FILE_PROVIDER_PATHS, resourceId);
|
||||
}
|
||||
final XmlResourceParser in = info.loadXmlMetaData(context.getPackageManager(), META_DATA_FILE_PROVIDER_PATHS);
|
||||
if (in == null) {
|
||||
throw new IllegalArgumentException("Missing " + META_DATA_FILE_PROVIDER_PATHS + " meta-data");
|
||||
|
|
@ -161,10 +156,10 @@ public class FileProvider extends ContentProvider {
|
|||
return in;
|
||||
}
|
||||
|
||||
private static PathStrategy parsePathStrategy(Context context, String authority, int resourceId) throws IOException, XmlPullParserException {
|
||||
private static PathStrategy parsePathStrategy(Context context, String authority) throws IOException, XmlPullParserException {
|
||||
final SimplePathStrategy strat = new SimplePathStrategy(authority);
|
||||
final ProviderInfo info = context.getPackageManager().resolveContentProvider(authority, PackageManager.GET_META_DATA);
|
||||
final XmlResourceParser in = getFileProviderPathsMetaData(context, authority, info, resourceId);
|
||||
final XmlResourceParser in = getFileProviderPathsMetaData(context, authority, info);
|
||||
int type;
|
||||
while ((type = in.next()) != END_DOCUMENT) {
|
||||
if (type == START_TAG) {
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@ import android.text.TextUtils;
|
|||
import com.github.catvod.spider.Init;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.net.URLConnection;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
|
@ -39,22 +37,6 @@ public class FileUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public static String md5(File file) {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("MD5");
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
byte[] bytes = new byte[4096];
|
||||
int count;
|
||||
while ((count = fis.read(bytes)) != -1) digest.update(bytes, 0, count);
|
||||
fis.close();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : digest.digest()) sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
|
||||
return sb.toString();
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static Uri getShareUri(File file) {
|
||||
return Build.VERSION.SDK_INT < Build.VERSION_CODES.N ? Uri.fromFile(file) : FileProvider.getUriForFile(Init.context(), Init.context().getPackageName() + ".provider", file);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public class Notify {
|
|||
}
|
||||
|
||||
public static void show(String text) {
|
||||
Init.run(() -> get().makeText(text));
|
||||
Init.post(() -> get().makeText(text));
|
||||
}
|
||||
|
||||
private void makeText(String message) {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import java.io.FileInputStream;
|
|||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
|
@ -63,7 +64,7 @@ public class Path {
|
|||
byte[] data = new byte[is.available()];
|
||||
is.read(data);
|
||||
is.close();
|
||||
return new String(data, "UTF-8");
|
||||
return new String(data, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
package com.github.catvod.utils;
|
||||
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.TypedValue;
|
||||
|
||||
import com.github.catvod.spider.Init;
|
||||
|
||||
public class ResUtil {
|
||||
|
||||
private static DisplayMetrics getDisplayMetrics() {
|
||||
return Init.context().getResources().getDisplayMetrics();
|
||||
}
|
||||
|
||||
public static int dp2px(int dp) {
|
||||
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getDisplayMetrics());
|
||||
}
|
||||
}
|
||||
|
|
@ -3,35 +3,21 @@ package com.github.catvod.utils;
|
|||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.webkit.ValueCallback;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
import com.github.catvod.spider.Init;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
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/134.0.0.0 Safari/537.36";
|
||||
public static final String CHROME = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36";
|
||||
public static final List<String> MEDIA = Arrays.asList("mp4", "mkv", "mov", "wav", "wma", "wmv", "flv", "avi", "iso", "mpg", "ts", "mp3", "aac", "flac", "m4a", "ape", "ogg");
|
||||
public static final List<String> SUB = Arrays.asList("srt", "ass", "ssa", "vtt");
|
||||
|
||||
public static boolean isVip(String url) {
|
||||
List<String> hosts = Arrays.asList("iqiyi.com", "v.qq.com", "youku.com", "le.com", "tudou.com", "mgtv.com", "sohu.com", "acfun.cn", "bilibili.com", "baofeng.com", "pptv.com");
|
||||
for (String host : hosts) if (url.contains(host)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isThunder(String url) {
|
||||
return THUNDER.matcher(url).find() || isTorrent(url);
|
||||
}
|
||||
|
|
@ -40,11 +26,6 @@ public class Util {
|
|||
return !url.startsWith("magnet") && url.split(";")[0].endsWith(".torrent");
|
||||
}
|
||||
|
||||
public static boolean isVideoFormat(String url) {
|
||||
if (url.contains("url=http") || url.contains(".js") || url.contains(".css") || url.contains(".html")) return false;
|
||||
return RULE.matcher(url).find();
|
||||
}
|
||||
|
||||
public static boolean isSub(String text) {
|
||||
return SUB.contains(getExt(text).toLowerCase());
|
||||
}
|
||||
|
|
@ -59,31 +40,9 @@ public class Util {
|
|||
|
||||
public static String getSize(double size) {
|
||||
if (size <= 0) return "";
|
||||
if (size > 1024 * 1024 * 1024 * 1024.0) {
|
||||
size /= (1024 * 1024 * 1024 * 1024.0);
|
||||
return String.format(Locale.getDefault(), "%.2f%s", size, "TB");
|
||||
} else if (size > 1024 * 1024 * 1024.0) {
|
||||
size /= (1024 * 1024 * 1024.0);
|
||||
return String.format(Locale.getDefault(), "%.2f%s", size, "GB");
|
||||
} else if (size > 1024 * 1024.0) {
|
||||
size /= (1024 * 1024.0);
|
||||
return String.format(Locale.getDefault(), "%.2f%s", size, "MB");
|
||||
} else {
|
||||
size /= 1024.0;
|
||||
return String.format(Locale.getDefault(), "%.2f%s", size, "KB");
|
||||
}
|
||||
}
|
||||
|
||||
public static String fixUrl(String base, String src) {
|
||||
if (src.startsWith("//")) {
|
||||
Uri parse = Uri.parse(base);
|
||||
return parse.getScheme() + ":" + src;
|
||||
} else if (!src.contains("://")) {
|
||||
Uri parse = Uri.parse(base);
|
||||
return parse.getScheme() + "://" + parse.getHost() + src;
|
||||
} else {
|
||||
return src;
|
||||
}
|
||||
String[] units = new String[]{"bytes", "KB", "MB", "GB", "TB"};
|
||||
int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
|
||||
return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
|
||||
}
|
||||
|
||||
public static String removeExt(String text) {
|
||||
|
|
@ -118,46 +77,4 @@ public class Util {
|
|||
manager.setPrimaryClip(ClipData.newPlainText("fongmi", text));
|
||||
Notify.show("已複製 " + text);
|
||||
}
|
||||
|
||||
public static void loadUrl(WebView webView, String script) {
|
||||
loadUrl(webView, script, null);
|
||||
}
|
||||
|
||||
public static void loadUrl(WebView webView, String script, ValueCallback<String> callback) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
webView.evaluateJavascript(script, callback);
|
||||
} else {
|
||||
webView.loadUrl("javascript:" + script);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addView(View view, ViewGroup.LayoutParams params) {
|
||||
try {
|
||||
ViewGroup group = Init.getActivity().getWindow().getDecorView().findViewById(android.R.id.content);
|
||||
group.addView(view, params);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeView(View view) {
|
||||
try {
|
||||
ViewGroup group = Init.getActivity().getWindow().getDecorView().findViewById(android.R.id.content);
|
||||
group.removeView(view);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadWebView(String url, WebViewClient client) {
|
||||
Init.run(() -> {
|
||||
WebView webView = new WebView(Init.context());
|
||||
webView.getSettings().setDatabaseEnabled(true);
|
||||
webView.getSettings().setDomStorageEnabled(true);
|
||||
webView.getSettings().setJavaScriptEnabled(true);
|
||||
addView(webView, new ViewGroup.LayoutParams(0, 0));
|
||||
webView.setWebViewClient(client);
|
||||
webView.loadUrl(url);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,69 +1,95 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true">
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content"
|
||||
android:fillViewport="true"
|
||||
android:padding="16dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/homeContent"
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="homeContent"
|
||||
android:textAllCaps="false" />
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/homeVideoContent"
|
||||
android:layout_width="wrap_content"
|
||||
<Button
|
||||
android:id="@+id/home"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="home"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/homeVideo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="homeVideo"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/category"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="category"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/detail"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="detail"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/player"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="player"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/search"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="search"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/live"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="live"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/proxy"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="proxy"
|
||||
android:textAllCaps="false" />
|
||||
</LinearLayout>
|
||||
</HorizontalScrollView>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:background="#000000" />
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="homeVideoContent"
|
||||
android:textAllCaps="false" />
|
||||
android:padding="16dp"
|
||||
android:textColor="#000000"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/categoryContent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="categoryContent"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/detailContent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="detailContent"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/playerContent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="playerContent"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/searchContent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="searchContent"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/liveContent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="liveContent"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
id 'ru.cleverpumpkin.proguard-dictionaries-generator' version '1.0.8' apply false
|
||||
id 'com.android.application' version '8.8.0-alpha05' apply false
|
||||
id 'com.android.library' version '8.8.0-alpha05' apply false
|
||||
id 'com.android.application' version '8.13.0' apply false
|
||||
id 'com.android.library' version '8.13.0' apply false
|
||||
}
|
||||
|
||||
tasks.register('clean', Delete) {
|
||||
|
|
@ -10,5 +10,5 @@ tasks.register('clean', Delete) {
|
|||
}
|
||||
|
||||
project.ext {
|
||||
okhttpVersion = '5.0.0-alpha.14'
|
||||
okhttpVersion = '5.1.0'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#Wed Mar 29 12:54:35 CST 2023
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.11.1-bin.zip
|
||||
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.14.3-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1 +1 @@
|
|||
fd389e3446f23e76f9112a2097d81884
|
||||
bd8c878db83953d74efc2cb0723f68ac
|
||||
|
|
|
|||
|
|
@ -1,41 +1,17 @@
|
|||
[
|
||||
{
|
||||
"name": "小雅",
|
||||
"server": "http://alist.xiaoya.pro"
|
||||
},
|
||||
{
|
||||
"name": "觸光",
|
||||
"server": "https://pan.ichuguang.com"
|
||||
},
|
||||
{
|
||||
"name": "一只魚",
|
||||
"server": "https://vtok.pp.ua/"
|
||||
},
|
||||
{
|
||||
"name": "七米藍",
|
||||
"server": "https://al.chirmyram.com"
|
||||
},
|
||||
{
|
||||
"name": "神族九帝",
|
||||
"server": "https://alist.shenzjd.com"
|
||||
},
|
||||
{
|
||||
"name": "梓澪",
|
||||
"server": "https://zi0.cc"
|
||||
},
|
||||
{
|
||||
"name": "範本",
|
||||
"server": "https://one.fongmi.com",
|
||||
"name": "Tangsan",
|
||||
"server": "http://192.168.0.1",
|
||||
"search": true,
|
||||
"hidden": false,
|
||||
"login": {
|
||||
"username": "fongmi",
|
||||
"password": "fongmi"
|
||||
"username": "1234",
|
||||
"password": "1234"
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"path": "/安齋拉拉",
|
||||
"pass": "18181818"
|
||||
"path": "/test",
|
||||
"pass": "1234"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
{
|
||||
"spider": "./jar/custom_spider.jar",
|
||||
"wallpaper": "http://饭太硬.top/深色壁纸/api.php",
|
||||
"spider": "../jar/custom_spider.jar",
|
||||
"lives": [
|
||||
{
|
||||
"name": "XtreamCode",
|
||||
"api": "csp_XtreamCode",
|
||||
"url": "http://iptv.icsnleb.com:25461/player_api.php?username=12&password=12",
|
||||
"epg": "http://iptv.icsnleb.com:25461/xmltv.php?username=12&password=12",
|
||||
"type": 3,
|
||||
"ext": {
|
||||
"live": true,
|
||||
"vod": true,
|
||||
|
|
@ -16,29 +14,43 @@
|
|||
"ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "MQiTV",
|
||||
"api": "csp_MQiTV",
|
||||
"ext": [
|
||||
{
|
||||
"name": "Hotel A",
|
||||
"url": "https://127.0.0.1:4433"
|
||||
},
|
||||
{
|
||||
"name": "Hotel B",
|
||||
"url": "http://127.0.0.1"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"sites": [
|
||||
{
|
||||
"key": "本地",
|
||||
"name": "本地",
|
||||
"key": "local",
|
||||
"name": "Local",
|
||||
"type": 3,
|
||||
"api": "csp_Local",
|
||||
"searchable": 0,
|
||||
"changeable": 0
|
||||
},
|
||||
{
|
||||
"key": "商店",
|
||||
"name": "商店",
|
||||
"key": "market",
|
||||
"name": "Market",
|
||||
"type": 3,
|
||||
"api": "csp_Market",
|
||||
"searchable": 0,
|
||||
"changeable": 0,
|
||||
"ext": "./json/market.json"
|
||||
"ext": "./market.json"
|
||||
},
|
||||
{
|
||||
"key": "push_agent",
|
||||
"name": "推送",
|
||||
"name": "Push",
|
||||
"type": 3,
|
||||
"api": "csp_Push",
|
||||
"searchable": 0,
|
||||
|
|
@ -64,68 +76,11 @@
|
|||
"2606:4700:4700::1111",
|
||||
"2606:4700:4700::1001"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "AdGuard",
|
||||
"url": "https://dns.adguard.com/dns-query",
|
||||
"ips": [
|
||||
"94.140.14.140",
|
||||
"94.140.14.141"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "DNSWatch",
|
||||
"url": "https://resolver2.dns.watch/dns-query",
|
||||
"ips": [
|
||||
"84.200.69.80",
|
||||
"84.200.70.40"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Quad9",
|
||||
"url": "https://dns.quad9.net/dns-quer",
|
||||
"ips": [
|
||||
"9.9.9.9",
|
||||
"149.112.112.112"
|
||||
]
|
||||
}
|
||||
],
|
||||
"proxy": [
|
||||
"raw.githubusercontent.com",
|
||||
"googlevideo.com",
|
||||
"googleapis.com",
|
||||
"youtube.com"
|
||||
],
|
||||
"rules": [
|
||||
{
|
||||
"name": "火山嗅探",
|
||||
"hosts": [
|
||||
"huoshan.com"
|
||||
],
|
||||
"regex": [
|
||||
"item_id="
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "抖音嗅探",
|
||||
"hosts": [
|
||||
"douyin.com"
|
||||
],
|
||||
"regex": [
|
||||
"is_play_url="
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "農民嗅探",
|
||||
"hosts": [
|
||||
"toutiaovod.com"
|
||||
],
|
||||
"regex": [
|
||||
"video/tos/cn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "七新嗅探",
|
||||
"name": "sniffer",
|
||||
"hosts": [
|
||||
"api.52wyb.com"
|
||||
],
|
||||
|
|
@ -134,7 +89,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"name": "毛驢點擊",
|
||||
"name": "click",
|
||||
"hosts": [
|
||||
"www.maolvys.com"
|
||||
],
|
||||
794
json/douban.json
794
json/douban.json
|
|
@ -1,794 +0,0 @@
|
|||
{
|
||||
"hot_gaia": [
|
||||
{
|
||||
"key": "sort",
|
||||
"name": "排序",
|
||||
"value": [
|
||||
{
|
||||
"n": "热度",
|
||||
"v": "recommend"
|
||||
},
|
||||
{
|
||||
"n": "最新",
|
||||
"v": "time"
|
||||
},
|
||||
{
|
||||
"n": "评分",
|
||||
"v": "rank"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "area",
|
||||
"name": "地区",
|
||||
"value": [
|
||||
{
|
||||
"n": "全部",
|
||||
"v": "全部"
|
||||
},
|
||||
{
|
||||
"n": "华语",
|
||||
"v": "华语"
|
||||
},
|
||||
{
|
||||
"n": "欧美",
|
||||
"v": "欧美"
|
||||
},
|
||||
{
|
||||
"n": "韩国",
|
||||
"v": "韩国"
|
||||
},
|
||||
{
|
||||
"n": "日本",
|
||||
"v": "日本"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tv_hot": [
|
||||
{
|
||||
"key": "type",
|
||||
"name": "分类",
|
||||
"value": [
|
||||
{
|
||||
"n": "综合",
|
||||
"v": "tv_hot"
|
||||
},
|
||||
{
|
||||
"n": "国产剧",
|
||||
"v": "tv_domestic"
|
||||
},
|
||||
{
|
||||
"n": "欧美剧",
|
||||
"v": "tv_american"
|
||||
},
|
||||
{
|
||||
"n": "日剧",
|
||||
"v": "tv_japanese"
|
||||
},
|
||||
{
|
||||
"n": "韩剧",
|
||||
"v": "tv_korean"
|
||||
},
|
||||
{
|
||||
"n": "动画",
|
||||
"v": "tv_animation"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"show_hot": [
|
||||
{
|
||||
"key": "type",
|
||||
"name": "分类",
|
||||
"value": [
|
||||
{
|
||||
"n": "综合",
|
||||
"v": "show_hot"
|
||||
},
|
||||
{
|
||||
"n": "国内",
|
||||
"v": "show_domestic"
|
||||
},
|
||||
{
|
||||
"n": "国外",
|
||||
"v": "show_foreign"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"movie": [
|
||||
{
|
||||
"key": "类型",
|
||||
"name": "类型",
|
||||
"value": [
|
||||
{
|
||||
"n": "全部类型",
|
||||
"v": ""
|
||||
},
|
||||
{
|
||||
"n": "喜剧",
|
||||
"v": "喜剧"
|
||||
},
|
||||
{
|
||||
"n": "爱情",
|
||||
"v": "爱情"
|
||||
},
|
||||
{
|
||||
"n": "动作",
|
||||
"v": "动作"
|
||||
},
|
||||
{
|
||||
"n": "科幻",
|
||||
"v": "科幻"
|
||||
},
|
||||
{
|
||||
"n": "动画",
|
||||
"v": "动画"
|
||||
},
|
||||
{
|
||||
"n": "悬疑",
|
||||
"v": "悬疑"
|
||||
},
|
||||
{
|
||||
"n": "犯罪",
|
||||
"v": "犯罪"
|
||||
},
|
||||
{
|
||||
"n": "惊悚",
|
||||
"v": "惊悚"
|
||||
},
|
||||
{
|
||||
"n": "冒险",
|
||||
"v": "冒险"
|
||||
},
|
||||
{
|
||||
"n": "音乐",
|
||||
"v": "音乐"
|
||||
},
|
||||
{
|
||||
"n": "历史",
|
||||
"v": "历史"
|
||||
},
|
||||
{
|
||||
"n": "奇幻",
|
||||
"v": "奇幻"
|
||||
},
|
||||
{
|
||||
"n": "恐怖",
|
||||
"v": "恐怖"
|
||||
},
|
||||
{
|
||||
"n": "战争",
|
||||
"v": "战争"
|
||||
},
|
||||
{
|
||||
"n": "传记",
|
||||
"v": "传记"
|
||||
},
|
||||
{
|
||||
"n": "歌舞",
|
||||
"v": "歌舞"
|
||||
},
|
||||
{
|
||||
"n": "武侠",
|
||||
"v": "武侠"
|
||||
},
|
||||
{
|
||||
"n": "情色",
|
||||
"v": "情色"
|
||||
},
|
||||
{
|
||||
"n": "灾难",
|
||||
"v": "灾难"
|
||||
},
|
||||
{
|
||||
"n": "西部",
|
||||
"v": "西部"
|
||||
},
|
||||
{
|
||||
"n": "纪录片",
|
||||
"v": "纪录片"
|
||||
},
|
||||
{
|
||||
"n": "短片",
|
||||
"v": "短片"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "地区",
|
||||
"name": "地区",
|
||||
"value": [
|
||||
{
|
||||
"n": "全部地区",
|
||||
"v": ""
|
||||
},
|
||||
{
|
||||
"n": "华语",
|
||||
"v": "华语"
|
||||
},
|
||||
{
|
||||
"n": "欧美",
|
||||
"v": "欧美"
|
||||
},
|
||||
{
|
||||
"n": "韩国",
|
||||
"v": "韩国"
|
||||
},
|
||||
{
|
||||
"n": "日本",
|
||||
"v": "日本"
|
||||
},
|
||||
{
|
||||
"n": "中国大陆",
|
||||
"v": "中国大陆"
|
||||
},
|
||||
{
|
||||
"n": "美国",
|
||||
"v": "美国"
|
||||
},
|
||||
{
|
||||
"n": "中国香港",
|
||||
"v": "中国香港"
|
||||
},
|
||||
{
|
||||
"n": "中国台湾",
|
||||
"v": "中国台湾"
|
||||
},
|
||||
{
|
||||
"n": "英国",
|
||||
"v": "英国"
|
||||
},
|
||||
{
|
||||
"n": "法国",
|
||||
"v": "法国"
|
||||
},
|
||||
{
|
||||
"n": "德国",
|
||||
"v": "德国"
|
||||
},
|
||||
{
|
||||
"n": "意大利",
|
||||
"v": "意大利"
|
||||
},
|
||||
{
|
||||
"n": "西班牙",
|
||||
"v": "西班牙"
|
||||
},
|
||||
{
|
||||
"n": "印度",
|
||||
"v": "印度"
|
||||
},
|
||||
{
|
||||
"n": "泰国",
|
||||
"v": "泰国"
|
||||
},
|
||||
{
|
||||
"n": "俄罗斯",
|
||||
"v": "俄罗斯"
|
||||
},
|
||||
{
|
||||
"n": "加拿大",
|
||||
"v": "加拿大"
|
||||
},
|
||||
{
|
||||
"n": "澳大利亚",
|
||||
"v": "澳大利亚"
|
||||
},
|
||||
{
|
||||
"n": "爱尔兰",
|
||||
"v": "爱尔兰"
|
||||
},
|
||||
{
|
||||
"n": "瑞典",
|
||||
"v": "瑞典"
|
||||
},
|
||||
{
|
||||
"n": "巴西",
|
||||
"v": "巴西"
|
||||
},
|
||||
{
|
||||
"n": "丹麦",
|
||||
"v": "丹麦"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "sort",
|
||||
"name": "排序",
|
||||
"value": [
|
||||
{
|
||||
"n": "近期热度",
|
||||
"v": "T"
|
||||
},
|
||||
{
|
||||
"n": "首映时间",
|
||||
"v": "R"
|
||||
},
|
||||
{
|
||||
"n": "高分优先",
|
||||
"v": "S"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "年代",
|
||||
"name": "年代",
|
||||
"value": [
|
||||
{
|
||||
"n": "全部年代",
|
||||
"v": ""
|
||||
},
|
||||
{
|
||||
"n": "2023",
|
||||
"v": "2023"
|
||||
},
|
||||
{
|
||||
"n": "2022",
|
||||
"v": "2022"
|
||||
},
|
||||
{
|
||||
"n": "2021",
|
||||
"v": "2021"
|
||||
},
|
||||
{
|
||||
"n": "2020",
|
||||
"v": "2020"
|
||||
},
|
||||
{
|
||||
"n": "2019",
|
||||
"v": "2019"
|
||||
},
|
||||
{
|
||||
"n": "2010年代",
|
||||
"v": "2010年代"
|
||||
},
|
||||
{
|
||||
"n": "2000年代",
|
||||
"v": "2000年代"
|
||||
},
|
||||
{
|
||||
"n": "90年代",
|
||||
"v": "90年代"
|
||||
},
|
||||
{
|
||||
"n": "80年代",
|
||||
"v": "80年代"
|
||||
},
|
||||
{
|
||||
"n": "70年代",
|
||||
"v": "70年代"
|
||||
},
|
||||
{
|
||||
"n": "60年代",
|
||||
"v": "60年代"
|
||||
},
|
||||
{
|
||||
"n": "更早",
|
||||
"v": "更早"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tv": [
|
||||
{
|
||||
"key": "类型",
|
||||
"name": "类型",
|
||||
"value": [
|
||||
{
|
||||
"n": "不限",
|
||||
"v": ""
|
||||
},
|
||||
{
|
||||
"n": "电视剧",
|
||||
"v": "电视剧"
|
||||
},
|
||||
{
|
||||
"n": "综艺",
|
||||
"v": "综艺"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "电视剧形式",
|
||||
"name": "电视剧形式",
|
||||
"value": [
|
||||
{
|
||||
"n": "不限",
|
||||
"v": ""
|
||||
},
|
||||
{
|
||||
"n": "喜剧",
|
||||
"v": "喜剧"
|
||||
},
|
||||
{
|
||||
"n": "爱情",
|
||||
"v": "爱情"
|
||||
},
|
||||
{
|
||||
"n": "悬疑",
|
||||
"v": "悬疑"
|
||||
},
|
||||
{
|
||||
"n": "动画",
|
||||
"v": "动画"
|
||||
},
|
||||
{
|
||||
"n": "武侠",
|
||||
"v": "武侠"
|
||||
},
|
||||
{
|
||||
"n": "古装",
|
||||
"v": "古装"
|
||||
},
|
||||
{
|
||||
"n": "家庭",
|
||||
"v": "家庭"
|
||||
},
|
||||
{
|
||||
"n": "犯罪",
|
||||
"v": "犯罪"
|
||||
},
|
||||
{
|
||||
"n": "科幻",
|
||||
"v": "科幻"
|
||||
},
|
||||
{
|
||||
"n": "恐怖",
|
||||
"v": "恐怖"
|
||||
},
|
||||
{
|
||||
"n": "历史",
|
||||
"v": "历史"
|
||||
},
|
||||
{
|
||||
"n": "战争",
|
||||
"v": "战争"
|
||||
},
|
||||
{
|
||||
"n": "动作",
|
||||
"v": "动作"
|
||||
},
|
||||
{
|
||||
"n": "冒险",
|
||||
"v": "冒险"
|
||||
},
|
||||
{
|
||||
"n": "传记",
|
||||
"v": "传记"
|
||||
},
|
||||
{
|
||||
"n": "剧情",
|
||||
"v": "剧情"
|
||||
},
|
||||
{
|
||||
"n": "奇幻",
|
||||
"v": "奇幻"
|
||||
},
|
||||
{
|
||||
"n": "惊悚",
|
||||
"v": "惊悚"
|
||||
},
|
||||
{
|
||||
"n": "灾难",
|
||||
"v": "灾难"
|
||||
},
|
||||
{
|
||||
"n": "歌舞",
|
||||
"v": "歌舞"
|
||||
},
|
||||
{
|
||||
"n": "音乐",
|
||||
"v": "音乐"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "综艺形式",
|
||||
"name": "综艺形式",
|
||||
"value": [
|
||||
{
|
||||
"n": "不限",
|
||||
"v": ""
|
||||
},
|
||||
{
|
||||
"n": "真人秀",
|
||||
"v": "真人秀"
|
||||
},
|
||||
{
|
||||
"n": "脱口秀",
|
||||
"v": "脱口秀"
|
||||
},
|
||||
{
|
||||
"n": "音乐",
|
||||
"v": "音乐"
|
||||
},
|
||||
{
|
||||
"n": "歌舞",
|
||||
"v": "歌舞"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "地区",
|
||||
"name": "地区",
|
||||
"value": [
|
||||
{
|
||||
"n": "全部地区",
|
||||
"v": ""
|
||||
},
|
||||
{
|
||||
"n": "华语",
|
||||
"v": "华语"
|
||||
},
|
||||
{
|
||||
"n": "欧美",
|
||||
"v": "欧美"
|
||||
},
|
||||
{
|
||||
"n": "国外",
|
||||
"v": "国外"
|
||||
},
|
||||
{
|
||||
"n": "韩国",
|
||||
"v": "韩国"
|
||||
},
|
||||
{
|
||||
"n": "日本",
|
||||
"v": "日本"
|
||||
},
|
||||
{
|
||||
"n": "中国大陆",
|
||||
"v": "中国大陆"
|
||||
},
|
||||
{
|
||||
"n": "中国香港",
|
||||
"v": "中国香港"
|
||||
},
|
||||
{
|
||||
"n": "美国",
|
||||
"v": "美国"
|
||||
},
|
||||
{
|
||||
"n": "英国",
|
||||
"v": "英国"
|
||||
},
|
||||
{
|
||||
"n": "泰国",
|
||||
"v": "泰国"
|
||||
},
|
||||
{
|
||||
"n": "中国台湾",
|
||||
"v": "中国台湾"
|
||||
},
|
||||
{
|
||||
"n": "意大利",
|
||||
"v": "意大利"
|
||||
},
|
||||
{
|
||||
"n": "法国",
|
||||
"v": "法国"
|
||||
},
|
||||
{
|
||||
"n": "德国",
|
||||
"v": "德国"
|
||||
},
|
||||
{
|
||||
"n": "西班牙",
|
||||
"v": "西班牙"
|
||||
},
|
||||
{
|
||||
"n": "俄罗斯",
|
||||
"v": "俄罗斯"
|
||||
},
|
||||
{
|
||||
"n": "瑞典",
|
||||
"v": "瑞典"
|
||||
},
|
||||
{
|
||||
"n": "巴西",
|
||||
"v": "巴西"
|
||||
},
|
||||
{
|
||||
"n": "丹麦",
|
||||
"v": "丹麦"
|
||||
},
|
||||
{
|
||||
"n": "印度",
|
||||
"v": "印度"
|
||||
},
|
||||
{
|
||||
"n": "加拿大",
|
||||
"v": "加拿大"
|
||||
},
|
||||
{
|
||||
"n": "爱尔兰",
|
||||
"v": "爱尔兰"
|
||||
},
|
||||
{
|
||||
"n": "澳大利亚",
|
||||
"v": "澳大利亚"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "sort",
|
||||
"name": "排序",
|
||||
"value": [
|
||||
{
|
||||
"n": "近期热度",
|
||||
"v": "T"
|
||||
},
|
||||
{
|
||||
"n": "首播时间",
|
||||
"v": "R"
|
||||
},
|
||||
{
|
||||
"n": "高分优先",
|
||||
"v": "S"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "年代",
|
||||
"name": "年代",
|
||||
"value": [
|
||||
{
|
||||
"n": "全部",
|
||||
"v": ""
|
||||
},
|
||||
{
|
||||
"n": "2023",
|
||||
"v": "2023"
|
||||
},
|
||||
{
|
||||
"n": "2022",
|
||||
"v": "2022"
|
||||
},
|
||||
{
|
||||
"n": "2021",
|
||||
"v": "2021"
|
||||
},
|
||||
{
|
||||
"n": "2020",
|
||||
"v": "2020"
|
||||
},
|
||||
{
|
||||
"n": "2019",
|
||||
"v": "2019"
|
||||
},
|
||||
{
|
||||
"n": "2010年代",
|
||||
"v": "2010年代"
|
||||
},
|
||||
{
|
||||
"n": "2000年代",
|
||||
"v": "2000年代"
|
||||
},
|
||||
{
|
||||
"n": "90年代",
|
||||
"v": "90年代"
|
||||
},
|
||||
{
|
||||
"n": "80年代",
|
||||
"v": "80年代"
|
||||
},
|
||||
{
|
||||
"n": "70年代",
|
||||
"v": "70年代"
|
||||
},
|
||||
{
|
||||
"n": "60年代",
|
||||
"v": "60年代"
|
||||
},
|
||||
{
|
||||
"n": "更早",
|
||||
"v": "更早"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "平台",
|
||||
"name": "平台",
|
||||
"value": [
|
||||
{
|
||||
"n": "全部",
|
||||
"v": ""
|
||||
},
|
||||
{
|
||||
"n": "腾讯视频",
|
||||
"v": "腾讯视频"
|
||||
},
|
||||
{
|
||||
"n": "爱奇艺",
|
||||
"v": "爱奇艺"
|
||||
},
|
||||
{
|
||||
"n": "优酷",
|
||||
"v": "优酷"
|
||||
},
|
||||
{
|
||||
"n": "湖南卫视",
|
||||
"v": "湖南卫视"
|
||||
},
|
||||
{
|
||||
"n": "Netflix",
|
||||
"v": "Netflix"
|
||||
},
|
||||
{
|
||||
"n": "HBO",
|
||||
"v": "HBO"
|
||||
},
|
||||
{
|
||||
"n": "BBC",
|
||||
"v": "BBC"
|
||||
},
|
||||
{
|
||||
"n": "NHK",
|
||||
"v": "NHK"
|
||||
},
|
||||
{
|
||||
"n": "CBS",
|
||||
"v": "CBS"
|
||||
},
|
||||
{
|
||||
"n": "NBC",
|
||||
"v": "NBC"
|
||||
},
|
||||
{
|
||||
"n": "tvN",
|
||||
"v": "tvN"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"rank_list_movie": [
|
||||
{
|
||||
"key": "榜单",
|
||||
"name": "榜单",
|
||||
"value": [
|
||||
{
|
||||
"n": "实时热门电影",
|
||||
"v": "movie_real_time_hotest"
|
||||
},
|
||||
{
|
||||
"n": "一周口碑电影榜",
|
||||
"v": "movie_weekly_best"
|
||||
},
|
||||
{
|
||||
"n": "豆瓣电影Top250",
|
||||
"v": "movie_top250"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"rank_list_tv": [
|
||||
{
|
||||
"key": "榜单",
|
||||
"name": "榜单",
|
||||
"value": [
|
||||
{
|
||||
"n": "实时热门电视",
|
||||
"v": "tv_real_time_hotest"
|
||||
},
|
||||
{
|
||||
"n": "华语口碑剧集榜",
|
||||
"v": "tv_chinese_best_weekly"
|
||||
},
|
||||
{
|
||||
"n": "全球口碑剧集榜",
|
||||
"v": "tv_global_best_weekly"
|
||||
},
|
||||
{
|
||||
"n": "国内口碑综艺榜",
|
||||
"v": "show_chinese_best_weekly"
|
||||
},
|
||||
{
|
||||
"n": "国外口碑综艺榜",
|
||||
"v": "show_global_best_weekly"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,108 +1,9 @@
|
|||
{
|
||||
"0": [
|
||||
{
|
||||
"key": "area",
|
||||
"name": "地區",
|
||||
"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": "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": "排序",
|
||||
"value": [
|
||||
{
|
||||
"n": "热门",
|
||||
"v": "hot"
|
||||
},
|
||||
{
|
||||
"n": "更新",
|
||||
"v": "updata"
|
||||
},
|
||||
{
|
||||
"n": "评分",
|
||||
"v": "rating"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"1": [
|
||||
{
|
||||
"key": "area",
|
||||
"name": "地區",
|
||||
"init": "1",
|
||||
"value": [
|
||||
{
|
||||
"n": "全部",
|
||||
|
|
@ -142,6 +43,10 @@
|
|||
"n": "全部",
|
||||
"v": "0"
|
||||
},
|
||||
{
|
||||
"n": "2025",
|
||||
"v": "107"
|
||||
},
|
||||
{
|
||||
"n": "2024",
|
||||
"v": "119"
|
||||
|
|
@ -183,6 +88,7 @@
|
|||
{
|
||||
"key": "by",
|
||||
"name": "排序",
|
||||
"init": "updata",
|
||||
"value": [
|
||||
{
|
||||
"n": "热门",
|
||||
|
|
@ -203,6 +109,7 @@
|
|||
{
|
||||
"key": "area",
|
||||
"name": "地區",
|
||||
"init": "1",
|
||||
"value": [
|
||||
{
|
||||
"n": "全部",
|
||||
|
|
@ -242,6 +149,10 @@
|
|||
"n": "全部",
|
||||
"v": "0"
|
||||
},
|
||||
{
|
||||
"n": "2025",
|
||||
"v": "107"
|
||||
},
|
||||
{
|
||||
"n": "2024",
|
||||
"v": "119"
|
||||
|
|
@ -283,6 +194,7 @@
|
|||
{
|
||||
"key": "by",
|
||||
"name": "排序",
|
||||
"init": "updata",
|
||||
"value": [
|
||||
{
|
||||
"n": "热门",
|
||||
|
|
@ -303,6 +215,7 @@
|
|||
{
|
||||
"key": "area",
|
||||
"name": "地區",
|
||||
"init": "1",
|
||||
"value": [
|
||||
{
|
||||
"n": "全部",
|
||||
|
|
@ -342,6 +255,10 @@
|
|||
"n": "全部",
|
||||
"v": "0"
|
||||
},
|
||||
{
|
||||
"n": "2025",
|
||||
"v": "107"
|
||||
},
|
||||
{
|
||||
"n": "2024",
|
||||
"v": "119"
|
||||
|
|
@ -383,6 +300,7 @@
|
|||
{
|
||||
"key": "by",
|
||||
"name": "排序",
|
||||
"init": "updata",
|
||||
"value": [
|
||||
{
|
||||
"n": "热门",
|
||||
|
|
@ -403,6 +321,7 @@
|
|||
{
|
||||
"key": "area",
|
||||
"name": "地區",
|
||||
"init": "1",
|
||||
"value": [
|
||||
{
|
||||
"n": "全部",
|
||||
|
|
@ -442,6 +361,10 @@
|
|||
"n": "全部",
|
||||
"v": "0"
|
||||
},
|
||||
{
|
||||
"n": "2025",
|
||||
"v": "107"
|
||||
},
|
||||
{
|
||||
"n": "2024",
|
||||
"v": "119"
|
||||
|
|
@ -483,6 +406,7 @@
|
|||
{
|
||||
"key": "by",
|
||||
"name": "排序",
|
||||
"init": "updata",
|
||||
"value": [
|
||||
{
|
||||
"n": "热门",
|
||||
|
|
|
|||
121
json/market.json
121
json/market.json
|
|
@ -1,126 +1,15 @@
|
|||
[
|
||||
{
|
||||
"name": "推薦",
|
||||
"name": "APP",
|
||||
"list": [
|
||||
{
|
||||
"url": "https://i.imgs.ovh/2023/10/19/2mfxN.jpeg",
|
||||
"icon": "https://i.imgs.ovh/2023/10/19/2mfxN.jpeg"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "正式版",
|
||||
"list": [
|
||||
{
|
||||
"name": "電視-java",
|
||||
"url": "https://github.com/FongMi/Release/raw/fongmi/apk/release/leanback-java-armeabi_v7a.apk",
|
||||
"icon": "https://i.imgs.ovh/2023/10/17/r8nk2.png",
|
||||
"name": "電視版",
|
||||
"url": "https://github.com/FongMi/Release/raw/fongmi/apk/release/leanback-armeabi_v7a.apk",
|
||||
"version": "v7a"
|
||||
},
|
||||
{
|
||||
"name": "電視-java",
|
||||
"url": "https://github.com/FongMi/Release/raw/fongmi/apk/release/leanback-java-arm64_v8a.apk",
|
||||
"icon": "https://i.imgs.ovh/2023/10/17/r8nk2.png",
|
||||
"version": "v8a"
|
||||
},
|
||||
{
|
||||
"name": "電視-py",
|
||||
"url": "https://github.com/FongMi/Release/raw/fongmi/apk/release/leanback-python-armeabi_v7a.apk",
|
||||
"icon": "https://i.imgs.ovh/2023/10/17/r8nk2.png",
|
||||
"version": "v7a"
|
||||
},
|
||||
{
|
||||
"name": "電視-py",
|
||||
"url": "https://github.com/FongMi/Release/raw/fongmi/apk/release/leanback-python-arm64_v8a.apk",
|
||||
"icon": "https://i.imgs.ovh/2023/10/17/r8nk2.png",
|
||||
"version": "v8a"
|
||||
},
|
||||
{
|
||||
"name": "手機-java",
|
||||
"url": "https://github.com/FongMi/Release/raw/fongmi/apk/release/mobile-java-armeabi_v7a.apk",
|
||||
"icon": "https://i.imgs.ovh/2023/10/17/r8lVK.png",
|
||||
"version": "v7a"
|
||||
},
|
||||
{
|
||||
"name": "手機-java",
|
||||
"url": "https://github.com/FongMi/Release/raw/fongmi/apk/release/mobile-java-arm64_v8a.apk",
|
||||
"icon": "https://i.imgs.ovh/2023/10/17/r8lVK.png",
|
||||
"version": "v8a"
|
||||
},
|
||||
{
|
||||
"name": "手機-py",
|
||||
"url": "https://github.com/FongMi/Release/raw/fongmi/apk/release/mobile-python-armeabi_v7a.apk",
|
||||
"icon": "https://i.imgs.ovh/2023/10/17/r8lVK.png",
|
||||
"version": "v7a"
|
||||
},
|
||||
{
|
||||
"name": "手機-py",
|
||||
"url": "https://github.com/FongMi/Release/raw/fongmi/apk/release/mobile-python-arm64_v8a.apk",
|
||||
"icon": "https://i.imgs.ovh/2023/10/17/r8lVK.png",
|
||||
"version": "v8a"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "內測版",
|
||||
"list": [
|
||||
{
|
||||
"name": "電視-java",
|
||||
"url": "https://fm.caioa.link/main/apk/dev/leanback-java-armeabi_v7a.apk",
|
||||
"icon": "https://i.imgs.ovh/2023/10/17/r8nk2.png",
|
||||
"version": "v7a"
|
||||
},
|
||||
{
|
||||
"name": "電視-java",
|
||||
"url": "https://fm.caioa.link/main/apk/dev/leanback-java-arm64_v8a.apk",
|
||||
"icon": "https://i.imgs.ovh/2023/10/17/r8nk2.png",
|
||||
"version": "v8a"
|
||||
},
|
||||
{
|
||||
"name": "電視-py",
|
||||
"url": "https://fm.caioa.link/main/apk/dev/leanback-python-armeabi_v7a.apk",
|
||||
"icon": "https://i.imgs.ovh/2023/10/17/r8nk2.png",
|
||||
"version": "v7a"
|
||||
},
|
||||
{
|
||||
"name": "電視-py",
|
||||
"url": "https://fm.caioa.link/main/apk/dev/leanback-python-arm64_v8a.apk",
|
||||
"icon": "https://i.imgs.ovh/2023/10/17/r8nk2.png",
|
||||
"version": "v8a"
|
||||
},
|
||||
{
|
||||
"name": "手機-java",
|
||||
"url": "https://fm.caioa.link/main/apk/dev/mobile-java-armeabi_v7a.apk",
|
||||
"icon": "https://i.imgs.ovh/2023/10/17/r8lVK.png",
|
||||
"version": "v7a"
|
||||
},
|
||||
{
|
||||
"name": "手機-java",
|
||||
"url": "https://fm.caioa.link/main/apk/dev/mobile-java-arm64_v8a.apk",
|
||||
"icon": "https://i.imgs.ovh/2023/10/17/r8lVK.png",
|
||||
"version": "v8a"
|
||||
},
|
||||
{
|
||||
"name": "手機-py",
|
||||
"url": "https://fm.caioa.link/main/apk/dev/mobile-python-armeabi_v7a.apk",
|
||||
"icon": "https://i.imgs.ovh/2023/10/17/r8lVK.png",
|
||||
"version": "v7a"
|
||||
},
|
||||
{
|
||||
"name": "手機-py",
|
||||
"url": "https://fm.caioa.link/main/apk/dev/mobile-python-arm64_v8a.apk",
|
||||
"icon": "https://i.imgs.ovh/2023/10/17/r8lVK.png",
|
||||
"version": "v8a"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "4.x版",
|
||||
"list": [
|
||||
{
|
||||
"name": "電視",
|
||||
"url": "https://fm.caioa.link/main/apk/kitkat/leanback.apk",
|
||||
"icon": "https://i.imgs.ovh/2023/10/17/r8nk2.png",
|
||||
"name": "行動版",
|
||||
"url": "https://github.com/FongMi/Release/raw/fongmi/apk/release/mobile-armeabi_v7a.apk",
|
||||
"version": "v7a"
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"msg": "FongMi 天下第一",
|
||||
"date": "20230604000000",
|
||||
"duration": 10
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
[
|
||||
{
|
||||
"name": "Tangsan",
|
||||
"server": "smb://192.168.0.2/Users"
|
||||
"server": "smb://192.168.0.1/Users"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,14 +1,8 @@
|
|||
[
|
||||
{
|
||||
"name": "七米藍",
|
||||
"server": "https://al.chirmyram.com/dav",
|
||||
"user": "alist",
|
||||
"pass": "alist"
|
||||
},
|
||||
{
|
||||
"name": "影視庫",
|
||||
"server": "https://esir.eu.org/dav",
|
||||
"user": "alist",
|
||||
"pass": "alist"
|
||||
"name": "Tangsan",
|
||||
"server": "http://192.168.0.1/dav",
|
||||
"user": "1234",
|
||||
"pass": "1234"
|
||||
}
|
||||
]
|
||||
Loading…
Reference in New Issue