[WIP] Very-WIP first steps at parsing options and downloading
This commit is contained in:
parent
f6fd0775d9
commit
fad1e39bad
5 changed files with 161 additions and 9 deletions
|
|
@ -10,6 +10,10 @@ defmodule Pinchflat.Downloader.Backends.YtDlp.CommandRunner do
|
|||
|
||||
@doc """
|
||||
Runs a yt-dlp command and returns the string output
|
||||
|
||||
# TODO: deduplicate command opts, keeping the last one on conflict
|
||||
although possibly not needed (and a LOT easier) if yt-dlp
|
||||
just ignores duplicate options (ie: look into that)
|
||||
"""
|
||||
@impl BackendCommandRunner
|
||||
def run(url, command_opts) do
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ defmodule Pinchflat.Downloader.Backends.YtDlp.Video do
|
|||
|
||||
The video will be moved to its final destination... elsewhere
|
||||
# TODO: update these docs when I figure out a module to move videos
|
||||
# TODO: test
|
||||
# NOTE: maybe instead of moving it to the tempdir, I can just download it
|
||||
to the final destination by using the `output` option. The
|
||||
parser could be updated to generate a value for the output option.
|
||||
|
|
@ -17,15 +18,9 @@ defmodule Pinchflat.Downloader.Backends.YtDlp.Video do
|
|||
newer users can use the easier liquid-like syntax.
|
||||
"""
|
||||
def download(url, command_opts \\ []) do
|
||||
default_output_path = Path.join([base_directory(), "%(id)s", "%(id)s.%(ext)s"])
|
||||
default_opts = [output: default_output_path]
|
||||
opts = Keyword.merge(default_opts, command_opts)
|
||||
|
||||
backend_runner().run(url, opts)
|
||||
end
|
||||
|
||||
defp base_directory do
|
||||
Application.get_env(:pinchflat, :media_directory)
|
||||
# TODO: if this stays this simple, consider not abstracting it
|
||||
# HOWEVER - this module does provide clarity of intent so maybe keep?
|
||||
backend_runner().run(url, command_opts)
|
||||
end
|
||||
|
||||
defp backend_runner do
|
||||
|
|
|
|||
39
lib/pinchflat/downloader/video_downloader.ex
Normal file
39
lib/pinchflat/downloader/video_downloader.ex
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
defmodule Pinchflat.Downloader.VideoDownloader do
|
||||
@moduledoc """
|
||||
This is the integration layer for actually downloading videos.
|
||||
It takes into account the media profile's settings in order
|
||||
to download the video with the desired options.
|
||||
|
||||
Technically hardcodes the yt-dlp backend for now, but should leave
|
||||
it open-ish for future expansion (just in case).
|
||||
"""
|
||||
|
||||
alias Pinchflat.Downloader.Backends.YtDlp.Video, as: YtDlpVideo
|
||||
alias Pinchflat.Profiles.Options.YtDlp.OptionBuilder, as: YtDlpOptionBuilder
|
||||
|
||||
@doc """
|
||||
Downloads a single video based on the settings in the given media profile.
|
||||
|
||||
# TODO: implement media profiles - so far this is a glorified mock
|
||||
# TODO: test
|
||||
"""
|
||||
def download_for_media_profile(url, media_profile, backend \\ :yt_dlp) do
|
||||
option_builder = option_builder(backend)
|
||||
video_backend = video_backend(backend)
|
||||
{:ok, options} = option_builder.build(media_profile)
|
||||
|
||||
video_backend.download(url, options)
|
||||
end
|
||||
|
||||
def option_builder(backend) do
|
||||
case backend do
|
||||
:yt_dlp -> YtDlpOptionBuilder
|
||||
end
|
||||
end
|
||||
|
||||
def video_backend(backend) do
|
||||
case backend do
|
||||
:yt_dlp -> YtDlpVideo
|
||||
end
|
||||
end
|
||||
end
|
||||
43
lib/pinchflat/profiles/options/yt_dlp/option_builder.ex
Normal file
43
lib/pinchflat/profiles/options/yt_dlp/option_builder.ex
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
defmodule Pinchflat.Profiles.Options.YtDlp.OptionBuilder do
|
||||
@moduledoc """
|
||||
Builds the options for yt-dlp based on the given media profile.
|
||||
|
||||
TODO: probably make this a behaviour so I can add other backends later
|
||||
"""
|
||||
|
||||
alias Pinchflat.Profiles.Options.YtDlp.OutputPathBuilder
|
||||
|
||||
@doc """
|
||||
Builds the options for yt-dlp based on the given media profile.
|
||||
|
||||
TODO: add a guard to ensure argument is a media profile
|
||||
TODO: consider adding the ability to pass in a second argument to override
|
||||
these options
|
||||
TODO: test
|
||||
"""
|
||||
def build(media_profile) do
|
||||
{:ok, output_path} = OutputPathBuilder.build(media_profile.output_path_template)
|
||||
|
||||
# NOTE: I'll be hardcoding most things for now (esp. options to help me test) -
|
||||
# add more configuration later as I build out the models. Walk before you can run!
|
||||
|
||||
{:ok,
|
||||
[
|
||||
:write_thumbnail,
|
||||
:write_subs,
|
||||
:embed_metadata,
|
||||
:embed_thumbnail,
|
||||
:embed_subs,
|
||||
:write_info_json,
|
||||
:write_auto_subs,
|
||||
:no_progress,
|
||||
convert_thumbnails: "jpg",
|
||||
sub_langs: "en.*",
|
||||
output: Path.join(base_directory(), output_path)
|
||||
]}
|
||||
end
|
||||
|
||||
defp base_directory do
|
||||
Application.get_env(:pinchflat, :media_directory)
|
||||
end
|
||||
end
|
||||
71
lib/pinchflat/profiles/options/yt_dlp/output_path_builder.ex
Normal file
71
lib/pinchflat/profiles/options/yt_dlp/output_path_builder.ex
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
defmodule Pinchflat.Profiles.Options.YtDlp.OutputPathBuilder do
|
||||
@moduledoc """
|
||||
Builds yt-dlp-friendly output paths for downloaded media
|
||||
|
||||
TODO: probably make this a behaviour so I can add other backends later
|
||||
"""
|
||||
|
||||
alias Pinchflat.RenderedString.Parser, as: TemplateParser
|
||||
|
||||
@doc """
|
||||
Builds the actual final filepath from a given template.
|
||||
|
||||
Translates liquid-style templates into yt-dlp-style templates,
|
||||
leaving yt-dlp syntax intact.
|
||||
|
||||
TODO: test
|
||||
"""
|
||||
def build(template_string) do
|
||||
TemplateParser.parse(template_string, full_yt_dlp_options_map())
|
||||
end
|
||||
|
||||
defp full_yt_dlp_options_map do
|
||||
Map.merge(
|
||||
standard_yt_dlp_option_map(),
|
||||
custom_yt_dlp_option_map()
|
||||
)
|
||||
end
|
||||
|
||||
defp standard_yt_dlp_option_map do
|
||||
%{
|
||||
"id" => "%(id)s",
|
||||
"ext" => "%(ext)s",
|
||||
"title" => "%(title)s",
|
||||
"fulltitle" => "%(fulltitle)s",
|
||||
"uploader" => "%(uploader)s",
|
||||
"creator" => "%(creator)s",
|
||||
"upload_date" => "%(upload_date)s",
|
||||
"release_date" => "%(release_date)s",
|
||||
"duration" => "%(duration)s",
|
||||
# For videos classified as an episode of a series:
|
||||
"series" => "%(series)s",
|
||||
"season" => "%(season)s",
|
||||
"season_number" => "%(season_number)s",
|
||||
"episode" => "%(episode)s",
|
||||
"episode_number" => "%(episode_number)s",
|
||||
"episode_id" => "%(episode_id)s",
|
||||
# For videos classified as music:
|
||||
"track" => "%(track)s",
|
||||
"track_number" => "%(track_number)s",
|
||||
"artist" => "%(artist)s",
|
||||
"album" => "%(album)s",
|
||||
"album_type" => "%(album_type)s",
|
||||
"genre" => "%(genre)s"
|
||||
}
|
||||
end
|
||||
|
||||
defp custom_yt_dlp_option_map do
|
||||
%{
|
||||
# Filepath-safe versions of some standard options
|
||||
"safe_id" => "%(id)S",
|
||||
"safe_title" => "%(title)S",
|
||||
"safe_fulltitle" => "%(fulltitle)S",
|
||||
"safe_uploader" => "%(uploader)S",
|
||||
"safe_creator" => "%(creator)S",
|
||||
# Individual parts of the upload date
|
||||
"upload_year" => "%(upload_date>%Y)s",
|
||||
"upload_month" => "%(upload_date>%m)s",
|
||||
"upload_day" => "%(upload_date>%d)s"
|
||||
}
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue