Upgrade third party modules to use requests

This commit is contained in:
krateng 2023-11-01 19:01:29 +01:00
parent 139de02d9a
commit 76691a5b0f
6 changed files with 98 additions and 81 deletions

View File

@ -28,4 +28,5 @@ minor_release_name: "Nicole"
- "[Bugfix] Fixed scrobbling of tracks when all artists have been removed by server parsing" - "[Bugfix] Fixed scrobbling of tracks when all artists have been removed by server parsing"
- "[Bugfix] Fixed Spotify import of multiple files" - "[Bugfix] Fixed Spotify import of multiple files"
- "[Bugfix] Fixed process control on FreeBSD" - "[Bugfix] Fixed process control on FreeBSD"
- "[Bugfix] Fixed Spotify authentication thread blocking the process from terminating" - "[Bugfix] Fixed Spotify authentication thread blocking the process from terminating"
- "[Technical] Upgraded all third party modules to use requests module and send User Agent"

View File

@ -8,7 +8,8 @@
import xml.etree.ElementTree as ElementTree import xml.etree.ElementTree as ElementTree
import json import json
import urllib.parse, urllib.request import requests
import urllib.parse
import base64 import base64
import time import time
from doreah.logging import log from doreah.logging import log
@ -16,6 +17,7 @@ from threading import BoundedSemaphore
from ..pkg_global.conf import malojaconfig from ..pkg_global.conf import malojaconfig
from .. import database from .. import database
from ..__pkginfo__ import USER_AGENT
services = { services = {
@ -100,6 +102,8 @@ class GenericInterface:
scrobbleimport = {} scrobbleimport = {}
metadata = {} metadata = {}
useragent = USER_AGENT
def __init__(self): def __init__(self):
# populate from settings file once on creation # populate from settings file once on creation
# avoid constant disk access, restart on adding services is acceptable # avoid constant disk access, restart on adding services is acceptable
@ -127,16 +131,6 @@ class GenericInterface:
return True return True
# per default. no authorization is necessary # per default. no authorization is necessary
# wrapper method
def request(self,url,data,responsetype):
response = urllib.request.urlopen(
url,
data=utf(data)
)
responsedata = response.read()
if responsetype == "xml":
data = ElementTree.fromstring(responsedata)
return data
# proxy scrobbler # proxy scrobbler
class ProxyScrobbleInterface(GenericInterface,abstract=True): class ProxyScrobbleInterface(GenericInterface,abstract=True):
@ -155,11 +149,15 @@ class ProxyScrobbleInterface(GenericInterface,abstract=True):
) )
def scrobble(self,artists,title,timestamp): def scrobble(self,artists,title,timestamp):
response = urllib.request.urlopen( response = requests.post(
self.proxyscrobble["scrobbleurl"], url=self.proxyscrobble["scrobbleurl"],
data=utf(self.proxyscrobble_postdata(artists,title,timestamp))) data=self.proxyscrobble_postdata(artists,title,timestamp),
responsedata = response.read() headers={
"User-Agent":self.useragent
}
)
if self.proxyscrobble["response_type"] == "xml": if self.proxyscrobble["response_type"] == "xml":
responsedata = response.text
data = ElementTree.fromstring(responsedata) data = ElementTree.fromstring(responsedata)
return self.proxyscrobble_parse_response(data) return self.proxyscrobble_parse_response(data)
@ -211,13 +209,15 @@ class MetadataInterface(GenericInterface,abstract=True):
artists, title = track artists, title = track
artiststring = urllib.parse.quote(", ".join(artists)) artiststring = urllib.parse.quote(", ".join(artists))
titlestring = urllib.parse.quote(title) titlestring = urllib.parse.quote(title)
response = urllib.request.urlopen( response = requests.get(
self.metadata["trackurl"].format(artist=artiststring,title=titlestring,**self.settings) self.metadata["trackurl"].format(artist=artiststring,title=titlestring,**self.settings),
headers={
"User-Agent":self.useragent
}
) )
responsedata = response.read()
if self.metadata["response_type"] == "json": if self.metadata["response_type"] == "json":
data = json.loads(responsedata) data = response.json()
imgurl = self.metadata_parse_response_track(data) imgurl = self.metadata_parse_response_track(data)
else: else:
imgurl = None imgurl = None
@ -227,13 +227,15 @@ class MetadataInterface(GenericInterface,abstract=True):
def get_image_artist(self,artist): def get_image_artist(self,artist):
artiststring = urllib.parse.quote(artist) artiststring = urllib.parse.quote(artist)
response = urllib.request.urlopen( response = requests.get(
self.metadata["artisturl"].format(artist=artiststring,**self.settings) self.metadata["artisturl"].format(artist=artiststring,**self.settings),
headers={
"User-Agent":self.useragent
}
) )
responsedata = response.read()
if self.metadata["response_type"] == "json": if self.metadata["response_type"] == "json":
data = json.loads(responsedata) data = response.json()
imgurl = self.metadata_parse_response_artist(data) imgurl = self.metadata_parse_response_artist(data)
else: else:
imgurl = None imgurl = None
@ -245,13 +247,15 @@ class MetadataInterface(GenericInterface,abstract=True):
artists, title = album artists, title = album
artiststring = urllib.parse.quote(", ".join(artists or [])) artiststring = urllib.parse.quote(", ".join(artists or []))
titlestring = urllib.parse.quote(title) titlestring = urllib.parse.quote(title)
response = urllib.request.urlopen( response = requests.get(
self.metadata["albumurl"].format(artist=artiststring,title=titlestring,**self.settings) self.metadata["albumurl"].format(artist=artiststring,title=titlestring,**self.settings),
headers={
"User-Agent":self.useragent
}
) )
responsedata = response.read()
if self.metadata["response_type"] == "json": if self.metadata["response_type"] == "json":
data = json.loads(responsedata) data = response.json()
imgurl = self.metadata_parse_response_album(data) imgurl = self.metadata_parse_response_album(data)
else: else:
imgurl = None imgurl = None

