Skip to content

Commit e2e5b25

Browse files
committed
Add command to optimize the thumbnails of existing albums
By setting an explicit thumbnail, the loading process becomes faster
1 parent 87fbb63 commit e2e5b25

5 files changed

Lines changed: 385 additions & 17 deletions

File tree

MANUAL.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,6 +1123,7 @@ pmv-cli album <COMMAND>
11231123
| [add](#command-album-add) | Adds a media asset to an album |
11241124
| [remove](#command-album-remove) | Removes a media asset from an album |
11251125
| [set-position](#command-album-set-position) | Changes the position of a media asset inside al album |
1126+
| [optimize-thumbnails](#command-album-optimize-thumbnails) | Optimizes thumbnails of albums, making the loading process faster |
11261127

11271128
<ins>**Options:**</ins>
11281129

@@ -1358,6 +1359,22 @@ pmv-cli album set-position <ALBUM> <MEDIA> <POSITION>
13581359
| --- | --- |
13591360
| `-h, --help` | Print help |
13601361

1362+
### Command: album optimize-thumbnails
1363+
1364+
Optimizes thumbnails of albums, making the loading process faster
1365+
1366+
<ins>**Usage:**</ins>
1367+
1368+
```
1369+
pmv-cli album optimize-thumbnails
1370+
```
1371+
1372+
<ins>**Options:**</ins>
1373+
1374+
| Option | Description |
1375+
| --- | --- |
1376+
| `-h, --help` | Print help |
1377+
13611378
## Command: config
13621379

13631380
Manages vault configuration

src/api/albums.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@ use std::sync::{Arc, Mutex};
44

55
use crate::{
66
models::{
7-
Album, AlbumIdResponse, AlbumListItem, AlbumMediaBody, AlbumMoveMediaBody, AlbumNameBody, MediaUpdateThumbnailResponse
7+
Album, AlbumIdResponse, AlbumListItem, AlbumMediaBody, AlbumMoveMediaBody, AlbumNameBody,
8+
MediaUpdateThumbnailResponse,
9+
},
10+
tools::{
11+
do_get_request, do_multipart_upload_request, do_multipart_upload_request_memory,
12+
do_post_request, ProgressReceiver, RequestError, VaultURI,
813
},
9-
tools::{do_get_request, do_multipart_upload_request, do_post_request, ProgressReceiver, RequestError, VaultURI},
1014
};
1115

1216
pub async fn api_call_get_albums(
@@ -183,3 +187,31 @@ pub async fn api_call_album_change_thumbnail(
183187

184188
Ok(parsed_body.unwrap())
185189
}
190+
191+
pub async fn api_call_album_change_thumbnail_memory(
192+
url: &VaultURI,
193+
album: u64,
194+
thumb_data: Vec<u8>,
195+
debug: bool,
196+
) -> Result<MediaUpdateThumbnailResponse, RequestError> {
197+
let body_str = do_multipart_upload_request_memory(
198+
url,
199+
format!("/api/albums/{album}/thumbnail"),
200+
"file".to_string(),
201+
thumb_data,
202+
"thumbnail.jpg".to_string(),
203+
debug,
204+
)
205+
.await?;
206+
207+
let parsed_body: Result<MediaUpdateThumbnailResponse, _> = serde_json::from_str(&body_str);
208+
209+
if parsed_body.is_err() {
210+
return Err(RequestError::Json {
211+
message: parsed_body.err().unwrap().to_string(),
212+
body: body_str,
213+
});
214+
}
215+
216+
Ok(parsed_body.unwrap())
217+
}

src/commands/album.rs

Lines changed: 198 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,22 @@ use reqwest::StatusCode;
77

88
use crate::{
99
api::{
10-
api_call_album_add_media, api_call_album_move_media, api_call_album_remove_media,
11-
api_call_create_album, api_call_delete_album, api_call_get_album, api_call_get_albums,
12-
api_call_get_media, api_call_get_media_albums, api_call_get_tags, api_call_rename_album,
10+
api_call_album_add_media, api_call_album_change_thumbnail_memory, api_call_album_move_media, api_call_album_remove_media, api_call_create_album, api_call_delete_album, api_call_get_album, api_call_get_albums, api_call_get_media, api_call_get_media_albums, api_call_get_tags, api_call_rename_album
1311
},
1412
commands::logout::do_logout,
1513
models::{
1614
tags_map_from_list, tags_names_from_ids, AlbumListItem, AlbumMediaBody, AlbumMoveMediaBody,
1715
AlbumNameBody,
1816
},
1917
tools::{
20-
ask_user, ensure_login, format_date, identifier_to_string, parse_identifier,
21-
parse_vault_uri, print_table, render_media_duration, to_csv_string,
18+
ask_user, do_get_download_request_memory, ensure_login, format_date, identifier_to_string, parse_identifier, parse_vault_uri, print_table, render_media_duration, to_csv_string
2219
},
2320
};
2421

25-
use super::{get_vault_url, print_request_error, run_cmd_download_album_thumbnail, run_cmd_upload_album_thumbnail, CommandGlobalOptions};
22+
use super::{
23+
get_vault_url, print_request_error, run_cmd_download_album_thumbnail,
24+
run_cmd_upload_album_thumbnail, CommandGlobalOptions,
25+
};
2626

2727
#[derive(Subcommand)]
2828
pub enum AlbumCommand {
@@ -133,6 +133,9 @@ pub enum AlbumCommand {
133133
/// New position for the media asset, starting at 1
134134
position: u32,
135135
},
136+
137+
/// Optimizes thumbnails of albums, making the loading process faster
138+
OptimizeThumbnails,
136139
}
137140

138141
pub async fn run_album_cmd(global_opts: CommandGlobalOptions, cmd: AlbumCommand) {
@@ -176,10 +179,17 @@ pub async fn run_album_cmd(global_opts: CommandGlobalOptions, cmd: AlbumCommand)
176179
}
177180
AlbumCommand::ChangeThumbnail { album, path } => {
178181
run_cmd_upload_album_thumbnail(global_opts, album, path).await;
179-
},
180-
AlbumCommand::DownloadThumbnail { album, output, print_link } => {
182+
}
183+
AlbumCommand::DownloadThumbnail {
184+
album,
185+
output,
186+
print_link,
187+
} => {
181188
run_cmd_download_album_thumbnail(global_opts, album, output, print_link).await;
182-
},
189+
}
190+
AlbumCommand::OptimizeThumbnails => {
191+
run_cmd_optimize_albums_thumbnails(global_opts).await;
192+
}
183193
}
184194
}
185195

@@ -1367,9 +1377,7 @@ pub async fn run_cmd_album_media_change_position(
13671377

13681378
let api_get_res = api_call_get_album(&vault_url, album_id, global_opts.debug).await;
13691379
let album_name = match api_get_res {
1370-
Ok(album_data) => {
1371-
album_data.name
1372-
}
1380+
Ok(album_data) => album_data.name,
13731381
Err(e) => {
13741382
print_request_error(e);
13751383
if logout_after_operation {
@@ -1430,3 +1438,181 @@ pub async fn run_cmd_album_media_change_position(
14301438
}
14311439
}
14321440
}
1441+
1442+
struct AlbumToOptimize {
1443+
pub id: u64,
1444+
pub thumbnail_url: String,
1445+
}
1446+
1447+
pub async fn run_cmd_optimize_albums_thumbnails(global_opts: CommandGlobalOptions) {
1448+
let url_parse_res = parse_vault_uri(get_vault_url(&global_opts.vault_url));
1449+
1450+
if url_parse_res.is_err() {
1451+
match url_parse_res.err().unwrap() {
1452+
crate::tools::VaultURIParseError::InvalidProtocol => {
1453+
eprintln!("Invalid vault URL provided. Must be an HTTP or HTTPS URL.");
1454+
}
1455+
crate::tools::VaultURIParseError::URLError(e) => {
1456+
let err_msg = e.to_string();
1457+
eprintln!("Invalid vault URL provided: {err_msg}");
1458+
}
1459+
}
1460+
1461+
process::exit(1);
1462+
}
1463+
1464+
let mut vault_url = url_parse_res.unwrap();
1465+
1466+
let logout_after_operation = vault_url.is_login();
1467+
let login_result = ensure_login(&vault_url, &None, global_opts.debug).await;
1468+
1469+
if login_result.is_err() {
1470+
process::exit(1);
1471+
}
1472+
1473+
vault_url = login_result.unwrap();
1474+
1475+
// Get media albums
1476+
1477+
let api_res = api_call_get_albums(&vault_url, global_opts.debug).await;
1478+
1479+
match api_res {
1480+
Ok(albums_list) => {
1481+
let mut albums_to_optimize: Vec<AlbumToOptimize> = Vec::new();
1482+
let mut already_optimized_count: i32 = 0;
1483+
let mut no_thumbnail_count: i32 = 0;
1484+
1485+
for album in &albums_list {
1486+
if album.thumbnail.is_empty() {
1487+
no_thumbnail_count += 1;
1488+
continue;
1489+
}
1490+
1491+
if album.thumbnail.starts_with("/assets/album_thumb/") {
1492+
already_optimized_count += 1;
1493+
continue;
1494+
}
1495+
1496+
let album_to_optimize = AlbumToOptimize {
1497+
id: album.id,
1498+
thumbnail_url: album.thumbnail.clone(),
1499+
};
1500+
1501+
albums_to_optimize.push(album_to_optimize);
1502+
}
1503+
1504+
let total_count = albums_list.len();
1505+
let albums_to_optimize_count = albums_to_optimize.len();
1506+
1507+
eprintln!("Total number of albums: {total_count}");
1508+
eprintln!("Albums with no thumbnail: {no_thumbnail_count}");
1509+
eprintln!("Albums with optimized thumbnail: {already_optimized_count}");
1510+
eprintln!("Albums with unoptimized thumbnail: {albums_to_optimize_count}");
1511+
1512+
eprintln!();
1513+
1514+
if albums_to_optimize_count > 0 {
1515+
// Ask confirmation
1516+
1517+
if !global_opts.auto_confirm {
1518+
eprintln!("Do you want to optimize the thumbnails of {albums_to_optimize_count} albums?");
1519+
let confirmation = ask_user("Continue? y/n: ").await.unwrap_or("".to_string());
1520+
1521+
if confirmation.to_lowercase() != "y" {
1522+
if logout_after_operation {
1523+
let logout_res = do_logout(&global_opts, &vault_url).await;
1524+
1525+
match logout_res {
1526+
Ok(_) => {}
1527+
Err(_) => {
1528+
process::exit(1);
1529+
}
1530+
}
1531+
}
1532+
process::exit(1);
1533+
}
1534+
}
1535+
1536+
// Optimize
1537+
1538+
for album_to_optimize in albums_to_optimize {
1539+
let album_id = album_to_optimize.id;
1540+
eprintln!("Optimizing thumbnail for album #{album_id}...");
1541+
1542+
// Download thumbnail
1543+
1544+
let thumb_download_response = do_get_download_request_memory(&vault_url, album_to_optimize.thumbnail_url, global_opts.debug).await;
1545+
1546+
match thumb_download_response {
1547+
Ok(thumb_data) => {
1548+
// Upload
1549+
1550+
let upload_res = api_call_album_change_thumbnail_memory(&vault_url, album_id, thumb_data, global_opts.debug).await;
1551+
1552+
match upload_res {
1553+
Ok(_) => {
1554+
eprintln!("Successfully optimized thumbnail for album #{album_id}");
1555+
},
1556+
Err(e) => {
1557+
print_request_error(e);
1558+
if logout_after_operation {
1559+
let logout_res = do_logout(&global_opts, &vault_url).await;
1560+
1561+
match logout_res {
1562+
Ok(_) => {}
1563+
Err(_) => {
1564+
process::exit(1);
1565+
}
1566+
}
1567+
}
1568+
process::exit(1);
1569+
}
1570+
}
1571+
},
1572+
Err(e) => {
1573+
print_request_error(e);
1574+
if logout_after_operation {
1575+
let logout_res = do_logout(&global_opts, &vault_url).await;
1576+
1577+
match logout_res {
1578+
Ok(_) => {}
1579+
Err(_) => {
1580+
process::exit(1);
1581+
}
1582+
}
1583+
}
1584+
process::exit(1);
1585+
}
1586+
}
1587+
}
1588+
} else {
1589+
eprintln!("Congratulations! All your albums have an optimized thumbnail.");
1590+
1591+
if logout_after_operation {
1592+
let logout_res = do_logout(&global_opts, &vault_url).await;
1593+
1594+
match logout_res {
1595+
Ok(_) => {}
1596+
Err(_) => {
1597+
process::exit(1);
1598+
}
1599+
}
1600+
}
1601+
}
1602+
}
1603+
Err(e) => {
1604+
print_request_error(e);
1605+
if logout_after_operation {
1606+
let logout_res = do_logout(&global_opts, &vault_url).await;
1607+
1608+
match logout_res {
1609+
Ok(_) => {}
1610+
Err(_) => {
1611+
process::exit(1);
1612+
}
1613+
}
1614+
}
1615+
process::exit(1);
1616+
}
1617+
}
1618+
}

0 commit comments

Comments
 (0)