various: add links_extracted_at field to track markdown link extraction time

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Id13c6243de4c0f4fa5a87a13402379906a6a6964
This commit is contained in:
raf 2026-02-09 15:38:11 +03:00
commit d741e8d585
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
5 changed files with 64 additions and 13 deletions

View file

@ -701,7 +701,9 @@ impl StorageBackend for PostgresBackend {
"SELECT id, path, file_name, media_type, content_hash, file_size,
title, artist, album, genre, year, duration_secs, description,
thumbnail_path, file_mtime, date_taken, latitude, longitude,
camera_make, camera_model, rating, perceptual_hash, created_at, updated_at
camera_make, camera_model, rating, perceptual_hash,
storage_mode, original_filename, uploaded_at, storage_key,
created_at, updated_at, deleted_at, links_extracted_at
FROM media_items WHERE id = $1",
&[&id.0],
)
@ -725,7 +727,9 @@ impl StorageBackend for PostgresBackend {
"SELECT id, path, file_name, media_type, content_hash, file_size,
title, artist, album, genre, year, duration_secs, description,
thumbnail_path, file_mtime, date_taken, latitude, longitude,
camera_make, camera_model, rating, perceptual_hash, created_at, updated_at
camera_make, camera_model, rating, perceptual_hash,
storage_mode, original_filename, uploaded_at, storage_key,
created_at, updated_at, deleted_at, links_extracted_at
FROM media_items WHERE content_hash = $1",
&[&hash.0],
)
@ -754,7 +758,9 @@ impl StorageBackend for PostgresBackend {
"SELECT id, path, file_name, media_type, content_hash, file_size,
title, artist, album, genre, year, duration_secs, description,
thumbnail_path, file_mtime, date_taken, latitude, longitude,
camera_make, camera_model, rating, perceptual_hash, created_at, updated_at
camera_make, camera_model, rating, perceptual_hash,
storage_mode, original_filename, uploaded_at, storage_key,
created_at, updated_at, deleted_at, links_extracted_at
FROM media_items WHERE path = $1",
&[&path_str],
)
@ -794,7 +800,7 @@ impl StorageBackend for PostgresBackend {
thumbnail_path, file_mtime, date_taken, latitude, longitude,
camera_make, camera_model, rating, perceptual_hash,
storage_mode, original_filename, uploaded_at, storage_key,
created_at, updated_at, deleted_at
created_at, updated_at, deleted_at, links_extracted_at
FROM media_items
WHERE deleted_at IS NULL
ORDER BY {order_by}
@ -1345,7 +1351,10 @@ impl StorageBackend for PostgresBackend {
.query(
"SELECT m.id, m.path, m.file_name, m.media_type, m.content_hash, m.file_size,
m.title, m.artist, m.album, m.genre, m.year, m.duration_secs,
m.description, m.thumbnail_path, m.created_at, m.updated_at
m.description, m.thumbnail_path, m.file_mtime, m.date_taken, m.latitude,
m.longitude, m.camera_make, m.camera_model, m.rating, m.perceptual_hash,
m.storage_mode, m.original_filename, m.uploaded_at, m.storage_key,
m.created_at, m.updated_at, m.deleted_at, m.links_extracted_at
FROM media_items m
JOIN collection_members cm ON cm.media_id = m.id
WHERE cm.collection_id = $1
@ -1449,7 +1458,8 @@ impl StorageBackend for PostgresBackend {
m.title, m.artist, m.album, m.genre, m.year, m.duration_secs,
m.description, m.thumbnail_path, m.file_mtime, m.date_taken, m.latitude,
m.longitude, m.camera_make, m.camera_model, m.rating, m.perceptual_hash,
m.created_at, m.updated_at,
m.storage_mode, m.original_filename, m.uploaded_at, m.storage_key,
m.created_at, m.updated_at, m.deleted_at, m.links_extracted_at,
ts_rank(m.search_vector, plainto_tsquery('english', ${fts_param_idx})) AS rank
FROM media_items m
WHERE {full_where}
@ -1466,7 +1476,8 @@ impl StorageBackend for PostgresBackend {
m.title, m.artist, m.album, m.genre, m.year, m.duration_secs,
m.description, m.thumbnail_path, m.file_mtime, m.date_taken, m.latitude,
m.longitude, m.camera_make, m.camera_model, m.rating, m.perceptual_hash,
m.created_at, m.updated_at
m.storage_mode, m.original_filename, m.uploaded_at, m.storage_key,
m.created_at, m.updated_at, m.deleted_at, m.links_extracted_at
FROM media_items m
WHERE {full_where}
ORDER BY {order_by}

View file

@ -727,7 +727,11 @@ impl StorageBackend for SqliteBackend {
let mut stmt = db.prepare(
"SELECT id, path, file_name, media_type, content_hash, file_size, \
title, artist, album, genre, year, duration_secs, description, \
thumbnail_path, file_mtime, created_at, updated_at FROM media_items WHERE id = ?1",
thumbnail_path, file_mtime, date_taken, latitude, longitude, \
camera_make, camera_model, rating, perceptual_hash, \
storage_mode, original_filename, uploaded_at, storage_key, \
created_at, updated_at, deleted_at, links_extracted_at \
FROM media_items WHERE id = ?1",
)?;
let mut item = stmt
.query_row(params![id.0.to_string()], row_to_media_item)
@ -754,7 +758,11 @@ impl StorageBackend for SqliteBackend {
let mut stmt = db.prepare(
"SELECT id, path, file_name, media_type, content_hash, file_size, \
title, artist, album, genre, year, duration_secs, description, \
thumbnail_path, file_mtime, created_at, updated_at FROM media_items WHERE content_hash = ?1",
thumbnail_path, file_mtime, date_taken, latitude, longitude, \
camera_make, camera_model, rating, perceptual_hash, \
storage_mode, original_filename, uploaded_at, storage_key, \
created_at, updated_at, deleted_at, links_extracted_at \
FROM media_items WHERE content_hash = ?1",
)?;
let result = stmt
.query_row(params![hash.0], row_to_media_item)
@ -780,7 +788,11 @@ impl StorageBackend for SqliteBackend {
let mut stmt = db.prepare(
"SELECT id, path, file_name, media_type, content_hash, file_size, \
title, artist, album, genre, year, duration_secs, description, \
thumbnail_path, file_mtime, created_at, updated_at FROM media_items WHERE path = ?1",
thumbnail_path, file_mtime, date_taken, latitude, longitude, \
camera_make, camera_model, rating, perceptual_hash, \
storage_mode, original_filename, uploaded_at, storage_key, \
created_at, updated_at, deleted_at, links_extracted_at \
FROM media_items WHERE path = ?1",
)?;
let result = stmt
.query_row(params![path_str], row_to_media_item)
@ -817,7 +829,11 @@ impl StorageBackend for SqliteBackend {
let sql = format!(
"SELECT id, path, file_name, media_type, content_hash, file_size, \
title, artist, album, genre, year, duration_secs, description, \
thumbnail_path, file_mtime, created_at, updated_at FROM media_items \
thumbnail_path, file_mtime, date_taken, latitude, longitude, \
camera_make, camera_model, rating, perceptual_hash, \
storage_mode, original_filename, uploaded_at, storage_key, \
created_at, updated_at, deleted_at, links_extracted_at \
FROM media_items \
WHERE deleted_at IS NULL \
ORDER BY {order_by} LIMIT ?1 OFFSET ?2"
);
@ -1239,7 +1255,10 @@ impl StorageBackend for SqliteBackend {
let mut stmt = db.prepare(
"SELECT m.id, m.path, m.file_name, m.media_type, m.content_hash, m.file_size, \
m.title, m.artist, m.album, m.genre, m.year, m.duration_secs, m.description, \
m.thumbnail_path, m.created_at, m.updated_at \
m.thumbnail_path, m.file_mtime, m.date_taken, m.latitude, m.longitude, \
m.camera_make, m.camera_model, m.rating, m.perceptual_hash, \
m.storage_mode, m.original_filename, m.uploaded_at, m.storage_key, \
m.created_at, m.updated_at, m.deleted_at, m.links_extracted_at \
FROM media_items m \
JOIN collection_members cm ON cm.media_id = m.id \
WHERE cm.collection_id = ?1 \
@ -1275,7 +1294,11 @@ impl StorageBackend for SqliteBackend {
let mut sql = String::from(
"SELECT m.id, m.path, m.file_name, m.media_type, m.content_hash, m.file_size, \
m.title, m.artist, m.album, m.genre, m.year, m.duration_secs, m.description, \
m.thumbnail_path, m.created_at, m.updated_at FROM media_items m ",
m.thumbnail_path, m.file_mtime, m.date_taken, m.latitude, m.longitude, \
m.camera_make, m.camera_model, m.rating, m.perceptual_hash, \
m.storage_mode, m.original_filename, m.uploaded_at, m.storage_key, \
m.created_at, m.updated_at, m.deleted_at, m.links_extracted_at \
FROM media_items m ",
);
if use_fts {

View file

@ -34,6 +34,9 @@ pub struct MediaResponse {
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
// Markdown links
pub links_extracted_at: Option<DateTime<Utc>>,
}
#[derive(Debug, Serialize)]
@ -562,6 +565,9 @@ impl From<pinakes_core::model::MediaItem> for MediaResponse {
created_at: item.created_at,
updated_at: item.updated_at,
// Markdown links
links_extracted_at: item.links_extracted_at,
}
}
}

View file

@ -53,6 +53,8 @@ pub struct MediaResponse {
pub custom_fields: HashMap<String, CustomFieldResponse>,
pub created_at: String,
pub updated_at: String,
#[serde(default)]
pub links_extracted_at: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]

View file

@ -634,6 +634,15 @@ pub fn Detail(
span { class: "detail-label", "Updated" }
span { class: "detail-value", "{media.updated_at}" }
}
// Links extracted timestamp (only for markdown files)
if media.media_type == "md" || media.media_type == "markdown" {
if let Some(links_time) = &media.links_extracted_at {
div { class: "detail-field",
span { class: "detail-label", "Links Extracted" }
span { class: "detail-value", "{links_time}" }
}
}
}
}
}