'第一版'

This commit is contained in:
zhangjie
2024-03-10 16:44:17 +08:00
commit bceede467d
163 changed files with 29422 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
.gradle
.idea
*build
/local.properties

1
CNAME Normal file
View File

@@ -0,0 +1 @@
fm.t4tv.hz.cz

5
README.md Normal file
View File

@@ -0,0 +1,5 @@
# CatVodSpider
### Based on CatVod
https://github.com/CatVodTVOfficial/CatVodTVSpider

53
app/build.gradle Normal file
View File

@@ -0,0 +1,53 @@
plugins {
id 'com.android.application'
id 'ru.cleverpumpkin.proguard-dictionaries-generator'
}
android {
compileSdk 33
defaultConfig {
applicationId "com.github.catvod.demo"
minSdk 17
targetSdk 28
buildConfigField("String", "CLIENT_ID", "\"${clientId}\"")
}
buildTypes {
release {
minifyEnabled true
proguardFiles 'proguard-rules.pro'
proguardDictionaries {
dictionaryNames = ["build/class-dictionary", "build/package-dictionary", "build/obfuscation-dictionary"]
minLineLength 1
maxLineLength 3
linesCountInDictionary 100000
}
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
namespace 'com.github.catvod'
configurations.configureEach {
resolutionStrategy {
force 'com.squareup.okhttp3:okhttp:3.12.13'
}
}
}
dependencies {
implementation 'com.googlecode.juniversalchardet:juniversalchardet:1.0.3'
implementation 'com.github.thegrizzlylabs:sardine-android:0.8'
implementation 'wang.harlon.quickjs:wrapper-android:0.21.1'
implementation 'com.squareup.okhttp3:okhttp:3.12.13'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'cn.wanghaomiao:JsoupXpath:2.5.1'
implementation 'org.nanohttpd:nanohttpd:2.3.1'
implementation 'com.google.zxing:core:3.3.0'
implementation 'com.orhanobut:logger:2.2.0'
implementation 'org.jsoup:jsoup:1.15.3'
}

53
app/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,53 @@
# Merge
-flattenpackagehierarchy com.github.catvod.spider.merge
-dontwarn org.slf4j.impl.StaticLoggerBinder
# Spider
-keep class com.github.catvod.js.* { *; }
-keep class com.github.catvod.crawler.* { *; }
-keep class com.github.catvod.spider.* { public <methods>; }
-keep class com.github.catvod.parser.* { public <methods>; }
# AndroidX
-keep class androidx.core.** { *; }
# Gson
-keepattributes Signature
-keepattributes *Annotation*
-dontwarn sun.misc.**
-keep class com.google.gson.** { *; }
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
-keepclassmembers,allowobfuscation class * { @com.google.gson.annotations.SerializedName <fields>; }
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
# Nano
-keep class fi.iki.elonen.** { *; }
# OkHttp
-dontwarn okhttp3.**
-keep class okio.** { *; }
-keep class okhttp3.** { *; }
# Logger
-keep class com.orhanobut.logger.** { *; }
# QuickJS
-keep class com.whl.quickjs.** { *; }
# Sardine
-keep class com.thegrizzlylabs.sardineandroid.** { *; }
# Smbj
-keep class com.hierynomus.** { *; }
-keep class net.engio.mbassy.** { *; }
# Zxing
-keep class com.google.zxing.** { *; }
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-sdk tools:overrideLibrary="com.whl.quickjs.android" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:usesCleartextTraffic="true">
<activity
android:name=".debug.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,659 @@
package com.github.catvod.api;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.net.UrlQuerySanitizer;
import android.os.SystemClock;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.github.catvod.BuildConfig;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Sub;
import com.github.catvod.bean.Vod;
import com.github.catvod.bean.ali.Cache;
import com.github.catvod.bean.ali.Code;
import com.github.catvod.bean.ali.Data;
import com.github.catvod.bean.ali.Download;
import com.github.catvod.bean.ali.Drive;
import com.github.catvod.bean.ali.Item;
import com.github.catvod.bean.ali.OAuth;
import com.github.catvod.bean.ali.Preview;
import com.github.catvod.bean.ali.Resp;
import com.github.catvod.bean.ali.Share;
import com.github.catvod.bean.ali.User;
import com.github.catvod.crawler.SpiderDebug;
import com.github.catvod.net.OkHttp;
import com.github.catvod.net.OkResult;
import com.github.catvod.spider.Init;
import com.github.catvod.spider.Proxy;
import com.github.catvod.utils.Json;
import com.github.catvod.utils.Notify;
import com.github.catvod.utils.Path;
import com.github.catvod.utils.ProxyVideo;
import com.github.catvod.utils.QRCode;
import com.github.catvod.utils.ResUtil;
import com.github.catvod.utils.Util;
import com.google.gson.JsonObject;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantLock;
import okhttp3.Response;
public class AliYun {
private final Map<String, Map<String, String>> m3u8MediaMap;
private final Map<String, String> shareDownloadMap;
private final Map<String, String> downloadMap;
private final List<String> tempIds;
private final ReentrantLock lock;
private final Cache cache;
private ScheduledExecutorService service;
private String refreshToken;
private AlertDialog dialog;
private Share share;
private static class Loader {
static volatile AliYun INSTANCE = new AliYun();
}
public static AliYun get() {
return Loader.INSTANCE;
}
public File getCache() {
return Path.tv("aliyun");
}
private AliYun() {
Init.checkPermission();
lock = new ReentrantLock();
tempIds = new ArrayList<>();
downloadMap = new HashMap<>();
m3u8MediaMap = new HashMap<>();
shareDownloadMap = new HashMap<>();
cache = Cache.objectFrom(Path.read(getCache()));
}
public void setRefreshToken(String token) {
this.refreshToken = token;
}
public HashMap<String, String> getHeader() {
HashMap<String, String> headers = new HashMap<>();
headers.put("User-Agent", Util.CHROME);
headers.put("Referer", "https://www.aliyundrive.com/");
return headers;
}
private HashMap<String, String> getHeaders() {
HashMap<String, String> headers = getHeader();
headers.put("x-share-token", share.getShareToken());
headers.put("X-Canary", "client=Android,app=adrive,version=v4.3.1");
return headers;
}
private HashMap<String, String> getHeaderAuth() {
HashMap<String, String> headers = getHeader();
headers.put("x-share-token", share.getShareToken());
headers.put("X-Canary", "client=Android,app=adrive,version=v4.3.1");
if (cache.getUser().isAuthed()) headers.put("authorization", cache.getUser().getAuthorization());
return headers;
}
private HashMap<String, String> getHeaderOpen() {
HashMap<String, String> headers = getHeader();
headers.put("authorization", cache.getOAuth().getAuthorization());
return headers;
}
private boolean alist(String url, JsonObject param) {
String api = "https://api.xhofe.top/alist/ali_open/" + url;
OkResult result = OkHttp.post(api, param.toString(), getHeader());
SpiderDebug.log(result.getCode() + "," + api + "," + result.getBody());
if (isManyRequest(result.getBody())) return false;
cache.setOAuth(OAuth.objectFrom(result.getBody()));
return true;
}
private String post(String url, JsonObject param) {
url = url.startsWith("https") ? url : "https://api.aliyundrive.com/" + url;
OkResult result = OkHttp.post(url, param.toString(), getHeader());
SpiderDebug.log(result.getCode() + "," + url + "," + result.getBody());
return result.getBody();
}
private String auth(String url, String json, boolean retry) {
url = url.startsWith("https") ? url : "https://api.aliyundrive.com/" + url;
OkResult result = OkHttp.post(url, json, url.contains("file/list") ? getHeaders() : getHeaderAuth());
SpiderDebug.log(result.getCode() + "," + url + "," + result.getBody());
if (retry && result.getCode() == 401 && refreshAccessToken()) return auth(url, json, false);
if (retry && result.getCode() == 429) return auth(url, json, false);
return result.getBody();
}
private String oauth(String url, String json, boolean retry) {
url = url.startsWith("https") ? url : "https://open.aliyundrive.com/adrive/v1.0/" + url;
OkResult result = OkHttp.post(url, json, getHeaderOpen());
SpiderDebug.log(result.getCode() + "," + url + "," + result.getBody());
if (retry && (result.getCode() == 400 || result.getCode() == 401) && refreshOpenToken()) return oauth(url, json, false);
return result.getBody();
}
private boolean isManyRequest(String result) {
if (!result.contains("Too Many Requests")) return false;
Notify.show("洗洗睡吧Too Many Requests。");
cache.getOAuth().clean();
return true;
}
private boolean onTimeout() {
stopService();
return false;
}
private void refreshShareToken(String shareId) {
if (share != null && share.alive(shareId)) return;
SpiderDebug.log("refreshShareToken...");
JsonObject param = new JsonObject();
param.addProperty("share_id", shareId);
param.addProperty("share_pwd", "");
String json = post("v2/share_link/get_share_token", param);
share = Share.objectFrom(json).setShareId(shareId).setTime();
if (share.getShareToken().isEmpty()) Notify.show("來晚啦,該分享已失效。");
}
private boolean refreshAccessToken() {
try {
SpiderDebug.log("refreshAccessToken...");
JsonObject param = new JsonObject();
String token = cache.getUser().getRefreshToken();
if (token.isEmpty()) token = refreshToken;
if (token != null && token.startsWith("http")) token = OkHttp.string(token).trim();
param.addProperty("refresh_token", token);
param.addProperty("grant_type", "refresh_token");
String json = post("https://auth.aliyundrive.com/v2/account/token", param);
cache.setUser(User.objectFrom(json));
if (cache.getUser().getAccessToken().isEmpty()) throw new Exception(json);
return true;
} catch (Exception e) {
if (e instanceof TimeoutException) return onTimeout();
cache.getUser().clean();
e.printStackTrace();
stopService();
startFlow();
return true;
} finally {
while (cache.getUser().getAccessToken().isEmpty()) SystemClock.sleep(250);
}
}
private void getDriveId() {
SpiderDebug.log("Get Drive Id...");
String json = auth("https://user.aliyundrive.com/v2/user/get", "{}", true);
cache.setDrive(Drive.objectFrom(json));
}
private boolean oauthRequest() {
SpiderDebug.log("OAuth Request...");
JsonObject param = new JsonObject();
param.addProperty("authorize", 1);
param.addProperty("scope", "user:base,file:all:read,file:all:write");
String url = "https://open.aliyundrive.com/oauth/users/authorize?client_id=" + BuildConfig.CLIENT_ID + "&redirect_uri=https://alist.nn.ci/tool/aliyundrive/callback&scope=user:base,file:all:read,file:all:write&state=";
String json = auth(url, param.toString(), true);
return oauthRedirect(Code.objectFrom(json).getCode());
}
private boolean oauthRedirect(String code) {
SpiderDebug.log("OAuth Redirect...");
JsonObject param = new JsonObject();
param.addProperty("code", code);
param.addProperty("grant_type", "authorization_code");
return alist("code", param);
}
private boolean refreshOpenToken() {
if (cache.getOAuth().getRefreshToken().isEmpty()) return oauthRequest();
SpiderDebug.log("refreshOpenToken...");
JsonObject param = new JsonObject();
param.addProperty("grant_type", "refresh_token");
param.addProperty("refresh_token", cache.getOAuth().getRefreshToken());
return alist("token", param);
}
public Vod getVod(String url, String shareId, String fileId) {
refreshShareToken(shareId);
JsonObject param = new JsonObject();
param.addProperty("share_id", shareId);
Share share = Share.objectFrom(post("adrive/v3/share_link/get_share_by_anonymous", param));
List<Item> files = new ArrayList<>();
List<Item> subs = new ArrayList<>();
listFiles(shareId, new Item(getParentFileId(fileId, share)), files, subs);
Collections.sort(files);
List<String> playFrom = Arrays.asList("轉存原畫", "分享原畫", "代理普畫");
List<String> episode = new ArrayList<>();
List<String> playUrl = new ArrayList<>();
for (Item file : files) episode.add(file.getDisplayName() + "$" + shareId + "+" + file.getFileId() + findSubs(file.getName(), subs));
for (int i = 0; i < playFrom.size(); i++) playUrl.add(TextUtils.join("#", episode));
Vod vod = new Vod();
vod.setVodId(url);
vod.setVodContent(url);
vod.setVodPic(share.getAvatar());
vod.setVodName(share.getShareName());
vod.setVodPlayUrl(TextUtils.join("$$$", playUrl));
vod.setVodPlayFrom(TextUtils.join("$$$", playFrom));
vod.setTypeName("阿里雲盤");
return vod;
}
private void listFiles(String shareId, Item folder, List<Item> files, List<Item> subs) {
listFiles(shareId, folder, files, subs, "");
}
private void listFiles(String shareId, Item parent, List<Item> files, List<Item> subs, String marker) {
List<Item> folders = new ArrayList<>();
JsonObject param = new JsonObject();
param.addProperty("limit", 200);
param.addProperty("share_id", shareId);
param.addProperty("parent_file_id", parent.getFileId());
param.addProperty("order_by", "name");
param.addProperty("order_direction", "ASC");
if (marker.length() > 0) param.addProperty("marker", marker);
Item item = Item.objectFrom(auth("adrive/v3/file/list", param.toString(), true));
for (Item file : item.getItems()) {
if (file.getType().equals("folder")) {
folders.add(file);
} else if (file.getCategory().equals("video") || file.getCategory().equals("audio")) {
files.add(file.parent(parent.getName()));
} else if (Util.isSub(file.getExt())) {
subs.add(file);
}
}
if (item.getNextMarker().length() > 0) {
listFiles(shareId, parent, files, subs, item.getNextMarker());
}
for (Item folder : folders) {
listFiles(shareId, folder, files, subs);
}
}
private String getParentFileId(String fileId, Share share) {
if (!TextUtils.isEmpty(fileId)) return fileId;
if (share.getFileInfos().isEmpty()) return "";
Item item = share.getFileInfos().get(0);
return item.getType().equals("folder") ? item.getFileId() : "root";
}
private void pair(String name1, List<Item> items, List<Item> subs) {
for (Item item : items) {
String name2 = Util.removeExt(item.getName()).toLowerCase();
if (name1.contains(name2) || name2.contains(name1)) subs.add(item);
}
}
private String findSubs(String name1, List<Item> items) {
List<Item> subs = new ArrayList<>();
pair(Util.removeExt(name1).toLowerCase(), items, subs);
if (subs.isEmpty()) subs.addAll(items);
StringBuilder sb = new StringBuilder();
for (Item sub : subs) sb.append("+").append(Util.removeExt(sub.getName())).append("@@@").append(sub.getExt()).append("@@@").append(sub.getFileId());
return sb.toString();
}
public List<Sub> getSubs(String[] ids) {
List<Sub> sub = new ArrayList<>();
for (String text : ids) {
if (!text.contains("@@@")) continue;
String[] split = text.split("@@@");
String name = split[0];
String ext = split[1];
String url = Proxy.getUrl() + "?do=ali&type=sub&shareId=" + ids[0] + "&fileId=" + split[2];
sub.add(Sub.create().name(name).ext(ext).url(url));
}
return sub;
}
public String getShareDownloadUrl(String shareId, String fileId) {
try {
if (shareDownloadMap.containsKey(fileId) && shareDownloadMap.get(fileId) != null && !isExpire(shareDownloadMap.get(fileId))) return shareDownloadMap.get(fileId);
refreshShareToken(shareId);
SpiderDebug.log("getShareDownloadUrl..." + fileId);
JsonObject param = new JsonObject();
param.addProperty("file_id", fileId);
param.addProperty("share_id", shareId);
param.addProperty("expire_sec", 600);
String json = auth("v2/file/get_share_link_download_url", param.toString(), false);
String url = Json.parse(json).getAsJsonObject().get("download_url").getAsString();
shareDownloadMap.put(fileId, url);
return url;
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
public String getDownloadUrl(String shareId, String fileId) {
try {
if (downloadMap.containsKey(fileId) && downloadMap.get(fileId) != null && !isExpire(downloadMap.get(fileId))) return downloadMap.get(fileId);
refreshShareToken(shareId);
SpiderDebug.log("getDownloadUrl..." + fileId);
tempIds.add(0, copy(shareId, fileId));
JsonObject param = new JsonObject();
param.addProperty("file_id", tempIds.get(0));
param.addProperty("drive_id", cache.getDrive().getDriveId());
param.addProperty("expire_sec", 900);
String json = oauth("openFile/getDownloadUrl", param.toString(), true);
String url = Download.objectFrom(json).getUrl();
downloadMap.put(fileId, url);
return url;
} catch (Exception e) {
e.printStackTrace();
return "";
} finally {
Init.execute(this::deleteAll);
}
}
public Preview.Info getVideoPreviewPlayInfo(String shareId, String fileId) {
try {
refreshShareToken(shareId);
SpiderDebug.log("getVideoPreviewPlayInfo..." + fileId);
tempIds.add(0, copy(shareId, fileId));
JsonObject param = new JsonObject();
param.addProperty("file_id", tempIds.get(0));
param.addProperty("drive_id", cache.getDrive().getDriveId());
param.addProperty("category", "live_transcoding");
param.addProperty("url_expire_sec", 900);
String json = oauth("openFile/getVideoPreviewPlayInfo", param.toString(), true);
return Preview.objectFrom(json).getVideoPreviewPlayInfo();
} catch (Exception e) {
e.printStackTrace();
return new Preview.Info();
} finally {
Init.execute(this::deleteAll);
}
}
public String playerContent(String[] ids, String flag) {
if (flag.split("#")[0].equals("代理普畫")) {
return getPreviewContent(ids);
} else if (flag.split("#")[0].equals("轉存原畫")) {
return Result.get().url(proxyVideoUrl("open", ids[0], ids[1])).octet().subs(getSubs(ids)).header(getHeader()).string();
} else if (flag.split("#")[0].equals("分享原畫")) {
return Result.get().url(proxyVideoUrl("share", ids[0], ids[1])).octet().subs(getSubs(ids)).header(getHeader()).string();
} else {
return "";
}
}
private String getPreviewContent(String[] ids) {
Preview.Info info = getVideoPreviewPlayInfo(ids[0], ids[1]);
List<String> url = getPreviewUrl(info, ids[0], ids[1], true);
List<Sub> subs = getSubs(ids);
subs.addAll(getSubs(info));
return Result.get().url(url).m3u8().subs(subs).header(getHeader()).string();
}
private List<String> getPreviewUrl(Preview.Info info, String shareId, String fileId, boolean proxy) {
List<Preview.LiveTranscodingTask> tasks = info.getLiveTranscodingTaskList();
List<String> url = new ArrayList<>();
for (int i = tasks.size() - 1; i >= 0; i--) {
url.add(tasks.get(i).getTemplateId());
url.add(proxy ? proxyVideoUrl("preview", shareId, fileId, tasks.get(i).getTemplateId()) : tasks.get(i).getUrl());
}
return url;
}
private List<Sub> getSubs(Preview.Info info) {
List<Sub> subs = new ArrayList<>();
for (Preview.LiveTranscodingTask task : info.getLiveTranscodingSubtitleTaskList()) subs.add(task.getSub());
return subs;
}
private String copy(String shareId, String fileId) {
if (cache.getDrive().getDriveId().isEmpty()) getDriveId();
SpiderDebug.log("Copy..." + fileId);
String json = "{\"requests\":[{\"body\":{\"file_id\":\"%s\",\"share_id\":\"%s\",\"auto_rename\":true,\"to_parent_file_id\":\"root\",\"to_drive_id\":\"%s\"},\"headers\":{\"Content-Type\":\"application/json\"},\"id\":\"0\",\"method\":\"POST\",\"url\":\"/file/copy\"}],\"resource\":\"file\"}";
json = String.format(json, fileId, shareId, cache.getDrive().getDriveId());
Resp resp = Resp.objectFrom(auth("adrive/v2/batch", json, true));
return resp.getResponse().getBody().getFileId();
}
private void deleteAll() {
List<String> ids = new ArrayList<>(tempIds);
for (String id : ids) {
boolean deleted = delete(id);
if (deleted) tempIds.remove(id);
}
}
private boolean delete(String fileId) {
SpiderDebug.log("Delete..." + fileId);
String json = "{\"requests\":[{\"body\":{\"drive_id\":\"%s\",\"file_id\":\"%s\"},\"headers\":{\"Content-Type\":\"application/json\"},\"id\":\"%s\",\"method\":\"POST\",\"url\":\"/file/delete\"}],\"resource\":\"file\"}";
json = String.format(json, cache.getDrive().getDriveId(), fileId, fileId);
Resp resp = Resp.objectFrom(auth("adrive/v2/batch", json, true));
return resp.getResponse().getStatus() == 404;
}
private String proxyVideoUrl(String cate, String shareId, String fileId) {
return String.format(Proxy.getUrl() + "?do=ali&type=video&cate=%s&shareId=%s&fileId=%s", cate, shareId, fileId);
}
private String proxyVideoUrl(String cate, String shareId, String fileId, String templateId) {
return String.format(Proxy.getUrl() + "?do=ali&type=video&cate=%s&shareId=%s&fileId=%s&templateId=%s", cate, shareId, fileId, templateId);
}
private String proxyVideoUrl(String cate, String shareId, String fileId, String templateId, String mediaId) {
return String.format(Proxy.getUrl() + "?do=ali&type=video&cate=%s&shareId=%s&fileId=%s&templateId=%s&mediaId=%s", cate, shareId, fileId, templateId, mediaId);
}
private static boolean isExpire(String url) {
String expires = new UrlQuerySanitizer(url).getValue("x-oss-expires");
if (TextUtils.isEmpty(expires)) return false;
return Long.parseLong(expires) - getTimeStamp() <= 60;
}
private static long getTimeStamp() {
return System.currentTimeMillis() / 1000;
}
public Object[] proxyVideo(Map<String, String> params) throws Exception {
if (dialog != null && dialog.isShowing()) return null;
String templateId = params.get("templateId");
String shareId = params.get("shareId");
String mediaId = params.get("mediaId");
String fileId = params.get("fileId");
String cate = params.get("cate");
String downloadUrl = "";
if ("preview".equals(cate)) {
return new Object[]{200, "application/vnd.apple.mpegurl", new ByteArrayInputStream(getM3u8(shareId, fileId, templateId).getBytes())};
}
if ("open".equals(cate)) {
downloadUrl = getDownloadUrl(shareId, fileId);
} else if ("share".equals(cate)) {
downloadUrl = getShareDownloadUrl(shareId, fileId);
} else if ("m3u8".equals(cate)) {
lock.lock();
String mediaUrl = m3u8MediaMap.get(fileId).get(mediaId);
if (isExpire(mediaUrl)) {
getM3u8(shareId, fileId, templateId);
mediaUrl = m3u8MediaMap.get(fileId).get(mediaId);
}
lock.unlock();
downloadUrl = mediaUrl;
}
Map<String, String> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
for (String key : params.keySet()) {
if (key.equals("referer") || key.equals("icy-metadata") || key.equals("range") || key.equals("connection") || key.equals("accept-encoding") || key.equals("user-agent")) {
headers.put(key, params.get(key));
}
}
return new Object[]{ProxyVideo.proxy(downloadUrl, headers)};
}
private String getM3u8Url(String shareId, String fileId, String templateId) {
Preview.Info info = getVideoPreviewPlayInfo(shareId, fileId);
List<String> url = getPreviewUrl(info, shareId, fileId, false);
Map<String, String> previewMap = new HashMap<>();
for (int i = 0; i < url.size(); i = i + 2) {
previewMap.put(url.get(i), url.get(i + 1));
}
return previewMap.get(templateId);
}
private String getM3u8(String shareId, String fileId, String templateId) {
String m3u8Url = getM3u8Url(shareId, fileId, templateId);
String m3u8 = OkHttp.string(m3u8Url, getHeader());
String[] m3u8Arr = m3u8.split("\n");
List<String> listM3u8 = new ArrayList<>();
Map<String, String> media = new HashMap<>();
String site = m3u8Url.substring(0, m3u8Url.lastIndexOf("/")) + "/";
int mediaId = 0;
for (String oneLine : m3u8Arr) {
String thisOne = oneLine;
if (oneLine.contains("x-oss-expires")) {
media.put(String.valueOf(mediaId), site + thisOne);
thisOne = proxyVideoUrl("m3u8", shareId, fileId, templateId, String.valueOf(mediaId));
mediaId++;
}
listM3u8.add(thisOne);
}
m3u8MediaMap.put(fileId, media);
return TextUtils.join("\n", listM3u8);
}
public Object[] proxySub(Map<String, String> params) throws Exception {
String fileId = params.get("fileId");
String shareId = params.get("shareId");
Response res = OkHttp.newCall(getDownloadUrl(shareId, fileId), getHeaderAuth());
byte[] body = Util.toUtf8(res.body().bytes());
Object[] result = new Object[3];
result[0] = 200;
result[1] = "application/octet-stream";
result[2] = new ByteArrayInputStream(body);
return result;
}
private void startFlow() {
Init.run(this::showInput);
}
private void showInput() {
try {
int margin = ResUtil.dp2px(16);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
FrameLayout frame = new FrameLayout(Init.context());
params.setMargins(margin, margin, margin, margin);
EditText input = new EditText(Init.context());
frame.addView(input, params);
dialog = new AlertDialog.Builder(Init.getActivity()).setTitle("請輸入Token").setView(frame).setNeutralButton("QRCode", (dialog, which) -> onNeutral()).setNegativeButton(android.R.string.cancel, null).setPositiveButton(android.R.string.ok, (dialog, which) -> onPositive(input.getText().toString())).show();
} catch (Exception ignored) {
}
}
private void onNeutral() {
dismiss();
Init.execute(this::getQRCode);
}
private void onPositive(String text) {
dismiss();
Init.execute(() -> {
if (text.startsWith("http")) setToken(OkHttp.string(text));
else setToken(text);
});
}
private void getQRCode() {
String json = OkHttp.string("https://passport.aliyundrive.com/newlogin/qrcode/generate.do?appName=aliyun_drive&fromSite=52&appName=aliyun_drive&appEntrance=web&isMobile=false&lang=zh_CN&returnUrl=&bizParams=&_bx-v=2.2.3");
Data data = Data.objectFrom(json).getContent().getData();
Init.run(() -> openApp(json, data));
}
private void openApp(String json, Data data) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClassName("com.alicloud.databox", "com.taobao.login4android.scan.QrScanActivity");
intent.putExtra("key_scanParam", json);
Init.getActivity().startActivity(intent);
} catch (Exception e) {
showQRCode(data);
} finally {
Init.execute(() -> startService(data.getParams()));
}
}
private void showQRCode(Data data) {
try {
int size = ResUtil.dp2px(240);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(size, size);
ImageView image = new ImageView(Init.context());
image.setScaleType(ImageView.ScaleType.CENTER_CROP);
image.setImageBitmap(QRCode.getBitmap(data.getCodeContent(), size, 2));
FrameLayout frame = new FrameLayout(Init.context());
params.gravity = Gravity.CENTER;
frame.addView(image, params);
dialog = new AlertDialog.Builder(Init.getActivity()).setView(frame).setOnCancelListener(this::dismiss).setOnDismissListener(this::dismiss).show();
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
Notify.show("請使用阿里雲盤 App 掃描二維碼");
} catch (Exception ignored) {
}
}
private void startService(Map<String, String> params) {
service = Executors.newScheduledThreadPool(1);
service.scheduleAtFixedRate(() -> {
String result = OkHttp.post("https://passport.aliyundrive.com/newlogin/qrcode/query.do?appName=aliyun_drive&fromSite=52&_bx-v=2.2.3", params);
Data data = Data.objectFrom(result).getContent().getData();
if (data.hasToken()) setToken(data.getToken());
}, 1, 1, TimeUnit.SECONDS);
}
private void setToken(String value) {
cache.getUser().setRefreshToken(value);
SpiderDebug.log("Token:" + value);
Notify.show("Token:" + value);
refreshAccessToken();
stopService();
}
private void stopService() {
if (service != null) service.shutdownNow();
Init.run(this::dismiss);
}
private void dismiss(DialogInterface dialog) {
stopService();
}
private void dismiss() {
try {
if (dialog != null) dialog.dismiss();
} catch (Exception ignored) {
}
}
}

View File

@@ -0,0 +1,49 @@
package com.github.catvod.bean;
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.List;
public class Class {
@SerializedName("type_id")
private String typeId;
@SerializedName("type_name")
private String typeName;
@SerializedName("type_flag")
private String typeFlag;
public static List<Class> arrayFrom(String str) {
Type listType = new TypeToken<List<Class>>() {}.getType();
return new Gson().fromJson(str, listType);
}
public Class(String typeId) {
this(typeId, typeId);
}
public Class(String typeId, String typeName) {
this(typeId, typeName, null);
}
public Class(String typeId, String typeName, String typeFlag) {
this.typeId = typeId;
this.typeName = typeName;
this.typeFlag = typeFlag;
}
public String getTypeId() {
return typeId;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Class)) return false;
Class it = (Class) obj;
return getTypeId().equals(it.getTypeId());
}
}

View File

@@ -0,0 +1,39 @@
package com.github.catvod.bean;
import com.google.gson.annotations.SerializedName;
import java.util.List;
public class Filter {
@SerializedName("key")
private String key;
@SerializedName("name")
private String name;
@SerializedName("value")
private List<Value> value;
public Filter(String key, String name, List<Value> value) {
this.key = key;
this.name = name;
this.value = value;
}
public static class Value {
@SerializedName("n")
private String n;
@SerializedName("v")
private String v;
public Value(String value) {
this.n = value;
this.v = value;
}
public Value(String n, String v) {
this.n = n;
this.v = v;
}
}
}

View File

@@ -0,0 +1,240 @@
package com.github.catvod.bean;
import com.github.catvod.utils.Util;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import org.json.JSONObject;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class Result {
@SerializedName("class")
private List<Class> classes;
@SerializedName("list")
private List<Vod> list;
@SerializedName("filters")
private LinkedHashMap<String, List<Filter>> filters;
@SerializedName("header")
private String header;
@SerializedName("format")
private String format;
@SerializedName("danmaku")
private String danmaku;
@SerializedName("msg")
private String msg;
@SerializedName("url")
private Object url;
@SerializedName("subs")
private List<Sub> subs;
@SerializedName("parse")
private int parse;
@SerializedName("jx")
private int jx;
@SerializedName("page")
private Integer page;
@SerializedName("pagecount")
private Integer pagecount;
@SerializedName("limit")
private Integer limit;
@SerializedName("total")
private Integer total;
public static Result objectFrom(String str) {
return new Gson().fromJson(str, Result.class);
}
public static String string(List<Class> classes, List<Vod> list, LinkedHashMap<String, List<Filter>> filters) {
return Result.get().classes(classes).vod(list).filters(filters).string();
}
public static String string(List<Class> classes, List<Vod> list, JSONObject filters) {
return Result.get().classes(classes).vod(list).filters(filters).string();
}
public static String string(Integer page,Integer pagecount,Integer limit,Integer total,List<Vod> list){
return Result.get().page(page,pagecount,limit,total).vod(list).string();
}
public static String string(List<Class> classes, List<Vod> list, JsonElement filters) {
return Result.get().classes(classes).vod(list).filters(filters).string();
}
public static String string(List<Class> classes, LinkedHashMap<String, List<Filter>> filters) {
return Result.get().classes(classes).filters(filters).string();
}
public static String string(List<Class> classes, JsonElement filters) {
return Result.get().classes(classes).filters(filters).string();
}
public static String string(List<Class> classes, JSONObject filters) {
return Result.get().classes(classes).filters(filters).string();
}
public static String string(List<Class> classes, List<Vod> list) {
return Result.get().classes(classes).vod(list).string();
}
public static String string(List<Vod> list) {
return Result.get().vod(list).string();
}
public static String string(Vod item) {
return Result.get().vod(item).string();
}
public static String error(String msg) {
return Result.get().vod(Collections.emptyList()).msg(msg).string();
}
public static Result get() {
return new Result();
}
public Result classes(List<Class> classes) {
this.classes = classes;
return this;
}
public Result vod(List<Vod> list) {
this.list = list;
return this;
}
public Result vod(Vod item) {
this.list = Arrays.asList(item);
return this;
}
public Result filters(LinkedHashMap<String, List<Filter>> filters) {
this.filters = filters;
return this;
}
public Result filters(JSONObject object) {
if (object == null) return this;
Type listType = new TypeToken<LinkedHashMap<String, List<Filter>>>() {}.getType();
this.filters = new Gson().fromJson(object.toString(), listType);
return this;
}
public Result filters(JsonElement element) {
if (element == null) return this;
Type listType = new TypeToken<LinkedHashMap<String, List<Filter>>>() {}.getType();
this.filters = new Gson().fromJson(element.toString(), listType);
return this;
}
public Result header(Map<String, String> header) {
if (header.isEmpty()) return this;
this.header = new Gson().toJson(header);
return this;
}
public Result chrome() {
Map<String, String> header = new HashMap<>();
header.put("User-Agent", Util.CHROME);
header(header);
return this;
}
public Result parse() {
this.parse = 1;
return this;
}
public Result parse(int parse) {
this.parse = parse;
return this;
}
public Result jx() {
this.jx = 1;
return this;
}
public Result url(String url) {
this.url = url;
return this;
}
public Result url(List<String> url) {
this.url = url;
return this;
}
public Result danmaku(String danmaku) {
this.danmaku = danmaku;
return this;
}
public Result msg(String msg) {
this.msg = msg;
return this;
}
public Result format(String format) {
this.format = format;
return this;
}
public Result subs(List<Sub> subs) {
this.subs = subs;
return this;
}
public Result dash() {
this.format = "application/dash+xml";
return this;
}
public Result m3u8() {
this.format = "application/x-mpegURL";
return this;
}
public Result rtsp() {
this.format = "application/x-rtsp";
return this;
}
public Result octet() {
this.format = "application/octet-stream";
return this;
}
public Result page() {
return page(1, 1, 0, 1);
}
public Result page(int page, int count, int limit, int total) {
this.page = page > 0 ? page : Integer.MAX_VALUE;
this.limit = limit > 0 ? limit : Integer.MAX_VALUE;
this.total = total > 0 ? total : Integer.MAX_VALUE;
this.pagecount = count > 0 ? count : Integer.MAX_VALUE;
return this;
}
public List<Vod> getList() {
return list == null ? Collections.emptyList() : list;
}
public String string() {
return toString();
}
@Override
public String toString() {
return new Gson().newBuilder().disableHtmlEscaping().create().toJson(this);
}
}

