Skip to content

Commit 57ba94a

Browse files
committed
Store original path if found
1 parent cd1f81d commit 57ba94a

File tree

8 files changed

+110
-18
lines changed

8 files changed

+110
-18
lines changed

config.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ database_password = "shoebox"
1111
root_path = "/mnt/storage/tove/immich/auto-transcoded/"
1212
name = "videos"
1313
description = "Bmpcc transcoded videos"
14+
originals_path = "/mnt/storage/bmpcc/raw/"
1415

1516

1617
[immich]
Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
-- Your SQL goes here
22
CREATE TABLE media
33
(
4-
id SERIAL PRIMARY KEY,
5-
root_path TEXT NOT NULL,
6-
route TEXT NOT NULL,
7-
file_name TEXT NOT NULL,
8-
file_path TEXT NOT NULL unique,
9-
media_type TEXT NOT NULL CHECK (media_type IN ('photo', 'video')),
10-
usable BOOLEAN DEFAULT TRUE,
11-
highlight BOOLEAN DEFAULT FALSE,
12-
reviewed BOOLEAN DEFAULT FALSE,
13-
description TEXT,
14-
duration_ms INTEGER DEFAULT 0,
15-
created_at TIMESTAMPtz NOT NULL DEFAULT NOW(),
16-
uploaded_at timestamptz DEFAULT NOW()
4+
id SERIAL PRIMARY KEY,
5+
root_path TEXT NOT NULL,
6+
route TEXT NOT NULL,
7+
file_name TEXT NOT NULL,
8+
file_path TEXT NOT NULL unique,
9+
original_path TEXT DEFAULT NULL,
10+
media_type TEXT NOT NULL CHECK (media_type IN ('photo', 'video')),
11+
usable BOOLEAN DEFAULT TRUE,
12+
highlight BOOLEAN DEFAULT FALSE,
13+
reviewed BOOLEAN DEFAULT FALSE,
14+
description TEXT,
15+
duration_ms INTEGER DEFAULT 0,
16+
created_at TIMESTAMPtz NOT NULL DEFAULT NOW(),
17+
uploaded_at timestamptz DEFAULT NOW()
1718
);

src/app.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,11 @@ pub fn App() -> impl IntoView {
8383

8484
#[server]
8585
pub async fn get_files() -> Result<(), ServerFnError> {
86-
use crate::filesystem::fs_watcher;
8786
use crate::filesystem::fs_watcher::scan_all;
87+
use crate::filesystem::fs_watcher::scan_original_paths;
8888
log!("Getting files");
8989
let files = scan_all().await;
90+
let _ = scan_original_paths().await;
9091
log!("Files: {:?}", files);
9192
Ok(())
9293
}

src/database/pg_calls.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::database::pg_conn::pg_connection;
22
use crate::lib_models::MediaWeb;
3-
use crate::models::{Media, MediaTag, NewMedia, Person, Tag};
3+
use crate::models::{Media, MediaOriginalPathUpdate, MediaTag, NewMedia, Person, Tag};
44
use crate::schema::*;
55
use diesel::associations::HasTable;
66
use diesel::dsl::insert_into;
@@ -245,3 +245,36 @@ pub fn get_file_paths_by_ids(media_ids: Vec<i32>) -> Result<Vec<String>, diesel:
245245

246246
Ok(results)
247247
}
248+
249+
pub fn update_media_original_path(
250+
file_name_: &str,
251+
root_path_: &str,
252+
original_path_: String,
253+
) -> Result<(), diesel::result::Error> {
254+
use crate::schema::media::dsl::*;
255+
let conn = &mut pg_connection();
256+
257+
// Get the base name without extension
258+
let base_name = file_name_
259+
.rsplit_once('.')
260+
.map(|(base, _)| base)
261+
.unwrap_or(file_name_);
262+
263+
let update = MediaOriginalPathUpdate {
264+
original_path: Some(original_path_),
265+
};
266+
267+
// Use a more precise pattern that ensures we match the exact base name
268+
diesel::update(media)
269+
.filter(
270+
file_name
271+
.like(format!("{}.%", base_name))
272+
.and(root_path.eq(root_path_))
273+
// Exclude any files that start with ._
274+
.and(file_name.not_like("._%.%")),
275+
)
276+
.set(&update)
277+
.execute(conn)?;
278+
279+
Ok(())
280+
}

