Skip to content

Commit

Permalink
Add magnet support.
Browse files Browse the repository at this point in the history
  • Loading branch information
Cuke committed Jul 14, 2022
1 parent bba0e91 commit b19f45c
Show file tree
Hide file tree
Showing 7 changed files with 436 additions and 2 deletions.
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation files('libs\\thunder.jar')

annotationProcessor 'androidx.room:room-compiler:2.3.0'
implementation 'androidx.room:room-runtime:2.3.0'
Expand Down
Binary file added app/libs/thunder.jar
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import com.github.tvbox.osc.util.MD5;
import com.github.tvbox.osc.util.PlayerHelper;
import com.github.tvbox.osc.util.XWalkUtils;
import com.github.tvbox.osc.util.thunder.Thunder;
import com.github.tvbox.osc.viewmodel.SourceViewModel;
import com.lzy.okgo.OkGo;
import com.lzy.okgo.callback.AbsCallback;
Expand Down Expand Up @@ -462,6 +463,28 @@ public void play() {

playUrl(null, null);
String progressKey = mVodInfo.sourceKey + mVodInfo.id + mVodInfo.playFlag + mVodInfo.playIndex;
if (Thunder.play(vs.url, new Thunder.ThunderCallback() {
@Override
public void status(int code, String info) {
if (code < 0) {
setTip(info, false, true);
} else {
setTip(info, true, false);
}
}

@Override
public void list(String playList) {
}

@Override
public void play(String url) {
playUrl(url, null);
}
})) {
mController.showParse(false);
return;
}
sourceViewModel.getPlay(sourceKey, mVodInfo.playFlag, progressKey, vs.url);
}

Expand Down
333 changes: 333 additions & 0 deletions app/src/main/java/com/github/tvbox/osc/util/thunder/Thunder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,333 @@
package com.github.tvbox.osc.util.thunder;

import android.content.Context;
import android.content.SharedPreferences;
import android.net.Uri;
import android.text.TextUtils;

import com.xunlei.downloadlib.XLDownloadManager;
import com.xunlei.downloadlib.XLTaskHelper;
import com.xunlei.downloadlib.android.XLUtil;
import com.xunlei.downloadlib.parameter.TorrentFileInfo;
import com.xunlei.downloadlib.parameter.TorrentInfo;
import com.xunlei.downloadlib.parameter.XLTaskInfo;

