Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package heroic-gogdl for openSUSE:Factory 
checked in at 2026-08-24 12:10:37
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/heroic-gogdl (Old)
 and      /work/SRC/openSUSE:Factory/.heroic-gogdl.new.1258 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "heroic-gogdl"

Mon Aug 24 12:10:37 2026 rev:9 rq:1373159 version:1.3.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/heroic-gogdl/heroic-gogdl.changes        
2026-06-08 14:24:20.262612969 +0200
+++ /work/SRC/openSUSE:Factory/.heroic-gogdl.new.1258/heroic-gogdl.changes      
2026-08-24 12:16:01.344397989 +0200
@@ -1,0 +2,11 @@
+Sat Aug 22 19:40:06 UTC 2026 - Jonatas Gonçalves <[email protected]>
+
+- Update to 1.3.0
+  * Set path property in ScummVM config file if we're running native ScummVM
+    by @CommandMC in #82
+  * Improve support for native DOSBox and ScummVM on macOS by @JKingweb in #85
+  * Fix 83 - IPv6 and Timeouts by @Moon-yungg in #86
+  * feat: cdn fallbacks by @imLinguin in d9eb7dc
+  * fix: cdn fallback on stream disconnection (HTTP 200) by @NicholasDymov in 
#88
+
+-------------------------------------------------------------------

Old:
----
  _scmsync.obsinfo
  heroic-gogdl-1.2.2.tar.gz

New:
----
  heroic-gogdl-1.3.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ heroic-gogdl.spec ++++++
--- /var/tmp/diff_new_pack.8wbVIL/_old  2026-08-24 12:16:02.215429199 +0200
+++ /var/tmp/diff_new_pack.8wbVIL/_new  2026-08-24 12:16:02.216429235 +0200
@@ -16,7 +16,7 @@
 #
 
 Name:             heroic-gogdl
-Version:          1.2.2
+Version:          1.3.0
 Release:          0
 Summary:          GOG download module for Heroic Games Launcher
 License:          GPL-3.0-only

++++++ heroic-gogdl-1.2.2.tar.gz -> heroic-gogdl-1.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/heroic-gogdl-1.2.2/gogdl/__init__.py 
new/heroic-gogdl-1.3.0/gogdl/__init__.py
--- old/heroic-gogdl-1.2.2/gogdl/__init__.py    2026-06-04 17:29:32.000000000 
+0200
+++ new/heroic-gogdl-1.3.0/gogdl/__init__.py    2026-08-07 16:20:08.000000000 
+0200
@@ -7,4 +7,4 @@
 
 
 
-version = "1.2.2"
+version = "1.3.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/heroic-gogdl-1.2.2/gogdl/auth.py 
new/heroic-gogdl-1.3.0/gogdl/auth.py
--- old/heroic-gogdl-1.2.2/gogdl/auth.py        2026-06-04 17:29:32.000000000 
+0200
+++ new/heroic-gogdl-1.3.0/gogdl/auth.py        2026-08-07 16:20:08.000000000 
+0200
@@ -5,6 +5,7 @@
 import os.path
 import requests
 import time
+from gogdl import net
 from gogdl import version
 
 CODE_URL = 
"https://auth.gog.com/token?client_id=46899977096215655&client_secret=9d85c43b1482497dbbce61f6e4aa173a433796eeae2ca8c5f6129f2dc4de46d9&grant_type=authorization_code&redirect_uri=https%3A%2F%2Fembed.gog.com%2Fon_login_success%3Forigin%3Dclient&code=";
@@ -14,7 +15,7 @@
 
 class AuthorizationManager:
     def __init__(self, config_path):
-        self.session = requests.session()
+        self.session = net.Session()
         self.logger = logging.getLogger("AUTH")
 
         self.config_path = config_path
@@ -120,7 +121,13 @@
         self.logger.debug("Handling cli")
 
         if arguments.authorization_code:
-            response = self.session.get(CODE_URL + 
arguments.authorization_code)
+            try:
+                response = self.session.get(CODE_URL + 
arguments.authorization_code)
+            except (requests.ConnectionError, requests.Timeout) as e:
+                # Don't log the exception itself because it contains client id 
and client secret
+                self.logger.error(f"Failed to reach GOG ({type(e).__name__})")
+                print(json.dumps({"error": True}))
+                return
 
             if not response.ok:
                 print(json.dumps({"error": True}))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/heroic-gogdl-1.2.2/gogdl/dl/workers/task_executor.py 
new/heroic-gogdl-1.3.0/gogdl/dl/workers/task_executor.py
--- old/heroic-gogdl-1.2.2/gogdl/dl/workers/task_executor.py    2026-06-04 
17:29:32.000000000 +0200
+++ new/heroic-gogdl-1.3.0/gogdl/dl/workers/task_executor.py    2026-08-07 
16:20:08.000000000 +0200
@@ -27,6 +27,7 @@
     UNAUTHORIZED = auto()
 
     MISSING_CHUNK = auto()