src/filesystem/fs_watcher.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
use crate::database::pg_calls::insert_new_media;
1+
use crate::database::pg_calls::{insert_new_media, update_media_original_path};
22
use crate::filesystem::exif_parse::parse_exif;
33
use crate::lib_models::{FileType, Metadata};
44
use crate::models::NewMedia;
55
use crate::settings::settings;
6+
use anyhow::Result;
67
use chrono::DateTime;
78
use leptos::logging::log;
89
use std::fs;
@@ -139,3 +140,42 @@ pub async fn scan_files(dir: &str, route: &str, root_path: &str) -> Vec<FileType
139140

140141
files
141142
}
143+
144+
pub async fn scan_original_paths() {
145+
let settings = settings();
146+
for path in &settings.paths {
147+
if let Some(orig_path) = &path.originals_path {
148+
let _ = update_original_paths(orig_path.as_str(), path.root_path.as_str()).await;
149+
150+
// Scan subdirectories
151+
let dirs = find_dirs(orig_path.as_str());
152+
for dir in dirs {
153+
let _ = update_original_paths(dir.as_str(), path.root_path.as_str()).await;
154+
}
155+
}
156+
}
157+
}
158+
159+
pub async fn update_original_paths(dir: &str, root_path: &str) -> Result<()> {
160+
log!("scanning original paths in: {}", dir);
161+
162+
if let Ok(entries) = fs::read_dir(dir) {
163+
for entry in entries.filter_map(Result::ok) {
164+
if entry.file_type().unwrap().is_dir() {
165+
continue;
166+
}
167+
168+
let path = entry.path();
169+
if let Some(file_name) = path.file_name().map(|n| n.to_string_lossy().to_string()) {
170+
// Update the database record that matches this filename and root_path
171+
update_media_original_path(
172+
&file_name,
173+
root_path,
174+
path.to_string_lossy().to_string(),
175+
)?;
176+
}
177+
}
178+
}
179+
180+
Ok(())
181+
}

src/models.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use chrono::{DateTime, Utc};
77
use diesel::prelude::*;
88
use serde::{Deserialize, Serialize};
99

10-
#[derive(Queryable, Selectable, Debug, Serialize, Deserialize, Identifiable)]
10+
#[derive(Queryable, Identifiable, Debug, Selectable)]
1111
#[diesel(table_name = media)]
1212
#[diesel(check_for_backend(diesel::pg::Pg))]
1313
pub struct Media {
@@ -16,6 +16,7 @@ pub struct Media {
1616
pub route: String,
1717
pub file_name: String,
1818
pub file_path: String,
19+
pub original_path: Option<String>,
1920
pub media_type: String,
2021
pub usable: Option<bool>,
2122
pub highlight: Option<bool>,
@@ -53,6 +54,13 @@ pub struct MediaUpdate {
5354
pub description: String,
5455
}
5556

57+
// Add a specific struct for updating original_path
58+
#[derive(AsChangeset, Debug, Selectable)]
59+
#[diesel(table_name = media)]
60+
pub struct MediaOriginalPathUpdate {
61+
pub original_path: Option<String>,
62+
}
63+
5664
#[derive(Queryable, Selectable, Debug, Insertable, Associations, Identifiable)]
5765
#[diesel(belongs_to(Media, foreign_key = media_id))]
5866
#[diesel(belongs_to(Tag, foreign_key = tag_id))]

src/schema.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ diesel::table! {
77
route -> Text,
88
file_name -> Text,
99
file_path -> Text,
10+
original_path -> Nullable<Text>,
1011
media_type -> Text,
1112
usable -> Nullable<Bool>,
1213
highlight -> Nullable<Bool>,
@@ -51,4 +52,10 @@ diesel::joinable!(media_people -> people (person_id));
5152
diesel::joinable!(media_tags -> media (media_id));
5253
diesel::joinable!(media_tags -> tags (tag_id));
5354

54-
diesel::allow_tables_to_appear_in_same_query!(media, media_people, media_tags, people, tags,);
55+
diesel::allow_tables_to_appear_in_same_query!(
56+
media,
57+
media_people,
58+
media_tags,
59+
people,
60+
tags,
61+
);

src/settings.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ pub struct PathConfig {
4444
pub root_path: String,
4545
pub name: String,
4646
pub description: String,
47+
pub originals_path: Option<String>,
4748
}
4849

4950
impl PathConfig {

0 commit comments

Comments
 (0)