import java.io.File;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Thunder {

private static String cacheRoot = "";
private static long currentTask = 0L;
private static ArrayList<TorrentFileInfo> torrentFileInfoArrayList = null;
private static ExecutorService threadPool = null;


private static void init(Context context) {
// fake deviceId and Mac
SharedPreferences sharedPreferences = context.getSharedPreferences("rand_thunder_id", Context.MODE_PRIVATE);
String imei = sharedPreferences.getString("imei", null);
String mac = sharedPreferences.getString("mac", null);
if (imei == null) {
imei = randomImei();
sharedPreferences.edit().putString("imei", imei).commit();
}
if (mac == null) {
mac = randomMac();
sharedPreferences.edit().putString("mac", mac).commit();
}

XLUtil.mIMEI = imei;
XLUtil.isGetIMEI = true;
XLUtil.mMAC = mac;
XLUtil.isGetMAC = true;
String cd3 = "cee25055f125a2fde0";
String base64Decode = "axzNjAwMQ^^yb==0^852^083dbcff^";
String substring = base64Decode.substring(1);
String substring2 = cd3.substring(0, cd3.length() - 1);
String cd = substring + substring2;
XLTaskHelper.init(context, cd, "21.01.07.800002");
cacheRoot = context.getCacheDir().getAbsolutePath() + File.separator + "thunder";
}

public static void stop() {
if (currentTask > 0) {
XLTaskHelper.instance().stopTask(currentTask);
currentTask = 0L;
}
torrentFileInfoArrayList = null;
// del cache file
File cache = new File(cacheRoot);
recursiveDelete(cache);
if (!cache.exists())
cache.mkdirs();
if (threadPool != null) {
try {
threadPool.shutdownNow();
threadPool = null;
} catch (Throwable th) {

}
}
}

public interface ThunderCallback {

void status(int code, String info);

void list(String playList);

void play(String url);
}

public static void parse(Context context, String url, ThunderCallback callback) {
init(context);
stop();
threadPool = Executors.newSingleThreadExecutor();
if (isMagnet(url) || isThunder(url)) {
String link = isThunder(url) ? XLDownloadManager.getInstance().parserThunderUrl(url) : url;
Uri p = Uri.parse(link);
if (p == null) {
callback.status(-1, "链接错误");
return;
}
String fileName = XLTaskHelper.instance().getFileName(link);
File cache = new File(cacheRoot + File.separator + fileName);
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
currentTask = isMagnet(url) ?
XLTaskHelper.instance().addMagentTask(url, cacheRoot, fileName) :
XLTaskHelper.instance().addThunderTask(url, cacheRoot, fileName);
} catch (Exception exception) {
exception.printStackTrace();
currentTask = 0;
}
if (currentTask <= 0) {
callback.status(-1, "链接错误");
return;
}
int count = 30;
while (true) {
count--;
if (count <= 0) {
callback.status(-1, "解析超时");
break;
}
XLTaskInfo taskInfo = XLTaskHelper.instance().getTaskInfo(currentTask);
switch (taskInfo.mTaskStatus) {
case 2: {
callback.status(0, "正在获取文件列表...");
try {
TorrentInfo torrentInfo = XLTaskHelper.instance().getTorrentInfo(cache.getAbsolutePath());
if (torrentInfo == null || TextUtils.isEmpty(torrentInfo.mInfoHash)) {
callback.status(-1, "解析失败");
} else {
TorrentFileInfo[] mSubFileInfo = torrentInfo.mSubFileInfo;
ArrayList<String> playList = new ArrayList<>();
ArrayList<TorrentFileInfo> list = new ArrayList<>();
if (mSubFileInfo != null && mSubFileInfo.length >= 0) {
for (TorrentFileInfo sub : mSubFileInfo) {
if (isMedia(sub.mFileName)) {
sub.torrentPath = cache.getAbsolutePath();
playList.add(sub.mFileName + "$tvbox-torrent:" + list.size());
list.add(sub);
}
}
}
if (list.size() > 0) {
torrentFileInfoArrayList = list;
callback.list(TextUtils.join("#", playList));
} else {
callback.status(-1, "文件列表为空!");
}
}
} catch (Throwable throwable) {
throwable.printStackTrace();
callback.status(-1, "解析失败");
}
return;
}
case 3: {
callback.status(-1, "解析失败");
return;
}
default: {
callback.status(0, "解析中...");
break;
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
}


public static boolean play(String url, ThunderCallback callback) {
if (url.startsWith("tvbox-torrent:")) {
int idx = Integer.parseInt(url.substring(14));
TorrentFileInfo info = torrentFileInfoArrayList.get(idx);
if (currentTask > 0) {
XLTaskHelper.instance().stopTask(currentTask);
currentTask = 0L;
}
threadPool.execute(new Runnable() {
@Override
public void run() {
String torrentName = new File(info.torrentPath).getName();
String cache = cacheRoot + File.separator + torrentName.substring(0, torrentName.lastIndexOf("."));
currentTask = XLTaskHelper.instance().addTorrentTask(info.torrentPath, cache, info.mFileIndex);
if (currentTask < 0)
callback.status(-1, "下载出错");
int count = 30;
while (true) {
count--;
if (count <= 0) {
callback.status(-1, "解析下载超时");
break;
}
XLTaskInfo taskInfo = XLTaskHelper.instance().getBtSubTaskInfo(currentTask, info.mFileIndex).mTaskInfo;
switch (taskInfo.mTaskStatus) {
case 3: {
callback.status(-1, errorInfo(taskInfo.mErrorCode));
return;
}
case 1:
case 4: // 下载中
case 2: { // 下载完成
String pUrl = XLTaskHelper.instance().getLoclUrl(cache + File.separator + info.mFileName);
callback.play(pUrl);
return;
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
return true;
}
return false;
}

private static String errorInfo(int code) {
switch (code) {
case 9125:
return "文件名太长";
case 111120:
return "文件路径太长";
case 111142:
return "文件太小";
case 111085:
return "磁盘空间不足";
case 111171:
return "拒绝的网络连接";
case 9301:
return "缓冲区不足";
case 114001:
case 114004:
case 114005:
case 114006:
case 114007:
case 114011:
case 9304:
case 111154:
return "版权限制:无权下载";
case 114101:
return "无效链接";
default:
return "ErrorCode=" + code;
}
}


public static boolean isSupportUrl(String url) {
return isMagnet(url) || isThunder(url)/* || isTorrent(url) || isEd2k(url)*/;
}

private static boolean isMagnet(String url) {
return url.toLowerCase().startsWith("magnet:");
}

private static boolean isThunder(String url) {
return url.toLowerCase().startsWith("thunder");
}

private static boolean isTorrent(String url) {
return url.toLowerCase().split(";")[0].endsWith(".torrent");
}

private static boolean isEd2k(String url) {
return url.toLowerCase().startsWith("ed2k:");
}

static void recursiveDelete(File file) {
if (!file.exists())
return;
if (file.isDirectory()) {
for (File f : file.listFiles()) {
recursiveDelete(f);
}
}
file.delete();
}

static ArrayList<String> formats = new ArrayList<>();

static boolean isMedia(String name) {
if (formats.size() == 0) {
formats.add(".rmvb");
formats.add(".avi");
formats.add(".mkv");
formats.add(".flv");
formats.add(".mp4");
formats.add(".rm");
formats.add(".vob");
formats.add(".wmv");
formats.add(".mov");
formats.add(".3gp");
formats.add(".asf");
formats.add("mpg");
formats.add("mpeg");
formats.add("mpe");
}
for (String f : formats) {
if (name.toLowerCase().endsWith(f))
return true;

}
return false;
}

static String randomImei() {
return randomString("0123456", 15);
}

static String randomMac() {
return randomString("ABCDEF0123456", 12).toUpperCase();
}

static String randomString(String base, int length) {
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}

}
Loading

0 comments on commit b19f45c

Please sign in to comment.