View File

@@ -0,0 +1,51 @@
package com.github.catvod.bean;
import com.google.gson.annotations.SerializedName;
public class Sub {
@SerializedName("url")
private String url;
@SerializedName("name")
private String name;
@SerializedName("lang")
private String lang;
@SerializedName("format")
private String format;
public static Sub create() {
return new Sub();
}
public Sub name(String name) {
this.name = name;
return this;
}
public Sub url(String url) {
this.url = url;
return this;
}
public Sub lang(String lang) {
this.lang = lang;
return this;
}
public Sub format(String format) {
this.format = format;
return this;
}
public Sub ext(String ext) {
switch (ext) {
case "vtt":
return format("text/vtt");
case "ass":
case "ssa":
return format("text/x-ssa");
default:
return format("application/x-subrip");
}
}
}

View File

@@ -0,0 +1,174 @@
package com.github.catvod.bean;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
public class Vod {
@SerializedName("type_name")
private String typeName;
@SerializedName("vod_id")
private String vodId;
@SerializedName("vod_name")
private String vodName;
@SerializedName("vod_pic")
private String vodPic;
@SerializedName("vod_remarks")
private String vodRemarks;
@SerializedName("vod_year")
private String vodYear;
@SerializedName("vod_area")
private String vodArea;
@SerializedName("vod_actor")
private String vodActor;
@SerializedName("vod_director")
private String vodDirector;
@SerializedName("vod_content")
private String vodContent;
@SerializedName("vod_play_from")
private String vodPlayFrom;
@SerializedName("vod_play_url")
private String vodPlayUrl;
@SerializedName("vod_tag")
private String vodTag;
@SerializedName("style")
private Style style;
public static Vod objectFrom(String str) {
Vod item = new Gson().fromJson(str, Vod.class);
return item == null ? new Vod() : item;
}
public Vod() {
}
public Vod(String vodId, String vodName, String vodPic) {
setVodId(vodId);
setVodName(vodName);
setVodPic(vodPic);
}
public Vod(String vodId, String vodName, String vodPic, String vodRemarks) {
setVodId(vodId);
setVodName(vodName);
setVodPic(vodPic);
setVodRemarks(vodRemarks);
}
public Vod(String vodId, String vodName, String vodPic, String vodRemarks, Style style) {
setVodId(vodId);
setVodName(vodName);
setVodPic(vodPic);
setVodRemarks(vodRemarks);
setStyle(style);
}
public Vod(String vodId, String vodName, String vodPic, String vodRemarks, boolean folder) {
setVodId(vodId);
setVodName(vodName);
setVodPic(vodPic);
setVodRemarks(vodRemarks);
setVodTag(folder ? "folder" : "file");
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
public void setVodId(String vodId) {
this.vodId = vodId;
}
public void setVodName(String vodName) {
this.vodName = vodName;
}
public void setVodPic(String vodPic) {
this.vodPic = vodPic;
}
public void setVodRemarks(String vodRemarks) {
this.vodRemarks = vodRemarks;
}
public void setVodYear(String vodYear) {
this.vodYear = vodYear;
}
public void setVodArea(String vodArea) {
this.vodArea = vodArea;
}
public void setVodActor(String vodActor) {
this.vodActor = vodActor;
}
public void setVodDirector(String vodDirector) {
this.vodDirector = vodDirector;
}
public void setVodContent(String vodContent) {
this.vodContent = vodContent;
}
public String getVodContent() {
return vodContent;
}
public void setVodPlayFrom(String vodPlayFrom) {
this.vodPlayFrom = vodPlayFrom;
}
public void setVodPlayUrl(String vodPlayUrl) {
this.vodPlayUrl = vodPlayUrl;
}
public String getVodPlayUrl() {
return vodPlayUrl;
}
public void setVodTag(String vodTag) {
this.vodTag = vodTag;
}
public void setStyle(Style style) {
this.style = style;
}
public static class Style {
@SerializedName("type")
private String type;
@SerializedName("ratio")
private Float ratio;
public static Style rect() {
return rect(0.75f);
}
public static Style rect(float ratio) {
return new Style("rect", ratio);
}
public static Style oval() {
return new Style("oval", 1.0f);
}
public static Style full() {
return new Style("full");
}
public static Style list() {
return new Style("list");
}
public Style(String type) {
this.type = type;
}
public Style(String type, Float ratio) {
this.type = type;
this.ratio = ratio;
}
}
}

View File

@@ -0,0 +1,66 @@
package com.github.catvod.bean.ali;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.util.List;
public class Biz {
@SerializedName("pds_login_result")
private Biz pdsLoginResult;
@SerializedName("role")
private String role;
@SerializedName("isFirstLogin")
private Boolean isFirstLogin;
@SerializedName("needLink")
private Boolean needLink;
@SerializedName("loginType")
private String loginType;
@SerializedName("nickName")
private String nickName;
@SerializedName("needRpVerify")
private Boolean needRpVerify;
@SerializedName("avatar")
private String avatar;
@SerializedName("accessToken")
private String accessToken;
@SerializedName("userName")
private String userName;
@SerializedName("userId")
private String userId;
@SerializedName("defaultDriveId")
private String defaultDriveId;
@SerializedName("existLink")
private List<?> existLink;
@SerializedName("expiresIn")
private Integer expiresIn;
@SerializedName("expireTime")
private String expireTime;
@SerializedName("requestId")
private String requestId;
@SerializedName("dataPinSetup")
private Boolean dataPinSetup;
@SerializedName("state")
private String state;
@SerializedName("tokenType")
private String tokenType;
@SerializedName("dataPinSaved")
private Boolean dataPinSaved;
@SerializedName("refreshToken")
private String refreshToken;
@SerializedName("status")
private String status;
public static Biz objectFrom(String str) {
return new Gson().fromJson(str, Biz.class);
}
public Biz getPdsLoginResult() {
return pdsLoginResult;
}
public String getRefreshToken() {
return refreshToken;
}
}

View File

@@ -0,0 +1,58 @@
package com.github.catvod.bean.ali;
import com.github.catvod.api.AliYun;
import com.github.catvod.spider.Init;
import com.github.catvod.utils.Path;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
public class Cache {
@SerializedName("user")
private User user;
@SerializedName("oauth")
private OAuth oauth;
@SerializedName("drive")
private Drive drive;
public static Cache objectFrom(String str) {
Cache item = new Gson().fromJson(str, Cache.class);
return item == null ? new Cache() : item;
}
public User getUser() {
return user == null ? new User() : user;
}
public void setUser(User user) {
this.user = user;
this.save();
}
public OAuth getOAuth() {
return oauth == null ? new OAuth() : oauth;
}
public void setOAuth(OAuth oauth) {
this.oauth = oauth;
this.save();
}
public Drive getDrive() {
return drive == null ? new Drive() : drive;
}
public void setDrive(Drive drive) {
this.drive = drive;
this.save();
}
public void save() {
Init.execute(() -> Path.write(AliYun.get().getCache(), toString()));
}
@Override
public String toString() {
return new Gson().toJson(this);
}
}

View File

@@ -0,0 +1,24 @@
package com.github.catvod.bean.ali;
import android.text.TextUtils;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
public class Code {
@SerializedName("redirectUri")
private String redirectUri;
public static Code objectFrom(String str) {
return new Gson().fromJson(str, Code.class);
}
public String getRedirectUri() {
return TextUtils.isEmpty(redirectUri) ? "" : redirectUri;
}
public String getCode() {
return getRedirectUri().split("code=")[1];
}
}

View File

@@ -0,0 +1,88 @@
package com.github.catvod.bean.ali;
import android.util.Base64;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.util.HashMap;
import java.util.Map;
public class Data {
@SerializedName("data")
private Data data;
@SerializedName("content")
private Data content;
@SerializedName("t")
private String t;
@SerializedName("ck")
private String ck;
@SerializedName("codeContent")
private String codeContent;
@SerializedName("qrCodeStatus")
private String qrCodeStatus;
@SerializedName("bizExt")
private String bizExt;
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 Data getData() {
return data == null ? new Data() : data;
}
public Data getContent() {
return content == null ? new Data() : content;
}
public String getT() {
return t == null ? "" : t;
}
public String getCk() {
return ck == null ? "" : ck;
}
public String getCodeContent() {
return codeContent == null ? "" : codeContent;
}
public String getQrCodeStatus() {
return qrCodeStatus == null ? "" : qrCodeStatus;
}
public String getBizExt() {
return bizExt == null ? "" : bizExt;
}
public String getToken() {
return Biz.objectFrom(new String(Base64.decode(getBizExt(), Base64.DEFAULT))).getPdsLoginResult().getRefreshToken();
}
public boolean hasToken() {
return getQrCodeStatus().equals("CONFIRMED") && getBizExt().length() > 0;
}
public Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put("t", getT());
params.put("ck", getCk());
params.put("appName", "aliyun_drive");
params.put("appEntrance", "web");
params.put("isMobile", "false");
params.put("lang", "zh_CN");
params.put("returnUrl", "");
params.put("fromSite", "52");
params.put("bizParams", "");
params.put("navlanguage", "zh-CN");
params.put("navPlatform", "MacIntel");
return params;
}
}

View File

@@ -0,0 +1,32 @@
package com.github.catvod.bean.ali;
import android.text.TextUtils;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
public class Download {
@SerializedName("url")
private String url;
@SerializedName("file_id")
private String fileId;
@SerializedName("expiration")
private String expiration;
public static Download objectFrom(String str) {
return new Gson().fromJson(str, Download.class);
}
public String getUrl() {
return TextUtils.isEmpty(url) ? "" : url;
}
public String getFileId() {
return TextUtils.isEmpty(fileId) ? "" : fileId;
}
public String getExpiration() {
return TextUtils.isEmpty(expiration) ? "" : expiration;
}
}

View File

@@ -0,0 +1,31 @@
package com.github.catvod.bean.ali;
import android.text.TextUtils;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
public class Drive {
@SerializedName("default_drive_id")
private String defaultDriveId;
@SerializedName("resource_drive_id")
private String resourceDriveId;
public static Drive objectFrom(String str) {
Drive item = new Gson().fromJson(str, Drive.class);
return item == null ? new Drive() : item;
}
private String getDefaultDriveId() {
return TextUtils.isEmpty(defaultDriveId) ? "" : defaultDriveId;
}
private String getResourceDriveId() {
return TextUtils.isEmpty(resourceDriveId) ? "" : resourceDriveId;
}
public String getDriveId() {
return getResourceDriveId().isEmpty() ? getDefaultDriveId() : getResourceDriveId();
}
}

View File

@@ -0,0 +1,97 @@
package com.github.catvod.bean.ali;
import android.text.TextUtils;
import com.github.catvod.utils.Util;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Item implements Comparable<Item> {
@SerializedName("items")
private List<Item> items;
@SerializedName("next_marker")
private String nextMarker;
@SerializedName("file_id")
private String fileId;
@SerializedName("share_id")
private String shareId;
@SerializedName("name")
private String name;
@SerializedName("type")
private String type;
@SerializedName("file_extension")
private String fileExtension;
@SerializedName("category")
private String category;
@SerializedName("size")
private double size;
@SerializedName("parent")
private String parent;
public static Item objectFrom(String str) {
return new Gson().fromJson(str, Item.class);
}
public Item(String fileId) {
this.fileId = fileId;
}
public List<Item> getItems() {
return items == null ? Collections.emptyList() : items;
}
public String getNextMarker() {
return TextUtils.isEmpty(nextMarker) ? "" : nextMarker;
}
public String getFileId() {
return TextUtils.isEmpty(fileId) ? "" : fileId;
}
public String getName() {
return TextUtils.isEmpty(name) ? "" : name;
}
public String getType() {
return TextUtils.isEmpty(type) ? "" : type;
}
public String getExt() {
return TextUtils.isEmpty(fileExtension) ? "" : fileExtension;
}
public String getCategory() {
return TextUtils.isEmpty(category) ? "" : category;
}
public String getSize() {
return size == 0 ? "" : "[" + Util.getSize(size) + "]";
}
public String getParent() {
return TextUtils.isEmpty(parent) ? "" : "[" + parent + "]";
}
public Item parent(String parent) {
this.parent = parent;
return this;
}
public String getDisplayName() {
return TextUtils.join(" ", Arrays.asList(getParent(), getName(), getSize())).trim();
}
public String getSortName() {
return TextUtils.join(" ", Arrays.asList(getParent(), Util.getDigit(getName()))).trim();
}
@Override
public int compareTo(Item item) {
return getSortName().compareTo(item.getSortName());
}
}

View File

@@ -0,0 +1,42 @@
package com.github.catvod.bean.ali;
import android.text.TextUtils;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
public class OAuth {
@SerializedName("token_type")
private String tokenType;
@SerializedName("access_token")
private String accessToken;
@SerializedName("refresh_token")
private String refreshToken;
public static OAuth objectFrom(String str) {
OAuth item = new Gson().fromJson(str, OAuth.class);
return item == null ? new OAuth() : item;
}
public String getTokenType() {
return TextUtils.isEmpty(tokenType) ? "" : tokenType;
}
public String getAccessToken() {
return TextUtils.isEmpty(accessToken) ? "" : accessToken;
}
public String getRefreshToken() {
return TextUtils.isEmpty(refreshToken) ? "" : refreshToken;
}
public String getAuthorization() {
return getTokenType() + " " + getAccessToken();
}
public void clean() {
this.refreshToken = "";
this.accessToken = "";
}
}

View File

@@ -0,0 +1,84 @@
package com.github.catvod.bean.ali;
import android.text.TextUtils;
import com.github.catvod.bean.Sub;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.util.Collections;
import java.util.List;
public class Preview {
@SerializedName("video_preview_play_info")
private Info videoPreviewPlayInfo;
@SerializedName("drive_id")
private String driveId;
@SerializedName("file_id")
private String fileId;
public static Preview objectFrom(String str) {
return new Gson().fromJson(str, Preview.class);
}
public Info getVideoPreviewPlayInfo() {
return videoPreviewPlayInfo == null ? new Info() : videoPreviewPlayInfo;
}
public String getDriveId() {
return TextUtils.isEmpty(driveId) ? "" : driveId;
}
public String getFileId() {
return TextUtils.isEmpty(fileId) ? "" : fileId;
}
public static class Info {
@SerializedName("live_transcoding_task_list")
private List<LiveTranscodingTask> liveTranscodingTaskList;
@SerializedName("live_transcoding_subtitle_task_list")
private List<LiveTranscodingTask> liveTranscodingSubtitleTaskList;
public List<LiveTranscodingTask> getLiveTranscodingTaskList() {
return liveTranscodingTaskList == null ? Collections.emptyList() : liveTranscodingTaskList;
}
public List<LiveTranscodingTask> getLiveTranscodingSubtitleTaskList() {
return liveTranscodingSubtitleTaskList == null ? Collections.emptyList() : liveTranscodingSubtitleTaskList;
}
}
public static class LiveTranscodingTask {
@SerializedName("template_id")
private String templateId;
@SerializedName("language")
private String language;
@SerializedName("status")
private String status;
@SerializedName("url")
private String url;
public String getTemplateId() {
return TextUtils.isEmpty(templateId) ? "" : templateId;
}
public String getLanguage() {
return TextUtils.isEmpty(language) ? "" : language;
}
public String getStatus() {
return TextUtils.isEmpty(status) ? "" : status;
}
public String getUrl() {
return TextUtils.isEmpty(url) ? "" : url;
}
public Sub getSub() {
return Sub.create().url(getUrl()).name(getLanguage()).lang(getLanguage()).ext("vtt");
}
}
}

View File

@@ -0,0 +1,79 @@
package com.github.catvod.bean.ali;
import android.text.TextUtils;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.util.Collections;
import java.util.List;
public class Resp {
@SerializedName("responses")
private List<Resp> responses;
@SerializedName("body")
private Body body;
@SerializedName("id")
private String id;
@SerializedName("status")
private int status;
public static Resp objectFrom(String str) {
return new Gson().fromJson(str, Resp.class);
}
public List<Resp> getResponses() {
return responses == null ? Collections.emptyList() : responses;
}
public Resp getResponse() {
return getResponses().isEmpty() ? new Resp() : getResponses().get(0);
}
public Body getBody() {
return body == null ? new Body() : body;
}
public String getId() {
return TextUtils.isEmpty(id) ? "" : id;
}
public int getStatus() {
return status;
}
public static class Body {
@SerializedName("domain_id")
private String domainId;
@SerializedName("drive_id")
private String driveId;
@SerializedName("file_id")
private String fileId;
@SerializedName("code")
private String code;
@SerializedName("message")
private String message;
public String getDomainId() {
return TextUtils.isEmpty(domainId) ? "" : domainId;
}
public String getDriveId() {
return TextUtils.isEmpty(driveId) ? "" : driveId;
}
public String getFileId() {
return TextUtils.isEmpty(fileId) ? "" : fileId;
}
public String getCode() {
return TextUtils.isEmpty(code) ? "" : code;
}
public String getMessage() {
return TextUtils.isEmpty(message) ? "" : message;
}
}
}

View File

@@ -0,0 +1,130 @@
package com.github.catvod.bean.ali;
import android.text.TextUtils;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.util.Collections;
import java.util.List;
public class Share {
@SerializedName("share_id")
private String shareId;
@SerializedName("share_token")
private String shareToken;
@SerializedName("expire_time")
private String expireTime;
@SerializedName("expires_in")
private int expiresIn;
@SerializedName("creator_id")
private String creatorId;
@SerializedName("creator_name")
private String creatorName;
@SerializedName("creator_phone")
private String creatorPhone;
@SerializedName("expiration")
private String expiration;
@SerializedName("updated_at")
private String updatedAt;
@SerializedName("vip")
private String vip;
@SerializedName("avatar")
private String avatar;
@SerializedName("share_name")
private String shareName;
@SerializedName("display_name")
private String displayName;
@SerializedName("share_title")
private String shareTitle;
@SerializedName("has_pwd")
private boolean hasPwd;
@SerializedName("file_infos")
private List<Item> fileInfos;
private long time;
public static Share objectFrom(String str) {
return new Gson().fromJson(str, Share.class);
}
public String getShareId() {
return TextUtils.isEmpty(shareId) ? "" : shareId;
}
public String getShareToken() {
return TextUtils.isEmpty(shareToken) ? "" : shareToken;
}
public String getExpireTime() {
return TextUtils.isEmpty(expireTime) ? "" : expireTime;
}
public int getExpiresIn() {
return expiresIn;
}
public String getCreatorId() {
return TextUtils.isEmpty(creatorId) ? "" : creatorId;
}
public String getCreatorName() {
return TextUtils.isEmpty(creatorName) ? "" : creatorName;
}
public String getCreatorPhone() {
return TextUtils.isEmpty(creatorPhone) ? "" : creatorPhone;
}
public String getExpiration() {
return TextUtils.isEmpty(expiration) ? "" : expiration;
}
public String getUpdatedAt() {
return TextUtils.isEmpty(updatedAt) ? "" : updatedAt;
}
public String getVip() {
return TextUtils.isEmpty(vip) ? "" : vip;
}
public String getAvatar() {
return TextUtils.isEmpty(avatar) ? "" : avatar;
}
public String getShareName() {
return TextUtils.isEmpty(shareName) ? "" : shareName;
}
public String getDisplayName() {
return TextUtils.isEmpty(displayName) ? "" : displayName;
}
public String getShareTitle() {
return TextUtils.isEmpty(shareTitle) ? "" : shareTitle;
}
public boolean isHasPwd() {
return hasPwd;
}
public List<Item> getFileInfos() {
return fileInfos == null ? Collections.emptyList() : fileInfos;
}
public Share setTime() {
this.time = System.currentTimeMillis() + 60 * 60 * 1000;
return this;
}
public Share setShareId(String shareId) {
this.shareId = shareId;
return this;
}
public boolean alive(String shareId) {
return getShareId().equals(shareId) && System.currentTimeMillis() <= time;
}
}

View File

@@ -0,0 +1,50 @@
package com.github.catvod.bean.ali;
import android.text.TextUtils;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
public class User {
@SerializedName("token_type")
private String tokenType;
@SerializedName("access_token")
private String accessToken;
@SerializedName("refresh_token")
private String refreshToken;
public static User objectFrom(String str) {
User item = new Gson().fromJson(str, User.class);
return item == null ? new User() : item;
}
public String getTokenType() {
return TextUtils.isEmpty(tokenType) ? "" : tokenType;
}
public String getAccessToken() {
return TextUtils.isEmpty(accessToken) ? "" : accessToken;
}
public String getRefreshToken() {
return TextUtils.isEmpty(refreshToken) ? "" : refreshToken;
}
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
public String getAuthorization() {
return getTokenType() + " " + getAccessToken();
}
public boolean isAuthed() {
return getTokenType().length() > 0 && getAccessToken().length() > 0;
}
public void clean() {
this.refreshToken = "";
this.accessToken = "";
}
}

View File

@@ -0,0 +1,184 @@
package com.github.catvod.bean.alist;
import android.net.Uri;
import android.text.TextUtils;
import com.github.catvod.bean.Class;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Image;
import com.github.catvod.utils.Util;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Drive {
@SerializedName("drives")
private List<Drive> drives;
@SerializedName("params")
private List<Param> params;
@SerializedName("login")
private Login login;
@SerializedName("vodPic")
private String vodPic;
@SerializedName("name")
private String name;
@SerializedName("server")
private String server;
@SerializedName("version")
private int version;
@SerializedName("path")
private String path;
@SerializedName("token")
private String token;
@SerializedName("search")
private Boolean search;
@SerializedName("hidden")
private Boolean hidden;
public static Drive objectFrom(String str) {
return new Gson().fromJson(str, Drive.class);
}
public List<Drive> getDrives() {
return drives == null ? new ArrayList<>() : drives;
}
public List<Param> getParams() {
return params == null ? new ArrayList<>() : params;
}
public Login getLogin() {
return login;
}
public Drive(String name) {
this.name = name;
}
public String getVodPic() {
return TextUtils.isEmpty(vodPic) ? Image.FOLDER : vodPic;
}
public String getName() {
return TextUtils.isEmpty(name) ? "" : name;
}
public String getServer() {
return TextUtils.isEmpty(server) ? "" : server;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public String getPath() {
return TextUtils.isEmpty(path) ? "" : path;
}
public void setPath(String path) {
this.path = TextUtils.isEmpty(path) ? "" : path;
}
public String getToken() {
return TextUtils.isEmpty(token) ? "" : token;
}
public void setToken(String token) {
this.token = token;
}
public Boolean search() {
return search == null || search;
}
public Boolean hidden() {
return hidden != null && hidden;
}
public boolean isNew() {
return getVersion() == 3;
}
public Class toType() {
return new Class(getName(), getName(), "1");
}
public String getHost() {
return getServer().replace(getPath(), "");
}
public String settingsApi() {
return getHost() + "/api/public/settings";
}
public String loginApi() {
return getHost() + "/api/auth/login";
}
public String listApi() {
return getHost() + (isNew() ? "/api/fs/list" : "/api/public/path");
}
public String getApi() {
return getHost() + (isNew() ? "/api/fs/get" : "/api/public/path");
}
public String searchApi() {
return getHost() + (isNew() ? "/api/fs/search" : "/api/public/search");
}
public String searchApi(String param) {
return getHost() + "/search?box=" + param + "&url=&type=video";
}
public Drive check() {
if (path == null) setPath(Uri.parse(getServer()).getPath());
if (version == 0) setVersion(OkHttp.string(settingsApi()).contains("v2.") ? 2 : 3);
return this;
}
public String params(String keyword) {
if (isNew()) {
Map<String, Object> params = new HashMap<>();
params.put("keywords", keyword);
params.put("page", 1);
params.put("parent", "/");
params.put("per_page", 100);
return new Gson().toJson(params);
} else {
Map<String, Object> params = new HashMap<>();
params.put("keyword", keyword);
params.put("path", "/");
return new Gson().toJson(params);
}
}
public HashMap<String, String> getHeader() {
HashMap<String, String> headers = new HashMap<>();
headers.put("User-Agent", Util.CHROME);
if (!getToken().isEmpty()) headers.put("Authorization", token);
return headers;
}
public String findPass(String path) {
for (Param param : getParams()) if (path.startsWith(param.getPath())) return param.getPass();
return "";
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Drive)) return false;
Drive it = (Drive) obj;
return getName().equals(it.getName());
}
}

View File

@@ -0,0 +1,135 @@
package com.github.catvod.bean.alist;
import android.text.TextUtils;
import com.github.catvod.bean.Vod;
import com.github.catvod.utils.Util;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class Item {
@SerializedName("name")
private String name;
@SerializedName(value = "path", alternate = "parent")
private String path;
@SerializedName("type")
private int type;
@SerializedName("size")
private long size;
@SerializedName(value = "thumb", alternate = "thumbnail")
private String thumb;
@SerializedName(value = "url", alternate = "raw_url")
private String url;
@SerializedName(value = "modified", alternate = "updated_at")
private String modified;
public static Item objectFrom(String str) {
return new Gson().fromJson(str, Item.class);
}
public static List<Item> arrayFrom(String str) {
Type listType = new TypeToken<List<Item>>() {}.getType();
return new Gson().fromJson(str, listType);
}
public String getName() {
return TextUtils.isEmpty(name) ? "" : name;
}
public void setName(String name) {
this.name = name;
}
public String getPath() {
return TextUtils.isEmpty(path) ? "" : path;
}
public void setPath(String path) {
this.path = path;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public long getSize() {
return size;
}
public String getThumb() {
return TextUtils.isEmpty(thumb) ? "" : thumb;
}
public void setThumb(String thumb) {
this.thumb = thumb;
}
public String getUrl() {
return TextUtils.isEmpty(url) ? "" : url.startsWith("//") ? "http:" + url : url;
}
public String getModified() {
return modified;
}
public Date getDate() {
try {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault());
return format.parse(getModified());
} catch (Exception e) {
return new Date();
}
}
public boolean isFolder() {
return getType() == 1;
}
public boolean isMedia(boolean isNew) {
if (getName().endsWith(".ts") || getName().endsWith(".mpg")) return true;
if (isNew) return getType() == 2 || getType() == 3;
return getType() == 3 || getType() == 4;
}
public boolean ignore(boolean isNew) {
if (getName().endsWith(".ts") || getName().endsWith(".mpg")) return false;
if (isNew) return getType() == 0 || getType() == 4;
return getType() == 0 || getType() == 2 || getType() == 5;
}
public String getExt() {
return Util.getExt(getName());
}
public String getVodId(String id) {
return id + getPath() + "/" + getName();
}
public String getPic(String pic) {
return getThumb().isEmpty() && isFolder() ? pic : getThumb();
}
public String getRemark() {
return Util.getSize(getSize());
}
public Vod getVod(String id, String pic) {
return new Vod(getVodId(id), getName(), getPic(pic), getRemark(), isFolder());
}
public Vod getVod(Drive drive, String pic) {
return new Vod(getVodId(drive.getName()), getName(), getPic(pic), drive.getName(), isFolder());
}
}

View File

@@ -0,0 +1,21 @@
package com.github.catvod.bean.alist;
import android.text.TextUtils;
import com.google.gson.annotations.SerializedName;
public class Login {
@SerializedName("username")
private String username;
@SerializedName("password")
private String password;
public String getUsername() {
return TextUtils.isEmpty(username) ? "" : username;
}
public String getPassword() {
return TextUtils.isEmpty(password) ? "" : password;
}
}

View File

@@ -0,0 +1,21 @@
package com.github.catvod.bean.alist;
import android.text.TextUtils;
import com.google.gson.annotations.SerializedName;
public class Param {
@SerializedName("path")
private String path;
@SerializedName("pass")
private String pass;
public String getPath() {
return TextUtils.isEmpty(path) ? "" : path;
}
public String getPass() {
return TextUtils.isEmpty(pass) ? "" : pass;
}
}

View File

@@ -0,0 +1,35 @@
package com.github.catvod.bean.alist;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Sorter implements Comparator<Item> {
private final String type;
private final String order;
public static void sort(String type, String order, List<Item> items) {
Collections.sort(items, new Sorter(type, order));
}
public Sorter(String type, String order) {
this.type = type;
this.order = order;
}
@Override
public int compare(Item o1, Item o2) {
boolean asc = order.equals("asc");
switch (type) {
case "name":
return asc ? o1.getName().compareTo(o2.getName()) : o2.getName().compareTo(o1.getName());
case "size":
return asc ? Long.compare(o1.getSize(), o2.getSize()) : Long.compare(o2.getSize(), o1.getSize());
case "date":
return asc ? o1.getDate().compareTo(o2.getDate()) : o2.getDate().compareTo(o1.getDate());
default:
return -1;
}
}
}

View File

@@ -0,0 +1,39 @@
package com.github.catvod.bean.bili;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.util.Collections;
import java.util.List;
public class Dash {
@SerializedName("duration")
private String duration;
@SerializedName("minBufferTime")
private String minBufferTime;
@SerializedName("video")
private List<Media> video;
@SerializedName("audio")
private List<Media> audio;
public static Dash objectFrom(String str) {
return new Gson().fromJson(str, Dash.class);
}
public String getDuration() {
return duration == null ? "0" : duration;
}
public String getMinBufferTime() {
return minBufferTime == null ? "0" : minBufferTime;
}
public List<Media> getVideo() {
return video == null ? Collections.emptyList() : video;
}
public List<Media> getAudio() {
return audio == null ? Collections.emptyList() : audio;
}
}

View File

@@ -0,0 +1,131 @@
package com.github.catvod.bean.bili;
import android.text.TextUtils;
import com.google.gson.JsonElement;
import com.google.gson.annotations.SerializedName;
import java.util.Collections;
import java.util.List;
public class Data {
@SerializedName("result")
private JsonElement result;
@SerializedName("list")
private JsonElement list;
@SerializedName("isLogin")
private Boolean isLogin;
@SerializedName("vipStatus")
private Integer vipStatus;
@SerializedName("qrcode_key")
private String qrcodeKey;
@SerializedName("url")
private String url;
@SerializedName("aid")
private String aid;
@SerializedName("cid")
private String cid;
@SerializedName("title")
private String title;
@SerializedName("tname")
private String tname;
@SerializedName("pic")
private String pic;
@SerializedName("duration")
private Long duration;
@SerializedName("desc")
private String desc;
@SerializedName("accept_description")
private List<String> acceptDescription;
@SerializedName("accept_quality")
private List<Integer> acceptQuality;
@SerializedName("pages")
private List<Page> pages;
@SerializedName("dash")
private Dash dash;
@SerializedName("owner")
private Owner owner;
@SerializedName("wbi_img")
private Wbi wbi;
public JsonElement getResult() {
return result;
}
public JsonElement getList() {
return list;
}
public boolean isLogin() {
return isLogin != null && isLogin;
}
public Integer getVipStatus() {
return vipStatus;
}
public boolean isVip() {
return vipStatus != null && vipStatus != 0;
}
public String getQrcodeKey() {
return TextUtils.isEmpty(qrcodeKey) ? "" : qrcodeKey;
}
public String getUrl() {
return TextUtils.isEmpty(url) ? "" : url;
}
public String getAid() {
return TextUtils.isEmpty(aid) ? "" : aid;
}
public String getCid() {
return TextUtils.isEmpty(cid) ? "" : cid;
}
public String getTitle() {
return TextUtils.isEmpty(title) ? "" : title;
}
public String getType() {
return TextUtils.isEmpty(tname) ? "" : tname;
}
public String getPic() {
return TextUtils.isEmpty(pic) ? "" : pic;
}
public Long getDuration() {
return duration == null ? 0 : duration;
}
public String getDesc() {
return TextUtils.isEmpty(desc) ? "" : desc;
}
public List<String> getAcceptDescription() {
return acceptDescription == null ? Collections.emptyList() : acceptDescription;
}
public List<Integer> getAcceptQuality() {
return acceptQuality == null ? Collections.emptyList() : acceptQuality;
}
public List<Page> getPages() {
return pages == null ? Collections.emptyList() : pages;
}
public Dash getDash() {
return dash == null ? new Dash() : dash;
}
public Owner getOwner() {
return owner == null ? new Owner() : owner;
}
public Wbi getWbi() {
return wbi == null ? new Wbi() : wbi;
}
}

View File

@@ -0,0 +1,79 @@
package com.github.catvod.bean.bili;
import com.google.gson.annotations.SerializedName;
public class Media {
@SerializedName("id")
private String id;
@SerializedName("baseUrl")
private String baseUrl;
@SerializedName("bandwidth")
private String bandwidth;
@SerializedName("mimeType")
private String mimeType;
@SerializedName("codecs")
private String codecs;
@SerializedName("width")
private String width;
@SerializedName("height")
private String height;
@SerializedName("frameRate")
private String frameRate;
@SerializedName("sar")
private String sar;
@SerializedName("startWithSap")
private String startWithSap;
@SerializedName("SegmentBase")
private Segment segmentBase;
@SerializedName("codecid")
private String codecid;
public String getId() {
return id;
}
public String getBaseUrl() {
return baseUrl;
}
public String getBandWidth() {
return bandwidth;
}
public String getMimeType() {
return mimeType;
}
public String getCodecs() {
return codecs;
}
public String getWidth() {
return width;
}
public String getHeight() {
return height;
}
public String getFrameRate() {
return frameRate;
}
public String getSar() {
return sar;
}
public String getStartWithSap() {
return startWithSap;
}
public Segment getSegmentBase() {
return segmentBase;
}
public String getCodecId() {
return codecid;
}
}

View File

@@ -0,0 +1,25 @@
package com.github.catvod.bean.bili;
import android.text.TextUtils;
import com.google.gson.annotations.SerializedName;
public class Owner {
@SerializedName("mid")
private String mid;
@SerializedName("name")
private String name;
public String getMid() {
return TextUtils.isEmpty(mid) ? "" : mid;
}
public String getName() {
return TextUtils.isEmpty(name) ? "" : name;
}
public String getFormat() {
return String.format("[a=cr:{\"id\":\"%s\",\"name\":\"%s\"}/]%s[/a]", getMid() + "/{pg}", getName(), getName());
}
}

View File

@@ -0,0 +1,21 @@
package com.github.catvod.bean.bili;
import android.text.TextUtils;
import com.google.gson.annotations.SerializedName;
public class Page {
@SerializedName("cid")
private String cid;
@SerializedName("part")
private String part;
public String getCid() {
return TextUtils.isEmpty(cid) ? "" : cid;
}
public String getPart() {
return TextUtils.isEmpty(part) ? "" : part;
}
}

View File

@@ -0,0 +1,86 @@
package com.github.catvod.bean.bili;
import android.text.TextUtils;
import com.github.catvod.bean.Vod;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import org.jsoup.Jsoup;
import java.lang.reflect.Type;
import java.util.List;
public class Resp {
@SerializedName("code")
private Integer code;
@SerializedName("message")
private String message;
@SerializedName("data")
private Data data;
public static Resp objectFrom(String str) {
return new Gson().fromJson(str, Resp.class);
}
public Data getData() {
return data == null ? new Data() : data;
}
public static class Result {
@SerializedName("bvid")
private String bvid;
@SerializedName("aid")
private String aid;
@SerializedName("title")
private String title;
@SerializedName("pic")
private String pic;
@SerializedName("duration")
private String duration;
@SerializedName("length")
private String length;
public static List<Result> arrayFrom(JsonElement str) {
Type listType = new TypeToken<List<Result>>() {}.getType();
return new Gson().fromJson(str, listType);
}
public String getBvId() {
return TextUtils.isEmpty(bvid) ? "" : bvid;
}
public String getAid() {
return TextUtils.isEmpty(aid) ? "" : aid;
}
public String getTitle() {
return TextUtils.isEmpty(title) ? "" : title;
}
public String getDuration() {
return TextUtils.isEmpty(duration) ? getLength() : duration.split(":")[0] + "分鐘";
}
public String getLength() {
return TextUtils.isEmpty(length) ? "" : length;
}
public String getPic() {
return TextUtils.isEmpty(pic) ? "" : pic;
}
public Vod getVod() {
Vod vod = new Vod();
vod.setVodId(getBvId() + "@" + getAid());
vod.setVodName(Jsoup.parse(getTitle()).text());
vod.setVodPic(getPic().startsWith("//") ? "https:" + getPic() : getPic());
vod.setVodRemarks(getDuration());
return vod;
}
}
}

View File

@@ -0,0 +1,19 @@
package com.github.catvod.bean.bili;
import com.google.gson.annotations.SerializedName;
public class Segment {
@SerializedName("Initialization")
private String initialization;
@SerializedName("indexRange")
private String indexRange;
public String getInitialization() {
return initialization;
}
public String getIndexRange() {
return indexRange;
}
}

View File

@@ -0,0 +1,47 @@
package com.github.catvod.bean.bili;
import android.net.Uri;
import android.text.TextUtils;
import com.github.catvod.utils.Util;
import com.google.gson.annotations.SerializedName;
import java.net.URLEncoder;
import java.util.LinkedHashMap;
public class Wbi {
private final int[] mixinKeyEncTab = new int[]{46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, 36, 20, 34, 44, 52};
@SerializedName("img_url")
private String imgUrl;
@SerializedName("sub_url")
private String subUrl;
public String getImgUrl() {
return TextUtils.isEmpty(imgUrl) ? "" : imgUrl;
}
public String getSubUrl() {
return TextUtils.isEmpty(subUrl) ? "" : subUrl;
}
private String getMixinKey(String imgKey, String subKey) {
String s = imgKey + subKey;
StringBuilder key = new StringBuilder();
for (int i = 0; i < 32; i++) key.append(s.charAt(mixinKeyEncTab[i]));
return key.toString();
}
public String getQuery(LinkedHashMap<String, Object> params) {
String imgKey = Uri.parse(getImgUrl()).getLastPathSegment().split("\\.")[0];
String subKey = Uri.parse(getSubUrl()).getLastPathSegment().split("\\.")[0];
String mixinKey = getMixinKey(imgKey, subKey);
StringBuilder sb = new StringBuilder();
params.put("wts", System.currentTimeMillis() / 1000);
for (String key : params.keySet()) sb.append(key).append("=").append(URLEncoder.encode(params.get(key).toString())).append("&");
String query = Util.substring(sb.toString());
String w_rid = Util.MD5(query + mixinKey);
return query + "&w_rid=" + w_rid;
}
}

View File

@@ -0,0 +1,130 @@
package com.github.catvod.bean.jianpian;
import android.text.TextUtils;
import com.github.catvod.bean.Vod;
import com.github.catvod.utils.Util;
import com.google.gson.annotations.SerializedName;
import java.util.Collections;
import java.util.List;
public class Data {
@SerializedName(value = "jump_id", alternate = "id")
private String jumpId;
@SerializedName(value = "thumbnail", alternate = "path")
private String thumbnail;
@SerializedName("title")
private String title;
@SerializedName("mask")
private String mask;
@SerializedName("description")
private String description;
@SerializedName("playlist")
private Value playlist;
@SerializedName("year")
private Value year;
@SerializedName("area")
private Value 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;
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 getTitle() {
return TextUtils.isEmpty(title) ? "" : title;
}
public String getMask() {
return TextUtils.isEmpty(mask) ? getPlaylist() : mask;
}
public String getDescription() {
return TextUtils.isEmpty(description) ? "" : description.replace(" ", "");
}
public String getPlaylist() {
return playlist == null ? "" : playlist.getTitle();
}
public String getYear() {
return year == null ? "" : year.getTitle();
}
public String getArea() {
return area == null ? "" : area.getTitle();
}
public String getTypes() {
return types == null ? "" : getValues(types, false);
}
public String getActors() {
return actors == null ? "" : getValues(actors, true);
}
public String getDirectors() {
return directors == null ? "" : getValues(directors, true);
}
public List<BtboDown> getBtboDownlist() {
return btboDownlist == null ? Collections.emptyList() : btboDownlist;
}
public Vod vod() {
return new Vod(getJumpId(), getTitle(), getThumbnail(), getMask());
}
public String getValues(List<Value> items, boolean link) {
StringBuilder sb = new StringBuilder();
for (Value value : items) sb.append(value.getValue(link)).append(" ");
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")
private String title;
private String getTitle() {
return TextUtils.isEmpty(title) ? "" : title;
}
private String getLink() {
return String.format("[a=cr:{\"id\":\"%s\",\"name\":\"%s\"}/]%s[/a]", getTitle() + "/{pg}", getTitle(), getTitle());
}
public String getValue(boolean link) {
return link ? getLink() : getTitle();
}
}
public static class BtboDown {
@SerializedName("val")
private String val;
public String getVal() {
return TextUtils.isEmpty(val) ? "" : val.replaceAll("ftp", "tvbox-xg:ftp");
}
}
}

View File

@@ -0,0 +1,18 @@
package com.github.catvod.bean.jianpian;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
public class Detail {
@SerializedName("data")
private Data data;
public static Detail objectFrom(String str) {
return new Gson().fromJson(str, Detail.class);
}
public Data getData() {
return data == null ? new Data() : data;
}
}

View File

@@ -0,0 +1,21 @@
package com.github.catvod.bean.jianpian;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.util.Collections;
import java.util.List;
public class Resp {
@SerializedName("data")
private List<Data> data;
public static Resp objectFrom(String str) {
return new Gson().fromJson(str, Resp.class);
}
public List<Data> getData() {
return data == null ? Collections.emptyList() : data;
}
}

View File

@@ -0,0 +1,45 @@
package com.github.catvod.bean.market;
import android.text.TextUtils;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Vod;
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.Collections;
import java.util.List;
public class Data {
@SerializedName("name")
private String name;
@SerializedName("list")
private List<Item> list;
public static List<Data> arrayFrom(String str) {
Type listType = new TypeToken<ArrayList<Data>>() {}.getType();
return new Gson().fromJson(str, listType);
}
public String getName() {
return TextUtils.isEmpty(name) ? "" : name;
}
public List<Item> getList() {
return list == null ? Collections.emptyList() : list;
}
public List<Vod> getVod() {
List<Vod> vodList = new ArrayList<>();
for (Item item : getList()) vodList.add(item.vod());
return vodList;
}
public Class type() {
return new Class(getName(), getName());
}
}

View File

@@ -0,0 +1,56 @@
package com.github.catvod.bean.market;
import android.text.TextUtils;
import com.github.catvod.bean.Vod;
import com.google.gson.annotations.SerializedName;
public class Item {
@SerializedName("name")
private String name;
@SerializedName("url")
private String url;
@SerializedName("icon")
private String icon;
@SerializedName("copy")
private String copy;
@SerializedName("version")
private String version;
public Item(String url) {
this.url = url;
}
public String getName() {
return TextUtils.isEmpty(name) ? "" : name;
}
public String getUrl() {
return TextUtils.isEmpty(url) ? "" : url;
}
public String getIcon() {
return TextUtils.isEmpty(icon) ? "" : icon;
}
public String getCopy() {
return TextUtils.isEmpty(copy) ? "" : copy;
}
public String getVersion() {
return TextUtils.isEmpty(version) ? "" : version;
}
public Vod vod() {
return new Vod(getUrl(), getName(), getIcon(), getVersion(), Vod.Style.rect(1.0f));
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Item)) return false;
Item it = (Item) obj;
return getUrl().equals(it.getUrl());
}
}

View File

@@ -0,0 +1,61 @@
package com.github.catvod.bean.star;
import android.text.TextUtils;
import com.github.catvod.bean.Vod;
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.Collections;
import java.util.List;
public class Card {
@SerializedName("name")
private String name;
@SerializedName(value = "img", alternate = "picurl")
private String img;
@SerializedName("id")
private String id;
@SerializedName("countStr")
private String countStr;
@SerializedName("url")
private String url;
@SerializedName("cards")
private List<Card> cards;
public static List<Card> arrayFrom(String str) {
Type listType = new TypeToken<List<Card>>() {}.getType();
return new Gson().fromJson(str, listType);
}
public String getName() {
return TextUtils.isEmpty(name) ? "" : name;
}
public String getImg() {
return TextUtils.isEmpty(img) ? "" : img;
}
public String getId() {
return TextUtils.isEmpty(id) ? "" : id;
}
public String getCountStr() {
return TextUtils.isEmpty(countStr) ? "" : countStr;
}
public String getUrl() {
return TextUtils.isEmpty(url) ? "" : url;
}
public List<Card> getCards() {
return cards == null ? Collections.emptyList() : cards;
}
public Vod vod() {
return new Vod(getId(), getName(), getImg(), getCountStr());
}
}

View File

@@ -0,0 +1,65 @@
package com.github.catvod.bean.star;
import com.github.catvod.bean.Filter;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Condition {
@SerializedName("label")
private List<List<String>> label;
@SerializedName("country")
private List<String> country;
@SerializedName("time")
private List<Integer> time;
public static Condition objectFrom(String str) {
return new Gson().fromJson(str, Condition.class);
}
public List<List<String>> getLabel() {
return label == null ? Collections.emptyList() : label;
}
public List<String> getCountry() {
return country == null ? Collections.emptyList() : country;
}
public List<Integer> getTime() {
return time == null ? Collections.emptyList() : time;
}
public List<Filter> getFilter() {
List<Filter> filters = new ArrayList<>();
filters.add(new Filter("type", "類型", getTypeValues()));
filters.add(new Filter("area", "地區", getAreaValues()));
filters.add(new Filter("year", "年份", getYearValues()));
return filters;
}
private List<Filter.Value> getTypeValues() {
List<Filter.Value> values = new ArrayList<>();
values.add(new Filter.Value("全部", ""));
for (List<String> list : getLabel()) values.add(new Filter.Value(list.get(0)));
return values;
}
private List<Filter.Value> getAreaValues() {
List<Filter.Value> values = new ArrayList<>();
values.add(new Filter.Value("全部", ""));
for (String text : getCountry()) values.add(new Filter.Value(text));
return values;
}
private List<Filter.Value> getYearValues() {
List<Filter.Value> values = new ArrayList<>();
values.add(new Filter.Value("全部", ""));
Collections.sort(getTime(), Collections.reverseOrder());
for (Integer year : getTime()) if (year >= 2010) values.add(new Filter.Value(String.valueOf(year)));
return values;
}
}

View File

@@ -0,0 +1,24 @@
package com.github.catvod.bean.star;
import android.text.TextUtils;
import com.google.gson.annotations.SerializedName;
import java.util.Collections;
import java.util.List;
public class Group {
@SerializedName("name")
private String name;
@SerializedName("videos")
private List<Video> videos;
public String getName() {
return TextUtils.isEmpty(name) ? "" : name;
}
public List<Video> getVideos() {
return videos == null ? Collections.emptyList() : videos;
}
}

View File

@@ -0,0 +1,71 @@
package com.github.catvod.bean.star;
import android.text.TextUtils;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.util.Collections;
import java.util.List;
public class Info {
@SerializedName("videosGroup")
private List<Group> videosGroup;
@SerializedName("actor")
private List<Person> actor;
@SerializedName("country")
private String country;
@SerializedName("desc")
private String desc;
@SerializedName("director")
private List<Person> director;
@SerializedName("name")
private String name;
@SerializedName("picurl")
private String picurl;
@SerializedName("time")
private String time;
@SerializedName("countStr")
private String countStr;
public static Info objectFrom(String str) {
return new Gson().fromJson(str, Info.class);
}
public List<Group> getVideosGroup() {
return videosGroup == null ? Collections.emptyList() : videosGroup;
}
public List<Person> getActor() {
return actor == null ? Collections.emptyList() : actor;
}
public String getCountry() {
return TextUtils.isEmpty(country) ? "" : country;
}
public String getDesc() {
return TextUtils.isEmpty(desc) ? "" : desc;
}
public List<Person> getDirector() {
return director == null ? Collections.emptyList() : director;
}
public String getName() {
return TextUtils.isEmpty(name) ? "" : name;
}
public String getPicurl() {
return TextUtils.isEmpty(picurl) ? "" : picurl;
}
public String getTime() {
return TextUtils.isEmpty(time) ? "" : time;
}
public String getCountStr() {
return TextUtils.isEmpty(countStr) ? "" : countStr;
}
}

View File

@@ -0,0 +1,21 @@
package com.github.catvod.bean.star;
import android.text.TextUtils;
import com.google.gson.annotations.SerializedName;
public class Person {
@SerializedName("id")
private int id;
@SerializedName("name")
private String name;
public int getId() {
return id;
}
public String getName() {
return TextUtils.isEmpty(name) ? "" : name;
}
}

View File

@@ -0,0 +1,60 @@
package com.github.catvod.bean.star;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
public class Query {
@SerializedName("country")
private String country;
@SerializedName("label")
private String label;
@SerializedName("chName")
private String chName;
@SerializedName("startTime")
private Integer startTime;
@SerializedName("endTime")
private Integer endTime;
@SerializedName("pageSize")
private Integer pageSize;
@SerializedName("page")
private Integer page;
public void setCountry(String country) {
this.country = country;
}
public void setLabel(String label) {
this.label = label;
}
public void setChName(String chName) {
this.chName = chName;
}
public void setStartTime(Integer startTime) {
this.startTime = startTime;
}
public void setEndTime(Integer endTime) {
this.endTime = endTime;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public void setPage(Integer page) {
this.page = page;
}
public void setYear(String year) {
setStartTime(Integer.parseInt(year));
setEndTime(Integer.parseInt(year));
}
@Override
public String toString() {
return new Gson().toJson(this);
}
}

View File

@@ -0,0 +1,21 @@
package com.github.catvod.bean.star;
import android.text.TextUtils;
import com.google.gson.annotations.SerializedName;
public class Video {
@SerializedName("purl")
private String purl;
@SerializedName("eporder")
private int eporder;
public String getPurl() {
return TextUtils.isEmpty(purl) ? "" : purl;
}
public int getEporder() {
return eporder;
}
}

View File

@@ -0,0 +1,27 @@
package com.github.catvod.bean.upyun;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.util.Collections;
import java.util.List;
public class Data {
@SerializedName("result")
private Data result;
@SerializedName("items")
private List<Item> items;
public static Data objectFrom(String str) {
return new Gson().fromJson(str, Data.class);
}
public Data getResult() {
return result == null ? new Data() : result;
}
public List<Item> getItems() {
return items == null ? Collections.emptyList() : items;
}
}

View File

@@ -0,0 +1,37 @@
package com.github.catvod.bean.upyun;
import android.text.TextUtils;
import com.github.catvod.bean.Vod;
import com.google.gson.annotations.SerializedName;
public class Item {
@SerializedName("title")
private String title;
@SerializedName("page_url")
private String pageUrl;
@SerializedName("insert_time")
private String insertTime;
public String getTitle() {
return TextUtils.isEmpty(title) ? "" : title.replaceAll("<em>", "").replaceAll("</em>", "");
}
public String getPageUrl() {
return TextUtils.isEmpty(pageUrl) ? "" : pageUrl;
}
public String getInsertTime() {
return TextUtils.isEmpty(insertTime) ? "" : insertTime;
}
public Item url(String pageUrl) {
this.pageUrl = pageUrl;
return this;
}
public Vod getVod() {
return new Vod(getPageUrl(), getTitle(), "https://inews.gtimg.com/newsapp_bt/0/13263837859/1000", getInsertTime());
}
}

View File

@@ -0,0 +1,101 @@
package com.github.catvod.bean.webdav;
import android.net.Uri;
import android.text.TextUtils;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Vod;
import com.github.catvod.utils.Util;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import com.thegrizzlylabs.sardineandroid.DavResource;
import com.thegrizzlylabs.sardineandroid.Sardine;
import com.thegrizzlylabs.sardineandroid.impl.OkHttpSardine;
import java.util.ArrayList;
import java.util.List;
public class Drive {
@SerializedName("drives")
private List<Drive> drives;
@SerializedName("name")
private String name;
@SerializedName("server")
private String server;
@SerializedName("user")
private String user;
@SerializedName("pass")
private String pass;
@SerializedName("path")
private String path;
@SerializedName("webdav")
private Sardine webdav;
public static Drive objectFrom(String str) {
return new Gson().fromJson(str, Drive.class);
}
public Drive(String name) {
this.name = name;
}
public List<Drive> getDrives() {
return drives == null ? new ArrayList<>() : drives;
}
public String getName() {
return TextUtils.isEmpty(name) ? "" : name;
}
public String getServer() {
return TextUtils.isEmpty(server) ? "" : server;
}
public String getUser() {
return TextUtils.isEmpty(user) ? "" : user;
}
public String getPass() {
return TextUtils.isEmpty(pass) ? "" : pass;
}
public String getPath() {
return TextUtils.isEmpty(path) ? "" : path;
}
public void setPath(String path) {
this.path = TextUtils.isEmpty(path) ? "" : path;
}
public String getHost() {
return getServer().replace(getPath(), "");
}
public Sardine getWebdav() {
if (webdav == null) init();
return webdav;
}
public Class toType() {
return new Class(getName(), getName(), "1");
}
private void init() {
webdav = new OkHttpSardine();
webdav.setCredentials(getUser(), getPass());
setPath(Uri.parse(getServer()).getPath());
}
public Vod vod(DavResource item, String vodPic) {
return new Vod(getName() + item.getPath(), item.getName(), vodPic, Util.getSize(item.getContentLength()), item.isDirectory());
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Drive)) return false;
Drive it = (Drive) obj;
return getName().equals(it.getName());
}
}

View File

@@ -0,0 +1,37 @@
package com.github.catvod.bean.webdav;
import com.thegrizzlylabs.sardineandroid.DavResource;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Sorter implements Comparator<DavResource> {
private final String type;
private final String order;
public static void sort(String type, String order, List<DavResource> items) {
Collections.sort(items, new Sorter(type, order));
}
public Sorter(String type, String order) {
this.type = type;
this.order = order;
}
@Override
public int compare(DavResource o1, DavResource o2) {
boolean asc = order.equals("asc");
switch (type) {
case "name":
return asc ? o1.getName().compareTo(o2.getName()) : o2.getName().compareTo(o1.getName());
case "size":
return asc ? Long.compare(o1.getContentLength(), o2.getContentLength()) : Long.compare(o2.getContentLength(), o1.getContentLength());
case "date":
return asc ? o1.getModified().compareTo(o2.getModified()) : o2.getModified().compareTo(o1.getModified());
default:
return -1;
}
}
}

View File

@@ -0,0 +1,695 @@
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);
}
}

View File

@@ -0,0 +1,71 @@
package com.github.catvod.crawler;
import android.content.Context;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import okhttp3.Dns;
import okhttp3.OkHttpClient;
public abstract class Spider {
public void init(Context context) throws Exception {
}
public void init(Context context, String extend) throws Exception {
init(context);
}
public String homeContent(boolean filter) throws Exception {
return "";
}
public String homeVideoContent() throws Exception {
return "";
}
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
return "";
}
public String detailContent(List<String> ids) throws Exception {
return "";
}
public String searchContent(String key, boolean quick) throws Exception {
return "";
}
public String searchContent(String key, boolean quick, String pg) throws Exception {
return "";
}
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
return "";
}
public boolean manualVideoCheck() throws Exception {
return false;
}
public boolean isVideoFormat(String url) throws Exception {
return false;
}
public Object[] proxyLocal(Map<String, String> params) throws Exception {
return null;
}
public void destroy() {
}
public static Dns safeDns() {
return null;
}
public static OkHttpClient client() {
return null;
}
}

View File

@@ -0,0 +1,16 @@
package com.github.catvod.crawler;
import android.util.Log;
public class SpiderDebug {
private static final String TAG = SpiderDebug.class.getSimpleName();
public static void log(Throwable e) {
Log.d(TAG, e.getMessage());
}
public static void log(String msg) {
Log.d(TAG, msg);
}
}

View File

