Added UI explaining output template options

This commit is contained in:
Kieran Eglin 2024-02-20 12:33:19 -08:00
parent e5f8c9de4f
commit 9a18716bad
No known key found for this signature in database
GPG key ID: 193984967FCF432D
8 changed files with 151 additions and 10 deletions

View file

@ -11,7 +11,8 @@ module.exports = {
darkMode: 'class', darkMode: 'class',
theme: { theme: {
fontFamily: { fontFamily: {
satoshi: ['Satoshi', 'sans-serif'] satoshi: ['Satoshi', 'sans-serif'],
...defaultTheme.fontFamily
}, },
screens: { screens: {
'2xsm': '375px', '2xsm': '375px',

View file

@ -29,7 +29,7 @@ defmodule Pinchflat.Profiles.MediaProfile do
schema "media_profiles" do schema "media_profiles" do
field :name, :string field :name, :string
field :output_path_template, :string, default: "/{{ uploader }}/{{ title }}/{{ title }}-{{ id }}.{{ ext }}" field :output_path_template, :string, default: "/{{ channel }}/{{ title }}/{{ title }} [{{ id }}].{{ ext }}"
field :download_subs, :boolean, default: true field :download_subs, :boolean, default: true
field :download_auto_subs, :boolean, default: true field :download_auto_subs, :boolean, default: true

View file

@ -88,6 +88,7 @@ defmodule PinchflatWeb do
# Core UI components and translation # Core UI components and translation
import PinchflatWeb.Gettext import PinchflatWeb.Gettext
import PinchflatWeb.CoreComponents import PinchflatWeb.CoreComponents
import PinchflatWeb.CustomComponents.TextComponents
import PinchflatWeb.CustomComponents.TableComponents import PinchflatWeb.CustomComponents.TableComponents
import PinchflatWeb.CustomComponents.ButtonComponents import PinchflatWeb.CustomComponents.ButtonComponents

View file

@ -256,6 +256,7 @@ defmodule PinchflatWeb.CoreComponents do
attr :prompt, :string, default: nil, doc: "the prompt for select inputs" attr :prompt, :string, default: nil, doc: "the prompt for select inputs"
attr :options, :list, doc: "the options to pass to Phoenix.HTML.Form.options_for_select/2" attr :options, :list, doc: "the options to pass to Phoenix.HTML.Form.options_for_select/2"
attr :multiple, :boolean, default: false, doc: "the multiple flag for select inputs" attr :multiple, :boolean, default: false, doc: "the multiple flag for select inputs"
attr :inputclass, :string, default: ""
attr :rest, :global, include: ~w(accept autocomplete capture cols disabled form list max maxlength min minlength attr :rest, :global, include: ~w(accept autocomplete capture cols disabled form list max maxlength min minlength
multiple pattern placeholder readonly required rows size step) multiple pattern placeholder readonly required rows size step)
@ -281,7 +282,15 @@ defmodule PinchflatWeb.CoreComponents do
<div phx-feedback-for={@name}> <div phx-feedback-for={@name}>
<label class="flex items-center gap-4 text-sm leading-6"> <label class="flex items-center gap-4 text-sm leading-6">
<input type="hidden" name={@name} value="false" /> <input type="hidden" name={@name} value="false" />
<input type="checkbox" id={@id} name={@name} value="true" checked={@checked} class="rounded focus:ring-0" {@rest} /> <input
type="checkbox"
id={@id}
name={@name}
value="true"
checked={@checked}
class={["rounded focus:ring-0", @inputclass]}
{@rest}
/>
<%= @label %> <%= @label %>
</label> </label>
<.help :if={@help}><%= @help %></.help> <.help :if={@help}><%= @help %></.help>
@ -315,7 +324,10 @@ defmodule PinchflatWeb.CoreComponents do
<div x-bind:class="enabled && '!bg-primary'" class="block h-8 w-14 rounded-full bg-black"></div> <div x-bind:class="enabled && '!bg-primary'" class="block h-8 w-14 rounded-full bg-black"></div>
<div <div
x-bind:class="enabled && '!right-1 !translate-x-full'" x-bind:class="enabled && '!right-1 !translate-x-full'"
class="absolute left-1 top-1 flex h-6 w-6 items-center justify-center rounded-full bg-white transition" class={[
"absolute left-1 top-1 flex h-6 w-6 items-center justify-center rounded-full bg-white transition",
@inputclass
]}
> >
</div> </div>
</div> </div>
@ -335,7 +347,8 @@ defmodule PinchflatWeb.CoreComponents do
name={@name} name={@name}
class={[ class={[
"relative z-20 w-full appearance-none rounded border border-stroke bg-transparent py-3 pl-5 pr-12 outline-none transition", "relative z-20 w-full appearance-none rounded border border-stroke bg-transparent py-3 pl-5 pr-12 outline-none transition",
"focus:border-primary active:border-primary dark:border-form-strokedark dark:bg-form-input text-black dark:text-white" "focus:border-primary active:border-primary dark:border-form-strokedark dark:bg-form-input text-black dark:text-white",
@inputclass
]} ]}
multiple={@multiple} multiple={@multiple}
{@rest} {@rest}
@ -359,6 +372,7 @@ defmodule PinchflatWeb.CoreComponents do
class={[ class={[
"mt-2 block w-full rounded-lg text-zinc-900 focus:ring-0 sm:text-sm sm:leading-6", "mt-2 block w-full rounded-lg text-zinc-900 focus:ring-0 sm:text-sm sm:leading-6",
"min-h-[6rem] phx-no-feedback:border-zinc-300 phx-no-feedback:focus:border-zinc-400", "min-h-[6rem] phx-no-feedback:border-zinc-300 phx-no-feedback:focus:border-zinc-400",
@inputclass,
@errors == [] && "border-zinc-300 focus:border-zinc-400", @errors == [] && "border-zinc-300 focus:border-zinc-400",
@errors != [] && "border-rose-400 focus:border-rose-400" @errors != [] && "border-rose-400 focus:border-rose-400"
]} ]}
@ -384,6 +398,7 @@ defmodule PinchflatWeb.CoreComponents do
"w-full rounded-lg border-[1.5px] border-stroke bg-transparent px-5 py-3 font-normal text-black", "w-full rounded-lg border-[1.5px] border-stroke bg-transparent px-5 py-3 font-normal text-black",
"outline-none transition focus:border-primary active:border-primary disabled:cursor-default disabled:bg-whiter", "outline-none transition focus:border-primary active:border-primary disabled:cursor-default disabled:bg-whiter",
"dark:border-form-strokedark dark:bg-form-input dark:text-white dark:focus:border-primary", "dark:border-form-strokedark dark:bg-form-input dark:text-white dark:focus:border-primary",
@inputclass,
@errors != [] && "border-rose-400 focus:border-rose-400" @errors != [] && "border-rose-400 focus:border-rose-400"
]} ]}
{@rest} {@rest}

View file

@ -0,0 +1,31 @@
defmodule PinchflatWeb.CustomComponents.TextComponents do
@moduledoc false
use Phoenix.Component
@doc """
Renders a code block with the given content.
"""
slot :inner_block
def inline_code(assigns) do
~H"""
<code class="inline-block text-sm font-mono text-gray bg-boxdark rounded-md p-0.5 mx-0.5 text-nowrap">
<%= render_slot(@inner_block) %>
</code>
"""
end
@doc """
Renders a reference link with the given href and content.
"""
attr :href, :string, required: true
slot :inner_block
def reference_link(assigns) do
~H"""
<.link href={@href} target="_blank" class="text-blue-500 hover:text-blue-300">
<%= render_slot(@inner_block) %>
</.link>
"""
end
end

View file

@ -28,4 +28,21 @@ defmodule PinchflatWeb.MediaProfiles.MediaProfileHTML do
{"360p", "360p"} {"360p", "360p"}
] ]
end end
def custom_output_template_options do
~w(upload_day upload_month upload_year)a
end
def common_output_template_options do
~w(
id
ext
title
fulltitle
uploader
channel
upload_date
duration_string
)a
end
end end

View file

@ -6,11 +6,13 @@
General Options General Options
</h3> </h3>
<.input field={f[:name]} type="text" label="Name" placeholder="New Profile" help="(required)" /> <.input field={f[:name]} type="text" label="Name" placeholder="New Profile" help="(required)" />
<.input <.input
field={f[:output_path_template]} field={f[:output_path_template]}
type="text" type="text"
inputclass="font-mono"
label="Output path template" label="Output path template"
help="TODO: provide docs (required)" help="Must end with .{{ ext }}. See below for more details. I promise the default is good for most cases (required)"
/> />
<h3 class="mb-4 mt-8 text-2xl text-black dark:text-white"> <h3 class="mb-4 mt-8 text-2xl text-black dark:text-white">
@ -67,7 +69,7 @@
options={friendly_format_type_options()} options={friendly_format_type_options()}
type="select" type="select"
label="Include Shorts?" label="Include Shorts?"
help="Experimental" help="Experimental. Please report any issues on GitHub"
/> />
<.input <.input
field={f[:livestream_behaviour]} field={f[:livestream_behaviour]}
@ -88,7 +90,9 @@
help="Will grab the closest available resolution if your preferred is not available" help="Will grab the closest available resolution if your preferred is not available"
/> />
<:actions> <.button class="mt-15 mb-5 sm:mb-7.5">Save Media profile</.button>
<.button class="mt-15 mb-5 sm:mb-7.5">Save Media profile</.button>
</:actions> <div class="rounded-sm dark:bg-meta-4 p-4 md:p-6 mb-5">
<.output_template_help />
</div>
</.simple_form> </.simple_form>

