diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b7f680ff4..bce04cb228 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ - **FEATURE(Linux):** Für exotische Window Manager können nun die FlatLaf-Dekorationen mittels `-dfd` oder `--disable-flatlaf-decorations` Parametern deaktiviert werden. - **FEATURE:** Info-Datei kann nun per Kontextmenü für jeden Eintrag manuell erzeugt werden. - **FEATURE:** Die Filmliste wird nun beim Laden zusätzlich auf Duplikate untersucht. Hierbei werden die Mediatheken der ARD und ZDF erst am Ende berücksichtigt um das Angebot der "kleineren" Sender nicht zu benachteiligen. -- **FEATURE:** Duplikate werden im Tab `Filme` farblich hervorgehoben. Die Farbe kann in den Einstellungen modifiziert werden. +- **FEATURE:** Duplikate werden im Tab `Filme` farblich hervorgehoben. Die Farbe kann in den Einstellungen modifiziert werden. Es werden nur Filme als Duplikat markiert, deren normale und high-quality Film-URL identisch sind. - **FEATURE:** Im Tab `Filme` können über das Kontextmenü `Zusammengehörige Filme anzeigen...` bei einem markierten Duplikat alle zusammenghörigen Filme angezeigt werden. - **FEATURE:** Mittels `Ansicht/Filmstatistik anzeigen` können nun für die vorhandenen Sender Informationen bzgl. Anzahl der Filme und der Duplikate angezeigt werden. Es wird hier nur die gesamte Filmliste ohne jegliche Filter abzüglich Livestreams berücksichtigt, so dass es zu Abweichungen zur Anzeige in der Statuszeile kommen kann. - **FEATURE:** Mit der Lucene-Suche können mittels des `duplicate`-Boolean Parameters Filmduplikate berücksichtigt werden. diff --git a/src/main/java/mediathek/daten/DatenFilm.java b/src/main/java/mediathek/daten/DatenFilm.java index 0505522b65..f8705c31df 100644 --- a/src/main/java/mediathek/daten/DatenFilm.java +++ b/src/main/java/mediathek/daten/DatenFilm.java @@ -66,7 +66,6 @@ public class DatenFilm implements Comparable { */ private DatumFilm datumFilm = DatumFilm.UNDEFINED_FILM_DATE; private String description; - private String datumLong = ""; private String sender = ""; private String thema = ""; private String titel = ""; @@ -85,7 +84,6 @@ public DatenFilm(@NotNull DatenFilm other) { this.datumFilm = other.datumFilm; this.filmSize.setSize(other.filmSize.toString()); this.description = other.description; - this.datumLong = other.datumLong; this.sender = other.sender; this.thema = other.thema; this.titel = other.titel; @@ -177,16 +175,24 @@ public String getHighQualityUrl() { public void setHighQualityUrl(@NotNull String urlHd) { if (urlHd.isEmpty()) dataMap.remove(MapKeys.HIGH_QUALITY_URL); - else + else { + if (isCompressedUrl(urlHd)) { + urlHd = decompressUrl(urlHd); + } dataMap.put(MapKeys.HIGH_QUALITY_URL, urlHd); - } - - public String getDatumLong() { - return datumLong; + } } public void setDatumLong(String datumLong) { - this.datumLong = datumLong; + long datum_long; + try { + datum_long = Long.parseLong(datumLong); + } + catch (Exception e) { + logger.error("Failed to parse datum long string", e); + datum_long = 0; + } + dataMap.put(MapKeys.TEMP_DATUM_LONG, datum_long); } public boolean isTrailerTeaser() { @@ -411,23 +417,22 @@ public int compareTo(@NotNull DatenFilm other) { return ret; } - private void setDatum() { + private void setupDatumFilm() { if (!getSendeDatum().isEmpty()) { // nur dann gibts ein Datum - try { - final long l = Long.parseLong(getDatumLong()); - datumFilm = new DatumFilm(l * 1000); // sind SEKUNDEN!! - } catch (Exception ex) { - logger.error("Datum: {}, Zeit: {}, Datum_LONG: {}", getSendeDatum(), getSendeZeit(), getDatumLong(), ex); - datumFilm = new DatumFilm(0); + long datum_long = (long)dataMap.getOrDefault(MapKeys.TEMP_DATUM_LONG, 0); + datumFilm = new DatumFilm(datum_long * 1000); // convert from SECONDS to MILLISECONDS + if (datum_long == 0) + { setSendeDatum(""); setSendeZeit(""); } } + dataMap.remove(MapKeys.TEMP_DATUM_LONG); } public void init() { - setDatum(); + setupDatumFilm(); } /** @@ -586,5 +591,9 @@ public boolean isBookmarked() { return dataMap.containsKey(MapKeys.BOOKMARK_DATA); } - enum MapKeys {FILM_NR, SUBTITLE_URL, WEBSITE_URL, LOW_QUALITY_URL, NORMAL_QUALITY_URL, HIGH_QUALITY_URL, BOOKMARK_DATA, ABO_DATA} + enum MapKeys {FILM_NR, SUBTITLE_URL, WEBSITE_URL, LOW_QUALITY_URL, NORMAL_QUALITY_URL, HIGH_QUALITY_URL, + BOOKMARK_DATA, + ABO_DATA, + TEMP_DATUM_LONG + } } diff --git a/src/main/java/mediathek/filmlisten/writer/FilmListWriter.java b/src/main/java/mediathek/filmlisten/writer/FilmListWriter.java index 21f586fde1..5eadc490e1 100644 --- a/src/main/java/mediathek/filmlisten/writer/FilmListWriter.java +++ b/src/main/java/mediathek/filmlisten/writer/FilmListWriter.java @@ -152,7 +152,7 @@ private void writeEntry(DatenFilm datenFilm, JsonGenerator jg) throws IOExceptio skipEntry(jg); //DatenFilm.URL_RTMP_KLEIN writeHighQualityUrl(jg, datenFilm); skipEntry(jg); //DatenFilm.FILM_URL_RTMP_HD - jg.writeString(datenFilm.getDatumLong()); + jg.writeString(String.valueOf(datenFilm.getDatumFilm().getTime() / 1000)); skipEntry(jg); //DatenFilm.FILM_URL_HISTORY if (datenFilm.countrySet.isEmpty()) jg.writeString(""); diff --git a/src/main/java/mediathek/gui/duplicates/FilmDuplicateEvaluationTask.java b/src/main/java/mediathek/gui/duplicates/FilmDuplicateEvaluationTask.java index 86cea2f95f..8b15d67f69 100644 --- a/src/main/java/mediathek/gui/duplicates/FilmDuplicateEvaluationTask.java +++ b/src/main/java/mediathek/gui/duplicates/FilmDuplicateEvaluationTask.java @@ -3,12 +3,14 @@ import ca.odell.glazedlists.TransactionList; import com.google.common.base.Stopwatch; import com.google.common.collect.Sets; +import com.google.common.hash.Hashing; import mediathek.config.Daten; import mediathek.daten.DatenFilm; import mediathek.daten.ListeFilme; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.nio.charset.StandardCharsets; import java.util.Comparator; import java.util.Map; import java.util.Set; @@ -46,17 +48,23 @@ private void printDuplicateStatistics() { private void checkDuplicates() { logger.trace("Start Duplicate URL search"); - final Set urlCache = Sets.newConcurrentHashSet(); + final Set urlCache = Sets.newConcurrentHashSet(); + var hf = Hashing.murmur3_128(); Stopwatch watch = Stopwatch.createStarted(); listeFilme.stream() .filter(f -> !f.isLivestream()) .sorted(new BigSenderPenaltyComparator()) .forEach(film -> { - final var url = film.getUrlNormalQuality(); - film.setDuplicate(urlCache.contains(url)); - urlCache.add(url); - }); + final var hc = hf.newHasher() + .putString(film.getUrlNormalQuality(), StandardCharsets.UTF_8) + .putString(film.getHighQualityUrl(), StandardCharsets.UTF_8) + .hash(); + final var hash = hc.padToLong(); + + film.setDuplicate(urlCache.contains(hash)); + urlCache.add(hash); + }); watch.stop(); logger.trace("Duplicate URL search took: {}", watch); urlCache.clear();