Skip to content

Commit

Permalink
Refactoring and preparation of 0.14 release
Browse files Browse the repository at this point in the history
  • Loading branch information
Caleb9 committed Dec 21, 2024
1 parent f3869dc commit 3c12083
Show file tree
Hide file tree
Showing 13 changed files with 185 additions and 125 deletions.
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
[package]
name = "syno-photo-frame"
version = "0.13.0"
version = "0.14.0"
edition = "2021"
description = "Full-screen slideshow for Synology Photos albums"
description = "Full-screen slideshow for Synology Photos and Immich albums"
license = "GPL-3.0-or-later"
authors = ["Piotr Karasinski"]
readme = "README.md"
repository = "https://github.com/caleb9/syno-photo-frame"
keywords = [
"synology",
"synology-photos",
"immich",
"digital-photo-frame",
"slideshow",
"raspberry-pi",
]
rust-version = "1.74"
Expand Down
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
# for RPi Zero seems to be a native compilation, which is VERY slow.
##

FROM rust:bookworm as build
FROM rust:bookworm AS build

RUN DEBIAN_FRONTEND=noninteractive apt update && \
apt install -y libsdl2-dev libssl-dev lintian && \
Expand All @@ -53,8 +53,8 @@ RUN make
# The following two stages can be used as --target options for `docker
# build`, making it possible to extract the artifacts from Docker
# images to the local file system.
FROM scratch as dpkg
FROM scratch AS dpkg
COPY --from=build /workspace/dpkg/syno-photo-frame_*.deb ./

FROM scratch as bin
FROM scratch AS bin
COPY --from=build /workspace/target/release/syno-photo-frame ./
34 changes: 30 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
Version](https://img.shields.io/crates/v/syno-photo-frame)](https://crates.io/crates/syno-photo-frame)

[Synology
Photos](https://www.synology.com/en-global/dsm/feature/photos)
full-screen slideshow for Raspberry Pi.
Photos](https://www.synology.com/en-global/dsm/feature/photos) and
[Immich](https://immich.app/) full-screen slideshow for Raspberry Pi.

<img src="doc/syno-photo-frame.png" width=600 />

Expand All @@ -22,6 +22,9 @@ __If you like the project, give it a star ⭐, or consider becoming a__
- [Why?](#why)
- [Setup](#setup)
- [Synology Photos (NAS)](#synology-photos-nas)
- [Limitations](#limitations)
- [Alternative: Immich](#alternative-immich)
- [Limitations](#limitations-1)
- [Raspberry Pi](#raspberry-pi)
- [Option 1: Install From Debian Package](#option-1-install-from-debian-package)
- [Option 2: Build From Source](#option-2-build-from-source)
Expand Down Expand Up @@ -75,11 +78,34 @@ Assuming the Synology Photos package is installed on DSM:

<img src="doc/ShareLink.png" alt="Album Sharing" />

##### Limitations

* Accessing Synology Photos via a **Quick Connect** link is not
currently supported.
* Upper limit on number of photos in an album is set to 5000.
* [Video playback is not
supported](https://github.com/Caleb9/syno-photo-frame/issues/15)

### Alternative: Immich

Alternatively, instead of using Synology Photos, photos can also be
hosted on Immich server. Create an __album__ in Immich, add photos to
it, and create a share link (click the "Share" button in the
album). Optionally set a password (the same recommendation as with
Synology Photos about using HTTPS scheme when accessing the server
over the internet applies). Copy/write down the link - you'll need it
when setting up the app on Raspberry Pi later on.

##### Limitations

* Video playback is not supported

### Raspberry Pi

Let's assume that you're starting with a fresh installation of
Raspberry Pi OS Lite, the network has been set up (so you can access
Synology Photos), and you can access the command line on your Pi.
Synology Photos or Immich server), and you can access the command line
on your Pi.

#### Option 1: Install From Debian Package

Expand Down Expand Up @@ -176,7 +202,7 @@ syno-photo-frame --help
Run the app:

```bash
syno-photo-frame {sharing link to Synology Photos album}
syno-photo-frame {sharing link to Synology Photos or Immich album}
```

If everything works as expected, press Ctrl-C to kill the app.
Expand Down
6 changes: 6 additions & 0 deletions dpkg/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
syno-photo-frame (0.14.0) stable; urgency=low
[Piotr Karasinski ]
* Add support for Immich server

-- Piotr-Karasinski <[email protected]> Sat, 21 Dec 2024 12:00:00 +0200

syno-photo-frame (0.13.0) stable; urgency=low
[Piotr Karasinski ]
* Add `--background` option to select between blurred or black
Expand Down
2 changes: 1 addition & 1 deletion dpkg/control
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Section: utils
Priority: optional
Architecture:
Maintainer: Piotr Karasinski <[email protected]>
Description: Full-screen slideshow for Synology Photos albums
Description: Full-screen slideshow for Synology Photos and Immich albums
.
Depends: libc6 (>= 2.31), libegl1 (>= 1.3.2), libgl1 (>= 1.3.2), libsdl2-2.0-0 (>= 2.0.26), libssl3 | libssl1.1
Homepage: https://github.com/Caleb9/syno-photo-frame
3 changes: 1 addition & 2 deletions src/api_client/immich_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ use regex::Regex;
use crate::{
api_client::{
immich_client::dto::{Album, AlbumInfo, Asset, AssetsInfo},
syno_client::SortBy,
ApiClient, SharingId,
ApiClient, SharingId, SortBy,
},
cli::SourceSize,
http::{read_response, HttpClient, HttpResponse, Url},
Expand Down
45 changes: 39 additions & 6 deletions src/api_client/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use crate::cli::Backend;
use crate::{api_client::syno_client::SortBy, cli::SourceSize, http::Url};
use std::{fmt, ops::Deref, sync::OnceLock};

use anyhow::{bail, Result};
use bytes::Bytes;
use regex::Regex;
use std::sync::OnceLock;
use std::{fmt::Formatter, ops::Deref};

use crate::{
cli::{Backend, Order, SourceSize},
http::Url,
};

pub mod immich_client;
pub mod syno_client;
Expand All @@ -24,8 +27,8 @@ pub trait ApiClient {
#[derive(Debug)]
pub struct LoginError(pub anyhow::Error);

impl std::fmt::Display for LoginError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
impl fmt::Display for LoginError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
Expand All @@ -43,6 +46,36 @@ impl Deref for SharingId {
}
}

#[derive(Clone, Copy, Debug)]
pub enum SortBy {
TakenTime,
FileName,
}

impl From<Order> for SortBy {
fn from(value: Order) -> Self {
match value {
/* Random is not an option in the API. Randomization is implemented client-side and
* essentially makes the sort_by query parameter irrelevant. */
Order::ByDate | Order::Random => SortBy::TakenTime,
Order::ByName => SortBy::FileName,
}
}
}

impl fmt::Display for SortBy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
SortBy::FileName => "filename",
SortBy::TakenTime => "takentime",
}
)
}
}

pub fn detect_backend(share_link: &Url) -> Result<Backend> {
static SYNO_LINK_RE: OnceLock<Regex> = OnceLock::new();
let syno_link_re = SYNO_LINK_RE
Expand Down
40 changes: 4 additions & 36 deletions src/api_client/syno_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,11 @@ use serde::Deserialize;
use syno_api::dto::{ApiResponse, List};

use crate::{
cli::{Order, SourceSize},
http::{read_response, InvalidHttpResponse},
http::{CookieStore, HttpClient, HttpResponse, Url},
api_client::{ApiClient, LoginError, SharingId, SortBy},
cli::SourceSize,
http::{read_response, CookieStore, HttpClient, HttpResponse, InvalidHttpResponse, Url},
};

use super::{ApiClient, LoginError, SharingId};

pub struct SynoApiClient<'a, H, C> {
http_client: &'a H,
cookie_store: &'a C,
Expand Down Expand Up @@ -68,7 +66,7 @@ impl<H: HttpClient, C: CookieStore> ApiClient for SynoApiClient<'_, H, C> {
("version", "1"),
("additional", "[\"thumbnail\"]"),
("offset", "0"),
("limit", "5000"),
("limit", "5000"), // Limit imposed by API
("sort_by", &sort_by.to_string()),
("sort_direction", "asc"),
];
Expand Down Expand Up @@ -158,36 +156,6 @@ fn parse_share_link(share_link: &Url) -> Result<(Url, SharingId)> {
#[derive(Debug, Deserialize)]
pub struct Login {/* Empty brackets are needed for the deserializer to work */}

#[derive(Clone, Copy, Debug)]
pub enum SortBy {
TakenTime,
FileName,
}

impl From<Order> for SortBy {
fn from(value: Order) -> Self {
match value {
/* Random is not an option in the API. Randomization is implemented client-side and
* essentially makes the sort_by query parameter irrelevant. */
Order::ByDate | Order::Random => SortBy::TakenTime,
Order::ByName => SortBy::FileName,
}
}
}

impl Display for SortBy {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
SortBy::FileName => "filename",
SortBy::TakenTime => "takentime",
}
)
}
}

#[derive(Debug)]
pub struct InvalidApiResponse(&'static str, u16);

Expand Down
Loading

0 comments on commit 3c12083

Please sign in to comment.