[Enhancement] Media from before a source's cutoff date is now automatically deleted (#329)
* Changed the purpose of the 'culled_at' flag. renamed some methods * implemented new culling behaviour for source cutoff dates * Removed culled_at flag if a media item gets redownloaded * Updated source form * Removed unused method
This commit is contained in:
@@ -91,8 +91,7 @@ defmodule Pinchflat.Downloading.DownloadingHelpers do
|
||||
[m, s, mp],
|
||||
^MediaQuery.for_source(source) and
|
||||
^MediaQuery.downloaded() and
|
||||
not (^MediaQuery.download_prevented()) and
|
||||
not (^MediaQuery.culled())
|
||||
not (^MediaQuery.download_prevented())
|
||||
)
|
||||
)
|
||||
|> Repo.all()
|
||||
|
||||
@@ -79,6 +79,7 @@ defmodule Pinchflat.Downloading.MediaDownloader do
|
||||
|> MetadataParser.parse_for_media_item()
|
||||
|> Map.merge(%{
|
||||
media_downloaded_at: DateTime.utc_now(),
|
||||
culled_at: nil,
|
||||
nfo_filepath: determine_nfo_filepath(media_with_preloads, parsed_json),
|
||||
metadata: %{
|
||||
# IDEA: might be worth kicking off a job for this since thumbnail fetching
|
||||
|
||||
@@ -23,10 +23,10 @@ defmodule Pinchflat.Downloading.MediaQualityUpgradeWorker do
|
||||
"""
|
||||
@impl Oban.Worker
|
||||
def perform(%Oban.Job{}) do
|
||||
redownloadable_media = Media.list_redownloadable_media_items()
|
||||
Logger.info("Redownloading #{length(redownloadable_media)} media items")
|
||||
upgradable_media = Media.list_upgradeable_media_items()
|
||||
Logger.info("Redownloading #{length(upgradable_media)} media items")
|
||||
|
||||
Enum.each(redownloadable_media, fn media_item ->
|
||||
Enum.each(upgradable_media, fn media_item ->
|
||||
MediaDownloadWorker.kickoff_with_task(media_item, %{quality_upgrade?: true})
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -6,8 +6,11 @@ defmodule Pinchflat.Downloading.MediaRetentionWorker do
|
||||
unique: [period: :infinity, states: [:available, :scheduled, :retryable, :executing]],
|
||||
tags: ["media_item", "local_metadata"]
|
||||
|
||||
use Pinchflat.Media.MediaQuery
|
||||
|
||||
require Logger
|
||||
|
||||
alias Pinchflat.Repo
|
||||
alias Pinchflat.Media
|
||||
|
||||
@doc """
|
||||
@@ -20,14 +23,51 @@ defmodule Pinchflat.Downloading.MediaRetentionWorker do
|
||||
"""
|
||||
@impl Oban.Worker
|
||||
def perform(%Oban.Job{}) do
|
||||
cullable_media = Media.list_cullable_media_items()
|
||||
cull_cullable_media_items()
|
||||
delete_media_items_from_before_cutoff()
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
defp cull_cullable_media_items do
|
||||
cullable_media =
|
||||
MediaQuery.new()
|
||||
|> MediaQuery.require_assoc(:source)
|
||||
|> where(^MediaQuery.cullable())
|
||||
|> Repo.all()
|
||||
|
||||
Logger.info("Culling #{length(cullable_media)} media items past their retention date")
|
||||
|
||||
Enum.each(cullable_media, fn media_item ->
|
||||
# Setting `prevent_download` does what it says on the tin, but `culled_at` is purely informational.
|
||||
# We don't actually do anything with that in terms of queries and it gets set to nil if the media item
|
||||
# gets re-downloaded.
|
||||
Media.delete_media_files(media_item, %{
|
||||
prevent_download: true,
|
||||
culled_at: DateTime.utc_now()
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
defp delete_media_items_from_before_cutoff do
|
||||
deletable_media =
|
||||
MediaQuery.new()
|
||||
|> MediaQuery.require_assoc(:source)
|
||||
|> where(^MediaQuery.deletable_based_on_source_cutoff())
|
||||
|> Repo.all()
|
||||
|
||||
Logger.info("Deleting #{length(deletable_media)} media items that are from before the source cutoff")
|
||||
|
||||
Enum.each(deletable_media, fn media_item ->
|
||||
# Note that I'm not setting `prevent_download` on the media_item here.
|
||||
# That's because cutoff_date can easily change and it's a valid behavior to re-download older
|
||||
# media items if the cutoff_date changes.
|
||||
# Download is ultimately prevented because `MediaQuery.pending()` only returns media items
|
||||
# from after the cutoff date (among other things), so it's not like the media will just immediately
|
||||
# be re-downloaded.
|
||||
Media.delete_media_files(media_item, %{
|
||||
culled_at: DateTime.utc_now()
|
||||
})
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -25,21 +25,10 @@ defmodule Pinchflat.Media do
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns a list of media_items that are cullable based on the retention period
|
||||
of the source they belong to.
|
||||
|
||||
Returns [%MediaItem{}, ...]
|
||||
"""
|
||||
def list_cullable_media_items do
|
||||
MediaQuery.new()
|
||||
|> MediaQuery.require_assoc(:source)
|
||||
|> where(^MediaQuery.cullable())
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns a list of media_items that are redownloadable based on the redownload delay
|
||||
of the media_profile their source belongs to.
|
||||
Returns a list of media_items that are upgradeable based on the redownload delay
|
||||
of the media_profile their source belongs to. In this context, upgradeable means
|
||||
that it's been long enough since upload that the video may be in a higher quality
|
||||
or have better sponsorblock segments (or similar).
|
||||
|
||||
The logic is that a media_item is past_redownload_delay if the media_item's uploaded_at is
|
||||
at least redownload_delay_days ago AND `media_downloaded_at` - `redownload_delay_days`
|
||||
@@ -52,10 +41,10 @@ defmodule Pinchflat.Media do
|
||||
|
||||
Returns [%MediaItem{}, ...]
|
||||
"""
|
||||
def list_redownloadable_media_items do
|
||||
def list_upgradeable_media_items do
|
||||
MediaQuery.new()
|
||||
|> MediaQuery.require_assoc(:media_profile)
|
||||
|> where(^MediaQuery.redownloadable())
|
||||
|> where(^MediaQuery.upgradeable())
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ defmodule Pinchflat.Media.MediaQuery do
|
||||
def downloaded, do: dynamic([mi], not is_nil(mi.media_filepath))
|
||||
def download_prevented, do: dynamic([mi], mi.prevent_download == true)
|
||||
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 upload_date_matches(other_date), do: dynamic([mi], fragment("date(?) = date(?)", mi.uploaded_at, ^other_date))
|
||||
|
||||
@@ -108,6 +107,15 @@ defmodule Pinchflat.Media.MediaQuery do
|
||||
)
|
||||
end
|
||||
|
||||
def deletable_based_on_source_cutoff do
|
||||
dynamic(
|
||||
[mi, source],
|
||||
^downloaded() and
|
||||
not (^upload_date_after_source_cutoff()) and
|
||||
not (^culling_prevented())
|
||||
)
|
||||
end
|
||||
|
||||
def pending do
|
||||
dynamic(
|
||||
[mi],
|
||||
@@ -119,12 +127,11 @@ defmodule Pinchflat.Media.MediaQuery do
|
||||
)
|
||||
end
|
||||
|
||||
def redownloadable do
|
||||
def upgradeable do
|
||||
dynamic(
|
||||
[mi, source],
|
||||
^downloaded() and
|
||||
not (^download_prevented()) and
|
||||
not (^culled()) and
|
||||
not (^redownloaded()) and
|
||||
^past_redownload_delay()
|
||||
)
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
maxlength="10"
|
||||
pattern="((?:19|20)[0-9][0-9])-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])"
|
||||
title="YYYY-MM-DD"
|
||||
help="Only download media uploaded after this date. Leave blank to download all media. Must be in YYYY-MM-DD format"
|
||||
help="Only download media uploaded after this date. Leave blank to download all media. Must be in YYYY-MM-DD format. Old media may be deleted or downloaded if you change this date"
|
||||
/>
|
||||
|
||||
<.input
|
||||
|
||||
Reference in New Issue
Block a user