From 0885b5454efa8977a55ece82b645c8bde89fde67 Mon Sep 17 00:00:00 2001 From: Brennen Raimer <5969754+norweeg@users.noreply.github.com> Date: Mon, 4 May 2026 12:44:03 -0400 Subject: [PATCH] changes to accomodate potential comment lines in files added comments to code --- relative-playlist-maker.py | 39 ++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/relative-playlist-maker.py b/relative-playlist-maker.py index 3cb4afd..5810740 100644 --- a/relative-playlist-maker.py +++ b/relative-playlist-maker.py @@ -1,39 +1,57 @@ from argparse import ArgumentParser +from itertools import filterfalse from pathlib import Path from logging import basicConfig, warning, WARNING from shutil import copyfile def main(music_folder: Path): + # get the absolute path of the music folder from the argument music_folder = music_folder.resolve().absolute() + # recursively traverse music_folder looking for .m3u files and, for each, ... for m3u in music_folder.rglob("*.m3u"): + # create a copy in the same directory as a backup copyfile(m3u, m3u.with_suffix(".m3u.bak")) + # read the contents of the file with m3u.open("r") as contents: - tracks = [Path(p) for p in contents.readlines()] - + lines = contents.readlines() + + # check that all non-comment lines refer to files in the music directory if not all( - music_folder in track.parents - if track.is_absolute() - else music_folder in m3u.parent.joinpath(track).resolve().parents - for track in tracks + music_folder in Path(line).parents + if Path(line).is_absolute() + # join the parent path to the relative path in line, then resolve out the relative parts + else music_folder in m3u.parent.joinpath(Path(line)).resolve().parents + # ignore lines which start with # because they are comments, not paths to tracks + for line in filterfalse(lambda l: l.strip().startswith("#"), lines) ): + # if the file contains references to files outside of the music folder, skip the m3u file and continue to the next one warning(f"{m3u} contains references to tracks that are not in {music_folder} and will be skipped") continue with m3u.open("w") as updated_contents: - for track in tracks: - if track.is_absolute(): - updated_contents.write(track.relative_to(m3u, walk_up=True).as_posix()) + for line in lines: + # comment line. just write it. + if line.strip().startswith("#"): + updated_contents.write(line) + # line contains an absolute path + elif Path(line).is_absolute(): + # get the path of the track file relative to the playlist file and write it in posix form (/ is path delimiter) + updated_contents.write(Path(line).relative_to(m3u, walk_up=True).as_posix()) + # line already contains a relative path else: - updated_contents.write(track.as_posix()) + # normalize as a posix path + updated_contents.write(Path(line).as_posix()) if __name__ == "__main__": + # setup logging to terminal basicConfig( level=WARNING, ) + # setup a parser for the CLI parser = ArgumentParser( description="Recursively traverse a music folder containing tracks and playlist files that reference them, replacing absolute paths in the playlists with equivalent relative paths." ) @@ -44,6 +62,7 @@ if __name__ == "__main__": type=Path ) + # parse the command line for the one and only argument args = parser.parse_args() main(args.music_folder)