+    INCOMPLETE_READ = auto()
 
 
 @dataclass
@@ -110,33 +111,48 @@
         self.session.close()
         self.shared_memory.close()
 
-    def v2(self, task: DownloadTask2):
-        retries = 5 
-        urls = self.secure_links[task.product_id]
-
-        compressed_md5 = task.compressed_sum
-
-        endpoint = copy(urls[0])
+    def _get_download_url_v2(self, task, urls, index):
+        if len(urls) <= index:
+            index = len(urls) - 1
+        endpoint = copy(urls[index])
         if task.product_id != 'redist':
-            endpoint["parameters"]["path"] += 
f"/{dl_utils.galaxy_path(compressed_md5)}"
+            endpoint["parameters"]["path"] += 
f"/{dl_utils.galaxy_path(task.compressed_sum)}"
             url = dl_utils.merge_url_with_params(
                 endpoint["url_format"], endpoint["parameters"]
             )
         else:
-            endpoint["url"] += "/" + dl_utils.galaxy_path(compressed_md5)
+            endpoint["url"] += "/" + dl_utils.galaxy_path(task.compressed_sum)
             url = endpoint["url"]
+        return url
 
-        buffer = bytes()
-        compressed_sum = hashlib.md5()
-        download_size = 0
-        response = None
+    def _get_download_url_v1(self, urls):
+        if type(urls) == str:
+            url = urls
+        else:
+            endpoint = copy(urls[0])
+            endpoint["parameters"]["path"] += "/main.bin"
+            url = dl_utils.merge_url_with_params(
+                endpoint["url_format"], endpoint["parameters"]
+            )
+        return url
+    
+    def v2(self, task: DownloadTask2):
+        retries = 5 
+        urls = self.secure_links[task.product_id]
+
+        compressed_md5 = task.compressed_sum
+        preferred_endpoint = 0
+        url = self._get_download_url_v2(task, urls, preferred_endpoint)
+
+        fail_reason = None
         while retries > 0:
+            response = None
             buffer = bytes()
             compressed_sum = hashlib.md5()
             download_size = 0
             decompressor = zlib.decompressobj()
             try:
-                response = self.session.get(url, stream=True, timeout=10)
+                response = self.session.get(url, stream=True, timeout=(5, 15))
                 response.raise_for_status()
                 for chunk in response.iter_content(1024 * 512):
                     download_size += len(chunk)
@@ -144,19 +160,30 @@
                     decompressed = decompressor.decompress(chunk)
                     buffer += decompressed
                     self.speed_queue.put((len(chunk), len(decompressed)))
-
-            except Exception as e:
+            except (requests.exceptions.HTTPError, 
requests.exceptions.ConnectTimeout)  as e:
                 print("Connection failed", e)
-                if response and response.status_code == 401:
+                if response and response.status_code in [401, 403]:
                     self.results_queue.put(DownloadTaskResult(False, 
FailReason.UNAUTHORIZED, task))
                     print("Connection failed, unauthorized")
                     return
-                retries -= 1
+                else:
+                    fail_reason = FailReason.CONNECTION
+            except requests.exceptions.RequestException as e:
+                print("Connection failed", e)
+                fail_reason = FailReason.INCOMPLETE_READ
+            except Exception as e:
+                print("Connection failed", e)
+                fail_reason = FailReason.UNKNOWN
+            else:
+                break
+            preferred_endpoint += 1
+            if preferred_endpoint >= len(urls):
+                preferred_endpoint = 0
                 time.sleep(2)
-                continue
-            break
+            url = self._get_download_url_v2(task, urls, preferred_endpoint)
+            retries -= 1
         else:
-            self.results_queue.put(DownloadTaskResult(False, 
FailReason.CHECKSUM, task))
+            self.results_queue.put(DownloadTaskResult(False, fail_reason, 
task))
             return
 
         decompressed_size = 0
@@ -180,18 +207,12 @@
         urls = self.secure_links[task.product_id]
 
         response = None
-        if type(urls) == str:
-            url = urls
-        else:
-            endpoint = copy(urls[0])
-            endpoint["parameters"]["path"] += "/main.bin"
-            url = dl_utils.merge_url_with_params(
-                endpoint["url_format"], endpoint["parameters"]
-            )
+        url = self._get_download_url_v1(urls)
         range_header = dl_utils.get_range_header(task.offset, task.size)
 
         buffer = bytes()
         while retries > 0:
