Commit 6c88c23a authored by codey's avatar codey
Browse files

radio_util: open tracks SQLite DB in readonly mode; black: reformat files

parent 96add377
Loading
Loading
Loading
Loading
+0 −1
Changes for .gitignore: 0 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -12,7 +12,6 @@ youtube*
playlist_creator.py
artist_genre_tag.py
uv.lock
py.typed
pyproject.toml
mypy.ini
.python-version
 No newline at end of file
+38 −31
Changes for base.py: 38 added lines, 31 removed lines.
Original line number Diff line number Diff line
import importlib
import sys

sys.path.insert(0, ".")
import logging
import asyncio
@@ -12,58 +13,57 @@ logger = logging.getLogger()
logger.setLevel(logging.INFO)

loop = asyncio.get_event_loop()
app = FastAPI(title="codey.lol API",
app = FastAPI(
    title="codey.lol API",
    version="1.0",
              contact={
                  'name': 'codey'
              },
    contact={"name": "codey"},
    redirect_slashes=False,
              loop=loop)
    loop=loop,
)


constants = importlib.import_module("constants").Constants()
util = importlib.import_module("util").Utilities(app, constants)

origins = [
    "https://codey.lol",
    "https://api.codey.lol"
]
origins = ["https://codey.lol", "https://api.codey.lol"]

app.add_middleware(CORSMiddleware, # type: ignore
app.add_middleware(
    CORSMiddleware,  # type: ignore
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["POST", "GET", "HEAD"],
allow_headers=["*"]) # type: ignore
    allow_headers=["*"],
)  # type: ignore

"""
Blacklisted routes
"""


@app.get("/", include_in_schema=False)
def disallow_get():
    return util.get_blocked_response()


@app.head("/", include_in_schema=False)
def base_head():
    return


@app.get("/{path}", include_in_schema=False)
def disallow_get_any(request: Request, var: Any = None):
    path = request.path_params['path']
    if not (
        isinstance(path, str) 
            and
            path.split("/", maxsplit=1) == "widget"
        ):
    path = request.path_params["path"]
    if not (isinstance(path, str) and path.split("/", maxsplit=1) == "widget"):
        return util.get_blocked_response()
    else:
        logging.info("OK, %s",
                     path)
        logging.info("OK, %s", path)


@app.post("/", include_in_schema=False)
def disallow_base_post():
    return util.get_blocked_response()


"""
End Blacklisted Routes
"""
@@ -73,20 +73,28 @@ Actionable Routes
"""

routes: dict = {
    'randmsg': importlib.import_module("endpoints.rand_msg").RandMsg(app, util, constants),
    'transcriptions': importlib.import_module("endpoints.transcriptions").Transcriptions(app, util, constants),
    'lyrics': importlib.import_module("endpoints.lyric_search").LyricSearch(app, util, constants),
    'lastfm': importlib.import_module("endpoints.lastfm").LastFM(app, util, constants),
    'yt': importlib.import_module("endpoints.yt").YT(app, util, constants),
    'karma': importlib.import_module("endpoints.karma").Karma(app, util, constants),
    'radio': importlib.import_module("endpoints.radio").Radio(app, util, constants),
    'mgr': importlib.import_module("endpoints.mgr.mgr_test").Mgr(app, util, constants),
    "randmsg": importlib.import_module("endpoints.rand_msg").RandMsg(
        app, util, constants
    ),
    "transcriptions": importlib.import_module(
        "endpoints.transcriptions"
    ).Transcriptions(app, util, constants),
    "lyrics": importlib.import_module("endpoints.lyric_search").LyricSearch(
        app, util, constants
    ),
    "lastfm": importlib.import_module("endpoints.lastfm").LastFM(app, util, constants),
    "yt": importlib.import_module("endpoints.yt").YT(app, util, constants),
    "karma": importlib.import_module("endpoints.karma").Karma(app, util, constants),
    "radio": importlib.import_module("endpoints.radio").Radio(app, util, constants),
    "mgr": importlib.import_module("endpoints.mgr.mgr_test").Mgr(app, util, constants),
}

# Misc endpoint depends on radio endpoint instance
radio_endpoint = routes.get('radio')
radio_endpoint = routes.get("radio")
if radio_endpoint:
    routes['misc'] = importlib.import_module("endpoints.misc").Misc(app, util, constants, radio_endpoint)
    routes["misc"] = importlib.import_module("endpoints.misc").Misc(
        app, util, constants, radio_endpoint
    )

"""
End Actionable Routes
@@ -98,5 +106,4 @@ Startup
"""

redis = redis_cache.RedisCache()
loop.create_task(
    redis.create_index())
 No newline at end of file
loop.create_task(redis.create_index())
+41 −4
Changes for endpoints/constructors.py: 41 added lines, 4 removed lines.
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ from pydantic import BaseModel
Karma
"""


class ValidKarmaUpdateRequest(BaseModel):
    """
    Requires authentication
@@ -25,19 +26,24 @@ class ValidKarmaRetrievalRequest(BaseModel):

    keyword: str


class ValidTopKarmaRequest(BaseModel):
    """
    - **n**: Number of top results to return (default: 10)
    """

    n: Optional[int] = 10


"""
LastFM
"""


class LastFMException(Exception):
    pass


class ValidArtistSearchRequest(BaseModel):
    """
    - **a**: artist name
@@ -50,10 +56,12 @@ class ValidArtistSearchRequest(BaseModel):
            "examples": [
                {
                    "a": "eminem",
                }]
                }
            ]
        }
    }


class ValidAlbumDetailRequest(BaseModel):
    """
    - **a**: artist name
@@ -69,9 +77,11 @@ class ValidAlbumDetailRequest(BaseModel):
                {
                    "a": "eminem",
                    "release": "houdini",
                }]
                }
            ]
        }
    }


class ValidTrackInfoRequest(BaseModel):
    """
@@ -88,14 +98,17 @@ class ValidTrackInfoRequest(BaseModel):
                {
                    "a": "eminem",
                    "t": "rap god",
                }]
                }
            ]
        }
    }


"""
Rand Msg
"""


class RandMsgRequest(BaseModel):
    """
    - **short**: Short randmsg?
@@ -103,10 +116,12 @@ class RandMsgRequest(BaseModel):

    short: Optional[bool] = False


"""
YT
"""


class ValidYTSearchRequest(BaseModel):
    """
    - **t**: title to search
@@ -114,10 +129,12 @@ class ValidYTSearchRequest(BaseModel):

    t: str = "rick astley - never gonna give you up"


"""
XC
"""


class ValidXCRequest(BaseModel):
    """
    - **key**: valid XC API key
@@ -131,10 +148,12 @@ class ValidXCRequest(BaseModel):
    cmd: str
    data: Optional[dict]


"""
Transcriptions
"""


class ValidShowEpisodeListRequest(BaseModel):
    """
    - **s**: show id
@@ -142,6 +161,7 @@ class ValidShowEpisodeListRequest(BaseModel):

    s: int


class ValidShowEpisodeLineRequest(BaseModel):
    """
    - **s**: show id
@@ -151,10 +171,12 @@ class ValidShowEpisodeLineRequest(BaseModel):
    s: int
    e: int


"""
Lyric Search
"""


class ValidLyricRequest(BaseModel):
    """
    - **a**: artist
@@ -186,7 +208,8 @@ class ValidLyricRequest(BaseModel):
                    "extra": True,
                    "lrc": False,
                    "excluded_sources": [],
                    }]
                }
            ]
        }
    }

@@ -195,15 +218,19 @@ class ValidTypeAheadRequest(BaseModel):
    """
    - **query**: query string
    """

    query: str


"""
Radio
"""


class RadioException(Exception):
    pass


class ValidRadioSongRequest(BaseModel):
    """
    - **key**: API Key
@@ -212,16 +239,19 @@ class ValidRadioSongRequest(BaseModel):
    - **artistsong**: may be used IN PLACE OF artist/song to perform a combined/string search in the format "artist - song"
    - **alsoSkip**: Whether to skip immediately to this track [not implemented]
    """

    key: str
    artist: Optional[str] = None
    song: Optional[str] = None
    artistsong: Optional[str] = None
    alsoSkip: Optional[bool] = False


class ValidRadioTypeaheadRequest(BaseModel):
    """
    - **query**: Typeahead query
    """

    query: str


@@ -234,33 +264,40 @@ class ValidRadioQueueGetRequest(BaseModel):
    key: Optional[str] = None
    limit: Optional[int] = 15_000


class ValidRadioNextRequest(BaseModel):
    """
    - **key**: API Key
    - **skipTo**: UUID to skip to [optional]
    """

    key: str
    skipTo: Optional[str] = None


class ValidRadioReshuffleRequest(ValidRadioNextRequest):
    """
    - **key**: API Key
    """


class ValidRadioQueueShiftRequest(BaseModel):
    """
    - **key**: API Key
    - **uuid**: UUID to shift
    - **next**: Play next if true, immediately if false, default False
    """

    key: str
    uuid: str
    next: Optional[bool] = False


class ValidRadioQueueRemovalRequest(BaseModel):
    """
    - **key**: API Key
    - **uuid**: UUID to remove
    """

    key: str
    uuid: str
+120 −55
Changes for endpoints/karma.py: 120 added lines, 55 removed lines.
Original line number Diff line number Diff line
@@ -7,14 +7,20 @@ import aiosqlite as sqlite3
from typing import LiteralString, Optional, Union
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import JSONResponse
from .constructors import (ValidTopKarmaRequest, ValidKarmaRetrievalRequest,
    ValidKarmaUpdateRequest)
from .constructors import (
    ValidTopKarmaRequest,
    ValidKarmaRetrievalRequest,
    ValidKarmaUpdateRequest,
)


class KarmaDB:
    """Karma DB Util"""

    def __init__(self) -> None:
        self.db_path: LiteralString = os.path.join("/", "usr", "local", "share",
                                    "sqlite_dbs", "karma.db")
        self.db_path: LiteralString = os.path.join(
            "/", "usr", "local", "share", "sqlite_dbs", "karma.db"
        )

    async def get_karma(self, keyword: str) -> Union[int, dict]:
        """Get Karma Value for Keyword
@@ -24,14 +30,16 @@ class KarmaDB:
            Union[int, dict]
        """
        async with sqlite3.connect(self.db_path, timeout=2) as db_conn:
            async with await db_conn.execute("SELECT score FROM karma WHERE keyword LIKE ? LIMIT 1", (keyword,)) as db_cursor:
            async with await db_conn.execute(
                "SELECT score FROM karma WHERE keyword LIKE ? LIMIT 1", (keyword,)
            ) as db_cursor:
                try:
                    (score,) = await db_cursor.fetchone()
                    return score
                except TypeError:
                    return {
                        'err': True,
                        'errorText': f'No records for {keyword}',
                        "err": True,
                        "errorText": f"No records for {keyword}",
                    }

    async def get_top(self, n: Optional[int] = 10) -> Optional[list[tuple]]:
@@ -44,14 +52,17 @@ class KarmaDB:
        """
        try:
            async with sqlite3.connect(self.db_path, timeout=2) as db_conn:
                async with await db_conn.execute("SELECT keyword, score FROM karma ORDER BY score DESC LIMIT ?", (n,)) as db_cursor:
                async with await db_conn.execute(
                    "SELECT keyword, score FROM karma ORDER BY score DESC LIMIT ?", (n,)
                ) as db_cursor:
                    return await db_cursor.fetchall()
        except:
            traceback.print_exc()
            return None

    async def update_karma(self, granter: str, keyword: str,
                           flag: int) -> Optional[bool]:
    async def update_karma(
        self, granter: str, keyword: str, flag: int
    ) -> Optional[bool]:
        """
        Update Karma for Keyword
        Args:
@@ -66,26 +77,53 @@ class KarmaDB:
            return None

        modifier: str = "score + 1" if not flag else "score - 1"
        query: str = f"UPDATE karma SET score = {modifier}, last_change = ? WHERE keyword LIKE ?"
        new_keyword_query: str = "INSERT INTO karma(keyword, score, last_change) VALUES(?, ?, ?)"
        query: str = (
            f"UPDATE karma SET score = {modifier}, last_change = ? WHERE keyword LIKE ?"
        )
        new_keyword_query: str = (
            "INSERT INTO karma(keyword, score, last_change) VALUES(?, ?, ?)"
        )
        friendly_flag: str = "++" if not flag else "--"
        audit_message: str = f"{granter} adjusted karma for {keyword} @ {datetime.datetime.now().isoformat()}: {friendly_flag}"
        audit_query: str = "INSERT INTO karma_audit(impacted_keyword, comment) VALUES(?, ?)"
        audit_message: str = (
            f"{granter} adjusted karma for {keyword} @ {datetime.datetime.now().isoformat()}: {friendly_flag}"
        )
        audit_query: str = (
            "INSERT INTO karma_audit(impacted_keyword, comment) VALUES(?, ?)"
        )
        now: int = int(time.time())

        logging.debug("Audit message: %s{audit_message}\nKeyword: %s{keyword}")

        async with sqlite3.connect(self.db_path, timeout=2) as db_conn:
            async with await db_conn.execute(audit_query, (keyword, audit_message,)) as db_cursor:
            async with await db_conn.execute(
                audit_query,
                (
                    keyword,
                    audit_message,
                ),
            ) as db_cursor:
                await db_conn.commit()
            async with await db_conn.execute(query, (now, keyword,)) as db_cursor:
            async with await db_conn.execute(
                query,
                (
                    now,
                    keyword,
                ),
            ) as db_cursor:
                if db_cursor.rowcount:
                    await db_conn.commit()
                    return True
                if db_cursor.rowcount < 1:  # Keyword does not already exist
                    await db_cursor.close()
                    new_val = 1 if not flag else -1
                    async with await db_conn.execute(new_keyword_query, (keyword, new_val, now,)) as db_cursor:
                    async with await db_conn.execute(
                        new_keyword_query,
                        (
                            keyword,
                            new_val,
                            now,
                        ),
                    ) as db_cursor:
                        if db_cursor.rowcount >= 1:
                            await db_conn.commit()
                            return True
@@ -93,10 +131,12 @@ class KarmaDB:
                            return False
                return False


class Karma(FastAPI):
    """
    Karma Endpoints
    """

    def __init__(self, app: FastAPI, util, constants) -> None:
        self.app: FastAPI = app
        self.util = util
@@ -110,66 +150,83 @@ class Karma(FastAPI):
        }

        for endpoint, handler in self.endpoints.items():
            app.add_api_route(f"/{endpoint}", handler, methods=["POST"],
                              include_in_schema=True)

            app.add_api_route(
                f"/{endpoint}", handler, methods=["POST"], include_in_schema=True
            )

    async def top_karma_handler(self, request: Request,
                                data: Optional[ValidTopKarmaRequest] = None) -> JSONResponse:
    async def top_karma_handler(
        self, request: Request, data: Optional[ValidTopKarmaRequest] = None
    ) -> JSONResponse:
        """
        Get top keywords for karma
         - **n**: Number of top results to return (default: 10)
        """

        if not self.util.check_key(request.url.path, request.headers.get('X-Authd-With')):
        if not self.util.check_key(
            request.url.path, request.headers.get("X-Authd-With")
        ):
            raise HTTPException(status_code=403, detail="Unauthorized")

        n: int = 10
        if data and data.n:
            n = int(data.n)


        try:
            top10: Optional[list[tuple]] = await self.db.get_top(n=n)
            if not top10:
                return JSONResponse(status_code=500, content={
                    'err': True,
                    'errorText': 'General failure',
                    })
                return JSONResponse(
                    status_code=500,
                    content={
                        "err": True,
                        "errorText": "General failure",
                    },
                )
            return JSONResponse(content=top10)
        except:
            traceback.print_exc()
            return JSONResponse(status_code=500, content={
                'err': True,
                'errorText': 'Exception occurred.',
                })
            return JSONResponse(
                status_code=500,
                content={
                    "err": True,
                    "errorText": "Exception occurred.",
                },
            )

    async def get_karma_handler(self, data: ValidKarmaRetrievalRequest,
                                request: Request) -> JSONResponse:
    async def get_karma_handler(
        self, data: ValidKarmaRetrievalRequest, request: Request
    ) -> JSONResponse:
        """
        Get current karma value
        - **keyword**: Keyword to retrieve karma value for
        """

        if not self.util.check_key(request.url.path, request.headers.get('X-Authd-With')):
        if not self.util.check_key(
            request.url.path, request.headers.get("X-Authd-With")
        ):
            raise HTTPException(status_code=403, detail="Unauthorized")

        keyword: str = data.keyword
        try:
            count: Union[int, dict] = await self.db.get_karma(keyword)
            return JSONResponse(content={
                'keyword': keyword,
                'count': count,
                })
            return JSONResponse(
                content={
                    "keyword": keyword,
                    "count": count,
                }
            )
        except:
            traceback.print_exc()
            return JSONResponse(status_code=500, content={
                'err': True,
                'errorText': "Exception occurred.",
                })
            return JSONResponse(
                status_code=500,
                content={
                    "err": True,
                    "errorText": "Exception occurred.",
                },
            )

    async def modify_karma_handler(self, data: ValidKarmaUpdateRequest,
                                   request: Request) -> JSONResponse:
    async def modify_karma_handler(
        self, data: ValidKarmaUpdateRequest, request: Request
    ) -> JSONResponse:
        """
        Update karma count
        - **granter**: User who granted the karma
@@ -177,16 +234,24 @@ class Karma(FastAPI):
        - **flag**: 0 to decrement (--), 1 to increment (++)
        """

        if not self.util.check_key(request.url.path, request.headers.get('X-Authd-With'), 2):
        if not self.util.check_key(
            request.url.path, request.headers.get("X-Authd-With"), 2
        ):
            raise HTTPException(status_code=403, detail="Unauthorized")

        if not data.flag in [0, 1]:
            return JSONResponse(status_code=500, content={
                'err': True,
                'errorText': 'Invalid request',
            })
        
        return JSONResponse(content={
            'success': await self.db.update_karma(data.granter,
                                                  data.keyword, data.flag)
            })
 No newline at end of file
            return JSONResponse(
                status_code=500,
                content={
                    "err": True,
                    "errorText": "Invalid request",
                },
            )

        return JSONResponse(
            content={
                "success": await self.db.update_karma(
                    data.granter, data.keyword, data.flag
                )
            }
        )
+136 −89

File changed.

Preview size limit exceeded, changes collapsed.

Loading