]> git.draconx.ca Git - scripts.git/blob - caa-fetcher.py
caa-fetcher: Create downloaded files with correct permissions.
[scripts.git] / caa-fetcher.py
1 #!/usr/bin/env python
2 #
3 # Copyright © 2018-2019 Nick Bowler
4 #
5 # Tool to fetch album art for a release from the Cover Art Archive.
6 #
7 # License WTFPL2: Do What The Fuck You Want To Public License, version 2.
8 # This is free software: you are free to do what the fuck you want to.
9 # There is NO WARRANTY, to the extent permitted by law.
10
11 from pathlib import Path
12 import musicbrainzngs
13 import argparse
14 import tempfile
15 import sys
16 import os
17
18 umask = os.umask(0)
19 os.umask(umask)
20
21 progname = "caa-fetcher"
22 version = "1"
23 musicbrainzngs.set_useragent(progname, version)
24
25 parser = argparse.ArgumentParser(
26     description='Download album artwork from the Cover Art Archive'
27 )
28
29 # NamedTemporaryFile workalike which allows control of the file mode...
30 def open_tmp(prefix="tmp", suffix="", dir=".", mode=0o600):
31     names = tempfile._get_candidate_names()
32     for seq in range(100):
33         name = os.path.join(dir, "%s%s%s" % (prefix, next(names), suffix))
34         try:
35             f = open(name, "x+", mode)
36         except FileExistsError:
37             continue
38         return tempfile._TemporaryFileWrapper(f, name)
39     return None
40
41 class VersionAction(argparse.Action):
42     def __init__(self, **kw):
43         super().__init__(nargs=0, help="show a version message and exit", **kw)
44     def __call__(self, parser, namespace, values, option_string=None):
45         print("%s %s" % (progname, version))
46         print('''Copyright © 2019 Nick Bowler
47 License WTFPL2: Do What The Fuck You Want To Public License, version 2.
48 This is free software: you are free to do what the fuck you want to.
49 There is NO WARRANTY, to the extent permitted by law.''')
50         sys.exit(0)
51 parser.add_argument('--version', action=VersionAction)
52
53 parser.add_argument('-o', '--output-directory', metavar='DIR',
54                     help='''downloaded files are written to DIR, which is
55                             created if it does not exists.  Default: .''')
56 parser.add_argument('-r', '--release-mbid', metavar='MBID', required=True)
57 args = parser.parse_args()
58
59 # TODO: allow the naming scheme to be configured...
60 name_format = "{num:02d}"
61
62 covers = musicbrainzngs.get_image_list(args.release_mbid)
63 if len(covers["images"]) == 0:
64     print("release has no cover art, nothing to do")
65     sys.exit()
66
67 if args.output_directory:
68     Path(args.output_directory).mkdir(parents=True, exist_ok=True)
69     os.chdir(args.output_directory)
70
71 failed = False
72 for c in covers["images"]:
73     (_,ext) = os.path.splitext(c["image"])
74     outname = (name_format + "{0}").format(ext,
75         num = (covers["images"].index(c) + 1)
76     )
77
78     if Path(outname).exists():
79         print("%s already exists, skipping..." % outname)
80         continue
81
82     outfile = open_tmp(suffix=ext, dir=".", mode=0o666)
83     rc = os.spawnlp(os.P_WAIT, 'wget', 'wget', '-O', outfile.name, c["image"])
84     if rc:
85         failed = True
86
87     os.link(outfile.name, outname)
88     outfile.close()
89
90 if failed:
91     sys.exit(1)