View file

@ -0,0 +1,72 @@
<%!-- The heex HTML formatter is really struggling with this file - I apologize in advance --%>
<aside>
<h2 class="text-xl font-bold mb-2">Output Template Syntax</h2>
<section class="ml-2 md:ml-4 mb-4 max-w-prose">
<p>When generating an output template, you have 3 options for syntax:</p>
<ul class="list-disc list-inside ml-2 md:ml-5">
<li>
Liquid-style:
<.inline_code>/{{ channel }}/{{ title }} - {{ id }}.{{ ext }}</.inline_code>
</li>
<li>
<code class="text-sm">yt-dlp</code>-style
<.reference_link href="https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#output-template">
<.icon name="hero-arrow-top-right-on-square" class="h-4 w-4" />
</.reference_link>:
<.inline_code>/%(channel)s/%(duration>%H-%M-%S)s-%(id)s.%(ext)s</.inline_code>
</li>
<li>
Any bare words:
<.inline_code>/videos/1080p/{{ id }}.{{ ext }}</.inline_code>
</li>
</ul>
<p class="my-2">
Apart from custom aliases, the liquid-style syntax maps 1:1 to the <code class="text-sm">yt-dlp</code>-style syntax behind-the-scenes. This means that
<em>any</em>
single-word <code class="text-sm">yt-dlp</code>
option can be used as liquid-style and it's automatically made filepath-safe. For example, the
<.inline_code>{{ duration }}</.inline_code>
option is translated to
<.inline_code>%(duration)S</.inline_code>
</p>
<p class="my-2">
<strong>Major 🔑:</strong>
these syntaxes can be mixed and matched freely! I prefer to use liquid-style and bare words
but I'll include <code class="text-sm">yt-dlp</code>-style when I need more control. For example:
<.inline_code>/1080p/{{ channel }}/{{ title }}-(%(subtitles.en.-1.ext)s).{{ ext }}</.inline_code>
</p>
<p class="my-2">
<strong>NOTE:</strong>
Your template <em>must</em>
end with an extension option (<.inline_code>.{{ ext }}</.inline_code>
or
<.inline_code>.%(ext)S</.inline_code>).
Downloading won't work as expected without it.
</p>
</section>
<h2 class="text-xl font-bold mb-2">Template Options</h2>
<section class="ml-2 md:ml-4 mb-4 max-w-prose">
<p>
Any single-word <code class="text-sm">yt-dlp</code>
option
<.reference_link href="https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#output-template">
<.icon name="hero-arrow-top-right-on-square" class="h-4 w-4" />
</.reference_link>
can be used with the curly braced liquid-style syntax.
This is just a list of the most common options as well as some custom aliases
</p>
<h3 class="text-lg font-bold mb-2">Custom Aliases</h3>
<ul class="list-disc list-inside ml-2 md:ml-5">
<li :for={opt <- custom_output_template_options()}>
<.inline_code>{{ <%= opt %> }}</.inline_code>
</li>
</ul>
<h3 class="text-lg font-bold mb-2">Common Options</h3>
<ul class="list-disc list-inside ml-2 md:ml-5">
<li :for={opt <- common_output_template_options()}>
<.inline_code>{{ <%= opt %> }}</.inline_code>
</li>
</ul>
</section>
</aside>