1
0
mirror of https://github.com/krateng/maloja.git synced 2023-08-10 21:12:55 +03:00

Can now upload artist / track images from web

This commit is contained in:
Krateng 2019-11-21 23:14:53 +01:00
parent 3ebde4a187
commit 3c12462d36
9 changed files with 73 additions and 12 deletions

View File

@ -885,6 +885,18 @@ def search(**keys):
return {"artists":artists_result[:max_],"tracks":tracks_result[:max_]} return {"artists":artists_result[:max_],"tracks":tracks_result[:max_]}
@dbserver.post("addpicture")
def add_picture(b64,key,artist:Multi=[],title=None):
if (checkAPIkey(key)):
keys = FormsDict()
for a in artist:
keys.append("artist",a)
if title is not None: keys.append("title",title)
k_filter, _, _, _ = uri_to_internal(keys)
if "track" in k_filter: k_filter = k_filter["track"]
utilities.set_image(b64,**k_filter)
#### ####
## Server operation ## Server operation
#### ####

View File

@ -5,6 +5,6 @@ author = {
"email":"maloja@krateng.dev", "email":"maloja@krateng.dev",
"github": "krateng" "github": "krateng"
} }
version = 1,5,14 version = 1,5,15
versionstr = ".".join(str(n) for n in version) versionstr = ".".join(str(n) for n in version)
dev = os.path.exists("./.dev") dev = os.path.exists("./.dev")

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
# server stuff # server stuff
from bottle import Bottle, route, get, post, error, run, template, static_file, request, response, FormsDict, redirect, template, HTTPResponse from bottle import Bottle, route, get, post, error, run, template, static_file, request, response, FormsDict, redirect, template, HTTPResponse, BaseRequest
import waitress import waitress
# monkey patching # monkey patching
import monkey import monkey
@ -35,6 +35,8 @@ import urllib
#settings.update("settings/default.ini","settings/settings.ini") #settings.update("settings/default.ini","settings/settings.ini")
MAIN_PORT = settings.get_settings("WEB_PORT") MAIN_PORT = settings.get_settings("WEB_PORT")
HOST = settings.get_settings("HOST") HOST = settings.get_settings("HOST")
THREADS = 12
BaseRequest.MEMFILE_MAX = 15 * 1024 * 1024
webserver = Bottle() webserver = Bottle()
@ -251,4 +253,5 @@ database.start_db()
database.dbserver.mount(server=webserver) database.dbserver.mount(server=webserver)
log("Starting up Maloja server...") log("Starting up Maloja server...")
run(webserver, host=HOST, port=MAIN_PORT, server='waitress') #run(webserver, host=HOST, port=MAIN_PORT, server='waitress')
waitress.serve(webserver, host=HOST, port=MAIN_PORT, threads=THREADS)

View File

