changes to accomodate potential comment lines in files

added comments to code
This commit is contained in:
Brennen Raimer
2026-05-04 12:44:03 -04:00
parent 506bb0f96c
commit 0885b5454e
+29 -10
View File
@@ -1,39 +1,57 @@
from argparse import ArgumentParser from argparse import ArgumentParser
from itertools import filterfalse
from pathlib import Path from pathlib import Path
from logging import basicConfig, warning, WARNING from logging import basicConfig, warning, WARNING
from shutil import copyfile from shutil import copyfile
def main(music_folder: Path): def main(music_folder: Path):
# get the absolute path of the music folder from the argument
music_folder = music_folder.resolve().absolute() music_folder = music_folder.resolve().absolute()
# recursively traverse music_folder looking for .m3u files and, for each, ...
for m3u in music_folder.rglob("*.m3u"): for m3u in music_folder.rglob("*.m3u"):
# create a copy in the same directory as a backup
copyfile(m3u, m3u.with_suffix(".m3u.bak")) copyfile(m3u, m3u.with_suffix(".m3u.bak"))
# read the contents of the file
with m3u.open("r") as contents: 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( if not all(
music_folder in track.parents music_folder in Path(line).parents
if track.is_absolute() if Path(line).is_absolute()
else music_folder in m3u.parent.joinpath(track).resolve().parents # join the parent path to the relative path in line, then resolve out the relative parts
for track in tracks 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") warning(f"{m3u} contains references to tracks that are not in {music_folder} and will be skipped")
continue continue
with m3u.open("w") as updated_contents: with m3u.open("w") as updated_contents:
for track in tracks: for line in lines:
if track.is_absolute(): # comment line. just write it.
updated_contents.write(track.relative_to(m3u, walk_up=True).as_posix()) 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: else:
updated_contents.write(track.as_posix()) # normalize as a posix path
updated_contents.write(Path(line).as_posix())
if __name__ == "__main__": if __name__ == "__main__":
# setup logging to terminal
basicConfig( basicConfig(
level=WARNING, level=WARNING,
) )
# setup a parser for the CLI
parser = ArgumentParser( 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." 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 type=Path
) )
# parse the command line for the one and only argument
args = parser.parse_args() args = parser.parse_args()
main(args.music_folder) main(args.music_folder)