def save_pending_covers() -> None: """ For the releases with pending covers-to-save, look at their first track for a cover art to save. If a cover art is found, save it to the ``COVER_ART_DIR``, generate a thumbnail, and update the database with the filename. """ logger.info("Saving cover art for newly-found releases.") with database() as conn: for rls_id in _get_pending_releases(conn): logger.debug(f"Searching for cover art in release {rls_id}.") track_path = _get_track_path_of_release(rls_id, conn) if not track_path: logger.debug(f"No tracks found for release {rls_id}.") _delete_release_from_pending(rls_id, conn) continue img = save_image(TagFile(track_path), conn) if not img: logger.debug(f"No image found for release {rls_id}.") _delete_release_from_pending(rls_id, conn) continue _update_release_image(rls_id, img, conn) _delete_release_from_pending(rls_id, conn) conn.commit()
def token(): """Generate an authorization token.""" # Currently, we only support a single user. with database() as conn: if usr := user.from_id(1, conn): token = user.new_token(usr, conn) else:
def index_crontab_str() -> str: """ A crontab representing when to index the library. """ with database() as conn: cursor = conn.execute( "SELECT value FROM system__config WHERE key = ?", (INDEX_CRONTAB, ), ) return cursor.fetchone()["value"]
async def test_new_token(db, graphql_query): cursor = db.execute("SELECT token_prefix FROM system__users WHERE id = 1") old_prefix = cursor.fetchone()[0] _, result = await graphql_query(TOKEN_QUERY) assert result["data"]["newToken"]["hex"] with database() as conn: cursor = conn.cursor() cursor.execute("SELECT token_prefix FROM system__users WHERE id = 1") new_prefix = cursor.fetchone()[0] assert old_prefix != new_prefix
def calculate_track_sha256s(track_ids: list[int]) -> None: """ Calculate a list of track's full SHA256s. """ with database() as conn: for id_ in track_ids: trk = track.from_id(id_, conn) if not trk or trk.sha256: continue track.calculate_track_full_sha256(trk, conn) conn.commit()
def music_directories() -> list[str]: """ The directories to scan when indexing the library. """ with database() as conn: cursor = conn.execute( "SELECT value FROM system__config WHERE key = ?", (MUSIC_DIRECTORIES, ), ) try: return json.loads(cursor.fetchone()["value"]) except (TypeError, ValueError): raise InvalidConfig( "music_directories is not a valid JSON-encoded list.")
def initialize_config() -> None: """ Write the default config if a config file doesn't exist. And if the existing config lacks keys, update it with new default values. """ with database() as conn: cursor = conn.execute("SELECT key FROM system__config") keys = [r["key"] for r in cursor] if not keys: write_default_config(conn) else: _update_config(conn) conn.commit()
def _populate_inbox(user_id: int) -> None: with database() as conn: inbox = collection.inbox_of(user_id, conn) conn.execute( """ INSERT INTO music__collections_releases (collection_id, release_id) SELECT ?, rls.id FROM music__releases AS rls WHERE rls.id != 1 """, (inbox.id, ), ) conn.commit()
def _get_secret_key(): # This function is called whenever webserver starts, but when Sphinx is generating # docs, we don't have a database. So just return random bytes. logger.debug("Fetching/generating webserver secret key.") if "sphinx" in sys.modules: # pragma: no cover return secrets.token_bytes(32) with database() as conn: cursor = conn.cursor() cursor.execute("SELECT key FROM system__secret_key LIMIT 1") if row := cursor.fetchone(): return row[0] secret_key = secrets.token_bytes(32) cursor.execute("INSERT INTO system__secret_key (key) VALUES (?)", (secret_key,)) conn.commit() return secret_key
async def executor(query): used_fragments = "\n".join(v for k, v in FRAGMENTS.items() if k in query) query = f"{query}\n{used_fragments}" async with quart_app.test_request_context("/testing", method="GET"): with database() as conn: return await graphql( schema=schema, data={ "operationName": None, "variables": {}, "query": query }, context_value=GraphQLContext( user=user.from_id(1, conn), # type: ignore db=conn, request=quart.request, ), error_formatter=error_formatter, debug=False, )
def scan_directory(directory: Path) -> None: """ Scan a given directory for music files and catalog the discovered files. :param directory: The directory to scan. :raises NotADirectoryError: If the directory does not exist. """ logger.info(f"Scanning `{directory}`.") if not directory.is_dir(): logger.error(f"{directory} is not a directory.") raise NotADirectoryError(f"{directory} is not a directory.") with database() as conn: track_batch: list[track.T] = [] for ext in EXTS: for filepath in glob.iglob(f"{directory}/**/*{ext}", recursive=True): # Every 50 tracks, run some specialized logic. if len(track_batch) == 50: # pragma: no cover handle_track_batch(track_batch, conn) track_batch = [] if not _in_database(filepath, conn): logger.debug(f"Discovered new file `{filepath}`.") trk = catalog_file(filepath, conn) track_batch.append(trk) else: logger.debug( f"File `{filepath}` already in database, skipping...") # Handle the last batch of tracks. handle_track_batch(track_batch, conn) conn.commit()
def db(isolated_dir): with database() as conn: yield conn