pull/586/head
FongMi 2 years ago
parent f05fad18fd
commit e2931cece7
  1. 6
      app/src/main/java/com/fongmi/android/tv/bean/Result.java
  2. 11
      app/src/main/java/com/fongmi/android/tv/bean/Sub.java
  3. 4
      app/src/main/java/com/fongmi/android/tv/event/PlayerEvent.java
  4. 47
      app/src/main/java/com/fongmi/android/tv/player/ExoUtil.java
  5. 54
      app/src/main/java/com/fongmi/android/tv/player/Players.java

@ -80,6 +80,8 @@ public class Result implements Parcelable {
private Integer code;
@SerializedName("jx")
private Integer jx;
@SerializedName("drm")
private Drm drm;
public static Result objectFrom(String str) {
try {
@ -273,6 +275,10 @@ public class Result implements Parcelable {
return jx == null ? 0 : jx;
}
public Drm getDrm() {
return drm;
}
public boolean hasMsg() {
return getMsg().length() > 0;
}

@ -3,6 +3,7 @@ package com.fongmi.android.tv.bean;
import android.net.Uri;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.MediaItem;
@ -78,7 +79,15 @@ public class Sub {
this.name = Trans.s2t(name);
}
public MediaItem.SubtitleConfiguration getExo() {
public MediaItem.SubtitleConfiguration getConfig() {
return new MediaItem.SubtitleConfiguration.Builder(Uri.parse(getUrl())).setLabel(getName()).setMimeType(getFormat()).setSelectionFlags(getFlag()).setLanguage(getLang()).build();
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) return true;
if (!(obj instanceof Sub)) return false;
Sub it = (Sub) obj;
return getUrl().equals(it.getUrl());
}
}

@ -8,6 +8,10 @@ public class PlayerEvent {
private final int state;
public static void prepare() {
EventBus.getDefault().post(new PlayerEvent(0));
}
public static void ready() {
EventBus.getDefault().post(new PlayerEvent(Player.STATE_READY));
}

@ -39,9 +39,7 @@ import androidx.media3.ui.CaptionStyleCompat;
import com.fongmi.android.tv.App;
import com.fongmi.android.tv.Setting;
import com.fongmi.android.tv.bean.Channel;
import com.fongmi.android.tv.bean.Drm;
import com.fongmi.android.tv.bean.Result;
import com.fongmi.android.tv.bean.Sub;
import com.fongmi.android.tv.player.custom.NextRenderersFactory;
import com.fongmi.android.tv.utils.Sniffer;
@ -106,7 +104,7 @@ public class ExoUtil {
return MimeTypes.APPLICATION_SUBRIP;
}
private static String getMimeType(String format, int errorCode) {
public static String getMimeType(String format, int errorCode) {
if (format != null) return format;
if (errorCode == PlaybackException.ERROR_CODE_PARSING_MANIFEST_UNSUPPORTED || errorCode == PlaybackException.ERROR_CODE_PARSING_MANIFEST_MALFORMED) return MimeTypes.APPLICATION_OCTET;
if (errorCode == PlaybackException.ERROR_CODE_PARSING_CONTAINER_UNSUPPORTED || errorCode == PlaybackException.ERROR_CODE_PARSING_CONTAINER_MALFORMED) return MimeTypes.APPLICATION_M3U8;
@ -117,40 +115,31 @@ public class ExoUtil {
return errorCode >= PlaybackException.ERROR_CODE_PARSING_CONTAINER_MALFORMED && errorCode <= PlaybackException.ERROR_CODE_PARSING_MANIFEST_UNSUPPORTED ? 2 : errorCode > 999 ? 1 : 0;
}
public static MediaSource getSource(Result result, Sub sub, int decode, int errorCode) {
return getSource(result.getHeaders(), result.getRealUrl(), result.getFormat(), result.getSubs(), sub, null, decode, errorCode);
public static MediaSource getSource(Map<String, String> headers, String url, String mimeType, Drm drm, List<Sub> subs, int decode) {
if (url.contains("***") && url.contains("|||")) return getConcat(headers, url, mimeType, drm, subs, decode);
return getMediaSource(headers, url, mimeType, drm, subs, decode);
}
public static MediaSource getSource(Channel channel, Sub sub, int decode, int errorCode) {
return getSource(channel.getHeaders(), channel.getUrl(), channel.getFormat(), new ArrayList<>(), sub, channel.getDrm(), decode, errorCode);
}
public static MediaSource getSource(Map<String, String> headers, String url, Sub sub, int decode, int errorCode) {
return getSource(headers, url, null, new ArrayList<>(), sub, null, decode, errorCode);
}
private static MediaSource getSource(Map<String, String> headers, String url, String format, List<Sub> subs, Sub sub, Drm drm, int decode, int errorCode) {
Uri uri = UrlUtil.uri(url);
if (sub != null) subs.add(sub);
String mimeType = getMimeType(format, errorCode);
if (url.contains("***") && url.contains("|||")) return getConcat(headers, url, format, subs, drm, decode, errorCode);
return new DefaultMediaSourceFactory(getDataSourceFactory(headers), getExtractorsFactory()).createMediaSource(getMediaItem(uri, mimeType, subs, drm, decode));
}
private static MediaSource getConcat(Map<String, String> headers, String url, String format, List<Sub> subs, Drm drm, int decode, int errorCode) {
private static MediaSource getConcat(Map<String, String> headers, String url, String mimeType, Drm drm, List<Sub> subs, int decode) {
ConcatenatingMediaSource2.Builder builder = new ConcatenatingMediaSource2.Builder();
for (String split : url.split("\\*\\*\\*")) {
String[] info = split.split("\\|\\|\\|");
if (info.length < 2) continue;
long duration = Long.parseLong(info[1]);
builder.add(getSource(headers, info[0], format, subs, null, drm, decode, errorCode), duration);
builder.add(getMediaSource(headers, info[0], mimeType, drm, subs, decode), duration);
}
return builder.build();
}
private static MediaItem getMediaItem(Uri uri, String mimeType, List<Sub> subs, Drm drm, int decode) {
private static MediaSource getMediaSource(Map<String, String> headers, String url, String mimeType, Drm drm, List<Sub> subs, int decode) {
return new DefaultMediaSourceFactory(getDataSourceFactory(headers), getExtractorsFactory()).createMediaSource(getMediaItem(UrlUtil.uri(url), mimeType, drm, subs, decode));
}
private static MediaItem getMediaItem(Uri uri, String mimeType, Drm drm, List<Sub> subs, int decode) {
List<MediaItem.SubtitleConfiguration> subtitleConfigurations = new ArrayList<>();
for (Sub sub : subs) subtitleConfigurations.add(sub.getConfig());
MediaItem.Builder builder = new MediaItem.Builder().setUri(uri);
if (!subs.isEmpty()) builder.setSubtitleConfigurations(getSubtitles(subs));
builder.setSubtitleConfigurations(subtitleConfigurations);
if (drm != null) builder.setDrmConfiguration(drm.get());
if (mimeType != null) builder.setMimeType(mimeType);
builder.setAllowChunklessPreparation(decode == 1);
@ -159,12 +148,6 @@ public class ExoUtil {
return builder.build();
}
private static List<MediaItem.SubtitleConfiguration> getSubtitles(List<Sub> subs) {
List<MediaItem.SubtitleConfiguration> items = new ArrayList<>();
for (Sub sub : subs) items.add(sub.getExo());
return items;
}
private static void selectTrack(ExoPlayer player, int group, int track, List<Integer> trackIndices) {
if (group >= player.getCurrentTracks().getGroups().size()) return;
Tracks.Group trackGroup = player.getCurrentTracks().getGroups().get(group);
@ -198,7 +181,7 @@ public class ExoUtil {
private static synchronized DataSource.Factory getDataSourceFactory(Map<String, String> headers) {
if (dataSourceFactory == null) dataSourceFactory = buildReadOnlyCacheDataSource(new DefaultDataSource.Factory(App.get(), getHttpDataSourceFactory()), getCache());
httpDataSourceFactory.setDefaultRequestProperties(Players.checkUa(headers));
httpDataSourceFactory.setDefaultRequestProperties(headers);
return dataSourceFactory;
}

@ -27,6 +27,7 @@ import com.fongmi.android.tv.Constant;
import com.fongmi.android.tv.R;
import com.fongmi.android.tv.Setting;
import com.fongmi.android.tv.bean.Channel;
import com.fongmi.android.tv.bean.Drm;
import com.fongmi.android.tv.bean.Result;
import com.fongmi.android.tv.bean.Sub;
import com.fongmi.android.tv.bean.Track;
@ -66,6 +67,8 @@ public class Players implements Player.Listener, AnalyticsListener, ParseCallbac
private ParseJob parseJob;
private Runnable runnable;
private ExoPlayer player;
private List<Sub> subs;
private String format;
private String url;
private Sub sub;
@ -75,6 +78,7 @@ public class Players implements Player.Listener, AnalyticsListener, ParseCallbac
private int retry;
public Players init(Activity activity) {
subs = new ArrayList<>();
decode = Setting.getDecode();
builder = new StringBuilder();
runnable = ErrorEvent::timeout;
@ -109,7 +113,7 @@ public class Players implements Player.Listener, AnalyticsListener, ParseCallbac
public void setSub(Sub sub) {
this.sub = sub;
setMediaSource(headers, url);
setMediaSource(headers, url, format);
}
public ExoPlayer get() {
@ -117,7 +121,7 @@ public class Players implements Player.Listener, AnalyticsListener, ParseCallbac
}
public Map<String, String> getHeaders() {
return headers == null ? new HashMap<>() : checkUa(headers);
return headers == null ? new HashMap<>() : headers;
}
public String getUrl() {
@ -141,6 +145,8 @@ public class Players implements Player.Listener, AnalyticsListener, ParseCallbac
public void clear() {
headers = null;
format = null;
subs = null;
url = null;
}
@ -352,32 +358,45 @@ public class Players implements Player.Listener, AnalyticsListener, ParseCallbac
parseJob = null;
}
private Map<String, String> checkUa(Map<String, String> headers) {
if (Setting.getUa().isEmpty()) return headers;
for (Map.Entry<String, String> header : headers.entrySet()) if (HttpHeaders.USER_AGENT.equalsIgnoreCase(header.getKey())) return headers;
headers.put(HttpHeaders.USER_AGENT, Setting.getUa());
return headers;
}
private List<Sub> checkSub(List<Sub> subs) {
if (sub == null || subs.contains(sub)) return subs;
subs.add(0, sub);
return subs;
}
public void setMediaSource(String url) {
setMediaSource(new HashMap<>(), url);
}
private void setMediaSource(Result result, int timeout) {
if (player != null) player.setMediaSource(ExoUtil.getSource(result, sub, decode, error), position);
setTimeoutCheck(result.getHeaders(), result.getRealUrl(), timeout);
private void setMediaSource(Map<String, String> headers, String url) {
setMediaSource(checkUa(headers), url, null, null, checkSub(subs), Constant.TIMEOUT_PLAY);
}
private void setMediaSource(Map<String, String> headers, String url, String format) {
setMediaSource(checkUa(headers), url, format, null, checkSub(subs), Constant.TIMEOUT_PLAY);
}
private void setMediaSource(Channel channel, int timeout) {
if (player != null) player.setMediaSource(ExoUtil.getSource(channel, sub, decode, error));
setTimeoutCheck(channel.getHeaders(), channel.getUrl(), timeout);
setMediaSource(checkUa(channel.getHeaders()), channel.getUrl(), channel.getFormat(), channel.getDrm(), checkSub(subs), timeout);
}
private void setMediaSource(Map<String, String> headers, String url) {
if (player != null) player.setMediaSource(ExoUtil.getSource(headers, url, sub, decode, error), position);
setTimeoutCheck(headers, url, Constant.TIMEOUT_PLAY);
private void setMediaSource(Result result, int timeout) {
setMediaSource(checkUa(result.getHeaders()), result.getRealUrl(), result.getFormat(), result.getDrm(), checkSub(result.getSubs()), timeout);
}
private void setTimeoutCheck(Map<String, String> headers, String url, int timeout) {
private void setMediaSource(Map<String, String> headers, String url, String format, Drm drm, List<Sub> subs, int timeout) {
if (player != null) player.setMediaSource(ExoUtil.getSource(this.headers = headers, this.url = url, ExoUtil.getMimeType(this.format = format, error), drm, this.subs = subs, decode), position);
if (player != null) player.prepare();
Logger.t(TAG).d(error + "," + url);
App.post(runnable, timeout);
this.headers = headers;
PlayerEvent.state(0);
this.url = url;
PlayerEvent.prepare();
}
private void removeTimeoutCheck() {
@ -409,13 +428,6 @@ public class Players implements Player.Listener, AnalyticsListener, ParseCallbac
return scheme.isEmpty() || "file".equals(scheme) ? !Path.exists(url) : host.isEmpty();
}
public static Map<String, String> checkUa(Map<String, String> headers) {
if (Setting.getUa().isEmpty()) return headers;
for (Map.Entry<String, String> header : headers.entrySet()) if (HttpHeaders.USER_AGENT.equalsIgnoreCase(header.getKey())) return headers;
headers.put(HttpHeaders.USER_AGENT, Setting.getUa());
return headers;
}
public Uri getUri() {
return getUrl().startsWith("file://") || getUrl().startsWith("/") ? FileUtil.getShareUri(getUrl()) : Uri.parse(getUrl());
}

Loading…
Cancel
Save