diff --git a/lib/pinchflat/yt_dlp/backend/media.ex b/lib/pinchflat/yt_dlp/backend/media.ex index 89ff3f0..1c96237 100644 --- a/lib/pinchflat/yt_dlp/backend/media.ex +++ b/lib/pinchflat/yt_dlp/backend/media.ex @@ -3,12 +3,22 @@ defmodule Pinchflat.YtDlp.Backend.Media do Contains utilities for working with singular pieces of media """ + @enforce_keys [ + :media_id, + :title, + :description, + :original_url, + :livestream, + :short_form_content + ] + defstruct [ :media_id, :title, :description, :original_url, - :livestream + :livestream, + :short_form_content ] alias __MODULE__ @@ -57,20 +67,39 @@ defmodule Pinchflat.YtDlp.Backend.Media do Returns the output template for yt-dlp's indexing command. """ def indexing_output_template do - "%(.{id,title,was_live,original_url,description})j" + "%(.{id,title,was_live,webpage_url,description,aspect_ratio,duration})j" end - # TODO: test + @doc """ + Transforms a response from yt-dlp into a struct. Interprets the response to + determine if the media is short-form content. + + Returns %Media{}. + """ def response_to_struct(response) do %Media{ media_id: response["id"], title: response["title"], description: response["description"], - original_url: response["original_url"], - livestream: response["was_live"] + original_url: response["webpage_url"], + livestream: response["was_live"], + short_form_content: short_form_content?(response) } end + defp short_form_content?(response) do + if String.contains?(response["webpage_url"], "/shorts/") do + true + else + # Sometimes shorts are returned without /shorts/ in the URL, + # so we need to do our best to determine if it's a short. This + # WILL returns false positives, but it's a best-effort approach + # that should work for most cases. The aspect_ratio check is + # based on a gut feeling and may need to be tweaked. + response["duration"] <= 60 && response["aspect_ratio"] < 0.8 + end + end + defp backend_runner do # This approach lets us mock the command for testing Application.get_env(:pinchflat, :yt_dlp_runner) diff --git a/test/pinchflat/tasks/media_items_tasks_test.exs b/test/pinchflat/tasks/media_items_tasks_test.exs index 8e93f2f..7cf18e8 100644 --- a/test/pinchflat/tasks/media_items_tasks_test.exs +++ b/test/pinchflat/tasks/media_items_tasks_test.exs @@ -84,9 +84,11 @@ defmodule Pinchflat.Tasks.MediaItemTasksTest do Phoenix.json_library().encode!(%{ id: "video2", title: "Video 2", - original_url: "https://example.com/shorts/video2", + webpage_url: "https://example.com/shorts/video2", was_live: true, - description: "desc2" + description: "desc2", + aspect_ratio: 1.67, + duration: 345.67 }) {:ok, output} diff --git a/test/pinchflat/tasks/source_tasks_test.exs b/test/pinchflat/tasks/source_tasks_test.exs index 3d688ee..74bec27 100644 --- a/test/pinchflat/tasks/source_tasks_test.exs +++ b/test/pinchflat/tasks/source_tasks_test.exs @@ -229,9 +229,11 @@ defmodule Pinchflat.Tasks.SourceTasksTest do Phoenix.json_library().encode!(%{ id: "video2", title: "Video 2", - original_url: "https://example.com/shorts/video2", + webpage_url: "https://example.com/shorts/video2", was_live: true, - description: "desc2" + description: "desc2", + aspect_ratio: 1.67, + duration: 345.67 }) File.write(filepath, contents) diff --git a/test/pinchflat/yt_dlp/backend/media_test.exs b/test/pinchflat/yt_dlp/backend/media_test.exs index 8072a2e..94c031d 100644 --- a/test/pinchflat/yt_dlp/backend/media_test.exs +++ b/test/pinchflat/yt_dlp/backend/media_test.exs @@ -64,7 +64,7 @@ defmodule Pinchflat.YtDlp.Backend.MediaTest do assert opts == [:simulate, :skip_download] assert ot == Media.indexing_output_template() - {:ok, "{}"} + {:ok, media_attributes_return_fixture()} end) assert {:ok, _} = Media.get_media_attributes(@media_url) @@ -79,8 +79,61 @@ defmodule Pinchflat.YtDlp.Backend.MediaTest do describe "indexing_output_template/0" do test "contains all the greatest hits" do - assert "%(.{id,title,was_live,original_url,description})j" == + assert "%(.{id,title,was_live,webpage_url,description,aspect_ratio,duration})j" == Media.indexing_output_template() end end + + describe "response_to_struct/1" do + test "transforms a response into a struct" do + response = %{ + "id" => "TiZPUDkDYbk", + "title" => "Trying to Wheelie Without the Rear Brake", + "description" => "I'm not sure what I expected.", + "webpage_url" => "https://www.youtube.com/watch?v=TiZPUDkDYbk", + "was_live" => false, + "aspect_ratio" => 1.0, + "duration" => 60 + } + + assert %Media{ + media_id: "TiZPUDkDYbk", + title: "Trying to Wheelie Without the Rear Brake", + description: "I'm not sure what I expected.", + original_url: "https://www.youtube.com/watch?v=TiZPUDkDYbk", + livestream: false, + short_form_content: false + } = Media.response_to_struct(response) + end + + test "sets short_form_content to true if the URL contains /shorts/" do + response = %{ + "webpage_url" => "https://www.youtube.com/shorts/TiZPUDkDYbk", + "aspect_ratio" => 1.0, + "duration" => 61 + } + + assert %Media{short_form_content: true} = Media.response_to_struct(response) + end + + test "sets short_form_content to true if the aspect ratio are duration are right" do + response = %{ + "webpage_url" => "https://www.youtube.com/watch?v=TiZPUDkDYbk", + "aspect_ratio" => 0.5, + "duration" => 59 + } + + assert %Media{short_form_content: true} = Media.response_to_struct(response) + end + + test "sets short_form_content to false otherwise" do + response = %{ + "webpage_url" => "https://www.youtube.com/watch?v=TiZPUDkDYbk", + "aspect_ratio" => 1.0, + "duration" => 61 + } + + assert %Media{short_form_content: false} = Media.response_to_struct(response) + end + end end diff --git a/test/support/fixtures/media_fixtures.ex b/test/support/fixtures/media_fixtures.ex index 9a4a0cb..e4f3ffe 100644 --- a/test/support/fixtures/media_fixtures.ex +++ b/test/support/fixtures/media_fixtures.ex @@ -71,9 +71,11 @@ defmodule Pinchflat.MediaFixtures do media_attributes = %{ id: "video1", title: "Video 1", - original_url: "https://example.com/video1", + webpage_url: "https://example.com/video1", was_live: false, - description: "desc1" + description: "desc1", + aspect_ratio: 1.67, + duration: 123.45 } Phoenix.json_library().encode!(media_attributes) diff --git a/test/support/fixtures/sources_fixtures.ex b/test/support/fixtures/sources_fixtures.ex index 5c25ffc..89c113c 100644 --- a/test/support/fixtures/sources_fixtures.ex +++ b/test/support/fixtures/sources_fixtures.ex @@ -35,23 +35,29 @@ defmodule Pinchflat.SourcesFixtures do %{ id: "video1", title: "Video 1", - original_url: "https://example.com/video1", + webpage_url: "https://example.com/video1", was_live: false, - description: "desc1" + description: "desc1", + aspect_ratio: 1.67, + duration: 12.34 }, %{ id: "video2", title: "Video 2", - original_url: "https://example.com/video2", + webpage_url: "https://example.com/video2", was_live: true, - description: "desc2" + description: "desc2", + aspect_ratio: 1.67, + duration: 345.67 }, %{ id: "video3", title: "Video 3", - original_url: "https://example.com/video3", + webpage_url: "https://example.com/video3", was_live: false, - description: "desc3" + description: "desc3", + aspect_ratio: 1.0, + duration: 678.90 } ]