feat(api): Errors are raised faster, add Exception classes
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
from typing import List, Optional, Tuple
|
from typing import List, Optional, Tuple
|
||||||
from typing_extensions import TypedDict
|
from typing_extensions import TypedDict
|
||||||
import re
|
import re
|
||||||
|
import json
|
||||||
import unicodedata
|
import unicodedata
|
||||||
import logging
|
import logging
|
||||||
from os import environ
|
from os import environ
|
||||||
@@ -195,6 +196,22 @@ class Story(TypedDict):
|
|||||||
|
|
||||||
story_ta = TypeAdapter(Story)
|
story_ta = TypeAdapter(Story)
|
||||||
|
|
||||||
|
# --- Exceptions --- #
|
||||||
|
|
||||||
|
|
||||||
|
class WattpadError(Exception):
|
||||||
|
"""Base Exception class for Wattpad related errors."""
|
||||||
|
|
||||||
|
|
||||||
|
class StoryNotFoundError(WattpadError):
|
||||||
|
"""Display the "This story was not found" error to the user."""
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class PartNotFoundError(StoryNotFoundError): ...
|
||||||
|
|
||||||
|
|
||||||
# --- API Calls --- #
|
# --- API Calls --- #
|
||||||
|
|
||||||
|
|
||||||
@@ -210,10 +227,16 @@ async def fetch_story_from_partId(
|
|||||||
async with session.get(
|
async with session.get(
|
||||||
f"https://www.wattpad.com/api/v3/story_parts/{part_id}?fields=groupId,group(tags,id,title,createDate,modifyDate,language(name),description,completed,mature,url,isPaywalled,user(username),parts(id,title),cover)"
|
f"https://www.wattpad.com/api/v3/story_parts/{part_id}?fields=groupId,group(tags,id,title,createDate,modifyDate,language(name),description,completed,mature,url,isPaywalled,user(username),parts(id,title),cover)"
|
||||||
) as response:
|
) as response:
|
||||||
response.raise_for_status()
|
|
||||||
|
|
||||||
body = await response.json()
|
body = await response.json()
|
||||||
|
|
||||||
|
if response.status == 400:
|
||||||
|
match body.get("error_code"):
|
||||||
|
case 1020: # "Story part not found"
|
||||||
|
logger.info(f"{part_id=} not found on Wattpad, returning.")
|
||||||
|
raise PartNotFoundError()
|
||||||
|
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
return str(body["groupId"]), story_ta.validate_python(body["group"])
|
return str(body["groupId"]), story_ta.validate_python(body["group"])
|
||||||
|
|
||||||
|
|
||||||
@@ -227,10 +250,16 @@ async def retrieve_story(story_id: int, cookies: Optional[dict] = None) -> Story
|
|||||||
async with session.get(
|
async with session.get(
|
||||||
f"https://www.wattpad.com/api/v3/stories/{story_id}?fields=tags,id,title,createDate,modifyDate,language(name),description,completed,mature,url,isPaywalled,user(username),parts(id,title),cover"
|
f"https://www.wattpad.com/api/v3/stories/{story_id}?fields=tags,id,title,createDate,modifyDate,language(name),description,completed,mature,url,isPaywalled,user(username),parts(id,title),cover"
|
||||||
) as response:
|
) as response:
|
||||||
response.raise_for_status()
|
|
||||||
|
|
||||||
body = await response.json()
|
body = await response.json()
|
||||||
|
|
||||||
|
if response.status == 400:
|
||||||
|
match body.get("error_code"):
|
||||||
|
case 1017: # "Story not found"
|
||||||
|
logger.info(f"{story_id=} not found on Wattpad, returning.")
|
||||||
|
raise StoryNotFoundError()
|
||||||
|
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
return story_ta.validate_python(body)
|
return story_ta.validate_python(body)
|
||||||
|
|
||||||
|
|
||||||
@@ -244,10 +273,19 @@ async def fetch_part_content(part_id: int, cookies: Optional[dict] = None) -> st
|
|||||||
async with session.get(
|
async with session.get(
|
||||||
f"https://www.wattpad.com/apiv2/?m=storytext&id={part_id}"
|
f"https://www.wattpad.com/apiv2/?m=storytext&id={part_id}"
|
||||||
) as response:
|
) as response:
|
||||||
response.raise_for_status()
|
|
||||||
|
|
||||||
body = await response.text()
|
body = await response.text()
|
||||||
|
|
||||||
|
if response.status == 400:
|
||||||
|
data = json.loads(body)
|
||||||
|
match data.get("code"):
|
||||||
|
case 463: # ""Could not find any parts for that story""
|
||||||
|
logger.info(
|
||||||
|
f"{part_id=} for text not found on Wattpad, returning."
|
||||||
|
)
|
||||||
|
raise PartNotFoundError()
|
||||||
|
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
return body
|
return body
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,15 @@ def download_error_handler(request: Request, exception: ClientResponseError):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.exception_handler(WattpadError)
|
||||||
|
def download_wp_error_handler(request: Request, exception: WattpadError):
|
||||||
|
if isinstance(exception, StoryNotFoundError):
|
||||||
|
return HTMLResponse(
|
||||||
|
status_code=404,
|
||||||
|
content='This story does not exist, or has been deleted. Support is available on the <a href="https://discord.gg/P9RHC4KCwd" target="_blank">Discord</a>',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/download/{download_id}")
|
@app.get("/download/{download_id}")
|
||||||
async def handle_download(
|
async def handle_download(
|
||||||
download_id: int,
|
download_id: int,
|
||||||
|
|||||||
Reference in New Issue
Block a user