mirror of
https://github.com/alexta69/metube.git
synced 2026-09-21 21:45:04 +00:00
fix: strip trailing slashes from the download directories
get_custom_dirs() builds the folder dropdown by removing the base path as a prefix from every subdirectory it finds. The base directory's own path does not carry a trailing slash, so with DOWNLOAD_DIR=/downloads/ the base failed to match itself and fell through to the leading-slash trim, leaking 'downloads' into the dropdown as a bogus folder option. Selecting it would have downloaded into /downloads/downloads. Normalised in Config alongside URL_PREFIX, after the '%%' indirection so AUDIO_DOWNLOAD_DIR is resolved first. '/' and '///' still resolve to '/' rather than the empty string. Found while trying to reproduce #542, which does not reproduce on current code -- both directory listings populate correctly with a distinct AUDIO_DOWNLOAD_DIR. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+11
@@ -116,6 +116,17 @@ class Config:
|
||||
if not self.URL_PREFIX.endswith('/'):
|
||||
self.URL_PREFIX += '/'
|
||||
|
||||
# Strip trailing slashes from the download directories. get_custom_dirs()
|
||||
# builds the folder dropdown by removing the base path as a prefix from
|
||||
# each subdirectory, and the base directory's own path does not carry the
|
||||
# trailing slash — so 'DOWNLOAD_DIR=/downloads/' failed to match itself
|
||||
# and leaked 'downloads' into the dropdown as a bogus folder option.
|
||||
# Runs after the '%%' indirection above so AUDIO_DOWNLOAD_DIR is resolved.
|
||||
for attr in ('DOWNLOAD_DIR', 'AUDIO_DOWNLOAD_DIR', 'TEMP_DIR', 'STATE_DIR'):
|
||||
val = getattr(self, attr)
|
||||
if isinstance(val, str) and len(val) > 1 and val.endswith('/'):
|
||||
setattr(self, attr, val.rstrip('/') or '/')
|
||||
|
||||
# A blank PUBLIC_HOST_AUDIO_URL (e.g. set empty in a compose file) bypasses the
|
||||
# default via os.environ.get, which would leave audio links root-relative and 404.
|
||||
# Fall back to the 'audio_download/' route that serves AUDIO_DOWNLOAD_DIR. When
|
||||
|
||||
@@ -77,6 +77,34 @@ class ConfigTests(unittest.TestCase):
|
||||
self.assertEqual(c.PUBLIC_HOST_URL, "https://ytdl.example.com/")
|
||||
self.assertEqual(c.PUBLIC_HOST_AUDIO_URL, "https://audio.example.com/")
|
||||
|
||||
def test_download_dirs_lose_trailing_slash(self):
|
||||
# get_custom_dirs strips the base path as a prefix from each subdirectory,
|
||||
# and the base directory's own path has no trailing slash -- so a trailing
|
||||
# slash here leaked the absolute path into the folder dropdown.
|
||||
with patch.dict(os.environ, _base_env(
|
||||
DOWNLOAD_DIR="/downloads/",
|
||||
AUDIO_DOWNLOAD_DIR="/audio/",
|
||||
TEMP_DIR="/tmp/",
|
||||
STATE_DIR="/state/",
|
||||
), clear=False):
|
||||
c = Config()
|
||||
self.assertEqual(c.DOWNLOAD_DIR, "/downloads")
|
||||
self.assertEqual(c.AUDIO_DOWNLOAD_DIR, "/audio")
|
||||
self.assertEqual(c.TEMP_DIR, "/tmp")
|
||||
self.assertEqual(c.STATE_DIR, "/state")
|
||||
|
||||
def test_root_download_dir_survives_normalisation(self):
|
||||
with patch.dict(os.environ, _base_env(DOWNLOAD_DIR="/", AUDIO_DOWNLOAD_DIR="///"), clear=False):
|
||||
c = Config()
|
||||
self.assertEqual(c.DOWNLOAD_DIR, "/")
|
||||
self.assertEqual(c.AUDIO_DOWNLOAD_DIR, "/")
|
||||
|
||||
def test_download_dirs_without_trailing_slash_unchanged(self):
|
||||
with patch.dict(os.environ, _base_env(DOWNLOAD_DIR="/downloads", AUDIO_DOWNLOAD_DIR="."), clear=False):
|
||||
c = Config()
|
||||
self.assertEqual(c.DOWNLOAD_DIR, "/downloads")
|
||||
self.assertEqual(c.AUDIO_DOWNLOAD_DIR, ".")
|
||||
|
||||
def test_ytdl_options_json_loaded(self):
|
||||
opts = {"quiet": True, "no_warnings": True}
|
||||
with patch.dict(
|
||||
|
||||
Reference in New Issue
Block a user