Remove xtream code

pull/589/head
FongMi 1 year ago
parent 6319140b4d
commit f9d413b42c
  1. 2
      app/src/main/java/com/fongmi/android/tv/api/Decoder.java
  2. 50
      app/src/main/java/com/fongmi/android/tv/api/LiveParser.java
  3. 85
      app/src/main/java/com/fongmi/android/tv/api/XtreamParser.java
  4. 10
      app/src/main/java/com/fongmi/android/tv/api/config/LiveConfig.java
  5. 14
      app/src/main/java/com/fongmi/android/tv/bean/Live.java
  6. 33
      app/src/main/java/com/fongmi/android/tv/bean/XCategory.java
  7. 53
      app/src/main/java/com/fongmi/android/tv/bean/XInfo.java
  8. 73
      app/src/main/java/com/fongmi/android/tv/bean/XStream.java
  9. 3
      app/src/main/java/com/fongmi/android/tv/gson/DanmakuAdapter.java
  10. 2
      app/src/main/java/com/fongmi/android/tv/utils/Sniffer.java
  11. 14
      catvod/src/main/java/com/github/catvod/utils/Json.java
  12. 10
      other/sample/live/xtream.json
  13. 4
      quickjs/src/main/java/com/fongmi/quickjs/crawler/Spider.java

