From 0417fd6bfb66ffc11c17eda39074a887485011da Mon Sep 17 00:00:00 2001 From: 0xboobface <0xboobface@gmail.com> Date: Wed, 23 Jan 2019 18:27:34 +0100 Subject: [PATCH 1/5] Remove guest session cookies on start for LiveJasmin --- .../main/java/ctbrec/io/CookieJarImpl.java | 23 +++++++++++++++---- .../sites/jasmin/LiveJasminHttpClient.java | 12 ++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/common/src/main/java/ctbrec/io/CookieJarImpl.java b/common/src/main/java/ctbrec/io/CookieJarImpl.java index 324fb93a..add7b643 100644 --- a/common/src/main/java/ctbrec/io/CookieJarImpl.java +++ b/common/src/main/java/ctbrec/io/CookieJarImpl.java @@ -34,7 +34,7 @@ public class CookieJarImpl implements CookieJar { String name = oldCookie.name(); for (Cookie newCookie : cookies) { if(newCookie.name().equalsIgnoreCase(name)) { - LOG.debug("Replacing cookie {} {} -> {} [{}]", oldCookie.name(), oldCookie.value(), newCookie.value(), oldCookie.domain()); + LOG.trace("Replacing cookie {} {} -> {} [{}]", oldCookie.name(), oldCookie.value(), newCookie.value(), oldCookie.domain()); iterator.remove(); break; } @@ -42,11 +42,11 @@ public class CookieJarImpl implements CookieJar { } cookiesForUrl.addAll(cookies); cookieStore.put(host, cookiesForUrl); - LOG.debug("Adding cookie: {} for {}", cookiesForUrl, host); + LOG.trace("Adding cookie: {} for {}", cookiesForUrl, host); } else { cookieStore.put(host, cookies); - LOG.debug("Storing cookie: {} for {}", cookies, host); + LOG.trace("Storing cookie: {} for {}", cookies, host); } } @@ -54,9 +54,9 @@ public class CookieJarImpl implements CookieJar { public List loadForRequest(HttpUrl url) { String host = getDomain(url); List cookies = cookieStore.get(host); - LOG.debug("Cookies for {}", url); + LOG.trace("Cookies for {}", url); Optional.ofNullable(cookies).ifPresent(cookiez -> cookiez.forEach(c -> { - LOG.debug(" {} expires on:{}", c, c.expiresAt()); + LOG.trace(" {} expires on:{}", c, c.expiresAt()); })); //LOG.debug("Cookies for {}: {}", url.host(), cookies); return cookies != null ? cookies : new ArrayList(); @@ -72,6 +72,19 @@ public class CookieJarImpl implements CookieJar { throw new NoSuchElementException("No cookie named " + name + " for " + url.host() + " available"); } + public void deleteCookie(HttpUrl url, String name) { + List cookies = loadForRequest(url); + for (Iterator iterator = cookies.iterator(); iterator.hasNext();) { + Cookie cookie = iterator.next(); + if(Objects.equals(cookie.name(), name)) { + iterator.remove(); + LOG.debug("Removed cookie \"{}\" for {}", name, url.toString()); + return; + } + } + throw new NoSuchElementException("No cookie named " + name + " for " + url.host() + " available"); + } + private String getDomain(HttpUrl url) { // String host = url.host(); // if (host.startsWith("www.")) { diff --git a/common/src/main/java/ctbrec/sites/jasmin/LiveJasminHttpClient.java b/common/src/main/java/ctbrec/sites/jasmin/LiveJasminHttpClient.java index 98c77107..dd625e90 100644 --- a/common/src/main/java/ctbrec/sites/jasmin/LiveJasminHttpClient.java +++ b/common/src/main/java/ctbrec/sites/jasmin/LiveJasminHttpClient.java @@ -20,6 +20,18 @@ public class LiveJasminHttpClient extends HttpClient { protected LiveJasminHttpClient() { super("livejasmin"); + + // delete session, if we are guests, because old guest sessions cause + // endless redirects + if(Config.getInstance().getSettings().livejasminUsername.isEmpty()) { + HttpUrl url = HttpUrl.parse("https://" + LiveJasmin.baseDomain); + try { + getCookieJar().deleteCookie(url, "session"); + } catch (NoSuchElementException e) { + LOG.debug("Session cookie not found -> let's go!"); + // fine, no session cookie means we are good to go + } + } } @Override From aa093c0ec1185c4167ef39da03880c9125d22271 Mon Sep 17 00:00:00 2001 From: 0xboobface <0xboobface@gmail.com> Date: Thu, 24 Jan 2019 15:47:26 +0100 Subject: [PATCH 2/5] Delete all LiveJasmin cookies, if we are guests --- .../java/ctbrec/sites/jasmin/LiveJasminHttpClient.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/common/src/main/java/ctbrec/sites/jasmin/LiveJasminHttpClient.java b/common/src/main/java/ctbrec/sites/jasmin/LiveJasminHttpClient.java index dd625e90..00800c10 100644 --- a/common/src/main/java/ctbrec/sites/jasmin/LiveJasminHttpClient.java +++ b/common/src/main/java/ctbrec/sites/jasmin/LiveJasminHttpClient.java @@ -21,16 +21,10 @@ public class LiveJasminHttpClient extends HttpClient { protected LiveJasminHttpClient() { super("livejasmin"); - // delete session, if we are guests, because old guest sessions cause + // delete all cookies, if we are guests, because old guest sessions cause // endless redirects if(Config.getInstance().getSettings().livejasminUsername.isEmpty()) { - HttpUrl url = HttpUrl.parse("https://" + LiveJasmin.baseDomain); - try { - getCookieJar().deleteCookie(url, "session"); - } catch (NoSuchElementException e) { - LOG.debug("Session cookie not found -> let's go!"); - // fine, no session cookie means we are good to go - } + getCookieJar().clear(); } } From 6fcdce673d9d1194abb469fd32d47623aa8f2745 Mon Sep 17 00:00:00 2001 From: 0xboobface <0xboobface@gmail.com> Date: Thu, 24 Jan 2019 15:52:25 +0100 Subject: [PATCH 3/5] Show error message on Followed tab, if credentials are missing --- .../ui/sites/jasmin/LiveJasminFollowedUpdateService.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedUpdateService.java b/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedUpdateService.java index ecbd0066..4c1ae667 100644 --- a/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedUpdateService.java +++ b/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedUpdateService.java @@ -38,6 +38,10 @@ public class LiveJasminFollowedUpdateService extends PaginatedScheduledService { return new Task>() { @Override public List call() throws IOException { + if(!liveJasmin.credentialsAvailable()) { + throw new RuntimeException("Credentials missing"); + } + boolean loggedIn = SiteUiFactory.getUi(liveJasmin).login(); if(!loggedIn) { throw new RuntimeException("Couldn't login to livejasmin"); From d346270da2ce78997056e29de46078f032f9ee50 Mon Sep 17 00:00:00 2001 From: 0xboobface <0xboobface@gmail.com> Date: Thu, 24 Jan 2019 17:36:23 +0100 Subject: [PATCH 4/5] Show the number of active recordings in the window title Use the event system to show the number of active recordings in the window title. Requested in #155. --- .../java/ctbrec/ui/CamrecApplication.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/client/src/main/java/ctbrec/ui/CamrecApplication.java b/client/src/main/java/ctbrec/ui/CamrecApplication.java index 0e8cf692..057915aa 100644 --- a/client/src/main/java/ctbrec/ui/CamrecApplication.java +++ b/client/src/main/java/ctbrec/ui/CamrecApplication.java @@ -17,13 +17,16 @@ import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.eventbus.Subscribe; import com.squareup.moshi.JsonAdapter; import com.squareup.moshi.Moshi; import com.squareup.moshi.Types; import ctbrec.Config; +import ctbrec.Model; import ctbrec.StringUtil; import ctbrec.Version; +import ctbrec.event.Event; import ctbrec.event.EventBusHolder; import ctbrec.event.EventHandler; import ctbrec.event.EventHandlerConfiguration; @@ -69,9 +72,11 @@ public class CamrecApplication extends Application { private List sites = new ArrayList<>(); public static HttpClient httpClient; public static String title; + private Stage primaryStage; @Override public void start(Stage primaryStage) throws Exception { + this.primaryStage = primaryStage; logEnvironment(); sites.add(new BongaCams()); sites.add(new Cam4()); @@ -82,6 +87,7 @@ public class CamrecApplication extends Application { sites.add(new Streamate()); loadConfig(); registerAlertSystem(); + registerActiveRecordingsCounter(); createHttpClient(); hostServices = getHostServices(); createRecorder(); @@ -238,6 +244,24 @@ public class CamrecApplication extends Application { }).start(); } + private void registerActiveRecordingsCounter() { + EventBusHolder.BUS.register(new Object() { + @Subscribe + public void handleEvent(Event evt) { + if(evt.getType() == Event.Type.MODEL_STATUS_CHANGED || evt.getType() == Event.Type.RECORDING_STATUS_CHANGED) { + try { + List models = recorder.getOnlineModels(); + long count = models.stream().filter(m -> !recorder.isSuspended(m)).count(); + String _title = count > 0 ? "(" + count + ") " + title : title; + Platform.runLater(() -> primaryStage.setTitle(_title)); + } catch (Exception e) { + LOG.warn("Couldn't update window title", e); + } + } + } + }); + } + private void writeColorSchemeStyleSheet(Stage primaryStage) { File colorCss = new File(Config.getInstance().getConfigDir(), "color.css"); try(FileOutputStream fos = new FileOutputStream(colorCss)) { From a91819c2ca15cbdca03651763abe0a5b01f5a3ce Mon Sep 17 00:00:00 2001 From: 0xboobface <0xboobface@gmail.com> Date: Thu, 24 Jan 2019 19:00:02 +0100 Subject: [PATCH 5/5] Extend the recording name to include seconds and milliseconds This is necessary, because there are models, who stream on different sites with the same name as mentioned in #141. In that case it can happen that a recording for each site would be started within the same minute and one recording would overwrite the other. --- common/src/main/java/ctbrec/Config.java | 5 +++-- .../main/java/ctbrec/recorder/LocalRecorder.java | 13 ++++++------- .../java/ctbrec/recorder/download/HlsDownload.java | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/common/src/main/java/ctbrec/Config.java b/common/src/main/java/ctbrec/Config.java index 9170a5f1..085ab8ba 100644 --- a/common/src/main/java/ctbrec/Config.java +++ b/common/src/main/java/ctbrec/Config.java @@ -33,6 +33,7 @@ public class Config { private String filename; private List sites; private File configDir; + public static final String RECORDING_DATE_FORMAT = "yyyy-MM-dd_HH-mm-ss_SSS"; private Config(List sites) throws FileNotFoundException, IOException { this.sites = sites; @@ -134,7 +135,7 @@ public class Config { public File getFileForRecording(Model model) { File dirForRecording = getDirForRecording(model); - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm"); + SimpleDateFormat sdf = new SimpleDateFormat(RECORDING_DATE_FORMAT); String startTime = sdf.format(new Date()); File targetFile = new File(dirForRecording, model.getName() + '_' + startTime + ".ts"); return targetFile; @@ -146,7 +147,7 @@ public class Config { return new File(getSettings().recordingsDir, model.getName()); case ONE_PER_RECORDING: File modelDir = new File(getSettings().recordingsDir, model.getName()); - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm"); + SimpleDateFormat sdf = new SimpleDateFormat(RECORDING_DATE_FORMAT); String startTime = sdf.format(new Date()); return new File(modelDir, startTime); case FLAT: diff --git a/common/src/main/java/ctbrec/recorder/LocalRecorder.java b/common/src/main/java/ctbrec/recorder/LocalRecorder.java index 52b49b6f..914f2335 100644 --- a/common/src/main/java/ctbrec/recorder/LocalRecorder.java +++ b/common/src/main/java/ctbrec/recorder/LocalRecorder.java @@ -66,7 +66,6 @@ public class LocalRecorder implements Recorder { private static final transient Logger LOG = LoggerFactory.getLogger(LocalRecorder.class); private static final boolean IGNORE_CACHE = true; - private static final String DATE_FORMAT = "yyyy-MM-dd_HH-mm"; private List models = Collections.synchronizedList(new ArrayList<>()); private Map recordingProcesses = Collections.synchronizedMap(new HashMap<>()); @@ -466,17 +465,17 @@ public class LocalRecorder implements Recorder { private List listMergedRecordings() { File recordingsDir = new File(config.getSettings().recordingsDir); List possibleRecordings = new LinkedList<>(); - listRecursively(recordingsDir, possibleRecordings, (dir, name) -> name.matches(".*?_\\d{4}-\\d{2}-\\d{2}_\\d{2}-\\d{2}\\.(ts|mp4)")); - SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT); + listRecursively(recordingsDir, possibleRecordings, (dir, name) -> name.matches(".*?_\\d{4}-\\d{2}-\\d{2}_\\d{2}-\\d{2}-\\d{2}_\\d{3}\\.(ts|mp4)")); + SimpleDateFormat sdf = new SimpleDateFormat(Config.RECORDING_DATE_FORMAT); List recordings = new ArrayList<>(); for (File ts: possibleRecordings) { try { String filename = ts.getName(); int extLength = filename.length() - filename.lastIndexOf('.'); - String dateString = filename.substring(filename.length() - extLength - DATE_FORMAT.length(), filename.length() - extLength); + String dateString = filename.substring(filename.length() - extLength - Config.RECORDING_DATE_FORMAT.length(), filename.length() - extLength); Date startDate = sdf.parse(dateString); Recording recording = new Recording(); - recording.setModelName(filename.substring(0, filename.length() - extLength - 1 - DATE_FORMAT.length())); + recording.setModelName(filename.substring(0, filename.length() - extLength - 1 - Config.RECORDING_DATE_FORMAT.length())); recording.setStartDate(Instant.ofEpochMilli(startDate.getTime())); String path = ts.getAbsolutePath().replace(config.getSettings().recordingsDir, ""); if(!path.startsWith("/")) { @@ -541,11 +540,11 @@ public class LocalRecorder implements Recorder { // start going over valid directories for (File rec : recordingsDirs) { - SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT); + SimpleDateFormat sdf = new SimpleDateFormat(Config.RECORDING_DATE_FORMAT); if (rec.isDirectory()) { try { // ignore directories, which are probably not created by ctbrec - if (rec.getName().length() != DATE_FORMAT.length()) { + if (rec.getName().length() != Config.RECORDING_DATE_FORMAT.length()) { continue; } // ignore empty directories diff --git a/common/src/main/java/ctbrec/recorder/download/HlsDownload.java b/common/src/main/java/ctbrec/recorder/download/HlsDownload.java index 9eef5d7c..11a0d67c 100644 --- a/common/src/main/java/ctbrec/recorder/download/HlsDownload.java +++ b/common/src/main/java/ctbrec/recorder/download/HlsDownload.java @@ -56,7 +56,7 @@ public class HlsDownload extends AbstractHlsDownload { running = true; startTime = Instant.now(); super.model = model; - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm"); + SimpleDateFormat sdf = new SimpleDateFormat(Config.RECORDING_DATE_FORMAT); String startTime = sdf.format(new Date()); Path modelDir = FileSystems.getDefault().getPath(config.getSettings().recordingsDir, model.getName()); downloadDir = FileSystems.getDefault().getPath(modelDir.toString(), startTime);