Spaces:
Paused
Paused
Download api/src/upgrade/v001_backdrop_cache_keys.rs from stremio-db/a: direct link, hf CLI and curl.
- Browser
- Download file 3.36 kB
-
https://huggingface.co/spaces/stremio-db/a/resolve/main/api/src/upgrade/v001_backdrop_cache_keys.rs
- Command line
-
hf download hf://spaces/stremio-db/a/api/src/upgrade/v001_backdrop_cache_keys.rs
-
curl -L -o v001_backdrop_cache_keys.rs https://huggingface.co/spaces/stremio-db/a/resolve/main/api/src/upgrade/v001_backdrop_cache_keys.rs
3.36 kB
| use sea_orm::{ConnectionTrait, DatabaseConnection}; | |
| use crate::error::AppError; | |
| /// Migrate backdrop cache keys from `_b@` to `_b_f@`. | |
| /// | |
| /// Before this change, logos and backdrops were served exclusively via fanart.tv | |
| /// and backdrop cache keys used the kind prefix `_b` with no source marker. | |
| /// The new multi-source architecture adds `_t` (TMDB) and `_f` (Fanart.tv) | |
| /// source markers. Existing backdrops (all from fanart.tv) need `_f` appended. | |
| pub async fn run( | |
| db: &DatabaseConnection, | |
| cache_dir: &str, | |
| external_cache_only: bool, | |
| ) -> Result<(), AppError> { | |
| run_db(db).await?; | |
| run_fs(cache_dir, external_cache_only).await?; | |
| Ok(()) | |
| } | |
| /// Database step — idempotent. | |
| pub async fn run_db(db: &impl ConnectionTrait) -> Result<(), AppError> { | |
| let result = db | |
| .execute(sea_orm::Statement::from_sql_and_values( | |
| sea_orm::DatabaseBackend::Postgres, | |
| "UPDATE image_meta SET cache_key = replace(cache_key, '_b@', '_b_f@') \ | |
| WHERE image_type = 'b' AND cache_key LIKE '%_b@%'", | |
| [], | |
| )) | |
| .await?; | |
| tracing::info!(db_rows = result.rows_affected(), "backdrop cache keys migrated in DB (_b@ → _b_f@)"); | |
| Ok(()) | |
| } | |
| /// Migrate backdrop cache keys — filesystem step (idempotent). | |
| /// | |
| /// Renames files containing `_b@` to `_b_f@`. Safe to call multiple times; | |
| /// already-renamed files are skipped. | |
| pub async fn run_fs(cache_dir: &str, external_cache_only: bool) -> Result<(), AppError> { | |
| if external_cache_only { | |
| tracing::info!("backdrop filesystem rename skipped (external_cache_only)"); | |
| return Ok(()); | |
| } | |
| let backdrop_dir = std::path::Path::new(cache_dir).join("backdrops"); | |
| let renamed = tokio::task::spawn_blocking(move || rename_files(&backdrop_dir)) | |
| .await | |
| .map_err(|e| AppError::Other(format!("rename task panicked: {e}")))? | |
| ?; | |
| tracing::info!(fs_renamed = renamed, "backdrop cache files renamed (_b@ → _b_f@)"); | |
| Ok(()) | |
| } | |
| /// Recursively rename files containing `_b@` to `_b_f@` in the given directory. | |
| fn rename_files(dir: &std::path::Path) -> Result<u64, AppError> { | |
| let entries = match std::fs::read_dir(dir) { | |
| Ok(e) => e, | |
| Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(0), | |
| Err(e) => { | |
| return Err(AppError::Other(format!( | |
| "failed to read {}: {e}", | |
| dir.display() | |
| ))) | |
| } | |
| }; | |
| let mut count = 0u64; | |
| for entry in entries { | |
| let entry = entry.map_err(|e| AppError::Other(e.to_string()))?; | |
| let path = entry.path(); | |
| if path.is_dir() { | |
| count += rename_files(&path)?; | |
| } else if let Some(name) = path.file_name().and_then(|n| n.to_str()) { | |
| if name.contains("_b@") && !name.contains("_b_f@") && !name.contains("_b_t@") { | |
| let new_name = name.replace("_b@", "_b_f@"); | |
| let new_path = path.with_file_name(new_name); | |
| std::fs::rename(&path, &new_path).map_err(|e| { | |
| AppError::Other(format!( | |
| "rename failed: {} → {}: {e}", | |
| path.display(), | |
| new_path.display() | |
| )) | |
| })?; | |
| count += 1; | |
| } | |
| } | |
| } | |
| Ok(count) | |
| } | |