forgt what i was doing

This commit is contained in:
Jesse Bannon 2025-03-08 13:24:45 -08:00
parent 9af03eea9b
commit cdff1c7565
5 changed files with 119 additions and 112 deletions

View file

@ -1,90 +1,80 @@
==================
Configuration File
==================
-----------
config.yaml
-----------
Something
ytdl-sub is configured using a ``config.yaml`` file.
dl_aliases
----------
.. _dl_aliases:
The ``config.yaml`` is made up of two sections:
Alias definitions to shorten ``ytdl-sub dl`` arguments. For example,
.. code-block:: yaml
configuration:
presets:
configuration:
dl_aliases:
mv: "--preset music_video"
u: "--download.url"
You can jump to any section and subsection of the config using the navigation
section to the left.
Simplifies
Note for Windows users, paths can be represented with ``C:/forward/slashes/like/linux``.
If you wish to represent paths like Windows, you will need to ``C:\\double\\bashslash\\paths``
in order to escape the backslash character.
.. code-block:: bash
configuration
~~~~~~~~~~~~~
The ``configuration`` section contains app-wide configs applied to all presets
and subscriptions.
ytdl-sub dl --preset "Jellyfin Music Videos" --download.url "youtube.com/watch?v=a1b2c3"
.. autoclass:: ytdl_sub.config.config_validator.ConfigOptions()
:members:
:member-order: bysource
:exclude-members: subscription_value, persist_logs, experimental
to
.. code-block:: bash
ytdl-sub dl --mv --u "youtube.com/watch?v=a1b2c3"
experimental
------------
TODO(jessebannon) fill out
``enable_update_with_info_json``
Enables modifying subscription files using info.json files using the argument
``--update-with-info-json``. This feature is still being tested and has the ability to
destroy files. Ensure you have a full backup before usage. You have been warned!
ffmpeg_path
-----------
Path to ffmpeg executable. Defaults to ``/usr/bin/ffmpeg`` for Linux, and
``ffmpeg.exe`` for Windows (in the same directory as ytdl-sub).
ffprobe_path
------------
Path to ffprobe executable. Defaults to ``/usr/bin/ffprobe`` for Linux, and
``ffprobe.exe`` for Windows (in the same directory as ytdl-sub).
file_name_max_bytes
-------------------
Max file name size in bytes. Most OS's typically default to 255 bytes.
lock_directory
--------------
The directory to temporarily store file locks, which prevents multiple instances
of ``ytdl-sub`` from running. Note that file locks do not work on network-mounted
directories. Ensure that this directory resides on the host machine. Defaults to ``/tmp``.
persist_logs
""""""""""""
Within ``configuration``, define whether logs from subscription downloads
should be persisted.
------------
TODO(jessebannon) fill out
.. code-block:: yaml
``keep_successful_logs``
configuration:
persist_logs:
logs_directory: "/path/to/log/directory"
Optional. Whether to store logs when downloading is successful. Defaults to True.
Log files are stored as
``YYYY-mm-dd-HHMMSS.subscription_name.(success|error).log``.
``logs_directory``
.. autoclass:: ytdl_sub.config.config_validator.PersistLogsValidator()
:members:
:member-order: bysource
Required. The directory to store the logs in.
presets
~~~~~~~
``presets`` define a `formula` for how to format downloaded media and metadata.
umask
-----
Umask (octal format) to apply to every created file. Defaults to "022".
This section is work-in-progress!
preset
""""""
Presets support inheritance by defining a parent preset:
.. code-block:: yaml
presets:
custom_preset:
...
parent_preset:
...
child_preset:
preset: "parent_preset"
In the example above, ``child_preset`` inherits all fields defined in ``parent_preset``.
It is advantageous to use parent presets where possible to reduce duplicate yaml
definitions.
Presets also support inheritance from multiple presets:
.. code-block:: yaml
child_preset:
preset:
- "custom_preset"
- "parent_preset"
In this example, ``child_preset`` will inherit all fields from ``custom_preset``
and ``parent_preset`` in that order. The bottom-most preset has the highest
priority.
If you are only inheriting from one preset, the syntax ``preset: "parent_preset"`` is
valid YAML. Inheriting from multiple presets require use of a list.
working_directory
-----------------
The directory to temporarily store downloaded files before moving them into their final
directory. Defaults to .ytdl-sub-working-directory

View file

