]> jfr.im git - yt-dlp.git/commitdiff
[update] Ability to set a maximum version for specific variants
authorpukkandan <redacted>
Wed, 29 Jun 2022 01:13:24 +0000 (06:43 +0530)
committerpukkandan <redacted>
Wed, 29 Jun 2022 01:13:24 +0000 (06:43 +0530)
.github/workflows/build.yml
yt_dlp/YoutubeDL.py
yt_dlp/update.py
yt_dlp/utils.py

index ca17a1e59cb90a7e240cff3e4f7e0a5c086c2dee..0c88319272719bb621126791426acee33a0e9c10 100644 (file)
@@ -449,6 +449,19 @@ jobs:
         asset_name: SHA2-512SUMS
         asset_content_type: text/plain
 
         asset_name: SHA2-512SUMS
         asset_content_type: text/plain
 
+    - name: Make Update spec
+      run: |
+        echo "# This file is used for regulating self-update" >> _update_spec
+    - name: Upload update spec
+      uses: actions/upload-release-asset@v1
+      env:
+        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+      with:
+        upload_url: ${{ needs.create_release.outputs.upload_url }}
+        asset_path: ./_update_spec
+        asset_name: _update_spec
+        asset_content_type: text/plain
+
     - name: Finalize release
       env:
         GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
     - name: Finalize release
       env:
         GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
index c6882d0d795b0cf78e06b09857e893a723595fef..9ebb0b82abbe0e034507766c053d2f17bbe6c546 100644 (file)
@@ -10,7 +10,6 @@
 import locale
 import operator
 import os
 import locale
 import operator
 import os
-import platform
 import random
 import re
 import shutil
 import random
 import re
 import shutil
     number_of_digits,
     orderedSet,
     parse_filesize,
     number_of_digits,
     orderedSet,
     parse_filesize,
-    platform_name,
     preferredencoding,
     prepend_extension,
     register_socks_protocols,
     preferredencoding,
     prepend_extension,
     register_socks_protocols,
     strftime_or_none,
     subtitles_filename,
     supports_terminal_sequences,
     strftime_or_none,
     subtitles_filename,
     supports_terminal_sequences,
+    system_identifier,
     timetuple_from_msec,
     to_high_limit_path,
     traverse_obj,
     timetuple_from_msec,
     to_high_limit_path,
     traverse_obj,
@@ -3656,17 +3655,7 @@ def get_encoding(stream):
                 with contextlib.suppress(Exception):
                     sys.exc_clear()
 
                 with contextlib.suppress(Exception):
                     sys.exc_clear()
 
-        def python_implementation():
-            impl_name = platform.python_implementation()
-            if impl_name == 'PyPy' and hasattr(sys, 'pypy_version_info'):
-                return impl_name + ' version %d.%d.%d' % sys.pypy_version_info[:3]
-            return impl_name
-
-        write_debug('Python version %s (%s %s) - %s' % (
-            platform.python_version(),
-            python_implementation(),
-            platform.architecture()[0],
-            platform_name()))
+        write_debug(system_identifier())
 
         exe_versions, ffmpeg_features = FFmpegPostProcessor.get_versions_and_features(self)
         ffmpeg_features = {key for key, val in ffmpeg_features.items() if val}
 
         exe_versions, ffmpeg_features = FFmpegPostProcessor.get_versions_and_features(self)
         ffmpeg_features = {key for key, val in ffmpeg_features.items() if val}
index c4214433798511ca17f224284d3a6ee2cd2f039e..9589443a70f289690d231245d2e7782269f5d227 100644 (file)
@@ -3,17 +3,25 @@
 import json
 import os
 import platform
 import json
 import os
 import platform
+import re
 import subprocess
 import sys
 from zipimport import zipimporter
 
 from .compat import functools  # isort: split
 from .compat import compat_realpath
 import subprocess
 import sys
 from zipimport import zipimporter
 
 from .compat import functools  # isort: split
 from .compat import compat_realpath
-from .utils import Popen, shell_quote, traverse_obj, version_tuple
+from .utils import (
+    Popen,
+    cached_method,
+    shell_quote,
+    system_identifier,
+    traverse_obj,
+    version_tuple,
+)
 from .version import __version__
 
 REPOSITORY = 'yt-dlp/yt-dlp'
 from .version import __version__
 
 REPOSITORY = 'yt-dlp/yt-dlp'
-API_URL = f'https://api.github.com/repos/{REPOSITORY}/releases/latest'
+API_URL = f'https://api.github.com/repos/{REPOSITORY}/releases'
 
 
 @functools.cache
 
 
 @functools.cache
@@ -79,9 +87,20 @@ def __init__(self, ydl):
         self.ydl = ydl
 
     @functools.cached_property
         self.ydl = ydl
 
     @functools.cached_property
-    def _new_version_info(self):
-        self.ydl.write_debug(f'Fetching release info: {API_URL}')
-        return json.loads(self.ydl.urlopen(API_URL).read().decode())
+    def _tag(self):
+        identifier = f'{detect_variant()} {system_identifier()}'
+        for line in self._download('_update_spec', 'latest').decode().splitlines():
+            if not line.startswith('lock '):
+                continue
+            _, tag, pattern = line.split(' ', 2)
+            if re.match(pattern, identifier):
+                return f'tags/{tag}'
+        return 'latest'
+
+    @cached_method
+    def _get_version_info(self, tag):
+        self.ydl.write_debug(f'Fetching release info: {API_URL}/{tag}')
+        return json.loads(self.ydl.urlopen(f'{API_URL}/{tag}').read().decode())
 
     @property
     def current_version(self):
 
     @property
     def current_version(self):