@ -33,7 +33,7 @@ public class Decoder {
private static String verify(String url, String data) throws Exception {
if (data.isEmpty()) throw new Exception();
if (Json.valid(data)) return fix(url, data);
if (Json.isObj(data)) return fix(url, data);
if (data.contains("**")) data = base64(data);
if (data.startsWith("2423")) data = cbc(data);
return fix(url, data);

@ -8,16 +8,12 @@ import com.fongmi.android.tv.bean.ClearKey;
import com.fongmi.android.tv.bean.Drm;
import com.fongmi.android.tv.bean.Group;
import com.fongmi.android.tv.bean.Live;
import com.fongmi.android.tv.bean.XCategory;
import com.fongmi.android.tv.bean.XInfo;
import com.fongmi.android.tv.bean.XStream;
import com.fongmi.android.tv.utils.UrlUtil;
import com.github.catvod.net.OkHttp;
import com.github.catvod.utils.Json;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -50,16 +46,20 @@ public class LiveParser {
public static void start(Live live) throws Exception {
if (!live.getGroups().isEmpty()) return;
if (live.getType() == 0) text(live, getText(live));
if (live.getType() == 1) json(live, getText(live));
if (live.getType() == 3) spider(live);
String text = getText(live);
if (Json.isArray(text)) json(live, text);
else text(live, text);
}
private static String getText(Live live) throws Exception {
if (live.getType() == 3) return live.spider().liveContent(live.getUrl());
return OkHttp.string(UrlUtil.convert(live.getUrl()), live.getHeaders());
}
public static void text(Live live, String text) {
int number = 0;
if (!live.getGroups().isEmpty()) return;
if (M3U.matcher(text).find()) m3u(live, text); else txt(live, text);
if (live.isXtream()) xtream(live);
for (Group group : live.getGroups()) {
for (Channel channel : group.getChannel()) {
if (channel.getNumber().isEmpty()) channel.setNumber(++number);
@ -69,20 +69,16 @@ public class LiveParser {
}
private static void json(Live live, String text) {
int number = 0;
live.getGroups().addAll(Group.arrayFrom(text));
for (Group group : live.getGroups()) {
for (Channel channel : group.getChannel()) {
if (channel.getNumber().isEmpty()) channel.setNumber(++number);
channel.live(live);
}
}
}
private static void spider(Live live) throws Exception {
String text = live.spider().liveContent(live.getUrl());
if (Json.valid(text)) json(live, text);
else text(live, text);
}
private static void m3u(Live live, String text) {
Setting setting = Setting.create();
Catchup catchup = Catchup.create();
@ -119,27 +115,6 @@ public class LiveParser {
}
}
private static void xtream(Live live) {
XInfo info = XtreamParser.getInfo(live);
if (live.getEpg().isEmpty()) live.setEpg(XtreamParser.getEpgUrl(live));
if (live.getTimeZone().isEmpty()) live.setTimeZone(info.getServerInfo().getTimezone());
if (!live.getGroups().isEmpty()) return;
List<XCategory> categoryList = XtreamParser.getCategoryList(live);
List<XStream> streamList = XtreamParser.getStreamList(live);
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 = live.find(Group.create(categoryMap.get(stream.getCategoryId()), live.isPass()));
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(live, info.getUserInfo().getAllowedOutputFormats()));
}
}
private static void txt(Live live, String text) {
Setting setting = Setting.create();
text = text.replace("\r\n", "\n").replace("\r", "");
@ -160,11 +135,6 @@ public class LiveParser {
}
}
private static String getText(Live live) {
if (live.isXtream() && !XtreamParser.isGetUrl(live.getUrl())) return "";
return OkHttp.string(UrlUtil.convert(live.getUrl()), live.getHeaders());
}
private static class Setting {
private String ua;

@ -1,85 +0,0 @@
package com.fongmi.android.tv.api;
import android.net.Uri;
import com.fongmi.android.tv.bean.Live;
import com.fongmi.android.tv.bean.XCategory;
import com.fongmi.android.tv.bean.XInfo;
import com.fongmi.android.tv.bean.XStream;
import com.github.catvod.net.OkHttp;
import java.util.List;
import okhttp3.HttpUrl;
public class XtreamParser {
public static HttpUrl.Builder getBuilder(Live live) {
HttpUrl url = HttpUrl.parse(live.getUrl());
return new HttpUrl.Builder().scheme(url.scheme()).host(url.host()).port(url.port());
}
public static boolean isVerify(Uri uri) {
return uri.getPath() != null && uri.getQueryParameter("username") != null && uri.getQueryParameter("password") != null && (uri.getPath().contains("player_api.php") || uri.getPath().contains("get.php"));
}
public static boolean isApiUrl(String url) {
return isApiUrl(Uri.parse(url));
}
public static boolean isApiUrl(Uri uri) {
return uri.getPath() != null && uri.getQueryParameter("username") != null && uri.getQueryParameter("password") != null && uri.getPath().contains("player_api.php");
}
public static boolean isGetUrl(String url) {
return isGetUrl(Uri.parse(url));
}
public static boolean isGetUrl(Uri uri) {
return uri.getPath() != null && uri.getQueryParameter("username") != null && uri.getQueryParameter("password") != null && uri.getPath().contains("get.php");
}
public static String getEpgUrl(Live live) {
return getBuilder(live).addPathSegment("xmltv.php").addQueryParameter("username", live.getUsername()).addQueryParameter("password", live.getPassword()).build().toString();
}
public static String getApiUrl(Live live) {
return getBuilder(live).addPathSegment("player_api.php").addQueryParameter("username", live.getUsername()).addQueryParameter("password", live.getPassword()).build().toString();
}
public static String getApiUrl(Live live, String action) {
return getBuilder(live).addPathSegment("player_api.php").addQueryParameter("username", live.getUsername()).addQueryParameter("password", live.getPassword()).addQueryParameter("action", action).build().toString();
}
public static XInfo getInfo(Live live) {
return XInfo.objectFrom(OkHttp.string(getApiUrl(live)));
}
public static List<XCategory> getLiveCategoryList(Live live) {
return XCategory.arrayFrom(OkHttp.string(getApiUrl(live, "get_live_categories")));
}
public static List<XStream> getLiveStreamList(Live live) {
return XStream.arrayFrom(OkHttp.string(getApiUrl(live, "get_live_streams")));
}
public static List<XCategory> getVodCategoryList(Live live) {
return XCategory.arrayFrom(OkHttp.string(getApiUrl(live, "get_vod_categories")));
}
public static List<XStream> getVodStreamList(Live live) {
return XStream.arrayFrom(OkHttp.string(getApiUrl(live, "get_vod_streams")));
}
public static List<XCategory> getCategoryList(Live live) {
List<XCategory> categoryList = XtreamParser.getLiveCategoryList(live);
categoryList.addAll(XtreamParser.getVodCategoryList(live));
return categoryList;
}
public static List<XStream> getStreamList(Live live) {
List<XStream> streamList = XtreamParser.getLiveStreamList(live);
streamList.addAll(XtreamParser.getVodStreamList(live));
return streamList;
}
}

@ -8,7 +8,6 @@ import com.fongmi.android.tv.R;
import com.fongmi.android.tv.Setting;
import com.fongmi.android.tv.api.Decoder;
import com.fongmi.android.tv.api.LiveParser;
import com.fongmi.android.tv.api.XtreamParser;
import com.fongmi.android.tv.api.loader.BaseLoader;
import com.fongmi.android.tv.bean.Channel;
import com.fongmi.android.tv.bean.Config;
@ -114,8 +113,7 @@ public class LiveConfig {
private void loadConfig(Callback callback) {
try {
boolean xtream = XtreamParser.isApiUrl(config.getUrl());
parseConfig(xtream ? "" : Decoder.getJson(config.getUrl()), callback);
parseConfig(Decoder.getJson(config.getUrl()), callback);
} catch (Throwable e) {
if (TextUtils.isEmpty(config.getUrl())) App.post(() -> callback.error(""));
else App.post(() -> callback.error(Notify.getError(R.string.error_config_get, e)));
@ -124,7 +122,7 @@ public class LiveConfig {
}
private void parseConfig(String text, Callback callback) {
if (Json.invalid(text)) {
if (!Json.isObj(text)) {
parseText(text, callback);
} else {
checkJson(Json.parse(text).getAsJsonObject(), callback);
@ -132,7 +130,7 @@ public class LiveConfig {
}
private void parseText(String text, Callback callback) {
Live live = new Live(parseName(config.getUrl()), config.getUrl()).check().sync();
Live live = new Live(parseName(config.getUrl()), config.getUrl()).sync();
LiveParser.text(live, text);
lives.add(live);
setHome(live, true);
@ -187,7 +185,7 @@ public class LiveConfig {
live.setApi(UrlUtil.convert(live.getApi()));
live.setExt(UrlUtil.convert(live.getExt()));
live.setJar(parseJar(live, spider));
lives.add(live.check().sync());
lives.add(live.sync());
}
for (Live live : lives) {
if (live.getName().equals(config.getHome())) {

@ -1,6 +1,5 @@
package com.fongmi.android.tv.bean;
import android.net.Uri;
import android.text.TextUtils;
import androidx.annotation.NonNull;
@ -11,7 +10,6 @@ import androidx.room.PrimaryKey;
import com.fongmi.android.tv.App;
import com.fongmi.android.tv.Constant;
import com.fongmi.android.tv.R;
import com.fongmi.android.tv.api.XtreamParser;
import com.fongmi.android.tv.api.loader.BaseLoader;
import com.fongmi.android.tv.db.AppDatabase;
import com.fongmi.android.tv.gson.ExtAdapter;
@ -313,10 +311,6 @@ public class Live {
this.width = width;
}
public boolean isXtream() {
return !getUsername().isEmpty() && !getPassword().isEmpty();
}
public boolean isEmpty() {
return getName().isEmpty();
}
@ -360,14 +354,6 @@ public class Live {
return this;
}
public Live check() {
Uri uri = Uri.parse(getUrl());
boolean xtream = XtreamParser.isVerify(uri);
if (xtream) setUsername(uri.getQueryParameter("username"));
if (xtream) setPassword(uri.getQueryParameter("password"));
return this;
}
public Live recent() {
BaseLoader.get().setRecent(getName(), getApi(), getJar());
return this;

@ -1,33 +0,0 @@
package com.fongmi.android.tv.bean;
import android.text.TextUtils;
import com.fongmi.android.tv.App;
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 = App.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;
}
}

@ -1,53 +0,0 @@
package com.fongmi.android.tv.bean;
import android.text.TextUtils;
import com.fongmi.android.tv.App;
import com.google.gson.annotations.SerializedName;
import java.util.ArrayList;
import java.util.List;
public class XInfo {
@SerializedName("user_info")
private UserInfo userInfo;
@SerializedName("server_info")
private ServerInfo serverInfo;
public static XInfo objectFrom(String str) {
XInfo item = App.gson().fromJson(str, XInfo.class);
return item == null ? new XInfo() : item;
}
public UserInfo getUserInfo() {
return userInfo == null ? new UserInfo() : userInfo;
}
public ServerInfo getServerInfo() {
return serverInfo == null ? new ServerInfo() : serverInfo;
}
public static class UserInfo {
@SerializedName("allowed_output_formats")
private List<String> allowedOutputFormats;
public List<String> getAllowedOutputFormats() {
if (allowedOutputFormats == null) allowedOutputFormats = new ArrayList<>();
if (allowedOutputFormats.isEmpty()) allowedOutputFormats.add("ts");
allowedOutputFormats.remove("rtmp");
return allowedOutputFormats;
}
}
public static class ServerInfo {
@SerializedName("timezone")
private String timezone;
public String getTimezone() {
return TextUtils.isEmpty(timezone) ? "" : timezone;
}
}
}

@ -1,73 +0,0 @@
package com.fongmi.android.tv.bean;
import android.text.TextUtils;
import com.fongmi.android.tv.App;
import com.fongmi.android.tv.api.XtreamParser;
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 = App.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(Live live, List<String> formats) {
List<String> urls = new ArrayList<>();
if (!getContainerExtension().isEmpty()) urls.add(XtreamParser.getBuilder(live).addPathSegment(getStreamType()).addPathSegment(live.getUsername()).addPathSegment(live.getPassword()).addPathSegment(getStreamId() + "." + getContainerExtension()).build().toString());
else for (String format : formats) urls.add(XtreamParser.getBuilder(live).addPathSegment(getStreamType()).addPathSegment(live.getUsername()).addPathSegment(live.getPassword()).addPathSegment(getStreamId() + "." + format + "$" + format.toUpperCase()).build().toString());
return urls;
}
}

@ -2,6 +2,7 @@ package com.fongmi.android.tv.gson;
import com.fongmi.android.tv.App;
import com.fongmi.android.tv.bean.Danmaku;
import com.github.catvod.utils.Json;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
@ -16,7 +17,7 @@ public class DanmakuAdapter implements JsonDeserializer<List<Danmaku>> {
public List<Danmaku> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (!json.isJsonPrimitive()) return App.gson().fromJson(json, typeOfT);
String text = json.getAsString().trim();
if (text.startsWith("[")) return App.gson().fromJson(text, typeOfT);
if (Json.isArray(text)) return App.gson().fromJson(text, typeOfT);
else return Danmaku.from(text);
}
}

@ -21,7 +21,7 @@ public class Sniffer {
public static final Pattern SNIFFER = Pattern.compile("http((?!http).){12,}?\\.(m3u8|mp4|mkv|flv|mp3|m4a|aac|mpd)\\?.*|http((?!http).){12,}\\.(m3u8|mp4|mkv|flv|mp3|m4a|aac|mpd)|http((?!http).)*?video/tos*|http((?!http).)*?obj/tos*|rtmp:[^\\s]+");
public static String getUrl(String text) {
if (Json.valid(text) || text.contains("$")) return text;
if (Json.isObj(text) || text.contains("$")) return text;
Matcher m = AI_PUSH.matcher(text);
if (m.find()) return m.group(0);
return text;

@ -6,6 +6,7 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
@ -23,8 +24,9 @@ public class Json {
}
}
public static boolean valid(String text) {
public static boolean isObj(String text) {
try {
if (TextUtils.isEmpty(text)) return false;
new JSONObject(text);
return true;
} catch (Exception e) {
@ -32,8 +34,14 @@ public class Json {
}
}
public static boolean invalid(String text) {
return !valid(text);
public static boolean isArray(String text) {
try {
if (TextUtils.isEmpty(text)) return false;
new JSONArray(text);
return true;
} catch (Exception e) {
return false;
}
}
public static String safeString(JsonObject obj, String key) {

@ -1,10 +0,0 @@
{
"lives": [
{
"name": "Xtream",
"url": "http://127.0.0.2:8888",
"username": "tangsan",
"password": "tangsan"
}
]
}

@ -65,7 +65,7 @@ public class Spider extends com.github.catvod.crawler.Spider {
@Override
public void init(Context context, String extend) throws Exception {
if (cat) call("init", submit(() -> cfg(extend)).get());
else call("init", Json.valid(extend) ? ctx.parse(extend) : extend);
else call("init", Json.isObj(extend) ? ctx.parse(extend) : extend);
}
@Override
@ -196,7 +196,7 @@ public class Spider extends com.github.catvod.crawler.Spider {
JSObject cfg = ctx.createNewJSObject();
cfg.setProperty("stype", 3);
cfg.setProperty("skey", key);
if (Json.invalid(ext)) cfg.setProperty("ext", ext);
if (!Json.isObj(ext)) cfg.setProperty("ext", ext);
else cfg.setProperty("ext", (JSObject) ctx.parse(ext));
return cfg;
}

Loading…
Cancel
Save