Added ability to discern a short from yt-dlp response
This commit is contained in:
parent
f50bcb24bf
commit
451c52ae06
6 changed files with 113 additions and 19 deletions
|
|
@ -3,12 +3,22 @@ defmodule Pinchflat.YtDlp.Backend.Media do
|
||||||
Contains utilities for working with singular pieces of media
|
Contains utilities for working with singular pieces of media
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@enforce_keys [
|
||||||
|
:media_id,
|
||||||
|
:title,
|
||||||
|
:description,
|
||||||
|
:original_url,
|
||||||
|
:livestream,
|
||||||
|
:short_form_content
|
||||||
|
]
|
||||||
|
|
||||||
defstruct [
|
defstruct [
|
||||||
:media_id,
|
:media_id,
|
||||||
:title,
|
:title,
|
||||||
:description,
|
:description,
|
||||||
:original_url,
|
:original_url,
|
||||||
:livestream
|
:livestream,
|
||||||
|
:short_form_content
|
||||||
]
|
]
|
||||||
|
|
||||||
alias __MODULE__
|
alias __MODULE__
|
||||||
|
|
@ -57,20 +67,39 @@ defmodule Pinchflat.YtDlp.Backend.Media do
|
||||||
Returns the output template for yt-dlp's indexing command.
|
Returns the output template for yt-dlp's indexing command.
|
||||||
"""
|
"""
|
||||||
def indexing_output_template do
|
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
|
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
|
def response_to_struct(response) do
|
||||||
%Media{
|
%Media{
|
||||||
media_id: response["id"],
|
media_id: response["id"],
|
||||||
title: response["title"],
|
title: response["title"],
|
||||||
description: response["description"],
|
description: response["description"],
|
||||||
original_url: response["original_url"],
|
original_url: response["webpage_url"],
|
||||||
livestream: response["was_live"]
|
livestream: response["was_live"],
|
||||||
|
short_form_content: short_form_content?(response)
|
||||||
}
|
}
|
||||||
end
|
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
|
defp backend_runner do
|
||||||
# This approach lets us mock the command for testing
|
# This approach lets us mock the command for testing
|
||||||
Application.get_env(:pinchflat, :yt_dlp_runner)
|
Application.get_env(:pinchflat, :yt_dlp_runner)
|
||||||
|
|
|
||||||
|
|
@ -84,9 +84,11 @@ defmodule Pinchflat.Tasks.MediaItemTasksTest do
|
||||||
Phoenix.json_library().encode!(%{
|
Phoenix.json_library().encode!(%{
|
||||||
id: "video2",
|
id: "video2",
|
||||||
title: "Video 2",
|
title: "Video 2",
|
||||||
original_url: "https://example.com/shorts/video2",
|
webpage_url: "https://example.com/shorts/video2",
|
||||||
was_live: true,
|
was_live: true,
|
||||||
description: "desc2"
|
description: "desc2",
|
||||||
|
aspect_ratio: 1.67,
|
||||||
|
duration: 345.67
|
||||||
})
|
})
|
||||||
|
|
||||||
{:ok, output}
|
{:ok, output}
|
||||||
|
|
|
||||||
|
|
@ -229,9 +229,11 @@ defmodule Pinchflat.Tasks.SourceTasksTest do
|
||||||
Phoenix.json_library().encode!(%{
|
Phoenix.json_library().encode!(%{
|
||||||
id: "video2",
|
id: "video2",
|
||||||
title: "Video 2",
|
title: "Video 2",
|
||||||
original_url: "https://example.com/shorts/video2",
|
webpage_url: "https://example.com/shorts/video2",
|
||||||
was_live: true,
|
was_live: true,
|
||||||
description: "desc2"
|
description: "desc2",
|
||||||
|
aspect_ratio: 1.67,
|
||||||
|
duration: 345.67
|
||||||
})
|
})
|
||||||
|
|
||||||
File.write(filepath, contents)
|
File.write(filepath, contents)
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ defmodule Pinchflat.YtDlp.Backend.MediaTest do
|
||||||
assert opts == [:simulate, :skip_download]
|
assert opts == [:simulate, :skip_download]
|
||||||
assert ot == Media.indexing_output_template()
|
assert ot == Media.indexing_output_template()
|
||||||
|
|
||||||
{:ok, "{}"}
|
{:ok, media_attributes_return_fixture()}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
assert {:ok, _} = Media.get_media_attributes(@media_url)
|
assert {:ok, _} = Media.get_media_attributes(@media_url)
|
||||||
|
|
@ -79,8 +79,61 @@ defmodule Pinchflat.YtDlp.Backend.MediaTest do
|
||||||
|
|
||||||
describe "indexing_output_template/0" do
|
describe "indexing_output_template/0" do
|
||||||
test "contains all the greatest hits" 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()
|
Media.indexing_output_template()
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
|
||||||
|
|
@ -71,9 +71,11 @@ defmodule Pinchflat.MediaFixtures do
|
||||||
media_attributes = %{
|
media_attributes = %{
|
||||||
id: "video1",
|
id: "video1",
|
||||||
title: "Video 1",
|
title: "Video 1",
|
||||||
original_url: "https://example.com/video1",
|
webpage_url: "https://example.com/video1",
|
||||||
was_live: false,
|
was_live: false,
|
||||||
description: "desc1"
|
description: "desc1",
|
||||||
|
aspect_ratio: 1.67,
|
||||||
|
duration: 123.45
|
||||||
}
|
}
|
||||||
|
|
||||||
Phoenix.json_library().encode!(media_attributes)
|
Phoenix.json_library().encode!(media_attributes)
|
||||||
|
|
|
||||||
|
|
@ -35,23 +35,29 @@ defmodule Pinchflat.SourcesFixtures do
|
||||||
%{
|
%{
|
||||||
id: "video1",
|
id: "video1",
|
||||||
title: "Video 1",
|
title: "Video 1",
|
||||||
original_url: "https://example.com/video1",
|
webpage_url: "https://example.com/video1",
|
||||||
was_live: false,
|
was_live: false,
|
||||||
description: "desc1"
|
description: "desc1",
|
||||||
|
aspect_ratio: 1.67,
|
||||||
|
duration: 12.34
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
id: "video2",
|
id: "video2",
|
||||||
title: "Video 2",
|
title: "Video 2",
|
||||||
original_url: "https://example.com/video2",
|
webpage_url: "https://example.com/video2",
|
||||||
was_live: true,
|
was_live: true,
|
||||||
description: "desc2"
|
description: "desc2",
|
||||||
|
aspect_ratio: 1.67,
|
||||||
|
duration: 345.67
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
id: "video3",
|
id: "video3",
|
||||||
title: "Video 3",
|
title: "Video 3",
|
||||||
original_url: "https://example.com/video3",
|
webpage_url: "https://example.com/video3",
|
||||||
was_live: false,
|
was_live: false,
|
||||||
description: "desc3"
|
description: "desc3",
|
||||||
|
aspect_ratio: 1.0,
|
||||||
|
duration: 678.90
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue