From 90691ba2b9ee3bd4dce0514c89cc7744e54d29be Mon Sep 17 00:00:00 2001 From: Jakub Kuczys Date: Mon, 26 Aug 2024 19:34:37 +0200 Subject: [PATCH] Generate default LL server config and attach it to GH release (#6430) --- .github/workflows/publish_release.yml | 40 ++++ .../scripts/get_default_ll_server_config.py | 31 +++ redbot/cogs/audio/managed_node/__init__.py | 16 ++ .../audio/managed_node/ll_server_config.py | 119 ++++++++++ redbot/cogs/audio/managed_node/ll_version.py | 204 ++++++++++++++++ .../cogs/audio/managed_node/version_pins.py | 9 + redbot/cogs/audio/manager.py | 224 +----------------- redbot/cogs/audio/utils.py | 69 +----- .../test_ll_version.py} | 2 +- 9 files changed, 431 insertions(+), 283 deletions(-) create mode 100644 .github/workflows/scripts/get_default_ll_server_config.py create mode 100644 redbot/cogs/audio/managed_node/__init__.py create mode 100644 redbot/cogs/audio/managed_node/ll_server_config.py create mode 100644 redbot/cogs/audio/managed_node/ll_version.py create mode 100644 redbot/cogs/audio/managed_node/version_pins.py rename tests/cogs/audio/{test_manager.py => managed_node/test_ll_version.py} (98%) diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml index 00f023549..e9d3449d8 100644 --- a/.github/workflows/publish_release.yml +++ b/.github/workflows/publish_release.yml @@ -80,10 +80,38 @@ jobs: name: build-output path: ./dist + generate_default_ll_server_config: + name: Generate default application.yml + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.8' + + - name: Install script's dependencies + run: python -m pip install PyYAML + + - name: Generate default application.yml + env: + APP_YML_FILE: "Red-DiscordBot-${{ github.ref_name }}-default-lavalink-application.yml" + run: | + mkdir -p dist + python .github/workflows/scripts/get_default_ll_server_config.py "dist/$APP_YML_FILE" + + - name: Upload default application.yml + uses: actions/upload-artifact@v3 + with: + name: ll-default-server-config + path: ./dist + release_to_pypi: needs: - release_information - build + - generate_default_ll_server_config environment: Release name: Release to PyPI runs-on: ubuntu-latest @@ -96,6 +124,18 @@ jobs: name: build-output path: dist/ + - name: Download default application.yml + uses: actions/download-artifact@v3 + with: + name: ll-default-server-config + path: dist/ + + - name: Upload dists to GitHub Release + env: + GITHUB_TOKEN: "${{ github.token }}" + run: | + gh release upload "$GITHUB_REF_NAME" dist/* + - name: Publish package distributions to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: diff --git a/.github/workflows/scripts/get_default_ll_server_config.py b/.github/workflows/scripts/get_default_ll_server_config.py new file mode 100644 index 000000000..c25020f3e --- /dev/null +++ b/.github/workflows/scripts/get_default_ll_server_config.py @@ -0,0 +1,31 @@ +import sys +from pathlib import Path + +import yaml + +ROOT_FOLDER = Path(__file__).parents[3].absolute() +AUDIO_FOLDER = ROOT_FOLDER / "redbot/cogs/audio" + +# We want to import `redbot.cogs.audio.managed_node` package as if it were top-level package +# so we have to the `redbot/cogs/audio` directory to Python's path. +sys.path.insert(0, str(AUDIO_FOLDER)) + + +def main() -> int: + try: + output_file = sys.argv[1] + except IndexError: + print("Usage:", sys.argv[0], "", file=sys.stderr) + return 2 + + import managed_node + + server_config = managed_node.get_default_server_config() + with open(output_file, "w", encoding="utf-8") as fp: + yaml.safe_dump(server_config, fp) + + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/redbot/cogs/audio/managed_node/__init__.py b/redbot/cogs/audio/managed_node/__init__.py new file mode 100644 index 000000000..52d0a443b --- /dev/null +++ b/redbot/cogs/audio/managed_node/__init__.py @@ -0,0 +1,16 @@ +# Note: contents of this package are meant to be self-contained +# and should not depend on anything in Red or on external dependencies. + +from .ll_server_config import generate_server_config, get_default_server_config +from .ll_version import LAVALINK_BUILD_LINE, LavalinkOldVersion, LavalinkVersion +from .version_pins import JAR_VERSION, YT_PLUGIN_VERSION + +__all__ = ( + "generate_server_config", + "get_default_server_config", + "LAVALINK_BUILD_LINE", + "LavalinkOldVersion", + "LavalinkVersion", + "JAR_VERSION", + "YT_PLUGIN_VERSION", +) diff --git a/redbot/cogs/audio/managed_node/ll_server_config.py b/redbot/cogs/audio/managed_node/ll_server_config.py new file mode 100644 index 000000000..3e9faec84 --- /dev/null +++ b/redbot/cogs/audio/managed_node/ll_server_config.py @@ -0,0 +1,119 @@ +from __future__ import annotations + +from typing import Any, Dict, Final + +from . import version_pins + +__all__ = ( + "DEFAULT_LAVALINK_YAML", + "get_default_server_config", + "generate_server_config", + "change_dict_naming_convention", +) + +YT_PLUGIN_REPOSITORY: Final[str] = "https://maven.lavalink.dev/releases" + +DEFAULT_LAVALINK_YAML = { + # The nesting structure of this dict is very important, it's a 1:1 mirror of application.yaml in JSON + "yaml__server__address": "localhost", + "yaml__server__port": 2333, + "yaml__lavalink__server__password": "youshallnotpass", + "yaml__lavalink__server__sources__http": True, + "yaml__lavalink__server__sources__bandcamp": True, + "yaml__lavalink__server__sources__local": True, + "yaml__lavalink__server__sources__soundcloud": True, + "yaml__lavalink__server__sources__youtube": True, + "yaml__lavalink__server__sources__twitch": True, + "yaml__lavalink__server__sources__vimeo": True, + "yaml__lavalink__server__bufferDurationMs": 400, + "yaml__lavalink__server__frameBufferDurationMs": 1000, + # 100 pages - 100 entries per page = 10,000 tracks which is the Audio Limit for a single playlist. + "yaml__lavalink__server__youtubePlaylistLoadLimit": 100, + "yaml__lavalink__server__playerUpdateInterval": 1, + "yaml__lavalink__server__youtubeSearchEnabled": True, + "yaml__lavalink__server__soundcloudSearchEnabled": True, + "yaml__lavalink__server__gc_warnings": True, + "yaml__metrics__prometheus__enabled": False, + "yaml__metrics__prometheus__endpoint": "/metrics", + "yaml__sentry__dsn": "", + "yaml__sentry__environment": "", + "yaml__logging__file__path": "./logs/", + "yaml__logging__level__root": "INFO", + "yaml__logging__level__lavalink": "INFO", + "yaml__logging__logback__rollingpolicy__max_history": 15, + "yaml__logging__logback__rollingpolicy__max_size": "10MB", + # plugin configuration - note that the plugin may be disabled by the manager + "yaml__plugins__youtube__enabled": True, + "yaml__plugins__youtube__allowSearch": True, + "yaml__plugins__youtube__allowDirectVideoIds": True, + "yaml__plugins__youtube__allowDirectPlaylistIds": True, + "yaml__plugins__youtube__clients": [ + "MUSIC", + "WEB", + "ANDROID_TESTSUITE", + "TVHTML5EMBEDDED", + "ANDROID_LITE", + "MEDIA_CONNECT", + "IOS", + ], + "yaml__plugins__youtube__WEB__playback": True, + "yaml__plugins__youtube__TVHTML5EMBEDDED__playlistLoading": False, + "yaml__plugins__youtube__TVHTML5EMBEDDED__videoLoading": False, + "yaml__plugins__youtube__TVHTML5EMBEDDED__searching": False, +} + + +def _unflatten_config_defaults(config_defaults: Dict[str, Any]) -> Dict[str, Any]: + ret: Dict[str, Any] = {} + + # based on Config._get_defaults_dict() + for flat_key, value in config_defaults.items(): + keys = flat_key.split("__") + partial = ret + for idx, key in enumerate(keys, start=1): + if idx == len(keys): + partial[key] = value + else: + partial = partial.setdefault(key, {}) + + return ret + + +def get_default_server_config() -> Dict[str, Any]: + return generate_server_config(_unflatten_config_defaults(DEFAULT_LAVALINK_YAML)["yaml"]) + + +def generate_server_config(config_data: Dict[str, Any]) -> Dict[str, Any]: + data = change_dict_naming_convention(config_data) + ll_config = data["lavalink"] + sources = ll_config["server"]["sources"] + plugins = ll_config.setdefault("plugins", []) + + enable_yt_plugin = sources["youtube"] + if enable_yt_plugin: + sources["youtube"] = False + yt_plugin = { + "dependency": f"dev.lavalink.youtube:youtube-plugin:{version_pins.YT_PLUGIN_VERSION}", + "repository": YT_PLUGIN_REPOSITORY, + } + plugins.append(yt_plugin) + + return data + + +# This assumes all keys with `_` should be converted from `part1_part2` to `part1-part2` +def _convert_function(key: str) -> str: + return key.replace("_", "-") + + +def change_dict_naming_convention(data: Any) -> Any: + ret: Any = data + if isinstance(data, dict): + ret = {} + for key, value in data.items(): + ret[_convert_function(key)] = change_dict_naming_convention(value) + elif isinstance(data, list): + ret = [] + for value in data: + ret.append(change_dict_naming_convention(value)) + return ret diff --git a/redbot/cogs/audio/managed_node/ll_version.py b/redbot/cogs/audio/managed_node/ll_version.py new file mode 100644 index 000000000..a29f5326f --- /dev/null +++ b/redbot/cogs/audio/managed_node/ll_version.py @@ -0,0 +1,204 @@ +from __future__ import annotations + +import re +from typing import Final, Optional, Pattern, Tuple + +__all__ = ( + "LAVALINK_BUILD_LINE", + "LavalinkOldVersion", + "LavalinkVersion", +) + + +# present until Lavalink 3.5-rc4 +LAVALINK_BUILD_LINE: Final[Pattern] = re.compile(rb"^Build:\s+(?P\d+)$", re.MULTILINE) +# we don't actually care about what the version format before 3.5-rc4 is exactly +# as the comparison is based entirely on the build number +_LAVALINK_VERSION_LINE_PRE35: Final[Pattern] = re.compile( + rb"^Version:\s+(?P\S+)$", re.MULTILINE | re.VERBOSE +) +# used for LL versions >=3.5-rc4 but below 3.6. +# Since this only applies to historical version, this regex is based only on +# version numbers that actually existed, not ones that technically could. +_LAVALINK_VERSION_LINE_PRE36: Final[Pattern] = re.compile( + rb""" + ^ + Version:\s+ + (?P + (?P3)\.(?P[0-5]) + # Before LL 3.6, when patch version == 0, it was stripped from the version string + (?:\.(?P[1-9]\d*))? + # Before LL 3.6, the dot in rc.N was optional + (?:-rc\.?(?P0|[1-9]\d*))? + # additional build metadata, can be used by our downstream Lavalink + # if we need to alter an upstream release + (?:\+red\.(?P[1-9]\d*))? + ) + $ + """, + re.MULTILINE | re.VERBOSE, +) +# used for LL 3.6 and newer +# This regex is limited to the realistic usage in the LL version number, +# not everything that could be a part of it according to the spec. +# We can easily release an update to this regex in the future if it ever becomes necessary. +_LAVALINK_VERSION_LINE: Final[Pattern] = re.compile( + rb""" + ^ + Version:\s+ + (?P + (?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*) + (?:-rc\.(?P0|[1-9]\d*))? + # additional build metadata, can be used by our downstream Lavalink + # if we need to alter an upstream release + (?:\+red\.(?P[1-9]\d*))? + ) + $ + """, + re.MULTILINE | re.VERBOSE, +) + + +class LavalinkOldVersion: + def __init__(self, raw_version: str, *, build_number: int) -> None: + self.raw_version = raw_version + self.build_number = build_number + + def __str__(self) -> str: + return f"{self.raw_version}_{self.build_number}" + + @classmethod + def from_version_output(cls, output: bytes) -> LavalinkOldVersion: + build_match = LAVALINK_BUILD_LINE.search(output) + if build_match is None: + raise ValueError( + "Could not find 'Build' line in the given `--version` output," + " or invalid build number given." + ) + version_match = _LAVALINK_VERSION_LINE_PRE35.search(output) + if version_match is None: + raise ValueError( + "Could not find 'Version' line in the given `--version` output," + " or invalid version number given." + ) + return cls( + raw_version=version_match["version"].decode(), + build_number=int(build_match["build"]), + ) + + def __eq__(self, other: object) -> bool: + if isinstance(other, LavalinkOldVersion): + return self.build_number == other.build_number + if isinstance(other, LavalinkVersion): + return False + return NotImplemented + + def __lt__(self, other: object) -> bool: + if isinstance(other, LavalinkOldVersion): + return self.build_number < other.build_number + if isinstance(other, LavalinkVersion): + return True + return NotImplemented + + def __le__(self, other: object) -> bool: + if isinstance(other, LavalinkOldVersion): + return self.build_number <= other.build_number + if isinstance(other, LavalinkVersion): + return True + return NotImplemented + + def __gt__(self, other: object) -> bool: + if isinstance(other, LavalinkOldVersion): + return self.build_number > other.build_number + if isinstance(other, LavalinkVersion): + return False + return NotImplemented + + def __ge__(self, other: object) -> bool: + if isinstance(other, LavalinkOldVersion): + return self.build_number >= other.build_number + if isinstance(other, LavalinkVersion): + return False + return NotImplemented + + +class LavalinkVersion: + def __init__( + self, + major: int, + minor: int, + patch: int = 0, + *, + rc: Optional[int] = None, + red: int = 0, + ) -> None: + self.major = major + self.minor = minor + self.patch = patch + self.rc = rc + self.red = red + + def __str__(self) -> str: + version = f"{self.major}.{self.minor}.{self.patch}" + if self.rc is not None: + version += f"-rc.{self.rc}" + if self.red: + version += f"+red.{self.red}" + return version + + @classmethod + def from_version_output(cls, output: bytes) -> LavalinkVersion: + match = _LAVALINK_VERSION_LINE.search(output) + if match is None: + # >=3.5-rc4, <3.6 + match = _LAVALINK_VERSION_LINE_PRE36.search(output) + if match is None: + raise ValueError( + "Could not find 'Version' line in the given `--version` output," + " or invalid version number given." + ) + return cls( + major=int(match["major"]), + minor=int(match["minor"]), + patch=int(match["patch"] or 0), + rc=int(match["rc"]) if match["rc"] is not None else None, + red=int(match["red"] or 0), + ) + + def _get_comparison_tuple(self) -> Tuple[int, int, int, bool, int, int]: + return self.major, self.minor, self.patch, self.rc is None, self.rc or 0, self.red + + def __eq__(self, other: object) -> bool: + if isinstance(other, LavalinkVersion): + return self._get_comparison_tuple() == other._get_comparison_tuple() + if isinstance(other, LavalinkOldVersion): + return False + return NotImplemented + + def __lt__(self, other: object) -> bool: + if isinstance(other, LavalinkVersion): + return self._get_comparison_tuple() < other._get_comparison_tuple() + if isinstance(other, LavalinkOldVersion): + return False + return NotImplemented + + def __le__(self, other: object) -> bool: + if isinstance(other, LavalinkVersion): + return self._get_comparison_tuple() <= other._get_comparison_tuple() + if isinstance(other, LavalinkOldVersion): + return False + return NotImplemented + + def __gt__(self, other: object) -> bool: + if isinstance(other, LavalinkVersion): + return self._get_comparison_tuple() > other._get_comparison_tuple() + if isinstance(other, LavalinkOldVersion): + return True + return NotImplemented + + def __ge__(self, other: object) -> bool: + if isinstance(other, LavalinkVersion): + return self._get_comparison_tuple() >= other._get_comparison_tuple() + if isinstance(other, LavalinkOldVersion): + return True + return NotImplemented diff --git a/redbot/cogs/audio/managed_node/version_pins.py b/redbot/cogs/audio/managed_node/version_pins.py new file mode 100644 index 000000000..694d31ebb --- /dev/null +++ b/redbot/cogs/audio/managed_node/version_pins.py @@ -0,0 +1,9 @@ +from typing import Final + +from .ll_version import LavalinkVersion + +__all__ = ("JAR_VERSION", "YT_PLUGIN_VERSION") + + +JAR_VERSION: Final[LavalinkVersion] = LavalinkVersion(3, 7, 11, red=3) +YT_PLUGIN_VERSION: Final[str] = "1.5.2" diff --git a/redbot/cogs/audio/manager.py b/redbot/cogs/audio/manager.py index f86089de5..93ad89e3d 100644 --- a/redbot/cogs/audio/manager.py +++ b/redbot/cogs/audio/manager.py @@ -22,6 +22,7 @@ from red_commons.logging import getLogger from redbot.core import data_manager, Config from redbot.core.i18n import Translator +from . import managed_node from .errors import ( LavalinkDownloadFailed, InvalidArchitectureException, @@ -35,8 +36,8 @@ from .errors import ( NoProcessFound, NodeUnhealthy, ) +from .managed_node.ll_version import LAVALINK_BUILD_LINE, LavalinkVersion, LavalinkOldVersion from .utils import ( - change_dict_naming_convention, get_max_allocation_size, replace_p_with_prefix, ) @@ -55,7 +56,7 @@ _LL_PLUGIN_LOG: Final[Pattern[bytes]] = re.compile( ) _FAILED_TO_START: Final[Pattern[bytes]] = re.compile(rb"Web server failed to start\. (.*)") -# Version regexes +# Java version regexes # # We expect the output to look something like: # $ java -version @@ -103,210 +104,14 @@ LAVALINK_LAVAPLAYER_LINE: Final[Pattern] = re.compile( LAVALINK_BUILD_TIME_LINE: Final[Pattern] = re.compile( rb"^Build time:\s+(?P\d+[.\d+]*).*$", re.MULTILINE ) -# present until Lavalink 3.5-rc4 -LAVALINK_BUILD_LINE: Final[Pattern] = re.compile(rb"^Build:\s+(?P\d+)$", re.MULTILINE) -# we don't actually care about what the version format before 3.5-rc4 is exactly -# as the comparison is based entirely on the build number -LAVALINK_VERSION_LINE_PRE35: Final[Pattern] = re.compile( - rb"^Version:\s+(?P\S+)$", re.MULTILINE | re.VERBOSE -) -# used for LL versions >=3.5-rc4 but below 3.6. -# Since this only applies to historical version, this regex is based only on -# version numbers that actually existed, not ones that technically could. -LAVALINK_VERSION_LINE_PRE36: Final[Pattern] = re.compile( - rb""" - ^ - Version:\s+ - (?P - (?P3)\.(?P[0-5]) - # Before LL 3.6, when patch version == 0, it was stripped from the version string - (?:\.(?P[1-9]\d*))? - # Before LL 3.6, the dot in rc.N was optional - (?:-rc\.?(?P0|[1-9]\d*))? - # additional build metadata, can be used by our downstream Lavalink - # if we need to alter an upstream release - (?:\+red\.(?P[1-9]\d*))? - ) - $ - """, - re.MULTILINE | re.VERBOSE, -) -# used for LL 3.6 and newer -# This regex is limited to the realistic usage in the LL version number, -# not everything that could be a part of it according to the spec. -# We can easily release an update to this regex in the future if it ever becomes necessary. -LAVALINK_VERSION_LINE: Final[Pattern] = re.compile( - rb""" - ^ - Version:\s+ - (?P - (?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*) - (?:-rc\.(?P0|[1-9]\d*))? - # additional build metadata, can be used by our downstream Lavalink - # if we need to alter an upstream release - (?:\+red\.(?P[1-9]\d*))? - ) - $ - """, - re.MULTILINE | re.VERBOSE, -) - - -class LavalinkOldVersion: - def __init__(self, raw_version: str, *, build_number: int) -> None: - self.raw_version = raw_version - self.build_number = build_number - - def __str__(self) -> None: - return f"{self.raw_version}_{self.build_number}" - - @classmethod - def from_version_output(cls, output: bytes) -> Self: - build_match = LAVALINK_BUILD_LINE.search(output) - if build_match is None: - raise ValueError( - "Could not find 'Build' line in the given `--version` output," - " or invalid build number given." - ) - version_match = LAVALINK_VERSION_LINE_PRE35.search(output) - if version_match is None: - raise ValueError( - "Could not find 'Version' line in the given `--version` output," - " or invalid version number given." - ) - return cls( - raw_version=version_match["version"].decode(), - build_number=int(build_match["build"]), - ) - - def __eq__(self, other: object) -> bool: - if isinstance(other, LavalinkOldVersion): - return self.build_number == other.build_number - if isinstance(other, LavalinkVersion): - return False - return NotImplemented - - def __lt__(self, other: object) -> bool: - if isinstance(other, LavalinkOldVersion): - return self.build_number < other.build_number - if isinstance(other, LavalinkVersion): - return True - return NotImplemented - - def __le__(self, other: object) -> bool: - if isinstance(other, LavalinkOldVersion): - return self.build_number <= other.build_number - if isinstance(other, LavalinkVersion): - return True - return NotImplemented - - def __gt__(self, other: object) -> bool: - if isinstance(other, LavalinkOldVersion): - return self.build_number > other.build_number - if isinstance(other, LavalinkVersion): - return False - return NotImplemented - - def __ge__(self, other: object) -> bool: - if isinstance(other, LavalinkOldVersion): - return self.build_number >= other.build_number - if isinstance(other, LavalinkVersion): - return False - return NotImplemented - - -class LavalinkVersion: - def __init__( - self, - major: int, - minor: int, - patch: int = 0, - *, - rc: Optional[int] = None, - red: int = 0, - ) -> None: - self.major = major - self.minor = minor - self.patch = patch - self.rc = rc - self.red = red - - def __str__(self) -> None: - version = f"{self.major}.{self.minor}.{self.patch}" - if self.rc is not None: - version += f"-rc.{self.rc}" - if self.red: - version += f"+red.{self.red}" - return version - - @classmethod - def from_version_output(cls, output: bytes) -> Self: - match = LAVALINK_VERSION_LINE.search(output) - if match is None: - # >=3.5-rc4, <3.6 - match = LAVALINK_VERSION_LINE_PRE36.search(output) - if match is None: - raise ValueError( - "Could not find 'Version' line in the given `--version` output," - " or invalid version number given." - ) - return LavalinkVersion( - major=int(match["major"]), - minor=int(match["minor"]), - patch=int(match["patch"] or 0), - rc=int(match["rc"]) if match["rc"] is not None else None, - red=int(match["red"] or 0), - ) - - def _get_comparison_tuple(self) -> Tuple[int, int, int, bool, int, int]: - return self.major, self.minor, self.patch, self.rc is None, self.rc or 0, self.red - - def __eq__(self, other: object) -> bool: - if isinstance(other, LavalinkVersion): - return self._get_comparison_tuple() == other._get_comparison_tuple() - if isinstance(other, LavalinkOldVersion): - return False - return NotImplemented - - def __lt__(self, other: object) -> bool: - if isinstance(other, LavalinkVersion): - return self._get_comparison_tuple() < other._get_comparison_tuple() - if isinstance(other, LavalinkOldVersion): - return False - return NotImplemented - - def __le__(self, other: object) -> bool: - if isinstance(other, LavalinkVersion): - return self._get_comparison_tuple() <= other._get_comparison_tuple() - if isinstance(other, LavalinkOldVersion): - return False - return NotImplemented - - def __gt__(self, other: object) -> bool: - if isinstance(other, LavalinkVersion): - return self._get_comparison_tuple() > other._get_comparison_tuple() - if isinstance(other, LavalinkOldVersion): - return True - return NotImplemented - - def __ge__(self, other: object) -> bool: - if isinstance(other, LavalinkVersion): - return self._get_comparison_tuple() >= other._get_comparison_tuple() - if isinstance(other, LavalinkOldVersion): - return True - return NotImplemented class ServerManager: - JAR_VERSION: Final[str] = LavalinkVersion(3, 7, 11, red=3) - YT_PLUGIN_VERSION: Final[str] = "1.5.2" - LAVALINK_DOWNLOAD_URL: Final[str] = ( "https://github.com/Cog-Creators/Lavalink-Jars/releases/download/" - f"{JAR_VERSION}/" + f"{managed_node.JAR_VERSION}/" "Lavalink.jar" ) - YT_PLUGIN_REPOSITORY: Final[str] = "https://maven.lavalink.dev/releases" _java_available: ClassVar[Optional[bool]] = None _java_version: ClassVar[Optional[Tuple[int, int]]] = None @@ -429,19 +234,7 @@ class ServerManager: raise async def process_settings(self): - data = change_dict_naming_convention(await self._config.yaml.all()) - ll_config = data["lavalink"] - sources = ll_config["server"]["sources"] - plugins = ll_config.setdefault("plugins", []) - - enable_yt_plugin = sources["youtube"] - if enable_yt_plugin: - sources["youtube"] = False - yt_plugin = { - "dependency": f"dev.lavalink.youtube:youtube-plugin:{self.YT_PLUGIN_VERSION}", - "repository": self.YT_PLUGIN_REPOSITORY, - } - plugins.append(yt_plugin) + data = managed_node.generate_server_config(await self._config.yaml.all()) with open(self.lavalink_app_yml, "w", encoding="utf-8") as f: yaml.safe_dump(data, f) @@ -584,7 +377,8 @@ class ServerManager: # A 404 means our LAVALINK_DOWNLOAD_URL is invalid, so likely the jar version # hasn't been published yet raise LavalinkDownloadFailed( - f"Lavalink jar version {self.JAR_VERSION} hasn't been published yet", + f"Lavalink jar version {managed_node.JAR_VERSION}" + " hasn't been published yet", response=response, should_retry=False, ) @@ -670,7 +464,7 @@ class ServerManager: self._jvm = java["jvm"].decode() self._lavaplayer = lavaplayer["lavaplayer"].decode() self._buildtime = date - self._up_to_date = self._lavalink_version >= self.JAR_VERSION + self._up_to_date = self._lavalink_version >= managed_node.JAR_VERSION return self._up_to_date async def maybe_download_jar(self): @@ -690,7 +484,7 @@ class ServerManager: log.info( "Lavalink version outdated, triggering update from %s to %s...", self._lavalink_version, - self.JAR_VERSION, + managed_node.JAR_VERSION, ) await self._download_jar() diff --git a/redbot/cogs/audio/utils.py b/redbot/cogs/audio/utils.py index e3b5a541a..e0cb1b1d2 100644 --- a/redbot/cogs/audio/utils.py +++ b/redbot/cogs/audio/utils.py @@ -18,6 +18,8 @@ from redbot.core import commands from redbot.core.bot import Red from redbot.core.i18n import Translator +from .managed_node.ll_server_config import DEFAULT_LAVALINK_YAML, change_dict_naming_convention + log = getLogger("red.cogs.Audio.task.callback") _ = Translator("Audio", Path(__file__)) @@ -54,55 +56,6 @@ def get_jar_ram_defaults() -> Tuple[str, str]: MIN_JAVA_RAM, MAX_JAVA_RAM = get_jar_ram_defaults() -DEFAULT_LAVALINK_YAML = { - # The nesting structure of this dict is very important, it's a 1:1 mirror of application.yaml in JSON - "yaml__server__address": "localhost", - "yaml__server__port": 2333, - "yaml__lavalink__server__password": "youshallnotpass", - "yaml__lavalink__server__sources__http": True, - "yaml__lavalink__server__sources__bandcamp": True, - "yaml__lavalink__server__sources__local": True, - "yaml__lavalink__server__sources__soundcloud": True, - "yaml__lavalink__server__sources__youtube": True, - "yaml__lavalink__server__sources__twitch": True, - "yaml__lavalink__server__sources__vimeo": True, - "yaml__lavalink__server__bufferDurationMs": 400, - "yaml__lavalink__server__frameBufferDurationMs": 1000, - # 100 pages - 100 entries per page = 10,000 tracks which is the Audio Limit for a single playlist. - "yaml__lavalink__server__youtubePlaylistLoadLimit": 100, - "yaml__lavalink__server__playerUpdateInterval": 1, - "yaml__lavalink__server__youtubeSearchEnabled": True, - "yaml__lavalink__server__soundcloudSearchEnabled": True, - "yaml__lavalink__server__gc_warnings": True, - "yaml__metrics__prometheus__enabled": False, - "yaml__metrics__prometheus__endpoint": "/metrics", - "yaml__sentry__dsn": "", - "yaml__sentry__environment": "", - "yaml__logging__file__path": "./logs/", - "yaml__logging__level__root": "INFO", - "yaml__logging__level__lavalink": "INFO", - "yaml__logging__logback__rollingpolicy__max_history": 15, - "yaml__logging__logback__rollingpolicy__max_size": "10MB", - # plugin configuration - note that the plugin may be disabled by the manager - "yaml__plugins__youtube__enabled": True, - "yaml__plugins__youtube__allowSearch": True, - "yaml__plugins__youtube__allowDirectVideoIds": True, - "yaml__plugins__youtube__allowDirectPlaylistIds": True, - "yaml__plugins__youtube__clients": [ - "MUSIC", - "WEB", - "ANDROID_TESTSUITE", - "TVHTML5EMBEDDED", - "ANDROID_LITE", - "MEDIA_CONNECT", - "IOS", - ], - "yaml__plugins__youtube__WEB__playback": True, - "yaml__plugins__youtube__TVHTML5EMBEDDED__playlistLoading": False, - "yaml__plugins__youtube__TVHTML5EMBEDDED__videoLoading": False, - "yaml__plugins__youtube__TVHTML5EMBEDDED__searching": False, -} - DEFAULT_LAVALINK_SETTINGS = { "host": DEFAULT_LAVALINK_YAML["yaml__server__address"], "rest_port": DEFAULT_LAVALINK_YAML["yaml__server__port"], @@ -122,24 +75,6 @@ def sizeof_fmt(num: Union[float, int]) -> str: return f"{num:.1f}Y" -# This assumes all keys with `_` should be converted from `part1_part2` to `part1-part2` -def convert_function(key: str) -> str: - return key.replace("_", "-") - - -def change_dict_naming_convention(data) -> dict: - ret: Any = data - if isinstance(data, dict): - ret = {} - for key, value in data.items(): - ret[convert_function(key)] = change_dict_naming_convention(value) - elif isinstance(data, list): - ret = [] - for value in data: - ret.append(change_dict_naming_convention(value)) - return ret - - class CacheLevel: __slots__ = ("value",) diff --git a/tests/cogs/audio/test_manager.py b/tests/cogs/audio/managed_node/test_ll_version.py similarity index 98% rename from tests/cogs/audio/test_manager.py rename to tests/cogs/audio/managed_node/test_ll_version.py index 25deb8062..eedfa362a 100644 --- a/tests/cogs/audio/test_manager.py +++ b/tests/cogs/audio/managed_node/test_ll_version.py @@ -3,7 +3,7 @@ from typing import Optional import pytest -from redbot.cogs.audio.manager import LavalinkOldVersion, LavalinkVersion +from redbot.cogs.audio.managed_node.ll_version import LavalinkOldVersion, LavalinkVersion ORDERED_VERSIONS = [