+            response = None
             buffer = bytes()
             try:
                 response = self.session.get(url, stream=True, timeout=10, 
headers={'Range': range_header})
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/heroic-gogdl-1.2.2/gogdl/launch.py 
new/heroic-gogdl-1.3.0/gogdl/launch.py
--- old/heroic-gogdl-1.2.2/gogdl/launch.py      2026-06-04 17:29:32.000000000 
+0200
+++ new/heroic-gogdl-1.3.0/gogdl/launch.py      2026-08-07 16:20:08.000000000 
+0200
@@ -1,3 +1,4 @@
+import configparser
 import os
 import json
 import sys
@@ -39,6 +40,20 @@
         pass
     return []
 
+def get_app_bundle_command(id: str) -> list[str]:
+    if sys.platform != "darwin":
+        return []
+    try:
+        p = subprocess.run(["mdfind", "kMDItemCFBundleIdentifier==", id], 
stdout=subprocess.PIPE, stderr=None)
+        if len(p.stdout) > 0:
+            bundle = p.stdout.split(b"\n")[0].decode("utf-8")
+            p = subprocess.run(["defaults", "read", bundle + 
"/Contents/Info.plist", "CFBundleExecutable"], stdout=subprocess.PIPE, 
stderr=None)
+            if len(p.stdout) > 0:
+                bin = p.stdout.split(b"\n")[0].decode("utf-8")
+                return [bundle + "/Contents/MacOS/" + bin]
+    except FileNotFoundError:
+        pass
+    return []
 
 # Supports launching linux builds
 def launch(arguments, unknown_args):
@@ -95,21 +110,44 @@
         if sys.platform != "win32" and arguments.platform == 'windows' and not 
arguments.override_exe:
             if "scummvm.exe" in executable.lower():
                 flatpak_scummvm = get_flatpak_command("org.scummvm.ScummVM")
+                bundle_scummvm = get_app_bundle_command("org.scummvm.app")
                 native_scummvm = shutil.which("scummvm")
                 if native_scummvm:
                     native_scummvm = [native_scummvm]
             
-                native_runner = flatpak_scummvm or native_scummvm
+                native_runner = flatpak_scummvm or bundle_scummvm or 
native_scummvm
                 if native_runner:
                     wrapper = native_runner
                     executable = None
+                    # ScummVM games require a "path" option to be set in their 
configuration file (pointing to the
+                    # game installation dir). This path is usually set by 
ScriptInterpreter, but since SI is a Windows
+                    # application, this path will be wrong. Open the config 
file and update the path
+                    config_file = next((
+                        arg
+                        for i, arg in enumerate(launch_arguments)
+                        if launch_arguments[i-1] == '-c'
+                    ), None)
+                    config_section = launch_arguments[-1]
+                    if config_file and config_section:
+                        full_config_file = os.path.join(working_dir, 
config_file)
+                        config = configparser.ConfigParser()
+                        config.read(full_config_file)
+                        config.set(config_section, 'path', arguments.path)
+                        with open(full_config_file, 'w') as f:
+                            config.write(f)
             elif "dosbox.exe" in executable.lower():
                 flatpak_dosbox = 
get_flatpak_command("io.github.dosbox-staging")
-                native_dosbox= shutil.which("dosbox")
-                if native_dosbox:
-                    native_dosbox = [native_dosbox]
-                
-                native_runner = flatpak_dosbox or native_dosbox
+                bundle_dosbox = 
get_app_bundle_command("io.github.dosbox-staging")
+                for candidate in ["dosbox-staging", "dosbox"]:
+                    # Most distributions prefer "dosbox" for DOSBox Staging's
+                    #  binary and let different DOSBox variants conflict, but
+                    #  Homebrew in particular uses "dosbox-staging". As the
+                    #  latter is more specific we try that first.
+                    native_dosbox= shutil.which(candidate)
+                    if native_dosbox:
+                        native_dosbox = [native_dosbox]
+                        break
+                native_runner = flatpak_dosbox or bundle_dosbox or 
native_dosbox
                 if native_runner:
                     wrapper = native_runner
                     executable = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/heroic-gogdl-1.2.2/gogdl/net.py 
new/heroic-gogdl-1.3.0/gogdl/net.py
--- old/heroic-gogdl-1.2.2/gogdl/net.py 1970-01-01 01:00:00.000000000 +0100
+++ new/heroic-gogdl-1.3.0/gogdl/net.py 2026-08-07 16:20:08.000000000 +0200
@@ -0,0 +1,13 @@
+# Add request timeouts. Matters when ipv6 is given by ISP but not routed
+# python will automatically fallback to ipv4 when the ipv6 request timeouts
+import requests
+
+# connect, read
+TIMEOUT = (10, 30)
+
+
+class Session(requests.Session):
+    def request(self, method, url, **kwargs):
+        if kwargs.get("timeout") is None:
+            kwargs["timeout"] = TIMEOUT
+        return super().request(method, url, **kwargs)

Reply via email to