@ -22,6 +22,10 @@ from ytdl_sub.validators.validators import StringValidator
class ExperimentalValidator(StrictDictValidator):
"""
TODO(jessebannon) fill out
"""
_optional_keys = {"enable_update_with_info_json"}
_allow_extra_keys = True
@ -43,6 +47,10 @@ class ExperimentalValidator(StrictDictValidator):
class PersistLogsValidator(StrictDictValidator):
"""
TODO(jessebannon) fill out
"""
_required_keys = {"logs_directory"}
_optional_keys = {"keep_logs_after", "keep_successful_logs"}
@ -98,6 +106,10 @@ class PersistLogsValidator(StrictDictValidator):
class ConfigOptions(StrictDictValidator):
"""
Something
"""
_optional_keys = {
"working_directory",
"umask",

View file

@ -1,5 +1,6 @@
from typing import Type
from tools.docgen.configuration import ConfigurationDocGen
from tools.docgen.docgen import DocGen
from tools.docgen.entry_variables import EntryVariablesDocGen
from tools.docgen.plugins import PluginsDocGen
@ -28,3 +29,6 @@ class TestDocGen:
def test_plugins_generated(self):
_test_doc_gen(PluginsDocGen)
def test_configuration_generated(self):
_test_doc_gen(ConfigurationDocGen)

View file

@ -1,26 +1,8 @@
from pathlib import Path
from typing import Any
from typing import Dict
from typing import Type
from tools.docgen.docgen import DocGen
from tools.docgen.utils import cached_properties
from tools.docgen.utils import camel_case_to_human
from tools.docgen.utils import get_function_docs
from tools.docgen.utils import line_section
from tools.docgen.utils import section
from tools.docgen.utils import generate_options_validator_docs
from ytdl_sub.config.config_validator import ConfigOptions
from ytdl_sub.entries.script.variable_definitions import VARIABLES
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
def _variable_class_to_name(obj: Type[Any]) -> str:
assert "VariableDefinitions" in obj.__name__, f"{obj.__name__} doesnt have VariableDefinitions"
return (
camel_case_to_human(obj.__name__)
.replace("Variable Definitions", "Variables")
.replace("Ytdl Sub", "Ytdl-Sub")
)
class ConfigurationDocGen(DocGen):
@ -28,23 +10,14 @@ class ConfigurationDocGen(DocGen):
LOCATION = Path("docs/source/config_reference/config_yaml.rst")
@classmethod
def generate(cls) -> str:
docs = section("Configuration File", level=0)
parent_objs: Dict[str, Type[Any]] = {
_variable_class_to_name(obj): obj for obj in ConfigOptions.__bases__
}
for idx, name in enumerate(sorted(parent_objs.keys())):
docs += line_section(section_idx=idx)
docs += section(name, level=1)
for variable_function_name in cached_properties(parent_objs[name]):
docs += get_function_docs(
function_name=variable_function_name,
obj=parent_objs[name],
pre_docstring=f":type: ``{getattr(VARIABLES, variable_function_name).human_readable_type()}``\n",
level=2,
)
def generate(cls):
docs = generate_options_validator_docs(
name="Configuration File",
options=ConfigOptions,
offset=0,
skip_properties=False,
recurse_property_options=True,
property_sections=True
)
return docs

View file

@ -4,10 +4,10 @@ from typing import Any
from typing import Dict
from typing import List
from typing import Optional
from typing import Set
from typing import Type
from ytdl_sub.config.validators.options import OptionsValidator
from ytdl_sub.script.utils.type_checking import is_optional, get_optional_type
from ytdl_sub.validators.validators import Validator
LEVEL_CHARS: Dict[int, str] = {0: "=", 1: "-", 2: "~", 3: "^"}
@ -25,6 +25,19 @@ def _should_filter_property(property_name: str) -> bool:
"unresolvable",
)
def _is_validator_property(options: Type[Validator], property_name: str) -> Optional[Type[Validator]]:
property_return_type = inspect.getfullargspec(getattr(options, property_name).fget).annotations['return']
if is_optional(property_return_type):
property_return_type = get_optional_type(property_return_type)
try:
if issubclass(property_return_type, Validator):
return property_return_type
except TypeError:
return None
return None
def section(name: str, level: Optional[int]) -> str:
if level is None:
@ -85,7 +98,7 @@ def get_function_docs(
def generate_options_validator_docs(
name: str, options: Type[OptionsValidator], offset: int, skip_properties: bool
name: str, options: Type[Validator], offset: int, skip_properties: bool, recurse_property_options: bool = False, property_sections: bool = False
) -> str:
docs = ""
docs += section(name, level=offset + 0)
@ -98,6 +111,21 @@ def generate_options_validator_docs(
property_names = [prop for prop in properties(options) if not _should_filter_property(prop)]
for property_name in sorted(property_names):
docs += get_function_docs(function_name=property_name, obj=options, level=None, display_function_name=f"``{property_name}``")
maybe_validator_property = _is_validator_property(options, property_name) if recurse_property_options else None
if maybe_validator_property:
docs += generate_options_validator_docs(
name=property_name,
options=maybe_validator_property,
offset=offset + 1,
skip_properties=False,
recurse_property_options=False
)
else:
docs += get_function_docs(
function_name=property_name,
obj=options,
level=(offset + 1) if property_sections else None,
display_function_name=f"``{property_name}``" if not property_sections else None,
)
return docs