feat(api): expose seasons.vanished (#141)

Season objects from the series endpoints now carry the conflict flag
#137 writes, the way episodes already do.
This commit is contained in:
Miguel Palhas
2026-08-23 20:27:34 +01:00
parent 4efc7b1833
commit 571ec42e92
2 changed files with 58 additions and 3 deletions
@@ -1,6 +1,6 @@
{
"db_name": "SQLite",
"query": "SELECT id AS \"id!: i64\", series_id AS \"series_id!: i64\", number AS \"number!: i64\", tracked AS \"tracked!: bool\" FROM seasons WHERE series_id = ? ORDER BY number",
"query": "SELECT id AS \"id!: i64\", series_id AS \"series_id!: i64\", number AS \"number!: i64\", tracked AS \"tracked!: bool\", vanished AS \"vanished!: bool\" FROM seasons WHERE series_id = ? ORDER BY number",
"describe": {
"columns": [
{
@@ -22,6 +22,11 @@
"name": "tracked!: bool",
"ordinal": 3,
"type_info": "Integer"
},
{
"name": "vanished!: bool",
"ordinal": 4,
"type_info": "Integer"
}
],
"parameters": {
@@ -31,8 +36,9 @@
true,
false,
false,
false,
false
]
},
"hash": "ecbf65c10aa20bc04c841981e59919485518877b49e9702fc92512f39cc2a72e"
"hash": "583b48cc8a0c618294361f606a9c8a4b3a42000c96343ff9a5490bb518700f81"
}
+50 -1
View File
@@ -97,6 +97,10 @@ pub struct Season {
pub number: i64,
/// §4.1. Whether new episodes of this season arrive wanted.
pub tracked: bool,
/// #141. The season vanished upstream while files remained under it,
/// which is why the row still exists. A conflict for the operator to
/// resolve; nothing was deleted from disk.
pub vanished: bool,
pub episodes: Vec<Episode>,
}
@@ -629,7 +633,7 @@ async fn remove_library_files(state: &AppState, id: i64) -> Result<(), ApiError>
async fn load_seasons(state: &AppState, series_id: i64) -> Result<Vec<Season>, ApiError> {
let seasons = sqlx::query!(
r#"SELECT id AS "id!: i64", series_id AS "series_id!: i64", number AS "number!: i64", tracked AS "tracked!: bool" FROM seasons WHERE series_id = ? ORDER BY number"#,
r#"SELECT id AS "id!: i64", series_id AS "series_id!: i64", number AS "number!: i64", tracked AS "tracked!: bool", vanished AS "vanished!: bool" FROM seasons WHERE series_id = ? ORDER BY number"#,
series_id
)
.fetch_all(pool(state)?)
@@ -650,6 +654,7 @@ async fn load_seasons(state: &AppState, series_id: i64) -> Result<Vec<Season>, A
series_id: season.series_id,
number: season.number,
tracked: season.tracked,
vanished: season.vanished,
episodes: episodes
.iter()
.filter(|episode| episode.season_id == season.id)
@@ -1390,6 +1395,50 @@ mod tests {
assert_eq!(season["number"], 1);
}
#[tokio::test]
async fn a_vanished_season_reaches_the_seasons_endpoint() {
let (_dir, state, base) = application().await;
let root_id = tv_root(&state, "main").await;
let series = add_series(&base, root_id, false).await;
let series_id = series["id"].as_i64().expect("id");
let clean = add_season(
&base,
series_id,
1,
serde_json::json!([{"number": 1, "title": "One"}]),
)
.await;
assert_eq!(clean["vanished"], false);
add_season(
&base,
series_id,
2,
serde_json::json!([{"number": 1, "title": "One"}]),
)
.await;
sqlx::query("UPDATE seasons SET vanished = 1 WHERE series_id = ? AND number = 2")
.bind(series_id)
.execute(state.database().expect("database").pool())
.await
.expect("flag season vanished");
let seasons: serde_json::Value = reqwest::Client::new()
.get(format!("{base}/api/series/{series_id}/seasons"))
.send()
.await
.expect("list seasons")
.json()
.await
.expect("seasons json");
let seasons = seasons.as_array().expect("seasons array");
assert_eq!(seasons[0]["vanished"], false);
assert_eq!(
seasons[1]["vanished"], true,
"#141: the conflict flag is not stopped at the database"
);
}
#[tokio::test]
async fn intent_is_set_on_seasons_and_on_single_episodes() {
let (_dir, state, base) = application().await;