Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ebf5d6afb5 |
@@ -0,0 +1,70 @@
|
|||||||
|
defmodule Pinchflat.Boot.NfoBackfillWorker do
|
||||||
|
@moduledoc false
|
||||||
|
|
||||||
|
use Oban.Worker,
|
||||||
|
queue: :local_metadata,
|
||||||
|
# This should have it running once _ever_ (until the job is pruned, anyway)
|
||||||
|
# NOTE: remove within the next month
|
||||||
|
unique: [period: :infinity, states: Oban.Job.states()],
|
||||||
|
tags: ["media_item", "media_metadata", "local_metadata", "data_backfill"]
|
||||||
|
|
||||||
|
import Ecto.Query, warn: false
|
||||||
|
require Logger
|
||||||
|
|
||||||
|
alias Pinchflat.Repo
|
||||||
|
alias Pinchflat.Media
|
||||||
|
alias Pinchflat.Media.MediaItem
|
||||||
|
alias Pinchflat.Metadata.NfoBuilder
|
||||||
|
alias Pinchflat.Metadata.MetadataFileHelpers
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Runs a one-off backfill job to regenerate NFO files for media items that have
|
||||||
|
both an NFO file and a metadata file. This is needed because NFO files weren't
|
||||||
|
escaping characters properly so we need to regenerate them.
|
||||||
|
|
||||||
|
This job will only run once as long as I remove it before the jobs are pruned in a month.
|
||||||
|
|
||||||
|
Returns :ok
|
||||||
|
"""
|
||||||
|
@impl Oban.Worker
|
||||||
|
def perform(%Oban.Job{}) do
|
||||||
|
Logger.info("Running NFO backfill worker")
|
||||||
|
|
||||||
|
media_items = get_media_items_to_backfill()
|
||||||
|
|
||||||
|
Enum.each(media_items, fn media_item ->
|
||||||
|
nfo_exists = File.exists?(media_item.nfo_filepath)
|
||||||
|
metadata_exists = File.exists?(media_item.metadata.metadata_filepath)
|
||||||
|
|
||||||
|
if nfo_exists && metadata_exists do
|
||||||
|
Logger.info("NFO and metadata exist for media item #{media_item.id} - proceeding")
|
||||||
|
|
||||||
|
regenerate_nfo_for_media_item(media_item)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_media_items_to_backfill do
|
||||||
|
from(m in MediaItem, where: not is_nil(m.nfo_filepath))
|
||||||
|
|> Repo.all()
|
||||||
|
|> Repo.preload([:metadata, source: :media_profile])
|
||||||
|
end
|
||||||
|
|
||||||
|
defp regenerate_nfo_for_media_item(media_item) do
|
||||||
|
try do
|
||||||
|
case MetadataFileHelpers.read_compressed_metadata(media_item.metadata.metadata_filepath) do
|
||||||
|
{:ok, metadata} ->
|
||||||
|
Media.update_media_item(media_item, %{
|
||||||
|
nfo_filepath: NfoBuilder.build_and_store_for_media_item(media_item.nfo_filepath, metadata)
|
||||||
|
})
|
||||||
|
|
||||||
|
_err ->
|
||||||
|
Logger.error("Failed to read metadata for media item #{media_item.id}")
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
e -> Logger.error("Unknown error regenerating NFO file for MI ##{media_item.id}: #{inspect(e)}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -7,6 +7,9 @@ defmodule Pinchflat.Boot.PostJobStartupTasks do
|
|||||||
Phoenix supervision tree.
|
Phoenix supervision tree.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
alias Pinchflat.Repo
|
||||||
|
alias Pinchflat.Boot.NfoBackfillWorker
|
||||||
|
|
||||||
# restart: :temporary means that this process will never be restarted (ie: will run once and then die)
|
# restart: :temporary means that this process will never be restarted (ie: will run once and then die)
|
||||||
use GenServer, restart: :temporary
|
use GenServer, restart: :temporary
|
||||||
import Ecto.Query, warn: false
|
import Ecto.Query, warn: false
|
||||||
@@ -26,7 +29,7 @@ defmodule Pinchflat.Boot.PostJobStartupTasks do
|
|||||||
"""
|
"""
|
||||||
@impl true
|
@impl true
|
||||||
def init(state) do
|
def init(state) do
|
||||||
# Nothing at the moment!
|
Repo.insert_unique_job(NfoBackfillWorker.new(%{}))
|
||||||
|
|
||||||
{:ok, state}
|
{:ok, state}
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -62,6 +62,31 @@ defmodule PinchflatWeb.Sources.SourceController do
|
|||||||
render(conn, :show, source: source, pending_tasks: pending_tasks)
|
render(conn, :show, source: source, pending_tasks: pending_tasks)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# TODO: test
|
||||||
|
# TODO: also do for media items
|
||||||
|
# TODO: check to see if I've lost the plot here
|
||||||
|
def show_image(conn, %{"source_id" => id, "image_type" => image_type}) do
|
||||||
|
source = Sources.get_source!(id)
|
||||||
|
|
||||||
|
filepath =
|
||||||
|
case image_type do
|
||||||
|
"poster" -> source.poster_filepath
|
||||||
|
"fanart" -> source.fanart_filepath
|
||||||
|
"banner" -> source.banner_filepath
|
||||||
|
_ -> nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if filepath && File.exists?(filepath) do
|
||||||
|
conn
|
||||||
|
|> put_resp_content_type(MIME.from_path(filepath))
|
||||||
|
|> send_file(200, filepath)
|
||||||
|
else
|
||||||
|
conn
|
||||||
|
|> put_status(404)
|
||||||
|
|> text("Image not found")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def edit(conn, %{"id" => id}) do
|
def edit(conn, %{"id" => id}) do
|
||||||
source = Sources.get_source!(id)
|
source = Sources.get_source!(id)
|
||||||
changeset = Sources.change_source(source)
|
changeset = Sources.change_source(source)
|
||||||
|
|||||||
@@ -25,6 +25,16 @@ defmodule PinchflatWeb.Sources.SourceHTML do
|
|||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def source_image_mapping(source) do
|
||||||
|
image_mapping = [
|
||||||
|
{"Poster", source.poster_filepath, "poster"},
|
||||||
|
{"Banner", source.banner_filepath, "banner"},
|
||||||
|
{"Fanart", source.fanart_filepath, "fanart"}
|
||||||
|
]
|
||||||
|
|
||||||
|
Enum.filter(image_mapping, fn {_, filepath, _} -> filepath end)
|
||||||
|
end
|
||||||
|
|
||||||
def rss_feed_url(conn, source) do
|
def rss_feed_url(conn, source) do
|
||||||
url(conn, ~p"/sources/#{source.uuid}/feed") <> ".xml"
|
url(conn, ~p"/sources/#{source.uuid}/feed") <> ".xml"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -36,6 +36,23 @@
|
|||||||
<.list_items_from_map map={Map.from_struct(@source)} />
|
<.list_items_from_map map={Map.from_struct(@source)} />
|
||||||
</div>
|
</div>
|
||||||
</:tab>
|
</:tab>
|
||||||
|
<:tab title="Images">
|
||||||
|
<section>
|
||||||
|
<h3 class="font-bold text-xl mt-6 mb-4">Images</h3>
|
||||||
|
<%= if source_image_mapping(@source) == [] do %>
|
||||||
|
<p class="text-black dark:text-white">Nothing Here!</p>
|
||||||
|
<% else %>
|
||||||
|
<div class="grid grid-cols-1 gap-4 lg:grid-cols-3">
|
||||||
|
<div :for={{name, _, image_type} <- source_image_mapping(@source)}>
|
||||||
|
<span><%= name %></span>
|
||||||
|
<a href={~p"/sources/#{@source}/image/#{image_type}"} target="_blank">
|
||||||
|
<img src={~p"/sources/#{@source}/image/#{image_type}"} alt={name} class="w-full h-auto" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</section>
|
||||||
|
</:tab>
|
||||||
<:tab title="Pending Media">
|
<:tab title="Pending Media">
|
||||||
<%= live_render(
|
<%= live_render(
|
||||||
@conn,
|
@conn,
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ defmodule PinchflatWeb.Router do
|
|||||||
resources "/settings", Settings.SettingController, only: [:show, :update], singleton: true
|
resources "/settings", Settings.SettingController, only: [:show, :update], singleton: true
|
||||||
|
|
||||||
resources "/sources", Sources.SourceController do
|
resources "/sources", Sources.SourceController do
|
||||||
|
get "/image/:image_type", Sources.SourceController, :show_image
|
||||||
post "/force_download", Sources.SourceController, :force_download
|
post "/force_download", Sources.SourceController, :force_download
|
||||||
post "/force_index", Sources.SourceController, :force_index
|
post "/force_index", Sources.SourceController, :force_index
|
||||||
post "/force_metadata_refresh", Sources.SourceController, :force_metadata_refresh
|
post "/force_metadata_refresh", Sources.SourceController, :force_metadata_refresh
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ defmodule Pinchflat.MixProject do
|
|||||||
def project do
|
def project do
|
||||||
[
|
[
|
||||||
app: :pinchflat,
|
app: :pinchflat,
|
||||||
version: "0.1.15",
|
version: "0.1.14",
|
||||||
elixir: "~> 1.16",
|
elixir: "~> 1.16",
|
||||||
elixirc_paths: elixirc_paths(Mix.env()),
|
elixirc_paths: elixirc_paths(Mix.env()),
|
||||||
start_permanent: Mix.env() == :prod,
|
start_permanent: Mix.env() == :prod,
|
||||||
|
|||||||
Reference in New Issue
Block a user