music-fetch: duration filter (11 min default, --allow-long-songs); populate dungeon-synth themed ambience tracks (9 tracks across 8 ambiences)

This commit is contained in:
Dejvino 2026-06-24 21:56:42 +02:00
parent a2a6b1cb26
commit fdb9d4afc2
3 changed files with 37 additions and 4 deletions

View File

@ -32,6 +32,9 @@ python3 tools/music-fetch.py tavern --replace
# Preview without downloading
python3 tools/music-fetch.py tavern --dry-run
# Allow tracks longer than 10 minutes
python3 tools/music-fetch.py tavern --allow-long-songs
```
Sources are recorded in `session/ambience_sources.md` so tracks can be
@ -45,7 +48,7 @@ re-downloaded without keeping audio files in git.
| calm | calm_01.ogg |
| combat | combat_01.ogg |
| dungeon | dungeon_01.ogg, dungeon_02.ogg |
| forest | forest_01.ogg, forest_02.ogg |
| forest | forest_01.ogg |
| tavern | tavern_01.ogg |
| tension | tension_01.ogg |
| town | town_01.ogg |

View File

@ -5,3 +5,12 @@ re-downloaded without keeping the audio files in git.
| File | Ambience | Source |
|------|----------|--------|
| calm_01.ogg | calm | https://www.youtube.com/watch?v=7Vc4-FDGBxo |
| combat_01.ogg | combat | https://www.youtube.com/watch?v=zUkuSkXJf_s |
| dungeon_01.ogg | dungeon | https://www.youtube.com/watch?v=Xh9maYRrU4s |
| dungeon_02.ogg | dungeon | https://www.youtube.com/watch?v=MtFKomQfLUg |
| forest_01.ogg | forest | https://www.youtube.com/watch?v=HbefWLz9jwA |
| tavern_01.ogg | tavern | https://www.youtube.com/watch?v=GQzKGrCwFtk |
| tension_01.ogg | tension | https://www.youtube.com/watch?v=KoxxBeH7J3Q |
| town_01.ogg | town | https://www.youtube.com/watch?v=c0zfiRLVpKU |
| wilds_01.ogg | wilds | https://www.youtube.com/watch?v=UXkcbVKxs9k |

View File

@ -13,6 +13,7 @@ Usage:
python3 tools/music-fetch.py tavern --url "https://youtu.be/..."
python3 tools/music-fetch.py tavern --replace
python3 tools/music-fetch.py tavern --dry-run
python3 tools/music-fetch.py tavern --allow-long-songs
"""
import argparse
@ -79,9 +80,13 @@ def make_stem(ambience, existing_files):
# ── YouTube search / info ─────────────────────────────────
def search_videos(query, max_results=20):
YoutubeDL = _import_ytdlp()
ydl = YoutubeDL({"quiet": True, "no_warnings": True})
ydl = YoutubeDL({"quiet": True, "no_warnings": True, "ignoreerrors": True})
try:
info = ydl.extract_info(f"ytsearch{max_results}:{query}", download=False)
return info.get("entries", [])
except Exception:
return []
entries = info.get("entries", []) if info else []
return [e for e in entries if e is not None]
def get_video_info(url):
@ -272,6 +277,8 @@ def main():
help="Show what would be fetched without downloading")
parser.add_argument("--max-results", type=int, default=20,
help="Number of search results to consider (default: 20)")
parser.add_argument("--allow-long-songs", action="store_true",
help="Allow tracks longer than 10 minutes")
args = parser.parse_args()
name = args.ambience.strip().lower()
@ -310,6 +317,20 @@ def main():
print("No results found.")
sys.exit(1)
source_desc = f"top {len(candidates)} results for \"{query}\""
# Filter to short tracks (< 10 min) unless --allow-long-songs
if not args.allow_long_songs:
short = [v for v in candidates if v.get("duration") is not None and v["duration"] <= 660]
if not short:
# Retry with a shorter-focused query
short_query = f"10 minutes {query}"
print(f" no short tracks found, retrying with: \"{short_query}\"")
candidates = search_videos(short_query, args.max_results)
short = [v for v in candidates if v.get("duration") is not None and v["duration"] <= 660]
if short:
candidates = short
if not candidates:
print("All results were longer than 10 minutes. Use --allow-long-songs to include them.")
sys.exit(1)
# Pick randomly from the pool
video = random.choice(candidates)
candidates = [video]