@@ -0,0 +1,111 @@
package com.github.catvod.debug;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.Toast;
import com.github.catvod.R;
import com.github.catvod.crawler.Spider;
import com.github.catvod.spider.Cg51;
import com.github.catvod.spider.Douban;
import com.github.catvod.spider.Init;
import com.github.catvod.spider.J91;
import com.github.catvod.spider.Jable;
import com.github.catvod.spider.QxiTv;
import com.github.catvod.spider.Wogg;
import com.github.catvod.spider.Zhaozy;
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 Cg51();
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 {
Logger.t("categoryContent").d(spider.categoryContent("wpcz", "6", true, new HashMap<>()));
} catch (Throwable e) {
e.printStackTrace();
}
}
public void detailContent() {
try {
Logger.t("detailContent").d(spider.detailContent(Arrays.asList("123488")));
} catch (Throwable e) {
e.printStackTrace();
}
}
public void playerContent() {
try {
Logger.t("playerContent").d(spider.playerContent("轉存原畫", "kahf2rw5Uuk+652f55f6943ee2f75d8e4fa590b4ec65fd007f8c", new ArrayList<>()));
} catch (Throwable e) {
e.printStackTrace();
}
}
public void searchContent() {
try {
Logger.t("searchContent").d(spider.searchContent("空姐", false));
} catch (Throwable e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,19 @@
package com.github.catvod.js;
import com.github.catvod.utils.Notify;
import com.whl.quickjs.wrapper.JSMethod;
import com.whl.quickjs.wrapper.QuickJSContext;
public class Method {
private QuickJSContext ctx;
public Method(QuickJSContext ctx) {
this.ctx = ctx;
}
@JSMethod
public void showToast(String msg) {
Notify.show(msg);
}
}

View File

@@ -0,0 +1,107 @@
package com.github.catvod.net;
import com.github.catvod.crawler.Spider;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import okhttp3.Dns;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class OkHttp {
public static final String POST = "POST";
public static final String GET = "GET";
private OkHttpClient client;
private static class Loader {
static volatile OkHttp INSTANCE = new OkHttp();
}
private static OkHttp get() {
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, 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() : "";
}
public static String post(String url, Map<String, String> params) {
return post(url, params, null).getBody();
}
public static OkResult post(String url, Map<String, String> params, Map<String, String> header) {
return new OkRequest(POST, url, params, header).execute(client());
}
public static String post(String url, String json) {
return post(url, json, null).getBody();
}
public static OkResult post(String url, String json, Map<String, String> header) {
return new OkRequest(POST, url, json, header).execute(client());
}
public static String getLocation(String url, Map<String, String> header) throws IOException {
return getLocation(client().newBuilder().followRedirects(false).followSslRedirects(false).build().newCall(new Request.Builder().url(url).headers(Headers.of(header)).build()).execute().headers().toMultimap());
}
public static String getLocation(Map<String, List<String>> headers) {
if (headers == null) return null;
if (headers.containsKey("location")) return headers.get("location").get(0);
if (headers.containsKey("Location")) return headers.get("Location").get(0);
return null;
}
private static OkHttpClient build() {
if (get().client != null) return get().client;
return get().client = getBuilder().build();
}
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(new SSLCompat(), SSLCompat.TM);
}
private static OkHttpClient client() {
try {
return Objects.requireNonNull(Spider.client());
} catch (Throwable e) {
return build();
}
}
private static Dns safeDns() {
try {
return Objects.requireNonNull(Spider.safeDns());
} catch (Throwable e) {
return Dns.SYSTEM;
}
}
}

View File

@@ -0,0 +1,72 @@
package com.github.catvod.net;
import android.text.TextUtils;
import com.github.catvod.utils.Util;
import java.io.IOException;
import java.util.Map;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
class OkRequest {
private final Map<String, String> header;
private final Map<String, String> params;
private final String method;
private final String json;
private Request request;
private String url;
OkRequest(String method, String url, Map<String, String> params, Map<String, String> header) {
this(method, url, params, null, header);
}
OkRequest(String method, String url, String json, Map<String, String> header) {
this(method, url, null, json, header);
}
private OkRequest(String method, String url, Map<String, String> params, String json, Map<String, String> header) {
this.url = url;
this.json = json;
this.method = method;
this.params = params;
this.header = header;
getInstance();
}
private void getInstance() {
Request.Builder builder = new Request.Builder();
if (method.equals(OkHttp.GET) && params != null) setParams();
if (method.equals(OkHttp.POST)) builder.post(getRequestBody());
if (header != null) for (String key : header.keySet()) builder.addHeader(key, header.get(key));
request = builder.url(url).build();
}
private RequestBody getRequestBody() {
if (!TextUtils.isEmpty(json)) return RequestBody.create(MediaType.get("application/json; charset=utf-8"), json);
FormBody.Builder formBody = new FormBody.Builder();
if (params != null) for (String key : params.keySet()) formBody.add(key, params.get(key));
return formBody.build();
}
private void setParams() {
url = url + "?";
for (String key : params.keySet()) url = url.concat(key + "=" + params.get(key) + "&");
url = Util.substring(url);
}
public OkResult execute(OkHttpClient client) {
try {
Response response = client.newCall(request).execute();
return new OkResult(response.code(), response.body().string(), response.headers().toMultimap());
} catch (IOException e) {
return new OkResult();
}
}
}

View File

@@ -0,0 +1,38 @@
package com.github.catvod.net;
import android.text.TextUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class OkResult {
private final int code;
private final String body;
private final Map<String, List<String>> resp;
public OkResult() {
this.code = 500;
this.body = "";
this.resp = new HashMap<>();
}
public OkResult(int code, String body, Map<String, List<String>> resp) {
this.code = code;
this.body = body;
this.resp = resp;
}
public int getCode() {
return code;
}
public String getBody() {
return TextUtils.isEmpty(body) ? "" : body;
}
public Map<String, List<String>> getResp() {
return resp;
}
}

View File

@@ -0,0 +1,112 @@
package com.github.catvod.net;
import android.annotation.SuppressLint;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
public class SSLCompat extends SSLSocketFactory {
private SSLSocketFactory factory;
private String[] cipherSuites;
private String[] protocols;
public SSLCompat() {
try {
List<String> list = new LinkedList<>();
SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket();
for (String protocol : socket.getSupportedProtocols()) if (!protocol.toUpperCase().contains("SSL")) list.add(protocol);
protocols = list.toArray(new String[0]);
List<String> allowedCiphers = Arrays.asList("TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECHDE_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");
List<String> availableCiphers = Arrays.asList(socket.getSupportedCipherSuites());
HashSet<String> preferredCiphers = new HashSet<>(allowedCiphers);
preferredCiphers.retainAll(availableCiphers);
preferredCiphers.addAll(new HashSet<>(Arrays.asList(socket.getEnabledCipherSuites())));
cipherSuites = preferredCiphers.toArray(new String[0]);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new X509TrustManager[]{TM}, null);
HttpsURLConnection.setDefaultSSLSocketFactory(factory = context.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public String[] getDefaultCipherSuites() {
return cipherSuites;
}
@Override
public String[] getSupportedCipherSuites() {
return cipherSuites;
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
Socket ssl = factory.createSocket(s, host, port, autoClose);
if (ssl instanceof SSLSocket) upgradeTLS((SSLSocket) ssl);
return ssl;
}
@Override
public Socket createSocket(String host, int port) throws IOException {
Socket ssl = factory.createSocket(host, port);
if (ssl instanceof SSLSocket) upgradeTLS((SSLSocket) ssl);
return ssl;
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
Socket ssl = factory.createSocket(host, port, localHost, localPort);
if (ssl instanceof SSLSocket) upgradeTLS((SSLSocket) ssl);
return ssl;
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
Socket ssl = factory.createSocket(host, port);
if (ssl instanceof SSLSocket) upgradeTLS((SSLSocket) ssl);
return ssl;
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
Socket ssl = factory.createSocket(address, port, localAddress, localPort);
if (ssl instanceof SSLSocket) upgradeTLS((SSLSocket) ssl);
return ssl;
}
private void upgradeTLS(SSLSocket ssl) {
if (protocols != null) ssl.setEnabledProtocols(protocols);
if (cipherSuites != null) ssl.setEnabledCipherSuites(cipherSuites);
}
@SuppressLint({"TrustAllX509TrustManager", "CustomX509TrustManager"})
public static final X509TrustManager TM = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
};
}

View File

@@ -0,0 +1,291 @@
package com.github.catvod.spider;
import android.content.Context;
import android.text.TextUtils;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Filter;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Sub;
import com.github.catvod.bean.Vod;
import com.github.catvod.bean.alist.Drive;
import com.github.catvod.bean.alist.Item;
import com.github.catvod.bean.alist.Sorter;
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.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class AList extends Spider {
private List<Drive> drives;
private String vodPic;
private String ext;
private List<Filter> getFilter() {
List<Filter> items = new ArrayList<>();
items.add(new Filter("type", "排序類型", Arrays.asList(new Filter.Value("預設", ""), new Filter.Value("名稱", "name"), new Filter.Value("大小", "size"), new Filter.Value("修改時間", "date"))));
items.add(new Filter("order", "排序方式", Arrays.asList(new Filter.Value("預設", ""), new Filter.Value("", "asc"), new Filter.Value("", "desc"))));
return items;
}
private void fetchRule() {
if (drives != null && !drives.isEmpty()) return;
if (ext.startsWith("http")) ext = OkHttp.string(ext);
Drive drive = Drive.objectFrom(ext);
drives = drive.getDrives();
vodPic = drive.getVodPic();
}
private Drive getDrive(String name) {
return drives.get(drives.indexOf(new Drive(name))).check();
}
private String post(Drive drive, String url, String param) {
return post(drive, url, param, true);
}
private String post(Drive drive, String url, String param, boolean retry) {
String response = OkHttp.post(url, param, drive.getHeader()).getBody();
SpiderDebug.log(response);
if (retry && response.contains("Guest user is disabled") && login(drive)) return post(drive, url, param, false);
return response;
}
@Override
public void init(Context context, String extend) {
try {
ext = extend;
fetchRule();
} catch (Exception ignored) {
}
}
@Override
public String homeContent(boolean filter) throws Exception {
fetchRule();
List<Class> classes = new ArrayList<>();
LinkedHashMap<String, List<Filter>> filters = new LinkedHashMap<>();
for (Drive drive : drives) if (!drive.hidden()) classes.add(drive.toType());
for (Class item : classes) filters.put(item.getTypeId(), getFilter());
return Result.string(classes, filters);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
fetchRule();
String type = extend.containsKey("type") ? extend.get("type") : "";
String order = extend.containsKey("order") ? extend.get("order") : "";
List<Item> folders = new ArrayList<>();
List<Item> files = new ArrayList<>();
List<Vod> list = new ArrayList<>();
for (Item item : getList(tid, true)) {
if (item.isFolder()) folders.add(item);
else files.add(item);
}
if (!TextUtils.isEmpty(type) && !TextUtils.isEmpty(order)) {
Sorter.sort(type, order, folders);
Sorter.sort(type, order, files);
}
for (Item item : folders) list.add(item.getVod(tid, vodPic));
for (Item item : files) list.add(item.getVod(tid, vodPic));
return Result.get().vod(list).page().string();
}
@Override
public String detailContent(List<String> ids) throws Exception {
fetchRule();
String id = ids.get(0);
String key = id.contains("/") ? id.substring(0, id.indexOf("/")) : id;
String path = id.substring(0, id.lastIndexOf("/"));
String name = path.substring(path.lastIndexOf("/") + 1);
Drive drive = getDrive(key);
List<Item> parents = getList(path, false);
Sorter.sort("name", "asc", parents);
Vod vod = new Vod();
vod.setVodPlayFrom(key);
vod.setVodId(id);
vod.setVodName(name);
vod.setVodPic(vodPic);
List<String> playUrls = new ArrayList<>();
for (Item item : parents) if (item.isMedia(drive.isNew())) playUrls.add(item.getName() + "$" + item.getVodId(path) + findSubs(path, parents));
vod.setVodPlayUrl(TextUtils.join("#", playUrls));
return Result.string(vod);
}
@Override
public String searchContent(String keyword, boolean quick) throws Exception {
fetchRule();
List<Vod> list = new ArrayList<>();
List<Job> jobs = new ArrayList<>();
ExecutorService executor = Executors.newCachedThreadPool();
for (Drive drive : drives) if (drive.search()) jobs.add(new Job(drive.check(), keyword));
for (Future<List<Vod>> future : executor.invokeAll(jobs, 15, TimeUnit.SECONDS)) list.addAll(future.get());
return Result.string(list);
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) {
String[] ids = id.split("~~~");
return Result.get().url(getDetail(ids[0]).getUrl()).subs(getSub(ids)).string();
}
private boolean login(Drive drive) {
try {
JSONObject params = new JSONObject();
params.put("username", drive.getLogin().getUsername());
params.put("password", drive.getLogin().getPassword());
String response = OkHttp.post(drive.loginApi(), params.toString());
drive.setToken(new JSONObject(response).getJSONObject("data").getString("token"));
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
private Item getDetail(String id) {
try {
String key = id.contains("/") ? id.substring(0, id.indexOf("/")) : id;
String path = id.contains("/") ? id.substring(id.indexOf("/")) : "";
Drive drive = getDrive(key);
path = path.startsWith(drive.getPath()) ? path : drive.getPath() + path;
JSONObject params = new JSONObject();
params.put("path", path);
params.put("password", drive.findPass(path));
String response = post(drive, drive.getApi(), params.toString());
return Item.objectFrom(getDetailJson(drive.isNew(), response));
} catch (Exception e) {
return new Item();
}
}
private List<Item> getList(String id, boolean filter) {
try {
String key = id.contains("/") ? id.substring(0, id.indexOf("/")) : id;
String path = id.contains("/") ? id.substring(id.indexOf("/")) : "";
Drive drive = getDrive(key);
path = path.startsWith(drive.getPath()) ? path : drive.getPath() + path;
JSONObject params = new JSONObject();
params.put("path", path);
params.put("password", drive.findPass(path));
String response = post(drive, drive.listApi(), params.toString());
List<Item> items = Item.arrayFrom(getListJson(drive.isNew(), response));
Iterator<Item> iterator = items.iterator();
if (filter) while (iterator.hasNext()) if (iterator.next().ignore(drive.isNew())) iterator.remove();
return items;
} catch (Exception e) {
return Collections.emptyList();
}
}
private String getListJson(boolean isNew, String response) throws Exception {
if (isNew) {
return new JSONObject(response).getJSONObject("data").getJSONArray("content").toString();
} else {
return new JSONObject(response).getJSONObject("data").getJSONArray("files").toString();
}
}
private String getDetailJson(boolean isNew, String response) throws Exception {
if (isNew) {
return new JSONObject(response).getJSONObject("data").toString();
} else {
return new JSONObject(response).getJSONObject("data").getJSONArray("files").getJSONObject(0).toString();
}
}
private String getSearchJson(boolean isNew, String response) throws Exception {
if (isNew) {
return new JSONObject(response).getJSONObject("data").getJSONArray("content").toString();
} else {
return new JSONObject(response).getJSONArray("data").toString();
}
}
private String findSubs(String path, List<Item> items) {
StringBuilder sb = new StringBuilder();
for (Item item : items) if (Util.isSub(item.getExt())) sb.append("~~~").append(item.getName()).append("@@@").append(item.getExt()).append("@@@").append(item.getVodId(path));
return sb.toString();
}
private List<Sub> getSub(String[] ids) {
List<Sub> sub = new ArrayList<>();
for (String text : ids) {
if (!text.contains("@@@")) continue;
String[] split = text.split("@@@");
String name = split[0];
String ext = split[1];
String url = getDetail(split[2]).getUrl();
sub.add(Sub.create().name(name).ext(ext).url(url));
}
return sub;
}
class Job implements Callable<List<Vod>> {
private final Drive drive;
private final String keyword;
public Job(Drive drive, String keyword) {
this.drive = drive;
this.keyword = keyword;
}
@Override
public List<Vod> call() {
List<Vod> alist = alist();
return alist.size() > 0 ? 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, vodPic));
}
return list;
}
private List<Vod> alist() {
try {
List<Vod> list = new ArrayList<>();
String response = post(drive, drive.searchApi(), drive.params(keyword));
List<Item> items = Item.arrayFrom(getSearchJson(drive.isNew(), response));
for (Item item : items) if (!item.ignore(drive.isNew())) list.add(item.getVod(drive, vodPic));
return list;
} catch (Exception e) {
return Collections.emptyList();
}
}
}
}

View File

@@ -0,0 +1,87 @@
package com.github.catvod.spider;
import android.content.Context;
import android.text.TextUtils;
import com.github.catvod.api.AliYun;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author ColaMint & Adam & FongMi
*/
public class Ali extends Spider {
public static final Pattern pattern = Pattern.compile("(www.aliyundrive.com|www.alipan.com)/s/([^/]+)(/folder/([^/]+))?");
@Override
public void init(Context context, String extend) {
AliYun.get().setRefreshToken(extend);
}
@Override
public String detailContent(List<String> ids) throws Exception {
String id = ids.get(0).trim();
Matcher matcher = pattern.matcher(id);
return matcher.find() ? Result.string(parseVod(matcher, id)) : "";
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) {
return AliYun.get().playerContent(id.split("\\+"), flag);
}
private Vod parseVod(Matcher matcher, String id) {
String shareId = matcher.group(2);
String fileId = matcher.groupCount() == 4 ? matcher.group(4) : "";
return AliYun.get().getVod(id, shareId, fileId);
}
/**
* 獲取詳情內容視頻播放來源(多 shared_link
*
* @param ids share_link 集合
* @return 詳情內容視頻播放來源
*/
public String detailContentVodPlayFrom(List<String> ids) {
List<String> playFrom = new ArrayList<>();
if (ids.size() < 2) return TextUtils.join("$$$", Arrays.asList("轉存原畫", "分享原畫", "代理普畫"));
for (int i = 1; i <= ids.size(); i++) {
playFrom.add(String.format(Locale.getDefault(), "轉存原畫#%02d", i));
playFrom.add(String.format(Locale.getDefault(), "分享原畫#%02d", i));
playFrom.add(String.format(Locale.getDefault(), "代理普畫#%02d", i));
}
return TextUtils.join("$$$", playFrom);
}
/**
* 獲取詳情內容視頻播放地址(多 share_link
*
* @param ids share_link 集合
* @return 詳情內容視頻播放地址
*/
public String detailContentVodPlayUrl(List<String> ids) {
List<String> playUrl = new ArrayList<>();
for (String id : ids) {
Matcher matcher = pattern.matcher(id);
if (matcher.find()) playUrl.add(parseVod(matcher, id).getVodPlayUrl());
}
return TextUtils.join("$$$", playUrl);
}
public static Object[] proxy(Map<String, String> params) throws Exception {
String type = params.get("type");
if ("video".equals(type)) return AliYun.get().proxyVideo(params);
if ("sub".equals(type)) return AliYun.get().proxySub(params);
return null;
}
}

View File

@@ -0,0 +1,820 @@
package com.github.catvod.spider;
import android.content.Context;
import android.text.TextUtils;
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.JSONException;
import org.json.JSONObject;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* M浏览器中的App影视
* Author: 群友 不负此生
*/
public class AppYsV2 extends Spider {
@Override
public void init(Context context, String extend) throws Exception {
super.init(context, extend);
try {
extInfos = extend.split("###");
} catch (Exception ignored) {
}
}
@Override
public String homeContent(boolean filter) throws Exception {
String url = getCateUrl(getApiUrl());
JSONArray jsonArray = null;
if (!url.isEmpty()) {
SpiderDebug.log(url);
String json = OkHttp.string(url, getHeaders(url));
JSONObject obj = new JSONObject(json);
if (obj.has("list") && obj.get("list") instanceof JSONArray) {
jsonArray = obj.getJSONArray("list");
} else if (obj.has("data") && obj.get("data") instanceof JSONObject && obj.getJSONObject("data").has("list") && obj.getJSONObject("data").get("list") instanceof JSONArray) {
jsonArray = obj.getJSONObject("data").getJSONArray("list");
} else if (obj.has("data") && obj.get("data") instanceof JSONArray) {
jsonArray = obj.getJSONArray("data");
}
} else { // 通过filter列表读分类
String filterStr = getFilterTypes(url, null);
String[] classes = filterStr.split("\n")[0].split("\\+");
jsonArray = new JSONArray();
for (int i = 1; i < classes.length; i++) {
String[] kv = classes[i].trim().split("=");
if (kv.length < 2) continue;
JSONObject newCls = new JSONObject();
newCls.put("type_name", kv[0].trim());
newCls.put("type_id", kv[1].trim());
jsonArray.put(newCls);
}
}
JSONObject result = new JSONObject();
JSONArray classes = new JSONArray();
if (jsonArray != null) {
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jObj = jsonArray.getJSONObject(i);
String typeName = jObj.getString("type_name");
String typeId = jObj.getString("type_id");
JSONObject newCls = new JSONObject();
newCls.put("type_id", typeId);
newCls.put("type_name", typeName);
JSONObject typeExtend = jObj.optJSONObject("type_extend");
if (filter) {
String filterStr = getFilterTypes(url, typeExtend);
String[] filters = filterStr.split("\n");
JSONArray filterArr = new JSONArray();
for (int k = url.isEmpty() ? 1 : 0; k < filters.length; k++) {
String l = filters[k].trim();
if (l.isEmpty()) continue;
String[] oneLine = l.split("\\+");
String type = oneLine[0].trim();
String typeN = type;
if (type.contains("筛选")) {
type = type.replace("筛选", "");
switch (type) {
case "class":
typeN = "类型";
break;
case "area":
typeN = "地区";
break;
case "lang":
typeN = "语言";
break;
case "year":
typeN = "年份";
break;
}
}
JSONObject jOne = new JSONObject();
jOne.put("key", type);
jOne.put("name", typeN);
JSONArray valueArr = new JSONArray();
for (int j = 1; j < oneLine.length; j++) {
JSONObject kvo = new JSONObject();
String kv = oneLine[j].trim();
int sp = kv.indexOf("=");
if (sp == -1) {
kvo.put("n", kv);
kvo.put("v", kv);
} else {
String n = kv.substring(0, sp);
kvo.put("n", n.trim());
kvo.put("v", kv.substring(sp + 1).trim());
}
valueArr.put(kvo);
}
jOne.put("value", valueArr);
filterArr.put(jOne);
}
if (!result.has("filters")) {
result.put("filters", new JSONObject());
}
result.getJSONObject("filters").put(typeId, filterArr);
}
classes.put(newCls);
}
}
result.put("class", classes);
return result.toString();
}
@Override
public String homeVideoContent() throws Exception {
String apiUrl = getApiUrl();
String url = getRecommendUrl(apiUrl);
boolean isTV = false;
if (url.isEmpty()) {
url = getCateFilterUrlPrefix(apiUrl) + "movie&page=1&area=&type=&start=";
isTV = true;
}
SpiderDebug.log(url);
String json = OkHttp.string(url, getHeaders(url));
JSONObject obj = new JSONObject(json);
JSONArray videos = new JSONArray();
if (isTV) {
JSONArray jsonArray = obj.getJSONArray("data");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject vObj = jsonArray.getJSONObject(i);
JSONObject v = new JSONObject();
v.put("vod_id", vObj.getString("nextlink"));
v.put("vod_name", vObj.getString("title"));
v.put("vod_pic", vObj.getString("pic"));
v.put("vod_remarks", vObj.getString("state"));
videos.put(v);
}
} else {
ArrayList<JSONArray> arrays = new ArrayList<>();
findJsonArray(obj, "vlist", arrays);
if (arrays.isEmpty()) {
findJsonArray(obj, "vod_list", arrays);
}
List<String> ids = new ArrayList<>();
for (JSONArray jsonArray : arrays) {
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject vObj = jsonArray.getJSONObject(i);
String vid = vObj.getString("vod_id");
if (ids.contains(vid)) continue;
ids.add(vid);
JSONObject v = new JSONObject();
v.put("vod_id", vid);
v.put("vod_name", vObj.getString("vod_name"));
v.put("vod_pic", vObj.getString("vod_pic"));
v.put("vod_remarks", vObj.getString("vod_remarks"));
videos.put(v);
}
}
}
JSONObject result = new JSONObject();
result.put("list", videos);
return result.toString();
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
String apiUrl = getApiUrl();
String url = getCateFilterUrlPrefix(apiUrl) + tid + getCateFilterUrlSuffix(apiUrl);
url = url.replace("#PN#", pg);
url = url.replace("筛选class", (extend != null && extend.containsKey("class")) ? extend.get("class") : "");
url = url.replace("筛选area", (extend != null && extend.containsKey("area")) ? extend.get("area") : "");
url = url.replace("筛选lang", (extend != null && extend.containsKey("lang")) ? extend.get("lang") : "");
url = url.replace("筛选year", (extend != null && extend.containsKey("year")) ? extend.get("year") : "");
url = url.replace("排序", (extend != null && extend.containsKey("排序")) ? extend.get("排序") : "");
SpiderDebug.log(url);
String json = OkHttp.string(url, getHeaders(url));
JSONObject obj = new JSONObject(json);
int totalPg = Integer.MAX_VALUE;
try {
if (obj.has("totalpage") && obj.get("totalpage") instanceof Integer) {
totalPg = obj.getInt("totalpage");
} else if (obj.has("pagecount") && obj.get("pagecount") instanceof Integer) {
totalPg = obj.getInt("pagecount");
} else if (obj.has("data") && obj.get("data") instanceof JSONObject && (obj.getJSONObject("data").has("total") && obj.getJSONObject("data").get("total") instanceof Integer && obj.getJSONObject("data").has("limit") && obj.getJSONObject("data").get("limit") instanceof Integer)) {
int limit = obj.getJSONObject("data").getInt("limit");
int total = obj.getJSONObject("data").getInt("total");
totalPg = total % limit == 0 ? (total / limit) : (total / limit + 1);
}
} catch (Exception e) {
SpiderDebug.log(e);
}
JSONArray jsonArray = null;
JSONArray videos = new JSONArray();
if (obj.has("list") && obj.get("list") instanceof JSONArray) {
jsonArray = obj.getJSONArray("list");
} else if (obj.has("data") && obj.get("data") instanceof JSONObject && obj.getJSONObject("data").has("list") && obj.getJSONObject("data").get("list") instanceof JSONArray) {
jsonArray = obj.getJSONObject("data").getJSONArray("list");
} else if (obj.has("data") && obj.get("data") instanceof JSONArray) {
jsonArray = obj.getJSONArray("data");
}
if (jsonArray != null) {
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject vObj = jsonArray.getJSONObject(i);
if (vObj.has("vod_id")) {
JSONObject v = new JSONObject();
v.put("vod_id", vObj.getString("vod_id"));
v.put("vod_name", vObj.getString("vod_name"));
v.put("vod_pic", vObj.getString("vod_pic"));
v.put("vod_remarks", vObj.getString("vod_remarks"));
videos.put(v);
} else {
JSONObject v = new JSONObject();
v.put("vod_id", vObj.getString("nextlink"));
v.put("vod_name", vObj.getString("title"));
v.put("vod_pic", vObj.getString("pic"));
v.put("vod_remarks", vObj.getString("state"));
videos.put(v);
}
}
}
JSONObject result = new JSONObject();
result.put("page", pg);
result.put("pagecount", totalPg);
result.put("limit", 90);
result.put("total", Integer.MAX_VALUE);
result.put("list", videos);
return result.toString();
}
@Override
public String detailContent(List<String> ids) throws Exception {
String apiUrl = getApiUrl();
String url = getPlayUrlPrefix(apiUrl) + ids.get(0);
SpiderDebug.log(url);
String json = OkHttp.string(url, getHeaders(url));
JSONObject obj = new JSONObject(json);
JSONObject result = new JSONObject();
JSONObject vod = new JSONObject();
genPlayList(apiUrl, obj, json, vod, ids.get(0));
JSONArray list = new JSONArray();
list.put(vod);
result.put("list", list);
return result.toString();
}
@Override
public String searchContent(String key, boolean quick) throws Exception {
String apiUrl = getApiUrl();
String url = getSearchUrl(apiUrl, URLEncoder.encode(key));
String json = OkHttp.string(url, getHeaders(url));
JSONObject obj = new JSONObject(json);
JSONArray jsonArray = null;
JSONArray videos = new JSONArray();
if (obj.has("list") && obj.get("list") instanceof JSONArray) {
jsonArray = obj.getJSONArray("list");
} else if (obj.has("data") && obj.get("data") instanceof JSONObject && obj.getJSONObject("data").has("list") && obj.getJSONObject("data").get("list") instanceof JSONArray) {
jsonArray = obj.getJSONObject("data").getJSONArray("list");
} else if (obj.has("data") && obj.get("data") instanceof JSONArray) {
jsonArray = obj.getJSONArray("data");
}
if (jsonArray != null) {
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject vObj = jsonArray.getJSONObject(i);
if (vObj.has("vod_id")) {
JSONObject v = new JSONObject();
v.put("vod_id", vObj.getString("vod_id"));
v.put("vod_name", vObj.getString("vod_name"));
v.put("vod_pic", vObj.getString("vod_pic"));
v.put("vod_remarks", vObj.getString("vod_remarks"));
videos.put(v);
} else {
JSONObject v = new JSONObject();
v.put("vod_id", vObj.getString("nextlink"));
v.put("vod_name", vObj.getString("title"));
v.put("vod_pic", vObj.getString("pic"));
v.put("vod_remarks", vObj.getString("state"));
videos.put(v);
}
}
}
JSONObject result = new JSONObject();
result.put("list", videos);
return result.toString();
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
if (flag.contains("fanqie") && Util.isVideoFormat(id)) {
JSONObject result = new JSONObject();
result.put("parse", 0);
result.put("playUrl", "");
result.put("url", id);
return result.toString();
}
ArrayList<String> parseUrls = parseUrlMap.get(flag);
if (parseUrls == null) parseUrls = new ArrayList<>();
if (!parseUrls.isEmpty()) {
JSONObject result = getFinalVideo(flag, parseUrls, id);
if (result != null) return result.toString();
}
if (Util.isVideoFormat(id)) {
JSONObject result = new JSONObject();
result.put("parse", 0);
result.put("playUrl", "");
result.put("url", id);
return result.toString();
} else {
JSONObject result = new JSONObject();
result.put("parse", 1);
result.put("jx", "1");
result.put("url", id);
return result.toString();
}
}
private void findJsonArray(JSONObject obj, String match, ArrayList<JSONArray> result) {
Iterator<String> keys = obj.keys();
while (keys.hasNext()) {
String k = keys.next();
try {
Object o = obj.get(k);
if (k.equals(match) && o instanceof JSONArray) result.add((JSONArray) o);
if (o instanceof JSONObject) {
findJsonArray((JSONObject) o, match, result);
} else if (o instanceof JSONArray) {
JSONArray array = (JSONArray) o;
for (int i = 0; i < array.length(); i++) {
findJsonArray(array.getJSONObject(i), match, result);
}
}
} catch (JSONException e) {
SpiderDebug.log(e);
}
}
}
private String jsonArr2Str(JSONArray array) {
try {
ArrayList<String> strings = new ArrayList<>();
for (int i = 0; i < array.length(); i++) {
strings.add(array.getString(i));
}
return TextUtils.join(",", strings);
} catch (JSONException e) {
return "";
}
}
private HashMap<String, String> getHeaders(String URL) {
HashMap<String, String> headers = new HashMap<>();
headers.put("User-Agent", UA(URL));
return headers;
}
// M 扩展方法
// ######重组搜索
private String getSearchUrl(String URL, String KEY) {
if (URL.contains(".vod")) {
if (URL.contains("iopenyun.com")) {
return URL + "/list?wd=" + KEY + "&page=";
} else {
return URL + "?wd=" + KEY + "&page=";
}
} else if (URL.contains("api.php/app") || URL.contains("xgapp")) {
return URL + "search?text=" + KEY + "&pg=";
} else if (urlPattern1.matcher(URL).find()) {
if (URL.contains("esellauto") || URL.contains("1.14.63.101") || URL.contains("zjys") || URL.contains("dcd") || URL.contains("lxue") || URL.contains("weetai.cn") || URL.contains("haokanju1") || URL.contains("fit:8") || URL.contains("zjj.life") || URL.contains("love9989") || URL.contains("8d8q") || URL.contains("lk.pxun") || URL.contains("hgyx") || URL.contains("521x5") || URL.contains("lxyyy") || URL.contains("0818tv") || URL.contains("diyoui") || URL.contains("diliktv") || URL.contains("ppzhu") || URL.contains("aitesucai") || URL.contains("zz.ci") || URL.contains("chxjon") || URL.contains("watchmi") || URL.contains("vipbp") || URL.contains("bhtv") || URL.contains("xfykl")) {
return URL + "?ac=list&" + "wd=" + KEY + "&page=";
} else {
return URL + "?ac=list&" + "zm=" + KEY + "&page=";
}
}
return "";
}
// ######UA
private static final Pattern urlPattern1 = Pattern.compile("api\\.php/.*?/vod");
private static final Pattern urlPattern2 = Pattern.compile("api\\.php/.+?\\.vod");
private static final Pattern parsePattern = Pattern.compile("/.+\\?.+=");
private static final Pattern parsePattern1 = Pattern.compile(".*(url|v|vid|php\\?id)=");
private static final Pattern parsePattern2 = Pattern.compile("https?://[^/]*");
protected static final Pattern[] htmlVideoKeyMatch = new Pattern[]{Pattern.compile("player=new"), Pattern.compile("<div id=\"video\""), Pattern.compile("<div id=\"[^\"]*?player\""), Pattern.compile("//视频链接"), Pattern.compile("HlsJsPlayer\\("), Pattern.compile("<iframe[\\s\\S]*?src=\"[^\"]+?\""), Pattern.compile("<video[\\s\\S]*?src=\"[^\"]+?\"")};
private String UA(String URL) {
if (URL.contains("vod.9e03.com")) {
return "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Mobile Safari/537.36";
} else if (URL.contains("api.php/app") || URL.contains("xgapp") || URL.contains("freekan")) {
return "Dart/2.14 (dart:io)";
} else if (URL.contains("zsb") || URL.contains("fkxs") || URL.contains("xays") || URL.contains("xcys") || URL.contains("szys") || URL.contains("dxys") || URL.contains("ytys") || URL.contains("qnys")) {
return "Dart/2.15 (dart:io)";
} else if (URL.contains(".vod")) {
return "okhttp/4.1.0";
} else {
return "Dalvik/2.1.0";
}
}
// ######获取分类地址
String getCateUrl(String URL) {
if (URL.contains("api.php/app") || URL.contains("xgapp")) {
return URL + "nav?token=";
} else if (URL.contains(".vod")) {
if (URL.contains("iopenyun.com")) {
return URL + "/list?type";
} else {
return URL + "/types";
}
} else {
return "";
}
}
// ######分类筛选前缀地址
String getCateFilterUrlPrefix(String URL) {
if (URL.contains("api.php/app") || URL.contains("xgapp")) {
if (URL.contains("dijiaxia")) {
URL = "http://www.dijiaxia.com/api.php/app/";
return URL + "video?tid=";
} else {
return URL + "video?tid=";
}
} else if (URL.contains(".vod")) {
if (URL.contains("tv.bulei.cc")) {
return "https://tv.bulei.cc/api2.php/v1.vod?type=";
}
if (URL.contains("iopenyun")) {
return URL + "/list?type=";
} else {
return URL + "?type=";
}
} else {
return URL + "?ac=list&class=";
}
}
// ######分类筛选后缀地址
String getCateFilterUrlSuffix(String URL) {
if (URL.contains("api.php/app") || URL.contains("xgapp")) {
return "&class=筛选class&area=筛选area&lang=筛选lang&year=筛选year&limit=18&pg=#PN#";
} else if (URL.contains(".vod")) {
return "&class=筛选class&area=筛选area&lang=筛选lang&year=筛选year&by=排序&limit=18&page=#PN#";
} else {
return "&page=#PN#&area=筛选area&type=筛选class&start=筛选year";
}
}
// ######筛选内容
String getFilterTypes(String URL, JSONObject typeExtend) {
String str = "";
if (typeExtend != null) {
Iterator<String> typeExtendKeys = typeExtend.keys();
while (typeExtendKeys.hasNext()) {
String key = typeExtendKeys.next();
if (key.equals("class") || key.equals("area") || key.equals("lang") || key.equals("year")) {
try {
str = str + "筛选" + key + "+全部=+" + typeExtend.getString(key).replace(",", "+") + "\n";
} catch (JSONException e) {
}
}
}
}
if (URL.contains(".vod")) {
str += "\n" + "排序+全部=+最新=time+最热=hits+评分=score";
} else if (URL.contains("api.php/app") || URL.contains("xgapp")) {
} else {
str = "分类+全部=+电影=movie+连续剧=tvplay+综艺=tvshow+动漫=comic+4K=movie_4k+体育=tiyu\n筛选class+全部=+喜剧+爱情+恐怖+动作+科幻+剧情+战争+警匪+犯罪+动画+奇幻+武侠+冒险+枪战+恐怖+悬疑+惊悚+经典+青春+文艺+微电影+古装+历史+运动+农村+惊悚+惊悚+伦理+情色+福利+三级+儿童+网络电影\n筛选area+全部=+大陆+香港+台湾+美国+英国+法国+日本+韩国+德国+泰国+印度+西班牙+加拿大+其他\n筛选year+全部=+2023+2022+2021+2020+2019+2018+2017+2016+2015+2014+2013+2012+2011+2010+2009+2008+2007+2006+2005+2004+2003+2002+2001+2000";
}
return str;
}
// ######推荐地址
String getRecommendUrl(String URL) {
if (URL.contains("api.php/app") || URL.contains("xgapp")) {
return URL + "index_video?token=";
} else if (URL.contains(".vod")) {
return URL + "/vodPhbAll";
} else {
return "";
}
}
// ######播放器前缀地址
String getPlayUrlPrefix(String URL) {
if (URL.contains("api.php/app") || URL.contains("xgapp")) {
if (URL.contains("dijiaxia")) {
URL = "https://www.dijiaxia.com/api.php/app/";
return URL + "video_detail?id=";
} else if (URL.contains("1010dy")) {
URL = "http://www.1010dy.cc/api.php/app/";
return URL + "video_detail?id=";
} else {
return URL + "video_detail?id=";
}
} else if (URL.contains(".vod")) {
if (URL.contains("iopenyun")) {
return URL + "/detailID?vod_id=";
} else {
return URL + "/detail?vod_id=";
}
} else {
return "";
}
}
// ######选集
protected final HashMap<String, ArrayList<String>> parseUrlMap = new HashMap<>();
private void genPlayList(String URL, JSONObject object, String json, JSONObject vod, String vid) throws JSONException {
ArrayList<String> playUrls = new ArrayList<>();
ArrayList<String> playFlags = new ArrayList<>();
if (URL.contains("api.php/app/")) {
JSONObject data = object.getJSONObject("data");
vod.put("vod_id", data.optString("vod_id", vid));
vod.put("vod_name", data.getString("vod_name"));
vod.put("vod_pic", data.getString("vod_pic"));
vod.put("type_name", data.optString("vod_class"));
vod.put("vod_year", data.optString("vod_year"));
vod.put("vod_area", data.optString("vod_area"));
vod.put("vod_remarks", data.optString("vod_remarks"));
vod.put("vod_actor", data.optString("vod_actor"));
vod.put("vod_director", data.optString("vod_director"));
vod.put("vod_content", data.optString("vod_content"));
JSONArray vodUrlWithPlayer = data.getJSONArray("vod_url_with_player");
for (int i = 0; i < vodUrlWithPlayer.length(); i++) {
JSONObject from = vodUrlWithPlayer.getJSONObject(i);
String flag = from.optString("code").trim();
if (flag.isEmpty()) flag = from.getString("name").trim();
playFlags.add(flag);
playUrls.add(from.getString("url"));
String purl = from.optString("parse_api").trim();
ArrayList<String> parseUrls = parseUrlMap.get(flag);
if (parseUrls == null) {
parseUrls = new ArrayList<>();
parseUrlMap.put(flag, parseUrls);
}
if (!purl.isEmpty() && !parseUrls.contains(purl)) parseUrls.add(purl);
}
} else if (URL.contains("xgapp")) {
JSONObject data = object.getJSONObject("data").getJSONObject("vod_info");
vod.put("vod_id", data.optString("vod_id", vid));
vod.put("vod_name", data.getString("vod_name"));
vod.put("vod_pic", data.getString("vod_pic"));
vod.put("type_name", data.optString("vod_class"));
vod.put("vod_year", data.optString("vod_year"));
vod.put("vod_area", data.optString("vod_area"));
vod.put("vod_remarks", data.optString("vod_remarks"));
vod.put("vod_actor", data.optString("vod_actor"));
vod.put("vod_director", data.optString("vod_director"));
vod.put("vod_content", data.optString("vod_content"));
JSONArray vodUrlWithPlayer = data.getJSONArray("vod_url_with_player");
for (int i = 0; i < vodUrlWithPlayer.length(); i++) {
JSONObject from = vodUrlWithPlayer.getJSONObject(i);
String flag = from.optString("code").trim();
if (flag.isEmpty()) flag = from.getString("name").trim();
playFlags.add(flag);
playUrls.add(from.getString("url"));
String purl = from.optString("parse_api").trim();
ArrayList<String> parseUrls = parseUrlMap.get(flag);
if (parseUrls == null) {
parseUrls = new ArrayList<>();
parseUrlMap.put(flag, parseUrls);
}
if (!purl.isEmpty() && !parseUrls.contains(purl)) parseUrls.add(purl);
}
} else if (/*urlPattern2.matcher(URL).find()*/URL.contains(".vod")) {
JSONObject data = object.getJSONObject("data");
vod.put("vod_id", data.optString("vod_id", vid));
vod.put("vod_name", data.getString("vod_name"));
vod.put("vod_pic", data.getString("vod_pic"));
vod.put("type_name", data.optString("vod_class"));
vod.put("vod_year", data.optString("vod_year"));
vod.put("vod_area", data.optString("vod_area"));
vod.put("vod_remarks", data.optString("vod_remarks"));
vod.put("vod_actor", data.optString("vod_actor"));
vod.put("vod_director", data.optString("vod_director"));
vod.put("vod_content", data.optString("vod_content"));
JSONArray vodUrlWithPlayer = data.getJSONArray("vod_play_list");
for (int i = 0; i < vodUrlWithPlayer.length(); i++) {
JSONObject from = vodUrlWithPlayer.getJSONObject(i);
String flag = from.getJSONObject("player_info").optString("from").trim();
if (flag.isEmpty()) flag = from.getJSONObject("player_info").optString("show").trim();
playFlags.add(flag);
playUrls.add(from.getString("url"));
try {
ArrayList<String> parses = new ArrayList<>();
String[] parse1 = from.getJSONObject("player_info").optString("parse").split(",");
String[] parse2 = from.getJSONObject("player_info").optString("parse2").split(",");
parses.addAll(Arrays.asList(parse1));
parses.addAll(Arrays.asList(parse2));
ArrayList<String> parseUrls = parseUrlMap.get(flag);
if (parseUrls == null) {
parseUrls = new ArrayList<>();
parseUrlMap.put(flag, parseUrls);
}
for (String purl : parses) {
if (purl.contains("http")) {
Matcher matcher = parsePattern1.matcher(purl);
if (matcher.find()) {
purl = matcher.group(0);
}
} else if (purl.contains("//")) {
Matcher matcher = parsePattern1.matcher(purl);
if (matcher.find()) {
purl = "http:" + matcher.group(0);
}
} else {
Matcher matcher = parsePattern2.matcher(URL);
if (matcher.find()) {
Matcher matcher1 = parsePattern1.matcher(URL);
if (matcher1.find()) {
purl = matcher.group(0) + matcher1.group(0);
}
}
}
purl = purl.replace("..", ".").trim();
if (!purl.isEmpty() && !parseUrls.contains(purl)) parseUrls.add(purl);
}
} catch (Exception e) {
SpiderDebug.log(e);
}
}
} else if (urlPattern1.matcher(URL).find()) {
JSONObject data = object;
vod.put("vod_id", data.optString("vod_id", vid));
vod.put("vod_name", data.getString("title"));
vod.put("vod_pic", data.getString("img_url"));
vod.put("type_name", jsonArr2Str(data.optJSONArray("type")));
vod.put("vod_year", data.optString("pubtime"));
vod.put("vod_area", jsonArr2Str(data.optJSONArray("area")));
vod.put("vod_remarks", data.optString("trunk"));
vod.put("vod_actor", jsonArr2Str(data.optJSONArray("actor")));
vod.put("vod_director", jsonArr2Str(data.optJSONArray("director")));
vod.put("vod_content", data.optString("intro"));
JSONObject playList = data.getJSONObject("videolist");
Iterator<String> playListKeys = playList.keys();
while (playListKeys.hasNext()) {
String flag = playListKeys.next();
ArrayList<String> parseUrls = parseUrlMap.get(flag);
if (parseUrls == null) {
parseUrls = new ArrayList<>();
parseUrlMap.put(flag, parseUrls);
}
JSONArray playListUrls = playList.getJSONArray(flag);
ArrayList<String> urls = new ArrayList<>();
for (int j = 0; j < playListUrls.length(); j++) {
JSONObject urlObj = playListUrls.getJSONObject(j);
String url = urlObj.getString("url");
if (url.contains("url=")) {
int spIdx = url.indexOf("url=") + 4;
String pUrl = url.substring(0, spIdx).trim();
if (!pUrl.isEmpty() && !parseUrls.contains(pUrl)) parseUrls.add(pUrl);
urls.add(urlObj.getString("title") + "$" + url.substring(spIdx).trim());
} else {
urls.add(urlObj.getString("title") + "$" + url);
}
}
playFlags.add(flag);
playUrls.add(TextUtils.join("#", urls));
}
}
vod.put("vod_play_from", TextUtils.join("$$$", playFlags));
vod.put("vod_play_url", TextUtils.join("$$$", playUrls));
}
// ######视频地址
protected JSONObject getFinalVideo(String flag, ArrayList<String> parseUrls, String url) throws JSONException {
String htmlPlayUrl = "";
for (String parseUrl : parseUrls) {
if (parseUrl.isEmpty() || parseUrl.equals("null")) continue;
String playUrl = parseUrl + url;
String content = OkHttp.string(playUrl);
JSONObject tryJson = null;
try {
tryJson = jsonParse(url, content);
} catch (Throwable th) {
}
if (tryJson != null && tryJson.has("url") && tryJson.has("header")) {
tryJson.put("header", tryJson.getJSONObject("header").toString());
return tryJson;
}
if (content.contains("<html")) {
boolean sniffer = false;
for (Pattern p : htmlVideoKeyMatch) {
if (p.matcher(content).find()) {
sniffer = true;
break;
}
}
if (sniffer) {
htmlPlayUrl = parseUrl;
}
}
}
if (!htmlPlayUrl.isEmpty()) {
JSONObject result = new JSONObject();
result.put("parse", 1);
result.put("playUrl", htmlPlayUrl);
result.put("url", url);
return result;
}
return null;
}
@Override
public boolean manualVideoCheck() {
return true;
}
@Override
public boolean isVideoFormat(String url) {
return Util.isVideoFormat(url);
}
private String getApiUrl() {
if (extInfos == null || extInfos.length < 1) return "";
return extInfos[0].trim();
}
private String[] extInfos = null;
public static JSONObject jsonParse(String input, String json) throws JSONException {
//处理解析接口返回的报文如果返回的报文中包含header信息就加到返回值中
JSONObject jsonPlayData = new JSONObject(json);
if (jsonPlayData.has("data") && jsonPlayData.get("data") instanceof JSONObject && !jsonPlayData.has("url")) {
jsonPlayData = jsonPlayData.getJSONObject("data");
}
String url = jsonPlayData.getString("url");
if (url.startsWith("//")) {
url = "https:" + url;
}
if (!url.trim().startsWith("http")) {
return null;
}
if (url.equals(input)) {
if (Util.isVip(url) || !Util.isVideoFormat(url)) {
return null;
}
}
if (Util.isBlackVodUrl(url)) {
return null;
}
JSONObject headers = new JSONObject();
if (jsonPlayData.has("header")) {
headers = jsonPlayData.optJSONObject("header");
} else if (jsonPlayData.has("Header")) {
headers = jsonPlayData.optJSONObject("Header");
} else if (jsonPlayData.has("headers")) {
headers = jsonPlayData.optJSONObject("headers");
} else if (jsonPlayData.has("Headers")) {
headers = jsonPlayData.optJSONObject("Headers");
}
String ua = "";
if (jsonPlayData.has("user-agent")) {
ua = jsonPlayData.optString("user-agent", "");
} else if (jsonPlayData.has("User-Agent")) {
ua = jsonPlayData.optString("User-Agent", "");
}
if (ua.trim().length() > 0) {
headers.put("User-Agent", " " + ua);
}
String referer = "";
if (jsonPlayData.has("referer")) {
referer = jsonPlayData.optString("referer", "");
} else if (jsonPlayData.has("Referer")) {
referer = jsonPlayData.optString("Referer", "");
}
if (referer.trim().length() > 0) {
headers.put("Referer", " " + referer);
}
headers = fixJsonVodHeader(headers, input, url);
JSONObject taskResult = new JSONObject();
taskResult.put("header", headers);
taskResult.put("url", url);
taskResult.put("parse", "0");
return taskResult;
}
public static JSONObject fixJsonVodHeader(JSONObject headers, String input, String url) throws JSONException {
if (headers == null) headers = new JSONObject();
if (input.contains("www.mgtv.com")) {
headers.put("Referer", " ");
headers.put("User-Agent", " Mozilla/5.0");
} else if (url.contains("titan.mgtv")) {
headers.put("Referer", " ");
headers.put("User-Agent", " Mozilla/5.0");
} else if (input.contains("bilibili")) {
headers.put("Referer", " https://www.bilibili.com/");
headers.put("User-Agent", " " + Util.CHROME);
}
return headers;
}
}

View File

@@ -0,0 +1,280 @@
package com.github.catvod.spider;
import android.content.Context;
import android.text.TextUtils;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Filter;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.bean.bili.Dash;
import com.github.catvod.bean.bili.Data;
import com.github.catvod.bean.bili.Media;
import com.github.catvod.bean.bili.Page;
import com.github.catvod.bean.bili.Resp;
import com.github.catvod.bean.bili.Wbi;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Json;
import com.github.catvod.utils.Path;
import com.github.catvod.utils.Util;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* @author ColaMint & FongMi & 唐三
*/
public class Bili extends Spider {
private static final String COOKIE = "buvid3=84B0395D-C9F2-C490-E92E-A09AB48FE26E71636infoc";
private static Map<String, String> audios;
private static String cookie;
private JsonObject extend;
private boolean login;
private boolean isVip;
private Wbi wbi;
private static Map<String, String> getHeader() {
Map<String, String> headers = new HashMap<>();
headers.put("User-Agent", Util.CHROME);
headers.put("Referer", "https://www.bilibili.com");
if (cookie != null) headers.put("cookie", cookie);
return headers;
}
private void setAudio() {
audios = new HashMap<>();
audios.put("30280", "192000");
audios.put("30232", "132000");
audios.put("30216", "64000");
}
private void setCookie() {
cookie = extend.get("cookie").getAsString();
if (cookie.startsWith("http")) cookie = OkHttp.string(cookie).trim();
if (TextUtils.isEmpty(cookie)) cookie = Path.read(getCache());
if (TextUtils.isEmpty(cookie)) cookie = COOKIE;
}
private List<Filter> getFilter() {
List<Filter> items = new ArrayList<>();
items.add(new Filter("order", "排序", Arrays.asList(new Filter.Value("預設", "totalrank"), new Filter.Value("最多點擊", "click"), new Filter.Value("最新發布", "pubdate"), new Filter.Value("最多彈幕", "dm"), new Filter.Value("最多收藏", "stow"))));
items.add(new Filter("duration", "時長", Arrays.asList(new Filter.Value("全部時長", "0"), new Filter.Value("60分鐘以上", "4"), new Filter.Value("30~60分鐘", "3"), new Filter.Value("10~30分鐘", "2"), new Filter.Value("10分鐘以下", "1"))));
return items;
}
private File getCache() {
return Path.tv("bilibili");
}
@Override
public void init(Context context, String extend) throws Exception {
this.extend = Json.safeObject(extend);
setCookie();
setAudio();
}
@Override
public String homeContent(boolean filter) throws Exception {
if (extend.has("json")) return OkHttp.string(extend.get("json").getAsString());
List<Class> classes = new ArrayList<>();
LinkedHashMap<String, List<Filter>> filters = new LinkedHashMap<>();
String[] types = extend.get("type").getAsString().split("#");
for (String type : types) {
classes.add(new Class(type));
filters.put(type, getFilter());
}
return Result.string(classes, filters);
}
@Override
public String homeVideoContent() {
String api = "https://api.bilibili.com/x/web-interface/popular?ps=20";
String json = OkHttp.string(api, getHeader());
Resp resp = Resp.objectFrom(json);
List<Vod> list = new ArrayList<>();
for (Resp.Result item : Resp.Result.arrayFrom(resp.getData().getList())) list.add(item.getVod());
return Result.string(list);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
if (tid.endsWith("/{pg}")) {
LinkedHashMap<String, Object> params = new LinkedHashMap<>();
params.put("mid", tid.split("/")[0]);
params.put("pn", pg);
List<Vod> list = new ArrayList<>();
String json = OkHttp.string("https://api.bilibili.com/x/space/wbi/arc/search?" + wbi.getQuery(params), getHeader());
for (Resp.Result item : Resp.Result.arrayFrom(Resp.objectFrom(json).getData().getList().getAsJsonObject().get("vlist"))) list.add(item.getVod());
return Result.string(list);
} else {
String order = extend.containsKey("order") ? extend.get("order") : "totalrank";
String duration = extend.containsKey("duration") ? extend.get("duration") : "0";
if (extend.containsKey("tid")) tid = tid + " " + extend.get("tid");
String api = "https://api.bilibili.com/x/web-interface/search/type?search_type=video&keyword=" + URLEncoder.encode(tid) + "&order=" + order + "&duration=" + duration + "&page=" + pg;
String json = OkHttp.string(api, getHeader());
Resp resp = Resp.objectFrom(json);
List<Vod> list = new ArrayList<>();
for (Resp.Result item : Resp.Result.arrayFrom(resp.getData().getResult())) list.add(item.getVod());
return Result.string(list);
}
}
@Override
public String detailContent(List<String> ids) throws Exception {
if (!login) checkLogin();
String[] split = ids.get(0).split("@");
String bvid = split[0];
String aid = split[1];
String api = "https://api.bilibili.com/x/web-interface/view?aid=" + aid;
String json = OkHttp.string(api, getHeader());
Data detail = Resp.objectFrom(json).getData();
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodPic(detail.getPic());
vod.setVodName(detail.getTitle());
vod.setTypeName(detail.getType());
vod.setVodContent(detail.getDesc());
vod.setVodDirector(detail.getOwner().getFormat());
vod.setVodRemarks(detail.getDuration() / 60 + "分鐘");
List<String> acceptDesc = new ArrayList<>();
List<Integer> acceptQuality = new ArrayList<>();
api = "https://api.bilibili.com/x/player/playurl?avid=" + aid + "&cid=" + detail.getCid() + "&qn=127&fnval=4048&fourk=1";
json = OkHttp.string(api, getHeader());
Data play = Resp.objectFrom(json).getData();
for (int i = 0; i < play.getAcceptQuality().size(); i++) {
int qn = play.getAcceptQuality().get(i);
if (!login && qn > 32) continue;
if (!isVip && qn > 80) continue;
acceptQuality.add(play.getAcceptQuality().get(i));
acceptDesc.add(play.getAcceptDescription().get(i));
}
List<String> episode = new ArrayList<>();
LinkedHashMap<String, String> flag = new LinkedHashMap<>();
for (Page page : detail.getPages()) episode.add(page.getPart() + "$" + aid + "+" + page.getCid() + "+" + TextUtils.join(":", acceptQuality) + "+" + TextUtils.join(":", acceptDesc));
flag.put("B站", TextUtils.join("#", episode));
episode = new ArrayList<>();
api = "https://api.bilibili.com/x/web-interface/archive/related?bvid=" + bvid;
json = OkHttp.string(api, getHeader());
JsonArray array = Json.parse(json).getAsJsonObject().getAsJsonArray("data");
for (int i = 0; i < array.size(); i++) {
JsonObject object = array.get(i).getAsJsonObject();
episode.add(object.get("title").getAsString() + "$" + object.get("aid").getAsInt() + "+" + object.get("cid").getAsInt() + "+" + TextUtils.join(":", acceptQuality) + "+" + TextUtils.join(":", acceptDesc));
}
flag.put("相关", TextUtils.join("#", episode));
vod.setVodPlayFrom(TextUtils.join("$$$", flag.keySet()));
vod.setVodPlayUrl(TextUtils.join("$$$", flag.values()));
return Result.string(vod);
}
@Override
public String searchContent(String key, boolean quick) throws Exception {
return categoryContent(key, "1", true, new HashMap<>());
}
@Override
public String searchContent(String key, boolean quick, String pg) throws Exception {
return categoryContent(key, pg, true, new HashMap<>());
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
String[] ids = id.split("\\+");
String aid = ids[0];
String cid = ids[1];
String[] acceptDesc = ids[3].split(":");
String[] acceptQuality = ids[2].split(":");
List<String> url = new ArrayList<>();
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");
}
return Result.get().url(url).danmaku(dan).dash().header(getHeader()).string();
}
public static Object[] proxy(Map<String, String> params) {
String aid = params.get("aid");
String cid = params.get("cid");
String qn = params.get("qn");
String api = "https://api.bilibili.com/x/player/playurl?avid=" + aid + "&cid=" + cid + "&qn=" + qn + "&fnval=4048&fourk=1";
String json = OkHttp.string(api, getHeader());
Resp resp = Resp.objectFrom(json);
Dash dash = resp.getData().getDash();
StringBuilder video = new StringBuilder();
StringBuilder audio = new StringBuilder();
findAudio(dash, audio);
findVideo(dash, video, qn);
String mpd = getMpd(dash, video.toString(), audio.toString());
Object[] result = new Object[3];
result[0] = 200;
result[1] = "application/dash+xml";
result[2] = new ByteArrayInputStream(mpd.getBytes());
return result;
}
private static void findAudio(Dash dash, StringBuilder sb) {
for (Media audio : dash.getAudio()) {
for (String key : audios.keySet()) {
if (audio.getId().equals(key)) {
sb.append(getMedia(audio));
}
}
}
}
private static void findVideo(Dash dash, StringBuilder sb, String qn) {
for (Media video : dash.getVideo()) {
if (video.getId().equals(qn)) {
sb.append(getMedia(video));
}
}
}
private static String getMedia(Media media) {
if (media.getMimeType().startsWith("video")) {
return getAdaptationSet(media, String.format(Locale.getDefault(), "height='%s' width='%s' frameRate='%s' sar='%s'", media.getHeight(), media.getWidth(), media.getFrameRate(), media.getSar()));
} else if (media.getMimeType().startsWith("audio")) {
return getAdaptationSet(media, String.format("numChannels='2' sampleRate='%s'", audios.get(media.getId())));
} else {
return "";
}
}
private static String getAdaptationSet(Media media, String params) {
String id = media.getId() + "_" + media.getCodecId();
String type = media.getMimeType().split("/")[0];
String baseUrl = media.getBaseUrl().replace("&", "&amp;");
return String.format(Locale.getDefault(), "<AdaptationSet>\n" + "<ContentComponent contentType=\"%s\"/>\n" + "<Representation id=\"%s\" bandwidth=\"%s\" codecs=\"%s\" mimeType=\"%s\" %s startWithSAP=\"%s\">\n" + "<BaseURL>%s</BaseURL>\n" + "<SegmentBase indexRange=\"%s\">\n" + "<Initialization range=\"%s\"/>\n" + "</SegmentBase>\n" + "</Representation>\n" + "</AdaptationSet>", type, id, media.getBandWidth(), media.getCodecs(), media.getMimeType(), params, media.getStartWithSap(), baseUrl, media.getSegmentBase().getIndexRange(), media.getSegmentBase().getInitialization());
}
private static String getMpd(Dash dash, String videoList, String audioList) {
return String.format(Locale.getDefault(), "<MPD xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"urn:mpeg:dash:schema:mpd:2011\" xsi:schemaLocation=\"urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd\" type=\"static\" mediaPresentationDuration=\"PT%sS\" minBufferTime=\"PT%sS\" profiles=\"urn:mpeg:dash:profile:isoff-on-demand:2011\">\n" + "<Period duration=\"PT%sS\" start=\"PT0S\">\n" + "%s\n" + "%s\n" + "</Period>\n" + "</MPD>", dash.getDuration(), dash.getMinBufferTime(), dash.getDuration(), videoList, audioList);
}
private void checkLogin() {
String json = OkHttp.string("https://api.bilibili.com/x/web-interface/nav", getHeader());
Data data = Resp.objectFrom(json).getData();
login = data.isLogin();
isVip = data.isVip();
wbi = data.getWbi();
}
}

View File

@@ -0,0 +1,123 @@
package com.github.catvod.spider;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Json;
import com.github.catvod.utils.Util;
import com.google.gson.JsonElement;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Cg51 extends Spider {
private static final String proxyImgUrl = "https://api.buxiangyao.link/51cg/img/?url=";
private static final String siteUrl = "https://h25dz1.gxhfkyztz.com";
private static final String cateUrl = siteUrl + "/category/";
private static final String detailUrl = siteUrl + "/archives/";
private static final String searchUrl = siteUrl + "/search?keywords=";
private HashMap<String, String> getHeaders() {
HashMap<String, String> headers = new HashMap<>();
headers.put("User-Agent", Util.CHROME);
return headers;
}
private List<Vod> parseVods(Document doc) {
List<Vod> list = new ArrayList<>();
for (Element element : doc.select("article")) {
String pic = String.valueOf(element.select("script"));
String pattern = "'(https?://[^']+)";
Pattern regex = Pattern.compile(pattern);
Matcher matcher = regex.matcher(pic);
String PicAddress = "";
if (matcher.find()) {
PicAddress = proxyImgUrl + matcher.group(1);
} else {
}
String url = element.select("a").attr("href");
String name = element.select(".post-card-title").text();
String id = url.split("/")[2];
if (name != "" && url != ""){
list.add(new Vod(id, name, PicAddress));
}
}
return list;
}
@Override
public String homeContent(boolean filter) throws Exception {
List<Class> classes = new ArrayList<>();
String[] typeIdList = {"wpcz","mrdg","rdsj","bkdg","whhl","xsxy","whmx"};
String[] typeNameList = {"今日吃瓜","每日大瓜","热门吃瓜","必看大瓜","网红黑料","学生学校","明星黑料"};
for (int i = 0; i < typeNameList.length; i++) {
classes.add(new Class(typeIdList[i], typeNameList[i]));
}
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeaders()));
List<Vod> list = parseVods(doc);
return Result.string(classes, list);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
String target = cateUrl + tid + "/" + pg + "/";
Document doc = Jsoup.parse(OkHttp.string(target, getHeaders()));
List<Vod> list = parseVods(doc);
Integer total = (Integer.parseInt(pg)+1)*20;
return Result.string(Integer.parseInt(pg),Integer.parseInt(pg)+1,20,total,list);
}
@Override
public String detailContent(List<String> ids) throws Exception {
Document doc = Jsoup.parse(OkHttp.string(detailUrl.concat(ids.get(0)), getHeaders()));
String playUrl = "";
int index = 1;
for (Element element : doc.select("div.dplayer")) {
String play = element.attr("data-config");
JSONObject jsonObject = new JSONObject(play);
if (playUrl == ""){
playUrl = "" + index + "集$" + jsonObject.get("url");
}else {
playUrl = playUrl + "#第" + index + "集$" + jsonObject.get("url");
}
index++;
}
String name = doc.select("meta[property=og:title]").attr("content");
String pic = doc.select("meta[property=og:image]").attr("content");
String year = doc.select("meta[property=video:release_date]").attr("content");
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodPic(pic);
vod.setVodYear(year);
vod.setVodName(name);
vod.setVodPlayFrom("Cg51");
vod.setVodPlayUrl(playUrl);
return Result.string(vod);
}
@Override
public String searchContent(String key, boolean quick) throws Exception {
Document doc = Jsoup.parse(OkHttp.string(searchUrl.concat(URLEncoder.encode(key)), getHeaders()));
List<Vod> list = parseVods(doc);
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();
}
}

View File

@@ -0,0 +1,179 @@
package com.github.catvod.spider;
import android.text.TextUtils;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Filter;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Util;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* @author FongMi
*/
public class Dm84 extends Spider {
private static final String siteUrl = "https://dm84.tv";
private HashMap<String, String> getHeaders() {
HashMap<String, String> headers = new HashMap<>();
headers.put("User-Agent", Util.CHROME);
headers.put("Accept", Util.ACCEPT);
return headers;
}
private Filter getFilter(String name, String key, List<String> texts) {
List<Filter.Value> values = new ArrayList<>();
for (String text : texts) {
if (text.isEmpty()) continue;
String n = text.replace("", "");
String v = key.equals("by") ? replaceBy(text) : text;
values.add(new Filter.Value(n, v));
}
return new Filter(key, name, values);
}
private String replaceBy(String text) {
return text.replace("按时间", "time").replace("按人气", "hits").replace("按评分", "score");
}
@Override
public String homeContent(boolean filter) {
List<Vod> list = new ArrayList<>();
List<Class> classes = new ArrayList<>();
LinkedHashMap<String, List<Filter>> filters = new LinkedHashMap<>();
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeaders()));
for (Element element : doc.select("ul.nav_row > li > a")) {
if (element.attr("href").startsWith("/list")) {
String id = element.attr("href").split("-")[1].substring(0, 1);
String name = element.text().substring(0, 2);
classes.add(new Class(id, name));
}
}
for (Class item : classes) {
doc = Jsoup.parse(OkHttp.string(siteUrl + "/list-" + item.getTypeId() + ".html", getHeaders()));
Elements elements = doc.select("ul.list_filter > li > div");
List<Filter> array = new ArrayList<>();
array.add(getFilter("類型", "type", elements.get(0).select("a").eachText()));
array.add(getFilter("時間", "year", elements.get(1).select("a").eachText()));
array.add(getFilter("排序", "by", elements.get(2).select("a").eachText()));
filters.put(item.getTypeId(), array);
}
for (Element element : doc.select("div.item")) {
String img = element.select("a.cover").attr("data-bg");
String url = element.select("a.title").attr("href");
String name = element.select("a.title").text();
String remark = element.select("span.desc").text();
String id = url.split("/")[2];
list.add(new Vod(id, name, img, remark));
}
return Result.string(classes, list, filters);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
List<Vod> list = new ArrayList<>();
if (extend.get("type") == null) extend.put("type", "");
if (extend.get("year") == null) extend.put("year", "");
if (extend.get("by") == null) extend.put("by", "time");
String by = extend.get("by");
String type = URLEncoder.encode(extend.get("type"));
String year = extend.get("year");
String target = siteUrl + String.format("/show-%s--%s-%s--%s-%s.html", tid, by, type, year, pg);
Document doc = Jsoup.parse(OkHttp.string(target, getHeaders()));
for (Element element : doc.select("div.item")) {
String img = element.select("a.cover").attr("data-bg");
String url = element.select("a.title").attr("href");
String name = element.select("a.title").text();
String remark = element.select("span.desc").text();
String id = url.split("/")[2];
list.add(new Vod(id, name, img, remark));
}
return Result.string(list);
}
@Override
public String detailContent(List<String> ids) {
Document doc = Jsoup.parse(OkHttp.string(siteUrl.concat("/v/").concat(ids.get(0)), getHeaders()));
String name = doc.select("h1.v_title").text();
String remarks = doc.select("p.v_desc > span.desc").text();
String img = doc.select("meta[property=og:image]").attr("content");
String area = doc.select("meta[name=og:video:area]").attr("content");
String type = doc.select("meta[name=og:video:class]").attr("content");
String actor = doc.select("meta[name=og:video:actor]").attr("content");
String content = doc.select("meta[property=og:description]").attr("content");
String year = doc.select("meta[name=og:video:release_date]").attr("content");
String director = doc.select("meta[name=og:video:director]").attr("content");
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodPic(img);
vod.setVodYear(year);
vod.setVodName(name);
vod.setVodArea(area);
vod.setVodActor(actor);
vod.setVodRemarks(remarks);
vod.setVodContent(content);
vod.setVodDirector(director);
vod.setTypeName(type);
Map<String, String> sites = new LinkedHashMap<>();
Elements sources = doc.select("ul.tab_control > li");
Elements sourceList = doc.select("ul.play_list");
for (int i = 0; i < sources.size(); i++) {
Element source = sources.get(i);
String sourceName = source.text();
Elements playList = sourceList.get(i).select("a");
List<String> vodItems = new ArrayList<>();
for (int j = 0; j < playList.size(); j++) {
Element e = playList.get(j);
vodItems.add(e.text() + "$" + e.attr("href"));
}
if (vodItems.size() > 0) {
sites.put(sourceName, TextUtils.join("#", vodItems));
}
}
if (sites.size() > 0) {
vod.setVodPlayFrom(TextUtils.join("$$$", sites.keySet()));
vod.setVodPlayUrl(TextUtils.join("$$$", sites.values()));
}
return Result.string(vod);
}
@Override
public String searchContent(String key, boolean quick) {
List<Vod> list = new ArrayList<>();
String target = siteUrl.concat("/s----------.html?wd=").concat(key);
Document doc = Jsoup.parse(OkHttp.string(target, getHeaders()));
for (Element element : doc.select("div.item")) {
String img = element.select("a.cover").attr("data-bg");
String url = element.select("a.title").attr("href");
String name = element.select("a.title").text();
String remark = element.select("span.desc").text();
String id = url.split("/")[2];
list.add(new Vod(id, name, img, remark));
}
return Result.string(list);
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) {
Document doc = Jsoup.parse(OkHttp.string(siteUrl.concat(id), getHeaders()));
String url = doc.select("iframe").attr("src");
return Result.get().url(url).parse().header(getHeaders()).string();
}
}

View File

@@ -0,0 +1,126 @@
package com.github.catvod.spider;
import android.text.TextUtils;
import android.util.Base64;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Doll extends Spider {
private final String url = "https://hongkongdollvideo.com/";
@Override
public String homeContent(boolean filter) throws Exception {
List<Class> classes = new ArrayList<>();
List<Vod> list = new ArrayList<>();
Document doc = Jsoup.parse(OkHttp.string(url));
for (Element a : doc.select("ul#side-menu").get(0).select("li > a")) {
String typeName = a.text();
String typeId = a.attr("href").replace(url, "");
classes.add(new Class(typeId, typeName));
}
for (Element div : doc.select("div.video-detail")) {
String id = div.select("h3.video-title > a").attr("href").replace(url, "");
String name = div.select("h3.video-title > a").text();
String pic = url + div.select("div.thumb > a > img").attr("data-src");
String remark = div.select("div.date").text();
list.add(new Vod(id, name, pic, remark));
}
return Result.string(classes, list);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
List<Vod> list = new ArrayList<>();
String target = pg.equals("1") ? url + tid : url + tid + "/" + pg + ".html";
Document doc = Jsoup.parse(OkHttp.string(target));
for (Element div : doc.select("div.video-detail")) {
String id = div.select("h3.video-title > a").attr("href").replace(url, "");
String name = div.select("h3.video-title > a").text();
String pic = url + div.select("div.thumb > a > img").attr("data-src");
String remark = div.select("div.date").text();
list.add(new Vod(id, name, pic, remark));
}
return Result.string(list);
}
@Override
public String detailContent(List<String> ids) throws Exception {
String html = OkHttp.string(url + ids.get(0));
Document doc = Jsoup.parse(html);
String pic = doc.select("meta[property=og:image]").attr("content");
String name = doc.select("meta[property=og:title]").attr("content");
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodPic(pic);
vod.setVodName(name);
vod.setVodPlayFrom("玩偶姐姐");
vod.setVodPlayUrl("播放$" + url + ids.get(0));
return Result.string(vod);
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
String key = "";
String voteTag = "";
StringBuilder code = new StringBuilder();
String html = OkHttp.string(id);
Document doc = Jsoup.parse(html);
Matcher m = Pattern.compile("/video/(\\w+).html").matcher(id);
if (m.find()) key = m.group(1);
for (Element a : doc.select("script")) {
if (a.html().startsWith("var voteTag")) {
Pattern pattern = Pattern.compile("voteTag=\"([^&]+)\"");
Matcher matcher = pattern.matcher(a.html());
if (matcher.find()) voteTag = matcher.group(1);
break;
}
}
if (TextUtils.isEmpty(voteTag)) return Result.get().url(id).parse().string();
voteTag = new String(Base64.decode(voteTag, 0));
for (int i = 0; i < voteTag.length(); i++) {
int k = i % key.length();
code.append((char) (voteTag.charAt(i) ^ key.charAt(k)));
}
String playUrl = URLDecoder.decode(new String(Base64.decode(code.toString(), 0)));
return Result.get().url(playUrl).string();
}
@Override
public String searchContent(String key, boolean quick) throws Exception {
return searchContent("search/" + key);
}
@Override
public String searchContent(String key, boolean quick, String pg) throws Exception {
return searchContent("search/" + key + "/" + pg + ".html");
}
private String searchContent(String query) {
List<Vod> list = new ArrayList<>();
Document doc = Jsoup.parse(OkHttp.string(url + query));
for (Element div : doc.select("div.video-detail")) {
String id = div.select("h3.video-title > a").attr("href").replace(url, "");
String name = div.select("h3.video-title > a").text();
String pic = url + div.select("div.thumb > a > img").attr("data-src");
String remark = div.select("div.date").text();
list.add(new Vod(id, name, pic, remark));
}
return Result.string(list);
}
}

View File

