diff --git a/app/src/main/java/com/fongmi/android/tv/api/LiveParser.java b/app/src/main/java/com/fongmi/android/tv/api/LiveParser.java index 9e418675f..0ae0c78eb 100644 --- a/app/src/main/java/com/fongmi/android/tv/api/LiveParser.java +++ b/app/src/main/java/com/fongmi/android/tv/api/LiveParser.java @@ -11,6 +11,7 @@ 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; @@ -110,8 +111,11 @@ public class LiveParser { } private static void xtream(Live live) { - List categoryList = XtreamParser.getCategoryList(live); + XInfo info = XtreamParser.getInfo(live); + live.setTimeZone(info.getServerInfo().getTimezone()); List streamList = XtreamParser.getStreamList(live); + List categoryList = XtreamParser.getCategoryList(live); + List formats = info.getUserInfo().getAllowedOutputFormats(); Map categoryMap = new HashMap<>(); for (XCategory category : categoryList) { categoryMap.put(category.getCategoryId(), category.getCategoryName()); @@ -120,9 +124,10 @@ public class LiveParser { 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())); - channel.getUrls().add(XtreamParser.getTsUrl(live, stream.getStreamId())); if (!stream.getStreamIcon().isEmpty()) channel.setLogo(stream.getStreamIcon()); if (!stream.getEpgChannelId().isEmpty()) channel.setTvgName(stream.getEpgChannelId()); + if (formats.isEmpty()) channel.getUrls().add(XtreamParser.getPlayUrl(live, stream.getStreamId(), "ts")); + for (String format : formats) channel.getUrls().add(XtreamParser.getPlayUrl(live, stream.getStreamId(), format)); } } @@ -146,7 +151,7 @@ public class LiveParser { } private static String getText(Live live) { - return live.isXtream() ? "" : getText(live.getUrl(), live.getHeaders()).replace("\r\n", "\n"); + return XtreamParser.isApiUrl(live.getUrl()) ? "" : getText(live.getUrl(), live.getHeaders()).replace("\r\n", "\n"); } private static String getText(String url, Map header) { diff --git a/app/src/main/java/com/fongmi/android/tv/api/XtreamParser.java b/app/src/main/java/com/fongmi/android/tv/api/XtreamParser.java index 508d81880..0ca3de782 100644 --- a/app/src/main/java/com/fongmi/android/tv/api/XtreamParser.java +++ b/app/src/main/java/com/fongmi/android/tv/api/XtreamParser.java @@ -4,6 +4,7 @@ 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; @@ -18,24 +19,36 @@ public class XtreamParser { return new HttpUrl.Builder().scheme(url.scheme()).host(url.host()).port(url.port()); } - public static boolean isVerify(String url) { - return isVerify(Uri.parse(url)); - } - 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 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 String getTsUrl(Live live, String id) { - return getBuilder(live).addPathSegment("live").addPathSegment(live.getUsername()).addPathSegment(live.getPassword()).addPathSegment(id + ".ts").build().toString(); + public static String getPlayUrl(Live live, String id, String format) { + return getBuilder(live).addPathSegment("live").addPathSegment(live.getUsername()).addPathSegment(live.getPassword()).addPathSegment(id + "." + format + "$" + format.toUpperCase()).build().toString(); + } + + public static XInfo getInfo(Live live) { + return XInfo.objectFrom(OkHttp.string(getApiUrl(live))); } public static List getCategoryList(Live live) { diff --git a/app/src/main/java/com/fongmi/android/tv/api/config/LiveConfig.java b/app/src/main/java/com/fongmi/android/tv/api/config/LiveConfig.java index 8c22ed602..9c6bc72b8 100644 --- a/app/src/main/java/com/fongmi/android/tv/api/config/LiveConfig.java +++ b/app/src/main/java/com/fongmi/android/tv/api/config/LiveConfig.java @@ -114,7 +114,7 @@ public class LiveConfig { private void loadConfig(Callback callback) { try { - boolean xtream = XtreamParser.isVerify(config.getUrl()); + boolean xtream = XtreamParser.isApiUrl(config.getUrl()); parseConfig(xtream ? "" : Decoder.getJson(config.getUrl()), callback); } catch (Throwable e) { if (TextUtils.isEmpty(config.getUrl())) App.post(() -> callback.error("")); diff --git a/app/src/main/java/com/fongmi/android/tv/bean/Live.java b/app/src/main/java/com/fongmi/android/tv/bean/Live.java index c29ba1734..2541ac137 100644 --- a/app/src/main/java/com/fongmi/android/tv/bean/Live.java +++ b/app/src/main/java/com/fongmi/android/tv/bean/Live.java @@ -86,6 +86,10 @@ public class Live { @SerializedName("password") private String password; + @Ignore + @SerializedName("timeZone") + private String timeZone; + @Ignore @SerializedName("type") private Integer type; @@ -230,6 +234,14 @@ public class Live { this.password = password; } + public String getTimeZone() { + return TextUtils.isEmpty(timeZone) ? "" : timeZone; + } + + public void setTimeZone(String timeZone) { + this.timeZone = timeZone; + } + public Integer getType() { return type == null ? 0 : type; } diff --git a/app/src/main/java/com/fongmi/android/tv/bean/XInfo.java b/app/src/main/java/com/fongmi/android/tv/bean/XInfo.java new file mode 100644 index 000000000..3c77ba1f9 --- /dev/null +++ b/app/src/main/java/com/fongmi/android/tv/bean/XInfo.java @@ -0,0 +1,51 @@ +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.Collections; +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 allowedOutputFormats; + + public List getAllowedOutputFormats() { + if (allowedOutputFormats != null) allowedOutputFormats.remove("rtmp"); + return allowedOutputFormats == null ? Collections.emptyList() : allowedOutputFormats; + } + } + + public static class ServerInfo { + + @SerializedName("timezone") + private String timezone; + + public String getTimezone() { + return TextUtils.isEmpty(timezone) ? "" : timezone; + } + } +} diff --git a/app/src/main/java/com/fongmi/android/tv/model/LiveViewModel.java b/app/src/main/java/com/fongmi/android/tv/model/LiveViewModel.java index 881e5864c..a313a8a60 100644 --- a/app/src/main/java/com/fongmi/android/tv/model/LiveViewModel.java +++ b/app/src/main/java/com/fongmi/android/tv/model/LiveViewModel.java @@ -1,7 +1,5 @@ package com.fongmi.android.tv.model; -import android.net.Uri; - import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; @@ -61,7 +59,7 @@ public class LiveViewModel extends ViewModel { public void getLive(Live item) { execute(LIVE, () -> { LiveParser.start(item.recent()); - setTimeZone(item.getEpg()); + setTimeZone(item); verify(item); return item; }); @@ -100,10 +98,9 @@ public class LiveViewModel extends ViewModel { }); } - private void setTimeZone(String url) { + private void setTimeZone(Live live) { try { - if (!url.contains("serverTimeZone=")) return; - TimeZone timeZone = TimeZone.getTimeZone(Uri.parse(url).getQueryParameter("serverTimeZone")); + TimeZone timeZone = live.getTimeZone().isEmpty() ? TimeZone.getDefault() : TimeZone.getTimeZone(live.getTimeZone()); formatDate.setTimeZone(timeZone); formatTime.setTimeZone(timeZone); } catch (Exception ignored) {