commit bceede467d3ef24f6c57425a3b7fb62767ae8c1d Author: zhangjie <768284730@qq.com> Date: Sun Mar 10 16:44:17 2024 +0800 '第一版' diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f96d801 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.gradle +.idea +*build +/local.properties \ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..7d9dec2 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +fm.t4tv.hz.cz \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..4b83a1f --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# CatVodSpider + +### Based on CatVod + +https://github.com/CatVodTVOfficial/CatVodTVSpider diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..31af501 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,53 @@ +plugins { + id 'com.android.application' + id 'ru.cleverpumpkin.proguard-dictionaries-generator' +} + +android { + compileSdk 33 + + defaultConfig { + applicationId "com.github.catvod.demo" + minSdk 17 + targetSdk 28 + buildConfigField("String", "CLIENT_ID", "\"${clientId}\"") + } + + buildTypes { + release { + minifyEnabled true + proguardFiles 'proguard-rules.pro' + proguardDictionaries { + dictionaryNames = ["build/class-dictionary", "build/package-dictionary", "build/obfuscation-dictionary"] + minLineLength 1 + maxLineLength 3 + linesCountInDictionary 100000 + } + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + namespace 'com.github.catvod' + + configurations.configureEach { + resolutionStrategy { + force 'com.squareup.okhttp3:okhttp:3.12.13' + } + } +} + +dependencies { + implementation 'com.googlecode.juniversalchardet:juniversalchardet:1.0.3' + implementation 'com.github.thegrizzlylabs:sardine-android:0.8' + implementation 'wang.harlon.quickjs:wrapper-android:0.21.1' + implementation 'com.squareup.okhttp3:okhttp:3.12.13' + implementation 'com.google.code.gson:gson:2.8.6' + implementation 'cn.wanghaomiao:JsoupXpath:2.5.1' + implementation 'org.nanohttpd:nanohttpd:2.3.1' + implementation 'com.google.zxing:core:3.3.0' + implementation 'com.orhanobut:logger:2.2.0' + implementation 'org.jsoup:jsoup:1.15.3' +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..4e9d28a --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,53 @@ +# Merge +-flattenpackagehierarchy com.github.catvod.spider.merge +-dontwarn org.slf4j.impl.StaticLoggerBinder + +# Spider +-keep class com.github.catvod.js.* { *; } +-keep class com.github.catvod.crawler.* { *; } +-keep class com.github.catvod.spider.* { public ; } +-keep class com.github.catvod.parser.* { public ; } + +# AndroidX +-keep class androidx.core.** { *; } + +# Gson +-keepattributes Signature +-keepattributes *Annotation* +-dontwarn sun.misc.** +-keep class com.google.gson.** { *; } +-keep class * extends com.google.gson.TypeAdapter +-keep class * implements com.google.gson.TypeAdapterFactory +-keep class * implements com.google.gson.JsonSerializer +-keep class * implements com.google.gson.JsonDeserializer +-keepclassmembers,allowobfuscation class * { @com.google.gson.annotations.SerializedName ; } +-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken +-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken + +# Nano +-keep class fi.iki.elonen.** { *; } + +# OkHttp +-dontwarn okhttp3.** +-keep class okio.** { *; } +-keep class okhttp3.** { *; } + +# Logger +-keep class com.orhanobut.logger.** { *; } + +# QuickJS +-keep class com.whl.quickjs.** { *; } + +# Sardine +-keep class com.thegrizzlylabs.sardineandroid.** { *; } + +# Smbj +-keep class com.hierynomus.** { *; } +-keep class net.engio.mbassy.** { *; } + +# Zxing +-keep class com.google.zxing.** { *; } +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..d68fdf9 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/github/catvod/api/AliYun.java b/app/src/main/java/com/github/catvod/api/AliYun.java new file mode 100644 index 0000000..e0497f5 --- /dev/null +++ b/app/src/main/java/com/github/catvod/api/AliYun.java @@ -0,0 +1,659 @@ +package com.github.catvod.api; + +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.net.UrlQuerySanitizer; +import android.os.SystemClock; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.github.catvod.BuildConfig; +import com.github.catvod.bean.Result; +import com.github.catvod.bean.Sub; +import com.github.catvod.bean.Vod; +import com.github.catvod.bean.ali.Cache; +import com.github.catvod.bean.ali.Code; +import com.github.catvod.bean.ali.Data; +import com.github.catvod.bean.ali.Download; +import com.github.catvod.bean.ali.Drive; +import com.github.catvod.bean.ali.Item; +import com.github.catvod.bean.ali.OAuth; +import com.github.catvod.bean.ali.Preview; +import com.github.catvod.bean.ali.Resp; +import com.github.catvod.bean.ali.Share; +import com.github.catvod.bean.ali.User; +import com.github.catvod.crawler.SpiderDebug; +import com.github.catvod.net.OkHttp; +import com.github.catvod.net.OkResult; +import com.github.catvod.spider.Init; +import com.github.catvod.spider.Proxy; +import com.github.catvod.utils.Json; +import com.github.catvod.utils.Notify; +import com.github.catvod.utils.Path; +import com.github.catvod.utils.ProxyVideo; +import com.github.catvod.utils.QRCode; +import com.github.catvod.utils.ResUtil; +import com.github.catvod.utils.Util; +import com.google.gson.JsonObject; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.locks.ReentrantLock; + +import okhttp3.Response; + +public class AliYun { + + private final Map> m3u8MediaMap; + private final Map shareDownloadMap; + private final Map downloadMap; + private final List tempIds; + private final ReentrantLock lock; + private final Cache cache; + private ScheduledExecutorService service; + private String refreshToken; + private AlertDialog dialog; + private Share share; + + private static class Loader { + static volatile AliYun INSTANCE = new AliYun(); + } + + public static AliYun get() { + return Loader.INSTANCE; + } + + public File getCache() { + return Path.tv("aliyun"); + } + + private AliYun() { + Init.checkPermission(); + lock = new ReentrantLock(); + tempIds = new ArrayList<>(); + downloadMap = new HashMap<>(); + m3u8MediaMap = new HashMap<>(); + shareDownloadMap = new HashMap<>(); + cache = Cache.objectFrom(Path.read(getCache())); + } + + public void setRefreshToken(String token) { + this.refreshToken = token; + } + + public HashMap getHeader() { + HashMap headers = new HashMap<>(); + headers.put("User-Agent", Util.CHROME); + headers.put("Referer", "https://www.aliyundrive.com/"); + return headers; + } + + private HashMap getHeaders() { + HashMap headers = getHeader(); + headers.put("x-share-token", share.getShareToken()); + headers.put("X-Canary", "client=Android,app=adrive,version=v4.3.1"); + return headers; + } + + private HashMap getHeaderAuth() { + HashMap headers = getHeader(); + headers.put("x-share-token", share.getShareToken()); + headers.put("X-Canary", "client=Android,app=adrive,version=v4.3.1"); + if (cache.getUser().isAuthed()) headers.put("authorization", cache.getUser().getAuthorization()); + return headers; + } + + private HashMap getHeaderOpen() { + HashMap headers = getHeader(); + headers.put("authorization", cache.getOAuth().getAuthorization()); + return headers; + } + + private boolean alist(String url, JsonObject param) { + String api = "https://api.xhofe.top/alist/ali_open/" + url; + OkResult result = OkHttp.post(api, param.toString(), getHeader()); + SpiderDebug.log(result.getCode() + "," + api + "," + result.getBody()); + if (isManyRequest(result.getBody())) return false; + cache.setOAuth(OAuth.objectFrom(result.getBody())); + return true; + } + + private String post(String url, JsonObject param) { + url = url.startsWith("https") ? url : "https://api.aliyundrive.com/" + url; + OkResult result = OkHttp.post(url, param.toString(), getHeader()); + SpiderDebug.log(result.getCode() + "," + url + "," + result.getBody()); + return result.getBody(); + } + + private String auth(String url, String json, boolean retry) { + url = url.startsWith("https") ? url : "https://api.aliyundrive.com/" + url; + OkResult result = OkHttp.post(url, json, url.contains("file/list") ? getHeaders() : getHeaderAuth()); + SpiderDebug.log(result.getCode() + "," + url + "," + result.getBody()); + if (retry && result.getCode() == 401 && refreshAccessToken()) return auth(url, json, false); + if (retry && result.getCode() == 429) return auth(url, json, false); + return result.getBody(); + } + + private String oauth(String url, String json, boolean retry) { + url = url.startsWith("https") ? url : "https://open.aliyundrive.com/adrive/v1.0/" + url; + OkResult result = OkHttp.post(url, json, getHeaderOpen()); + SpiderDebug.log(result.getCode() + "," + url + "," + result.getBody()); + if (retry && (result.getCode() == 400 || result.getCode() == 401) && refreshOpenToken()) return oauth(url, json, false); + return result.getBody(); + } + + private boolean isManyRequest(String result) { + if (!result.contains("Too Many Requests")) return false; + Notify.show("洗洗睡吧,Too Many Requests。"); + cache.getOAuth().clean(); + return true; + } + + private boolean onTimeout() { + stopService(); + return false; + } + + private void refreshShareToken(String shareId) { + if (share != null && share.alive(shareId)) return; + SpiderDebug.log("refreshShareToken..."); + JsonObject param = new JsonObject(); + param.addProperty("share_id", shareId); + param.addProperty("share_pwd", ""); + String json = post("v2/share_link/get_share_token", param); + share = Share.objectFrom(json).setShareId(shareId).setTime(); + if (share.getShareToken().isEmpty()) Notify.show("來晚啦,該分享已失效。"); + } + + private boolean refreshAccessToken() { + try { + SpiderDebug.log("refreshAccessToken..."); + JsonObject param = new JsonObject(); + String token = cache.getUser().getRefreshToken(); + if (token.isEmpty()) token = refreshToken; + if (token != null && token.startsWith("http")) token = OkHttp.string(token).trim(); + param.addProperty("refresh_token", token); + param.addProperty("grant_type", "refresh_token"); + String json = post("https://auth.aliyundrive.com/v2/account/token", param); + cache.setUser(User.objectFrom(json)); + if (cache.getUser().getAccessToken().isEmpty()) throw new Exception(json); + return true; + } catch (Exception e) { + if (e instanceof TimeoutException) return onTimeout(); + cache.getUser().clean(); + e.printStackTrace(); + stopService(); + startFlow(); + return true; + } finally { + while (cache.getUser().getAccessToken().isEmpty()) SystemClock.sleep(250); + } + } + + private void getDriveId() { + SpiderDebug.log("Get Drive Id..."); + String json = auth("https://user.aliyundrive.com/v2/user/get", "{}", true); + cache.setDrive(Drive.objectFrom(json)); + } + + private boolean oauthRequest() { + SpiderDebug.log("OAuth Request..."); + JsonObject param = new JsonObject(); + param.addProperty("authorize", 1); + param.addProperty("scope", "user:base,file:all:read,file:all:write"); + String url = "https://open.aliyundrive.com/oauth/users/authorize?client_id=" + BuildConfig.CLIENT_ID + "&redirect_uri=https://alist.nn.ci/tool/aliyundrive/callback&scope=user:base,file:all:read,file:all:write&state="; + String json = auth(url, param.toString(), true); + return oauthRedirect(Code.objectFrom(json).getCode()); + } + + private boolean oauthRedirect(String code) { + SpiderDebug.log("OAuth Redirect..."); + JsonObject param = new JsonObject(); + param.addProperty("code", code); + param.addProperty("grant_type", "authorization_code"); + return alist("code", param); + } + + private boolean refreshOpenToken() { + if (cache.getOAuth().getRefreshToken().isEmpty()) return oauthRequest(); + SpiderDebug.log("refreshOpenToken..."); + JsonObject param = new JsonObject(); + param.addProperty("grant_type", "refresh_token"); + param.addProperty("refresh_token", cache.getOAuth().getRefreshToken()); + return alist("token", param); + } + + public Vod getVod(String url, String shareId, String fileId) { + refreshShareToken(shareId); + JsonObject param = new JsonObject(); + param.addProperty("share_id", shareId); + Share share = Share.objectFrom(post("adrive/v3/share_link/get_share_by_anonymous", param)); + List files = new ArrayList<>(); + List subs = new ArrayList<>(); + listFiles(shareId, new Item(getParentFileId(fileId, share)), files, subs); + Collections.sort(files); + List playFrom = Arrays.asList("轉存原畫", "分享原畫", "代理普畫"); + List episode = new ArrayList<>(); + List playUrl = new ArrayList<>(); + for (Item file : files) episode.add(file.getDisplayName() + "$" + shareId + "+" + file.getFileId() + findSubs(file.getName(), subs)); + for (int i = 0; i < playFrom.size(); i++) playUrl.add(TextUtils.join("#", episode)); + Vod vod = new Vod(); + vod.setVodId(url); + vod.setVodContent(url); + vod.setVodPic(share.getAvatar()); + vod.setVodName(share.getShareName()); + vod.setVodPlayUrl(TextUtils.join("$$$", playUrl)); + vod.setVodPlayFrom(TextUtils.join("$$$", playFrom)); + vod.setTypeName("阿里雲盤"); + return vod; + } + + private void listFiles(String shareId, Item folder, List files, List subs) { + listFiles(shareId, folder, files, subs, ""); + } + + private void listFiles(String shareId, Item parent, List files, List subs, String marker) { + List folders = new ArrayList<>(); + JsonObject param = new JsonObject(); + param.addProperty("limit", 200); + param.addProperty("share_id", shareId); + param.addProperty("parent_file_id", parent.getFileId()); + param.addProperty("order_by", "name"); + param.addProperty("order_direction", "ASC"); + if (marker.length() > 0) param.addProperty("marker", marker); + Item item = Item.objectFrom(auth("adrive/v3/file/list", param.toString(), true)); + for (Item file : item.getItems()) { + if (file.getType().equals("folder")) { + folders.add(file); + } else if (file.getCategory().equals("video") || file.getCategory().equals("audio")) { + files.add(file.parent(parent.getName())); + } else if (Util.isSub(file.getExt())) { + subs.add(file); + } + } + if (item.getNextMarker().length() > 0) { + listFiles(shareId, parent, files, subs, item.getNextMarker()); + } + for (Item folder : folders) { + listFiles(shareId, folder, files, subs); + } + } + + private String getParentFileId(String fileId, Share share) { + if (!TextUtils.isEmpty(fileId)) return fileId; + if (share.getFileInfos().isEmpty()) return ""; + Item item = share.getFileInfos().get(0); + return item.getType().equals("folder") ? item.getFileId() : "root"; + } + + private void pair(String name1, List items, List subs) { + for (Item item : items) { + String name2 = Util.removeExt(item.getName()).toLowerCase(); + if (name1.contains(name2) || name2.contains(name1)) subs.add(item); + } + } + + private String findSubs(String name1, List items) { + List subs = new ArrayList<>(); + pair(Util.removeExt(name1).toLowerCase(), items, subs); + if (subs.isEmpty()) subs.addAll(items); + StringBuilder sb = new StringBuilder(); + for (Item sub : subs) sb.append("+").append(Util.removeExt(sub.getName())).append("@@@").append(sub.getExt()).append("@@@").append(sub.getFileId()); + return sb.toString(); + } + + public List getSubs(String[] ids) { + List sub = new ArrayList<>(); + for (String text : ids) { + if (!text.contains("@@@")) continue; + String[] split = text.split("@@@"); + String name = split[0]; + String ext = split[1]; + String url = Proxy.getUrl() + "?do=ali&type=sub&shareId=" + ids[0] + "&fileId=" + split[2]; + sub.add(Sub.create().name(name).ext(ext).url(url)); + } + return sub; + } + + public String getShareDownloadUrl(String shareId, String fileId) { + try { + if (shareDownloadMap.containsKey(fileId) && shareDownloadMap.get(fileId) != null && !isExpire(shareDownloadMap.get(fileId))) return shareDownloadMap.get(fileId); + refreshShareToken(shareId); + SpiderDebug.log("getShareDownloadUrl..." + fileId); + JsonObject param = new JsonObject(); + param.addProperty("file_id", fileId); + param.addProperty("share_id", shareId); + param.addProperty("expire_sec", 600); + String json = auth("v2/file/get_share_link_download_url", param.toString(), false); + String url = Json.parse(json).getAsJsonObject().get("download_url").getAsString(); + shareDownloadMap.put(fileId, url); + return url; + } catch (Exception e) { + e.printStackTrace(); + return ""; + } + } + + public String getDownloadUrl(String shareId, String fileId) { + try { + if (downloadMap.containsKey(fileId) && downloadMap.get(fileId) != null && !isExpire(downloadMap.get(fileId))) return downloadMap.get(fileId); + refreshShareToken(shareId); + SpiderDebug.log("getDownloadUrl..." + fileId); + tempIds.add(0, copy(shareId, fileId)); + JsonObject param = new JsonObject(); + param.addProperty("file_id", tempIds.get(0)); + param.addProperty("drive_id", cache.getDrive().getDriveId()); + param.addProperty("expire_sec", 900); + String json = oauth("openFile/getDownloadUrl", param.toString(), true); + String url = Download.objectFrom(json).getUrl(); + downloadMap.put(fileId, url); + return url; + } catch (Exception e) { + e.printStackTrace(); + return ""; + } finally { + Init.execute(this::deleteAll); + } + } + + public Preview.Info getVideoPreviewPlayInfo(String shareId, String fileId) { + try { + refreshShareToken(shareId); + SpiderDebug.log("getVideoPreviewPlayInfo..." + fileId); + tempIds.add(0, copy(shareId, fileId)); + JsonObject param = new JsonObject(); + param.addProperty("file_id", tempIds.get(0)); + param.addProperty("drive_id", cache.getDrive().getDriveId()); + param.addProperty("category", "live_transcoding"); + param.addProperty("url_expire_sec", 900); + String json = oauth("openFile/getVideoPreviewPlayInfo", param.toString(), true); + return Preview.objectFrom(json).getVideoPreviewPlayInfo(); + } catch (Exception e) { + e.printStackTrace(); + return new Preview.Info(); + } finally { + Init.execute(this::deleteAll); + } + } + + public String playerContent(String[] ids, String flag) { + if (flag.split("#")[0].equals("代理普畫")) { + return getPreviewContent(ids); + } else if (flag.split("#")[0].equals("轉存原畫")) { + return Result.get().url(proxyVideoUrl("open", ids[0], ids[1])).octet().subs(getSubs(ids)).header(getHeader()).string(); + } else if (flag.split("#")[0].equals("分享原畫")) { + return Result.get().url(proxyVideoUrl("share", ids[0], ids[1])).octet().subs(getSubs(ids)).header(getHeader()).string(); + } else { + return ""; + } + } + + private String getPreviewContent(String[] ids) { + Preview.Info info = getVideoPreviewPlayInfo(ids[0], ids[1]); + List url = getPreviewUrl(info, ids[0], ids[1], true); + List subs = getSubs(ids); + subs.addAll(getSubs(info)); + return Result.get().url(url).m3u8().subs(subs).header(getHeader()).string(); + } + + private List getPreviewUrl(Preview.Info info, String shareId, String fileId, boolean proxy) { + List tasks = info.getLiveTranscodingTaskList(); + List url = new ArrayList<>(); + for (int i = tasks.size() - 1; i >= 0; i--) { + url.add(tasks.get(i).getTemplateId()); + url.add(proxy ? proxyVideoUrl("preview", shareId, fileId, tasks.get(i).getTemplateId()) : tasks.get(i).getUrl()); + } + return url; + } + + private List getSubs(Preview.Info info) { + List subs = new ArrayList<>(); + for (Preview.LiveTranscodingTask task : info.getLiveTranscodingSubtitleTaskList()) subs.add(task.getSub()); + return subs; + } + + private String copy(String shareId, String fileId) { + if (cache.getDrive().getDriveId().isEmpty()) getDriveId(); + SpiderDebug.log("Copy..." + fileId); + String json = "{\"requests\":[{\"body\":{\"file_id\":\"%s\",\"share_id\":\"%s\",\"auto_rename\":true,\"to_parent_file_id\":\"root\",\"to_drive_id\":\"%s\"},\"headers\":{\"Content-Type\":\"application/json\"},\"id\":\"0\",\"method\":\"POST\",\"url\":\"/file/copy\"}],\"resource\":\"file\"}"; + json = String.format(json, fileId, shareId, cache.getDrive().getDriveId()); + Resp resp = Resp.objectFrom(auth("adrive/v2/batch", json, true)); + return resp.getResponse().getBody().getFileId(); + } + + private void deleteAll() { + List ids = new ArrayList<>(tempIds); + for (String id : ids) { + boolean deleted = delete(id); + if (deleted) tempIds.remove(id); + } + } + + private boolean delete(String fileId) { + SpiderDebug.log("Delete..." + fileId); + String json = "{\"requests\":[{\"body\":{\"drive_id\":\"%s\",\"file_id\":\"%s\"},\"headers\":{\"Content-Type\":\"application/json\"},\"id\":\"%s\",\"method\":\"POST\",\"url\":\"/file/delete\"}],\"resource\":\"file\"}"; + json = String.format(json, cache.getDrive().getDriveId(), fileId, fileId); + Resp resp = Resp.objectFrom(auth("adrive/v2/batch", json, true)); + return resp.getResponse().getStatus() == 404; + } + + private String proxyVideoUrl(String cate, String shareId, String fileId) { + return String.format(Proxy.getUrl() + "?do=ali&type=video&cate=%s&shareId=%s&fileId=%s", cate, shareId, fileId); + } + + private String proxyVideoUrl(String cate, String shareId, String fileId, String templateId) { + return String.format(Proxy.getUrl() + "?do=ali&type=video&cate=%s&shareId=%s&fileId=%s&templateId=%s", cate, shareId, fileId, templateId); + } + + private String proxyVideoUrl(String cate, String shareId, String fileId, String templateId, String mediaId) { + return String.format(Proxy.getUrl() + "?do=ali&type=video&cate=%s&shareId=%s&fileId=%s&templateId=%s&mediaId=%s", cate, shareId, fileId, templateId, mediaId); + } + + private static boolean isExpire(String url) { + String expires = new UrlQuerySanitizer(url).getValue("x-oss-expires"); + if (TextUtils.isEmpty(expires)) return false; + return Long.parseLong(expires) - getTimeStamp() <= 60; + } + + private static long getTimeStamp() { + return System.currentTimeMillis() / 1000; + } + + public Object[] proxyVideo(Map params) throws Exception { + if (dialog != null && dialog.isShowing()) return null; + String templateId = params.get("templateId"); + String shareId = params.get("shareId"); + String mediaId = params.get("mediaId"); + String fileId = params.get("fileId"); + String cate = params.get("cate"); + String downloadUrl = ""; + + if ("preview".equals(cate)) { + return new Object[]{200, "application/vnd.apple.mpegurl", new ByteArrayInputStream(getM3u8(shareId, fileId, templateId).getBytes())}; + } + + if ("open".equals(cate)) { + downloadUrl = getDownloadUrl(shareId, fileId); + } else if ("share".equals(cate)) { + downloadUrl = getShareDownloadUrl(shareId, fileId); + } else if ("m3u8".equals(cate)) { + lock.lock(); + String mediaUrl = m3u8MediaMap.get(fileId).get(mediaId); + if (isExpire(mediaUrl)) { + getM3u8(shareId, fileId, templateId); + mediaUrl = m3u8MediaMap.get(fileId).get(mediaId); + } + lock.unlock(); + downloadUrl = mediaUrl; + } + + Map headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + for (String key : params.keySet()) { + if (key.equals("referer") || key.equals("icy-metadata") || key.equals("range") || key.equals("connection") || key.equals("accept-encoding") || key.equals("user-agent")) { + headers.put(key, params.get(key)); + } + } + + return new Object[]{ProxyVideo.proxy(downloadUrl, headers)}; + } + + private String getM3u8Url(String shareId, String fileId, String templateId) { + Preview.Info info = getVideoPreviewPlayInfo(shareId, fileId); + List url = getPreviewUrl(info, shareId, fileId, false); + Map previewMap = new HashMap<>(); + for (int i = 0; i < url.size(); i = i + 2) { + previewMap.put(url.get(i), url.get(i + 1)); + } + return previewMap.get(templateId); + } + + private String getM3u8(String shareId, String fileId, String templateId) { + String m3u8Url = getM3u8Url(shareId, fileId, templateId); + String m3u8 = OkHttp.string(m3u8Url, getHeader()); + String[] m3u8Arr = m3u8.split("\n"); + List listM3u8 = new ArrayList<>(); + Map media = new HashMap<>(); + String site = m3u8Url.substring(0, m3u8Url.lastIndexOf("/")) + "/"; + int mediaId = 0; + for (String oneLine : m3u8Arr) { + String thisOne = oneLine; + if (oneLine.contains("x-oss-expires")) { + media.put(String.valueOf(mediaId), site + thisOne); + thisOne = proxyVideoUrl("m3u8", shareId, fileId, templateId, String.valueOf(mediaId)); + mediaId++; + } + listM3u8.add(thisOne); + } + m3u8MediaMap.put(fileId, media); + return TextUtils.join("\n", listM3u8); + } + + public Object[] proxySub(Map params) throws Exception { + String fileId = params.get("fileId"); + String shareId = params.get("shareId"); + Response res = OkHttp.newCall(getDownloadUrl(shareId, fileId), getHeaderAuth()); + byte[] body = Util.toUtf8(res.body().bytes()); + Object[] result = new Object[3]; + result[0] = 200; + result[1] = "application/octet-stream"; + result[2] = new ByteArrayInputStream(body); + return result; + } + + private void startFlow() { + Init.run(this::showInput); + } + + private void showInput() { + try { + int margin = ResUtil.dp2px(16); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + FrameLayout frame = new FrameLayout(Init.context()); + params.setMargins(margin, margin, margin, margin); + EditText input = new EditText(Init.context()); + frame.addView(input, params); + dialog = new AlertDialog.Builder(Init.getActivity()).setTitle("請輸入Token").setView(frame).setNeutralButton("QRCode", (dialog, which) -> onNeutral()).setNegativeButton(android.R.string.cancel, null).setPositiveButton(android.R.string.ok, (dialog, which) -> onPositive(input.getText().toString())).show(); + } catch (Exception ignored) { + } + } + + private void onNeutral() { + dismiss(); + Init.execute(this::getQRCode); + } + + private void onPositive(String text) { + dismiss(); + Init.execute(() -> { + if (text.startsWith("http")) setToken(OkHttp.string(text)); + else setToken(text); + }); + } + + private void getQRCode() { + String json = OkHttp.string("https://passport.aliyundrive.com/newlogin/qrcode/generate.do?appName=aliyun_drive&fromSite=52&appName=aliyun_drive&appEntrance=web&isMobile=false&lang=zh_CN&returnUrl=&bizParams=&_bx-v=2.2.3"); + Data data = Data.objectFrom(json).getContent().getData(); + Init.run(() -> openApp(json, data)); + } + + private void openApp(String json, Data data) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setClassName("com.alicloud.databox", "com.taobao.login4android.scan.QrScanActivity"); + intent.putExtra("key_scanParam", json); + Init.getActivity().startActivity(intent); + } catch (Exception e) { + showQRCode(data); + } finally { + Init.execute(() -> startService(data.getParams())); + } + } + + private void showQRCode(Data data) { + try { + int size = ResUtil.dp2px(240); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(size, size); + ImageView image = new ImageView(Init.context()); + image.setScaleType(ImageView.ScaleType.CENTER_CROP); + image.setImageBitmap(QRCode.getBitmap(data.getCodeContent(), size, 2)); + FrameLayout frame = new FrameLayout(Init.context()); + params.gravity = Gravity.CENTER; + frame.addView(image, params); + dialog = new AlertDialog.Builder(Init.getActivity()).setView(frame).setOnCancelListener(this::dismiss).setOnDismissListener(this::dismiss).show(); + dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + Notify.show("請使用阿里雲盤 App 掃描二維碼"); + } catch (Exception ignored) { + } + } + + private void startService(Map params) { + service = Executors.newScheduledThreadPool(1); + service.scheduleAtFixedRate(() -> { + String result = OkHttp.post("https://passport.aliyundrive.com/newlogin/qrcode/query.do?appName=aliyun_drive&fromSite=52&_bx-v=2.2.3", params); + Data data = Data.objectFrom(result).getContent().getData(); + if (data.hasToken()) setToken(data.getToken()); + }, 1, 1, TimeUnit.SECONDS); + } + + private void setToken(String value) { + cache.getUser().setRefreshToken(value); + SpiderDebug.log("Token:" + value); + Notify.show("Token:" + value); + refreshAccessToken(); + stopService(); + } + + private void stopService() { + if (service != null) service.shutdownNow(); + Init.run(this::dismiss); + } + + private void dismiss(DialogInterface dialog) { + stopService(); + } + + private void dismiss() { + try { + if (dialog != null) dialog.dismiss(); + } catch (Exception ignored) { + } + } +} diff --git a/app/src/main/java/com/github/catvod/bean/Class.java b/app/src/main/java/com/github/catvod/bean/Class.java new file mode 100644 index 0000000..34cfd66 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/Class.java @@ -0,0 +1,49 @@ +package com.github.catvod.bean; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.util.List; + +public class Class { + + @SerializedName("type_id") + private String typeId; + @SerializedName("type_name") + private String typeName; + @SerializedName("type_flag") + private String typeFlag; + + public static List arrayFrom(String str) { + Type listType = new TypeToken>() {}.getType(); + return new Gson().fromJson(str, listType); + } + + public Class(String typeId) { + this(typeId, typeId); + } + + public Class(String typeId, String typeName) { + this(typeId, typeName, null); + } + + public Class(String typeId, String typeName, String typeFlag) { + this.typeId = typeId; + this.typeName = typeName; + this.typeFlag = typeFlag; + } + + public String getTypeId() { + return typeId; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof Class)) return false; + Class it = (Class) obj; + return getTypeId().equals(it.getTypeId()); + } +} diff --git a/app/src/main/java/com/github/catvod/bean/Filter.java b/app/src/main/java/com/github/catvod/bean/Filter.java new file mode 100644 index 0000000..f3441cb --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/Filter.java @@ -0,0 +1,39 @@ +package com.github.catvod.bean; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +public class Filter { + + @SerializedName("key") + private String key; + @SerializedName("name") + private String name; + @SerializedName("value") + private List value; + + public Filter(String key, String name, List value) { + this.key = key; + this.name = name; + this.value = value; + } + + public static class Value { + + @SerializedName("n") + private String n; + @SerializedName("v") + private String v; + + public Value(String value) { + this.n = value; + this.v = value; + } + + public Value(String n, String v) { + this.n = n; + this.v = v; + } + } +} diff --git a/app/src/main/java/com/github/catvod/bean/Result.java b/app/src/main/java/com/github/catvod/bean/Result.java new file mode 100644 index 0000000..7fff2c5 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/Result.java @@ -0,0 +1,240 @@ +package com.github.catvod.bean; + +import com.github.catvod.utils.Util; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; + +import org.json.JSONObject; + +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class Result { + + @SerializedName("class") + private List classes; + @SerializedName("list") + private List list; + @SerializedName("filters") + private LinkedHashMap> filters; + @SerializedName("header") + private String header; + @SerializedName("format") + private String format; + @SerializedName("danmaku") + private String danmaku; + @SerializedName("msg") + private String msg; + @SerializedName("url") + private Object url; + @SerializedName("subs") + private List subs; + @SerializedName("parse") + private int parse; + @SerializedName("jx") + private int jx; + @SerializedName("page") + private Integer page; + @SerializedName("pagecount") + private Integer pagecount; + @SerializedName("limit") + private Integer limit; + @SerializedName("total") + private Integer total; + + public static Result objectFrom(String str) { + return new Gson().fromJson(str, Result.class); + } + + public static String string(List classes, List list, LinkedHashMap> filters) { + return Result.get().classes(classes).vod(list).filters(filters).string(); + } + + public static String string(List classes, List list, JSONObject filters) { + return Result.get().classes(classes).vod(list).filters(filters).string(); + } + + public static String string(Integer page,Integer pagecount,Integer limit,Integer total,List list){ + return Result.get().page(page,pagecount,limit,total).vod(list).string(); + } + + public static String string(List classes, List list, JsonElement filters) { + return Result.get().classes(classes).vod(list).filters(filters).string(); + } + + public static String string(List classes, LinkedHashMap> filters) { + return Result.get().classes(classes).filters(filters).string(); + } + + public static String string(List classes, JsonElement filters) { + return Result.get().classes(classes).filters(filters).string(); + } + + public static String string(List classes, JSONObject filters) { + return Result.get().classes(classes).filters(filters).string(); + } + + public static String string(List classes, List list) { + return Result.get().classes(classes).vod(list).string(); + } + + public static String string(List list) { + return Result.get().vod(list).string(); + } + + public static String string(Vod item) { + return Result.get().vod(item).string(); + } + + public static String error(String msg) { + return Result.get().vod(Collections.emptyList()).msg(msg).string(); + } + + public static Result get() { + return new Result(); + } + + public Result classes(List classes) { + this.classes = classes; + return this; + } + + public Result vod(List list) { + this.list = list; + return this; + } + + public Result vod(Vod item) { + this.list = Arrays.asList(item); + return this; + } + + public Result filters(LinkedHashMap> filters) { + this.filters = filters; + return this; + } + + public Result filters(JSONObject object) { + if (object == null) return this; + Type listType = new TypeToken>>() {}.getType(); + this.filters = new Gson().fromJson(object.toString(), listType); + return this; + } + + public Result filters(JsonElement element) { + if (element == null) return this; + Type listType = new TypeToken>>() {}.getType(); + this.filters = new Gson().fromJson(element.toString(), listType); + return this; + } + + public Result header(Map header) { + if (header.isEmpty()) return this; + this.header = new Gson().toJson(header); + return this; + } + + public Result chrome() { + Map header = new HashMap<>(); + header.put("User-Agent", Util.CHROME); + header(header); + return this; + } + + public Result parse() { + this.parse = 1; + return this; + } + + public Result parse(int parse) { + this.parse = parse; + return this; + } + + public Result jx() { + this.jx = 1; + return this; + } + + public Result url(String url) { + this.url = url; + return this; + } + + public Result url(List url) { + this.url = url; + return this; + } + + public Result danmaku(String danmaku) { + this.danmaku = danmaku; + return this; + } + + public Result msg(String msg) { + this.msg = msg; + return this; + } + + public Result format(String format) { + this.format = format; + return this; + } + + public Result subs(List subs) { + this.subs = subs; + return this; + } + + public Result dash() { + this.format = "application/dash+xml"; + return this; + } + + public Result m3u8() { + this.format = "application/x-mpegURL"; + return this; + } + + public Result rtsp() { + this.format = "application/x-rtsp"; + return this; + } + + public Result octet() { + this.format = "application/octet-stream"; + return this; + } + + public Result page() { + return page(1, 1, 0, 1); + } + + public Result page(int page, int count, int limit, int total) { + this.page = page > 0 ? page : Integer.MAX_VALUE; + this.limit = limit > 0 ? limit : Integer.MAX_VALUE; + this.total = total > 0 ? total : Integer.MAX_VALUE; + this.pagecount = count > 0 ? count : Integer.MAX_VALUE; + return this; + } + + public List getList() { + return list == null ? Collections.emptyList() : list; + } + + public String string() { + return toString(); + } + + @Override + public String toString() { + return new Gson().newBuilder().disableHtmlEscaping().create().toJson(this); + } +} diff --git a/app/src/main/java/com/github/catvod/bean/Sub.java b/app/src/main/java/com/github/catvod/bean/Sub.java new file mode 100644 index 0000000..f36c900 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/Sub.java @@ -0,0 +1,51 @@ +package com.github.catvod.bean; + +import com.google.gson.annotations.SerializedName; + +public class Sub { + + @SerializedName("url") + private String url; + @SerializedName("name") + private String name; + @SerializedName("lang") + private String lang; + @SerializedName("format") + private String format; + + public static Sub create() { + return new Sub(); + } + + public Sub name(String name) { + this.name = name; + return this; + } + + public Sub url(String url) { + this.url = url; + return this; + } + + public Sub lang(String lang) { + this.lang = lang; + return this; + } + + public Sub format(String format) { + this.format = format; + return this; + } + + public Sub ext(String ext) { + switch (ext) { + case "vtt": + return format("text/vtt"); + case "ass": + case "ssa": + return format("text/x-ssa"); + default: + return format("application/x-subrip"); + } + } +} diff --git a/app/src/main/java/com/github/catvod/bean/Vod.java b/app/src/main/java/com/github/catvod/bean/Vod.java new file mode 100644 index 0000000..e849450 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/Vod.java @@ -0,0 +1,174 @@ +package com.github.catvod.bean; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +public class Vod { + + @SerializedName("type_name") + private String typeName; + @SerializedName("vod_id") + private String vodId; + @SerializedName("vod_name") + private String vodName; + @SerializedName("vod_pic") + private String vodPic; + @SerializedName("vod_remarks") + private String vodRemarks; + @SerializedName("vod_year") + private String vodYear; + @SerializedName("vod_area") + private String vodArea; + @SerializedName("vod_actor") + private String vodActor; + @SerializedName("vod_director") + private String vodDirector; + @SerializedName("vod_content") + private String vodContent; + @SerializedName("vod_play_from") + private String vodPlayFrom; + @SerializedName("vod_play_url") + private String vodPlayUrl; + @SerializedName("vod_tag") + private String vodTag; + @SerializedName("style") + private Style style; + + public static Vod objectFrom(String str) { + Vod item = new Gson().fromJson(str, Vod.class); + return item == null ? new Vod() : item; + } + + public Vod() { + } + + public Vod(String vodId, String vodName, String vodPic) { + setVodId(vodId); + setVodName(vodName); + setVodPic(vodPic); + } + + public Vod(String vodId, String vodName, String vodPic, String vodRemarks) { + setVodId(vodId); + setVodName(vodName); + setVodPic(vodPic); + setVodRemarks(vodRemarks); + } + + public Vod(String vodId, String vodName, String vodPic, String vodRemarks, Style style) { + setVodId(vodId); + setVodName(vodName); + setVodPic(vodPic); + setVodRemarks(vodRemarks); + setStyle(style); + } + + public Vod(String vodId, String vodName, String vodPic, String vodRemarks, boolean folder) { + setVodId(vodId); + setVodName(vodName); + setVodPic(vodPic); + setVodRemarks(vodRemarks); + setVodTag(folder ? "folder" : "file"); + } + + public void setTypeName(String typeName) { + this.typeName = typeName; + } + + public void setVodId(String vodId) { + this.vodId = vodId; + } + + public void setVodName(String vodName) { + this.vodName = vodName; + } + + public void setVodPic(String vodPic) { + this.vodPic = vodPic; + } + + public void setVodRemarks(String vodRemarks) { + this.vodRemarks = vodRemarks; + } + + public void setVodYear(String vodYear) { + this.vodYear = vodYear; + } + + public void setVodArea(String vodArea) { + this.vodArea = vodArea; + } + + public void setVodActor(String vodActor) { + this.vodActor = vodActor; + } + + public void setVodDirector(String vodDirector) { + this.vodDirector = vodDirector; + } + + public void setVodContent(String vodContent) { + this.vodContent = vodContent; + } + + public String getVodContent() { + return vodContent; + } + + public void setVodPlayFrom(String vodPlayFrom) { + this.vodPlayFrom = vodPlayFrom; + } + + public void setVodPlayUrl(String vodPlayUrl) { + this.vodPlayUrl = vodPlayUrl; + } + + public String getVodPlayUrl() { + return vodPlayUrl; + } + + public void setVodTag(String vodTag) { + this.vodTag = vodTag; + } + + public void setStyle(Style style) { + this.style = style; + } + + public static class Style { + + @SerializedName("type") + private String type; + @SerializedName("ratio") + private Float ratio; + + public static Style rect() { + return rect(0.75f); + } + + public static Style rect(float ratio) { + return new Style("rect", ratio); + } + + public static Style oval() { + return new Style("oval", 1.0f); + } + + public static Style full() { + return new Style("full"); + } + + public static Style list() { + return new Style("list"); + } + + public Style(String type) { + this.type = type; + } + + public Style(String type, Float ratio) { + this.type = type; + this.ratio = ratio; + } + } +} diff --git a/app/src/main/java/com/github/catvod/bean/ali/Biz.java b/app/src/main/java/com/github/catvod/bean/ali/Biz.java new file mode 100644 index 0000000..aa9d554 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/ali/Biz.java @@ -0,0 +1,66 @@ +package com.github.catvod.bean.ali; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +public class Biz { + + @SerializedName("pds_login_result") + private Biz pdsLoginResult; + @SerializedName("role") + private String role; + @SerializedName("isFirstLogin") + private Boolean isFirstLogin; + @SerializedName("needLink") + private Boolean needLink; + @SerializedName("loginType") + private String loginType; + @SerializedName("nickName") + private String nickName; + @SerializedName("needRpVerify") + private Boolean needRpVerify; + @SerializedName("avatar") + private String avatar; + @SerializedName("accessToken") + private String accessToken; + @SerializedName("userName") + private String userName; + @SerializedName("userId") + private String userId; + @SerializedName("defaultDriveId") + private String defaultDriveId; + @SerializedName("existLink") + private List existLink; + @SerializedName("expiresIn") + private Integer expiresIn; + @SerializedName("expireTime") + private String expireTime; + @SerializedName("requestId") + private String requestId; + @SerializedName("dataPinSetup") + private Boolean dataPinSetup; + @SerializedName("state") + private String state; + @SerializedName("tokenType") + private String tokenType; + @SerializedName("dataPinSaved") + private Boolean dataPinSaved; + @SerializedName("refreshToken") + private String refreshToken; + @SerializedName("status") + private String status; + + public static Biz objectFrom(String str) { + return new Gson().fromJson(str, Biz.class); + } + + public Biz getPdsLoginResult() { + return pdsLoginResult; + } + + public String getRefreshToken() { + return refreshToken; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/ali/Cache.java b/app/src/main/java/com/github/catvod/bean/ali/Cache.java new file mode 100644 index 0000000..155d216 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/ali/Cache.java @@ -0,0 +1,58 @@ +package com.github.catvod.bean.ali; + +import com.github.catvod.api.AliYun; +import com.github.catvod.spider.Init; +import com.github.catvod.utils.Path; +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +public class Cache { + + @SerializedName("user") + private User user; + @SerializedName("oauth") + private OAuth oauth; + @SerializedName("drive") + private Drive drive; + + public static Cache objectFrom(String str) { + Cache item = new Gson().fromJson(str, Cache.class); + return item == null ? new Cache() : item; + } + + public User getUser() { + return user == null ? new User() : user; + } + + public void setUser(User user) { + this.user = user; + this.save(); + } + + public OAuth getOAuth() { + return oauth == null ? new OAuth() : oauth; + } + + public void setOAuth(OAuth oauth) { + this.oauth = oauth; + this.save(); + } + + public Drive getDrive() { + return drive == null ? new Drive() : drive; + } + + public void setDrive(Drive drive) { + this.drive = drive; + this.save(); + } + + public void save() { + Init.execute(() -> Path.write(AliYun.get().getCache(), toString())); + } + + @Override + public String toString() { + return new Gson().toJson(this); + } +} diff --git a/app/src/main/java/com/github/catvod/bean/ali/Code.java b/app/src/main/java/com/github/catvod/bean/ali/Code.java new file mode 100644 index 0000000..a0c0cc2 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/ali/Code.java @@ -0,0 +1,24 @@ +package com.github.catvod.bean.ali; + +import android.text.TextUtils; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +public class Code { + + @SerializedName("redirectUri") + private String redirectUri; + + public static Code objectFrom(String str) { + return new Gson().fromJson(str, Code.class); + } + + public String getRedirectUri() { + return TextUtils.isEmpty(redirectUri) ? "" : redirectUri; + } + + public String getCode() { + return getRedirectUri().split("code=")[1]; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/ali/Data.java b/app/src/main/java/com/github/catvod/bean/ali/Data.java new file mode 100644 index 0000000..5b083d2 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/ali/Data.java @@ -0,0 +1,88 @@ +package com.github.catvod.bean.ali; + +import android.util.Base64; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +import java.util.HashMap; +import java.util.Map; + +public class Data { + + @SerializedName("data") + private Data data; + @SerializedName("content") + private Data content; + @SerializedName("t") + private String t; + @SerializedName("ck") + private String ck; + @SerializedName("codeContent") + private String codeContent; + @SerializedName("qrCodeStatus") + private String qrCodeStatus; + @SerializedName("bizExt") + private String bizExt; + + public static Data objectFrom(String str) { + try { + Data data = new Gson().fromJson(str, Data.class); + return data == null ? new Data() : data; + } catch (Exception e) { + return new Data(); + } + } + + public Data getData() { + return data == null ? new Data() : data; + } + + public Data getContent() { + return content == null ? new Data() : content; + } + + public String getT() { + return t == null ? "" : t; + } + + public String getCk() { + return ck == null ? "" : ck; + } + + public String getCodeContent() { + return codeContent == null ? "" : codeContent; + } + + public String getQrCodeStatus() { + return qrCodeStatus == null ? "" : qrCodeStatus; + } + + public String getBizExt() { + return bizExt == null ? "" : bizExt; + } + + public String getToken() { + return Biz.objectFrom(new String(Base64.decode(getBizExt(), Base64.DEFAULT))).getPdsLoginResult().getRefreshToken(); + } + + public boolean hasToken() { + return getQrCodeStatus().equals("CONFIRMED") && getBizExt().length() > 0; + } + + public Map getParams() { + Map params = new HashMap<>(); + params.put("t", getT()); + params.put("ck", getCk()); + params.put("appName", "aliyun_drive"); + params.put("appEntrance", "web"); + params.put("isMobile", "false"); + params.put("lang", "zh_CN"); + params.put("returnUrl", ""); + params.put("fromSite", "52"); + params.put("bizParams", ""); + params.put("navlanguage", "zh-CN"); + params.put("navPlatform", "MacIntel"); + return params; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/ali/Download.java b/app/src/main/java/com/github/catvod/bean/ali/Download.java new file mode 100644 index 0000000..c0f8c61 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/ali/Download.java @@ -0,0 +1,32 @@ +package com.github.catvod.bean.ali; + +import android.text.TextUtils; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +public class Download { + + @SerializedName("url") + private String url; + @SerializedName("file_id") + private String fileId; + @SerializedName("expiration") + private String expiration; + + public static Download objectFrom(String str) { + return new Gson().fromJson(str, Download.class); + } + + public String getUrl() { + return TextUtils.isEmpty(url) ? "" : url; + } + + public String getFileId() { + return TextUtils.isEmpty(fileId) ? "" : fileId; + } + + public String getExpiration() { + return TextUtils.isEmpty(expiration) ? "" : expiration; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/ali/Drive.java b/app/src/main/java/com/github/catvod/bean/ali/Drive.java new file mode 100644 index 0000000..8f34856 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/ali/Drive.java @@ -0,0 +1,31 @@ +package com.github.catvod.bean.ali; + +import android.text.TextUtils; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +public class Drive { + + @SerializedName("default_drive_id") + private String defaultDriveId; + @SerializedName("resource_drive_id") + private String resourceDriveId; + + public static Drive objectFrom(String str) { + Drive item = new Gson().fromJson(str, Drive.class); + return item == null ? new Drive() : item; + } + + private String getDefaultDriveId() { + return TextUtils.isEmpty(defaultDriveId) ? "" : defaultDriveId; + } + + private String getResourceDriveId() { + return TextUtils.isEmpty(resourceDriveId) ? "" : resourceDriveId; + } + + public String getDriveId() { + return getResourceDriveId().isEmpty() ? getDefaultDriveId() : getResourceDriveId(); + } +} diff --git a/app/src/main/java/com/github/catvod/bean/ali/Item.java b/app/src/main/java/com/github/catvod/bean/ali/Item.java new file mode 100644 index 0000000..41a2e20 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/ali/Item.java @@ -0,0 +1,97 @@ +package com.github.catvod.bean.ali; + +import android.text.TextUtils; + +import com.github.catvod.utils.Util; +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class Item implements Comparable { + + @SerializedName("items") + private List items; + @SerializedName("next_marker") + private String nextMarker; + @SerializedName("file_id") + private String fileId; + @SerializedName("share_id") + private String shareId; + @SerializedName("name") + private String name; + @SerializedName("type") + private String type; + @SerializedName("file_extension") + private String fileExtension; + @SerializedName("category") + private String category; + @SerializedName("size") + private double size; + @SerializedName("parent") + private String parent; + + public static Item objectFrom(String str) { + return new Gson().fromJson(str, Item.class); + } + + public Item(String fileId) { + this.fileId = fileId; + } + + public List getItems() { + return items == null ? Collections.emptyList() : items; + } + + public String getNextMarker() { + return TextUtils.isEmpty(nextMarker) ? "" : nextMarker; + } + + public String getFileId() { + return TextUtils.isEmpty(fileId) ? "" : fileId; + } + + public String getName() { + return TextUtils.isEmpty(name) ? "" : name; + } + + public String getType() { + return TextUtils.isEmpty(type) ? "" : type; + } + + public String getExt() { + return TextUtils.isEmpty(fileExtension) ? "" : fileExtension; + } + + public String getCategory() { + return TextUtils.isEmpty(category) ? "" : category; + } + + public String getSize() { + return size == 0 ? "" : "[" + Util.getSize(size) + "]"; + } + + public String getParent() { + return TextUtils.isEmpty(parent) ? "" : "[" + parent + "]"; + } + + public Item parent(String parent) { + this.parent = parent; + return this; + } + + public String getDisplayName() { + return TextUtils.join(" ", Arrays.asList(getParent(), getName(), getSize())).trim(); + } + + public String getSortName() { + return TextUtils.join(" ", Arrays.asList(getParent(), Util.getDigit(getName()))).trim(); + } + + @Override + public int compareTo(Item item) { + return getSortName().compareTo(item.getSortName()); + } +} diff --git a/app/src/main/java/com/github/catvod/bean/ali/OAuth.java b/app/src/main/java/com/github/catvod/bean/ali/OAuth.java new file mode 100644 index 0000000..ae37e2b --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/ali/OAuth.java @@ -0,0 +1,42 @@ +package com.github.catvod.bean.ali; + +import android.text.TextUtils; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +public class OAuth { + + @SerializedName("token_type") + private String tokenType; + @SerializedName("access_token") + private String accessToken; + @SerializedName("refresh_token") + private String refreshToken; + + public static OAuth objectFrom(String str) { + OAuth item = new Gson().fromJson(str, OAuth.class); + return item == null ? new OAuth() : item; + } + + public String getTokenType() { + return TextUtils.isEmpty(tokenType) ? "" : tokenType; + } + + public String getAccessToken() { + return TextUtils.isEmpty(accessToken) ? "" : accessToken; + } + + public String getRefreshToken() { + return TextUtils.isEmpty(refreshToken) ? "" : refreshToken; + } + + public String getAuthorization() { + return getTokenType() + " " + getAccessToken(); + } + + public void clean() { + this.refreshToken = ""; + this.accessToken = ""; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/ali/Preview.java b/app/src/main/java/com/github/catvod/bean/ali/Preview.java new file mode 100644 index 0000000..0d6c6a3 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/ali/Preview.java @@ -0,0 +1,84 @@ +package com.github.catvod.bean.ali; + +import android.text.TextUtils; + +import com.github.catvod.bean.Sub; +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +import java.util.Collections; +import java.util.List; + +public class Preview { + + @SerializedName("video_preview_play_info") + private Info videoPreviewPlayInfo; + @SerializedName("drive_id") + private String driveId; + @SerializedName("file_id") + private String fileId; + + public static Preview objectFrom(String str) { + return new Gson().fromJson(str, Preview.class); + } + + public Info getVideoPreviewPlayInfo() { + return videoPreviewPlayInfo == null ? new Info() : videoPreviewPlayInfo; + } + + public String getDriveId() { + return TextUtils.isEmpty(driveId) ? "" : driveId; + } + + public String getFileId() { + return TextUtils.isEmpty(fileId) ? "" : fileId; + } + + public static class Info { + + @SerializedName("live_transcoding_task_list") + private List liveTranscodingTaskList; + @SerializedName("live_transcoding_subtitle_task_list") + private List liveTranscodingSubtitleTaskList; + + public List getLiveTranscodingTaskList() { + return liveTranscodingTaskList == null ? Collections.emptyList() : liveTranscodingTaskList; + } + + public List getLiveTranscodingSubtitleTaskList() { + return liveTranscodingSubtitleTaskList == null ? Collections.emptyList() : liveTranscodingSubtitleTaskList; + } + } + + public static class LiveTranscodingTask { + + @SerializedName("template_id") + private String templateId; + @SerializedName("language") + private String language; + @SerializedName("status") + private String status; + @SerializedName("url") + private String url; + + public String getTemplateId() { + return TextUtils.isEmpty(templateId) ? "" : templateId; + } + + public String getLanguage() { + return TextUtils.isEmpty(language) ? "" : language; + } + + public String getStatus() { + return TextUtils.isEmpty(status) ? "" : status; + } + + public String getUrl() { + return TextUtils.isEmpty(url) ? "" : url; + } + + public Sub getSub() { + return Sub.create().url(getUrl()).name(getLanguage()).lang(getLanguage()).ext("vtt"); + } + } +} diff --git a/app/src/main/java/com/github/catvod/bean/ali/Resp.java b/app/src/main/java/com/github/catvod/bean/ali/Resp.java new file mode 100644 index 0000000..65b1454 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/ali/Resp.java @@ -0,0 +1,79 @@ +package com.github.catvod.bean.ali; + +import android.text.TextUtils; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +import java.util.Collections; +import java.util.List; + +public class Resp { + + @SerializedName("responses") + private List responses; + @SerializedName("body") + private Body body; + @SerializedName("id") + private String id; + @SerializedName("status") + private int status; + + public static Resp objectFrom(String str) { + return new Gson().fromJson(str, Resp.class); + } + + public List getResponses() { + return responses == null ? Collections.emptyList() : responses; + } + + public Resp getResponse() { + return getResponses().isEmpty() ? new Resp() : getResponses().get(0); + } + + public Body getBody() { + return body == null ? new Body() : body; + } + + public String getId() { + return TextUtils.isEmpty(id) ? "" : id; + } + + public int getStatus() { + return status; + } + + public static class Body { + + @SerializedName("domain_id") + private String domainId; + @SerializedName("drive_id") + private String driveId; + @SerializedName("file_id") + private String fileId; + @SerializedName("code") + private String code; + @SerializedName("message") + private String message; + + public String getDomainId() { + return TextUtils.isEmpty(domainId) ? "" : domainId; + } + + public String getDriveId() { + return TextUtils.isEmpty(driveId) ? "" : driveId; + } + + public String getFileId() { + return TextUtils.isEmpty(fileId) ? "" : fileId; + } + + public String getCode() { + return TextUtils.isEmpty(code) ? "" : code; + } + + public String getMessage() { + return TextUtils.isEmpty(message) ? "" : message; + } + } +} diff --git a/app/src/main/java/com/github/catvod/bean/ali/Share.java b/app/src/main/java/com/github/catvod/bean/ali/Share.java new file mode 100644 index 0000000..40e2101 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/ali/Share.java @@ -0,0 +1,130 @@ +package com.github.catvod.bean.ali; + +import android.text.TextUtils; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +import java.util.Collections; +import java.util.List; + +public class Share { + + @SerializedName("share_id") + private String shareId; + @SerializedName("share_token") + private String shareToken; + @SerializedName("expire_time") + private String expireTime; + @SerializedName("expires_in") + private int expiresIn; + + @SerializedName("creator_id") + private String creatorId; + @SerializedName("creator_name") + private String creatorName; + @SerializedName("creator_phone") + private String creatorPhone; + @SerializedName("expiration") + private String expiration; + @SerializedName("updated_at") + private String updatedAt; + @SerializedName("vip") + private String vip; + @SerializedName("avatar") + private String avatar; + @SerializedName("share_name") + private String shareName; + @SerializedName("display_name") + private String displayName; + @SerializedName("share_title") + private String shareTitle; + @SerializedName("has_pwd") + private boolean hasPwd; + @SerializedName("file_infos") + private List fileInfos; + + private long time; + + public static Share objectFrom(String str) { + return new Gson().fromJson(str, Share.class); + } + + public String getShareId() { + return TextUtils.isEmpty(shareId) ? "" : shareId; + } + + public String getShareToken() { + return TextUtils.isEmpty(shareToken) ? "" : shareToken; + } + + public String getExpireTime() { + return TextUtils.isEmpty(expireTime) ? "" : expireTime; + } + + public int getExpiresIn() { + return expiresIn; + } + + public String getCreatorId() { + return TextUtils.isEmpty(creatorId) ? "" : creatorId; + } + + public String getCreatorName() { + return TextUtils.isEmpty(creatorName) ? "" : creatorName; + } + + public String getCreatorPhone() { + return TextUtils.isEmpty(creatorPhone) ? "" : creatorPhone; + } + + public String getExpiration() { + return TextUtils.isEmpty(expiration) ? "" : expiration; + } + + public String getUpdatedAt() { + return TextUtils.isEmpty(updatedAt) ? "" : updatedAt; + } + + public String getVip() { + return TextUtils.isEmpty(vip) ? "" : vip; + } + + public String getAvatar() { + return TextUtils.isEmpty(avatar) ? "" : avatar; + } + + public String getShareName() { + return TextUtils.isEmpty(shareName) ? "" : shareName; + } + + public String getDisplayName() { + return TextUtils.isEmpty(displayName) ? "" : displayName; + } + + public String getShareTitle() { + return TextUtils.isEmpty(shareTitle) ? "" : shareTitle; + } + + public boolean isHasPwd() { + return hasPwd; + } + + public List getFileInfos() { + return fileInfos == null ? Collections.emptyList() : fileInfos; + } + + public Share setTime() { + this.time = System.currentTimeMillis() + 60 * 60 * 1000; + return this; + } + + public Share setShareId(String shareId) { + this.shareId = shareId; + return this; + } + + public boolean alive(String shareId) { + return getShareId().equals(shareId) && System.currentTimeMillis() <= time; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/ali/User.java b/app/src/main/java/com/github/catvod/bean/ali/User.java new file mode 100644 index 0000000..f332abd --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/ali/User.java @@ -0,0 +1,50 @@ +package com.github.catvod.bean.ali; + +import android.text.TextUtils; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +public class User { + + @SerializedName("token_type") + private String tokenType; + @SerializedName("access_token") + private String accessToken; + @SerializedName("refresh_token") + private String refreshToken; + + public static User objectFrom(String str) { + User item = new Gson().fromJson(str, User.class); + return item == null ? new User() : item; + } + + public String getTokenType() { + return TextUtils.isEmpty(tokenType) ? "" : tokenType; + } + + public String getAccessToken() { + return TextUtils.isEmpty(accessToken) ? "" : accessToken; + } + + public String getRefreshToken() { + return TextUtils.isEmpty(refreshToken) ? "" : refreshToken; + } + + public void setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } + + public String getAuthorization() { + return getTokenType() + " " + getAccessToken(); + } + + public boolean isAuthed() { + return getTokenType().length() > 0 && getAccessToken().length() > 0; + } + + public void clean() { + this.refreshToken = ""; + this.accessToken = ""; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/alist/Drive.java b/app/src/main/java/com/github/catvod/bean/alist/Drive.java new file mode 100644 index 0000000..aedec77 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/alist/Drive.java @@ -0,0 +1,184 @@ +package com.github.catvod.bean.alist; + +import android.net.Uri; +import android.text.TextUtils; + +import com.github.catvod.bean.Class; +import com.github.catvod.net.OkHttp; +import com.github.catvod.utils.Image; +import com.github.catvod.utils.Util; +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Drive { + + @SerializedName("drives") + private List drives; + @SerializedName("params") + private List params; + @SerializedName("login") + private Login login; + @SerializedName("vodPic") + private String vodPic; + @SerializedName("name") + private String name; + @SerializedName("server") + private String server; + @SerializedName("version") + private int version; + @SerializedName("path") + private String path; + @SerializedName("token") + private String token; + @SerializedName("search") + private Boolean search; + @SerializedName("hidden") + private Boolean hidden; + + public static Drive objectFrom(String str) { + return new Gson().fromJson(str, Drive.class); + } + + public List getDrives() { + return drives == null ? new ArrayList<>() : drives; + } + + public List getParams() { + return params == null ? new ArrayList<>() : params; + } + + public Login getLogin() { + return login; + } + + public Drive(String name) { + this.name = name; + } + + public String getVodPic() { + return TextUtils.isEmpty(vodPic) ? Image.FOLDER : vodPic; + } + + public String getName() { + return TextUtils.isEmpty(name) ? "" : name; + } + + public String getServer() { + return TextUtils.isEmpty(server) ? "" : server; + } + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } + + public String getPath() { + return TextUtils.isEmpty(path) ? "" : path; + } + + public void setPath(String path) { + this.path = TextUtils.isEmpty(path) ? "" : path; + } + + public String getToken() { + return TextUtils.isEmpty(token) ? "" : token; + } + + public void setToken(String token) { + this.token = token; + } + + public Boolean search() { + return search == null || search; + } + + public Boolean hidden() { + return hidden != null && hidden; + } + + public boolean isNew() { + return getVersion() == 3; + } + + public Class toType() { + return new Class(getName(), getName(), "1"); + } + + public String getHost() { + return getServer().replace(getPath(), ""); + } + + public String settingsApi() { + return getHost() + "/api/public/settings"; + } + + public String loginApi() { + return getHost() + "/api/auth/login"; + } + + public String listApi() { + return getHost() + (isNew() ? "/api/fs/list" : "/api/public/path"); + } + + public String getApi() { + return getHost() + (isNew() ? "/api/fs/get" : "/api/public/path"); + } + + public String searchApi() { + return getHost() + (isNew() ? "/api/fs/search" : "/api/public/search"); + } + + public String searchApi(String param) { + return getHost() + "/search?box=" + param + "&url=&type=video"; + } + + public Drive check() { + if (path == null) setPath(Uri.parse(getServer()).getPath()); + if (version == 0) setVersion(OkHttp.string(settingsApi()).contains("v2.") ? 2 : 3); + return this; + } + + public String params(String keyword) { + if (isNew()) { + Map params = new HashMap<>(); + params.put("keywords", keyword); + params.put("page", 1); + params.put("parent", "/"); + params.put("per_page", 100); + return new Gson().toJson(params); + } else { + Map params = new HashMap<>(); + params.put("keyword", keyword); + params.put("path", "/"); + return new Gson().toJson(params); + } + } + + public HashMap getHeader() { + HashMap headers = new HashMap<>(); + headers.put("User-Agent", Util.CHROME); + if (!getToken().isEmpty()) headers.put("Authorization", token); + return headers; + } + + public String findPass(String path) { + for (Param param : getParams()) if (path.startsWith(param.getPath())) return param.getPass(); + return ""; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof Drive)) return false; + Drive it = (Drive) obj; + return getName().equals(it.getName()); + } +} diff --git a/app/src/main/java/com/github/catvod/bean/alist/Item.java b/app/src/main/java/com/github/catvod/bean/alist/Item.java new file mode 100644 index 0000000..e4c9152 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/alist/Item.java @@ -0,0 +1,135 @@ +package com.github.catvod.bean.alist; + +import android.text.TextUtils; + +import com.github.catvod.bean.Vod; +import com.github.catvod.utils.Util; +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +public class Item { + + @SerializedName("name") + private String name; + @SerializedName(value = "path", alternate = "parent") + private String path; + @SerializedName("type") + private int type; + @SerializedName("size") + private long size; + @SerializedName(value = "thumb", alternate = "thumbnail") + private String thumb; + @SerializedName(value = "url", alternate = "raw_url") + private String url; + @SerializedName(value = "modified", alternate = "updated_at") + private String modified; + + public static Item objectFrom(String str) { + return new Gson().fromJson(str, Item.class); + } + + public static List arrayFrom(String str) { + Type listType = new TypeToken>() {}.getType(); + return new Gson().fromJson(str, listType); + } + + public String getName() { + return TextUtils.isEmpty(name) ? "" : name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPath() { + return TextUtils.isEmpty(path) ? "" : path; + } + + public void setPath(String path) { + this.path = path; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public long getSize() { + return size; + } + + public String getThumb() { + return TextUtils.isEmpty(thumb) ? "" : thumb; + } + + public void setThumb(String thumb) { + this.thumb = thumb; + } + + public String getUrl() { + return TextUtils.isEmpty(url) ? "" : url.startsWith("//") ? "http:" + url : url; + } + + public String getModified() { + return modified; + } + + public Date getDate() { + try { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault()); + return format.parse(getModified()); + } catch (Exception e) { + return new Date(); + } + } + + public boolean isFolder() { + return getType() == 1; + } + + public boolean isMedia(boolean isNew) { + if (getName().endsWith(".ts") || getName().endsWith(".mpg")) return true; + if (isNew) return getType() == 2 || getType() == 3; + return getType() == 3 || getType() == 4; + } + + public boolean ignore(boolean isNew) { + if (getName().endsWith(".ts") || getName().endsWith(".mpg")) return false; + if (isNew) return getType() == 0 || getType() == 4; + return getType() == 0 || getType() == 2 || getType() == 5; + } + + public String getExt() { + return Util.getExt(getName()); + } + + public String getVodId(String id) { + return id + getPath() + "/" + getName(); + } + + public String getPic(String pic) { + return getThumb().isEmpty() && isFolder() ? pic : getThumb(); + } + + public String getRemark() { + return Util.getSize(getSize()); + } + + public Vod getVod(String id, String pic) { + return new Vod(getVodId(id), getName(), getPic(pic), getRemark(), isFolder()); + } + + public Vod getVod(Drive drive, String pic) { + return new Vod(getVodId(drive.getName()), getName(), getPic(pic), drive.getName(), isFolder()); + } +} diff --git a/app/src/main/java/com/github/catvod/bean/alist/Login.java b/app/src/main/java/com/github/catvod/bean/alist/Login.java new file mode 100644 index 0000000..09437c3 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/alist/Login.java @@ -0,0 +1,21 @@ +package com.github.catvod.bean.alist; + +import android.text.TextUtils; + +import com.google.gson.annotations.SerializedName; + +public class Login { + + @SerializedName("username") + private String username; + @SerializedName("password") + private String password; + + public String getUsername() { + return TextUtils.isEmpty(username) ? "" : username; + } + + public String getPassword() { + return TextUtils.isEmpty(password) ? "" : password; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/alist/Param.java b/app/src/main/java/com/github/catvod/bean/alist/Param.java new file mode 100644 index 0000000..9caafd2 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/alist/Param.java @@ -0,0 +1,21 @@ +package com.github.catvod.bean.alist; + +import android.text.TextUtils; + +import com.google.gson.annotations.SerializedName; + +public class Param { + + @SerializedName("path") + private String path; + @SerializedName("pass") + private String pass; + + public String getPath() { + return TextUtils.isEmpty(path) ? "" : path; + } + + public String getPass() { + return TextUtils.isEmpty(pass) ? "" : pass; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/alist/Sorter.java b/app/src/main/java/com/github/catvod/bean/alist/Sorter.java new file mode 100644 index 0000000..7aee0f1 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/alist/Sorter.java @@ -0,0 +1,35 @@ +package com.github.catvod.bean.alist; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class Sorter implements Comparator { + + private final String type; + private final String order; + + public static void sort(String type, String order, List items) { + Collections.sort(items, new Sorter(type, order)); + } + + public Sorter(String type, String order) { + this.type = type; + this.order = order; + } + + @Override + public int compare(Item o1, Item o2) { + boolean asc = order.equals("asc"); + switch (type) { + case "name": + return asc ? o1.getName().compareTo(o2.getName()) : o2.getName().compareTo(o1.getName()); + case "size": + return asc ? Long.compare(o1.getSize(), o2.getSize()) : Long.compare(o2.getSize(), o1.getSize()); + case "date": + return asc ? o1.getDate().compareTo(o2.getDate()) : o2.getDate().compareTo(o1.getDate()); + default: + return -1; + } + } +} diff --git a/app/src/main/java/com/github/catvod/bean/bili/Dash.java b/app/src/main/java/com/github/catvod/bean/bili/Dash.java new file mode 100644 index 0000000..bbecc56 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/bili/Dash.java @@ -0,0 +1,39 @@ +package com.github.catvod.bean.bili; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +import java.util.Collections; +import java.util.List; + +public class Dash { + + @SerializedName("duration") + private String duration; + @SerializedName("minBufferTime") + private String minBufferTime; + @SerializedName("video") + private List video; + @SerializedName("audio") + private List audio; + + public static Dash objectFrom(String str) { + return new Gson().fromJson(str, Dash.class); + } + + public String getDuration() { + return duration == null ? "0" : duration; + } + + public String getMinBufferTime() { + return minBufferTime == null ? "0" : minBufferTime; + } + + public List getVideo() { + return video == null ? Collections.emptyList() : video; + } + + public List getAudio() { + return audio == null ? Collections.emptyList() : audio; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/bili/Data.java b/app/src/main/java/com/github/catvod/bean/bili/Data.java new file mode 100644 index 0000000..076abe9 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/bili/Data.java @@ -0,0 +1,131 @@ +package com.github.catvod.bean.bili; + +import android.text.TextUtils; + +import com.google.gson.JsonElement; +import com.google.gson.annotations.SerializedName; + +import java.util.Collections; +import java.util.List; + +public class Data { + + @SerializedName("result") + private JsonElement result; + @SerializedName("list") + private JsonElement list; + @SerializedName("isLogin") + private Boolean isLogin; + @SerializedName("vipStatus") + private Integer vipStatus; + @SerializedName("qrcode_key") + private String qrcodeKey; + @SerializedName("url") + private String url; + @SerializedName("aid") + private String aid; + @SerializedName("cid") + private String cid; + @SerializedName("title") + private String title; + @SerializedName("tname") + private String tname; + @SerializedName("pic") + private String pic; + @SerializedName("duration") + private Long duration; + @SerializedName("desc") + private String desc; + @SerializedName("accept_description") + private List acceptDescription; + @SerializedName("accept_quality") + private List acceptQuality; + @SerializedName("pages") + private List pages; + @SerializedName("dash") + private Dash dash; + @SerializedName("owner") + private Owner owner; + @SerializedName("wbi_img") + private Wbi wbi; + + public JsonElement getResult() { + return result; + } + + public JsonElement getList() { + return list; + } + + public boolean isLogin() { + return isLogin != null && isLogin; + } + + public Integer getVipStatus() { + return vipStatus; + } + + public boolean isVip() { + return vipStatus != null && vipStatus != 0; + } + + public String getQrcodeKey() { + return TextUtils.isEmpty(qrcodeKey) ? "" : qrcodeKey; + } + + public String getUrl() { + return TextUtils.isEmpty(url) ? "" : url; + } + + public String getAid() { + return TextUtils.isEmpty(aid) ? "" : aid; + } + + public String getCid() { + return TextUtils.isEmpty(cid) ? "" : cid; + } + + public String getTitle() { + return TextUtils.isEmpty(title) ? "" : title; + } + + public String getType() { + return TextUtils.isEmpty(tname) ? "" : tname; + } + + public String getPic() { + return TextUtils.isEmpty(pic) ? "" : pic; + } + + public Long getDuration() { + return duration == null ? 0 : duration; + } + + public String getDesc() { + return TextUtils.isEmpty(desc) ? "" : desc; + } + + public List getAcceptDescription() { + return acceptDescription == null ? Collections.emptyList() : acceptDescription; + } + + public List getAcceptQuality() { + return acceptQuality == null ? Collections.emptyList() : acceptQuality; + } + + public List getPages() { + return pages == null ? Collections.emptyList() : pages; + } + + public Dash getDash() { + return dash == null ? new Dash() : dash; + } + + public Owner getOwner() { + return owner == null ? new Owner() : owner; + } + + public Wbi getWbi() { + return wbi == null ? new Wbi() : wbi; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/bili/Media.java b/app/src/main/java/com/github/catvod/bean/bili/Media.java new file mode 100644 index 0000000..7cf395a --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/bili/Media.java @@ -0,0 +1,79 @@ +package com.github.catvod.bean.bili; + +import com.google.gson.annotations.SerializedName; + +public class Media { + + @SerializedName("id") + private String id; + @SerializedName("baseUrl") + private String baseUrl; + @SerializedName("bandwidth") + private String bandwidth; + @SerializedName("mimeType") + private String mimeType; + @SerializedName("codecs") + private String codecs; + @SerializedName("width") + private String width; + @SerializedName("height") + private String height; + @SerializedName("frameRate") + private String frameRate; + @SerializedName("sar") + private String sar; + @SerializedName("startWithSap") + private String startWithSap; + @SerializedName("SegmentBase") + private Segment segmentBase; + @SerializedName("codecid") + private String codecid; + + public String getId() { + return id; + } + + public String getBaseUrl() { + return baseUrl; + } + + public String getBandWidth() { + return bandwidth; + } + + public String getMimeType() { + return mimeType; + } + + public String getCodecs() { + return codecs; + } + + public String getWidth() { + return width; + } + + public String getHeight() { + return height; + } + + public String getFrameRate() { + return frameRate; + } + + public String getSar() { + return sar; + } + + public String getStartWithSap() { + return startWithSap; + } + + public Segment getSegmentBase() { + return segmentBase; + } + + public String getCodecId() { + return codecid; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/bili/Owner.java b/app/src/main/java/com/github/catvod/bean/bili/Owner.java new file mode 100644 index 0000000..131a50c --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/bili/Owner.java @@ -0,0 +1,25 @@ +package com.github.catvod.bean.bili; + +import android.text.TextUtils; + +import com.google.gson.annotations.SerializedName; + +public class Owner { + + @SerializedName("mid") + private String mid; + @SerializedName("name") + private String name; + + public String getMid() { + return TextUtils.isEmpty(mid) ? "" : mid; + } + + public String getName() { + return TextUtils.isEmpty(name) ? "" : name; + } + + public String getFormat() { + return String.format("[a=cr:{\"id\":\"%s\",\"name\":\"%s\"}/]%s[/a]", getMid() + "/{pg}", getName(), getName()); + } +} diff --git a/app/src/main/java/com/github/catvod/bean/bili/Page.java b/app/src/main/java/com/github/catvod/bean/bili/Page.java new file mode 100644 index 0000000..e2599a4 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/bili/Page.java @@ -0,0 +1,21 @@ +package com.github.catvod.bean.bili; + +import android.text.TextUtils; + +import com.google.gson.annotations.SerializedName; + +public class Page { + + @SerializedName("cid") + private String cid; + @SerializedName("part") + private String part; + + public String getCid() { + return TextUtils.isEmpty(cid) ? "" : cid; + } + + public String getPart() { + return TextUtils.isEmpty(part) ? "" : part; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/bili/Resp.java b/app/src/main/java/com/github/catvod/bean/bili/Resp.java new file mode 100644 index 0000000..37d5774 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/bili/Resp.java @@ -0,0 +1,86 @@ +package com.github.catvod.bean.bili; + +import android.text.TextUtils; + +import com.github.catvod.bean.Vod; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; + +import org.jsoup.Jsoup; + +import java.lang.reflect.Type; +import java.util.List; + +public class Resp { + + @SerializedName("code") + private Integer code; + @SerializedName("message") + private String message; + @SerializedName("data") + private Data data; + + public static Resp objectFrom(String str) { + return new Gson().fromJson(str, Resp.class); + } + + public Data getData() { + return data == null ? new Data() : data; + } + + public static class Result { + + @SerializedName("bvid") + private String bvid; + @SerializedName("aid") + private String aid; + @SerializedName("title") + private String title; + @SerializedName("pic") + private String pic; + @SerializedName("duration") + private String duration; + @SerializedName("length") + private String length; + + public static List arrayFrom(JsonElement str) { + Type listType = new TypeToken>() {}.getType(); + return new Gson().fromJson(str, listType); + } + + public String getBvId() { + return TextUtils.isEmpty(bvid) ? "" : bvid; + } + + public String getAid() { + return TextUtils.isEmpty(aid) ? "" : aid; + } + + public String getTitle() { + return TextUtils.isEmpty(title) ? "" : title; + } + + public String getDuration() { + return TextUtils.isEmpty(duration) ? getLength() : duration.split(":")[0] + "分鐘"; + } + + public String getLength() { + return TextUtils.isEmpty(length) ? "" : length; + } + + public String getPic() { + return TextUtils.isEmpty(pic) ? "" : pic; + } + + public Vod getVod() { + Vod vod = new Vod(); + vod.setVodId(getBvId() + "@" + getAid()); + vod.setVodName(Jsoup.parse(getTitle()).text()); + vod.setVodPic(getPic().startsWith("//") ? "https:" + getPic() : getPic()); + vod.setVodRemarks(getDuration()); + return vod; + } + } +} diff --git a/app/src/main/java/com/github/catvod/bean/bili/Segment.java b/app/src/main/java/com/github/catvod/bean/bili/Segment.java new file mode 100644 index 0000000..0acbbca --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/bili/Segment.java @@ -0,0 +1,19 @@ +package com.github.catvod.bean.bili; + +import com.google.gson.annotations.SerializedName; + +public class Segment { + + @SerializedName("Initialization") + private String initialization; + @SerializedName("indexRange") + private String indexRange; + + public String getInitialization() { + return initialization; + } + + public String getIndexRange() { + return indexRange; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/bili/Wbi.java b/app/src/main/java/com/github/catvod/bean/bili/Wbi.java new file mode 100644 index 0000000..853813f --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/bili/Wbi.java @@ -0,0 +1,47 @@ +package com.github.catvod.bean.bili; + +import android.net.Uri; +import android.text.TextUtils; + +import com.github.catvod.utils.Util; +import com.google.gson.annotations.SerializedName; + +import java.net.URLEncoder; +import java.util.LinkedHashMap; + +public class Wbi { + + private final int[] mixinKeyEncTab = new int[]{46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, 36, 20, 34, 44, 52}; + + @SerializedName("img_url") + private String imgUrl; + @SerializedName("sub_url") + private String subUrl; + + public String getImgUrl() { + return TextUtils.isEmpty(imgUrl) ? "" : imgUrl; + } + + public String getSubUrl() { + return TextUtils.isEmpty(subUrl) ? "" : subUrl; + } + + private String getMixinKey(String imgKey, String subKey) { + String s = imgKey + subKey; + StringBuilder key = new StringBuilder(); + for (int i = 0; i < 32; i++) key.append(s.charAt(mixinKeyEncTab[i])); + return key.toString(); + } + + public String getQuery(LinkedHashMap params) { + String imgKey = Uri.parse(getImgUrl()).getLastPathSegment().split("\\.")[0]; + String subKey = Uri.parse(getSubUrl()).getLastPathSegment().split("\\.")[0]; + String mixinKey = getMixinKey(imgKey, subKey); + StringBuilder sb = new StringBuilder(); + params.put("wts", System.currentTimeMillis() / 1000); + for (String key : params.keySet()) sb.append(key).append("=").append(URLEncoder.encode(params.get(key).toString())).append("&"); + String query = Util.substring(sb.toString()); + String w_rid = Util.MD5(query + mixinKey); + return query + "&w_rid=" + w_rid; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/jianpian/Data.java b/app/src/main/java/com/github/catvod/bean/jianpian/Data.java new file mode 100644 index 0000000..38db856 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/jianpian/Data.java @@ -0,0 +1,130 @@ +package com.github.catvod.bean.jianpian; + +import android.text.TextUtils; + +import com.github.catvod.bean.Vod; +import com.github.catvod.utils.Util; +import com.google.gson.annotations.SerializedName; + +import java.util.Collections; +import java.util.List; + +public class Data { + + @SerializedName(value = "jump_id", alternate = "id") + private String jumpId; + @SerializedName(value = "thumbnail", alternate = "path") + private String thumbnail; + @SerializedName("title") + private String title; + @SerializedName("mask") + private String mask; + @SerializedName("description") + private String description; + @SerializedName("playlist") + private Value playlist; + @SerializedName("year") + private Value year; + @SerializedName("area") + private Value area; + @SerializedName("types") + private List types; + @SerializedName("actors") + private List actors; + @SerializedName("directors") + private List directors; + @SerializedName("btbo_downlist") + private List btboDownlist; + + public String getJumpId() { + return TextUtils.isEmpty(jumpId) ? "" : jumpId; + } + + public String getThumbnail() { + return TextUtils.isEmpty(thumbnail) ? "" : thumbnail + "@Referer=www.jianpianapp.com@User-Agent=jianpian-version362"; + } + + public String getTitle() { + return TextUtils.isEmpty(title) ? "" : title; + } + + public String getMask() { + return TextUtils.isEmpty(mask) ? getPlaylist() : mask; + } + + public String getDescription() { + return TextUtils.isEmpty(description) ? "" : description.replace(" ", ""); + } + + public String getPlaylist() { + return playlist == null ? "" : playlist.getTitle(); + } + + public String getYear() { + return year == null ? "" : year.getTitle(); + } + + public String getArea() { + return area == null ? "" : area.getTitle(); + } + + public String getTypes() { + return types == null ? "" : getValues(types, false); + } + + public String getActors() { + return actors == null ? "" : getValues(actors, true); + } + + public String getDirectors() { + return directors == null ? "" : getValues(directors, true); + } + + public List getBtboDownlist() { + return btboDownlist == null ? Collections.emptyList() : btboDownlist; + } + + public Vod vod() { + return new Vod(getJumpId(), getTitle(), getThumbnail(), getMask()); + } + + public String getValues(List items, boolean link) { + StringBuilder sb = new StringBuilder(); + for (Value value : items) sb.append(value.getValue(link)).append(" "); + return Util.substring(sb.toString()); + } + + public String getPlayUrl() { + StringBuilder sb = new StringBuilder(); + for (BtboDown value : getBtboDownlist()) sb.append(value.getVal()).append("#"); + return Util.substring(sb.toString()); + } + + public static class Value { + + @SerializedName(value = "title", alternate = "name") + private String title; + + private String getTitle() { + return TextUtils.isEmpty(title) ? "" : title; + } + + private String getLink() { + return String.format("[a=cr:{\"id\":\"%s\",\"name\":\"%s\"}/]%s[/a]", getTitle() + "/{pg}", getTitle(), getTitle()); + } + + public String getValue(boolean link) { + return link ? getLink() : getTitle(); + } + } + + public static class BtboDown { + + @SerializedName("val") + private String val; + + public String getVal() { + return TextUtils.isEmpty(val) ? "" : val.replaceAll("ftp", "tvbox-xg:ftp"); + } + } +} diff --git a/app/src/main/java/com/github/catvod/bean/jianpian/Detail.java b/app/src/main/java/com/github/catvod/bean/jianpian/Detail.java new file mode 100644 index 0000000..4ab7bc7 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/jianpian/Detail.java @@ -0,0 +1,18 @@ +package com.github.catvod.bean.jianpian; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +public class Detail { + + @SerializedName("data") + private Data data; + + public static Detail objectFrom(String str) { + return new Gson().fromJson(str, Detail.class); + } + + public Data getData() { + return data == null ? new Data() : data; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/jianpian/Resp.java b/app/src/main/java/com/github/catvod/bean/jianpian/Resp.java new file mode 100644 index 0000000..d21de02 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/jianpian/Resp.java @@ -0,0 +1,21 @@ +package com.github.catvod.bean.jianpian; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +import java.util.Collections; +import java.util.List; + +public class Resp { + + @SerializedName("data") + private List data; + + public static Resp objectFrom(String str) { + return new Gson().fromJson(str, Resp.class); + } + + public List getData() { + return data == null ? Collections.emptyList() : data; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/market/Data.java b/app/src/main/java/com/github/catvod/bean/market/Data.java new file mode 100644 index 0000000..6abf0f5 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/market/Data.java @@ -0,0 +1,45 @@ +package com.github.catvod.bean.market; + +import android.text.TextUtils; + +import com.github.catvod.bean.Class; +import com.github.catvod.bean.Vod; +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Data { + + @SerializedName("name") + private String name; + @SerializedName("list") + private List list; + + public static List arrayFrom(String str) { + Type listType = new TypeToken>() {}.getType(); + return new Gson().fromJson(str, listType); + } + + public String getName() { + return TextUtils.isEmpty(name) ? "" : name; + } + + public List getList() { + return list == null ? Collections.emptyList() : list; + } + + public List getVod() { + List vodList = new ArrayList<>(); + for (Item item : getList()) vodList.add(item.vod()); + return vodList; + } + + public Class type() { + return new Class(getName(), getName()); + } +} diff --git a/app/src/main/java/com/github/catvod/bean/market/Item.java b/app/src/main/java/com/github/catvod/bean/market/Item.java new file mode 100644 index 0000000..f2b274c --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/market/Item.java @@ -0,0 +1,56 @@ +package com.github.catvod.bean.market; + +import android.text.TextUtils; + +import com.github.catvod.bean.Vod; +import com.google.gson.annotations.SerializedName; + +public class Item { + + @SerializedName("name") + private String name; + @SerializedName("url") + private String url; + @SerializedName("icon") + private String icon; + @SerializedName("copy") + private String copy; + @SerializedName("version") + private String version; + + public Item(String url) { + this.url = url; + } + + public String getName() { + return TextUtils.isEmpty(name) ? "" : name; + } + + public String getUrl() { + return TextUtils.isEmpty(url) ? "" : url; + } + + public String getIcon() { + return TextUtils.isEmpty(icon) ? "" : icon; + } + + public String getCopy() { + return TextUtils.isEmpty(copy) ? "" : copy; + } + + public String getVersion() { + return TextUtils.isEmpty(version) ? "" : version; + } + + public Vod vod() { + return new Vod(getUrl(), getName(), getIcon(), getVersion(), Vod.Style.rect(1.0f)); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof Item)) return false; + Item it = (Item) obj; + return getUrl().equals(it.getUrl()); + } +} diff --git a/app/src/main/java/com/github/catvod/bean/star/Card.java b/app/src/main/java/com/github/catvod/bean/star/Card.java new file mode 100644 index 0000000..3c25110 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/star/Card.java @@ -0,0 +1,61 @@ +package com.github.catvod.bean.star; + +import android.text.TextUtils; + +import com.github.catvod.bean.Vod; +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.util.Collections; +import java.util.List; + +public class Card { + + @SerializedName("name") + private String name; + @SerializedName(value = "img", alternate = "picurl") + private String img; + @SerializedName("id") + private String id; + @SerializedName("countStr") + private String countStr; + @SerializedName("url") + private String url; + @SerializedName("cards") + private List cards; + + public static List arrayFrom(String str) { + Type listType = new TypeToken>() {}.getType(); + return new Gson().fromJson(str, listType); + } + + public String getName() { + return TextUtils.isEmpty(name) ? "" : name; + } + + public String getImg() { + return TextUtils.isEmpty(img) ? "" : img; + } + + public String getId() { + return TextUtils.isEmpty(id) ? "" : id; + } + + public String getCountStr() { + return TextUtils.isEmpty(countStr) ? "" : countStr; + } + + public String getUrl() { + return TextUtils.isEmpty(url) ? "" : url; + } + + public List getCards() { + return cards == null ? Collections.emptyList() : cards; + } + + public Vod vod() { + return new Vod(getId(), getName(), getImg(), getCountStr()); + } +} diff --git a/app/src/main/java/com/github/catvod/bean/star/Condition.java b/app/src/main/java/com/github/catvod/bean/star/Condition.java new file mode 100644 index 0000000..f335440 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/star/Condition.java @@ -0,0 +1,65 @@ +package com.github.catvod.bean.star; + +import com.github.catvod.bean.Filter; +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Condition { + + @SerializedName("label") + private List> label; + @SerializedName("country") + private List country; + @SerializedName("time") + private List time; + + public static Condition objectFrom(String str) { + return new Gson().fromJson(str, Condition.class); + } + + public List> getLabel() { + return label == null ? Collections.emptyList() : label; + } + + public List getCountry() { + return country == null ? Collections.emptyList() : country; + } + + public List getTime() { + return time == null ? Collections.emptyList() : time; + } + + public List getFilter() { + List filters = new ArrayList<>(); + filters.add(new Filter("type", "類型", getTypeValues())); + filters.add(new Filter("area", "地區", getAreaValues())); + filters.add(new Filter("year", "年份", getYearValues())); + return filters; + } + + private List getTypeValues() { + List values = new ArrayList<>(); + values.add(new Filter.Value("全部", "")); + for (List list : getLabel()) values.add(new Filter.Value(list.get(0))); + return values; + } + + private List getAreaValues() { + List values = new ArrayList<>(); + values.add(new Filter.Value("全部", "")); + for (String text : getCountry()) values.add(new Filter.Value(text)); + return values; + } + + private List getYearValues() { + List values = new ArrayList<>(); + values.add(new Filter.Value("全部", "")); + Collections.sort(getTime(), Collections.reverseOrder()); + for (Integer year : getTime()) if (year >= 2010) values.add(new Filter.Value(String.valueOf(year))); + return values; + } +} diff --git a/app/src/main/java/com/github/catvod/bean/star/Group.java b/app/src/main/java/com/github/catvod/bean/star/Group.java new file mode 100644 index 0000000..9027f67 --- /dev/null +++ b/app/src/main/java/com/github/catvod/bean/star/Group.java @@ -0,0 +1,24 @@ +package com.github.catvod.bean.star; + +import android.text.TextUtils; + +import com.google.gson.annotations.SerializedName; + +import java.util.Collections; +import java.util.List; + +public class Group { + + @SerializedName("name") + private String name; + @SerializedName("videos") + private List