@@ -0,0 +1,141 @@
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.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Json;
import com.github.catvod.utils.Util;
import org.json.JSONArray;
import org.json.JSONObject;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Douban extends Spider {
private final String siteUrl = "https://frodo.douban.com/api/v2";
private final String apikey = "?apikey=0ac44ae016490db2204ce0a042db2916";
private String extend;
private Map<String, String> getHeader() {
Map<String, String> header = new HashMap<>();
header.put("Host", "frodo.douban.com");
header.put("Connection", "Keep-Alive");
header.put("Referer", "https://servicewechat.com/wx2f9b06c1de1ccfca/84/page-frame.html");
header.put("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat");
return header;
}
@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("hot_gaia", "tv_hot", "show_hot", "movie", "tv", "rank_list_movie", "rank_list_tv");
List<String> typeNames = Arrays.asList("热门电影", "热播剧集", "热播综艺", "电影筛选", "电视筛选", "电影榜单", "电视剧榜单");
for (int i = 0; i < typeIds.size(); i++) classes.add(new Class(typeIds.get(i), typeNames.get(i)));
String recommendUrl = "http://api.douban.com/api/v2/subject_collection/subject_real_time_hotest/items" + apikey;
JSONObject jsonObject = new JSONObject(OkHttp.string(recommendUrl, getHeader()));
JSONArray items = jsonObject.optJSONArray("subject_collection_items");
return Result.string(classes, parseVodListFromJSONArray(items), filter ? Json.parse(OkHttp.string(extend)) : null);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
String sort = extend.get("sort") == null ? "T" : extend.get("sort");
String tags = URLEncoder.encode(getTags(extend));
int start = (Integer.parseInt(pg) - 1) * 20;
String cateUrl;
String itemKey = "items";
switch (tid) {
case "hot_gaia":
sort = extend.get("sort") == null ? "recommend" : extend.get("sort");
String area = extend.get("area") == null ? "全部" : extend.get("area");
sort = sort + "&area=" + URLEncoder.encode(area);
cateUrl = siteUrl + "/movie/hot_gaia" + apikey + "&sort=" + sort + "&start=" + start + "&count=20";
break;
case "tv_hot":
String type = extend.get("type") == null ? "tv_hot" : extend.get("type");
cateUrl = siteUrl + "/subject_collection/" + type + "/items" + apikey + "&start=" + start + "&count=20";
itemKey = "subject_collection_items";
break;
case "show_hot":
String showType = extend.get("type") == null ? "show_hot" : extend.get("type");
cateUrl = siteUrl + "/subject_collection/" + showType + "/items" + apikey + "&start=" + start + "&count=20";
itemKey = "subject_collection_items";
break;
case "tv":
cateUrl = siteUrl + "/tv/recommend" + apikey + "&sort=" + sort + "&tags=" + tags + "&start=" + start + "&count=20";
break;
case "rank_list_movie":
String rankMovieType = extend.get("榜单") == null ? "movie_real_time_hotest" : extend.get("榜单");
cateUrl = siteUrl + "/subject_collection/" + rankMovieType + "/items" + apikey + "&start=" + start + "&count=20";
itemKey = "subject_collection_items";
break;
case "rank_list_tv":
String rankTVType = extend.get("榜单") == null ? "tv_real_time_hotest" : extend.get("榜单");
cateUrl = siteUrl + "/subject_collection/" + rankTVType + "/items" + apikey + "&start=" + start + "&count=20";
itemKey = "subject_collection_items";
break;
default:
cateUrl = siteUrl + "/movie/recommend" + apikey + "&sort=" + sort + "&tags=" + tags + "&start=" + start + "&count=20";
break;
}
JSONObject object = new JSONObject(OkHttp.string(cateUrl, getHeader()));
JSONArray array = object.getJSONArray(itemKey);
List<Vod> list = parseVodListFromJSONArray(array);
int page = Integer.parseInt(pg), count = Integer.MAX_VALUE, limit = 20, total = Integer.MAX_VALUE;
return Result.get().vod(list).page(page, count, limit, total).string();
}
private List<Vod> parseVodListFromJSONArray(JSONArray items) throws Exception {
List<Vod> list = new ArrayList<>();
for (int i = 0; i < items.length(); i++) {
JSONObject item = items.getJSONObject(i);
String vodId = "msearch:" + item.optString("id");
String name = item.optString("title");
String pic = getPic(item);
String remark = getRating(item);
list.add(new Vod(vodId, name, pic, remark));
}
return list;
}
private String getRating(JSONObject item) {
try {
return "评分:" + item.getJSONObject("rating").optString("value");
} catch (Exception e) {
return "";
}
}
private String getPic(JSONObject item) {
try {
return item.getJSONObject("pic").optString("normal") + "@Referer=https://api.douban.com/@User-Agent=" + Util.CHROME;
} catch (Exception e) {
return "";
}
}
private String getTags(HashMap<String, String> extend) {
try {
StringBuilder tags = new StringBuilder();
for (String key : extend.keySet()) if (!key.equals("sort")) tags.append(extend.get(key)).append(",");
return Util.substring(tags.toString());
} catch (Exception e) {
return "";
}
}
}

View File

@@ -0,0 +1,150 @@
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.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 org.jsoup.select.Elements;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Qile
*/
public class Duanju extends Spider {
private static String siteUrl = "https://duanju.one";
private Map<String, String> getHeader() {
Map<String, String> header = new HashMap<>();
header.put("User-Agent", Util.CHROME);
return header;
}
@Override
public void init(Context context, String extend) throws Exception {
if (!extend.isEmpty()) siteUrl = extend;
}
@Override
public String homeContent(boolean filter) throws Exception {
List<Class> classes = new ArrayList<>();
List<String> typeIds = Arrays.asList("1", "2", "3", "26", "25", "27", "28", "32");
List<String> typeNames = Arrays.asList("抖剧", "快剧", "都市", "穿越", "逆袭", "虐恋", "重生", "其他");
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("div.module-items").eq(0).select(".module-item")) {
String vid = siteUrl + li.select(".module-item-pic a").attr("href");
String name = li.select(".module-item-pic a").attr("title");
String pic = li.select(".module-item-pic img").attr("data-src");
String remark = li.select(".module-item-text").text();
list.add(new Vod(vid, name, pic, remark));
}
return Result.string(classes, list);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
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 cateUrl = siteUrl + String.format("/vodshow/%s--------%s---.html", cateId, pg);
Document doc = Jsoup.parse(OkHttp.string(cateUrl, getHeader()));
List<Vod> list = new ArrayList<>();
for (Element li : doc.select(".module-items .module-item")) {
String vid = siteUrl + li.select(".module-item-pic a").attr("href");
String name = li.select(".module-item-pic a").attr("title");
String pic = li.select(".module-item-pic img").attr("data-src");
String remark = li.select(".module-item-text").text();
list.add(new Vod(vid, name, pic, remark));
}
return Result.string(list);
}
@Override
public String detailContent(List<String> ids) throws Exception {
Document doc = Jsoup.parse(OkHttp.string(ids.get(0), getHeader()));
Elements circuits = doc.select(".module-tab-item.tab-item");
Elements sources = doc.select("[class=scroll-content]");
StringBuilder vod_play_url = new StringBuilder();
StringBuilder vod_play_from = new StringBuilder();
for (int i = 0; i < sources.size(); i++) {
String spanText = circuits.get(i).select("span").text();
String smallText = circuits.get(i).select("small").text();
String playFromText = spanText + "(共" + smallText + "集)";
vod_play_from.append(playFromText).append("$$$");
Elements aElementArray = sources.get(i).select("a");
for (int j = 0; j < aElementArray.size(); j++) {
Element a = aElementArray.get(j);
String href = siteUrl + a.attr("href");
String text = a.text();
vod_play_url.append(text).append("$").append(href);
boolean notLastEpisode = j < aElementArray.size() - 1;
vod_play_url.append(notLastEpisode ? "#" : "$$$");
}
}
String title = doc.select("h1.page-title").text();
String classifyName = doc.select("div.tag-link a").text();
String year = doc.select("a.tag-link").eq(1).text();
String area = doc.select("a.tag-link").eq(2).text();
String remark = doc.select("div.title-info span").text();
String director = "Qile";
String actor = "FongMi";
String brief = "该剧由蜂蜜用爱发电制作,欢迎观看!";
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodYear(year);
vod.setVodName(title);
vod.setVodArea(area);
vod.setVodActor(actor);
vod.setVodRemarks(remark);
vod.setVodContent(brief);
vod.setVodDirector(director);
vod.setTypeName(classifyName);
vod.setVodPlayFrom(vod_play_from.toString());
vod.setVodPlayUrl(vod_play_url.toString());
return Result.string(vod);
}
@Override
public String searchContent(String key, boolean quick) throws Exception {
String searchUrl = siteUrl + "/vodsearch/" + URLEncoder.encode(key) + "-------------.html";
Document doc = Jsoup.parse(OkHttp.string(searchUrl, getHeader()));
List<Vod> list = new ArrayList<>();
for (Element li : doc.select(".module-search-item")) {
String vid = siteUrl + li.select(".module-item-pic a").attr("href");
String name = li.select(".module-item-pic img").attr("alt");
String pic = li.select(".module-item-pic img").attr("data-src");
String remark = li.select(".video-info-header a.video-serial").text();
list.add(new Vod(vid, name, pic, remark));
}
return Result.string(list);
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
String content = OkHttp.string(id, getHeader());
Matcher matcher = Pattern.compile("player_aaaa=(.*?)</script>").matcher(content);
String json = matcher.find() ? matcher.group(1) : "";
JSONObject player = new JSONObject(json);
String realUrl = player.getString("url");
return Result.get().url(realUrl).header(getHeader()).string();
}
}

View File

@@ -0,0 +1,112 @@
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.crawler.Spider;
import com.github.catvod.net.OkHttp;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class Eighteen extends Spider {
private final String url = "https://mjv002.com/zh/";
@Override
public void init(Context context, String extend) throws Exception {
OkHttp.newCall("https://mjv002.com/zh/chinese_IamOverEighteenYearsOld/19/index.html").close();
}
@Override
public String homeContent(boolean filter) throws Exception {
List<Class> classes = new ArrayList<>();
List<Vod> list = new ArrayList<>();
Document doc = Jsoup.parse(OkHttp.string(url));
for (Element a : doc.select("ul.animenu__nav > li > a")) {
String typeName = a.text();
String typeId = a.attr("href").replace(url, "");
if (!typeId.contains("random/all/")) continue;
if (typeName.contains("18H")) break;
classes.add(new Class(typeId, typeName));
}
for (Element div : doc.select("div.post")) {
String id = div.select("a").attr("href").replace(url, "");
String name = div.select("h3").text();
String pic = div.select("a > img").attr("src");
String remark = div.select("div.meta").text();
list.add(new Vod(id, name, pic, remark));
}
return Result.string(classes, list);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
List<Vod> list = new ArrayList<>();
tid = tid.replace("random", "list");
tid = tid.replace("index", pg);
Document doc = Jsoup.parse(OkHttp.string(url + tid));
for (Element div : doc.select("div.post")) {
String id = div.select("a").attr("href").replace(url, "");
String name = div.select("h3").text();
String pic = div.select("a > img").attr("src");
String remark = div.select("div.meta").text();
list.add(new Vod(id, name, pic, remark));
}
return Result.string(list);
}
@Override
public String detailContent(List<String> ids) throws Exception {
Document doc = Jsoup.parse(OkHttp.string(url + ids.get(0)));
Element wrap = doc.select("div.video-wrap").get(0);
String name = wrap.select("div.archive-title > h1").text();
String pic = wrap.select("div.player-wrap > img").attr("src");
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodPic(pic);
vod.setVodName(name);
vod.setVodPlayFrom("18AV");
vod.setVodPlayUrl("播放$" + ids.get(0));
return Result.string(vod);
}
@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);
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
return Result.get().parse().url(url + id).string();
}
private String searchContent(String key, String pg) {
HashMap<String, String> params = new HashMap<>();
params.put("search_keyword", key);
params.put("search_type", "fc");
params.put("op", "search");
String res = OkHttp.post(url + "searchform_search/all/" + pg + ".html", params);
List<Vod> list = new ArrayList<>();
for (Element div : Jsoup.parse(res).select("div.post")) {
String id = div.select("a").attr("href").replace(url, "");
String name = div.select("h3").text();
String pic = div.select("a > img").attr("src");
String remark = div.select("div.meta").text();
list.add(new Vod(id, name, pic, remark));
}
return Result.string(list);
}
}

View File

@@ -0,0 +1,106 @@
package com.github.catvod.spider;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Util;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Qile
*/
public class FirstAid extends Spider {
private final String siteUrl = "https://m.youlai.cn";
private Map<String, String> getHeader() {
Map<String, String> header = new HashMap<>();
header.put("User-Agent", Util.CHROME);
return header;
}
@Override
public String homeContent(boolean filter) throws Exception {
List<Class> classes = new ArrayList<>();
List<String> typeIds = Arrays.asList("jijiu|0", "jijiu|1", "jijiu|2", "jijiu|3", "jijiu|4", "jijiu|5", "jijiu|6", "jijiu|7");
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, Collections.emptyList());
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
String[] item = tid.split("\\|");
String id = item[0];
String digit = item[1];
int digitValue = Integer.parseInt(digit);
String cateId = extend.get("cateId") == null ? id : extend.get("cateId");
Document doc = Jsoup.parse(OkHttp.string(siteUrl + String.format("/%s", cateId), getHeader()));
String pic = "https:" + doc.select(".block100").eq(digitValue).attr("src");
Elements lis = doc.select(".jj-title-li").eq(digitValue).select(".list-br3");
List<Vod> list = new ArrayList<>();
for (Element li : lis) {
String vid = siteUrl + li.select("a").attr("href");
String name = li.select("a").text();
list.add(new Vod(vid, name, pic));
}
return Result.get().page(1, 1, 0, lis.size()).vod(list).string();
}
@Override
public String detailContent(List<String> ids) throws Exception {
Document doc = Jsoup.parse(OkHttp.string(ids.get(0), getHeader()));
String title = doc.select(".video-title.h1-title").text();
String pic = doc.select(".video-cover.list-flex-in img").attr("src");
String actor = doc.select("span.doc-name").text();
String area = "中国";
String brief = doc.select(".img-text-con").text();
String play_url = doc.select("#video source").attr("src");
if (play_url.isEmpty()) play_url = doc.select("#video").attr("src");
String vod_play_url = title + "$" + play_url;
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodPic(pic);
vod.setVodName(title);
vod.setVodActor(actor);
vod.setVodArea(area);
vod.setVodContent(brief);
vod.setVodPlayFrom("Qile");
vod.setVodPlayUrl(vod_play_url);
return Result.string(vod);
}
@Override
public String searchContent(String key, boolean quick) throws Exception {
String searchUrl = siteUrl + "/cse/search?q=" + URLEncoder.encode(key);
Elements lis = Jsoup.parse(OkHttp.string(searchUrl, getHeader())).select(".search-video-li.list-br2");
List<Vod> list = new ArrayList<>();
for (Element li : lis) {
String vid = siteUrl + li.select("a").attr("href");
String name = li.select("h5.line-clamp1").text();
String pic = li.select("dt.logo-bg img").attr("src");
if (!pic.startsWith("https")) pic = "https:" + pic;
list.add(new Vod(vid, 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(getHeader()).string();
}
}

View File

@@ -0,0 +1,138 @@
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();
}
}

View File

@@ -0,0 +1,90 @@
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.Handler;
import android.os.Looper;
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;
public class Init {
private final ExecutorService executor;
private final Handler handler;
private Application app;
private static class Loader {
static volatile Init INSTANCE = new Init();
}
public static Init get() {
return Loader.INSTANCE;
}
public Init() {
this.handler = new Handler(Looper.getMainLooper());
this.executor = Executors.newFixedThreadPool(5);
}
public static Application context() {
return get().app;
}
public static void init(Context context) {
get().app = ((Application) context);
SpiderDebug.log("自定義爬蟲代碼載入成功!");
}
public static void execute(Runnable runnable) {
get().executor.execute(runnable);
}
public static void run(Runnable runnable) {
get().handler.post(runnable);
}
public static void run(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;
}
}
return null;
}
}

View File

@@ -0,0 +1,100 @@
package com.github.catvod.spider;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Util;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
public class J91 extends Spider {
private static final String siteUrl = "https://pta.9a07g.com";
private static final String cateUrl = siteUrl + "/video/category/";
private static final String detailUrl = siteUrl + "/video/view/";
private static final String searchUrl = siteUrl + "/search?keywords=";
private HashMap<String, String> getHeaders() {
HashMap<String, String> headers = new HashMap<>();
headers.put("User-Agent", Util.CHROME);
return headers;
}
private List<Vod> parseVods(Document doc) {
List<Vod> list = new ArrayList<>();
for (Element element : doc.select("div.video-elem")) {
String pic = element.select("div.img").attr("style");
String url = element.select("a").attr("href");
String name = element.select("a.title").text();
if (pic.endsWith(".gif") || name.isEmpty()) continue;
if (!url.startsWith("http")) {
pic = pic.replace("background-image: url('", "").replace("')", "");
if (!pic.startsWith("http")) pic = "https:" + pic;
String id = url.split("/")[3];
list.add(new Vod(id, name, pic));
}
}
return list;
}
@Override
public String homeContent(boolean filter) throws Exception {
List<Class> classes = new ArrayList<>();
String[] typeIdList = {"latest","hd","recent-favorite","hot-list","recent-rating","nonpaid","ori","long-list","longer-list","month-discuss","top-favorite","most-favorite","top-list","top-last"};
String[] typeNameList = {"最近更新","高清视频","最近加精","当前最热","最近得分","非付费","91原创","10分钟以上","20分钟以上","本月讨论","本月收藏","收藏最多","本月最热","上月最热"};
for (int i = 0; i < typeNameList.length; i++) {
classes.add(new Class(typeIdList[i], typeNameList[i]));
}
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeaders()));
List<Vod> list = parseVods(doc);
return Result.string(classes, list);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
String target = cateUrl + tid + "/" + pg;
Document doc = Jsoup.parse(OkHttp.string(target, getHeaders()));
List<Vod> list = parseVods(doc);
Integer total = (Integer.parseInt(pg)+1) * 20;
return Result.string(Integer.parseInt(pg),Integer.parseInt(pg)+1,20,total,list);
}
@Override
public String detailContent(List<String> ids) throws Exception {
Document doc = Jsoup.parse(OkHttp.string(detailUrl.concat(ids.get(0)), getHeaders()));
String name = doc.select("meta[property=og:title]").attr("content");
String pic = doc.select("meta[property=og:image]").attr("content");
String year = doc.select("meta[property=video:release_date]").attr("content");
String playUrl = doc.select("#video-play").attr("data-src");
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodPic(pic);
vod.setVodYear(year);
vod.setVodName(name);
vod.setVodPlayFrom("J91");
vod.setVodPlayUrl("播放$" + playUrl);
return Result.string(vod);
}
@Override
public String searchContent(String key, boolean quick) throws Exception {
Document doc = Jsoup.parse(OkHttp.string(searchUrl.concat(URLEncoder.encode(key)), getHeaders()));
List<Vod> list = parseVods(doc);
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();
}
}

View File

@@ -0,0 +1,54 @@
package com.github.catvod.spider;
import android.content.Context;
import com.github.catvod.crawler.Spider;
import com.whl.quickjs.android.QuickJSLoader;
import com.whl.quickjs.wrapper.QuickJSContext;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class JSDemo extends Spider {
private ExecutorService executor;
private QuickJSContext ctx;
private void submit(Runnable runnable) {
executor.submit(runnable);
}
private <T> Future<T> submit(Callable<T> callable) {
return executor.submit(callable);
}
private void initJS() {
if (ctx != null) return;
ctx = QuickJSContext.create();
QuickJSLoader.initConsoleLog(ctx);
}
@Override
public void init(Context context, String extend) {
this.executor = Executors.newSingleThreadExecutor();
submit(this::initJS);
}
@Override
public String homeContent(boolean filter) throws Exception {
return submit(() -> {
ctx.evaluate("var text = 'homeContent';");
return ctx.getGlobalObject().getString("text");
}).get();
}
@Override
public void destroy() {
submit(() -> {
executor.shutdownNow();
ctx.destroy();
});
}
}

View File

@@ -0,0 +1,105 @@
package com.github.catvod.spider;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Util;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
public class Jable extends Spider {
private static final String siteUrl = "https://jable.tv";
private static final String cateUrl = siteUrl + "/categories/";
private static final String detailUrl = siteUrl + "/videos/";
private static final String searchUrl = siteUrl + "/search/";
private HashMap<String, String> getHeaders() {
HashMap<String, String> headers = new HashMap<>();
headers.put("User-Agent", Util.CHROME);
return headers;
}
@Override
public String homeContent(boolean filter) throws Exception {
List<Vod> list = new ArrayList<>();
List<Class> classes = new ArrayList<>();
Document doc = Jsoup.parse(OkHttp.string(cateUrl, getHeaders()));
for (Element element : doc.select("div.img-box")) {
String typeId = element.select("a").attr("href").split("/")[4];
String typeName = element.select("div.absolute-center > h4").text();
classes.add(new Class(typeId, typeName));
}
doc = Jsoup.parse(OkHttp.string(siteUrl, getHeaders()));
for (Element element : doc.select("div.video-img-box")) {
String pic = element.select("img").attr("data-src");
String url = element.select("a").attr("href");
String name = element.select("div.detail > h6").text();
if (pic.endsWith(".gif") || name.isEmpty()) continue;
String id = url.split("/")[4];
list.add(new Vod(id, name, pic));
}
return Result.string(classes, list);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
List<Vod> list = new ArrayList<>();
String target = cateUrl + tid + "/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=post_date&from=" + String.format(Locale.getDefault(), "%02d", Integer.parseInt(pg)) + "&_=" + System.currentTimeMillis();
Document doc = Jsoup.parse(OkHttp.string(target, getHeaders()));
for (Element element : doc.select("div.video-img-box")) {
String pic = element.select("img").attr("data-src");
String url = element.select("a").attr("href");
String name = element.select("div.detail > h6").text();
String id = url.split("/")[4];
list.add(new Vod(id, name, pic));
}
Integer total = (Integer.parseInt(pg)+1)*20;
return Result.string(Integer.parseInt(pg),Integer.parseInt(pg)+1,20,total,list);
}
@Override
public String detailContent(List<String> ids) throws Exception {
Document doc = Jsoup.parse(OkHttp.string(detailUrl.concat(ids.get(0)).concat("/"), getHeaders()));
String name = doc.select("meta[property=og:title]").attr("content");
String pic = doc.select("meta[property=og:image]").attr("content");
String year = doc.select("span.inactive-color").get(0).text();
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodPic(pic);
vod.setVodYear(year.replace("上市於 ", ""));
vod.setVodName(name);
vod.setVodPlayFrom("Jable");
vod.setVodPlayUrl("播放$" + Util.getVar(doc.html(), "hlsUrl"));
return Result.string(vod);
}
@Override
public String searchContent(String key, boolean quick) throws Exception {
List<Vod> list = new ArrayList<>();
Document doc = Jsoup.parse(OkHttp.string(searchUrl.concat(URLEncoder.encode(key)).concat("/"), getHeaders()));
for (Element element : doc.select("div.video-img-box")) {
String pic = element.select("img").attr("data-src");
String url = element.select("a").attr("href");
String name = element.select("div.detail > h6").text();
String id = url.split("/")[4];
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();
}
}

View File

@@ -0,0 +1,133 @@
package com.github.catvod.spider;
import android.content.Context;
import android.net.Uri;
import android.text.TextUtils;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Util;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Qile
*/
public class JavDb extends Spider {
private static String siteUrl = "https://javdb523.com";
@Override
public void init(Context context, String extend) throws Exception {
if (!extend.isEmpty()) siteUrl = extend;
}
private Map<String, String> getHeader() {
Map<String, String> header = new HashMap<>();
header.put("User-Agent", Util.CHROME);
header.put("Referer", siteUrl + "/");
return header;
}
@Override
public String homeContent(boolean filter) throws Exception {
List<Class> classes = new ArrayList<>();
List<String> typeIds = Arrays.asList("", "censored", "uncensored", "western");
List<String> typeNames = Arrays.asList("全部", "有码", "无码", "欧美");
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(".item")) {
String vid = siteUrl + li.select("a").attr("href");
String name = li.select("a").attr("title");
String pic = li.select("img").attr("src");
list.add(new Vod(vid, name, pic));
}
return Result.string(classes, list);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
String cateUrl = siteUrl + String.format("/%s?page=%s", tid, pg);
Document doc = Jsoup.parse(OkHttp.string(cateUrl, getHeader()));
List<Vod> list = new ArrayList<>();
for (Element li : doc.select(".item")) {
String vid = siteUrl + li.select("a").attr("href");
String name = li.select("a").attr("title");
String pic = li.select("img").attr("src");
list.add(new Vod(vid, name, pic));
}
return Result.string(list);
}
@Override
public String detailContent(List<String> ids) throws Exception {
Document doc = Jsoup.parse(OkHttp.string(ids.get(0), getHeader()));
if (doc.text().contains("歡迎登入")) return Result.error("该资源需要登入");
List<String> vodItems = new ArrayList<>();
Elements sourceList = doc.select(".item.columns");
for (Element a : sourceList) {
String episodeUrl = a.select("div a").attr("href");
String episodeName = a.select("div a").text();
vodItems.add(episodeName + "$" + episodeUrl);
}
Elements elements = doc.select(".panel-block");
String classifyName = "";
String year = "";
String area = "";
String remark = "";
for (Element element : elements) {
String text = element.text();
if (text.startsWith("類別:")) {
classifyName = element.select("span a").text();
} else if (text.startsWith("片商:")) {
area = element.select("span a").text();
} else if (text.startsWith("日期:")) {
year = element.select("span").text();
} else if (text.startsWith("時長:")) {
remark = element.select("span").text();
}
}
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodYear(year);
vod.setVodArea(area);
vod.setVodRemarks(remark);
vod.setTypeName(classifyName);
vod.setVodContent(ids.get(0));
vod.setVodPlayFrom("Qile");
vod.setVodPlayUrl(TextUtils.join("#", vodItems));
return Result.string(vod);
}
@Override
public String searchContent(String key, boolean quick) throws Exception {
String searchUrl = siteUrl + "/search?q=" + Uri.encode(key) + "&f=all";
Document doc = Jsoup.parse(OkHttp.string(searchUrl, getHeader()));
List<Vod> list = new ArrayList<>();
for (Element li : doc.select(".item")) {
String vid = siteUrl + li.select("a").attr("href");
String name = li.select("a").attr("title");
String pic = li.select("img").attr("src");
list.add(new Vod(vid, 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(getHeader()).string();
}
}

View File

@@ -0,0 +1,114 @@
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);
}
}

View File

@@ -0,0 +1,170 @@
package com.github.catvod.spider;
import android.content.Context;
import android.text.TextUtils;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Util;
import org.json.JSONArray;
import org.json.JSONObject;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* @author Qile
*/
public class JustLive extends Spider {
private String siteUrl = "http://live.yj1211.work";
private Map<String, String> getHeader() {
Map<String, String> header = new HashMap<>();
header.put("User-Agent", Util.CHROME);
return header;
}
@Override
public void init(Context context, String extend) throws Exception {
if (!extend.isEmpty()) siteUrl = extend;
}
@Override
public String homeContent(boolean filter) throws Exception {
List<Class> classes = new ArrayList<>();
List<String> typeIds = Arrays.asList("网游", "手游", "单机", "娱乐", "其他");
List<String> typeNames = Arrays.asList("网游", "手游", "单机", "娱乐", "其他");
for (int i = 0; i < typeIds.size(); i++) classes.add(new Class(typeIds.get(i), typeNames.get(i)));
String f = "{\"网游\": [{\"key\": \"class\", \"name\": \"类型\", \"value\": [{\"n\": \"英雄联盟\", \"v\": \"英雄联盟\"}, {\"n\": \"无畏契约\", \"v\": \"无畏契约\"}, {\"n\": \"CS:GO\", \"v\": \"CS:GO\"}, {\"n\": \"APEX英雄\", \"v\": \"APEX英雄\"}, {\"n\": \"永劫无间\", \"v\": \"永劫无间\"}, {\"n\": \"穿越火线\", \"v\": \"穿越火线\"}, {\"n\": \"命运方舟\", \"v\": \"命运方舟\"}, {\"n\": \"DOTA2\", \"v\": \"DOTA2\"}, {\"n\": \"吃鸡行动\", \"v\": \"吃鸡行动\"}, {\"n\": \"逃离塔科夫\", \"v\": \"逃离塔科夫\"}, {\"n\": \"传奇\", \"v\": \"传奇\"}, {\"n\": \"DNF\", \"v\": \"DNF\"}, {\"n\": \"卡拉彼丘\", \"v\": \"卡拉彼丘\"}, {\"n\": \"幕后高手\", \"v\": \"幕后高手\"}, {\"n\": \"生死狙击2\", \"v\": \"生死狙击2\"}, {\"n\": \"洛奇英雄传\", \"v\": \"洛奇英雄传\"}, {\"n\": \"最终幻想14\", \"v\": \"最终幻想14\"}, {\"n\": \"重生边缘\", \"v\": \"重生边缘\"}, {\"n\": \"星际战甲\", \"v\": \"星际战甲\"}, {\"n\": \"梦三国\", \"v\": \"梦三国\"}, {\"n\": \"英魂之刃\", \"v\": \"英魂之刃\"}, {\"n\": \"剑网3\", \"v\": \"剑网3\"}]}], \"手游\": [{\"key\": \"class\", \"name\": \"类型\", \"value\": [{\"n\": \"王者荣耀\", \"v\": \"王者荣耀\"}, {\"n\": \"和平精英\", \"v\": \"和平精英\"}, {\"n\": \"原神\", \"v\": \"原神\"}, {\"n\": \"崩坏:星穹铁道\", \"v\": \"崩坏:星穹铁道\"}, {\"n\": \"第五人格\", \"v\": \"第五人格\"}, {\"n\": \"LOL手游\", \"v\": \"LOL手游\"}, {\"n\": \"明日方舟\", \"v\": \"明日方舟\"}, {\"n\": \"黎明觉醒:生机\", \"v\": \"黎明觉醒:生机\"}, {\"n\": \"蛋仔派对\", \"v\": \"蛋仔派对\"}, {\"n\": \"冒险岛手游\", \"v\": \"冒险岛手游\"}, {\"n\": \"闪耀!优俊少女\", \"v\": \"闪耀!优俊少女\"}, {\"n\": \"斯露德\", \"v\": \"斯露德\"}, {\"n\": \"千年之旅\", \"v\": \"千年之旅\"}, {\"n\": \"白夜极光\", \"v\": \"白夜极光\"}, {\"n\": \"逆水寒手游\", \"v\": \"逆水寒手游\"}, {\"n\": \"率土之滨\", \"v\": \"率土之滨\"}, {\"n\": \"月圆之夜\", \"v\": \"月圆之夜\"}]}],\"单机\": [{\"key\": \"class\", \"name\": \"类型\", \"value\": [{\"n\": \"主机游戏\", \"v\": \"主机游戏\"}, {\"n\": \"我的世界\", \"v\": \"我的世界\"}, {\"n\": \"独立游戏\", \"v\": \"独立游戏\"}, {\"n\": \"怀旧游戏\", \"v\": \"怀旧游戏\"}, {\"n\": \"猛兽派对\", \"v\": \"猛兽派对\"}, {\"n\": \"星空\", \"v\": \"星空\"}, {\"n\": \"塞尔达传说\", \"v\": \"塞尔达传说\"}, {\"n\": \"苍翼:混沌效应\", \"v\": \"苍翼:混沌效应\"}, {\"n\": \"命运2\", \"v\": \"命运2\"}, {\"n\": \"收获日3\", \"v\": \"收获日3\"}, {\"n\": \"机战佣兵VI 境界天火\", \"v\": \"机战佣兵VI 境界天火\"}, {\"n\": \"暗黑破坏神Ⅳ\", \"v\": \"暗黑破坏神Ⅳ\"}, {\"n\": \"匹诺曹的谎言\", \"v\": \"匹诺曹的谎言\"}, {\"n\": \"博德之门3\", \"v\": \"博德之门3\"}, {\"n\": \"绝世好武功\", \"v\": \"绝世好武功\"}, {\"n\": \"恐怖游戏\", \"v\": \"恐怖游戏\"}, {\"n\": \"Dark and Darker\", \"v\": \"Dark and Darker\"}, {\"n\": \"Warlander\", \"v\": \"Warlander\"}, {\"n\": \"FORZA 极限竞速\", \"v\": \"FORZA 极限竞速\"}, {\"n\": \"边境\", \"v\": \"边境\"}, {\"n\": \"生化危机\", \"v\": \"生化危机\"}]}], \"娱乐\": [{\"key\": \"class\", \"name\": \"类型\", \"value\": [{\"n\": \"聊天室\", \"v\": \"聊天室\"}, {\"n\": \"视频唱见\", \"v\": \"视频唱见\"}, {\"n\": \"萌宅领域\", \"v\": \"萌宅领域\"}, {\"n\": \"视频聊天\", \"v\": \"视频聊天\"}, {\"n\": \"舞见\", \"v\": \"舞见\"}, {\"n\": \"唱见电台\", \"v\": \"唱见电台\"}, {\"n\": \"聊天电台\", \"v\": \"聊天电台\"}, {\"n\": \"甜宠电台\", \"v\": \"甜宠电台\"}, {\"n\": \"TopStar\", \"v\": \"TopStar\"}, {\"n\": \"虚拟Singer\", \"v\": \"虚拟Singer\"}, {\"n\": \"虚拟Gamer\", \"v\": \"虚拟Gamer\"}, {\"n\": \"虚拟声优\", \"v\": \"虚拟声优\"}, {\"n\": \"虚拟日常\", \"v\": \"虚拟日常\"}, {\"n\": \"星秀\", \"v\": \"星秀\"}]}], \"其他\": [{\"key\": \"class\", \"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\": \"科技\"}]}]}";
JSONObject filterConfig = new JSONObject(f);
String content = OkHttp.string(siteUrl + "/api/live/getRecommend?page=1&size=20", getHeader());
List<Vod> list = new ArrayList<>();
JSONArray dataArray = new JSONObject(content).getJSONArray("data");
for (int i = 0; i < dataArray.length(); i++) {
JSONObject jsonObject = dataArray.getJSONObject(i);
String platform = jsonObject.getString("platForm");
String roomId = jsonObject.getString("roomId");
String categoryName = jsonObject.getString("categoryName");
String roomName = jsonObject.getString("roomName");
String name = categoryName + roomName;
String pic = jsonObject.getString("roomPic");
String remark = jsonObject.getString("ownerName");
String vid = "platform=" + platform + "&roomId=" + roomId;
list.add(new Vod(vid, name, pic, remark));
}
return Result.string(classes, list, filterConfig);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
Map<String, String> ClassTypeMap = new HashMap<>();
ClassTypeMap.put("网游", "英雄联盟");
ClassTypeMap.put("手游", "王者荣耀");
ClassTypeMap.put("单机", "主机游戏");
ClassTypeMap.put("娱乐", "聊天室");
ClassTypeMap.put("其他", "生活分享");
String cateId = extend.get("cateId") == null ? tid : extend.get("cateId");
String classType = extend.get("class") == null ? ClassTypeMap.get(cateId) : extend.get("class");
String cateUrl = siteUrl + String.format("/api/live/getRecommendByAreaAll?areaType=%s&area=%s&page=%s", cateId, classType, pg);
String content = OkHttp.string(cateUrl, getHeader());
List<Vod> list = new ArrayList<>();
JSONArray dataArray = new JSONObject(content).getJSONArray("data");
for (int i = 0; i < dataArray.length(); i++) {
JSONObject jsonObject = dataArray.getJSONObject(i);
String platform = jsonObject.getString("platForm");
String roomId = jsonObject.getString("roomId");
String categoryName = jsonObject.getString("categoryName");
String name = jsonObject.getString("roomName");
String pic = jsonObject.getString("roomPic");
String remark = jsonObject.getString("ownerName");
remark = remark + "-" + categoryName;
String vid = "platform=" + platform + "&roomId=" + roomId;
list.add(new Vod(vid, name, pic, remark));
}
return Result.string(list);
}
@Override
public String detailContent(List<String> ids) throws Exception {
String getRoomInfo = siteUrl + "/api/live/getRoomInfo?" + ids.get(0);
String getRealUrl = siteUrl + "/api/live/getRealUrlMultiSource?" + ids.get(0);
String content = OkHttp.string(getRealUrl, getHeader());
String content1 = OkHttp.string(getRoomInfo, getHeader());
JSONObject dataObject = new JSONObject(content).getJSONObject("data");
List<String> lineNames = new ArrayList<>();
List<String> vodItems = new ArrayList<>();
Iterator<String> keys = dataObject.keys();
while (keys.hasNext()) {
String key = keys.next();
if (key.startsWith("线路")) lineNames.add(key);
}
Collections.sort(lineNames, (line1, line2) -> {
int num1 = Integer.parseInt(line1.substring(2));
int num2 = Integer.parseInt(line2.substring(2));
return Integer.compare(num1, num2);
});
for (String lineName : lineNames) {
JSONArray lineArray = dataObject.getJSONArray(lineName);
List<String> episodeItems = new ArrayList<>();
for (int i = 0; i < lineArray.length(); i++) {
JSONObject item = lineArray.getJSONObject(i);
String qualityName = item.getString("qualityName");
String playUrl = item.getString("playUrl");
episodeItems.add(qualityName + "$" + playUrl);
}
vodItems.add(TextUtils.join("#", episodeItems));
}
String vod_play_from = TextUtils.join("$$$", lineNames);
String vod_play_urls = TextUtils.join("$$$", vodItems);
JSONObject data = new JSONObject(content1).getJSONObject("data");
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodPic(data.getString("roomPic"));
vod.setVodName(data.getString("roomName"));
vod.setVodArea(data.getString("platForm").replace("douyu", "斗鱼").replace("huya", "虎牙").replace("bilibili", "哔哩哔哩").replace("douyin", "抖音").replace("cc", "网易CC"));
vod.setVodActor(data.getString("ownerName"));
vod.setVodRemarks("在线" + data.getInt("online") + "");
vod.setVodContent(getRealUrl);
vod.setVodDirector("Qile");
vod.setTypeName(data.getString("categoryName"));
vod.setVodPlayFrom(vod_play_from);
vod.setVodPlayUrl(vod_play_urls);
return Result.string(vod);
}
@Override
public String searchContent(String key, boolean quick) throws Exception {
String searchUrl = siteUrl + "/api/live/search?platform=all&keyWords=" + URLEncoder.encode(key) + "&uid=35717d71548f4ec9ab6f327cc16ad2bf";
String content = OkHttp.string(searchUrl, getHeader());
List<Vod> list = new ArrayList<>();
JSONArray dataArray = new JSONObject(content).getJSONArray("data");
for (int i = 0; i < dataArray.length(); i++) {
JSONObject jsonObject = dataArray.getJSONObject(i);
String platform = jsonObject.optString("platform");
String roomId = jsonObject.optString("roomId");
String name = jsonObject.optString("nickName");
String pic = jsonObject.optString("headPic");
String remark = jsonObject.optString("isLive");
remark = remark.equals("1") ? "直播中" : "未开播";
String vid = "platform=" + platform + "&roomId=" + roomId;
list.add(new Vod(vid, name, pic, remark));
}
return Result.string(list);
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
return Result.get().url(id).header(getHeader()).string();
}
}

View File

@@ -0,0 +1,102 @@
package com.github.catvod.spider;
import android.content.Context;
import android.text.TextUtils;
import android.util.Base64;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Util;
import org.json.JSONArray;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Qile
*/
public class Kanqiu extends Spider {
private static String siteUrl = "http://www.88kanqiu.one";
private Map<String, String> getHeader() {
Map<String, String> header = new HashMap<>();
header.put("User-Agent", Util.CHROME);
return header;
}
@Override
public void init(Context context, String extend) throws Exception {
if (!extend.isEmpty()) siteUrl = extend;
}
@Override
public String homeContent(boolean filter) throws Exception {
List<Class> classes = new ArrayList<>();
List<String> typeIds = Arrays.asList("", "1", "8", "21");
List<String> typeNames = Arrays.asList("全部直播", "篮球直播", "足球直播", "其他直播");
for (int i = 0; i < typeIds.size(); i++) classes.add(new Class(typeIds.get(i), typeNames.get(i)));
String f = "{\"1\": [{\"key\": \"cateId\", \"name\": \"类型\", \"value\": [{\"n\": \"NBA\", \"v\": \"1\"}, {\"n\": \"CBA\", \"v\": \"2\"}, {\"n\": \"篮球综合\", \"v\": \"4\"}, {\"n\": \"纬来体育\", \"v\": \"21\"}]}],\"8\": [{\"key\": \"cateId\", \"name\": \"类型\", \"value\": [{\"n\": \"英超\", \"v\": \"8\"}, {\"n\": \"西甲\", \"v\": \"9\"}, {\"n\": \"意甲\", \"v\": \"10\"}, {\"n\": \"欧冠\", \"v\": \"12\"}, {\"n\": \"欧联\", \"v\": \"13\"}, {\"n\": \"德甲\", \"v\": \"14\"}, {\"n\": \"法甲\", \"v\": \"15\"}, {\"n\": \"欧国联\", \"v\": \"16\"}, {\"n\": \"足总杯\", \"v\": \"27\"}, {\"n\": \"国王杯\", \"v\": \"33\"}, {\"n\": \"中超\", \"v\": \"7\"}, {\"n\": \"亚冠\", \"v\": \"11\"}, {\"n\": \"足球综合\", \"v\": \"23\"}, {\"n\": \"欧协联\", \"v\": \"28\"}, {\"n\": \"美职联\", \"v\": \"26\"}]}], \"29\": [{\"key\": \"cateId\", \"name\": \"类型\", \"value\": [{\"n\": \"网球\", \"v\": \"29\"}, {\"n\": \"斯洛克\", \"v\": \"30\"}, {\"n\": \"MLB\", \"v\": \"38\"}, {\"n\": \"UFC\", \"v\": \"32\"}, {\"n\": \"NFL\", \"v\": \"25\"}, {\"n\": \"CCTV5\", \"v\": \"18\"}]}]}";
JSONObject filterConfig = new JSONObject(f);
return Result.string(classes, filterConfig);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
String cateId = extend.get("cateId") == null ? tid : extend.get("cateId");
String urlPath = cateId == null || cateId.isEmpty() ? "" : String.format("/match/%s/live", cateId);
Elements lis = Jsoup.parse(OkHttp.string(siteUrl + urlPath, getHeader())).select(".list-group-item");
List<Vod> list = new ArrayList<>();
for (Element li : lis) {
String vid = siteUrl + li.select(".btn.btn-primary").attr("href");
String name = li.select(".row.d-none").text();
if (name.isEmpty()) name = li.text();
String pic = li.select(".col-xs-1").eq(0).select("img").attr("src");
if (pic.isEmpty()) pic = "https://pic.imgdb.cn/item/657673d6c458853aeff94ab9.jpg";
if (!pic.startsWith("http")) pic = siteUrl + pic;
String remark = li.select(".btn.btn-primary").text();
list.add(new Vod(vid, name, pic, remark));
}
return Result.get().page(1, 1, 0, lis.size()).vod(list).string();
}
@Override
public String detailContent(List<String> ids) throws Exception {
if (ids.get(0).equals(siteUrl)) return Result.error("比賽尚未開始");
Document doc = Jsoup.parse(OkHttp.string(ids.get(0), getHeader()));
String t = doc.select("#t").attr("value");
String result = t.substring(6);
result = result.substring(0, result.length() - 2);
String json = new String(Base64.decode(result, Base64.DEFAULT));
JSONArray linksArray = new JSONObject(json).getJSONArray("links");
List<String> vodItems = new ArrayList<>();
for (int i = 0; i < linksArray.length(); i++) {
JSONObject linkObject = linksArray.getJSONObject(i);
String text = linkObject.optString("name");
String href = linkObject.optString("url").replace("#", "***");
vodItems.add(text + "$" + href);
}
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodPlayFrom("Qile");
vod.setVodPlayUrl(TextUtils.join("#", vodItems));
return Result.string(vod);
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
return Result.get().url(id.replace("***", "#")).parse().header(getHeader()).string();
}
}

View File

@@ -0,0 +1,97 @@
package com.github.catvod.spider;
import android.text.TextUtils;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Util;
import org.json.JSONArray;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Qile
*/
public class Kugou extends Spider {
private Map<String, String> getHeader() {
Map<String, String> header = new HashMap<>();
header.put("User-Agent", Util.CHROME);
return header;
}
@Override
public String homeContent(boolean filter) throws Exception {
List<Class> classes = new ArrayList<>();
List<Vod> list = new ArrayList<>();
List<String> typeIds = Arrays.asList("6666|0", "33162|1", "4681|2");
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, list);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
HashMap<String, String> ext = new HashMap<>();
if (extend != null && extend.size() > 0) ext.putAll(extend);
String[] item = tid.split("\\|");
String id = item[0];
String digit = item[1];
int digitValue = Integer.parseInt(digit);
String cateId = ext.get("cateId") == null ? id : ext.get("cateId");
String cateUrl = String.format("https://www.kugou.com/yy/rank/home/1-%s.html?from=rank", cateId);
Document doc = Jsoup.parse(OkHttp.string(cateUrl, getHeader()));
Elements lis = doc.select(".pc_rank_sidebar").eq(digitValue).select("ul li a");
JSONArray videos = new JSONArray();
for (Element li : lis) {
String vid = li.attr("href");
String name = li.attr("title");
JSONObject vod = new JSONObject().put("vod_id", vid).put("vod_name", name);
videos.put(vod);
}
JSONObject result = new JSONObject().put("total", lis.size()).put("pagecount", 1).put("list", videos);
return result.toString();
}
@Override
public String detailContent(List<String> ids) throws Exception {
Document doc = Jsoup.parse(OkHttp.string(ids.get(0), getHeader()));
Elements playlist = doc.select(".pc_temp_songlist ul li");
List<String> vodItems = new ArrayList<>();
for (int j = 0; j < playlist.size(); j++) {
Element a = playlist.get(j);
String href = a.select("a.pc_temp_songname").attr("href");
String text = a.select("a.pc_temp_songname").text();
vodItems.add(text + "$" + href);
}
String title = doc.select(".pc_temp_title h3").text();
String remark = doc.select(".rank_update").text();
String vod_play_from = "Qile";
String vod_play_url = TextUtils.join("#", vodItems);
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodName(title);
vod.setVodRemarks(remark);
vod.setVodPlayFrom(vod_play_from);
vod.setVodPlayUrl(vod_play_url);
return Result.string(vod);
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
return Result.get().url(id).parse().header(getHeader()).string();
}
}

View File

@@ -0,0 +1,117 @@
package com.github.catvod.spider;
import android.content.Context;
import android.net.Uri;
import android.os.Environment;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Sub;
import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider;
import com.github.catvod.utils.Image;
import com.github.catvod.utils.Util;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
public class Local extends Spider {
private SimpleDateFormat format;
@Override
public void init(Context context, String extend) {
format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.getDefault());
}
@Override
public String homeContent(boolean filter) throws Exception {
List<Class> classes = new ArrayList<>();
classes.add(new Class(Environment.getExternalStorageDirectory().getAbsolutePath(), "本地文件", "1"));
File[] files = new File("/storage").listFiles();
if (files == null) return Result.string(classes, new ArrayList<>());
List<String> exclude = Arrays.asList("emulated", "sdcard", "self");
for (File file : files) {
if (exclude.contains(file.getName())) continue;
classes.add(new Class(file.getAbsolutePath(), file.getName(), "1"));
}
return Result.string(classes, new ArrayList<>());
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
List<Vod> items = new ArrayList<>();
List<Vod> media = new ArrayList<>();
List<Vod> folders = new ArrayList<>();
File[] files = new File(tid).listFiles();
if (files == null) return Result.string(items);
Arrays.sort(files, (a, b) -> a.getName().compareTo(b.getName()));
for (File file : files) {
if (file.getName().startsWith(".")) continue;
if (file.isDirectory()) folders.add(create(file));
else if (Util.isMedia(file.getName())) media.add(create(file));
}
items.addAll(folders);
items.addAll(media);
return Result.get().vod(items).page().string();
}
@Override
public String detailContent(List<String> ids) {
String url = ids.get(0);
if (url.startsWith("http")) {
String name = Uri.parse(url).getLastPathSegment();
return Result.string(create(name, url));
} else {
File file = new File(ids.get(0));
return Result.string(create(file.getName(), file.getAbsolutePath()));
}
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
if (id.startsWith("http")) {
return Result.get().url(id).string();
} else {
return Result.get().url("file://" + id).subs(getSubs(id)).string();
}
}
private Vod create(String name, String url) {
Vod vod = new Vod();
vod.setTypeName("FongMi");
vod.setVodId(url);
vod.setVodName(name);
vod.setVodPic(Image.VIDEO);
vod.setVodPlayFrom("播放");
vod.setVodPlayUrl(name + "$" + url);
return vod;
}
private Vod create(File file) {
Vod vod = new Vod();
vod.setVodId(file.getAbsolutePath());
vod.setVodName(file.getName());
vod.setVodPic(Image.getIcon(file.isDirectory()));
vod.setVodRemarks(format.format(file.lastModified()));
vod.setVodTag(file.isDirectory() ? "folder" : "file");
return vod;
}
private List<Sub> getSubs(String path) {
File file = new File(path);
if (file.getParentFile() == null) return Collections.emptyList();
List<Sub> subs = new ArrayList<>();
for (File f : file.getParentFile().listFiles()) {
String ext = Util.getExt(f.getName());
if (Util.isSub(ext)) subs.add(Sub.create().name(Util.removeExt(f.getName())).ext(ext).url("file://" + f.getAbsolutePath()));
}
return subs;
}
}

View File

@@ -0,0 +1,159 @@
package com.github.catvod.spider;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.net.Uri;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.bean.market.Data;
import com.github.catvod.bean.market.Item;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.FileUtil;
import com.github.catvod.utils.Notify;
import com.github.catvod.utils.Path;
import com.github.catvod.utils.Util;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import okhttp3.Response;
public class Market extends Spider {
private ProgressDialog dialog;
private List<Data> datas;
private boolean busy;
public boolean isBusy() {
return busy;
}
public void setBusy(boolean busy) {
this.busy = busy;
}
@Override
public void init(Context context, String extend) throws Exception {
if (extend.startsWith("http")) extend = OkHttp.string(extend);
datas = Data.arrayFrom(extend);
Init.checkPermission();
}
@Override
public String homeContent(boolean filter) throws Exception {
List<Class> classes = new ArrayList<>();
if (datas.size() > 1) for (int i = 1; i < datas.size(); i++) classes.add(datas.get(i).type());
return Result.string(classes, datas.get(0).getVod());
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
for (Data data : datas) if (data.getName().equals(tid)) return Result.get().page().vod(data.getVod()).string();
return super.categoryContent(tid, pg, filter, extend);
}
@Override
public String detailContent(List<String> ids) throws Exception {
Init.run(this::finish);
Vod vod = new Vod();
vod.setVodPlayFrom("FongMi");
vod.setVodPlayUrl("FongMi$FongMi");
Init.execute(() -> download(ids.get(0)));
return Result.string(vod);
}
private void finish() {
try {
Activity activity = Init.getActivity();
if (activity != null) activity.finish();
} catch (Exception e) {
e.printStackTrace();
}
}
private void download(String url) {
try {
if (isBusy()) return;
setBusy(true);
Init.run(this::setDialog, 500);
Response response = OkHttp.newCall(url);
File file = Path.create(new File(Path.download(), Uri.parse(url).getLastPathSegment()));
download(file, response.body().byteStream(), Double.parseDouble(response.header("Content-Length", "1")));
if (file.getName().endsWith(".zip")) FileUtil.unzip(file, Path.download());
if (file.getName().endsWith(".apk")) FileUtil.openFile(file);
else Notify.show("下載完成");
checkCopy(url);
dismiss();
} catch (Exception e) {
Notify.show(e.getMessage());
dismiss();
}
}
private void download(File file, InputStream is, double length) throws Exception {
FileOutputStream os = new FileOutputStream(file);
try (BufferedInputStream input = new BufferedInputStream(is)) {
byte[] buffer = new byte[4096];
int readBytes;
long totalBytes = 0;
while ((readBytes = input.read(buffer)) != -1) {
totalBytes += readBytes;
os.write(buffer, 0, readBytes);
setProgress((int) (totalBytes / length * 100.0));
}
}
}
private void checkCopy(String url) {
for (Data data : datas) {
int index = data.getList().indexOf(new Item(url));
if (index == -1) continue;
String text = data.getList().get(index).getCopy();
if (!text.isEmpty()) Util.copy(text);
break;
}
}
private void setDialog() {
Init.run(() -> {
try {
dialog = new ProgressDialog(Init.getActivity());
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setCancelable(false);
if (isBusy()) dialog.show();
} catch (Exception e) {
e.printStackTrace();
}
});
}
private void dismiss() {
Init.run(() -> {
try {
setBusy(false);
if (dialog != null) dialog.dismiss();
} catch (Exception e) {
e.printStackTrace();
}
});
}
private void setProgress(int value) {
Init.run(() -> {
try {
if (dialog != null) dialog.setProgress(value);
} catch (Exception e) {
e.printStackTrace();
}
});
}
}

View File

@@ -0,0 +1,114 @@
package com.github.catvod.spider;
import android.text.TextUtils;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Filter;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
public class Miss extends Spider {
private final String url = "https://missav.com/";
@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 doc = Jsoup.parse(OkHttp.string(url));
for (Element a : doc.select("a.block.px-4.py-2.text-sm.leading-5.text-nord5.bg-nord3")) {
String typeId = a.attr("href").replace(url, "");
if (typeId.startsWith("dm") || typeId.contains("VR")) {
classes.add(new Class(typeId, a.text()));
filters.put(typeId, Arrays.asList(new Filter("filters", "過濾", Arrays.asList(new Filter.Value("全部", ""), new Filter.Value("單人作品", "individual"), new Filter.Value("中文字幕", "chinese-subtitle")))));
}
}
for (Element div : doc.select("div.thumbnail")) {
String id = div.select("a.text-secondary").attr("href").replace(url, "");
String name = div.select("a.text-secondary").text();
String pic = div.select("img").attr("data-src");
if (pic.isEmpty()) pic = div.select("img").attr("src");
String remark = div.select("span").text();
if (TextUtils.isEmpty(name)) continue;
list.add(new Vod(id, name, pic, remark));
}
return Result.string(classes, list, filters);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
List<Vod> list = new ArrayList<>();
String target = url + tid;
String filters = extend.get("filters");
if (TextUtils.isEmpty(filters)) target += "?page=" + pg;
else target += "?filters=" + extend.get("filters") + "&page=" + pg;
Document doc = Jsoup.parse(OkHttp.string(target));
for (Element div : doc.select("div.thumbnail")) {
String id = div.select("a.text-secondary").attr("href").replace(url, "");
String name = div.select("a.text-secondary").text();
String pic = div.select("img").attr("data-src");
if (pic.isEmpty()) pic = div.select("img").attr("src");
String remark = div.select("span").text();
if (TextUtils.isEmpty(name)) continue;
list.add(new Vod(id, name, pic, remark));
}
return Result.string(list);
}
@Override
public String detailContent(List<String> ids) throws Exception {
Document doc = Jsoup.parse(OkHttp.string(url + ids.get(0)));
String name = doc.select("meta[property=og:title]").attr("content");
String pic = doc.select("meta[property=og:image]").attr("content");
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodPic(pic);
vod.setVodName(name);
vod.setVodPlayFrom("MissAV");
vod.setVodPlayUrl("播放$" + ids.get(0));
return Result.string(vod);
}
@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);
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
return Result.get().parse().url(url + id).string();
}
private String searchContent(String key, String pg) {
List<Vod> list = new ArrayList<>();
Document doc = Jsoup.parse(OkHttp.string(url + "search/" + key + "?page=" + pg));
for (Element div : doc.select("div.thumbnail")) {
String id = div.select("a.text-secondary").attr("href").replace(url, "");
String name = div.select("a.text-secondary").text();
String pic = div.select("img").attr("data-src");
if (pic.isEmpty()) pic = div.select("img").attr("src");
String remark = div.select("span").text();
if (TextUtils.isEmpty(name)) continue;
list.add(new Vod(id, name, pic, remark));
}
return Result.string(list);
}
}

View File

@@ -0,0 +1,349 @@
package com.github.catvod.spider;
import android.annotation.SuppressLint;
import android.content.Context;
import android.text.TextUtils;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Filter;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider;
import com.github.catvod.crawler.SpiderDebug;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Util;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.security.Key;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
public class NiNi extends Spider {
private static final String desktopUrl = "https://api.nivodz.com/index/desktop/WEB/3.4";
private static final String rankingUrl = "https://api.nivodz.com/index/ranking/list/WEB/3.2";
private static final String filterUrl = "https://api.nivodz.com/show/filter/condition/WEB/3.2";
private static final String searchUrl = "https://api.nivodz.com/show/search/WEB/3.2";
private static final String categoryUrl = "https://api.nivodz.com/show/filter/WEB/3.2";
private static final String detailUrl = "https://api.nivodz.com/show/detail/WEB/3.2";
private static final String playUrl = "https://api.nivodz.com/show/play/info/WEB/3.2";
private static final String des_key = "diao.com";
private boolean adult;
private HashMap<String, String> getHeaders() {
HashMap<String, String> headers = new HashMap<>();
headers.put("User-Agent", Util.CHROME);
headers.put("Referer", "https://m.nbys.tv/");
return headers;
}
private Filter getFilter(String name, String key, JSONArray target, String n, String v) throws JSONException {
List<Filter.Value> values = new ArrayList<>();
if (!key.equals("by")) values.add(new Filter.Value("全部", ""));
for (int j = 0; j < target.length(); j++) values.add(new Filter.Value(target.getJSONObject(j).get(n).toString(), target.getJSONObject(j).get(v).toString()));
return new Filter(key, name, values);
}
private void checkExtend(HashMap<String, String> extend, String key, String value) {
if (extend.get(key) == null || extend.get(key).equals("")) extend.put(key, value);
}
@Override
public void init(Context context, String extend) {
adult = !TextUtils.isEmpty(extend);
}
@Override
public String homeContent(boolean filter) throws Exception {
List<Class> classes = new ArrayList<>();
LinkedHashMap<String, List<Filter>> filters = new LinkedHashMap<>();
JSONObject object = new JSONObject(get(filterUrl));
for (int i = 0; i < object.getJSONArray("channels").length(); i++) {
String typeId = object.getJSONArray("channels").getJSONObject(i).get("channelId").toString();
String typeName = object.getJSONArray("channels").getJSONObject(i).get("channelName").toString();
if (!adult && typeName.contains("午夜")) continue;
classes.add(adult && typeName.contains("午夜") ? 0 : classes.size(), new Class(typeId, typeName));
List<Filter> array = new ArrayList<>();
array.add(getFilter("排序", "by", object.getJSONObject("sortsMap").getJSONArray(typeId), "title", "id"));
array.add(getFilter("語言", "lang", object.getJSONArray("langs"), "langName", "langId"));
array.add(getFilter("地區", "area", object.getJSONArray("regions"), "regionName", "regionId"));
array.add(getFilter("類型", "class", object.getJSONObject("typesMap").getJSONArray(typeId), "showTypeName", "showTypeId"));
array.add(getFilter("年份", "year", object.getJSONArray("yearRanges"), "name", "code"));
filters.put(typeId, array);
}
return Result.string(classes, filters);
}
private String getAdultHome() throws Exception {
Map<String, String> params = new TreeMap<>();
params.put("channel_id", "7");
params.put("start", "0");
params.put("more", "1");
JSONObject object = new JSONObject(post(desktopUrl, params));
JSONArray array = object.getJSONArray("list");
List<Vod> list = new ArrayList<>();
for (int i = 0; i < array.length(); i++) {
JSONArray rows = array.getJSONObject(i).getJSONArray("rows");
for (int j = 0; j < rows.length(); j++) {
JSONArray cells = rows.getJSONObject(j).getJSONArray("cells");
for (int k = 0; k < cells.length(); k++) {
JSONObject item = cells.getJSONObject(k).getJSONObject("show");
String id = item.getString("showIdCode");
String name = item.getString("showTitle");
String pic = item.getString("showImg");
list.add(new Vod(id, name, getPic(pic), getRemarks(item)));
}
}
}
return Result.string(list);
}
@Override
public String homeVideoContent() throws Exception {
if (adult) return getAdultHome();
JSONObject object = new JSONObject(get(rankingUrl));
JSONArray array = object.getJSONArray("list");
List<Vod> list = new ArrayList<>();
for (int i = 0; i < array.length(); i++) {
JSONArray dataItem = array.getJSONArray(i);
for (int j = 0; j < dataItem.length(); j++) {
JSONObject item = dataItem.getJSONObject(j);
String id = item.getString("showIdCode");
String name = item.getString("showTitle");
String pic = item.getString("showImg");
list.add(new Vod(id, name, getPic(pic), getRemarks(item)));
}
}
return Result.string(list);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
int page = Integer.parseInt(pg) - 1;
if (tid.endsWith("/{pg}")) return searchContent(tid.split("/")[0], page);
checkExtend(extend, "by", "3");
checkExtend(extend, "area", "0");
checkExtend(extend, "lang", "0");
checkExtend(extend, "year", "");
checkExtend(extend, "class", "0");
Map<String, String> params = new TreeMap<>();
params.put("sort_by", extend.get("by"));
params.put("channel_id", tid);
params.put("show_type_id", extend.get("class"));
params.put("region_id", extend.get("area"));
params.put("lang_id", extend.get("lang"));
params.put("year_range", extend.get("year"));
params.put("start", String.valueOf(page * 20));
JSONObject object = new JSONObject(post(categoryUrl, params));
JSONArray array = object.getJSONArray("list");
List<Vod> list = new ArrayList<>();
boolean land = tid.equals("7") || tid.equals("16");
for (int i = 0; i < array.length(); i++) {
JSONObject item = array.getJSONObject(i);
String id = item.getString("showIdCode");
String name = item.getString("showTitle");
String pic = item.getString("showImg");
if (land) list.add(new Vod(id, name, getPic(pic), getRemarks(item), Vod.Style.rect(1.33f)));
else list.add(new Vod(id, name, getPic(pic), getRemarks(item)));
}
return Result.string(list);
}
@Override
public String detailContent(List<String> ids) throws Exception {
Map<String, String> params = new TreeMap<>();
params.put("show_id_code", ids.get(0));
JSONObject object = new JSONObject(post(detailUrl, params));
JSONObject entity = object.getJSONObject("entity");
JSONArray plays = entity.getJSONArray("plays");
String id = entity.optString("showIdCode");
List<String> vodItems = new ArrayList<>();
for (int j = 0; j < plays.length(); j++) {
JSONObject item = plays.getJSONObject(j);
String episodeName = item.getString("episodeName");
episodeName = TextUtils.isEmpty(episodeName) ? "播放" : episodeName;
vodItems.add(episodeName + "$" + id + "_" + item.getString("playIdCode"));
}
Vod vod = new Vod();
vod.setVodId(id);
vod.setVodName(entity.optString("showTitle"));
vod.setVodPic(getPic(entity.optString("showImg")));
vod.setVodContent(entity.optString("showDesc"));
vod.setVodDirector(convert(entity.optString("director")));
vod.setVodActor(convert(entity.optString("actors")));
vod.setVodYear(entity.optString("postYear"));
vod.setVodArea(entity.optString("regionName"));
vod.setTypeName((entity.optString("channelName")));
vod.setVodPlayUrl(TextUtils.join("#", vodItems));
vod.setVodRemarks(getRemarks(entity));
vod.setVodPlayFrom("泥巴");
return Result.string(vod);
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
String[] ids = id.split("_");
Map<String, String> params = new TreeMap<>();
params.put("show_id_code", ids[0]);
params.put("play_id_code", ids[1]);
params.put("oid", "1");
JSONObject object = new JSONObject(post(playUrl, params));
String playUrl = object.getJSONObject("entity").optString("playUrl");
return Result.get().url(playUrl).header(getHeaders()).string();
}
@Override
public String searchContent(String key, boolean quick) throws Exception {
return searchContent(key, 0);
}
@Override
public String searchContent(String key, boolean quick, String pg) throws Exception {
return searchContent(key, Integer.parseInt(pg) - 1);
}
public String searchContent(String key, int pg) throws Exception {
Map<String, String> params = new TreeMap<>();
params.put("keyword", key);
params.put("start", String.valueOf(pg * 20));
params.put("cat_id", adult ? "2" : "1");
params.put("keyword_type", "0");
JSONObject object = new JSONObject(post(searchUrl, params));
JSONArray array = object.getJSONArray("list");
List<Vod> list = new ArrayList<>();
for (int i = 0; i < array.length(); i++) {
JSONObject item = array.getJSONObject(i);
String id = item.getString("showIdCode");
String name = item.getString("showTitle");
String pic = item.getString("showImg");
list.add(new Vod(id, name, getPic(pic), getRemarks(item)));
}
return Result.string(list);
}
private String genUrl(String url, Map<String, String> bodys) {
String randomStr = "AABBCC";
String oidTime = String.valueOf(new Date().getTime() - 10 * 60 * 1000);
String oid = encode(oidTime + "_" + randomStr);
Map<String, String> params = new TreeMap<>();
params.put("_ts", String.valueOf(new Date().getTime()));
params.put("app_version", "1.0");
params.put("platform", "3");
params.put("market_id", "web_nivod");
params.put("device_code", "web");
params.put("versioncode", "1");
params.put("oid", oid);
StringBuilder sign_query = new StringBuilder("__QUERY::");
for (Map.Entry<String, String> entry : params.entrySet()) {
if (entry.getValue().equals("")) continue;
sign_query.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
}
StringBuilder sign_body = new StringBuilder("__BODY::");
for (Map.Entry<String, String> entry : bodys.entrySet()) {
if (entry.getValue().equals("")) continue;
sign_body.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
}
String _SECRET_PREFIX = "__KEY::";
String secretKey = "2x_Give_it_a_shot";
String has = Util.MD5(sign_query + sign_body.toString() + _SECRET_PREFIX + secretKey, "UTF-8");
url += "?_ts=" + params.get("_ts") + "&app_version=" + params.get("app_version") + "&platform=" + params.get("platform") + "&market_id=" + params.get("market_id") + "&device_code=" + params.get("device_code") + "&versioncode=" + params.get("versioncode") + "&oid=" + params.get("oid") + "&sign=" + has;
return url;
}
private String getPic(String pic) {
return pic.replace(".nivod4.", ".nivod.");
}
private String getRemarks(JSONObject item) {
String remark = item.optString("episodesTxt");
remark = TextUtils.isEmpty(remark) || remark.equals("null") ? "" : remark;
return remark;
}
private String convert(String text) {
StringBuilder sb = new StringBuilder();
for (String s : text.split(",")) sb.append(String.format("[a=cr:{\"id\":\"%s\",\"name\":\"%s\"}/]%s[/a]", s + "/{pg}", s, s)).append(",");
return Util.substring(sb.toString());
}
private String get(String url) {
return decode(OkHttp.string(genUrl(url, new HashMap<>()), getHeaders()));
}
private String post(String url, Map<String, String> params) {
return decode(OkHttp.post(genUrl(url, params), params, getHeaders()).getBody());
}
@SuppressLint("GetInstance")
private Cipher getCipher(int mode) {
try {
DESKeySpec dks = new DESKeySpec(des_key.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
Key secretKey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS7Padding");
cipher.init(mode, secretKey);
return cipher;
} catch (Exception e) {
SpiderDebug.log(e);
return null;
}
}
private String encode(String data) {
try {
if (data == null || data.isEmpty()) return "";
Cipher cipher = getCipher(Cipher.ENCRYPT_MODE);
if (cipher == null) return "";
byte[] byteHex = cipher.doFinal(data.getBytes("UTF-8"));
return byteToHexString(byteHex);
} catch (Exception e) {
return "";
}
}
private String decode(String data) {
try {
if (data == null || data.isEmpty()) return "";
byte[] b = hex2byte(data);
Cipher cipher = getCipher(Cipher.DECRYPT_MODE);
if (cipher == null) return "";
return new String(cipher.doFinal(b), "UTF-8");
} catch (Exception e) {
return "";
}
}
private String byteToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length);
String sTemp;
for (byte aByte : bytes) {
sTemp = Integer.toHexString(0xFF & aByte);
if (sTemp.length() < 2) sb.append(0);
sb.append(sTemp.toUpperCase());
}
return sb.toString().toLowerCase();
}
private byte[] hex2byte(String hex) throws IllegalArgumentException {
char[] arr = hex.toCharArray();
byte[] b = new byte[hex.length() / 2];
for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {
String swap = String.valueOf(arr[i++]) + arr[i];
int byteInt = Integer.parseInt(swap, 16) & 0xFF;
b[j] = Integer.valueOf(byteInt).byteValue();
}
return b;
}
}