@@ -91,7 +110,7 @@ def current_version(self):
     @property
     def new_version(self):
         """Version of the latest release"""
     @property
     def new_version(self):
         """Version of the latest release"""
-        return self._new_version_info['tag_name']
+        return self._get_version_info(self._tag)['tag_name']
 
     @property
     def has_update(self):
 
     @property
     def has_update(self):
@@ -103,9 +122,8 @@ def filename(self):
         """Filename of the executable"""
         return compat_realpath(_get_variant_and_executable_path()[1])
 
         """Filename of the executable"""
         return compat_realpath(_get_variant_and_executable_path()[1])
 
-    def _download(self, name=None):
-        name = name or self.release_name
-        url = traverse_obj(self._new_version_info, (
+    def _download(self, name, tag):
+        url = traverse_obj(self._get_version_info(tag), (
             'assets', lambda _, v: v['name'] == name, 'browser_download_url'), get_all=False)
         if not url:
             raise Exception('Unable to find download URL')
             'assets', lambda _, v: v['name'] == name, 'browser_download_url'), get_all=False)
         if not url:
             raise Exception('Unable to find download URL')
@@ -123,7 +141,7 @@ def release_name(self):
     @functools.cached_property
     def release_hash(self):
         """Hash of the latest release"""
     @functools.cached_property
     def release_hash(self):
         """Hash of the latest release"""
-        hash_data = dict(ln.split()[::-1] for ln in self._download('SHA2-256SUMS').decode().splitlines())
+        hash_data = dict(ln.split()[::-1] for ln in self._download('SHA2-256SUMS', self._tag).decode().splitlines())
         return hash_data[self.release_name]
 
     def _report_error(self, msg, expected=False):
         return hash_data[self.release_name]
 
     def _report_error(self, msg, expected=False):
@@ -176,7 +194,7 @@ def update(self):
             return self._report_error('Unable to remove the old version')
 
         try:
             return self._report_error('Unable to remove the old version')
 
         try:
-            newcontent = self._download()
+            newcontent = self._download(self.release_name, self._tag)
         except OSError:
             return self._report_network_error('download latest version')
         except Exception:
         except OSError:
             return self._report_network_error('download latest version')
         except Exception:
index 40cefd62eb2de52f55afcdc6b9fce646901a8e90..9c9be5fe552b8f5f77f8c00cd2809020e84a6fc1 100644 (file)
@@ -18,6 +18,7 @@
 import http.client
 import http.cookiejar
 import importlib.util
 import http.client
 import http.cookiejar
 import importlib.util
+import inspect
 import io
 import itertools
 import json
 import io
 import itertools
 import json
@@ -1909,12 +1910,23 @@ def __str__(self):
 
 def platform_name():
     """ Returns the platform name as a str """
 
 def platform_name():
     """ Returns the platform name as a str """
-    res = platform.platform()
-    if isinstance(res, bytes):
-        res = res.decode(preferredencoding())
+    write_string('DeprecationWarning: yt_dlp.utils.platform_name is deprecated, use platform.platform instead')
+    return platform.platform()
 
 
-    assert isinstance(res, str)
-    return res
+
+@functools.cache
+def system_identifier():
+    python_implementation = platform.python_implementation()
+    if python_implementation == 'PyPy' and hasattr(sys, 'pypy_version_info'):
+        python_implementation += ' version %d.%d.%d' % sys.pypy_version_info[:3]
+
+    return 'Python %s (%s %s) - %s %s' % (
+        platform.python_version(),
+        python_implementation,
+        platform.architecture()[0],
+        platform.platform(),
+        format_field(join_nonempty(*platform.libc_ver(), delim=' '), None, '(%s)'),
+    )
 
 
 @functools.cache
 
 
 @functools.cache
@@ -5544,8 +5556,27 @@ def merge_headers(*dicts):
     return {k.title(): v for k, v in itertools.chain.from_iterable(map(dict.items, dicts))}
 
 
     return {k.title(): v for k, v in itertools.chain.from_iterable(map(dict.items, dicts))}
 
 
+def cached_method(f):
+    """Cache a method"""
+    signature = inspect.signature(f)
+
+    @functools.wraps(f)
+    def wrapper(self, *args, **kwargs):
+        bound_args = signature.bind(self, *args, **kwargs)
+        bound_args.apply_defaults()
+        key = tuple(bound_args.arguments.values())
+
+        if not hasattr(self, '__cached_method__cache'):
+            self.__cached_method__cache = {}
+        cache = self.__cached_method__cache.setdefault(f.__name__, {})
+        if key not in cache:
+            cache[key] = f(self, *args, **kwargs)
+        return cache[key]
+    return wrapper
+
+
 class classproperty:
 class classproperty:
-    """classmethod(property(func)) that works in py < 3.9"""
+    """property access for class methods"""
 
     def __init__(self, func):
         functools.update_wrapper(self, func)
 
     def __init__(self, func):
         functools.update_wrapper(self, func)