Updated every command to optionally include cookies

This commit is contained in:
Kieran Eglin 2024-08-14 09:24:24 -07:00
parent 73dec37857
commit cf0133bae4
No known key found for this signature in database
GPG key ID: 193984967FCF432D
9 changed files with 55 additions and 25 deletions

View file

@ -106,8 +106,10 @@ defmodule Pinchflat.Downloading.MediaDownloader do
defp download_with_options(url, item_with_preloads, output_filepath, override_opts) do defp download_with_options(url, item_with_preloads, output_filepath, override_opts) do
{:ok, options} = DownloadOptionBuilder.build(item_with_preloads, override_opts) {:ok, options} = DownloadOptionBuilder.build(item_with_preloads, override_opts)
# TODO: test
runner_opts = [output_filepath: output_filepath, use_cookies: item_with_preloads.source.use_cookies]
YtDlpMedia.download(url, options, output_filepath: output_filepath) YtDlpMedia.download(url, options, runner_opts)
end end
defp recoverable_errors do defp recoverable_errors do

View file

@ -68,7 +68,8 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpers do
defp create_media_item_from_media_id(source, media_id) do defp create_media_item_from_media_id(source, media_id) do
url = "https://www.youtube.com/watch?v=#{media_id}" url = "https://www.youtube.com/watch?v=#{media_id}"
case YtDlpMedia.get_media_attributes(url) do # TODO: test
case YtDlpMedia.get_media_attributes(url, use_cookies: source.use_cookies) do
{:ok, media_attrs} -> {:ok, media_attrs} ->
Media.create_media_item_from_backend_attrs(source, media_attrs) Media.create_media_item_from_backend_attrs(source, media_attrs)

View file

@ -62,11 +62,14 @@ defmodule Pinchflat.Metadata.MetadataFileHelpers do
Returns binary() | nil Returns binary() | nil
""" """
def download_and_store_thumbnail_for(database_record) do def download_and_store_thumbnail_for(media_item_with_preloads) do
yt_dlp_filepath = generate_filepath_for(database_record, "thumbnail.%(ext)s") yt_dlp_filepath = generate_filepath_for(media_item_with_preloads, "thumbnail.%(ext)s")
real_filepath = generate_filepath_for(database_record, "thumbnail.jpg") real_filepath = generate_filepath_for(media_item_with_preloads, "thumbnail.jpg")
command_opts = [output: yt_dlp_filepath]
addl_opts = [use_cookies: media_item_with_preloads.source.use_cookies]
case YtDlpMedia.download_thumbnail(database_record.original_url, output: yt_dlp_filepath) do # TODO: test
case YtDlpMedia.download_thumbnail(media_item_with_preloads.original_url, command_opts, addl_opts) do
{:ok, _} -> real_filepath {:ok, _} -> real_filepath
_ -> nil _ -> nil
end end

View file

@ -92,7 +92,10 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorker do
defp determine_series_directory(source) do defp determine_series_directory(source) do
output_path = DownloadOptionBuilder.build_output_path_for(source) output_path = DownloadOptionBuilder.build_output_path_for(source)
{:ok, %{filepath: filepath}} = MediaCollection.get_source_details(source.original_url, output: output_path) # TODO: test
runner_opts = [output: output_path]
addl_opts = [use_cookies: source.use_cookies]
{:ok, %{filepath: filepath}} = MediaCollection.get_source_details(source.original_url, runner_opts, addl_opts)
case MetadataFileHelpers.series_directory_from_media_filepath(filepath) do case MetadataFileHelpers.series_directory_from_media_filepath(filepath) do
{:ok, series_directory} -> series_directory {:ok, series_directory} -> series_directory
@ -119,7 +122,8 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorker do
base_opts ++ [:write_thumbnail, playlist_items: 1] base_opts ++ [:write_thumbnail, playlist_items: 1]
end end
MediaCollection.get_source_metadata(source.original_url, opts) # TODO: test
MediaCollection.get_source_metadata(source.original_url, opts, use_cookies: source.use_cookies)
end end
defp tmp_directory do defp tmp_directory do

View file

@ -94,7 +94,9 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpers do
{:ok, pid} = FileFollowerServer.start_link() {:ok, pid} = FileFollowerServer.start_link()
handler = fn filepath -> setup_file_follower_watcher(pid, filepath, source) end handler = fn filepath -> setup_file_follower_watcher(pid, filepath, source) end
result = MediaCollection.get_media_attributes_for_collection(source.original_url, file_listener_handler: handler) runner_opts = [file_listener_handler: handler, use_cookies: source.use_cookies]
# TODO: test
result = MediaCollection.get_media_attributes_for_collection(source.original_url, runner_opts)
FileFollowerServer.stop(pid) FileFollowerServer.stop(pid)

View file

@ -180,7 +180,9 @@ defmodule Pinchflat.Sources do
end end
defp add_source_details_to_changeset(source, changeset) do defp add_source_details_to_changeset(source, changeset) do
case MediaCollection.get_source_details(changeset.changes.original_url) do use_cookies = Ecto.Changeset.get_field(changeset, :use_cookies)
case MediaCollection.get_source_details(changeset.changes.original_url, [], use_cookies: use_cookies) do
{:ok, source_details} -> {:ok, source_details} ->
add_source_details_by_collection_type(source, changeset, source_details) add_source_details_by_collection_type(source, changeset, source_details)

View file

@ -18,6 +18,8 @@ defmodule Pinchflat.YtDlp.CommandRunner do
- :output_filepath - the path to save the output to. If not provided, a temporary - :output_filepath - the path to save the output to. If not provided, a temporary
file will be created and used. Useful for if you need a reference to the file file will be created and used. Useful for if you need a reference to the file
for a file watcher. for a file watcher.
- :use_cookies - if true, will add a cookie file to the command options. Will not
attach a cookie file if the user hasn't set one up.
Returns {:ok, binary()} | {:error, output, status}. Returns {:ok, binary()} | {:error, output, status}.
""" """
@ -28,7 +30,7 @@ defmodule Pinchflat.YtDlp.CommandRunner do
output_filepath = generate_output_filepath(addl_opts) output_filepath = generate_output_filepath(addl_opts)
print_to_file_opts = [{:print_to_file, output_template}, output_filepath] print_to_file_opts = [{:print_to_file, output_template}, output_filepath]
user_configured_opts = cookie_file_options() user_configured_opts = cookie_file_options(addl_opts)
# These must stay in exactly this order, hence why I'm giving it its own variable. # These must stay in exactly this order, hence why I'm giving it its own variable.
all_opts = command_opts ++ print_to_file_opts ++ user_configured_opts ++ global_options() all_opts = command_opts ++ print_to_file_opts ++ user_configured_opts ++ global_options()
formatted_command_opts = [url] ++ CliUtils.parse_options(all_opts) formatted_command_opts = [url] ++ CliUtils.parse_options(all_opts)
@ -78,7 +80,14 @@ defmodule Pinchflat.YtDlp.CommandRunner do
] ]
end end
defp cookie_file_options do defp cookie_file_options(addl_opts) do
case Keyword.get(addl_opts, :use_cookies) do
true -> add_cookie_file()
_ -> []
end
end
defp add_cookie_file do
base_dir = Application.get_env(:pinchflat, :extras_directory) base_dir = Application.get_env(:pinchflat, :extras_directory)
filename_options_map = %{cookies: "cookies.txt"} filename_options_map = %{cookies: "cookies.txt"}

View file

@ -53,12 +53,13 @@ defmodule Pinchflat.YtDlp.Media do
Returns {:ok, ""} | {:error, any, ...}. Returns {:ok, ""} | {:error, any, ...}.
""" """
def download_thumbnail(url, command_opts \\ []) do def download_thumbnail(url, command_opts \\ [], addl_opts \\ []) do
opts = [:no_simulate, :skip_download, :write_thumbnail, convert_thumbnail: "jpg"] ++ command_opts all_command_opts = [:no_simulate, :skip_download, :write_thumbnail, convert_thumbnail: "jpg"] ++ command_opts
# NOTE: it doesn't seem like this command actually returns anything in `after_move` since # NOTE: it doesn't seem like this command actually returns anything in `after_move` since
# we aren't downloading the main media file # we aren't downloading the main media file
backend_runner().run(url, opts, "after_move:%()j") # TODO: test
backend_runner().run(url, all_command_opts, "after_move:%()j", addl_opts)
end end
@doc """ @doc """
@ -66,12 +67,13 @@ defmodule Pinchflat.YtDlp.Media do
Returns {:ok, %Media{}} | {:error, any, ...}. Returns {:ok, %Media{}} | {:error, any, ...}.
""" """
def get_media_attributes(url) do def get_media_attributes(url, addl_opts \\ []) do
runner = Application.get_env(:pinchflat, :yt_dlp_runner) runner = Application.get_env(:pinchflat, :yt_dlp_runner)
command_opts = [:simulate, :skip_download] command_opts = [:simulate, :skip_download]
output_template = indexing_output_template() output_template = indexing_output_template()
case runner.run(url, command_opts, output_template) do # TODO: test
case runner.run(url, command_opts, output_template, addl_opts) do
{:ok, output} -> {:ok, output} ->
output output
|> Phoenix.json_library().decode!() |> Phoenix.json_library().decode!()

View file

@ -25,15 +25,18 @@ defmodule Pinchflat.YtDlp.MediaCollection do
# the first video has not released yet (ie: is a premier). We don't care about # the first video has not released yet (ie: is a premier). We don't care about
# available formats since we're just getting the media details # available formats since we're just getting the media details
command_opts = [:simulate, :skip_download, :ignore_no_formats_error, :no_warnings] command_opts = [:simulate, :skip_download, :ignore_no_formats_error, :no_warnings]
use_cookies = Keyword.get(addl_opts, :use_cookies, false)
output_template = YtDlpMedia.indexing_output_template() output_template = YtDlpMedia.indexing_output_template()
output_filepath = FilesystemUtils.generate_metadata_tmpfile(:json) output_filepath = FilesystemUtils.generate_metadata_tmpfile(:json)
file_listener_handler = Keyword.get(addl_opts, :file_listener_handler, false) file_listener_handler = Keyword.get(addl_opts, :file_listener_handler, false)
# TODO: test
runner_opts = [output_filepath: output_filepath, use_cookies: use_cookies]
if file_listener_handler do if file_listener_handler do
file_listener_handler.(output_filepath) file_listener_handler.(output_filepath)
end end
case runner.run(url, command_opts, output_template, output_filepath: output_filepath) do case runner.run(url, command_opts, output_template, runner_opts) do
{:ok, output} -> {:ok, output} ->
parsed_lines = parsed_lines =
output output
@ -64,7 +67,7 @@ defmodule Pinchflat.YtDlp.MediaCollection do
Returns {:ok, map()} | {:error, any, ...}. Returns {:ok, map()} | {:error, any, ...}.
""" """
def get_source_details(source_url, addl_opts \\ []) do def get_source_details(source_url, command_opts \\ [], addl_opts \\ []) do
# `ignore_no_formats_error` is necessary because yt-dlp will error out if # `ignore_no_formats_error` is necessary because yt-dlp will error out if
# the first video has not released yet (ie: is a premier). We don't care about # the first video has not released yet (ie: is a premier). We don't care about
# available formats since we're just getting the source details # available formats since we're just getting the source details
@ -75,10 +78,11 @@ defmodule Pinchflat.YtDlp.MediaCollection do
playlist_end: 1 playlist_end: 1
] ]
command_opts = default_opts ++ addl_opts all_command_opts = default_opts ++ command_opts
output_template = "%(.{channel,channel_id,playlist_id,playlist_title,filename})j" output_template = "%(.{channel,channel_id,playlist_id,playlist_title,filename})j"
with {:ok, output} <- backend_runner().run(source_url, command_opts, output_template), # TODO: test
with {:ok, output} <- backend_runner().run(source_url, all_command_opts, output_template, addl_opts),
{:ok, parsed_json} <- Phoenix.json_library().decode(output) do {:ok, parsed_json} <- Phoenix.json_library().decode(output) do
{:ok, format_source_details(parsed_json)} {:ok, format_source_details(parsed_json)}
else else
@ -109,14 +113,15 @@ defmodule Pinchflat.YtDlp.MediaCollection do
Returns {:ok, map()} | {:error, any, ...}. Returns {:ok, map()} | {:error, any, ...}.
""" """
def get_source_metadata(source_url, addl_opts \\ [playlist_items: 0]) do def get_source_metadata(source_url, command_opts \\ [playlist_items: 0], addl_opts \\ []) do
# This only validates that the `playlist_items` key is present. It's otherwise unused # This only validates that the `playlist_items` key is present. It's otherwise unused
_playlist_items = Keyword.fetch!(addl_opts, :playlist_items) _playlist_items = Keyword.fetch!(command_opts, :playlist_items)
opts = [:skip_download] ++ addl_opts all_command_opts = [:skip_download] ++ command_opts
output_template = "playlist:%()j" output_template = "playlist:%()j"
with {:ok, output} <- backend_runner().run(source_url, opts, output_template), # TODO: test
with {:ok, output} <- backend_runner().run(source_url, all_command_opts, output_template, addl_opts),
{:ok, parsed_json} <- Phoenix.json_library().decode(output) do {:ok, parsed_json} <- Phoenix.json_library().decode(output) do
{:ok, parsed_json} {:ok, parsed_json}
else else