From fae7ba3304fee4c1c43e268dc8645d33abc0bd2a Mon Sep 17 00:00:00 2001 From: Kieran Date: Thu, 28 Mar 2024 21:51:04 -0700 Subject: [PATCH] [Enhancement] Start tracking a media item's duration (#146) * Added duration field, started importing it during indexing and download * Added duration to RSS feed --- lib/pinchflat/media/media_item.ex | 2 ++ lib/pinchflat/metadata/metadata_parser.ex | 3 ++- lib/pinchflat/podcasts/rss_feed_builder.ex | 1 + lib/pinchflat/yt_dlp/media.ex | 7 ++++-- ...0328221845_add_duration_to_media_items.exs | 9 +++++++ .../downloading/media_downloader_test.exs | 8 +++++- .../metadata/metadata_parser_test.exs | 6 +++++ test/pinchflat/yt_dlp/media_test.exs | 25 ++++++++++++++++++- 8 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 priv/repo/migrations/20240328221845_add_duration_to_media_items.exs diff --git a/lib/pinchflat/media/media_item.ex b/lib/pinchflat/media/media_item.ex index a11b5c0..40353db 100644 --- a/lib/pinchflat/media/media_item.ex +++ b/lib/pinchflat/media/media_item.ex @@ -22,6 +22,7 @@ defmodule Pinchflat.Media.MediaItem do :source_id, :short_form_content, :upload_date, + :duration_seconds, # these fields are captured only on download :media_downloaded_at, :media_filepath, @@ -57,6 +58,7 @@ defmodule Pinchflat.Media.MediaItem do field :short_form_content, :boolean, default: false field :media_downloaded_at, :utc_datetime field :upload_date, :date + field :duration_seconds, :integer field :media_filepath, :string field :media_size_bytes, :integer diff --git a/lib/pinchflat/metadata/metadata_parser.ex b/lib/pinchflat/metadata/metadata_parser.ex index 53ca066..1173001 100644 --- a/lib/pinchflat/metadata/metadata_parser.ex +++ b/lib/pinchflat/metadata/metadata_parser.ex @@ -30,7 +30,8 @@ defmodule Pinchflat.Metadata.MetadataParser do original_url: metadata["original_url"], description: metadata["description"], media_filepath: metadata["filepath"], - livestream: metadata["was_live"] + livestream: metadata["was_live"], + duration_seconds: metadata["duration"] && round(metadata["duration"]) } end diff --git a/lib/pinchflat/podcasts/rss_feed_builder.ex b/lib/pinchflat/podcasts/rss_feed_builder.ex index 54eb104..f429a73 100644 --- a/lib/pinchflat/podcasts/rss_feed_builder.ex +++ b/lib/pinchflat/podcasts/rss_feed_builder.ex @@ -80,6 +80,7 @@ defmodule Pinchflat.Podcasts.RssFeedBuilder do #{media_item.original_url} #{safe(media_item.description)} #{generate_upload_date(media_item)} + #{media_item.duration_seconds} {:ok, render_metadata(:media_metadata)} end) @@ -93,6 +93,12 @@ defmodule Pinchflat.Downloading.MediaDownloaderTest do assert [["de", _], ["en", _] | _rest] = updated_media_item.subtitle_filepaths end + test "it extracts the duration_seconds", %{media_item: media_item} do + assert media_item.duration_seconds == nil + assert {:ok, updated_media_item} = MediaDownloader.download_for_media_item(media_item) + assert is_integer(updated_media_item.duration_seconds) + end + test "it extracts the thumbnail_filepath", %{media_item: media_item} do expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> metadata = render_parsed_metadata(:media_metadata) diff --git a/test/pinchflat/metadata/metadata_parser_test.exs b/test/pinchflat/metadata/metadata_parser_test.exs index 2d4e8d4..dd55a19 100644 --- a/test/pinchflat/metadata/metadata_parser_test.exs +++ b/test/pinchflat/metadata/metadata_parser_test.exs @@ -45,6 +45,12 @@ defmodule Pinchflat.Metadata.MetadataParserTest do assert result.livestream == metadata["was_live"] end + + test "it extracts the duration in seconds", %{metadata: metadata} do + result = Parser.parse_for_media_item(metadata) + + assert result.duration_seconds == round(metadata["duration"]) + end end describe "parse_for_media_item/1 when testing subtitle metadata" do diff --git a/test/pinchflat/yt_dlp/media_test.exs b/test/pinchflat/yt_dlp/media_test.exs index 3d617c1..0b12621 100644 --- a/test/pinchflat/yt_dlp/media_test.exs +++ b/test/pinchflat/yt_dlp/media_test.exs @@ -104,7 +104,8 @@ defmodule Pinchflat.YtDlp.MediaTest do original_url: "https://www.youtube.com/watch?v=TiZPUDkDYbk", livestream: false, short_form_content: false, - upload_date: Date.from_iso8601!("2021-01-01") + upload_date: Date.from_iso8601!("2021-01-01"), + duration_seconds: 60 } == Media.response_to_struct(response) end @@ -174,5 +175,27 @@ defmodule Pinchflat.YtDlp.MediaTest do assert %Media{upload_date: nil} = Media.response_to_struct(response) end + + test "parses the duration" do + response = %{ + "webpage_url" => "https://www.youtube.com/watch?v=TiZPUDkDYbk", + "aspect_ratio" => 1.0, + "duration" => 60.4, + "upload_date" => "20210101" + } + + assert %Media{duration_seconds: 60} = Media.response_to_struct(response) + end + + test "doesn't blow up if duration is missing" do + response = %{ + "webpage_url" => "https://www.youtube.com/watch?v=TiZPUDkDYbk", + "aspect_ratio" => 1.0, + "duration" => nil, + "upload_date" => "20210101" + } + + assert %Media{duration_seconds: nil} = Media.response_to_struct(response) + end end end