Exemple #1
0
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()
Exemple #2
0
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:
Exemple #3
0
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"]
Exemple #4
0
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
Exemple #5
0
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()
Exemple #6
0
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.")
Exemple #7
0
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()
Exemple #8
0
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()
Exemple #9
0
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
Exemple #10
0
    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,
                )
Exemple #11
0
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()
Exemple #12
0
def db(isolated_dir):
    with database() as conn:
        yield conn