Add XtreamCode

pull/103/head
FongMi 10 months ago
parent 3007a2c25d
commit 9919ae4a35
  1. 94
      app/src/main/java/com/github/catvod/bean/live/Channel.java
  2. 69
      app/src/main/java/com/github/catvod/bean/live/Group.java
  3. 50
      app/src/main/java/com/github/catvod/bean/xc/Config.java
  4. 33
      app/src/main/java/com/github/catvod/bean/xc/XCategory.java
  5. 72
      app/src/main/java/com/github/catvod/bean/xc/XStream.java
  6. 100
      app/src/main/java/com/github/catvod/spider/Feiyang.java
  7. 88
      app/src/main/java/com/github/catvod/spider/XtreamCode.java
  8. 8
      app/src/main/res/layout/activity_main.xml
  9. BIN
      jar/custom_spider.jar
  10. 2
      jar/custom_spider.jar.md5

@ -0,0 +1,94 @@
package com.github.catvod.bean.live;
import android.text.TextUtils;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.annotations.SerializedName;
import java.util.ArrayList;
import java.util.List;
public class Channel {
@SerializedName("urls")
private List<String> urls;
@SerializedName("tvgName")
private String tvgName;
@SerializedName("number")
private String number;
@SerializedName("logo")
private String logo;
@SerializedName("name")
private String name;
@SerializedName("epg")
private String epg;
@SerializedName("ua")
private String ua;
@SerializedName("referer")
private String referer;
public static Channel objectFrom(JsonElement element) {
return new Gson().fromJson(element, Channel.class);
}
public static Channel create(String name) {
return new Channel(name);
}
public Channel(String name) {
this.name = name;
}
public String getNumber() {
return TextUtils.isEmpty(number) ? "" : number;
}
public String getName() {
return TextUtils.isEmpty(name) ? "" : name;
}
public List<String> getUrls() {
return urls = urls == null ? new ArrayList<>() : urls;
}
public void setUrls(List<String> urls) {
this.urls = urls;
}
public void setTvgName(String tvgName) {
this.tvgName = tvgName;
}
public void setNumber(String number) {
this.number = number;
}
public void setLogo(String logo) {
this.logo = logo;
}
public void setName(String name) {
this.name = name;
}
public void setEpg(String epg) {
this.epg = epg;
}
public void setUa(String ua) {
this.ua = ua;
}
public void setReferer(String referer) {
this.referer = referer;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Channel)) return false;
Channel it = (Channel) obj;
return getName().equals(it.getName()) || (!getNumber().isEmpty() && getNumber().equals(it.getNumber()));
}
}

@ -0,0 +1,69 @@
package com.github.catvod.bean.live;
import android.text.TextUtils;
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 Group {
@SerializedName("channel")
private List<Channel> channel;
@SerializedName("name")
private String name;
public static List<Group> arrayFrom(String str) {
Type listType = new TypeToken<List<Group>>() {}.getType();
List<Group> items = new Gson().fromJson(str, listType);
return items == null ? Collections.emptyList() : items;
}
public static Group find(List<Group> items, Group item) {
for (Group group : items) if (group.getName().equals(item.getName())) return group;
items.add(item);
return item;
}
public static Group create(String name) {
return new Group(name);
}
public Group(String name) {
this.name = name;
if (name.contains("_")) setName(name.split("_")[0]);
}
public List<Channel> getChannel() {
return channel = channel == null ? new ArrayList<>() : channel;
}
public String getName() {
return TextUtils.isEmpty(name) ? "" : name;
}
public void setName(String name) {
this.name = name;
}
public Channel find(Channel channel) {
int index = getChannel().indexOf(channel);
if (index != -1) return getChannel().get(index);
getChannel().add(channel);
return channel;
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (this == obj) return true;
if (!(obj instanceof Group)) return false;
Group it = (Group) obj;
return getName().equals(it.getName()) && getChannel().size() == it.getChannel().size();
}
}

@ -0,0 +1,50 @@
package com.github.catvod.bean.xc;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.util.Arrays;
import java.util.List;
public class Config {
@SerializedName("name")
private String name;
@SerializedName("pass")
private String pass;
@SerializedName("vod")
private boolean vod;
@SerializedName("formats")
private List<String> formats;
private String url;
public static Config objectFrom(String str) {
Config item = new Gson().fromJson(str, Config.class);
return item == null ? new Config() : item;
}
public void setUrl(String url) {
this.url = url;
}
public String getUrl() {
return url;
}
public String getName() {
return name;
}
public String getPass() {
return pass;
}
public boolean isVod() {
return vod;
}
public List<String> getFormats() {
return formats == null ? Arrays.asList("ts") : formats;
}
}

