Make Showup downloads work in v4
Also fix the Followed tab
This commit is contained in:
parent
e789ce2029
commit
0f5a05bfd7
|
@ -53,7 +53,7 @@ public class ShowupFollowedUpdateService extends PaginatedScheduledService {
|
||||||
if (json.optString("status").equalsIgnoreCase("success")) {
|
if (json.optString("status").equalsIgnoreCase("success")) {
|
||||||
Map<String, String> onlineModels = parseOnlineModels(json);
|
Map<String, String> onlineModels = parseOnlineModels(json);
|
||||||
return parseFavorites(json).stream()
|
return parseFavorites(json).stream()
|
||||||
.filter(m -> onlineModels.containsKey(m.getName()) == showOnline)
|
.filter(m -> onlineModels.containsKey(m.getUid()) == showOnline)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
} else {
|
} else {
|
||||||
throw new UnexpectedResponseException("Request was not successful: " + body);
|
throw new UnexpectedResponseException("Request was not successful: " + body);
|
||||||
|
@ -71,9 +71,10 @@ public class ShowupFollowedUpdateService extends PaginatedScheduledService {
|
||||||
JSONObject m = list.getJSONObject(i);
|
JSONObject m = list.getJSONObject(i);
|
||||||
ShowupModel model = new ShowupModel();
|
ShowupModel model = new ShowupModel();
|
||||||
model.setSite(site);
|
model.setSite(site);
|
||||||
|
model.setUid(m.optString("fav_uid"));
|
||||||
model.setName(m.optString("username"));
|
model.setName(m.optString("username"));
|
||||||
model.setUrl(site.getBaseUrl() + '/' + model.getName());
|
model.setUrl(site.getBaseUrl() + '/' + model.getName());
|
||||||
|
favorites.add(model);
|
||||||
}
|
}
|
||||||
return favorites;
|
return favorites;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,9 @@ public class ShowupTabProvider extends TabProvider {
|
||||||
tabs.add(createTab("Women", "female"));
|
tabs.add(createTab("Women", "female"));
|
||||||
tabs.add(createTab("Men", "male"));
|
tabs.add(createTab("Men", "male"));
|
||||||
tabs.add(createTab("All", "all"));
|
tabs.add(createTab("All", "all"));
|
||||||
tabs.add(new ShowupFollowedTab("Favorites", site));
|
ShowupFollowedTab showupFollowedTab = new ShowupFollowedTab("Favorites", site);
|
||||||
|
showupFollowedTab.setRecorder(site.getRecorder());
|
||||||
|
tabs.add(showupFollowedTab);
|
||||||
return tabs;
|
return tabs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -164,7 +164,7 @@ public abstract class AbstractHlsDownload extends AbstractDownload {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleHttpException(HttpException e) throws IOException {
|
protected void handleHttpException(HttpException e) throws IOException {
|
||||||
if (e.getResponseCode() == 404) {
|
if (e.getResponseCode() == 404) {
|
||||||
checkIfModelIsStillOnline("Playlist not found (404). Model {} probably went offline. Model state: {}");
|
checkIfModelIsStillOnline("Playlist not found (404). Model {} probably went offline. Model state: {}");
|
||||||
} else if (e.getResponseCode() == 403) {
|
} else if (e.getResponseCode() == 403) {
|
||||||
|
|
|
@ -37,12 +37,12 @@ public class MergedFfmpegHlsDownload extends AbstractHlsDownload {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(MergedFfmpegHlsDownload.class);
|
private static final Logger LOG = LoggerFactory.getLogger(MergedFfmpegHlsDownload.class);
|
||||||
|
|
||||||
private File targetFile;
|
protected File targetFile;
|
||||||
private transient FFmpeg ffmpeg;
|
protected transient FFmpeg ffmpeg;
|
||||||
private transient Process ffmpegProcess;
|
protected transient Process ffmpegProcess;
|
||||||
private transient OutputStream ffmpegStdIn;
|
protected transient OutputStream ffmpegStdIn;
|
||||||
private transient BlockingQueue<Future<SegmentDownload>> queue = new LinkedBlockingQueue<>();
|
protected transient BlockingQueue<Future<SegmentDownload>> queue = new LinkedBlockingQueue<>();
|
||||||
private transient Lock ffmpegStreamLock = new ReentrantLock();
|
protected transient Lock ffmpegStreamLock = new ReentrantLock();
|
||||||
|
|
||||||
public MergedFfmpegHlsDownload(HttpClient client) {
|
public MergedFfmpegHlsDownload(HttpClient client) {
|
||||||
super(client);
|
super(client);
|
||||||
|
@ -80,7 +80,7 @@ public class MergedFfmpegHlsDownload extends AbstractHlsDownload {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void streamSegmentDataToFfmpeg() {
|
protected void streamSegmentDataToFfmpeg() {
|
||||||
downloadExecutor.submit(() -> {
|
downloadExecutor.submit(() -> {
|
||||||
ffmpegStreamLock.lock();
|
ffmpegStreamLock.lock();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,12 +1,139 @@
|
||||||
package ctbrec.sites.showup;
|
package ctbrec.sites.showup;
|
||||||
|
|
||||||
|
import static ctbrec.io.HttpConstants.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.iheartradio.m3u8.ParseException;
|
||||||
|
import com.iheartradio.m3u8.PlaylistException;
|
||||||
|
|
||||||
|
import ctbrec.Config;
|
||||||
|
import ctbrec.Model;
|
||||||
|
import ctbrec.io.BandwidthMeter;
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
|
import ctbrec.io.HttpException;
|
||||||
|
import ctbrec.recorder.download.ProcessExitedUncleanException;
|
||||||
|
import ctbrec.recorder.download.hls.AbstractHlsDownload;
|
||||||
import ctbrec.recorder.download.hls.MergedFfmpegHlsDownload;
|
import ctbrec.recorder.download.hls.MergedFfmpegHlsDownload;
|
||||||
|
import ctbrec.recorder.download.hls.SegmentPlaylist;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
public class ShowupMergedDownload extends MergedFfmpegHlsDownload {
|
public class ShowupMergedDownload extends MergedFfmpegHlsDownload {
|
||||||
|
|
||||||
|
private static final transient Logger LOG = LoggerFactory.getLogger(ShowupMergedDownload.class);
|
||||||
|
|
||||||
|
private transient Response response;
|
||||||
|
private transient InputStream in;
|
||||||
|
private transient byte[] buffer = new byte[10240];
|
||||||
|
|
||||||
public ShowupMergedDownload(HttpClient client) {
|
public ShowupMergedDownload(HttpClient client) {
|
||||||
super(client);
|
super(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Config config, Model model, Instant startTime, ExecutorService executorService) throws IOException {
|
||||||
|
super.init(config, model, startTime, executorService);
|
||||||
|
try {
|
||||||
|
if (segmentPlaylistUrl == null) {
|
||||||
|
segmentPlaylistUrl = getSegmentPlaylistUrl(model);
|
||||||
|
}
|
||||||
|
startDownload(segmentPlaylistUrl);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Error starting the stream", e);
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void startDownload(String segmentPlaylistUri) throws IOException, ParseException, PlaylistException {
|
||||||
|
try {
|
||||||
|
SegmentPlaylist lsp = getNextSegments(segmentPlaylistUri);
|
||||||
|
emptyPlaylistCheck(lsp);
|
||||||
|
|
||||||
|
String segment = lsp.segments.get(0);
|
||||||
|
Request request = new Request.Builder().url(segment)
|
||||||
|
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||||
|
.header(CONNECTION, KEEP_ALIVE)
|
||||||
|
.build();
|
||||||
|
response = client.execute(request);
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
in = response.body().byteStream();
|
||||||
|
} else {
|
||||||
|
throw new HttpException(response.code(), response.message());
|
||||||
|
}
|
||||||
|
} catch (HttpException e) {
|
||||||
|
handleHttpException(e);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.info("Unexpected error while downloading {}", model, e);
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractHlsDownload call() throws Exception {
|
||||||
|
if (!running) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!ffmpegProcess.isAlive()) {
|
||||||
|
running = false;
|
||||||
|
int exitValue = ffmpegProcess.exitValue();
|
||||||
|
ffmpeg.shutdown(exitValue);
|
||||||
|
}
|
||||||
|
} catch (ProcessExitedUncleanException e) {
|
||||||
|
LOG.error("FFmpeg exited unclean", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
streamSegmentDataToFfmpeg();
|
||||||
|
rescheduleTime = Instant.now().plusSeconds(1);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void streamSegmentDataToFfmpeg() {
|
||||||
|
downloadExecutor.submit(() -> {
|
||||||
|
if (!ffmpegStreamLock.tryLock()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int length = -1;
|
||||||
|
boolean keepGoing = true;
|
||||||
|
while ((length = in.read(buffer)) > 0 && keepGoing) {
|
||||||
|
BandwidthMeter.add(length);
|
||||||
|
ffmpegStdIn.write(buffer, 0, length);
|
||||||
|
keepGoing = running && !Thread.interrupted() && model.isOnline(true);
|
||||||
|
splittingStrategy.splitNecessary(this);
|
||||||
|
}
|
||||||
|
if (length == -1) {
|
||||||
|
LOG.info("End of stream reached for {}", model);
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
LOG.debug("loop finished");
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Error while streaming data to FFmpeg", e);
|
||||||
|
} finally {
|
||||||
|
ffmpegStreamLock.unlock();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finalizeDownload() {
|
||||||
|
super.finalizeDownload();
|
||||||
|
try {
|
||||||
|
in.close();
|
||||||
|
response.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("Error while finalizing download", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import ctbrec.recorder.download.StreamSource;
|
||||||
|
|
||||||
public class ShowupModel extends AbstractModel {
|
public class ShowupModel extends AbstractModel {
|
||||||
|
|
||||||
|
private String uid;
|
||||||
private String streamId;
|
private String streamId;
|
||||||
private String streamTranscoderAddr;
|
private String streamTranscoderAddr;
|
||||||
private int[] resolution = new int[2];
|
private int[] resolution = new int[2];
|
||||||
|
@ -128,6 +129,14 @@ public class ShowupModel extends AbstractModel {
|
||||||
this.streamTranscoderAddr = streamTranscoderAddr;
|
this.streamTranscoderAddr = streamTranscoderAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getUid() {
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUid(String uid) {
|
||||||
|
this.uid = uid;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Download createDownload() {
|
public Download createDownload() {
|
||||||
if (Config.isServerMode() && !Config.getInstance().getSettings().recordSingleFile) {
|
if (Config.isServerMode() && !Config.getInstance().getSettings().recordSingleFile) {
|
||||||
|
|
Loading…
Reference in New Issue