View File

@ -1,6 +1,7 @@
from . import MetadataInterface, ProxyScrobbleInterface, utf from . import MetadataInterface, ProxyScrobbleInterface, utf
import hashlib import hashlib
import urllib.parse, urllib.request import requests
import xml.etree.ElementTree as ElementTree
from doreah.logging import log from doreah.logging import log
class LastFM(MetadataInterface, ProxyScrobbleInterface): class LastFM(MetadataInterface, ProxyScrobbleInterface):
@ -54,27 +55,37 @@ class LastFM(MetadataInterface, ProxyScrobbleInterface):
def authorize(self): def authorize(self):
try: try:
result = self.request( response = requests.post(
self.proxyscrobble['scrobbleurl'], url=self.proxyscrobble['scrobbleurl'],
self.query_compose({ params=self.query_compose({
"method":"auth.getMobileSession", "method":"auth.getMobileSession",
"username":self.settings["username"], "username":self.settings["username"],
"password":self.settings["password"], "password":self.settings["password"],
"api_key":self.settings["apikey"] "api_key":self.settings["apikey"]
}), }),
responsetype="xml" headers={
"User-Agent":self.useragent
}
) )
self.settings["sk"] = result.find("session").findtext("key")
data = ElementTree.fromstring(response.text)
self.settings["sk"] = data.find("session").findtext("key")
except Exception as e: except Exception as e:
pass log("Error while authenticating with LastFM: " + repr(e))
#log("Error while authenticating with LastFM: " + repr(e))
# creates signature and returns full query string # creates signature and returns full query
def query_compose(self,parameters): def query_compose(self,parameters):
m = hashlib.md5() m = hashlib.md5()
keys = sorted(str(k) for k in parameters) keys = sorted(str(k) for k in parameters)
m.update(utf("".join(str(k) + str(parameters[k]) for k in keys))) m.update(utf("".join(str(k) + str(parameters[k]) for k in keys)))
m.update(utf(self.settings["secret"])) m.update(utf(self.settings["secret"]))
sig = m.hexdigest() sig = m.hexdigest()
return urllib.parse.urlencode(parameters) + "&api_sig=" + sig return {**parameters,"api_sig":sig}
def handle_json_result_error(self,result):
if "track" in result and not result.get("track").get('album',{}):
return True
if "error" in result and result.get("error") == 6:
return True

View File

@ -1,5 +1,5 @@
from . import ProxyScrobbleInterface, ImportInterface from . import ProxyScrobbleInterface, ImportInterface
import urllib.request import requests
from doreah.logging import log from doreah.logging import log
import json import json
@ -32,8 +32,8 @@ class OtherMalojaInstance(ProxyScrobbleInterface, ImportInterface):
def get_remote_scrobbles(self): def get_remote_scrobbles(self):
url = f"{self.settings['instance']}/apis/mlj_1/scrobbles" url = f"{self.settings['instance']}/apis/mlj_1/scrobbles"
response = urllib.request.urlopen(url) response = requests.get(url)
data = json.loads(response.read().decode('utf-8')) data = response.json()
for scrobble in data['list']: for scrobble in data['list']:
yield scrobble yield scrobble

View File

