package ctbrec.sites.amateurtv; 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.List; import java.util.concurrent.ExecutionException; import javax.xml.bind.JAXBException; import org.json.JSONObject; import org.jsoup.nodes.Element; 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.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.HttpClient; import ctbrec.io.HttpException; import ctbrec.recorder.download.StreamSource; import okhttp3.Request; import okhttp3.Response; public class AmateurTvModel extends AbstractModel { private static final Logger LOG = LoggerFactory.getLogger(AmateurTvModel.class); private boolean online = false; @Override public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException { if (ignoreCache) { JSONObject json = getModelInfo(); online = json.optString("status").equalsIgnoreCase("online"); onlineState = online ? ONLINE : OFFLINE; } return online; } @Override public State getOnlineState(boolean failFast) throws IOException, ExecutionException { if (failFast) { return onlineState; } else { try { isOnline(true); } catch (InterruptedException e) { Thread.currentThread().interrupt(); onlineState = OFFLINE; } catch (IOException | ExecutionException e) { onlineState = OFFLINE; } return onlineState; } } @Override public List getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException, JAXBException { List streamSources = new ArrayList<>(); String streamUrl = getStreamUrl(); Request req = new Request.Builder().url(streamUrl).build(); try (Response response = site.getHttpClient().execute(req)) { if (response.isSuccessful()) { InputStream inputStream = response.body().byteStream(); PlaylistParser parser = new PlaylistParser(inputStream, Format.EXT_M3U, Encoding.UTF_8, ParsingMode.LENIENT); Playlist playlist = parser.parse(); MasterPlaylist master = playlist.getMasterPlaylist(); for (PlaylistData playlistData : master.getPlaylists()) { StreamSource streamsource = new StreamSource(); Element img = new Element("img"); img.setBaseUri(streamUrl); img.attr("src", playlistData.getUri()); streamsource.mediaPlaylistUrl = img.absUrl("src"); 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 { throw new HttpException(response.code(), response.message()); } } return streamSources; } private String getStreamUrl() throws IOException { JSONObject json = getModelInfo(); JSONObject videoTech = json.getJSONObject("videoTechnologies"); return videoTech.getString("hlsV2"); } @Override public void invalidateCacheEntries() { // nothing to do } @Override public void receiveTip(Double tokens) throws IOException { // not supported } @Override public int[] getStreamResolution(boolean failFast) throws ExecutionException { try { return new int[] { getStreamSources().get(0).width, getStreamSources().get(0).height }; } catch (Exception e) { throw new ExecutionException(e); } } @Override public boolean follow() throws IOException { return false; } @Override public boolean unfollow() throws IOException { return false; } private JSONObject getModelInfo() throws IOException { String url = AmateurTv.baseUrl + "/v3/readmodel/show/" + getName() + "/es"; Request req = new Request.Builder().url(url) .header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent) .header(ACCEPT, MIMETYPE_APPLICATION_JSON) .header(ACCEPT_LANGUAGE, "en") .header(REFERER, getSite().getBaseUrl() + '/' + getName()) .build(); try (Response resp = site.getHttpClient().execute(req)) { JSONObject json = new JSONObject(HttpClient.bodyToJsonObject(resp)); return json; } } }