From 84d480adaf178d4ad651b8cfdba6432b71f5640a Mon Sep 17 00:00:00 2001 From: Retinue Bonnets Date: Wed, 20 May 2026 20:09:19 +0500 Subject: [PATCH] Fix subscription update: preserve base64 result and set User-Agent Two regressions broke subscription updates against typical providers: 1. In SubscriptionManager.successCallback, the plain-text fallback added in 88e447d ran unconditionally after the base64 try block, overwriting the correctly parsed share links with a single line of raw base64. Move it into the failure branch (with a "://" sanity check so pybase64's lenient decode of plain text doesn't slip through as a false positive), and report failure only when both decoders fail. 2. updateSubsByWebGET issued the request without a User-Agent header. Some providers respond with 503 to the default Qt UA. Identify ourselves as "Furious/" so the request goes through. --- Furious/Widget/UserServersQTableWidget.py | 52 +++++++++++++++-------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/Furious/Widget/UserServersQTableWidget.py b/Furious/Widget/UserServersQTableWidget.py index d49616d..c0e6623 100644 --- a/Furious/Widget/UserServersQTableWidget.py +++ b/Furious/Widget/UserServersQTableWidget.py @@ -208,34 +208,44 @@ class SubscriptionManager(WebGETManager): data = networkReply.readAll().data() + uris = None + lastException = None + try: - uris = list( - filter( - lambda x: x != '', - PyBase64Encoder.decode(data).decode().split('\n'), - ) - ) + decoded = PyBase64Encoder.decode(data).decode() except Exception as ex: # Any non-exit exceptions + lastException = ex + logger.error( f'parse base64 share link from \'{webURL}\' failed: {ex}. ' f'Try to fall back to plain text' ) + else: + # pybase64 decodes leniently and happily turns plain text into + # garbage bytes, so only accept the base64 result when it actually + # looks like share links. + if '://' in decoded: + uris = list(filter(lambda x: x != '', decoded.split('\n'))) - try: - uris = list( - filter( - lambda x: x != '', - data.decode().split('\n'), + if uris is None: + try: + uris = list( + filter( + lambda x: x != '', + data.decode().split('\n'), + ) ) - ) - except Exception as ex: - # Any non-exit exceptions + except Exception as ex: + # Any non-exit exceptions - logger.error(f'parse share link from \'{webURL}\' failed: {ex}') + lastException = ex - failureArgs.append({'error': classname(ex), **kwargs}) + logger.error(f'parse share link from \'{webURL}\' failed: {ex}') + + if uris is None: + failureArgs.append({'error': classname(lastException), **kwargs}) else: logger.info( f'update subs ({remark}, {webURL}) success. Got {len(uris)} share link' @@ -264,7 +274,15 @@ class SubscriptionManager(WebGETManager): logActionMessage = kwargs.pop('logActionMessage', False) - self.webGET(url, logActionMessage=logActionMessage, **kwargs) + # Some providers reject the default Qt User-Agent (e.g. with 503), + # so identify ourselves explicitly. + request = QNetworkRequest(QtCore.QUrl(url)) + request.setRawHeader( + b'User-Agent', + f'{APPLICATION_NAME}/{APPLICATION_VERSION}'.encode(), + ) + + self.webGET(request, logActionMessage=logActionMessage, **kwargs) def updateSubsByUnique(self, unique: str, **kwargs): depthMap = kwargs.get('depthMap', {'depth': 1})