Compare commits
No commits in common. "multiThread" and "mine" have entirely different histories.
multiThrea
...
mine
|
|
@ -1,80 +1,27 @@
|
||||||
name: Spider Jar Gen CI
|
name: Spider Jar Gen CI
|
||||||
|
|
||||||
on:
|
on: workflow_dispatch
|
||||||
push:
|
|
||||||
branches: [ "multiThread" ]
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: windows-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v2
|
||||||
- name: Set up JDK 21
|
- name: set up JDK 21
|
||||||
uses: actions/setup-java@v5
|
uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
distribution: 'jetbrains'
|
distribution: 'adopt'
|
||||||
cache: gradle
|
cache: gradle
|
||||||
|
|
||||||
- name: Grant execute permission to gradlew
|
|
||||||
run: chmod +x ./gradlew
|
|
||||||
|
|
||||||
- name: Build with Gradle
|
|
||||||
run: ./gradlew app:buildCustomSpiderJar
|
|
||||||
|
|
||||||
|
|
||||||
- name: Add & Commit
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- name: Build with Gradle
|
||||||
|
run: ./build.bat ec
|
||||||
|
|
||||||
|
- name: Update spider jar
|
||||||
|
uses: EndBug/add-and-commit@v7
|
||||||
|
with:
|
||||||
|
default_author: github_actions
|
||||||
|
message: 'update spider jar'
|
||||||
|
add: "['./jar/custom_spider.jar', './jar/custom_spider.jar.md5']"
|
||||||
|
|
|
||||||
139
app/build.gradle
139
app/build.gradle
|
|
@ -2,7 +2,6 @@ plugins {
|
||||||
id 'com.android.application'
|
id 'com.android.application'
|
||||||
id 'ru.cleverpumpkin.proguard-dictionaries-generator'
|
id 'ru.cleverpumpkin.proguard-dictionaries-generator'
|
||||||
id 'org.jetbrains.kotlin.android'
|
id 'org.jetbrains.kotlin.android'
|
||||||
|
|
||||||
}
|
}
|
||||||
java {
|
java {
|
||||||
toolchain {
|
toolchain {
|
||||||
|
|
@ -48,12 +47,6 @@ android {
|
||||||
jvmTarget = "11"
|
jvmTarget = "11"
|
||||||
|
|
||||||
}
|
}
|
||||||
packagingOptions {
|
|
||||||
|
|
||||||
exclude 'META-INF/*'
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
configurations.configureEach {
|
configurations.configureEach {
|
||||||
resolutionStrategy {
|
resolutionStrategy {
|
||||||
|
|
@ -81,143 +74,13 @@ dependencies {
|
||||||
// Optional -- Mockito framework(可选,用于模拟一些依赖对象,以达到隔离依赖的效果)
|
// Optional -- Mockito framework(可选,用于模拟一些依赖对象,以达到隔离依赖的效果)
|
||||||
testImplementation 'org.mockito:mockito-core:5.12.0'
|
testImplementation 'org.mockito:mockito-core:5.12.0'
|
||||||
testImplementation "org.robolectric:robolectric:4.13"
|
testImplementation "org.robolectric:robolectric:4.13"
|
||||||
testImplementation 'cn.hutool:hutool-all:5.8.26'
|
testImplementation 'cn.hutool:hutool-all:5.8.26'
|
||||||
|
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1"
|
||||||
// https://mvnrepository.com/artifact/com.sun.net.httpserver/http
|
|
||||||
/* implementation(files("libs/sun-common-server.jar"))
|
|
||||||
implementation("com.sun.net.httpserver:http:20070405")*/
|
|
||||||
// implementation("com.hibegin:simplewebserver:0.1.15")
|
|
||||||
//implementation("com.github.codeborne.klite:klite-server:1.7.0")
|
|
||||||
|
|
||||||
|
|
||||||
//implementation 'wang.harlon.quickjs:wrapper-java:1.0.0'
|
//implementation 'wang.harlon.quickjs:wrapper-java:1.0.0'
|
||||||
// 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'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Binary file not shown.
|
|
@ -44,12 +44,3 @@
|
||||||
# Please add these rules to your existing keep rules in order to suppress warnings.
|
# Please add these rules to your existing keep rules in order to suppress warnings.
|
||||||
# This is generated automatically by the Android Gradle plugin.
|
# This is generated automatically by the Android Gradle plugin.
|
||||||
-dontwarn org.bouncycastle.jce.provider.BouncyCastleProvider
|
-dontwarn org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-keepattributes SourceFile,LineNumberTable
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 禁用代码混淆
|
|
||||||
#-dontobfuscate
|
|
||||||
|
|
@ -507,7 +507,7 @@ public class AliYun {
|
||||||
Map<String, String> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
Map<String, String> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||||
List<String> keys = Arrays.asList("referer", "icy-metadata", "range", "connection", "accept-encoding", "user-agent");
|
List<String> keys = Arrays.asList("referer", "icy-metadata", "range", "connection", "accept-encoding", "user-agent");
|
||||||
for (String key : params.keySet()) if (keys.contains(key)) headers.put(key, params.get(key));
|
for (String key : params.keySet()) if (keys.contains(key)) headers.put(key, params.get(key));
|
||||||
return ProxyVideo.proxyMultiThread(downloadUrl, headers);
|
return ProxyVideo.proxy(downloadUrl, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getM3u8Url(String shareId, String fileId, String templateId) {
|
private String getM3u8Url(String shareId, String fileId, String templateId) {
|
||||||
|
|
|
||||||
|
|
@ -1,262 +0,0 @@
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,797 +0,0 @@
|
||||||
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.net.OkHttp
|
|
||||||
import com.github.catvod.utils.Json
|
|
||||||
import com.github.catvod.utils.ProxyServer.buildProxyUrl
|
|
||||||
import com.github.catvod.utils.Util
|
|
||||||
import com.github.catvod.utils.Util.MEDIA
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import java.net.URLEncoder
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
object BaiduDrive {
|
|
||||||
private val cache = mutableMapOf<String, String>();
|
|
||||||
|
|
||||||
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/"
|
|
||||||
)
|
|
||||||
|
|
||||||
//是否删除过文件标志
|
|
||||||
private var deleteTag = 0;
|
|
||||||
private val saveDirName = "TVBOX_BD"
|
|
||||||
|
|
||||||
private var cookies = BaiDuYunHandler.get().token
|
|
||||||
|
|
||||||
|
|
||||||
private val apiHost = "https://pan.baidu.com"
|
|
||||||
private val displayName = listOf("BD原画")
|
|
||||||
|
|
||||||
|
|
||||||
fun setCookie(extend: String) {
|
|
||||||
if (extend.isEmpty()) return
|
|
||||||
cookies = extend
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
|
|
||||||
val results = urls.map { url ->
|
|
||||||
processSingleLink(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
val names = mutableListOf<String>()
|
|
||||||
val allVideos = mutableListOf<String>()
|
|
||||||
|
|
||||||
results.forEach { result ->
|
|
||||||
if (result != null) {
|
|
||||||
val (avideos, videos) = result
|
|
||||||
names.addAll(displayName)
|
|
||||||
allVideos.add(avideos.joinToString("#"))
|
|
||||||
//allVideos.add(videos.joinToString("#"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return names to allVideos
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun processSingleLink(url: String): Pair<List<String>, List<String>>? {
|
|
||||||
return try {
|
|
||||||
val urlInfo = parseShareUrl(url)
|
|
||||||
if (urlInfo.containsKey("error")) return null
|
|
||||||
|
|
||||||
val tokenInfo = getShareToken(urlInfo)
|
|
||||||
if (tokenInfo?.containsKey("error") == true) return null
|
|
||||||
|
|
||||||
getAllVideos(tokenInfo!!)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseShareUrl(url: String): Map<String, String> {
|
|
||||||
var lurl = url
|
|
||||||
if ("提取码" in url) lurl = url.replace("提取码:", "?pwd=")
|
|
||||||
|
|
||||||
if ("/share/" !in url) {
|
|
||||||
val response = OkHttp.getLocation(url, headers)
|
|
||||||
lurl = response ?: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
val queryParams = parseQueryParams(lurl)
|
|
||||||
val finalUrl = if ("/share/" in url) url.replace("share/init?surl=", "s/1") else url
|
|
||||||
|
|
||||||
return mapOf<String, String>(
|
|
||||||
"url" to finalUrl,
|
|
||||||
"surl" to (queryParams["surl"]?.firstOrNull() ?: ""),
|
|
||||||
"pwd" to (queryParams["pwd"]?.firstOrNull() ?: "")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getShareToken(urlInfo: Map<String, String>): Map<String, String>? {
|
|
||||||
val params = mapOf(
|
|
||||||
"t" to System.currentTimeMillis().toString(), "surl" to (urlInfo["surl"] ?: "")
|
|
||||||
)
|
|
||||||
|
|
||||||
val data = mapOf("pwd" to (urlInfo["pwd"] ?: ""))
|
|
||||||
|
|
||||||
val response = OkHttp.post(
|
|
||||||
"$apiHost/share/verify?t=${params["t"]}&surl=${params["surl"]}", data, headers
|
|
||||||
)
|
|
||||||
|
|
||||||
// if ("error" in response) return response
|
|
||||||
val json = Json.safeObject(response.body)
|
|
||||||
|
|
||||||
|
|
||||||
val randsk = json.asJsonObject.get("randsk").asString ?: return mapOf("error" to "获取randsk失败")
|
|
||||||
|
|
||||||
return mapOf(
|
|
||||||
"yurl" to (urlInfo["url"]?.split("s/")?.last()?.split("?")?.first() ?: ""),
|
|
||||||
"randsk" to randsk,
|
|
||||||
"surl" to (urlInfo["surl"] ?: "")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getAllVideos(tokenInfo: Map<String, String>): Pair<List<String>, List<String>> {
|
|
||||||
val videos = mutableListOf<String>()
|
|
||||||
val avideos = mutableListOf<String>()
|
|
||||||
val seenFolders = mutableSetOf<String>()
|
|
||||||
val pendingFolders = mutableListOf<Map<String, Any>>()
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 处理根目录
|
|
||||||
var currentPage = 1
|
|
||||||
var uk = ""
|
|
||||||
var shareid = ""
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
val rootFolder = mutableMapOf(
|
|
||||||
"surl" to tokenInfo["surl"]!!,
|
|
||||||
"randsk" to tokenInfo["randsk"]!!,
|
|
||||||
"page" to currentPage,
|
|
||||||
"is_root" to true
|
|
||||||
)
|
|
||||||
|
|
||||||
val rootResult = getFolderContents(rootFolder)
|
|
||||||
// if ("error" in rootResult) break
|
|
||||||
val data = rootResult?.asJsonObject
|
|
||||||
|
|
||||||
val items = data?.get("list")?.asJsonArray ?: break
|
|
||||||
|
|
||||||
if (items.isEmpty) break
|
|
||||||
|
|
||||||
// 第一页获取uk和shareid
|
|
||||||
if (currentPage == 1) {
|
|
||||||
uk = data["uk"]?.toString() ?: ""
|
|
||||||
shareid = data["share_id"]?.toString() ?: ""
|
|
||||||
if (uk.isEmpty() || shareid.isEmpty()) return emptyList<String>() to emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理items
|
|
||||||
items.forEach { item ->
|
|
||||||
if (item.asJsonObject["isdir"].asInt == 1) {
|
|
||||||
val folderPath =
|
|
||||||
"/sharelink$uk-${item.asJsonObject["fs_id"].asString}/${item.asJsonObject["server_filename"].asString}"
|
|
||||||
if (folderPath !in seenFolders) {
|
|
||||||
seenFolders.add(folderPath)
|
|
||||||
pendingFolders.add(
|
|
||||||
mapOf(
|
|
||||||
"surl" to tokenInfo["surl"]!!,
|
|
||||||
"randsk" to tokenInfo["randsk"]!!,
|
|
||||||
"uk" to uk,
|
|
||||||
"shareid" to shareid,
|
|
||||||
"dir" to folderPath,
|
|
||||||
"page" to 1
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else if (isVideoFile(item.asJsonObject["server_filename"].asString ?: "")) {
|
|
||||||
addVideo(item.asJsonObject, uk, shareid, tokenInfo, avideos, videos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (items.size() < 9999) break
|
|
||||||
currentPage++
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理子文件夹
|
|
||||||
while (pendingFolders.isNotEmpty()) {
|
|
||||||
val currentBatch = pendingFolders.toList()
|
|
||||||
pendingFolders.clear()
|
|
||||||
|
|
||||||
val results = currentBatch.map { folderInfo ->
|
|
||||||
getFolderContents(folderInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
results.forEachIndexed { i, result ->
|
|
||||||
val folderInfo = currentBatch[i]
|
|
||||||
//if ("error" in result) return@forEachIndexed
|
|
||||||
|
|
||||||
val items = result?.asJsonObject?.get("list")?.asJsonArray ?: return@forEachIndexed
|
|
||||||
|
|
||||||
items.forEach { item ->
|
|
||||||
if (item.asJsonObject["isdir"].asInt == 1) {
|
|
||||||
val folderPath = item.asJsonObject["path"].asString ?: ""
|
|
||||||
if (folderPath !in seenFolders) {
|
|
||||||
seenFolders.add(folderPath)
|
|
||||||
pendingFolders.add(
|
|
||||||
mapOf(
|
|
||||||
"surl" to tokenInfo["surl"]!!,
|
|
||||||
"randsk" to tokenInfo["randsk"]!!,
|
|
||||||
"uk" to folderInfo["uk"]!!,
|
|
||||||
"shareid" to folderInfo["shareid"]!!,
|
|
||||||
"dir" to folderPath,
|
|
||||||
"page" to 1
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else if (isVideoFile(item.asJsonObject["server_filename"].asString ?: "")) {
|
|
||||||
addVideo(
|
|
||||||
item.asJsonObject,
|
|
||||||
folderInfo["uk"]?.toString() ?: "",
|
|
||||||
folderInfo["shareid"]?.toString() ?: "",
|
|
||||||
tokenInfo,
|
|
||||||
avideos,
|
|
||||||
videos
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (items.size() >= 9999) {
|
|
||||||
pendingFolders.add(folderInfo.toMutableMap().apply {
|
|
||||||
this["page"] = (this["page"] as Int) + 1
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return avideos to videos
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
return emptyList<String>() to emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isVideoFile(string: String): Boolean {
|
|
||||||
|
|
||||||
return string.substringAfterLast(".").lowercase(Locale.ROOT) in MEDIA
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addVideo(
|
|
||||||
item: JsonObject,
|
|
||||||
uk: String,
|
|
||||||
shareid: String,
|
|
||||||
tokenInfo: Map<String, String>,
|
|
||||||
avideos: MutableList<String>,
|
|
||||||
videos: MutableList<String>
|
|
||||||
) {
|
|
||||||
val sizeStr = formatSize(item["size"].asLong)
|
|
||||||
val name = item["server_filename"] ?: ""
|
|
||||||
|
|
||||||
val originalData = mapOf(
|
|
||||||
"uk" to uk,
|
|
||||||
"shareid" to shareid,
|
|
||||||
"fid" to item["fs_id"],
|
|
||||||
"randsk" to tokenInfo["randsk"],
|
|
||||||
"pname" to name,
|
|
||||||
"qtype" to "original"
|
|
||||||
)
|
|
||||||
|
|
||||||
val previewData = mapOf(
|
|
||||||
"uk" to uk,
|
|
||||||
"fid" to item["fs_id"],
|
|
||||||
"shareid" to shareid,
|
|
||||||
"surl" to tokenInfo["yurl"],
|
|
||||||
"pname" to name,
|
|
||||||
"qtype" to "preview"
|
|
||||||
)
|
|
||||||
|
|
||||||
avideos.add(
|
|
||||||
"[$sizeStr]$name$${
|
|
||||||
Util.base64Encode(Json.toJson(originalData).toByteArray())
|
|
||||||
}"
|
|
||||||
)
|
|
||||||
videos.add(
|
|
||||||
"[$sizeStr]$name$${
|
|
||||||
Util.base64Encode(Json.toJson(previewData).toByteArray())
|
|
||||||
}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getFolderContents(folderInfo: Map<String, Any>): JsonObject? {
|
|
||||||
val params = if (folderInfo.containsKey("dir")) {
|
|
||||||
mapOf(
|
|
||||||
"uk" to folderInfo["uk"]!!.toString(),
|
|
||||||
"shareid" to folderInfo["shareid"]!!.toString(),
|
|
||||||
"page" to folderInfo["page"].toString(),
|
|
||||||
"num" to "9999",
|
|
||||||
"dir" to URLEncoder.encode(folderInfo["dir"]!!.toString()),
|
|
||||||
"desc" to "0",
|
|
||||||
"order" to "name",
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
mapOf(
|
|
||||||
"page" to folderInfo["page"].toString(),
|
|
||||||
"num" to "9999",
|
|
||||||
"shorturl" to folderInfo["surl"]!!.toString(),
|
|
||||||
"root" to "1",
|
|
||||||
"desc" to "0",
|
|
||||||
"order" to "name",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val tempHeader = headers.toMutableMap()
|
|
||||||
tempHeader.put("Cookie", "BDCLND=${folderInfo["randsk"]}")
|
|
||||||
val result = OkHttp.string("$apiHost/share/list", params, tempHeader)
|
|
||||||
return Json.safeObject(result)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun parseQueryParams(url: String): Map<String, List<String>> {
|
|
||||||
val query = url.substringAfter(
|
|
||||||
"?"
|
|
||||||
).substringBefore('#')
|
|
||||||
return query.split('&').associate {
|
|
||||||
val (key, value) = it.split('=', limit = 2)
|
|
||||||
key to listOf(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun formatSize(bytes: Long): String {
|
|
||||||
if (bytes <= 0) return "0 B"
|
|
||||||
val units = arrayOf("B", "KB", "MB", "GB", "TB")
|
|
||||||
val digitGroups = (Math.log10(bytes.toDouble()) / Math.log10(1024.0)).toInt()
|
|
||||||
return "%.1f %s".format(bytes / Math.pow(1024.0, digitGroups.toDouble()), units[digitGroups])
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun getBdUid(): String? {
|
|
||||||
if (cache["uid"] != null) {
|
|
||||||
return cache["uid"]
|
|
||||||
}
|
|
||||||
val tempHeader = headers.toMutableMap()
|
|
||||||
tempHeader.put("Cookie", cookies)
|
|
||||||
try {
|
|
||||||
val response = OkHttp.string(
|
|
||||||
|
|
||||||
"https://mbd.baidu.com/userx/v1/info/get?appname=baiduboxapp&fields=%20%20%20%20%20%20%20%20%5B%22bg_image%22,%22member%22,%22uid%22,%22avatar%22,%20%22avatar_member%22%5D&client&clientfrom&lang=zh-cn&tpl&ttt",
|
|
||||||
emptyMap<String, String>(),
|
|
||||||
tempHeader
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
val responseJson = Json.safeObject(response)
|
|
||||||
val user = responseJson["data"].asJsonObject
|
|
||||||
|
|
||||||
val fields = user?.get("fields")?.asJsonObject
|
|
||||||
|
|
||||||
val uidValue = fields?.get("uid")?.asString
|
|
||||||
|
|
||||||
if (uidValue != null) {
|
|
||||||
cache["uid"] = uidValue
|
|
||||||
return uidValue
|
|
||||||
} else {
|
|
||||||
throw Exception("Failed to retrieve UID from Baidu Drive.")
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
println("获取百度网盘用户ID失败: ${e.message}")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun _getSign(videoData: JsonObject): Pair<String, String> {
|
|
||||||
val tempHeader = headers.toMutableMap()
|
|
||||||
tempHeader.put("Cookie", cookies)
|
|
||||||
val response: String? = OkHttp.string(
|
|
||||||
"${apiHost}/share/tplconfig", mapOf<String, String>(
|
|
||||||
"surl" to videoData["surl"].asString, "fields" to "cfrom_id,Espace_info,card_info,sign,timestamp"
|
|
||||||
),
|
|
||||||
|
|
||||||
tempHeader
|
|
||||||
)
|
|
||||||
return try {
|
|
||||||
val data = Json.safeObject(response)["data"].asJsonObject
|
|
||||||
|
|
||||||
data["sign"].asString to data["timestamp"].asString
|
|
||||||
} catch (_: Exception) {
|
|
||||||
"" to ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun _getDownloadUrl(videoData: JsonObject): String {
|
|
||||||
return try {
|
|
||||||
var cookie = ""
|
|
||||||
val BDCLND = "BDCLND=" + videoData["randsk"].asString
|
|
||||||
// 更新Cookie中的BDCLND值
|
|
||||||
if (!this.cookies.contains("BDCLND")) {
|
|
||||||
cookie = this.cookies + ";" + BDCLND
|
|
||||||
|
|
||||||
} else {
|
|
||||||
cookie = this.cookies.split(";").joinToString(";") {
|
|
||||||
if (it.contains("BDCLND")) {
|
|
||||||
BDCLND
|
|
||||||
} else {
|
|
||||||
it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val transferHeaders = mapOf(
|
|
||||||
"User-Agent" to "Android",
|
|
||||||
"Connection" to "Keep-Alive",
|
|
||||||
"Content-Type" to "application/x-www-form-urlencoded",
|
|
||||||
"Accept-Language" to "zh-CN,zh;q=0.8",
|
|
||||||
"charset" to "UTF-8",
|
|
||||||
"Referer" to "https://pan.baidu.com",
|
|
||||||
"Cookie" to cookie
|
|
||||||
)
|
|
||||||
// 先清空文件夹在创建文件夹
|
|
||||||
|
|
||||||
if (deleteTag == 0) {
|
|
||||||
_deleteTransferFile("/$saveDirName")
|
|
||||||
//创建路径
|
|
||||||
createSaveDir()
|
|
||||||
deleteTag = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val data =
|
|
||||||
"from=${videoData["uk"].asString}&shareid=${videoData["shareid"].asString}&ondup=newcopy&path=/${saveDirName}&fsidlist=[${videoData["fid"].asString}]"
|
|
||||||
|
|
||||||
var to = ""
|
|
||||||
for (i in 1..30) {
|
|
||||||
|
|
||||||
|
|
||||||
val response =
|
|
||||||
OkHttp.post("${apiHost}/share/transfer?${data}", emptyMap<String, String>(), transferHeaders)
|
|
||||||
|
|
||||||
val result = Json.safeObject(response.body)
|
|
||||||
|
|
||||||
try {
|
|
||||||
to = (result["extra"].asJsonObject)["list"].asJsonArray[0].asJsonObject["to"].asString
|
|
||||||
// videoData["to"] = to
|
|
||||||
if (to.isNotEmpty()) {
|
|
||||||
println("成功转存文件到: $to")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
println("解析转存响应出错: ${e.message}")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (to.isEmpty()) {
|
|
||||||
println("转存文件失败,无法获取下载链接")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
val mediaInfoHeaders = mapOf(
|
|
||||||
|
|
||||||
"User-Agent" to "netdisk;1.4.2;22021211RC;android-android;12;JSbridge4.4.0;jointBridge;1.1.0;",
|
|
||||||
"Connection" to "Keep-Alive",
|
|
||||||
"Accept-Language" to "zh-CN,zh;q=0.8",
|
|
||||||
"charset" to "UTF-8",
|
|
||||||
"Cookie" to cookie
|
|
||||||
).toMutableMap()
|
|
||||||
|
|
||||||
|
|
||||||
val mediaInfoParams = mapOf(
|
|
||||||
"type" to "M3U8_FLV_264_480", "path" to "/$to", "clienttype" to "80", "origin" to "dlna"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
val mediaInfoResponse: String? = OkHttp.string(
|
|
||||||
"${apiHost}/api/mediainfo", mediaInfoParams, mediaInfoHeaders
|
|
||||||
)
|
|
||||||
val responseJson = Json.safeObject(mediaInfoResponse)
|
|
||||||
val info = responseJson["info"].asJsonObject
|
|
||||||
val downloadUrl = info["dlink"].asString
|
|
||||||
println("获取到下载链接: $downloadUrl")
|
|
||||||
downloadUrl
|
|
||||||
} catch (e: Exception) {
|
|
||||||
println("获取下载链接过程中出错: ${e.message}")
|
|
||||||
e.printStackTrace()
|
|
||||||
""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getVideoUrl(videoData: JsonObject, flag: String): Map<String, Any> {
|
|
||||||
return try {
|
|
||||||
val bdUid = getBdUid()
|
|
||||||
println("获取百度网盘用户ID: $bdUid")
|
|
||||||
|
|
||||||
if (flag.contains("原画")) {
|
|
||||||
|
|
||||||
var headersApp = mapOf("User-Agent" to "netdisk;P2SP;2.2.91.136;android-android;")
|
|
||||||
|
|
||||||
var downloadUrl = _getAppDownloadUrl(videoData)
|
|
||||||
if (downloadUrl.isEmpty()) {
|
|
||||||
|
|
||||||
headersApp = mapOf(
|
|
||||||
|
|
||||||
"User-Agent" to "netdisk;1.4.2;22021211RC;android-android;12;JSbridge4.4.0;jointBridge;1.1.0;"
|
|
||||||
)
|
|
||||||
|
|
||||||
downloadUrl = _getDownloadUrl(videoData)
|
|
||||||
}
|
|
||||||
if (downloadUrl.isNotEmpty()) {
|
|
||||||
|
|
||||||
val result = mapOf(
|
|
||||||
"parse" to "0", "url" to downloadUrl, "header" to headersApp
|
|
||||||
)
|
|
||||||
|
|
||||||
result
|
|
||||||
} else {
|
|
||||||
_handleError
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val (sign, time) = _getSign(videoData)
|
|
||||||
if (sign.isEmpty() || time.isEmpty()) {
|
|
||||||
return _handleError
|
|
||||||
}
|
|
||||||
val plist = _getPlayList(videoData, sign, time)
|
|
||||||
val tempHeader = headers.toMutableMap()
|
|
||||||
tempHeader.put("Cookie", cookies)
|
|
||||||
mapOf(
|
|
||||||
"parse" to "0", "url" to plist[0], "header" to tempHeader
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
println("获取播放链接失败: ${e.message}")
|
|
||||||
_handleError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun _getAppDownloadUrl(videoData: JsonObject): String {
|
|
||||||
return try {
|
|
||||||
val headers = mapOf<String, String>(
|
|
||||||
|
|
||||||
"User-Agent" to "netdisk;P2SP;2.2.91.136;android-android;",
|
|
||||||
"Connection" to "Keep-Alive",
|
|
||||||
"Accept-Language" to "zh-CN,zh;q=0.8",
|
|
||||||
"charset" to "UTF-8",
|
|
||||||
"cookie" to cookies
|
|
||||||
)
|
|
||||||
val uid = this.getBdUid()
|
|
||||||
val t = System.currentTimeMillis()
|
|
||||||
val params = mapOf<String, String>(
|
|
||||||
"shareid" to videoData["shareid"].asString,
|
|
||||||
"uk" to videoData["uk"].asString,
|
|
||||||
"fid" to videoData["fid"].asString,
|
|
||||||
"sekey" to unquote(videoData["randsk"].asString),
|
|
||||||
"origin" to "dlna",
|
|
||||||
"devuid" to "73CED981D0F186D12BC18CAE1684FFD5|VSRCQTF6W",
|
|
||||||
"clienttype" to "1",
|
|
||||||
"channel" to "android_12_zhao_bd-netdisk_1024266h",
|
|
||||||
"version" to "11.30.2",
|
|
||||||
"time" to t.toString()
|
|
||||||
).toMutableMap()
|
|
||||||
|
|
||||||
val randstr = this.sha1(
|
|
||||||
this.sha1(
|
|
||||||
Util.findByRegex(
|
|
||||||
"BDUSS=(.+?);", cookies, 1
|
|
||||||
)
|
|
||||||
) + uid + "ebrcUYiuxaZv2XGu7KIYKxUrqfnOfpDF$t${params["devuid"]}11.30.2ae5821440fab5e1a61a025f014bd8972"
|
|
||||||
)
|
|
||||||
|
|
||||||
params.put("rand", randstr)
|
|
||||||
|
|
||||||
val response = OkHttp.string(
|
|
||||||
"${apiHost}/share/list", params, headers
|
|
||||||
)
|
|
||||||
val json = Json.safeObject(response)
|
|
||||||
val dlink = json["list"].asJsonArray[0].asJsonObject["dlink"].asString
|
|
||||||
|
|
||||||
/* val url = response["data"] as Map<String, Any>
|
|
||||||
val list = url["list"] as List<Map<String, Any>>
|
|
||||||
val dlink = list[0]["dlink"] as String
|
|
||||||
|
|
||||||
val pDataResponse = client.get(dlink) {
|
|
||||||
headers { this@_getAppDownloadUrl.headers.forEach { name, value -> append(name, value) } }
|
|
||||||
cookies?.let { setCookie(it) }
|
|
||||||
followRedirects = false
|
|
||||||
timeout.socketTimeoutMillis = 10000
|
|
||||||
}
|
|
||||||
|
|
||||||
val pUrl = pDataResponse.headers[HttpHeaders.Location]?.toString()
|
|
||||||
pUrl ?: dlink*/
|
|
||||||
dlink
|
|
||||||
} catch (e: Exception) {
|
|
||||||
println("获取下载链接失败: ${e.message}")
|
|
||||||
""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun _getPlayList(videoData: JsonObject, sign: String, time: String): List<String> {
|
|
||||||
val hz = getPlayFormatList()
|
|
||||||
val plist = mutableListOf<String>()
|
|
||||||
|
|
||||||
for (quality in hz) {
|
|
||||||
val url =
|
|
||||||
("${apiHost}/share/streaming?" + "uk=${videoData["uk"].asString}&" + "fid=${videoData["fid"].asString}&" + "sign=$sign&" + "timestamp=$time&" + "shareid=${videoData["shareid"].asString}&" + "type=M3U8_AUTO_${
|
|
||||||
quality.replace(
|
|
||||||
"P", ""
|
|
||||||
)
|
|
||||||
}")
|
|
||||||
plist.add(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
return plist
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建保存目录
|
|
||||||
*/
|
|
||||||
fun createSaveDir(): Long? {
|
|
||||||
var saveDirId: Long? = null
|
|
||||||
// 创建保存目录
|
|
||||||
if (cookies.isEmpty()) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
val tempHeader = headers.toMutableMap()
|
|
||||||
tempHeader.put("Cookie", cookies)
|
|
||||||
return try {
|
|
||||||
val listResp = OkHttp.string(
|
|
||||||
"${apiHost}/api/list", mapOf(
|
|
||||||
"dir" to "/",
|
|
||||||
"order" to "name",
|
|
||||||
"desc" to "0",
|
|
||||||
"showempty" to "0",
|
|
||||||
"web" to "1",
|
|
||||||
"app_id" to "250528"
|
|
||||||
), tempHeader
|
|
||||||
)
|
|
||||||
val json = Json.safeObject(listResp)
|
|
||||||
|
|
||||||
if (json["errno"].asInt != 0) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
val drpyDir = json["list"].asJsonArray.find { item ->
|
|
||||||
item.asJsonObject.get("isdir").asInt == 1 && item.asJsonObject.get("server_filename").asString == saveDirName
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (drpyDir != null) {
|
|
||||||
saveDirId = drpyDir.asJsonObject.get("fs_id").asLong
|
|
||||||
return saveDirId
|
|
||||||
}
|
|
||||||
|
|
||||||
val createResp = OkHttp.post(
|
|
||||||
"${apiHost}/api/create?a=commit&bdstoken=${getBdstoken()}&clienttype=0&app_id=250528&web=1&dp-logid=73131200762376420075",
|
|
||||||
mapOf(
|
|
||||||
"path" to "//$saveDirName",
|
|
||||||
"isdir" to "1",
|
|
||||||
"block_list" to "[]",
|
|
||||||
|
|
||||||
),
|
|
||||||
tempHeader
|
|
||||||
)
|
|
||||||
val createJson = Json.safeObject(createResp.body)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
saveDirId = createJson["fs_id"].asLong
|
|
||||||
saveDirId
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
println("创建保存目录失败: ${e.message}")
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getBdstoken(): String {
|
|
||||||
if (cache["bdstoken"] != null) {
|
|
||||||
return cache["bdstoken"]!!
|
|
||||||
}
|
|
||||||
val tempHeader = headers.toMutableMap()
|
|
||||||
tempHeader.put("Cookie", cookies)
|
|
||||||
val userInfo = OkHttp.string(
|
|
||||||
"${apiHost}/api/gettemplatevariable?clienttype=0&app_id=250528&web=1&fields=[\"bdstoken\",\"token\",\"uk\",\"isdocuser\",\"servertime\"]",
|
|
||||||
mapOf(),
|
|
||||||
tempHeader
|
|
||||||
|
|
||||||
)
|
|
||||||
val json = Json.safeObject(userInfo)
|
|
||||||
|
|
||||||
val bdstoken: String? = json["result"]?.asJsonObject?.get("bdstoken")?.asString
|
|
||||||
cache["bdstoken"] = bdstoken ?: ""
|
|
||||||
return bdstoken ?: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun _deleteTransferFile(filePath: String) {
|
|
||||||
try {
|
|
||||||
val url =
|
|
||||||
"$apiHost/api/filemanager?async=2&onnest=fail&opera=delete&bdstoken=${getBdstoken()}&newVerify=1&clienttype=0&app_id=250528&web=1&dp-logid=39292100213290200076"
|
|
||||||
val params = mapOf(
|
|
||||||
"filelist" to "[\"$filePath\"]"
|
|
||||||
)
|
|
||||||
|
|
||||||
val headers = mutableMapOf(
|
|
||||||
"User-Agent" to "Android",
|
|
||||||
"Connection" to "Keep-Alive",
|
|
||||||
"Accept-Encoding" to "br,gzip",
|
|
||||||
"Content-Type" to "application/x-www-form-urlencoded; charset=utf-8",
|
|
||||||
"Accept-Language" to "zh-CN,zh;q=0.8",
|
|
||||||
"charset" to "UTF-8",
|
|
||||||
"Cookie" to cookies,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
val response = OkHttp.post(url, params, headers)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
println("删除文件响应: ${response.body}")
|
|
||||||
println("响应状态码: ${response.code}")
|
|
||||||
} catch (e: Exception) {
|
|
||||||
println("删除文件出错: ${e.message}")
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun unquote(encoded: String): String {
|
|
||||||
return encoded.replace("%([0-9A-Fa-f]{2})".toRegex()) { match ->
|
|
||||||
Integer.parseInt(match.groupValues[1], 16).toChar().toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun sha1(input: String): String {
|
|
||||||
|
|
||||||
return Util.sha1Hex(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val _handleError = mapOf(
|
|
||||||
"parse" to "1", "msg" to "Error retrieving video URL"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
fun getVod(shareUrl: String): Vod {
|
|
||||||
val (froms, urls) = processShareLinks(listOf(shareUrl))
|
|
||||||
val builder = VodPlayBuilder()
|
|
||||||
for (i in froms.indices) {
|
|
||||||
val playUrls = mutableListOf<VodPlayBuilder.PlayUrl>();
|
|
||||||
for (url in urls[i].split("#")) {
|
|
||||||
val arr = url.split("$")
|
|
||||||
val play = VodPlayBuilder.PlayUrl()
|
|
||||||
play.name = arr[0]
|
|
||||||
play.url = arr[1]
|
|
||||||
|
|
||||||
playUrls.add(play)
|
|
||||||
|
|
||||||
}
|
|
||||||
builder.append(froms[i], playUrls)
|
|
||||||
}
|
|
||||||
val buildResult = builder.build();
|
|
||||||
|
|
||||||
val vod = Vod()
|
|
||||||
vod.setVodId(shareUrl)
|
|
||||||
vod.setVodPic("")
|
|
||||||
vod.setVodYear("")
|
|
||||||
vod.setVodName("")
|
|
||||||
vod.setVodContent("")
|
|
||||||
vod.setVodPlayFrom(buildResult.vodPlayFrom)
|
|
||||||
vod.setVodPlayUrl(buildResult.vodPlayUrl)
|
|
||||||
return vod
|
|
||||||
}
|
|
||||||
|
|
||||||
fun playerContent(json: JsonObject, flag: String): String {
|
|
||||||
val play = getVideoUrl(json, flag);
|
|
||||||
val header = play["header"] as Map<String, String>
|
|
||||||
return Result.get().url(buildProxyUrl(play["url"] as String, header)).octet().header(header).string();
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getPlayFormatList(): Array<String> {
|
|
||||||
return listOf("1080P").toTypedArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun proxyVideo(params: MutableMap<String, String>): Array<Any> {
|
|
||||||
return emptyList<Any>().toTypedArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,398 +0,0 @@
|
||||||
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();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,142 +0,0 @@
|
||||||
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: $uname,passwd:$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) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -12,6 +12,7 @@ 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;
|
||||||
|
|
@ -25,6 +26,7 @@ import com.github.catvod.spider.Init;
|
||||||
import com.github.catvod.spider.Proxy;
|
import com.github.catvod.spider.Proxy;
|
||||||
import com.github.catvod.utils.*;
|
import com.github.catvod.utils.*;
|
||||||
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;
|
||||||
|
|
@ -71,7 +73,7 @@ public class QuarkApi {
|
||||||
if (Util.getExt(url).contains("m3u8")) {
|
if (Util.getExt(url).contains("m3u8")) {
|
||||||
return getM3u8(url, header);
|
return getM3u8(url, header);
|
||||||
}
|
}
|
||||||
return ProxyVideo.proxyMultiThread(url, header);
|
return ProxyVideo.proxy(url, header);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -166,7 +168,7 @@ public class QuarkApi {
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
SpiderDebug.log("资源已取消:" + e.getMessage());
|
SpiderDebug.log("资源已取消:" + e.getMessage());
|
||||||
Notify.show("资源已取消");
|
Notify.show("资源已取消");
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> playFrom = QuarkApi.get().getPlayFormatList();
|
List<String> playFrom = QuarkApi.get().getPlayFormatList();
|
||||||
|
|
@ -210,18 +212,15 @@ 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");
|
||||||
if (flag.contains("quark原画")) {
|
return Result.get().url(proxyVideoUrl(playUrl, header)).octet().header(header).string();
|
||||||
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) {
|
||||||
|
|
@ -378,7 +377,7 @@ public class QuarkApi {
|
||||||
|
|
||||||
public List<String> getPlayFormatList() {
|
public List<String> getPlayFormatList() {
|
||||||
if (this.isVip) {
|
if (this.isVip) {
|
||||||
return Arrays.asList("4K"/*, "超清", "高清", "普画"*/);
|
return Arrays.asList("4K", "超清", "高清", "普画");
|
||||||
} else {
|
} else {
|
||||||
return Collections.singletonList("普画");
|
return Collections.singletonList("普画");
|
||||||
}
|
}
|
||||||
|
|
@ -414,7 +413,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")) && (Util.isMedia((String) item.get("file_name")))) {
|
} else if (Boolean.TRUE.equals(item.get("file")) && "video".equals(item.get("obj_category"))) {
|
||||||
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));
|
||||||
|
|
@ -475,17 +474,14 @@ public class QuarkApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearSaveDir() throws Exception {
|
private void clearSaveDir() throws Exception {
|
||||||
Map<String, Object> listData = Json.parseSafe(api("file/sort?" + this.pr + "&pdir_fid=" + this.saveDirId + "&_page=1&_size=200&_sort=file_type:asc,updated_at:desc", Collections.emptyMap(), Collections.emptyMap(), 0, "GET"), Map.class);
|
|
||||||
|
|
||||||
if (listData.get("data") != null) {
|
Map<String, Object> listData = Json.parseSafe(api("file/sort?" + this.pr + "&pdir_fid=" + this.saveDirId + "&_page=1&_size=200&_sort=file_type:asc,updated_at:desc", Collections.emptyMap(), Collections.emptyMap(), 0, "GET"), Map.class);
|
||||||
List<Map<String, Object>> fileList = (List<Map<String, Object>>) ((Map<String, Object>) listData.get("data")).get("list");
|
if (listData.get("data") != null && ((List<Map<String, Object>>) ((Map<String, Object>) listData.get("data")).get("list")).size() > 0) {
|
||||||
if (fileList.size() >= 10) {
|
List<String> list = new ArrayList<>();
|
||||||
List<String> fileIdsToDelete = new ArrayList<>();
|
for (Map<String, Object> stringStringMap : ((List<Map<String, Object>>) ((Map<String, Object>) listData.get("data")).get("list"))) {
|
||||||
for (Map<String, Object> file : fileList) {
|
list.add((String) stringStringMap.get("fid"));
|
||||||
fileIdsToDelete.add((String) file.get("fid"));
|
|
||||||
}
|
|
||||||
api("file/delete?" + this.pr + "&uc_param_str=", Collections.emptyMap(), Map.of("action_type", 2, "filelist", fileIdsToDelete, "exclude_fids", Collections.emptyList()), 0, "POST");
|
|
||||||
}
|
}
|
||||||
|
api("file/delete?" + this.pr, Collections.emptyMap(), Map.of("action_type", "2", "filelist", Json.toJson(list), "exclude_fids", ""), 0, "POST");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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_CONTAIN = "cloud.189.cn/";
|
public static final String URL_START = "https://cloud.189.cn/";
|
||||||
|
|
||||||
|
|
||||||
private Map<String, JsonObject> shareTokenCache = new HashMap<>();
|
private Map<String, JsonObject> shareTokenCache = new HashMap<>();
|
||||||
|
|
@ -175,7 +175,7 @@ public class TianyiApi {
|
||||||
|
|
||||||
|
|
||||||
header.put("Cookie", cookieJar.loadForRequest("https://cloud.189.cn/api/portal/getNewVlcVideoPlayUrl.action"));
|
header.put("Cookie", cookieJar.loadForRequest("https://cloud.189.cn/api/portal/getNewVlcVideoPlayUrl.action"));
|
||||||
return Result.get().url(ProxyServer.INSTANCE.buildProxyUrl(playUrl, header)).octet().header(header).string();
|
return Result.get().url(ProxyVideo.buildCommonProxyUrl(playUrl, header)).octet().header(header).string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -221,30 +221,41 @@ public class TianyiApi {
|
||||||
|
|
||||||
|
|
||||||
public ShareData getShareData(String url, String accessCode) {
|
public ShareData getShareData(String url, String accessCode) {
|
||||||
// 从整个URL中直接提取访问码,无论格式如何
|
String shareCode = "";
|
||||||
Matcher accessMatcher = Pattern.compile("访问码[::]([a-zA-Z0-9]+)").matcher(url);
|
// 第一种匹配规则:使用预编译的 regex
|
||||||
if (accessMatcher.find()) {
|
Matcher matcher = Pattern.compile("https:\\/\\/cloud\\.189\\.cn\\/web\\/share\\?code=([^&]+)").matcher(url);
|
||||||
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/ 格式,兼容http和https,匹配到空格前
|
// 第二种匹配规则:直接匹配 cloud.189.cn/t/ 格式
|
||||||
Matcher fallbackMatcher = Pattern.compile("https?:\\/\\/cloud\\.189\\.cn\\/t/([^\\s]+)").matcher(url);
|
Matcher fallbackMatcher = Pattern.compile("https://cloud\\.189\\.cn/t/([^&]+)").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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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&sys=darwin&ve=1.8.6&ut=Nk27FcCv6q1eo6rXz8QHR/nIG6qLA3jh7KdL+agFgcOvww==";
|
private String pr = "pr=UCBrowser&fr=pc";
|
||||||
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,15 +87,7 @@ 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()));
|
||||||
|
|
||||||
java.lang.String tokenCacheJson = tokenCache.getUser().getCookie();
|
this.cookieToken = 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,9 +181,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()) {
|
||||||
|
|
@ -225,19 +217,23 @@ 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原画")) {
|
|
||||||
playUrl = this.getDownload(shareId, stoken, fileId, fileToken, true);
|
//UCTV 可以直接播放,不需要代理
|
||||||
|
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) {
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,25 @@ 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();
|
||||||
|
|
||||||
OkResult okResult1 = getAccessToken(code, false);
|
pathname = "/token";
|
||||||
|
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) {
|
||||||
|
|
@ -190,14 +208,15 @@ 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(Json.toJson(tokenResData.get("data").getAsJsonObject())));
|
cache.setTokenUser(User.objectFrom(tokenResData.get("data").getAsJsonObject().get("access_token").getAsString()));
|
||||||
|
|
||||||
//停止检验线程,关闭弹窗
|
//停止检验线程,关闭弹窗
|
||||||
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");
|
||||||
|
|
||||||
|
|
@ -207,74 +226,6 @@ 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);
|
||||||
|
|
@ -315,11 +266,6 @@ 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;
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,25 @@
|
||||||
package com.github.catvod.api;
|
package com.github.catvod.api;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import com.github.catvod.bean.Result;
|
|
||||||
import com.github.catvod.crawler.SpiderDebug;
|
|
||||||
import com.github.catvod.net.OkHttp;
|
import com.github.catvod.net.OkHttp;
|
||||||
import com.github.catvod.net.OkResult;
|
import com.github.catvod.net.OkResult;
|
||||||
import com.github.catvod.utils.Json;
|
import com.github.catvod.utils.Json;
|
||||||
import com.github.catvod.utils.ProxyServer;
|
|
||||||
import com.github.catvod.utils.ProxyVideo;
|
|
||||||
import com.github.catvod.utils.Util;
|
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import javax.crypto.spec.IvParameterSpec;
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
|
||||||
|
|
||||||
public class YunDrive {
|
public class YunDrive {
|
||||||
private final Pattern regex = Pattern.compile("https://yun\\.139\\.com/shareweb/#/w/i/([^&]+)");
|
private final Pattern regex = Pattern.compile("https://yun\\.139\\.com/shareweb/#/w/i/([^&]+)");
|
||||||
private final SecretKeySpec secretKey;
|
private final SecretKeySpec secretKey;
|
||||||
|
|
@ -90,14 +76,6 @@ public class YunDrive {
|
||||||
matcher = Pattern.compile("https://caiyun\\.139\\.com/m/i\\?([^&]+)").matcher(url);
|
matcher = Pattern.compile("https://caiyun\\.139\\.com/m/i\\?([^&]+)").matcher(url);
|
||||||
finded = matcher.find();
|
finded = matcher.find();
|
||||||
}
|
}
|
||||||
if (!finded) {
|
|
||||||
matcher = Pattern.compile("https://yun.139.com/shareweb/#/w/i/([\\w-]+)").matcher(url);
|
|
||||||
finded = matcher.find();
|
|
||||||
}
|
|
||||||
if (!finded) {
|
|
||||||
matcher = Pattern.compile("https://caiyun.139.com/w/i/([\\w-]+)").matcher(url);
|
|
||||||
finded = matcher.find();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (finded) linkID = matcher.group(1);
|
if (finded) linkID = matcher.group(1);
|
||||||
return linkID;
|
return linkID;
|
||||||
|
|
@ -191,7 +169,7 @@ public class YunDrive {
|
||||||
for (JsonElement element : response.getAsJsonArray("coLst")) {
|
for (JsonElement element : response.getAsJsonArray("coLst")) {
|
||||||
JsonObject entry = element.getAsJsonObject();
|
JsonObject entry = element.getAsJsonObject();
|
||||||
if (entry.get("coType").getAsInt() == 3) {
|
if (entry.get("coType").getAsInt() == 3) {
|
||||||
items.add(Map.of("name", entry.get("coName").getAsString(), "contentId", entry.get("coID").getAsString(), "linkID", linkID, "path", entry.get("path").getAsString()));
|
items.add(Map.of("name", entry.get("coName").getAsString(), "contentId", entry.get("coID").getAsString(), "linkID", linkID));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (response.has("caLst")) {
|
} else if (response.has("caLst")) {
|
||||||
|
|
@ -217,99 +195,8 @@ public class YunDrive {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m3u8.split("playlist.m3u8")[0] + resultUrl;
|
return m3u8.split("playlist.m3u8")[0]+resultUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String get4kVideoInfo(String fid, String linkID) throws Exception {
|
|
||||||
String auth = getAuth();
|
|
||||||
String phone = getPhone();
|
|
||||||
|
|
||||||
// 构建 JSON 请求体
|
|
||||||
Map<String, Object> requestBody = new HashMap<>();
|
|
||||||
Map<String, Object> dlFromOutLinkReqV3 = new HashMap<>();
|
|
||||||
Map<String, Object> commonAccountInfo = new HashMap<>();
|
|
||||||
|
|
||||||
dlFromOutLinkReqV3.put("linkID", linkID);
|
|
||||||
dlFromOutLinkReqV3.put("account", phone);
|
|
||||||
|
|
||||||
Map<String, Object> coIDLst = new HashMap<>();
|
|
||||||
coIDLst.put("item", Collections.singletonList(fid));
|
|
||||||
dlFromOutLinkReqV3.put("coIDLst", coIDLst);
|
|
||||||
|
|
||||||
commonAccountInfo.put("account", phone);
|
|
||||||
commonAccountInfo.put("accountType", 1);
|
|
||||||
|
|
||||||
requestBody.put("dlFromOutLinkReqV3", dlFromOutLinkReqV3);
|
|
||||||
requestBody.put("commonAccountInfo", commonAccountInfo);
|
|
||||||
|
|
||||||
/* {
|
|
||||||
"dlFromOutLinkReqV3" : {
|
|
||||||
"linkID" : "105CpbaJQFYc6",
|
|
||||||
"account" : "18896781601",
|
|
||||||
"coIDLst" : {
|
|
||||||
"item" : [ "DFTOdJkuAEwA1011ZpAcj1pl039202404112124392cb/Fkco6TgMKlnJwKbVul0ZKeYT5p2hIioVy" ]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"commonAccountInfo" : {
|
|
||||||
"account" : "18896781601",
|
|
||||||
"accountType" : 1
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
// 构建请求
|
|
||||||
Map<String, String> header = getHeader();
|
|
||||||
|
|
||||||
|
|
||||||
OkResult okResult = OkHttp.post(baseUrl + "dlFromOutLinkV3", encrypt(Json.toJson(requestBody)), header);
|
|
||||||
JsonObject resultJson = Json.safeObject(decrypt(okResult.getBody()));
|
|
||||||
if (resultJson.get("resultCode").getAsInt() == 0) {
|
|
||||||
return resultJson.getAsJsonObject("data").get("redrUrl").getAsString();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析 JSON 响应
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getPhone() {
|
|
||||||
String phone = StringUtils.split(Util.base64Decode(getAuth()), ":")[1];
|
|
||||||
SpiderDebug.log("phone:" + phone);
|
|
||||||
return phone;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getAuth() {
|
|
||||||
String auth = YunTokenHandler.get().getToken();
|
|
||||||
SpiderDebug.log("auth:" + auth);
|
|
||||||
return auth;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private static Map<String, String> getHeader() {
|
|
||||||
Map<String, String> header = new HashMap<>();
|
|
||||||
|
|
||||||
header.put("X-Deviceinfo", "||3|12.27.0|safari|13.1.2|1||macos 10.15.6|1324X381|zh-cn|||");
|
|
||||||
header.put("hcy-cool-flag", "1");
|
|
||||||
header.put("Authorization", "Basic " + getAuth());
|
|
||||||
header.put("Content-Type", "application/json");
|
|
||||||
return header;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String playerContent(String[] split, String flag) throws Exception {
|
|
||||||
String playUrl = "";
|
|
||||||
if (flag.contains("原画")) {
|
|
||||||
String contentId = split[0];
|
|
||||||
String linkID = split[1];
|
|
||||||
playUrl = YunDrive.get().get4kVideoInfo(contentId, linkID);
|
|
||||||
playUrl = ProxyServer.INSTANCE.buildProxyUrl(playUrl, new HashMap<>());
|
|
||||||
|
|
||||||
} else {
|
|
||||||
String contentId = split[0];
|
|
||||||
String linkID = split[1];
|
|
||||||
playUrl = YunDrive.get().fetchPlayUrl(contentId, linkID);
|
|
||||||
}
|
|
||||||
return Result.get().url(playUrl).octet().header(getHeader()).string();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
package com.github.catvod.api;
|
|
||||||
|
|
||||||
|
|
||||||
import com.github.catvod.bean.yun.Cache;
|
|
||||||
import com.github.catvod.bean.yun.User;
|
|
||||||
import com.github.catvod.utils.Path;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public class YunTokenHandler {
|
|
||||||
|
|
||||||
private final Cache cache;
|
|
||||||
|
|
||||||
public File getCache() {
|
|
||||||
return Path.tv("yun139");
|
|
||||||
}
|
|
||||||
|
|
||||||
private YunTokenHandler() {
|
|
||||||
cache = Cache.objectFrom(Path.read(getCache()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Loader {
|
|
||||||
static volatile YunTokenHandler INSTANCE = new YunTokenHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static YunTokenHandler get() {
|
|
||||||
return YunTokenHandler.Loader.INSTANCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getToken() {
|
|
||||||
User user = cache.getUser();
|
|
||||||
return user.getCookie();
|
|
||||||
//return "cGM6MTg4OTY3ODE2MDE6eTM1Tjd1dG58MXxSQ1N8MTc1NDQ2OTgwNzEyOXxzMlN0T1VEV3lOVmF5V3pNbGFfM2tJbVp1ZmlqSHBqaEhTSzVyNHZqVXNRLmlhV3loSUxHNDFkMUI5N1BqXzhWN0dtVWtKLnBTclhpNGpZU1EuTGZWMTV3MVFoZmNpcEVoZkxUV2tvYjB0bkFTYV9RTUhhaHhveWx6YkdmcEhQdjNCS1lrbnp1LkxaWDdKOE40YkNNRjkzT3piNmx2Y0d3TWdVUkl5b18ubVUt";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
package com.github.catvod.bean.BD;
|
|
||||||
|
|
||||||
|
|
||||||
import com.github.catvod.api.BaiDuYunHandler;
|
|
||||||
import com.github.catvod.bean.yun.User;
|
|
||||||
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) {
|
|
||||||
Cache item = new Gson().fromJson(str, Cache.class);
|
|
||||||
return item == null ? new Cache() : item;
|
|
||||||
}
|
|
||||||
|
|
||||||
public User getUser() {
|
|
||||||
return user == null ? new User("") : user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUser(User user) {
|
|
||||||
this.user = user;
|
|
||||||
this.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void save() {
|
|
||||||
Init.execute(() -> Path.write(BaiDuYunHandler.get().getCache(), toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return new Gson().toJson(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -6,16 +6,13 @@ import com.github.catvod.bean.Vod;
|
||||||
import com.github.catvod.utils.Util;
|
import com.github.catvod.utils.Util;
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class Data {
|
public class Data {
|
||||||
|
|
||||||
@SerializedName("jump_id")
|
@SerializedName(value = "jump_id", alternate = "id")
|
||||||
private String jumpId;
|
private String jumpId;
|
||||||
@SerializedName("id")
|
|
||||||
private String id;
|
|
||||||
@SerializedName(value = "thumbnail", alternate = "path")
|
@SerializedName(value = "thumbnail", alternate = "path")
|
||||||
private String thumbnail;
|
private String thumbnail;
|
||||||
@SerializedName("title")
|
@SerializedName("title")
|
||||||
|
|
@ -27,30 +24,24 @@ public class Data {
|
||||||
@SerializedName("playlist")
|
@SerializedName("playlist")
|
||||||
private Value playlist;
|
private Value playlist;
|
||||||
@SerializedName("year")
|
@SerializedName("year")
|
||||||
private String year;
|
private Value year;
|
||||||
@SerializedName("area")
|
@SerializedName("area")
|
||||||
private String area;
|
private Value area;
|
||||||
@SerializedName("types")
|
@SerializedName("types")
|
||||||
private List<Value> types;
|
private List<Value> types;
|
||||||
@SerializedName("actors")
|
@SerializedName("actors")
|
||||||
private List<Value> actors;
|
private List<Value> actors;
|
||||||
@SerializedName("directors")
|
@SerializedName("directors")
|
||||||
private List<Value> directors;
|
private List<Value> directors;
|
||||||
@SerializedName("source_list_source")
|
@SerializedName("btbo_downlist")
|
||||||
private List<SourceListSource> source;
|
private List<BtboDown> btboDownlist;
|
||||||
@SerializedName("dataList")
|
|
||||||
private List<Data> dataList;
|
|
||||||
|
|
||||||
public String getJumpId() {
|
public String getJumpId() {
|
||||||
return TextUtils.isEmpty(jumpId) ? "" : jumpId;
|
return TextUtils.isEmpty(jumpId) ? "" : jumpId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getId() {
|
public String getThumbnail() {
|
||||||
return TextUtils.isEmpty(id) ? "" : id;
|
return TextUtils.isEmpty(thumbnail) ? "" : thumbnail + "@Referer=www.jianpianapp.com@User-Agent=jianpian-version362";
|
||||||
}
|
|
||||||
|
|
||||||
public String getThumbnail(String imgDomain) {
|
|
||||||
return TextUtils.isEmpty(thumbnail) ? "" : "http://" + imgDomain + thumbnail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
|
|
@ -70,11 +61,11 @@ public class Data {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getYear() {
|
public String getYear() {
|
||||||
return year == null ? "" : year;
|
return year == null ? "" : year.getTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getArea() {
|
public String getArea() {
|
||||||
return area == null ? "" : area;
|
return area == null ? "" : area.getTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTypes() {
|
public String getTypes() {
|
||||||
|
|
@ -89,20 +80,12 @@ public class Data {
|
||||||
return directors == null ? "" : getValues(directors, true);
|
return directors == null ? "" : getValues(directors, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SourceListSource> getSource() {
|
public List<BtboDown> getBtboDownlist() {
|
||||||
return source == null ? Collections.emptyList() : source;
|
return btboDownlist == null ? Collections.emptyList() : btboDownlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Data> getDataList() {
|
public Vod vod() {
|
||||||
return dataList == null ? Collections.emptyList() : dataList;
|
return new Vod(getJumpId(), getTitle(), getThumbnail(), getMask());
|
||||||
}
|
|
||||||
|
|
||||||
public Vod homeVod(String imgDomain) {
|
|
||||||
return new Vod(getJumpId(), getTitle(), getThumbnail(imgDomain));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vod vod(String imgDomain) {
|
|
||||||
return new Vod(getId(), getTitle(), getThumbnail(imgDomain), getMask());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getValues(List<Value> items, boolean link) {
|
public String getValues(List<Value> items, boolean link) {
|
||||||
|
|
@ -111,6 +94,12 @@ public class Data {
|
||||||
return Util.substring(sb.toString());
|
return Util.substring(sb.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPlayUrl() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (BtboDown value : getBtboDownlist()) sb.append(value.getVal()).append("#");
|
||||||
|
return Util.substring(sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
public static class Value {
|
public static class Value {
|
||||||
|
|
||||||
@SerializedName(value = "title", alternate = "name")
|
@SerializedName(value = "title", alternate = "name")
|
||||||
|
|
@ -129,51 +118,13 @@ public class Data {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SourceListSource {
|
public static class BtboDown {
|
||||||
|
|
||||||
@SerializedName("name")
|
@SerializedName("val")
|
||||||
private String name;
|
private String val;
|
||||||
@SerializedName("source_list")
|
|
||||||
private List<SourceList> list;
|
|
||||||
|
|
||||||
public String getName() {
|
public String getVal() {
|
||||||
return TextUtils.isEmpty(name) ? "" : name;
|
return TextUtils.isEmpty(val) ? "" : val.replaceAll("ftp", "tvbox-xg:ftp");
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SourceList> getList() {
|
|
||||||
return list == null ? Collections.emptyList() : list;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class SourceList {
|
|
||||||
|
|
||||||
@SerializedName("source_name")
|
|
||||||
private String name;
|
|
||||||
@SerializedName("url")
|
|
||||||
private String url;
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return TextUtils.isEmpty(name) ? "" : name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUrl() {
|
|
||||||
return TextUtils.isEmpty(url) ? "" : url.replaceAll("ftp", "tvbox-xg:ftp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVodFrom() {
|
|
||||||
List<String> items = new ArrayList<>();
|
|
||||||
for (SourceListSource source : getSource()) items.add(source.getName());
|
|
||||||
return TextUtils.join("$$$", items);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVodUrl() {
|
|
||||||
List<String> items = new ArrayList<>();
|
|
||||||
for (SourceListSource source : getSource()) {
|
|
||||||
List<String> urls = new ArrayList<>();
|
|
||||||
for (SourceList item : source.getList()) urls.add(item.getName() + "$" + item.getUrl());
|
|
||||||
items.add(TextUtils.join("#", urls));
|
|
||||||
}
|
|
||||||
return TextUtils.join("$$$", items);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
package com.github.catvod.bean.jianpian;
|
|
||||||
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import com.github.catvod.bean.Vod;
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class Search {
|
|
||||||
|
|
||||||
@SerializedName("data")
|
|
||||||
private List<Search> data;
|
|
||||||
@SerializedName("id")
|
|
||||||
private String id;
|
|
||||||
@SerializedName(value = "thumbnail", alternate = "path")
|
|
||||||
private String thumbnail;
|
|
||||||
@SerializedName("title")
|
|
||||||
private String title;
|
|
||||||
@SerializedName("mask")
|
|
||||||
private String mask;
|
|
||||||
|
|
||||||
public static Search objectFrom(String str) {
|
|
||||||
return new Gson().fromJson(str, Search.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getId() {
|
|
||||||
return TextUtils.isEmpty(id) ? "" : id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getThumbnail(String imgDomain) {
|
|
||||||
return TextUtils.isEmpty(thumbnail) ? "" : "http://" + imgDomain + thumbnail;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTitle() {
|
|
||||||
return TextUtils.isEmpty(title) ? "" : title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMask() {
|
|
||||||
return TextUtils.isEmpty(mask) ? "" : mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vod vod(String imgDomain) {
|
|
||||||
return new Vod(getId(), getTitle(), getThumbnail(imgDomain), getMask());
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Search> getData() {
|
|
||||||
return data == null ? Collections.emptyList() : data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
package com.github.catvod.bean.yun;
|
|
||||||
|
|
||||||
|
|
||||||
import com.github.catvod.api.YunTokenHandler;
|
|
||||||
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) {
|
|
||||||
Cache item = new Gson().fromJson(str, Cache.class);
|
|
||||||
return item == null ? new Cache() : item;
|
|
||||||
}
|
|
||||||
|
|
||||||
public User getUser() {
|
|
||||||
return user == null ? new User("") : user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUser(User user) {
|
|
||||||
this.user = user;
|
|
||||||
this.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void save() {
|
|
||||||
Init.execute(() -> Path.write(YunTokenHandler.get().getCache(), toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return new Gson().toJson(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
package com.github.catvod.bean.yun;
|
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
|
||||||
|
|
||||||
public class User {
|
|
||||||
public User(String cookie) {
|
|
||||||
this.cookie = cookie;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SerializedName("cookie")
|
|
||||||
private String cookie;
|
|
||||||
|
|
||||||
public String getCookie() {
|
|
||||||
return cookie;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCookie(String cookie) {
|
|
||||||
this.cookie = cookie;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static User objectFrom(String cookie) {
|
|
||||||
return new User(cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void clean() {
|
|
||||||
this.cookie = "";
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,107 +0,0 @@
|
||||||
package com.github.catvod.spider
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.text.TextUtils
|
|
||||||
import com.github.catvod.api.BaiduDrive
|
|
||||||
import com.github.catvod.api.BaiduDrive.getPlayFormatList
|
|
||||||
import com.github.catvod.api.BaiduDrive.getVod
|
|
||||||
import com.github.catvod.api.BaiduDrive.playerContent
|
|
||||||
import com.github.catvod.api.BaiduDrive.setCookie
|
|
||||||
import com.github.catvod.bean.Result
|
|
||||||
import com.github.catvod.bean.Vod
|
|
||||||
import com.github.catvod.crawler.Spider
|
|
||||||
import com.github.catvod.crawler.SpiderDebug
|
|
||||||
import com.github.catvod.utils.Json
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ColaMint & Adam & FongMi
|
|
||||||
*/
|
|
||||||
class BaiDuPan : Spider() {
|
|
||||||
@Throws(Exception::class)
|
|
||||||
override fun init(context: Context?, extend: String) {
|
|
||||||
setCookie(extend)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ids 為 share_link
|
|
||||||
* @param ids
|
|
||||||
* @return
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
@Throws(Exception::class)
|
|
||||||
override fun detailContent(ids: MutableList<String>): String? {
|
|
||||||
var vod: Vod? = null;
|
|
||||||
runBlocking {
|
|
||||||
vod = getVod(ids[0])
|
|
||||||
}
|
|
||||||
return Result.string(vod);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Throws(Exception::class)
|
|
||||||
override fun playerContent(flag: String, id: String, vipFlags: MutableList<String?>?): String {
|
|
||||||
var content = ""
|
|
||||||
runBlocking {
|
|
||||||
content = playerContent(Json.safeObject(com.github.catvod.utils.Util.base64Decode(id)), flag)
|
|
||||||
}
|
|
||||||
return content
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 獲取詳情內容視頻播放來源(多 shared_link)
|
|
||||||
*
|
|
||||||
* @param ids share_link 集合
|
|
||||||
* @param i
|
|
||||||
* @return 詳情內容視頻播放來源
|
|
||||||
*/
|
|
||||||
fun detailContentVodPlayFrom(ids: MutableList<String?>, index: Int): String? {
|
|
||||||
val playFrom: MutableList<String?> = ArrayList<String?>()
|
|
||||||
|
|
||||||
/* if (ids.size() < 2){
|
|
||||||
return TextUtils.join("$$$", BaiduDrive.get().getPlayFormatList());
|
|
||||||
}*/
|
|
||||||
for (i in 1..ids.size) {
|
|
||||||
playFrom.add( String.format(Locale.getDefault(), "BD原画" + "#%02d_%02d", i, index))
|
|
||||||
/* for (s in getPlayFormatList()) {
|
|
||||||
playFrom.add(String.format(Locale.getDefault(), "BD" + s + "#%02d%02d", i, index))
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
return TextUtils.join("$$$", playFrom)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 獲取詳情內容視頻播放地址(多 share_link)
|
|
||||||
*
|
|
||||||
* @param ids share_link 集合
|
|
||||||
* @return 詳情內容視頻播放地址
|
|
||||||
*/
|
|
||||||
|
|
||||||
fun detailContentVodPlayUrl(ids: List<String>): String? {
|
|
||||||
val playUrl: MutableList<String?> = ArrayList<String?>()
|
|
||||||
for (id in ids) {
|
|
||||||
try {
|
|
||||||
playUrl.add(getVod(id).getVodPlayUrl())
|
|
||||||
} catch (e: Exception) {
|
|
||||||
SpiderDebug.log("获取播放地址出错:" + e.message)
|
|
||||||
playUrl.add("")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TextUtils.join("$$$", playUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
@JvmField
|
|
||||||
var URL_START = "https://pan.baidu.com"
|
|
||||||
|
|
||||||
@Throws(Exception::class)
|
|
||||||
fun proxy(params: MutableMap<String, String>): Array<Any> {
|
|
||||||
val type = params["type"]
|
|
||||||
if ("video" == type) return BaiduDrive.proxyVideo(params)
|
|
||||||
//if ("sub".equals(type)) return AliYun.get().proxySub(params);
|
|
||||||
return arrayOf<Any>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,84 +2,63 @@ 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.Pan123Api;
|
import com.github.catvod.api.TianyiApi;
|
||||||
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.*;
|
import java.util.ArrayList;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.Future;
|
|
||||||
|
|
||||||
import static com.github.catvod.api.TianyiApi.URL_CONTAIN;
|
import static com.github.catvod.api.TianyiApi.URL_START;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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 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();
|
|
||||||
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, "");
|
|
||||||
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 */
|
} else if (shareUrl.get(0).matches(Util.patternQuark)) {
|
||||||
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).contains(URL_CONTAIN)) {
|
} else if (shareUrl.get(0).startsWith(TianyiApi.URL_START)) {
|
||||||
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)) {
|
|
||||||
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")) {
|
||||||
|
|
@ -88,105 +67,47 @@ public class Cloud extends Spider {
|
||||||
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")) {
|
|
||||||
return baiDuPan.playerContent(flag, id, vipFlags);
|
|
||||||
} else if (flag.contains("pan123")) {
|
|
||||||
return pan123.playerContent(flag, id, vipFlags);
|
|
||||||
}
|
}
|
||||||
return flag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String detailContentVodPlayFrom(List<String> shareLinks) {
|
protected String detailContentVodPlayFrom(List<String> shareLinks) {
|
||||||
ImmutablePair<List<String>, List<String>> pairs = resultMap.get(Util.MD5(Json.toJson(shareLinks)));
|
List<String> from = new ArrayList<>();
|
||||||
if (pairs != null && pairs.left != null && !pairs.left.isEmpty()) {
|
int i = 0;
|
||||||
return TextUtils.join("$$$", pairs.right);
|
for (String shareLink : shareLinks) {
|
||||||
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getPlayFromAndUrl(shareLinks);
|
return TextUtils.join("$$$", from);
|
||||||
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) {
|
protected String detailContentVodPlayUrl(List<String> shareLinks) throws Exception {
|
||||||
ImmutablePair<List<String>, List<String>> pairs = resultMap.get(Util.MD5(Json.toJson(shareLinks)));
|
List<String> urls = new ArrayList<>();
|
||||||
if (pairs != null && pairs.left != null && !pairs.left.isEmpty()) {
|
for (String shareLink : shareLinks) {
|
||||||
return TextUtils.join("$$$", pairs.left);
|
if (shareLink.matches(Util.patternUC)) {
|
||||||
}
|
urls.add(uc.detailContentVodPlayUrl(List.of(shareLink)));
|
||||||
|
} else if (shareLink.matches(Util.patternQuark)) {
|
||||||
getPlayFromAndUrl(shareLinks);
|
urls.add(quark.detailContentVodPlayUrl(List.of(shareLink)));
|
||||||
pairs = resultMap.get(Util.MD5(Json.toJson(shareLinks)));
|
} else if (shareLink.matches(Util.patternAli)) {
|
||||||
if (pairs != null && pairs.left != null && !pairs.left.isEmpty()) {
|
|
||||||
return TextUtils.join("$$$", pairs.left);
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//同時获取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)));
|
urls.add(ali.detailContentVodPlayUrl(List.of(shareLink)));
|
||||||
} */ else if (shareLink.contains(URL_CONTAIN)) {
|
} else if (shareLink.startsWith(URL_START)) {
|
||||||
url = tianYi.detailContentVodPlayUrl(List.of(shareLink));
|
urls.add(tianYi.detailContentVodPlayUrl(List.of(shareLink)));
|
||||||
from = tianYi.detailContentVodPlayFrom(List.of(shareLink), finalI);
|
} else if (shareLink.contains(YiDongYun.URL_START)) {
|
||||||
} else if (shareLink.contains(YiDongYun.URL_START)) {
|
urls.add(yiDongYun.detailContentVodPlayUrl(List.of(shareLink)));
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,180 +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.bean.Vod.VodPlayBuilder
|
|
||||||
import com.github.catvod.net.OkHttp
|
|
||||||
import com.github.catvod.utils.ProxyVideo
|
|
||||||
import com.github.catvod.utils.Util
|
|
||||||
import org.jsoup.Jsoup
|
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import org.jsoup.select.Elements
|
|
||||||
import java.net.URLEncoder
|
|
||||||
|
|
||||||
class DiDa : Cloud() {
|
|
||||||
private val headers: HashMap<String?, String?>
|
|
||||||
get() {
|
|
||||||
val headers = java.util.HashMap<String?, String?>()
|
|
||||||
headers.put("User-Agent", Util.CHROME)
|
|
||||||
return headers
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseVodFromDoc(doc: Document): MutableList<Vod?> {
|
|
||||||
val list: MutableList<Vod?> = ArrayList<Vod?>()
|
|
||||||
for (element in doc.select("div.myui-vodlist__box")) {
|
|
||||||
var pic = element.selectFirst("img")?.attr("src")
|
|
||||||
if (pic.isNullOrBlank()) {
|
|
||||||
pic = element.selectFirst("a")?.attr("data-original")
|
|
||||||
}
|
|
||||||
val url = element.selectFirst("a")?.attr("href")
|
|
||||||
val name = element.select("h4 > a").text()
|
|
||||||
|
|
||||||
|
|
||||||
list.add(Vod(url, name, pic))
|
|
||||||
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(Exception::class)
|
|
||||||
override fun homeContent(filter: Boolean): String? {
|
|
||||||
|
|
||||||
val doc = Jsoup.parse(
|
|
||||||
OkHttp.string(
|
|
||||||
siteUrl, this.headers
|
|
||||||
)
|
|
||||||
)
|
|
||||||
var classes: List<Class?>
|
|
||||||
val menuList = doc.select("ul.nav-menu > li > a")
|
|
||||||
classes = menuList.map {
|
|
||||||
val url = it.attr("href")
|
|
||||||
val title = it.text()
|
|
||||||
Class(url, title)
|
|
||||||
}
|
|
||||||
|
|
||||||
val list: MutableList<Vod?> = parseVodFromDoc(doc)
|
|
||||||
return Result.string(classes, list)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(Exception::class)
|
|
||||||
override fun categoryContent(
|
|
||||||
tid: String, pg: String, filter: Boolean, extend: java.util.HashMap<String?, String?>?
|
|
||||||
): String? {
|
|
||||||
|
|
||||||
val type = tid.replace("/type/", "").replace(".html", "")
|
|
||||||
val target: String = siteUrl + "/show/${type}--------${pg}---.html"
|
|
||||||
|
|
||||||
val doc = Jsoup.parse(OkHttp.string(target, this.headers))
|
|
||||||
val list = parseVodFromDoc(doc)
|
|
||||||
val total = (pg.toInt() + 1) * 24
|
|
||||||
return Result.get().vod(list).page(pg.toInt(), pg.toInt() + 1, 48, total).string()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(Exception::class)
|
|
||||||
override fun detailContent(ids: MutableList<String?>): String? {
|
|
||||||
val doc = Jsoup.parse(
|
|
||||||
OkHttp.string(
|
|
||||||
siteUrl + ids.get(0), this.headers
|
|
||||||
)
|
|
||||||
)
|
|
||||||
val name = doc.select("h1").text()
|
|
||||||
val img = doc.select("a.myui-vodlist__thumb > img")
|
|
||||||
val pic = img.attr("src") ?: img.attr("data-original")
|
|
||||||
|
|
||||||
val desc = doc.select("p.data").text()
|
|
||||||
val year = Util.findByRegex("年份:(.*)又名", desc, 1).trim()
|
|
||||||
val area = Util.findByRegex("地区:(.*)语言", desc, 1).trim()
|
|
||||||
val actor = Util.findByRegex("主演:(.*)导演", desc, 1).trim()
|
|
||||||
|
|
||||||
val builder = VodPlayBuilder()
|
|
||||||
val playFromTab = doc.selectFirst("div.myui-panel__head > ul.nav ")
|
|
||||||
val playFromEles = playFromTab?.select("ul > li > a") ?: Elements()
|
|
||||||
for (ele in playFromEles) {
|
|
||||||
val playUrlList = mutableListOf<Vod.VodPlayBuilder.PlayUrl>()
|
|
||||||
|
|
||||||
val id = ele.attr("href")
|
|
||||||
val playFrom = ele.text()
|
|
||||||
if (playFrom.contains("网盘")) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
val playElement = doc.select("$id")
|
|
||||||
for (element in playElement.select("ul > li > a")) {
|
|
||||||
val playUrl = VodPlayBuilder.PlayUrl()
|
|
||||||
playUrl.url = element.attr("href")
|
|
||||||
playUrl.name = element.text()
|
|
||||||
playUrlList.add(playUrl)
|
|
||||||
|
|
||||||
}
|
|
||||||
builder.append(playFrom, playUrlList)
|
|
||||||
}
|
|
||||||
var panFrom = ""
|
|
||||||
var panURl = ""
|
|
||||||
|
|
||||||
for (element in doc.select(" div.myui-panel_bd.clearfix > p > a")) {
|
|
||||||
if (element.attr("href").matches(Util.patternQuark.toRegex())) {
|
|
||||||
panFrom = super.detailContentVodPlayFrom(listOf<String>(element.attr("href")))
|
|
||||||
panURl = super.detailContentVodPlayUrl(listOf<String>(element.attr("href")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val result = builder.build()
|
|
||||||
val vod = Vod()
|
|
||||||
vod.setVodId(ids[0])
|
|
||||||
vod.setVodPic(ProxyVideo.buildCommonProxyUrl(pic, Util.webHeaders(pic)))
|
|
||||||
vod.setVodYear(year)
|
|
||||||
vod.setVodActor(actor)
|
|
||||||
vod.setVodArea(area)
|
|
||||||
vod.setVodName(name)
|
|
||||||
vod.setVodPlayFrom(result.vodPlayFrom + "$$$" + panFrom)
|
|
||||||
vod.setVodPlayUrl(result.vodPlayUrl + "$$$" + panURl)
|
|
||||||
return Result.string(vod)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(Exception::class)
|
|
||||||
override fun searchContent(key: String?, quick: Boolean): String? {
|
|
||||||
val doc = Jsoup.parse(
|
|
||||||
OkHttp.string(
|
|
||||||
searchUrl + URLEncoder.encode(key), this.headers
|
|
||||||
)
|
|
||||||
)
|
|
||||||
val list: MutableList<Vod?> = ArrayList<Vod?>()
|
|
||||||
for (element in doc.select("a.cover-link")) {
|
|
||||||
val pic = element.select("img").attr("data-src")
|
|
||||||
val url = element.attr("href")
|
|
||||||
val name = element.select("img").attr("alt")
|
|
||||||
val id: String? = url.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[2]
|
|
||||||
|
|
||||||
list.add(Vod(id, name, ProxyVideo.buildCommonProxyUrl(pic, Util.webHeaders(pic))))
|
|
||||||
}
|
|
||||||
return Result.string(list)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(Exception::class)
|
|
||||||
override fun playerContent(flag: String?, id: String?, vipFlags: MutableList<String?>?): String? {
|
|
||||||
if (flag == null) {
|
|
||||||
return Result.get().url("").header(this.headers).string()
|
|
||||||
} else if (flag.contains("quark")) {
|
|
||||||
super.playerContent(flag, id, vipFlags)
|
|
||||||
} else {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return Result.get().url(id).header(this.headers).string()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val siteUrl = "https://www.didahd.pro"
|
|
||||||
|
|
||||||
private val searchUrl: String = siteUrl + "/search?q="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -10,7 +10,6 @@ import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
|
||||||
import com.github.catvod.crawler.SpiderDebug;
|
import com.github.catvod.crawler.SpiderDebug;
|
||||||
import com.github.catvod.utils.ProxyServer;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
@ -42,11 +41,7 @@ public class Init {
|
||||||
|
|
||||||
public static void init(Context context) {
|
public static void init(Context context) {
|
||||||
get().app = ((Application) context);
|
get().app = ((Application) context);
|
||||||
SpiderDebug.log("自定義爬蟲代碼載入成功!" + "1");
|
SpiderDebug.log("自定義爬蟲代碼載入成功!");
|
||||||
execute(() -> {
|
|
||||||
ProxyServer.INSTANCE.stop();
|
|
||||||
ProxyServer.INSTANCE.start();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void execute(Runnable runnable) {
|
public static void execute(Runnable runnable) {
|
||||||
|
|
@ -65,8 +60,7 @@ public class Init {
|
||||||
try {
|
try {
|
||||||
Activity activity = Init.getActivity();
|
Activity activity = Init.getActivity();
|
||||||
if (activity == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return;
|
if (activity == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return;
|
||||||
if (activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
|
if (activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) return;
|
||||||
return;
|
|
||||||
activity.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 9999);
|
activity.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 9999);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,133 @@
|
||||||
|
package com.github.catvod.spider;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.github.catvod.bean.Class;
|
||||||
|
import com.github.catvod.bean.Result;
|
||||||
|
import com.github.catvod.bean.Vod;
|
||||||
|
import com.github.catvod.crawler.Spider;
|
||||||
|
import com.github.catvod.net.OkHttp;
|
||||||
|
import com.github.catvod.utils.Util;
|
||||||
|
|
||||||
|
import org.jsoup.Jsoup;
|
||||||
|
import org.jsoup.nodes.Document;
|
||||||
|
import org.jsoup.nodes.Element;
|
||||||
|
import org.jsoup.select.Elements;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Qile
|
||||||
|
*/
|
||||||
|
public class JavDb extends Spider {
|
||||||
|
|
||||||
|
private static String siteUrl = "https://javdb523.com";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Context context, String extend) throws Exception {
|
||||||
|
if (!extend.isEmpty()) siteUrl = extend;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> getHeader() {
|
||||||
|
Map<String, String> header = new HashMap<>();
|
||||||
|
header.put("User-Agent", Util.CHROME);
|
||||||
|
header.put("Referer", siteUrl + "/");
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String homeContent(boolean filter) throws Exception {
|
||||||
|
List<Class> classes = new ArrayList<>();
|
||||||
|
List<String> typeIds = Arrays.asList("", "censored", "uncensored", "western");
|
||||||
|
List<String> typeNames = Arrays.asList("全部", "有码", "无码", "欧美");
|
||||||
|
for (int i = 0; i < typeIds.size(); i++) classes.add(new Class(typeIds.get(i), typeNames.get(i)));
|
||||||
|
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeader()));
|
||||||
|
List<Vod> list = new ArrayList<>();
|
||||||
|
for (Element li : doc.select(".item")) {
|
||||||
|
String vid = siteUrl + li.select("a").attr("href");
|
||||||
|
String name = li.select("a").attr("title");
|
||||||
|
String pic = li.select("img").attr("src");
|
||||||
|
list.add(new Vod(vid, name, pic));
|
||||||
|
}
|
||||||
|
return Result.string(classes, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
|
||||||
|
String cateUrl = siteUrl + String.format("/%s?page=%s", tid, pg);
|
||||||
|
Document doc = Jsoup.parse(OkHttp.string(cateUrl, getHeader()));
|
||||||
|
List<Vod> list = new ArrayList<>();
|
||||||
|
for (Element li : doc.select(".item")) {
|
||||||
|
String vid = siteUrl + li.select("a").attr("href");
|
||||||
|
String name = li.select("a").attr("title");
|
||||||
|
String pic = li.select("img").attr("src");
|
||||||
|
list.add(new Vod(vid, name, pic));
|
||||||
|
}
|
||||||
|
return Result.string(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String detailContent(List<String> ids) throws Exception {
|
||||||
|
Document doc = Jsoup.parse(OkHttp.string(ids.get(0), getHeader()));
|
||||||
|
if (doc.text().contains("歡迎登入")) return Result.error("该资源需要登入");
|
||||||
|
List<String> vodItems = new ArrayList<>();
|
||||||
|
Elements sourceList = doc.select(".item.columns");
|
||||||
|
for (Element a : sourceList) {
|
||||||
|
String episodeUrl = a.select("div a").attr("href");
|
||||||
|
String episodeName = a.select("div a").text();
|
||||||
|
vodItems.add(episodeName + "$" + episodeUrl);
|
||||||
|
}
|
||||||
|
Elements elements = doc.select(".panel-block");
|
||||||
|
String classifyName = "";
|
||||||
|
String year = "";
|
||||||
|
String area = "";
|
||||||
|
String remark = "";
|
||||||
|
for (Element element : elements) {
|
||||||
|
String text = element.text();
|
||||||
|
if (text.startsWith("類別:")) {
|
||||||
|
classifyName = element.select("span a").text();
|
||||||
|
} else if (text.startsWith("片商:")) {
|
||||||
|
area = element.select("span a").text();
|
||||||
|
} else if (text.startsWith("日期:")) {
|
||||||
|
year = element.select("span").text();
|
||||||
|
} else if (text.startsWith("時長:")) {
|
||||||
|
remark = element.select("span").text();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Vod vod = new Vod();
|
||||||
|
vod.setVodId(ids.get(0));
|
||||||
|
vod.setVodYear(year);
|
||||||
|
vod.setVodArea(area);
|
||||||
|
vod.setVodRemarks(remark);
|
||||||
|
vod.setTypeName(classifyName);
|
||||||
|
vod.setVodContent(ids.get(0));
|
||||||
|
vod.setVodPlayFrom("Qile");
|
||||||
|
vod.setVodPlayUrl(TextUtils.join("#", vodItems));
|
||||||
|
return Result.string(vod);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String searchContent(String key, boolean quick) throws Exception {
|
||||||
|
String searchUrl = siteUrl + "/search?q=" + Uri.encode(key) + "&f=all";
|
||||||
|
Document doc = Jsoup.parse(OkHttp.string(searchUrl, getHeader()));
|
||||||
|
List<Vod> list = new ArrayList<>();
|
||||||
|
for (Element li : doc.select(".item")) {
|
||||||
|
String vid = siteUrl + li.select("a").attr("href");
|
||||||
|
String name = li.select("a").attr("title");
|
||||||
|
String pic = li.select("img").attr("src");
|
||||||
|
list.add(new Vod(vid, name, pic));
|
||||||
|
}
|
||||||
|
return Result.string(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
|
||||||
|
return Result.get().url(id).header(getHeader()).string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,114 +1,84 @@
|
||||||
package com.github.catvod.spider;
|
package com.github.catvod.spider;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import com.github.catvod.bean.Class;
|
import com.github.catvod.bean.Class;
|
||||||
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.jianpian.Data;
|
import com.github.catvod.bean.jianpian.Data;
|
||||||
import com.github.catvod.bean.jianpian.Detail;
|
import com.github.catvod.bean.jianpian.Detail;
|
||||||
import com.github.catvod.bean.jianpian.Resp;
|
import com.github.catvod.bean.jianpian.Resp;
|
||||||
import com.github.catvod.bean.jianpian.Search;
|
|
||||||
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.google.gson.Gson;
|
import com.github.catvod.utils.Json;
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
|
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Qile
|
* Qile
|
||||||
*/
|
*/
|
||||||
public class Jianpian extends Spider {
|
public class Jianpian extends Spider {
|
||||||
|
|
||||||
private String siteUrl = "https://ev5356.970xw.com";
|
private final String siteUrl = "http://api2.rinhome.com";
|
||||||
private String imgDomain;
|
|
||||||
private String extend;
|
private String extend;
|
||||||
|
|
||||||
private Map<String, String> getHeader() {
|
private Map<String, String> getHeader() {
|
||||||
Map<String, String> headers = new HashMap<>();
|
Map<String, String> headers = new HashMap<>();
|
||||||
headers.put("User-Agent", "Mozilla/5.0 (Linux; Android 9; V2196A Build/PQ3A.190705.08211809; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/91.0.4472.114 Mobile Safari/537.36;webank/h5face;webank/1.0;netType:NETWORK_WIFI;appVersion:416;packageName:com.jp3.xg3");
|
headers.put("User-Agent", "jianpian-android/360");
|
||||||
headers.put("Referer", siteUrl);
|
headers.put("JPAUTH", "y261ow7kF2dtzlxh1GS9EB8nbTxNmaK/QQIAjctlKiEv");
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Context context, String extend) throws Exception {
|
public void init(Context context, String extend) throws Exception {
|
||||||
this.extend = extend;
|
this.extend = extend;
|
||||||
JsonObject domains = new Gson().fromJson(OkHttp.string("https://dns.alidns.com/resolve?name=swrdsfeiujo25sw.cc&type=TXT"), JsonObject.class);
|
|
||||||
String parts = domains.getAsJsonArray("Answer").get(0).getAsJsonObject().get("data").getAsString();
|
|
||||||
parts = parts.replace("\"", "");
|
|
||||||
String[] domain = parts.split(",");
|
|
||||||
for (String d : domain) {
|
|
||||||
siteUrl = "https://wangerniu." + d;
|
|
||||||
String json = OkHttp.string(siteUrl + "/api/appAuthConfig");
|
|
||||||
if (!json.isEmpty()) {
|
|
||||||
JsonObject root = new Gson().fromJson(json, JsonObject.class);
|
|
||||||
imgDomain = root.getAsJsonObject("data").get("imgDomain").getAsString();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String homeContent(boolean filter) throws Exception {
|
public String homeContent(boolean filter) throws Exception {
|
||||||
List<Class> classes = new ArrayList<>();
|
List<Class> classes = new ArrayList<>();
|
||||||
List<String> typeIds = Arrays.asList("1", "2", "3", "4", "50", "99");
|
List<String> typeIds = Arrays.asList("0", "1", "2", "3", "4");
|
||||||
List<String> typeNames = Arrays.asList("電影", "電視劇", "動漫", "綜藝", "紀錄片", "Netflix");
|
List<String> typeNames = Arrays.asList("全部", "电影", "电视剧", "动漫", "综艺");
|
||||||
for (int i = 0; i < typeIds.size(); i++) classes.add(new Class(typeIds.get(i), typeNames.get(i)));
|
for (int i = 0; i < typeIds.size(); i++) classes.add(new Class(typeIds.get(i), typeNames.get(i)));
|
||||||
return Result.string(classes, JsonParser.parseString(OkHttp.string(extend)));
|
return Result.string(classes, Json.parse(OkHttp.string(extend)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String homeVideoContent() {
|
public String homeVideoContent() {
|
||||||
List<Vod> list = new ArrayList<>();
|
List<Vod> list = new ArrayList<>();
|
||||||
String url = siteUrl + "/api/slide/list?pos_id=88";
|
String url = siteUrl + "/api/slide/list?code=unknown9039b6856c3a3306&pos_id=888&channel=wandoujia";
|
||||||
Resp resp = Resp.objectFrom(OkHttp.string(url, getHeader()));
|
Resp resp = Resp.objectFrom(OkHttp.string(url, getHeader()));
|
||||||
for (Data data : resp.getData()) list.add(data.homeVod(imgDomain));
|
for (Data data : resp.getData()) list.add(data.vod());
|
||||||
return Result.string(list);
|
return Result.string(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
|
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
|
||||||
if (tid.endsWith("/{pg}")) return searchContent(tid.split("/")[0], pg);
|
if (tid.endsWith("/{pg}")) return searchContent(tid.split("/")[0], pg);
|
||||||
if (tid.equals("50") || tid.equals("99") || tid.equals("111")) {
|
List<Vod> list = new ArrayList<>();
|
||||||
List<Vod> list = new ArrayList<>();
|
HashMap<String, String> ext = new HashMap<>();
|
||||||
String url = siteUrl + String.format("/api/dyTag/list?category_id=%s&page=%s", tid, pg);
|
if (extend != null && extend.size() > 0) ext.putAll(extend);
|
||||||
Resp resp = Resp.objectFrom(OkHttp.string(url, getHeader()));
|
String cateId = ext.get("cateId") == null ? tid : ext.get("cateId");
|
||||||
for (Data data : resp.getData()) for (Data dataList : data.getDataList()) list.add(dataList.vod(imgDomain));
|
String area = ext.get("area") == null ? "0" : ext.get("area");
|
||||||
return Result.get().page().vod(list).string();
|
String year = ext.get("year") == null ? "0" : ext.get("year");
|
||||||
} else {
|
String by = ext.get("by") == null ? "hot" : ext.get("by");
|
||||||
List<Vod> list = new ArrayList<>();
|
String url = siteUrl + String.format("/api/crumb/list?area=%s&category_id=%s&page=%s&type=0&limit=24&sort=%s&year=%s", area, cateId, pg, by, year);
|
||||||
HashMap<String, String> ext = new HashMap<>();
|
Resp resp = Resp.objectFrom(OkHttp.string(url, getHeader()));
|
||||||
if (extend != null && !extend.isEmpty()) ext.putAll(extend);
|
for (Data data : resp.getData()) list.add(data.vod());
|
||||||
String area = ext.get("area") == null ? "0" : ext.get("area");
|
return Result.string(Integer.parseInt(pg), Integer.parseInt(pg) + 1, 24, Integer.MAX_VALUE, list);
|
||||||
String year = ext.get("year") == null ? "0" : ext.get("year");
|
|
||||||
String by = ext.get("by") == null ? "updata" : ext.get("by");
|
|
||||||
String url = siteUrl + String.format("/api/crumb/list?fcate_pid=%s&area=%s&year=%s&type=0&sort=%s&page=%s&category_id=", tid, area, year, by, pg);
|
|
||||||
Resp resp = Resp.objectFrom(OkHttp.string(url, getHeader()));
|
|
||||||
for (Data data : resp.getData()) list.add(data.vod(imgDomain));
|
|
||||||
return Result.string(list);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String detailContent(List<String> ids) throws Exception {
|
public String detailContent(List<String> ids) throws Exception {
|
||||||
String url = siteUrl + "/api/video/detailv2?id=" + ids.get(0);
|
String url = siteUrl + "/api/node/detail?channel=wandoujia&token=&id=" + ids.get(0);
|
||||||
Data data = Detail.objectFrom(OkHttp.string(url, getHeader())).getData();
|
Data data = Detail.objectFrom(OkHttp.string(url, getHeader())).getData();
|
||||||
Vod vod = data.vod(imgDomain);
|
Vod vod = data.vod();
|
||||||
vod.setVodPlayFrom(data.getVodFrom());
|
vod.setVodPlayFrom("Jianpian");
|
||||||
vod.setVodYear(data.getYear());
|
vod.setVodYear(data.getYear());
|
||||||
vod.setVodArea(data.getArea());
|
vod.setVodArea(data.getArea());
|
||||||
vod.setTypeName(data.getTypes());
|
vod.setTypeName(data.getTypes());
|
||||||
vod.setVodActor(data.getActors());
|
vod.setVodActor(data.getActors());
|
||||||
vod.setVodPlayUrl(data.getVodUrl());
|
vod.setVodPlayUrl(data.getPlayUrl());
|
||||||
vod.setVodDirector(data.getDirectors());
|
vod.setVodDirector(data.getDirectors());
|
||||||
vod.setVodContent(data.getDescription());
|
vod.setVodContent(data.getDescription());
|
||||||
return Result.string(vod);
|
return Result.string(vod);
|
||||||
|
|
@ -131,9 +101,9 @@ public class Jianpian extends Spider {
|
||||||
|
|
||||||
public String searchContent(String key, String pg) throws Exception {
|
public String searchContent(String key, String pg) throws Exception {
|
||||||
List<Vod> list = new ArrayList<>();
|
List<Vod> list = new ArrayList<>();
|
||||||
String url = siteUrl + String.format("/api/v2/search/videoV2?key=%s&category_id=88&page=%s&pageSize=20", URLEncoder.encode(key), pg);
|
String url = siteUrl + "/api/video/search?page=" + pg + "&key=" + URLEncoder.encode(key);
|
||||||
Search search = Search.objectFrom(OkHttp.string(url, getHeader()));
|
Resp resp = Resp.objectFrom(OkHttp.string(url, getHeader()));
|
||||||
for (Search data : search.getData()) list.add(data.vod(imgDomain));
|
for (Data data : resp.getData()) list.add(data.vod());
|
||||||
return Result.string(list);
|
return Result.string(list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,90 +0,0 @@
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -55,7 +55,7 @@ public class Proxy extends Spider {
|
||||||
/*for (Map.Entry<String, String> entry : params.entrySet()) {
|
/*for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||||
if (!keys.contains(entry.getKey())) header.put(entry.getKey(), entry.getValue());
|
if (!keys.contains(entry.getKey())) header.put(entry.getKey(), entry.getValue());
|
||||||
}*/
|
}*/
|
||||||
return ProxyVideo.proxyMultiThread(url, header);
|
return ProxyVideo.proxy(url, header);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ 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;
|
||||||
|
|
@ -20,54 +19,31 @@ import java.util.List;
|
||||||
|
|
||||||
public class Push extends Spider {
|
public class Push extends Spider {
|
||||||
|
|
||||||
private Cloud cloud;
|
private final Ali ali;
|
||||||
|
|
||||||
public Push() {
|
public Push() {
|
||||||
cloud = new Cloud();
|
ali = new Ali();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Context context, String extend) {
|
public void init(Context context, String extend) {
|
||||||
try {
|
ali.init(context, extend);
|
||||||
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 {
|
||||||
String url = ids.get(0);
|
if (Ali.pattern.matcher(ids.get(0)).find()) return ali.detailContent(ids);
|
||||||
|
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 Result.get().url(id).string();
|
return ali.playerContent(flag, id, vipFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vod vod(String url) {
|
private Vod vod(String url) {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import com.github.catvod.bean.Result;
|
||||||
import com.github.catvod.bean.quark.ShareData;
|
import com.github.catvod.bean.quark.ShareData;
|
||||||
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 com.github.catvod.utils.Notify;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -54,12 +55,12 @@ public class Quark extends Spider {
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
for (int i = 1; i <= ids.size(); i++) {
|
for (int i = 1; i <= ids.size(); i++) {
|
||||||
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));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
playFrom.add("quark原画" + i + index);
|
||||||
}
|
}
|
||||||
return TextUtils.join("$$$", playFrom);
|
return TextUtils.join("$$$", playFrom);
|
||||||
}
|
}
|
||||||
|
|
@ -70,15 +71,14 @@ public class Quark extends Spider {
|
||||||
* @param ids share_link 集合
|
* @param ids share_link 集合
|
||||||
* @return 詳情內容視頻播放地址
|
* @return 詳情內容視頻播放地址
|
||||||
*/
|
*/
|
||||||
public String detailContentVodPlayUrl(List<String> ids) {
|
public String detailContentVodPlayUrl(List<String> ids) throws Exception {
|
||||||
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)==null?"":QuarkApi.get().getVod(shareData).getVodPlayUrl());
|
playUrl.add(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);
|
||||||
|
|
|
||||||
|
|
@ -1,192 +0,0 @@
|
||||||
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\":[]}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
package com.github.catvod.spider
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import com.github.catvod.bean.Class
|
|
||||||
import com.github.catvod.bean.Result
|
|
||||||
import com.github.catvod.bean.Vod
|
|
||||||
import com.github.catvod.net.OkHttp
|
|
||||||
import com.github.catvod.utils.Json
|
|
||||||
import com.github.catvod.utils.Util
|
|
||||||
import org.jsoup.Jsoup
|
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import java.net.URLEncoder
|
|
||||||
import java.nio.charset.Charset
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 电影云集
|
|
||||||
*
|
|
||||||
* @author lushunming
|
|
||||||
* @createdate 2024-12-03
|
|
||||||
*/
|
|
||||||
class ReBoYingShi : Cloud() {
|
|
||||||
private val siteUrl = "https://reboys.cn"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private val headerWithCookie: MutableMap<String?, String?>
|
|
||||||
get() {
|
|
||||||
val header: MutableMap<String?, String?> = HashMap<String?, String?>()
|
|
||||||
header.put("User-Agent", Util.CHROME)
|
|
||||||
|
|
||||||
return header
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(Exception::class)
|
|
||||||
override fun init(context: Context?, extend: String?) {
|
|
||||||
super.init(context, extend)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@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 searchPageURL = siteUrl + "/s/${URLEncoder.encode(key, Charset.defaultCharset().name())}.html"
|
|
||||||
val html = OkHttp.string(searchPageURL, this.headerWithCookie)
|
|
||||||
val apiToken = Util.findByRegex("const apiToken = \"(.*?)\";", html, 1)
|
|
||||||
|
|
||||||
val searchURL = siteUrl + "/search?keyword=${URLEncoder.encode(key, Charset.defaultCharset().name())}"
|
|
||||||
val header = headerWithCookie.toMutableMap()
|
|
||||||
header.put("API-TOKEN", apiToken)
|
|
||||||
val json = OkHttp.string(searchURL, header)
|
|
||||||
val jsonObj = Json.safeObject(json)
|
|
||||||
var vodList = emptyList<Vod>()
|
|
||||||
if (jsonObj.get("code").asInt == 0) {
|
|
||||||
val results = jsonObj.get("data").asJsonObject.get("data").asJsonObject.get("results").asJsonArray
|
|
||||||
vodList = results.map {
|
|
||||||
val title = it.asJsonObject.get("title").asString
|
|
||||||
val vodId = it.asJsonObject.get("links").asJsonArray[0].asJsonObject.get("url").asString
|
|
||||||
Vod(vodId, title, "", "")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Result.string(vodList)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,248 +0,0 @@
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,211 @@
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
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 Tg189Search : 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=cloud189_group,yunpan139,cloud189_group,cloudtianyi,kuakeclound,tianyirigeng,txtyzy,tyypzhpd,tyysypzypd,yunpan189&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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
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 TgQuarkSearch : 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=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, 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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.crawler.SpiderDebug;
|
||||||
|
import com.github.catvod.net.OkHttp;
|
||||||
|
import com.github.catvod.utils.Json;
|
||||||
|
import com.github.catvod.utils.Util;
|
||||||
|
import org.jsoup.Jsoup;
|
||||||
|
import org.jsoup.nodes.Document;
|
||||||
|
import org.jsoup.nodes.Element;
|
||||||
|
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhixc
|
||||||
|
*/
|
||||||
|
public class TgSearch extends Cloud {
|
||||||
|
|
||||||
|
private final String URL = "https://tg.252035.xyz/";
|
||||||
|
|
||||||
|
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 {
|
||||||
|
|
||||||
|
String url = URL + "?channelUsername=tianyirigeng,tyypzhpd,XiangxiuNB,yunpanpan,kuakeyun,zaihuayun,Quark_Movies,alyp_4K_Movies,vip115hot,yunpanshare,dianyingshare&keyword=" + URLEncoder.encode(key, Charset.defaultCharset().name());
|
||||||
|
List<Vod> list = new ArrayList<>();
|
||||||
|
String html = OkHttp.string(url, getHeader());
|
||||||
|
String[] arr = html.split(":I");
|
||||||
|
if (arr.length > 0) {
|
||||||
|
for (String s : arr) {
|
||||||
|
Document doc = Jsoup.parse(Util.findByRegex("链接(.*)", s, 1));
|
||||||
|
String id = doc.select(" a").attr("href");
|
||||||
|
String name = Util.findByRegex("名称(.*)描述", s, 1).replace(":","").replace(":","");
|
||||||
|
String desc = Util.findByRegex("描述(.*) 链接", s, 1).replace(":","").replace(":","");
|
||||||
|
|
||||||
|
list.add(new Vod(id, name, "", desc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return Result.string(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
package com.github.catvod.spider
|
|
||||||
|
|
||||||
import com.github.catvod.bean.Result
|
|
||||||
import com.github.catvod.bean.Vod
|
|
||||||
import com.github.catvod.net.OkHttp
|
|
||||||
import com.github.catvod.utils.Util
|
|
||||||
import org.jsoup.Jsoup
|
|
||||||
import java.net.URLEncoder
|
|
||||||
import java.nio.charset.Charset
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhixc
|
|
||||||
*/
|
|
||||||
class TgSearch : Cloud() {
|
|
||||||
private val URL = "https://tg.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=tianyirigeng,tyypzhpd,XiangxiuNB,yunpanpan,kuakeyun,zaihuayun,Quark_Movies,alyp_4K_Movies,vip115hot,yunpanshare,dianyingshare&pic=true&keyword=" + URLEncoder.encode(
|
|
||||||
key, Charset.defaultCharset().name()
|
|
||||||
)
|
|
||||||
val list: MutableList<Vod> = ArrayList()
|
|
||||||
val html = OkHttp.string(url, header)
|
|
||||||
val arr = html.split(":I".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
|
||||||
if (arr.size > 0) {
|
|
||||||
for (s in arr) {
|
|
||||||
val doc = Jsoup.parse(s)
|
|
||||||
val id = doc.select(" a").eachAttr("href")
|
|
||||||
.first { it.contains("189") || it.contains("139") || it.contains("quark") }
|
|
||||||
val name = doc.select("strong").text()
|
|
||||||
list.add(Vod(id, name, "", ""))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return Result.string(list)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,258 +0,0 @@
|
||||||
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 "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,258 +0,0 @@
|
||||||
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 "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,258 +0,0 @@
|
||||||
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 "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,258 +0,0 @@
|
||||||
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 TgSearchBaidu 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 "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,258 +0,0 @@
|
||||||
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 "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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) {
|
public String detailContentVodPlayUrl(List<String> ids) throws Exception {
|
||||||
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,7 +77,6 @@ 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);
|
||||||
|
|
|
||||||
|
|
@ -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,17 +71,11 @@ public class UC extends Spider {
|
||||||
* @param ids share_link 集合
|
* @param ids share_link 集合
|
||||||
* @return 詳情內容視頻播放地址
|
* @return 詳情內容視頻播放地址
|
||||||
*/
|
*/
|
||||||
public String detailContentVodPlayUrl(List<String> ids) {
|
public String detailContentVodPlayUrl(List<String> ids) throws Exception {
|
||||||
List<String> playUrl = new ArrayList<>();
|
List<String> playUrl = new ArrayList<>();
|
||||||
for (String id : ids) {
|
for (String id : ids) {
|
||||||
try {
|
ShareData shareData = UCApi.get().getShareData(id);
|
||||||
ShareData shareData = UCApi.get().getShareData(id);
|
playUrl.add(UCApi.get().getVod(shareData).getVodPlayUrl());
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,20 +49,7 @@ public class YiDongYun extends Spider {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
builder.append("移动(极速)", list);
|
builder.append("移动", list);
|
||||||
List<Vod.VodPlayBuilder.PlayUrl> list2 = new ArrayList<>();
|
|
||||||
|
|
||||||
for (String s : result.keySet()) {
|
|
||||||
vodName = s;
|
|
||||||
for (Map<String, String> stringStringMap : result.get(s)) {
|
|
||||||
Vod.VodPlayBuilder.PlayUrl playUrl = new Vod.VodPlayBuilder.PlayUrl();
|
|
||||||
playUrl.url = stringStringMap.get("path") + "++" + stringStringMap.get("linkID");
|
|
||||||
playUrl.name = stringStringMap.get("name");
|
|
||||||
list2.add(playUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
builder.append("移动(原画)", list2);
|
|
||||||
Vod.VodPlayBuilder.BuildResult buildResult = builder.build();
|
Vod.VodPlayBuilder.BuildResult buildResult = builder.build();
|
||||||
Vod vod = new Vod();
|
Vod vod = new Vod();
|
||||||
vod.setVodId(ids.get(0));
|
vod.setVodId(ids.get(0));
|
||||||
|
|
@ -78,8 +65,11 @@ public class YiDongYun extends Spider {
|
||||||
|
|
||||||
@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 {
|
||||||
|
String contentId = id.split("\\+\\+")[0];
|
||||||
return YunDrive.get().playerContent(id.split("\\+\\+"), flag);
|
String linkID = id.split("\\+\\+")[1];
|
||||||
|
String playContent = YunDrive.get().fetchPlayUrl(contentId, linkID);
|
||||||
|
SpiderDebug.log("playContent:" + playContent);
|
||||||
|
return Result.get().url(playContent).octet().string();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -93,10 +83,7 @@ public class YiDongYun extends Spider {
|
||||||
List<String> playFrom = new ArrayList<>();
|
List<String> playFrom = new ArrayList<>();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (String id : ids) {
|
for (String id : ids) {
|
||||||
i++;
|
playFrom.add("移动" + i++);
|
||||||
playFrom.add(String.format("移动(极速)#%2d", i));
|
|
||||||
playFrom.add(String.format("移动(原画)#%2d", i));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -109,17 +96,10 @@ public class YiDongYun extends Spider {
|
||||||
* @param ids share_link 集合
|
* @param ids share_link 集合
|
||||||
* @return 詳情內容視頻播放地址
|
* @return 詳情內容視頻播放地址
|
||||||
*/
|
*/
|
||||||
public String detailContentVodPlayUrl(List<String> ids) {
|
public String detailContentVodPlayUrl(List<String> ids) throws Exception {
|
||||||
List<String> playUrl = new ArrayList<>();
|
List<String> playUrl = new ArrayList<>();
|
||||||
for (String id : ids) {
|
for (String id : ids) {
|
||||||
try {
|
playUrl.add(getVod(List.of(id)).getVodPlayUrl());
|
||||||
playUrl.add(getVod(List.of(id)).getVodPlayUrl());
|
|
||||||
}catch (Exception e) {
|
|
||||||
SpiderDebug.log("获取播放地址出错:" + e.getMessage());
|
|
||||||
playUrl.add("");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return TextUtils.join("$$$", playUrl);
|
return TextUtils.join("$$$", playUrl);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -120,8 +120,6 @@ public class YunPanBa extends Cloud {
|
||||||
shareLinks.add(element.attr("href").trim());
|
shareLinks.add(element.attr("href").trim());
|
||||||
} else if (element.attr("href").matches(Util.patternAli)) {
|
} else if (element.attr("href").matches(Util.patternAli)) {
|
||||||
shareLinks.add(element.attr("href").trim());
|
shareLinks.add(element.attr("href").trim());
|
||||||
} else if (element.attr("href").startsWith(BaiDuPan.URL_START)) {
|
|
||||||
shareLinks.add(element.attr("href").trim());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,362 +0,0 @@
|
||||||
package com.github.catvod.utils
|
|
||||||
|
|
||||||
import com.github.catvod.crawler.SpiderDebug
|
|
||||||
import java.io.BufferedOutputStream
|
|
||||||
import java.io.BufferedReader
|
|
||||||
import java.io.IOException
|
|
||||||
import java.io.InputStreamReader
|
|
||||||
import java.net.ServerSocket
|
|
||||||
import java.net.Socket
|
|
||||||
import java.net.URLDecoder
|
|
||||||
import java.util.concurrent.ExecutorService
|
|
||||||
import java.util.concurrent.Executors
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
|
||||||
import kotlin.text.Charsets.UTF_8
|
|
||||||
|
|
||||||
class AdvancedHttpServer(private val port: Int) {
|
|
||||||
private val serverSocket: ServerSocket
|
|
||||||
private val threadPool: ExecutorService
|
|
||||||
private var isRunning = false
|
|
||||||
private val routes = mutableMapOf<String, (Request, Response) -> Unit>()
|
|
||||||
|
|
||||||
init {
|
|
||||||
serverSocket = ServerSocket(port)
|
|
||||||
threadPool = Executors.newFixedThreadPool(10)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addRoutes(path: String, handler: (Request, Response) -> Unit) {
|
|
||||||
routes[path] = handler
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun start() {
|
|
||||||
isRunning = true
|
|
||||||
SpiderDebug.log("服务器已启动,监听端口: $port")
|
|
||||||
|
|
||||||
while (isRunning) {
|
|
||||||
try {
|
|
||||||
val clientSocket = serverSocket.accept()
|
|
||||||
threadPool.execute { handleRequest(clientSocket) }
|
|
||||||
} catch (e: IOException) {
|
|
||||||
e.printStackTrace();SpiderDebug.log("出错:" + e.message)
|
|
||||||
if (isRunning) e.printStackTrace();SpiderDebug.log("出错:" + e.message)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleRequest(clientSocket: Socket) {
|
|
||||||
try {
|
|
||||||
val reader = BufferedReader(InputStreamReader(clientSocket.inputStream, UTF_8))
|
|
||||||
val writer = BufferedOutputStream(clientSocket.outputStream)
|
|
||||||
|
|
||||||
// 解析请求行
|
|
||||||
val requestLine = reader.readLine() ?: ""
|
|
||||||
SpiderDebug.log("requestLine: $requestLine")
|
|
||||||
|
|
||||||
val (method, path, _) = parseRequestLine(requestLine)
|
|
||||||
|
|
||||||
// 解析路径和查询参数
|
|
||||||
val (basePath, queryParams) = parsePath(path)
|
|
||||||
|
|
||||||
// 读取请求头
|
|
||||||
val headers = mutableMapOf<String, String>()
|
|
||||||
var line: String?
|
|
||||||
while (reader.readLine().also { line = it } != null && line!!.isNotEmpty()) {
|
|
||||||
val colonIndex = line!!.indexOf(':')
|
|
||||||
if (colonIndex > 0) {
|
|
||||||
headers[line!!.substring(0, colonIndex).trim()] =
|
|
||||||
line!!.substring(colonIndex + 1).trim()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析请求体参数
|
|
||||||
val contentLength = headers["Content-Length"]?.toIntOrNull() ?: 0
|
|
||||||
val requestBody = if (contentLength > 0) {
|
|
||||||
buildString {
|
|
||||||
repeat(contentLength) {
|
|
||||||
val char = reader.read().takeIf { it != -1 }?.toChar() ?: return@buildString
|
|
||||||
append(char)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else ""
|
|
||||||
|
|
||||||
val contentType = headers["Content-Type"] ?: ""
|
|
||||||
val bodyParams = parseRequestBody(contentType, requestBody)
|
|
||||||
|
|
||||||
// 创建请求对象
|
|
||||||
val request = Request(
|
|
||||||
method = method,
|
|
||||||
path = basePath,
|
|
||||||
queryParams = queryParams,
|
|
||||||
headers = headers,
|
|
||||||
body = requestBody,
|
|
||||||
bodyParams = bodyParams
|
|
||||||
)
|
|
||||||
|
|
||||||
// 创建响应处理器
|
|
||||||
val response = Response(writer)
|
|
||||||
|
|
||||||
// 路由处理
|
|
||||||
routeRequest(request, response)
|
|
||||||
|
|
||||||
response.flush()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
e.printStackTrace()
|
|
||||||
SpiderDebug.log("出错:" + e.message)
|
|
||||||
} finally {
|
|
||||||
clientSocket.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun routeRequest(request: Request, response: Response) {
|
|
||||||
val route = routes[request.path]
|
|
||||||
if (route == null) {
|
|
||||||
handleNotFound(response)
|
|
||||||
} else {
|
|
||||||
route.invoke(request, response)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleRoot(request: Request, response: Response) {
|
|
||||||
response.setContentType("text/html")
|
|
||||||
response.start()
|
|
||||||
|
|
||||||
response.write("<html><body>")
|
|
||||||
response.write("<h1>高级HTTP服务器</h1>")
|
|
||||||
response.write("<p>支持参数解析和分块响应</p>")
|
|
||||||
response.write("<h2>功能演示</h2>")
|
|
||||||
response.write("<ul>")
|
|
||||||
response.write("<li><a href=\"/echo?param1=value1¶m2=value2\">Echo参数</a></li>")
|
|
||||||
response.write("<li><a href=\"/stream\">流式响应</a></li>")
|
|
||||||
response.write("<li><a href=\"/slow\">服务器推送事件</a></li>")
|
|
||||||
response.write("</ul>")
|
|
||||||
|
|
||||||
// 演示表单提交
|
|
||||||
response.write("<h2>表单提交测试</h2>")
|
|
||||||
response.write("<form action=\"/echo\" method=\"post\">")
|
|
||||||
response.write("Name: <input type=\"text\" name=\"name\"><br>")
|
|
||||||
response.write("Age: <input type=\"number\" name=\"age\"><br>")
|
|
||||||
response.write("<input type=\"submit\" value=\"提交\">")
|
|
||||||
response.write("</form>")
|
|
||||||
|
|
||||||
response.write("</body></html>")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleEcho(request: Request, response: Response) {
|
|
||||||
response.setContentType("text/html")
|
|
||||||
response.start()
|
|
||||||
|
|
||||||
response.write("<html><body>")
|
|
||||||
response.write("<h1>Echo服务</h1>")
|
|
||||||
|
|
||||||
// 输出请求信息
|
|
||||||
response.write("<h2>请求信息</h2>")
|
|
||||||
response.write("<p>方法: ${request.method}</p>")
|
|
||||||
response.write("<p>路径: ${request.path}</p>")
|
|
||||||
|
|
||||||
// 输出查询参数
|
|
||||||
response.write("<h2>查询参数</h2>")
|
|
||||||
response.write("<ul>")
|
|
||||||
if (request.queryParams.isEmpty()) {
|
|
||||||
response.write("<li>无</li>")
|
|
||||||
} else {
|
|
||||||
request.queryParams.forEach { (key, value) ->
|
|
||||||
response.write("<li>$key: $value</li>")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response.write("</ul>")
|
|
||||||
|
|
||||||
// 输出请求头
|
|
||||||
response.write("<h2>请求头</h2>")
|
|
||||||
response.write("<ul>")
|
|
||||||
request.headers.forEach { (key, value) ->
|
|
||||||
response.write("<li>$key: $value</li>")
|
|
||||||
}
|
|
||||||
response.write("</ul>")
|
|
||||||
|
|
||||||
// 输出请求体
|
|
||||||
response.write("<h2>请求体</h2>")
|
|
||||||
response.write("<pre>${request.body}</pre>")
|
|
||||||
|
|
||||||
// 输出解析后的参数
|
|
||||||
response.write("<h2>解析后的参数</h2>")
|
|
||||||
response.write("<ul>")
|
|
||||||
if (request.bodyParams.isEmpty()) {
|
|
||||||
response.write("<li>无</li>")
|
|
||||||
} else {
|
|
||||||
request.bodyParams.forEach { (key, value) ->
|
|
||||||
response.write("<li>$key: $value</li>")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response.write("</ul>")
|
|
||||||
|
|
||||||
response.write("</body></html>")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleStreamResponse(response: Response) {
|
|
||||||
response.setContentType("text/plain")
|
|
||||||
response.start()
|
|
||||||
|
|
||||||
for (i in 1..5) {
|
|
||||||
response.write("这是第 $i 部分内容\n")
|
|
||||||
Thread.sleep(500)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleSlowResponse(response: Response) {
|
|
||||||
response.setContentType("text/event-stream")
|
|
||||||
response.setHeader("Cache-Control", "no-cache")
|
|
||||||
response.setHeader("Connection", "keep-alive")
|
|
||||||
response.start()
|
|
||||||
|
|
||||||
for (i in 1..10) {
|
|
||||||
response.write("data: 消息 $i\n\n")
|
|
||||||
response.flush()
|
|
||||||
Thread.sleep(1000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleNotFound(response: Response) {
|
|
||||||
response.setStatusCode(404)
|
|
||||||
response.setContentType("text/html")
|
|
||||||
response.start()
|
|
||||||
response.write("<html><body><h1>404 Not Found</h1></body></html>")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseRequestLine(requestLine: String): Triple<String, String, String> {
|
|
||||||
val parts = requestLine.split(" ", limit = 3)
|
|
||||||
return when {
|
|
||||||
parts.size >= 3 -> Triple(parts[0], parts[1], parts[2])
|
|
||||||
parts.size == 2 -> Triple(parts[0], parts[1], "HTTP/1.1")
|
|
||||||
else -> Triple("GET", "/", "HTTP/1.1")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parsePath(path: String): Pair<String, Map<String, String>> {
|
|
||||||
val queryIndex = path.indexOf('?')
|
|
||||||
return if (queryIndex >= 0) {
|
|
||||||
Pair(path.substring(0, queryIndex), parseQueryString(path.substring(queryIndex + 1)))
|
|
||||||
} else {
|
|
||||||
Pair(path, emptyMap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseQueryString(queryString: String): Map<String, String> {
|
|
||||||
return queryString.split("&").filter { it.isNotEmpty() }.map { param ->
|
|
||||||
val equalsIndex = param.indexOf('=')
|
|
||||||
if (equalsIndex >= 0) {
|
|
||||||
val key = URLDecoder.decode(param.substring(0, equalsIndex), "UTF-8")
|
|
||||||
val value = URLDecoder.decode(param.substring(equalsIndex + 1), "UTF-8")
|
|
||||||
key to value
|
|
||||||
} else {
|
|
||||||
URLDecoder.decode(param, "UTF-8") to ""
|
|
||||||
}
|
|
||||||
}.toMap()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseRequestBody(contentType: String, body: String): Map<String, String> {
|
|
||||||
return when {
|
|
||||||
contentType.contains("application/x-www-form-urlencoded") -> parseQueryString(body)
|
|
||||||
|
|
||||||
contentType.contains("multipart/form-data") -> parseMultipartFormData(contentType, body)
|
|
||||||
|
|
||||||
else -> emptyMap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseMultipartFormData(contentType: String, body: String): Map<String, String> {
|
|
||||||
// 简化的multipart/form-data解析,实际实现需要处理boundary等
|
|
||||||
return emptyMap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun stop() {
|
|
||||||
isRunning = false
|
|
||||||
threadPool.shutdown()
|
|
||||||
serverSocket.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
data class Request(
|
|
||||||
val method: String,
|
|
||||||
val path: String,
|
|
||||||
val queryParams: Map<String, String>,
|
|
||||||
val headers: Map<String, String>,
|
|
||||||
val body: String,
|
|
||||||
val bodyParams: Map<String, String>
|
|
||||||
)
|
|
||||||
|
|
||||||
class Response(private val writer: BufferedOutputStream) {
|
|
||||||
private val headers = mutableMapOf<String, String>()
|
|
||||||
private var contentType = "text/plain"
|
|
||||||
private var statusCode = 200
|
|
||||||
private var started = AtomicBoolean(false)
|
|
||||||
|
|
||||||
fun setContentType(contentType: String) {
|
|
||||||
this.contentType = contentType
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setHeader(name: String, value: String) {
|
|
||||||
headers[name] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setStatusCode(statusCode: Int) {
|
|
||||||
this.statusCode = statusCode
|
|
||||||
}
|
|
||||||
|
|
||||||
private val codeMap = mutableMapOf<Int, String>(
|
|
||||||
206 to "Partial Content",
|
|
||||||
200 to "OK",
|
|
||||||
404 to "NOT FOUND",
|
|
||||||
400 to "BAD REQUEST",
|
|
||||||
401 to "UNAUTHORIZED",
|
|
||||||
403 to "FORBIDDEN",
|
|
||||||
405 to "METHOD NOT ALLOWED",
|
|
||||||
408 to "REQUEST TIMEOUT",
|
|
||||||
413 to "PAYLOAD TOO LARGE",
|
|
||||||
414 to "URI TOO LONG",
|
|
||||||
415 to "UNSUPPORTED MEDIA TYPE",
|
|
||||||
429 to "TOO MANY REQUESTS",
|
|
||||||
500 to "INTERNAL SERVER ERROR",
|
|
||||||
501 to "NOT IMPLEMENTED",
|
|
||||||
503 to "SERVICE UNAVAILABLE",
|
|
||||||
504 to "GATEWAY TIMEOUT",
|
|
||||||
505 to "HTTP VERSION NOT SUPPORTED",
|
|
||||||
507 to "INSUFFICIENT STORAGE",
|
|
||||||
511 to "NETWORK AUTHENTICATION REQUIRED"
|
|
||||||
)
|
|
||||||
|
|
||||||
fun start() {
|
|
||||||
if (started.compareAndSet(false, true)) {
|
|
||||||
writer.write("HTTP/1.1 $statusCode ${codeMap[statusCode]}\r\n".toByteArray(UTF_8))
|
|
||||||
|
|
||||||
writer.write("Content-Type: $contentType; charset=utf-8\r\n".toByteArray(UTF_8))
|
|
||||||
|
|
||||||
headers.forEach { (name, value) ->
|
|
||||||
writer.write("$name: $value\r\n".toByteArray(UTF_8))
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.write("\r\n".toByteArray(UTF_8))
|
|
||||||
writer.flush()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun write(content: ByteArray) {
|
|
||||||
if (!started.get()) {
|
|
||||||
start()
|
|
||||||
}
|
|
||||||
writer.write(content)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun write(content: String) {
|
|
||||||
if (!started.get()) {
|
|
||||||
start()
|
|
||||||
}
|
|
||||||
writer.write(content.toByteArray(UTF_8))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun flush() {
|
|
||||||
writer.flush()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
package com.github.catvod.utils;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class DownloadInfo {
|
|
||||||
|
|
||||||
private List<long[]> parts;
|
|
||||||
private String url;
|
|
||||||
|
|
||||||
public List<long[]> getParts() {
|
|
||||||
return parts;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setParts(List<long[]> parts) {
|
|
||||||
this.parts = parts;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUrl() {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUrl(String url) {
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,173 +0,0 @@
|
||||||
package com.github.catvod.utils
|
|
||||||
|
|
||||||
import com.github.catvod.crawler.SpiderDebug
|
|
||||||
import com.github.catvod.net.OkHttp
|
|
||||||
import com.github.catvod.utils.ProxyVideo.getMimeType
|
|
||||||
import com.github.catvod.utils.ProxyVideo.parseRange
|
|
||||||
import kotlinx.coroutines.*
|
|
||||||
import okhttp3.Response
|
|
||||||
import org.apache.commons.lang3.StringUtils
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.io.SequenceInputStream
|
|
||||||
import java.util.*
|
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
object DownloadMT {
|
|
||||||
private val THREAD_NUM: Int = 16
|
|
||||||
|
|
||||||
private val infos = mutableMapOf<String, Array<Any>>();
|
|
||||||
|
|
||||||
fun proxyMultiThread(url: String, headers: Map<String, String>): Array<out Any?>? = runBlocking {
|
|
||||||
proxyAsync(url, headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取是否分片信息,顺带请求一个1MB块
|
|
||||||
*/
|
|
||||||
@Throws(java.lang.Exception::class)
|
|
||||||
fun getInfo(url: String?, headers: Map<String, String>): Array<Any> {
|
|
||||||
val newHeaders: MutableMap<String, String> = java.util.HashMap(headers)
|
|
||||||
newHeaders["Range"] = "bytes=0-" + (1024 * 1024 - 1)
|
|
||||||
newHeaders["range"] = "bytes=0-" + (1024 * 1024 - 1)
|
|
||||||
val info = ProxyVideo.proxy(url, newHeaders)
|
|
||||||
return info
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun proxyAsync(url: String, headers: Map<String, String>): Array<out Any?>? {
|
|
||||||
|
|
||||||
/* val service = Executors.newFixedThreadPool(THREAD_NUM)*/
|
|
||||||
SpiderDebug.log("--proxyMultiThread: THREAD_NUM: $THREAD_NUM")
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
//缓存,避免每次都请求total等信息
|
|
||||||
var info = infos[url]
|
|
||||||
//第一次请求,请求是否支持range,顺带返回一个1MB块
|
|
||||||
if (info == null) {
|
|
||||||
infos.clear()
|
|
||||||
info = CoroutineScope(Dispatchers.IO).async { getInfo(url, headers) }.await()
|
|
||||||
infos[url] = info/* //支持分片,先返回这个1MB块
|
|
||||||
if (info[0] as Int == 206) {
|
|
||||||
return info
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
val code = info[0] as Int
|
|
||||||
SpiderDebug.log("-----------code:$code")
|
|
||||||
|
|
||||||
if (code != 206) {
|
|
||||||
return ProxyVideo.proxy(url, headers)
|
|
||||||
}
|
|
||||||
val resHeader = info[3] as MutableMap<String, String>
|
|
||||||
val contentRange =
|
|
||||||
if (StringUtils.isAllBlank(resHeader["Content-Range"])) resHeader["content-range"] else resHeader["Content-Range"]
|
|
||||||
|
|
||||||
SpiderDebug.log("--contentRange:$contentRange")
|
|
||||||
//文件总大小
|
|
||||||
val total = StringUtils.split(contentRange, "/")[1]
|
|
||||||
SpiderDebug.log("--文件总大小:$total")
|
|
||||||
|
|
||||||
//如果文件太小,也不走代理
|
|
||||||
/* if (total.toLong() < 1024 * 1024 * 100) {
|
|
||||||
return proxy(url, headers)
|
|
||||||
}*/
|
|
||||||
var range = if (StringUtils.isAllBlank(headers["range"])) headers["Range"] else headers["range"]
|
|
||||||
if (StringUtils.isAllBlank(range)) range = "bytes=0-";
|
|
||||||
SpiderDebug.log("---proxyMultiThread,Range:$range")
|
|
||||||
val rangeObj = parseRange(
|
|
||||||
range!!
|
|
||||||
)
|
|
||||||
//没有range,无需分割
|
|
||||||
|
|
||||||
val partList = generatePart(rangeObj, total)
|
|
||||||
|
|
||||||
// 存储执行结果的List
|
|
||||||
val jobs = mutableListOf<Deferred<InputStream>>()
|
|
||||||
val inputStreams = mutableListOf<InputStream>()
|
|
||||||
for ((index, part) in partList.withIndex()) {
|
|
||||||
|
|
||||||
|
|
||||||
val newRange = "bytes=" + part[0] + "-" + part[1]
|
|
||||||
val headerNew: MutableMap<String, String> = HashMap(headers)
|
|
||||||
|
|
||||||
headerNew["range"] = newRange
|
|
||||||
headerNew["Range"] = newRange
|
|
||||||
jobs += CoroutineScope(Dispatchers.IO).async {
|
|
||||||
val res = downloadRange(url, headerNew)
|
|
||||||
SpiderDebug.log(
|
|
||||||
("---第" + index + "块下载完成" + ";Content-Range:" + (res?.headers())?.get(
|
|
||||||
"Content-Range"
|
|
||||||
))
|
|
||||||
)
|
|
||||||
res?.body()!!.byteStream()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inputStreams += jobs.awaitAll()
|
|
||||||
|
|
||||||
var contentType: String? = ""
|
|
||||||
|
|
||||||
|
|
||||||
// SpiderDebug.log(" ++proxy res data:" + Json.toJson(response.body()));
|
|
||||||
contentType = resHeader["Content-Type"]
|
|
||||||
if (StringUtils.isAllBlank(contentType)) {
|
|
||||||
contentType = resHeader["content-type"]
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isAllBlank(contentType) && StringUtils.isNoneBlank(resHeader["Content-Disposition"])) {
|
|
||||||
contentType = getMimeType(resHeader["Content-Disposition"])
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* respHeaders.put("Access-Control-Allow-Credentials", "true");
|
|
||||||
respHeaders.put("Access-Control-Allow-Origin", "*");*/
|
|
||||||
resHeader["Content-Length"] = (partList[THREAD_NUM - 1][1] - partList[0][0] + 1).toString()
|
|
||||||
resHeader.remove("content-length")
|
|
||||||
|
|
||||||
resHeader["Content-Range"] = String.format(
|
|
||||||
"bytes %s-%s/%s", partList[0][0], partList[THREAD_NUM - 1][1], total
|
|
||||||
)
|
|
||||||
resHeader.remove("content-range")
|
|
||||||
|
|
||||||
SpiderDebug.log("----proxy res contentType:$contentType")
|
|
||||||
// SpiderDebug.log("++proxy res body:" + response.body());
|
|
||||||
SpiderDebug.log("----proxy res respHeaders:" + Json.toJson(resHeader))
|
|
||||||
|
|
||||||
return arrayOf(
|
|
||||||
206, contentType, SequenceInputStream(Vector(inputStreams).elements()), resHeader
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
SpiderDebug.log("proxyMultiThread error:" + e.message)
|
|
||||||
e.printStackTrace()
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun generatePart(rangeObj: Map<String?, String>, total: String): List<LongArray> {
|
|
||||||
val totalSize = total.toLong()
|
|
||||||
//超过10GB,分块是32Mb,不然是16MB
|
|
||||||
val partSize = if (totalSize > 1024L * 1024L * 1024L * 10L) 1024 * 1024 * 8 * 4L else 1024 * 1024 * 8 * 2L
|
|
||||||
|
|
||||||
var start = rangeObj["start"]!!.toLong()
|
|
||||||
var end = if (StringUtils.isAllBlank(rangeObj["end"])) start + partSize else rangeObj["end"]!!.toLong()
|
|
||||||
|
|
||||||
|
|
||||||
end = min(end.toDouble(), (totalSize - 1).toDouble()).toLong()
|
|
||||||
val length = end - start + 1
|
|
||||||
|
|
||||||
val size = length / THREAD_NUM
|
|
||||||
val partList: MutableList<LongArray> = ArrayList()
|
|
||||||
for (i in 0..<THREAD_NUM) {
|
|
||||||
val partEnd = min((start + size).toDouble(), end.toDouble()).toLong()
|
|
||||||
|
|
||||||
partList.add(longArrayOf(start, partEnd))
|
|
||||||
start = partEnd + 1
|
|
||||||
}
|
|
||||||
return partList
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun downloadRange(
|
|
||||||
url: String, headerNew: MutableMap<String, String>
|
|
||||||
): Response? = OkHttp.newCall(url, headerNew)
|
|
||||||
}
|
|
||||||
|
|
@ -1,168 +0,0 @@
|
||||||
package com.github.catvod.utils;
|
|
||||||
|
|
||||||
|
|
||||||
import com.github.catvod.crawler.SpiderDebug;
|
|
||||||
import com.github.catvod.net.OkHttp;
|
|
||||||
import okhttp3.Response;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
public class DownloadService {
|
|
||||||
private static final int THREAD_NUM = 16;
|
|
||||||
//最小分片,按这个下载
|
|
||||||
private static final int PER_PIECE = 1024 * 1024;
|
|
||||||
//按照这个分割视频,每一个部分多线程下载,下载完下载下一个部分
|
|
||||||
private static final int PER_PART = 1024 * 1024 * THREAD_NUM;
|
|
||||||
private List<Future<Response>> results = new ArrayList<Future<Response>>();
|
|
||||||
private RandomAccessFile file = null;
|
|
||||||
private List<long[]> parts;
|
|
||||||
private AtomicInteger index = new AtomicInteger(0);
|
|
||||||
|
|
||||||
private static class Loader {
|
|
||||||
static volatile DownloadService INSTANCE = new DownloadService();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DownloadService get() {
|
|
||||||
return DownloadService.Loader.INSTANCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下载链接
|
|
||||||
*/
|
|
||||||
private String url;
|
|
||||||
/**
|
|
||||||
* 下载信息
|
|
||||||
*/
|
|
||||||
private DownloadInfo downloadInfo;
|
|
||||||
|
|
||||||
|
|
||||||
public void submitDownload(String url, Map<String, String> headers, long length) {
|
|
||||||
if (url.equals(this.url)) {
|
|
||||||
SpiderDebug.log("url相同,任务已存在");
|
|
||||||
} else {
|
|
||||||
this.url = url;
|
|
||||||
parts = generatePart(length);
|
|
||||||
downloadInfo = new DownloadInfo();
|
|
||||||
downloadInfo.setParts(parts);
|
|
||||||
downloadInfo.setUrl(url);
|
|
||||||
new Thread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
ExecutorService service = Executors.newFixedThreadPool(THREAD_NUM);
|
|
||||||
|
|
||||||
for (long[] part : parts) {
|
|
||||||
String newRange = "bytes=" + part[0] + "-" + part[1];
|
|
||||||
SpiderDebug.log("下载开始" + ";newRange:" + newRange);
|
|
||||||
|
|
||||||
Map<String, String> headerNew = new HashMap<>(headers);
|
|
||||||
|
|
||||||
headerNew.put("range", newRange);
|
|
||||||
headerNew.put("Range", newRange);
|
|
||||||
Future<Response> result = service.submit(() -> {
|
|
||||||
try {
|
|
||||||
part[2] = 1;
|
|
||||||
return OkHttp.newCall(url, headerNew);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
results.add(result);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
file = new RandomAccessFile(Path.tv() + File.separator + Util.MD5(url) + ".mp4", "rw");
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
SpiderDebug.log("创建文件失败");
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
while (index.get() < results.size()) {
|
|
||||||
Response response = null;
|
|
||||||
try {
|
|
||||||
response = results.get(index.get()).get();
|
|
||||||
file.seek(parts.get(index.get())[0]);
|
|
||||||
file.write(response.body().bytes());
|
|
||||||
index.addAndGet(1);
|
|
||||||
} catch (ExecutionException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
service.shutdown();
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回信息
|
|
||||||
*
|
|
||||||
* @param start 开始
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Object[] getDownloadBytes(long start) throws ExecutionException, InterruptedException {
|
|
||||||
long partIndex = start / PER_PART;
|
|
||||||
|
|
||||||
while (parts.get((int) partIndex)[2] == 0) {
|
|
||||||
index.set((int) partIndex);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
file.seek(start);
|
|
||||||
byte[] bytes = new byte[Math.toIntExact(parts.get((int) partIndex)[1] - start + 1)];
|
|
||||||
file.read(bytes);
|
|
||||||
return new Object[]{bytes,start,parts.get((int) partIndex)[1] };
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分割为需要下载的部分
|
|
||||||
*
|
|
||||||
* @param total 文件总大小
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private static List<long[]> generatePart(long total) {
|
|
||||||
SpiderDebug.log("generatePart.total:" + total);
|
|
||||||
|
|
||||||
long start = 0;
|
|
||||||
long end = total - 1;
|
|
||||||
|
|
||||||
//分割为多少个部分
|
|
||||||
long size = total / PER_PART;
|
|
||||||
SpiderDebug.log("generatePart.size:" + size);
|
|
||||||
List<long[]> partList = new ArrayList<>();
|
|
||||||
for (int i = 0; i < size * THREAD_NUM; i++) {
|
|
||||||
long partEnd = Math.min(start + PER_PIECE, end);
|
|
||||||
|
|
||||||
partList.add(new long[]{start, partEnd, 0});
|
|
||||||
start = partEnd + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//最后多出分为一块下载
|
|
||||||
if (start <= end) {
|
|
||||||
partList.add(new long[]{start, end, 0});
|
|
||||||
}
|
|
||||||
return partList;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,525 +0,0 @@
|
||||||
package com.github.catvod.utils
|
|
||||||
|
|
||||||
import com.github.catvod.crawler.SpiderDebug
|
|
||||||
import com.github.catvod.net.OkHttp
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.channels.Channel
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
|
|
||||||
|
|
||||||
object ProxyServer {
|
|
||||||
private val THREAD_NUM = Runtime.getRuntime().availableProcessors()
|
|
||||||
private val partSize = 1024 * 1024
|
|
||||||
private var port = 12345
|
|
||||||
private var httpServer: AdvancedHttpServer? = null
|
|
||||||
private val infos = mutableMapOf<String, MutableMap<String, MutableList<String>>>();
|
|
||||||
private val urlMap = mutableMapOf<String, String>();
|
|
||||||
private val headerMap = mutableMapOf<String, Map<String, String>>();
|
|
||||||
|
|
||||||
|
|
||||||
fun stop() {
|
|
||||||
httpServer?.stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun start() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
try {
|
|
||||||
httpServer = AdvancedHttpServer(port)
|
|
||||||
httpServer?.addRoutes("/") { _, response ->
|
|
||||||
run {
|
|
||||||
response.setContentType("text/html")
|
|
||||||
response.start()
|
|
||||||
response.write("Hello, world!")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
httpServer?.addRoutes("/proxy") { req, response ->
|
|
||||||
try {
|
|
||||||
run {
|
|
||||||
val key = req.queryParams["key"];
|
|
||||||
val url = urlMap[key]
|
|
||||||
val header = headerMap[key]
|
|
||||||
|
|
||||||
if (url != null && header != null) {
|
|
||||||
proxyAsync(url, header, req, response)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
SpiderDebug.log("代理视频出错:" + e.message)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
httpServer?.start()
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
SpiderDebug.log("启动服务出错:" + e.message)
|
|
||||||
|
|
||||||
port++
|
|
||||||
httpServer?.stop()
|
|
||||||
}
|
|
||||||
} while (port < 20000)
|
|
||||||
SpiderDebug.log("启动服务 on $port")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun proxyAsync(
|
|
||||||
url: String,
|
|
||||||
headers: Map<String, String>,
|
|
||||||
request: AdvancedHttpServer.Request,
|
|
||||||
response: AdvancedHttpServer.Response
|
|
||||||
) {
|
|
||||||
runBlocking {
|
|
||||||
val channels = List(THREAD_NUM) { Channel<ByteArray>() }
|
|
||||||
SpiderDebug.log("--proxyAsync url: $url")
|
|
||||||
SpiderDebug.log("--proxyAsync headers: ${Json.toJson(headers)}")
|
|
||||||
|
|
||||||
try {
|
|
||||||
SpiderDebug.log("--proxyMultiThread: THREAD_NUM: $THREAD_NUM")
|
|
||||||
|
|
||||||
|
|
||||||
var rangeHeader = request.headers["Range"]
|
|
||||||
//没有range头
|
|
||||||
if (rangeHeader.isNullOrEmpty()) {
|
|
||||||
// 处理初始请求
|
|
||||||
rangeHeader = "bytes=0-"
|
|
||||||
}
|
|
||||||
headers.toMutableMap().apply {
|
|
||||||
put("Range", rangeHeader)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析范围请求
|
|
||||||
val (startPoint, endPoint) = parseRangePoint(
|
|
||||||
rangeHeader
|
|
||||||
)
|
|
||||||
|
|
||||||
//缓存response header
|
|
||||||
var info = infos[url]
|
|
||||||
if (info == null) {
|
|
||||||
info = getInfo(url, headers)
|
|
||||||
infos[url] = info
|
|
||||||
}
|
|
||||||
|
|
||||||
SpiderDebug.log("startPoint: $startPoint; endPoint: $endPoint")
|
|
||||||
val contentLength = getContentLength(info)
|
|
||||||
SpiderDebug.log("contentLength: $contentLength")
|
|
||||||
val finalEndPoint = if (endPoint == -1L) contentLength - 1 else endPoint
|
|
||||||
response.setContentType("text/html")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
response.setHeader("Connection", "keep-alive")
|
|
||||||
response.setHeader(
|
|
||||||
"Content-Length", (finalEndPoint - startPoint + 1).toString()
|
|
||||||
)
|
|
||||||
response.setHeader(
|
|
||||||
"Content-Range", "bytes $startPoint-$finalEndPoint/$contentLength"
|
|
||||||
)
|
|
||||||
info["Content-Type"]?.get(0)?.let { response.setHeader("Content-Type", it) }
|
|
||||||
|
|
||||||
response.setStatusCode(206)
|
|
||||||
response.start()
|
|
||||||
// 使用流式响应
|
|
||||||
|
|
||||||
var currentStart = startPoint
|
|
||||||
|
|
||||||
|
|
||||||
// 启动生产者协程下载数据
|
|
||||||
|
|
||||||
val producerJob = mutableListOf<Job>()
|
|
||||||
|
|
||||||
while (currentStart <= finalEndPoint) {
|
|
||||||
producerJob.clear()
|
|
||||||
// 创建通道用于接收数据块
|
|
||||||
|
|
||||||
for (i in 0 until THREAD_NUM) {
|
|
||||||
|
|
||||||
if (currentStart > finalEndPoint) break
|
|
||||||
val chunkStart = currentStart
|
|
||||||
val chunkEnd = minOf(currentStart + partSize - 1, finalEndPoint)
|
|
||||||
producerJob += CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
// 异步下载数据块
|
|
||||||
val data = getVideoStream(chunkStart, chunkEnd, url, headers)
|
|
||||||
//如果是0开始,且检测到恶意头,那么就把数据截断
|
|
||||||
if (chunkStart == 0L) {
|
|
||||||
val offset = detectMaliciousPrefix(data)
|
|
||||||
channels[i].send(data.copyOfRange(offset, data.size))
|
|
||||||
} else {
|
|
||||||
channels[i].send(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
currentStart = chunkEnd + 1
|
|
||||||
}
|
|
||||||
for ((index, _) in producerJob.withIndex()) {
|
|
||||||
|
|
||||||
val data = channels[index].receive()
|
|
||||||
SpiderDebug.log("Received chunk: ${data.size} bytes")
|
|
||||||
response.write(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
channels.forEach { it.close() }
|
|
||||||
} catch (e: Exception) {
|
|
||||||
SpiderDebug.log("proxyAsync error: ${e.message}")
|
|
||||||
e.printStackTrace()
|
|
||||||
response.write("proxyAsync error: ${e.message}")
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
// channels.forEach { it.close() }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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>? {
|
|
||||||
if (query == null) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
val result: MutableMap<String, String> = HashMap()
|
|
||||||
for (param in query.split("&".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) {
|
|
||||||
val entry = param.split("=".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
|
||||||
if (entry.size > 1) {
|
|
||||||
result[entry[0]] = entry[1]
|
|
||||||
} else {
|
|
||||||
result[entry[0]] = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// 辅助函数(需要实现)
|
|
||||||
private fun parseRangePoint(rangeHeader: String): Pair<Long, Long> {
|
|
||||||
// 实现范围解析逻辑
|
|
||||||
val regex = """bytes=(\d+)-(\d*)""".toRegex()
|
|
||||||
val match = regex.find(rangeHeader) ?: return 0L to -1L
|
|
||||||
val start = match.groupValues[1].toLong()
|
|
||||||
val end = match.groupValues[2].takeIf { it.isNotEmpty() }?.toLong() ?: -1L
|
|
||||||
return start to end
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getInfo(
|
|
||||||
url: String?, headers: Map<String, String>
|
|
||||||
): MutableMap<String, MutableList<String>> {
|
|
||||||
val newHeaders: MutableMap<String, String> = java.util.HashMap(headers)
|
|
||||||
newHeaders["Range"] = "bytes=0-" + (1024 * 1024 - 1)
|
|
||||||
newHeaders["range"] = "bytes=0-" + (1024 * 1024 - 1)
|
|
||||||
val res = OkHttp.newCall(url, headers)
|
|
||||||
res.body()?.close()
|
|
||||||
return res.headers().toMultimap()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getContentLength(info: MutableMap<String, MutableList<String>>): Long {
|
|
||||||
// 实现获取内容长度逻辑
|
|
||||||
return info["Content-Length"]?.get(0)?.toLong() ?: 0L
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getVideoStream(
|
|
||||||
start: Long, end: Long, url: String, headers: Map<String, String>
|
|
||||||
): ByteArray {
|
|
||||||
val header = headers.toMutableMap()
|
|
||||||
// 实现分段下载逻辑
|
|
||||||
SpiderDebug.log("getVideoStream: $start-$end; ")
|
|
||||||
header["Range"] = "bytes=$start-$end"
|
|
||||||
val res = OkHttp.newCall(url, header)
|
|
||||||
val body = res.body()
|
|
||||||
return body?.bytes() ?: ByteArray(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun buildProxyUrl(url: String, headers: Map<String, String>): String {
|
|
||||||
urlMap.clear()
|
|
||||||
headerMap.clear()
|
|
||||||
val key = Util.MD5(url)
|
|
||||||
urlMap[key] = url
|
|
||||||
headerMap[key] = headers
|
|
||||||
|
|
||||||
return "http://127.0.0.1:$port/proxy?key=$key"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
package com.github.catvod.utils
|
|
||||||
|
|
||||||
import com.github.catvod.crawler.SpiderDebug
|
|
||||||
import com.github.catvod.net.OkHttp
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import io.ktor.http.ContentType
|
|
||||||
import io.ktor.http.HttpHeaders
|
|
||||||
import io.ktor.http.HttpStatusCode
|
|
||||||
import io.ktor.server.application.ApplicationCall
|
|
||||||
import io.ktor.server.application.call
|
|
||||||
import io.ktor.server.application.install
|
|
||||||
|
|
||||||
import io.ktor.server.engine.embeddedServer
|
|
||||||
import io.ktor.server.netty.Netty
|
|
||||||
import io.ktor.server.plugins.callloging.CallLogging
|
|
||||||
import io.ktor.server.response.respondBytesWriter
|
|
||||||
import io.ktor.server.response.respondText
|
|
||||||
import io.ktor.server.routing.get
|
|
||||||
import io.ktor.server.routing.routing
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.channels.Channel
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import okhttp3.Response
|
|
||||||
import java.nio.ByteBuffer
|
|
||||||
import java.nio.charset.Charset
|
|
||||||
|
|
||||||
object KtorServer {
|
|
||||||
|
|
||||||
private val THREAD_NUM = Runtime.getRuntime().availableProcessors() * 2
|
|
||||||
private val infos = mutableMapOf<String, Array<Any>>()
|
|
||||||
var ser: io.ktor.server.engine.ApplicationEngine? = null
|
|
||||||
var port = 10010
|
|
||||||
|
|
||||||
//每个片1MB
|
|
||||||
private val partSize = 1024 * 1024 * 1
|
|
||||||
fun init() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
try {
|
|
||||||
ser = embeddedServer(Netty, port) {
|
|
||||||
install(CallLogging)
|
|
||||||
|
|
||||||
|
|
||||||
routing {
|
|
||||||
get("/") {
|
|
||||||
call.respondText("ktor running on $port", ContentType.Text.Plain)
|
|
||||||
}
|
|
||||||
get("/proxy") {
|
|
||||||
SpiderDebug.log("代理中: ${call.parameters["url"]}")
|
|
||||||
|
|
||||||
|
|
||||||
val url = Util.base64Decode(call.parameters["url"])
|
|
||||||
val header: Map<String, String> = Gson().fromJson<Map<String, String>>(
|
|
||||||
Util.base64Decode(call.parameters["headers"]),
|
|
||||||
MutableMap::class.java
|
|
||||||
)
|
|
||||||
proxyAsync(
|
|
||||||
url, header, call
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.start(wait = true)
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
SpiderDebug.log("start server e:" + e.message)
|
|
||||||
++port
|
|
||||||
ser?.stop()
|
|
||||||
}
|
|
||||||
} while (port < 13000)
|
|
||||||
SpiderDebug.log("ktorServer start on $port")
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
/** 启动服务器 *//*
|
|
||||||
|
|
||||||
fun start() {
|
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch { init() }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
/** 停止服务器 *//*
|
|
||||||
|
|
||||||
fun stop() {
|
|
||||||
ser?.stop(1_000, 2_000)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* 获取是否分片信息,顺带请求一个1MB块
|
|
||||||
*//*
|
|
||||||
|
|
||||||
@Throws(java.lang.Exception::class)
|
|
||||||
fun getInfo(url: String?, headers: Map<String, String>): Array<Any> {
|
|
||||||
val newHeaders: MutableMap<String, String> = java.util.HashMap(headers)
|
|
||||||
newHeaders["Range"] = "bytes=0-" + (1024 * 1024 - 1)
|
|
||||||
newHeaders["range"] = "bytes=0-" + (1024 * 1024 - 1)
|
|
||||||
val info = ProxyVideo.proxy(url, newHeaders)
|
|
||||||
return info
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun proxyAsync(
|
|
||||||
url: String, headers: Map<String, String>, call: ApplicationCall
|
|
||||||
) {
|
|
||||||
val channels = List(THREAD_NUM) { Channel<ByteArray>() }
|
|
||||||
try {
|
|
||||||
SpiderDebug.log("--proxyMultiThread: THREAD_NUM: $THREAD_NUM")
|
|
||||||
|
|
||||||
|
|
||||||
var rangeHeader = call.request.headers[HttpHeaders.Range]
|
|
||||||
//没有range头
|
|
||||||
if (rangeHeader.isNullOrEmpty()) {
|
|
||||||
// 处理初始请求
|
|
||||||
rangeHeader = "bytes=0-"
|
|
||||||
}
|
|
||||||
headers.toMutableMap().apply {
|
|
||||||
put(HttpHeaders.Range, rangeHeader)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析范围请求
|
|
||||||
val (startPoint, endPoint) = parseRangePoint(
|
|
||||||
rangeHeader
|
|
||||||
)
|
|
||||||
SpiderDebug.log("startPoint: $startPoint; endPoint: $endPoint")
|
|
||||||
val contentLength = getContentLength(url, headers)
|
|
||||||
SpiderDebug.log("contentLength: $contentLength")
|
|
||||||
val finalEndPoint = if (endPoint == -1L) contentLength - 1 else endPoint
|
|
||||||
|
|
||||||
call.response.headers.apply {
|
|
||||||
append(HttpHeaders.Connection, "keep-alive")
|
|
||||||
append(HttpHeaders.ContentLength, (finalEndPoint - startPoint + 1).toString())
|
|
||||||
append(HttpHeaders.ContentRange, "bytes $startPoint-$finalEndPoint/$contentLength")
|
|
||||||
}
|
|
||||||
call.response.status(HttpStatusCode.PartialContent)
|
|
||||||
|
|
||||||
// 使用流式响应
|
|
||||||
call.respondBytesWriter() {
|
|
||||||
var currentStart = startPoint
|
|
||||||
|
|
||||||
|
|
||||||
// 启动生产者协程下载数据
|
|
||||||
|
|
||||||
val producerJob = mutableListOf<Job>()
|
|
||||||
|
|
||||||
while (currentStart <= finalEndPoint) {
|
|
||||||
producerJob.clear()
|
|
||||||
// 创建通道用于接收数据块
|
|
||||||
|
|
||||||
for (i in 0 until THREAD_NUM) {
|
|
||||||
|
|
||||||
if (currentStart > finalEndPoint) break
|
|
||||||
val chunkStart = currentStart
|
|
||||||
val chunkEnd = minOf(currentStart + partSize - 1, finalEndPoint)
|
|
||||||
producerJob += CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
// 异步下载数据块
|
|
||||||
val data = getVideoStream(chunkStart, chunkEnd, url, headers)
|
|
||||||
channels[i].send(data)
|
|
||||||
|
|
||||||
}
|
|
||||||
currentStart = chunkEnd + 1
|
|
||||||
}
|
|
||||||
for ((index, job) in producerJob.withIndex()) {
|
|
||||||
|
|
||||||
val data = channels[index].receive()
|
|
||||||
SpiderDebug.log("Received chunk: ${data.size} bytes")
|
|
||||||
writeFully(ByteBuffer.wrap(data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
SpiderDebug.log("error: ${e.message}")
|
|
||||||
call.respondText("error: ${e.message}", ContentType.Text.Plain)
|
|
||||||
} finally {
|
|
||||||
channels.forEach { it.close() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 辅助函数(需要实现)
|
|
||||||
private fun parseRangePoint(rangeHeader: String): Pair<Long, Long> {
|
|
||||||
// 实现范围解析逻辑
|
|
||||||
val regex = """bytes=(\d+)-(\d*)""".toRegex()
|
|
||||||
val match = regex.find(rangeHeader) ?: return 0L to -1L
|
|
||||||
val start = match.groupValues[1].toLong()
|
|
||||||
val end = match.groupValues[2].takeIf { it.isNotEmpty() }?.toLong() ?: -1L
|
|
||||||
return start to end
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getContentLength(url: String, headers: Map<String, String>): Long {
|
|
||||||
// 实现获取内容长度逻辑
|
|
||||||
val res = OkHttp.newCall(url, headers)
|
|
||||||
res.body()?.close()
|
|
||||||
return res.headers(HttpHeaders.ContentLength)[0]?.toLong() ?: 0L
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun getVideoStream(
|
|
||||||
start: Long, end: Long, url: String, headers: Map<String, String>
|
|
||||||
): ByteArray {
|
|
||||||
val header = headers.toMutableMap()
|
|
||||||
// 实现分段下载逻辑
|
|
||||||
SpiderDebug.log("getVideoStream: $start-$end; ")
|
|
||||||
header[HttpHeaders.Range] = "bytes=$start-$end"
|
|
||||||
val res = OkHttp.newCall(url, header)
|
|
||||||
val body = res.body()
|
|
||||||
return body?.bytes() ?: ByteArray(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun downloadRange(
|
|
||||||
url: String, headerNew: Map<String, String>
|
|
||||||
): Response? = OkHttp.newCall(url, headerNew)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
@ -2,32 +2,22 @@ package com.github.catvod.utils;
|
||||||
|
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.github.catvod.crawler.SpiderDebug;
|
import com.github.catvod.crawler.SpiderDebug;
|
||||||
import com.github.catvod.net.OkHttp;
|
import com.github.catvod.net.OkHttp;
|
||||||
import com.github.catvod.spider.Proxy;
|
import com.github.catvod.spider.Proxy;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import okhttp3.Response;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import okhttp3.Response;
|
|
||||||
|
|
||||||
public class ProxyVideo {
|
public class ProxyVideo {
|
||||||
|
|
||||||
private static final String GO_SERVER = "http://127.0.0.1:7777/";
|
private static final String GO_SERVER = "http://127.0.0.1:7777/";
|
||||||
//线程数4
|
|
||||||
private static final int THREAD_NUM = Runtime.getRuntime().availableProcessors() * 2;
|
|
||||||
private static Map<String, Object[]> infos = new HashMap<>();
|
|
||||||
|
|
||||||
|
|
||||||
public static String buildCommonProxyUrl(String url, Map<String, String> headers) {
|
public static String buildCommonProxyUrl(String url, Map<String, String> headers) {
|
||||||
return Proxy.getUrl() + "?do=proxy&url=" + Util.base64Encode(url.getBytes(Charset.defaultCharset())) + "&header=" + Util.base64Encode((new Gson().toJson(headers)).getBytes(Charset.defaultCharset()));
|
return Proxy.getUrl() + "?do=proxy&url=" + Util.base64Encode(url.getBytes(Charset.defaultCharset())) + "&header=" + Util.base64Encode((new Gson().toJson(headers)).getBytes(Charset.defaultCharset()));
|
||||||
|
|
@ -64,16 +54,10 @@ public class ProxyVideo {
|
||||||
SpiderDebug.log(" ++proxy res code:" + response.code());
|
SpiderDebug.log(" ++proxy res code:" + response.code());
|
||||||
SpiderDebug.log(" ++proxy res header:" + Json.toJson(response.headers()));
|
SpiderDebug.log(" ++proxy res header:" + Json.toJson(response.headers()));
|
||||||
// SpiderDebug.log(" ++proxy res data:" + Json.toJson(response.body()));
|
// SpiderDebug.log(" ++proxy res data:" + Json.toJson(response.body()));
|
||||||
|
String contentType = response.headers().get("Content-Type");
|
||||||
|
|
||||||
String contentType = StringUtils.isAllBlank(response.headers().get("Content-Type")) ? response.headers().get("content-type") : response.headers().get("Content-Type");
|
|
||||||
String contentDisposition = response.headers().get("Content-Disposition");
|
String contentDisposition = response.headers().get("Content-Disposition");
|
||||||
if (contentDisposition != null && StringUtils.isAllBlank(contentType)) {
|
if (contentDisposition != null) contentType = getMimeType(contentDisposition);
|
||||||
contentType = getMimeType(contentDisposition);
|
|
||||||
}
|
|
||||||
Map<String, String> respHeaders = new HashMap<>();
|
Map<String, String> respHeaders = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
/* 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", "*");*/
|
||||||
|
|
||||||
|
|
@ -86,26 +70,7 @@ public class ProxyVideo {
|
||||||
return new Object[]{response.code(), contentType, response.body().byteStream(), respHeaders};
|
return new Object[]{response.code(), contentType, response.body().byteStream(), respHeaders};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getMimeType(String contentDisposition) {
|
||||||
|
|
||||||
public static Object[] proxyMultiThread(String url, Map<String, String> headers) {
|
|
||||||
return DownloadMT.INSTANCE.proxyMultiThread(url, headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static Map<String, String> parseRange(String range) {
|
|
||||||
SpiderDebug.log("parseRange:" + range);
|
|
||||||
if (StringUtils.isNoneBlank(range)) {
|
|
||||||
|
|
||||||
String[] ranges = StringUtils.split(range.replace("bytes=", ""), "-");
|
|
||||||
String start = ranges[0];
|
|
||||||
String end = ranges.length > 1 ? ranges[1] : "";
|
|
||||||
return Map.of("start", start, "end", end);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getMimeType(String contentDisposition) {
|
|
||||||
if (contentDisposition.endsWith(".mp4")) {
|
if (contentDisposition.endsWith(".mp4")) {
|
||||||
return "video/mp4";
|
return "video/mp4";
|
||||||
} else if (contentDisposition.endsWith(".webm")) {
|
} else if (contentDisposition.endsWith(".webm")) {
|
||||||
|
|
@ -136,9 +101,4 @@ public class ProxyVideo {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 视频range
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -23,8 +23,6 @@ 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\\/[^\"]+)";
|
||||||
|
|
@ -32,8 +30,6 @@ public class Util {
|
||||||
public static final Pattern RULE = Pattern.compile("http((?!http).){12,}?\\.(m3u8|mp4|mkv|flv|mp3|m4a|aac)\\?.*|http((?!http).){12,}\\.(m3u8|mp4|mkv|flv|mp3|m4a|aac)|http((?!http).)*?video/tos*");
|
public static final Pattern 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");
|
||||||
|
|
@ -261,12 +257,6 @@ 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());
|
||||||
|
|
|
||||||
|
|
@ -1,229 +0,0 @@
|
||||||
/*
|
|
||||||
package com.github.catvod.utils
|
|
||||||
|
|
||||||
import com.github.catvod.crawler.SpiderDebug
|
|
||||||
import com.github.catvod.net.OkHttp
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import io.ktor.http.ContentType
|
|
||||||
import io.ktor.http.HttpHeaders
|
|
||||||
import io.ktor.http.HttpStatusCode
|
|
||||||
import io.ktor.server.application.ApplicationCall
|
|
||||||
import io.ktor.server.application.call
|
|
||||||
import io.ktor.server.application.install
|
|
||||||
|
|
||||||
import io.ktor.server.engine.embeddedServer
|
|
||||||
import io.ktor.server.netty.Netty
|
|
||||||
import io.ktor.server.plugins.callloging.CallLogging
|
|
||||||
import io.ktor.server.response.respondBytesWriter
|
|
||||||
import io.ktor.server.response.respondText
|
|
||||||
import io.ktor.server.routing.get
|
|
||||||
import io.ktor.server.routing.routing
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.channels.Channel
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import okhttp3.Response
|
|
||||||
import java.nio.ByteBuffer
|
|
||||||
import java.nio.charset.Charset
|
|
||||||
|
|
||||||
object KtorServer {
|
|
||||||
|
|
||||||
private val THREAD_NUM = Runtime.getRuntime().availableProcessors() * 2
|
|
||||||
private val infos = mutableMapOf<String, Array<Any>>()
|
|
||||||
var ser: io.ktor.server.engine.ApplicationEngine? = null
|
|
||||||
var port = 10010
|
|
||||||
|
|
||||||
//每个片1MB
|
|
||||||
private val partSize = 1024 * 1024 * 1
|
|
||||||
fun init() {
|
|
||||||
|
|
||||||
do {
|
|
||||||
try {
|
|
||||||
ser = embeddedServer(Netty, port) {
|
|
||||||
install(CallLogging)
|
|
||||||
|
|
||||||
|
|
||||||
routing {
|
|
||||||
get("/") {
|
|
||||||
call.respondText("ktor running on $port", ContentType.Text.Plain)
|
|
||||||
}
|
|
||||||
get("/proxy") {
|
|
||||||
SpiderDebug.log("代理中: ${call.parameters["url"]}")
|
|
||||||
|
|
||||||
|
|
||||||
val url = Util.base64Decode(call.parameters["url"])
|
|
||||||
val header: Map<String, String> = Gson().fromJson<Map<String, String>>(
|
|
||||||
Util.base64Decode(call.parameters["headers"]),
|
|
||||||
MutableMap::class.java
|
|
||||||
)
|
|
||||||
proxyAsync(
|
|
||||||
url, header, call
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.start(wait = true)
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
SpiderDebug.log("start server e:" + e.message)
|
|
||||||
++port
|
|
||||||
ser?.stop()
|
|
||||||
}
|
|
||||||
} while (port < 13000)
|
|
||||||
SpiderDebug.log("ktorServer start on $port")
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
/** 启动服务器 *//*
|
|
||||||
|
|
||||||
fun start() {
|
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch { init() }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
/** 停止服务器 *//*
|
|
||||||
|
|
||||||
fun stop() {
|
|
||||||
ser?.stop(1_000, 2_000)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun buildProxyUrl(url: String, headers: Map<String, String>): String {
|
|
||||||
return "http://127.0.0.1:$port/proxy?url=${Util.base64Encode(url.toByteArray(Charset.defaultCharset()))}&headers=${
|
|
||||||
Util.base64Encode(
|
|
||||||
Gson().toJson(headers).toByteArray(
|
|
||||||
Charset.defaultCharset()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}"
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* 获取是否分片信息,顺带请求一个1MB块
|
|
||||||
*//*
|
|
||||||
|
|
||||||
@Throws(java.lang.Exception::class)
|
|
||||||
fun getInfo(url: String?, headers: Map<String, String>): Array<Any> {
|
|
||||||
val newHeaders: MutableMap<String, String> = java.util.HashMap(headers)
|
|
||||||
newHeaders["Range"] = "bytes=0-" + (1024 * 1024 - 1)
|
|
||||||
newHeaders["range"] = "bytes=0-" + (1024 * 1024 - 1)
|
|
||||||
val info = ProxyVideo.proxy(url, newHeaders)
|
|
||||||
return info
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun proxyAsync(
|
|
||||||
url: String, headers: Map<String, String>, call: ApplicationCall
|
|
||||||
) {
|
|
||||||
val channels = List(THREAD_NUM) { Channel<ByteArray>() }
|
|
||||||
try {
|
|
||||||
SpiderDebug.log("--proxyMultiThread: THREAD_NUM: $THREAD_NUM")
|
|
||||||
|
|
||||||
|
|
||||||
var rangeHeader = call.request.headers[HttpHeaders.Range]
|
|
||||||
//没有range头
|
|
||||||
if (rangeHeader.isNullOrEmpty()) {
|
|
||||||
// 处理初始请求
|
|
||||||
rangeHeader = "bytes=0-"
|
|
||||||
}
|
|
||||||
headers.toMutableMap().apply {
|
|
||||||
put(HttpHeaders.Range, rangeHeader)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析范围请求
|
|
||||||
val (startPoint, endPoint) = parseRangePoint(
|
|
||||||
rangeHeader
|
|
||||||
)
|
|
||||||
SpiderDebug.log("startPoint: $startPoint; endPoint: $endPoint")
|
|
||||||
val contentLength = getContentLength(url, headers)
|
|
||||||
SpiderDebug.log("contentLength: $contentLength")
|
|
||||||
val finalEndPoint = if (endPoint == -1L) contentLength - 1 else endPoint
|
|
||||||
|
|
||||||
call.response.headers.apply {
|
|
||||||
append(HttpHeaders.Connection, "keep-alive")
|
|
||||||
append(HttpHeaders.ContentLength, (finalEndPoint - startPoint + 1).toString())
|
|
||||||
append(HttpHeaders.ContentRange, "bytes $startPoint-$finalEndPoint/$contentLength")
|
|
||||||
}
|
|
||||||
call.response.status(HttpStatusCode.PartialContent)
|
|
||||||
|
|
||||||
// 使用流式响应
|
|
||||||
call.respondBytesWriter() {
|
|
||||||
var currentStart = startPoint
|
|
||||||
|
|
||||||
|
|
||||||
// 启动生产者协程下载数据
|
|
||||||
|
|
||||||
val producerJob = mutableListOf<Job>()
|
|
||||||
|
|
||||||
while (currentStart <= finalEndPoint) {
|
|
||||||
producerJob.clear()
|
|
||||||
// 创建通道用于接收数据块
|
|
||||||
|
|
||||||
for (i in 0 until THREAD_NUM) {
|
|
||||||
|
|
||||||
if (currentStart > finalEndPoint) break
|
|
||||||
val chunkStart = currentStart
|
|
||||||
val chunkEnd = minOf(currentStart + partSize - 1, finalEndPoint)
|
|
||||||
producerJob += CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
// 异步下载数据块
|
|
||||||
val data = getVideoStream(chunkStart, chunkEnd, url, headers)
|
|
||||||
channels[i].send(data)
|
|
||||||
|
|
||||||
}
|
|
||||||
currentStart = chunkEnd + 1
|
|
||||||
}
|
|
||||||
for ((index, job) in producerJob.withIndex()) {
|
|
||||||
|
|
||||||
val data = channels[index].receive()
|
|
||||||
SpiderDebug.log("Received chunk: ${data.size} bytes")
|
|
||||||
writeFully(ByteBuffer.wrap(data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
SpiderDebug.log("error: ${e.message}")
|
|
||||||
call.respondText("error: ${e.message}", ContentType.Text.Plain)
|
|
||||||
} finally {
|
|
||||||
channels.forEach { it.close() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 辅助函数(需要实现)
|
|
||||||
private fun parseRangePoint(rangeHeader: String): Pair<Long, Long> {
|
|
||||||
// 实现范围解析逻辑
|
|
||||||
val regex = """bytes=(\d+)-(\d*)""".toRegex()
|
|
||||||
val match = regex.find(rangeHeader) ?: return 0L to -1L
|
|
||||||
val start = match.groupValues[1].toLong()
|
|
||||||
val end = match.groupValues[2].takeIf { it.isNotEmpty() }?.toLong() ?: -1L
|
|
||||||
return start to end
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getContentLength(url: String, headers: Map<String, String>): Long {
|
|
||||||
// 实现获取内容长度逻辑
|
|
||||||
val res = OkHttp.newCall(url, headers)
|
|
||||||
res.body()?.close()
|
|
||||||
return res.headers(HttpHeaders.ContentLength)[0]?.toLong() ?: 0L
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun getVideoStream(
|
|
||||||
start: Long, end: Long, url: String, headers: Map<String, String>
|
|
||||||
): ByteArray {
|
|
||||||
val header = headers.toMutableMap()
|
|
||||||
// 实现分段下载逻辑
|
|
||||||
SpiderDebug.log("getVideoStream: $start-$end; ")
|
|
||||||
header[HttpHeaders.Range] = "bytes=$start-$end"
|
|
||||||
val res = OkHttp.newCall(url, header)
|
|
||||||
val body = res.body()
|
|
||||||
return body?.bytes() ?: ByteArray(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun downloadRange(
|
|
||||||
url: String, headerNew: Map<String, String>
|
|
||||||
): Response? = OkHttp.newCall(url, headerNew)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
import android.app.Application;
|
|
||||||
import com.github.catvod.spider.BaiDuPan;
|
|
||||||
import com.github.catvod.spider.Init;
|
|
||||||
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 BaiDuPanTest {
|
|
||||||
|
|
||||||
private Application mockContext;
|
|
||||||
|
|
||||||
private BaiDuPan spider;
|
|
||||||
|
|
||||||
@org.junit.Before
|
|
||||||
public void setUp() throws Exception {
|
|
||||||
mockContext = RuntimeEnvironment.application;
|
|
||||||
Init.init(mockContext);
|
|
||||||
spider = new BaiDuPan();
|
|
||||||
// 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, "BIDUPSID=D122360716A06862B6689D4FE32053A1; PSTM=1756869077; MAWEBCUID=web_KAGxElHEQyrFImqrzARlkIssFfvhfCLGaXDsxmWKbhxsfEsvhs; PANWEB=1; H_WISE_SIDS_BFESS=110085_656765_660924_665265_666660_667682_662823_668348_668761_668756_669314_667565_669628_669693_669848_669685_669681_670119_670114_670116_670307_669051_670308_670357_670598_669700_670824_669791_669664_670557_667838_669418_663788; MCITY=-276%3A; csrfToken=6tn2uwGoOUgn87ZBElHEGjCD; newlogin=1; XFI=627d86b0-a655-11f0-b1eb-0f9d37032cfb; XFCS=B8C411ADE99EE9C3B29FDF31558D538BB636F205DF4F52FE2E57F1312E01079F; XFT=yvSTf+EcMsgYHnGyS774OLqljjYcjil0ZkCgy1g0Aso=; Hm_lvt_182d6d59474cf78db37e0b2248640ea5=1760154644; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; Hm_lvt_fa0277816200010a74ab7d2895df481b=1760339732; Hm_lpvt_fa0277816200010a74ab7d2895df481b=1760344537; BAIDUID=BFD9E2570D797C8F01BC34C196D7E6B7:FG=1; H_PS_PSSID=60279_63143_64005_64983_65126_65194_65248_65272_65368_65420_65450_65510_65538_65543_65618_65599_65633_65656_65674_65667_65653_65706_65713; BAIDUID_BFESS=BFD9E2570D797C8F01BC34C196D7E6B7:FG=1; delPer=0; PSINO=5; H_WISE_SIDS=60279_63143_64005_64983_65126_65194_65248_65272_65368_65420_65450_65510_65538_65543_65618_65599_65633_65656_65674_65667_65653_65706_65713; BA_HECTOR=ak24050g8ha5ah018l0g2g802ke50i1ker7km25; ZFY=LJHc036:AkCyc1OPqFkXugSCgXnfaMIH:AjDQUOfkXtP4:C; BDCLND=vGxYxxMPQqznqvbjTPyD6CQEOejzkIZgEuuv9D5ctzM%3D; ndut_fmt=C6428C500AB0E62AC4B1CBB9671EF7803530C20D2457081012790E5079FD5D8E; ab_sr=1.0.1_MjFjNTFiYTgwYzAxOWFlOWJmYTRmYjUwYmQwNmJkYTg4NTkxYzA4YTk1YTU0MWIxMDQ1YjgzN2QzZGU4Y2MxMzRlNGQ4M2YxNjJmNzliNWFkMjg0N2U4ZWUzOGRiMzljNzM0MmJmMjc2YzQwYmJhYzdmMWU2NThkYmQ4MjRlODRlZDA0Mjc2ZWE3YmQxNGZiZGE3Yzk1MDU1Njk3NmVlOQ==; ppfuid=FOCoIC3q5fKa8fgJnwzbE67EJ49BGJeplOzf+4l4EOvDuu2RXBRv6R3A1AZMa49I27C0gDDLrJyxcIIeAeEhD8JYsoLTpBiaCXhLqvzbzmvy3SeAW17tKgNq/Xx+RgOdb8TWCFe62MVrDTY6lMf2GrfqL8c87KLF2qFER3obJGmVXQmqM6seEAgB/LlOs0+zGEimjy3MrXEpSuItnI4KDwxAMUTOS16BfoXMcd2lpC/ZmOvCi7lsE0/UM0w4HSMVhh7EfifsXEYHtGj52zkQan6UDL686lBL6BHUyL9m3lfGgLbz7OSojK1zRbqBESR5Pdk2R9IA3lxxOVzA+Iw1TWLSgWjlFVG9Xmh1+20oPSbrzvDjYtVPmZ+9/6evcXmhcO1Y58MgLozKnaQIaLfWRFwa8A3ZyTRp/cDxRMhYc97xUSUZS0ReZYJMPG6nCsxNJlhI2UyeJA6QroZFMelR7tnTNS/pLMWceus0e757/UMPmrThfasmhDJrMFcBfoSrAAv3LCf1Y7/fHL3PTSf9vid/u2VLX4h1nBtx8EF07eCMhWVv+2qjbPV7ZhXk3reaWRFEeso3s/Kc9n/UXtUfNU1sHiCdbrCW5yYsuSM9SPGDZsl7FhTAKw7qIu38vFZiq+DRc8Vbf7jOiN9xPe0lOdZHUhGHZ82rL5jTCsILwcRVCndrarbwmu7G154MpYiKmTXZkqV7Alo4QZzicdyMbWvwvmR2/m//YVTM8qeZWgDSHjDmtehgLWM45zARbPujeqU0T92Gmgs89l2htrSKITeYE0TpfIvjPXsgyQghyP8U3sViHT1z07gbfu1XO5QQ/upk1AkHGkWrkbMWm+rpwpdImdyxYIjA1uSy2hfTFv/d3cnXH4nh+maaicAPllDgrppZTr0lDf2Vsiy73L8egP9ck5gsaaSE4obz9V1JGvyp8lNw+IyCN2Gou0efGgcYWqtuH+3KMtXW4uAv+XUaBDreXqEwrDxmyUrecavkqQ9rGRChHnhPuJeIKACPXiVuli9ItRLEkdb1mLxNHAk3uJy88YX/Rf/sKUjR12zxRTDxxJNDJS+Dlsbqu3n4I65ujli/3rQ8Zk1MjmTOsz9+kTqOM4upsnQ6IWq/zeZTItMCgHpQhuhr4ip73honuzoJgge1cqWBFYvpabAPTOERTOP1kmx5SXPARX5uxyJzAiNILBC8zh7fGfNXOWV37O9gEbYklWGnWpu55tg8Y8GaT7BFVDtu1KaJzjx51nTN1+xVI8c7otOFm3py1Y+wrt2CfI5v5JSd2kRNZE7s6bQrA5yMI31SfUDgxDrsd6lPtUU=; BDUSS=YyTmxnRVJQN2FOeXpOZU5TazhHdX56a1h3NnlsTmVaUlFqTEFKSm43aTNPaFZwSVFBQUFBJCQAAAAAAAAAAAEAAAB0wRMxMTIzNDWwtMqxtPLL4wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALet7Wi3re1odF; BDUSS_BFESS=YyTmxnRVJQN2FOeXpOZU5TazhHdX56a1h3NnlsTmVaUlFqTEFKSm43aTNPaFZwSVFBQUFBJCQAAAAAAAAAAAEAAAB0wRMxMTIzNDWwtMqxtPLL4wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALet7Wi3re1odF; STOKEN=7970ecc47cebf55b8bbd63fee5e5e4b612753bceae56d51073b1b69bab616df6; PANPSC=17920541514426231310%3Au9Rut0jYI4omsQqGlPk7plcS2d9ns3O5C61tf8CKQkigT9ngiMB1eA3MPJHnDhkC6WRWG5ljYM%2BmSRyxE8aegpNZSd%2B1SXYsBm6rqQ5QdYLMOw0WWU7tUSqLe%2F%2Bg%2FDWP4i2i1JdCg%2BQ3uGXWluwqDsVi7NXtJ9t339k3FioH%2FAqA1gqZJvix0rmqJrAOClKcX0r3JWTW68Ah7IX89yGaj0Eyueu6wBwEDZC8PXQ9dy48%2FX4Y2hjenzCvC2qz1EInzo%2F1llKJ4P7gQiGlDEks0p8M%2Flyi7z69BCKhGHn%2Fawh9ff8YI35KVRVksnPVbyr%2FTaFwbj9JM%2FCSsVZaqyA8TA%3D%3D; Hm_lpvt_182d6d59474cf78db37e0b2248640ea5=1760406982");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@org.junit.Test
|
|
||||||
public void init() throws Exception {
|
|
||||||
spider.init(mockContext, "BIDUPSID=D122360716A06862B6689D4FE32053A1; PSTM=1756869077; MAWEBCUID=web_KAGxElHEQyrFImqrzARlkIssFfvhfCLGaXDsxmWKbhxsfEsvhs; PANWEB=1; H_WISE_SIDS_BFESS=110085_656765_660924_665265_666660_667682_662823_668348_668761_668756_669314_667565_669628_669693_669848_669685_669681_670119_670114_670116_670307_669051_670308_670357_670598_669700_670824_669791_669664_670557_667838_669418_663788; MCITY=-276%3A; csrfToken=6tn2uwGoOUgn87ZBElHEGjCD; newlogin=1; XFI=627d86b0-a655-11f0-b1eb-0f9d37032cfb; XFCS=B8C411ADE99EE9C3B29FDF31558D538BB636F205DF4F52FE2E57F1312E01079F; XFT=yvSTf+EcMsgYHnGyS774OLqljjYcjil0ZkCgy1g0Aso=; Hm_lvt_182d6d59474cf78db37e0b2248640ea5=1760154644; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; Hm_lvt_fa0277816200010a74ab7d2895df481b=1760339732; Hm_lpvt_fa0277816200010a74ab7d2895df481b=1760344537; BAIDUID=BFD9E2570D797C8F01BC34C196D7E6B7:FG=1; H_PS_PSSID=60279_63143_64005_64983_65126_65194_65248_65272_65368_65420_65450_65510_65538_65543_65618_65599_65633_65656_65674_65667_65653_65706_65713; BAIDUID_BFESS=BFD9E2570D797C8F01BC34C196D7E6B7:FG=1; delPer=0; PSINO=5; H_WISE_SIDS=60279_63143_64005_64983_65126_65194_65248_65272_65368_65420_65450_65510_65538_65543_65618_65599_65633_65656_65674_65667_65653_65706_65713; BA_HECTOR=ak24050g8ha5ah018l0g2g802ke50i1ker7km25; ZFY=LJHc036:AkCyc1OPqFkXugSCgXnfaMIH:AjDQUOfkXtP4:C; BDCLND=vGxYxxMPQqznqvbjTPyD6CQEOejzkIZgEuuv9D5ctzM%3D; ndut_fmt=C6428C500AB0E62AC4B1CBB9671EF7803530C20D2457081012790E5079FD5D8E; ab_sr=1.0.1_MjFjNTFiYTgwYzAxOWFlOWJmYTRmYjUwYmQwNmJkYTg4NTkxYzA4YTk1YTU0MWIxMDQ1YjgzN2QzZGU4Y2MxMzRlNGQ4M2YxNjJmNzliNWFkMjg0N2U4ZWUzOGRiMzljNzM0MmJmMjc2YzQwYmJhYzdmMWU2NThkYmQ4MjRlODRlZDA0Mjc2ZWE3YmQxNGZiZGE3Yzk1MDU1Njk3NmVlOQ==; ppfuid=FOCoIC3q5fKa8fgJnwzbE67EJ49BGJeplOzf+4l4EOvDuu2RXBRv6R3A1AZMa49I27C0gDDLrJyxcIIeAeEhD8JYsoLTpBiaCXhLqvzbzmvy3SeAW17tKgNq/Xx+RgOdb8TWCFe62MVrDTY6lMf2GrfqL8c87KLF2qFER3obJGmVXQmqM6seEAgB/LlOs0+zGEimjy3MrXEpSuItnI4KDwxAMUTOS16BfoXMcd2lpC/ZmOvCi7lsE0/UM0w4HSMVhh7EfifsXEYHtGj52zkQan6UDL686lBL6BHUyL9m3lfGgLbz7OSojK1zRbqBESR5Pdk2R9IA3lxxOVzA+Iw1TWLSgWjlFVG9Xmh1+20oPSbrzvDjYtVPmZ+9/6evcXmhcO1Y58MgLozKnaQIaLfWRFwa8A3ZyTRp/cDxRMhYc97xUSUZS0ReZYJMPG6nCsxNJlhI2UyeJA6QroZFMelR7tnTNS/pLMWceus0e757/UMPmrThfasmhDJrMFcBfoSrAAv3LCf1Y7/fHL3PTSf9vid/u2VLX4h1nBtx8EF07eCMhWVv+2qjbPV7ZhXk3reaWRFEeso3s/Kc9n/UXtUfNU1sHiCdbrCW5yYsuSM9SPGDZsl7FhTAKw7qIu38vFZiq+DRc8Vbf7jOiN9xPe0lOdZHUhGHZ82rL5jTCsILwcRVCndrarbwmu7G154MpYiKmTXZkqV7Alo4QZzicdyMbWvwvmR2/m//YVTM8qeZWgDSHjDmtehgLWM45zARbPujeqU0T92Gmgs89l2htrSKITeYE0TpfIvjPXsgyQghyP8U3sViHT1z07gbfu1XO5QQ/upk1AkHGkWrkbMWm+rpwpdImdyxYIjA1uSy2hfTFv/d3cnXH4nh+maaicAPllDgrppZTr0lDf2Vsiy73L8egP9ck5gsaaSE4obz9V1JGvyp8lNw+IyCN2Gou0efGgcYWqtuH+3KMtXW4uAv+XUaBDreXqEwrDxmyUrecavkqQ9rGRChHnhPuJeIKACPXiVuli9ItRLEkdb1mLxNHAk3uJy88YX/Rf/sKUjR12zxRTDxxJNDJS+Dlsbqu3n4I65ujli/3rQ8Zk1MjmTOsz9+kTqOM4upsnQ6IWq/zeZTItMCgHpQhuhr4ip73honuzoJgge1cqWBFYvpabAPTOERTOP1kmx5SXPARX5uxyJzAiNILBC8zh7fGfNXOWV37O9gEbYklWGnWpu55tg8Y8GaT7BFVDtu1KaJzjx51nTN1+xVI8c7otOFm3py1Y+wrt2CfI5v5JSd2kRNZE7s6bQrA5yMI31SfUDgxDrsd6lPtUU=; BDUSS=YyTmxnRVJQN2FOeXpOZU5TazhHdX56a1h3NnlsTmVaUlFqTEFKSm43aTNPaFZwSVFBQUFBJCQAAAAAAAAAAAEAAAB0wRMxMTIzNDWwtMqxtPLL4wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALet7Wi3re1odF; BDUSS_BFESS=YyTmxnRVJQN2FOeXpOZU5TazhHdX56a1h3NnlsTmVaUlFqTEFKSm43aTNPaFZwSVFBQUFBJCQAAAAAAAAAAAEAAAB0wRMxMTIzNDWwtMqxtPLL4wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALet7Wi3re1odF; STOKEN=7970ecc47cebf55b8bbd63fee5e5e4b612753bceae56d51073b1b69bab616df6; PANPSC=17920541514426231310%3Au9Rut0jYI4omsQqGlPk7plcS2d9ns3O5C61tf8CKQkigT9ngiMB1eA3MPJHnDhkC6WRWG5ljYM%2BmSRyxE8aegpNZSd%2B1SXYsBm6rqQ5QdYLMOw0WWU7tUSqLe%2F%2Bg%2FDWP4i2i1JdCg%2BQ3uGXWluwqDsVi7NXtJ9t339k3FioH%2FAqA1gqZJvix0rmqJrAOClKcX0r3JWTW68Ah7IX89yGaj0Eyueu6wBwEDZC8PXQ9dy48%2FX4Y2hjenzCvC2qz1EInzo%2F1llKJ4P7gQiGlDEks0p8M%2Flyi7z69BCKhGHn%2Fawh9ff8YI35KVRVksnPVbyr%2FTaFwbj9JM%2FCSsVZaqyA8TA%3D%3D; Hm_lpvt_182d6d59474cf78db37e0b2248640ea5=1760406982");
|
|
||||||
//Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@org.junit.Test
|
|
||||||
public void detailContent() throws Exception {
|
|
||||||
|
|
||||||
String content = spider.detailContent(Arrays.asList("https://pan.baidu.com/s/1Ov0S6S7rqnyW_S3AondhmQ?pwd=8888"));
|
|
||||||
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("BD原画", "eyJ1ayI6IjExMDMyNzkxMjIzNDEiLCJzaGFyZWlkIjoiMjk1NzE4ODcyOTgiLCJmaWQiOjMxOTM5NTUxMTQyOTU4MCwicmFuZHNrIjoidkd4WXh4TVBRcXpucXZialRQeUQ2Q1FFT2VqemtJWmdFdXV2OUQ1Y3R6TSUzRCIsInBuYW1lIjoiRHJhZ29uIEJhbGwgREFJTUEuUzAxRTAxLjIwMjQuMTA4MHAuQ1IuV0VCLURMLngyNjQuQUFDLm1rdiIsInF0eXBlIjoib3JpZ2luYWwifQ==", new ArrayList<>());
|
|
||||||
// String content = spider.playerContent("BD转码", "eyJ1ayI6IjExMDMyNzkxMjIzNDEiLCJmaWQiOjMxOTE2ODY2NDUxMzY1Nywic2hhcmVpZCI6IjI5NTcxODg3Mjk4Iiwic3VybCI6IjFPdjBTNlM3cnFueVdfUzNBb25kaG1RIiwicG5hbWUiOiJEcmFnb24gQmFsbCBEQUlNQS5TMDFFMjAuMjAyNC4xMDgwcC5DUi5XRUItREwueDI2NC5BQUMubWt2IiwicXR5cGUiOiJwcmV2aWV3In0=", 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) {
|
|
||||||
Thread.sleep(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,103 +0,0 @@
|
||||||
import android.app.Application
|
|
||||||
import com.github.catvod.spider.DiDa
|
|
||||||
import com.github.catvod.spider.Init
|
|
||||||
import com.github.catvod.utils.Json
|
|
||||||
import com.google.gson.GsonBuilder
|
|
||||||
import org.junit.Assert
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.RobolectricTestRunner
|
|
||||||
import org.robolectric.RuntimeEnvironment
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
|
||||||
class DiDaTest {
|
|
||||||
// @Mock
|
|
||||||
private var mockContext: Application? = null
|
|
||||||
|
|
||||||
private var spider: DiDa? = null
|
|
||||||
|
|
||||||
@Before
|
|
||||||
@Throws(Exception::class)
|
|
||||||
fun setUp() {
|
|
||||||
mockContext = RuntimeEnvironment.application
|
|
||||||
Init.init(mockContext)
|
|
||||||
spider = DiDa()
|
|
||||||
spider!!.init(mockContext, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Throws(Exception::class)
|
|
||||||
fun homeContent() {
|
|
||||||
val content = spider!!.homeContent(true)
|
|
||||||
val map = Json.safeObject(content)
|
|
||||||
val gson = GsonBuilder().setPrettyPrinting().create()
|
|
||||||
|
|
||||||
println("homeContent--" + gson.toJson(map))
|
|
||||||
|
|
||||||
//Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Throws(Exception::class)
|
|
||||||
fun homeVideoContent() {
|
|
||||||
val content = spider!!.homeVideoContent()
|
|
||||||
val map = Json.safeObject(content)
|
|
||||||
val gson = GsonBuilder().setPrettyPrinting().create()
|
|
||||||
|
|
||||||
println("homeVideoContent--" + gson.toJson(map))
|
|
||||||
|
|
||||||
//Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Throws(Exception::class)
|
|
||||||
fun categoryContent() {
|
|
||||||
val content = spider!!.categoryContent("/type/1.html", "2", true, null)
|
|
||||||
val map = Json.safeObject(content)
|
|
||||||
val gson = GsonBuilder().setPrettyPrinting().create()
|
|
||||||
println("categoryContent--" + gson.toJson(map))
|
|
||||||
Assert.assertFalse(map.getAsJsonArray("list").isEmpty())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Throws(Exception::class)
|
|
||||||
fun detailContent() {
|
|
||||||
val content = spider!!.detailContent(mutableListOf<String?>("/detail/1370.html"))
|
|
||||||
val map = Json.safeObject(content)
|
|
||||||
val gson = GsonBuilder().setPrettyPrinting().create()
|
|
||||||
println("detailContent--" + gson.toJson(map))
|
|
||||||
Assert.assertFalse(map.getAsJsonArray("list").isEmpty())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Throws(Exception::class)
|
|
||||||
fun playerContent() {
|
|
||||||
val froms ="BD3$$\$超清F$$\$超清A$$\$超清B$$\$夸克网盘$$\$百度网盘"
|
|
||||||
|
|
||||||
val urls ="HD1080P(英语)$/play/1370-1-1.html$$$1080P$/play/1370-6-1.html$$\$HD$/play/1370-3-1.html$$$1080P$/play/1370-4-1.html$$$1080P$/play/1370-2-1.html$$\$合集$/play/1370-5-1.html"
|
|
||||||
for (i in urls.split("\\$\\$\\$".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray().indices) {
|
|
||||||
val content = spider!!.playerContent(
|
|
||||||
froms.split("\\$\\$\\$".toRegex()).dropLastWhile { it.isEmpty() }
|
|
||||||
.toTypedArray()[i],
|
|
||||||
urls.split("\\$\\$\\$".toRegex()).dropLastWhile { it.isEmpty() }
|
|
||||||
.toTypedArray()[i].split("\\$".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1],
|
|
||||||
ArrayList<String?>()
|
|
||||||
)
|
|
||||||
val map = Json.safeObject(content)
|
|
||||||
val gson = GsonBuilder().setPrettyPrinting().create()
|
|
||||||
println("playerContent--" + gson.toJson(map))
|
|
||||||
Assert.assertFalse(map.getAsJsonPrimitive("url").getAsString().isEmpty())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Throws(Exception::class)
|
|
||||||
fun searchContent() {
|
|
||||||
val content = spider!!.searchContent("红海", false)
|
|
||||||
val map = Json.safeObject(content)
|
|
||||||
val gson = GsonBuilder().setPrettyPrinting().create()
|
|
||||||
println("searchContent--" + gson.toJson(map))
|
|
||||||
Assert.assertFalse(map.getAsJsonArray("list").isEmpty())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -70,7 +70,7 @@ public class LeiJingTest {
|
||||||
@org.junit.Test
|
@org.junit.Test
|
||||||
public void detailContent() throws Exception {
|
public void detailContent() throws Exception {
|
||||||
|
|
||||||
String content = spider.detailContent(Arrays.asList("thread?topicId=40214"));
|
String content = spider.detailContent(Arrays.asList("thread?topicId=35472"));
|
||||||
System.out.println("detailContent--" + content);
|
System.out.println("detailContent--" + content);
|
||||||
|
|
||||||
JsonObject map = Json.safeObject(content);
|
JsonObject map = Json.safeObject(content);
|
||||||
|
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
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){
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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_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");
|
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");
|
||||||
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/469c2acf8640"));
|
String content = spider.detailContent(Arrays.asList("https://pan.quark.cn/s/38c5e16d71f7"));
|
||||||
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("quark原画", "a04522f504a742db8ebaf69e3b7f50d6++375807f3f1068a8fdabac127ec4db89f++469c2acf8640++PVTgPNXNtRFDDkE6SAYX4KPSjk9xl449JkTHl6mtu7k=", new ArrayList<>());
|
String content = spider.playerContent("普画","41ea9a50cbdd4e50b019bcd78687ebc1++22fc6fa8350d22e0eaecc49035368e81++38c5e16d71f7++WFcYTmRhjJpKTui56aleYdzBZi9R203GERBVzYNxDxI=",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();
|
||||||
|
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
import android.app.Application
|
|
||||||
import com.github.catvod.server.Server
|
|
||||||
import com.github.catvod.spider.DianYingYunJi
|
|
||||||
import com.github.catvod.spider.Init
|
|
||||||
import com.github.catvod.spider.ReBoYingShi
|
|
||||||
import com.github.catvod.utils.Json
|
|
||||||
import com.google.gson.GsonBuilder
|
|
||||||
import org.junit.Assert
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.RobolectricTestRunner
|
|
||||||
import org.robolectric.RuntimeEnvironment
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
|
||||||
class ReBoYSTest {
|
|
||||||
private var mockContext: Application? = null
|
|
||||||
|
|
||||||
private var spider: ReBoYingShi? = null
|
|
||||||
|
|
||||||
@Before
|
|
||||||
@Throws(Exception::class)
|
|
||||||
fun setUp() {
|
|
||||||
mockContext = RuntimeEnvironment.application
|
|
||||||
Init.init(mockContext)
|
|
||||||
spider = ReBoYingShi()
|
|
||||||
|
|
||||||
// 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\":\"ctoken=rldVUeNBAbGyhJdbpC4wEUE-;__pus=75e54cf66f9ea5ed1497838782a90a78AATTBUV9c9w7KXUiHDEl6VdV8Wxki4L9R5kIIjSKQnX1wedJe3s8weva95YKUkRqI1aBY/MA+YBNvaTO0JkXvLp+;__kp=be6b9e10-74f8-11ef-aa08-7d8956cd7603;__kps=AATcZArVgS76EPn0FMaV4HEj;__ktd=sii/iz4ePzEaoVirXul7QQ==;__uid=AATcZArVgS76EPn0FMaV4HEj\"}");
|
|
||||||
// spider.init(mockContext, "");
|
|
||||||
/* 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\"}"
|
|
||||||
)*/
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Throws(Exception::class)
|
|
||||||
fun homeContent() {
|
|
||||||
val content = spider!!.homeContent(true)
|
|
||||||
val map = Json.safeObject(content)
|
|
||||||
val gson = GsonBuilder().setPrettyPrinting().create()
|
|
||||||
|
|
||||||
println("homeContent--" + gson.toJson(map))
|
|
||||||
|
|
||||||
//Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Throws(Exception::class)
|
|
||||||
fun homeVideoContent() {
|
|
||||||
val content = spider!!.homeVideoContent()
|
|
||||||
val map = Json.safeObject(content)
|
|
||||||
val gson = GsonBuilder().setPrettyPrinting().create()
|
|
||||||
|
|
||||||
println("homeVideoContent--" + gson.toJson(map))
|
|
||||||
|
|
||||||
// Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Throws(Exception::class)
|
|
||||||
fun categoryContent() {
|
|
||||||
val content = spider!!.categoryContent("https://dyyjpro.com/category/dianying", "2", true, null)
|
|
||||||
val map = Json.safeObject(content)
|
|
||||||
val gson = GsonBuilder().setPrettyPrinting().create()
|
|
||||||
println("categoryContent--" + gson.toJson(map))
|
|
||||||
Assert.assertFalse(map.getAsJsonArray("list").isEmpty())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Throws(Exception::class)
|
|
||||||
fun detailContent() {
|
|
||||||
val content = spider!!.detailContent(mutableListOf<String?>("/s/家庭煮夫.html"))
|
|
||||||
println("detailContent--" + content)
|
|
||||||
|
|
||||||
val map = Json.safeObject(content)
|
|
||||||
val gson = GsonBuilder().setPrettyPrinting().create()
|
|
||||||
println("detailContent--" + gson.toJson(map))
|
|
||||||
Assert.assertFalse(map.getAsJsonArray("list").isEmpty())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Throws(Exception::class)
|
|
||||||
fun playerContent() {
|
|
||||||
val content = spider!!.playerContent(
|
|
||||||
"quark4K",
|
|
||||||
"81c9aa49887d4b07aba861d7dd76d0ac++0ec2d75805f83bd045434f0d22f71489++4be1d75e17aa++wGlrbmw95nBbzO2rbCcEicZ8f4a+z5aKiuyoLQLA5SQ=",
|
|
||||||
ArrayList<String?>()
|
|
||||||
)
|
|
||||||
println("playerContent--" + content)
|
|
||||||
val map = Json.safeObject(content)
|
|
||||||
val gson = GsonBuilder().setPrettyPrinting().create()
|
|
||||||
println("playerContent--" + gson.toJson(map))
|
|
||||||
Assert.assertFalse(map.getAsJsonPrimitive("url").getAsString().isEmpty())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Throws(Exception::class)
|
|
||||||
fun searchContent() {
|
|
||||||
val content = spider!!.searchContent("屠户之子的科举之路", false)
|
|
||||||
val map = Json.safeObject(content)
|
|
||||||
val gson = GsonBuilder().setPrettyPrinting().create()
|
|
||||||
println("searchContent--" + gson.toJson(map))
|
|
||||||
Assert.assertFalse(map.getAsJsonArray("list").isEmpty())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
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.TgSearchBaidu;
|
import com.github.catvod.spider.PanSearch;
|
||||||
|
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;
|
||||||
|
|
@ -11,7 +13,6 @@ 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)
|
||||||
|
|
@ -19,26 +20,25 @@ public class TgSearchTest {
|
||||||
|
|
||||||
private Application mockContext;
|
private Application mockContext;
|
||||||
|
|
||||||
private TgSearchBaidu spider;
|
private TgSearch 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 TgSearchBaidu();
|
spider = new TgSearch();
|
||||||
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, "{\"tianyicookie\":\"{\\\"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}]}\"}");
|
||||||
"\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);
|
||||||
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("searchContent--" + gson.toJson(map));
|
System.out.println("searchContent--" + gson.toJson(map));
|
||||||
|
|
@ -48,18 +48,7 @@ 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("https://123684.com/s/u9izjv-smUWv"));
|
String content = spider.detailContent(Arrays.asList("/s/LEvn4lUGB6ufdQ"));
|
||||||
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));
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,8 @@ public class TianYiSoTest {
|
||||||
spider = new TianYiSo();
|
spider = new TianYiSo();
|
||||||
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, "{\"tianyicookie\":\"{\\\"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}]}\"}");
|
||||||
"\t\"username\":\"18896781601\" ,\"password\":\"Lushunming@0526\"\n" +
|
// spider.init(mockContext, "");
|
||||||
"}"); // spider.init(mockContext, "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ public class YiDongYunTest {
|
||||||
@org.junit.Test
|
@org.junit.Test
|
||||||
public void detailContent() throws Exception {
|
public void detailContent() throws Exception {
|
||||||
|
|
||||||
String content = spider.detailContent(Arrays.asList("https://caiyun.139.com/w/i/2nQQVZWCR24yf"));
|
String content = spider.detailContent(Arrays.asList("https://yun.139.com/shareweb/#/w/i/165CkRwb9G885"));
|
||||||
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();
|
||||||
|
|
@ -49,15 +49,10 @@ public class YiDongYunTest {
|
||||||
Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
|
Assert.assertFalse(map.getAsJsonArray("list").isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* "vod_play_from": "移动(极速)$$$移动(原画)",
|
|
||||||
* "vod_play_url": "01.mp4$FtgoS0iBwhPFnG-daRU5HJKQ2yBYj8I3x++2nQQVZWCR24yf#02.mp4$FiPG4ttnS-78swp-1sTFG4prNYnLaUvK_++2nQQVZWCR24yf$$$01.mp4$FtB-r8kHUbJFKbzW_r9tJt6YjcTZCVGWR/FtgoS0iBwhPFnG-daRU5HJKQ2yBYj8I3x++2nQQVZWCR24yf#02.mp4$FtB-r8kHUbJFKbzW_r9tJt6YjcTZCVGWR/FiPG4ttnS-78swp-1sTFG4prNYnLaUvK_++2nQQVZWCR24yf"
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
@org.junit.Test
|
@org.junit.Test
|
||||||
public void playerContent() throws Exception {
|
public void playerContent() throws Exception {
|
||||||
|
|
||||||
String content = spider.playerContent("移动(原画)","FtB-r8kHUbJFKbzW_r9tJt6YjcTZCVGWR/FiPG4ttnS-78swp-1sTFG4prNYnLaUvK_++2nQQVZWCR24yf",new ArrayList<>());
|
String content = spider.playerContent("普画","41ea9a50cbdd4e50b019bcd78687ebc1++22fc6fa8350d22e0eaecc49035368e81++38c5e16d71f7++WFcYTmRhjJpKTui56aleYdzBZi9R203GERBVzYNxDxI=",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();
|
||||||
|
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
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");
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
package com.github.catvod.api
|
|
||||||
|
|
||||||
import com.github.catvod.utils.Json
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.RobolectricTestRunner
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
|
||||||
class BaiduDriveTest {
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun getShareList() {
|
|
||||||
|
|
||||||
runBlocking {
|
|
||||||
val reslut =
|
|
||||||
BaiduDrive.processShareLinks(listOf("https://pan.baidu.com/s/1So5RhSmNts0rWKEzjqinhQ?pwd=9527"))
|
|
||||||
System.out.println(Json.toJson(reslut))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun getBdUid() {
|
|
||||||
|
|
||||||
runBlocking {
|
|
||||||
val reslut = BaiduDrive.getBdUid()
|
|
||||||
System.out.println(reslut)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun _getSign() {
|
|
||||||
val jsonStr =
|
|
||||||
com.github.catvod.utils.Util.base64Decode("eyJ1ayI6IjExMDI4NjAxODI4OTgiLCJmaWQiOjE1NTY5Mzk0MDE4MjQ2NCwic2hhcmVpZCI6IjUzNDc0MDY5NzI0Iiwic3VybCI6IjFmMHk2MFJrWWNTc3A0RXdXb2xLZ0pnIiwicG5hbWUiOiIwNeWbveivrS00Sy7pq5jnoIHnjocubXA0IiwicXR5cGUiOiJwcmV2aWV3In0=")
|
|
||||||
val obj = Json.safeObject(jsonStr)
|
|
||||||
runBlocking {
|
|
||||||
val reslut = BaiduDrive._getSign(obj)
|
|
||||||
System.out.println(reslut)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun getVideoUrl() {/* val jsonStr =
|
|
||||||
com.github.catvod.utils.Util.base64Decode("eyJ1ayI6IjExMDI4NjAxODI4OTgiLCJmaWQiOjE1NTY5Mzk0MDE4MjQ2NCwic2hhcmVpZCI6IjUzNDc0MDY5NzI0Iiwic3VybCI6IjFmMHk2MFJrWWNTc3A0RXdXb2xLZ0pnIiwicG5hbWUiOiIwNeWbveivrS00Sy7pq5jnoIHnjocubXA0IiwicXR5cGUiOiJwcmV2aWV3In0=")
|
|
||||||
val obj = Json.safeObject(jsonStr)
|
|
||||||
runBlocking {
|
|
||||||
val reslut = yunDrive?.getVideoUrl(obj)
|
|
||||||
System.out.println(reslut)
|
|
||||||
}*/
|
|
||||||
val jsonStr =
|
|
||||||
com.github.catvod.utils.Util.base64Decode("eyJ1ayI6IjI0MDAxMjE2NzIiLCJzaGFyZWlkIjoiMjc2NTk2OTA4MTAiLCJmaWQiOjcxNzUwMDM4OTg1MjYzOSwicmFuZHNrIjoiNEdjMzFTejVsZHNpdHcwRW12ZDNzam9XYWFuVjFEQlFsUHk3VkdESHklMkI0JTNEIiwicG5hbWUiOiJUaGUuUmV0dXJuLm9mLnRoZS5MYW1lLkhlcm8uMjAyNS4yMTYwcC5XRUItREwuSDI2NS5IRFIuNjBmcHMuRERQNS4xLURyZWFtSEQubWt2IiwicXR5cGUiOiJvcmlnaW5hbCJ9")
|
|
||||||
val obj = Json.safeObject(jsonStr)
|
|
||||||
runBlocking {
|
|
||||||
val reslut = BaiduDrive.getVideoUrl(obj, "BD原画1")
|
|
||||||
System.out.println(reslut)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun createSaveDir() {/* val jsonStr =
|
|
||||||
com.github.catvod.utils.Util.base64Decode("eyJ1ayI6IjExMDI4NjAxODI4OTgiLCJmaWQiOjE1NTY5Mzk0MDE4MjQ2NCwic2hhcmVpZCI6IjUzNDc0MDY5NzI0Iiwic3VybCI6IjFmMHk2MFJrWWNTc3A0RXdXb2xLZ0pnIiwicG5hbWUiOiIwNeWbveivrS00Sy7pq5jnoIHnjocubXA0IiwicXR5cGUiOiJwcmV2aWV3In0=")
|
|
||||||
val obj = Json.safeObject(jsonStr)
|
|
||||||
runBlocking {
|
|
||||||
val reslut = yunDrive?.getVideoUrl(obj)
|
|
||||||
System.out.println(reslut)
|
|
||||||
}*/
|
|
||||||
|
|
||||||
runBlocking {
|
|
||||||
val reslut = BaiduDrive.createSaveDir()
|
|
||||||
System.out.println(reslut)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
@ -32,7 +32,7 @@ public class QuarkApiTest {
|
||||||
public void testdownload() throws Exception {
|
public void testdownload() throws Exception {
|
||||||
|
|
||||||
String url = "https://video-play-p-zb.cdn.yun.cn/P7r95SEr/1997440970/7986fbd7419840ba83d70e7ec36f933867d2fadf/67d2fadf98f5dd83fcd64481858236a79b4c3384?auth_key=1741952223-3304496-16098-d233ccbc65c0321102d36db56f3db9c2&sp=642&token=3-08917a23ee79367eab5e9dcfbd898751-3-2-963-5cbf_3bd039d6d54ec6a8737515d6f20a488c-0-0-0-0-e9fc047ff0aa9b590be130819e1e82f2&ud=9-0-1-2-1-5-8-N-0-4-0-N";
|
String url = "https://video-play-p-zb.cdn.yun.cn/P7r95SEr/1997440970/7986fbd7419840ba83d70e7ec36f933867d2fadf/67d2fadf98f5dd83fcd64481858236a79b4c3384?auth_key=1741952223-3304496-16098-d233ccbc65c0321102d36db56f3db9c2&sp=642&token=3-08917a23ee79367eab5e9dcfbd898751-3-2-963-5cbf_3bd039d6d54ec6a8737515d6f20a488c-0-0-0-0-e9fc047ff0aa9b590be130819e1e82f2&ud=9-0-1-2-1-5-8-N-0-4-0-N";
|
||||||
OkResult okResult1 = OkHttp.get(url, new HashMap<>(), Map.of("Range", "bytes=0-"));
|
OkResult okResult1 = OkHttp.get(url, new HashMap<>(), Map.of("Range", "bytes=0-0"));
|
||||||
assert okResult1.getCode() == 206;
|
assert okResult1.getCode() == 206;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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("http://cloud.189.cn/t/3uIFJrzIFJV3(访问码:qf4b)", "");
|
com.github.catvod.bean.tianyi.ShareData shareData1 = TianyiApi.get().getShareData("https://cloud.189.cn/web/share?code=2eyARfBzURZj(访问码:kz6y)", "");
|
||||||
|
|
||||||
// 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", "");
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package com.github.catvod.api;
|
package com.github.catvod.api;
|
||||||
|
|
||||||
import com.github.catvod.bean.tianyi.ShareData;
|
import com.github.catvod.bean.tianyi.ShareData;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
@ -28,32 +27,14 @@ public class YunDriveTest {
|
||||||
System.out.println(result);
|
System.out.println(result);
|
||||||
for (String s : result.keySet()) {
|
for (String s : result.keySet()) {
|
||||||
for (Map<String, String> stringStringMap : result.get(s)) {
|
for (Map<String, String> stringStringMap : result.get(s)) {
|
||||||
String playUrl = yunDrive.fetchPlayUrl(stringStringMap.get("contentId"), "");
|
String playUrl = yunDrive.fetchPlayUrl(stringStringMap.get("contentId"),"");
|
||||||
System.out.println(stringStringMap.get("name") + ":" + playUrl);
|
System.out.println(stringStringMap.get("name")+":"+playUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void download() throws Exception {
|
|
||||||
|
|
||||||
Map<String, List<Map<String, String>>> result = yunDrive.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 = yunDrive.fetchPlayUrl(stringStringMap.get("contentId"), stringStringMap.get("linkID"));
|
|
||||||
String url2 = yunDrive.get4kVideoInfo(stringStringMap.get("linkID"), stringStringMap.get("path"));
|
|
||||||
System.out.println(stringStringMap.get("name") + ":" + playUrl);
|
|
||||||
System.out.println(stringStringMap.get("url2") + ":" + url2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -67,5 +48,4 @@ public class YunDriveTest {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
package com.github.catvod.utils;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.robolectric.RobolectricTestRunner;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
|
||||||
public class ProxyVideoTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void proxyMultiThread() {
|
|
||||||
// ProxyVideo.proxyMultiThread()
|
|
||||||
/* Server.get().start();
|
|
||||||
String url = ProxyVideo.buildCommonProxyUrl(
|
|
||||||
// "https://js.shipin520.com/pc/images/new/banner20250225.mp4", new HashMap<>());
|
|
||||||
"http://172.16.1.217:18089/ng-grid/video.mp4", new HashMap<>());
|
|
||||||
System.out.println(url);*/
|
|
||||||
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();
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -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.
|
|
@ -1 +1 @@
|
||||||
5cca7cdb874fb79dee68e08a876fc8ec
|
4a9814b359e0f39cf4613cd801871c06
|
||||||
|
|
|
||||||
520
json/index.json
520
json/index.json
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"spider": "http://gh.halonice.com/https://raw.githubusercontent.com/lushunming/AndroidCatVodSpider/refs/heads/multiThread/jar/custom_spider.jar;md5;5cca7cdb874fb79dee68e08a876fc8ec",
|
"spider": "https://androidcatvodspider.netlify.app/jar/custom_spider.jar;md5;4a9814b359e0f39cf4613cd801871c06",
|
||||||
"lives": [
|
"lives": [
|
||||||
{
|
{
|
||||||
"name": "电视直播",
|
"name": "电视直播",
|
||||||
|
|
@ -66,15 +66,7 @@
|
||||||
"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",
|
||||||
|
|
@ -101,146 +93,15 @@
|
||||||
"searchable": 1,
|
"searchable": 1,
|
||||||
"changeable": 1,
|
"changeable": 1,
|
||||||
"ext": {}
|
"ext": {}
|
||||||
},
|
}, {
|
||||||
{
|
"key": "TgSearch",
|
||||||
"key": "Qupans",
|
"name": "TgSearch|Pan",
|
||||||
"name": "Qupans|Pan",
|
|
||||||
"type": 3,
|
"type": 3,
|
||||||
"api": "csp_Qupans",
|
"api": "csp_TgSearch",
|
||||||
"searchable": 1,
|
"searchable": 1,
|
||||||
"changeable": 1,
|
"changeable": 1,
|
||||||
"ext": {}
|
"ext": {}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"key": "Tg123Search",
|
|
||||||
"name": "Tg123Search",
|
|
||||||
"type": 3,
|
|
||||||
"api": "csp_Tg123Search",
|
|
||||||
"searchable": 1,
|
|
||||||
"changeable": 1,
|
|
||||||
"ext": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "TgbaiduSearch",
|
|
||||||
"name": "TgbaiduSearch",
|
|
||||||
"type": 3,
|
|
||||||
"api": "csp_TgbaiduSearch",
|
|
||||||
"searchable": 1,
|
|
||||||
"changeable": 1,
|
|
||||||
"ext": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "Tg189Search",
|
|
||||||
"name": "Tg189Search",
|
|
||||||
"type": 3,
|
|
||||||
"api": "csp_Tg189Search",
|
|
||||||
"searchable": 1,
|
|
||||||
"changeable": 1,
|
|
||||||
"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",
|
|
||||||
"name": "☁TgSearchBaidu┃网盘",
|
|
||||||
"type": 3,
|
|
||||||
"api": "csp_TgSearchBaidu",
|
|
||||||
"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": "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": [
|
|
||||||
"移动"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "KuaKeBa",
|
"key": "KuaKeBa",
|
||||||
"name": "夸克吧",
|
"name": "夸克吧",
|
||||||
|
|
@ -268,15 +129,7 @@
|
||||||
"changeable": 1,
|
"changeable": 1,
|
||||||
"ext": {}
|
"ext": {}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"key": "ReBoYingShi",
|
|
||||||
"name": "热播影视4k",
|
|
||||||
"type": 3,
|
|
||||||
"api": "csp_ReBoYingShi",
|
|
||||||
"searchable": 1,
|
|
||||||
"changeable": 1,
|
|
||||||
"ext": {}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "XuanFeng",
|
"key": "XuanFeng",
|
||||||
"name": "旋风影视",
|
"name": "旋风影视",
|
||||||
|
|
@ -459,32 +312,349 @@
|
||||||
"timeout": 30
|
"timeout": 30
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "local",
|
"key": "newvision",
|
||||||
"name": "Local",
|
"name": "(js)新视觉影院(不稳定)",
|
||||||
"type": 3,
|
"api": "https://androidcatvodspider.netlify.app/json/js/newvision.js",
|
||||||
"api": "csp_Local",
|
"timeout": 30,
|
||||||
"searchable": 0,
|
"ext": {
|
||||||
"changeable": 0
|
"box": "TVBox"
|
||||||
|
},
|
||||||
|
"playerType": 0,
|
||||||
|
"type": 3
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "market",
|
"key": "kankan70",
|
||||||
"name": "Market",
|
"name": "(js)70看看┃📺",
|
||||||
"type": 3,
|
"api": "https://androidcatvodspider.netlify.app/json/js/kankan70.js",
|
||||||
"api": "csp_Market",
|
"timeout": 30,
|
||||||
"searchable": 0,
|
"ext": {
|
||||||
"changeable": 0,
|
"box": "TVBox"
|
||||||
"ext": "./market.json"
|
},
|
||||||
|
"playerType": 0,
|
||||||
|
"type": 3
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "push_agent",
|
"key": "jpyy",
|
||||||
"name": "Push",
|
"name": "(js)金牌影院",
|
||||||
"type": 3,
|
"api": "https://androidcatvodspider.netlify.app/json/js/jpyy.js",
|
||||||
"api": "csp_Push",
|
"timeout": 30,
|
||||||
"searchable": 0,
|
"ext": {
|
||||||
"changeable": 0,
|
"box": "TVBox"
|
||||||
"timeout": 60
|
},
|
||||||
|
"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": [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
613
json/test.json
613
json/test.json
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"spider": "https://gh.llkk.cc/https://raw.githubusercontent.com/lushunming/AndroidCatVodSpider/123/jar/custom_spider.jar;md5;77ff0d77d6fccecddd174ee82161f3bd",
|
"spider": "https://ghproxy.net/https://raw.githubusercontent.com/lushunming/AndroidCatVodSpider/refs/heads/tianyiPassword/jar/custom_spider.jar;md5;bb54c03fd035f011b948b4ccf1273819",
|
||||||
"lives": [
|
"lives": [
|
||||||
{
|
{
|
||||||
"name": "电视直播",
|
"name": "电视直播",
|
||||||
|
|
@ -41,26 +41,611 @@
|
||||||
"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": "TgSearchBaidu",
|
"key": "PanTa",
|
||||||
"name": "☁TgSearchBaidu┃网盘",
|
"name": "盘他|139Pan",
|
||||||
"type": 3,
|
"type": 3,
|
||||||
"api": "csp_TgSearchBaidu",
|
"api": "csp_PanTa",
|
||||||
|
"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": {
|
||||||
"api_urls": [
|
"box": "TVBox"
|
||||||
"https://psweb.banye.tech:7777/api/search",
|
},
|
||||||
"https://so.566987.xyz/api/search",
|
"playerType": 0,
|
||||||
"http://152.69.222.142:8088/api/search"
|
"type": 3
|
||||||
],
|
},
|
||||||
"sources": [
|
{
|
||||||
"123盘"
|
"key": "kankan70",
|
||||||
]
|
"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": [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
pluginManagement {
|
pluginManagement {
|
||||||
repositories {
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
maven { url 'https://mirrors.huaweicloud.com/repository/maven/' }
|
|
||||||
maven { url 'https://maven.aliyun.com/repository/public/' }
|
maven { url 'https://maven.aliyun.com/repository/public/' }
|
||||||
maven { url 'https://maven.aliyun.com/repository/google/' }
|
maven { url 'https://maven.aliyun.com/repository/google/' }
|
||||||
maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
|
maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
|
||||||
|
|
@ -10,7 +9,6 @@ pluginManagement {
|
||||||
maven { url 'https://maven.aliyun.com/repository/mapr-public/' }
|
maven { url 'https://maven.aliyun.com/repository/mapr-public/' }
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
|
||||||
|
|
||||||
maven { url "https://plugins.gradle.org/m2/" }
|
maven { url "https://plugins.gradle.org/m2/" }
|
||||||
maven { url "https://www.jitpack.io" }
|
maven { url "https://www.jitpack.io" }
|
||||||
|
|
@ -19,8 +17,7 @@ pluginManagement {
|
||||||
dependencyResolutionManagement {
|
dependencyResolutionManagement {
|
||||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||||
repositories {
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
maven { url 'https://mirrors.huaweicloud.com/repository/maven/' }
|
|
||||||
maven { url 'https://maven.aliyun.com/repository/public/' }
|
maven { url 'https://maven.aliyun.com/repository/public/' }
|
||||||
maven { url 'https://maven.aliyun.com/repository/google/' }
|
maven { url 'https://maven.aliyun.com/repository/google/' }
|
||||||
maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
|
maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
|
||||||
|
|
@ -28,7 +25,6 @@ dependencyResolutionManagement {
|
||||||
maven { url 'https://maven.aliyun.com/repository/central/'}
|
maven { url 'https://maven.aliyun.com/repository/central/'}
|
||||||
maven { url 'https://maven.aliyun.com/repository/mapr-public/' }
|
maven { url 'https://maven.aliyun.com/repository/mapr-public/' }
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
|
||||||
maven { url "https://www.jitpack.io" }
|
maven { url "https://www.jitpack.io" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue