Add XtreamCode
This commit is contained in:
parent
3007a2c25d
commit
9919ae4a35
|
|
@ -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…
Reference in New Issue