Compare commits

...

167 Commits

Author SHA1 Message Date
github-actions 3b83ebef35 update spider jar and json 2025-12-15 06:40:41 +00:00
lushunming 9d67a07a84 uc刷新access token 2025-12-15 14:37:45 +08:00
github-actions 12ac9fd628 update spider jar and json 2025-12-15 05:32:35 +00:00
lushunming 84a3f4399b uc刷新access token 2025-12-15 13:29:55 +08:00
github-actions e467112e39 update spider jar and json 2025-12-15 03:26:32 +00:00
lushunming 6b0b4b6a74 uc刷新access token 2025-12-15 11:23:48 +08:00
github-actions 6c0841e4c5 update spider jar and json 2025-12-13 01:30:04 +00:00
lushunming ffffe95c47 Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-12-13 09:11:32 +08:00
lushunming d1bb29a314 cloud异步 2025-12-13 09:11:08 +08:00
github-actions 858579c462 update spider jar and json 2025-12-13 00:23:15 +00:00
lushunming d280d770bb cloud异步 2025-12-13 08:09:34 +08:00
github-actions d488a00eab update spider jar and json 2025-12-12 08:36:45 +00:00
lushunming 2e028809e8 Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-12-12 16:34:13 +08:00
lushunming 3002b235f9 cloud异步 2025-12-12 16:33:28 +08:00
github-actions c28917b071 update spider jar and json 2025-12-12 08:27:15 +00:00
lushunming 61dcb1d4f3 cloud异步 2025-12-12 16:24:41 +08:00
github-actions 1c3929d920 update spider jar and json 2025-12-12 08:18:19 +00:00
lushunming 4b66ac8c19 Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-12-12 16:15:48 +08:00
lushunming 68b72532e8 cloud异步 2025-12-12 16:15:37 +08:00
github-actions 58ccf67b2d update spider jar and json 2025-12-09 07:45:52 +00:00
lushunming cb27d8b6d0 Merge remote-tracking branch 'origin/multiThread' into multiThread
# Conflicts:
#	json/index.json
2025-12-09 15:43:03 +08:00
lushunming ed7963420f action 2025-12-09 15:42:50 +08:00
github-actions 6e56986b19 update spider jar and json 2025-12-09 07:30:22 +00:00
lushunming 661727b7f0 Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-12-09 15:27:48 +08:00
lushunming eacd5fff22 action 2025-12-09 15:27:38 +08:00
github-actions 4a57536a3a update spider jar and json 2025-12-09 07:25:38 +00:00
lushunming d31a069b85 action 2025-12-09 15:22:57 +08:00
github-actions d0f6e7b601 update spider jar and json 2025-12-09 07:09:59 +00:00
github-actions f90f88cfc5 update spider jar and json 2025-12-09 07:01:46 +00:00
github-actions 1ed471cb16 update spider jar and json 2025-12-09 06:48:25 +00:00
lushunming 514d49f2f5 Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-12-09 14:45:54 +08:00
lushunming 5dd19bc9e9 action 2025-12-09 14:45:44 +08:00
github-actions 77196c2037 update spider jar and json 2025-12-09 06:35:04 +00:00
lushunming 4f56a6f6d7 Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-12-09 14:32:12 +08:00
lushunming 0a90b60ce1 action 2025-12-09 14:32:01 +08:00
github-actions f80c8ab7d1 update spider jar and json 2025-12-09 06:29:29 +00:00
lushunming f0624a9014 Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-12-09 14:26:48 +08:00
lushunming 5130a64ba6 action 2025-12-09 14:26:35 +08:00
github-actions 235dfd716d update spider jar and json 2025-12-09 06:23:16 +00:00
lushunming cf427b4224 Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-12-09 14:20:41 +08:00
lushunming e5833f43a9 action 2025-12-09 14:20:31 +08:00
github-actions 8e0d555073 update spider jar and json 2025-12-09 06:19:02 +00:00
lushunming c5e74b576a Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-12-09 14:16:10 +08:00
lushunming d671e7090b action 2025-12-09 14:14:31 +08:00
github-actions 2b0bdcf9ce update spider jar and json 2025-12-09 06:01:04 +00:00
lushunming c40988d997 action 2025-12-09 13:56:38 +08:00
lushunming 976fc63f4d action 2025-12-09 13:50:41 +08:00
github-actions ebbe5360c3 update spider jar and json 2025-12-09 05:48:02 +00:00
lushunming 354d818fbf action 2025-12-09 13:44:40 +08:00
github-actions 00db8e8173 update spider jar and json 2025-12-09 05:31:10 +00:00
lushunming 4312efd414
Update genJar.yml 2025-12-09 13:28:36 +08:00
github-actions 59b48044b7 update spider jar and json 2025-12-09 03:52:15 +00:00
lushunming da79d74b06
Update genJar.yml 2025-12-09 11:49:46 +08:00
github-actions 271c56767c update spider jar and json 2025-12-09 03:48:12 +00:00
lushunming 96272da9fc Merge remote-tracking branch 'origin/multiThread' into multiThread
# Conflicts:
#	json/index.json
2025-12-09 11:45:19 +08:00
lushunming 2e95dbcc9c quark根据文件名判断是否是视频 2025-12-09 11:44:55 +08:00
github-actions 6ec990b2f1 update spider jar and json 2025-12-08 03:03:29 +00:00
lushunming 537a84cc5b quark根据文件名判断是否是视频 2025-12-08 11:00:47 +08:00
github-actions bbb4d37922 update spider jar and json 2025-12-08 02:05:59 +00:00
lushunming b753ae7fa4 魔数前增加恶意头检测 2025-12-08 10:03:25 +08:00
lushunming 4204acc672 Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-12-08 09:59:00 +08:00
lushunming 3540ecc3aa 魔数前增加恶意头检测 2025-12-08 09:58:45 +08:00
github-actions af044f37c4 update spider jar and json 2025-12-05 02:48:59 +00:00
lushunming ed88ad03cf 百度保证每次使用只会清理一次文件夹 2025-12-05 10:46:20 +08:00
github-actions 2b88bf1c9d update spider jar and json 2025-12-01 02:27:05 +00:00
lushunming b96fd2e894 Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-12-01 10:24:35 +08:00
lushunming 2d0ad541fc uc和quark 优化 2025-12-01 09:57:30 +08:00
github-actions 9096420bac update spider jar and json 2025-11-27 03:32:14 +00:00
lushunming f107976989 Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-11-27 11:29:50 +08:00
lushunming 089113fbe4 uc和quark空指针 2025-11-27 11:29:35 +08:00
github-actions 7e26202bec update spider jar and json 2025-11-27 03:23:37 +00:00
lushunming 8a8991f03f Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-11-27 11:21:07 +08:00
lushunming a0bd2a128a uc和quark空指针 2025-11-27 11:16:17 +08:00
github-actions 394601dc07 update spider jar and json 2025-11-27 02:49:00 +00:00
lushunming 69ae330c7a uc和quark空指针 2025-11-27 10:46:06 +08:00
github-actions 608e1b51a1 update spider jar and json 2025-11-25 03:00:57 +00:00
lushunming 58e158be75 Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-11-25 10:58:25 +08:00
lushunming bb5c605425 格式美化 2025-11-25 10:58:16 +08:00
github-actions cff732fdac update spider jar and json 2025-11-25 01:11:11 +00:00
lushunming 448f2cf2c3 SeedHub 2025-11-25 09:08:19 +08:00
github-actions 2886403c73 update spider jar and json 2025-11-25 00:50:55 +00:00
lushunming 104a9c9b8a Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-11-25 08:48:19 +08:00
lushunming 36bcf9fbf1 SeedHub 2025-11-25 08:48:08 +08:00
github-actions 20d7bed2f9 update spider jar and json 2025-11-24 00:30:08 +00:00
lushunming b5e302aa99 Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-11-24 08:27:36 +08:00
lushunming bc672c7965 分块调节 2025-11-24 08:26:41 +08:00
github-actions 39248d9a0a update spider jar and json 2025-11-18 07:39:40 +00:00
lushunming 08edebc431 Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-11-18 15:37:03 +08:00
lushunming 12b675da04 代理视频的异常捕获 2025-11-18 14:42:01 +08:00
github-actions 93a5981c39 update spider jar and json 2025-11-17 00:18:49 +00:00
lushunming 240e9fb3b0 Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-11-17 08:16:03 +08:00
lushunming 26d525f436 代理视频的异常捕获 2025-11-17 08:15:51 +08:00
github-actions 67a6cc2aa6 update spider jar and json 2025-11-15 01:29:07 +00:00
lushunming 565c92ce63 Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-11-15 09:23:39 +08:00
lushunming 7f49ff239f tg搜 2025-11-15 09:19:09 +08:00
github-actions 0cdff801a4 update spider jar and json 2025-11-06 23:30:44 +00:00
lushunming a3386d343a Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-11-07 07:27:55 +08:00
lushunming 52347dd0fd 网盘优化 2025-11-07 07:24:26 +08:00
github-actions 3043f08f4c update spider jar and json 2025-11-05 13:27:17 +00:00
lushunming ecd1467d33 Merge remote-tracking branch 'origin/multiThread' into multiThread
# Conflicts:
#	jar/custom_spider.jar
#	jar/custom_spider.jar.md5
#	json/index.json
2025-11-05 21:24:20 +08:00
lushunming 28a473a084 删除代码 2025-11-05 16:06:10 +08:00
github-actions cf45ab210c update spider jar and json 2025-11-03 08:10:09 +00:00
lushunming 4fb678c4bf Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-11-03 16:07:46 +08:00
lushunming 85bff735dd 优化下载 2025-11-03 16:07:31 +08:00
github-actions 12832816fe update spider jar and json 2025-11-03 08:04:30 +00:00
lushunming d6ee012dff Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-11-03 16:01:51 +08:00
lushunming 1e7e846c5b 优化下载 2025-11-03 16:01:40 +08:00
github-actions 45b5dcdfba update spider jar and json 2025-11-03 07:22:03 +00:00
lushunming bc388773d0 Merge remote-tracking branch 'origin/multiThread' into multiThread 2025-11-03 15:19:41 +08:00
lushunming 03276cf9dd 构建问题 2025-11-03 15:14:15 +08:00
github-actions 537583e59b update spider jar and json 2025-11-03 07:08:09 +00:00
lushunming 9c00eb51d5 构建问题 2025-11-03 15:05:37 +08:00
lushunming 683621c729 构建问题 2025-11-03 14:56:03 +08:00
lushunming 5c4b3c3ab4 构建问题 2025-11-03 14:48:49 +08:00
lushunming 4e7ba34997 构建问题 2025-11-03 14:24:40 +08:00
lushunming ab6b0f030c 构建问题 2025-11-03 14:23:31 +08:00
lushunming 7aaec80904 构建问题 2025-11-03 14:21:00 +08:00
lushunming 986f2009f7 构建问题 2025-11-03 14:20:13 +08:00
lushunming 8ac4501b1d 构建问题 2025-11-03 14:18:42 +08:00
lushunming 49b2c7c1e5 构建问题 2025-11-03 14:10:20 +08:00
lushunming c96d3dcca1 天翼问题修复 2025-11-03 11:49:12 +08:00
lushunming b47e9b12ac 123问题修复 2025-10-30 16:08:43 +08:00
lushunming 2d4d690431 Qupans 2025-10-30 10:48:12 +08:00
lushunming aabb9d7698 Qupans 2025-10-24 14:02:58 +08:00
lushunming 001f56c842 百度bug 2025-10-21 16:20:57 +08:00
lushunming e38debf3c1 123盘expire 2025-10-21 13:46:29 +08:00
lushunming 586b4919c7 123盘expire 2025-10-21 11:50:17 +08:00
lushunming 35ab144e27 123盘基本完成 2025-10-21 10:52:14 +08:00
lushunming 0fd1d6df7c 123盘基本完成 2025-10-21 10:44:20 +08:00
lushunming fc1403c4a8 123盘测试 2025-10-21 10:37:58 +08:00
lushunming debbcad7be 123盘测试 2025-10-21 10:28:57 +08:00
lushunming 3449968aa8 123盘测试 2025-10-21 10:18:29 +08:00
lushunming 4e873ca2a9 123盘测试 2025-10-21 10:11:40 +08:00
lushunming 09324a563d 123盘测试 2025-10-21 09:53:59 +08:00
lushunming de261ec674 123盘测试 2025-10-21 09:48:36 +08:00
lushunming 62e00061fd 123盘测试 2025-10-21 09:29:57 +08:00
lushunming 58b9479dc4 123盘测试 2025-10-21 09:22:44 +08:00
lushunming 9f224ab326 123盘测试 2025-10-21 08:55:41 +08:00
lushunming 4f31d98da5 123盘测试 2025-10-21 08:34:32 +08:00
lushunming d15d2874e1 123盘测试 2025-10-21 07:44:06 +08:00
lushunming 445810ddc0 123盘测试 2025-10-20 15:45:55 +08:00
lushunming 1e2766edcb 123盘测试 2025-10-20 15:30:09 +08:00
lushunming c1443930da 123盘测试 2025-10-20 15:13:45 +08:00
lushunming 228cd96bf3 123盘测试 2025-10-20 14:34:55 +08:00
lushunming f9fee85737 123盘测试 2025-10-20 14:25:56 +08:00
lushunming 528376b09e 123盘测试 2025-10-20 14:15:05 +08:00
lushunming 96f1dc0757 123盘测试 2025-10-20 14:08:10 +08:00
lushunming 5387abbd61 123盘测试 2025-10-20 13:38:55 +08:00
lushunming 05685aab0b 123盘测试 2025-10-20 11:55:45 +08:00
lushunming a87f9ca53d 123盘测试 2025-10-20 11:43:08 +08:00
lushunming 6de76787e6 123盘测试 2025-10-20 11:04:20 +08:00
lushunming d847d8ff49 123盘测试 2025-10-20 10:41:03 +08:00
lushunming 3ffe3e459d 123盘测试 2025-10-20 10:19:56 +08:00
lushunming 80fc42168f 123盘测试 2025-10-20 09:11:51 +08:00
lushunming f706fa34af 123盘测试 2025-10-20 09:09:08 +08:00
lushunming 2feb20da84 123盘测试 2025-10-20 08:02:27 +08:00
lushunming f7b13b1b21 百度扫码登录优化 2025-10-17 13:24:55 +08:00
lushunming 932e6ebab5 百度扫码登录优化 2025-10-17 11:52:46 +08:00
lushunming bb57f23567 百度扫码登录 2025-10-17 11:03:25 +08:00
lushunming 69555118cb 百度扫码登录 2025-10-17 10:51:19 +08:00
lushunming e67b2d874a 百度扫码登录 2025-10-17 10:20:18 +08:00
lushunming 9afcc6e32a Rename .java to .kt 2025-10-17 10:20:16 +08:00
lushunming 1e139be660 百度扫码登录 2025-10-17 10:00:23 +08:00
lushunming 08b5acbf0a TGsou百度 2025-10-15 11:35:50 +08:00
lushunming 33a100d5e6 TGsou百度 2025-10-15 11:27:13 +08:00
lushunming ccf4c0b068 TGsou百度 2025-10-15 08:53:26 +08:00
lushunming c9ebf3c7d7 bd网盘完成 2025-10-14 17:06:24 +08:00
57 changed files with 3819 additions and 9194 deletions

View File

@ -1,27 +1,80 @@
name: Spider Jar Gen CI name: Spider Jar Gen CI
on: workflow_dispatch on:
push:
branches: [ "multiThread" ]
workflow_dispatch:
jobs: jobs:
build: build:
runs-on: windows-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: set up JDK 21 - name: Set up JDK 21
uses: actions/setup-java@v2 uses: actions/setup-java@v5
with: with:
java-version: '21' java-version: '21'
distribution: 'adopt' distribution: 'jetbrains'
cache: gradle cache: gradle
- name: Build with Gradle - name: Grant execute permission to gradlew
run: ./build.bat ec run: chmod +x ./gradlew
- name: Update spider jar - name: Build with Gradle
uses: EndBug/add-and-commit@v7 run: ./gradlew app:buildCustomSpiderJar
with:
default_author: github_actions
message: 'update spider jar' - name: Add & Commit
add: "['./jar/custom_spider.jar', './jar/custom_spider.jar.md5']" uses: EndBug/add-and-commit@v9.1.4
with:
default_author: github_actions
message: 'update spider jar and json'
add: "['./jar/custom_spider.jar', './jar/custom_spider.jar.md5','./json/index.json']"
- name: upload json
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
with:
# ftp server
server: ftpupload.net
# ftp username
username: mseet_40633048
# ftp password
password: ${{ secrets.FTP_PWD }}
# Server port to connect to (read your web hosts docs)
port: 21
# protocol to deploy with - ftp, ftps, or ftps-legacy
protocol: ftp
# Folder to upload from, must end with trailing slash /
local-dir: ${{ github.workspace }}/json/
# Path to upload to on the server. Must end with trailing slash /
server-dir: htdocs/json/
# Deletes ALL contents of server-dir, even items in excluded with exclude argument
dangerous-clean-slate: true
exclude: |
**/js/**
- name: upload jar
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
with:
# ftp server
server: ftpupload.net
# ftp username
username: mseet_40633048
# ftp password
password: ${{ secrets.FTP_PWD }}
# Server port to connect to (read your web hosts docs)
port: 21
# protocol to deploy with - ftp, ftps, or ftps-legacy
protocol: ftp
# Folder to upload from, must end with trailing slash /
local-dir: ${{ github.workspace }}/jar/
# Path to upload to on the server. Must end with trailing slash /
server-dir: htdocs/jar/
# Deletes ALL contents of server-dir, even items in excluded with exclude argument
dangerous-clean-slate: true

View File

@ -96,5 +96,128 @@ dependencies {
// implementation(ext: 'aar', name: 'quickjs', group: 'fongmi', version: 'release') // implementation(ext: 'aar', name: 'quickjs', group: 'fongmi', version: 'release')
// api 'wang.harlon.quickjs:wrapper-android:2.0.0' // api 'wang.harlon.quickjs:wrapper-android:2.0.0'
task buildCustomSpiderJar {
doLast {
def workDir = file("${projectDir}").parentFile
def spiderJarDir = file("$workDir/jar/spider.jar")
def smaliOutputDir = file("$workDir/jar/Smali_classes")
def customSpiderJar = file("$workDir/jar/custom_spider.jar")
def baksmaliJar = file("$workDir/jar/3rd/baksmali-2.5.2.jar")
def apktoolJar = file("$workDir/jar/3rd/apktool_2.4.1.jar")
def classesDex = file("$workDir/app/build/intermediates/dex/release/minifyReleaseWithR8/classes.dex")
def indexJsonFile = file("$workDir/json/index.json")
//
if (customSpiderJar.exists()) {
customSpiderJar.delete()
}
if (smaliOutputDir.exists()) {
delete(smaliOutputDir)
}
// 使 baksmali classes.dex
javaexec {
main = "-jar"
args = [
baksmaliJar.absolutePath,
"d",
classesDex.absolutePath,
"-o",
smaliOutputDir.absolutePath
]
}
// spider.jar
def targetDirs = [
file("$spiderJarDir/smali/com/github/catvod/spider"),
file("$spiderJarDir/smali/com/github/catvod/parser"),
file("$spiderJarDir/smali/com/github/catvod/js")
]
targetDirs.each { dir ->
if (dir.exists()) {
delete(dir)
}
}
//
def targetBaseDir = file("$spiderJarDir/smali/com/github/catvod")
if (!targetBaseDir.exists()) {
targetBaseDir.mkdirs()
}
//
def sourceDirs = [
file("$smaliOutputDir/com/github/catvod/spider"),
file("$smaliOutputDir/com/github/catvod/parser"),
file("$smaliOutputDir/com/github/catvod/js")
]
def targetPaths = [
file("$targetBaseDir/spider"),
file("$targetBaseDir/parser"),
file("$targetBaseDir/js")
]
sourceDirs.eachWithIndex { src, idx ->
if (src.exists()) {
copy {
from src
into targetPaths[idx]
}
delete(src)
}
}
// 使 apktool
javaexec {
main = "-jar"
args = [
apktoolJar.absolutePath,
"b",
spiderJarDir.absolutePath,
"-c"
]
}
// dex.jar custom_spider.jar
def distJar = file("$spiderJarDir/dist/dex.jar")
if (distJar.exists()) {
copy {
from distJar
into file("$workDir/jar")
rename "dex.jar", "custom_spider.jar"
}
}
// MD5
def md5File = file("$workDir/jar/custom_spider.jar.md5")
def md5 = java.security.MessageDigest.getInstance("MD5").digest(customSpiderJar.bytes).encodeHex().toString()
md5File.text = md5
// index.json md5
def indexJsonContent = indexJsonFile.text
// 使 spider MD5
def updatedContent = indexJsonContent.replaceAll(
/("spider":\s*"[^;]+;md5;)[^"]+"/,
'$1' + md5 + '"'
)
//
indexJsonFile.write(updatedContent)
//
delete(
"$spiderJarDir/build",
"$spiderJarDir/smali",
"$spiderJarDir/dist",
smaliOutputDir
)
}
}
tasks.named('buildCustomSpiderJar') {
dependsOn 'assembleRelease'
}
} }

View File

@ -1,37 +0,0 @@
package com.github.catvod.api;
import com.github.catvod.bean.BD.Cache;
import com.github.catvod.bean.yun.User;
import com.github.catvod.utils.Path;
import java.io.File;
public class BaiDuYunHandler {
private final Cache cache;
public File getCache() {
return Path.tv("bd");
}
private BaiDuYunHandler() {
cache = Cache.objectFrom(Path.read(getCache()));
}
private static class Loader {
static volatile BaiDuYunHandler INSTANCE = new BaiDuYunHandler();
}
public static BaiDuYunHandler get() {
return BaiDuYunHandler.Loader.INSTANCE;
}
public String getToken() {
User user = cache.getUser();
return user.getCookie();
//return "cGM6MTg4OTY3ODE2MDE6eTM1Tjd1dG58MXxSQ1N8MTc1NDQ2OTgwNzEyOXxzMlN0T1VEV3lOVmF5V3pNbGFfM2tJbVp1ZmlqSHBqaEhTSzVyNHZqVXNRLmlhV3loSUxHNDFkMUI5N1BqXzhWN0dtVWtKLnBTclhpNGpZU1EuTGZWMTV3MVFoZmNpcEVoZkxUV2tvYjB0bkFTYV9RTUhhaHhveWx6YkdmcEhQdjNCS1lrbnp1LkxaWDdKOE40YkNNRjkzT3piNmx2Y0d3TWdVUkl5b18ubVUt";
}
}

View File

@ -0,0 +1,262 @@
package com.github.catvod.api
import android.app.AlertDialog
import android.content.DialogInterface
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.text.TextUtils
import android.view.Gravity
import android.widget.FrameLayout
import android.widget.ImageView
import com.github.catvod.bean.BD.Cache
import com.github.catvod.bean.yun.User
import com.github.catvod.crawler.SpiderDebug
import com.github.catvod.net.OkHttp
import com.github.catvod.spider.Init
import com.github.catvod.utils.*
import okhttp3.Headers
import okhttp3.Request
import org.apache.commons.lang3.StringEscapeUtils
import java.io.File
import java.io.IOException
import java.io.UnsupportedEncodingException
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit
import kotlin.concurrent.Volatile
class BaiDuYunHandler private constructor() {
private val cache: Cache
private var service: ScheduledExecutorService? = null
private var dialog: AlertDialog? = null
private var cookies = ""
private val headers = mapOf(
"User-Agent" to "Mozilla/5.0 (Linux; Android 12; SM-X800) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.40 Safari/537.36",
"Accept" to "application/json, text/plain, */*",
"Content-Type" to "application/x-www-form-urlencoded",
"Origin" to "https://pan.baidu.com",
"Referer" to "https://pan.baidu.com/"
)
fun getCache(): File {
return Path.tv("bd")
}
init {
cache = Cache.objectFrom(Path.read(getCache()))
}
private object Loader {
@Volatile
var INSTANCE: BaiDuYunHandler = BaiDuYunHandler()
}
val token: String
get() {
val user: User = cache.getUser()
return user.getCookie()
//return "cGM6MTg4OTY3ODE2MDE6eTM1Tjd1dG58MXxSQ1N8MTc1NDQ2OTgwNzEyOXxzMlN0T1VEV3lOVmF5V3pNbGFfM2tJbVp1ZmlqSHBqaEhTSzVyNHZqVXNRLmlhV3loSUxHNDFkMUI5N1BqXzhWN0dtVWtKLnBTclhpNGpZU1EuTGZWMTV3MVFoZmNpcEVoZkxUV2tvYjB0bkFTYV9RTUhhaHhveWx6YkdmcEhQdjNCS1lrbnp1LkxaWDdKOE40YkNNRjkzT3piNmx2Y0d3TWdVUkl5b18ubVUt";
}
companion object {
@JvmStatic
fun get(): BaiDuYunHandler {
return Loader.INSTANCE
}
}
@Throws(java.lang.Exception::class)
fun startScan(): ByteArray {
val result = loginByQRCode()
// Step 2: Get QR Code
val byteStr: ByteArray = downloadQRCode(result["qrCodeImageUrl"]!!);
Init.run(Runnable { showQRCode(byteStr) })
// Step 3: Check login status
Init.execute(Runnable {
startService(
result["sign"]!!
)
})
return byteStr
}
@Throws(IOException::class)
fun downloadQRCode(url: String): ByteArray {
val headers: MutableMap<String?, String?> = HashMap<String?, String?>()
headers.put(
"user-agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36"
)
val request = Request.Builder().url(url).headers(Headers.of(headers)).build()
val response = OkHttp.newCall(request)
if (response.code() == 200) {
return response.body()!!.bytes()
}
return "".toByteArray()
}
fun loginByQRCode(): Map<String, String> {
return try {
// 获取登录二维码
val timestamp = System.currentTimeMillis()
val qrCodeUrl = "https://passport.baidu.com/v2/api/getqrcode?lp=pc&_=$timestamp"
val response = OkHttp.string(qrCodeUrl, emptyMap(), headers)
val json = Json.safeObject(response)
if (json["errno"].asInt != 0) {
return mapOf("error" to "获取登录二维码错误, code: ${json["errno"].asInt}")
}
val sign = json["sign"].asString
val imgurl = json["imgurl"].asString
val qrCodeImageUrl = "https://$imgurl"
val qrLoginUrl =
"https://wappass.baidu.com/wp/?qrlogin&t=$timestamp" + "&error=0&sign=$sign&cmd=login&lp=pc&tpl=netdisk&uaonly=" + "&client_id=&adapter=3&client=&qrloginfrom=pc&wechat=0&traceid="
// 返回二维码信息供前端显示
val result = mapOf(
"qrCodeImageUrl" to qrCodeImageUrl, "qrLoginUrl" to qrLoginUrl, "sign" to sign
)
result
} catch (e: Exception) {
mapOf("error" to "获取二维码失败: ${e.message}")
}
}
fun checkQRLoginStatus(sign: String): Map<String, Any> {
return try {
val timestamp = System.currentTimeMillis()
val checkUrl =
"https://passport.baidu.com/channel/unicast?channel_id=$sign" + "&tpl=netdisk&callback=&apiver=v3&tt=$timestamp&_=$timestamp"
val response = OkHttp.string(checkUrl, emptyMap(), headers)
val cleanResponse = response.trim('(', ' ', '\n', ')')
val json = Json.safeObject(cleanResponse)
if (json["errno"].asInt == 0) {
SpiderDebug.log("百度扫码成功")
val channelV = json["channel_v"].asString
val channelJson = Json.safeObject(channelV)
if (channelJson["status"].asInt == 0) {
val bduss = channelJson["v"].asString
// 执行登录
val loginTimestamp = System.currentTimeMillis()
val loginUrl =
"https://passport.baidu.com/v3/login/main/qrbdusslogin?" + "v=$loginTimestamp&bduss=$bduss&u=&loginVersion=v4&qrcode=1&tpl=netdisk&apiver=v3" + "&tt=$loginTimestamp&traceid=&callback=bd__cbs__cupstt"
val loginResponse = OkHttp.get(loginUrl, emptyMap(), headers)
val cleanLoginResponse = loginResponse.body.substringAfter("(").substringBeforeLast(")")
val loginJson = Json.safeObject(StringEscapeUtils.unescapeHtml4(cleanLoginResponse))
if (loginJson.has("errInfo") && loginJson["errInfo"].asJsonObject["no"].asString == "0") {
// 登录成功设置cookie
SpiderDebug.log("百度登录成功设置cookie${bduss}")
cookies = "BDUSS=$bduss"
cookies = generateCooike(loginResponse.resp["set-cookie"])
if (cookies.isNotEmpty()) {
cache.setUser(User.objectFrom(this.cookies))
//停止检验线程,关闭弹窗
stopService()
Notify.show("百度登录成功")
}
mapOf("success" to true, "bduss" to bduss)
} else {
mapOf("error" to "登录失败: $cleanLoginResponse")
}
} else {
mapOf("status" to channelJson["status"].asInt)
}
} else {
mapOf("errno" to json["errno"].asInt)
}
} catch (e: Exception) {
mapOf("error" to "检查登录状态失败: ${e.message}")
}
}
fun generateCooike(cookies: List<String>?): String {
if (cookies == null || cookies.isEmpty()) {
return ""
}
val cookieList: MutableList<String?> = ArrayList<String?>()
for (cookie in cookies) {
cookieList.add(cookie.split(";".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0])
}
return TextUtils.join(";", cookieList)
}
/**
* 显示qrcode
*
* @param base64Str
*/
fun showQRCode(bytes: ByteArray) {
try {
val size = ResUtil.dp2px(240)
val params = FrameLayout.LayoutParams(size, size)
val image = ImageView(Init.context())
image.setScaleType(ImageView.ScaleType.CENTER_CROP)
image.setImageBitmap(QRCode.Bytes2Bimap(bytes))
val frame = FrameLayout(Init.context())
params.gravity = Gravity.CENTER
frame.addView(image, params)
dialog = AlertDialog.Builder(Init.getActivity()).setView(frame)
.setOnCancelListener(DialogInterface.OnCancelListener { dialog: DialogInterface? -> this.dismiss(dialog) })
.setOnDismissListener(DialogInterface.OnDismissListener { dialog: DialogInterface? ->
this.dismiss(dialog)
}).show()
dialog!!.getWindow()!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
Notify.show("请使用百度网盘App扫描二维码")
} catch (ignored: java.lang.Exception) {
}
}
private fun dismiss() {
try {
dialog?.dismiss()
} catch (ignored: java.lang.Exception) {
}
}
private fun dismiss(dialog: DialogInterface?) {
stopService()
}
private fun stopService() {
service?.shutdownNow()
Init.run(Runnable { this.dismiss() })
}
fun startService(sign: String) {
SpiderDebug.log("----start 百度 token service")
service = Executors.newScheduledThreadPool(1)
service?.scheduleWithFixedDelay(Runnable {
try {
SpiderDebug.log("----check百度tatus中")
checkQRLoginStatus(sign)
} catch (e: UnsupportedEncodingException) {
throw RuntimeException(e)
}
}, 3, 3, TimeUnit.SECONDS)
}
}

View File