@ -1,9 +1,7 @@
from . import MetadataInterface from . import MetadataInterface
import urllib.parse, urllib.request import requests
import json
import time import time
import threading import threading
from ..__pkginfo__ import USER_AGENT
class MusicBrainz(MetadataInterface): class MusicBrainz(MetadataInterface):
name = "MusicBrainz" name = "MusicBrainz"
@ -11,7 +9,6 @@ class MusicBrainz(MetadataInterface):
# musicbrainz is rate-limited # musicbrainz is rate-limited
lock = threading.Lock() lock = threading.Lock()
useragent = USER_AGENT
thumbnailsize_order = ['500','large','1200','250','small'] thumbnailsize_order = ['500','large','1200','250','small']
@ -35,30 +32,32 @@ class MusicBrainz(MetadataInterface):
searchstr = f'release:"{title}"' searchstr = f'release:"{title}"'
for artist in artists: for artist in artists:
searchstr += f' artist:"{artist}"' searchstr += f' artist:"{artist}"'
querystr = urllib.parse.urlencode({ res = requests.get(**{
"fmt":"json", "url":"https://musicbrainz.org/ws/2/release",
"query":searchstr "params":{
}) "fmt":"json",
req = urllib.request.Request(**{ "query":searchstr
"url":"https://musicbrainz.org/ws/2/release?" + querystr, },
"method":"GET",
"headers":{ "headers":{
"User-Agent":self.useragent "User-Agent":self.useragent
} }
}) })
response = urllib.request.urlopen(req) data = res.json()
responsedata = response.read()
data = json.loads(responsedata)
entity = data["releases"][0] entity = data["releases"][0]
coverartendpoint = "release" coverartendpoint = "release"
while True: while True:
mbid = entity["id"] mbid = entity["id"]
try: try:
response = urllib.request.urlopen( response = requests.get(
f"https://coverartarchive.org/{coverartendpoint}/{mbid}?fmt=json" f"https://coverartarchive.org/{coverartendpoint}/{mbid}",
params={
"fmt":"json"
},
headers={
"User-Agent":self.useragent
}
) )
responsedata = response.read() data = response.json()
data = json.loads(responsedata)
thumbnails = data['images'][0]['thumbnails'] thumbnails = data['images'][0]['thumbnails']
for size in self.thumbnailsize_order: for size in self.thumbnailsize_order:
if thumbnails.get(size) is not None: if thumbnails.get(size) is not None:
@ -88,30 +87,29 @@ class MusicBrainz(MetadataInterface):
searchstr = f'recording:"{title}"' searchstr = f'recording:"{title}"'
for artist in artists: for artist in artists:
searchstr += f' artist:"{artist}"' searchstr += f' artist:"{artist}"'
querystr = urllib.parse.urlencode({ res = requests.get(**{
"fmt":"json", "url":"https://musicbrainz.org/ws/2/recording",
"query":searchstr "params":{
}) "fmt":"json",
req = urllib.request.Request(**{ "query":searchstr
"url":"https://musicbrainz.org/ws/2/recording?" + querystr, },
"method":"GET",
"headers":{ "headers":{
"User-Agent":self.useragent "User-Agent":self.useragent
} }
}) })
response = urllib.request.urlopen(req) data = res.json()
responsedata = response.read()
data = json.loads(responsedata)
entity = data["recordings"][0]["releases"][0] entity = data["recordings"][0]["releases"][0]
coverartendpoint = "release" coverartendpoint = "release"
while True: while True:
mbid = entity["id"] mbid = entity["id"]
try: try:
response = urllib.request.urlopen( response = requests.get(
f"https://coverartarchive.org/{coverartendpoint}/{mbid}?fmt=json" f"https://coverartarchive.org/{coverartendpoint}/{mbid}",
params={
"fmt":"json"
}
) )
responsedata = response.read() data = response.json()
data = json.loads(responsedata)
thumbnails = data['images'][0]['thumbnails'] thumbnails = data['images'][0]['thumbnails']
for size in self.thumbnailsize_order: for size in self.thumbnailsize_order:
if thumbnails.get(size) is not None: if thumbnails.get(size) is not None:

View File

@ -1,6 +1,5 @@
from . import MetadataInterface, utf, b64 from . import MetadataInterface, utf, b64
import urllib.parse, urllib.request import requests
import json
from threading import Timer from threading import Timer
from doreah.logging import log from doreah.logging import log
@ -31,15 +30,14 @@ class Spotify(MetadataInterface):
try: try:
keys = { keys = {
"url":"https://accounts.spotify.com/api/token", "url":"https://accounts.spotify.com/api/token",
"method":"POST",
"headers":{ "headers":{
"Authorization":"Basic " + b64(utf(self.settings["apiid"] + ":" + self.settings["secret"])).decode("utf-8") "Authorization":"Basic " + b64(utf(self.settings["apiid"] + ":" + self.settings["secret"])).decode("utf-8"),
"User-Agent": self.useragent
}, },
"data":bytes(urllib.parse.urlencode({"grant_type":"client_credentials"}),encoding="utf-8") "data":{"grant_type":"client_credentials"}
} }
req = urllib.request.Request(**keys) res = requests.post(**keys)
response = urllib.request.urlopen(req) responsedata = res.json()
responsedata = json.loads(response.read())
if "error" in responsedata: if "error" in responsedata:
log("Error authenticating with Spotify: " + responsedata['error_description']) log("Error authenticating with Spotify: " + responsedata['error_description'])
expire = 3600 expire = 3600
@ -52,3 +50,8 @@ class Spotify(MetadataInterface):
t.start() t.start()
except Exception as e: except Exception as e:
log("Error while authenticating with Spotify: " + repr(e)) log("Error while authenticating with Spotify: " + repr(e))
def handle_json_result_error(self,result):
result = result.get('tracks') or result.get('albums') or result.get('artists')
if not result['items']:
return True