Created
June 8, 2022 05:19
-
-
Save PaulWebster/1c2f5fb0a435e63cff918b9858f5e670 to your computer and use it in GitHub Desktop.
lms_getalbums
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
from operator import itemgetter | |
from argparse import ArgumentParser | |
from argparse import RawDescriptionHelpFormatter | |
from datetime import datetime | |
import urllib.request | |
import json, re | |
html_styling = ''' | |
<style type="text/css"> | |
ol,ul { | |
list-style: none; | |
font-weight: bold; | |
} | |
.navbar { | |
overflow: visible; | |
background-color: #103c48; | |
position: fixed; | |
z-index: 1; | |
top: 0; | |
left: 95%; | |
float: right; | |
width: 5%; | |
overflow-x: hidden; | |
padding: 0 0 0 0; | |
} | |
.navbar a { | |
float: left; | |
display: block; | |
color: #adbcbc; | |
text-align: right; | |
text-decoration: none; | |
padding: 2px 2px; | |
} | |
.content { | |
width: 100%; | |
} | |
</style> | |
''' | |
''' | |
width: 100%; | |
position: fixed; | |
padding: 5px 5px; | |
.content { | |
margin-top: 30px; | |
} | |
''' | |
headers = { 'Content-Type': 'application/json'} | |
table_tmpl ='<tr>{}<td>{}</td><td>{}</td></tr>' | |
json_data_albums = {"id":1, "method":"slim.request", "params": ["-", ["albums", 0, 99999, "tags:aaly"]]} | |
json_data_sort = {"id":1,"method":"slim.request","params":["-", ["pref","ignoredarticles", "?"]]} | |
json_data_libraries = {"id":1, "method":"slim.request", "params": ["-", ["libraries",0,25000]]} | |
parser = ArgumentParser(description="writes all albums from LMS to a html file", formatter_class=RawDescriptionHelpFormatter) | |
parser.add_argument('lmshost', action='store', help='LMS host name (including port, e.g. lmssrv:9000)') | |
parser.add_argument('outfile', action='store', help='output file') | |
parser.add_argument('--no-quickjump', action='store_true', help='do no add quickjump links') | |
parser.add_argument('--no-sortcase', action='store_true', help='do no use case-sensitive sorting') | |
parser.add_argument('--sort-ignorearticles', action='store_true', help='ignore articles for sorting') | |
parser.add_argument('--hlcolor', action='store', default="#184956", help='highlight color') | |
parser.add_argument('--libraryview', action='store', help='library view name (use quotes if spaces)') | |
args = parser.parse_args() | |
url = "http://{}/jsonrpc.js".format( args.lmshost) | |
libraryid = '' | |
libraryname = '' | |
if args.libraryview: | |
post_data_libraries = json.dumps( json_data_libraries).encode('utf-8') | |
req = urllib.request.Request(url, post_data_libraries, headers) | |
with urllib.request.urlopen(req) as response: | |
result = response.read() | |
res = json.loads(result.decode("utf-8")) | |
if res and 'result' in res and res['result'] and 'folder_loop' in res['result']: | |
# example result | |
# {'id': 1, 'result': {'folder_loop': [{'id': 'aabbccdd', 'name': 'Name1'}, {'id': 'bbccddee', 'name': 'Name2'}, {'name': 'AnotherName', 'id': '12345678'}]}, 'method': 'slim.request', 'params': ['-', ['libraries', '0', '25000']]}) | |
#print("Library search found (result: {})".format( repr( res))) | |
libraries = res['result']['folder_loop'] | |
for library in libraries: | |
#print("Library:" + str(library['name'])) | |
if library['name'] == args.libraryview: | |
print("Matched: " + args.libraryview) | |
libraryid = library['id'] | |
libraryname = library['name'] | |
json_data_albums["params"][1].append("library_id:" + libraryid) | |
#print("now set to " + str(json.dumps( json_data_albums).encode('utf-8'))) | |
if libraryid == '': | |
print("Error: could not find this library view (result: {})".format( repr( res))) | |
else: | |
print("Error: could not find any library views (result: {})".format( repr( res))) | |
post_data_albums = json.dumps( json_data_albums).encode('utf-8') | |
post_data_sort = json.dumps( json_data_sort).encode('utf-8') | |
ignoredarticles_re = None | |
if args.sort_ignorearticles: | |
req = urllib.request.Request(url, post_data_sort, headers) | |
with urllib.request.urlopen(req) as response: | |
result = response.read() | |
res = json.loads(result.decode("utf-8")) | |
if res and 'result' in res and res['result'] and '_p2' in res['result'] and len( res['result']['_p2']) != 0: | |
ignoredarticles = res['result']['_p2'].split(" ") | |
_ignoredarticles_re = [ "^{} ".format( re.escape(x)) for x in ignoredarticles] | |
ignoredarticles_re = re.compile( "|".join( _ignoredarticles_re), flags=re.IGNORECASE) | |
#print("ignoredarticles_re={}".format( repr( ignoredarticles_re))) | |
else: | |
print("Error: couldn't get ignoredarticles from server (result: {})".format( repr( res))) | |
req = urllib.request.Request(url, post_data_albums, headers) | |
with urllib.request.urlopen(req) as response: | |
result = response.read() | |
res = json.loads(result.decode("utf-8")) | |
if res and 'result' in res and res['result'] and 'albums_loop' in res['result']: | |
albums = res['result']['albums_loop'] | |
for i, row in enumerate(albums): | |
if not row['artist']: | |
albums[i]['artist'] = "Unknown Artist" | |
if not row['year'] or row['year'] == 0: | |
albums[i]['year'] = "?" | |
if not args.no_sortcase: | |
albums[i]['sortartist'] = albums[i]['artist'] if not args.sort_ignorearticles else re.sub( ignoredarticles_re, "", albums[i]['artist']) | |
albums[i]['sortalbum'] = albums[i]['album'] | |
else: | |
albums[i]['sortartist'] = albums[i]['artist'].casefold() if not args.sort_ignorearticles else re.sub( ignoredarticles_re, "", albums[i]['artist']).casefold() | |
albums[i]['sortalbum'] = albums[i]['album'].casefold() | |
albums.sort( key=itemgetter('sortartist', 'sortalbum')) | |
#albums.sort( key=lambda el: ( el['artist'].casefold(), el['album'].casefold())) | |
albums.append( { 'artist': 'dummy', 'sortartist': 'dummy'}) | |
num_albums = len( albums) | |
albums_flat = [] | |
qj_labels = {} | |
prev_artist = None | |
artist_proc = [] | |
for i, row in enumerate( albums): | |
curr_artist = row['sortartist'] | |
if (curr_artist != prev_artist or i == (num_albums - 1)): | |
# if i == (num_albums - 1): | |
# print("last loop ca: {} pa: {} len ap:{}".format( curr_artist, prev_artist, artist_proc)) | |
if not prev_artist: | |
prev_artist = curr_artist | |
sort_char = prev_artist[0:1].upper() if args.no_sortcase else prev_artist[0:1] | |
if not args.no_quickjump and sort_char not in qj_labels: | |
#print("i={} label [{}] rows: {}".format( i, prev_artist[0:1], repr( artist_proc))) | |
qj_labels[ sort_char] = '<li><a href="#qj_{}">[ {} ]</a></li>'.format( sort_char, sort_char) | |
albums_flat.append( '<tr id="qj_{}"><td colspan="3" style="background-color:{}; color: #cad8d9; font-weight: bold">{}</td></tr>\n'.format( sort_char, args.hlcolor, sort_char)) | |
for j, subrow in enumerate( artist_proc): | |
if j == 0: | |
albums_flat.append( table_tmpl.format( '<td rowspan="{}" style="vertical-align:top">{}</td>'.format( len( artist_proc), subrow['artist']), subrow['album'], subrow['year'])) | |
else: | |
albums_flat.append( table_tmpl.format( '', subrow['album'], subrow['year'])) | |
artist_proc = [] | |
prev_artist = curr_artist | |
artist_proc.append( row) | |
#albums_flat.append( table_tmpl.format( '<td rowspan=1>{}</td>'.format( curr_artist), row['album'], row['year'])) | |
with open( args.outfile, 'w', encoding='utf-8') as fp: | |
page_title = '<title>LMS@{} {view}- {} albums ({})</title>'.format( args.lmshost.partition(':')[0], num_albums, datetime.now().isoformat( timespec='seconds'), view="" if not libraryname else "(" + libraryname + ") ") | |
fp.write( '<html><head><meta charset="UTF-8"/>{}\n{}</head><body bgcolor="#dddddd">\n'.format( page_title, html_styling if not args.no_quickjump else "")) | |
if not args.no_quickjump: | |
fp.write( '<div class="navbar"><ul>\n') | |
fp.write( " ".join( qj_labels[key] for key in sorted(qj_labels.keys()))) | |
fp.write( '</ul></div>\n') | |
fp.write('<div class="content">\n<table border=1>\n<thead><tr><th>Artist</th><th>Album</th><th>Year</th></tr></thead>\n<tbody>{}</tbody>\n'.format( '\n'.join( albums_flat))) | |
fp.write( '</div></table></body></html>\n') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment