#!/usr/bin/env -S python -u
|
import argparse
|
import os
|
import glob
|
import subprocess
|
import json
|
import re
|
import requests
|
import sys
|
from queryAudiobookServer import findalbumbyname
|
|
# 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 = normalize_data(metadata['format']['tags']['copyright'])
|
return copyright
|
|
|
def getmetadatatags(key):
|
# get specific data
|
tag = metadata['format']['tags'][key]
|
return " ".join(tag.split())
|
|
|
def normalize_data(data):
|
# Return a normalized title
|
data = data.replace(" ", "_")
|
pattern = re.compile('\W')
|
return re.sub(pattern, '', data)
|
|
|
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)
|
subprocess.run(command, shell=True)
|
return
|
|
|
def getcorrectkey():
|
# request the key for the checksum
|
try:
|
r = requests.post('http://faas.darkurthe.net/function/checkkey',
|
metadata['checksum'], verify=False, timeout=None)
|
return r.text.strip()
|
except requests.exceptions.HTTPError as err:
|
raise err
|
|
def findalbumbyname_stub(album):
|
return False
|
|
|
if args.filename.find("aax"):
|
rfile = args.filename
|
metadata = getmetadata(rfile)
|
album = getmetadatatags('album')
|
# See if we got it already
|
if not findalbumbyname(album):
|
artist = normalize_data(getmetadatatags('artist'))
|
title = normalize_data(getmetadatatags('title'))
|
act_byte = getcorrectkey()
|
if act_byte is None or act_byte == '':
|
sys.exit(f"Can't continue with this file {rfile}")
|
else:
|
ddir = "%s/%s/%s" % (path, artist, title)
|
single_file_path = "/processing/%s.mp3" % (title)
|
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')
|