Skip to content

Commit

Permalink
asyncio versions of read/write metadb (#816)
Browse files Browse the repository at this point in the history
  • Loading branch information
aw-was-here committed May 13, 2023
1 parent 07a1763 commit 8d30091
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 55 deletions.
97 changes: 82 additions & 15 deletions nowplaying/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import time
import traceback

import aiosqlite

from watchdog.observers import Observer # pylint: disable=import-error
from watchdog.events import PatternMatchingEventHandler # pylint: disable=import-error

Expand Down Expand Up @@ -143,7 +145,7 @@ def watcher(self):
''' get access to a watch on the database file '''
return DBWatcher(self.databasefile)

def write_to_metadb(self, metadata=None):
async def write_to_metadb(self, metadata=None):
''' update metadb '''

def filterkeys(mydict):
Expand All @@ -161,7 +163,8 @@ def filterkeys(mydict):
if not self.databasefile.exists():
self.setupsql()

with sqlite3.connect(self.databasefile, timeout=10) as connection:
async with aiosqlite.connect(self.databasefile,
timeout=10) as connection:
# do not want to modify the original dictionary
# otherwise Bad Things(tm) will happen
mdcopy = copy.deepcopy(metadata)
Expand All @@ -170,7 +173,7 @@ def filterkeys(mydict):
# toss any keys we do not care about
mdcopy = filterkeys(mdcopy)

cursor = connection.cursor()
cursor = await connection.cursor()

logging.debug('Adding record with %s/%s', mdcopy['artist'],
mdcopy['title'])
Expand All @@ -190,7 +193,8 @@ def filterkeys(mydict):
sql += '?,' * (len(mdcopy.keys()) - 1) + '?)'

datatuple = tuple(list(mdcopy.values()))
cursor.execute(sql, datatuple)
await cursor.execute(sql, datatuple)
await connection.commit()

def make_previoustracklist(self):
''' create a reversed list of the tracks played '''
Expand Down Expand Up @@ -220,28 +224,38 @@ def make_previoustracklist(self):

return previouslist

def read_last_meta(self):
''' update metadb '''
async def make_previoustracklist_async(self):
''' create a reversed list of the tracks played '''

if not self.databasefile.exists():
logging.error('MetadataDB does not exist yet?')
return None

with sqlite3.connect(self.databasefile, timeout=10) as connection:
async with aiosqlite.connect(self.databasefile,
timeout=10) as connection:
connection.row_factory = sqlite3.Row
cursor = connection.cursor()
cursor = await connection.cursor()
try:
cursor.execute(
'''SELECT * FROM currentmeta ORDER BY id DESC LIMIT 1''')
await cursor.execute(
'''SELECT artist, title FROM currentmeta ORDER BY id DESC'''
)
except sqlite3.OperationalError:
for line in traceback.format_exc().splitlines():
logging.error(line)
return None

row = cursor.fetchone()
if not row:
return None
records = await cursor.fetchall()

previouslist = []
if records:
previouslist.extend({
'artist': row['artist'],
'title': row['title']
} for row in records)

return previouslist

@staticmethod
def _postprocess_read_last_meta(row):
''' common post-process of read_last_meta '''
metadata = {data: row[data] for data in METADATALIST}
for key in METADATABLOBLIST:
metadata[key] = row[key]
Expand All @@ -254,6 +268,59 @@ def read_last_meta(self):
metadata[key] = metadata[key].split(SPLITSTR)

metadata['dbid'] = row['id']
return metadata

async def read_last_meta_async(self):
''' update metadb '''

if not self.databasefile.exists():
logging.error('MetadataDB does not exist yet?')
return None

async with aiosqlite.connect(self.databasefile,
timeout=10) as connection:
connection.row_factory = sqlite3.Row
cursor = await connection.cursor()
try:
await cursor.execute(
'''SELECT * FROM currentmeta ORDER BY id DESC LIMIT 1''')
except sqlite3.OperationalError:
for line in traceback.format_exc().splitlines():
logging.error(line)
return None

row = await cursor.fetchone()
await cursor.close()
if not row:
return None

metadata = self._postprocess_read_last_meta(row)
metadata['previoustrack'] = await self.make_previoustracklist_async()
return metadata

def read_last_meta(self):
''' update metadb '''

if not self.databasefile.exists():
logging.error('MetadataDB does not exist yet?')
return None

with sqlite3.connect(self.databasefile, timeout=10) as connection:
connection.row_factory = sqlite3.Row
cursor = connection.cursor()
try:
cursor.execute(
'''SELECT * FROM currentmeta ORDER BY id DESC LIMIT 1''')
except sqlite3.OperationalError:
for line in traceback.format_exc().splitlines():
logging.error(line)
return None

row = cursor.fetchone()
if not row:
return None

metadata = self._postprocess_read_last_meta(row)
metadata['previoustrack'] = self.make_previoustracklist()
return metadata

Expand Down
2 changes: 1 addition & 1 deletion nowplaying/processes/discordbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ async def start(self):
if not template:
continue

metadata = metadb.read_last_meta()
metadata = await metadb.read_last_meta_async()
if not metadata:
continue

Expand Down
2 changes: 1 addition & 1 deletion nowplaying/processes/trackpoll.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ async def gettrack(self): # pylint: disable=too-many-branches,

if not self.testmode:
metadb = nowplaying.db.MetadataDB()
metadb.write_to_metadb(metadata=self.currentmeta)
await metadb.write_to_metadb(metadata=self.currentmeta)
self._write_to_text()

def _artfallbacks(self):
Expand Down
16 changes: 8 additions & 8 deletions nowplaying/processes/webserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ async def _htm_handler(request, template, metadata=None): # pylint: disable=unu
htmloutput = INDEXREFRESH
try:
if not metadata:
metadata = request.app['metadb'].read_last_meta()
metadata = await request.app['metadb'].read_last_meta_async()
if not metadata:
metadata = nowplaying.hostmeta.gethostmeta()
metadata['httpport'] = request.app['config'].cparser.value(
Expand All @@ -202,7 +202,7 @@ async def _metacheck_htm_handler(self, request, template): # pylint: disable=un
source = os.path.basename(template)
htmloutput = ""
request.app['config'].get()
metadata = request.app['metadb'].read_last_meta()
metadata = await request.app['metadb'].read_last_meta_async()
lastid = await self.getlastid(request, source)
once = request.app['config'].cparser.value('weboutput/once', type=bool)
#once = False
Expand Down Expand Up @@ -252,7 +252,7 @@ async def getlastid(request, source):
@staticmethod
async def indextxt_handler(request):
''' handle static index.txt '''
metadata = request.app['metadb'].read_last_meta()
metadata = await request.app['metadb'].read_last_meta_async()
txtoutput = ""
if metadata:
request.app['config'].get()
Expand All @@ -279,7 +279,7 @@ async def _image_handler(imgtype, request):
# this makes the client code significantly easier
image = nowplaying.utils.TRANSPARENT_PNG_BIN
try:
metadata = request.app['metadb'].read_last_meta()
metadata = await request.app['metadb'].read_last_meta_async()
if metadata and metadata.get(imgtype):
image = metadata[imgtype]
except: #pylint: disable=bare-except
Expand All @@ -306,7 +306,7 @@ async def artistthumb_handler(self, request):
async def api_v1_last_handler(self, request):
''' v1/last just returns the metadata'''
data = {}
if metadata := request.app['metadb'].read_last_meta():
if metadata := await request.app['metadb'].read_last_meta_async():
try:
del metadata['dbid']
data = self._base64ifier(metadata)
Expand Down Expand Up @@ -364,7 +364,7 @@ async def websocket_artistfanart_streamer(self, request):
try:
while not self.stopevent.is_set(
) and not endloop and not websocket.closed:
metadata = request.app['metadb'].read_last_meta()
metadata = await request.app['metadb'].read_last_meta_async()
if not metadata or not metadata.get('artist'):
await asyncio.sleep(5)
continue
Expand Down Expand Up @@ -408,7 +408,7 @@ async def websocket_artistfanart_streamer(self, request):

async def websocket_lastjson_handler(self, request, websocket):
''' handle singular websocket request '''
metadata = request.app['metadb'].read_last_meta()
metadata = await request.app['metadb'].read_last_meta_async()
del metadata['dbid']
if not websocket.closed:
await websocket.send_json(self._base64ifier(metadata))
Expand All @@ -421,7 +421,7 @@ async def _wss_do_update(self, websocket, database):
while not metadata and not websocket.closed:
if self.stopevent.is_set():
return time.time()
metadata = database.read_last_meta()
metadata = await database.read_last_meta_async()
await asyncio.sleep(1)
del metadata['dbid']
if not websocket.closed:
Expand Down
2 changes: 1 addition & 1 deletion nowplaying/trackrequests.py
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ async def twofer_request(self, setting, user, user_input):
''' twofer request '''

metadb = nowplaying.db.MetadataDB()
metadata = metadb.read_last_meta()
metadata = await metadb.read_last_meta_async()
if not metadata:
logging.debug('Twofer: No currently playing track? skipping')
return {}
Expand Down
4 changes: 2 additions & 2 deletions nowplaying/twitch/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ async def _async_announce_track(self):
anntemplate)
return

metadata = self.metadb.read_last_meta()
metadata = await self.metadb.read_last_meta_async()

if not metadata:
logging.debug('No metadata to announce')
Expand Down Expand Up @@ -425,7 +425,7 @@ async def _post_template(self, msg=None, template=None, moremetadata=None): #py
''' take a template, fill it in, and post it '''
if not template:
return
metadata = self.metadb.read_last_meta()
metadata = await self.metadb.read_last_meta_async()
if not metadata:
metadata = {}
if 'coverimageraw' in metadata:
Expand Down
Loading

0 comments on commit 8d30091

Please sign in to comment.