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