@ -0,0 +1,33 @@
package com.github.catvod.bean.xc;
import android.text.TextUtils;
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 XCategory {
@SerializedName("category_id")
private String categoryId;
@SerializedName("category_name")
private String categoryName;
public static List<XCategory> arrayFrom(String str) {
Type listType = new TypeToken<List<XCategory>>() {}.getType();
List<XCategory> items = new Gson().fromJson(str, listType);
return items == null ? Collections.emptyList() : items;
}
public String getCategoryId() {
return TextUtils.isEmpty(categoryId) ? "" : categoryId;
}
public String getCategoryName() {
return TextUtils.isEmpty(categoryName) ? "" : categoryName;
}
}

@ -0,0 +1,72 @@
package com.github.catvod.bean.xc;
import android.text.TextUtils;
import com.github.catvod.spider.XtreamCode;
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 XStream {
@SerializedName("name")
private String name;
@SerializedName("stream_id")
private String streamId;
@SerializedName("stream_type")
private String streamType;
@SerializedName("stream_icon")
private String streamIcon;
@SerializedName("epg_channel_id")
private String epgChannelId;
@SerializedName("category_id")
private String categoryId;
@SerializedName("container_extension")
private String containerExtension;
public static List<XStream> arrayFrom(String str) {
Type listType = new TypeToken<List<XStream>>() {}.getType();
List<XStream> items = new Gson().fromJson(str, listType);
return items == null ? Collections.emptyList() : items;
}
public String getName() {
return TextUtils.isEmpty(name) ? "" : name;
}
public String getStreamId() {
return TextUtils.isEmpty(streamId) ? "" : streamId;
}
public String getStreamType() {
return TextUtils.isEmpty(streamType) ? "" : streamType;
}
public String getStreamIcon() {
return TextUtils.isEmpty(streamIcon) ? "" : streamIcon;
}
public String getEpgChannelId() {
return TextUtils.isEmpty(epgChannelId) ? "" : epgChannelId;
}
public String getCategoryId() {
return TextUtils.isEmpty(categoryId) ? "" : categoryId;
}
public String getContainerExtension() {
return TextUtils.isEmpty(containerExtension) ? "" : containerExtension;
}
public List<String> getPlayUrl(Config config) {
List<String> urls = new ArrayList<>();
if (!getContainerExtension().isEmpty()) urls.add(XtreamCode.getBuilder(config).addPathSegment(getStreamType()).addPathSegment(config.getName()).addPathSegment(config.getPass()).addPathSegment(getStreamId() + "." + getContainerExtension()).build().toString());
else for (String format : config.getFormats()) urls.add(XtreamCode.getBuilder(config).addPathSegment(getStreamType()).addPathSegment(config.getName()).addPathSegment(config.getPass()).addPathSegment(getStreamId() + "." + format + "$" + format.toUpperCase()).build().toString());
return urls;
}
}

@ -1,100 +0,0 @@
package com.github.catvod.spider;
import android.content.Context;
import android.os.SystemClock;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.FileUtil;
import com.github.catvod.utils.Path;
import com.github.catvod.utils.Shell;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
public class Feiyang extends Spider {
private static final String URL = "http://127.0.0.1:35345/";
private static final String AIO = "allinone-linux-musl";
private static final String SHELL = "run-allinone.sh";
private static final File f_shell = new File(Path.files(), SHELL);
private static final File f_aio = new File(Path.files(), AIO);
private static Thread thread;
@Override
public void init(Context context, String extend) throws Exception {
createShell();
checkExtend(extend);
findAIO(Path.tv().listFiles());
findAIO(Path.download().listFiles());
}
@Override
public String liveContent(String url) {
int retry = 0;
while ((OkHttp.string(URL)).isEmpty() && retry++ < 20) SystemClock.sleep(250);
return OkHttp.string(url.startsWith("http") ? url : URL + url);
}
private void createShell() {
File cache = Path.cache("allinone.cache");
String cachePath = cache.getAbsolutePath();
String shellPath = f_shell.getAbsolutePath();
String aioPath = f_aio.getAbsolutePath();
String script = "if [ -e " + shellPath + ".kill ]; then\n" + "sh " + shellPath + ".kill;\n" + "killall -9 " + AIO + ";\n" + "sleep 1;\n" + "rm -f " + shellPath + ".kill;\n" + "fi\n" + "echo \"kill -9 $$\" >> " + shellPath + ".kill;\n" + "while(true)\n" + "do\n" + "TMPDIR=" + cachePath + " " + aioPath + " -ipv6=true " + " -port 35345 " + " >/dev/null 2>&1\n" + "pidlist=$(ps -ef|grep " + SHELL + "|grep -v grep|awk '{print $2}')\n" + "selfpid=$$\n" + "for pid in $pidlist\n" + "do\n" + "if [[ $pid != \"$selfpid\" ]] then\n" + "kill -9 $pid\n" + "fi\n" + "done\n" + "killall -9 " + AIO + "\n" + "rm -rf \"" + cachePath + "\"/*\n" + "sleep 5;\n" + "done";
Path.write(f_shell, script);
}
private void checkExtend(String extend) {
if (!extend.contains(";md5;")) return;
String[] texts = extend.split(";md5;");
String url = texts[0].trim();
String md5 = texts[1].trim();
if (md5.startsWith("http")) md5 = OkHttp.string(md5).trim();
if (FileUtil.md5(f_aio).equals(md5)) return;
try {
File file = Path.create(new File(Path.download(), AIO));
download(file, OkHttp.newCall(url).body().byteStream());
} catch (Exception e) {
e.printStackTrace();
}
}
private void download(File file, InputStream is) throws Exception {
FileOutputStream os = new FileOutputStream(file);
try (BufferedInputStream input = new BufferedInputStream(is)) {
byte[] buffer = new byte[4096];
int readBytes;
while ((readBytes = input.read(buffer)) != -1) {
os.write(buffer, 0, readBytes);
}
}
}
private void findAIO(File[] files) {
if (files == null || thread != null) return;
for (File f : files) {
if (f.getName().equals("allinone") || f.getName().startsWith("allinone-linux")) {
Path.move(f, f_aio);
}
}
if (f_aio.exists()) {
thread = new Thread(() -> Shell.exec("nohup " + f_shell.getAbsolutePath() + " &"));
thread.start();
}
}
@Override
public void destroy() {
try {
Shell.exec("killall -9 " + AIO);
if (thread != null) thread.interrupt();
} catch (Exception e) {
e.printStackTrace();
} finally {
thread = null;
}
}
}

