Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 25 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,23 +169,43 @@ With no arguments, imogen draws your library.

```
┌ imogen · library ────────────────────────── 12,431 photographs ─┐
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
│ │ photo │ │ photo │ │ photo │ │ photo │
│ │2019-07 │ │2019-07 │ │2019-07★│ │2019-07 │
│ └────────┘ └────────┘ └────────┘ └────────┘
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ 2024
│ │ photo │ │ photo │ │ photo │ │ photo │ 2022
│ │2019-07 │ │2019-07 │ │2019-07★│ │2019-07 │ ›2019
│ └────────┘ └────────┘ └────────┘ └────────┘ 2016
└ harbour.jpg · 2019-07-14 · 2.4 MiB ★ ? help q quit ─────┘
```

The rail down the right edge is the whole library, however many years of it there are, with
`›` marking where you are. imogen holds the stretch you are looking at rather than
everything you have scrolled past, so the far end costs the same as the near one.

| | |
|---|---|
| `↑ ↓ ← →` `h j k l` | move |
| `enter` · `escape` | look at it · back |
| `/` | search |
| `g` | jump to a date |
| `[` · `]` | a year older · a year newer |
| `home` · `end` | first · last |
| `f` · `e` · `d` · `r` | favourite · archive · trash · restore |
| `i` · `a` | details · albums |
| `u` | pick files to upload |
| `1` `2` `3` `4` | library · favourites · archive · trash |
| `g` `G` · `R` · `?` | first · last · reload · keys |
| `R` · `?` | reload · keys |

### Going to a date

`g` asks where you want to be, and takes the same vocabulary as `--after` does, plus month
names:

```
jump to: aug 2011▏
```

`2011`, `aug 2011`, `august 2011` and `2011-08-14` all work. If the day you name has no
photographs — and on a library of any age most days do not — it lands on the nearest day
that does, however many years away that is, and says where it put you.

### Picking files

Expand Down
63 changes: 44 additions & 19 deletions src/commands/albums.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Albums, and the links that publish them.

use anyhow::Result;
use imogen_sdk::{AlbumCreate, AlbumUpdate};
use imogen_sdk::{AlbumCreate, AlbumUpdate, AssetFilter, AssetSelection};
use serde_json::json;

use crate::cli::{AlbumCommand, QueryArgs};
Expand Down Expand Up @@ -74,38 +74,55 @@ async fn list(ctx: &Context) -> Result<()> {
Ok(())
}

/// The album, and every photograph in it.
///
/// The assets on `GET /albums/{id}` are a capped cover sample now — sixty of them,
/// however many the album holds — so this pages the timeline under an `albumId` filter
/// instead. It has to be every one: `imogen album show holidays --ids | xargs imogen
/// trash` is a real pipeline, and a list quietly cut to sixty would trash sixty.
///
/// The header counts what was actually fetched rather than the album's own
/// `assetCount`, so the number above the rows is the number of rows. The two agree in
/// the ordinary case — both leave out the trashed, the archived and the vaulted — and
/// where they would not, the honest number is the one belonging to the list printed.
async fn show(ctx: &Context, reference: &str, ids_only: bool) -> Result<()> {
let album = ctx.find_album(reference).await?;
let full = ctx.client.albums.get(&album.id).await?;
let tiles = crate::commands::assets::all_tiles(
ctx,
&AssetFilter {
album_id: Some(album.id.clone()),
..Default::default()
},
)
.await?;

if ctx.out.is_json() {
return ctx.out.json(&full);
return ctx.out.json(&json!({
"album": album,
"items": tiles,
"count": tiles.len(),
}));
}
if ids_only {
for asset in &full.assets {
ctx.out.value(&asset.id);
}
return Ok(());
return crate::commands::assets::print_tiles(ctx, &tiles, true);
}
ctx.out.heading(&full.album.name);
ctx.out.heading(&album.name);
ctx.out.fields(&[
("id", full.album.id.clone()),
(
"description",
full.album.description.clone().unwrap_or_default(),
),
("photographs", full.album.asset_count.to_string()),
("created", crate::output::date(&full.album.created_at)),
("id", album.id.clone()),
("description", album.description.clone().unwrap_or_default()),
("photographs", tiles.len().to_string()),
("created", crate::output::date(&album.created_at)),
(
"public link",
full.album
album
.share_slug
.as_ref()
.map(|slug| format!("{}/share/{slug}", ctx.server))
.unwrap_or_default(),
),
]);
ctx.out.line("");
crate::commands::assets::print_assets(ctx, &full.assets, false)
crate::commands::assets::print_tiles(ctx, &tiles, false)
}

async fn create(
Expand Down Expand Up @@ -193,7 +210,11 @@ async fn add(ctx: &Context, reference: &str, assets: &[String], query: &QueryArg
let mut skipped = 0u64;
let mut count = 0u64;
for chunk in ids.chunks(500) {
let result = ctx.client.albums.add_assets(&album.id, chunk).await?;
let result = ctx
.client
.albums
.add_assets(&album.id, &AssetSelection::ids(chunk))
.await?;
added += result.added;
skipped += result.skipped;
count = result.asset_count;
Expand Down Expand Up @@ -222,7 +243,11 @@ async fn add(ctx: &Context, reference: &str, assets: &[String], query: &QueryArg

async fn remove(ctx: &Context, reference: &str, assets: &[String]) -> Result<()> {
let album = ctx.find_album(reference).await?;
let result = ctx.client.albums.remove_assets(&album.id, assets).await?;
let result = ctx
.client
.albums
.remove_assets(&album.id, &AssetSelection::ids(assets))
.await?;
if ctx.out.is_json() {
return ctx.out.json(&result);
}
Expand Down
Loading