View File

@@ -0,0 +1,100 @@
package com.github.catvod.spider;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.util.Base64;
import android.view.Gravity;
import android.widget.FrameLayout;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.github.catvod.ui.ScrollTextView;
import com.github.catvod.utils.ResUtil;
import com.github.catvod.utils.Util;
import org.json.JSONObject;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Random;
public class Notice extends Spider {
private static final String SPACE = " ";
private ScrollTextView view;
private String extend;
private int duration;
private String msg;
public static void show(String extend) {
try {
Notice notice = new Notice();
notice.init(null, extend);
notice.homeContent(false);
} catch (Exception ignored) {
}
}
@Override
public void init(Context context, String extend) {
this.extend = extend;
}
@Override
public String homeContent(boolean filter) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault());
String json = extend.startsWith("http") ? OkHttp.string(extend) : new String(Base64.decode(extend, Base64.DEFAULT));
JSONObject object = new JSONObject(json);
msg = object.optString("msg");
duration = object.optInt("duration", 30);
String date = object.optString("date");
boolean show = msg.length() > 0 && (date.isEmpty() || new Date().after(sdf.parse(date)));
if (show) Init.run(this::createView, 500);
return "";
}
private void createView() {
createText();
createRoot();
setColor();
hide();
}
private void createText() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 2; i++) sb.append(SPACE).append(msg);
view = new ScrollTextView(Init.context());
view.setTextSize(20);
view.setDuration(duration);
view.setText(sb.toString());
view.setTypeface(null, Typeface.BOLD);
view.setPadding(0, ResUtil.dp2px(16), 0, ResUtil.dp2px(16));
view.setBackgroundColor(Color.argb(200, 255, 255, 255));
view.startScroll();
}
private void createRoot() {
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.TOP;
Util.addView(view, params);
}
private void hide() {
Init.run(() -> Util.removeView(view), duration * 1000);
}
private void setColor() {
Init.run(runnable, 500);
}
private final Runnable runnable = new Runnable() {
@Override
public void run() {
Random random = new Random();
view.setTextColor(Color.argb(255, random.nextInt(128), random.nextInt(128), random.nextInt(128)));
setColor();
}
};
}

View File

@@ -0,0 +1,60 @@
package com.github.catvod.spider;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Util;
import org.json.JSONArray;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author zhixc
*/
public class PanSearch extends Ali {
private final String URL = "https://www.pansearch.me/";
private Map<String, String> getHeader() {
Map<String, String> header = new HashMap<>();
header.put("User-Agent", Util.CHROME);
return header;
}
private Map<String, String> getSearchHeader() {
Map<String, String> header = getHeader();
header.put("x-nextjs-data", "1");
header.put("referer", URL);
return header;
}
@Override
public String searchContent(String key, boolean quick) throws Exception {
String html = OkHttp.string(URL, getHeader());
String data = Jsoup.parse(html).select("script[id=__NEXT_DATA__]").get(0).data();
String buildId = new JSONObject(data).getString("buildId");
String url = URL + "_next/data/" + buildId + "/search.json?keyword=" + URLEncoder.encode(key) + "&pan=aliyundrive";
String result = OkHttp.string(url, getSearchHeader());
JSONArray array = new JSONObject(result).getJSONObject("pageProps").getJSONObject("data").getJSONArray("data");
List<Vod> list = new ArrayList<>();
for (int i = 0; i < array.length(); i++) {
JSONObject item = array.getJSONObject(i);
String content = item.optString("content");
String[] split = content.split("\\n");
if (split.length == 0) continue;
String vodId = Jsoup.parse(content).select("a").attr("href");
String name = split[0].replaceAll("</?[^>]+>", "");
String remark = item.optString("time");
String pic = item.optString("image");
list.add(new Vod(vodId, name, pic, remark));
}
return Result.string(list);
}
}

View File

@@ -0,0 +1,73 @@
package com.github.catvod.spider;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Util;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author ColaMint & FongMi
*/
public class PanSou extends Ali {
private final String siteUrl = "https://www.alipansou.com";
private Map<String, String> getHeaders(String id) {
HashMap<String, String> headers = new HashMap<>();
headers.put("User-Agent", Util.CHROME);
headers.put("Referer", siteUrl + id);
headers.put("_bid", "6d14a5dd6c07980d9dc089a693805ad8");
return headers;
}
private Map<String, String> getHeader() {
HashMap<String, String> header = new HashMap<>();
header.put("User-Agent", Util.CHROME);
return header;
}
@Override
public String detailContent(List<String> ids) throws Exception {
if (pattern.matcher(ids.get(0)).find()) return super.detailContent(ids);
String url = siteUrl + ids.get(0).replace("/s/", "/cv/");
url = OkHttp.getLocation(url, getHeaders(ids.get(0)));
return super.detailContent(Arrays.asList(url));
}
@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);
}
private String searchContent(String key, String pg) {
String url = siteUrl + "/search?k=" + URLEncoder.encode(key) + "&page=" + pg + "&s=0&t=-1";
Elements items = Jsoup.parse(OkHttp.string(url, getHeader())).select("van-row > a");
List<Vod> list = new ArrayList<>();
for (Element item : items) {
String title = item.selectFirst("template").text().trim();
if (!title.contains(key)) continue;
Vod vod = new Vod();
vod.setVodId(item.attr("href"));
vod.setVodPic("https://inews.gtimg.com/newsapp_bt/0/13263837859/1000");
vod.setVodName(title);
list.add(vod);
}
return Result.string(list);
}
}

View File

@@ -0,0 +1,52 @@
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.util.Map;
public class Proxy extends Spider {
private static int port = -1;
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"))};
case "ali":
return Ali.proxy(params);
case "bili":
return Bili.proxy(params);
case "webdav":
return WebDAV.vod(params);
default:
return null;
}
}
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 int getPort() {
adjustPort();
return port;
}
public static String getUrl() {
adjustPort();
return "http://127.0.0.1:" + port + "/proxy";
}
}

View File

@@ -0,0 +1,91 @@
package com.github.catvod.spider;
import android.content.Context;
import android.net.Uri;
import android.text.TextUtils;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Sub;
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 java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Push extends Spider {
private final Ali ali;
public Push() {
ali = new Ali();
}
@Override
public void init(Context context, String extend) {
ali.init(context, extend);
}
@Override
public String detailContent(List<String> ids) throws Exception {
if (Ali.pattern.matcher(ids.get(0)).find()) return ali.detailContent(ids);
return Result.string(vod(ids.get(0)));
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) {
if (id.startsWith("http") && id.contains("***")) id = id.replace("***", "#");
if (flag.equals("直連")) return Result.get().url(id).subs(getSubs(id)).string();
if (flag.equals("解析")) return Result.get().parse().jx().url(id).string();
if (flag.equals("嗅探")) return Result.get().parse().url(id).string();
if (flag.equals("迅雷")) return Result.get().url(id).string();
return ali.playerContent(flag, id, vipFlags);
}
private Vod vod(String url) {
Vod vod = new Vod();
vod.setVodId(url);
vod.setTypeName("FongMi");
vod.setVodName(url.startsWith("file://") ? new File(url).getName() : url);
if (url.startsWith("http") && url.contains("#")) url = url.replace("#", "***");
vod.setVodPic("https://pic.rmb.bdstatic.com/bjh/1d0b02d0f57f0a42201f92caba5107ed.jpeg");
String play = "播放$" + url;
boolean thunder = Util.isThunder(url);
vod.setVodPlayUrl(thunder ? play : TextUtils.join("$$$", Arrays.asList(play, play, play)));
vod.setVodPlayFrom(thunder ? "迅雷" : TextUtils.join("$$$", Arrays.asList("直連", "嗅探", "解析")));
return vod;
}
private List<Sub> getSubs(String url) {
List<Sub> subs = new ArrayList<>();
if (url.startsWith("file://")) setFileSub(url, subs);
if (url.startsWith("http://")) setHttpSub(url, subs);
return subs;
}
private void setHttpSub(String url, List<Sub> subs) {
List<String> vodTypes = Arrays.asList("mp4", "mkv");
List<String> subTypes = Arrays.asList("srt", "ass");
if (!vodTypes.contains(Util.getExt(url))) return;
for (String ext : subTypes) detectSub(url, ext, subs);
}
private void detectSub(String url, String ext, List<Sub> subs) {
url = Util.removeExt(url).concat(".").concat(ext);
if (OkHttp.string(url).length() < 100) return;
String name = Uri.parse(url).getLastPathSegment();
subs.add(Sub.create().name(name).ext(ext).url(url));
}
private void setFileSub(String url, List<Sub> subs) {
File file = new File(url.replace("file://", ""));
if (file.getParentFile() == null) return;
for (File f : file.getParentFile().listFiles()) {
String ext = Util.getExt(f.getName());
if (Util.isSub(ext)) subs.add(Sub.create().name(Util.removeExt(f.getName())).ext(ext).url("file://" + f.getAbsolutePath()));
}
}
}

View File

@@ -0,0 +1,110 @@
package com.github.catvod.spider;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Util;
import com.orhanobut.logger.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
public class QxiTv extends Spider {
private static final String siteUrl = "https://7xi.tv";
private static final String cateUrl = siteUrl + "/vodtype/";
private static final String detailUrl = siteUrl + "/videos/";
private static final String searchUrl = siteUrl + "/search/";
private HashMap<String, String> getHeaders() {
HashMap<String, String> headers = new HashMap<>();
headers.put("User-Agent", Util.CHROME);
return headers;
}
@Override
public String homeContent(boolean filter) throws Exception {
List<Vod> list = new ArrayList<>();
List<Class> classes = new ArrayList<>();
Document doc = Jsoup.parse(OkHttp.string(cateUrl.concat("1.html"), getHeaders()));
// for (Element element : doc.select(".header_nav1 div.this-wap > a")) {
// String typeId = element.attr("href");
// String typeName = element.text();
// classes.add(new Class(typeId, typeName));
// }
doc = Jsoup.parse(OkHttp.string(siteUrl, getHeaders()));
for (Element element : doc.select("div.public-list-div")) {
try {
String pic = element.select("img").attr("data-src");
String url = element.select("a").attr("href");
String name = element.select("a.title").text();
if (pic.endsWith(".gif") || name.isEmpty()) continue;
String id = url.split("/")[2];
list.add(new Vod(id, name, pic));
}catch (Exception e){
}
}
return Result.string(classes, list);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
List<Vod> list = new ArrayList<>();
String target = cateUrl + tid + "/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=post_date&from=" + String.format(Locale.getDefault(), "%02d", Integer.parseInt(pg)) + "&_=" + System.currentTimeMillis();
Document doc = Jsoup.parse(OkHttp.string(target, getHeaders()));
for (Element element : doc.select("div.video-img-box")) {
String pic = element.select("img").attr("data-src");
String url = element.select("a").attr("href");
String name = element.select("div.detail > h6").text();
String id = url.split("/")[4];
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(detailUrl.concat(ids.get(0)).concat("/"), getHeaders()));
String name = doc.select("meta[property=og:title]").attr("content");
String pic = doc.select("meta[property=og:image]").attr("content");
String year = doc.select("span.inactive-color").get(0).text();
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodPic(pic);
vod.setVodYear(year.replace("上市於 ", ""));
vod.setVodName(name);
vod.setVodPlayFrom("Jable");
vod.setVodPlayUrl("播放$" + Util.getVar(doc.html(), "hlsUrl"));
return Result.string(vod);
}
@Override
public String searchContent(String key, boolean quick) throws Exception {
List<Vod> list = new ArrayList<>();
Document doc = Jsoup.parse(OkHttp.string(searchUrl.concat(URLEncoder.encode(key)).concat("/"), getHeaders()));
for (Element element : doc.select("div.video-img-box")) {
String pic = element.select("img").attr("data-src");
String url = element.select("a").attr("href");
String name = element.select("div.detail > h6").text();
String id = url.split("/")[4];
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();
}
}

View File

@@ -0,0 +1,153 @@
package com.github.catvod.spider;
import android.content.Context;
import android.text.TextUtils;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Filter;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.bean.star.Card;
import com.github.catvod.bean.star.Condition;
import com.github.catvod.bean.star.Group;
import com.github.catvod.bean.star.Info;
import com.github.catvod.bean.star.Person;
import com.github.catvod.bean.star.Query;
import com.github.catvod.bean.star.Video;
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.Element;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class Star extends Spider {
private static final String apiUrl = "https://aws.ulivetv.net/v3/web/api/filter";
private static final String siteUrl = "https://www.histar.tv/";
private static final String detail = siteUrl + "vod/detail/";
private static final String data = "_next/data/";
private LinkedHashMap<String, String> map;
private String ver;
private Map<String, String> getHeader() {
Map<String, String> headers = new HashMap<>();
headers.put("User-Agent", Util.CHROME);
headers.put("Referer", siteUrl);
return headers;
}
private String getVer() {
for (Element script : Jsoup.parse(OkHttp.string(siteUrl, getHeader())).select("script")) if (script.attr("src").contains("buildManifest.js")) return script.attr("src").split("/")[3];
return "";
}
@Override
public void init(Context context, String extend) {
map = new LinkedHashMap<>();
map.put("movie", "电影");
map.put("drama", "电视剧");
map.put("animation", "动漫");
map.put("variety", "综艺");
ver = getVer();
}
@Override
public String homeContent(boolean filter) throws Exception {
List<Class> classes = new ArrayList<>();
LinkedHashMap<String, List<Filter>> filters = new LinkedHashMap<>();
for (Map.Entry<String, String> entry : map.entrySet()) classes.add(new Class(entry.getKey(), entry.getValue()));
for (Class type : classes) {
Element script = Jsoup.parse(OkHttp.string(siteUrl + type.getTypeId() + "/all/all/all", getHeader())).select("#__NEXT_DATA__").get(0);
JSONObject obj = new JSONObject(script.data()).getJSONObject("props").getJSONObject("pageProps").getJSONObject("filterCondition");
Condition item = Condition.objectFrom(obj.toString());
filters.put(type.getTypeId(), item.getFilter());
}
return Result.string(classes, filters);
}
@Override
public String homeVideoContent() throws Exception {
List<Vod> list = new ArrayList<>();
Element script = Jsoup.parse(OkHttp.string(siteUrl, getHeader())).select("#__NEXT_DATA__").get(0);
List<Card> cards = Card.arrayFrom(new JSONObject(script.data()).getJSONObject("props").getJSONObject("pageProps").getJSONArray("cards").toString());
for (Card card : cards) if (!card.getName().equals("电视直播")) for (Card item : card.getCards()) list.add(item.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], true);
String year = extend.containsKey("year") ? extend.get("year") : "";
String type = extend.containsKey("type") ? extend.get("type") : "";
String area = extend.containsKey("area") ? extend.get("area") : "";
Query query = new Query();
query.setPageSize(16);
query.setChName(map.get(tid));
query.setPage(Integer.parseInt(pg));
if (year.length() > 0) query.setYear(year);
if (type.length() > 0) query.setLabel(type);
if (area.length() > 0) query.setCountry(area);
String body = OkHttp.post(apiUrl, query.toString());
List<Card> cards = Card.arrayFrom(new JSONObject(body).getJSONObject("data").getJSONArray("list").toString());
List<Vod> list = new ArrayList<>();
for (Card card : cards) list.add(card.vod());
return Result.string(list);
}
@Override
public String detailContent(List<String> ids) throws Exception {
Element script = Jsoup.parse(OkHttp.string(detail.concat(ids.get(0)), getHeader())).select("#__NEXT_DATA__").get(0);
Info detail = Info.objectFrom(new JSONObject(script.data()).getJSONObject("props").getJSONObject("pageProps").getJSONObject("collectionInfo").toString());
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodYear(detail.getTime());
vod.setVodName(detail.getName());
vod.setVodPic(detail.getPicurl());
vod.setVodArea(detail.getCountry());
vod.setVodContent(detail.getDesc());
vod.setVodRemarks(detail.getCountStr());
vod.setVodActor(convert(detail.getActor()));
vod.setVodDirector(convert(detail.getDirector()));
List<String> playFrom = new ArrayList<>();
List<String> playUrls = new ArrayList<>();
for (Group group : detail.getVideosGroup()) {
List<String> urls = new ArrayList<>();
for (Video video : group.getVideos()) urls.add(video.getEporder() + "$" + video.getPurl());
playUrls.add(TextUtils.join("#", urls));
playFrom.add(group.getName());
}
vod.setVodPlayUrl(TextUtils.join("$$$", playUrls));
vod.setVodPlayFrom(TextUtils.join("$$$", playFrom));
return Result.string(vod);
}
@Override
public String searchContent(String key, boolean quick) throws Exception {
List<Vod> list = new ArrayList<>();
String json = OkHttp.string(siteUrl + data + ver + "/search.json?word=" + URLEncoder.encode(key), getHeader());
List<Card> items = Card.arrayFrom(new JSONObject(json).getJSONObject("pageProps").getJSONArray("initList").toString());
for (Card item : items) list.add(item.vod());
return Result.get().vod(list).page().string();
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
return Result.get().url(id).string();
}
private String convert(List<Person> items) {
StringBuilder sb = new StringBuilder();
for (Person item : items) sb.append(String.format("[a=cr:{\"id\":\"%s\",\"name\":\"%s\"}/]%s[/a]", item.getName() + "/{pg}", item.getName(), item.getName())).append(",");
return Util.substring(sb.toString());
}
}

View File

@@ -0,0 +1,53 @@
package com.github.catvod.spider;
import android.util.Base64;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Util;
import org.json.JSONArray;
import org.json.JSONObject;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class UpYun extends Ali {
private Map<String, String> getHeader() {
Map<String, String> header = new HashMap<>();
header.put("User-Agent", Util.CHROME);
return header;
}
@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);
}
private String searchContent(String key, String pg) throws Exception {
String searchUrl = "https://upapi.juapp9.com/search?keyword=" + URLEncoder.encode(key) + "&page=" + pg + "&s_type=2";
String content = OkHttp.string(searchUrl, getHeader());
String decodedContent = new String(Base64.decode(content, Base64.DEFAULT));
JSONArray jsonArray = new JSONObject(decodedContent).getJSONObject("result").getJSONArray("items");
List<Vod> list = new ArrayList<>();
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObj = jsonArray.getJSONObject(i);
String id = jsonObj.optString("page_url");
String name = jsonObj.optString("title");
String pic = "https://pic.imgdb.cn/item/65767399c458853aeff8a6a0.webp";
String remark = jsonObj.optString("insert_time");
if (name.contains(key)) list.add(new Vod(id, name, pic, remark));
}
return Result.string(list);
}
}

View File

@@ -0,0 +1,191 @@
package com.github.catvod.spider;
import android.content.Context;
import android.text.TextUtils;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Filter;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Sub;
import com.github.catvod.bean.Vod;
import com.github.catvod.bean.webdav.Drive;
import com.github.catvod.bean.webdav.Sorter;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Image;
import com.github.catvod.utils.Util;
import com.thegrizzlylabs.sardineandroid.DavResource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class WebDAV extends Spider {
private static List<Drive> drives;
private List<String> allExt;
private String extend;
private List<Filter> getFilter() {
List<Filter> items = new ArrayList<>();
items.add(new Filter("type", "排序類型", Arrays.asList(new Filter.Value("預設", ""), new Filter.Value("名稱", "name"), new Filter.Value("大小", "size"), new Filter.Value("修改時間", "date"))));
items.add(new Filter("order", "排序方式", Arrays.asList(new Filter.Value("預設", ""), new Filter.Value("", "asc"), new Filter.Value("", "desc"))));
return items;
}
private void fetchRule() {
if (drives != null && !drives.isEmpty()) return;
if (extend.startsWith("http")) extend = OkHttp.string(extend);
Drive drive = Drive.objectFrom(extend);
drives = drive.getDrives();
}
private String getExt(DavResource item) {
return Util.getExt(item.getName());
}
private String removeExt(DavResource item) {
return Util.removeExt(item.getName());
}
private static Drive getDrive(String name) {
return drives.get(drives.indexOf(new Drive(name)));
}
@Override
public void init(Context context, String extend) {
this.allExt = new ArrayList<>(Arrays.asList("ass", "ssa", "srt"));
this.allExt.addAll(Util.MEDIA);
this.extend = extend;
fetchRule();
}
@Override
public String homeContent(boolean filter) throws Exception {
List<Class> classes = new ArrayList<>();
LinkedHashMap<String, List<Filter>> filters = new LinkedHashMap<>();
for (Drive drive : drives) classes.add(drive.toType());
for (Class item : classes) filters.put(item.getTypeId(), getFilter());
return Result.string(classes, filters);
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
String key = tid.contains("/") ? tid.substring(0, tid.indexOf("/")) : tid;
String path = tid.contains("/") ? tid.substring(tid.indexOf("/")) : "";
String order = extend.containsKey("order") ? extend.get("order") : "";
String type = extend.containsKey("type") ? extend.get("type") : "";
List<DavResource> folders = new ArrayList<>();
List<DavResource> files = new ArrayList<>();
List<Vod> list = new ArrayList<>();
Drive drive = getDrive(key);
for (DavResource item : getList(drive, path, Util.MEDIA)) {
if (item.isDirectory()) folders.add(item);
else files.add(item);
}
if (!TextUtils.isEmpty(type) && !TextUtils.isEmpty(order)) {
Sorter.sort(type, order, folders);
Sorter.sort(type, order, files);
}
for (DavResource item : folders) list.add(drive.vod(item, Image.FOLDER));
for (DavResource item : files) list.add(drive.vod(item, Image.VIDEO));
return Result.get().vod(list).page().string();
}
@Override
public String detailContent(List<String> ids) throws Exception {
String id = ids.get(0);
String key = id.contains("/") ? id.substring(0, id.indexOf("/")) : id;
String parent = id.substring(0, id.lastIndexOf("/"));
String path = parent.contains("/") ? parent.substring(parent.indexOf("/")) + "/" : "";
String name = parent.substring(parent.lastIndexOf("/") + 1);
Drive drive = getDrive(key);
List<DavResource> parents = getList(drive, path, allExt);
List<DavResource> subs = getSubs(parents);
Sorter.sort("name", "asc", parents);
List<String> playUrls = new ArrayList<>();
for (DavResource item : parents) {
if (Util.isMedia(item.getName())) {
playUrls.add(item.getName() + "$" + drive.getName() + item.getPath() + findSubs(drive, item, subs));
}
}
Vod vod = new Vod();
vod.setVodId(name);
vod.setVodName(name);
vod.setVodPlayFrom(key);
vod.setVodPic(Image.VIDEO);
vod.setVodPlayUrl(TextUtils.join("#", playUrls));
return Result.string(vod);
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
String[] ids = id.split("~~~");
return Result.get().url(getProxyUrl(ids[0])).subs(getSub(ids)).string();
}
private List<DavResource> getList(Drive drive, String path, List<String> ext) throws Exception {
path = drive.getHost() + (path.startsWith(drive.getPath()) ? path : drive.getPath() + path);
List<DavResource> items = drive.getWebdav().list(path);
items.remove(0); //Remove parent
Iterator<DavResource> iterator = items.iterator();
while (iterator.hasNext()) {
DavResource item = iterator.next();
if (!item.isDirectory() && !item.getName().contains(".")) iterator.remove();
if (!item.isDirectory() && !ext.contains(getExt(item))) iterator.remove();
}
return items;
}
private List<DavResource> getSubs(List<DavResource> items) {
List<DavResource> subs = new ArrayList<>();
for (DavResource item : items) if (Util.isSub(getExt(item))) subs.add(item);
return subs;
}
private String findSubs(Drive drive, DavResource res, List<DavResource> items) {
StringBuilder sb = new StringBuilder();
for (DavResource item : items) if (removeExt(item).equals(removeExt(res))) sb.append("~~~").append(item.getName()).append("@@@").append(getExt(item)).append("@@@").append(drive.getName() + item.getPath());
return sb.length() > 0 ? sb.toString() : findSubs(drive, items);
}
private String findSubs(Drive drive, List<DavResource> items) {
StringBuilder sb = new StringBuilder();
for (DavResource item : items) sb.append("~~~").append(item.getName()).append("@@@").append(getExt(item)).append("@@@").append(drive.getName() + item.getPath());
return sb.toString();
}
private List<Sub> getSub(String[] ids) {
List<Sub> sub = new ArrayList<>();
for (String text : ids) {
if (!text.contains("@@@")) continue;
String[] split = text.split("@@@");
String name = split[0];
String ext = split[1];
String url = getProxyUrl(split[2]);
sub.add(Sub.create().name(name).ext(ext).url(url));
}
return sub;
}
private String getProxyUrl(String url) {
return Proxy.getUrl() + "?do=webdav&url=" + url;
}
public static Object[] vod(Map<String, String> params) throws IOException {
String url = params.get("url");
String key = url.contains("/") ? url.substring(0, url.indexOf("/")) : url;
url = url.substring(key.length());
Drive drive = getDrive(key);
Object[] result = new Object[3];
result[0] = 200;
result[1] = "application/octet-stream";
result[2] = drive.getWebdav().get(drive.getHost() + url);
return result;
}
}

View File

@@ -0,0 +1,151 @@
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.net.OkHttp;
import com.github.catvod.utils.Json;
import com.github.catvod.utils.Util;
import com.google.gson.JsonObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author zhixc
*/
public class Wogg extends Ali {
private final String siteUrl = "https://tvfan.xxooo.cf";
private final Pattern regexCategory = Pattern.compile("/vodtype/(\\w+).html");
private final Pattern regexPageTotal = Pattern.compile("\\$\\(\"\\.mac_total\"\\)\\.text\\('(\\d+)'\\);");
private Map<String, String> getHeader() {
Map<String, String> header = new HashMap<>();
header.put("User-Agent", Util.CHROME);
return header;
}
@Override
public void init(Context context, String extend) {
JsonObject ext = Json.safeObject(extend);
super.init(context, ext.has("token") ? ext.get("token").getAsString() : "");
}
@Override
public String homeContent(boolean filter) {
List<Class> classes = new ArrayList<>();
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeader()));
Elements elements = doc.select(".nav-link");
for (Element e : elements) {
Matcher mather = regexCategory.matcher(e.attr("href"));
if (mather.find()) {
classes.add(new Class(mather.group(1), e.text().trim()));
}
}
return Result.string(classes, parseVodListFromDoc(doc));
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
String[] urlParams = new String[]{tid, "", "", "", "", "", "", "", pg, "", "", ""};
if (extend != null && extend.size() > 0) {
for (String key : extend.keySet()) {
urlParams[Integer.parseInt(key)] = extend.get(key);
}
}
Document doc = Jsoup.parse(OkHttp.string(String.format("%s/index.php/vodshow/%s.html", siteUrl, String.join("-", urlParams)), getHeader()));
int page = Integer.parseInt(pg), limit = 72, total = 0;
Matcher matcher = regexPageTotal.matcher(doc.html());
if (matcher.find()) total = Integer.parseInt(matcher.group(1));
int count = total <= limit ? 1 : ((int) Math.ceil(total / (double) limit));
return Result.get().vod(parseVodListFromDoc(doc)).page(page, count, limit, total).string();
}
private List<Vod> parseVodListFromDoc(Document doc) {
List<Vod> list = new ArrayList<>();
Elements elements = doc.select(".module-item");
for (Element e : elements) {
String vodId = e.selectFirst(".video-name a").attr("href");
String vodPic = e.selectFirst(".module-item-pic > img").attr("data-src");
String vodName = e.selectFirst(".video-name").text();
String vodRemarks = e.selectFirst(".module-item-text").text();
list.add(new Vod(vodId, vodName, vodPic, vodRemarks));
}
return list;
}
@Override
public String detailContent(List<String> ids) throws Exception {
String vodId = ids.get(0);
Document doc = Jsoup.parse(OkHttp.string(siteUrl + vodId, getHeader()));
Vod item = new Vod();
item.setVodId(vodId);
item.setVodName(doc.selectFirst(".video-info-header > .page-title").text());
item.setVodPic(doc.selectFirst(".module-item-pic img").attr("data-src"));
item.setVodArea(doc.select(".video-info-header a.tag-link").last().text());
item.setTypeName(String.join(",", doc.select(".video-info-header div.tag-link a").eachText()));
List<String> shareLinks = doc.select(".module-row-text").eachAttr("data-clipboard-text");
for (int i = 0; i < shareLinks.size(); i++) shareLinks.set(i, shareLinks.get(i).trim());
item.setVodPlayFrom(detailContentVodPlayFrom(shareLinks));
item.setVodPlayUrl(detailContentVodPlayUrl(shareLinks));
Elements elements = doc.select(".video-info-item");
for (Element e : elements) {
String title = e.previousElementSibling().text();
if (title.contains("导演")) {
item.setVodDirector(String.join(",", e.select("a").eachText()));
} else if (title.contains("主演")) {
item.setVodActor(String.join(",", e.select("a").eachText()));
} else if (title.contains("年代")) {
item.setVodYear(e.selectFirst("a").text().trim());
} else if (title.contains("备注")) {
item.setVodRemarks(e.text().trim());
} else if (title.contains("剧情")) {
item.setVodContent(e.selectFirst(".sqjj_a").text().replace("[收起部分]", "").trim());
}
}
return Result.string(item);
}
@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);
}
private String searchContent(String key, String pg) {
String searchURL = siteUrl + String.format("/index.php/vodsearch/%s----------%s---.html", URLEncoder.encode(key), pg);
String html = OkHttp.string(searchURL, getHeader());
Elements items = Jsoup.parse(html).select(".module-search-item");
List<Vod> list = new ArrayList<>();
for (Element item : items) {
String vodId = item.select(".video-serial").attr("href");
String name = item.select(".video-serial").attr("title");
String pic = item.select(".module-item-pic > img").attr("data-src");
String remark = item.select(".video-tag-icon").text();
list.add(new Vod(vodId, name, pic, remark));
}
return Result.string(list);
}
}

View File

@@ -0,0 +1,345 @@
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().size() > 0) {
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().size() == 0) {
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.size() == 0 && 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().length() > 0) headers.put("User-Agent", rule.getPlayUa());
if (rule.getPlayReferer().length() > 0) 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());
}
}

View File

@@ -0,0 +1,34 @@
package com.github.catvod.spider;
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.size() > 0) {
for (String key : extend.keySet()) {
String value = extend.get(key);
if (value.length() > 0) {
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;
}
}

View File

@@ -0,0 +1,196 @@
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.length() > 0 && playerConfigJs.length() > 0) { // 嘗試通過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.length() > 0) {
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().length() > 0) headers.put("User-Agent", rule.getPlayUa());
if (rule.getPlayReferer().length() > 0) 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);
}
}

Some files were not shown because too many files have changed in this diff Show More