forked from j62/ctbrec
Move HLS related classes ot own package
This commit is contained in:
parent
40c910bd5c
commit
00ea43c8b3
|
@ -44,6 +44,7 @@ import ctbrec.sites.chaturbate.Chaturbate;
|
||||||
import ctbrec.sites.fc2live.Fc2Live;
|
import ctbrec.sites.fc2live.Fc2Live;
|
||||||
import ctbrec.sites.flirt4free.Flirt4Free;
|
import ctbrec.sites.flirt4free.Flirt4Free;
|
||||||
import ctbrec.sites.jasmin.LiveJasmin;
|
import ctbrec.sites.jasmin.LiveJasmin;
|
||||||
|
import ctbrec.sites.mfc.MyFreeCams;
|
||||||
import ctbrec.sites.streamate.Streamate;
|
import ctbrec.sites.streamate.Streamate;
|
||||||
import ctbrec.ui.news.NewsTab;
|
import ctbrec.ui.news.NewsTab;
|
||||||
import ctbrec.ui.settings.SettingsTab;
|
import ctbrec.ui.settings.SettingsTab;
|
||||||
|
@ -88,7 +89,7 @@ public class CamrecApplication extends Application {
|
||||||
sites.add(new Fc2Live());
|
sites.add(new Fc2Live());
|
||||||
sites.add(new Flirt4Free());
|
sites.add(new Flirt4Free());
|
||||||
sites.add(new LiveJasmin());
|
sites.add(new LiveJasmin());
|
||||||
//sites.add(new MyFreeCams());
|
sites.add(new MyFreeCams());
|
||||||
sites.add(new Streamate());
|
sites.add(new Streamate());
|
||||||
loadConfig();
|
loadConfig();
|
||||||
registerAlertSystem();
|
registerAlertSystem();
|
||||||
|
|
|
@ -38,7 +38,7 @@ import ctbrec.Recording;
|
||||||
import ctbrec.Recording.State;
|
import ctbrec.Recording.State;
|
||||||
import ctbrec.StringUtil;
|
import ctbrec.StringUtil;
|
||||||
import ctbrec.recorder.Recorder;
|
import ctbrec.recorder.Recorder;
|
||||||
import ctbrec.recorder.download.MergedHlsDownload;
|
import ctbrec.recorder.download.hls.MergedHlsDownload;
|
||||||
import ctbrec.sites.Site;
|
import ctbrec.sites.Site;
|
||||||
import ctbrec.ui.controls.Toast;
|
import ctbrec.ui.controls.Toast;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
|
|
@ -536,9 +536,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
contextMenu.getItems().addAll(copyUrl, ignore);
|
contextMenu.getItems().addAll(copyUrl, ignore);
|
||||||
if(cell.getModel() instanceof MyFreeCamsModel && Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
|
if(cell.getModel() instanceof MyFreeCamsModel && Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
|
||||||
MenuItem debug = new MenuItem("debug");
|
MenuItem debug = new MenuItem("debug");
|
||||||
debug.setOnAction((e) -> {
|
debug.setOnAction(e -> MyFreeCamsClient.getInstance().getSessionState(cell.getModel()));
|
||||||
MyFreeCamsClient.getInstance().getSessionState(cell.getModel());
|
|
||||||
});
|
|
||||||
contextMenu.getItems().add(debug);
|
contextMenu.getItems().add(debug);
|
||||||
}
|
}
|
||||||
return contextMenu;
|
return contextMenu;
|
||||||
|
|
|
@ -26,7 +26,7 @@ import okhttp3.Response;
|
||||||
|
|
||||||
public class CamsodaUpdateService extends PaginatedScheduledService {
|
public class CamsodaUpdateService extends PaginatedScheduledService {
|
||||||
|
|
||||||
private static final transient Logger LOG = LoggerFactory.getLogger(CamsodaUpdateService.class);
|
private static final Logger LOG = LoggerFactory.getLogger(CamsodaUpdateService.class);
|
||||||
|
|
||||||
private String url;
|
private String url;
|
||||||
private boolean loginRequired;
|
private boolean loginRequired;
|
||||||
|
@ -66,7 +66,6 @@ public class CamsodaUpdateService extends PaginatedScheduledService {
|
||||||
if(result.has("tpl")) {
|
if(result.has("tpl")) {
|
||||||
JSONArray tpl = result.getJSONArray("tpl");
|
JSONArray tpl = result.getJSONArray("tpl");
|
||||||
String name = tpl.getString(getTemplateIndex(template, "username"));
|
String name = tpl.getString(getTemplateIndex(template, "username"));
|
||||||
String displayName = tpl.getString(getTemplateIndex(template, "display_name"));
|
|
||||||
// int connections = tpl.getInt(2);
|
// int connections = tpl.getInt(2);
|
||||||
String streamName = tpl.getString(getTemplateIndex(template, "stream_name"));
|
String streamName = tpl.getString(getTemplateIndex(template, "stream_name"));
|
||||||
CamsodaModel model = (CamsodaModel) camsoda.createModel(name);
|
CamsodaModel model = (CamsodaModel) camsoda.createModel(name);
|
||||||
|
@ -76,7 +75,11 @@ public class CamsodaUpdateService extends PaginatedScheduledService {
|
||||||
model.setPreview(preview);
|
model.setPreview(preview);
|
||||||
JSONArray edgeServers = tpl.getJSONArray(getTemplateIndex(template, "edge_servers"));
|
JSONArray edgeServers = tpl.getJSONArray(getTemplateIndex(template, "edge_servers"));
|
||||||
model.setStreamUrl("https://" + edgeServers.getString(0) + "/cam/mp4:" + streamName + "_h264_aac_480p/playlist.m3u8");
|
model.setStreamUrl("https://" + edgeServers.getString(0) + "/cam/mp4:" + streamName + "_h264_aac_480p/playlist.m3u8");
|
||||||
model.setDisplayName(displayName);
|
String displayName = tpl.getString(getTemplateIndex(template, "display_name"));
|
||||||
|
model.setDisplayName(displayName.replaceAll("[^a-zA-Z0-9]", ""));
|
||||||
|
if(model.getDisplayName().isBlank()) {
|
||||||
|
model.setDisplayName(name);
|
||||||
|
}
|
||||||
models.add(model);
|
models.add(model);
|
||||||
} else {
|
} else {
|
||||||
String name = result.getString("username");
|
String name = result.getString("username");
|
||||||
|
@ -89,7 +92,10 @@ public class CamsodaUpdateService extends PaginatedScheduledService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(result.has("display_name")) {
|
if(result.has("display_name")) {
|
||||||
model.setDisplayName(result.getString("display_name"));
|
model.setDisplayName(result.getString("display_name").replaceAll("[^a-zA-Z0-9]", ""));
|
||||||
|
if(model.getDisplayName().isBlank()) {
|
||||||
|
model.setDisplayName(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(result.has("edge_servers")) {
|
if(result.has("edge_servers")) {
|
||||||
|
@ -103,7 +109,7 @@ public class CamsodaUpdateService extends PaginatedScheduledService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.warn("Couldn't parse one of the models: {}", result.toString(), e);
|
LOG.warn("Couldn't parse one of the models: {}", result, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return models.stream()
|
return models.stream()
|
||||||
|
@ -112,7 +118,7 @@ public class CamsodaUpdateService extends PaginatedScheduledService {
|
||||||
.limit(modelsPerPage)
|
.limit(modelsPerPage)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
} else {
|
} else {
|
||||||
LOG.debug("Response was not successful: {}", json.toString());
|
LOG.debug("Response was not successful: {}", json);
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ctbrec.ui.sites.myfreecams;
|
package ctbrec.ui.sites.myfreecams;
|
||||||
|
|
||||||
|
import static java.nio.charset.StandardCharsets.*;
|
||||||
import static java.nio.file.StandardOpenOption.*;
|
import static java.nio.file.StandardOpenOption.*;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -28,17 +29,23 @@ import ctbrec.Config;
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
import ctbrec.StringUtil;
|
import ctbrec.StringUtil;
|
||||||
import ctbrec.sites.mfc.MyFreeCams;
|
import ctbrec.sites.mfc.MyFreeCams;
|
||||||
|
import ctbrec.sites.mfc.MyFreeCamsClient;
|
||||||
import ctbrec.sites.mfc.MyFreeCamsModel;
|
import ctbrec.sites.mfc.MyFreeCamsModel;
|
||||||
import ctbrec.sites.mfc.SessionState;
|
import ctbrec.sites.mfc.SessionState;
|
||||||
|
import ctbrec.sites.mfc.User;
|
||||||
import ctbrec.ui.DesktopIntegration;
|
import ctbrec.ui.DesktopIntegration;
|
||||||
import ctbrec.ui.TabSelectionListener;
|
import ctbrec.ui.TabSelectionListener;
|
||||||
import ctbrec.ui.action.FollowAction;
|
import ctbrec.ui.action.FollowAction;
|
||||||
import ctbrec.ui.action.PlayAction;
|
import ctbrec.ui.action.PlayAction;
|
||||||
import ctbrec.ui.action.StartRecordingAction;
|
import ctbrec.ui.action.StartRecordingAction;
|
||||||
import ctbrec.ui.controls.SearchBox;
|
import ctbrec.ui.controls.SearchBox;
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
import javafx.beans.property.DoubleProperty;
|
import javafx.beans.property.DoubleProperty;
|
||||||
|
import javafx.beans.property.IntegerProperty;
|
||||||
import javafx.beans.property.Property;
|
import javafx.beans.property.Property;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.property.SimpleDoubleProperty;
|
import javafx.beans.property.SimpleDoubleProperty;
|
||||||
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.beans.property.StringProperty;
|
import javafx.beans.property.StringProperty;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
|
@ -73,9 +80,9 @@ import javafx.stage.FileChooser;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
|
|
||||||
public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
private static final transient Logger LOG = LoggerFactory.getLogger(MyFreeCamsTableTab.class);
|
private static final Logger LOG = LoggerFactory.getLogger(MyFreeCamsTableTab.class);
|
||||||
private ScrollPane scrollPane = new ScrollPane();
|
private ScrollPane scrollPane = new ScrollPane();
|
||||||
private TableView<ModelTableRow> table = new TableView<ModelTableRow>();
|
private TableView<ModelTableRow> table = new TableView<>();
|
||||||
private ObservableList<ModelTableRow> filteredModels = FXCollections.observableArrayList();
|
private ObservableList<ModelTableRow> filteredModels = FXCollections.observableArrayList();
|
||||||
private ObservableList<ModelTableRow> observableModels = FXCollections.observableArrayList();
|
private ObservableList<ModelTableRow> observableModels = FXCollections.observableArrayList();
|
||||||
private TableUpdateService updateService;
|
private TableUpdateService updateService;
|
||||||
|
@ -102,9 +109,7 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
updateService = new TableUpdateService(mfc);
|
updateService = new TableUpdateService(mfc);
|
||||||
updateService.setPeriod(new Duration(TimeUnit.SECONDS.toMillis(1)));
|
updateService.setPeriod(new Duration(TimeUnit.SECONDS.toMillis(1)));
|
||||||
updateService.setOnSucceeded(this::onSuccess);
|
updateService.setOnSucceeded(this::onSuccess);
|
||||||
updateService.setOnFailed((event) -> {
|
updateService.setOnFailed(event -> LOG.info("Couldn't update MyFreeCams model table", event.getSource().getException()));
|
||||||
LOG.info("Couldn't update MyFreeCams model table", event.getSource().getException());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onSuccess(WorkerStateEvent evt) {
|
private void onSuccess(WorkerStateEvent evt) {
|
||||||
|
@ -202,6 +207,10 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
});
|
});
|
||||||
|
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
|
TableColumn<ModelTableRow, Number> uid = createTableColumn("UID", 65, idx++);
|
||||||
|
uid.setCellValueFactory(cdf -> cdf.getValue().uidProperty());
|
||||||
|
addTableColumnIfEnabled(uid);
|
||||||
|
|
||||||
TableColumn<ModelTableRow, String> name = createTableColumn("Name", 200, idx++);
|
TableColumn<ModelTableRow, String> name = createTableColumn("Name", 200, idx++);
|
||||||
name.setCellValueFactory(cdf -> cdf.getValue().nameProperty());
|
name.setCellValueFactory(cdf -> cdf.getValue().nameProperty());
|
||||||
addTableColumnIfEnabled(name);
|
addTableColumnIfEnabled(name);
|
||||||
|
@ -210,6 +219,14 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
state.setCellValueFactory(cdf -> cdf.getValue().stateProperty());
|
state.setCellValueFactory(cdf -> cdf.getValue().stateProperty());
|
||||||
addTableColumnIfEnabled(state);
|
addTableColumnIfEnabled(state);
|
||||||
|
|
||||||
|
TableColumn<ModelTableRow, Boolean> hd = createTableColumn("HD", 130, idx++);
|
||||||
|
hd.setCellValueFactory(cdf -> cdf.getValue().hdProperty());
|
||||||
|
addTableColumnIfEnabled(hd);
|
||||||
|
|
||||||
|
TableColumn<ModelTableRow, Number> flags = createTableColumn("Flags", 75, idx++);
|
||||||
|
flags.setCellValueFactory(cdf -> cdf.getValue().flagsProperty());
|
||||||
|
addTableColumnIfEnabled(flags);
|
||||||
|
|
||||||
TableColumn<ModelTableRow, Number> camscore = createTableColumn("Score", 75, idx++);
|
TableColumn<ModelTableRow, Number> camscore = createTableColumn("Score", 75, idx++);
|
||||||
camscore.setCellValueFactory(cdf -> cdf.getValue().camScoreProperty());
|
camscore.setCellValueFactory(cdf -> cdf.getValue().camScoreProperty());
|
||||||
addTableColumnIfEnabled(camscore);
|
addTableColumnIfEnabled(camscore);
|
||||||
|
@ -250,7 +267,7 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
blurp.setCellValueFactory(cdf -> cdf.getValue().blurpProperty());
|
blurp.setCellValueFactory(cdf -> cdf.getValue().blurpProperty());
|
||||||
addTableColumnIfEnabled(blurp);
|
addTableColumnIfEnabled(blurp);
|
||||||
|
|
||||||
TableColumn<ModelTableRow, String> topic = createTableColumn("Topic", 600, idx++);
|
TableColumn<ModelTableRow, String> topic = createTableColumn("Topic", 600, idx);
|
||||||
topic.setCellValueFactory(cdf -> cdf.getValue().topicProperty());
|
topic.setCellValueFactory(cdf -> cdf.getValue().topicProperty());
|
||||||
addTableColumnIfEnabled(topic);
|
addTableColumnIfEnabled(topic);
|
||||||
|
|
||||||
|
@ -278,7 +295,7 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuItem copyUrl = new MenuItem("Copy URL");
|
MenuItem copyUrl = new MenuItem("Copy URL");
|
||||||
copyUrl.setOnAction((e) -> {
|
copyUrl.setOnAction(e -> {
|
||||||
Model selected = selectedModels.get(0);
|
Model selected = selectedModels.get(0);
|
||||||
final Clipboard clipboard = Clipboard.getSystemClipboard();
|
final Clipboard clipboard = Clipboard.getSystemClipboard();
|
||||||
final ClipboardContent content = new ClipboardContent();
|
final ClipboardContent content = new ClipboardContent();
|
||||||
|
@ -287,13 +304,13 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
});
|
});
|
||||||
|
|
||||||
MenuItem startRecording = new MenuItem("Start Recording");
|
MenuItem startRecording = new MenuItem("Start Recording");
|
||||||
startRecording.setOnAction((e) -> startRecording(selectedModels));
|
startRecording.setOnAction(e -> startRecording(selectedModels));
|
||||||
MenuItem openInBrowser = new MenuItem("Open in Browser");
|
MenuItem openInBrowser = new MenuItem("Open in Browser");
|
||||||
openInBrowser.setOnAction((e) -> DesktopIntegration.open(selectedModels.get(0).getUrl()));
|
openInBrowser.setOnAction(e -> DesktopIntegration.open(selectedModels.get(0).getUrl()));
|
||||||
MenuItem openInPlayer = new MenuItem("Open in Player");
|
MenuItem openInPlayer = new MenuItem("Open in Player");
|
||||||
openInPlayer.setOnAction((e) -> openInPlayer(selectedModels.get(0)));
|
openInPlayer.setOnAction(e -> openInPlayer(selectedModels.get(0)));
|
||||||
MenuItem follow = new MenuItem("Follow");
|
MenuItem follow = new MenuItem("Follow");
|
||||||
follow.setOnAction((e) -> new FollowAction(getTabPane(), selectedModels).execute());
|
follow.setOnAction(e -> new FollowAction(getTabPane(), selectedModels).execute());
|
||||||
|
|
||||||
ContextMenu menu = new ContextMenu();
|
ContextMenu menu = new ContextMenu();
|
||||||
menu.getItems().addAll(startRecording, copyUrl, openInPlayer, openInBrowser, follow);
|
menu.getItems().addAll(startRecording, copyUrl, openInPlayer, openInBrowser, follow);
|
||||||
|
@ -304,6 +321,12 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
openInBrowser.setDisable(true);
|
openInBrowser.setDisable(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
|
||||||
|
MenuItem debug = new MenuItem("debug");
|
||||||
|
debug.setOnAction(e -> MyFreeCamsClient.getInstance().getSessionState(selectedModels.get(0)));
|
||||||
|
menu.getItems().add(debug);
|
||||||
|
}
|
||||||
|
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,8 +415,7 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
ps.println();
|
ps.println();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.debug("Couldn't write mfc models table data: {}", e.getMessage());
|
LOG.debug("Couldn't write mfc models table data", e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -488,7 +510,7 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
data.put(model);
|
data.put(model);
|
||||||
}
|
}
|
||||||
File file = new File(Config.getInstance().getConfigDir(), "mfc-models.json");
|
File file = new File(Config.getInstance().getConfigDir(), "mfc-models.json");
|
||||||
Files.write(file.toPath(), data.toString(2).getBytes("utf-8"), CREATE, WRITE);
|
Files.write(file.toPath(), data.toString(2).getBytes(UTF_8), CREATE, WRITE);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.debug("Couldn't write mfc models table data: {}", e.getMessage());
|
LOG.debug("Couldn't write mfc models table data: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
|
@ -519,7 +541,9 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
row.tags.set(model.optString("tags"));
|
row.tags.set(model.optString("tags"));
|
||||||
row.topic.set(model.optString("topic"));
|
row.topic.set(model.optString("topic"));
|
||||||
observableModels.add(row);
|
observableModels.add(row);
|
||||||
} catch (Exception e) {}
|
} catch (Exception e) {
|
||||||
|
// ignore this error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.debug("Couldn't read mfc models table data: {}", e.getMessage());
|
LOG.debug("Couldn't read mfc models table data: {}", e.getMessage());
|
||||||
|
@ -537,7 +561,7 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
columnWidths[i] = table.getColumns().get(i).getWidth();
|
columnWidths[i] = table.getColumns().get(i).getWidth();
|
||||||
}
|
}
|
||||||
Config.getInstance().getSettings().mfcModelsTableColumnWidths = columnWidths;
|
Config.getInstance().getSettings().mfcModelsTableColumnWidths = columnWidths;
|
||||||
};
|
}
|
||||||
|
|
||||||
private void restoreState() {
|
private void restoreState() {
|
||||||
String sortCol = Config.getInstance().getSettings().mfcModelsTableSortColumn;
|
String sortCol = Config.getInstance().getSettings().mfcModelsTableSortColumn;
|
||||||
|
@ -563,12 +587,7 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private ListChangeListener<TableColumn<ModelTableRow, ?>> createSortOrderChangedListener() {
|
private ListChangeListener<TableColumn<ModelTableRow, ?>> createSortOrderChangedListener() {
|
||||||
return new ListChangeListener<TableColumn<ModelTableRow, ?>>() {
|
return c -> saveState();
|
||||||
@Override
|
|
||||||
public void onChanged(Change<? extends TableColumn<ModelTableRow, ?>> c) {
|
|
||||||
saveState();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ModelTableRow {
|
private static class ModelTableRow {
|
||||||
|
@ -584,6 +603,9 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
private StringProperty tags = new SimpleStringProperty();
|
private StringProperty tags = new SimpleStringProperty();
|
||||||
private StringProperty blurp = new SimpleStringProperty();
|
private StringProperty blurp = new SimpleStringProperty();
|
||||||
private StringProperty topic = new SimpleStringProperty();
|
private StringProperty topic = new SimpleStringProperty();
|
||||||
|
private BooleanProperty isHd = new SimpleBooleanProperty();
|
||||||
|
private SimpleIntegerProperty uidProperty = new SimpleIntegerProperty();
|
||||||
|
private SimpleIntegerProperty flagsProperty = new SimpleIntegerProperty();
|
||||||
|
|
||||||
public ModelTableRow(SessionState st) {
|
public ModelTableRow(SessionState st) {
|
||||||
update(st);
|
update(st);
|
||||||
|
@ -594,18 +616,23 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
|
|
||||||
public void update(SessionState st) {
|
public void update(SessionState st) {
|
||||||
uid = st.getUid();
|
uid = st.getUid();
|
||||||
|
uidProperty.set(uid);
|
||||||
setProperty(name, Optional.ofNullable(st.getNm()));
|
setProperty(name, Optional.ofNullable(st.getNm()));
|
||||||
setProperty(state, Optional.ofNullable(st.getVs()).map(vs -> ctbrec.sites.mfc.State.of(vs).toString()));
|
setProperty(state, Optional.ofNullable(st.getVs()).map(vs -> ctbrec.sites.mfc.State.of(vs).toString()));
|
||||||
setProperty(camScore, Optional.ofNullable(st.getM()).map(m -> m.getCamscore()));
|
setProperty(camScore, Optional.ofNullable(st.getM()).map(ctbrec.sites.mfc.Model::getCamscore));
|
||||||
Optional<Integer> isNew = Optional.ofNullable(st.getM()).map(m -> m.getNewModel());
|
Optional<Integer> isNew = Optional.ofNullable(st.getM()).map(ctbrec.sites.mfc.Model::getNewModel);
|
||||||
if(isNew.isPresent()) {
|
if(isNew.isPresent()) {
|
||||||
newModel.set(isNew.get() == 1 ? "new" : "");
|
newModel.set(isNew.get() == 1 ? "new" : "");
|
||||||
}
|
}
|
||||||
setProperty(ethnic, Optional.ofNullable(st.getU()).map(u -> u.getEthnic()));
|
setProperty(ethnic, Optional.ofNullable(st.getU()).map(User::getEthnic));
|
||||||
setProperty(country, Optional.ofNullable(st.getU()).map(u -> u.getCountry()));
|
setProperty(country, Optional.ofNullable(st.getU()).map(User::getCountry));
|
||||||
setProperty(continent, Optional.ofNullable(st.getM()).map(m -> m.getContinent()));
|
setProperty(continent, Optional.ofNullable(st.getM()).map(ctbrec.sites.mfc.Model::getContinent));
|
||||||
setProperty(occupation, Optional.ofNullable(st.getU()).map(u -> u.getOccupation()));
|
setProperty(occupation, Optional.ofNullable(st.getU()).map(User::getOccupation));
|
||||||
Set<String> tagSet = Optional.ofNullable(st.getM()).map(m -> m.getTags()).orElse(Collections.emptySet());
|
int flags = Optional.ofNullable(st.getM()).map(ctbrec.sites.mfc.Model::getFlags).orElse(0);
|
||||||
|
//isHd.set((flags & 1024) == 1024);
|
||||||
|
isHd.set(Optional.ofNullable(st.getU()).map(User::getPhase).orElse("z").equalsIgnoreCase("a"));
|
||||||
|
flagsProperty.setValue(flags);
|
||||||
|
Set<String> tagSet = Optional.ofNullable(st.getM()).map(ctbrec.sites.mfc.Model::getTags).orElse(Collections.emptySet());
|
||||||
if(!tagSet.isEmpty()) {
|
if(!tagSet.isEmpty()) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (String t : tagSet) {
|
for (String t : tagSet) {
|
||||||
|
@ -613,8 +640,8 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
}
|
}
|
||||||
tags.set(sb.substring(0, sb.length()-2));
|
tags.set(sb.substring(0, sb.length()-2));
|
||||||
}
|
}
|
||||||
setProperty(blurp, Optional.ofNullable(st.getU()).map(u -> u.getBlurb()));
|
setProperty(blurp, Optional.ofNullable(st.getU()).map(User::getBlurb));
|
||||||
String tpc = Optional.ofNullable(st.getM()).map(m -> m.getTopic()).orElse("n/a");
|
String tpc = Optional.ofNullable(st.getM()).map(ctbrec.sites.mfc.Model::getTopic).orElse("n/a");
|
||||||
try {
|
try {
|
||||||
tpc = URLDecoder.decode(tpc, "utf-8");
|
tpc = URLDecoder.decode(tpc, "utf-8");
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
@ -631,48 +658,60 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
|
|
||||||
public StringProperty nameProperty() {
|
public StringProperty nameProperty() {
|
||||||
return name;
|
return name;
|
||||||
};
|
}
|
||||||
|
|
||||||
public StringProperty stateProperty() {
|
public StringProperty stateProperty() {
|
||||||
return state;
|
return state;
|
||||||
};
|
}
|
||||||
|
|
||||||
public DoubleProperty camScoreProperty() {
|
public DoubleProperty camScoreProperty() {
|
||||||
return camScore;
|
return camScore;
|
||||||
};
|
}
|
||||||
|
|
||||||
public StringProperty newModelProperty() {
|
public StringProperty newModelProperty() {
|
||||||
return newModel;
|
return newModel;
|
||||||
};
|
}
|
||||||
|
|
||||||
public StringProperty ethnicityProperty() {
|
public StringProperty ethnicityProperty() {
|
||||||
return ethnic;
|
return ethnic;
|
||||||
};
|
}
|
||||||
|
|
||||||
public StringProperty countryProperty() {
|
public StringProperty countryProperty() {
|
||||||
return country;
|
return country;
|
||||||
};
|
}
|
||||||
|
|
||||||
public StringProperty continentProperty() {
|
public StringProperty continentProperty() {
|
||||||
return continent;
|
return continent;
|
||||||
};
|
}
|
||||||
|
|
||||||
public StringProperty occupationProperty() {
|
public StringProperty occupationProperty() {
|
||||||
return occupation;
|
return occupation;
|
||||||
};
|
}
|
||||||
|
|
||||||
public StringProperty tagsProperty() {
|
public StringProperty tagsProperty() {
|
||||||
return tags;
|
return tags;
|
||||||
};
|
}
|
||||||
|
|
||||||
public StringProperty blurpProperty() {
|
public StringProperty blurpProperty() {
|
||||||
return blurp;
|
return blurp;
|
||||||
};
|
}
|
||||||
|
|
||||||
public StringProperty topicProperty() {
|
public StringProperty topicProperty() {
|
||||||
return topic;
|
return topic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BooleanProperty hdProperty() {
|
||||||
|
return isHd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntegerProperty flagsProperty() {
|
||||||
|
return flagsProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntegerProperty uidProperty() {
|
||||||
|
return uidProperty;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
|
@ -696,8 +735,6 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
|
||||||
} else if (!uid.equals(other.uid))
|
} else if (!uid.equals(other.uid))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -71,6 +71,27 @@
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mp4parser</groupId>
|
||||||
|
<artifactId>isoparser</artifactId>
|
||||||
|
<version>1.9.41</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mp4parser</groupId>
|
||||||
|
<artifactId>muxer</artifactId>
|
||||||
|
<version>1.9.41</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-api</artifactId>
|
||||||
|
<version>2.3.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish.jaxb</groupId>
|
||||||
|
<artifactId>jaxb-runtime</artifactId>
|
||||||
|
<version>2.3.1</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -10,8 +10,8 @@ import com.squareup.moshi.JsonReader;
|
||||||
import com.squareup.moshi.JsonWriter;
|
import com.squareup.moshi.JsonWriter;
|
||||||
|
|
||||||
import ctbrec.recorder.download.Download;
|
import ctbrec.recorder.download.Download;
|
||||||
import ctbrec.recorder.download.HlsDownload;
|
import ctbrec.recorder.download.hls.HlsDownload;
|
||||||
import ctbrec.recorder.download.MergedHlsDownload;
|
import ctbrec.recorder.download.hls.MergedHlsDownload;
|
||||||
import ctbrec.sites.Site;
|
import ctbrec.sites.Site;
|
||||||
|
|
||||||
public abstract class AbstractModel implements Model {
|
public abstract class AbstractModel implements Model {
|
||||||
|
|
|
@ -20,7 +20,7 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class MpegUtil {
|
public class MpegUtil {
|
||||||
private static final transient Logger LOG = LoggerFactory.getLogger(MpegUtil.class);
|
private static final Logger LOG = LoggerFactory.getLogger(MpegUtil.class);
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
readFile(new File("../../test-recs/ff.ts"));
|
readFile(new File("../../test-recs/ff.ts"));
|
||||||
|
@ -49,7 +49,7 @@ public class MpegUtil {
|
||||||
public static _2<Integer, Demuxer> createM2TSDemuxer(FileChannelWrapper ch, TrackType targetTrack) throws IOException {
|
public static _2<Integer, Demuxer> createM2TSDemuxer(FileChannelWrapper ch, TrackType targetTrack) throws IOException {
|
||||||
MTSDemuxer mts = new MTSDemuxer(ch);
|
MTSDemuxer mts = new MTSDemuxer(ch);
|
||||||
Set<Integer> programs = mts.getPrograms();
|
Set<Integer> programs = mts.getPrograms();
|
||||||
if (programs.size() == 0) {
|
if (programs.isEmpty()) {
|
||||||
LOG.error("The MPEG TS stream contains no programs");
|
LOG.error("The MPEG TS stream contains no programs");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -61,8 +61,8 @@ public class MpegUtil {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
MPSDemuxer demuxer = new MPSDemuxer(program);
|
MPSDemuxer demuxer = new MPSDemuxer(program);
|
||||||
if (targetTrack == TrackType.AUDIO && demuxer.getAudioTracks().size() > 0
|
if (targetTrack == TrackType.AUDIO && !demuxer.getAudioTracks().isEmpty()
|
||||||
|| targetTrack == TrackType.VIDEO && demuxer.getVideoTracks().size() > 0) {
|
|| targetTrack == TrackType.VIDEO && !demuxer.getVideoTracks().isEmpty()) {
|
||||||
found = org.jcodec.common.Tuple._2(pid, (Demuxer) demuxer);
|
found = org.jcodec.common.Tuple._2(pid, (Demuxer) demuxer);
|
||||||
} else {
|
} else {
|
||||||
program.close();
|
program.close();
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
package ctbrec;
|
package ctbrec;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
import com.iheartradio.m3u8.ParseException;
|
|
||||||
import com.iheartradio.m3u8.PlaylistException;
|
|
||||||
|
|
||||||
import ctbrec.event.EventBusHolder;
|
import ctbrec.event.EventBusHolder;
|
||||||
import ctbrec.event.RecordingStateChangedEvent;
|
import ctbrec.event.RecordingStateChangedEvent;
|
||||||
import ctbrec.recorder.download.Download;
|
import ctbrec.recorder.download.Download;
|
||||||
|
@ -25,7 +21,7 @@ public class Recording {
|
||||||
private long sizeInByte = -1;
|
private long sizeInByte = -1;
|
||||||
private String metaDataFile;
|
private String metaDataFile;
|
||||||
|
|
||||||
public static enum State {
|
public enum State {
|
||||||
RECORDING("recording"),
|
RECORDING("recording"),
|
||||||
GENERATING_PLAYLIST("generating playlist"),
|
GENERATING_PLAYLIST("generating playlist"),
|
||||||
POST_PROCESSING("post-processing"),
|
POST_PROCESSING("post-processing"),
|
||||||
|
@ -49,8 +45,6 @@ public class Recording {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Recording() {}
|
|
||||||
|
|
||||||
public Instant getStartDate() {
|
public Instant getStartDate() {
|
||||||
return startDate;
|
return startDate;
|
||||||
}
|
}
|
||||||
|
@ -67,7 +61,7 @@ public class Recording {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStatusWithEvent(State status, boolean fireEvent) {
|
public void setStatusWithEvent(State status) {
|
||||||
setStatus(status);
|
setStatus(status);
|
||||||
fireStatusEvent(status);
|
fireStatusEvent(status);
|
||||||
}
|
}
|
||||||
|
@ -135,7 +129,7 @@ public class Recording {
|
||||||
this.metaDataFile = metaDataFile;
|
this.metaDataFile = metaDataFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Duration getLength() throws IOException, ParseException, PlaylistException {
|
public Duration getLength() {
|
||||||
if (getDownload() != null) {
|
if (getDownload() != null) {
|
||||||
return getDownload().getLength();
|
return getDownload().getLength();
|
||||||
} else {
|
} else {
|
||||||
|
@ -197,15 +191,26 @@ public class Recording {
|
||||||
private long getSize() {
|
private long getSize() {
|
||||||
File rec = new File(Config.getInstance().getSettings().recordingsDir, getPath());
|
File rec = new File(Config.getInstance().getSettings().recordingsDir, getPath());
|
||||||
if(rec.isDirectory()) {
|
if(rec.isDirectory()) {
|
||||||
|
return getDirectorySize(rec);
|
||||||
|
} else {
|
||||||
|
if(!rec.exists()) {
|
||||||
|
return getDirectorySize(rec.getParentFile());
|
||||||
|
} else {
|
||||||
|
return rec.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getDirectorySize(File dir) {
|
||||||
long size = 0;
|
long size = 0;
|
||||||
File[] files = rec.listFiles();
|
File[] files = dir.listFiles();
|
||||||
|
if (files == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
size += file.length();
|
size += file.length();
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
} else {
|
|
||||||
return rec.length();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refresh() {
|
public void refresh() {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class StreamRedirectThread implements Runnable {
|
public class StreamRedirectThread implements Runnable {
|
||||||
private static final transient Logger LOG = LoggerFactory.getLogger(StreamRedirectThread.class);
|
private static final Logger LOG = LoggerFactory.getLogger(StreamRedirectThread.class);
|
||||||
|
|
||||||
private InputStream in;
|
private InputStream in;
|
||||||
private OutputStream out;
|
private OutputStream out;
|
||||||
|
|
|
@ -36,8 +36,6 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
import com.iheartradio.m3u8.ParseException;
|
|
||||||
import com.iheartradio.m3u8.PlaylistException;
|
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
|
@ -282,7 +280,7 @@ public class NextGenLocalRecorder implements Recorder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean deleteIfTooShort(Recording rec) throws IOException, ParseException, PlaylistException, InvalidKeyException, NoSuchAlgorithmException {
|
private boolean deleteIfTooShort(Recording rec) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
|
||||||
Duration minimumLengthInSeconds = Duration.ofSeconds(Config.getInstance().getSettings().minimumLengthInSeconds);
|
Duration minimumLengthInSeconds = Duration.ofSeconds(Config.getInstance().getSettings().minimumLengthInSeconds);
|
||||||
if (minimumLengthInSeconds.getSeconds() <= 0) {
|
if (minimumLengthInSeconds.getSeconds() <= 0) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package ctbrec.recorder.download;
|
package ctbrec.recorder.download.hls;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -42,6 +42,8 @@ import ctbrec.UnknownModel;
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
import ctbrec.io.HttpException;
|
import ctbrec.io.HttpException;
|
||||||
import ctbrec.io.StreamRedirectThread;
|
import ctbrec.io.StreamRedirectThread;
|
||||||
|
import ctbrec.recorder.download.Download;
|
||||||
|
import ctbrec.recorder.download.StreamSource;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package ctbrec.recorder.download;
|
package ctbrec.recorder.download.hls;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package ctbrec.recorder.download;
|
package ctbrec.recorder.download.hls;
|
||||||
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -182,9 +182,9 @@ public class HlsDownload extends AbstractHlsDownload {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void postprocess(Recording recording) {
|
public void postprocess(Recording recording) {
|
||||||
recording.setStatusWithEvent(State.GENERATING_PLAYLIST, true);
|
recording.setStatusWithEvent(State.GENERATING_PLAYLIST);
|
||||||
generatePlaylist(recording);
|
generatePlaylist(recording);
|
||||||
recording.setStatusWithEvent(State.POST_PROCESSING, true);
|
recording.setStatusWithEvent(State.POST_PROCESSING);
|
||||||
super.postprocess(recording);
|
super.postprocess(recording);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package ctbrec.recorder.download;
|
package ctbrec.recorder.download.hls;
|
||||||
|
|
||||||
import static java.nio.file.StandardOpenOption.*;
|
import static java.nio.file.StandardOpenOption.*;
|
||||||
|
|
||||||
|
@ -367,7 +367,7 @@ public class MergedHlsDownload extends AbstractHlsDownload {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
}
|
}
|
||||||
if(!downloadFinished) {
|
if(!downloadFinished) {
|
||||||
LOG.warn("Download didn't finishe properly for model {}", model);
|
LOG.warn("Download didn't finish properly for model {}", model);
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package ctbrec.recorder.download;
|
package ctbrec.recorder.download.hls;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ import okhttp3.Response;
|
||||||
|
|
||||||
public class CamsodaModel extends AbstractModel {
|
public class CamsodaModel extends AbstractModel {
|
||||||
|
|
||||||
private static final transient Logger LOG = LoggerFactory.getLogger(CamsodaModel.class);
|
private static final Logger LOG = LoggerFactory.getLogger(CamsodaModel.class);
|
||||||
private String streamUrl;
|
private String streamUrl;
|
||||||
private List<StreamSource> streamSources = null;
|
private List<StreamSource> streamSources = null;
|
||||||
private float sortOrder = 0;
|
private float sortOrder = 0;
|
||||||
|
|
|
@ -5,24 +5,17 @@ import java.io.IOException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import ctbrec.Config;
|
|
||||||
import ctbrec.Model;
|
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
import ctbrec.recorder.download.HlsDownload;
|
import ctbrec.recorder.download.hls.HlsDownload;
|
||||||
|
|
||||||
public class Fc2HlsDownload extends HlsDownload {
|
public class Fc2HlsDownload extends HlsDownload {
|
||||||
|
|
||||||
private static final transient Logger LOG = LoggerFactory.getLogger(Fc2HlsDownload.class);
|
private static final Logger LOG = LoggerFactory.getLogger(Fc2HlsDownload.class);
|
||||||
|
|
||||||
public Fc2HlsDownload(HttpClient client) {
|
public Fc2HlsDownload(HttpClient client) {
|
||||||
super(client);
|
super(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(Config config, Model model) {
|
|
||||||
super.init(config, model);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start() throws IOException {
|
public void start() throws IOException {
|
||||||
Fc2Model fc2Model = (Fc2Model) model;
|
Fc2Model fc2Model = (Fc2Model) model;
|
||||||
|
@ -30,14 +23,10 @@ public class Fc2HlsDownload extends HlsDownload {
|
||||||
fc2Model.openWebsocket();
|
fc2Model.openWebsocket();
|
||||||
super.start();
|
super.start();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
LOG.error("Couldn't start download for {}", model, e);
|
LOG.error("Couldn't start download for {}", model, e);
|
||||||
} finally {
|
} finally {
|
||||||
fc2Model.closeWebsocket();
|
fc2Model.closeWebsocket();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stop() {
|
|
||||||
super.stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,24 +5,17 @@ import java.io.IOException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import ctbrec.Config;
|
|
||||||
import ctbrec.Model;
|
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
import ctbrec.recorder.download.MergedHlsDownload;
|
import ctbrec.recorder.download.hls.MergedHlsDownload;
|
||||||
|
|
||||||
public class Fc2MergedHlsDownload extends MergedHlsDownload {
|
public class Fc2MergedHlsDownload extends MergedHlsDownload {
|
||||||
|
|
||||||
private static final transient Logger LOG = LoggerFactory.getLogger(Fc2MergedHlsDownload.class);
|
private static final Logger LOG = LoggerFactory.getLogger(Fc2MergedHlsDownload.class);
|
||||||
|
|
||||||
public Fc2MergedHlsDownload(HttpClient client) {
|
public Fc2MergedHlsDownload(HttpClient client) {
|
||||||
super(client);
|
super(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(Config config, Model model) {
|
|
||||||
super.init(config, model);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start() throws IOException {
|
public void start() throws IOException {
|
||||||
Fc2Model fc2Model = (Fc2Model) model;
|
Fc2Model fc2Model = (Fc2Model) model;
|
||||||
|
@ -30,14 +23,10 @@ public class Fc2MergedHlsDownload extends MergedHlsDownload {
|
||||||
fc2Model.openWebsocket();
|
fc2Model.openWebsocket();
|
||||||
super.start();
|
super.start();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
LOG.error("Couldn't start download for {}", model, e);
|
LOG.error("Couldn't start download for {}", model, e);
|
||||||
} finally {
|
} finally {
|
||||||
fc2Model.closeWebsocket();
|
fc2Model.closeWebsocket();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stop() {
|
|
||||||
super.stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ import okhttp3.WebSocketListener;
|
||||||
import okio.ByteString;
|
import okio.ByteString;
|
||||||
|
|
||||||
public class Fc2Model extends AbstractModel {
|
public class Fc2Model extends AbstractModel {
|
||||||
private static final transient Logger LOG = LoggerFactory.getLogger(Fc2Model.class);
|
private static final Logger LOG = LoggerFactory.getLogger(Fc2Model.class);
|
||||||
private String id;
|
private String id;
|
||||||
private int viewerCount;
|
private int viewerCount;
|
||||||
private boolean online;
|
private boolean online;
|
||||||
|
@ -95,7 +95,6 @@ public class Fc2Model extends AbstractModel {
|
||||||
setName(profileData.getString("name").replace('/', '_'));
|
setName(profileData.getString("name").replace('/', '_'));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resp.close();
|
|
||||||
throw new IOException("HTTP status " + resp.code() + " " + resp.message());
|
throw new IOException("HTTP status " + resp.code() + " " + resp.message());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,6 +119,7 @@ public class Fc2Model extends AbstractModel {
|
||||||
sources.addAll(parseMasterPlaylist(playlistUrl));
|
sources.addAll(parseMasterPlaylist(playlistUrl));
|
||||||
return sources;
|
return sources;
|
||||||
} catch (InterruptedException e1) {
|
} catch (InterruptedException e1) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
throw new ExecutionException(e1);
|
throw new ExecutionException(e1);
|
||||||
} finally {
|
} finally {
|
||||||
closeWebsocket();
|
closeWebsocket();
|
||||||
|
@ -205,10 +205,12 @@ public class Fc2Model extends AbstractModel {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invalidateCacheEntries() {
|
public void invalidateCacheEntries() {
|
||||||
|
// not needed
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void receiveTip(Double tokens) throws IOException {
|
public void receiveTip(Double tokens) throws IOException {
|
||||||
|
// tipping is not implemented for FC2
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -247,7 +249,6 @@ public class Fc2Model extends AbstractModel {
|
||||||
JSONObject json = new JSONObject(content);
|
JSONObject json = new JSONObject(content);
|
||||||
return json.optInt("status") == 1;
|
return json.optInt("status") == 1;
|
||||||
} else {
|
} else {
|
||||||
resp.close();
|
|
||||||
LOG.error("Login failed {} {}", resp.code(), resp.message());
|
LOG.error("Login failed {} {}", resp.code(), resp.message());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -316,7 +317,7 @@ public class Fc2Model extends AbstractModel {
|
||||||
playlistUrl = playlist.getString("url");
|
playlistUrl = playlist.getString("url");
|
||||||
LOG.debug("Master Playlist: {}", playlistUrl);
|
LOG.debug("Master Playlist: {}", playlistUrl);
|
||||||
synchronized (monitor) {
|
synchronized (monitor) {
|
||||||
monitor.notify();
|
monitor.notifyAll();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG.trace(json.toString());
|
LOG.trace(json.toString());
|
||||||
|
@ -340,7 +341,7 @@ public class Fc2Model extends AbstractModel {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(WebSocket webSocket, ByteString bytes) {
|
public void onMessage(WebSocket webSocket, ByteString bytes) {
|
||||||
LOG.debug("ws btxt {}", bytes.toString());
|
LOG.debug("ws btxt {}", bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -397,6 +398,6 @@ public class Fc2Model extends AbstractModel {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSanitizedNamed() {
|
public String getSanitizedNamed() {
|
||||||
return id;
|
return getId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import com.iheartradio.m3u8.ParseException;
|
||||||
import com.iheartradio.m3u8.PlaylistException;
|
import com.iheartradio.m3u8.PlaylistException;
|
||||||
|
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
import ctbrec.recorder.download.HlsDownload;
|
import ctbrec.recorder.download.hls.HlsDownload;
|
||||||
|
|
||||||
public class LiveJasminHlsDownload extends HlsDownload {
|
public class LiveJasminHlsDownload extends HlsDownload {
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import com.iheartradio.m3u8.ParseException;
|
||||||
import com.iheartradio.m3u8.PlaylistException;
|
import com.iheartradio.m3u8.PlaylistException;
|
||||||
|
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
import ctbrec.recorder.download.MergedHlsDownload;
|
import ctbrec.recorder.download.hls.MergedHlsDownload;
|
||||||
|
|
||||||
public class LiveJasminMergedHlsDownload extends MergedHlsDownload {
|
public class LiveJasminMergedHlsDownload extends MergedHlsDownload {
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import java.util.Map.Entry;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
import java.util.Random;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
@ -43,7 +44,9 @@ import okio.ByteString;
|
||||||
|
|
||||||
public class MyFreeCamsClient {
|
public class MyFreeCamsClient {
|
||||||
|
|
||||||
private static final transient Logger LOG = LoggerFactory.getLogger(MyFreeCamsClient.class);
|
private static final String HTTPS = "https://";
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(MyFreeCamsClient.class);
|
||||||
|
|
||||||
private static MyFreeCamsClient instance;
|
private static MyFreeCamsClient instance;
|
||||||
private MyFreeCams mfc;
|
private MyFreeCams mfc;
|
||||||
|
@ -87,30 +90,29 @@ public class MyFreeCamsClient {
|
||||||
public void start() throws IOException {
|
public void start() throws IOException {
|
||||||
running = true;
|
running = true;
|
||||||
serverConfig = new ServerConfig(mfc);
|
serverConfig = new ServerConfig(mfc);
|
||||||
List<String> websocketServers = new ArrayList<String>(serverConfig.wsServers.size());
|
List<String> websocketServers = new ArrayList<>(serverConfig.wsServers.size());
|
||||||
for (Entry<String, String> entry : serverConfig.wsServers.entrySet()) {
|
for (Entry<String, String> entry : serverConfig.wsServers.entrySet()) {
|
||||||
if (entry.getValue().equals("rfc6455")) {
|
if (entry.getValue().equals("rfc6455")) {
|
||||||
websocketServers.add(entry.getKey());
|
websocketServers.add(entry.getKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String server = websocketServers.get((int) (Math.random() * websocketServers.size() - 1));
|
|
||||||
|
String server = websocketServers.get(new Random().nextInt(websocketServers.size()-1));
|
||||||
String wsUrl = "ws://" + server + ".myfreecams.com:8080/fcsl";
|
String wsUrl = "ws://" + server + ".myfreecams.com:8080/fcsl";
|
||||||
LOG.debug("Connecting to random websocket server {}", wsUrl);
|
LOG.debug("Connecting to random websocket server {}", wsUrl);
|
||||||
|
|
||||||
Thread watchDog = new Thread(() -> {
|
Thread watchDog = new Thread(() -> {
|
||||||
while(running) {
|
while (running) {
|
||||||
if (ws == null && !connecting) {
|
if (ws == null && !connecting) {
|
||||||
LOG.info("Websocket is null. Starting a new connection");
|
LOG.info("Websocket is null. Starting a new connection");
|
||||||
Request req = new Request.Builder()
|
Request req = new Request.Builder().url(wsUrl).addHeader("Origin", "http://m.myfreecams.com").build();
|
||||||
.url(wsUrl)
|
|
||||||
.addHeader("Origin", "http://m.myfreecams.com")
|
|
||||||
.build();
|
|
||||||
ws = createWebSocket(req);
|
ws = createWebSocket(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(10000);
|
Thread.sleep(10000);
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
LOG.error("WatchDog couldn't sleep", e);
|
LOG.error("WatchDog couldn't sleep", e);
|
||||||
stop();
|
stop();
|
||||||
running = false;
|
running = false;
|
||||||
|
@ -140,7 +142,7 @@ public class MyFreeCamsClient {
|
||||||
|
|
||||||
private WebSocket createWebSocket(Request req) {
|
private WebSocket createWebSocket(Request req) {
|
||||||
connecting = true;
|
connecting = true;
|
||||||
WebSocket ws = mfc.getHttpClient().newWebSocket(req, new WebSocketListener() {
|
WebSocket websocket = mfc.getHttpClient().newWebSocket(req, new WebSocketListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onOpen(WebSocket webSocket, Response response) {
|
public void onOpen(WebSocket webSocket, Response response) {
|
||||||
super.onOpen(webSocket, response);
|
super.onOpen(webSocket, response);
|
||||||
|
@ -152,12 +154,14 @@ public class MyFreeCamsClient {
|
||||||
webSocket.send("hello fcserver\n");
|
webSocket.send("hello fcserver\n");
|
||||||
webSocket.send("fcsws_20180422\n");
|
webSocket.send("fcsws_20180422\n");
|
||||||
// TODO find out, what the values in the json message mean, at the moment we hust send 0s, which seems to work, too
|
// TODO find out, what the values in the json message mean, at the moment we hust send 0s, which seems to work, too
|
||||||
// webSocket.send("1 0 0 81 0 %7B%22err%22%3A0%2C%22start%22%3A1540159843072%2C%22stop%22%3A1540159844121%2C%22a%22%3A6392%2C%22time%22%3A1540159844%2C%22key%22%3A%228da80f985c9db390809713dac71df297%22%2C%22cid%22%3A%22c504d684%22%2C%22pid%22%3A1%2C%22site%22%3A%22www%22%7D\n");
|
// webSocket.send("1 0 0 81 0
|
||||||
webSocket.send("1 0 0 81 0 %7B%22err%22%3A0%2C%22start%22%3A0%2C%22stop%22%3A0%2C%22a%22%3A0%2C%22time%22%3A0%2C%22key%22%3A%22%22%2C%22cid%22%3A%22%22%2C%22pid%22%3A1%2C%22site%22%3A%22www%22%7D\n");
|
// %7B%22err%22%3A0%2C%22start%22%3A1540159843072%2C%22stop%22%3A1540159844121%2C%22a%22%3A6392%2C%22time%22%3A1540159844%2C%22key%22%3A%228da80f985c9db390809713dac71df297%22%2C%22cid%22%3A%22c504d684%22%2C%22pid%22%3A1%2C%22site%22%3A%22www%22%7D\n");
|
||||||
|
webSocket.send(
|
||||||
|
"1 0 0 81 0 %7B%22err%22%3A0%2C%22start%22%3A0%2C%22stop%22%3A0%2C%22a%22%3A0%2C%22time%22%3A0%2C%22key%22%3A%22%22%2C%22cid%22%3A%22%22%2C%22pid%22%3A1%2C%22site%22%3A%22www%22%7D\n");
|
||||||
heartBeat = System.currentTimeMillis();
|
heartBeat = System.currentTimeMillis();
|
||||||
startKeepAlive(webSocket);
|
startKeepAlive(webSocket);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
LOG.error("Error while processing onOpen event", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +171,7 @@ public class MyFreeCamsClient {
|
||||||
connecting = false;
|
connecting = false;
|
||||||
LOG.info("MFC websocket closed: {} {}", code, reason);
|
LOG.info("MFC websocket closed: {} {}", code, reason);
|
||||||
MyFreeCamsClient.this.ws = null;
|
MyFreeCamsClient.this.ws = null;
|
||||||
if(!running) {
|
if (!running) {
|
||||||
mfc.getHttpClient().shutdown();
|
mfc.getHttpClient().shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,7 +180,7 @@ public class MyFreeCamsClient {
|
||||||
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
|
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
|
||||||
super.onFailure(webSocket, t, response);
|
super.onFailure(webSocket, t, response);
|
||||||
connecting = false;
|
connecting = false;
|
||||||
if(response != null) {
|
if (response != null) {
|
||||||
int code = response.code();
|
int code = response.code();
|
||||||
String message = response.message();
|
String message = response.message();
|
||||||
LOG.error("MFC websocket failure: {} {}", code, message, t);
|
LOG.error("MFC websocket failure: {} {}", code, message, t);
|
||||||
|
@ -194,13 +198,13 @@ public class MyFreeCamsClient {
|
||||||
super.onMessage(webSocket, text);
|
super.onMessage(webSocket, text);
|
||||||
heartBeat = System.currentTimeMillis();
|
heartBeat = System.currentTimeMillis();
|
||||||
receivedTextHistory.add(text);
|
receivedTextHistory.add(text);
|
||||||
while(receivedTextHistory.size() > 100) {
|
while (receivedTextHistory.size() > 100) {
|
||||||
receivedTextHistory.poll();
|
receivedTextHistory.poll();
|
||||||
}
|
}
|
||||||
msgBuffer.append(text);
|
msgBuffer.append(text);
|
||||||
Message message;
|
Message message;
|
||||||
try {
|
try {
|
||||||
while( (message = parseMessage(msgBuffer)) != null) {
|
while ((message = parseMessage(msgBuffer)) != null) {
|
||||||
switch (message.getType()) {
|
switch (message.getType()) {
|
||||||
case NULL:
|
case NULL:
|
||||||
LOG.trace("NULL websocket still alive");
|
LOG.trace("NULL websocket still alive");
|
||||||
|
@ -221,8 +225,8 @@ public class MyFreeCamsClient {
|
||||||
case MYWEBCAM:
|
case MYWEBCAM:
|
||||||
case JOINCHAN:
|
case JOINCHAN:
|
||||||
case SESSIONSTATE:
|
case SESSIONSTATE:
|
||||||
if(!message.getMessage().isEmpty()) {
|
if (!message.getMessage().isEmpty()) {
|
||||||
//LOG.debug("SessionState: {}", message.getMessage());
|
// LOG.debug("SessionState: {}", message.getMessage());
|
||||||
JsonAdapter<SessionState> adapter = moshi.adapter(SessionState.class);
|
JsonAdapter<SessionState> adapter = moshi.adapter(SessionState.class);
|
||||||
try {
|
try {
|
||||||
SessionState sessionState = adapter.fromJson(message.getMessage());
|
SessionState sessionState = adapter.fromJson(message.getMessage());
|
||||||
|
@ -240,7 +244,7 @@ public class MyFreeCamsClient {
|
||||||
// LOG.debug("{}", message.getArg2());
|
// LOG.debug("{}", message.getArg2());
|
||||||
// LOG.debug("{}", message.getMessage());
|
// LOG.debug("{}", message.getMessage());
|
||||||
Consumer<Message> responseHandler = responseHandlers.remove(message.getArg1());
|
Consumer<Message> responseHandler = responseHandlers.remove(message.getArg1());
|
||||||
if(responseHandler != null) {
|
if (responseHandler != null) {
|
||||||
responseHandler.accept(message);
|
responseHandler.accept(message);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -257,10 +261,10 @@ public class MyFreeCamsClient {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EXTDATA:
|
case EXTDATA:
|
||||||
if(message.getArg1() == MessageTypes.LOGIN) {
|
if (message.getArg1() == MessageTypes.LOGIN) {
|
||||||
chatToken = message.getMessage();
|
chatToken = message.getMessage();
|
||||||
String username = Config.getInstance().getSettings().mfcUsername;
|
String username = Config.getInstance().getSettings().mfcUsername;
|
||||||
if(StringUtil.isNotBlank(username)) {
|
if (StringUtil.isNotBlank(username)) {
|
||||||
boolean login = mfc.getHttpClient().login();
|
boolean login = mfc.getHttpClient().login();
|
||||||
if (login) {
|
if (login) {
|
||||||
Cookie passcode = mfc.getHttpClient().getCookie("passcode");
|
Cookie passcode = mfc.getHttpClient().getCookie("passcode");
|
||||||
|
@ -272,7 +276,7 @@ public class MyFreeCamsClient {
|
||||||
} else {
|
} else {
|
||||||
webSocket.send("1 0 0 20080909 0 guest:guest\n");
|
webSocket.send("1 0 0 20080909 0 guest:guest\n");
|
||||||
}
|
}
|
||||||
} else if(message.getArg1() == MessageTypes.MANAGELIST) {
|
} else if (message.getArg1() == MessageTypes.MANAGELIST) {
|
||||||
requestExtData(message.getMessage());
|
requestExtData(message.getMessage());
|
||||||
} else {
|
} else {
|
||||||
LOG.debug("EXTDATA: {}", message);
|
LOG.debug("EXTDATA: {}", message);
|
||||||
|
@ -280,6 +284,7 @@ public class MyFreeCamsClient {
|
||||||
break;
|
break;
|
||||||
case ROOMDATA:
|
case ROOMDATA:
|
||||||
LOG.debug("ROOMDATA: {}", message);
|
LOG.debug("ROOMDATA: {}", message);
|
||||||
|
break;
|
||||||
case UEOPT:
|
case UEOPT:
|
||||||
LOG.trace("UEOPT: {}", message);
|
LOG.trace("UEOPT: {}", message);
|
||||||
break;
|
break;
|
||||||
|
@ -304,9 +309,9 @@ public class MyFreeCamsClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
e.printStackTrace();
|
LOG.error("Error while decoding ctxenc URL", e);
|
||||||
} catch (Throwable t) {
|
} catch (Exception e) {
|
||||||
t.printStackTrace();
|
LOG.error("Exception occured while processing websocket message {}", msgBuffer, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,22 +323,22 @@ public class MyFreeCamsClient {
|
||||||
long serv = json.getInt("serv");
|
long serv = json.getInt("serv");
|
||||||
long type = json.getInt("type");
|
long type = json.getInt("type");
|
||||||
String base = mfc.getBaseUrl() + "/php/FcwExtResp.php";
|
String base = mfc.getBaseUrl() + "/php/FcwExtResp.php";
|
||||||
String url = base + "?respkey="+respkey+"&opts="+opts+"&serv="+serv+"&type="+type;
|
String url = base + "?respkey=" + respkey + "&opts=" + opts + "&serv=" + serv + "&type=" + type;
|
||||||
Request req = new Request.Builder().url(url).build();
|
Request req = new Request.Builder().url(url).build();
|
||||||
LOG.trace("Requesting EXTDATA {}", url);
|
LOG.trace("Requesting EXTDATA {}", url);
|
||||||
try(Response resp = mfc.getHttpClient().execute(req)) {
|
try (Response resp = mfc.getHttpClient().execute(req)) {
|
||||||
if(resp.isSuccessful()) {
|
if (resp.isSuccessful()) {
|
||||||
parseExtDataSessionStates(resp.body().string());
|
parseExtDataSessionStates(resp.body().string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.warn("Couldn't request EXTDATA", e);
|
LOG.warn("Couldn't request EXTDATA", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseExtDataSessionStates(String json) {
|
private void parseExtDataSessionStates(String json) {
|
||||||
JSONObject object = new JSONObject(json);
|
JSONObject object = new JSONObject(json);
|
||||||
if(object.has("type") && object.getInt("type") == 21) {
|
if (object.has("type") && object.getInt("type") == 21) {
|
||||||
JSONArray outer = object.getJSONArray("rdata");
|
JSONArray outer = object.getJSONArray("rdata");
|
||||||
LOG.debug("{} models", outer.length());
|
LOG.debug("{} models", outer.length());
|
||||||
for (int i = 1; i < outer.length(); i++) {
|
for (int i = 1; i < outer.length(); i++) {
|
||||||
|
@ -367,26 +372,24 @@ public class MyFreeCamsClient {
|
||||||
state.getM().setRank(inner.getInt(idx++));
|
state.getM().setRank(inner.getInt(idx++));
|
||||||
state.getM().setRc(inner.getInt(idx++));
|
state.getM().setRc(inner.getInt(idx++));
|
||||||
state.getM().setTopic(inner.getString(idx++));
|
state.getM().setTopic(inner.getString(idx++));
|
||||||
state.getM().setHidecs(inner.getInt(idx++) == 1);
|
state.getM().setHidecs(inner.getInt(idx) == 1);
|
||||||
updateSessionState(state);
|
updateSessionState(state);
|
||||||
} catch(Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.warn("Couldn't parse session state {}", inner.toString());
|
LOG.warn("Couldn't parse session state {}", inner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(object.has("type") && object.getInt("type") == 20) {
|
} else if (object.has("type") && object.getInt("type") == 20) {
|
||||||
JSONObject outer = object.getJSONObject("rdata");
|
JSONObject outer = object.getJSONObject("rdata");
|
||||||
for (String uidString : outer.keySet()) {
|
for (String uidString : outer.keySet()) {
|
||||||
try {
|
try {
|
||||||
int uid = Integer.parseInt(uidString);
|
int uid = Integer.parseInt(uidString);
|
||||||
MyFreeCamsModel model = getModel(uid);
|
MyFreeCamsModel model = getModel(uid);
|
||||||
if(model != null) {
|
if (model != null) {
|
||||||
model.getTags().clear();
|
model.getTags().clear();
|
||||||
JSONArray jsonTags = outer.getJSONArray(uidString);
|
JSONArray jsonTags = outer.getJSONArray(uidString);
|
||||||
jsonTags.forEach((tag) -> {
|
jsonTags.forEach(tag -> model.getTags().add((String) tag));
|
||||||
model.getTags().add((String) tag);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch(Exception e) {
|
} catch (Exception e) {
|
||||||
// fail silently
|
// fail silently
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,22 +418,23 @@ public class MyFreeCamsClient {
|
||||||
|
|
||||||
private void updateModel(SessionState state) {
|
private void updateModel(SessionState state) {
|
||||||
// essential data not yet available
|
// essential data not yet available
|
||||||
if(state.getNm() == null || state.getM() == null || state.getU() == null || state.getU().getCamserv() == null || state.getU().getCamserv() == 0) {
|
if (state.getNm() == null || state.getM() == null || state.getU() == null || state.getU().getCamserv() == null
|
||||||
|
|| state.getU().getCamserv() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// tokens not yet available
|
// tokens not yet available
|
||||||
if(ctxenc == null) {
|
if (ctxenc == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// uid not set, we can't identify this model
|
// uid not set, we can't identify this model
|
||||||
if(state.getUid() == null || state.getUid() <= 0) {
|
if (state.getUid() == null || state.getUid() <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MyFreeCamsModel model = models.getIfPresent(state.getUid());
|
MyFreeCamsModel model = models.getIfPresent(state.getUid());
|
||||||
if(model == null) {
|
if (model == null) {
|
||||||
model = mfc.createModel(state.getNm());
|
model = mfc.createModel(state.getNm());
|
||||||
model.setUid(state.getUid());
|
model.setUid(state.getUid());
|
||||||
models.put(state.getUid(), model);
|
models.put(state.getUid(), model);
|
||||||
|
@ -460,18 +464,16 @@ public class MyFreeCamsClient {
|
||||||
msgBuffer.delete(0, packetLength);
|
msgBuffer.delete(0, packetLength);
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
} catch(Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error("StringBuilder contains invalid data {}", msgBuffer.toString(), e);
|
LOG.error("StringBuilder contains invalid data {}", msgBuffer.toString(), e);
|
||||||
String logfile = "mfc_messages.log";
|
String logfile = "mfc_messages.log";
|
||||||
try(FileOutputStream fout = new FileOutputStream(logfile)) {
|
try (FileOutputStream fout = new FileOutputStream(logfile)) {
|
||||||
for (String string : receivedTextHistory) {
|
for (String string : receivedTextHistory) {
|
||||||
fout.write(string.getBytes());
|
fout.write(string.getBytes());
|
||||||
fout.write(10);
|
fout.write(10);
|
||||||
}
|
}
|
||||||
//System.exit(1);
|
|
||||||
} catch (Exception e1) {
|
} catch (Exception e1) {
|
||||||
LOG.error("Couldn't write mfc message history to " + logfile);
|
LOG.error("Couldn't write mfc message history to {}", logfile, e1);
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
}
|
||||||
msgBuffer.setLength(0);
|
msgBuffer.setLength(0);
|
||||||
return null;
|
return null;
|
||||||
|
@ -492,11 +494,11 @@ public class MyFreeCamsClient {
|
||||||
LOG.debug("msgb: {}", bytes.hex());
|
LOG.debug("msgb: {}", bytes.hex());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return ws;
|
return websocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean follow(int uid) {
|
protected boolean follow(int uid) {
|
||||||
if(ws != null) {
|
if (ws != null) {
|
||||||
return ws.send(ADDFRIENDREQ + " " + sessionId + " 0 " + uid + " 1\n");
|
return ws.send(ADDFRIENDREQ + " " + sessionId + " 0 " + uid + " 1\n");
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -504,7 +506,7 @@ public class MyFreeCamsClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean unfollow(int uid) {
|
protected boolean unfollow(int uid) {
|
||||||
if(ws != null) {
|
if (ws != null) {
|
||||||
return ws.send(ADDFRIENDREQ + " " + sessionId + " 0 " + uid + " 2\n");
|
return ws.send(ADDFRIENDREQ + " " + sessionId + " 0 " + uid + " 2\n");
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -513,21 +515,22 @@ public class MyFreeCamsClient {
|
||||||
|
|
||||||
private void startKeepAlive(WebSocket ws) {
|
private void startKeepAlive(WebSocket ws) {
|
||||||
Thread keepAlive = new Thread(() -> {
|
Thread keepAlive = new Thread(() -> {
|
||||||
while(running) {
|
while (running) {
|
||||||
LOG.trace("--> NULL to keep the connection alive");
|
LOG.trace("--> NULL to keep the connection alive");
|
||||||
try {
|
try {
|
||||||
ws.send("0 0 0 0 0 -\n");
|
ws.send("0 0 0 0 0 -\n");
|
||||||
|
|
||||||
long millisSinceLastMessage = System.currentTimeMillis() - heartBeat;
|
long millisSinceLastMessage = System.currentTimeMillis() - heartBeat;
|
||||||
if(millisSinceLastMessage > TimeUnit.MINUTES.toMillis(2)) {
|
if (millisSinceLastMessage > TimeUnit.MINUTES.toMillis(2)) {
|
||||||
LOG.info("No message since 2 mins. Restarting websocket");
|
LOG.info("No message since 2 mins. Restarting websocket");
|
||||||
ws.close(1000, "");
|
ws.close(1000, "");
|
||||||
MyFreeCamsClient.this.ws = null;
|
MyFreeCamsClient.this.ws = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread.sleep(TimeUnit.SECONDS.toMillis(15));
|
Thread.sleep(TimeUnit.SECONDS.toMillis(15));
|
||||||
} catch (Exception e) {
|
} catch (InterruptedException e) {
|
||||||
e.printStackTrace();
|
Thread.currentThread().interrupt();
|
||||||
|
LOG.warn("Websocket watchdog has been interrupted");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -542,7 +545,7 @@ public class MyFreeCamsClient {
|
||||||
for (SessionState state : sessionStates.asMap().values()) {
|
for (SessionState state : sessionStates.asMap().values()) {
|
||||||
String nm = Optional.ofNullable(state.getNm()).orElse("");
|
String nm = Optional.ofNullable(state.getNm()).orElse("");
|
||||||
String name = Optional.ofNullable(model.getName()).orElse("");
|
String name = Optional.ofNullable(model.getName()).orElse("");
|
||||||
if(Objects.equals(nm.toLowerCase(), name.toLowerCase()) || Objects.equals(model.getUid(), state.getUid()) && state.getUid() > 0) {
|
if (Objects.equals(nm.toLowerCase(), name.toLowerCase()) || Objects.equals(model.getUid(), state.getUid()) && state.getUid() > 0) {
|
||||||
model.update(state, getStreamUrl(state));
|
model.update(state, getStreamUrl(state));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -553,29 +556,69 @@ public class MyFreeCamsClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getStreamUrl(SessionState state) {
|
public String getStreamUrl(SessionState state) {
|
||||||
Integer camserv = Optional.ofNullable(state.getU()).map(u -> u.getCamserv()).orElse(-1);
|
Integer camserv = Optional.ofNullable(state.getU()).map(User::getCamserv).orElse(-1);
|
||||||
if(camserv != null && camserv != -1) {
|
String camservString = camserv.toString();
|
||||||
int userChannel = 100000000 + state.getUid();
|
if (serverConfig.isOnWzObsVideoServer(state)) {
|
||||||
String streamUrl = "";
|
camservString = serverConfig.wzobsServers.get(camserv.toString());
|
||||||
String phase = state.getU().getPhase() != null ? state.getU().getPhase() : "z";
|
} else if (serverConfig.isOnObsServer(state)) {
|
||||||
if(serverConfig.isOnNgServer(state)) {
|
camservString = serverConfig.ngVideoServers.get(camserv.toString());
|
||||||
String server = serverConfig.ngVideoServers.get(camserv.toString());
|
} else if (serverConfig.isOnHtml5VideoServer(state)) {
|
||||||
streamUrl = "https://" + server + ".myfreecams.com:8444/x-hls/" + cxid + '/' + userChannel + '/' + ctxenc + "/mfc_" + phase + '_' + userChannel + ".m3u8";
|
camservString = serverConfig.h5Servers.get(camserv.toString());
|
||||||
} else if(serverConfig.isOnWzObsVideoServer(state)) {
|
} else if (camserv > 500) {
|
||||||
String server = serverConfig.wzobsServers.get(camserv.toString());
|
|
||||||
streamUrl = "https://"+ server + ".myfreecams.com/NxServer/ngrp:mfc_" + phase + '_' + userChannel + ".f4v_mobile/playlist.m3u8";
|
|
||||||
} else if(serverConfig.isOnHtml5VideoServer(state)) {
|
|
||||||
String server = serverConfig.h5Servers.get(camserv.toString());
|
|
||||||
streamUrl = "https://"+ server + ".myfreecams.com/NxServer/ngrp:mfc_" + userChannel + ".f4v_mobile/playlist.m3u8";
|
|
||||||
} else {
|
|
||||||
if(camserv > 500) {
|
|
||||||
camserv -= 500;
|
camserv -= 500;
|
||||||
|
camservString = camserv.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverConfig.isOnObsServer(state)) {
|
||||||
|
// techorder -> hls
|
||||||
|
} else {
|
||||||
|
// techorder -> dash hls
|
||||||
|
}
|
||||||
|
|
||||||
|
int userChannel = 100000000 + state.getUid();
|
||||||
|
String phase = state.getU().getPhase() != null ? state.getU().getPhase() : "z";
|
||||||
|
String server = "video" + camservString.replaceAll("^\\D+", "");
|
||||||
|
boolean useHls = serverConfig.isOnObsServer(state);
|
||||||
|
String streamUrl;
|
||||||
|
if (serverConfig.isOnWzObsVideoServer(state) || !serverConfig.isOnObsServer(state)) {
|
||||||
|
// wowza server
|
||||||
|
// https://video350.myfreecams.com/NxServer/ngrp:mfc_108514276.f4v_desktop/manifest_w515822224_qbmM9MC40NTQ0NTYxNjUyOTYzNDA4.mpd
|
||||||
|
if (useHls) {
|
||||||
|
streamUrl = HTTPS + server + ".myfreecams.com/NxServer/ngrp:mfc_" + userChannel + ".f4v_mobile/playlist.m3u8";
|
||||||
|
} else {
|
||||||
|
streamUrl = HTTPS + server + ".myfreecams.com/NxServer/ngrp:mfc_" + userChannel + ".f4v_desktop/manifest.mpd";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// nginx server
|
||||||
|
if (useHls) {
|
||||||
|
streamUrl = HTTPS + server + ".myfreecams.com:8444/x-hls/" + cxid + '/' + userChannel + '/' + ctxenc + "/mfc_" + phase + '_' + userChannel
|
||||||
|
+ ".m3u8";
|
||||||
|
} else {
|
||||||
|
streamUrl = HTTPS + server + ".myfreecams.com:8444/x-dsh/" + cxid + '/' + userChannel + '/' + ctxenc + "/mfc_" + phase + '_' + userChannel
|
||||||
|
+ ".mpd";
|
||||||
}
|
}
|
||||||
streamUrl = "https://video" + camserv + ".myfreecams.com/NxServer/ngrp:mfc_" + userChannel + ".f4v_mobile/playlist.m3u8";
|
|
||||||
}
|
}
|
||||||
return streamUrl;
|
return streamUrl;
|
||||||
}
|
|
||||||
return null;
|
// https://video848.myfreecams.com/NxServer/ngrp:mfc_117940536.f4v_desktop/manifest_w514169512_qbmM9MC40NzQwNzU4NzQxNTA0NDUyNQ==.mpd
|
||||||
|
|
||||||
|
// if(camserv != null && ) {
|
||||||
|
// int userChannel = 100000000 + state.getUid();
|
||||||
|
// String streamUrl = "";
|
||||||
|
// String phase = state.getU().getPhase() != null ? state.getU().getPhase() : "z";
|
||||||
|
// } else if(serverConfig.isOnNgServer(state)) {
|
||||||
|
// String server = serverConfig.ngVideoServers.get(camserv.toString());
|
||||||
|
// streamUrl = "https://" + server + ".myfreecams.com:8444/x-hls/" + cxid + '/' + userChannel + '/' + ctxenc + "/mfc_" + phase + '_' + userChannel +
|
||||||
|
// ".m3u8";
|
||||||
|
// } else if(serverConfig.isOnWzObsVideoServer(state)) {
|
||||||
|
// String server = serverConfig.wzobsServers.get(camserv.toString());
|
||||||
|
// streamUrl = "https://"+ server + ".myfreecams.com/NxServer/ngrp:mfc_" + phase + '_' + userChannel + ".f4v_mobile/playlist.m3u8";
|
||||||
|
// } else if(serverConfig.isOnHtml5VideoServer(state)) {
|
||||||
|
// String server = serverConfig.h5Servers.get(camserv.toString());
|
||||||
|
// streamUrl = "https://"+ server + ".myfreecams.com/NxServer/ngrp:mfc_" + userChannel + ".f4v_mobile/playlist.m3u8";
|
||||||
|
// } else {
|
||||||
|
// streamUrl = "https://video" + camserv + ".myfreecams.com/NxServer/ngrp:mfc_" + userChannel + ".f4v_mobile/playlist.m3u8";
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
public MyFreeCamsModel getModel(int uid) {
|
public MyFreeCamsModel getModel(int uid) {
|
||||||
|
@ -584,13 +627,15 @@ public class MyFreeCamsClient {
|
||||||
|
|
||||||
public void getSessionState(ctbrec.Model model) {
|
public void getSessionState(ctbrec.Model model) {
|
||||||
for (SessionState state : sessionStates.asMap().values()) {
|
for (SessionState state : sessionStates.asMap().values()) {
|
||||||
if(Objects.equals(state.getNm(), model.getName())) {
|
if (Objects.equals(state.getNm(), model.getName())) {
|
||||||
JsonAdapter<SessionState> adapter = moshi.adapter(SessionState.class).indent(" ");
|
JsonAdapter<SessionState> adapter = moshi.adapter(SessionState.class).indent(" ");
|
||||||
System.out.println(adapter.toJson(state));
|
System.out.println(adapter.toJson(state));
|
||||||
System.out.println(model.getPreview());
|
System.out.println(model.getPreview());
|
||||||
System.out.println("H5 " + serverConfig.isOnHtml5VideoServer(state));
|
System.out.println("H5 " + serverConfig.isOnHtml5VideoServer(state));
|
||||||
System.out.println("NG " + serverConfig.isOnNgServer(state));
|
System.out.println("NG " + serverConfig.isOnNgServer(state));
|
||||||
System.out.println("WZ " + serverConfig.isOnWzObsVideoServer(state));
|
System.out.println("WZ " + serverConfig.isOnWzObsVideoServer(state));
|
||||||
|
System.out.println("OBS " + serverConfig.isOnObsServer(state));
|
||||||
|
System.out.println("URL: " + getStreamUrl(state));
|
||||||
System.out.println("#####################");
|
System.out.println("#####################");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -606,8 +651,8 @@ public class MyFreeCamsClient {
|
||||||
Object monitor = new Object();
|
Object monitor = new Object();
|
||||||
List<ctbrec.Model> result = new ArrayList<>();
|
List<ctbrec.Model> result = new ArrayList<>();
|
||||||
responseHandlers.put(msgId, msg -> {
|
responseHandlers.put(msgId, msg -> {
|
||||||
LOG.debug("Search result: " + msg);
|
LOG.debug("Search result: {}", msg);
|
||||||
if(StringUtil.isNotBlank(msg.getMessage()) && !Objects.equals(msg.getMessage(), q)) {
|
if (StringUtil.isNotBlank(msg.getMessage()) && !Objects.equals(msg.getMessage(), q)) {
|
||||||
JSONObject json = new JSONObject(msg.getMessage());
|
JSONObject json = new JSONObject(msg.getMessage());
|
||||||
String name = json.getString("nm");
|
String name = json.getString("nm");
|
||||||
MyFreeCamsModel model = mfc.createModel(name);
|
MyFreeCamsModel model = mfc.createModel(name);
|
||||||
|
@ -615,12 +660,12 @@ public class MyFreeCamsClient {
|
||||||
model.setMfcState(State.of(json.getInt("vs")));
|
model.setMfcState(State.of(json.getInt("vs")));
|
||||||
String uid = Integer.toString(model.getUid());
|
String uid = Integer.toString(model.getUid());
|
||||||
String uidStart = uid.substring(0, 3);
|
String uidStart = uid.substring(0, 3);
|
||||||
String previewUrl = "https://img.mfcimg.com/photos2/"+uidStart+'/'+uid+"/avatar.90x90.jpg";
|
String previewUrl = "https://img.mfcimg.com/photos2/" + uidStart + '/' + uid + "/avatar.90x90.jpg";
|
||||||
model.setPreview(previewUrl);
|
model.setPreview(previewUrl);
|
||||||
result.add(model);
|
result.add(model);
|
||||||
}
|
}
|
||||||
synchronized (monitor) {
|
synchronized (monitor) {
|
||||||
monitor.notify();
|
monitor.notifyAll();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ws.send("10 " + sessionId + " 0 " + msgId + " 0 " + q + "\n");
|
ws.send("10 " + sessionId + " 0 " + msgId + " 0 " + q + "\n");
|
||||||
|
@ -629,12 +674,10 @@ public class MyFreeCamsClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (MyFreeCamsModel model : models.asMap().values()) {
|
for (MyFreeCamsModel model : models.asMap().values()) {
|
||||||
if(StringUtil.isNotBlank(model.getName())) {
|
if (StringUtil.isNotBlank(model.getName()) && model.getName().toLowerCase().contains(q.toLowerCase())) {
|
||||||
if(model.getName().toLowerCase().contains(q.toLowerCase())) {
|
|
||||||
result.add(model);
|
result.add(model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,9 @@ import ctbrec.AbstractModel;
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.io.HtmlParser;
|
import ctbrec.io.HtmlParser;
|
||||||
import ctbrec.io.HttpException;
|
import ctbrec.io.HttpException;
|
||||||
|
import ctbrec.recorder.download.Download;
|
||||||
import ctbrec.recorder.download.StreamSource;
|
import ctbrec.recorder.download.StreamSource;
|
||||||
|
import ctbrec.recorder.download.dash.DashDownload;
|
||||||
import okhttp3.FormBody;
|
import okhttp3.FormBody;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.RequestBody;
|
import okhttp3.RequestBody;
|
||||||
|
@ -40,14 +42,14 @@ import okhttp3.Response;
|
||||||
|
|
||||||
public class MyFreeCamsModel extends AbstractModel {
|
public class MyFreeCamsModel extends AbstractModel {
|
||||||
|
|
||||||
private static final transient Logger LOG = LoggerFactory.getLogger(MyFreeCamsModel.class);
|
private static final Logger LOG = LoggerFactory.getLogger(MyFreeCamsModel.class);
|
||||||
|
|
||||||
private int uid = -1; // undefined
|
private int uid = -1; // undefined
|
||||||
private String hlsUrl;
|
private String streamUrl;
|
||||||
private double camScore;
|
private double camScore;
|
||||||
private int viewerCount;
|
private int viewerCount;
|
||||||
private ctbrec.sites.mfc.State state;
|
private ctbrec.sites.mfc.State state;
|
||||||
private int resolution[] = new int[2];
|
private int[] resolution = new int[2];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor exists only for deserialization. Please don't call it directly
|
* This constructor exists only for deserialization. Please don't call it directly
|
||||||
|
@ -110,7 +112,7 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
src.width = Integer.MAX_VALUE;
|
src.width = Integer.MAX_VALUE;
|
||||||
src.height = Integer.MAX_VALUE;
|
src.height = Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
String masterUrl = hlsUrl;
|
String masterUrl = streamUrl;
|
||||||
String baseUrl = masterUrl.substring(0, masterUrl.lastIndexOf('/') + 1);
|
String baseUrl = masterUrl.substring(0, masterUrl.lastIndexOf('/') + 1);
|
||||||
String segmentUri = baseUrl + playlist.getUri();
|
String segmentUri = baseUrl + playlist.getUri();
|
||||||
src.mediaPlaylistUrl = segmentUri;
|
src.mediaPlaylistUrl = segmentUri;
|
||||||
|
@ -131,8 +133,8 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
if(getHlsUrl() == null) {
|
if(getHlsUrl() == null) {
|
||||||
throw new IllegalStateException("Stream url unknown");
|
throw new IllegalStateException("Stream url unknown");
|
||||||
}
|
}
|
||||||
LOG.trace("Loading master playlist {}", hlsUrl);
|
LOG.trace("Loading master playlist {}", streamUrl);
|
||||||
Request req = new Request.Builder().url(hlsUrl).build();
|
Request req = new Request.Builder().url(streamUrl).build();
|
||||||
try(Response response = site.getHttpClient().execute(req)) {
|
try(Response response = site.getHttpClient().execute(req)) {
|
||||||
if(response.isSuccessful()) {
|
if(response.isSuccessful()) {
|
||||||
InputStream inputStream = response.body().byteStream();
|
InputStream inputStream = response.body().byteStream();
|
||||||
|
@ -147,11 +149,11 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getHlsUrl() {
|
private String getHlsUrl() {
|
||||||
if(hlsUrl == null) {
|
if(streamUrl == null) {
|
||||||
MyFreeCams mfc = (MyFreeCams) getSite();
|
MyFreeCams mfc = (MyFreeCams) getSite();
|
||||||
mfc.getClient().update(this);
|
mfc.getClient().update(this);
|
||||||
}
|
}
|
||||||
return hlsUrl;
|
return streamUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -203,7 +205,7 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int[] getStreamResolution(boolean failFast) throws ExecutionException {
|
public int[] getStreamResolution(boolean failFast) throws ExecutionException {
|
||||||
if (!failFast && hlsUrl != null) {
|
if (!failFast && streamUrl != null) {
|
||||||
try {
|
try {
|
||||||
List<StreamSource> streamSources = getStreamSources();
|
List<StreamSource> streamSources = getStreamSources();
|
||||||
Collections.sort(streamSources);
|
Collections.sort(streamSources);
|
||||||
|
@ -218,12 +220,12 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
return resolution;
|
return resolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStreamUrl(String hlsUrl) {
|
public void setStreamUrl(String streamUrl) {
|
||||||
this.hlsUrl = hlsUrl;
|
this.streamUrl = streamUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getStreamUrl() {
|
public String getStreamUrl() {
|
||||||
return hlsUrl;
|
return streamUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getCamScore() {
|
public double getCamScore() {
|
||||||
|
@ -248,17 +250,16 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(SessionState state, String streamUrl) {
|
public void update(SessionState state, String streamUrl) {
|
||||||
uid = Integer.parseInt(state.getUid().toString());
|
uid = state.getUid();
|
||||||
setName(state.getNm());
|
setName(state.getNm());
|
||||||
setMfcState(ctbrec.sites.mfc.State.of(state.getVs()));
|
setMfcState(ctbrec.sites.mfc.State.of(state.getVs()));
|
||||||
setStreamUrl(streamUrl);
|
setStreamUrl(streamUrl);
|
||||||
Optional<Double> camScore = Optional.ofNullable(state.getM()).map(m -> m.getCamscore());
|
setCamScore(Optional.ofNullable(state.getM()).map(Model::getCamscore).orElse(0.0));
|
||||||
setCamScore(camScore.orElse(0.0));
|
|
||||||
|
|
||||||
// preview
|
// preview
|
||||||
String uid = state.getUid().toString();
|
String uidString = state.getUid().toString();
|
||||||
String uidStart = uid.substring(0, 3);
|
String uidStart = uidString.substring(0, 3);
|
||||||
String previewUrl = "https://img.mfcimg.com/photos2/"+uidStart+'/'+uid+"/avatar.300x300.jpg";
|
String previewUrl = "https://img.mfcimg.com/photos2/"+uidStart+'/'+uidString+"/avatar.300x300.jpg";
|
||||||
if(MyFreeCamsModel.this.state == ctbrec.sites.mfc.State.ONLINE) {
|
if(MyFreeCamsModel.this.state == ctbrec.sites.mfc.State.ONLINE) {
|
||||||
try {
|
try {
|
||||||
previewUrl = getLivePreviewUrl(state);
|
previewUrl = getLivePreviewUrl(state);
|
||||||
|
@ -269,14 +270,14 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
setPreview(previewUrl);
|
setPreview(previewUrl);
|
||||||
|
|
||||||
// tags
|
// tags
|
||||||
Optional.ofNullable(state.getM()).map((m) -> m.getTags()).ifPresent((tags) -> {
|
Optional.ofNullable(state.getM()).map(Model::getTags).ifPresent(tags -> {
|
||||||
ArrayList<String> t = new ArrayList<>();
|
ArrayList<String> t = new ArrayList<>();
|
||||||
t.addAll(tags);
|
t.addAll(tags);
|
||||||
setTags(t);
|
setTags(t);
|
||||||
});
|
});
|
||||||
|
|
||||||
// description
|
// description
|
||||||
Optional.ofNullable(state.getM()).map((m) -> m.getTopic()).ifPresent((topic) -> {
|
Optional.ofNullable(state.getM()).map(Model::getTopic).ifPresent(topic -> {
|
||||||
try {
|
try {
|
||||||
setDescription(URLDecoder.decode(topic, "utf-8"));
|
setDescription(URLDecoder.decode(topic, "utf-8"));
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
@ -284,14 +285,14 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
viewerCount = Optional.ofNullable(state.getM()).map((m) -> m.getRc()).orElseGet(() -> 0);
|
viewerCount = Optional.ofNullable(state.getM()).map(Model::getRc).orElse(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getLivePreviewUrl(SessionState state) {
|
private String getLivePreviewUrl(SessionState state) {
|
||||||
String previewUrl;
|
String previewUrl;
|
||||||
int userChannel = 100000000 + state.getUid();
|
int userChannel = 100000000 + state.getUid();
|
||||||
int camserv = state.getU().getCamserv();
|
int camserv = state.getU().getCamserv();
|
||||||
String server = Integer.toString(camserv);
|
String server;
|
||||||
ServerConfig sc = ((MyFreeCams)site).getClient().getServerConfig();
|
ServerConfig sc = ((MyFreeCams)site).getClient().getServerConfig();
|
||||||
if(sc.isOnNgServer(state)) {
|
if(sc.isOnNgServer(state)) {
|
||||||
server = sc.ngVideoServers.get(Integer.toString(camserv));
|
server = sc.ngVideoServers.get(Integer.toString(camserv));
|
||||||
|
@ -348,4 +349,13 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
public void writeSiteSpecificData(JsonWriter writer) throws IOException {
|
public void writeSiteSpecificData(JsonWriter writer) throws IOException {
|
||||||
writer.name("uid").value(uid);
|
writer.name("uid").value(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Download createDownload() {
|
||||||
|
if(streamUrl.endsWith("m3u8")) {
|
||||||
|
return super.createDownload();
|
||||||
|
} else {
|
||||||
|
return new DashDownload(getSite().getHttpClient(), streamUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,9 +65,16 @@ public class ServerConfig {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOnNgServer(SessionState state) {
|
public boolean isOnHtml5VideoServer(SessionState state) {
|
||||||
int camserv = Objects.requireNonNull(Objects.requireNonNull(state.getU()).getCamserv());
|
int camserv = Objects.requireNonNull(Objects.requireNonNull(state.getU()).getCamserv());
|
||||||
return ngVideoServers.containsKey(Integer.toString(camserv));
|
return isOnObsServer(state)
|
||||||
|
|| h5Servers.containsKey(Integer.toString(camserv))
|
||||||
|
|| (camserv >= 904 && camserv <= 915
|
||||||
|
|| camserv >= 938 && camserv <= 960);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOnObsServer(SessionState state) {
|
||||||
|
return isOnWzObsVideoServer(state) || isOnNgServer(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOnWzObsVideoServer(SessionState state) {
|
public boolean isOnWzObsVideoServer(SessionState state) {
|
||||||
|
@ -75,8 +82,8 @@ public class ServerConfig {
|
||||||
return wzobsServers.containsKey(Integer.toString(camserv));
|
return wzobsServers.containsKey(Integer.toString(camserv));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOnHtml5VideoServer(SessionState state) {
|
public boolean isOnNgServer(SessionState state) {
|
||||||
int camserv = Objects.requireNonNull(Objects.requireNonNull(state.getU()).getCamserv());
|
int camserv = Objects.requireNonNull(Objects.requireNonNull(state.getU()).getCamserv());
|
||||||
return h5Servers.containsKey(Integer.toString(camserv)) || (camserv >= 904 && camserv <= 915 || camserv >= 940 && camserv <= 960);
|
return ngVideoServers.containsKey(Integer.toString(camserv));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue