Support WebDAV - part 1
This commit is contained in:
parent
155066d132
commit
92c50f9780
|
|
@ -8,7 +8,7 @@ android {
|
|||
|
||||
defaultConfig {
|
||||
applicationId "com.github.catvod.demo"
|
||||
minSdk 17
|
||||
minSdk 21
|
||||
targetSdk 29
|
||||
ndk { abiFilters "armeabi-v7a" }
|
||||
buildConfigField("String", "CLIENT_ID", "\"${clientId}\"")
|
||||
|
|
@ -36,11 +36,12 @@ android {
|
|||
dependencies {
|
||||
//Debug For HTTP/3
|
||||
debugImplementation 'org.chromium.net:cronet-embedded:101.4951.41'
|
||||
implementation 'com.github.thegrizzlylabs:sardine-android:0.8'
|
||||
implementation 'com.google.net.cronet:cronet-okhttp:0.1.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.10'
|
||||
implementation 'androidx.annotation:annotation:1.5.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.12.13'
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
implementation 'com.google.code.gson:gson:2.10.1'
|
||||
implementation 'cn.wanghaomiao:JsoupXpath:2.5.1'
|
||||
implementation 'com.google.zxing:core:3.3.0'
|
||||
implementation 'com.google.zxing:core:3.4.1'
|
||||
implementation 'org.jsoup:jsoup:1.15.3'
|
||||
}
|
||||
|
|
@ -20,16 +20,20 @@
|
|||
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
|
||||
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
|
||||
|
||||
# Cronet
|
||||
-keep class org.chromium.net.** { *; }
|
||||
-keep class com.google.net.cronet.** { *; }
|
||||
|
||||
# OkHttp
|
||||
-dontwarn okhttp3.**
|
||||
-keep class okio.** { *; }
|
||||
-keep class okhttp3.** { *; }
|
||||
|
||||
# Sardine
|
||||
-keep class com.thegrizzlylabs.sardineandroid.** { *; }
|
||||
|
||||
# Zxing
|
||||
-keepclassmembers enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
# OkHttp
|
||||
-keep class okio.**{*;}
|
||||
-keep class okhttp3.**{*;}
|
||||
|
||||
# Cronet
|
||||
-keep class org.chromium.net.**{*;}
|
||||
-keep class com.google.net.cronet.**{*;}
|
||||
|
|
@ -11,9 +11,9 @@ import org.json.JSONObject;
|
|||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Result {
|
||||
|
||||
|
|
@ -105,7 +105,7 @@ public class Result {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Result header(HashMap<String, String> header) {
|
||||
public Result header(Map<String, String> header) {
|
||||
if (header.isEmpty()) return this;
|
||||
this.header = new Gson().toJson(header);
|
||||
return this;
|
||||
|
|
|
|||
|
|
@ -47,12 +47,12 @@ public class Vod {
|
|||
setVodRemarks(vodRemarks);
|
||||
}
|
||||
|
||||
public Vod(String vodId, String vodName, String vodPic, String vodRemarks, String vodTag) {
|
||||
public Vod(String vodId, String vodName, String vodPic, String vodRemarks, boolean folder) {
|
||||
setVodId(vodId);
|
||||
setVodName(vodName);
|
||||
setVodPic(vodPic);
|
||||
setVodRemarks(vodRemarks);
|
||||
setVodTag(vodTag);
|
||||
setVodTag(folder ? "folder" : "file");
|
||||
}
|
||||
|
||||
public void setTypeName(String typeName) {
|
||||
|
|
|
|||
|
|
@ -120,15 +120,11 @@ public class Item {
|
|||
return Utils.getSize(getSize());
|
||||
}
|
||||
|
||||
public String getVodTag() {
|
||||
return isFolder() ? "folder" : "file";
|
||||
}
|
||||
|
||||
public Vod getVod(String id, String pic) {
|
||||
return new Vod(getVodId(id), getName(), getPic(pic), getRemark(), getVodTag());
|
||||
return new Vod(getVodId(id), getName(), getPic(pic), getRemark(), isFolder());
|
||||
}
|
||||
|
||||
public Vod getVod(Drive drive, String pic) {
|
||||
return new Vod(getVodId(drive.getName()), getName(), getPic(pic), drive.getName(), getVodTag());
|
||||
return new Vod(getVodId(drive.getName()), getName(), getPic(pic), drive.getName(), isFolder());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,107 @@
|
|||
package com.github.catvod.bean.webdav;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.utils.Utils;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.thegrizzlylabs.sardineandroid.DavResource;
|
||||
import com.thegrizzlylabs.sardineandroid.Sardine;
|
||||
import com.thegrizzlylabs.sardineandroid.impl.OkHttpSardine;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Drive {
|
||||
|
||||
@SerializedName("vodPic")
|
||||
private String vodPic;
|
||||
@SerializedName("drives")
|
||||
private List<Drive> drives;
|
||||
@SerializedName("name")
|
||||
private String name;
|
||||
@SerializedName("server")
|
||||
private String server;
|
||||
@SerializedName("user")
|
||||
private String user;
|
||||
@SerializedName("pass")
|
||||
private String pass;
|
||||
@SerializedName("path")
|
||||
private String path;
|
||||
@SerializedName("webdav")
|
||||
private Sardine webdav;
|
||||
|
||||
public static Drive objectFrom(String str) {
|
||||
return new Gson().fromJson(str, Drive.class);
|
||||
}
|
||||
|
||||
public Drive(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<Drive> getDrives() {
|
||||
return drives == null ? new ArrayList<>() : drives;
|
||||
}
|
||||
|
||||
public String getVodPic() {
|
||||
return TextUtils.isEmpty(vodPic) ? "" : vodPic;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return TextUtils.isEmpty(name) ? "" : name;
|
||||
}
|
||||
|
||||
public String getServer() {
|
||||
return TextUtils.isEmpty(server) ? "" : server;
|
||||
}
|
||||
|
||||
public String getUser() {
|
||||
return TextUtils.isEmpty(user) ? "" : user;
|
||||
}
|
||||
|
||||
public String getPass() {
|
||||
return TextUtils.isEmpty(pass) ? "" : pass;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return TextUtils.isEmpty(path) ? "" : path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = TextUtils.isEmpty(path) ? "" : path;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return getServer().replace(getPath(), "");
|
||||
}
|
||||
|
||||
public Sardine getWebdav() {
|
||||
return webdav;
|
||||
}
|
||||
|
||||
public Class toType() {
|
||||
return new Class(getName(), getName(), "1");
|
||||
}
|
||||
|
||||
public Drive init() {
|
||||
webdav = new OkHttpSardine();
|
||||
webdav.setCredentials(getUser(), getPass());
|
||||
setPath(Uri.parse(getServer()).getPath());
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vod vod(DavResource item, String vodPic) {
|
||||
return new Vod(getName() + item.getPath(), item.getName(), vodPic, Utils.getSize(item.getContentLength()), item.isDirectory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof Drive)) return false;
|
||||
Drive it = (Drive) obj;
|
||||
return getName().equals(it.getName());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.github.catvod.bean.webdav;
|
||||
|
||||
import com.thegrizzlylabs.sardineandroid.DavResource;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class Sorter implements Comparator<DavResource> {
|
||||
|
||||
private final String type;
|
||||
private final String order;
|
||||
|
||||
public static void sort(String type, String order, List<DavResource> items) {
|
||||
Collections.sort(items, new Sorter(type, order));
|
||||
}
|
||||
|
||||
public Sorter(String type, String order) {
|
||||
this.type = type;
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(DavResource o1, DavResource o2) {
|
||||
boolean asc = order.equals("asc");
|
||||
switch (type) {
|
||||
case "name":
|
||||
return asc ? o1.getName().compareTo(o2.getName()) : o2.getName().compareTo(o1.getName());
|
||||
case "size":
|
||||
return asc ? Long.compare(o1.getContentLength(), o2.getContentLength()) : Long.compare(o2.getContentLength(), o1.getContentLength());
|
||||
case "date":
|
||||
return asc ? o1.getModified().compareTo(o2.getModified()) : o2.getModified().compareTo(o1.getModified());
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@ import com.github.catvod.crawler.SpiderDebug;
|
|||
import com.github.catvod.net.OkHttp;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
|
|
@ -13,12 +12,14 @@ public class Proxy extends Spider {
|
|||
|
||||
private static int port = -1;
|
||||
|
||||
public static Object[] proxy(Map<String, String> params) throws UnsupportedEncodingException {
|
||||
public static Object[] proxy(Map<String, String> params) throws Exception {
|
||||
switch (Objects.requireNonNull(params.get("do"))) {
|
||||
case "ck":
|
||||
return new Object[]{200, "text/plain; charset=utf-8", new ByteArrayInputStream("ok".getBytes("UTF-8"))};
|
||||
case "ali":
|
||||
return Ali.vod(params);
|
||||
case "webdav":
|
||||
return WebDAV.vod(params);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,197 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Filter;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Sub;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.bean.webdav.Drive;
|
||||
import com.github.catvod.bean.webdav.Sorter;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Utils;
|
||||
import com.thegrizzlylabs.sardineandroid.DavResource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class WebDAV extends Spider {
|
||||
|
||||
private static List<Drive> drives;
|
||||
private List<String> playExt;
|
||||
private List<String> allExt;
|
||||
private String vodPic;
|
||||
private String ext;
|
||||
|
||||
private List<Filter> getFilter() {
|
||||
List<Filter> items = new ArrayList<>();
|
||||
items.add(new Filter("type", "排序類型", Arrays.asList(new Filter.Value("預設", ""), new Filter.Value("名稱", "name"), new Filter.Value("大小", "size"), new Filter.Value("修改時間", "date"))));
|
||||
items.add(new Filter("order", "排序方式", Arrays.asList(new Filter.Value("預設", ""), new Filter.Value("⬆", "asc"), new Filter.Value("⬇", "desc"))));
|
||||
return items;
|
||||
}
|
||||
|
||||
private void fetchRule() {
|
||||
if (drives != null && !drives.isEmpty()) return;
|
||||
if (ext.startsWith("http")) ext = OkHttp.string(ext);
|
||||
Drive drive = Drive.objectFrom(ext);
|
||||
drives = drive.getDrives();
|
||||
vodPic = drive.getVodPic();
|
||||
}
|
||||
|
||||
private String getExt(DavResource item) {
|
||||
return item.getName().substring(item.getName().lastIndexOf(".") + 1);
|
||||
}
|
||||
|
||||
private String removeExt(DavResource item) {
|
||||
return item.getName().indexOf(".") > 0 ? item.getName().substring(0, item.getName().lastIndexOf(".")) : item.getName();
|
||||
}
|
||||
|
||||
private static Drive getDrive(String name) {
|
||||
return drives.get(drives.indexOf(new Drive(name)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) {
|
||||
playExt = Arrays.asList("mp4", "mkv", "flv", "avi", "mp3", "aac", "flac", "m4a");
|
||||
allExt = new ArrayList<>(Arrays.asList("ass", "ssa", "srt"));
|
||||
allExt.addAll(playExt);
|
||||
ext = extend;
|
||||
fetchRule();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) throws Exception {
|
||||
fetchRule();
|
||||
List<Class> classes = new ArrayList<>();
|
||||
LinkedHashMap<String, List<Filter>> filters = new LinkedHashMap<>();
|
||||
for (Drive drive : drives) classes.add(drive.init().toType());
|
||||
for (Class item : classes) filters.put(item.getTypeId(), getFilter());
|
||||
return Result.string(classes, filters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
|
||||
String key = tid.contains("/") ? tid.substring(0, tid.indexOf("/")) : tid;
|
||||
String path = tid.contains("/") ? tid.substring(tid.indexOf("/")) : "";
|
||||
String order = extend.containsKey("order") ? extend.get("order") : "";
|
||||
String type = extend.containsKey("type") ? extend.get("type") : "";
|
||||
List<DavResource> folders = new ArrayList<>();
|
||||
List<DavResource> files = new ArrayList<>();
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Drive drive = getDrive(key);
|
||||
for (DavResource item : getList(drive, path, playExt)) {
|
||||
if (item.isDirectory()) folders.add(item);
|
||||
else files.add(item);
|
||||
}
|
||||
if (!TextUtils.isEmpty(type) && !TextUtils.isEmpty(order)) {
|
||||
Sorter.sort(type, order, folders);
|
||||
Sorter.sort(type, order, files);
|
||||
}
|
||||
for (DavResource item : folders) list.add(drive.vod(item, vodPic));
|
||||
for (DavResource item : files) list.add(drive.vod(item, vodPic));
|
||||
return Result.get().vod(list).page().string();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
String id = ids.get(0);
|
||||
String key = id.contains("/") ? id.substring(0, id.indexOf("/")) : id;
|
||||
String name = id.substring(id.lastIndexOf("/") + 1);
|
||||
String parent = id.substring(0, id.lastIndexOf("/"));
|
||||
String path = parent.contains("/") ? parent.substring(parent.indexOf("/")) + "/" : "";
|
||||
Drive drive = getDrive(key);
|
||||
List<DavResource> parents = getList(drive, path, allExt);
|
||||
List<DavResource> subs = getSubs(parents);
|
||||
Sorter.sort("name", "asc", parents);
|
||||
List<String> playUrls = new ArrayList<>();
|
||||
for (DavResource item : parents) {
|
||||
if (playExt.contains(getExt(item))) {
|
||||
playUrls.add(item.getName() + "$" + drive.getName() + item.getPath() + findSubs(drive, item, subs));
|
||||
}
|
||||
}
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId(id);
|
||||
//TODO 資料夾名稱
|
||||
vod.setVodName(name);
|
||||
vod.setVodPic(vodPic);
|
||||
vod.setVodPlayFrom(key);
|
||||
vod.setVodPlayUrl(TextUtils.join("#", playUrls));
|
||||
return Result.string(vod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
|
||||
String[] ids = id.split("~~~");
|
||||
String key = ids[0].contains("/") ? ids[0].substring(0, ids[0].indexOf("/")) : ids[0];
|
||||
return Result.get().url(getProxyUrl(key, ids[0])).subs(getSub(ids)).string();
|
||||
}
|
||||
|
||||
private List<DavResource> getList(Drive drive, String path, List<String> ext) throws Exception {
|
||||
path = drive.getHost() + (path.startsWith(drive.getPath()) ? path : drive.getPath() + path);
|
||||
List<DavResource> items = drive.getWebdav().list(path);
|
||||
items.remove(0); //Remove parent
|
||||
Iterator<DavResource> iterator = items.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
DavResource item = iterator.next();
|
||||
if (!item.isDirectory() && !item.getName().contains(".")) iterator.remove();
|
||||
if (!item.isDirectory() && !ext.contains(getExt(item))) iterator.remove();
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
private List<DavResource> getSubs(List<DavResource> items) {
|
||||
List<DavResource> subs = new ArrayList<>();
|
||||
for (DavResource item : items) if (Utils.isSub(getExt(item))) subs.add(item);
|
||||
return subs;
|
||||
}
|
||||
|
||||
private String findSubs(Drive drive, DavResource res, List<DavResource> items) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (DavResource item : items) if (removeExt(item).equals(removeExt(res))) sb.append("~~~").append(item.getName()).append("@@@").append(getExt(item)).append("@@@").append(drive.getName() + item.getPath());
|
||||
return sb.length() > 0 ? sb.toString() : findSubs(drive, items);
|
||||
}
|
||||
|
||||
private String findSubs(Drive drive, List<DavResource> items) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (DavResource item : items) sb.append("~~~").append(item.getName()).append("@@@").append(getExt(item)).append("@@@").append(drive.getName() + item.getPath());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private List<Sub> getSub(String[] ids) {
|
||||
List<Sub> sub = new ArrayList<>();
|
||||
for (String text : ids) {
|
||||
if (!text.contains("@@@")) continue;
|
||||
String[] split = text.split("@@@");
|
||||
String name = split[0];
|
||||
String ext = split[1];
|
||||
String key = split[2].contains("/") ? split[2].substring(0, split[2].indexOf("/")) : split[2];
|
||||
String url = getProxyUrl(key, split[2]);
|
||||
sub.add(Sub.create().name(name).ext(ext).url(url));
|
||||
}
|
||||
return sub;
|
||||
}
|
||||
|
||||
private String getProxyUrl(String key, String path) {
|
||||
return Proxy.getUrl() + "?do=webdav" + "&key=" + key + "&url=" + getDrive(key).getHost() + path.replace(key, "");
|
||||
}
|
||||
|
||||
public static Object[] vod(Map<String, String> params) throws IOException {
|
||||
String key = params.get("key");
|
||||
String url = params.get("url");
|
||||
Drive drive = getDrive(key);
|
||||
Object[] result = new Object[3];
|
||||
result[0] = 200;
|
||||
result[1] = "application/octet-stream";
|
||||
result[2] = drive.getWebdav().get(url);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -39,7 +39,7 @@ public class Utils {
|
|||
}
|
||||
|
||||
public static String getSize(double size) {
|
||||
if (size == 0) return "";
|
||||
if (size <= 0) return "";
|
||||
if (size > 1024 * 1024 * 1024 * 1024.0) {
|
||||
size /= (1024 * 1024 * 1024 * 1024.0);
|
||||
return String.format(Locale.getDefault(), "%.2f%s", size, "TB");
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
||||
org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
|
|
@ -15,6 +15,7 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
|||
# Android operating system, and which are packaged with your app"s APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
# Enables namespacing of each library's R class so that its R class includes only the
|
||||
# resources declared in the library itself and none from the library's dependencies,
|
||||
# thereby reducing the size of the R class for that library
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ dependencyResolutionManagement {
|
|||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
}
|
||||
rootProject.name = "CatVodSpider"
|
||||
|
|
|
|||
Loading…
Reference in New Issue