Handle send_watch JSON errors by emitting an error log instead

This commit is contained in:
DevilXD committed 2024-10-28 16:53:48 +01:00
1 parent b7924231a4
commit 3b4923a289
1 file changed
+18 -6
+18 -6
View File
@@ -1,5 +1,7 @@
from __future__ import annotations from __future__ import annotations
import re
import json
import asyncio import asyncio
import logging import logging
from typing import Any, SupportsInt, cast, TYPE_CHECKING from typing import Any, SupportsInt, cast, TYPE_CHECKING
@@ -375,15 +377,28 @@ class Channel:
# fetch a list of chunks available to download for the stream # fetch a list of chunks available to download for the stream
# NOTE: the CDN is configured to forcibly disconnect shortly after serving the list, # NOTE: the CDN is configured to forcibly disconnect shortly after serving the list,
# if we don't do it yourselves. Lets help it by actually doing it ourselves instead. # if we don't do it yourselves. Lets help it by actually doing it ourselves instead.
available_chunks: str = ''
try:
async with self._twitch.request( async with self._twitch.request(
"GET", stream_url, headers={"Connection": "close"} "GET", stream_url, headers={"Connection": "close"}
) as chunks_response: ) as chunks_response:
if chunks_response.status >= 400: if chunks_response.status >= 400:
# if the stream goes OFFLINE, trying to get a list of chunks returns a 404 # if the stream goes OFFLINE, trying to get a list of chunks returns a 404
return False return False
available_chunks = await chunks_response.text() available_chunks: str = await chunks_response.text()
# the response may contain some invalid JSON with duplicate double quotes
# in the value strings: we need to get rid of them by removing the "url" key entirely
# if no JSON can be found within the response, this is a NOOP
available_chunks = re.sub(r'"url": ?".+}",', '', available_chunks)
# try to decode the suspected JSON
try:
available_json: JsonType = json.loads(available_chunks)
except json.JSONDecodeError:
# No JSON: this is the expected path. Do nothing and continue with the below.
pass
else:
# JSON was decoded - if there's an error, log it and report failure
if "error" in available_json:
logger.error(f"Send watch error: \"{available_json['error']}\"")
return False
# the list contains ~10-13 chunks of the stream at 2s intervals, # the list contains ~10-13 chunks of the stream at 2s intervals,
# pick the last chunk URL available. Ensure it's not the end-of-stream tag, # pick the last chunk URL available. Ensure it's not the end-of-stream tag,
# otherwise use the 2nd to last line. # otherwise use the 2nd to last line.
@@ -396,6 +411,3 @@ class Channel:
# without downloading the actual stream data # without downloading the actual stream data
async with self._twitch.request("HEAD", stream_chunk_url) as head_response: async with self._twitch.request("HEAD", stream_chunk_url) as head_response:
return head_response.status == 200 return head_response.status == 200
except aiohttp.InvalidURL as exc:
# Temporarily log the entire response into the output
raise MinerException(available_chunks) from exc