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
+35 -23
+35 -23
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,27 +377,37 @@ 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 = '' async with self._twitch.request(
"GET", stream_url, headers={"Connection": "close"}
) as chunks_response:
if chunks_response.status >= 400:
# if the stream goes OFFLINE, trying to get a list of chunks returns a 404
return False
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: try:
async with self._twitch.request( available_json: JsonType = json.loads(available_chunks)
"GET", stream_url, headers={"Connection": "close"} except json.JSONDecodeError:
) as chunks_response: # No JSON: this is the expected path. Do nothing and continue with the below.
if chunks_response.status >= 400: pass
# if the stream goes OFFLINE, trying to get a list of chunks returns a 404 else:
return False # JSON was decoded - if there's an error, log it and report failure
available_chunks = await chunks_response.text() if "error" in available_json:
# the list contains ~10-13 chunks of the stream at 2s intervals, logger.error(f"Send watch error: \"{available_json['error']}\"")
# pick the last chunk URL available. Ensure it's not the end-of-stream tag, return False
# otherwise use the 2nd to last line. # the list contains ~10-13 chunks of the stream at 2s intervals,
chunks_list: list[str] = available_chunks.strip().split("\n") # pick the last chunk URL available. Ensure it's not the end-of-stream tag,
selected_chunk: str = chunks_list[-1] # otherwise use the 2nd to last line.
if selected_chunk == "#EXT-X-ENDLIST": chunks_list: list[str] = available_chunks.strip().split("\n")
selected_chunk = chunks_list[-2] selected_chunk: str = chunks_list[-1]
stream_chunk_url: URLType = URLType(selected_chunk) if selected_chunk == "#EXT-X-ENDLIST":
# sending a HEAD request is enough to advance the drops, selected_chunk = chunks_list[-2]
# without downloading the actual stream data stream_chunk_url: URLType = URLType(selected_chunk)
async with self._twitch.request("HEAD", stream_chunk_url) as head_response: # sending a HEAD request is enough to advance the drops,
return head_response.status == 200 # without downloading the actual stream data
except aiohttp.InvalidURL as exc: async with self._twitch.request("HEAD", stream_chunk_url) as head_response:
# Temporarily log the entire response into the output return head_response.status == 200
raise MinerException(available_chunks) from exc