Skip to content

Commit

Permalink
1.4.1 <=> Edge cases related to IMDB badges fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
mynttt committed Aug 21, 2020
1 parent bd3acf0 commit f548c60
Show file tree
Hide file tree
Showing 10 changed files with 12,709 additions and 23 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 1.4.1
- handle edge cases regarding imdb badges

## 1.4.0
- support for new plex movie agent (will only work on libraries that have the IMDB setting set and the external ids downloaded from plex metadata servers after refreshing the library again)

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.4.0
1.4.1
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plugins {
id 'com.github.spotbugs' version '2.0.1'
}

version = '1.4.0'
version = '1.4.1'
sourceCompatibility = '11'

new File(projectDir, "VERSION").text = version;
Expand All @@ -31,6 +31,9 @@ dependencies {
implementation group: 'de.mynttt', name: 'ezconf', version: '1.1.0'

compileOnly group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: '3.1.12'

testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.5.2'
}

run {
Expand Down
110 changes: 110 additions & 0 deletions src/main/java/updatetool/common/ExtraData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package updatetool.common;

import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.annotation.concurrent.NotThreadSafe;
import org.tinylog.Logger;

@NotThreadSafe
public final class ExtraData {
private Map<String, String> mapping = new LinkedHashMap<>();

private ExtraData() {}

public boolean contains(Pair<String, String> mapping) {
String v = this.mapping.get(mapping.getKey());
if(Objects.equals(v, mapping.getValue()))
return true;
return false;
}

public boolean containsAny(List<Pair<String, String>> mapping) {
for(var kv : mapping) {
if(contains(kv))
return true;
}
return false;
}

public boolean containsKey(String key) {
return mapping.containsKey(key);
}

public void deleteKey(String key) {
mapping.remove(key);
}

public void prepend(String key, String value) {
var map = new LinkedHashMap<String, String>();
map.put(key, value);
mapping.remove(key);
map.putAll(mapping);
this.mapping = map;
}

public String toURI() {
if(mapping.isEmpty())
return "";

StringBuilder sb = new StringBuilder();
for(var entry : mapping.entrySet()) {
sb.append(handlePlexEncoding(entry.getKey()));
sb.append("=");
sb.append(handlePlexEncoding(entry.getValue()));
sb.append("&");
}
sb.deleteCharAt(sb.length()-1);

return sb.toString();
}

private String handlePlexEncoding(String s) {
// Plex has some interesting encoding behavior that does not match with the java default implementation
return URLEncoder.encode(s, StandardCharsets.UTF_8)
.replaceAll("\\.", "%2E")
.replaceAll("\\%2D", "-")
.replaceAll("\\_", "%5F")
.replaceAll("\\*", "%2A")
.replaceAll("\\%7E", "~");
}

public static ExtraData of(String uri) {
ExtraData u = new ExtraData();

if(uri != null) {
String[] components = uri.split("\\&");
for(String pair : components) {
if(pair.isBlank())
continue;
String[] kv = pair.split("\\=");

String key, value;

if(kv.length > 2) {
Logger.warn("ParsedURI: Encountered more than 2 K/V entries. Garbage date or bug? ({})", uri);
continue;
} else if(kv.length == 1) {
key = kv[0].trim();
value = "";
} else {
key = kv[0].trim();
value = kv[1].trim();
}

u.mapping.put(URLDecoder.decode(key, StandardCharsets.UTF_8), URLDecoder.decode(value, StandardCharsets.UTF_8));
}
}

return u;
}

@Override
public String toString() {
return "ExtraData [mapping=" + mapping + "]";
}
}
44 changes: 44 additions & 0 deletions src/main/java/updatetool/common/Pair.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package updatetool.common;

import java.util.Objects;

public final class Pair<K, V> {
private final K key;
private final V value;

private Pair(K key, V value) {
this.key = key;
this.value = value;
}

public K getKey() {
return key;
}

public V getValue() {
return value;
}

public static <K, V> Pair<K, V> of(K key, V value) {
Objects.requireNonNull(key, "key must not be null");
return new Pair<>(key, value);
}

@Override
public int hashCode() {
return Objects.hash(key, value);
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
@SuppressWarnings("rawtypes")
Pair other = (Pair) obj;
return Objects.equals(key, other.key) && Objects.equals(value, other.value);
}
}
3 changes: 2 additions & 1 deletion src/main/java/updatetool/imdb/ImdbPipeline.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.xml.parsers.DocumentBuilderFactory;
Expand Down Expand Up @@ -147,7 +148,7 @@ public void accumulateMetadata(ImdbJob job) throws Exception {
public void transformMetadata(ImdbJob job) throws Exception {
var map = new HashMap<ImdbMetadataResult, ExportedRating>();
job.items.forEach(i -> map.put(i, dataset.getRatingFor(i.imdbId)));
var noUpdate = map.entrySet().stream().filter(ImdbTransformer::needsNoUpdate).collect(Collectors.toSet());
var noUpdate = map.entrySet().stream().filter(Predicate.not(ImdbTransformer::needsUpdate)).collect(Collectors.toSet());
if(!noUpdate.isEmpty()) {
Logger.info(noUpdate.size() + " item(s) need no update.");
for(var item : noUpdate) {
Expand Down
48 changes: 29 additions & 19 deletions src/main/java/updatetool/imdb/ImdbTransformer.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,26 @@

import static updatetool.common.Utility.areEqualDouble;
import static updatetool.common.Utility.doubleToOneDecimalString;
import java.util.List;
import java.util.Map;
import org.tinylog.Logger;
import updatetool.api.ExportedRating;
import updatetool.common.ExtraData;
import updatetool.common.Pair;
import updatetool.imdb.ImdbDatabaseSupport.ImdbMetadataResult;

public class ImdbTransformer {
private static final String IMDB_FLAG_EMPTY = "at%3AratingImage=imdb%3A%2F%2Fimage%2Erating";
private static final String IMDB_FLAG = "at%3AratingImage=imdb%3A%2F%2Fimage%2Erating&";

private static final String N_RT_FLAG = "at%3AaudienceRatingImage=rottentomatoes%3A%2F%2Fimage%2Erating%2Eupright&at%3AratingImage=rottentomatoes%3A%2F%2Fimage%2Erating%2Eripe";
private static final String N_IMDB_FLAG_EMPTY = "at%3AaudienceRatingImage=imdb%3A%2F%2Fimage%2Erating";
private static final String N_IMDB_FLAG = "at%3AaudienceRatingImage=imdb%3A%2F%2Fimage%2Erating&";
private static final Pair<String, String>
NEW_TMDB = Pair.of("at:audienceRatingImage", "themoviedb://image.rating"),
NEW_IMDB = Pair.of("at:audienceRatingImage", "imdb://image.rating"),
ROTTEN_A = Pair.of("at:audienceRatingImage", "rottentomatoes://image.rating.upright"),
ROTTEN_R = Pair.of("at:ratingImage", "rottentomatoes://image.rating.ripe"),
OLD_IMDB = Pair.of("at:ratingImage", "imdb://image.rating");

public static boolean needsNoUpdate(Map.Entry<ImdbMetadataResult, ExportedRating> check) {
private static final List<Pair<String, String>> STRIP = List.of(NEW_TMDB, ROTTEN_A, ROTTEN_R);

public static boolean needsUpdate(Map.Entry<ImdbMetadataResult, ExportedRating> check) {
var meta = check.getKey();
var imdb = check.getValue();
double d = 0;
Expand All @@ -30,9 +36,12 @@ public static boolean needsNoUpdate(Map.Entry<ImdbMetadataResult, ExportedRating
boolean isNewMovieAgent = meta.guid.startsWith("plex://movie/");
Double actualRating = isNewMovieAgent ? meta.audienceRating : meta.rating;

return actualRating != null
&& areEqualDouble(actualRating, d, 3)
&& (isNewMovieAgent ? meta.extraData.contains("audienceRatingImage=imdb") : meta.extraData.contains("ratingImage=imdb"));
ExtraData e = ExtraData.of(meta.extraData);

return actualRating == null
|| !areEqualDouble(actualRating, d, 3)
|| !e.contains(isNewMovieAgent ? NEW_IMDB : OLD_IMDB)
|| e.containsAny(STRIP);
}

public static void updateMetadata(Map.Entry<ImdbMetadataResult, ExportedRating> target) {
Expand All @@ -53,18 +62,19 @@ public static void updateMetadata(Map.Entry<ImdbMetadataResult, ExportedRating>
}
}

if(isNewMovieAgent && meta.extraData.contains(N_RT_FLAG)) {
meta.extraData = meta.extraData.replace(N_RT_FLAG, N_IMDB_FLAG_EMPTY);
ExtraData extra = ExtraData.of(meta.extraData);

if(extra.containsAny(STRIP)) {
Logger.info("(Remove) Stripping useless badge data (RT, TMDB) for: {}", meta.title);
STRIP.forEach(p -> extra.deleteKey(p.getKey()));
}

if(!meta.extraData.contains(isNewMovieAgent ? "audienceRatingImage=imdb" : "ratingImage=imdb")) {
if(meta.extraData.trim().isEmpty()) {
Logger.info("(Set) Set IMDB Badge for: " + meta.title);
meta.extraData = isNewMovieAgent ? N_IMDB_FLAG_EMPTY : IMDB_FLAG_EMPTY;
} else {
Logger.info("(Prepend) Set IMDB Badge for: " + meta.title);
meta.extraData = isNewMovieAgent ? (N_IMDB_FLAG+meta.extraData) : (IMDB_FLAG+meta.extraData);
}
var targetBadge = isNewMovieAgent ? NEW_IMDB : OLD_IMDB;
if(!extra.contains(targetBadge)) {
Logger.info("(Set) Set IMDB Badge for: {}", meta.title);
extra.prepend(targetBadge.getKey(), targetBadge.getValue());
}

meta.extraData = extra.toURI();
}
}
2 changes: 1 addition & 1 deletion src/main/resources/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.4.0
1.4.1
18 changes: 18 additions & 0 deletions src/test/java/URITest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.junit.jupiter.api.Test;
import updatetool.common.ExtraData;

public class URITest {

@Test
public void testUriEncoding() throws IOException, URISyntaxException {
Files.lines(Paths.get(getClass().getResource("/uritestdata.txt").toURI())).forEach(l -> {
ExtraData e = ExtraData.of(l);
assertEquals(l, e.toURI());
});
}
}
Loading

0 comments on commit f548c60

Please sign in to comment.