@ -0,0 +1,88 @@
package com.github.catvod.spider;
import android.content.Context;
import com.github.catvod.bean.live.Channel;
import com.github.catvod.bean.live.Group;
import com.github.catvod.bean.xc.Config;
import com.github.catvod.bean.xc.XCategory;
import com.github.catvod.bean.xc.XStream;
import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import okhttp3.HttpUrl;
public class XtreamCode extends Spider {
private List<Group> groups;
private Config config;
@Override
public void init(Context context, String extend) throws Exception {
config = Config.objectFrom(extend);
groups = new ArrayList<>();
}
@Override
public String liveContent(String url) {
config.setUrl(url);
List<XCategory> categoryList = getCategoryList(config);
List<XStream> streamList = getStreamList(config);
Map<String, String> categoryMap = new HashMap<>();
for (XCategory category : categoryList) {
categoryMap.put(category.getCategoryId(), category.getCategoryName());
}
for (XStream stream : streamList) {
if (!categoryMap.containsKey(stream.getCategoryId())) continue;
Group group = Group.find(groups, Group.create(categoryMap.get(stream.getCategoryId())));
Channel channel = group.find(Channel.create(stream.getName()));
if (!stream.getStreamIcon().isEmpty()) channel.setLogo(stream.getStreamIcon());
if (!stream.getEpgChannelId().isEmpty()) channel.setTvgName(stream.getEpgChannelId());
channel.getUrls().addAll(stream.getPlayUrl(config));
}
return new Gson().toJson(groups);
}
public static HttpUrl.Builder getBuilder(Config config) {
HttpUrl url = HttpUrl.parse(config.getUrl());
return new HttpUrl.Builder().scheme(url.scheme()).host(url.host()).port(url.port());
}
private String getApiUrl(Config config, String action) {
return getBuilder(config).addPathSegment("player_api.php").addQueryParameter("username", config.getName()).addQueryParameter("password", config.getPass()).addQueryParameter("action", action).build().toString();
}
private List<XCategory> getLiveCategoryList(Config config) {
return XCategory.arrayFrom(OkHttp.string(getApiUrl(config, "get_live_categories")));
}
private List<XStream> getLiveStreamList(Config config) {
return XStream.arrayFrom(OkHttp.string(getApiUrl(config, "get_live_streams")));
}
private List<XCategory> getVodCategoryList(Config config) {
return XCategory.arrayFrom(OkHttp.string(getApiUrl(config, "get_vod_categories")));
}
private List<XStream> getVodStreamList(Config config) {
return XStream.arrayFrom(OkHttp.string(getApiUrl(config, "get_vod_streams")));
}
private List<XCategory> getCategoryList(Config config) {
List<XCategory> categoryList = getLiveCategoryList(config);
if (config.isVod()) categoryList.addAll(getVodCategoryList(config));
return categoryList;
}
private List<XStream> getStreamList(Config config) {
List<XStream> streamList = getLiveStreamList(config);
if (config.isVod()) streamList.addAll(getVodStreamList(config));
return streamList;
}
}

@ -57,5 +57,13 @@
android:text="searchContent"
android:textAllCaps="false" />
<Button
android:id="@+id/liveContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="liveContent"
android:textAllCaps="false" />
</LinearLayout>
</ScrollView>

Binary file not shown.

@ -1 +1 @@
91086bebb3dee1e2e8caf7d18c9a6c13
90fd2379b3fb688bf7f56c442c78c6b3

Loading…
Cancel
Save