@ -9,6 +9,7 @@ import com.github.catvod.utils.ProxyServer.buildProxyUrl
import com.github.catvod.utils.Util import com.github.catvod.utils.Util
import com.github.catvod.utils.Util.MEDIA import com.github.catvod.utils.Util.MEDIA
import com.google.gson.JsonObject import com.google.gson.JsonObject
import java.net.URLEncoder
import java.util.* import java.util.*
object BaiduDrive { object BaiduDrive {
@ -22,6 +23,8 @@ object BaiduDrive {
"Referer" to "https://pan.baidu.com/" "Referer" to "https://pan.baidu.com/"
) )
//是否删除过文件标志
private var deleteTag = 0;
private val saveDirName = "TVBOX_BD" private val saveDirName = "TVBOX_BD"
private var cookies = BaiDuYunHandler.get().token private var cookies = BaiDuYunHandler.get().token
@ -37,6 +40,12 @@ object BaiduDrive {
} }
fun processShareLinks(urls: List<String>): Pair<List<String>, List<String>> { fun processShareLinks(urls: List<String>): Pair<List<String>, List<String>> {
//首先确保cookie不为空
if (cookies.isEmpty()) {
BaiDuYunHandler.get().startScan()
cookies = BaiDuYunHandler.get().token
}
if (urls.isEmpty()) return emptyList<String>() to emptyList() if (urls.isEmpty()) return emptyList<String>() to emptyList()
@ -157,7 +166,8 @@ object BaiduDrive {
// 处理items // 处理items
items.forEach { item -> items.forEach { item ->
if (item.asJsonObject["isdir"].asInt == 1) { if (item.asJsonObject["isdir"].asInt == 1) {
val folderPath = "/sharelink$uk-$shareid/${item.asJsonObject["server_filename"].asString}" val folderPath =
"/sharelink$uk-${item.asJsonObject["fs_id"].asString}/${item.asJsonObject["server_filename"].asString}"
if (folderPath !in seenFolders) { if (folderPath !in seenFolders) {
seenFolders.add(folderPath) seenFolders.add(folderPath)
pendingFolders.add( pendingFolders.add(
@ -291,7 +301,7 @@ object BaiduDrive {
"shareid" to folderInfo["shareid"]!!.toString(), "shareid" to folderInfo["shareid"]!!.toString(),
"page" to folderInfo["page"].toString(), "page" to folderInfo["page"].toString(),
"num" to "9999", "num" to "9999",
"dir" to folderInfo["dir"]!!.toString(), "dir" to URLEncoder.encode(folderInfo["dir"]!!.toString()),
"desc" to "0", "desc" to "0",
"order" to "name", "order" to "name",
) )
@ -314,6 +324,7 @@ object BaiduDrive {
} }
private fun parseQueryParams(url: String): Map<String, List<String>> { private fun parseQueryParams(url: String): Map<String, List<String>> {
val query = url.substringAfter( val query = url.substringAfter(
"?" "?"
@ -417,9 +428,12 @@ object BaiduDrive {
) )
// 先清空文件夹在创建文件夹 // 先清空文件夹在创建文件夹
_deleteTransferFile("/$saveDirName") if (deleteTag == 0) {
//创建路径 _deleteTransferFile("/$saveDirName")
createSaveDir() //创建路径
createSaveDir()
deleteTag = 1
}
val data = val data =
@ -768,7 +782,7 @@ object BaiduDrive {
fun playerContent(json: JsonObject, flag: String): String { fun playerContent(json: JsonObject, flag: String): String {
val play = getVideoUrl(json, flag); val play = getVideoUrl(json, flag);
val header = play["header"] as Map<String, String> val header = play["header"] as Map<String, String>
return Result.get().url(buildProxyUrl(play["url"] as String, header) ).octet().header(header).string(); return Result.get().url(buildProxyUrl(play["url"] as String, header)).octet().header(header).string();
} }
fun getPlayFormatList(): Array<String> { fun getPlayFormatList(): Array<String> {

View File

@ -0,0 +1,398 @@
package com.github.catvod.api
import com.github.catvod.bean.Result
import com.github.catvod.bean.Vod
import com.github.catvod.bean.Vod.VodPlayBuilder
import com.github.catvod.bean.pan123.ShareInfo
import com.github.catvod.crawler.SpiderDebug
import com.github.catvod.net.OkHttp
import com.github.catvod.utils.Json
import com.github.catvod.utils.ProxyServer.buildProxyUrl
import com.github.catvod.utils.Util
import com.google.gson.JsonObject
import okhttp3.HttpUrl
import java.util.regex.Pattern
/**
* 123网盘API操作类
* 提供123网盘的文件分享下载播放等功能
*/
object Pan123Api {
public const val regex =
"https://(123592\\.com|123912\\.com|123865\\.com|123684\\.com|www\\.123684\\.com|www\\.123865\\.com|www\\.123912\\.com|www\\.123pan\\.com|www\\.123pan\\.cn|www\\.123592\\.com)/s/([^/]+)"
private const val api = "https://www.123684.com/b/api/share/"
private const val loginUrl = "https://login.123pan.com/api/user/sign_in"
private var authToken = ""
/**
* 初始化方法检查登录状态
*/
fun init() {
}
/**
* 获取认证token
*/
private fun getAuth(): String {
if (authToken.isNotBlank()) {
return authToken
}
return Pan123Handler.getAuth()
}
/**
* 登录方法
*/
fun login(passport: String, password: String): JsonObject? {
val data = mapOf(
"passport" to passport, "password" to password, "remember" to true
)
val headers = mapOf(
"User-Agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
"Content-Type" to "application/json",
"App-Version" to "43",
"Referer" to "https://login.123pan.com/centerlogin?redirect_url=https%3A%2F%2Fwww.123684.com&source_page=website",
"Accept" to "application/json, text/plain, */*",
"Origin" to "https://login.123pan.com",
"Connection" to "keep-alive",
"Accept-Language" to "zh-CN,zh;q=0.9"
)
try {
val response = OkHttp.post(loginUrl, Json.toJson(data), headers)
SpiderDebug.log("登录请求信息:")
SpiderDebug.log("URL: $loginUrl")
SpiderDebug.log("账号: ${passport}")
SpiderDebug.log("响应内容: ${response.body}")
if (response.code == 200) {
val authData = Json.safeObject(response.body)
SpiderDebug.log("解析后的响应数据: $authData")
if (authData.has("data") && authData.getAsJsonObject("data").has("token")) {
val token = authData.getAsJsonObject("data").get("token").asString
// setAuth(token)
SpiderDebug.log("登录成功")
authToken=token
return authData.get("data").asJsonObject
}
}
throw Exception("登录失败: HTTP状态码=${response.code}, 响应=${response.body}")
} catch (e: Exception) {
SpiderDebug.log("登录过程中发生错误: ${e.message}")
throw e
}
}
/**
* 解析分享链接提取分享密钥和提取码
*/
fun getShareData(url: String): Map<String, String> {
SpiderDebug.log("123链接$url")
var sharePwd = ""
var lurl = java.net.URLDecoder.decode(url, "UTF-8")
// 处理提取码格式
if ("提取码" in lurl && "?" !in lurl) {
lurl = lurl.replace(Regex("提取码[:]"), "?")
}
if ("提取码" in lurl && "?" in lurl) {
lurl = lurl.replace(Regex("提取码[:]?"), "")
}
if ("" in lurl) {
lurl = lurl.replace("", "")
}
val matcher = Pattern.compile(regex).matcher(lurl)
// 提取分享密码
if ("?" in lurl) {
val queryPart = lurl.split("?")[1]
val pwdMatcher = Regex("[A-Za-z0-9]+").find(queryPart)
if (pwdMatcher != null) {
sharePwd = queryPart.split("=")[1]
}
}
if (matcher.find()) {
val match = matcher.group(2) ?: ""
val key = when {
"?" in match -> match.split("?")[0]
".html" in match -> match.replace(".html", "")
"www" in match -> matcher.group(1) ?: match
else -> match
}
return mapOf("key" to key, "sharePwd" to sharePwd)
}
return emptyMap()
}
/**
* 根据分享链接获取文件列表
*/
fun getFilesByShareUrl(shareKey: String, sharePwd: String): List<ShareInfo> {
// 获取分享信息
val cate = getShareInfo(shareKey, sharePwd, 0, 0)
return cate
}
/**
* 获取分享信息
*/
private fun getShareInfo(
shareKey: String, sharePwd: String, next: Int, parentFileId: Long
): List<ShareInfo> {
//文件夹
val folders = mutableListOf<ShareInfo>()
//视频
val videos = mutableListOf<ShareInfo>()
val url =
"${api}get?limit=100&next=$next&orderBy=file_name&orderDirection=asc&shareKey=${shareKey.trim()}&SharePwd=${sharePwd.ifEmpty { "" }}&ParentFileId=$parentFileId&Page=1"
try {
val response = OkHttp.string(
url, mapOf(
"User-Agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
)
)
val data = Json.safeObject(response)
if (data.has("code") && data.get("code").asInt == 5103) {
SpiderDebug.log("123获取文件列表出错" + data.get("message").asString)
return emptyList()
}
val info = data.getAsJsonObject("data")
//其下没有文件
if (info.get("Len").asLong <= 0) {
return emptyList()
}
val nextValue = info.get("Next").asInt
val infoList = info.getAsJsonArray("InfoList")
// 处理文件夹
for (item in infoList) {
val itemObj = item.asJsonObject
//文件夹
if (itemObj.get("Category").asInt == 0) {
folders.add(
ShareInfo(
itemObj.get("FileName").asString,
shareKey,
sharePwd,
nextValue,
itemObj.get("FileId").asLong,
itemObj["S3KeyFlag"].asString,
itemObj["Size"].asLong,
itemObj["Etag"].asString,
)
)
} else if (itemObj.get("Category").asInt == 2) {
videos.add(
ShareInfo(
itemObj.get("FileName").asString,
shareKey,
sharePwd,
nextValue,
itemObj.get("FileId").asLong,
itemObj["S3KeyFlag"].asString,
itemObj["Size"].asLong,
itemObj["Etag"].asString,
)
)
}
}
// 递归获取子文件夹信息
for (item in folders) {
val result = getShareInfo(
item.shareKey, item.sharePwd, item.next, item.fileId
)
videos.addAll(result)
}
return videos
} catch (e: Exception) {
SpiderDebug.log("获取分享信息时发生错误: ${e.message}")
return emptyList()
}
}
/**
* 获取文件下载链接
*/
fun getDownload(
shareKey: String, fileId: Long, s3KeyFlag: String, size: Long, etag: String
): String {
SpiderDebug.log("获取下载链接参数:")
SpiderDebug.log("ShareKey: $shareKey")
SpiderDebug.log("FileID: $fileId")
SpiderDebug.log("S3KeyFlag: $s3KeyFlag")
SpiderDebug.log("Size: $size")
SpiderDebug.log("Etag: $etag")
SpiderDebug.log("Auth Token: ${getAuth().take(30)}...")
val data = mapOf(
"ShareKey" to shareKey, "FileID" to fileId, "S3KeyFlag" to s3KeyFlag, "Size" to size, "Etag" to etag
)
val url = "${api}download/info"
SpiderDebug.log("请求URL: $url")
SpiderDebug.log("请求数据: ${Json.toJson(data)}")
val headers = mapOf(
"User-Agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
"Content-Type" to "application/json",
"Authorization" to "Bearer ${getAuth()}",
"platform" to "android"
)
try {
val response = OkHttp.post(url, Json.toJson(data), headers)
SpiderDebug.log("响应状态码: ${response.code}")
SpiderDebug.log("响应内容: ${response.body}")
if (response.code == 200) {
val responseData = Json.safeObject(response.body)
if (responseData.has("data") && responseData.getAsJsonObject("data").has("DownloadURL")) {
val encodeUrl = responseData.getAsJsonObject("data").get("DownloadURL").asString
return Util.base64Decode(HttpUrl.parse(encodeUrl)?.queryParameter("params"))
}
}
throw Exception("获取下载链接失败: HTTP状态码=${response.code}, 响应=${response.body}")
} catch (e: Exception) {
SpiderDebug.log("获取下载链接时发生错误: ${e.message}")
throw e
}
}
/**
* 获取视频在线播放链接
*/
fun getLiveTranscoding(
shareKey: String, fileId: Long, s3KeyFlag: String, size: Long, etag: String
): List<Map<String, String>> {
val url = "https://www.123684.com/b/api/video/play/info?" + "etag=$etag&size=$size&from=1&shareKey=$shareKey"
val headers = mapOf(
"User-Agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
"Authorization" to "Bearer ${getAuth()}",
"Content-Type" to "application/json;charset=UTF-8",
"platform" to "android"
)
try {
val response = OkHttp.string(url, headers)
val downData = Json.safeObject(response)
if (downData.has("data") && downData.getAsJsonObject("data").has("video_play_info")) {
val videoInfo = mutableListOf<Map<String, String>>()
val videoPlayInfo = downData.getAsJsonObject("data").getAsJsonArray("video_play_info")
for (item in videoPlayInfo) {
val itemObj = item.asJsonObject
if (itemObj.has("url") && !itemObj.get("url").isJsonNull) {
val resolution = if (itemObj.has("resolution")) itemObj.get("resolution").asString else ""
val urlValue = itemObj.get("url").asString
videoInfo.add(
mapOf(
"name" to resolution, "url" to urlValue
)
)
}
}
return videoInfo
}
} catch (e: Exception) {
SpiderDebug.log("获取视频播放链接时发生错误: ${e.message}")
}
return emptyList()
}
fun getPlayFormatList(): Array<String> {
return arrayOf("原画")
}
fun getVod(key: String, sharePwd: String): Vod {
val list = getFilesByShareUrl(key, sharePwd)
val builder = VodPlayBuilder()
for (i in getPlayFormatList().indices) {
val playUrls = mutableListOf<VodPlayBuilder.PlayUrl>();
for (item in list) {
val play = VodPlayBuilder.PlayUrl()
play.name = "[${Util.getSize(item.Size.toDouble())}]${item.filename}"
play.url =
listOf(item.shareKey, item.fileId, item.S3KeyFlag, item.Size, item.Etag).joinToString("\\+\\+")
playUrls.add(play)
}
builder.append("pan123" + getPlayFormatList()[i], playUrls)
}
val buildResult = builder.build();
val vod = Vod()
vod.setVodId(key + "++" + sharePwd)
vod.setVodPic("")
vod.setVodYear("")
vod.setVodName("")
vod.setVodContent("")
vod.setVodPlayFrom(buildResult.vodPlayFrom)
vod.setVodPlayUrl(buildResult.vodPlayUrl)
return vod
}
fun playerContent(id: String, flag: String): String {
val itemJson = id.split("\\+\\+")
SpiderDebug.log("播放参数:$itemJson")
val url = getDownload(
itemJson[0], itemJson[1].toLong(), itemJson[2], itemJson[3].toLong(), itemJson[4]
)
val header = mapOf(
"User-Agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
)
return Result.get().url(buildProxyUrl(url, header)).octet().header(header).string();
}
}

View File

@ -0,0 +1,142 @@
package com.github.catvod.api
import android.R
import android.app.AlertDialog
import android.content.DialogInterface
import android.view.ViewGroup
import android.widget.EditText
import android.widget.LinearLayout
import com.github.catvod.api.Pan123Api.login
import com.github.catvod.bean.pan123.Cache
import com.github.catvod.bean.pan123.User
import com.github.catvod.crawler.SpiderDebug
import com.github.catvod.spider.Init
import com.github.catvod.utils.Notify
import com.github.catvod.utils.Path
import com.github.catvod.utils.ResUtil
import org.apache.commons.lang3.StringUtils
import java.io.File
object Pan123Handler {
private var cache: Cache? = null
private var dialog: AlertDialog? = null
private var auth = ""
private var userName = ""
private var passwd = ""
private var expire = 0L;
fun getCache(): File {
return Path.tv("pan123")
}
fun getAuth(): String {
return auth
}
init {
cache = Cache.objectFrom(Path.read(getCache()))
if (cache == null) {
SpiderDebug.log("cache 为null")
startFlow()
} else {
userName = cache!!.user.userName
passwd = cache!!.user.password
auth = cache!!.user.cookie
expire = cache!!.user.expire
if (StringUtils.isNotBlank(userName) && StringUtils.isNotBlank(passwd)) {
if (StringUtils.isBlank(auth) || expire == 0L || System.currentTimeMillis() > expire) {
SpiderDebug.log("auth 为空或者登录已过期")
this.loginWithPassword(userName, passwd)
}
} else {
SpiderDebug.log("userName passwd 为空")
startFlow()
}
}
}
fun loginWithPassword(uname: String?, passwd: String?) {
SpiderDebug.log("loginWithPassword uname: $unamepasswd$passwd")
try {
//保存的账号密码
val json = login(uname!!, passwd!!)
if (json != null) {
val user = User()
user.cookie = json.get("token").asString
user.password = passwd
user.userName = uname
user.expire = json.get("refresh_token_expire_time").asLong * 1000
this.auth = json.get("token").asString
cache?.setUserInfo(user)
Notify.show("123登录成功")
} else {
Notify.show("123登录失败")
}
} catch (e: Exception) {
SpiderDebug.log("登录失败: " + e.message)
Notify.show("123登录失败: " + e.message)
}
}
fun startFlow() {
Init.run { this.showInput() }
}
private fun showInput() {
try {
val margin = ResUtil.dp2px(16)
val params =
LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
val frame = LinearLayout(Init.context())
frame.setOrientation(LinearLayout.VERTICAL)
// frame.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
// params.setMargins(margin, margin, margin, margin);
val username = EditText(Init.context())
username.setHint("请输入123用户名")
val password = EditText(Init.context())
password.setHint("请输入123密码")
frame.addView(username, params)
frame.addView(password, params)
dialog = AlertDialog.Builder(Init.getActivity()).setTitle("请输入123用户名和密码").setView(frame)
.setNegativeButton(
R.string.cancel, null
).setPositiveButton(
R.string.ok, DialogInterface.OnClickListener { dialog: DialogInterface?, which: Int ->
onPositive(
username.getText().toString(), password.getText().toString()
)
}).show()
} catch (ignored: Exception) {
}
}
private fun onPositive(username: String?, password: String?) {
SpiderDebug.log("123用户名: $username")
SpiderDebug.log("123密码: $password")
dismiss()
Init.execute(Runnable {
loginWithPassword(username, password)
})
}
private fun dismiss() {
try {
if (dialog != null) dialog!!.dismiss()
} catch (ignored: Exception) {
}
}
}

View File

@ -12,7 +12,6 @@ import android.view.ViewGroup;
import android.widget.EditText; import android.widget.EditText;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ImageView; import android.widget.ImageView;
import com.github.catvod.bean.Result; import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod; import com.github.catvod.bean.Vod;
import com.github.catvod.bean.quark.Cache; import com.github.catvod.bean.quark.Cache;
@ -24,30 +23,14 @@ import com.github.catvod.net.OkHttp;
import com.github.catvod.net.OkResult; import com.github.catvod.net.OkResult;
import com.github.catvod.spider.Init; import com.github.catvod.spider.Init;
import com.github.catvod.spider.Proxy; import com.github.catvod.spider.Proxy;
import com.github.catvod.utils.Json; import com.github.catvod.utils.*;
import com.github.catvod.utils.Notify;
import com.github.catvod.utils.Path;
import com.github.catvod.utils.ProxyServer;
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.Gson; import com.google.gson.Gson;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -227,15 +210,18 @@ public class QuarkApi {
String fileId = split[0], fileToken = split[1], shareId = split[2], stoken = split[3]; String fileId = split[0], fileToken = split[1], shareId = split[2], stoken = split[3];
String playUrl = ""; String playUrl = "";
if (flag.contains("quark原画")) {
playUrl = this.getDownload(shareId, stoken, fileId, fileToken, true);
} else {
playUrl = this.getLiveTranscoding(shareId, stoken, fileId, fileToken, flag);
}
Map<String, String> header = getHeaders(); Map<String, String> header = getHeaders();
header.remove("Host"); header.remove("Host");
header.remove("Content-Type"); header.remove("Content-Type");
return Result.get().url(ProxyServer.INSTANCE.buildProxyUrl(playUrl, header)).octet().header(header).string(); if (flag.contains("quark原画")) {
playUrl = this.getDownload(shareId, stoken, fileId, fileToken, true);
return Result.get().url(ProxyServer.INSTANCE.buildProxyUrl(playUrl, header)).octet().header(header).string();
} else {
playUrl = this.getLiveTranscoding(shareId, stoken, fileId, fileToken, flag);
return Result.get().url(proxyVideoUrl(playUrl, header)).octet().header(header).string();
}
} }
private String proxyVideoUrl(String url, Map<String, String> header) { private String proxyVideoUrl(String url, Map<String, String> header) {
@ -428,7 +414,7 @@ public class QuarkApi {
for (Map<String, Object> item : items) { for (Map<String, Object> item : items) {
if (Boolean.TRUE.equals(item.get("dir"))) { if (Boolean.TRUE.equals(item.get("dir"))) {
subDir.add(item); subDir.add(item);
} else if (Boolean.TRUE.equals(item.get("file")) && "video".equals(item.get("obj_category"))) { } else if (Boolean.TRUE.equals(item.get("file")) && (Util.isMedia((String) item.get("file_name")))) {
if ((Double) item.get("size") < 1024 * 1024 * 5) continue; if ((Double) item.get("size") < 1024 * 1024 * 5) continue;
item.put("stoken", this.shareTokenCache.get(shareData.getShareId()).get("stoken")); item.put("stoken", this.shareTokenCache.get(shareData.getShareId()).get("stoken"));
videos.add(Item.objectFrom(item, shareData.getShareId(), shareIndex)); videos.add(Item.objectFrom(item, shareData.getShareId(), shareIndex));

View File

@ -23,7 +23,7 @@ import java.util.regex.Pattern;
public class TianyiApi { public class TianyiApi {
private String apiUrl = "https://cloud.189.cn/api/open/share/"; private String apiUrl = "https://cloud.189.cn/api/open/share/";
public static final String URL_START = "https://cloud.189.cn/"; public static final String URL_CONTAIN = "cloud.189.cn/";
private Map<String, JsonObject> shareTokenCache = new HashMap<>(); private Map<String, JsonObject> shareTokenCache = new HashMap<>();
@ -221,41 +221,30 @@ public class TianyiApi {
public ShareData getShareData(String url, String accessCode) { public ShareData getShareData(String url, String accessCode) {
String shareCode = ""; // 从整个URL中直接提取访问码无论格式如何
// 第一种匹配规则使用预编译的 regex Matcher accessMatcher = Pattern.compile("访问码[:]([a-zA-Z0-9]+)").matcher(url);
Matcher matcher = Pattern.compile("https:\\/\\/cloud\\.189\\.cn\\/web\\/share\\?code=([^&]+)").matcher(url); if (accessMatcher.find()) {
accessCode = accessMatcher.group(1);
} else if (accessCode == null || accessCode.isEmpty()) {
accessCode = "";
}
String shareCode = null;
// 第一种匹配规则兼容http和https
Matcher matcher = Pattern.compile("https?:\\/\\/cloud\\.189\\.cn\\/web\\/share\\?code=([^&\\s]+)").matcher(url);
if (matcher.find() && matcher.group(1) != null) { if (matcher.find() && matcher.group(1) != null) {
shareCode = matcher.group(1); shareCode = matcher.group(1);
// 从shareCode中提取访问码
Matcher accessMatcher = Pattern.compile("访问码:([a-zA-Z0-9]+)").matcher(shareCode);
if (accessMatcher.find()) {
accessCode = accessMatcher.group(1);
} else {
accessCode = "";
}
} else { } else {
// 第二种匹配规则直接匹配 cloud.189.cn/t/ 格式 // 第二种匹配规则直接匹配 cloud.189.cn/t/ 格式兼容http和https匹配到空格前
Matcher fallbackMatcher = Pattern.compile("https://cloud\\.189\\.cn/t/([^&]+)").matcher(url); Matcher fallbackMatcher = Pattern.compile("https?:\\/\\/cloud\\.189\\.cn\\/t/([^\\s]+)").matcher(url);
if (fallbackMatcher.find()) { if (fallbackMatcher.find()) {
shareCode = fallbackMatcher.group(1); shareCode = fallbackMatcher.group(1);
} else {
shareCode = null;
}
// 再次尝试从shareCode提取访问码
if (shareCode != null) {
Matcher accessMatcher = Pattern.compile("访问码:([a-zA-Z0-9]+)").matcher(shareCode);
accessCode = accessMatcher.find() ? accessMatcher.group(1) : "";
} else {
accessCode = "";
} }
} }
shareCode = shareCode.split("(访问码")[0].trim();
ShareData shareData = new ShareData(shareCode, "0"); ShareData shareData = new ShareData(shareCode, "0");
shareData.setSharePwd(accessCode); shareData.setSharePwd(accessCode);
return shareData; return shareData;
} }

View File

@ -44,7 +44,7 @@ public class UCApi {
private String cookieToken = ""; private String cookieToken = "";
private String ckey = ""; private String ckey = "";
private Map<String, Map<String, Object>> shareTokenCache = new HashMap<>(); private Map<String, Map<String, Object>> shareTokenCache = new HashMap<>();
private String pr = "pr=UCBrowser&fr=pc"; private String pr = "pr=UCBrowser&fr=pc&sys=darwin&ve=1.8.6&ut=Nk27FcCv6q1eo6rXz8QHR/nIG6qLA3jh7KdL+agFgcOvww==";
private List<String> subtitleExts = Arrays.asList(".srt", ".ass", ".scc", ".stl", ".ttml"); private List<String> subtitleExts = Arrays.asList(".srt", ".ass", ".scc", ".stl", ".ttml");
private Map<String, String> saveFileIdCaches = new HashMap<>(); private Map<String, String> saveFileIdCaches = new HashMap<>();
private String saveDirId = null; private String saveDirId = null;
@ -87,7 +87,15 @@ public class UCApi {
cache = Cache.objectFrom(Path.read(getCache())); cache = Cache.objectFrom(Path.read(getCache()));
tokenCache = Cache.objectFrom(Path.read(qrCodeHandler.getCache())); tokenCache = Cache.objectFrom(Path.read(qrCodeHandler.getCache()));
this.cookieToken = tokenCache.getUser().getCookie(); java.lang.String tokenCacheJson = tokenCache.getUser().getCookie();
if (StringUtils.isNoneBlank(tokenCacheJson)) {
//刷新token,并返回
this.cookieToken = qrCodeHandler.refreshToken(Json.safeObject(tokenCacheJson).getAsJsonObject().get("refresh_token").getAsString());
SpiderDebug.log("UC初始化获取到的cookieToken: " + cookieToken);
}
SpiderDebug.log("UC初始化获取到的cookieToken: " + cookieToken); SpiderDebug.log("UC初始化获取到的cookieToken: " + cookieToken);
} }
@ -181,9 +189,9 @@ public class UCApi {
List<String> playFrom = UCApi.get().getPlayFormatList(); List<String> playFrom = UCApi.get().getPlayFormatList();
List<String> playFromtmp = new ArrayList<>(); List<String> playFromtmp = new ArrayList<>();
playFromtmp.add("uc原画"); playFromtmp.add("uc原画");
for (String s : playFrom) { /* for (String s : playFrom) {
playFromtmp.add("uc" + s); playFromtmp.add("uc" + s);
} }*/
List<String> playUrl = new ArrayList<>(); List<String> playUrl = new ArrayList<>();
if (files.isEmpty()) { if (files.isEmpty()) {
@ -217,23 +225,19 @@ public class UCApi {
SpiderDebug.log("flag:" + flag); SpiderDebug.log("flag:" + flag);
String fileId = split[0], fileToken = split[1], shareId = split[2], stoken = split[3]; String fileId = split[0], fileToken = split[1], shareId = split[2], stoken = split[3];
String playUrl = ""; String playUrl = "";
if (flag.contains("uc原画")) {
playUrl = this.getDownload(shareId, stoken, fileId, fileToken, true);
} else {
playUrl = this.getLiveTranscoding(shareId, stoken, fileId, fileToken, flag);
}
SpiderDebug.log("origin playUrl:" + playUrl); SpiderDebug.log("origin playUrl:" + playUrl);
Map<String, String> header = getHeaders(); Map<String, String> header = getHeaders();
header.remove("Host"); header.remove("Host");
header.remove("Content-Type"); header.remove("Content-Type");
if (flag.contains("uc原画")) {
//UCTV 可以直接播放不需要代理 playUrl = this.getDownload(shareId, stoken, fileId, fileToken, true);
if (testVideo(playUrl)) {
SpiderDebug.log("UCTV 可以直接播放,不需要代理" );
return Result.get().url(playUrl).string(); return Result.get().url(playUrl).string();
} else {
playUrl = this.getLiveTranscoding(shareId, stoken, fileId, fileToken, flag);
return Result.get().url(proxyVideoUrl(playUrl, new HashMap<>())).string();
} }
return Result.get().url(proxyVideoUrl(playUrl, header)).octet().header(header).string();
} }
private boolean testVideo(String url) { private boolean testVideo(String url) {

View File

@ -178,25 +178,7 @@ public class UCTokenHandler {
JsonObject resData = Json.safeObject(okResult.getBody()); JsonObject resData = Json.safeObject(okResult.getBody());
String code = resData.get("code").getAsString(); String code = resData.get("code").getAsString();
pathname = "/token"; OkResult okResult1 = getAccessToken(code, false);
reqId = generateReqId(deviceID, timestamp);
Map<String, String> postData = new HashMap<>();
postData.put("req_id", reqId);
postData.put("app_ver", (String) conf.get("appVer"));
postData.put("device_id", deviceID);
postData.put("device_brand", "Xiaomi");
postData.put("platform", "tv");
postData.put("device_name", "M2004J7AC");
postData.put("device_model", "M2004J7AC");
postData.put("build_device", "M2004J7AC");
postData.put("build_product", "M2004J7AC");
postData.put("device_gpu", "Adreno (TM) 550");
postData.put("activity_rect", URLEncoder.encode("{}", "UTF-8"));
postData.put("channel", (String) conf.get("channel"));
postData.put("code", code);
OkResult okResult1 = OkHttp.post(conf.get("codeApi") + pathname, Json.toJson(postData), headers);
if (okResult1.getCode() == 200) { if (okResult1.getCode() == 200) {
@ -208,15 +190,14 @@ public class UCTokenHandler {
SpiderDebug.log("uc Token获取成功" + tokenResData.get("data").getAsJsonObject().get("access_token").getAsString()); SpiderDebug.log("uc Token获取成功" + tokenResData.get("data").getAsJsonObject().get("access_token").getAsString());
//保存到本地 //保存到本地
cache.setTokenUser(User.objectFrom(tokenResData.get("data").getAsJsonObject().get("access_token").getAsString())); cache.setTokenUser(User.objectFrom(Json.toJson(tokenResData.get("data").getAsJsonObject())));
//停止检验线程关闭弹窗 //停止检验线程关闭弹窗
stopService(); stopService();
return result; return result;
} }
} else if (okResult.getCode() == 400) { } else if (okResult.getCode() == 400) {
SpiderDebug.log("uc Token获取失败" +okResult.getBody()); SpiderDebug.log("uc Token获取失败" + okResult.getBody());
return Map.of("status", "NEW"); return Map.of("status", "NEW");
@ -226,6 +207,74 @@ public class UCTokenHandler {
platformStates.remove("UC_TOKEN"); platformStates.remove("UC_TOKEN");
return Map.of("status", "EXPIRED"); return Map.of("status", "EXPIRED");
} }
/**
* 获取访问令牌或者刷新令牌
*
* @param code
* @param refresh 是否刷新如果是code为refresh_token
* @return
* @throws UnsupportedEncodingException
*/
public OkResult getAccessToken(String code, boolean refresh) {
String timestamp = String.valueOf(new Date().getTime() / 1000 + 1) + "000";
String deviceID = StringUtils.isAllBlank((String) addition.get("DeviceID")) ? (String) addition.get("DeviceID") : generateDeviceID(timestamp);
Map<String, String> headers = new HashMap<>();
headers.put("Accept", "application/json, text/plain, */*");
headers.put("User-Agent", "Mozilla/5.0 (Linux; U; Android 13; zh-cn; M2004J7AC Build/UKQ1.231108.001) AppleWebKit/533.1 (KHTML, like Gecko) Mobile Safari/533.1");
String pathname = "/token";
String reqId = generateReqId(deviceID, timestamp);
Map<String, String> postData = new HashMap<>();
postData.put("req_id", reqId);
postData.put("app_ver", (String) conf.get("appVer"));
postData.put("device_id", deviceID);
postData.put("device_brand", "Xiaomi");
postData.put("platform", "tv");
postData.put("device_name", "M2004J7AC");
postData.put("device_model", "M2004J7AC");
postData.put("build_device", "M2004J7AC");
postData.put("build_product", "M2004J7AC");
postData.put("device_gpu", "Adreno (TM) 550");
try {
postData.put("activity_rect", URLEncoder.encode("{}", "UTF-8"));
} catch (Exception e) {
SpiderDebug.log("encode出错" + e.getMessage());
return null;
}
postData.put("channel", conf.get("channel"));
if (refresh) {
postData.put("refresh_token", code);
SpiderDebug.log("开始刷新uc accesstoken");
} else {
postData.put("code", code);
SpiderDebug.log("开始获取uc accesstoken");
}
return OkHttp.post(conf.get("codeApi") + pathname, Json.toJson(postData), headers);
}
/**
* 刷新refresh token
*
* @param refreshToken 刷新token
* @return 防火新的accesstoken
*/
public String refreshToken(String refreshToken) {
OkResult okResult1 = this.getAccessToken(refreshToken, true);
if (okResult1.getCode() == 200) {
JsonObject tokenResData = Json.safeObject(okResult1.getBody());
SpiderDebug.log("uc Token刷新成功" + tokenResData.get("data").getAsJsonObject().get("access_token").getAsString());
//保存到本地
cache.setTokenUser(User.objectFrom(Json.toJson(tokenResData.get("data").getAsJsonObject())));
return tokenResData.get("data").getAsJsonObject().get("access_token").getAsString();
}
return "";
}
public String download(String token, String saveFileId) throws Exception { public String download(String token, String saveFileId) throws Exception {
SpiderDebug.log("开始下载:" + saveFileId + ";token:" + token); SpiderDebug.log("开始下载:" + saveFileId + ";token:" + token);
@ -266,6 +315,11 @@ public class UCTokenHandler {
OkResult okResult1 = OkHttp.get(API_URL + pathname, params, headers); OkResult okResult1 = OkHttp.get(API_URL + pathname, params, headers);
JsonObject obj = Json.safeObject(okResult1.getBody()); JsonObject obj = Json.safeObject(okResult1.getBody());
if (okResult1.getCode() != 200) {
Notify.show(obj.get("error_info").getAsString());
SpiderDebug.log("uc TV 错误信息:" + obj.get("error_info").getAsString());
return null;
}
String downloadUrl = obj.get("data").getAsJsonObject().get("video_info").getAsJsonArray().get(0).getAsJsonObject().get("url").getAsString(); String downloadUrl = obj.get("data").getAsJsonObject().get("video_info").getAsJsonArray().get(0).getAsJsonObject().get("url").getAsString();
SpiderDebug.log("uc TV 下载文件内容:" + downloadUrl); SpiderDebug.log("uc TV 下载文件内容:" + downloadUrl);
return downloadUrl; return downloadUrl;

View File

@ -2,7 +2,6 @@ package com.github.catvod.bean.BD;
import com.github.catvod.api.BaiDuYunHandler; import com.github.catvod.api.BaiDuYunHandler;
import com.github.catvod.api.YunTokenHandler;
import com.github.catvod.bean.yun.User; import com.github.catvod.bean.yun.User;
import com.github.catvod.spider.Init; import com.github.catvod.spider.Init;
import com.github.catvod.utils.Path; import com.github.catvod.utils.Path;

View File

@ -0,0 +1,46 @@
package com.github.catvod.bean.pan123;
import com.github.catvod.api.Pan123Handler;
import com.github.catvod.crawler.SpiderDebug;
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;
public static Cache objectFrom(String str) {
if(str.isEmpty()) return new Cache();
SpiderDebug.log("Cache.objectFrom: " + 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 setUserInfo(User user) {
this.user = user;
this.saveUser();
}
public void saveUser() {
SpiderDebug.log("Cache.saveUser: " + toString());
SpiderDebug.log("Cache.path: " + Pan123Handler.INSTANCE.getCache().getAbsolutePath());
Init.execute(() -> Path.write(Pan123Handler.INSTANCE.getCache(), toString()));
}
@Override
public String toString() {
return new Gson().toJson(this);
}
}

View File

@ -0,0 +1,12 @@
package com.github.catvod.bean.pan123
data class ShareInfo(
val filename: String,
val shareKey: String,
val sharePwd: String,
val next: Int,
val fileId: Long,
val S3KeyFlag: String,
val Size: Long,
val Etag: String
)

View File

@ -0,0 +1,63 @@
package com.github.catvod.bean.pan123;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
public class User {
@SerializedName("expire")
private long expire;
@SerializedName("cookie")
private String cookie;
@SerializedName("userName")
private String userName;
@SerializedName("password")
private String password;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCookie() {
return cookie;
}
public void setCookie(String cookie) {
this.cookie = cookie;
}
public long getExpire() {
return expire;
}
public void setExpire(long expire) {
this.expire = expire;
}
public static User objectFrom(String str) {
User item = new Gson().fromJson(str, User.class);
return item == null ? new User() : item;
}
public void clean() {
this.cookie = "";
this.userName = "";
this.password = "";
this.expire = 0L;
}
}

View File

@ -64,7 +64,7 @@ class BaiDuPan : Spider() {
return TextUtils.join("$$$", BaiduDrive.get().getPlayFormatList()); return TextUtils.join("$$$", BaiduDrive.get().getPlayFormatList());
}*/ }*/
for (i in 1..ids.size) { for (i in 1..ids.size) {
playFrom.add("BD原画" + i + index) playFrom.add( String.format(Locale.getDefault(), "BD原画" + "#%02d_%02d", i, index))
/* for (s in getPlayFormatList()) { /* for (s in getPlayFormatList()) {
playFrom.add(String.format(Locale.getDefault(), "BD" + s + "#%02d%02d", i, index)) playFrom.add(String.format(Locale.getDefault(), "BD" + s + "#%02d%02d", i, index))
}*/ }*/
@ -78,7 +78,7 @@ class BaiDuPan : Spider() {
* @param ids share_link 集合 * @param ids share_link 集合
* @return 詳情內容視頻播放地址 * @return 詳情內容視頻播放地址
*/ */
@Throws(Exception::class)
fun detailContentVodPlayUrl(ids: List<String>): String? { fun detailContentVodPlayUrl(ids: List<String>): String? {
val playUrl: MutableList<String?> = ArrayList<String?>() val playUrl: MutableList<String?> = ArrayList<String?>()
for (id in ids) { for (id in ids) {
@ -86,6 +86,7 @@ class BaiDuPan : Spider() {
playUrl.add(getVod(id).getVodPlayUrl()) playUrl.add(getVod(id).getVodPlayUrl())
} catch (e: Exception) { } catch (e: Exception) {
SpiderDebug.log("获取播放地址出错:" + e.message) SpiderDebug.log("获取播放地址出错:" + e.message)
playUrl.add("")
} }
} }
return TextUtils.join("$$$", playUrl) return TextUtils.join("$$$", playUrl)

View File

@ -2,127 +2,191 @@ package com.github.catvod.spider;
import android.content.Context; import android.content.Context;
import android.text.TextUtils; import android.text.TextUtils;
import com.github.catvod.api.TianyiApi; import com.github.catvod.api.Pan123Api;
import com.github.catvod.crawler.Spider; import com.github.catvod.crawler.Spider;
import com.github.catvod.crawler.SpiderDebug;
import com.github.catvod.utils.Json; import com.github.catvod.utils.Json;
import com.github.catvod.utils.Util; import com.github.catvod.utils.Util;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import java.util.ArrayList; import java.util.*;
import java.util.List; import java.util.concurrent.ExecutorService;
import java.util.Objects; import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import static com.github.catvod.api.TianyiApi.URL_START; import static com.github.catvod.api.TianyiApi.URL_CONTAIN;
/** /**
* @author ColaMint & Adam & FongMi * @author ColaMint & Adam & FongMi
*/ */
public class Cloud extends Spider { public class Cloud extends Spider {
private Quark quark = null; private Quark quark = null;
/* private Ali ali = null; /* private Ali ali = null;*/
private UC uc = null;*/ private UC uc = null;
private TianYi tianYi = null; private TianYi tianYi = null;
private YiDongYun yiDongYun = null; private YiDongYun yiDongYun = null;
private BaiDuPan baiDuPan = null; private BaiDuPan baiDuPan = null;
private Pan123 pan123 = null;
private static final Map<String, ImmutablePair<List<String>, List<String>>> resultMap = new HashMap<>();
@Override @Override
public void init(Context context, String extend) throws Exception { public void init(Context context, String extend) throws Exception {
JsonObject ext = Json.safeObject(extend); JsonObject ext = Json.safeObject(extend);
quark = new Quark(); quark = new Quark();
/* uc = new UC(); uc = new UC();
ali = new Ali();*/ /* ali = new Ali();*/
tianYi = new TianYi(); tianYi = new TianYi();
yiDongYun = new YiDongYun(); yiDongYun = new YiDongYun();
baiDuPan = new BaiDuPan(); baiDuPan = new BaiDuPan();
pan123 = new Pan123();
boolean first = Objects.nonNull(ext); boolean first = Objects.nonNull(ext);
quark.init(context, first && ext.has("cookie") ? ext.get("cookie").getAsString() : ""); quark.init(context, first && ext.has("cookie") ? ext.get("cookie").getAsString() : "");
/* uc.init(context, first && ext.has("uccookie") ? ext.get("uccookie").getAsString() : ""); uc.init(context, first && ext.has("uccookie") ? ext.get("uccookie").getAsString() : "");
ali.init(context, first && ext.has("token") ? ext.get("token").getAsString() : "");*/ /* ali.init(context, first && ext.has("token") ? ext.get("token").getAsString() : "");*/
tianYi.init(context, first && ext.has("tianyicookie") ? ext.get("tianyicookie").getAsString() : ""); tianYi.init(context, first && ext.has("tianyicookie") ? ext.get("tianyicookie").getAsString() : "");
yiDongYun.init(context, ""); yiDongYun.init(context, "");
baiDuPan.init(context, ""); baiDuPan.init(context, "");
pan123.init(context, "");
} }
@Override @Override
public String detailContent(List<String> shareUrl) throws Exception { public String detailContent(List<String> shareUrl) throws Exception {
SpiderDebug.log("cloud detailContent shareUrl" + Json.toJson(shareUrl));
/* if (shareUrl.get(0).matches(Util.patternAli)) { /* if (shareUrl.get(0).matches(Util.patternAli)) {
return ali.detailContent(shareUrl); return ali.detailContent(shareUrl);
} else */if (shareUrl.get(0).matches(Util.patternQuark)) { } else */
if (shareUrl.get(0).matches(Util.patternQuark)) {
return quark.detailContent(shareUrl); return quark.detailContent(shareUrl);
} /*else if (shareUrl.get(0).matches(Util.patternUC)) { } else if (shareUrl.get(0).matches(Util.patternUC)) {
return uc.detailContent(shareUrl); return uc.detailContent(shareUrl);
} */else if (shareUrl.get(0).startsWith(TianyiApi.URL_START)) { } else if (shareUrl.get(0).contains(URL_CONTAIN)) {
return tianYi.detailContent(shareUrl); return tianYi.detailContent(shareUrl);
} else if (shareUrl.get(0).contains(YiDongYun.URL_START)) { } else if (shareUrl.get(0).contains(YiDongYun.URL_START)) {
return yiDongYun.detailContent(shareUrl); return yiDongYun.detailContent(shareUrl);
}else if (shareUrl.get(0).contains(BaiDuPan.URL_START)) { } else if (shareUrl.get(0).contains(BaiDuPan.URL_START)) {
return baiDuPan.detailContent(shareUrl); return baiDuPan.detailContent(shareUrl);
} else if (shareUrl.get(0).matches(Pan123Api.regex)) {
SpiderDebug.log("Pan123Api shareUrl" + Json.toJson(shareUrl));
return pan123.detailContent(shareUrl);
} }
return null; return null;
} }
@Override @Override
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception { public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
SpiderDebug.log("cloud playerContent flag" + flag + " id" + id);
if (flag.contains("quark")) { if (flag.contains("quark")) {
return quark.playerContent(flag, id, vipFlags); return quark.playerContent(flag, id, vipFlags);
} /*else if (flag.contains("uc")) { } else if (flag.contains("uc")) {
return uc.playerContent(flag, id, vipFlags); return uc.playerContent(flag, id, vipFlags);
} */else if (flag.contains("天意")) { } else if (flag.contains("天意")) {
return tianYi.playerContent(flag, id, vipFlags); return tianYi.playerContent(flag, id, vipFlags);
} else if (flag.contains("移动")) { } else if (flag.contains("移动")) {
return yiDongYun.playerContent(flag, id, vipFlags); return yiDongYun.playerContent(flag, id, vipFlags);
}/* else { }/* else {
return ali.playerContent(flag, id, vipFlags); return ali.playerContent(flag, id, vipFlags);
}*/ }*/ else if (flag.contains("BD")) {
else if (flag.contains("BD")) {
return baiDuPan.playerContent(flag, id, vipFlags); return baiDuPan.playerContent(flag, id, vipFlags);
} else if (flag.contains("pan123")) {
return pan123.playerContent(flag, id, vipFlags);
} }
return flag; return flag;
} }
protected String detailContentVodPlayFrom(List<String> shareLinks) { protected String detailContentVodPlayFrom(List<String> shareLinks) {
List<String> from = new ArrayList<>(); ImmutablePair<List<String>, List<String>> pairs = resultMap.get(Util.MD5(Json.toJson(shareLinks)));
int i = 0; if (pairs != null && pairs.left != null && !pairs.left.isEmpty()) {
for (String shareLink : shareLinks) { return TextUtils.join("$$$", pairs.right);
i++;
/*if (shareLink.matches(Util.patternUC)) {
from.add(uc.detailContentVodPlayFrom(List.of(shareLink), i));
} else*/ if (shareLink.matches(Util.patternQuark)) {
from.add(quark.detailContentVodPlayFrom(List.of(shareLink), i));
} /*else if (shareLink.matches(Util.patternAli)) {
from.add(ali.detailContentVodPlayFrom(List.of(shareLink), i));
} */else if (shareLink.startsWith(URL_START)) {
from.add(tianYi.detailContentVodPlayFrom(List.of(shareLink), i));
} else if (shareLink.contains(YiDongYun.URL_START)) {
from.add(yiDongYun.detailContentVodPlayFrom(List.of(shareLink), i));
}
else if (shareLink.contains(BaiDuPan.URL_START)) {
from.add(baiDuPan.detailContentVodPlayFrom(List.of(shareLink), i));
}
} }
return TextUtils.join("$$$", from); getPlayFromAndUrl(shareLinks);
pairs = resultMap.get(Util.MD5(Json.toJson(shareLinks)));
if (pairs != null && pairs.left != null && !pairs.left.isEmpty()) {
return TextUtils.join("$$$", pairs.right);
}
return "";
} }
protected String detailContentVodPlayUrl(List<String> shareLinks) throws Exception { protected String detailContentVodPlayUrl(List<String> shareLinks) {
List<String> urls = new ArrayList<>(); ImmutablePair<List<String>, List<String>> pairs = resultMap.get(Util.MD5(Json.toJson(shareLinks)));
for (String shareLink : shareLinks) { if (pairs != null && pairs.left != null && !pairs.left.isEmpty()) {
/* if (shareLink.matches(Util.patternUC)) { return TextUtils.join("$$$", pairs.left);
urls.add(uc.detailContentVodPlayUrl(List.of(shareLink))); }
} else */if (shareLink.matches(Util.patternQuark)) {
urls.add(quark.detailContentVodPlayUrl(List.of(shareLink))); getPlayFromAndUrl(shareLinks);
}/* else if (shareLink.matches(Util.patternAli)) { pairs = resultMap.get(Util.MD5(Json.toJson(shareLinks)));
urls.add(ali.detailContentVodPlayUrl(List.of(shareLink))); if (pairs != null && pairs.left != null && !pairs.left.isEmpty()) {
} */else if (shareLink.startsWith(URL_START)) { return TextUtils.join("$$$", pairs.left);
urls.add(tianYi.detailContentVodPlayUrl(List.of(shareLink))); }
} else if (shareLink.contains(YiDongYun.URL_START)) { return "";
urls.add(yiDongYun.detailContentVodPlayUrl(List.of(shareLink))); }
}else if (shareLink.contains(BaiDuPan.URL_START)) {
urls.add(baiDuPan.detailContentVodPlayUrl(List.of(shareLink)));
} //同時获取from 和url 放入缓存只要一个函数执行就行避免重复执行
private void getPlayFromAndUrl(List<String> shareLinks) {
ExecutorService service = Executors.newFixedThreadPool(4);
try { //首先清空缓存避免太多缓存
resultMap.clear();
List<String> urls = new ArrayList<>();
List<String> froms = new ArrayList<>();
List<Future<ImmutablePair<String, String>>> futures = new ArrayList<>();
int i = 0;
for (String shareLink : shareLinks) {
int finalI = ++i;
futures.add(service.submit(() -> {
String url = "";
String from = "";
if (shareLink.matches(Util.patternUC)) {
url = uc.detailContentVodPlayUrl(List.of(shareLink));
from = uc.detailContentVodPlayFrom(List.of(shareLink), finalI);
} else if (shareLink.matches(Util.patternQuark)) {
url = quark.detailContentVodPlayUrl(List.of(shareLink));
from = quark.detailContentVodPlayFrom(List.of(shareLink), finalI);
}/* else if (shareLink.matches(Util.patternAli)) {
urls.add(ali.detailContentVodPlayUrl(List.of(shareLink)));
} */ else if (shareLink.contains(URL_CONTAIN)) {
url = tianYi.detailContentVodPlayUrl(List.of(shareLink));
from = tianYi.detailContentVodPlayFrom(List.of(shareLink), finalI);
} else if (shareLink.contains(YiDongYun.URL_START)) {
url = yiDongYun.detailContentVodPlayUrl(List.of(shareLink));
from = yiDongYun.detailContentVodPlayFrom(List.of(shareLink), finalI);
} else if (shareLink.contains(BaiDuPan.URL_START)) {
url = baiDuPan.detailContentVodPlayUrl(List.of(shareLink));
from = baiDuPan.detailContentVodPlayFrom(List.of(shareLink), finalI);
} else if (shareLink.matches(Pan123Api.regex)) {
url = pan123.detailContentVodPlayUrl(List.of(shareLink));
from = pan123.detailContentVodPlayFrom(List.of(shareLink), finalI);
}
return new ImmutablePair<>(url, from);
}));
}
for (Future<ImmutablePair<String, String>> future : futures) {
//只有连接不为空才放入进去
if (StringUtils.isNoneBlank(future.get().left)) {
urls.add(future.get().left);
froms.add(future.get().right);
}
}
resultMap.put(Util.MD5(Json.toJson(shareLinks)), new ImmutablePair<>(urls, froms));
SpiderDebug.log("---urls" + Json.toJson(urls));
SpiderDebug.log("---froms" + Json.toJson(froms));
} catch (Exception e) {
SpiderDebug.log("获取异步结果出错:" + e);
} finally {
service.shutdown();
} }
return TextUtils.join("$$$", urls);
} }
} }

View File

@ -1,107 +0,0 @@
package com.github.catvod.spider;
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.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import com.github.catvod.bean.Class;
import com.github.catvod.utils.Util;
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", "PostmanRuntime/7.36.3");
headers.put("Host", "jable.tv");
headers.put("Postman-Token", "33290483-3c8d-413f-a160-0d3aea9e6f95");
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 > a")) {
String typeId = element.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));
}
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

@ -1,133 +0,0 @@
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,90 @@
package com.github.catvod.spider;
import android.content.Context;
import android.text.TextUtils;
import com.github.catvod.api.Pan123Api;
import com.github.catvod.bean.Result;
import com.github.catvod.crawler.Spider;
import com.github.catvod.crawler.SpiderDebug;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* @author lushunming
*/
public class Pan123 extends Spider {
@Override
public void init(Context context, String extend) throws Exception {
if (StringUtils.isNoneBlank(extend)) {
// Pan123Api.INSTANCE.setAuth(extend);
}
}
@Override
public String detailContent(List<String> ids) throws Exception {
@NotNull Map<@NotNull String, @NotNull String> shareData = Pan123Api.INSTANCE.getShareData(ids.get(0));
return Result.string(Pan123Api.INSTANCE.getVod(shareData.get("key"), shareData.get("sharePwd")));
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
return Pan123Api.INSTANCE.playerContent(id, flag);
}
/**
* 獲取詳情內容視頻播放來源 shared_link
*
* @param ids share_link 集合
* @param
* @return 詳情內容視頻播放來源
*/
public String detailContentVodPlayFrom(List<String> ids, int index) {
List<String> playFrom = new ArrayList<>();
/* if (ids.size() < 2){
return TextUtils.join("$$$", Pan123Api.INSTANCE.getPlayFormatList());
}*/
for (int i = 1; i <= ids.size(); i++) {
for (String s : Pan123Api.INSTANCE.getPlayFormatList()) {
playFrom.add(String.format(Locale.getDefault(), "pan123" + s + "#%02d_%02d", i, index));
}
// playFrom.add("天意" + i + index);
}
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) {
@NotNull Map<@NotNull String, @NotNull String> shareData = Pan123Api.INSTANCE.getShareData(id);
try {
playUrl.add(Pan123Api.INSTANCE.getVod(shareData.get("key"), shareData.get("sharePwd")).getVodPlayUrl());
} catch (Exception e) {
SpiderDebug.log("获取播放地址出错:" + e.getMessage());
playUrl.add("");
}
}
return TextUtils.join("$$$", playUrl);
}
}

View File

@ -8,6 +8,7 @@ import com.github.catvod.bean.Result;
import com.github.catvod.bean.Sub; import com.github.catvod.bean.Sub;
import com.github.catvod.bean.Vod; import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider; import com.github.catvod.crawler.Spider;
import com.github.catvod.crawler.SpiderDebug;
import com.github.catvod.net.OkHttp; import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Image; import com.github.catvod.utils.Image;
import com.github.catvod.utils.Util; import com.github.catvod.utils.Util;
@ -19,31 +20,54 @@ import java.util.List;
public class Push extends Spider { public class Push extends Spider {
private final Ali ali; private Cloud cloud;
public Push() { public Push() {
ali = new Ali(); cloud = new Cloud();
} }
@Override @Override
public void init(Context context, String extend) { public void init(Context context, String extend) {
ali.init(context, extend); try {
cloud.init(context, extend);
} catch (Exception e) {
SpiderDebug.log("Cloud init error: " + e.getMessage());
}
} }
@Override @Override
public String detailContent(List<String> ids) throws Exception { public String detailContent(List<String> ids) throws Exception {
if (Ali.pattern.matcher(ids.get(0)).find()) return ali.detailContent(ids); String url = ids.get(0);
return Result.string(vod(ids.get(0)));
// 使用Cloud类处理各种云盘链接
String cloudResult = cloud.detailContent(ids);
if (cloudResult != null) {
return cloudResult;
}
// 如果不是云盘链接返回普通链接处理结果
return Result.string(vod(url));
} }
@Override @Override
public String playerContent(String flag, String id, List<String> vipFlags) { public String playerContent(String flag, String id, List<String> vipFlags) {
try {
// 使用Cloud类处理云盘链接的播放
String cloudResult = cloud.playerContent(flag, id, vipFlags);
if (cloudResult != null) {
return cloudResult;
}
} catch (Exception e) {
SpiderDebug.log("Cloud playerContent error: " + e.getMessage());
}
// 原有逻辑处理其他类型链接
if (id.startsWith("http") && id.contains("***")) id = id.replace("***", "#"); 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().url(id).subs(getSubs(id)).string();
if (flag.equals("解析")) return Result.get().parse().jx().url(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().parse().url(id).string();
if (flag.equals("迅雷")) return Result.get().url(id).string(); if (flag.equals("迅雷")) return Result.get().url(id).string();
return ali.playerContent(flag, id, vipFlags); return Result.get().url(id).string();
} }
private Vod vod(String url) { private Vod vod(String url) {

View File

@ -54,9 +54,9 @@ public class Quark extends Spider {
}*/ }*/
for (int i = 1; i <= ids.size(); i++) { for (int i = 1; i <= ids.size(); i++) {
playFrom.add("quark原画" + i + index); playFrom.add(String.format("quark原画#%02d_%02d" ,i , index));
for (String s : QuarkApi.get().getPlayFormatList()) { for (String s : QuarkApi.get().getPlayFormatList()) {
playFrom.add(String.format(Locale.getDefault(), "quark" + s + "#%02d%02d", i, index)); playFrom.add(String.format(Locale.getDefault(), "quark" + s + "#%02d_%02d", i, index));
} }
@ -70,14 +70,15 @@ public class Quark extends Spider {
* @param ids share_link 集合 * @param ids share_link 集合
* @return 詳情內容視頻播放地址 * @return 詳情內容視頻播放地址
*/ */
public String detailContentVodPlayUrl(List<String> ids) throws Exception { public String detailContentVodPlayUrl(List<String> ids) {
List<String> playUrl = new ArrayList<>(); List<String> playUrl = new ArrayList<>();
for (String id : ids) { for (String id : ids) {
ShareData shareData = QuarkApi.get().getShareData(id); ShareData shareData = QuarkApi.get().getShareData(id);
try { try {
playUrl.add(QuarkApi.get().getVod(shareData).getVodPlayUrl()); playUrl.add(QuarkApi.get().getVod(shareData)==null?"":QuarkApi.get().getVod(shareData).getVodPlayUrl());
} catch (Exception e) { } catch (Exception e) {
SpiderDebug.log("获取播放地址出错:" + e.getMessage()); SpiderDebug.log("获取播放地址出错:" + e.getMessage());
playUrl.add("");
} }
} }
return TextUtils.join("$$$", playUrl); return TextUtils.join("$$$", playUrl);

View File

@ -0,0 +1,192 @@
package com.github.catvod.spider;
import android.text.TextUtils;
import android.util.Pair;
import org.json.JSONArray;
import org.json.JSONObject;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.net.OkHttp;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Qupans extends Cloud {
private static final String BASE_URL = "https://www.qupanshe.com";
private static final String DEFAULT_COVER_URL = "https://fs-im-kefu.7moor-fs1.com/ly/4d2c3f00-7d4c-11e5-af15-41bf63ae4ea0/1743950734122/baidu.jpg";
private String get(String url) {
Map<String, String> headers = new HashMap<>();
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
headers.put("Referer", BASE_URL);
return OkHttp.string(url, headers);
}
@Override
public String homeContent(boolean filter) {
try {
JSONObject result = new JSONObject();
JSONArray classes = new JSONArray();
String[][] types = {{"电影","3"}, {"电视剧","2"}, {"综艺","4"}, {"动漫","5"}, {"纪录片","6"}};
for (String[] type : types) {
JSONObject cls = new JSONObject();
cls.put("type_id", type[1]);
cls.put("type_name", type[0]);
classes.put(cls);
}
result.put("class", classes);
return result.toString();
} catch (Exception e) {
return "{\"class\":[]}";
}
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
try {
String html = get(BASE_URL + "/forum.php?mod=forumdisplay&fid=" + tid + "&page=" + pg);
Document doc = Jsoup.parse(html);
JSONArray list = new JSONArray();
for (Element item : doc.select("div.tit_box > a.s")) {
String title = item.text();
if (title.contains("公告") || title.contains("")) continue;
JSONObject vod = new JSONObject();
vod.put("vod_id", item.attr("href"));
vod.put("vod_name", title);
vod.put("vod_pic", DEFAULT_COVER_URL);
vod.put("vod_remarks", "");
list.put(vod);
}
return new JSONObject()
.put("list", list)
.put("page", pg)
.put("pagecount", "0")
.put("total", "0")
.toString();
} catch (Exception e) {
return "{\"list\":[]}";
}
}
@Override
public String detailContent(List<String> ids) {
try {
String vodId = ids.get(0);
String html = get(vodId.startsWith("http") ? vodId : BASE_URL + "/" + vodId);
Document doc = Jsoup.parse(html);
Vod vod = new Vod();
vod.setVodId(vodId);
vod.setVodName(doc.select("h1").first().text());
vod.setVodPic(DEFAULT_COVER_URL);
List<String> links = getLinks(doc);
if (!links.isEmpty()) {
String pwd = getPwd(doc);
for (int i = 0; i < links.size(); i++) {
String link = links.get(i);
if (!link.contains("pwd=") && !TextUtils.isEmpty(pwd)) {
links.set(i, link + "?pwd=" + pwd);
}
}
vod.setVodPlayFrom(super.detailContentVodPlayFrom(links));
vod.setVodPlayUrl(super.detailContentVodPlayUrl(links));
}
return Result.string(vod);
} catch (Exception e) {
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodName("加载失败");
vod.setVodPic(DEFAULT_COVER_URL);
return Result.string(vod);
}
}
private List<String> getLinks(Document doc) {
List<String> links = new ArrayList<>();
// 从a标签中提取链接
Elements linksElements = doc.select("a");
for (Element linkElement : linksElements) {
String href = linkElement.attr("href");
if (href.contains(".baidu")) {
links.add(href);
break; // 只提取第一个百度网盘链接
}
}
return links;
}
private String getPwd(Document doc) {
try {
// 使用正则表达式模式提取密码
String patternStr = "提取码:\\s*([A-Za-z0-9]{4})";
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(patternStr);
Element contentElement = doc.select("td.t_f").first();
if (contentElement != null) {
String text = contentElement.text();
java.util.regex.Matcher matcher = pattern.matcher(text);
if (matcher.find()) {
return matcher.group(1);
}
}
} catch (Exception e) {
// 忽略异常
}
return "";
}
@Override
public String searchContent(String key, boolean quick) {
return searchContent(key, quick, "1");
}
@Override
public String searchContent(String key, boolean quick, String pg) {
try {
Map<String, String> params = new HashMap<>();
params.put("searchsubmit", "yes");
params.put("srchtxt", key);
String[] fids = {"2", "3", "4", "5", "6"};
for (int i = 0; i < fids.length; i++) params.put("srchfid[" + i + "]", fids[i]);
Map<String, String> headers = new HashMap<>();
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
headers.put("content-type", "application/x-www-form-urlencoded");
String html = OkHttp.post(BASE_URL + "/search.php?mod=forum", params, headers).getBody();
Document doc = Jsoup.parse(html);
JSONArray list = new JSONArray();
for (Element item : doc.select("#threadlist ul li h3 > a")) {
JSONObject vod = new JSONObject();
vod.put("vod_id", item.attr("href"));
vod.put("vod_name", item.text());
vod.put("vod_pic", DEFAULT_COVER_URL);
vod.put("vod_remarks", "");
list.put(vod);
}
return new JSONObject()
.put("list", list)
.put("page", pg)
.put("pagecount", "1")
.put("total", list.length())
.toString();
} catch (Exception e) {
return "{\"list\":[]}";
}
}
}

View File

@ -0,0 +1,248 @@
package com.github.catvod.spider
import android.content.Context
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.net.OkHttp
import com.github.catvod.utils.Util
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import kotlinx.coroutines.*
import okhttp3.HttpUrl
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import java.net.URLEncoder
import java.util.concurrent.CopyOnWriteArrayList
import java.util.regex.Pattern
/**
* @author lushunming
*/
class SeedHub : Cloud() {
private val siteUrl = "https://www.seedhub.cc"
private val regexCategory: Pattern = Pattern.compile("/vodtype/(\\w+).html")
private val regexPageTotal: Pattern = Pattern.compile("\\$\\(\"\\.mac_total\"\\)\\.text\\('(\\d+)'\\);")
private var extend: JsonObject? = null
private val header: MutableMap<String?, String?>
get() {
val header: MutableMap<String?, String?> = HashMap<String?, String?>()
header.put("User-Agent", Util.MOBILE)
return header
}
@Throws(Exception::class)
override fun init(context: Context, extend: String) {
this.extend = JsonParser.parseString(extend).getAsJsonObject()
super.init(context, "")
}
override fun homeContent(filter: Boolean): String? {
val classes: MutableList<Class?> = ArrayList<Class?>()
val filters = LinkedHashMap<String?, MutableList<Filter?>?>()
val html = OkHttp.string(siteUrl, this.header)
val doc = Jsoup.parse(html)
parseClassFromDoc(doc, classes)
if (filter) {
parseFilterFromDoc(doc, filters)
}
return Result.string(classes, parseVodListFromDoc(doc), filters)
}
private fun parseFilterFromDoc(
doc: Document, filters: LinkedHashMap<String?, MutableList<Filter?>?>
) {
val groups = doc.select("div.sidebar-group")
for (group in groups) {
val clazz = group.select("p.sidebar-heading a")
if (clazz.attr("href").startsWith("/")) {
val name = clazz.text()
val url = clazz.attr("href")
val filter = group.select("ul.sidebar-sub-headers>li.sidebar-sub-header>a")
val filterList: MutableList<Filter?> = ArrayList<Filter?>()
val values: MutableList<Filter.Value> = ArrayList<Filter.Value>()
for (f in filter) {
val filterName = f.text()
val filterUrl = f.attr("href")
values.add(Filter.Value(filterName, filterUrl))
}
filterList.add(Filter("0", "分类", values))
filters[url] = filterList
}
}
}
/**
*获取分类
*/
private fun parseClassFromDoc(
doc: Document, classes: MutableList<Class?>
) {
val navs = doc.select("div.nav-item")
for (nav in navs) {
val link = nav.select("a")
if (link.attr("href").startsWith("/")) {
val name = nav.select("a").text()
val url = nav.select("a").attr("href")
classes.add(Class(url, name))
}
}
}
override fun categoryContent(
tid: String?, pg: String, filter: Boolean, extend: HashMap<String, String?>?
): String? {
var urlParams = tid
if (extend != null && extend.size > 0) {
extend.keys.forEach {
urlParams = extend[it]
}
}
val doc = Jsoup.parse(
OkHttp.string(
String.format("%s%s?page=%s", siteUrl, urlParams, pg), this.header
)
)
val page = pg.toInt()
val limit = 20
val total = Int.MAX_VALUE
return Result.get().vod(parseVodListFromDoc(doc)).page(page, 0, limit, total).string()
}
private fun parseVodListFromDoc(doc: Document): MutableList<Vod?> {
val list: MutableList<Vod?> = ArrayList<Vod?>()
val elements = doc.select("div.cover")
for (e in elements) {
val vodId = e.selectFirst(" a")!!.attr("href")
var vodPic = e.selectFirst("img")!!.attr("src")
if (!vodPic.startsWith("http")) {
vodPic = siteUrl + vodPic
}
val vodName = e.selectFirst("h2")!!.text()
val vodRemarks = e.select("ul >li")!!.text()
list.add(Vod(vodId, vodName, vodPic, vodRemarks))
}
return list
}
@Throws(Exception::class)
override fun detailContent(ids: MutableList<String?>): String? {
val vodId = ids.get(0)
val doc = Jsoup.parse(
OkHttp.string(
siteUrl + vodId, this.header
)
)
val infos = doc.select("div.cover-container >ul > li").text().replace(" ", "")
val item = Vod()
item.setVodId(vodId)
item.setVodName(doc.selectFirst("h1")!!.text())
item.setVodPic(doc.selectFirst("div.cover-container img")!!.attr("src"))
item.setVodArea(Util.getStrByRegex(Pattern.compile("制片国家/地区:(.*?)语言:"), infos))
item.setTypeName(Util.getStrByRegex(Pattern.compile("类型:(.*?)制片"), infos))
item.setVodDirector(Util.getStrByRegex(Pattern.compile("导演:(.*?)制片"), infos))
item.setVodActor(Util.getStrByRegex(Pattern.compile("主演:(.*?)类型"), infos))
item.setVodYear(Util.getStrByRegex(Pattern.compile("首播:(.*?)集数"), infos))
item.setVodRemarks(Util.getStrByRegex(Pattern.compile("豆瓣评分:(.*?)常用标签"), infos))
item.vodContent = doc.select("div.content > p").text()
val shareLinks: CopyOnWriteArrayList<String?> = CopyOnWriteArrayList<String?>()
val jobs = ArrayList<Job>()
runBlocking {
val docEle = doc.select("ul.pan-links > li > a")
docEle.filter { it.attr("data-link").contains("uc") }.take(2).forEach { element ->
jobs += CoroutineScope(Dispatchers.IO).launch {
var link = siteUrl + element.attr("href")
val movieTitle = HttpUrl.parse(link)?.queryParameter("movie_title")
link = HttpUrl.parse(link)?.newBuilder()?.removeAllQueryParameters("movie_title")
?.addEncodedQueryParameter(
"movie_title", URLEncoder.encode(movieTitle)
)?.build().toString()
val string = OkHttp.string(link, header)
val docEle = Jsoup.parse(string)
docEle.select("a.direct-pan").attr("href").let {
if (it.isNotEmpty()) {
shareLinks.add(it)
}
}
}
}
docEle.filter { it.attr("data-link").contains("baidu") }.take(2).forEach { element ->
jobs += CoroutineScope(Dispatchers.IO).launch {
var link = siteUrl + element.attr("href")
val movieTitle = HttpUrl.parse(link)?.queryParameter("movie_title")
link = HttpUrl.parse(link)?.newBuilder()?.removeAllQueryParameters("movie_title")
?.addEncodedQueryParameter(
"movie_title", URLEncoder.encode(movieTitle)
)?.build().toString()
val string = OkHttp.string(link, header)
val docEle = Jsoup.parse(string)
docEle.select("a.direct-pan").attr("href").let {
if (it.isNotEmpty()) {
shareLinks.add(it)
}
}
}
}
docEle.filter { it.attr("data-link").contains("quark") }.take(2).forEach { element ->
jobs += CoroutineScope(Dispatchers.IO).launch {
var link = siteUrl + element.attr("href")
val movieTitle = HttpUrl.parse(link)?.queryParameter("movie_title")
link = HttpUrl.parse(link)?.newBuilder()?.removeAllQueryParameters("movie_title")
?.addEncodedQueryParameter(
"movie_title", URLEncoder.encode(movieTitle)
)?.build().toString()
val string = OkHttp.string(link, header)
val docEle = Jsoup.parse(string)
docEle.select("a.direct-pan").attr("href").let {
if (it.isNotEmpty()) {
shareLinks.add(it)
}
}
}
}
jobs.joinAll()
item.vodPlayUrl = super.detailContentVodPlayUrl(java.util.ArrayList(shareLinks))
item.setVodPlayFrom(super.detailContentVodPlayFrom(java.util.ArrayList(shareLinks)))
}
return Result.string(item)
}
@Throws(Exception::class)
override fun searchContent(key: String?, quick: Boolean): String? {
return searchContent(key, "1")
}
@Throws(Exception::class)
override fun searchContent(key: String?, quick: Boolean, pg: String?): String? {
return searchContent(key, pg)
}
private fun searchContent(key: String?, pg: String?): String? {
val searchURL = siteUrl + String.format("/s/%s/?page=%s", URLEncoder.encode(key), pg)
val html = OkHttp.string(searchURL, this.header)
val doc = Jsoup.parse(html)
return Result.string(parseVodListFromDoc(doc))
}
}

View File

@ -1,211 +0,0 @@
package com.github.catvod.spider;
import com.github.catvod.bean.Class;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.ProxyVideo;
import com.github.catvod.utils.Util;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.*;
import java.nio.charset.Charset;
import java.util.*;
public class Supjav extends Spider {
private static final String siteUrl = "https://supjav.com/zh/";
private static final String playUrl = "https://lk1.supremejav.com/";
private HashMap<String, String> getHeaders() {
return getHeaders(siteUrl);
}
private HashMap<String, String> getHeaders(String referer) {
HashMap<String, String> headers = new HashMap<>();
headers.put("Referer", "https://supjav.com/");
headers.put("Host", "supjav.com");
headers.put("User-Agent", Util.CHROME);
return headers;
}
private HashMap<String, String> getTVVideoHeaders(String referer) {
HashMap<String, String> headers = new HashMap<>();
headers.put("Referer", referer);
headers.put("User-Agent", Util.CHROME);
return headers;
}
@Override
public String homeContent(boolean filter) {
List<Vod> list = new ArrayList<>();
List<Class> classes = new ArrayList<>();
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeaders()));
for (Element element : doc.select("ul.nav > li > a")) {
String href = element.attr("href");
if (href.split("/").length < 5) continue;
String typeId = href.replace(siteUrl, "");
String typeName = element.text();
classes.add(new Class(typeId, typeName));
}
for (Element element : doc.select("div.post")) {
String src = element.select("img").attr("src");
String data = element.select("img").attr("data-original");
String url = element.select("a").attr("href");
String name = element.select("a").attr("title");
String pic = StringUtils.isEmpty(data) ? src : data;
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) {
List<Vod> list = new ArrayList<>();
Document doc = Jsoup.parse(OkHttp.string(siteUrl + tid + "/page/" + pg, getHeaders()));
for (Element element : doc.select("div.post")) {
String pic = element.select("img").attr("data-original");
String url = element.select("a").attr("href");
String name = element.select("a").attr("title");
String id = url.split("/")[4];
list.add(new Vod(id, name, pic));
}
return Result.string(list);
}
@Override
public String detailContent(List<String> ids) {
Document doc = Jsoup.parse(OkHttp.string(siteUrl.concat(ids.get(0)), getHeaders()));
String name = doc.select("div.post-meta > img").attr("alt");
String img = doc.select("div.post-meta > img").attr("src");
String type = doc.select("p.cat > a").text();
String director = "", actor = "";
for (Element p : doc.select("div.cats > p")) {
if (p.select("span").text().contains("Maker")) {
director = p.select("a").text();
}
if (p.select("span").text().contains("Cast")) {
actor = p.select("a").text();
}
}
Vod vod = new Vod();
vod.setVodId(ids.get(0));
vod.setVodPic(img);
vod.setVodName(name);
vod.setVodActor(actor);
vod.setVodDirector(director);
vod.setTypeName(type);
Map<String, String> sites = new LinkedHashMap<>();
Elements sources = doc.select("a.btn-server");
for (int i = 0; i < sources.size(); i++) {
Element source = sources.get(i);
String sourceName = source.text();
if (sourceName.equals("TV")) continue;
String sourceUrl = source.attr("data-link");
sites.put(sourceName, "播放" + "$" + sourceUrl);
}
if (!sites.isEmpty()) {
vod.setVodPlayFrom(StringUtils.join(sites.keySet(), "$$$"));
vod.setVodPlayUrl(StringUtils.join(sites.values(), "$$$"));
}
return Result.string(vod);
}
@Override
public String searchContent(String key, boolean quick) throws UnsupportedEncodingException {
List<Vod> list = new ArrayList<>();
Document doc = Jsoup.parse(OkHttp.string(siteUrl.concat("?s=").concat(URLEncoder.encode(key, "UTF-8")), getHeaders()));
for (Element element : doc.select("div.post")) {
String pic = element.select("img").attr("data-original");
String url = element.select("a").attr("href");
String name = element.select("a").attr("title");
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 URISyntaxException, IOException {
String redirect = OkHttp.getLocation(playUrl + "supjav.php?c=" + new StringBuilder(id).reverse(), getTVVideoHeaders(playUrl + "supjav.php?l=" + id + "&bg=undefined"));
switch (flag) {
case "TV":
return parseTV(redirect);
case "ST":
return parseST(redirect);
case "FST":
return parseFST(redirect);
case "VOE":
return parseVOE(redirect);
default:
return Result.get().url(id).parse().string();
}
}
private String parseVOE(String redirect) {
String data = OkHttp.string(redirect, getTVVideoHeaders(playUrl));
redirect = Util.findByRegex("window.location.href = '(.*?)';", data, 1);
data = OkHttp.string(redirect, getTVVideoHeaders(playUrl));
String url=Util.findByRegex("prompt\\(\"Node\",(.*?)\\);", data, 1).trim().replace("\"", "");
return Result.get().url(ProxyVideo.buildCommonProxyUrl(url, Util.webHeaders(redirect))).header(getHeaders(redirect)).string();
}
private String parseFST(String redirect) {
String data = OkHttp.string(redirect, getTVVideoHeaders(playUrl));
return Result.get().url(Util.findByRegex("file:\"(.*?)\"}]", data, 1)).header(getHeaders(redirect)).string();
}
private String parseTV(String redirect) throws MalformedURLException {
String data = OkHttp.string(redirect, getTVVideoHeaders(Util.getHost(redirect)));
return Result.get().url(Util.getVar(data, "urlPlay")).header(getTVVideoHeaders(Util.getHost(redirect))).string();
}
private String parseST(String redirect) throws IOException {
String data = OkHttp.string(redirect, getTVVideoHeaders(playUrl));
String robot = Jsoup.parse(data).getElementById("robotlink").text();
robot = robot.substring(0, robot.indexOf("&token=") + 7);
for (String text : data.split("&token=")) {
if (!text.contains("').substring(")) continue;
robot = "https:/" + robot + text.split("'")[0] + "&stream=1";
String url = OkHttp.getLocation(robot, getTVVideoHeaders(redirect));
return Result.get().url(ProxyVideo.buildCommonProxyUrl(url, Util.webHeaders(robot))).header(getHeaders(redirect)).string();
}
return "";
}
private String parseDS(String redirect) throws URISyntaxException, IOException {
String host = "https://" + Util.getHost(redirect);
redirect = host + OkHttp.getLocation(redirect, getTVVideoHeaders(playUrl));
String data = OkHttp.string(redirect, getHeaders());
for (String text : data.split("'")) {
if (!text.startsWith("/pass_md5/")) continue;
String token = text.split("/")[3];
String url = OkHttp.string(host + text, getHeaders(redirect));
url = url + getDSRnd() + "?token=" + token + "&expiry=" + System.currentTimeMillis();
return Result.get().url(url).header(getHeaders(redirect)).string();
}
return "";
}
private String getDSRnd() {
StringBuilder sb = new StringBuilder();
String t = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (int o = 0; o < 10; o++)
sb.append(t.charAt((int) Math.floor(Math.random() * t.length())));
return sb.toString();
}
}

View File

@ -0,0 +1,56 @@
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.Json
import com.github.catvod.utils.Util
import java.net.URLEncoder
import java.nio.charset.Charset
/**
* @author zhixc
*/
class Tg123Search : Cloud() {
private val URL = "https://tgsou.252035.xyz/"
private val header: Map<String, String>
get() {
val header: MutableMap<String, String> = HashMap()
header["User-Agent"] = Util.CHROME
return header
}
@Throws(Exception::class)
override fun searchContent(key: String, quick: Boolean): String {
val url =
URL + "?channelUsername=wp123zy,xx123pan,yp123pan,zyfb123&pic=true&keyword=" + URLEncoder.encode(
key, Charset.defaultCharset().name()
)
val list: MutableList<Vod> = ArrayList()
val html = OkHttp.string(url, header)
val json = Json.safeObject(html);
json["results"].asJsonArray.forEach { element ->
val array = element.asString.split("$$$")
if (array.size >= 2 && array[1].isNotEmpty()) {
array[1].split("##").forEach {
val id = it.split("@")[0]
val pic = it.split("@")[1].split("$$")[0]
val name = it.split("@")[1].split("$$")[1]
list.add(Vod(id, name, pic, ""))
}
}
}
return Result.string(list)
}
}

View File

@ -3,8 +3,8 @@ package com.github.catvod.spider
import com.github.catvod.bean.Result import com.github.catvod.bean.Result
import com.github.catvod.bean.Vod import com.github.catvod.bean.Vod
import com.github.catvod.net.OkHttp import com.github.catvod.net.OkHttp
import com.github.catvod.utils.Json
import com.github.catvod.utils.Util import com.github.catvod.utils.Util
import org.jsoup.Jsoup
import java.net.URLEncoder import java.net.URLEncoder
import java.nio.charset.Charset import java.nio.charset.Charset
@ -12,7 +12,7 @@ import java.nio.charset.Charset
* @author zhixc * @author zhixc
*/ */
class Tg189Search : Cloud() { class Tg189Search : Cloud() {
private val URL = "https://tg.252035.xyz/" private val URL = "https://tgsou.252035.xyz/"
private val header: Map<String, String> private val header: Map<String, String>
get() { get() {
@ -30,16 +30,24 @@ class Tg189Search : Cloud() {
) )
val list: MutableList<Vod> = ArrayList() val list: MutableList<Vod> = ArrayList()
val html = OkHttp.string(url, header) val html = OkHttp.string(url, header)
val arr = html.split(":I".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() val json = Json.safeObject(html);
if (arr.isNotEmpty()) { json["results"].asJsonArray.forEach { element ->
for (s in arr) { val array = element.asString.split("$$$")
val doc = Jsoup.parse(s) if (array.size >= 2 && array[1].isNotEmpty()) {
val id = doc.select(" a").eachAttr("href") array[1].split("##").forEach {
.first { it.contains("189") || it.contains("139") }
val name=doc.select("strong").text()
val id = it.split("@")[0]
val pic = it.split("@")[1].split("$$")[0]
val name = it.split("@")[1].split("$$")[1]
list.add(Vod(id, name, pic, ""))
}
list.add(Vod(id, name, "", ""))
} }
} }

View File

@ -3,8 +3,8 @@ package com.github.catvod.spider
import com.github.catvod.bean.Result import com.github.catvod.bean.Result
import com.github.catvod.bean.Vod import com.github.catvod.bean.Vod
import com.github.catvod.net.OkHttp import com.github.catvod.net.OkHttp
import com.github.catvod.utils.Json
import com.github.catvod.utils.Util import com.github.catvod.utils.Util
import org.jsoup.Jsoup
import java.net.URLEncoder import java.net.URLEncoder
import java.nio.charset.Charset import java.nio.charset.Charset
@ -12,12 +12,11 @@ import java.nio.charset.Charset
* @author zhixc * @author zhixc
*/ */
class TgQuarkSearch : Cloud() { class TgQuarkSearch : Cloud() {
private val URL = "https://tg.252035.xyz/" private val URL = "https://tgsou.252035.xyz/"
private val header: Map<String, String> private val header: Map<String, String>
get() { get() {
val header: MutableMap<String, String> = val header: MutableMap<String, String> = HashMap()
HashMap()
header["User-Agent"] = Util.CHROME header["User-Agent"] = Util.CHROME
return header return header
} }
@ -27,23 +26,32 @@ class TgQuarkSearch : Cloud() {
override fun searchContent(key: String, quick: Boolean): String { override fun searchContent(key: String, quick: Boolean): String {
val url = val url =
URL + "?channelUsername=alyp_1,clouddriveresources,dianyingshare,hdhhd21,jdjdn1111,leoziyuan,NewQuark,PanjClub,Quark_Movies,xiangxiunb,yunpanchat,yunpanqk,XiangxiuNB,alyp_4K_Movies,alyp_Animation,alyp_TV,alyp_JLP&pic=true&keyword=" + URLEncoder.encode( URL + "?channelUsername=alyp_1,clouddriveresources,dianyingshare,hdhhd21,jdjdn1111,leoziyuan,NewQuark,PanjClub,Quark_Movies,xiangxiunb,yunpanchat,yunpanqk,XiangxiuNB,alyp_4K_Movies,alyp_Animation,alyp_TV,alyp_JLP&pic=true&keyword=" + URLEncoder.encode(
key, key, Charset.defaultCharset().name()
Charset.defaultCharset().name()
) )
val list: MutableList<Vod> = ArrayList() val list: MutableList<Vod> = ArrayList()
val html = OkHttp.string(url, header) val html = OkHttp.string(url, header)
val arr = html.split(":I".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() val json = Json.safeObject(html);
if (arr.size > 0) { json["results"].asJsonArray.forEach { element ->
for (s in arr) { val array = element.asString.split("$$$")
val doc = Jsoup.parse(s) if (array.size >= 2 && array[1].isNotEmpty()) {
val id = doc.select(" a").eachAttr("href") array[1].split("##").forEach {
.first { it.contains("189") || it.contains("139")|| it.contains("quark") }
val name=doc.select("strong").text()
list.add(Vod(id, name, "", "")) val id = it.split("@")[0]
val pic = it.split("@")[1].split("$$")[0]
val name = it.split("@")[1].split("$$")[1]
list.add(Vod(id, name, pic, ""))
}
} }
} }
return Result.string(list) return Result.string(list)
} }
} }

View File

@ -0,0 +1,258 @@
package com.github.catvod.spider;
import android.content.Context;
import android.text.TextUtils;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.net.OkHttp;
import com.github.catvod.net.OkResult;
import com.github.catvod.utils.Json;
import com.github.catvod.utils.Util;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.*;
public class TgSearch123 extends Cloud {
private static final String KEY_API_URLS = "api_urls";
private static final String KEY_DOMAIN_MAP = "siteurl";
private static final String KEY_SOURCES = "sources";
private static final int DEFAULT_PAGE_SIZE = 10;
private List<String> apiUrls = new ArrayList<>();
private Map<String, String> domainMap = new HashMap<String, String>() {{
put("alipan", "阿里");
put("aliyundrive", "阿里");
put("quark", "夸克");
put("115cdn", "115");
put("baidu.com", "百度");
put("uc", "UC");
put("189.cn", "天翼");
put("139.com", "移动");
put("123", "123盘");
}};
private Set<String> sources = new HashSet<>();
private String[] extInfos = null;
@Override
public synchronized void init(Context context, String extend) throws Exception {
super.init(context, extend);
this.apiUrls.clear();
if (!TextUtils.isEmpty(extend)) {
try {
if (extend.contains("###")) {
String[] infos = extend.split("###");
this.extInfos = infos;
if (infos.length > 0 && !TextUtils.isEmpty(infos[0])) {
processExtendConfig(infos[0]);
}
} else {
this.extInfos = new String[]{extend};
processExtendConfig(extend);
}
} catch (Exception e) {
}
}
this.extInfos = null; // 重置避免内存泄漏
}
private void processExtendConfig(String config) {
try {
// 检查是否为HTTP URL
if (isValidUrl(config)) {
if (!this.apiUrls.contains(config)) {
this.apiUrls.add(config);
}
return;
}
// 尝试JSON格式解析
JsonObject ext = Json.safeObject(config);
// 处理API URLs配置
processApiUrls(ext);
// 处理域名映射配置
processDomainMap(ext);
// 处理来源过滤配置
processSources(ext, true);
} catch (Exception e) {
// 可以添加日志记录
}
}
private void processApiUrls(JsonObject config) {
if (config.has(KEY_API_URLS) && config.get(KEY_API_URLS).isJsonArray()) {
JsonArray urlsArray = config.getAsJsonArray(KEY_API_URLS);
for (JsonElement element : urlsArray) {
if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) {
String url = element.getAsString();
if (isValidUrl(url) && !this.apiUrls.contains(url)) {
this.apiUrls.add(url);
}
}
}
}
}
private void processDomainMap(JsonObject config) {
if (config.has(KEY_DOMAIN_MAP) && config.get(KEY_DOMAIN_MAP).isJsonObject()) {
JsonObject customDomains = config.getAsJsonObject(KEY_DOMAIN_MAP);
for (Map.Entry<String, JsonElement> entry : customDomains.entrySet()) {
if (entry == null || entry.getValue() == null) continue;
String domain = entry.getKey();
String sourceName = "";
try {
sourceName = entry.getValue().getAsString();
} catch (Exception e) {
continue;
}
if (!TextUtils.isEmpty(domain) && !TextUtils.isEmpty(sourceName) && !domainMap.containsKey(domain)) {
domainMap.put(domain, sourceName);
}
}
}
}
private void processSources(JsonObject config, boolean clearExisting) {
if (config.has(KEY_SOURCES) && config.get(KEY_SOURCES).isJsonArray()) {
if (clearExisting) {
this.sources.clear();
}
JsonArray sourcesArray = config.getAsJsonArray(KEY_SOURCES);
for (JsonElement element : sourcesArray) {
if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) {
String source = element.getAsString();
if (!TextUtils.isEmpty(source) && !sources.contains(source)) {
sources.add(source);
}
}
}
}
}
private boolean isValidUrl(String url) {
return !TextUtils.isEmpty(url) && (url.startsWith("http://") || url.startsWith("https://"));
}
private Map<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 {
if (key == null || key.trim().isEmpty()) {
return Result.error("关键词不能为空");
}
return performSearch(key, 1, DEFAULT_PAGE_SIZE);
}
private String performSearch(String key, int page, int pageSize) throws Exception {
List<Vod> list = new ArrayList<>();
int total = 0;
Map<String, String> params = new HashMap<>();
params.put("kw", key);
params.put("page", String.valueOf(page));
params.put("size", String.valueOf(pageSize));
for (String apiUrl : apiUrls) {
if (!isValidUrl(apiUrl)) continue;
try {
OkResult result = OkHttp.get(apiUrl, params, getHeader());
if (result.getCode() == 500 || TextUtils.isEmpty(result.getBody())) continue;
JsonObject jsonObject = Json.safeObject(result.getBody());
if (!jsonObject.has("code") || jsonObject.get("code").getAsInt() != 0 || !jsonObject.has("data"))
continue;
JsonObject data = jsonObject.getAsJsonObject("data");
total = data.has("total") && !data.get("total").isJsonNull() ? data.get("total").getAsInt() : 0;
// 直接检查merged_by_type字段无需三重判断
if (!data.has("merged_by_type") || !data.get("merged_by_type").isJsonObject()) continue;
JsonObject mergedByType = data.getAsJsonObject("merged_by_type");
for (Map.Entry<String, JsonElement> categoryEntry : mergedByType.entrySet()) {
if (!categoryEntry.getValue().isJsonArray()) continue;
JsonArray items = categoryEntry.getValue().getAsJsonArray();
for (JsonElement item : items) {
if (!item.isJsonObject()) continue;
JsonObject entry = item.getAsJsonObject();
String vodUrl = entry.has("url") && !entry.get("url").isJsonNull() ? entry.get("url").getAsString() : "";
if (TextUtils.isEmpty(vodUrl)) continue;
// 获取来源信息并映射
String originalSource = entry.has("source") && !entry.get("source").isJsonNull() ? entry.get("source").getAsString() : "未知来源";
String sourceName = mapSource(vodUrl, originalSource);
// 获取标题
String title = entry.has("note") && !entry.get("note").isJsonNull() ? entry.get("note").getAsString() : "未命名资源";
// 获取图片
String pic = getFirstImage(entry);
// 简化VodPlayBuilder的使用
Vod vod = new Vod(vodUrl, title, pic, sourceName + " (" + originalSource + ")");
// 由于只有一个播放源直接设置播放信息
vod.setVodPlayFrom(sourceName);
vod.setVodPlayUrl("播放源$" + vodUrl);
// 来源过滤
if (sources.isEmpty() || sources.contains(sourceName)) {
list.add(vod);
}
}
}
int pageCount = total > 0 && pageSize > 0 ? (total + pageSize - 1) / pageSize : 1;
return Result.string(page, pageCount, pageSize, total, list);
} catch (Exception e) {
// 出错时继续尝试下一个API
continue;
}
}
return Result.error("无法连接到任何搜索API");
}
// 提取来源映射逻辑为单独方法
private String mapSource(String vodUrl, String originalSource) {
for (Map.Entry<String, String> domainEntry : domainMap.entrySet()) {
if (vodUrl.contains(domainEntry.getKey())) {
return domainEntry.getValue();
}
}
return originalSource;
}
// 提取图片获取逻辑为单独方法
private String getFirstImage(JsonObject entry) {
if (entry.has("images") && !entry.get("images").isJsonNull() && entry.get("images").isJsonArray()) {
JsonArray images = entry.getAsJsonArray("images");
if (images.size() > 0 && !images.get(0).isJsonNull() && images.get(0).isJsonPrimitive()) {
return images.get(0).getAsString();
}
}
return "";
}
}

View File

@ -0,0 +1,258 @@
package com.github.catvod.spider;
import android.content.Context;
import android.text.TextUtils;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.net.OkHttp;
import com.github.catvod.net.OkResult;
import com.github.catvod.utils.Json;
import com.github.catvod.utils.Util;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.*;
public class TgSearch139 extends Cloud {
private static final String KEY_API_URLS = "api_urls";
private static final String KEY_DOMAIN_MAP = "siteurl";
private static final String KEY_SOURCES = "sources";
private static final int DEFAULT_PAGE_SIZE = 10;
private List<String> apiUrls = new ArrayList<>();
private Map<String, String> domainMap = new HashMap<String, String>() {{
put("alipan", "阿里");
put("aliyundrive", "阿里");
put("quark", "夸克");
put("115cdn", "115");
put("baidu.com", "百度");
put("uc", "UC");
put("189.cn", "天翼");
put("139.com", "移动");
put("123", "123盘");
}};
private Set<String> sources = new HashSet<>();
private String[] extInfos = null;
@Override
public synchronized void init(Context context, String extend) throws Exception {
super.init(context, extend);
this.apiUrls.clear();
if (!TextUtils.isEmpty(extend)) {
try {
if (extend.contains("###")) {
String[] infos = extend.split("###");
this.extInfos = infos;
if (infos.length > 0 && !TextUtils.isEmpty(infos[0])) {
processExtendConfig(infos[0]);
}
} else {
this.extInfos = new String[]{extend};
processExtendConfig(extend);
}
} catch (Exception e) {
}
}
this.extInfos = null; // 重置避免内存泄漏
}
private void processExtendConfig(String config) {
try {
// 检查是否为HTTP URL
if (isValidUrl(config)) {
if (!this.apiUrls.contains(config)) {
this.apiUrls.add(config);
}
return;
}
// 尝试JSON格式解析
JsonObject ext = Json.safeObject(config);
// 处理API URLs配置
processApiUrls(ext);
// 处理域名映射配置
processDomainMap(ext);
// 处理来源过滤配置
processSources(ext, true);
} catch (Exception e) {
// 可以添加日志记录
}
}
private void processApiUrls(JsonObject config) {
if (config.has(KEY_API_URLS) && config.get(KEY_API_URLS).isJsonArray()) {
JsonArray urlsArray = config.getAsJsonArray(KEY_API_URLS);
for (JsonElement element : urlsArray) {
if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) {
String url = element.getAsString();
if (isValidUrl(url) && !this.apiUrls.contains(url)) {
this.apiUrls.add(url);
}
}
}
}
}
private void processDomainMap(JsonObject config) {
if (config.has(KEY_DOMAIN_MAP) && config.get(KEY_DOMAIN_MAP).isJsonObject()) {
JsonObject customDomains = config.getAsJsonObject(KEY_DOMAIN_MAP);
for (Map.Entry<String, JsonElement> entry : customDomains.entrySet()) {
if (entry == null || entry.getValue() == null) continue;
String domain = entry.getKey();
String sourceName = "";
try {
sourceName = entry.getValue().getAsString();
} catch (Exception e) {
continue;
}
if (!TextUtils.isEmpty(domain) && !TextUtils.isEmpty(sourceName) && !domainMap.containsKey(domain)) {
domainMap.put(domain, sourceName);
}
}
}
}
private void processSources(JsonObject config, boolean clearExisting) {
if (config.has(KEY_SOURCES) && config.get(KEY_SOURCES).isJsonArray()) {
if (clearExisting) {
this.sources.clear();
}
JsonArray sourcesArray = config.getAsJsonArray(KEY_SOURCES);
for (JsonElement element : sourcesArray) {
if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) {
String source = element.getAsString();
if (!TextUtils.isEmpty(source) && !sources.contains(source)) {
sources.add(source);
}
}
}
}
}
private boolean isValidUrl(String url) {
return !TextUtils.isEmpty(url) && (url.startsWith("http://") || url.startsWith("https://"));
}
private Map<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 {
if (key == null || key.trim().isEmpty()) {
return Result.error("关键词不能为空");
}
return performSearch(key, 1, DEFAULT_PAGE_SIZE);
}
private String performSearch(String key, int page, int pageSize) throws Exception {
List<Vod> list = new ArrayList<>();
int total = 0;
Map<String, String> params = new HashMap<>();
params.put("kw", key);
params.put("page", String.valueOf(page));
params.put("size", String.valueOf(pageSize));
for (String apiUrl : apiUrls) {
if (!isValidUrl(apiUrl)) continue;
try {
OkResult result = OkHttp.get(apiUrl, params, getHeader());
if (result.getCode() == 500 || TextUtils.isEmpty(result.getBody())) continue;
JsonObject jsonObject = Json.safeObject(result.getBody());
if (!jsonObject.has("code") || jsonObject.get("code").getAsInt() != 0 || !jsonObject.has("data"))
continue;
JsonObject data = jsonObject.getAsJsonObject("data");
total = data.has("total") && !data.get("total").isJsonNull() ? data.get("total").getAsInt() : 0;
// 直接检查merged_by_type字段无需三重判断
if (!data.has("merged_by_type") || !data.get("merged_by_type").isJsonObject()) continue;
JsonObject mergedByType = data.getAsJsonObject("merged_by_type");
for (Map.Entry<String, JsonElement> categoryEntry : mergedByType.entrySet()) {
if (!categoryEntry.getValue().isJsonArray()) continue;
JsonArray items = categoryEntry.getValue().getAsJsonArray();
for (JsonElement item : items) {
if (!item.isJsonObject()) continue;
JsonObject entry = item.getAsJsonObject();
String vodUrl = entry.has("url") && !entry.get("url").isJsonNull() ? entry.get("url").getAsString() : "";
if (TextUtils.isEmpty(vodUrl)) continue;
// 获取来源信息并映射
String originalSource = entry.has("source") && !entry.get("source").isJsonNull() ? entry.get("source").getAsString() : "未知来源";
String sourceName = mapSource(vodUrl, originalSource);
// 获取标题
String title = entry.has("note") && !entry.get("note").isJsonNull() ? entry.get("note").getAsString() : "未命名资源";
// 获取图片
String pic = getFirstImage(entry);
// 简化VodPlayBuilder的使用
Vod vod = new Vod(vodUrl, title, pic, sourceName + " (" + originalSource + ")");
// 由于只有一个播放源直接设置播放信息
vod.setVodPlayFrom(sourceName);
vod.setVodPlayUrl("播放源$" + vodUrl);
// 来源过滤
if (sources.isEmpty() || sources.contains(sourceName)) {
list.add(vod);
}
}
}
int pageCount = total > 0 && pageSize > 0 ? (total + pageSize - 1) / pageSize : 1;
return Result.string(page, pageCount, pageSize, total, list);
} catch (Exception e) {
// 出错时继续尝试下一个API
continue;
}
}
return Result.error("无法连接到任何搜索API");
}
// 提取来源映射逻辑为单独方法
private String mapSource(String vodUrl, String originalSource) {
for (Map.Entry<String, String> domainEntry : domainMap.entrySet()) {
if (vodUrl.contains(domainEntry.getKey())) {
return domainEntry.getValue();
}
}
return originalSource;
}
// 提取图片获取逻辑为单独方法
private String getFirstImage(JsonObject entry) {
if (entry.has("images") && !entry.get("images").isJsonNull() && entry.get("images").isJsonArray()) {
JsonArray images = entry.getAsJsonArray("images");
if (images.size() > 0 && !images.get(0).isJsonNull() && images.get(0).isJsonPrimitive()) {
return images.get(0).getAsString();
}
}
return "";
}
}

View File

@ -0,0 +1,258 @@
package com.github.catvod.spider;
import android.content.Context;
import android.text.TextUtils;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.net.OkHttp;
import com.github.catvod.net.OkResult;
import com.github.catvod.utils.Json;
import com.github.catvod.utils.Util;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.*;
public class TgSearch189 extends Cloud {
private static final String KEY_API_URLS = "api_urls";
private static final String KEY_DOMAIN_MAP = "siteurl";
private static final String KEY_SOURCES = "sources";
private static final int DEFAULT_PAGE_SIZE = 10;
private List<String> apiUrls = new ArrayList<>();
private Map<String, String> domainMap = new HashMap<String, String>() {{
put("alipan", "阿里");
put("aliyundrive", "阿里");
put("quark", "夸克");
put("115cdn", "115");
put("baidu.com", "百度");
put("uc", "UC");
put("189.cn", "天翼");
put("139.com", "移动");
put("123", "123盘");
}};
private Set<String> sources = new HashSet<>();
private String[] extInfos = null;
@Override
public synchronized void init(Context context, String extend) throws Exception {
super.init(context, extend);
this.apiUrls.clear();
if (!TextUtils.isEmpty(extend)) {
try {
if (extend.contains("###")) {
String[] infos = extend.split("###");
this.extInfos = infos;
if (infos.length > 0 && !TextUtils.isEmpty(infos[0])) {
processExtendConfig(infos[0]);
}
} else {
this.extInfos = new String[]{extend};
processExtendConfig(extend);
}
} catch (Exception e) {
}
}
this.extInfos = null; // 重置避免内存泄漏
}
private void processExtendConfig(String config) {
try {
// 检查是否为HTTP URL
if (isValidUrl(config)) {
if (!this.apiUrls.contains(config)) {
this.apiUrls.add(config);
}
return;
}
// 尝试JSON格式解析
JsonObject ext = Json.safeObject(config);
// 处理API URLs配置
processApiUrls(ext);
// 处理域名映射配置
processDomainMap(ext);
// 处理来源过滤配置
processSources(ext, true);
} catch (Exception e) {
// 可以添加日志记录
}
}
private void processApiUrls(JsonObject config) {
if (config.has(KEY_API_URLS) && config.get(KEY_API_URLS).isJsonArray()) {
JsonArray urlsArray = config.getAsJsonArray(KEY_API_URLS);
for (JsonElement element : urlsArray) {
if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) {
String url = element.getAsString();
if (isValidUrl(url) && !this.apiUrls.contains(url)) {
this.apiUrls.add(url);
}
}
}
}
}
private void processDomainMap(JsonObject config) {
if (config.has(KEY_DOMAIN_MAP) && config.get(KEY_DOMAIN_MAP).isJsonObject()) {
JsonObject customDomains = config.getAsJsonObject(KEY_DOMAIN_MAP);
for (Map.Entry<String, JsonElement> entry : customDomains.entrySet()) {
if (entry == null || entry.getValue() == null) continue;
String domain = entry.getKey();
String sourceName = "";
try {
sourceName = entry.getValue().getAsString();
} catch (Exception e) {
continue;
}
if (!TextUtils.isEmpty(domain) && !TextUtils.isEmpty(sourceName) && !domainMap.containsKey(domain)) {
domainMap.put(domain, sourceName);
}
}
}
}
private void processSources(JsonObject config, boolean clearExisting) {
if (config.has(KEY_SOURCES) && config.get(KEY_SOURCES).isJsonArray()) {
if (clearExisting) {
this.sources.clear();
}
JsonArray sourcesArray = config.getAsJsonArray(KEY_SOURCES);
for (JsonElement element : sourcesArray) {
if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) {
String source = element.getAsString();
if (!TextUtils.isEmpty(source) && !sources.contains(source)) {
sources.add(source);
}
}
}
}
}
private boolean isValidUrl(String url) {
return !TextUtils.isEmpty(url) && (url.startsWith("http://") || url.startsWith("https://"));
}
private Map<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 {
if (key == null || key.trim().isEmpty()) {
return Result.error("关键词不能为空");
}
return performSearch(key, 1, DEFAULT_PAGE_SIZE);
}
private String performSearch(String key, int page, int pageSize) throws Exception {
List<Vod> list = new ArrayList<>();
int total = 0;
Map<String, String> params = new HashMap<>();
params.put("kw", key);
params.put("page", String.valueOf(page));
params.put("size", String.valueOf(pageSize));
for (String apiUrl : apiUrls) {
if (!isValidUrl(apiUrl)) continue;
try {
OkResult result = OkHttp.get(apiUrl, params, getHeader());
if (result.getCode() == 500 || TextUtils.isEmpty(result.getBody())) continue;
JsonObject jsonObject = Json.safeObject(result.getBody());
if (!jsonObject.has("code") || jsonObject.get("code").getAsInt() != 0 || !jsonObject.has("data"))
continue;
JsonObject data = jsonObject.getAsJsonObject("data");
total = data.has("total") && !data.get("total").isJsonNull() ? data.get("total").getAsInt() : 0;
// 直接检查merged_by_type字段无需三重判断
if (!data.has("merged_by_type") || !data.get("merged_by_type").isJsonObject()) continue;
JsonObject mergedByType = data.getAsJsonObject("merged_by_type");
for (Map.Entry<String, JsonElement> categoryEntry : mergedByType.entrySet()) {
if (!categoryEntry.getValue().isJsonArray()) continue;
JsonArray items = categoryEntry.getValue().getAsJsonArray();
for (JsonElement item : items) {
if (!item.isJsonObject()) continue;
JsonObject entry = item.getAsJsonObject();
String vodUrl = entry.has("url") && !entry.get("url").isJsonNull() ? entry.get("url").getAsString() : "";
if (TextUtils.isEmpty(vodUrl)) continue;
// 获取来源信息并映射
String originalSource = entry.has("source") && !entry.get("source").isJsonNull() ? entry.get("source").getAsString() : "未知来源";
String sourceName = mapSource(vodUrl, originalSource);
// 获取标题
String title = entry.has("note") && !entry.get("note").isJsonNull() ? entry.get("note").getAsString() : "未命名资源";
// 获取图片
String pic = getFirstImage(entry);
// 简化VodPlayBuilder的使用
Vod vod = new Vod(vodUrl, title, pic, sourceName + " (" + originalSource + ")");
// 由于只有一个播放源直接设置播放信息
vod.setVodPlayFrom(sourceName);
vod.setVodPlayUrl("播放源$" + vodUrl);
// 来源过滤
if (sources.isEmpty() || sources.contains(sourceName)) {
list.add(vod);
}
}
}
int pageCount = total > 0 && pageSize > 0 ? (total + pageSize - 1) / pageSize : 1;
return Result.string(page, pageCount, pageSize, total, list);
} catch (Exception e) {
// 出错时继续尝试下一个API
continue;
}
}
return Result.error("无法连接到任何搜索API");
}
// 提取来源映射逻辑为单独方法
private String mapSource(String vodUrl, String originalSource) {
for (Map.Entry<String, String> domainEntry : domainMap.entrySet()) {
if (vodUrl.contains(domainEntry.getKey())) {
return domainEntry.getValue();
}
}
return originalSource;
}
// 提取图片获取逻辑为单独方法
private String getFirstImage(JsonObject entry) {
if (entry.has("images") && !entry.get("images").isJsonNull() && entry.get("images").isJsonArray()) {
JsonArray images = entry.getAsJsonArray("images");
if (images.size() > 0 && !images.get(0).isJsonNull() && images.get(0).isJsonPrimitive()) {
return images.get(0).getAsString();
}
}
return "";
}
}

View File

@ -11,19 +11,15 @@ import com.github.catvod.utils.Util;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import java.util.ArrayList;
import java.util.HashMap; import java.util.*;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class TgSearchBaidu extends Cloud { public class TgSearchBaidu extends Cloud {
private static final String KEY_API_URLS = "api_urls"; private static final String KEY_API_URLS = "api_urls";
private static final String KEY_DOMAIN_MAP = "siteurl"; private static final String KEY_DOMAIN_MAP = "siteurl";
private static final String KEY_SOURCES = "sources"; private static final String KEY_SOURCES = "sources";
private static final int DEFAULT_PAGE_SIZE = 10; private static final int DEFAULT_PAGE_SIZE = 10;
private List<String> apiUrls = new ArrayList<>(); private List<String> apiUrls = new ArrayList<>();
private Map<String, String> domainMap = new HashMap<String, String>() {{ private Map<String, String> domainMap = new HashMap<String, String>() {{
put("alipan", "阿里"); put("alipan", "阿里");
@ -42,15 +38,15 @@ public class TgSearchBaidu extends Cloud {
@Override @Override
public synchronized void init(Context context, String extend) throws Exception { public synchronized void init(Context context, String extend) throws Exception {
super.init(context, extend); super.init(context, extend);
this.apiUrls.clear(); this.apiUrls.clear();
if (!TextUtils.isEmpty(extend)) { if (!TextUtils.isEmpty(extend)) {
try { try {
if (extend.contains("###")) { if (extend.contains("###")) {
String[] infos = extend.split("###"); String[] infos = extend.split("###");
this.extInfos = infos; this.extInfos = infos;
if (infos.length > 0 && !TextUtils.isEmpty(infos[0])) { if (infos.length > 0 && !TextUtils.isEmpty(infos[0])) {
processExtendConfig(infos[0]); processExtendConfig(infos[0]);
} }
@ -58,11 +54,12 @@ public class TgSearchBaidu extends Cloud {
this.extInfos = new String[]{extend}; this.extInfos = new String[]{extend};
processExtendConfig(extend); processExtendConfig(extend);
} }
} catch (Exception e) {} } catch (Exception e) {
}
} }
this.extInfos = null; // 重置避免内存泄漏 this.extInfos = null; // 重置避免内存泄漏
} }
private void processExtendConfig(String config) { private void processExtendConfig(String config) {
try { try {
// 检查是否为HTTP URL // 检查是否为HTTP URL
@ -72,23 +69,23 @@ public class TgSearchBaidu extends Cloud {
} }
return; return;
} }
// 尝试JSON格式解析 // 尝试JSON格式解析
JsonObject ext = Json.safeObject(config); JsonObject ext = Json.safeObject(config);
// 处理API URLs配置 // 处理API URLs配置
processApiUrls(ext); processApiUrls(ext);
// 处理域名映射配置 // 处理域名映射配置
processDomainMap(ext); processDomainMap(ext);
// 处理来源过滤配置 // 处理来源过滤配置
processSources(ext, true); processSources(ext, true);
} catch (Exception e) { } catch (Exception e) {
// 可以添加日志记录 // 可以添加日志记录
} }
} }
private void processApiUrls(JsonObject config) { private void processApiUrls(JsonObject config) {
if (config.has(KEY_API_URLS) && config.get(KEY_API_URLS).isJsonArray()) { if (config.has(KEY_API_URLS) && config.get(KEY_API_URLS).isJsonArray()) {
JsonArray urlsArray = config.getAsJsonArray(KEY_API_URLS); JsonArray urlsArray = config.getAsJsonArray(KEY_API_URLS);
@ -102,30 +99,34 @@ public class TgSearchBaidu extends Cloud {
} }
} }
} }
private void processDomainMap(JsonObject config) { private void processDomainMap(JsonObject config) {
if (config.has(KEY_DOMAIN_MAP) && config.get(KEY_DOMAIN_MAP).isJsonObject()) { if (config.has(KEY_DOMAIN_MAP) && config.get(KEY_DOMAIN_MAP).isJsonObject()) {
JsonObject customDomains = config.getAsJsonObject(KEY_DOMAIN_MAP); JsonObject customDomains = config.getAsJsonObject(KEY_DOMAIN_MAP);
for (Map.Entry<String, JsonElement> entry : customDomains.entrySet()) { for (Map.Entry<String, JsonElement> entry : customDomains.entrySet()) {
if (entry == null || entry.getValue() == null) continue; if (entry == null || entry.getValue() == null) continue;
String domain = entry.getKey(); String domain = entry.getKey();
String sourceName = ""; String sourceName = "";
try { sourceName = entry.getValue().getAsString(); } catch (Exception e) { continue; } try {
sourceName = entry.getValue().getAsString();
} catch (Exception e) {
continue;
}
if (!TextUtils.isEmpty(domain) && !TextUtils.isEmpty(sourceName) && !domainMap.containsKey(domain)) { if (!TextUtils.isEmpty(domain) && !TextUtils.isEmpty(sourceName) && !domainMap.containsKey(domain)) {
domainMap.put(domain, sourceName); domainMap.put(domain, sourceName);
} }
} }
} }
} }
private void processSources(JsonObject config, boolean clearExisting) { private void processSources(JsonObject config, boolean clearExisting) {
if (config.has(KEY_SOURCES) && config.get(KEY_SOURCES).isJsonArray()) { if (config.has(KEY_SOURCES) && config.get(KEY_SOURCES).isJsonArray()) {
if (clearExisting) { if (clearExisting) {
this.sources.clear(); this.sources.clear();
} }
JsonArray sourcesArray = config.getAsJsonArray(KEY_SOURCES); JsonArray sourcesArray = config.getAsJsonArray(KEY_SOURCES);
for (JsonElement element : sourcesArray) { for (JsonElement element : sourcesArray) {
if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) { if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) {
@ -141,7 +142,6 @@ public class TgSearchBaidu extends Cloud {
private boolean isValidUrl(String url) { private boolean isValidUrl(String url) {
return !TextUtils.isEmpty(url) && (url.startsWith("http://") || url.startsWith("https://")); return !TextUtils.isEmpty(url) && (url.startsWith("http://") || url.startsWith("https://"));
} }
private Map<String, String> getHeader() { private Map<String, String> getHeader() {
@ -155,74 +155,75 @@ public class TgSearchBaidu extends Cloud {
if (key == null || key.trim().isEmpty()) { if (key == null || key.trim().isEmpty()) {
return Result.error("关键词不能为空"); return Result.error("关键词不能为空");
} }
return performSearch(key, 1, DEFAULT_PAGE_SIZE); return performSearch(key, 1, DEFAULT_PAGE_SIZE);
} }
private String performSearch(String key, int page, int pageSize) throws Exception { private String performSearch(String key, int page, int pageSize) throws Exception {
List<Vod> list = new ArrayList<>(); List<Vod> list = new ArrayList<>();
int total = 0; int total = 0;
Map<String, String> params = new HashMap<>(); Map<String, String> params = new HashMap<>();
params.put("kw", key); params.put("kw", key);
params.put("page", String.valueOf(page)); params.put("page", String.valueOf(page));
params.put("size", String.valueOf(pageSize)); params.put("size", String.valueOf(pageSize));
for (String apiUrl : apiUrls) { for (String apiUrl : apiUrls) {
if (!isValidUrl(apiUrl)) continue; if (!isValidUrl(apiUrl)) continue;
try { try {
OkResult result = OkHttp.get(apiUrl, params, getHeader()); OkResult result = OkHttp.get(apiUrl, params, getHeader());
if (result.getCode() == 500 || TextUtils.isEmpty(result.getBody())) continue; if (result.getCode() == 500 || TextUtils.isEmpty(result.getBody())) continue;
JsonObject jsonObject = Json.safeObject(result.getBody()); JsonObject jsonObject = Json.safeObject(result.getBody());
if (!jsonObject.has("code") || jsonObject.get("code").getAsInt() != 0 || !jsonObject.has("data")) continue; if (!jsonObject.has("code") || jsonObject.get("code").getAsInt() != 0 || !jsonObject.has("data"))
continue;
JsonObject data = jsonObject.getAsJsonObject("data"); JsonObject data = jsonObject.getAsJsonObject("data");
total = data.has("total") && !data.get("total").isJsonNull() ? data.get("total").getAsInt() : 0; total = data.has("total") && !data.get("total").isJsonNull() ? data.get("total").getAsInt() : 0;
// 直接检查merged_by_type字段无需三重判断 // 直接检查merged_by_type字段无需三重判断
if (!data.has("merged_by_type") || !data.get("merged_by_type").isJsonObject()) continue; if (!data.has("merged_by_type") || !data.get("merged_by_type").isJsonObject()) continue;
JsonObject mergedByType = data.getAsJsonObject("merged_by_type"); JsonObject mergedByType = data.getAsJsonObject("merged_by_type");
for (Map.Entry<String, JsonElement> categoryEntry : mergedByType.entrySet()) { for (Map.Entry<String, JsonElement> categoryEntry : mergedByType.entrySet()) {
if (!categoryEntry.getValue().isJsonArray()) continue; if (!categoryEntry.getValue().isJsonArray()) continue;
JsonArray items = categoryEntry.getValue().getAsJsonArray(); JsonArray items = categoryEntry.getValue().getAsJsonArray();
for (JsonElement item : items) { for (JsonElement item : items) {
if (!item.isJsonObject()) continue; if (!item.isJsonObject()) continue;
JsonObject entry = item.getAsJsonObject(); JsonObject entry = item.getAsJsonObject();
String vodUrl = entry.has("url") && !entry.get("url").isJsonNull() ? entry.get("url").getAsString() : ""; String vodUrl = entry.has("url") && !entry.get("url").isJsonNull() ? entry.get("url").getAsString() : "";
if (TextUtils.isEmpty(vodUrl)) continue; if (TextUtils.isEmpty(vodUrl)) continue;
// 获取来源信息并映射 // 获取来源信息并映射
String originalSource = entry.has("source") && !entry.get("source").isJsonNull() ? entry.get("source").getAsString() : "未知来源"; String originalSource = entry.has("source") && !entry.get("source").isJsonNull() ? entry.get("source").getAsString() : "未知来源";
String sourceName = mapSource(vodUrl, originalSource); String sourceName = mapSource(vodUrl, originalSource);
// 获取标题 // 获取标题
String title = entry.has("note") && !entry.get("note").isJsonNull() ? entry.get("note").getAsString() : "未命名资源"; String title = entry.has("note") && !entry.get("note").isJsonNull() ? entry.get("note").getAsString() : "未命名资源";
// 获取图片 // 获取图片
String pic = getFirstImage(entry); String pic = getFirstImage(entry);
// 简化VodPlayBuilder的使用 // 简化VodPlayBuilder的使用
Vod vod = new Vod("push://" + vodUrl, title, pic, sourceName + " (" + originalSource + ")"); Vod vod = new Vod(vodUrl, title, pic, sourceName + " (" + originalSource + ")");
// 由于只有一个播放源直接设置播放信息 // 由于只有一个播放源直接设置播放信息
vod.setVodPlayFrom(sourceName); vod.setVodPlayFrom(sourceName);
vod.setVodPlayUrl("播放源$" + vodUrl); vod.setVodPlayUrl("播放源$" + vodUrl);
// 来源过滤 // 来源过滤
if (sources.isEmpty() || sources.contains(sourceName)) { if (sources.isEmpty() || sources.contains(sourceName)) {
list.add(vod); list.add(vod);
} }
} }
} }
int pageCount = total > 0 && pageSize > 0 ? (total + pageSize - 1) / pageSize : 1; int pageCount = total > 0 && pageSize > 0 ? (total + pageSize - 1) / pageSize : 1;
return Result.string(page, pageCount, pageSize, total, list); return Result.string(page, pageCount, pageSize, total, list);
} catch (Exception e) { } catch (Exception e) {
@ -230,10 +231,10 @@ public class TgSearchBaidu extends Cloud {
continue; continue;
} }
} }
return Result.error("无法连接到任何搜索API"); return Result.error("无法连接到任何搜索API");
} }
// 提取来源映射逻辑为单独方法 // 提取来源映射逻辑为单独方法
private String mapSource(String vodUrl, String originalSource) { private String mapSource(String vodUrl, String originalSource) {
for (Map.Entry<String, String> domainEntry : domainMap.entrySet()) { for (Map.Entry<String, String> domainEntry : domainMap.entrySet()) {
@ -243,7 +244,7 @@ public class TgSearchBaidu extends Cloud {
} }
return originalSource; return originalSource;
} }
// 提取图片获取逻辑为单独方法 // 提取图片获取逻辑为单独方法
private String getFirstImage(JsonObject entry) { private String getFirstImage(JsonObject entry) {
if (entry.has("images") && !entry.get("images").isJsonNull() && entry.get("images").isJsonArray()) { if (entry.has("images") && !entry.get("images").isJsonNull() && entry.get("images").isJsonArray()) {

View File

@ -0,0 +1,258 @@
package com.github.catvod.spider;
import android.content.Context;
import android.text.TextUtils;
import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod;
import com.github.catvod.net.OkHttp;
import com.github.catvod.net.OkResult;
import com.github.catvod.utils.Json;
import com.github.catvod.utils.Util;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.*;
public class TgSearchQuark extends Cloud {
private static final String KEY_API_URLS = "api_urls";
private static final String KEY_DOMAIN_MAP = "siteurl";
private static final String KEY_SOURCES = "sources";
private static final int DEFAULT_PAGE_SIZE = 10;
private List<String> apiUrls = new ArrayList<>();
private Map<String, String> domainMap = new HashMap<String, String>() {{
put("alipan", "阿里");
put("aliyundrive", "阿里");
put("quark", "夸克");
put("115cdn", "115");
put("baidu.com", "百度");
put("uc", "UC");
put("189.cn", "天翼");
put("139.com", "移动");
put("123", "123盘");
}};
private Set<String> sources = new HashSet<>();
private String[] extInfos = null;
@Override
public synchronized void init(Context context, String extend) throws Exception {
super.init(context, extend);
this.apiUrls.clear();
if (!TextUtils.isEmpty(extend)) {
try {
if (extend.contains("###")) {
String[] infos = extend.split("###");
this.extInfos = infos;
if (infos.length > 0 && !TextUtils.isEmpty(infos[0])) {
processExtendConfig(infos[0]);
}
} else {
this.extInfos = new String[]{extend};
processExtendConfig(extend);
}
} catch (Exception e) {
}
}
this.extInfos = null; // 重置避免内存泄漏
}
private void processExtendConfig(String config) {
try {
// 检查是否为HTTP URL
if (isValidUrl(config)) {
if (!this.apiUrls.contains(config)) {
this.apiUrls.add(config);
}
return;
}
// 尝试JSON格式解析
JsonObject ext = Json.safeObject(config);
// 处理API URLs配置
processApiUrls(ext);
// 处理域名映射配置
processDomainMap(ext);
// 处理来源过滤配置
processSources(ext, true);
} catch (Exception e) {
// 可以添加日志记录
}
}
private void processApiUrls(JsonObject config) {
if (config.has(KEY_API_URLS) && config.get(KEY_API_URLS).isJsonArray()) {
JsonArray urlsArray = config.getAsJsonArray(KEY_API_URLS);
for (JsonElement element : urlsArray) {
if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) {
String url = element.getAsString();
if (isValidUrl(url) && !this.apiUrls.contains(url)) {
this.apiUrls.add(url);
}
}
}
}
}
private void processDomainMap(JsonObject config) {
if (config.has(KEY_DOMAIN_MAP) && config.get(KEY_DOMAIN_MAP).isJsonObject()) {
JsonObject customDomains = config.getAsJsonObject(KEY_DOMAIN_MAP);
for (Map.Entry<String, JsonElement> entry : customDomains.entrySet()) {
if (entry == null || entry.getValue() == null) continue;
String domain = entry.getKey();
String sourceName = "";
try {
sourceName = entry.getValue().getAsString();
} catch (Exception e) {
continue;
}
if (!TextUtils.isEmpty(domain) && !TextUtils.isEmpty(sourceName) && !domainMap.containsKey(domain)) {
domainMap.put(domain, sourceName);
}
}
}
}
private void processSources(JsonObject config, boolean clearExisting) {
if (config.has(KEY_SOURCES) && config.get(KEY_SOURCES).isJsonArray()) {
if (clearExisting) {
this.sources.clear();
}
JsonArray sourcesArray = config.getAsJsonArray(KEY_SOURCES);
for (JsonElement element : sourcesArray) {
if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) {
String source = element.getAsString();
if (!TextUtils.isEmpty(source) && !sources.contains(source)) {
sources.add(source);
}
}
}
}
}
private boolean isValidUrl(String url) {
return !TextUtils.isEmpty(url) && (url.startsWith("http://") || url.startsWith("https://"));
}
private Map<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 {
if (key == null || key.trim().isEmpty()) {
return Result.error("关键词不能为空");
}
return performSearch(key, 1, DEFAULT_PAGE_SIZE);
}
private String performSearch(String key, int page, int pageSize) throws Exception {
List<Vod> list = new ArrayList<>();
int total = 0;
Map<String, String> params = new HashMap<>();
params.put("kw", key);
params.put("page", String.valueOf(page));
params.put("size", String.valueOf(pageSize));
for (String apiUrl : apiUrls) {
if (!isValidUrl(apiUrl)) continue;
try {
OkResult result = OkHttp.get(apiUrl, params, getHeader());
if (result.getCode() == 500 || TextUtils.isEmpty(result.getBody())) continue;
JsonObject jsonObject = Json.safeObject(result.getBody());
if (!jsonObject.has("code") || jsonObject.get("code").getAsInt() != 0 || !jsonObject.has("data"))
continue;
JsonObject data = jsonObject.getAsJsonObject("data");
total = data.has("total") && !data.get("total").isJsonNull() ? data.get("total").getAsInt() : 0;
// 直接检查merged_by_type字段无需三重判断
if (!data.has("merged_by_type") || !data.get("merged_by_type").isJsonObject()) continue;
JsonObject mergedByType = data.getAsJsonObject("merged_by_type");
for (Map.Entry<String, JsonElement> categoryEntry : mergedByType.entrySet()) {
if (!categoryEntry.getValue().isJsonArray()) continue;
JsonArray items = categoryEntry.getValue().getAsJsonArray();
for (JsonElement item : items) {
if (!item.isJsonObject()) continue;
JsonObject entry = item.getAsJsonObject();
String vodUrl = entry.has("url") && !entry.get("url").isJsonNull() ? entry.get("url").getAsString() : "";
if (TextUtils.isEmpty(vodUrl)) continue;
// 获取来源信息并映射
String originalSource = entry.has("source") && !entry.get("source").isJsonNull() ? entry.get("source").getAsString() : "未知来源";
String sourceName = mapSource(vodUrl, originalSource);
// 获取标题
String title = entry.has("note") && !entry.get("note").isJsonNull() ? entry.get("note").getAsString() : "未命名资源";
// 获取图片
String pic = getFirstImage(entry);
// 简化VodPlayBuilder的使用
Vod vod = new Vod(vodUrl, title, pic, sourceName + " (" + originalSource + ")");
// 由于只有一个播放源直接设置播放信息
vod.setVodPlayFrom(sourceName);
vod.setVodPlayUrl("播放源$" + vodUrl);
// 来源过滤
if (sources.isEmpty() || sources.contains(sourceName)) {
list.add(vod);
}
}
}
int pageCount = total > 0 && pageSize > 0 ? (total + pageSize - 1) / pageSize : 1;
return Result.string(page, pageCount, pageSize, total, list);
} catch (Exception e) {
// 出错时继续尝试下一个API
continue;
}
}
return Result.error("无法连接到任何搜索API");
}
// 提取来源映射逻辑为单独方法
private String mapSource(String vodUrl, String originalSource) {
for (Map.Entry<String, String> domainEntry : domainMap.entrySet()) {
if (vodUrl.contains(domainEntry.getKey())) {
return domainEntry.getValue();
}
}
return originalSource;
}
// 提取图片获取逻辑为单独方法
private String getFirstImage(JsonObject entry) {
if (entry.has("images") && !entry.get("images").isJsonNull() && entry.get("images").isJsonArray()) {
JsonArray images = entry.getAsJsonArray("images");
if (images.size() > 0 && !images.get(0).isJsonNull() && images.get(0).isJsonPrimitive()) {
return images.get(0).getAsString();
}
}
return "";
}
}

View File

@ -0,0 +1,56 @@
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.Json
import com.github.catvod.utils.Util
import java.net.URLEncoder
import java.nio.charset.Charset
/**
* @author zhixc
*/
class TgbaiduSearch : Cloud() {
private val URL = "https://tgsou.252035.xyz/"
private val header: Map<String, String>
get() {
val header: MutableMap<String, String> = HashMap()
header["User-Agent"] = Util.CHROME
return header
}
@Throws(Exception::class)
override fun searchContent(key: String, quick: Boolean): String {
val url =
URL + "?channelUsername=BaiduCloudDisk,bdwpzhpd,Baidu_Netdisk&pic=true&keyword=" + URLEncoder.encode(
key, Charset.defaultCharset().name()
)
val list: MutableList<Vod> = ArrayList()
val html = OkHttp.string(url, header)
val json = Json.safeObject(html);
json["results"].asJsonArray.forEach { element ->
val array = element.asString.split("$$$")
if (array.size >= 2 && array[1].isNotEmpty()) {
array[1].split("##").forEach {
val id = it.split("@")[0]
val pic = it.split("@")[1].split("$$")[0]
val name = it.split("@")[1].split("$$")[1]
list.add(Vod(id, name, pic, ""))
}
}
}
return Result.string(list)
}
}

View File

@ -55,7 +55,7 @@ public class TianYi extends Spider {
for (int i = 1; i <= ids.size(); i++) { for (int i = 1; i <= ids.size(); i++) {
for (String s : TianyiApi.get().getPlayFormatList()) { for (String s : TianyiApi.get().getPlayFormatList()) {
playFrom.add(String.format(Locale.getDefault(), "天意" + s + "#%02d%02d", i, index)); playFrom.add(String.format(Locale.getDefault(), "天意" + s + "#%02d_%02d", i, index));
} }
// playFrom.add("天意" + i + index); // playFrom.add("天意" + i + index);
@ -69,7 +69,7 @@ public class TianYi extends Spider {
* @param ids share_link 集合 * @param ids share_link 集合
* @return 詳情內容視頻播放地址 * @return 詳情內容視頻播放地址
*/ */
public String detailContentVodPlayUrl(List<String> ids) throws Exception { public String detailContentVodPlayUrl(List<String> ids) {
List<String> playUrl = new ArrayList<>(); List<String> playUrl = new ArrayList<>();
for (String id : ids) { for (String id : ids) {
ShareData shareData = TianyiApi.get().getShareData(id, ""); ShareData shareData = TianyiApi.get().getShareData(id, "");
@ -77,6 +77,7 @@ public class TianYi extends Spider {
playUrl.add(TianyiApi.get().getVod(shareData).getVodPlayUrl()); playUrl.add(TianyiApi.get().getVod(shareData).getVodPlayUrl());
} catch (Exception e) { } catch (Exception e) {
SpiderDebug.log("获取播放地址出错:" + e.getMessage()); SpiderDebug.log("获取播放地址出错:" + e.getMessage());
playUrl.add("");
} }
} }
return TextUtils.join("$$$", playUrl); return TextUtils.join("$$$", playUrl);

View File

@ -56,10 +56,10 @@ public class UC extends Spider {
for (int i = 1; i <= ids.size(); i++) { for (int i = 1; i <= ids.size(); i++) {
for (String s : UCApi.get().getPlayFormatList()) { /* for (String s : UCApi.get().getPlayFormatList()) {
playFrom.add(String.format(Locale.getDefault(), "uc" + s + "#%02d%02d", i, index)); playFrom.add(String.format(Locale.getDefault(), "uc" + s + "#%02d%02d", i, index));
} }*/
playFrom.add("uc原画" + i + index); playFrom.add("uc原画" + i + index);
} }
return TextUtils.join("$$$", playFrom); return TextUtils.join("$$$", playFrom);
@ -71,11 +71,17 @@ public class UC extends Spider {
* @param ids share_link 集合 * @param ids share_link 集合
* @return 詳情內容視頻播放地址 * @return 詳情內容視頻播放地址
*/ */
public String detailContentVodPlayUrl(List<String> ids) throws Exception { public String detailContentVodPlayUrl(List<String> ids) {
List<String> playUrl = new ArrayList<>(); List<String> playUrl = new ArrayList<>();
for (String id : ids) { for (String id : ids) {
ShareData shareData = UCApi.get().getShareData(id); try {
playUrl.add(UCApi.get().getVod(shareData).getVodPlayUrl()); ShareData shareData = UCApi.get().getShareData(id);
playUrl.add(UCApi.get().getVod(shareData)==null?"":UCApi.get().getVod(shareData).getVodPlayUrl());
}catch (Exception e){
SpiderDebug.log("获取播放地址出错:" + e.getMessage());
playUrl.add("");
}
} }
return TextUtils.join("$$$", playUrl); return TextUtils.join("$$$", playUrl);
} }

View File

@ -2,13 +2,11 @@ package com.github.catvod.spider;
import android.content.Context; import android.content.Context;
import android.text.TextUtils; import android.text.TextUtils;
import com.github.catvod.api.YunDrive; import com.github.catvod.api.YunDrive;
import com.github.catvod.bean.Result; import com.github.catvod.bean.Result;
import com.github.catvod.bean.Vod; import com.github.catvod.bean.Vod;
import com.github.catvod.crawler.Spider; import com.github.catvod.crawler.Spider;
import com.github.catvod.crawler.SpiderDebug; import com.github.catvod.crawler.SpiderDebug;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
@ -96,8 +94,8 @@ public class YiDongYun extends Spider {
int i = 0; int i = 0;
for (String id : ids) { for (String id : ids) {
i++; i++;
playFrom.add("移动(极速)" + i); playFrom.add(String.format("移动(极速)#%2d", i));
playFrom.add("移动(原画)" + i); playFrom.add(String.format("移动(原画)#%2d", i));
} }
@ -111,10 +109,17 @@ public class YiDongYun extends Spider {
* @param ids share_link 集合 * @param ids share_link 集合
* @return 詳情內容視頻播放地址 * @return 詳情內容視頻播放地址
*/ */
public String detailContentVodPlayUrl(List<String> ids) throws Exception { public String detailContentVodPlayUrl(List<String> ids) {
List<String> playUrl = new ArrayList<>(); List<String> playUrl = new ArrayList<>();
for (String id : ids) { for (String id : ids) {
playUrl.add(getVod(List.of(id)).getVodPlayUrl()); try {
playUrl.add(getVod(List.of(id)).getVodPlayUrl());
}catch (Exception e) {
SpiderDebug.log("获取播放地址出错:" + e.getMessage());
playUrl.add("");
}
} }
return TextUtils.join("$$$", playUrl); return TextUtils.join("$$$", playUrl);
} }

View File

@ -4,28 +4,22 @@ import com.github.catvod.crawler.SpiderDebug
import com.github.catvod.net.OkHttp import com.github.catvod.net.OkHttp
import com.github.catvod.utils.ProxyVideo.getMimeType import com.github.catvod.utils.ProxyVideo.getMimeType
import com.github.catvod.utils.ProxyVideo.parseRange import com.github.catvod.utils.ProxyVideo.parseRange
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.*
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.runBlocking
import okhttp3.Response import okhttp3.Response
import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils
import java.io.InputStream import java.io.InputStream
import java.io.SequenceInputStream import java.io.SequenceInputStream
import java.util.Vector import java.util.*
import kotlin.math.min import kotlin.math.min
object DownloadMT { object DownloadMT {
private val THREAD_NUM: Int = Runtime.getRuntime().availableProcessors() * 2 private val THREAD_NUM: Int = 16
private val infos = mutableMapOf<String, Array<Any>>(); private val infos = mutableMapOf<String, Array<Any>>();
fun proxyMultiThread(url: String, headers: Map<String, String>): Array<out Any?>? = fun proxyMultiThread(url: String, headers: Map<String, String>): Array<out Any?>? = runBlocking {
runBlocking { proxyAsync(url, headers)
proxyAsync(url, headers) }
}
/** /**
* 获取是否分片信息顺带请求一个1MB块 * 获取是否分片信息顺带请求一个1MB块
@ -52,11 +46,10 @@ object DownloadMT {
if (info == null) { if (info == null) {
infos.clear() infos.clear()
info = CoroutineScope(Dispatchers.IO).async { getInfo(url, headers) }.await() info = CoroutineScope(Dispatchers.IO).async { getInfo(url, headers) }.await()
infos[url] = info infos[url] = info/* //支持分片先返回这个1MB块
/* //支持分片先返回这个1MB块 if (info[0] as Int == 206) {
if (info[0] as Int == 206) { return info
return info }*/
}*/
} }
val code = info[0] as Int val code = info[0] as Int
@ -78,8 +71,7 @@ object DownloadMT {
/* if (total.toLong() < 1024 * 1024 * 100) { /* if (total.toLong() < 1024 * 1024 * 100) {
return proxy(url, headers) return proxy(url, headers)
}*/ }*/
var range = var range = if (StringUtils.isAllBlank(headers["range"])) headers["Range"] else headers["range"]
if (StringUtils.isAllBlank(headers["range"])) headers["Range"] else headers["range"]
if (StringUtils.isAllBlank(range)) range = "bytes=0-"; if (StringUtils.isAllBlank(range)) range = "bytes=0-";
SpiderDebug.log("---proxyMultiThread,Range:$range") SpiderDebug.log("---proxyMultiThread,Range:$range")
val rangeObj = parseRange( val rangeObj = parseRange(
@ -128,8 +120,7 @@ object DownloadMT {
/* respHeaders.put("Access-Control-Allow-Credentials", "true"); /* respHeaders.put("Access-Control-Allow-Credentials", "true");
respHeaders.put("Access-Control-Allow-Origin", "*");*/ respHeaders.put("Access-Control-Allow-Origin", "*");*/
resHeader["Content-Length"] = resHeader["Content-Length"] = (partList[THREAD_NUM - 1][1] - partList[0][0] + 1).toString()
(partList[THREAD_NUM - 1][1] - partList[0][0] + 1).toString()
resHeader.remove("content-length") resHeader.remove("content-length")
resHeader["Content-Range"] = String.format( resHeader["Content-Range"] = String.format(
@ -156,12 +147,10 @@ object DownloadMT {
fun generatePart(rangeObj: Map<String?, String>, total: String): List<LongArray> { fun generatePart(rangeObj: Map<String?, String>, total: String): List<LongArray> {
val totalSize = total.toLong() val totalSize = total.toLong()
//超过10GB分块是32Mb不然是16MB //超过10GB分块是32Mb不然是16MB
val partSize = val partSize = if (totalSize > 1024L * 1024L * 1024L * 10L) 1024 * 1024 * 8 * 4L else 1024 * 1024 * 8 * 2L
if (totalSize > 1024L * 1024L * 1024L * 10L) 1024 * 1024 * 8 * 4L else 1024 * 1024 * 8 * 2L
var start = rangeObj["start"]!!.toLong() var start = rangeObj["start"]!!.toLong()
var end = var end = if (StringUtils.isAllBlank(rangeObj["end"])) start + partSize else rangeObj["end"]!!.toLong()
if (StringUtils.isAllBlank(rangeObj["end"])) start + partSize else rangeObj["end"]!!.toLong()
end = min(end.toDouble(), (totalSize - 1).toDouble()).toLong() end = min(end.toDouble(), (totalSize - 1).toDouble()).toLong()

View File

@ -8,11 +8,12 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import java.io.ByteArrayInputStream
object ProxyServer { object ProxyServer {
private val THREAD_NUM = Runtime.getRuntime().availableProcessors() private val THREAD_NUM = Runtime.getRuntime().availableProcessors()
private val partSize = 1024 * 1024 * 2 private val partSize = 1024 * 1024
private var port = 12345 private var port = 12345
private var httpServer: AdvancedHttpServer? = null private var httpServer: AdvancedHttpServer? = null
private val infos = mutableMapOf<String, MutableMap<String, MutableList<String>>>(); private val infos = mutableMapOf<String, MutableMap<String, MutableList<String>>>();
@ -37,15 +38,20 @@ object ProxyServer {
} }
}; };
httpServer?.addRoutes("/proxy") { req, response -> httpServer?.addRoutes("/proxy") { req, response ->
run { try {
val key = req.queryParams["key"]; run {
val url = urlMap[key] val key = req.queryParams["key"];
val header = headerMap[key] val url = urlMap[key]
val header = headerMap[key]
if (url != null && header != null) { if (url != null && header != null) {
proxyAsync(url, header, req, response) proxyAsync(url, header, req, response)
}
} }
} catch (e: Exception) {
SpiderDebug.log("代理视频出错:" + e.message)
} }
} }
httpServer?.start() httpServer?.start()
@ -138,7 +144,13 @@ object ProxyServer {
producerJob += CoroutineScope(Dispatchers.IO).launch { producerJob += CoroutineScope(Dispatchers.IO).launch {
// 异步下载数据块 // 异步下载数据块
val data = getVideoStream(chunkStart, chunkEnd, url, headers) val data = getVideoStream(chunkStart, chunkEnd, url, headers)
channels[i].send(data) //如果是0开始且检测到恶意头那么就把数据截断
if (chunkStart == 0L) {
val offset = detectMaliciousPrefix(data)
channels[i].send(data.copyOfRange(offset, data.size))
} else {
channels[i].send(data)
}
} }
currentStart = chunkEnd + 1 currentStart = chunkEnd + 1
@ -164,6 +176,64 @@ object ProxyServer {
} }
} }
fun detectMaliciousPrefix(data: ByteArray): Int {
val buffer = ByteArray(64) // 读取前64字节足够
ByteArrayInputStream(data).use { fis ->
fis.read(buffer)
}
// 检查是否以合法魔数开头
if (isValidVideoHeader(buffer)) {
return 0 // 正常,无恶意前缀
}
// 在后续位置查找合法魔数比如最多跳过前256字节
val searchLimit = minOf(256, data.size)
val searchBuffer = ByteArray(searchLimit)
ByteArrayInputStream(data).use { fis ->
fis.read(searchBuffer)
}
// 尝试从偏移1开始查找合法视频头
for (offset in 1 until searchLimit - 16) {
if (isValidVideoHeader(searchBuffer, offset)) {
SpiderDebug.log("发现合法视频头位于偏移 $offset,疑似被插入恶意前缀!")
return offset
}
}
return 0 // 未找到合法头,可能是损坏或非视频文件
}
// 判断从指定偏移开始是否是合法视频头
fun isValidVideoHeader(data: ByteArray, offset: Int = 0): Boolean {
if (data.size - offset < 8) return false
// MP4 / MOV: ... ftyp
if (offset + 8 <= data.size && data[offset + 4].toInt() == 0x66 && // 'f'
data[offset + 5].toInt() == 0x74 && // 't'
data[offset + 6].toInt() == 0x79 && // 'y'
data[offset + 7].toInt() == 0x70 // 'p'
) {
// 还可进一步校验前4字节是否为合法 size>=8 且合理)
val size =
(data[offset].toLong() and 0xFF shl 24) or (data[offset + 1].toLong() and 0xFF shl 16) or (data[offset + 2].toLong() and 0xFF shl 8) or (data[offset + 3].toLong() and 0xFF)
if (size >= 8 && size <= 0x100000) return true
}
// AVI: RIFF
if (offset + 4 <= data.size && data[offset] == 0x52.toByte() && data[offset + 1] == 0x49.toByte() && data[offset + 2] == 0x46.toByte() && data[offset + 3] == 0x46.toByte()) return true
// MKV
if (offset + 4 <= data.size && data[offset] == 0x1A.toByte() && data[offset + 1] == 0x45.toByte() && data[offset + 2] == 0xDF.toByte() && data[offset + 3] == 0xA3.toByte()) return true
// FLV
if (offset + 4 <= data.size && data[offset] == 0x46.toByte() && data[offset + 1] == 0x4C.toByte() && data[offset + 2] == 0x56.toByte() && data[offset + 3] == 0x01.toByte()) return true
return false
}
private fun queryToMap(query: String?): Map<String, String>? { private fun queryToMap(query: String?): Map<String, String>? {
if (query == null) { if (query == null) {
return null return null

View File

@ -23,6 +23,8 @@ import java.util.*;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static android.net.Uri.encode;
public class Util { public class Util {
public static final String patternAli = "(https:\\/\\/www\\.aliyundrive\\.com\\/s\\/[^\"]+|https:\\/\\/www\\.alipan\\.com\\/s\\/[^\"]+)"; public static final String patternAli = "(https:\\/\\/www\\.aliyundrive\\.com\\/s\\/[^\"]+|https:\\/\\/www\\.alipan\\.com\\/s\\/[^\"]+)";
public static final String patternQuark = "(https:\\/\\/pan\\.quark\\.cn\\/s\\/[^\"]+)"; public static final String patternQuark = "(https:\\/\\/pan\\.quark\\.cn\\/s\\/[^\"]+)";
@ -30,6 +32,8 @@ public class Util {
public static final Pattern RULE = Pattern.compile("http((?!http).){12,}?\\.(m3u8|mp4|mkv|flv|mp3|m4a|aac)\\?.*|http((?!http).){12,}\\.(m3u8|mp4|mkv|flv|mp3|m4a|aac)|http((?!http).)*?video/tos*"); public static final Pattern RULE = Pattern.compile("http((?!http).){12,}?\\.(m3u8|mp4|mkv|flv|mp3|m4a|aac)\\?.*|http((?!http).){12,}\\.(m3u8|mp4|mkv|flv|mp3|m4a|aac)|http((?!http).)*?video/tos*");
public static final Pattern THUNDER = Pattern.compile("(magnet|thunder|ed2k):.*"); public static final Pattern THUNDER = Pattern.compile("(magnet|thunder|ed2k):.*");
public static final String CHROME = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"; public static final String CHROME = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36";
public static final String MOBILE = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Mobile Safari/537.36 Edg/142.0.0.0";
public static final String ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"; public static final String ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
public static final List<String> MEDIA = Arrays.asList("mp4", "mkv", "wmv", "flv", "avi", "iso", "mpg", "ts", "mp3", "aac", "flac", "m4a", "ape", "ogg"); public static final List<String> MEDIA = Arrays.asList("mp4", "mkv", "wmv", "flv", "avi", "iso", "mpg", "ts", "mp3", "aac", "flac", "m4a", "ape", "ogg");
public static final List<String> SUB = Arrays.asList("srt", "ass", "ssa", "vtt"); public static final List<String> SUB = Arrays.asList("srt", "ass", "ssa", "vtt");
@ -257,6 +261,12 @@ public class Util {
return ""; return "";
} }
} }
public static String getStrByRegex(Pattern pattern, String str) {
Matcher matcher = pattern.matcher(str);
if (matcher.find()) return matcher.group(1).trim();
return "";
}
public static String base64Decode(String s) { public static String base64Decode(String s) {
return new String(android.util.Base64.decode(s, Base64.NO_WRAP), Charset.defaultCharset()); return new String(android.util.Base64.decode(s, Base64.NO_WRAP), Charset.defaultCharset());

View File

@ -0,0 +1,65 @@
import android.app.Application;
import com.github.catvod.spider.Init;
import com.github.catvod.spider.Pan123;
import com.github.catvod.spider.TianYi;
import com.github.catvod.utils.Json;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import org.junit.Assert;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.Arrays;
@RunWith(RobolectricTestRunner.class)
public class Pan123Test {
private Application mockContext;
private Pan123 spider;
@org.junit.Before
public void setUp() throws Exception {
mockContext = RuntimeEnvironment.application;
Init.init(mockContext);
spider = new Pan123();
// spider.init(mockContext, "b-user-id=89ede34e-0efc-e1dd-c997-f16aaa792d0c; _UP_A4A_11_=wb9661c6dfb642f88f73d8e0c7edd398; b-user-id=89ede34e-0efc-e1dd-c997-f16aaa792d0c; ctoken=wla6p3EUOLyn1FSB8IKp1SEW; grey-id=5583e32b-39df-4bf0-f39f-1adf83f604a2; grey-id.sig=p8ReBIMG2BeZu1sYvsuOAZxYbx-MVrsfKEiCv87MsTM; isQuark=true; isQuark.sig=hUgqObykqFom5Y09bll94T1sS9abT1X-4Df_lzgl8nM; _UP_F7E_8D_=ZkyvVHnrBLp1A1NFJIjWi0PwKLOVbxJPcg0RzQPI6KmBtV6ZMgPh38l93pgubgHDQqhaZ2Sfc0qv%2BRantbfg1mWGAUpRMP4RqXP78Wvu%2FCfvkWWGc5NhCTV71tGOIGgDBR3%2Bu6%2Fjj44KlE5biSNDOWW7Bigcz27lvOTidzNw8s%2FWtKAIxWbnCzZn4%2FJMBUub1SIMcW89g57k4mfPmDlCgpZKzxwl6beSfdtZ4RUWXmZOn5v5NkxVKhU4wR0Pq7NklczEGdRq2nIAcu7v22Uw2o%2FxMY0xBdeC9Korm5%2FNHnxl6K%2Bd6FXSoT9a3XIMQO359auZPiZWzrNlZe%2BqnOahXcx7KAhQIRqSOapSmL4ygJor4r5isJhRuDoXy7vJAVuH%2FRDtEJJ8rZTq0BdC23Bz%2B0MrsdgbK%2BiW; _UP_D_=pc; __wpkreporterwid_=3d3f74a7-99b7-4916-3f78-911fc2eb9d87; tfstk=fIoZNxjnbhKwPOu0TWZ4LsaRqirTcudSSmNbnxD0C5VgClMm8xMyB-GsnSu4tjpOflAOmSD-9PNiGl120XrgkVNb1SrqHbJBN3tSBAEYoQOWVUUg9qZ8n1bGGkD3CqGYINKSBABhjnXgp3_Vywz6gSc0Syj3BWf0mr2DLW24eZfiiovEKWefj1q0swq3E82iNEMinMy7SLrcpA4Fh3z_ZAViCfih3PbtdW5N_DuU77AaTijmYRkL2Wq54ENoy5a7ZXxCbok33XzS7QSZgxD-oyoVsdGotql0p2dVu7umC4nLStbiLmParc4FELHrI-c0u2dPVRrs8zoZWKCnIbNZrlHfUCMUz2z8KyXVSlgSFmUojh58OzeqTzgwaGll4YCYKwctDV5coP2LL79eKHxpNTXHmre1kZU32JPWCR_AkP2LL79eLZQY-WeUNdw1.; __pus=2051c82285199d8be553be41dd5a2100AAQ+mmv35G4FDDZ5x+3Mhe2OMbNgweQ1ODbW8zDt9YuP1LQVqHUuAAz9KWLsPjpNtim0AVGHusN4MCosTmbq/khM; __kp=e6604120-6051-11ef-bfe4-c31b6cdd0766; __kps=AATcZArVgS76EPn0FMaV4HEj; __ktd=sii/iz4ePzEaoVirXul7QQ==; __uid=AATcZArVgS76EPn0FMaV4HEj; __itrace_wid=5829b95d-dac1-48d3-bfd5-f60cd9462786; __puus=7da0b96cb710fa1b376934485f977e05AATp/q8/QupT7IiBR1GWqZhxlIRT677smMvoHlLxQA0Lk6CkP0YJBOTl+p9DZgzlMz6w4hPXPgWsokukk8PW7ZfhFfPmv8tKMgLpCGLW+tk57luhNghmSdTeVPkAF59STtyCPBEtiNzNAd/zZJ6qILJDi5ywEBAAAg+gOyWHoLHNUR+QxeHRuQa8g5WWA95J8jebIlrr8rCvI1vjTbtiYktT");
// spider.init(mockContext, "{\"open.e.189.cn\":[{\"name\":\"SSON\",\"value\":\"dc466c8192e3109eaea837c1d136c1fd065253ce1c7d3a66ca1520d7d6d6307b10a1fe65c7becac73b95f24a6e681e654ec4f47c39533ebcc48bb78d6d6e63d1bbf3334e6e97eaa7092d34f87bf1209ee35f344871bc5a329eac34ae948d399d4a6b3b28a929c4f353ade0981657e9e0f09ce27cc1c15d8322c6e45a8ebb21eb431509f1dd7dc3a7856b32b0991d654d5ced73dd20b764ca8737600cbe699c37ccf59b3c610893fc42bdc08b477c5d394e290c14d175d1ca0ee9fa61a1a8dcac7007e9219fd0ae6ccd5dc760524213f85b6b8c6166af01a31336dab797d9118010b81a5a3c26e08e\",\"expiresAt\":253402300799999,\"domain\":\"e.189.cn\",\"path\":\"/\",\"secure\":true,\"httpOnly\":true,\"persistent\":true,\"hostOnly\":false},{\"name\":\"GUID\",\"value\":\"525d8874e53e46a7ba3ed8907e9fef1f\",\"expiresAt\":1775176321000,\"domain\":\"e.189.cn\",\"path\":\"/\",\"secure\":false,\"httpOnly\":false,\"persistent\":true,\"hostOnly\":false},{\"name\":\"pageOp\",\"value\":\"336b9ddc820212fa6c9b5a0cfd7bf5b3\",\"expiresAt\":253402300799999,\"domain\":\"e.189.cn\",\"path\":\"/\",\"secure\":false,\"httpOnly\":false,\"persistent\":false,\"hostOnly\":false},{\"name\":\"OPENINFO\",\"value\":\"33c28688ef52ce9e3a9ef87388047efbde5e3e2e4c7ef6ef267632468c7dfaf294ff59fa59d34801\",\"expiresAt\":253402300799999,\"domain\":\"e.189.cn\",\"path\":\"/\",\"secure\":false,\"httpOnly\":true,\"persistent\":false,\"hostOnly\":false},{\"name\":\"GRAYNUMBER\",\"value\":\"319DE3F68C8730862F3BEF66F3D635B7\",\"expiresAt\":1775177653000,\"domain\":\"e.189.cn\",\"path\":\"/\",\"secure\":false,\"httpOnly\":false,\"persistent\":true,\"hostOnly\":false}],\"cloud.189.cn\":[{\"name\":\"JSESSIONID\",\"value\":\"431787526C43DF21B6373E914FE597EC\",\"expiresAt\":253402300799999,\"domain\":\"cloud.189.cn\",\"path\":\"/\",\"secure\":false,\"httpOnly\":true,\"persistent\":false,\"hostOnly\":true},{\"name\":\"COOKIE_LOGIN_USER\",\"value\":\"0C7407F59A6E5896EB6B777056E160DB020BAE67B121B5930CCD4777073744055308F7E8CD03F2FC2399E4823F60ECDD74120CEE4C529017\",\"expiresAt\":253402300799999,\"domain\":\"cloud.189.cn\",\"path\":\"/\",\"secure\":false,\"httpOnly\":true,\"persistent\":false,\"hostOnly\":false}]}");
// Server.get().start();
spider.init(mockContext, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NjE1MjEyNzksImlhdCI6MTc2MDkxNjQ3OSwiaWQiOjE4NDc0Mjg3NzAsIm1haWwiOiIiLCJuaWNrbmFtZSI6IjE4ODk2NzgxNjAxIiwic3VwcGVyIjpmYWxzZSwidXNlcm5hbWUiOjE4ODk2NzgxNjAxLCJ2IjowfQ.gVhIfG1t2tUts68eYY-AdUfJoBKBNeG41k3XGYfwCek");
}
@org.junit.Test
public void init() throws Exception {
spider.init(mockContext, "{\"open.e.189.cn\":[{\"name\":\"SSON\",\"value\":\"dc466c8192e3109eaea837c1d136c1fd065253ce1c7d3a66ca1520d7d6d6307b10a1fe65c7becac73b95f24a6e681e654ec4f47c39533ebcc48bb78d6d6e63d1bbf3334e6e97eaa7092d34f87bf1209ee35f344871bc5a329eac34ae948d399d4a6b3b28a929c4f353ade0981657e9e0f09ce27cc1c15d8322c6e45a8ebb21eb431509f1dd7dc3a7856b32b0991d654d5ced73dd20b764ca8737600cbe699c37ccf59b3c610893fc42bdc08b477c5d394e290c14d175d1ca0ee9fa61a1a8dcac7007e9219fd0ae6ccd5dc760524213f85b6b8c6166af01a31336dab797d9118010b81a5a3c26e08e\",\"expiresAt\":253402300799999,\"domain\":\"e.189.cn\",\"path\":\"/\",\"secure\":true,\"httpOnly\":true,\"persistent\":true,\"hostOnly\":false},{\"name\":\"GUID\",\"value\":\"525d8874e53e46a7ba3ed8907e9fef1f\",\"expiresAt\":1775176321000,\"domain\":\"e.189.cn\",\"path\":\"/\",\"secure\":false,\"httpOnly\":false,\"persistent\":true,\"hostOnly\":false},{\"name\":\"pageOp\",\"value\":\"336b9ddc820212fa6c9b5a0cfd7bf5b3\",\"expiresAt\":253402300799999,\"domain\":\"e.189.cn\",\"path\":\"/\",\"secure\":false,\"httpOnly\":false,\"persistent\":false,\"hostOnly\":false},{\"name\":\"OPENINFO\",\"value\":\"33c28688ef52ce9e3a9ef87388047efbde5e3e2e4c7ef6ef267632468c7dfaf294ff59fa59d34801\",\"expiresAt\":253402300799999,\"domain\":\"e.189.cn\",\"path\":\"/\",\"secure\":false,\"httpOnly\":true,\"persistent\":false,\"hostOnly\":false},{\"name\":\"GRAYNUMBER\",\"value\":\"319DE3F68C8730862F3BEF66F3D635B7\",\"expiresAt\":1775177653000,\"domain\":\"e.189.cn\",\"path\":\"/\",\"secure\":false,\"httpOnly\":false,\"persistent\":true,\"hostOnly\":false}],\"cloud.189.cn\":[{\"name\":\"JSESSIONID\",\"value\":\"431787526C43DF21B6373E914FE597EC\",\"expiresAt\":253402300799999,\"domain\":\"cloud.189.cn\",\"path\":\"/\",\"secure\":false,\"httpOnly\":true,\"persistent\":false,\"hostOnly\":true},{\"name\":\"COOKIE_LOGIN_USER\",\"value\":\"0C7407F59A6E5896EB6B777056E160DB020BAE67B121B5930CCD4777073744055308F7E8CD03F2FC2399E4823F60ECDD74120CEE4C529017\",\"expiresAt\":253402300799999,\"domain\":\"cloud.189.cn\",\"path\":\"/\",\"secure\":false,\"httpOnly\":true,\"persistent\":false,\"hostOnly\":false}]}");
//Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
}
@org.junit.Test
public void detailContent() throws Exception {
String content = spider.detailContent(Arrays.asList("https://www.123865.com/s/u9izjv-6hSWv"));
System.out.println("detailContent--" + content);
JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println("detailContent--" + gson.toJson(map));
Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
}
@org.junit.Test
public void playerContent() throws Exception {
String content = spider.playerContent("pan123原画","eyJmaWxlbmFtZSI6IuWRveaCrOS4gOeUny5TMDFFMDEuMjAyNS4yMTYwcC5XRUItREwuSDI2NS5ERFA1LjEubWt2Iiwic2hhcmVLZXkiOiJ1OWl6anYtNmhTV3YiLCJzaGFyZVB3ZCI6IiIsIm5leHQiOi0xLCJmaWxlSWQiOjI3MzQ0MjY3LCJTM0tleUZsYWciOiIxODI3MDg2NzQ5LTAiLCJTaXplIjoxNDExNDM3ODI2LCJFdGFnIjoiZGZmOGZlZWU2N2JkYzRhOTQxMjlhZTJlNTg1YmI0Y2QifQ==",new ArrayList<>());
System.out.println("playerContent--" + content);
JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println("playerContent--" + gson.toJson(map));
Assert.assertFalse(map.getAsJsonPrimitive("url").getAsString().isEmpty());
while(true){
}
}
}

View File

@ -28,7 +28,7 @@ public class QuarkTest {
Init.init(mockContext); Init.init(mockContext);
spider = new Quark(); spider = new Quark();
// spider.init(mockContext, "b-user-id=89ede34e-0efc-e1dd-c997-f16aaa792d0c; _UP_A4A_11_=wb9661c6dfb642f88f73d8e0c7edd398; b-user-id=89ede34e-0efc-e1dd-c997-f16aaa792d0c; ctoken=wla6p3EUOLyn1FSB8IKp1SEW; grey-id=5583e32b-39df-4bf0-f39f-1adf83f604a2; grey-id.sig=p8ReBIMG2BeZu1sYvsuOAZxYbx-MVrsfKEiCv87MsTM; isQuark=true; isQuark.sig=hUgqObykqFom5Y09bll94T1sS9abT1X-4Df_lzgl8nM; _UP_F7E_8D_=ZkyvVHnrBLp1A1NFJIjWi0PwKLOVbxJPcg0RzQPI6KmBtV6ZMgPh38l93pgubgHDQqhaZ2Sfc0qv%2BRantbfg1mWGAUpRMP4RqXP78Wvu%2FCfvkWWGc5NhCTV71tGOIGgDBR3%2Bu6%2Fjj44KlE5biSNDOWW7Bigcz27lvOTidzNw8s%2FWtKAIxWbnCzZn4%2FJMBUub1SIMcW89g57k4mfPmDlCgpZKzxwl6beSfdtZ4RUWXmZOn5v5NkxVKhU4wR0Pq7NklczEGdRq2nIAcu7v22Uw2o%2FxMY0xBdeC9Korm5%2FNHnxl6K%2Bd6FXSoT9a3XIMQO359auZPiZWzrNlZe%2BqnOahXcx7KAhQIRqSOapSmL4ygJor4r5isJhRuDoXy7vJAVuH%2FRDtEJJ8rZTq0BdC23Bz%2B0MrsdgbK%2BiW; _UP_D_=pc; __wpkreporterwid_=3d3f74a7-99b7-4916-3f78-911fc2eb9d87; tfstk=fIoZNxjnbhKwPOu0TWZ4LsaRqirTcudSSmNbnxD0C5VgClMm8xMyB-GsnSu4tjpOflAOmSD-9PNiGl120XrgkVNb1SrqHbJBN3tSBAEYoQOWVUUg9qZ8n1bGGkD3CqGYINKSBABhjnXgp3_Vywz6gSc0Syj3BWf0mr2DLW24eZfiiovEKWefj1q0swq3E82iNEMinMy7SLrcpA4Fh3z_ZAViCfih3PbtdW5N_DuU77AaTijmYRkL2Wq54ENoy5a7ZXxCbok33XzS7QSZgxD-oyoVsdGotql0p2dVu7umC4nLStbiLmParc4FELHrI-c0u2dPVRrs8zoZWKCnIbNZrlHfUCMUz2z8KyXVSlgSFmUojh58OzeqTzgwaGll4YCYKwctDV5coP2LL79eKHxpNTXHmre1kZU32JPWCR_AkP2LL79eLZQY-WeUNdw1.; __pus=2051c82285199d8be553be41dd5a2100AAQ+mmv35G4FDDZ5x+3Mhe2OMbNgweQ1ODbW8zDt9YuP1LQVqHUuAAz9KWLsPjpNtim0AVGHusN4MCosTmbq/khM; __kp=e6604120-6051-11ef-bfe4-c31b6cdd0766; __kps=AATcZArVgS76EPn0FMaV4HEj; __ktd=sii/iz4ePzEaoVirXul7QQ==; __uid=AATcZArVgS76EPn0FMaV4HEj; __itrace_wid=5829b95d-dac1-48d3-bfd5-f60cd9462786; __puus=7da0b96cb710fa1b376934485f977e05AATp/q8/QupT7IiBR1GWqZhxlIRT677smMvoHlLxQA0Lk6CkP0YJBOTl+p9DZgzlMz6w4hPXPgWsokukk8PW7ZfhFfPmv8tKMgLpCGLW+tk57luhNghmSdTeVPkAF59STtyCPBEtiNzNAd/zZJ6qILJDi5ywEBAAAg+gOyWHoLHNUR+QxeHRuQa8g5WWA95J8jebIlrr8rCvI1vjTbtiYktT"); // spider.init(mockContext, "b-user-id=89ede34e-0efc-e1dd-c997-f16aaa792d0c; _UP_A4A_11_=wb9661c6dfb642f88f73d8e0c7edd398; b-user-id=89ede34e-0efc-e1dd-c997-f16aaa792d0c; ctoken=wla6p3EUOLyn1FSB8IKp1SEW; grey-id=5583e32b-39df-4bf0-f39f-1adf83f604a2; grey-id.sig=p8ReBIMG2BeZu1sYvsuOAZxYbx-MVrsfKEiCv87MsTM; isQuark=true; isQuark.sig=hUgqObykqFom5Y09bll94T1sS9abT1X-4Df_lzgl8nM; _UP_F7E_8D_=ZkyvVHnrBLp1A1NFJIjWi0PwKLOVbxJPcg0RzQPI6KmBtV6ZMgPh38l93pgubgHDQqhaZ2Sfc0qv%2BRantbfg1mWGAUpRMP4RqXP78Wvu%2FCfvkWWGc5NhCTV71tGOIGgDBR3%2Bu6%2Fjj44KlE5biSNDOWW7Bigcz27lvOTidzNw8s%2FWtKAIxWbnCzZn4%2FJMBUub1SIMcW89g57k4mfPmDlCgpZKzxwl6beSfdtZ4RUWXmZOn5v5NkxVKhU4wR0Pq7NklczEGdRq2nIAcu7v22Uw2o%2FxMY0xBdeC9Korm5%2FNHnxl6K%2Bd6FXSoT9a3XIMQO359auZPiZWzrNlZe%2BqnOahXcx7KAhQIRqSOapSmL4ygJor4r5isJhRuDoXy7vJAVuH%2FRDtEJJ8rZTq0BdC23Bz%2B0MrsdgbK%2BiW; _UP_D_=pc; __wpkreporterwid_=3d3f74a7-99b7-4916-3f78-911fc2eb9d87; tfstk=fIoZNxjnbhKwPOu0TWZ4LsaRqirTcudSSmNbnxD0C5VgClMm8xMyB-GsnSu4tjpOflAOmSD-9PNiGl120XrgkVNb1SrqHbJBN3tSBAEYoQOWVUUg9qZ8n1bGGkD3CqGYINKSBABhjnXgp3_Vywz6gSc0Syj3BWf0mr2DLW24eZfiiovEKWefj1q0swq3E82iNEMinMy7SLrcpA4Fh3z_ZAViCfih3PbtdW5N_DuU77AaTijmYRkL2Wq54ENoy5a7ZXxCbok33XzS7QSZgxD-oyoVsdGotql0p2dVu7umC4nLStbiLmParc4FELHrI-c0u2dPVRrs8zoZWKCnIbNZrlHfUCMUz2z8KyXVSlgSFmUojh58OzeqTzgwaGll4YCYKwctDV5coP2LL79eKHxpNTXHmre1kZU32JPWCR_AkP2LL79eLZQY-WeUNdw1.; __pus=2051c82285199d8be553be41dd5a2100AAQ+mmv35G4FDDZ5x+3Mhe2OMbNgweQ1ODbW8zDt9YuP1LQVqHUuAAz9KWLsPjpNtim0AVGHusN4MCosTmbq/khM; __kp=e6604120-6051-11ef-bfe4-c31b6cdd0766; __kps=AATcZArVgS76EPn0FMaV4HEj; __ktd=sii/iz4ePzEaoVirXul7QQ==; __uid=AATcZArVgS76EPn0FMaV4HEj; __itrace_wid=5829b95d-dac1-48d3-bfd5-f60cd9462786; __puus=7da0b96cb710fa1b376934485f977e05AATp/q8/QupT7IiBR1GWqZhxlIRT677smMvoHlLxQA0Lk6CkP0YJBOTl+p9DZgzlMz6w4hPXPgWsokukk8PW7ZfhFfPmv8tKMgLpCGLW+tk57luhNghmSdTeVPkAF59STtyCPBEtiNzNAd/zZJ6qILJDi5ywEBAAAg+gOyWHoLHNUR+QxeHRuQa8g5WWA95J8jebIlrr8rCvI1vjTbtiYktT");
spider.init(mockContext, "_UP_A4A_11_=wb9681fbaed6454a8112f31e53b5c0be; __pus=45beefa93e8775c9211487d0c8ddd2b1AASCmV5S7LY0dfX90N3p4wU/G4f/oS0gZK6cpxZMZiDtXt9s7KiSs3tVZOXnIDel69C9KaQ61IQlnLYH2rS4NGjO; __kp=fe663a90-68d5-11ef-8b23-e77b0eaa352c; __kps=AAT32Fob+vq66znO5UHSHAPi; __ktd=39oXE+BT53YlFgUfFVq9kw==; __uid=AAT32Fob+vq66znO5UHSHAPi; xlly_s=1; b-user-id=91d551ad-db9e-f092-2b42-aa4db35b8ed0; isg=BNXVFRgkH_dXwTuJ8PizGl2W5NGP0onkjXrhLld60cybrvegHyMutYcsfLIYrqGc; tfstk=fNlSqGqmrgj57RpyCwL4hfk8bfFCODOw9waKS2CPJ7F-JWib0zWyEJ-IhDn42_P82ZEQ7caRpHf8M9aTxuFEUuzKc2nJry8uwiCY7PzLvzeLHsUUP6Ud9WQoncuOabJuT6NutWKwbCRZz4V39rUtZ-SukyUWT_U8JbtmmvxwbCR2eZFBVhkeml_RcyqYyzEdwENYSyFdv_nLD-UT7gFKvWLbHy4G2aCLJoUYJoEL9WnKkjXR5y97q4TY2O9qutVEyo1soja-eT0zc6CKGxw7XBrf96hbPqfsiZf6LlHg4RrtDI57OqUIcRkWf_iIJVDLhXsJzcnxdDUmnH6Qfv3rIj2RJT3jOuwtw-_9SVg8JDeInh1aP7kbCbMk-i3-buMTZ2764qwshR4YHw68aAuZtRhJNGq4IyibQYt1NcIzH1r_KcBClRfQll8Xl9Xh_6YQJFIaDQy8ozw2lEs-K8U0ll8Xl9X3er477ETf2vf..; __puus=514ad4334da84f912529719d557085b2AASV1aKJKLRXGjvHRfwQJ5gupjOzlxgeAImozKKYdppZduMrKS7Q5+3hUZZ0f6zk7YpAGu7p0GVPYojTpZdhvnamXzCBLryM3ULhlqkw9yR6oVeTr3b1MituYgqfeFM4jHi4ASNiLk22pCNKteAtD6aowAM0K1ZFVc7j7xlpxLEgS1CoNSttupAb56Zf+ruuTkDPsjZPiRW1S4yM/kduA247"); spider.init(mockContext, "_UP_28A_52_=386;_UP_BT_=html5;_UP_F7E_8D_=0z44HdIBxZZTFH3p1NV%2FwWJIkAWBTYaH20RoPCksvMmyhI6XxrMIHoi8gAqVoKf%2Bfw0hw4mmmcFLHpvA%2Fhicy1HUTu2LBlCP6GF%2FnM%2Bm0IJoj1BQdak3tm1o3OeN1OV9dQAEQ0UDfWTXDik4ZZxmO5Iwvj6IsFkb5GPrrCl5M87ivs0EP%2FjAQTQimMgEdat62Byd22%2BZGM703ymU3s8N9B3XRdiyy8E7vOTidzNw8s%2FWtKAIxWbnCzZn4%2FJMBUubLuroBmVIB9UVOMEdD6uzZJXMxBnUatpyAHLu79tlMNqP8TGNMQXXgvSqK5ufzR58ZeivnehV0qE%2FWt1yDEDt%2BfWrmT4mVs6zZWXvqpzmoV3MeygIUCEakh2GAn6rsLT1b2ZsrSkQkrM6F8u7yQFbh%2F0Q7RCSfK2U6tAXQttwc%2FtDK7HYGyvolg%3D%3D;_UP_6D1_64_=069;_UP_A4A_11_=wb9cc1693e1d486b8b2ac58e4839d64e;_UP_D_=mobilectoken=4IUaeDKAfn3pV-MKaWfg_GHG;__pus=76f683009a07bdd1c1a7c04f05838d4bAASVSWCD2jiL0GI43jmIC5x50sk6Tgbh4UtXFf/vqOUyaX8Aory/bsGsGCTl68Lo7sJPpZpBJdif81oItfZizhzH;__kp=d8da7a20-7522-11f0-8e98-7daef001221f;__kps=AATcZArVgS76EPn0FMaV4HEj;__ktd=sii/iz4ePzEaoVirXul7QQ==;__uid=AATcZArVgS76EPn0FMaV4HEj;__puus=b4617d4cdadeb05679ed39be924d99d8AATp/q8/QupT7IiBR1GWqZhx6c42nqKQR/5g49EMGJ5TE742htjk9EkPPibrpvSh8/N8ybuC/Wc4BP1YbLBb5ZFEEOPrmFBTCZtKVEh5HcqkSL6T6LoyeKfvGe32k9HckqoPn9MxbAThhpRlbHg8QgH8OwxLHp0V2cAYcsGY72XN2ZPL7JzZyOAwmSsJwpX9B0+LYNvco+Ixucn5KaaCTKND");
Server.get().start(); Server.get().start();
} }
@ -41,7 +41,7 @@ public class QuarkTest {
@org.junit.Test @org.junit.Test
public void detailContent() throws Exception { public void detailContent() throws Exception {
String content = spider.detailContent(Arrays.asList("https://pan.quark.cn/s/38c5e16d71f7")); String content = spider.detailContent(Arrays.asList("https://pan.quark.cn/s/469c2acf8640"));
System.out.println("detailContent--" + content); System.out.println("detailContent--" + content);
JsonObject map = Json.safeObject(content); JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create(); Gson gson = new GsonBuilder().setPrettyPrinting().create();
@ -52,7 +52,7 @@ public class QuarkTest {
@org.junit.Test @org.junit.Test
public void playerContent() throws Exception { public void playerContent() throws Exception {
String content = spider.playerContent("普画","41ea9a50cbdd4e50b019bcd78687ebc1++22fc6fa8350d22e0eaecc49035368e81++38c5e16d71f7++WFcYTmRhjJpKTui56aleYdzBZi9R203GERBVzYNxDxI=",new ArrayList<>()); String content = spider.playerContent("quark原画", "a04522f504a742db8ebaf69e3b7f50d6++375807f3f1068a8fdabac127ec4db89f++469c2acf8640++PVTgPNXNtRFDDkE6SAYX4KPSjk9xl449JkTHl6mtu7k=", new ArrayList<>());
System.out.println("playerContent--" + content); System.out.println("playerContent--" + content);
JsonObject map = Json.safeObject(content); JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create(); Gson gson = new GsonBuilder().setPrettyPrinting().create();

View File

@ -0,0 +1,100 @@
import android.app.Application;
import com.github.catvod.server.Server;
import com.github.catvod.spider.Init;
import com.github.catvod.spider.SeedHub;
import com.github.catvod.spider.Wogg;
import com.github.catvod.utils.Json;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import org.junit.Assert;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.Arrays;
@RunWith(RobolectricTestRunner.class)
public class SeedHubTest {
private Application mockContext;
private SeedHub spider;
@org.junit.Before
public void setUp() throws Exception {
mockContext = RuntimeEnvironment.application;
Init.init(mockContext);
spider = new SeedHub();
Server.get().start();
// spider.init(mockContext, "{\"cookie\":\"b-user-id=89ede34e-0efc-e1dd-c997-f16aaa792d0c; _UP_A4A_11_=wb9661c6dfb642f88f73d8e0c7edd398; b-user-id=89ede34e-0efc-e1dd-c997-f16aaa792d0c; ctoken=wla6p3EUOLyn1FSB8IKp1SEW; grey-id=5583e32b-39df-4bf0-f39f-1adf83f604a2; grey-id.sig=p8ReBIMG2BeZu1sYvsuOAZxYbx-MVrsfKEiCv87MsTM; isQuark=true; isQuark.sig=hUgqObykqFom5Y09bll94T1sS9abT1X-4Df_lzgl8nM; _UP_F7E_8D_=ZkyvVHnrBLp1A1NFJIjWi0PwKLOVbxJPcg0RzQPI6KmBtV6ZMgPh38l93pgubgHDQqhaZ2Sfc0qv%2BRantbfg1mWGAUpRMP4RqXP78Wvu%2FCfvkWWGc5NhCTV71tGOIGgDBR3%2Bu6%2Fjj44KlE5biSNDOWW7Bigcz27lvOTidzNw8s%2FWtKAIxWbnCzZn4%2FJMBUub1SIMcW89g57k4mfPmDlCgpZKzxwl6beSfdtZ4RUWXmZOn5v5NkxVKhU4wR0Pq7NklczEGdRq2nIAcu7v22Uw2o%2FxMY0xBdeC9Korm5%2FNHnxl6K%2Bd6FXSoT9a3XIMQO359auZPiZWzrNlZe%2BqnOahXcx7KAhQIRqSOapSmL4ygJor4r5isJhRuDoXy7vJAVuH%2FRDtEJJ8rZTq0BdC23Bz%2B0MrsdgbK%2BiW; _UP_D_=pc; __wpkreporterwid_=3d3f74a7-99b7-4916-3f78-911fc2eb9d87; tfstk=fIoZNxjnbhKwPOu0TWZ4LsaRqirTcudSSmNbnxD0C5VgClMm8xMyB-GsnSu4tjpOflAOmSD-9PNiGl120XrgkVNb1SrqHbJBN3tSBAEYoQOWVUUg9qZ8n1bGGkD3CqGYINKSBABhjnXgp3_Vywz6gSc0Syj3BWf0mr2DLW24eZfiiovEKWefj1q0swq3E82iNEMinMy7SLrcpA4Fh3z_ZAViCfih3PbtdW5N_DuU77AaTijmYRkL2Wq54ENoy5a7ZXxCbok33XzS7QSZgxD-oyoVsdGotql0p2dVu7umC4nLStbiLmParc4FELHrI-c0u2dPVRrs8zoZWKCnIbNZrlHfUCMUz2z8KyXVSlgSFmUojh58OzeqTzgwaGll4YCYKwctDV5coP2LL79eKHxpNTXHmre1kZU32JPWCR_AkP2LL79eLZQY-WeUNdw1.; __pus=2051c82285199d8be553be41dd5a2100AAQ+mmv35G4FDDZ5x+3Mhe2OMbNgweQ1ODbW8zDt9YuP1LQVqHUuAAz9KWLsPjpNtim0AVGHusN4MCosTmbq/khM; __kp=e6604120-6051-11ef-bfe4-c31b6cdd0766; __kps=AATcZArVgS76EPn0FMaV4HEj; __ktd=sii/iz4ePzEaoVirXul7QQ==; __uid=AATcZArVgS76EPn0FMaV4HEj; __itrace_wid=5829b95d-dac1-48d3-bfd5-f60cd9462786; __puus=7da0b96cb710fa1b376934485f977e05AATp/q8/QupT7IiBR1GWqZhxlIRT677smMvoHlLxQA0Lk6CkP0YJBOTl+p9DZgzlMz6w4hPXPgWsokukk8PW7ZfhFfPmv8tKMgLpCGLW+tk57luhNghmSdTeVPkAF59STtyCPBEtiNzNAd/zZJ6qILJDi5ywEBAAAg+gOyWHoLHNUR+QxeHRuQa8g5WWA95J8jebIlrr8rCvI1vjTbtiYktT\",\"token\":\"26fc6787afff43e78b78992e782502f1\"}");
spider.init(mockContext, "{\"site\": [\"https://www.wogg.net/\",\"https://wogg.xxooo.cf/\"],\"uccookie\":\"_UP_28A_52_=381;_UP_BT_=html5;_UP_F7E_8D_=ZkyvVHnrBLp1A1NFJIjWi0PwKLOVbxJPcg0RzQPI6Kl8ttcYB1X9Nkx0DnGMyJVLgv0M%2FCztZQaIhZhKaI%2F0Fa%2F5Fqe1t%2BDWF1o9sO71vnupc%2Fvxa%2B78J%2B%2BRZYZzk2EJNXvW0Y4gaAMFHf67r%2BOPjtggEPU7aNnlZbsGKBzPbuW85OJ3M3Dyz9a0oAjFZucLNmfj8kwFS5su6ugGZUgH1RU4wR0Pq7NklczEGdRq2nIAcu7v22Uw2o%2FxMY0xBdeC9Korm5%2FNHnxl6K%2Bd6FXSoT9a3XIMQO359auZPiZWzrNlZe%2BqnOahXcx7KAhQIRqSHYYCfquwtPWx%2FgYBqTnLfzoXy7vJAVuH%2FRDtEJJ8rZTq0BdC23Bz%2B0MrsdgbK%2BiW;_UP_6D1_64_=069;_UP_A4A_11_=wb96b12a16f941809f5af993726ba192;_UP_D_=mobilectoken=oxJV13ITm7aa7_rsplIXC-_v;__pus=cef2cc2dfd5d8af70df36bcedf83995cAAT3ZYhqlLos+yCaVQYYC944c4HEQnHz8uEpdQner0OcqISOpBObxl2kck65MGceRIDBd+MLtDxsNqwXvgDIFpYU;__kp=0d340990-9b39-11ef-ae54-4f733858896a;__kps=AAQXoZxLp9Oe2Ps0d/hNBJl4;__ktd=2gPNadz6Z9c+2+FyQyQZUw==;__uid=AAQXoZxLp9Oe2Ps0d/hNBJl4;UDRIVE_TRANSFER_SESS=UpLXXX2HAXJNW0AHgDcMurpazcqTbU-EQWnKG6RKtkdhdqZgHGTM-BSulf_oo1nmMMjo6hFdByLlm-bEiwjByMbIIEehsxhuuV00b96SSaPExn0wMcQ8SmzJa-YwonEE2MEVWCHcRYuW4Z-ljMOgab7qaGtQUpqjkl-p6OTv23BW-4gM6y7DNKvGeaMv_3NX\"," +
"\"cookie\":\"b-user-id=89ede34e-0efc-e1dd-c997-f16aaa792d0c; _UP_A4A_11_=wb9661c6dfb642f88f73d8e0c7edd398; b-user-id=89ede34e-0efc-e1dd-c997-f16aaa792d0c; ctoken=wla6p3EUOLyn1FSB8IKp1SEW; grey-id=5583e32b-39df-4bf0-f39f-1adf83f604a2; grey-id.sig=p8ReBIMG2BeZu1sYvsuOAZxYbx-MVrsfKEiCv87MsTM; isQuark=true; isQuark.sig=hUgqObykqFom5Y09bll94T1sS9abT1X-4Df_lzgl8nM; _UP_F7E_8D_=ZkyvVHnrBLp1A1NFJIjWi0PwKLOVbxJPcg0RzQPI6KmBtV6ZMgPh38l93pgubgHDQqhaZ2Sfc0qv%2BRantbfg1mWGAUpRMP4RqXP78Wvu%2FCfvkWWGc5NhCTV71tGOIGgDBR3%2Bu6%2Fjj44KlE5biSNDOWW7Bigcz27lvOTidzNw8s%2FWtKAIxWbnCzZn4%2FJMBUub1SIMcW89g57k4mfPmDlCgpZKzxwl6beSfdtZ4RUWXmZOn5v5NkxVKhU4wR0Pq7NklczEGdRq2nIAcu7v22Uw2o%2FxMY0xBdeC9Korm5%2FNHnxl6K%2Bd6FXSoT9a3XIMQO359auZPiZWzrNlZe%2BqnOahXcx7KAhQIRqSOapSmL4ygJor4r5isJhRuDoXy7vJAVuH%2FRDtEJJ8rZTq0BdC23Bz%2B0MrsdgbK%2BiW; _UP_D_=pc; __wpkreporterwid_=3d3f74a7-99b7-4916-3f78-911fc2eb9d87; tfstk=fIoZNxjnbhKwPOu0TWZ4LsaRqirTcudSSmNbnxD0C5VgClMm8xMyB-GsnSu4tjpOflAOmSD-9PNiGl120XrgkVNb1SrqHbJBN3tSBAEYoQOWVUUg9qZ8n1bGGkD3CqGYINKSBABhjnXgp3_Vywz6gSc0Syj3BWf0mr2DLW24eZfiiovEKWefj1q0swq3E82iNEMinMy7SLrcpA4Fh3z_ZAViCfih3PbtdW5N_DuU77AaTijmYRkL2Wq54ENoy5a7ZXxCbok33XzS7QSZgxD-oyoVsdGotql0p2dVu7umC4nLStbiLmParc4FELHrI-c0u2dPVRrs8zoZWKCnIbNZrlHfUCMUz2z8KyXVSlgSFmUojh58OzeqTzgwaGll4YCYKwctDV5coP2LL79eKHxpNTXHmre1kZU32JPWCR_AkP2LL79eLZQY-WeUNdw1.; __pus=2051c82285199d8be553be41dd5a2100AAQ+mmv35G4FDDZ5x+3Mhe2OMbNgweQ1ODbW8zDt9YuP1LQVqHUuAAz9KWLsPjpNtim0AVGHusN4MCosTmbq/khM; __kp=e6604120-6051-11ef-bfe4-c31b6cdd0766; __kps=AATcZArVgS76EPn0FMaV4HEj; __ktd=sii/iz4ePzEaoVirXul7QQ==; __uid=AATcZArVgS76EPn0FMaV4HEj; __itrace_wid=5829b95d-dac1-48d3-bfd5-f60cd9462786; __puus=7da0b96cb710fa1b376934485f977e05AATp/q8/QupT7IiBR1GWqZhxlIRT677smMvoHlLxQA0Lk6CkP0YJBOTl+p9DZgzlMz6w4hPXPgWsokukk8PW7ZfhFfPmv8tKMgLpCGLW+tk57luhNghmSdTeVPkAF59STtyCPBEtiNzNAd/zZJ6qILJDi5ywEBAAAg+gOyWHoLHNUR+QxeHRuQa8g5WWA95J8jebIlrr8rCvI1vjTbtiYktT\",\"token\":\"26fc6787afff43e78b78992e782502f1\"}");
// spider.init(mockContext, "");
}
@org.junit.Test
public void homeContent() throws Exception {
String content = spider.homeContent(true);
JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println("homeContent--" + gson.toJson(map));
//Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
}
@org.junit.Test
public void homeVideoContent() throws Exception {
String content = spider.homeVideoContent();
JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println("homeVideoContent--" + gson.toJson(map));
// Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
}
@org.junit.Test
public void categoryContent() throws Exception {
String content = spider.categoryContent("2", "2", true, null);
JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println("categoryContent--" + gson.toJson(map));
Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
}
@org.junit.Test
public void detailContent() throws Exception {
String content = spider.detailContent(Arrays.asList("/movies/113317/"));
System.out.println("detailContent--" + content);
JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println("detailContent--" + gson.toJson(map));
Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
}
@org.junit.Test
public void playerContent() throws Exception {
String content = spider.playerContent("uc普画", "52fd84f0bfd44c93a1fca6c76d0b8d16++28d4a0a00ad96562f96506da49b988a0++5ae2d1c474024++yA4L8FmH06i8nfmmY4MwHNSsyhpVzLhzxqDixCp0xm4=", new ArrayList<>());
System.out.println("playerContent--" + content);
JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println("playerContent--" + gson.toJson(map));
Assert.assertFalse(map.getAsJsonPrimitive("url").getAsString().isEmpty());
}
@org.junit.Test
public void searchContent() throws Exception {
String content = spider.searchContent("红海", false);
JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println("searchContent--" + gson.toJson(map));
Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
}
}

View File

@ -1,97 +0,0 @@
import android.app.Application;
import com.github.catvod.spider.DaGongRen;
import com.github.catvod.spider.Init;
import com.github.catvod.spider.Supjav;
import com.github.catvod.utils.Json;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import org.junit.Assert;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.Arrays;
@RunWith(RobolectricTestRunner.class)
public class SupjavTest {
// @Mock
private Application mockContext;
private Supjav spider;
@org.junit.Before
public void setUp() throws Exception {
mockContext = RuntimeEnvironment.application;
Init.init(mockContext);
spider = new Supjav();
spider.init(mockContext, "");
}
@org.junit.Test
public void homeContent() throws Exception {
String content = spider.homeContent(true);
JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println("homeContent--" + gson.toJson(map));
//Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
}
@org.junit.Test
public void homeVideoContent() throws Exception {
String content = spider.homeVideoContent();
JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println("homeVideoContent--" + gson.toJson(map));
//Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
}
@org.junit.Test
public void categoryContent() throws Exception {
String content = spider.categoryContent("popular", "2", true, null);
JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println("categoryContent--" + gson.toJson(map));
Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
}
@org.junit.Test
public void detailContent() throws Exception {
String content = spider.detailContent(Arrays.asList("288706.html"));
JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println("detailContent--" + gson.toJson(map));
Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
}
@org.junit.Test
public void playerContent() throws Exception {
String froms = "FST$$$ST$$$VOE";
String urls = "播放$7a39ff703f95e9c01ee6785def2cf624c8636748c26ab4afa219d49d98b7c77ebef268d993e34f9763bc07b2d690fb8d40ec53eb3cf4f17270830acf091765df$$$播放$a8a52ce3124daf8525aeaae8faf1a45e1e74d8b6e1b0db2ee59510d9a238d462be957d62dd34d708391cc6d394bc3bf326eeca43de00d2967a95ac96a12a3b94549b8fd2edab26b7049e1116b32c18c9$$$播放$0a38bff9ae3e860ff7cc5a760f2edd22604306efa019bf6d0adb9874e35d33b8a50955ac4154f2c25c073f23277513045b8c9b26fdfbb54fef4cad7eaf8a6b32"
;
for (int i = 0; i < urls.split("\\$\\$\\$").length; i++) {
String content = spider.playerContent(froms.split("\\$\\$\\$")[i], urls.split("\\$\\$\\$")[i].split("\\$")[1], new ArrayList<>());
JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println("playerContent--" + gson.toJson(map));
// Assert.assertFalse(map.getAsJsonPrimitive("url").getAsString().isEmpty());
}
}
@org.junit.Test
public void searchContent() throws Exception {
String content = spider.searchContent("fc", false);
JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println("searchContent--" + gson.toJson(map));
Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
}
}

View File

@ -1,11 +1,7 @@
import android.app.Application; import android.app.Application;
import com.github.catvod.server.Server; import com.github.catvod.server.Server;
import com.github.catvod.spider.Init; import com.github.catvod.spider.Init;
import com.github.catvod.spider.PanSearch; import com.github.catvod.spider.TgSearchBaidu;
import com.github.catvod.spider.Tg189Search;
import com.github.catvod.spider.TgQuarkSearch;
import com.github.catvod.spider.TgSearch;
import com.github.catvod.spider.TianYiSo;
import com.github.catvod.utils.Json; import com.github.catvod.utils.Json;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
@ -15,6 +11,7 @@ import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@ -22,23 +19,23 @@ public class TgSearchTest {
private Application mockContext; private Application mockContext;
private TgQuarkSearch spider; private TgSearchBaidu spider;
@org.junit.Before @org.junit.Before
public void setUp() throws Exception { public void setUp() throws Exception {
mockContext = RuntimeEnvironment.application; mockContext = RuntimeEnvironment.application;
Init.init(mockContext); Init.init(mockContext);
spider = new TgQuarkSearch(); spider = new TgSearchBaidu();
Server.get().start(); Server.get().start();
// spider.init(mockContext, "{\"cookie\":\"b-user-id=89ede34e-0efc-e1dd-c997-f16aaa792d0c; _UP_A4A_11_=wb9661c6dfb642f88f73d8e0c7edd398; b-user-id=89ede34e-0efc-e1dd-c997-f16aaa792d0c; ctoken=wla6p3EUOLyn1FSB8IKp1SEW; grey-id=5583e32b-39df-4bf0-f39f-1adf83f604a2; grey-id.sig=p8ReBIMG2BeZu1sYvsuOAZxYbx-MVrsfKEiCv87MsTM; isQuark=true; isQuark.sig=hUgqObykqFom5Y09bll94T1sS9abT1X-4Df_lzgl8nM; _UP_F7E_8D_=ZkyvVHnrBLp1A1NFJIjWi0PwKLOVbxJPcg0RzQPI6KmBtV6ZMgPh38l93pgubgHDQqhaZ2Sfc0qv%2BRantbfg1mWGAUpRMP4RqXP78Wvu%2FCfvkWWGc5NhCTV71tGOIGgDBR3%2Bu6%2Fjj44KlE5biSNDOWW7Bigcz27lvOTidzNw8s%2FWtKAIxWbnCzZn4%2FJMBUub1SIMcW89g57k4mfPmDlCgpZKzxwl6beSfdtZ4RUWXmZOn5v5NkxVKhU4wR0Pq7NklczEGdRq2nIAcu7v22Uw2o%2FxMY0xBdeC9Korm5%2FNHnxl6K%2Bd6FXSoT9a3XIMQO359auZPiZWzrNlZe%2BqnOahXcx7KAhQIRqSOapSmL4ygJor4r5isJhRuDoXy7vJAVuH%2FRDtEJJ8rZTq0BdC23Bz%2B0MrsdgbK%2BiW; _UP_D_=pc; __wpkreporterwid_=3d3f74a7-99b7-4916-3f78-911fc2eb9d87; tfstk=fIoZNxjnbhKwPOu0TWZ4LsaRqirTcudSSmNbnxD0C5VgClMm8xMyB-GsnSu4tjpOflAOmSD-9PNiGl120XrgkVNb1SrqHbJBN3tSBAEYoQOWVUUg9qZ8n1bGGkD3CqGYINKSBABhjnXgp3_Vywz6gSc0Syj3BWf0mr2DLW24eZfiiovEKWefj1q0swq3E82iNEMinMy7SLrcpA4Fh3z_ZAViCfih3PbtdW5N_DuU77AaTijmYRkL2Wq54ENoy5a7ZXxCbok33XzS7QSZgxD-oyoVsdGotql0p2dVu7umC4nLStbiLmParc4FELHrI-c0u2dPVRrs8zoZWKCnIbNZrlHfUCMUz2z8KyXVSlgSFmUojh58OzeqTzgwaGll4YCYKwctDV5coP2LL79eKHxpNTXHmre1kZU32JPWCR_AkP2LL79eLZQY-WeUNdw1.; __pus=2051c82285199d8be553be41dd5a2100AAQ+mmv35G4FDDZ5x+3Mhe2OMbNgweQ1ODbW8zDt9YuP1LQVqHUuAAz9KWLsPjpNtim0AVGHusN4MCosTmbq/khM; __kp=e6604120-6051-11ef-bfe4-c31b6cdd0766; __kps=AATcZArVgS76EPn0FMaV4HEj; __ktd=sii/iz4ePzEaoVirXul7QQ==; __uid=AATcZArVgS76EPn0FMaV4HEj; __itrace_wid=5829b95d-dac1-48d3-bfd5-f60cd9462786; __puus=7da0b96cb710fa1b376934485f977e05AATp/q8/QupT7IiBR1GWqZhxlIRT677smMvoHlLxQA0Lk6CkP0YJBOTl+p9DZgzlMz6w4hPXPgWsokukk8PW7ZfhFfPmv8tKMgLpCGLW+tk57luhNghmSdTeVPkAF59STtyCPBEtiNzNAd/zZJ6qILJDi5ywEBAAAg+gOyWHoLHNUR+QxeHRuQa8g5WWA95J8jebIlrr8rCvI1vjTbtiYktT\",\"token\":\"26fc6787afff43e78b78992e782502f1\"}"); // spider.init(mockContext, "{\"cookie\":\"b-user-id=89ede34e-0efc-e1dd-c997-f16aaa792d0c; _UP_A4A_11_=wb9661c6dfb642f88f73d8e0c7edd398; b-user-id=89ede34e-0efc-e1dd-c997-f16aaa792d0c; ctoken=wla6p3EUOLyn1FSB8IKp1SEW; grey-id=5583e32b-39df-4bf0-f39f-1adf83f604a2; grey-id.sig=p8ReBIMG2BeZu1sYvsuOAZxYbx-MVrsfKEiCv87MsTM; isQuark=true; isQuark.sig=hUgqObykqFom5Y09bll94T1sS9abT1X-4Df_lzgl8nM; _UP_F7E_8D_=ZkyvVHnrBLp1A1NFJIjWi0PwKLOVbxJPcg0RzQPI6KmBtV6ZMgPh38l93pgubgHDQqhaZ2Sfc0qv%2BRantbfg1mWGAUpRMP4RqXP78Wvu%2FCfvkWWGc5NhCTV71tGOIGgDBR3%2Bu6%2Fjj44KlE5biSNDOWW7Bigcz27lvOTidzNw8s%2FWtKAIxWbnCzZn4%2FJMBUub1SIMcW89g57k4mfPmDlCgpZKzxwl6beSfdtZ4RUWXmZOn5v5NkxVKhU4wR0Pq7NklczEGdRq2nIAcu7v22Uw2o%2FxMY0xBdeC9Korm5%2FNHnxl6K%2Bd6FXSoT9a3XIMQO359auZPiZWzrNlZe%2BqnOahXcx7KAhQIRqSOapSmL4ygJor4r5isJhRuDoXy7vJAVuH%2FRDtEJJ8rZTq0BdC23Bz%2B0MrsdgbK%2BiW; _UP_D_=pc; __wpkreporterwid_=3d3f74a7-99b7-4916-3f78-911fc2eb9d87; tfstk=fIoZNxjnbhKwPOu0TWZ4LsaRqirTcudSSmNbnxD0C5VgClMm8xMyB-GsnSu4tjpOflAOmSD-9PNiGl120XrgkVNb1SrqHbJBN3tSBAEYoQOWVUUg9qZ8n1bGGkD3CqGYINKSBABhjnXgp3_Vywz6gSc0Syj3BWf0mr2DLW24eZfiiovEKWefj1q0swq3E82iNEMinMy7SLrcpA4Fh3z_ZAViCfih3PbtdW5N_DuU77AaTijmYRkL2Wq54ENoy5a7ZXxCbok33XzS7QSZgxD-oyoVsdGotql0p2dVu7umC4nLStbiLmParc4FELHrI-c0u2dPVRrs8zoZWKCnIbNZrlHfUCMUz2z8KyXVSlgSFmUojh58OzeqTzgwaGll4YCYKwctDV5coP2LL79eKHxpNTXHmre1kZU32JPWCR_AkP2LL79eLZQY-WeUNdw1.; __pus=2051c82285199d8be553be41dd5a2100AAQ+mmv35G4FDDZ5x+3Mhe2OMbNgweQ1ODbW8zDt9YuP1LQVqHUuAAz9KWLsPjpNtim0AVGHusN4MCosTmbq/khM; __kp=e6604120-6051-11ef-bfe4-c31b6cdd0766; __kps=AATcZArVgS76EPn0FMaV4HEj; __ktd=sii/iz4ePzEaoVirXul7QQ==; __uid=AATcZArVgS76EPn0FMaV4HEj; __itrace_wid=5829b95d-dac1-48d3-bfd5-f60cd9462786; __puus=7da0b96cb710fa1b376934485f977e05AATp/q8/QupT7IiBR1GWqZhxlIRT677smMvoHlLxQA0Lk6CkP0YJBOTl+p9DZgzlMz6w4hPXPgWsokukk8PW7ZfhFfPmv8tKMgLpCGLW+tk57luhNghmSdTeVPkAF59STtyCPBEtiNzNAd/zZJ6qILJDi5ywEBAAAg+gOyWHoLHNUR+QxeHRuQa8g5WWA95J8jebIlrr8rCvI1vjTbtiYktT\",\"token\":\"26fc6787afff43e78b78992e782502f1\"}");
spider.init(mockContext,"{\n" + /* spider.init(mockContext,"{\n" +
"\t\"username\":\"18896781601\" ,\"password\":\"Lushunming@0526\"\n" + "\t\"username\":\"18896781601\" ,\"password\":\"Lushunming@0526\"\n" +
"}"); // spider.init(mockContext, ""); "}"); */
spider.init(mockContext, "{\n" + " \"api_urls\": [\n" + " \"https://psweb.banye.tech:7777/api/search\",\n" + " \"https://so.566987.xyz/api/search\",\n" + " \"http://152.69.222.142:8088/api/search\"\n" + " ],\n" + " \"sources\": [\n" + " \"123盘\"\n" + " ]\n" + " }");
} }
@org.junit.Test @org.junit.Test
public void searchContent() throws Exception { public void searchContent() throws Exception {
String content = spider.searchContent("水饺皇后", false); String content = spider.searchContent("水饺皇后", false);
@ -51,7 +48,18 @@ public class TgSearchTest {
@org.junit.Test @org.junit.Test
public void detailContent() throws Exception { public void detailContent() throws Exception {
String content = spider.detailContent(Arrays.asList("/s/LEvn4lUGB6ufdQ")); String content = spider.detailContent(Arrays.asList("https://123684.com/s/u9izjv-smUWv"));
JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println("detailContent--" + gson.toJson(map));
Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
}
@org.junit.Test
public void playerContent() throws Exception {
String content1 = spider.detailContent(Arrays.asList("https://123684.com/s/u9izjv-smUWv"));
String content = spider.playerContent("pan123原画", "eyJmaWxlbmFtZSI6IlRoZS5EdW1wbGluZy5RdWVlbi4yMDI1LjEwODBwLldFQi1ETC5IMjY0LkFBQy5tcDQiLCJzaGFyZUtleSI6InU5aXpqdi1zbVVXdiIsInNoYXJlUHdkIjoiIiwibmV4dCI6LTEsImZpbGVJZCI6MTg1NjgwODEsIlMzS2V5RmxhZyI6IjE4NDMwNTU4NTItMCIsIlNpemUiOjY0MDQyNTYzMTIsIkV0YWciOiIwYjNjZGIyOTYxZWM2NmQ5MjAyMTViOTRmZGY2MDZjNyJ9", new ArrayList<>());
JsonObject map = Json.safeObject(content); JsonObject map = Json.safeObject(content);
Gson gson = new GsonBuilder().setPrettyPrinting().create(); Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println("detailContent--" + gson.toJson(map)); System.out.println("detailContent--" + gson.toJson(map));

View File

@ -0,0 +1,87 @@
package com.github.catvod.api;
import cn.hutool.core.io.FileUtil;
import com.github.catvod.utils.Json;
import com.google.gson.JsonObject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.net.URLEncoder;
@RunWith(RobolectricTestRunner.class)
public class BaiDuYunHandlerTest {
private BaiDuYunHandler baiDuYunHandler;
@Before
public void setUp() {
baiDuYunHandler = BaiDuYunHandler.get();
}
@Test
public void startScan() throws Exception {
// Mock the OkHttp.get method to return a predefined OkResult
// Execute the method under test
FileUtil.writeBytes(baiDuYunHandler.startScan(), "c://qrcode.png");
while (true) {
}
}
/* @Test
public void refreshCookie() throws Exception {
JsonObject obj = Json.safeObject("{\"open.e.189.cn\":{\"OPENINFO\":\"33c28688ef52ce9e3a9ef87388047efbde5e3e2e4c7ef6ef267632468c7dfaf294ff59fa59d34801\",\"pageOp\":\"f73420158c5c010491f1faa4fc91870e\",\"LT\":\"a8900fc0ecae0c59\",\"GUID\":\"b959026ffdf84080ae8567afd9ea4c32\",\"SSON\":\"dc466c8192e3109eaea837c1d136c1fd065253ce1c7d3a66ca1520d7d6d6307b10a1fe65c7becac73b95f24a6e681e654ec4f47c39533ebcc48bb78d6d6e63d1bbf3334e6e97eaa7092d34f87bf1209e256cd4822db68da051a0aeb532d94408c8e50486347fc713813dafc5776a7cfa665ddf96837151232745aa2957fb441d8a79ca7d86f46452060794e6f4b5873ab99ed476629aed2c7b36a44613c92f925dcfd221fce142cd1ecaab667236df697ece293e3ca24030918e5b357bc193118772278748606ade7262bf25ae7527d3c8a059bd48fc08b53b182e61e543a7e9bd1562b50bf80438\"},\"cloud.189.cn\":{\"JSESSIONID\":\"12088774C4B78E632EB944ECA2E6705F\",\"COOKIE_LOGIN_USER\":\"24DA4CBA27A8388982710C2F3D55EFAA84AEE67E9B3EF1B7AC1C565BEEF24C562052CB9B5EAC85E733C10C2704225133CD625407C352ED5D\"}}");
baiDuYunHandler.setCookie(obj);
baiDuYunHandler.refreshCookie();
while (true) {
}
}
@Test
public void download() throws Exception {
// Mock the OkHttp.get method to return a predefined OkResult
// Execute the method under test
}
@Test
public void testgetUUID() throws Exception {
JsonObject uuid = tianYiHandler.getUUID();
System.out.println(uuid);
}
@Test
public void testdownloadQRCode() throws Exception {
*//*
JsonObject uuidInfo = tianYiHandler.getUUID();
String uuid = uuidInfo.get("uuid").getAsString();
byte[] qrCode = tianYiHandler.downloadQRCode(uuid);
FileUtil.writeBytes(qrCode, "c://qrcode.png");
System.out.println(uuid);*//*
String url = "https://cloud.189.cn/api/portal/callbackUnify.action?browserId=dff95dced0b03d9d972d920f03ddd05e&redirectURL=https%3A%2F%2Fcloud.189.cn%2Fweb%2Fredirect.html";
String encode = "https%3A%2F%2Fcloud.189.cn%2Fapi%2Fportal%2FcallbackUnify.action%3FbrowserId%3Ddff95dced0b03d9d972d920f03ddd05e%26redirectURL%3Dhttps%253A%252F%252Fcloud.189.cn%252Fweb%252Fredirect.html";
assert URLEncoder.encode(url, "UTF-8").equals(encode);
}
@Test
public void loginWithPassword() throws Exception {
tianYiHandler.loginWithPassword("18896781601","Lushunming@0526");
System.out.println("1111");
}
*/
}

View File

@ -15,7 +15,7 @@ class BaiduDriveTest {
runBlocking { runBlocking {
val reslut = val reslut =
BaiduDrive.processShareLinks(listOf("https://pan.baidu.com/s/1Ov0S6S7rqnyW_S3AondhmQ?pwd=8888")) BaiduDrive.processShareLinks(listOf("https://pan.baidu.com/s/1So5RhSmNts0rWKEzjqinhQ?pwd=9527"))
System.out.println(Json.toJson(reslut)) System.out.println(Json.toJson(reslut))
} }
} }
@ -51,7 +51,7 @@ class BaiduDriveTest {
System.out.println(reslut) System.out.println(reslut)
}*/ }*/
val jsonStr = val jsonStr =
com.github.catvod.utils.Util.base64Decode("eyJ1ayI6IjExMDMyNzkxMjIzNDEiLCJzaGFyZWlkIjoiMjk1NzE4ODcyOTgiLCJmaWQiOjMxOTM5NTUxMTQyOTU4MCwicmFuZHNrIjoidkd4WXh4TVBRcXpucXZialRQeUQ2Q1FFT2VqemtJWmdFdXV2OUQ1Y3R6TSUzRCIsInBuYW1lIjoiRHJhZ29uIEJhbGwgREFJTUEuUzAxRTAxLjIwMjQuMTA4MHAuQ1IuV0VCLURMLngyNjQuQUFDLm1rdiIsInF0eXBlIjoib3JpZ2luYWwifQ==") com.github.catvod.utils.Util.base64Decode("eyJ1ayI6IjI0MDAxMjE2NzIiLCJzaGFyZWlkIjoiMjc2NTk2OTA4MTAiLCJmaWQiOjcxNzUwMDM4OTg1MjYzOSwicmFuZHNrIjoiNEdjMzFTejVsZHNpdHcwRW12ZDNzam9XYWFuVjFEQlFsUHk3VkdESHklMkI0JTNEIiwicG5hbWUiOiJUaGUuUmV0dXJuLm9mLnRoZS5MYW1lLkhlcm8uMjAyNS4yMTYwcC5XRUItREwuSDI2NS5IRFIuNjBmcHMuRERQNS4xLURyZWFtSEQubWt2IiwicXR5cGUiOiJvcmlnaW5hbCJ9")
val obj = Json.safeObject(jsonStr) val obj = Json.safeObject(jsonStr)
runBlocking { runBlocking {
val reslut = BaiduDrive.getVideoUrl(obj, "BD原画1") val reslut = BaiduDrive.getVideoUrl(obj, "BD原画1")

View File

@ -0,0 +1,75 @@
package com.github.catvod.api
import com.github.catvod.utils.Util
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class Pan123Test {
var pan123: Pan123Api? = null
@Before
fun setUp() {
pan123 = Pan123Api
// pan123!!.login()
}
@Test
@Throws(Exception::class)
fun login() {
//pan123!!.login()
"https://123684.com/s/u9izjv-smUWv".matches(Pan123Api.regex.toRegex())
"https://www.123865.com/s/u9izjv-6hSWv".matches(Util.patternQuark.toRegex())
}
@Test
@Throws(Exception::class)
fun processShareData() {
val result: Map<String, String> = pan123!!.getShareData("https://www.123865.com/s/u9izjv-6hSWv")
println(result)
val files= pan123!!.getFilesByShareUrl(result["key"]!!, result["sharePwd"]!!);
println(files)
/* if (files != null) {
for (file in files) {
val playUrl = pan123!!.getDownload(result["key"]!!, file.fileId, file.S3KeyFlag, file.Size, file.Etag)
println(playUrl)
}
}*/ if (files != null) {
for (file in files) {
val playUrl = pan123!!.getLiveTranscoding(result["key"]!!, file.fileId, file.S3KeyFlag, file.Size, file.Etag)
println(playUrl)
}
}
/*for (String s : result.keySet()) {
for (Map<String, String> stringStringMap : result.get(s)) {
String playUrl = pan123.fetchPlayUrl(stringStringMap.get("contentId"), "");
System.out.println(stringStringMap.get("name") + ":" + playUrl);
}
}*/
} /* @Test
public void download() throws Exception {
Map<String, List<Map<String, String>>> result = pan123.processShareData("https://caiyun.139.com/w/i/2nQQVZWCR24yf");
System.out.println(result);
for (String s : result.keySet()) {
for (Map<String, String> stringStringMap : result.get(s)) {
String playUrl = pan123.fetchPlayUrl(stringStringMap.get("contentId"), stringStringMap.get("linkID"));
String url2 = pan123.get4kVideoInfo(stringStringMap.get("linkID"), stringStringMap.get("path"));
System.out.println(stringStringMap.get("name") + ":" + playUrl);
System.out.println(stringStringMap.get("url2") + ":" + url2);
}
}
//;
}
*/
}

View File

@ -21,9 +21,9 @@ public class TianyiApiTest {
@Test @Test
public void getShareData() throws Exception { public void getShareData() throws Exception {
com.github.catvod.bean.tianyi.ShareData shareData = TianyiApi.get().getShareData("https://cloud.189.cn/web/share?code=ZvEjUvq6FNr2", ""); // com.github.catvod.bean.tianyi.ShareData shareData = TianyiApi.get().getShareData("https://cloud.189.cn/web/share?code=ZvEjUvq6FNr2", "");
// TianyiApi.get().getVod(shareData); // TianyiApi.get().getVod(shareData);
com.github.catvod.bean.tianyi.ShareData shareData1 = TianyiApi.get().getShareData("https://cloud.189.cn/web/share?code=2eyARfBzURZj访问码kz6y", ""); com.github.catvod.bean.tianyi.ShareData shareData1 = TianyiApi.get().getShareData("http://cloud.189.cn/t/3uIFJrzIFJV3访问码qf4b", "");
// TianyiApi.get().getVod(shareData1); // TianyiApi.get().getVod(shareData1);
ShareData shareData2 = TianyiApi.get().getShareData("https://cloud.189.cn/t/ZvEjUvq6FNr2", ""); ShareData shareData2 = TianyiApi.get().getShareData("https://cloud.189.cn/t/ZvEjUvq6FNr2", "");

View File

@ -18,7 +18,7 @@ public class ProxyVideoTest {
// "https://js.shipin520.com/pc/images/new/banner20250225.mp4", new HashMap<>()); // "https://js.shipin520.com/pc/images/new/banner20250225.mp4", new HashMap<>());
"http://172.16.1.217:18089/ng-grid/video.mp4", new HashMap<>()); "http://172.16.1.217:18089/ng-grid/video.mp4", new HashMap<>());
System.out.println(url);*/ System.out.println(url);*/
System.out.println(ProxyServer.INSTANCE.buildProxyUrl("https://media.w3.org/2010/05/sintel/trailer.mp4", Map.of("header","2","header2","2"))); System.out.println(ProxyServer.INSTANCE.buildProxyUrl("http://172.16.1.217:18089/ng-grid/video.mp4", Map.of("header","2","header2","2")));
ProxyServer.INSTANCE.start(); ProxyServer.INSTANCE.start();
while (true) { while (true) {

View File

@ -1,5 +1,5 @@
@echo off @echo off
call "%~dp0\gradlew" clean
call "%~dp0\gradlew" assembleRelease --no-daemon call "%~dp0\gradlew" assembleRelease --no-daemon

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -1 +1 @@
851711824c28c744517e650d914bf07d 5cca7cdb874fb79dee68e08a876fc8ec

View File

@ -1,5 +1,5 @@
{ {
"spider": "https://andoridspidermt.netlify.app/jar/custom_spider.jar;md5;49c24003ea2a52abb468ad7661ae1730", "spider": "http://gh.halonice.com/https://raw.githubusercontent.com/lushunming/AndroidCatVodSpider/refs/heads/multiThread/jar/custom_spider.jar;md5;5cca7cdb874fb79dee68e08a876fc8ec",
"lives": [ "lives": [
{ {
"name": "电视直播", "name": "电视直播",
@ -66,6 +66,15 @@
"changeable": 1, "changeable": 1,
"ext": "{\"site\": [\"https://www.wogg.net/\",\"https://wogg.xxooo.cf/\"]}" "ext": "{\"site\": [\"https://www.wogg.net/\",\"https://wogg.xxooo.cf/\"]}"
}, },
{
"key": "SeedHub",
"name": "SeedHub",
"type": 3,
"api": "csp_SeedHub",
"searchable": 1,
"changeable": 1,
"ext": {}
},
{ {
"key": "PanTa", "key": "PanTa",
"name": "盘他|139Pan", "name": "盘他|139Pan",
@ -94,32 +103,69 @@
"ext": {} "ext": {}
}, },
{ {
"key": "TgSearch", "key": "Qupans",
"name": "TgSearch|Pan", "name": "Qupans|Pan",
"type": 3, "type": 3,
"api": "csp_TgSearch", "api": "csp_Qupans",
"searchable": 1, "searchable": 1,
"changeable": 1, "changeable": 1,
"ext": {} "ext": {}
}, },
{ {
"key": "TgQuarkSearch", "key": "Tg123Search",
"name": "TgQuarkSearch|Pan", "name": "Tg123Search",
"type": 3, "type": 3,
"api": "csp_TgQuarkSearch", "api": "csp_Tg123Search",
"searchable": 1,
"changeable": 1,
"ext": {}
},
{
"key": "TgbaiduSearch",
"name": "TgbaiduSearch",
"type": 3,
"api": "csp_TgbaiduSearch",
"searchable": 1, "searchable": 1,
"changeable": 1, "changeable": 1,
"ext": {} "ext": {}
}, },
{ {
"key": "Tg189Search", "key": "Tg189Search",
"name": "Tg189Search|Pan", "name": "Tg189Search",
"type": 3, "type": 3,
"api": "csp_Tg189Search", "api": "csp_Tg189Search",
"searchable": 1, "searchable": 1,
"changeable": 1, "changeable": 1,
"ext": {} "ext": {}
}, },
{
"key": "TgQuarkSearch",
"name": "TgQuarkSearch",
"type": 3,
"api": "csp_TgQuarkSearch",
"searchable": 1,
"changeable": 1,
"ext": {}
},{
"key": "TgSearchQuark",
"name": "☁TgSearchQuark┃网盘",
"type": 3,
"api": "csp_TgSearchQuark",
"searchable": 1,
"filterable": 0,
"ext": {
"api_urls": [
"https://api.jkai.de/api/search",
"https://so.252035.xyz/api/search",
"https://psweb.banye.tech:7777/api/search",
"https://so.566987.xyz/api/search",
"http://152.69.222.142:8088/api/search"
],
"sources": [
"夸克"
]
}
},
{ {
"key": "TgSearchBaidu", "key": "TgSearchBaidu",
"name": "☁TgSearchBaidu┃网盘", "name": "☁TgSearchBaidu┃网盘",
@ -129,12 +175,69 @@
"filterable": 0, "filterable": 0,
"ext": { "ext": {
"api_urls": [ "api_urls": [
"https://api.jkai.de/api/search","https://so.252035.xyz/api/search",
"https://psweb.banye.tech:7777/api/search", "https://psweb.banye.tech:7777/api/search",
"https://so.566987.xyz/api/search", "https://so.566987.xyz/api/search",
"http://152.69.222.142:8088/api/search" "http://152.69.222.142:8088/api/search"
], ],
"sources": [ "sources": [
"百度" "百度"
]
}
},
{
"key": "TgSearch123",
"name": "☁TgSearch123┃网盘",
"type": 3,
"api": "csp_TgSearch123",
"searchable": 1,
"filterable": 0,
"ext": {
"api_urls": [
"https://api.jkai.de/api/search","https://so.252035.xyz/api/search",
"https://psweb.banye.tech:7777/api/search",
"https://so.566987.xyz/api/search",
"http://152.69.222.142:8088/api/search"
],
"sources": [
"123盘"
]
}
},
{
"key": "TgSearch189",
"name": "☁TgSearch189┃网盘",
"type": 3,
"api": "csp_TgSearch189",
"searchable": 1,
"filterable": 0,
"ext": {
"api_urls": [
"https://api.jkai.de/api/search","https://so.252035.xyz/api/search",
"https://psweb.banye.tech:7777/api/search",
"https://so.566987.xyz/api/search",
"http://152.69.222.142:8088/api/search"
],
"sources": [
"天翼"
]
}
},{
"key": "TgSearch139",
"name": "☁TgSearch139┃网盘",
"type": 3,
"api": "csp_TgSearch139",
"searchable": 1,
"filterable": 0,
"ext": {
"api_urls": [
"https://api.jkai.de/api/search","https://so.252035.xyz/api/search",
"https://psweb.banye.tech:7777/api/search",
"https://so.566987.xyz/api/search",
"http://152.69.222.142:8088/api/search"
],
"sources": [
"移动"
] ]
} }
}, },
@ -354,7 +457,34 @@
"api": "csp_TianYiSo", "api": "csp_TianYiSo",
"searchable": 1, "searchable": 1,
"timeout": 30 "timeout": 30
},
{
"key": "local",
"name": "Local",
"type": 3,
"api": "csp_Local",
"searchable": 0,
"changeable": 0
},
{
"key": "market",
"name": "Market",
"type": 3,
"api": "csp_Market",
"searchable": 0,
"changeable": 0,
"ext": "./market.json"
},
{
"key": "push_agent",
"name": "Push",
"type": 3,
"api": "csp_Push",
"searchable": 0,
"changeable": 0,
"timeout": 60
} }
], ],
"parses": [ "parses": [
{ {

View File

@ -1,5 +1,5 @@
{ {
"spider": "https://gh.llkk.cc/https://raw.githubusercontent.com/lushunming/AndroidCatVodSpider/multiThreadNew/jar/custom_spider.jar;md5;8c76ee60eb0363060a2d78fb8dc2f0b6", "spider": "https://gh.llkk.cc/https://raw.githubusercontent.com/lushunming/AndroidCatVodSpider/123/jar/custom_spider.jar;md5;77ff0d77d6fccecddd174ee82161f3bd",
"lives": [ "lives": [
{ {
"name": "电视直播", "name": "电视直播",
@ -41,620 +41,26 @@
"type": 3, "type": 3,
"api": "csp_Introduce" "api": "csp_Introduce"
}, },
{
"key": "Douban",
"name": " 豆瓣仅推荐",
"type": 3,
"api": "csp_Douban",
"searchable": 0,
"filterable": 1
},
{
"key": "Jianpian",
"name": "荐片视频",
"type": 3,
"api": "csp_Jianpian",
"searchable": 1,
"filterable": 1
},
{
"key": "玩偶",
"name": "玩偶哥哥",
"type": 3,
"api": "csp_Wogg",
"searchable": 1,
"changeable": 1,
"ext": "{\"site\": [\"https://www.wogg.net/\",\"https://wogg.xxooo.cf/\"]}"
},
{ {
"key": "PanTa", "key": "TgSearchBaidu",
"name": "盘他|139Pan", "name": "☁TgSearchBaidu┃网盘",
"type": 3, "type": 3,
"api": "csp_PanTa", "api": "csp_TgSearchBaidu",
"searchable": 1,
"changeable": 1,
"ext": {}
},
{
"key": "LeiJing",
"name": "雷鲸|189Pan",
"type": 3,
"api": "csp_LeiJing",
"searchable": 1,
"changeable": 1,
"ext": {}
},
{
"key": "BiXin",
"name": "彼心|139Pan",
"type": 3,
"api": "csp_BiXin",
"searchable": 1,
"changeable": 1,
"ext": {}
}, {
"key": "TgSearch",
"name": "TgSearch|Pan",
"type": 3,
"api": "csp_TgSearch",
"searchable": 1,
"changeable": 1,
"ext": {}
},
{
"key": "KuaKeBa",
"name": "夸克吧",
"type": 3,
"api": "csp_KuaKeBa",
"searchable": 1,
"changeable": 1,
"ext": {}
},
{
"key": "DianYingYunJi",
"name": "电影云集",
"type": 3,
"api": "csp_DianYingYunJi",
"searchable": 1,
"changeable": 1,
"ext": {}
},
{
"key": "KuaKeS",
"name": "夸克网盘社",
"type": 3,
"api": "csp_KuaKeS",
"searchable": 1,
"changeable": 1,
"ext": {}
},
{
"key": "XuanFeng",
"name": "旋风影视",
"type": 3,
"api": "csp_XuanFeng",
"searchable": 1,
"changeable": 1,
"ext": {}
},
{
"key": "NCat",
"name": "网飞猫影视",
"type": 3,
"api": "csp_NCat",
"searchable": 1,
"filterable": 1
},
{
"key": "ChangZhang",
"name": "厂长影视",
"type": 3,
"api": "csp_ChangZhang",
"searchable": "1",
"filterable": "0",
"changeable": 0,
"ext": "https://www.czzy.site/"
},
{
"key": "Zxzj",
"name": "在线之家",
"type": 3,
"api": "csp_Zxzj",
"searchable": "1",
"filterable": "0",
"changeable": 0,
"ext": {}
},
{
"key": "TvDy",
"name": "电影天堂影视",
"type": 3,
"api": "csp_TvDy",
"searchable": 1,
"filterable": 1
},
{
"key": "W55Movie",
"name": "555电影",
"type": 3,
"api": "csp_W55Movie",
"searchable": 0,
"filterable": 1,
"ext": "https://w55xy.com/"
},
{
"key": "DaGongRen",
"name": "打工人电影",
"type": 3,
"api": "csp_DaGongRen",
"searchable": 1,
"filterable": 1
},
{
"key": "HkTv",
"name": "TVB云播影视",
"type": 3,
"api": "csp_HkTv",
"searchable": 0,
"filterable": 1,
"ext": "http://www.hktvyb.vip/"
},
{
"key": "NGkt",
"name": "瓜瓜",
"type": 3,
"api": "csp_NG",
"searchable": 1, "searchable": 1,
"filterable": 0, "filterable": 0,
"ext": {}
},
{
"key": "JustLive",
"name": "JustLive直播",
"type": 3,
"api": "csp_JustLive",
"searchable": 1,
"filterable": 1
},
{
"key": "Xb6v",
"name": "新版6V视频",
"type": 3,
"api": "csp_Xb6v",
"searchable": 1,
"filterable": 1
},
{
"key": "ikanbot",
"name": "爱看机器人",
"type": 3,
"api": "csp_Ikanbot",
"searchable": 1,
"filterable": 0,
"ext": "{\"box\": \"TVBox\", \"danmu\": false}"
},
{
"key": "Libvio",
"name": "立播影视",
"type": 3,
"api": "csp_Libvio",
"searchable": 1,
"filterable": 0,
"ext": "{ \"site\": \"https://www.libvio.app\" }"
},
{
"key": "Ddrk",
"name": "低端影视",
"type": 3,
"api": "csp_Ddrk",
"searchable": 1,
"filterable": 0,
"ext": " {\"site\":\"https://ddys.info/\"}"
},
{
"key": "Ysj",
"name": "异世界动漫(不稳定)",
"type": 3,
"api": "csp_Ysj",
"searchable": 1,
"filterable": 1
},
{
"key": "QxiTv",
"name": "七喜影视",
"type": 3,
"api": "csp_QxiTv",
"searchable": 1,
"changeable": 0,
"ext": {}
},
{
"key": "glod",
"name": "金牌 | 影视",
"type": 3,
"api": "csp_Glod",
"searchable": 1,
"changeable": 0,
"ext": {}
},
{
"key": "YunPanBa",
"name": "云盘吧",
"type": 3,
"api": "csp_YunPanBa",
"searchable": 1,
"timeout": 30
},
{
"key": "QiLeSo",
"name": "奇乐搜┃搜索",
"type": 3,
"api": "csp_QiLeSo",
"searchable": 1,
"timeout": 30
},
{
"key": "PanSearch",
"name": "盘搜┃搜索",
"type": 3,
"api": "csp_PanSearch",
"searchable": 1,
"timeout": 30
},
{
"key": "TianYiSo",
"name": "天翼┃搜索",
"type": 3,
"api": "csp_TianYiSo",
"searchable": 1,
"timeout": 30
},
{
"key": "newvision",
"name": "(js)新视觉影院(不稳定)",
"api": "https://androidcatvodspider.netlify.app/json/js/newvision.js",
"timeout": 30,
"ext": { "ext": {
"box": "TVBox" "api_urls": [
}, "https://psweb.banye.tech:7777/api/search",
"playerType": 0, "https://so.566987.xyz/api/search",
"type": 3 "http://152.69.222.142:8088/api/search"
}, ],
{ "sources": [
"key": "kankan70", "123盘"
"name": "(js)70看看┃📺", ]
"api": "https://androidcatvodspider.netlify.app/json/js/kankan70.js", }
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "jpyy",
"name": "(js)金牌影院",
"api": "https://androidcatvodspider.netlify.app/json/js/jpyy.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "jpyy2",
"name": "(js)金牌影院",
"api": "https://androidcatvodspider.netlify.app/json/js/jpyy2.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "tiantian",
"name": "(js)天天影视┃⛄",
"api": "https://androidcatvodspider.netlify.app/json/js/tiantian.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "xb6v",
"name": "(js)磁力新6V┃🧲",
"api": "https://androidcatvodspider.netlify.app/json/js/xb6v.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "mp4movie",
"name": "(js)Mp4电影┃🍚",
"api": "https://androidcatvodspider.netlify.app/json/js/mp4movie.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "jianpian",
"name": "(js)荐片┃🌼",
"api": "https://androidcatvodspider.netlify.app/json/js/jianpian.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "alipansou",
"name": "(js)阿里猫狸┃😸",
"api": "https://androidcatvodspider.netlify.app/json/js/alipansou.js",
"timeout": 30,
"ext": {
"box": "TVBox",
"aliToken": "26fc6787afff43e78b78992e782502f1",
"quarkCookie": "_UP_A4A_11_=wb965111521e45ffa80410c24a071a54; _UP_D_=pc; tfstk=fXFith4nnRk114LAjWc1TT-OQUXL5hGjqodxDjnVLDoBBchYujR4Drht3GaYxmqYlcPtWc34mknIMcFTB-Y_tuAv6G6_uIcxggIRw_U15jGV2EjCXmnslyoqlSMN9PGjgMEW0dR85uVOAjYmgwcEoqOqgIrqLyoIlq-ZuC738DgqgCJZgH8EuqxZNmAqqSPQTaC3h7bb2rFnSvW87D8jTW0iX0zasIR2zVDi4Poh2svabvzjnSTXixaaFogzbhS-Cry3xVcc9dlz--roR55Jj2wT8znUrEdYrfV3t-kh71znscDo-vYWpf24fSD_IE_78frQF0MNdMg367HmVvxFbyUnbY20XMOqX84UxYFpvQhbA-rqok-G4A9eUc4wG27YtK9jQ2gnVNJioG_mbu_h-wv5CAuIWgQh-K9jQ2gn2wbHFhMZRVIR.; __pus=c81f57897dafcb65d4ecb501bc299199AARcqF72zsatdbsCbiT3qVqsk36caaycoPQW7hz8rbEf+UY7f5aGgH1e90lsONAUwCAW8y27u5A/KXyYqkHCWgjS; __kp=99fa2760-1669-11ef-90cf-8f7a59c3b86e; __kps=AATSt4xuf6r6bqes3LdJvxvy; __ktd=c2e+aLICIvFoeklXXz36VA==; __uid=AATSt4xuf6r6bqes3LdJvxvy; Video-Auth=smob3MOUslklDq2MutANJYZCVo50sLv0GFelx3+cu1nK2fkdL2kvkdpT5yNOhNz0NLTyi5ThWRL47+ztJA4kXQ==; __puus=72f667c533c9a22496f88d2f1bb7ae71AAQ7mrvFw7s9AUPUXvnuGPkcDU3RRTVPdYaYQfsM9Cje2doYXgRZXbImg02EaUaEG+G9ikpo3xubGGdElArOuYvUtJzIXb6yHDnSZbtEUxkwvjfQRNEnDnVwLQ6LL2ORjRaxa9OUfwk/WppWvy6OcDqQtHYkaqB+Poxn5kFs7ZVdAtX7ZQks1czD+g9gAZjsbeBHxHQ1AP5MGc1s3M4RhwZQ"
},
"playerType": 0,
"type": 3
},
{
"key": "huya",
"name": "(js)虎牙直播┃🐯",
"api": "https://androidcatvodspider.netlify.app/json/js/huya.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "star",
"name": "(js)星视界┃墙☄️",
"api": "https://androidcatvodspider.netlify.app/json/js/star.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "nivod",
"name": "(js)泥视频┃墙👑",
"api": "https://androidcatvodspider.netlify.app/json/js/nivod.js",
"timeout": 30,
"ext": {
"box": "TVBox",
"code": 0
},
"playerType": 0,
"type": 3
},
{
"key": "aiyingshi",
"name": "(js)爱影视┃🚀",
"api": "https://androidcatvodspider.netlify.app/json/js/aiyingshi.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "sp360",
"name": "(js)360影视┃🥎",
"api": "https://androidcatvodspider.netlify.app/json/js/sp360.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "mxanime",
"name": "(js)MX动漫┃🍒",
"api": "https://androidcatvodspider.netlify.app/json/js/mxanime.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "cntv",
"name": "(js)中央影视┃🤵‍♂️",
"api": "https://androidcatvodspider.netlify.app/json/js/cntv.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "douban",
"name": "(js)豆瓣┃🍥",
"api": "https://androidcatvodspider.netlify.app/json/js/douban.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "pan_search",
"name": "(js)阿里盘搜┃🗂️",
"api": "https://androidcatvodspider.netlify.app/json/js/pan_search.js",
"timeout": 30,
"ext": {
"box": "TVBox",
"aliToken": "26fc6787afff43e78b78992e782502f1",
"quarkCookie": "_UP_A4A_11_=wb965111521e45ffa80410c24a071a54; _UP_D_=pc; tfstk=fXFith4nnRk114LAjWc1TT-OQUXL5hGjqodxDjnVLDoBBchYujR4Drht3GaYxmqYlcPtWc34mknIMcFTB-Y_tuAv6G6_uIcxggIRw_U15jGV2EjCXmnslyoqlSMN9PGjgMEW0dR85uVOAjYmgwcEoqOqgIrqLyoIlq-ZuC738DgqgCJZgH8EuqxZNmAqqSPQTaC3h7bb2rFnSvW87D8jTW0iX0zasIR2zVDi4Poh2svabvzjnSTXixaaFogzbhS-Cry3xVcc9dlz--roR55Jj2wT8znUrEdYrfV3t-kh71znscDo-vYWpf24fSD_IE_78frQF0MNdMg367HmVvxFbyUnbY20XMOqX84UxYFpvQhbA-rqok-G4A9eUc4wG27YtK9jQ2gnVNJioG_mbu_h-wv5CAuIWgQh-K9jQ2gn2wbHFhMZRVIR.; __pus=c81f57897dafcb65d4ecb501bc299199AARcqF72zsatdbsCbiT3qVqsk36caaycoPQW7hz8rbEf+UY7f5aGgH1e90lsONAUwCAW8y27u5A/KXyYqkHCWgjS; __kp=99fa2760-1669-11ef-90cf-8f7a59c3b86e; __kps=AATSt4xuf6r6bqes3LdJvxvy; __ktd=c2e+aLICIvFoeklXXz36VA==; __uid=AATSt4xuf6r6bqes3LdJvxvy; Video-Auth=smob3MOUslklDq2MutANJYZCVo50sLv0GFelx3+cu1nK2fkdL2kvkdpT5yNOhNz0NLTyi5ThWRL47+ztJA4kXQ==; __puus=72f667c533c9a22496f88d2f1bb7ae71AAQ7mrvFw7s9AUPUXvnuGPkcDU3RRTVPdYaYQfsM9Cje2doYXgRZXbImg02EaUaEG+G9ikpo3xubGGdElArOuYvUtJzIXb6yHDnSZbtEUxkwvjfQRNEnDnVwLQ6LL2ORjRaxa9OUfwk/WppWvy6OcDqQtHYkaqB+Poxn5kFs7ZVdAtX7ZQks1czD+g9gAZjsbeBHxHQ1AP5MGc1s3M4RhwZQ"
},
"playerType": 0,
"type": 3
},
{
"key": "bilibili",
"name": "(js)哔哩哔哩┃🏰",
"api": "https://androidcatvodspider.netlify.app/json/js/bilibili.js",
"timeout": 30,
"ext": {
"box": "TVBox",
"cookie": "buvid3=02675249-8ED3-C418-87F5-59E18316459714816infoc; b_nut=1704421014; _uuid=5D435F74-F574-D9AB-62C1-B9294DE465D913102infoc; buvid_fp=e8c5650c749398e9b5cad3f3ddb5081e; buvid4=007E85D1-52C1-7E6E-07CF-837FFBC9349516677-024010502-J5vTDSZDCw4fNnXRejbSVg%3D%3D; rpdid=|()kYJmulRu0J'u~|RRJl)JR; PVID=1; SESSDATA=3be091d3%2C1720332009%2C699ed%2A11CjAcCdwXG5kY1umhCOpQHOn_WP7L9xFBfWO7KKd4BPweodpR6VyIfeNyPiRmkr5jCqsSVjg0R0dZOVVHRUo3RnhPRTZFc3JPbGdiUjFCdHpiRDhiTkticmdKTjVyS1VhbDdvNjFMSDJlbUJydUlRdjFUNGFBNkJlV2ZTa0N1Q1BEVi1QYTQzTUh3IIEC; bili_jct=b0ee7b5d3f27df893545d811d95506d4; DedeUserID=78014638; DedeUserID__ckMd5=4c8c5d65065e468a; enable_web_push=DISABLE; header_theme_version=CLOSE; home_feed_column=5; CURRENT_BLACKGAP=0; CURRENT_FNVAL=4048; b_lsid=75E916AA_18EA1A8D995; bsource=search_baidu; FEED_LIVE_VERSION=V_HEADER_LIVE_NO_POP; browser_resolution=1507-691; bili_ticket=eyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTIzNjk5MTMsImlhdCI6MTcxMjExMDY1MywicGx0IjotMX0.8zQW_fNTCSBlK_JkHnzu3gDw62wuTK1qgKcbGec3swM; bili_ticket_expires=171236985"
},
"playerType": 0,
"type": 3
},
{
"key": "changzhang",
"name": "(js)厂长直连┃🏭️",
"api": "https://androidcatvodspider.netlify.app/json/js/changzhang.js",
"timeout": 30,
"ext": {
"box": "TVBox",
"aliToken": "26fc6787afff43e78b78992e782502f1",
"quarkCookie": "_UP_A4A_11_=wb965111521e45ffa80410c24a071a54; _UP_D_=pc; tfstk=fXFith4nnRk114LAjWc1TT-OQUXL5hGjqodxDjnVLDoBBchYujR4Drht3GaYxmqYlcPtWc34mknIMcFTB-Y_tuAv6G6_uIcxggIRw_U15jGV2EjCXmnslyoqlSMN9PGjgMEW0dR85uVOAjYmgwcEoqOqgIrqLyoIlq-ZuC738DgqgCJZgH8EuqxZNmAqqSPQTaC3h7bb2rFnSvW87D8jTW0iX0zasIR2zVDi4Poh2svabvzjnSTXixaaFogzbhS-Cry3xVcc9dlz--roR55Jj2wT8znUrEdYrfV3t-kh71znscDo-vYWpf24fSD_IE_78frQF0MNdMg367HmVvxFbyUnbY20XMOqX84UxYFpvQhbA-rqok-G4A9eUc4wG27YtK9jQ2gnVNJioG_mbu_h-wv5CAuIWgQh-K9jQ2gn2wbHFhMZRVIR.; __pus=c81f57897dafcb65d4ecb501bc299199AARcqF72zsatdbsCbiT3qVqsk36caaycoPQW7hz8rbEf+UY7f5aGgH1e90lsONAUwCAW8y27u5A/KXyYqkHCWgjS; __kp=99fa2760-1669-11ef-90cf-8f7a59c3b86e; __kps=AATSt4xuf6r6bqes3LdJvxvy; __ktd=c2e+aLICIvFoeklXXz36VA==; __uid=AATSt4xuf6r6bqes3LdJvxvy; Video-Auth=smob3MOUslklDq2MutANJYZCVo50sLv0GFelx3+cu1nK2fkdL2kvkdpT5yNOhNz0NLTyi5ThWRL47+ztJA4kXQ==; __puus=72f667c533c9a22496f88d2f1bb7ae71AAQ7mrvFw7s9AUPUXvnuGPkcDU3RRTVPdYaYQfsM9Cje2doYXgRZXbImg02EaUaEG+G9ikpo3xubGGdElArOuYvUtJzIXb6yHDnSZbtEUxkwvjfQRNEnDnVwLQ6LL2ORjRaxa9OUfwk/WppWvy6OcDqQtHYkaqB+Poxn5kFs7ZVdAtX7ZQks1czD+g9gAZjsbeBHxHQ1AP5MGc1s3M4RhwZQ"
},
"playerType": 0,
"type": 3
},
{
"key": "wogg",
"name": "(js)阿里玩偶┃💂",
"api": "https://androidcatvodspider.netlify.app/json/js/wogg.js",
"timeout": 30,
"ext": {
"box": "TVBox",
"aliToken": "26fc6787afff43e78b78992e782502f1",
"quarkCookie": "_UP_A4A_11_=wb965111521e45ffa80410c24a071a54; _UP_D_=pc; tfstk=fXFith4nnRk114LAjWc1TT-OQUXL5hGjqodxDjnVLDoBBchYujR4Drht3GaYxmqYlcPtWc34mknIMcFTB-Y_tuAv6G6_uIcxggIRw_U15jGV2EjCXmnslyoqlSMN9PGjgMEW0dR85uVOAjYmgwcEoqOqgIrqLyoIlq-ZuC738DgqgCJZgH8EuqxZNmAqqSPQTaC3h7bb2rFnSvW87D8jTW0iX0zasIR2zVDi4Poh2svabvzjnSTXixaaFogzbhS-Cry3xVcc9dlz--roR55Jj2wT8znUrEdYrfV3t-kh71znscDo-vYWpf24fSD_IE_78frQF0MNdMg367HmVvxFbyUnbY20XMOqX84UxYFpvQhbA-rqok-G4A9eUc4wG27YtK9jQ2gnVNJioG_mbu_h-wv5CAuIWgQh-K9jQ2gn2wbHFhMZRVIR.; __pus=c81f57897dafcb65d4ecb501bc299199AARcqF72zsatdbsCbiT3qVqsk36caaycoPQW7hz8rbEf+UY7f5aGgH1e90lsONAUwCAW8y27u5A/KXyYqkHCWgjS; __kp=99fa2760-1669-11ef-90cf-8f7a59c3b86e; __kps=AATSt4xuf6r6bqes3LdJvxvy; __ktd=c2e+aLICIvFoeklXXz36VA==; __uid=AATSt4xuf6r6bqes3LdJvxvy; Video-Auth=smob3MOUslklDq2MutANJYZCVo50sLv0GFelx3+cu1nK2fkdL2kvkdpT5yNOhNz0NLTyi5ThWRL47+ztJA4kXQ==; __puus=72f667c533c9a22496f88d2f1bb7ae71AAQ7mrvFw7s9AUPUXvnuGPkcDU3RRTVPdYaYQfsM9Cje2doYXgRZXbImg02EaUaEG+G9ikpo3xubGGdElArOuYvUtJzIXb6yHDnSZbtEUxkwvjfQRNEnDnVwLQ6LL2ORjRaxa9OUfwk/WppWvy6OcDqQtHYkaqB+Poxn5kFs7ZVdAtX7ZQks1czD+g9gAZjsbeBHxHQ1AP5MGc1s3M4RhwZQ"
},
"playerType": 0,
"type": 3
},
{
"key": "nangua",
"name": "(js)南瓜影视┃🎃",
"api": "https://androidcatvodspider.netlify.app/json/js/nangua.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "aliyunpanshare",
"name": "(js)阿里云盘分享┃🥏‍",
"api": "https://androidcatvodspider.netlify.app/json/js/aliyunpanshare.js",
"timeout": 30,
"ext": {
"box": "TVBox",
"aliToken": "26fc6787afff43e78b78992e782502f1",
"quarkCookie": "_UP_A4A_11_=wb965111521e45ffa80410c24a071a54; _UP_D_=pc; tfstk=fXFith4nnRk114LAjWc1TT-OQUXL5hGjqodxDjnVLDoBBchYujR4Drht3GaYxmqYlcPtWc34mknIMcFTB-Y_tuAv6G6_uIcxggIRw_U15jGV2EjCXmnslyoqlSMN9PGjgMEW0dR85uVOAjYmgwcEoqOqgIrqLyoIlq-ZuC738DgqgCJZgH8EuqxZNmAqqSPQTaC3h7bb2rFnSvW87D8jTW0iX0zasIR2zVDi4Poh2svabvzjnSTXixaaFogzbhS-Cry3xVcc9dlz--roR55Jj2wT8znUrEdYrfV3t-kh71znscDo-vYWpf24fSD_IE_78frQF0MNdMg367HmVvxFbyUnbY20XMOqX84UxYFpvQhbA-rqok-G4A9eUc4wG27YtK9jQ2gnVNJioG_mbu_h-wv5CAuIWgQh-K9jQ2gn2wbHFhMZRVIR.; __pus=c81f57897dafcb65d4ecb501bc299199AARcqF72zsatdbsCbiT3qVqsk36caaycoPQW7hz8rbEf+UY7f5aGgH1e90lsONAUwCAW8y27u5A/KXyYqkHCWgjS; __kp=99fa2760-1669-11ef-90cf-8f7a59c3b86e; __kps=AATSt4xuf6r6bqes3LdJvxvy; __ktd=c2e+aLICIvFoeklXXz36VA==; __uid=AATSt4xuf6r6bqes3LdJvxvy; Video-Auth=smob3MOUslklDq2MutANJYZCVo50sLv0GFelx3+cu1nK2fkdL2kvkdpT5yNOhNz0NLTyi5ThWRL47+ztJA4kXQ==; __puus=72f667c533c9a22496f88d2f1bb7ae71AAQ7mrvFw7s9AUPUXvnuGPkcDU3RRTVPdYaYQfsM9Cje2doYXgRZXbImg02EaUaEG+G9ikpo3xubGGdElArOuYvUtJzIXb6yHDnSZbtEUxkwvjfQRNEnDnVwLQ6LL2ORjRaxa9OUfwk/WppWvy6OcDqQtHYkaqB+Poxn5kFs7ZVdAtX7ZQks1czD+g9gAZjsbeBHxHQ1AP5MGc1s3M4RhwZQ"
},
"playerType": 0,
"type": 3
},
{
"key": "dubo",
"name": "(js)独播影视┃🛶",
"api": "https://androidcatvodspider.netlify.app/json/js/dubo.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "haiwaikan",
"name": "(js)海外看┃☕墙",
"api": "https://androidcatvodspider.netlify.app/json/js/haiwaikan.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "dygangs",
"name": "(js)电影港┃🏖️",
"api": "https://androidcatvodspider.netlify.app/json/js/dygangs.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "cilixiong",
"name": "(js)磁力熊┃🐻",
"api": "https://androidcatvodspider.netlify.app/json/js/cilixiong.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "lovemovie",
"name": "(js)爱情电影网┃💕",
"api": "https://androidcatvodspider.netlify.app/json/js/lovemovie.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "gitcafe",
"name": "(js)阿里纸条┃🦊",
"api": "https://androidcatvodspider.netlify.app/json/js/gitcafe.js",
"timeout": 30,
"ext": {
"box": "TVBox",
"aliToken": "26fc6787afff43e78b78992e782502f1",
"quarkCookie": "_UP_A4A_11_=wb965111521e45ffa80410c24a071a54; _UP_D_=pc; tfstk=fXFith4nnRk114LAjWc1TT-OQUXL5hGjqodxDjnVLDoBBchYujR4Drht3GaYxmqYlcPtWc34mknIMcFTB-Y_tuAv6G6_uIcxggIRw_U15jGV2EjCXmnslyoqlSMN9PGjgMEW0dR85uVOAjYmgwcEoqOqgIrqLyoIlq-ZuC738DgqgCJZgH8EuqxZNmAqqSPQTaC3h7bb2rFnSvW87D8jTW0iX0zasIR2zVDi4Poh2svabvzjnSTXixaaFogzbhS-Cry3xVcc9dlz--roR55Jj2wT8znUrEdYrfV3t-kh71znscDo-vYWpf24fSD_IE_78frQF0MNdMg367HmVvxFbyUnbY20XMOqX84UxYFpvQhbA-rqok-G4A9eUc4wG27YtK9jQ2gnVNJioG_mbu_h-wv5CAuIWgQh-K9jQ2gn2wbHFhMZRVIR.; __pus=c81f57897dafcb65d4ecb501bc299199AARcqF72zsatdbsCbiT3qVqsk36caaycoPQW7hz8rbEf+UY7f5aGgH1e90lsONAUwCAW8y27u5A/KXyYqkHCWgjS; __kp=99fa2760-1669-11ef-90cf-8f7a59c3b86e; __kps=AATSt4xuf6r6bqes3LdJvxvy; __ktd=c2e+aLICIvFoeklXXz36VA==; __uid=AATSt4xuf6r6bqes3LdJvxvy; Video-Auth=smob3MOUslklDq2MutANJYZCVo50sLv0GFelx3+cu1nK2fkdL2kvkdpT5yNOhNz0NLTyi5ThWRL47+ztJA4kXQ==; __puus=72f667c533c9a22496f88d2f1bb7ae71AAQ7mrvFw7s9AUPUXvnuGPkcDU3RRTVPdYaYQfsM9Cje2doYXgRZXbImg02EaUaEG+G9ikpo3xubGGdElArOuYvUtJzIXb6yHDnSZbtEUxkwvjfQRNEnDnVwLQ6LL2ORjRaxa9OUfwk/WppWvy6OcDqQtHYkaqB+Poxn5kFs7ZVdAtX7ZQks1czD+g9gAZjsbeBHxHQ1AP5MGc1s3M4RhwZQ"
},
"playerType": 0,
"type": 3
},
{
"key": "kuaikan",
"name": "(js)快看视频┃🛥︎",
"api": "https://androidcatvodspider.netlify.app/json/js/kuaikan.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
} }
], ],
"parses": [ "parses": [
{ {