diff --git a/.sqlx/query-2b67abe4db9e00517fecfa53fbad5bbbc633a9f537eaaaa9d46a445d8c25eb2c.json b/.sqlx/query-2b67abe4db9e00517fecfa53fbad5bbbc633a9f537eaaaa9d46a445d8c25eb2c.json
new file mode 100644
index 0000000..afdbb22
--- /dev/null
+++ b/.sqlx/query-2b67abe4db9e00517fecfa53fbad5bbbc633a9f537eaaaa9d46a445d8c25eb2c.json
@@ -0,0 +1,122 @@
+{
+ "db_name": "SQLite",
+ "query": "SELECT m.id AS \"movie_id!: i64\", m.tmdb_id AS \"tmdb_id!: i64\",\n m.title AS \"title!: String\", m.year, m.poster_path,\n mf.id AS \"media_file_id!: i64\", sa.language AS \"language!: String\",\n sa.state AS \"state!: arr_db::SubtitleState\", sa.last_failure\n FROM subtitle_attempts sa\n JOIN media_files mf ON mf.id = sa.media_file_id AND mf.owner_kind = 'movie'\n JOIN movies m ON m.id = mf.owner_id\n WHERE sa.state IN ('failed', 'capped', 'unavailable')\n ORDER BY m.title, sa.language",
+ "describe": {
+ "columns": [
+ {
+ "name": "movie_id!: i64",
+ "ordinal": 0,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "movies",
+ "name": "id"
+ }
+ }
+ },
+ {
+ "name": "tmdb_id!: i64",
+ "ordinal": 1,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "movies",
+ "name": "tmdb_id"
+ }
+ }
+ },
+ {
+ "name": "title!: String",
+ "ordinal": 2,
+ "type_info": "Text",
+ "origin": {
+ "Table": {
+ "table": "movies",
+ "name": "title"
+ }
+ }
+ },
+ {
+ "name": "year",
+ "ordinal": 3,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "movies",
+ "name": "year"
+ }
+ }
+ },
+ {
+ "name": "poster_path",
+ "ordinal": 4,
+ "type_info": "Text",
+ "origin": {
+ "Table": {
+ "table": "movies",
+ "name": "poster_path"
+ }
+ }
+ },
+ {
+ "name": "media_file_id!: i64",
+ "ordinal": 5,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "media_files",
+ "name": "id"
+ }
+ }
+ },
+ {
+ "name": "language!: String",
+ "ordinal": 6,
+ "type_info": "Text",
+ "origin": {
+ "Table": {
+ "table": "subtitle_attempts",
+ "name": "language"
+ }
+ }
+ },
+ {
+ "name": "state!: arr_db::SubtitleState",
+ "ordinal": 7,
+ "type_info": "Text",
+ "origin": {
+ "Table": {
+ "table": "subtitle_attempts",
+ "name": "state"
+ }
+ }
+ },
+ {
+ "name": "last_failure",
+ "ordinal": 8,
+ "type_info": "Text",
+ "origin": {
+ "Table": {
+ "table": "subtitle_attempts",
+ "name": "last_failure"
+ }
+ }
+ }
+ ],
+ "parameters": {
+ "Right": 0
+ },
+ "nullable": [
+ false,
+ false,
+ false,
+ true,
+ true,
+ false,
+ false,
+ false,
+ true
+ ]
+ },
+ "hash": "2b67abe4db9e00517fecfa53fbad5bbbc633a9f537eaaaa9d46a445d8c25eb2c"
+}
diff --git a/.sqlx/query-69f34468a61979b85b7513056d58e34c743af3ae62d5327d4dea49fe7586a85b.json b/.sqlx/query-69f34468a61979b85b7513056d58e34c743af3ae62d5327d4dea49fe7586a85b.json
new file mode 100644
index 0000000..1d494d9
--- /dev/null
+++ b/.sqlx/query-69f34468a61979b85b7513056d58e34c743af3ae62d5327d4dea49fe7586a85b.json
@@ -0,0 +1,98 @@
+{
+ "db_name": "SQLite",
+ "query": "SELECT m.id AS \"movie_id!: i64\", m.tmdb_id AS \"tmdb_id!: i64\",\n m.title AS \"title!: String\", m.year, m.poster_path,\n mf.id AS \"media_file_id!: i64\", sf.language AS \"language!: String\"\n FROM subtitle_files sf\n JOIN media_files mf ON mf.id = sf.media_file_id AND mf.owner_kind = 'movie'\n JOIN movies m ON m.id = mf.owner_id\n WHERE sf.sync_rejected = 1\n ORDER BY m.title, sf.language",
+ "describe": {
+ "columns": [
+ {
+ "name": "movie_id!: i64",
+ "ordinal": 0,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "movies",
+ "name": "id"
+ }
+ }
+ },
+ {
+ "name": "tmdb_id!: i64",
+ "ordinal": 1,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "movies",
+ "name": "tmdb_id"
+ }
+ }
+ },
+ {
+ "name": "title!: String",
+ "ordinal": 2,
+ "type_info": "Text",
+ "origin": {
+ "Table": {
+ "table": "movies",
+ "name": "title"
+ }
+ }
+ },
+ {
+ "name": "year",
+ "ordinal": 3,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "movies",
+ "name": "year"
+ }
+ }
+ },
+ {
+ "name": "poster_path",
+ "ordinal": 4,
+ "type_info": "Text",
+ "origin": {
+ "Table": {
+ "table": "movies",
+ "name": "poster_path"
+ }
+ }
+ },
+ {
+ "name": "media_file_id!: i64",
+ "ordinal": 5,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "media_files",
+ "name": "id"
+ }
+ }
+ },
+ {
+ "name": "language!: String",
+ "ordinal": 6,
+ "type_info": "Text",
+ "origin": {
+ "Table": {
+ "table": "subtitle_files",
+ "name": "language"
+ }
+ }
+ }
+ ],
+ "parameters": {
+ "Right": 0
+ },
+ "nullable": [
+ false,
+ false,
+ false,
+ true,
+ true,
+ false,
+ false
+ ]
+ },
+ "hash": "69f34468a61979b85b7513056d58e34c743af3ae62d5327d4dea49fe7586a85b"
+}
diff --git a/.sqlx/query-6cdb9a9344bbab557433da35471968b6e5cf96b5b220ffb41f10b6d851884803.json b/.sqlx/query-6cdb9a9344bbab557433da35471968b6e5cf96b5b220ffb41f10b6d851884803.json
new file mode 100644
index 0000000..316cb2a
--- /dev/null
+++ b/.sqlx/query-6cdb9a9344bbab557433da35471968b6e5cf96b5b220ffb41f10b6d851884803.json
@@ -0,0 +1,158 @@
+{
+ "db_name": "SQLite",
+ "query": "SELECT s.id AS \"series_id!: i64\", s.tmdb_id AS \"tmdb_id!: i64\",\n s.title AS \"title!: String\", s.year, s.poster_path,\n e.id AS \"episode_id!: i64\", se.number AS \"season_number!: i64\",\n e.number AS \"episode_number!: i64\", mf.id AS \"media_file_id!: i64\",\n sa.language AS \"language!: String\",\n sa.state AS \"state!: arr_db::SubtitleState\", sa.last_failure\n FROM subtitle_attempts sa\n JOIN media_files mf ON mf.id = sa.media_file_id AND mf.owner_kind = 'episode'\n JOIN episodes e ON e.id = mf.owner_id\n JOIN seasons se ON se.id = e.season_id\n JOIN series s ON s.id = se.series_id\n WHERE sa.state IN ('failed', 'capped', 'unavailable')\n ORDER BY s.title, se.number, e.number, sa.language",
+ "describe": {
+ "columns": [
+ {
+ "name": "series_id!: i64",
+ "ordinal": 0,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "series",
+ "name": "id"
+ }
+ }
+ },
+ {
+ "name": "tmdb_id!: i64",
+ "ordinal": 1,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "series",
+ "name": "tmdb_id"
+ }
+ }
+ },
+ {
+ "name": "title!: String",
+ "ordinal": 2,
+ "type_info": "Text",
+ "origin": {
+ "Table": {
+ "table": "series",
+ "name": "title"
+ }
+ }
+ },
+ {
+ "name": "year",
+ "ordinal": 3,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "series",
+ "name": "year"
+ }
+ }
+ },
+ {
+ "name": "poster_path",
+ "ordinal": 4,
+ "type_info": "Text",
+ "origin": {
+ "Table": {
+ "table": "series",
+ "name": "poster_path"
+ }
+ }
+ },
+ {
+ "name": "episode_id!: i64",
+ "ordinal": 5,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "episodes",
+ "name": "id"
+ }
+ }
+ },
+ {
+ "name": "season_number!: i64",
+ "ordinal": 6,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "seasons",
+ "name": "number"
+ }
+ }
+ },
+ {
+ "name": "episode_number!: i64",
+ "ordinal": 7,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "episodes",
+ "name": "number"
+ }
+ }
+ },
+ {
+ "name": "media_file_id!: i64",
+ "ordinal": 8,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "media_files",
+ "name": "id"
+ }
+ }
+ },
+ {
+ "name": "language!: String",
+ "ordinal": 9,
+ "type_info": "Text",
+ "origin": {
+ "Table": {
+ "table": "subtitle_attempts",
+ "name": "language"
+ }
+ }
+ },
+ {
+ "name": "state!: arr_db::SubtitleState",
+ "ordinal": 10,
+ "type_info": "Text",
+ "origin": {
+ "Table": {
+ "table": "subtitle_attempts",
+ "name": "state"
+ }
+ }
+ },
+ {
+ "name": "last_failure",
+ "ordinal": 11,
+ "type_info": "Text",
+ "origin": {
+ "Table": {
+ "table": "subtitle_attempts",
+ "name": "last_failure"
+ }
+ }
+ }
+ ],
+ "parameters": {
+ "Right": 0
+ },
+ "nullable": [
+ false,
+ false,
+ false,
+ true,
+ true,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true
+ ]
+ },
+ "hash": "6cdb9a9344bbab557433da35471968b6e5cf96b5b220ffb41f10b6d851884803"
+}
diff --git a/.sqlx/query-8543e4ad8c59e83911688ceace72f66d360240a45eee05aaf15dab233e22e7e6.json b/.sqlx/query-8543e4ad8c59e83911688ceace72f66d360240a45eee05aaf15dab233e22e7e6.json
new file mode 100644
index 0000000..3acf94b
--- /dev/null
+++ b/.sqlx/query-8543e4ad8c59e83911688ceace72f66d360240a45eee05aaf15dab233e22e7e6.json
@@ -0,0 +1,134 @@
+{
+ "db_name": "SQLite",
+ "query": "SELECT s.id AS \"series_id!: i64\", s.tmdb_id AS \"tmdb_id!: i64\",\n s.title AS \"title!: String\", s.year, s.poster_path,\n e.id AS \"episode_id!: i64\", se.number AS \"season_number!: i64\",\n e.number AS \"episode_number!: i64\", mf.id AS \"media_file_id!: i64\",\n sf.language AS \"language!: String\"\n FROM subtitle_files sf\n JOIN media_files mf ON mf.id = sf.media_file_id AND mf.owner_kind = 'episode'\n JOIN episodes e ON e.id = mf.owner_id\n JOIN seasons se ON se.id = e.season_id\n JOIN series s ON s.id = se.series_id\n WHERE sf.sync_rejected = 1\n ORDER BY s.title, se.number, e.number, sf.language",
+ "describe": {
+ "columns": [
+ {
+ "name": "series_id!: i64",
+ "ordinal": 0,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "series",
+ "name": "id"
+ }
+ }
+ },
+ {
+ "name": "tmdb_id!: i64",
+ "ordinal": 1,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "series",
+ "name": "tmdb_id"
+ }
+ }
+ },
+ {
+ "name": "title!: String",
+ "ordinal": 2,
+ "type_info": "Text",
+ "origin": {
+ "Table": {
+ "table": "series",
+ "name": "title"
+ }
+ }
+ },
+ {
+ "name": "year",
+ "ordinal": 3,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "series",
+ "name": "year"
+ }
+ }
+ },
+ {
+ "name": "poster_path",
+ "ordinal": 4,
+ "type_info": "Text",
+ "origin": {
+ "Table": {
+ "table": "series",
+ "name": "poster_path"
+ }
+ }
+ },
+ {
+ "name": "episode_id!: i64",
+ "ordinal": 5,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "episodes",
+ "name": "id"
+ }
+ }
+ },
+ {
+ "name": "season_number!: i64",
+ "ordinal": 6,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "seasons",
+ "name": "number"
+ }
+ }
+ },
+ {
+ "name": "episode_number!: i64",
+ "ordinal": 7,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "episodes",
+ "name": "number"
+ }
+ }
+ },
+ {
+ "name": "media_file_id!: i64",
+ "ordinal": 8,
+ "type_info": "Integer",
+ "origin": {
+ "Table": {
+ "table": "media_files",
+ "name": "id"
+ }
+ }
+ },
+ {
+ "name": "language!: String",
+ "ordinal": 9,
+ "type_info": "Text",
+ "origin": {
+ "Table": {
+ "table": "subtitle_files",
+ "name": "language"
+ }
+ }
+ }
+ ],
+ "parameters": {
+ "Right": 0
+ },
+ "nullable": [
+ false,
+ false,
+ false,
+ true,
+ true,
+ false,
+ false,
+ false,
+ false,
+ false
+ ]
+ },
+ "hash": "8543e4ad8c59e83911688ceace72f66d360240a45eee05aaf15dab233e22e7e6"
+}
diff --git a/crates/arr-api/src/lib.rs b/crates/arr-api/src/lib.rs
index cdfce02..be82dd8 100644
--- a/crates/arr-api/src/lib.rs
+++ b/crates/arr-api/src/lib.rs
@@ -48,9 +48,10 @@ pub use state::{
};
pub use subtitle_settings::{SubtitleSettings, SubtitleSettingsInput};
pub use subtitles::{
- EpisodeSubtitleStatus, MissingSubtitle, Subtitle, SubtitleCandidate, SubtitleGrabInput,
- SubtitleProviderError, SubtitleSearchInput, SubtitleSearchResults, SubtitleStatus,
- SubtitleTranslateInput,
+ EpisodeSubtitleGaps, EpisodeSubtitleStatus, MissingSubtitle, MovieSubtitleGaps,
+ SeasonSubtitleGaps, SeriesSubtitleGaps, Subtitle, SubtitleCandidate, SubtitleGap,
+ SubtitleGrabInput, SubtitleProviderError, SubtitleQueue, SubtitleSearchInput,
+ SubtitleSearchResults, SubtitleStatus, SubtitleTranslateInput,
};
pub use trailer::{Trailer, TrailerKind};
@@ -136,6 +137,7 @@ fn api_router() -> OpenApiRouter
+ a wanted language with no subtitle, and why — no candidate, a translation or provider + failure, the daily budget, or a sync `alass` flagged. open the title to search, + translate or retry by hand. +
+