Support exo drm

pull/137/head
FongMi 2 years ago
parent 48146995e0
commit b32132fa48
  1. 34
      app/src/main/java/com/fongmi/android/tv/api/LiveParser.java
  2. 10
      app/src/main/java/com/fongmi/android/tv/bean/Channel.java
  3. 52
      app/src/main/java/com/fongmi/android/tv/bean/Drm.java
  4. 14
      app/src/main/java/com/fongmi/android/tv/player/ExoUtil.java
  5. 2
      app/src/main/java/com/fongmi/android/tv/server/Nano.java

@ -4,6 +4,7 @@ import android.util.Base64;
import com.fongmi.android.tv.R; import com.fongmi.android.tv.R;
import com.fongmi.android.tv.bean.Channel; import com.fongmi.android.tv.bean.Channel;
import com.fongmi.android.tv.bean.Drm;
import com.fongmi.android.tv.bean.Group; import com.fongmi.android.tv.bean.Group;
import com.fongmi.android.tv.bean.Live; import com.fongmi.android.tv.bean.Live;
import com.fongmi.android.tv.utils.Utils; import com.fongmi.android.tv.utils.Utils;
@ -55,13 +56,16 @@ public class LiveParser {
} }
private static void m3u(Live live, String text) { private static void m3u(Live live, String text) {
Setting setting = Setting.create();
Channel channel = Channel.create(""); Channel channel = Channel.create("");
for (String line : text.split("\n")) { for (String line : text.split("\n")) {
setting.check(line);
if (Thread.interrupted()) break; if (Thread.interrupted()) break;
if (line.startsWith("#EXTINF:")) { if (line.startsWith("#EXTINF:")) {
Group group = live.find(Group.create(extract(line, GROUP))); Group group = live.find(Group.create(extract(line, GROUP)));
channel = group.find(Channel.create(extract(line, NAME))); channel = group.find(Channel.create(extract(line, NAME)));
channel.setLogo(extract(line, LOGO)); channel.setLogo(extract(line, LOGO));
setting.copy(channel).clear();
} else if (line.contains("://")) { } else if (line.contains("://")) {
channel.getUrls().add(line); channel.getUrls().add(line);
} }
@ -113,9 +117,11 @@ public class LiveParser {
private static class Setting { private static class Setting {
public String ua; private String ua;
public String referer; private String key;
public Integer player; private String type;
private String referer;
private Integer player;
public static Setting create() { public static Setting create() {
return new Setting(); return new Setting();
@ -125,13 +131,17 @@ public class LiveParser {
if (line.startsWith("ua")) ua(line); if (line.startsWith("ua")) ua(line);
if (line.startsWith("player")) player(line); if (line.startsWith("player")) player(line);
if (line.startsWith("referer")) referer(line); if (line.startsWith("referer")) referer(line);
if (line.startsWith("#KODIPROP:inputstream.adaptive.license_key")) key(line);
if (line.startsWith("#KODIPROP:inputstream.adaptive.license_type")) type(line);
if (line.contains("#genre#")) clear(); if (line.contains("#genre#")) clear();
} }
public void copy(Channel channel) { public Setting copy(Channel channel) {
if (ua != null) channel.setUa(ua); if (ua != null) channel.setUa(ua);
if (referer != null) channel.setReferer(referer); if (referer != null) channel.setReferer(referer);
if (player != null) channel.setPlayerType(player); if (player != null) channel.setPlayerType(player);
if (key != null && type != null) channel.setDrm(Drm.create(key, type));
return this;
} }
private void ua(String line) { private void ua(String line) {
@ -158,6 +168,22 @@ public class LiveParser {
} }
} }
private void key(String line) {
try {
key = line.split("=")[1].trim();
} catch (Exception e) {
key = null;
}
}
private void type(String line) {
try {
type = line.split("=")[1].trim();
} catch (Exception e) {
type = null;
}
}
private void clear() { private void clear() {
player = null; player = null;
referer = null; referer = null;

@ -39,6 +39,8 @@ public class Channel {
private JsonElement header; private JsonElement header;
@SerializedName("playerType") @SerializedName("playerType")
private Integer playerType; private Integer playerType;
@SerializedName("drm")
private Drm drm;
private boolean selected; private boolean selected;
private Group group; private Group group;
@ -141,6 +143,14 @@ public class Channel {
this.playerType = playerType; this.playerType = playerType;
} }
public Drm getDrm() {
return drm;
}
public void setDrm(Drm drm) {
this.drm = drm;
}
public Group getGroup() { public Group getGroup() {
return group; return group;
} }

@ -0,0 +1,52 @@
package com.fongmi.android.tv.bean;
import android.text.TextUtils;
import androidx.media3.common.C;
import androidx.media3.common.MediaItem;
import com.fongmi.android.tv.server.Server;
import com.github.catvod.utils.Util;
import com.google.gson.annotations.SerializedName;
import java.util.UUID;
public class Drm {
@SerializedName("key")
private String key;
@SerializedName("type")
private String type;
public static Drm create(String key, String type) {
return new Drm(key, type);
}
private Drm(String key, String type) {
this.key = key;
this.type = type;
}
private String getKey() {
return TextUtils.isEmpty(key) ? "" : key;
}
private String getType() {
return TextUtils.isEmpty(type) ? "" : type;
}
private UUID getUUID() {
if (getType().contains("widevine")) return C.WIDEVINE_UUID;
if (getType().contains("clearkey")) return C.CLEARKEY_UUID;
return C.UUID_NIL;
}
private String getUri() {
if (getKey().startsWith("http")) return getKey();
return Server.get().getAddress("license/") + Util.base64(getKey());
}
public MediaItem.DrmConfiguration get() {
return new MediaItem.DrmConfiguration.Builder(getUUID()).setLicenseUri(getUri()).build();
}
}

@ -37,6 +37,7 @@ import androidx.media3.ui.CaptionStyleCompat;
import com.fongmi.android.tv.App; import com.fongmi.android.tv.App;
import com.fongmi.android.tv.Setting; import com.fongmi.android.tv.Setting;
import com.fongmi.android.tv.bean.Channel; 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.Result;
import com.fongmi.android.tv.bean.Sub; import com.fongmi.android.tv.bean.Sub;
import com.fongmi.android.tv.utils.Sniffer; import com.fongmi.android.tv.utils.Sniffer;
@ -98,27 +99,28 @@ public class ExoUtil {
} }
public static MediaSource getSource(Result result, int errorCode) { public static MediaSource getSource(Result result, int errorCode) {
return getSource(result.getHeaders(), result.getRealUrl(), result.getFormat(), result.getSubs(), errorCode); return getSource(result.getHeaders(), result.getRealUrl(), result.getFormat(), result.getSubs(), null, errorCode);
} }
public static MediaSource getSource(Channel channel, int errorCode) { public static MediaSource getSource(Channel channel, int errorCode) {
return getSource(channel.getHeaders(), channel.getUrl(), null, Collections.emptyList(), errorCode); return getSource(channel.getHeaders(), channel.getUrl(), null, Collections.emptyList(), channel.getDrm(), errorCode);
} }
public static MediaSource getSource(Map<String, String> headers, String url, int errorCode) { public static MediaSource getSource(Map<String, String> headers, String url, int errorCode) {
return getSource(headers, url, null, Collections.emptyList(), errorCode); return getSource(headers, url, null, Collections.emptyList(), null, errorCode);
} }
private static MediaSource getSource(Map<String, String> headers, String url, String format, List<Sub> subs, int errorCode) { private static MediaSource getSource(Map<String, String> headers, String url, String format, List<Sub> subs, Drm drm, int errorCode) {
Uri uri = Uri.parse(url.trim().replace("\\", "")); Uri uri = Uri.parse(url.trim().replace("\\", ""));
String mimeType = getMimeType(format, errorCode); String mimeType = getMimeType(format, errorCode);
if (uri.getUserInfo() != null) headers.put(HttpHeaders.AUTHORIZATION, "Basic " + Util.base64(uri.getUserInfo())); if (uri.getUserInfo() != null) headers.put(HttpHeaders.AUTHORIZATION, "Basic " + Util.base64(uri.getUserInfo()));
return new DefaultMediaSourceFactory(getDataSourceFactory(headers), getExtractorsFactory()).createMediaSource(getMediaItem(uri, mimeType, subs)); return new DefaultMediaSourceFactory(getDataSourceFactory(headers), getExtractorsFactory()).createMediaSource(getMediaItem(uri, mimeType, subs, drm));
} }
private static MediaItem getMediaItem(Uri uri, String mimeType, List<Sub> subs) { private static MediaItem getMediaItem(Uri uri, String mimeType, List<Sub> subs, Drm drm) {
MediaItem.Builder builder = new MediaItem.Builder().setUri(uri); MediaItem.Builder builder = new MediaItem.Builder().setUri(uri);
if (subs.size() > 0) builder.setSubtitleConfigurations(getSubtitles(subs)); if (subs.size() > 0) builder.setSubtitleConfigurations(getSubtitles(subs));
if (drm != null) builder.setDrmConfiguration(drm.get());
builder.setAllowChunklessPreparation(Players.isHard()); builder.setAllowChunklessPreparation(Players.isHard());
if (mimeType != null) builder.setMimeType(mimeType); if (mimeType != null) builder.setMimeType(mimeType);
builder.setAds(Sniffer.getRegex(uri)); builder.setAds(Sniffer.getRegex(uri));

@ -1,6 +1,7 @@
package com.fongmi.android.tv.server; package com.fongmi.android.tv.server;
import android.net.Uri; import android.net.Uri;
import android.util.Base64;
import com.fongmi.android.tv.R; import com.fongmi.android.tv.R;
import com.fongmi.android.tv.api.ApiConfig; import com.fongmi.android.tv.api.ApiConfig;
@ -94,6 +95,7 @@ public class Nano extends NanoHTTPD {
else if (url.startsWith("/newFolder")) return doNewFolder(session.getParms()); else if (url.startsWith("/newFolder")) return doNewFolder(session.getParms());
else if (url.startsWith("/delFolder") || url.startsWith("/delFile")) return doDelFolder(session.getParms()); else if (url.startsWith("/delFolder") || url.startsWith("/delFile")) return doDelFolder(session.getParms());
else if (url.startsWith("/tvbus")) return createSuccessResponse(LiveConfig.get().getHome().getCore().getResp()); else if (url.startsWith("/tvbus")) return createSuccessResponse(LiveConfig.get().getHome().getCore().getResp());
else if (url.startsWith("/license/")) return createSuccessResponse(new String(Base64.decode(url.substring(9), Base64.DEFAULT)));
break; break;
} }
return createErrorResponse(NanoHTTPD.Response.Status.NOT_FOUND, "Not Found"); return createErrorResponse(NanoHTTPD.Response.Status.NOT_FOUND, "Not Found");

Loading…
Cancel
Save