Started implementing a cache system

Signed-off-by: Louis Vallat <louis@louis-vallat.xyz>
This commit is contained in:
Louis Vallat 2020-10-28 16:14:58 +01:00
parent b781f735ca
commit 9c48d932d6
6 changed files with 139 additions and 68 deletions

View File

@ -17,15 +17,16 @@ CREATE TABLE IF NOT EXISTS properties
*/ */
CREATE TABLE IF NOT EXISTS films CREATE TABLE IF NOT EXISTS films
( (
id int GENERATED ALWAYS AS IDENTITY, id int GENERATED ALWAYS AS IDENTITY,
imdb_id varchar(10) NOT NULL, imdb_id varchar(10) NOT NULL,
title text NOT NULL, title text NOT NULL,
release_date date, year int,
film_type text NOT NULL, film_type text NOT NULL,
season int, season int,
episode int, episode int,
poster_link text, poster_link text,
PRIMARY KEY (id) PRIMARY KEY (id),
UNIQUE (imdb_id)
); );
/** /**
@ -48,11 +49,12 @@ CREATE TABLE IF NOT EXISTS languages
*/ */
CREATE TABLE IF NOT EXISTS subtitles CREATE TABLE IF NOT EXISTS subtitles
( (
id int GENERATED ALWAYS AS IDENTITY, id int GENERATED ALWAYS AS IDENTITY,
film_id int NOT NULL, film_id int NOT NULL,
language_id int NOT NULL, language_id int NOT NULL,
importer varchar(37), importer varchar(37),
imported_date timestamptz NOT NULL DEFAULT now(), importer_guild_id text,
imported_date timestamptz NOT NULL DEFAULT now(),
UNIQUE (film_id, language_id), UNIQUE (film_id, language_id),
PRIMARY KEY (id), PRIMARY KEY (id),
FOREIGN KEY (film_id) FOREIGN KEY (film_id)

View File

@ -11,10 +11,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import xyz.vallat.louis.commands.*; import xyz.vallat.louis.commands.*;
import xyz.vallat.louis.database.DBManager; import xyz.vallat.louis.database.FilmManager;
import xyz.vallat.louis.env.EnvironmentVariables; import xyz.vallat.louis.omdb.OMDBClient;
import xyz.vallat.louis.subtitles.OpenSubtitles;
import java.io.IOException;
import java.text.ParseException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -36,7 +37,9 @@ public class MovieQuoteBot {
commands.put("download", new Download(PREFIX + "download")); commands.put("download", new Download(PREFIX + "download"));
} }
public static void main(String[] args) { public static void main(String[] args) throws InterruptedException, ParseException, IOException {
OMDBClient.getMovie("Surrogates", false);
/*
DBManager.testConnection(); DBManager.testConnection();
DBManager.initDatabase(); DBManager.initDatabase();
OpenSubtitles.login(); OpenSubtitles.login();
@ -50,6 +53,7 @@ public class MovieQuoteBot {
})); }));
discordClient.onDisconnect().block(); discordClient.onDisconnect().block();
*/
} }
private static void registerDiscordCommands() { private static void registerDiscordCommands() {

View File

@ -67,11 +67,12 @@ public final class DBManager {
try (Statement stmt = connection.createStatement()) { try (Statement stmt = connection.createStatement()) {
String query = "CREATE TABLE IF NOT EXISTS subtitles\n" + String query = "CREATE TABLE IF NOT EXISTS subtitles\n" +
"(\n" + "(\n" +
" id int GENERATED ALWAYS AS IDENTITY,\n" + " id int GENERATED ALWAYS AS IDENTITY,\n" +
" film_id int NOT NULL,\n" + " film_id int NOT NULL,\n" +
" language_id int NOT NULL,\n" + " language_id int NOT NULL,\n" +
" importer varchar(37),\n" + " importer varchar(37),\n" +
" imported_date timestamptz NOT NULL DEFAULT now(),\n" + " importer_guild_id text,\n" +
" imported_date timestamptz NOT NULL DEFAULT now(),\n" +
" UNIQUE (film_id, language_id),\n" + " UNIQUE (film_id, language_id),\n" +
" PRIMARY KEY (id),\n" + " PRIMARY KEY (id),\n" +
" FOREIGN KEY (film_id)\n" + " FOREIGN KEY (film_id)\n" +

View File

@ -7,7 +7,8 @@ import xyz.vallat.louis.database.exceptions.ImportationException;
import xyz.vallat.louis.omdb.objects.Movie; import xyz.vallat.louis.omdb.objects.Movie;
import java.sql.*; import java.sql.*;
import java.time.ZoneId;
import static java.sql.Statement.RETURN_GENERATED_KEYS;
public final class FilmManager { public final class FilmManager {
@ -21,15 +22,16 @@ public final class FilmManager {
try (Statement stmt = connection.createStatement()) { try (Statement stmt = connection.createStatement()) {
String query = "CREATE TABLE IF NOT EXISTS films\n" + String query = "CREATE TABLE IF NOT EXISTS films\n" +
"(\n" + "(\n" +
" id int GENERATED ALWAYS AS IDENTITY,\n" + " id int GENERATED ALWAYS AS IDENTITY,\n" +
" imdb_id varchar(10) NOT NULL,\n" + " imdb_id varchar(10) NOT NULL,\n" +
" title text NOT NULL,\n" + " title text NOT NULL,\n" +
" release_date date,\n" + " year int,\n" +
" film_type text NOT NULL,\n" + " film_type text NOT NULL,\n" +
" season int,\n" + " season int,\n" +
" episode int,\n" + " episode int,\n" +
" poster_link text,\n" + " poster_link text,\n" +
" PRIMARY KEY (id)\n" + " PRIMARY KEY (id),\n" +
" UNIQUE (imdb_id)\n" +
");"; ");";
stmt.executeUpdate(query); stmt.executeUpdate(query);
} }
@ -37,14 +39,17 @@ public final class FilmManager {
public static void importFilm(Movie movie) throws ImportationException { public static void importFilm(Movie movie) throws ImportationException {
try (Connection connection = DBManager.getConnection()) { try (Connection connection = DBManager.getConnection()) {
String insert = "INSERT INTO films(imdb_id, title, release_date, film_type, poster_link) VALUES(?, ?, ?, ?, ?);"; String insert = "INSERT INTO films(imdb_id, title, year, film_type, poster_link) VALUES(?, ?, ?, ?, ?);";
try (PreparedStatement stmt = connection.prepareStatement(insert)) { try (PreparedStatement stmt = connection.prepareStatement(insert, RETURN_GENERATED_KEYS)) {
stmt.setString(1, movie.getImdbID()); stmt.setString(1, movie.getImdbID());
stmt.setString(2, movie.getTitle()); stmt.setString(2, movie.getTitle());
stmt.setDate(3, Date.valueOf(movie.getReleased().atZone(ZoneId.systemDefault()).toLocalDate())); stmt.setObject(3, movie.getYear());
stmt.setString(4, movie.getType()); stmt.setString(4, movie.getType());
stmt.setString(5, movie.getPoster()); stmt.setString(5, movie.getPoster());
stmt.executeUpdate(); stmt.executeUpdate();
stmt.getGeneratedKeys().next();
movie.setId(stmt.getGeneratedKeys().getInt(1));
logger.debug("Movie inserted with id '{}'.", movie.getId());
} catch (SQLException e) { } catch (SQLException e) {
logger.error("Error while importing movie: {}", e.getMessage()); logger.error("Error while importing movie: {}", e.getMessage());
throw new ImportationException(); throw new ImportationException();
@ -55,4 +60,32 @@ public final class FilmManager {
} }
} }
public static Movie getMovieFromTitleOrImdbId(String value, boolean isId) {
Movie movie = null;
try (Connection connection = DBManager.getConnection()) {
String query = "SELECT id, imdb_id, title, year, film_type, poster_link " +
"FROM films WHERE " + (isId ? "imdb_id" : "title") + " = ?;";
try (PreparedStatement stmt = connection.prepareStatement(query)) {
stmt.setString(1, value);
stmt.execute();
ResultSet results = stmt.getResultSet();
if (results.next()) {
movie = new Movie(
results.getString("title"),
results.getString("imdb_id"),
results.getString("film_type"),
results.getString("poster_link")
);
movie.setId(results.getInt("id"));
if (results.getObject("year") != null)
movie.setYear(results.getInt("year"));
}
}
} catch (SQLException e) {
logger.error("Cannot connect or query to database right now. Reason: {}", e.getMessage());
System.exit(ExitCodes.CANNOT_CONNECT_TO_DB.getValue());
}
return movie;
}
} }

View File

@ -5,6 +5,8 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import xyz.vallat.louis.database.FilmManager;
import xyz.vallat.louis.database.exceptions.ImportationException;
import xyz.vallat.louis.env.EnvironmentVariables; import xyz.vallat.louis.env.EnvironmentVariables;
import xyz.vallat.louis.omdb.objects.Movie; import xyz.vallat.louis.omdb.objects.Movie;
@ -16,7 +18,6 @@ import java.net.http.HttpRequest;
import java.net.http.HttpResponse; import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -27,15 +28,14 @@ public final class OMDBClient {
private static final String API_KEY = System.getenv(EnvironmentVariables.OMDB_API_KEY.getValue()); private static final String API_KEY = System.getenv(EnvironmentVariables.OMDB_API_KEY.getValue());
private static final String IMDB_KEY = "imdbID"; private static final String IMDB_KEY = "imdbID";
private static final String TITLE_KEY = "Title"; private static final String TITLE_KEY = "Title";
private static final String RELEASED_KEY = "Released"; private static final String YEAR_KEY = "Year";
private static final String POSTER_KEY = "Poster"; private static final String POSTER_KEY = "Poster";
private static final String TYPE_KEY = "Type"; private static final String TYPE_KEY = "Type";
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd MMM yyyy");
private OMDBClient() { private OMDBClient() {
} }
public static List<Movie> searchMoviesByTitle(String name) throws IOException, InterruptedException, ParseException { public static List<Movie> searchMoviesByTitle(String name) throws IOException, InterruptedException {
logger.debug("Searching for '{}'.", name); logger.debug("Searching for '{}'.", name);
List<Movie> movies = new ArrayList<>(); List<Movie> movies = new ArrayList<>();
HttpRequest request = HttpRequest.newBuilder() HttpRequest request = HttpRequest.newBuilder()
@ -49,13 +49,14 @@ public final class OMDBClient {
for (JsonElement jsonElement : object.get("Search").getAsJsonArray()) { for (JsonElement jsonElement : object.get("Search").getAsJsonArray()) {
JsonObject jsonMovie = (JsonObject) jsonElement; JsonObject jsonMovie = (JsonObject) jsonElement;
if (jsonMovie.get(IMDB_KEY) == null || jsonMovie.get(TITLE_KEY) == null) continue; if (jsonMovie.get(IMDB_KEY) == null || jsonMovie.get(TITLE_KEY) == null) continue;
movies.add(new Movie( Movie movie = new Movie(
jsonMovie.get(TITLE_KEY).getAsString(), jsonMovie.get(TITLE_KEY).getAsString(),
DATE_FORMAT.parse(jsonMovie.get(RELEASED_KEY).getAsString()).toInstant(),
jsonMovie.get(IMDB_KEY).getAsString(), jsonMovie.get(IMDB_KEY).getAsString(),
jsonMovie.get(TYPE_KEY).getAsString(), jsonMovie.get(TYPE_KEY).getAsString(),
jsonMovie.get(POSTER_KEY).getAsString().equals("N/A") ? null : jsonMovie.get(POSTER_KEY).getAsString() jsonMovie.get(POSTER_KEY).getAsString().equals("N/A") ? null : jsonMovie.get(POSTER_KEY).getAsString()
)); );
movie.setYear(Integer.parseInt(jsonMovie.get(YEAR_KEY).getAsString().substring(0, 4)));
movies.add(movie);
} }
} else } else
logger.error("OMDB API returned an error: {}", object.get("Error").getAsString()); logger.error("OMDB API returned an error: {}", object.get("Error").getAsString());
@ -64,34 +65,52 @@ public final class OMDBClient {
return movies; return movies;
} }
public static Movie getMovie(String name, boolean id) throws IOException, InterruptedException, ParseException { public static Movie getMovie(String value, boolean isId) throws IOException, InterruptedException {
logger.debug("Getting movie by title '{}'.", name); logger.debug("Getting movie by title '{}'.", value);
Movie movie = null; Movie movie = FilmManager.getMovieFromTitleOrImdbId(value, isId);
if (movie != null) {
logger.debug("Found movie in database with id '{}'.", movie.getId());
return movie;
}
HttpRequest request = HttpRequest.newBuilder() HttpRequest request = HttpRequest.newBuilder()
.GET() .GET()
.uri(URI.create(ENDPOINT + "?apikey=" + API_KEY + "&type=movie" + .uri(URI.create(ENDPOINT + "?apikey=" + API_KEY + "&type=movie" +
"&" + (id ? "i" : "t") + "=" + URLEncoder.encode(name, StandardCharsets.UTF_8))) "&" + (isId ? "i" : "t") + "=" + URLEncoder.encode(value, StandardCharsets.UTF_8)))
.build(); .build();
HttpResponse<String> response = getHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); HttpResponse<String> response = getHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) { if (response.statusCode() == 200) {
JsonObject jsonMovie = JsonParser.parseString(response.body()).getAsJsonObject(); movie = getMovieFromJson(response.body());
if (jsonMovie.get("Response").getAsBoolean()) {
if (jsonMovie.get(IMDB_KEY) != null && jsonMovie.get(TITLE_KEY) != null) {
movie = new Movie(
jsonMovie.get(TITLE_KEY).getAsString(),
DATE_FORMAT.parse(jsonMovie.get(RELEASED_KEY).getAsString()).toInstant(),
jsonMovie.get(IMDB_KEY).getAsString(),
jsonMovie.get(TYPE_KEY).getAsString(),
jsonMovie.get(POSTER_KEY).getAsString().equals("N/A") ? null : jsonMovie.get(POSTER_KEY).getAsString()
);
}
} else
logger.error("OMDB API returned an error: {}", jsonMovie.get("Error").getAsString());
} else } else
logger.error("Querying the results gave this code: {}.", response.statusCode()); logger.error("Querying the results gave this code: {}.", response.statusCode());
return movie; return movie;
} }
private static Movie getMovieFromJson(String json) {
Movie movie = null;
JsonObject jsonMovie = JsonParser.parseString(json).getAsJsonObject();
if (jsonMovie.get("Response").getAsBoolean()) {
if (jsonMovie.get(IMDB_KEY) != null && jsonMovie.get(TITLE_KEY) != null) {
movie = new Movie(
jsonMovie.get(TITLE_KEY).getAsString(),
jsonMovie.get(IMDB_KEY).getAsString(),
jsonMovie.get(TYPE_KEY).getAsString(),
jsonMovie.get(POSTER_KEY).getAsString().equals("N/A") ? null : jsonMovie.get(POSTER_KEY).getAsString()
);
movie.setYear(Integer.parseInt(jsonMovie.get(YEAR_KEY).getAsString()
.substring(0, Math.min(4, jsonMovie.get(YEAR_KEY).getAsString().length()))));
try {
FilmManager.importFilm(movie);
} catch (ImportationException e) {
logger.error("Cannot import the movie with title '{}' and IMDB id '{}'.",
movie.getTitle(), movie.getImdbID());
logger.warn("Please fix this issue quickly as this could cause problems due to the OMDB limitations.");
}
}
} else
logger.error("OMDB API returned an error: {}", jsonMovie.get("Error").getAsString());
return movie;
}
private static HttpClient getHttpClient() { private static HttpClient getHttpClient() {
return HttpClient.newBuilder() return HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2) .version(HttpClient.Version.HTTP_2)

View File

@ -1,30 +1,42 @@
package xyz.vallat.louis.omdb.objects; package xyz.vallat.louis.omdb.objects;
import java.time.Instant;
import java.util.Date;
public class Movie { public class Movie {
private final String title; private final String title;
private final Instant released;
private final String imdbID; private final String imdbID;
private final String type; private final String type;
private final String poster; private final String poster;
private Integer year;
private int id;
public Movie(String title, Instant released, String imdbID, String type, String poster) { public Movie(String title, String imdbID, String type, String poster) {
this.id = 0;
this.title = title; this.title = title;
this.released = released;
this.imdbID = imdbID; this.imdbID = imdbID;
this.type = type; this.type = type;
this.poster = poster; this.poster = poster;
} }
public Movie setYear(int year) {
this.year = year;
return this;
}
public int getId() {
return this.id;
}
public Movie setId(Integer id) {
this.id = id;
return this;
}
public String getTitle() { public String getTitle() {
return title; return title;
} }
public Instant getReleased() { public Integer getYear() {
return released; return year;
} }
public String getImdbID() { public String getImdbID() {