fix: issue #7 rebuild media links to get gallery working again
This commit is contained in:
@@ -196,6 +196,14 @@ defmodule BDS.Desktop.ShellCommands do
|
||||
end)
|
||||
end
|
||||
|
||||
defp dispatch("rebuild_media_links", project, _params) do
|
||||
queue_task(project, "rebuild_media_links", "Rebuild Media Links", "Maintenance", fn report ->
|
||||
{:ok, result} = BDS.Media.rebuild_media_links(project.id, on_progress: report)
|
||||
report.(1.0, "Media links rebuilt")
|
||||
%{project_id: project.id, counts: %{media_links: result.links}}
|
||||
end)
|
||||
end
|
||||
|
||||
defp dispatch("regenerate_missing_thumbnails", project, _params) do
|
||||
queue_task(
|
||||
project,
|
||||
|
||||
@@ -375,7 +375,8 @@
|
||||
<button class="secondary ui-button ui-button-secondary" type="button" phx-click="settings_shell_command" phx-value-action="rebuild_media_from_files"><%= dgettext("ui", "Rebuild Media From Files") %></button>
|
||||
<button class="secondary ui-button ui-button-secondary" type="button" phx-click="settings_shell_command" phx-value-action="rebuild_scripts_from_files"><%= dgettext("ui", "Rebuild Scripts From Files") %></button>
|
||||
<button class="secondary ui-button ui-button-secondary" type="button" phx-click="settings_shell_command" phx-value-action="rebuild_templates_from_files"><%= dgettext("ui", "Rebuild Templates From Files") %></button>
|
||||
<button class="secondary ui-button ui-button-secondary" type="button" phx-click="settings_shell_command" phx-value-action="rebuild_post_links"><%= dgettext("ui", "Rebuild Links") %></button>
|
||||
<button class="secondary ui-button ui-button-secondary" type="button" phx-click="settings_shell_command" phx-value-action="rebuild_post_links"><%= dgettext("ui", "Rebuild Post Links") %></button>
|
||||
<button class="secondary ui-button ui-button-secondary" type="button" phx-click="settings_shell_command" phx-value-action="rebuild_media_links"><%= dgettext("ui", "Rebuild Media Links") %></button>
|
||||
<button class="secondary ui-button ui-button-secondary" type="button" phx-click="settings_shell_command" phx-value-action="regenerate_missing_thumbnails"><%= dgettext("ui", "Regenerate Missing Thumbnails") %></button>
|
||||
<button class="secondary ui-button ui-button-secondary" type="button" phx-click="settings_shell_command" phx-value-action="rebuild_embedding_index"><%= dgettext("ui", "Rebuild Embedding Index") %></button>
|
||||
<button class="secondary ui-button ui-button-secondary" type="button" phx-click="settings_shell_command" phx-value-action="open_data_folder"><%= dgettext("ui", "Open Data Folder") %></button>
|
||||
|
||||
@@ -66,6 +66,12 @@ defmodule BDS.Media do
|
||||
defdelegate link_media_to_post(media_id, post_id), to: BDS.Media.Linking
|
||||
defdelegate unlink_media_from_post(media_id, post_id), to: BDS.Media.Linking
|
||||
|
||||
defdelegate rebuild_media_links(project_id), to: BDS.Media.Linking,
|
||||
as: :rebuild_links_from_sidecars
|
||||
|
||||
defdelegate rebuild_media_links(project_id, opts), to: BDS.Media.Linking,
|
||||
as: :rebuild_links_from_sidecars
|
||||
|
||||
defdelegate rebuild_media_from_files(project_id), to: BDS.Media.Rebuilder
|
||||
defdelegate rebuild_media_from_files(project_id, opts), to: BDS.Media.Rebuilder
|
||||
|
||||
|
||||
@@ -5,6 +5,13 @@ defmodule BDS.Media.Linking do
|
||||
|
||||
import Ecto.Query
|
||||
|
||||
import BDS.Media.FileOps,
|
||||
only: [
|
||||
progress_callback: 1,
|
||||
report_rebuild_progress: 4,
|
||||
report_rebuild_started: 3
|
||||
]
|
||||
|
||||
alias BDS.Media.Media
|
||||
alias BDS.Media.Sidecars
|
||||
alias BDS.Persistence
|
||||
@@ -134,6 +141,45 @@ defmodule BDS.Media.Linking do
|
||||
|
||||
def restore_post_links(_project_id, _media_id, _post_ids), do: :ok
|
||||
|
||||
@doc """
|
||||
Rebuild the `post_media` junction for a project from every media sidecar's
|
||||
`linkedPostIds`.
|
||||
|
||||
Media sidecars are the source of truth for gallery associations (matching the
|
||||
old bDS `rebuildFromSidecars`). Existing project links are cleared and then
|
||||
re-created from the on-disk sidecars, so galleries reflect the project's
|
||||
metadata even if the junction table drifted or was never populated. Links to
|
||||
posts that are not present in the database are skipped.
|
||||
"""
|
||||
@spec rebuild_links_from_sidecars(String.t(), keyword()) ::
|
||||
{:ok, %{media: non_neg_integer(), links: non_neg_integer()}}
|
||||
def rebuild_links_from_sidecars(project_id, opts \\ []) when is_binary(project_id) do
|
||||
project = Projects.get_project!(project_id)
|
||||
on_progress = progress_callback(opts)
|
||||
|
||||
media_list =
|
||||
Repo.all(from m in Media, where: m.project_id == ^project_id, order_by: [asc: m.id])
|
||||
|
||||
total = length(media_list)
|
||||
:ok = report_rebuild_started(on_progress, total, "media links")
|
||||
|
||||
{_cleared, _} =
|
||||
Repo.delete_all(from pm in PostMedia, where: pm.project_id == ^project_id)
|
||||
|
||||
media_list
|
||||
|> Enum.with_index(1)
|
||||
|> Enum.each(fn {media, index} ->
|
||||
post_ids = Sidecars.read_linked_post_ids(project, media)
|
||||
restore_post_links(project_id, media.id, post_ids)
|
||||
:ok = report_rebuild_progress(on_progress, index, total, "media links")
|
||||
end)
|
||||
|
||||
links =
|
||||
Repo.aggregate(from(pm in PostMedia, where: pm.project_id == ^project_id), :count)
|
||||
|
||||
{:ok, %{media: total, links: links}}
|
||||
end
|
||||
|
||||
defp ensure_link(project_id, media_id, post_id) do
|
||||
already_linked? =
|
||||
Repo.exists?(
|
||||
|
||||
@@ -349,6 +349,29 @@ defmodule BDS.Media.Sidecars do
|
||||
|> File.exists?()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Read the `linkedPostIds` list persisted in a media item's canonical sidecar.
|
||||
|
||||
The media sidecar is the source of truth for gallery associations (matching
|
||||
the old bDS `linkedPostIds` field). Returns `[]` when the sidecar is missing
|
||||
or has no linked posts.
|
||||
"""
|
||||
@spec read_linked_post_ids(BDS.Projects.Project.t(), Media.t()) :: [String.t()]
|
||||
def read_linked_post_ids(project, %Media{} = media) do
|
||||
sidecar_path = Path.join(Projects.project_data_dir(project), media.sidecar_path)
|
||||
|
||||
case parse_existing_canonical_sidecar(project, sidecar_path) do
|
||||
{:ok, sidecar} ->
|
||||
sidecar.fields
|
||||
|> DocumentFields.get("linkedPostIds", [])
|
||||
|> List.wrap()
|
||||
|> Enum.filter(&is_binary/1)
|
||||
|
||||
{:error, _reason} ->
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
defp parse_existing_canonical_sidecar(project, sidecar_path) do
|
||||
if File.exists?(sidecar_path) do
|
||||
parse_canonical_sidecar(project, sidecar_path)
|
||||
|
||||
Reference in New Issue
Block a user