adding last.fm to archiver
Peter Molnar hello@petermolnar.eu
Wed, 01 Nov 2017 13:19:39 +0000
5 files changed,
153 insertions(+),
23 deletions(-)
M
archive.py
→
archive.py
@@ -7,6 +7,7 @@ import shutil
import subprocess import imghdr import arrow +import csv from requests_oauthlib import OAuth1Session from requests_oauthlib import oauth1_session@@ -15,6 +16,86 @@ from requests_oauthlib import oauth2_session
from oauthlib.oauth2 import BackendApplicationClient import shared + +class LastFM(object): + url = 'http://ws.audioscrobbler.com/2.0/' + def __init__(self): + self.service = 'lastfm' + self.target = shared.config.get("api_%s" % self.service, 'logfile') + self.params = { + 'method': 'user.getrecenttracks', + 'user': shared.config.get("api_%s" % self.service, 'username'), + 'api_key': shared.config.get("api_%s" % self.service, 'api_key'), + 'format': 'json', + 'limit': '200' + } + if os.path.isfile(self.target): + mtime = os.path.getmtime(self.target) + self.params.update({'from': mtime}) + + def hash2flat(self, data): + time = int(data.get('date').get('uts')) + r = { + 'date': arrow.get(time).format(shared.ARROWFORMAT['iso']), + 'title': data.get('name'), + 'title_mbid': data.get('mbid'), + 'artist': data.get('artist').get('#text'), + 'artist_mbid': data.get('artist').get('mbid'), + 'album': data.get('album').get('#text'), + 'album_mbid': data.get('album').get('mbid'), + } + return (time, r) + + def getpaged(self, pagenum): + logging.info('requesting page #%d of paginated results', pagenum) + self.params.update({ + 'page': pagenum + }) + r = requests.get( + self.url, + params=self.params + ) + parsed = json.loads(r.text).get('recenttracks', {}).get('track', []) + return parsed + + def run(self): + r = requests.get(self.url,params=self.params) + js = json.loads(r.text) + js = js.get('recenttracks', {}) + unordered = js.get('track', []) + ordered = {} + + total = int(js.get('@attr').get('totalPages')) + current = int(js.get('@attr').get('page')) + cntr = total - current + + while cntr > 0: + current = current + 1 + paged = self.getpaged(current) + unordered = unordered + paged + cntr = total - current + + for track in unordered: + # happens with nowplaying tracks + if 'date' not in track: + continue + time, data = self.hash2flat(track) + ordered[time] = data + + # no results + if not len(ordered): + return + + ordered = sorted(ordered.items()) + with open(self.target, 'a') as f: + fieldnames = ordered[0][1].keys() + writer = csv.DictWriter(f, fieldnames=fieldnames) + # only write csv header once, when the file is first created + if 'from' not in self.params: + writer.writeheader() + for time, track in ordered: + writer.writerow(track) + class Favs(object): def __init__(self, confgroup):@@ -865,3 +946,7 @@
if shared.config.has_section('api_deviantart'): da = DAFavs() da.run() + + if shared.config.has_section('api_lastfm'): + lfm = LastFM() + lfm.run()
M
nasg.py
→
nasg.py
@@ -892,12 +892,12 @@ if crop:
thumb.liquid_rescale(size, size, 1, 1) if self.meta.get('FileType', 'jpeg').lower() == 'jpeg': - thumb.compression_quality = 86 + thumb.compression_quality = 94 thumb.unsharp_mask( - radius=0, + radius=2, sigma=0.5, - amount=1, - threshold=0.03 + amount=0.7, + threshold=0 ) thumb.format = 'pjpeg'
M
templates/Singular.html
→
templates/Singular.html
@@ -60,6 +60,26 @@ {% endif %}
</p> </footer> + <aside class="donation"> + <p> + {% if post.category == 'photo' %} + Did you like this photo?<br />Thank it with a small donation. + {% elif post.category == 'article' %} + Did you find this article useful?<br />Buy me a coffee, so I can write more like this.<br />If you want my help with something similar, get in touch. + {% elif post.category == 'journal' %} + Did you like this entry?<br />Encourage me to write more of them. + {% else %} + Did you like what you read?<br />Thank it with a small donation.</a> + {% endif %} + </p> + <ul> + {% for value in [3,5,10,42] %} + <li><a href="{{ site.author.donateurl }}{{value}}GBP">£{{value}}</a></li> + {% endfor %} + </ul> + </aside> + + {% if post.replies|length %} <section class="replies"> <h6><a name="replies"></a>Replies</h6>
M
templates/style-dark.css
→
templates/style-dark.css
@@ -145,35 +145,26 @@
code, pre { font-family: "Inconsolata", "Courier New", monospace; - font-size: 0.9rem; + font-size: 0.8rem; color: limegreen; + background-color: #222; + border: 1px solid #666; direction: ltr; text-align: left; - white-space: pre; - word-spacing: normal; - word-break: normal; tab-size: 2; - hyphens: none; - outline: 1px solid #666; - background-color: #222; } -pre { +pre { + overflow: auto; padding: 0.3rem; - margin: 0.6rem 0; - overflow: auto; } code { - display: inline-block; - padding: 0 0.3rem 0.1rem 0.3rem; - line-height: 0.9rem; + padding: 0.1rem; } pre code { - background-color: transparent; border: none; - padding: 0; } code.sourceCode span.al { color: limegreen; }@@ -198,6 +189,7 @@ code.sourceCode span.sc { color: limegreen; }
code.sourceCode span.ss { color: limegreen; } code.sourceCode span.st { color: magenta; } code.sourceCode span.va { color: turquoise; } + .limit, .content-body {@@ -318,11 +310,16 @@ .content-footer {
margin-top: 2rem; padding: 0.3rem 0; opacity: 0.8; + text-align: center; +} + +.content-footer * { + display: inline-block; + vertical-align: top; } .content-footer img { - width: 1.1rem; - float: left; + width: 1rem; margin: 0 0.3rem 0rem 0; }@@ -570,7 +567,35 @@ padding: 0;
margin: 0 1rem 0 0; } +.donation { + text-align: center; +} +.donation p { + color: #ccc; +} + +.donation ul { + list-style-type: none; + padding: 0 0 1rem 0; +} + +.donation li { + display: inline; +} + +.donation li a { + display: inline-block; + border: 1px dashed #933; + padding: 0.6rem; + background-color: #111; + width: 5rem; +} + +.donation li a:hover { + border: 1px solid #933; + color: #fff; +} /* above is mobile first; this is the desktop */ @media all and (min-width: 50rem) {@@ -683,6 +708,7 @@ code.sourceCode span.ss { color: black; }
code.sourceCode span.st { color: magenta; } code.sourceCode span.va { color: darkturquoise; } } +