]>
Commit | Line | Data |
---|---|---|
19a03940 | 1 | import contextlib |
a0e07d31 | 2 | import errno |
a0e07d31 PH |
3 | import json |
4 | import os | |
5 | import re | |
6 | import shutil | |
7 | import traceback | |
8 | ||
f8271158 | 9 | from .utils import expand_path, write_json_file |
a0e07d31 PH |
10 | |
11 | ||
86e5f3ed | 12 | class Cache: |
a0e07d31 PH |
13 | def __init__(self, ydl): |
14 | self._ydl = ydl | |
15 | ||
16 | def _get_root_dir(self): | |
17 | res = self._ydl.params.get('cachedir') | |
18 | if res is None: | |
ac668111 | 19 | cache_root = os.getenv('XDG_CACHE_HOME', '~/.cache') |
7a5c1cfe | 20 | res = os.path.join(cache_root, 'yt-dlp') |
590bc6f6 | 21 | return expand_path(res) |
a0e07d31 PH |
22 | |
23 | def _get_cache_fn(self, section, key, dtype): | |
674c869a PH |
24 | assert re.match(r'^[a-zA-Z0-9_.-]+$', section), \ |
25 | 'invalid section %r' % section | |
26 | assert re.match(r'^[a-zA-Z0-9_.-]+$', key), 'invalid key %r' % key | |
a0e07d31 | 27 | return os.path.join( |
86e5f3ed | 28 | self._get_root_dir(), section, f'{key}.{dtype}') |
a0e07d31 PH |
29 | |
30 | @property | |
31 | def enabled(self): | |
32 | return self._ydl.params.get('cachedir') is not False | |
33 | ||
34 | def store(self, section, key, data, dtype='json'): | |
35 | assert dtype in ('json',) | |
36 | ||
37 | if not self.enabled: | |
38 | return | |
39 | ||
40 | fn = self._get_cache_fn(section, key, dtype) | |
41 | try: | |
42 | try: | |
43 | os.makedirs(os.path.dirname(fn)) | |
44 | except OSError as ose: | |
45 | if ose.errno != errno.EEXIST: | |
46 | raise | |
e6f21b3d | 47 | self._ydl.write_debug(f'Saving {section}.{key} to cache') |
a0e07d31 PH |
48 | write_json_file(data, fn) |
49 | except Exception: | |
50 | tb = traceback.format_exc() | |
86e5f3ed | 51 | self._ydl.report_warning(f'Writing cache to {fn!r} failed: {tb}') |
a0e07d31 PH |
52 | |
53 | def load(self, section, key, dtype='json', default=None): | |
54 | assert dtype in ('json',) | |
55 | ||
56 | if not self.enabled: | |
57 | return default | |
58 | ||
59 | cache_fn = self._get_cache_fn(section, key, dtype) | |
19a03940 | 60 | with contextlib.suppress(OSError): |
a0e07d31 | 61 | try: |
86e5f3ed | 62 | with open(cache_fn, encoding='utf-8') as cachef: |
e6f21b3d | 63 | self._ydl.write_debug(f'Loading {section}.{key} from cache') |
a0e07d31 PH |
64 | return json.load(cachef) |
65 | except ValueError: | |
66 | try: | |
67 | file_size = os.path.getsize(cache_fn) | |
86e5f3ed | 68 | except OSError as oe: |
a0e07d31 | 69 | file_size = str(oe) |
86e5f3ed | 70 | self._ydl.report_warning(f'Cache retrieval from {cache_fn} failed ({file_size})') |
a0e07d31 PH |
71 | |
72 | return default | |
73 | ||
74 | def remove(self): | |
75 | if not self.enabled: | |
76 | self._ydl.to_screen('Cache is disabled (Did you combine --no-cache-dir and --rm-cache-dir?)') | |
77 | return | |
78 | ||
79 | cachedir = self._get_root_dir() | |
80 | if not any((term in cachedir) for term in ('cache', 'tmp')): | |
81 | raise Exception('Not removing directory %s - this does not look like a cache dir' % cachedir) | |
82 | ||
83 | self._ydl.to_screen( | |
84 | 'Removing cache dir %s .' % cachedir, skip_eol=True) | |
85 | if os.path.exists(cachedir): | |
86 | self._ydl.to_screen('.', skip_eol=True) | |
87 | shutil.rmtree(cachedir) | |
88 | self._ydl.to_screen('.') |