@ -8,6 +8,7 @@ import urllib
import datetime import datetime
import random import random
import itertools import itertools
import base64
from doreah import settings from doreah import settings
from doreah import caching from doreah import caching
from doreah.logging import log from doreah.logging import log
@ -144,10 +145,10 @@ track_cache = caching.Cache(name="imgcache_tracks",maxage=cacheage,maxage_negati
def clean(name): def clean(name):
return "".join(c for c in name if c.isalnum() or c in []).strip() return "".join(c for c in name if c.isalnum() or c in []).strip()
def local_files(artist=None,artists=None,title=None): def get_all_possible_filenames(artist=None,artists=None,title=None):
# check if we're dealing with a track or artist, then clean up names # check if we're dealing with a track or artist, then clean up names
# (only remove non-alphanumeric, allow korean and stuff) # (only remove non-alphanumeric, allow korean and stuff)
if title is not None and artists is not None: if title is not None and artists is not None:
track = True track = True
title, artists = clean(title), [clean(a) for a in artists] title, artists = clean(title), [clean(a) for a in artists]
@ -203,20 +204,27 @@ def local_files(artist=None,artists=None,title=None):
filenames = list(set(filenames)) filenames = list(set(filenames))
if len(filenames) == 0: filenames.append(str(hash(artist))) if len(filenames) == 0: filenames.append(str(hash(artist)))
return [superfolder + name for name in filenames]
def local_files(artist=None,artists=None,title=None):
filenames = get_all_possible_filenames(artist,artists,title)
images = [] images = []
for purename in filenames: for purename in filenames:
# direct files # direct files
for ext in ["png","jpg","jpeg","gif"]: for ext in ["png","jpg","jpeg","gif"]:
#for num in [""] + [str(n) for n in range(0,10)]: #for num in [""] + [str(n) for n in range(0,10)]:
if os.path.exists(superfolder + purename + "." + ext): if os.path.exists(purename + "." + ext):
images.append("/" + superfolder + purename + "." + ext) images.append("/" + purename + "." + ext)
# folder # folder
try: try:
for f in os.listdir(superfolder + purename + "/"): for f in os.listdir(purename + "/"):
if f.split(".")[-1] in ["png","jpg","jpeg","gif"]: if f.split(".")[-1] in ["png","jpg","jpeg","gif"]:
images.append("/" + superfolder + purename + "/" + f) images.append("/" + purename + "/" + f)
except: except:
pass pass
@ -416,8 +424,32 @@ def resolveImage(artist=None,track=None):
def set_image(b64,**keys):
track = "title" in keys
regex = r"data:image/(\w+);base64,(.+)"
type,b64 = re.fullmatch(regex,b64).groups()
print(b64[:40])
b64 = base64.b64decode(b64)
filename = "webupload" + str(int(datetime.datetime.now().timestamp())) + "." + type
for folder in get_all_possible_filenames(**keys):
if os.path.exists(folder):
with open(os.path.join(folder,filename),"wb") as f:
f.write(b64)
# set as current picture in rotation
if track: local_track_cache.add((frozenset(keys["artists"]),keys["title"]),os.path.join(folder,filename))
else: local_artist_cache.add(keys["artist"],os.path.join(folder,filename))
return
folder = get_all_possible_filenames(**keys)[0]
os.makedirs(folder)
with open(os.path.join(folder,filename),"wb") as f:
f.write(b64)
# set as current picture in rotation
if track: local_track_cache.add((frozenset(keys["artists"]),keys["title"]),os.path.join(folder,filename))
else: local_artist_cache.add(keys["artist"],os.path.join(folder,filename))

View File

@ -48,7 +48,8 @@
<table class="top_info"> <table class="top_info">
<tr> <tr>
<td class="image"> <td class="image">
<div style="background-image:url('{utilities.getArtistImage(artist=artist,fast=True)}');"></div> <pyhp if="adminmode"><div class="changeable-image" data-uploader="b64=>upload('{encodedartist}','{apikey}',b64)" style="background-image:url('{utilities.getArtistImage(artist=artist,fast=True)}');"></div></pyhp>
<pyhp if="not adminmode"><div style="background-image:url('{utilities.getArtistImage(artist=artist,fast=True)}');"></div></pyhp>
</td> </td>
<td class="text"> <td class="text">
<h1><pyhp echo="artist" /></h1> <h1><pyhp echo="artist" /></h1>

View File

@ -8,3 +8,4 @@
<link rel="stylesheet" href="/css/style.css" /> <link rel="stylesheet" href="/css/style.css" />
<script src="/javascript/search.js" async></script> <script src="/javascript/search.js" async></script>
<script src="/javascript/neopolitan.js"></script> <script src="/javascript/neopolitan.js"></script>
<script src="/javascript/upload.js"></script>

View File

@ -25,4 +25,12 @@ if(functions.length>0){supervisor();}
var body=document.getElementsByTagName("BODY")[0] var body=document.getElementsByTagName("BODY")[0]
if(body.getAttribute("data-linkinterceptor")!=undefined){var interceptor=eval(body.getAttribute("data-linkinterceptor"));function interceptClickEvent(e){var href;var target=e.target||e.srcElement;if(target.tagName==='A'&&!target.classList.contains("no-intercept")){href=target.getAttribute('href');e.preventDefault();history.pushState({},"",href);interceptor();}} if(body.getAttribute("data-linkinterceptor")!=undefined){var interceptor=eval(body.getAttribute("data-linkinterceptor"));function interceptClickEvent(e){var href;var target=e.target||e.srcElement;if(target.tagName==='A'&&!target.classList.contains("no-intercept")){href=target.getAttribute('href');e.preventDefault();history.pushState({},"",href);interceptor();}}
document.addEventListener('click',interceptClickEvent);}},false);document.addEventListener('keyup',function(evt){if(evt.srcElement.tagName=="INPUT"){return;} document.addEventListener('click',interceptClickEvent);}},false);document.addEventListener('keyup',function(evt){if(evt.srcElement.tagName=="INPUT"){return;}
var elements=document.querySelectorAll('[data-hotkey]');for(let e of elements){if(e.getAttribute("data-hotkey")==evt.code){evt.preventDefault();e.onclick();break;}}},false); var elements=document.querySelectorAll('[data-hotkey]');for(let e of elements){if(e.getAttribute("data-hotkey")==evt.code){evt.preventDefault();e.onclick();break;}}},false);function dragover(evt){evt.preventDefault();}
function readImageFile(evt,crop=false){evt.preventDefault();var element=this;var file=evt.dataTransfer.files[0];var reader=new FileReader();reader.onload=(function(evt){parseImage(reader.result,element,crop);});reader.readAsArrayBuffer(file);}
function parseImage(buffer,element,crop){var binary='';var bytes=new Uint8Array(buffer);var len=bytes.byteLength;for(var i=0;i<len;i++){binary+=String.fromCharCode(bytes[i]);}
b64=window.btoa(binary);cropImage(b64,element,crop)
}
function cropImage(b64,element,crop){var img=new Image;img.src="data:image/png;base64,"+b64;img.onload=function(){if(crop){x=element.offsetWidth;y=element.offsetHeight;var canvas=document.createElement('canvas'),ctx=canvas.getContext('2d');wid=img.width;heig=img.height;wid_resize=x/wid;heig_resize=y/heig;resize=Math.max(wid_resize,heig_resize);use_wid=x/resize;use_heig=y/resize;new_wid=wid*resize;new_heig=heig*resize;crop_left=(new_wid-x)/(2*resize);crop_top=(new_heig-y)/(2*resize);canvas.width=x;canvas.height=y;ctx.drawImage(img,crop_left,crop_top,use_wid,use_heig,0,0,x,y);done=canvas.toDataURL();}
else{var canvas=document.createElement('canvas'),ctx=canvas.getContext('2d');canvas.width=img.width;canvas.height=img.height;ctx.drawImage(img,0,0);done=canvas.toDataURL();}
element.style.backgroundImage="url('"+done+"')";var callback=element.getAttribute("data-uploader");if(callback!=undefined){eval(callback)(done);}}}
document.addEventListener('DOMContentLoaded',function(){var elements=document.getElementsByClassName("changeable-image");for(var i=0;i<elements.length;i++){elements[i].ondragover=dragover;elements[i].ondrop=readImageFile;}})

View File

@ -0,0 +1,3 @@
function upload(encodedentity,apikey,b64) {
neo.xhttprequest("/api/addpicture?key=" + apikey + "&" + encodedentity,{"b64":b64},"POST")
}

View File

@ -30,7 +30,8 @@
<table class="top_info"> <table class="top_info">
<tr> <tr>
<td class="image"> <td class="image">
<div style="background-image:url('{utilities.getTrackImage(track['artists'],track['title'],fast=True)}')"></div> <pyhp if="adminmode"><div class="changeable-image" data-uploader="b64=>upload('{encodedtrack}','{apikey}',b64)" style="background-image:url('{utilities.getTrackImage(track['artists'],track['title'],fast=True)}')"></div></pyhp>
<pyhp if="not adminmode"><div style="background-image:url('{utilities.getTrackImage(track['artists'],track['title'],fast=True)}')"></div></pyhp>
</td> </td>
<td class="text"> <td class="text">
<span><pyhp echo="htmlgenerators.artistLinks(track['artists'])" /></span><br/> <span><pyhp echo="htmlgenerators.artistLinks(track['artists'])" /></span><br/>