Filter Jamendo music licenses

This commit is contained in:
hbrain 2026-05-25 10:43:55 +00:00
parent ecaa6cc959
commit e512b5012b
2 changed files with 27 additions and 13 deletions

View file

@ -442,7 +442,7 @@ def ascii_safe(value: str) -> str:
replacements = {
"æ": "ae", "Æ": "Ae",
"ø": "o", "Ø": "O",
"å": "a", "Å": "A",
"å": "aa", "Å": "Aa",
"đ": "d", "Đ": "D",
}
value = "".join(replacements.get(ch, ch) for ch in value)
@ -625,8 +625,10 @@ def download_jamendo_music(genre: str, out_dir: Path) -> Path | None:
"format": "json",
"limit": "50",
"search": genre,
"include": "musicinfo",
"include": "musicinfo licenses",
"audioformat": "mp32",
"ccnc": "true",
"ccnd": "false",
})
request = urllib.request.Request(
f"https://api.jamendo.com/v3.0/tracks/?{query}",
@ -639,7 +641,16 @@ def download_jamendo_music(genre: str, out_dir: Path) -> Path | None:
console(f"Could not search Jamendo music: {exc}")
return None
results = [track for track in data.get("results", []) if track.get("audio")]
results = []
for track in data.get("results", []):
license_url = str(track.get("license_ccurl", "")).lower()
if not track.get("audio"):
continue
if track.get("audiodownload_allowed") is False:
continue
if "creativecommons.org" not in license_url or "/nd" in license_url:
continue
results.append(track)
if not results:
console(f"No Jamendo music found for genre/query: {genre}")
return None
@ -656,14 +667,16 @@ def download_jamendo_music(genre: str, out_dir: Path) -> Path | None:
except Exception as exc:
console(f"Could not download Jamendo music: {exc}")
return None
attribution = out.with_suffix(".txt")
log_dir = out_dir / ".logs"
log_dir.mkdir(parents=True, exist_ok=True)
attribution = log_dir / f"{out.stem}.txt"
musicinfo = track.get("musicinfo", {}) if isinstance(track.get("musicinfo"), dict) else {}
attribution.write_text(
"Jamendo music downloaded by movmaker\n"
f"Title: {title}\n"
f"Artist: {artist}\n"
f"URL: {track.get('shareurl', '')}\n"
f"License: {musicinfo.get('license_ccurl', '')}\n"
f"License: {track.get('license_ccurl', '')}\n"
"Source: Jamendo\n",
encoding="utf-8",
)
@ -757,7 +770,7 @@ def build_video(
title_label = "titled"
title_font = str(Path.home() / ".local/share/fonts/google/BebasNeue-Regular.ttf")
stamp_font = "/usr/share/fonts/truetype/noto/NotoSans-Bold.ttf"
stamp_bold_font = "/usr/share/fonts/truetype/noto/NotoSans-Bold.ttf"
caption_font = "Montserrat\\:style=Bold"
if title_lines:
title_font_size = max(60, height // 10)
subtitle_font_size = max(40, height // 18)
@ -826,7 +839,7 @@ def build_video(
y_expr = f"h-text_h-62-{block_height - line_idx * line_gap}"
next_label = f"caption{idx}_{line_idx}"
filters.append(
f"[{caption_label}]drawtext=fontfile='{title_font}':{textfile_arg(caption_line)}:x=(w-text_w)/2:y={y_expr}:"
f"[{caption_label}]drawtext=font='{caption_font}':{textfile_arg(caption_line)}:x=(w-text_w)/2:y={y_expr}:"
f"fontsize={caption_size}:fontcolor=white:borderw=1:bordercolor=black:"
f"alpha='{caption_alpha}':enable='between(t,{start:.3f},{end:.3f})'[{next_label}]"
)
@ -844,7 +857,7 @@ def build_video(
else:
filters.append(f"[{caption_label}]copy[{stamp_left_label}]")
filters.append(
f"[{stamp_left_label}]drawtext=fontfile='{stamp_font}':{textfile_arg('@bubulescu')}:x=w-text_w-24:y=h-text_h-18:"
f"[{stamp_left_label}]drawtext=fontfile='{stamp_font}':{textfile_arg('Bubulescu.Org')}:x=w-text_w-24:y=h-text_h-18:"
f"fontsize={stamp_size}:fontcolor=white:borderw=1:bordercolor=black[{final_label}]"
)
@ -855,7 +868,7 @@ def build_video(
"location": data.place,
"place": data.place,
"com.apple.quicktime.location.name": data.place,
"artist": "@bubulescu",
"artist": "Bubulescu.Org",
"comment": "Created with movmaker",
"creation_time": creation_date.isoformat(),
}
@ -944,6 +957,7 @@ def main(argv: list[str] | None = None) -> int:
item.duration = item.duration + (2 * fade)
console(f"Found {len(media)} media file(s), {len(audio_files)} audio file(s).")
console(f"Audio: {audio_files[0] if audio_files else 'none'}")
console(f"Output: {output}")
console(f"Log: {LOG_PATH}")
if data.title or data.date or data.place:
@ -954,7 +968,6 @@ def main(argv: list[str] | None = None) -> int:
jobs = max(1, args.jobs)
clips = [tmp / f"clip_{idx:04d}.mp4" for idx in range(len(media))]
if jobs == 1:
console("Preparing clips...")
total_clips = len(media)
for done, (item, out) in enumerate(zip(media, clips), start=1):
percent = done / total_clips * 100
@ -981,7 +994,8 @@ def main(argv: list[str] | None = None) -> int:
captions = [data.captions.get(item.path.name, data.captions.get(str(item.path), "")) for item in media]
audio = concat_or_mix_audio(audio_files, tmp / "music.m4a")
console(f"Audio: {audio if audio else 'none'}")
if len(audio_files) > 1:
console(f"Audio: {audio if audio else 'none'}")
console(f"Estimated output: video length {estimated_duration:.1f}s, size about {format_bytes(estimated_size)}")
build_video(clips, durations, audio, output, data, first_media_date, captions, fade, audio_fade, audio_fade_in, video_fade, width, height, fps, preset, crf, tmp)