mirror of
https://github.com/kieraneglin/pinchflat.git
synced 2026-01-23 02:24:24 +00:00
[Enhancement] Capture playlist_index for use with output templates (#315)
* Started capturing playlist_index on indexing pass * Added playlist_index as a media item field * Added playlist index to output variable templates * Improved the way playlist_indexes are rejected on update * Updated docs * Undid unneeded changes
This commit is contained in:
parent
5a10015634
commit
e06e050f95
9 changed files with 67 additions and 11 deletions
|
|
@ -203,6 +203,7 @@ defmodule Pinchflat.Downloading.DownloadOptionBuilder do
|
|||
"source_collection_id" => source.collection_id,
|
||||
"source_collection_name" => source.collection_name,
|
||||
"source_collection_type" => to_string(source.collection_type),
|
||||
"media_playlist_index" => to_string(media_item_with_preloads.playlist_index),
|
||||
"media_upload_date_index" =>
|
||||
media_item_with_preloads.upload_date_index
|
||||
|> to_string()
|
||||
|
|
|
|||
|
|
@ -142,12 +142,17 @@ defmodule Pinchflat.Media do
|
|||
"""
|
||||
def create_media_item_from_backend_attrs(source, media_attrs_struct) do
|
||||
attrs = Map.merge(%{source_id: source.id}, Map.from_struct(media_attrs_struct))
|
||||
# Some fields should only be set on insert and not on update.
|
||||
fields_to_drop_on_update = [:playlist_index]
|
||||
|
||||
%MediaItem{}
|
||||
|> MediaItem.changeset(attrs)
|
||||
|> Repo.insert(
|
||||
on_conflict: [
|
||||
set: Map.to_list(attrs)
|
||||
set:
|
||||
attrs
|
||||
|> Map.drop(fields_to_drop_on_update)
|
||||
|> Map.to_list()
|
||||
],
|
||||
conflict_target: [:source_id, :media_id]
|
||||
)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ defmodule Pinchflat.Media.MediaItem do
|
|||
alias Pinchflat.Media.MediaItemsSearchIndex
|
||||
|
||||
@allowed_fields [
|
||||
# these fields are only captured on index
|
||||
:playlist_index,
|
||||
# these fields are captured on indexing (and again on download)
|
||||
:title,
|
||||
:media_id,
|
||||
|
|
@ -72,6 +74,7 @@ defmodule Pinchflat.Media.MediaItem do
|
|||
field :uploaded_at, :utc_datetime
|
||||
field :upload_date_index, :integer, default: 0
|
||||
field :duration_seconds, :integer
|
||||
field :playlist_index, :integer, default: 0
|
||||
|
||||
field :media_filepath, :string
|
||||
field :media_size_bytes, :integer
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ defmodule Pinchflat.YtDlp.Media do
|
|||
:livestream,
|
||||
:short_form_content,
|
||||
:uploaded_at,
|
||||
:duration_seconds
|
||||
:duration_seconds,
|
||||
:playlist_index
|
||||
]
|
||||
|
||||
alias __MODULE__
|
||||
|
|
@ -63,7 +64,7 @@ defmodule Pinchflat.YtDlp.Media do
|
|||
@doc """
|
||||
Returns a map representing the media at the given URL.
|
||||
|
||||
Returns {:ok, [map()]} | {:error, any, ...}.
|
||||
Returns {:ok, %Media{}} | {:error, any, ...}.
|
||||
"""
|
||||
def get_media_attributes(url) do
|
||||
runner = Application.get_env(:pinchflat, :yt_dlp_runner)
|
||||
|
|
@ -84,9 +85,11 @@ defmodule Pinchflat.YtDlp.Media do
|
|||
|
||||
@doc """
|
||||
Returns the output template for yt-dlp's indexing command.
|
||||
|
||||
NOTE: playlist_index is really only useful for playlists that will never change their order.
|
||||
"""
|
||||
def indexing_output_template do
|
||||
"%(.{id,title,was_live,webpage_url,description,aspect_ratio,duration,upload_date,timestamp})j"
|
||||
"%(.{id,title,was_live,webpage_url,description,aspect_ratio,duration,upload_date,timestamp,playlist_index})j"
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
|
@ -104,7 +107,8 @@ defmodule Pinchflat.YtDlp.Media do
|
|||
livestream: !!response["was_live"],
|
||||
duration_seconds: response["duration"] && round(response["duration"]),
|
||||
short_form_content: response["webpage_url"] && short_form_content?(response),
|
||||
uploaded_at: response["upload_date"] && parse_uploaded_at(response)
|
||||
uploaded_at: response["upload_date"] && parse_uploaded_at(response),
|
||||
playlist_index: response["playlist_index"] || 0
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,9 @@ defmodule PinchflatWeb.MediaProfiles.MediaProfileHTML do
|
|||
season_from_date: "alias for upload_year",
|
||||
season_episode_from_date: "the upload date formatted as sYYYYeMMDD",
|
||||
season_episode_index_from_date:
|
||||
"the upload date formatted as sYYYYeMMDDII where II is an index to prevent date collisions"
|
||||
"the upload date formatted as sYYYYeMMDDII where II is an index to prevent date collisions",
|
||||
media_playlist_index:
|
||||
"the place of the media item in the playlist. Do not use with channels. May not work if the playlist is updated"
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 493 KiB After Width: | Height: | Size: 424 KiB |
|
|
@ -0,0 +1,9 @@
|
|||
defmodule Pinchflat.Repo.Migrations.AddPlaylistIndexToMediaItems do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
alter table(:media_items) do
|
||||
add :playlist_index, :integer, null: false, default: 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -689,7 +689,24 @@ defmodule Pinchflat.MediaTest do
|
|||
assert {:ok, %MediaItem{} = media_item_2} = Media.create_media_item_from_backend_attrs(source, different_attrs)
|
||||
|
||||
assert media_item_1.id == media_item_2.id
|
||||
assert media_item_2.title == different_attrs.title
|
||||
assert Repo.reload(media_item_2).title == different_attrs.title
|
||||
end
|
||||
|
||||
test "doesn't update fields like playlist_index" do
|
||||
source = source_fixture()
|
||||
|
||||
media_attrs =
|
||||
media_attributes_return_fixture()
|
||||
|> Phoenix.json_library().decode!()
|
||||
|> Map.put("playlist_index", 1)
|
||||
|> YtDlpMedia.response_to_struct()
|
||||
|
||||
different_attrs = %YtDlpMedia{media_attrs | playlist_index: 9999}
|
||||
|
||||
assert {:ok, %MediaItem{} = _media_item_1} = Media.create_media_item_from_backend_attrs(source, media_attrs)
|
||||
assert {:ok, %MediaItem{} = media_item_2} = Media.create_media_item_from_backend_attrs(source, different_attrs)
|
||||
|
||||
assert Repo.reload(media_item_2).playlist_index == media_attrs.playlist_index
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -110,8 +110,10 @@ defmodule Pinchflat.YtDlp.MediaTest do
|
|||
|
||||
describe "indexing_output_template/0" do
|
||||
test "contains all the greatest hits" do
|
||||
assert "%(.{id,title,was_live,webpage_url,description,aspect_ratio,duration,upload_date,timestamp})j" ==
|
||||
Media.indexing_output_template()
|
||||
attrs = ~w(id title was_live webpage_url description aspect_ratio duration upload_date timestamp playlist_index)a
|
||||
formatted_attrs = "%(.{#{Enum.join(attrs, ",")}})j"
|
||||
|
||||
assert formatted_attrs == Media.indexing_output_template()
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -126,7 +128,8 @@ defmodule Pinchflat.YtDlp.MediaTest do
|
|||
"aspect_ratio" => 1.0,
|
||||
"duration" => 60,
|
||||
"upload_date" => "20210101",
|
||||
"timestamp" => 1_600_000_000
|
||||
"timestamp" => 1_600_000_000,
|
||||
"playlist_index" => 1
|
||||
}
|
||||
|
||||
assert %Media{
|
||||
|
|
@ -137,7 +140,8 @@ defmodule Pinchflat.YtDlp.MediaTest do
|
|||
livestream: false,
|
||||
short_form_content: false,
|
||||
uploaded_at: ~U[2020-09-13 12:26:40Z],
|
||||
duration_seconds: 60
|
||||
duration_seconds: 60,
|
||||
playlist_index: 1
|
||||
} == Media.response_to_struct(response)
|
||||
end
|
||||
|
||||
|
|
@ -217,6 +221,17 @@ defmodule Pinchflat.YtDlp.MediaTest do
|
|||
|
||||
assert %Media{livestream: false} = Media.response_to_struct(response)
|
||||
end
|
||||
|
||||
test "doesn't blow up if playlist_index is missing" do
|
||||
response = %{
|
||||
"webpage_url" => "https://www.youtube.com/watch?v=TiZPUDkDYbk",
|
||||
"aspect_ratio" => 1.0,
|
||||
"duration" => nil,
|
||||
"upload_date" => "20210101"
|
||||
}
|
||||
|
||||
assert %Media{playlist_index: 0} = Media.response_to_struct(response)
|
||||
end
|
||||
end
|
||||
|
||||
describe "response_to_struct/1 when testing uploaded_at" do
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue