Hooked up script runner for indexing

This commit is contained in:
Kieran Eglin
2024-05-28 10:43:54 -07:00
parent 5d624f545b
commit c5bf51dfb3
9 changed files with 182 additions and 15 deletions
@@ -16,10 +16,14 @@ defmodule Pinchflat.Downloading.DownloadingHelpers do
alias Pinchflat.Media.MediaItem
alias Pinchflat.Downloading.MediaDownloadWorker
alias Pinchflat.Lifecycle.UserScripts.CommandRunner, as: UserScriptRunner
@doc """
Starts tasks for downloading media for any of a sources _pending_ media items.
Jobs are not enqueued if the source is set to not download media. This will return :ok.
You can optionally set the `kickoff_delay` option to delay when the jobs are enqueued.
NOTE: this starts a download for each media item that is pending,
not just the ones that were indexed in this job run. This should ensure
that any stragglers are caught if, for some reason, they weren't enqueued
@@ -30,8 +34,6 @@ defmodule Pinchflat.Downloading.DownloadingHelpers do
def enqueue_pending_download_tasks(source, opts \\ [])
def enqueue_pending_download_tasks(%Source{download_media: true} = source, opts) do
# TODO: test
# TODO: doc
kickoff_delay = Keyword.get(opts, :kickoff_delay, 0)
source
@@ -59,11 +61,11 @@ defmodule Pinchflat.Downloading.DownloadingHelpers do
downloaded, based on the source's download settings and whether media is
considered pending.
You can optionally set the `kickoff_delay` option to delay when the jobs are enqueued.
Returns {:ok, %Task{}} | {:error, :should_not_download} | {:error, any()}
"""
def kickoff_download_if_pending(%MediaItem{} = media_item, opts \\ []) do
# TODO: test
# TODO: doc
kickoff_delay = Keyword.get(opts, :kickoff_delay, 0)
media_item = Repo.preload(media_item, :source)
@@ -107,4 +109,32 @@ defmodule Pinchflat.Downloading.DownloadingHelpers do
|> Repo.all()
|> Enum.map(&MediaDownloadWorker.kickoff_with_task/1)
end
@doc """
Creates a media item from the attributes returned by the video backend
(read: yt-dlp) and runs the user script with a `media_indexed` event type.
Only runs the user script if the media item was created successfully and the media item
doesn't already exist in the database.
Returns {:ok, %MediaItem{}} | {:error, any()}
"""
def create_media_item_and_run_script(%Source{} = source, media_attrs_struct) do
media_already_exists =
MediaQuery.new()
|> where(^dynamic(^MediaQuery.for_source(source) and ^MediaQuery.media_id(media_attrs_struct.media_id)))
|> Repo.exists?()
case Media.create_media_item_from_backend_attrs(source, media_attrs_struct) do
{:ok, media_item} ->
if !media_already_exists do
UserScriptRunner.run(:media_indexed, media_item)
end
{:ok, media_item}
err ->
err
end
end
end
@@ -10,7 +10,6 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpers do
use Pinchflat.Media.MediaQuery
alias Pinchflat.Repo
alias Pinchflat.Media
alias Pinchflat.Sources.Source
alias Pinchflat.FastIndexing.YoutubeRss
alias Pinchflat.Downloading.DownloadingHelpers
@@ -43,7 +42,6 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpers do
end)
# Wait 5s before enqueuing downloads to give the post-indexing user script a chance to run
# TODO: test
DownloadingHelpers.enqueue_pending_download_tasks(source, kickoff_delay: 5)
Enum.filter(maybe_new_media_items, & &1)
@@ -59,8 +57,8 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpers do
url = "https://www.youtube.com/watch?v=#{media_id}"
case YtDlpMedia.get_media_attributes(url) do
{:ok, media_attrs} ->
Media.create_media_item_from_backend_attrs(source, media_attrs)
{:ok, media_attrs_struct} ->
DownloadingHelpers.create_media_item_and_run_script(source, media_attrs_struct)
err ->
err
@@ -12,6 +12,7 @@ defmodule Pinchflat.Lifecycle.UserScripts.CommandRunner do
@behaviour UserScriptCommandRunner
@event_types [
:media_indexed,
:media_downloaded,
:media_deleted
]
+2
View File
@@ -35,6 +35,8 @@ defmodule Pinchflat.Media.MediaQuery do
def culling_prevented, do: dynamic([mi], mi.prevent_culling == true)
def culled, do: dynamic([mi], not is_nil(mi.culled_at))
def redownloaded, do: dynamic([mi], not is_nil(mi.media_redownloaded_at))
def media_id(nil), do: dynamic(false)
def media_id(media_id), do: dynamic([mi], mi.media_id == ^media_id)
def upload_date_after_source_cutoff do
dynamic([mi, source], is_nil(source.download_cutoff_date) or mi.upload_date >= source.download_cutoff_date)
@@ -8,7 +8,6 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpers do
require Logger
alias Pinchflat.Repo
alias Pinchflat.Media
alias Pinchflat.Tasks
alias Pinchflat.Sources
alias Pinchflat.Sources.Source
@@ -39,6 +38,9 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpers do
item belonging to the source. You can't tell me the method name isn't descriptive!
Returns a list of media items or changesets (if the media item couldn't be created).
For each new media item, the method will also run a user script with the `media_indexed`
event, if the script is present.
Indexing is slow and usually returns a list of all media data at once for record creation.
To help with this, we use a file follower to watch the file that yt-dlp writes to
so we can create media items as they come in. This parallelizes the process and adds
@@ -64,8 +66,8 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpers do
source = Repo.reload!(source)
result =
Enum.map(media_attributes, fn media_attrs ->
case Media.create_media_item_from_backend_attrs(source, media_attrs) do
Enum.map(media_attributes, fn media_attrs_struct ->
case DownloadingHelpers.create_media_item_and_run_script(source, media_attrs_struct) do
{:ok, media_item} -> media_item
{:error, changeset} -> changeset
end
@@ -73,7 +75,6 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpers do
Sources.update_source(source, %{last_indexed_at: DateTime.utc_now()})
# Wait 5s before enqueuing downloads to give the post-indexing user script a chance to run
# TODO: test
DownloadingHelpers.enqueue_pending_download_tasks(source, kickoff_delay: 5)
result
@@ -120,15 +121,14 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpers do
end)
end
defp create_media_item_and_enqueue_download(source, media_attrs) do
defp create_media_item_and_enqueue_download(source, media_attrs_struct) do
# Reload because the source may have been updated during the (long-running) indexing process
# and important settings like `download_media` may have changed.
source = Repo.reload!(source)
case Media.create_media_item_from_backend_attrs(source, media_attrs) do
case DownloadingHelpers.create_media_item_and_run_script(source, media_attrs_struct) do
{:ok, %MediaItem{} = media_item} ->
# Wait 5s before enqueuing downloads to give the post-indexing user script a chance to run
# TODO: test
DownloadingHelpers.kickoff_download_if_pending(media_item, kickoff_delay: 5)
{:error, changeset} ->