generated from brennen/python_project
changes to accomodate potential comment lines in files
added comments to code
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user