forgt what i was doing
This commit is contained in:
parent
9af03eea9b
commit
cdff1c7565
5 changed files with 119 additions and 112 deletions
|
|
@ -1,90 +1,80 @@
|
||||||
==================
|
|
||||||
Configuration File
|
Configuration File
|
||||||
==================
|
==================
|
||||||
-----------
|
Something
|
||||||
config.yaml
|
|
||||||
-----------
|
|
||||||
|
|
||||||
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
|
.. code-block:: yaml
|
||||||
|
|
||||||
configuration:
|
configuration:
|
||||||
presets:
|
dl_aliases:
|
||||||
|
mv: "--preset music_video"
|
||||||
|
u: "--download.url"
|
||||||
|
|
||||||
You can jump to any section and subsection of the config using the navigation
|
Simplifies
|
||||||
section to the left.
|
|
||||||
|
|
||||||
Note for Windows users, paths can be represented with ``C:/forward/slashes/like/linux``.
|
.. code-block:: bash
|
||||||
If you wish to represent paths like Windows, you will need to ``C:\\double\\bashslash\\paths``
|
|
||||||
in order to escape the backslash character.
|
|
||||||
|
|
||||||
configuration
|
ytdl-sub dl --preset "Jellyfin Music Videos" --download.url "youtube.com/watch?v=a1b2c3"
|
||||||
~~~~~~~~~~~~~
|
|
||||||
The ``configuration`` section contains app-wide configs applied to all presets
|
|
||||||
and subscriptions.
|
|
||||||
|
|
||||||
.. autoclass:: ytdl_sub.config.config_validator.ConfigOptions()
|
to
|
||||||
:members:
|
|
||||||
:member-order: bysource
|
.. code-block:: bash
|
||||||
:exclude-members: subscription_value, persist_logs, experimental
|
|
||||||
|
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
|
persist_logs
|
||||||
""""""""""""
|
------------
|
||||||
Within ``configuration``, define whether logs from subscription downloads
|
TODO(jessebannon) fill out
|
||||||
should be persisted.
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
``keep_successful_logs``
|
||||||
|
|
||||||
configuration:
|
Optional. Whether to store logs when downloading is successful. Defaults to True.
|
||||||
persist_logs:
|
|
||||||
logs_directory: "/path/to/log/directory"
|
|
||||||
|
|
||||||
Log files are stored as
|
``logs_directory``
|
||||||
``YYYY-mm-dd-HHMMSS.subscription_name.(success|error).log``.
|
|
||||||
|
|
||||||
.. autoclass:: ytdl_sub.config.config_validator.PersistLogsValidator()
|
Required. The directory to store the logs in.
|
||||||
:members:
|
|
||||||
:member-order: bysource
|
|
||||||
|
|
||||||
presets
|
umask
|
||||||
~~~~~~~
|
-----
|
||||||
``presets`` define a `formula` for how to format downloaded media and metadata.
|
Umask (octal format) to apply to every created file. Defaults to "022".
|
||||||
|
|
||||||
This section is work-in-progress!
|
working_directory
|
||||||
|
-----------------
|
||||||
preset
|
The directory to temporarily store downloaded files before moving them into their final
|
||||||
""""""
|
directory. Defaults to .ytdl-sub-working-directory
|
||||||
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.
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,10 @@ from ytdl_sub.validators.validators import StringValidator
|
||||||
|
|
||||||
|
|
||||||
class ExperimentalValidator(StrictDictValidator):
|
class ExperimentalValidator(StrictDictValidator):
|
||||||
|
"""
|
||||||
|
TODO(jessebannon) fill out
|
||||||
|
"""
|
||||||
|
|
||||||
_optional_keys = {"enable_update_with_info_json"}
|
_optional_keys = {"enable_update_with_info_json"}
|
||||||
_allow_extra_keys = True
|
_allow_extra_keys = True
|
||||||
|
|
||||||
|
|
@ -43,6 +47,10 @@ class ExperimentalValidator(StrictDictValidator):
|
||||||
|
|
||||||
|
|
||||||
class PersistLogsValidator(StrictDictValidator):
|
class PersistLogsValidator(StrictDictValidator):
|
||||||
|
"""
|
||||||
|
TODO(jessebannon) fill out
|
||||||
|
"""
|
||||||
|
|
||||||
_required_keys = {"logs_directory"}
|
_required_keys = {"logs_directory"}
|
||||||
_optional_keys = {"keep_logs_after", "keep_successful_logs"}
|
_optional_keys = {"keep_logs_after", "keep_successful_logs"}
|
||||||
|
|
||||||
|
|
@ -98,6 +106,10 @@ class PersistLogsValidator(StrictDictValidator):
|
||||||
|
|
||||||
|
|
||||||
class ConfigOptions(StrictDictValidator):
|
class ConfigOptions(StrictDictValidator):
|
||||||
|
"""
|
||||||
|
Something
|
||||||
|
"""
|
||||||
|
|
||||||
_optional_keys = {
|
_optional_keys = {
|
||||||
"working_directory",
|
"working_directory",
|
||||||
"umask",
|
"umask",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
|
from tools.docgen.configuration import ConfigurationDocGen
|
||||||
from tools.docgen.docgen import DocGen
|
from tools.docgen.docgen import DocGen
|
||||||
from tools.docgen.entry_variables import EntryVariablesDocGen
|
from tools.docgen.entry_variables import EntryVariablesDocGen
|
||||||
from tools.docgen.plugins import PluginsDocGen
|
from tools.docgen.plugins import PluginsDocGen
|
||||||
|
|
@ -28,3 +29,6 @@ class TestDocGen:
|
||||||
|
|
||||||
def test_plugins_generated(self):
|
def test_plugins_generated(self):
|
||||||
_test_doc_gen(PluginsDocGen)
|
_test_doc_gen(PluginsDocGen)
|
||||||
|
|
||||||
|
def test_configuration_generated(self):
|
||||||
|
_test_doc_gen(ConfigurationDocGen)
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,8 @@
|
||||||
from pathlib import Path
|
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.docgen import DocGen
|
||||||
from tools.docgen.utils import cached_properties
|
from tools.docgen.utils import generate_options_validator_docs
|
||||||
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 ytdl_sub.config.config_validator import ConfigOptions
|
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):
|
class ConfigurationDocGen(DocGen):
|
||||||
|
|
@ -28,23 +10,14 @@ class ConfigurationDocGen(DocGen):
|
||||||
LOCATION = Path("docs/source/config_reference/config_yaml.rst")
|
LOCATION = Path("docs/source/config_reference/config_yaml.rst")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate(cls) -> str:
|
def generate(cls):
|
||||||
docs = section("Configuration File", level=0)
|
docs = generate_options_validator_docs(
|
||||||
|
name="Configuration File",
|
||||||
parent_objs: Dict[str, Type[Any]] = {
|
options=ConfigOptions,
|
||||||
_variable_class_to_name(obj): obj for obj in ConfigOptions.__bases__
|
offset=0,
|
||||||
}
|
skip_properties=False,
|
||||||
|
recurse_property_options=True,
|
||||||
for idx, name in enumerate(sorted(parent_objs.keys())):
|
property_sections=True
|
||||||
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,
|
|
||||||
)
|
|
||||||
|
|
||||||
return docs
|
return docs
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,10 @@ from typing import Any
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import Set
|
|
||||||
from typing import Type
|
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: "^"}
|
LEVEL_CHARS: Dict[int, str] = {0: "=", 1: "-", 2: "~", 3: "^"}
|
||||||
|
|
||||||
|
|
@ -25,6 +25,19 @@ def _should_filter_property(property_name: str) -> bool:
|
||||||
"unresolvable",
|
"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:
|
def section(name: str, level: Optional[int]) -> str:
|
||||||
if level is None:
|
if level is None:
|
||||||
|
|
@ -85,7 +98,7 @@ def get_function_docs(
|
||||||
|
|
||||||
|
|
||||||
def generate_options_validator_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:
|
) -> str:
|
||||||
docs = ""
|
docs = ""
|
||||||
docs += section(name, level=offset + 0)
|
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)]
|
property_names = [prop for prop in properties(options) if not _should_filter_property(prop)]
|
||||||
for property_name in sorted(property_names):
|
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
|
return docs
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue