forked from j62/ctbrec
Implement recording state change events in RemoteRecorder
This commit is contained in:
parent
bcb89ef009
commit
2fc00404b8
|
@ -1,5 +1,6 @@
|
||||||
package ctbrec.recorder;
|
package ctbrec.recorder;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
|
@ -7,26 +8,31 @@ import java.security.NoSuchAlgorithmException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.iheartradio.m3u8.ParseException;
|
||||||
|
import com.iheartradio.m3u8.PlaylistException;
|
||||||
import com.squareup.moshi.JsonAdapter;
|
import com.squareup.moshi.JsonAdapter;
|
||||||
import com.squareup.moshi.Moshi;
|
import com.squareup.moshi.Moshi;
|
||||||
|
|
||||||
|
import ctbrec.AbstractModel;
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.Hmac;
|
import ctbrec.Hmac;
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
import ctbrec.Recording;
|
import ctbrec.Recording;
|
||||||
import ctbrec.event.EventBusHolder;
|
import ctbrec.event.EventBusHolder;
|
||||||
|
import ctbrec.event.RecordingStateChangedEvent;
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
import ctbrec.io.HttpException;
|
import ctbrec.io.HttpException;
|
||||||
import ctbrec.io.InstantJsonAdapter;
|
import ctbrec.io.InstantJsonAdapter;
|
||||||
import ctbrec.io.ModelJsonAdapter;
|
import ctbrec.io.ModelJsonAdapter;
|
||||||
|
import ctbrec.recorder.download.StreamSource;
|
||||||
import ctbrec.sites.Site;
|
import ctbrec.sites.Site;
|
||||||
import okhttp3.MediaType;
|
import okhttp3.MediaType;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
|
@ -37,7 +43,6 @@ import okhttp3.Response;
|
||||||
public class RemoteRecorder implements Recorder {
|
public class RemoteRecorder implements Recorder {
|
||||||
|
|
||||||
private static final transient Logger LOG = LoggerFactory.getLogger(RemoteRecorder.class);
|
private static final transient Logger LOG = LoggerFactory.getLogger(RemoteRecorder.class);
|
||||||
|
|
||||||
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
|
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
|
||||||
private Moshi moshi = new Moshi.Builder()
|
private Moshi moshi = new Moshi.Builder()
|
||||||
.add(Instant.class, new InstantJsonAdapter())
|
.add(Instant.class, new InstantJsonAdapter())
|
||||||
|
@ -49,6 +54,7 @@ public class RemoteRecorder implements Recorder {
|
||||||
|
|
||||||
private List<Model> models = Collections.emptyList();
|
private List<Model> models = Collections.emptyList();
|
||||||
private List<Model> onlineModels = Collections.emptyList();
|
private List<Model> onlineModels = Collections.emptyList();
|
||||||
|
private List<Recording> recordings = Collections.emptyList();
|
||||||
private List<Site> sites;
|
private List<Site> sites;
|
||||||
private long spaceTotal = -1;
|
private long spaceTotal = -1;
|
||||||
private long spaceFree = -1;
|
private long spaceFree = -1;
|
||||||
|
@ -159,6 +165,7 @@ public class RemoteRecorder implements Recorder {
|
||||||
syncModels();
|
syncModels();
|
||||||
syncOnlineModels();
|
syncOnlineModels();
|
||||||
syncSpace();
|
syncSpace();
|
||||||
|
syncRecordings();
|
||||||
sleep();
|
sleep();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,7 +243,6 @@ public class RemoteRecorder implements Recorder {
|
||||||
if (response.isSuccessful()) {
|
if (response.isSuccessful()) {
|
||||||
ModelListResponse resp = modelListResponseAdapter.fromJson(json);
|
ModelListResponse resp = modelListResponseAdapter.fromJson(json);
|
||||||
if (resp.status.equals("success")) {
|
if (resp.status.equals("success")) {
|
||||||
List<Model> previouslyOnline = onlineModels;
|
|
||||||
onlineModels = resp.models;
|
onlineModels = resp.models;
|
||||||
for (Model model : models) {
|
for (Model model : models) {
|
||||||
for (Site site : sites) {
|
for (Site site : sites) {
|
||||||
|
@ -245,25 +251,49 @@ public class RemoteRecorder implements Recorder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
LOG.error("Server returned error: {} - {}", resp.status, resp.msg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG.error("Couldn't synchronize with server. HTTP status: {} - {}", response.code(), json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException | InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e) {
|
||||||
|
LOG.error("Couldn't synchronize with server", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (Model prev : previouslyOnline) {
|
private void syncRecordings() {
|
||||||
if(!onlineModels.contains(prev)) {
|
try {
|
||||||
Map<String, Object> evt = new HashMap<>();
|
String msg = "{\"action\": \"recordings\"}";
|
||||||
evt.put("event", "model.status");
|
RequestBody body = RequestBody.create(JSON, msg);
|
||||||
evt.put("status", "offline");
|
Request.Builder builder = new Request.Builder()
|
||||||
evt.put("model", prev);
|
.url("http://" + config.getSettings().httpServer + ":" + config.getSettings().httpPort + "/rec")
|
||||||
|
.post(body);
|
||||||
|
addHmacIfNeeded(msg, builder);
|
||||||
|
Request request = builder.build();
|
||||||
|
try (Response response = client.execute(request)) {
|
||||||
|
String json = response.body().string();
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
RecordingListResponse resp = recordingListResponseAdapter.fromJson(json);
|
||||||
|
if (resp.status.equals("success")) {
|
||||||
|
List<Recording> newRecordings = resp.recordings;
|
||||||
|
// fire changed events
|
||||||
|
for (Iterator<Recording> iterator = recordings.iterator(); iterator.hasNext();) {
|
||||||
|
Recording recording = iterator.next();
|
||||||
|
if(newRecordings.contains(recording)) {
|
||||||
|
int idx = newRecordings.indexOf(recording);
|
||||||
|
Recording newRecording = newRecordings.get(idx);
|
||||||
|
if(newRecording.getStatus() != recording.getStatus()) {
|
||||||
|
File file = new File(recording.getPath());
|
||||||
|
Model m = new UnknownModel();
|
||||||
|
m.setName(newRecording.getModelName());
|
||||||
|
RecordingStateChangedEvent evt = new RecordingStateChangedEvent(file, newRecording.getStatus(), m, recording.getStartDate());
|
||||||
EventBusHolder.BUS.post(evt);
|
EventBusHolder.BUS.post(evt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Model model : onlineModels) {
|
|
||||||
if(!previouslyOnline.contains(model)) {
|
|
||||||
Map<String, Object> evt = new HashMap<>();
|
|
||||||
evt.put("event", "model.status");
|
|
||||||
evt.put("status", "online");
|
|
||||||
evt.put("model", model);
|
|
||||||
EventBusHolder.BUS.post(evt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
recordings = newRecordings;
|
||||||
} else {
|
} else {
|
||||||
LOG.error("Server returned error: {} - {}", resp.status, resp.msg);
|
LOG.error("Server returned error: {} - {}", resp.status, resp.msg);
|
||||||
}
|
}
|
||||||
|
@ -304,28 +334,7 @@ public class RemoteRecorder implements Recorder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Recording> getRecordings() throws IOException, InvalidKeyException, NoSuchAlgorithmException, IllegalStateException {
|
public List<Recording> getRecordings() throws IOException, InvalidKeyException, NoSuchAlgorithmException, IllegalStateException {
|
||||||
String msg = "{\"action\": \"recordings\"}";
|
|
||||||
RequestBody body = RequestBody.create(JSON, msg);
|
|
||||||
Request.Builder builder = new Request.Builder()
|
|
||||||
.url("http://" + config.getSettings().httpServer + ":" + config.getSettings().httpPort + "/rec")
|
|
||||||
.post(body);
|
|
||||||
addHmacIfNeeded(msg, builder);
|
|
||||||
Request request = builder.build();
|
|
||||||
try(Response response = client.execute(request)) {
|
|
||||||
String json = response.body().string();
|
|
||||||
if(response.isSuccessful()) {
|
|
||||||
RecordingListResponse resp = recordingListResponseAdapter.fromJson(json);
|
|
||||||
if(resp.status.equals("success")) {
|
|
||||||
List<Recording> recordings = resp.recordings;
|
|
||||||
return recordings;
|
return recordings;
|
||||||
} else {
|
|
||||||
LOG.error("Server returned error: {} - {}", resp.status, resp.msg);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG.error("Couldn't synchronize with server. HTTP status: {} - {}", response.code(), json);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -425,4 +434,151 @@ public class RemoteRecorder implements Recorder {
|
||||||
public long getFreeSpaceBytes() {
|
public long getFreeSpaceBytes() {
|
||||||
return spaceFree;
|
return spaceFree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class UnknownModel extends AbstractModel {
|
||||||
|
@Override
|
||||||
|
public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StreamSource> getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidateCacheEntries() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void receiveTip(int tokens) throws IOException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] getStreamResolution(boolean failFast) throws ExecutionException {
|
||||||
|
return new int[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean follow() throws IOException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean unfollow() throws IOException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Site getSite() {
|
||||||
|
return new Site() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsTips() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsSearch() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsFollow() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shutdown() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecorder(Recorder recorder) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean searchRequiresLogin() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Model> search(String q) throws IOException, InterruptedException {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean login() throws IOException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSiteForModel(Model m) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() throws IOException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getTokenBalance() throws IOException {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Recorder getRecorder() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpClient getHttpClient() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBuyTokensLink() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBaseUrl() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAffiliateLink() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean credentialsAvailable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Model createModelFromUrl(String url) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Model createModel(String name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue