From 947994f524161369cc267d1338f2961bc6406d83 Mon Sep 17 00:00:00 2001 From: 0xb00bface <0xboobface@gmail.com> Date: Wed, 16 Feb 2022 20:34:33 +0100 Subject: [PATCH] Fix Camsoda recordings (thx @Ban) Applied the patch from @Ban to fix Camsoda recordings --- .../ctbrec/sites/camsoda/CamsodaModel.java | 120 +++++++----------- 1 file changed, 49 insertions(+), 71 deletions(-) diff --git a/common/src/main/java/ctbrec/sites/camsoda/CamsodaModel.java b/common/src/main/java/ctbrec/sites/camsoda/CamsodaModel.java index ddbdd5b3..d297aac5 100644 --- a/common/src/main/java/ctbrec/sites/camsoda/CamsodaModel.java +++ b/common/src/main/java/ctbrec/sites/camsoda/CamsodaModel.java @@ -1,35 +1,10 @@ package ctbrec.sites.camsoda; -import static ctbrec.Model.State.*; -import static ctbrec.io.HttpConstants.*; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.Objects; -import java.util.Optional; -import java.util.Random; -import java.util.concurrent.ExecutionException; - -import org.json.JSONException; -import org.json.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.iheartradio.m3u8.Encoding; -import com.iheartradio.m3u8.Format; -import com.iheartradio.m3u8.ParseException; -import com.iheartradio.m3u8.ParsingMode; -import com.iheartradio.m3u8.PlaylistException; -import com.iheartradio.m3u8.PlaylistParser; +import com.iheartradio.m3u8.*; import com.iheartradio.m3u8.data.MasterPlaylist; import com.iheartradio.m3u8.data.Playlist; import com.iheartradio.m3u8.data.PlaylistData; import com.iheartradio.m3u8.data.StreamInfo; - import ctbrec.AbstractModel; import ctbrec.Config; import ctbrec.io.HttpException; @@ -38,6 +13,18 @@ import okhttp3.FormBody; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; +import org.json.JSONException; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.util.*; +import java.util.concurrent.ExecutionException; + +import static ctbrec.Model.State.*; +import static ctbrec.io.HttpConstants.*; public class CamsodaModel extends AbstractModel { @@ -50,7 +37,7 @@ public class CamsodaModel extends AbstractModel { private transient String gender; private float sortOrder = 0; - private Random random = new Random(); + private final Random random = new Random(); int[] resolution = new int[2]; @@ -77,8 +64,7 @@ public class CamsodaModel extends AbstractModel { StringBuilder url = new StringBuilder("https://"); url.append(edgeServer).append('/'); url.append(streamName); - url.append("_h264_aac"); - url.append(streamName.contains("-flu") ? "_720p" : "_480p"); + url.append("_v1"); url.append("/index.m3u8"); if (!isPublic(streamName)) { url.append("?token=").append(token); @@ -131,23 +117,24 @@ public class CamsodaModel extends AbstractModel { PlaylistParser parser = new PlaylistParser(inputStream, Format.EXT_M3U, Encoding.UTF_8, ParsingMode.LENIENT); Playlist playlist = parser.parse(); MasterPlaylist master = playlist.getMasterPlaylist(); - PlaylistData playlistData = master.getPlaylists().get(0); - StreamSource streamsource = new StreamSource(); - int cutOffAt = Math.max(playlistUrl.indexOf("index.m3u8"), playlistUrl.indexOf("playlist.m3u8")); - String segmentPlaylistUrl = playlistUrl.substring(0, cutOffAt) + playlistData.getUri(); - streamsource.mediaPlaylistUrl = segmentPlaylistUrl; - if (playlistData.hasStreamInfo()) { - StreamInfo info = playlistData.getStreamInfo(); - streamsource.bandwidth = info.getBandwidth(); - streamsource.width = info.hasResolution() ? info.getResolution().width : 0; - streamsource.height = info.hasResolution() ? info.getResolution().height : 0; - } else { - streamsource.bandwidth = 0; - streamsource.width = 0; - streamsource.height = 0; - } streamSources = new ArrayList<>(); - streamSources.add(streamsource); + for (PlaylistData playlistData : master.getPlaylists()) { + StreamSource streamsource = new StreamSource(); + int cutOffAt = Math.max(playlistUrl.indexOf("index.m3u8"), playlistUrl.indexOf("playlist.m3u8")); + String segmentPlaylistUrl = playlistUrl.substring(0, cutOffAt) + playlistData.getUri(); + streamsource.mediaPlaylistUrl = segmentPlaylistUrl; + if (playlistData.hasStreamInfo()) { + StreamInfo info = playlistData.getStreamInfo(); + streamsource.bandwidth = info.getBandwidth(); + streamsource.width = info.hasResolution() ? info.getResolution().width : 0; + streamsource.height = info.hasResolution() ? info.getResolution().height : 0; + } else { + streamsource.bandwidth = 0; + streamsource.width = 0; + streamsource.height = 0; + } + streamSources.add(streamsource); + } } else { LOG.trace("Response: {}", response.body().string()); throw new HttpException(playlistUrl, response.code(), response.message()); @@ -184,31 +171,22 @@ public class CamsodaModel extends AbstractModel { } public void setOnlineStateByStatus(String status) { - switch(status) { - case "online": - onlineState = ONLINE; - break; - case "offline": - onlineState = OFFLINE; - break; - case "connected": - onlineState = AWAY; - break; - case "private": - onlineState = PRIVATE; - break; - case "limited": - onlineState = GROUP; - break; - default: - LOG.debug("Unknown show type {}", status); - onlineState = UNKNOWN; + switch (status) { + case "online" -> onlineState = ONLINE; + case "offline" -> onlineState = OFFLINE; + case "connected" -> onlineState = AWAY; + case "private" -> onlineState = PRIVATE; + case "limited" -> onlineState = GROUP; + default -> { + LOG.debug("Unknown show type {}", status); + onlineState = UNKNOWN; + } } } @Override public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException { - if(ignoreCache || onlineState == UNKNOWN) { + if (ignoreCache || onlineState == UNKNOWN) { loadModel(); } return onlineState == ONLINE; @@ -216,10 +194,10 @@ public class CamsodaModel extends AbstractModel { @Override public State getOnlineState(boolean failFast) throws IOException, ExecutionException { - if(failFast) { + if (failFast) { return onlineState; } else { - if(onlineState == UNKNOWN) { + if (onlineState == UNKNOWN) { loadModel(); } return onlineState; @@ -239,10 +217,10 @@ public class CamsodaModel extends AbstractModel { try { List sources = getStreamSources(); if (sources.isEmpty()) { - return new int[] { 0, 0 }; + return new int[]{0, 0}; } else { StreamSource src = sources.get(0); - resolution = new int[] { src.width, src.height }; + resolution = new int[]{src.width, src.height}; return resolution; } } catch (IOException | ParseException | PlaylistException e) { @@ -282,7 +260,7 @@ public class CamsodaModel extends AbstractModel { public boolean follow() throws IOException { String url = Camsoda.BASE_URI + "/api/v1/follow/" + getName(); LOG.debug("Sending follow request {}", url); - String csrfToken = ((CamsodaHttpClient)site.getHttpClient()).getCsrfToken(); + String csrfToken = ((CamsodaHttpClient) site.getHttpClient()).getCsrfToken(); Request request = new Request.Builder() .url(url) .post(RequestBody.create(new byte[0])) @@ -305,7 +283,7 @@ public class CamsodaModel extends AbstractModel { public boolean unfollow() throws IOException { String url = Camsoda.BASE_URI + "/api/v1/unfollow/" + getName(); LOG.debug("Sending unfollow request {}", url); - String csrfToken = ((CamsodaHttpClient)site.getHttpClient()).getCsrfToken(); + String csrfToken = ((CamsodaHttpClient) site.getHttpClient()).getCsrfToken(); Request request = new Request.Builder() .url(url) .post(RequestBody.create(new byte[0]))