Chris Pomeroy
2021-08-09 5acaaa07e269ea0d2c2b53f12a9dc9329e4088c2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#!/usr/bin/env -S python -u
import argparse
import os
import glob
import subprocess
import shlex
import json
import requests
import unicodedata
from querysubsonic import findalbumbyname
from time import sleep
 
 
# arguments
# activation_key, file name, codec(default to mp3)
 
parser = argparse.ArgumentParser()
parser.add_argument("-s","--single", help="Use this option to create a single file. This is false by default", action="store_true")
parser.add_argument("-d","--dpath", help="Use this to set the destination path. Otherwise I will use the current directory")
parser.add_argument("-v", "--verbose", help="Send output to stdout", action="store_true")
parser.add_argument("filename", help="Filename to convert, or directory to look in")
 
args = parser.parse_args()
 
act_byte = ""
metadata = ""
mode = ""
stats = ""
 
if args.dpath:
    path = args.dpath
else:
    path = os.getcwd()
 
if args.single:
    mode = 'single'
else:
    mode = 'chapter'
 
if args.verbose:
    stats = "-stats"
else:
    stats = "-nostats"
 
 
def getmetadata(aaxfile):
# Returns the metadata from an aax file
    ret = subprocess.run(["ffprobe", "-v", "info", "-hide_banner", "-show_format", "-show_chapters", "-print_format", "json", os.path.abspath(aaxfile)], capture_output=True)
    mdata = json.loads(ret.stdout)
    aret = ret.stderr.decode().split('\n')[0]
    mdata["checksum"] = aret.split()[-1]
    return mdata
 
def getmetabitrate():
#Return the bitrate of the media
    bit_rate = metadata['format']['bit_rate']
    return bit_rate[:2]
 
def getmetacopyright():
# Return normalized copyright data
    copyright = unicodedata.normalize('NFKD', metadata['format']['tags']['copyright']).encode('ascii','ignore')
    return copyright.decode()
 
def getmetadatatags(key):
# get specific data
    tag = metadata['format']['tags'][key]
    return " ".join(tag.split())
 
 
def reencode(aaxfile, outpath):
# decrypt and reencode to mp3
    command = ("ffmpeg -loglevel error {} -activation_bytes {} -i {} -vn -codec:a libmp3lame -ab {}k -map_metadata -1 "
               "-metadata \"title={}\" -metadata 'artist={}' -metadata 'album_artist={}' -metadata \"album={}\" -metadata 'date={}' "
               "-metadata track=1/1 -metadata 'genre={}' -metadata 'copyright={}' \"{}\" " ).format(stats, act_byte,aaxfile,getmetabitrate(),
                                                                                           getmetadatatags('title'), getmetadatatags('artist'),
                                                                                           getmetadatatags('album_artist'), getmetadatatags('album'),
                                                                                           getmetadatatags('date'), getmetadatatags('genre'),
                                                                                           getmetacopyright(),outpath)
    if args.verbose:
        print(command)
        process = subprocess.run(command, shell=True, capture_output=True)
        # while True:
        #     output = process.stdout.readline()
        #     if output == '' and process.poll() is not None:
        #         break
        #     if output:
        #         print(output.strip())
        rc = process.stdout
        return rc
    else:
        process = subprocess.run(command, shell=True)
    return 
 
 
def getchaptercount():
# Get the number of chapters
    ccount = metadata['chapters']
    return len(ccount)
 
 
def getchaptermetadata(cid, key):
# get the Chapter metadata
    for i in metadata['chapters']:
        if i['id'] == cid:
            return i[key]
 
def movetochapters(path, outpath, chapter, title, start,end):
# Creating individual chapters
 
    outfile = "{}/Ch-{}_{}.mp3".format(outpath, chapter, title.replace(' ', '_'))
    command = "ffmpeg -loglevel error {} -i \"{}\" -ss {} -to {} -codec:a copy -metadata 'track={}' \"{}\"".format(stats, path,
                                                                                                               start, end,
                                                                                                               chapter, outfile)
    if args.verbose:
        print(command)
        process = subprocess.run(command, shell=True, capture_output=True)
        # while True:
        #     output = process.stdout.readline()
        #     if output == '' and process.poll() is not None:
        #         break
        #     if output:
        #         print(output.strip())
        rc = process.poll()
        return rc
    else:
        process = subprocess.run(command, shell=True)
    return
 
 
def getcoverart(path,outpath):
# Pull the coverart from the file
    command = "ffmpeg -loglevel error -activation_bytes {} -i \"{}\" -an -codec:v copy \"{}/cover.jpg\"".format(act_byte,
                                                                                                               path, outpath)
    if args.verbose:
        print(command)
    process = process = subprocess.run(command, shell=True)
    return
 
def getcorrectkey():
#request the key for the checksum
    try:
        r = requests.post('http://prod-faas-gw.darkurthe.net:8080/function/checkkey', metadata['checksum'], verify=False, timeout=None)
        return r.text.strip()
    except requests.exceptions.HTTPError as err:
        raise error
        return None
 
for rfile in glob.glob(args.filename):
    if rfile.find("aax") != -1 and os.path.isfile(rfile):
        metadata = getmetadata(rfile)
        album = getmetadatatags('album')
        #See if we got it already
        if (findalbumbyname(album) == False):
            artist = getmetadatatags('artist')
            title = getmetadatatags('title')
            act_byte = getcorrectkey()
            if act_byte == None:
                sys.exit("Can't continue with this file {rfile}")
            else:
                ddir = "%s/%s/%s" % (path, artist.replace(' ', '_'), title.replace(' ', '_'))
                single_file_path = "/processing/%s.mp3" % (title.replace(' ','_'))
                if not os.path.exists(ddir):
                    os.makedirs(ddir)
                print(ddir)
                reencode(rfile, single_file_path)
                if mode == 'chapter':
                    chapter = 0
                    numchapters = getchaptercount()
                    while (numchapters > 0 ):
                        cstart = getchaptermetadata(chapter, 'start_time')
                        cend = getchaptermetadata(chapter, 'end_time')
                        chapter += 1
                        numchapters -= 1
                        schap = str(chapter).zfill(2)
                        movetochapters(single_file_path, ddir, schap, title, cstart,cend)
                    os.remove(single_file_path)
                getcoverart(rfile, ddir)
        else:
            print('We have that book already')