-
-
Notifications
You must be signed in to change notification settings - Fork 27
Expand file tree
/
Copy pathRemoteFile.py
More file actions
executable file
·158 lines (112 loc) · 4.69 KB
/
Copy pathRemoteFile.py
File metadata and controls
executable file
·158 lines (112 loc) · 4.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
from pathlib import Path
from requests import Response, get
from tenacity import retry, stop_after_attempt, wait_fixed, wait_exponential
from tinydb import where
from modules.Debug import log
from modules.PersistentDatabase import PersistentDatabase
class RemoteFile:
"""
This class describes a RemoteFile. A RemoteFile is a file that is
loaded from the TCM Card Types repository, and is necessary to allow
card types to utilize non-standard files that can be downloaded at
runtime alongside CardType classes. This class has no real
executable methods, and upon initialization attempts to download the
remote file if it DNE.
"""
"""Base URL to look for remote content at"""
BASE_URL = (
'https://github.com/CollinHeist/TitleCardMaker-CardTypes/raw/master'
)
"""Temporary directory all files will be downloaded into"""
TEMP_DIR = Path(__file__).parent / '.objects'
"""Database of assets that have been loaded already"""
LOADED_FILE = 'remote_assets.json'
__slots__ = ('loaded', 'remote_source', 'local_file', 'valid')
def __init__(self, username: str, filename: str) -> None:
"""
Construct a new RemoteFile object. This downloads the file for
the given user and file into the temporary directory of the
Maker.
Args:
username: Username containing the file.
filename: Filename of the file within the user's folder to
download.
"""
# Object validity to be updated
self.valid = True
# Get database of loaded assets
self.loaded = PersistentDatabase(self.LOADED_FILE)
# Remote font will be stored at github/username/filename
self.remote_source = f'{self.BASE_URL}/{username}/{filename}'
# The font fill will be downloaded and exist in the temporary directory
self.local_file = self.TEMP_DIR / username / filename.rsplit('/')[-1]
# Create parent folder structure if necessary
self.local_file.parent.mkdir(parents=True, exist_ok=True)
# If file has already been loaded this run, skip
if self.loaded.get(where('remote') == self.remote_source) is not None:
return None
# Download the remote file for local use
try:
self.download()
log.debug(f'Downloaded RemoteFile "{username}/{filename}"')
except Exception:
self.valid = False
log.exception(f'Could not download RemoteFile '
f'"{username}/{filename}"')
return None
try:
self.loaded.insert({'remote': self.remote_source})
except Exception:
pass
return None
def __str__(self) -> str:
"""
Returns a string representation of the object. This is just the
complete filepath for the locally downloaded file.
"""
return str(self.local_file.resolve())
def __repr__(self) -> str:
"""Returns an unambiguous string representation of the object."""
return (
f'<RemoteFile remote_source={self.remote_source}, local_file='
f'{self.local_file}, valid={self.valid}>'
)
def resolve(self) -> Path:
"""
Get the absolute path of the locally downloaded file.
Returns:
Path to the locally downloaded file.
"""
return self.local_file.resolve()
def exists(self) -> bool:
"""Wrapper for `Path.exists()` of the associated file."""
return self.local_file.exists()
@retry(stop=stop_after_attempt(3),
wait=wait_fixed(3)+wait_exponential(min=1, max=16))
def __get_remote_content(self) -> Response:
"""
Get the content at the remote source.
Returns:
Response object from this object's remote source.
"""
return get(self.remote_source, timeout=10)
def download(self) -> None:
"""
Download the specified remote file from the TCM CardTypes
GitHub, and write it to a temporary local file.
Raises:
ValueError: The Response is not OK.
"""
# Download remote file
content = self.__get_remote_content()
# Verify content is valid
if not content.ok:
raise ValueError('File does not exist')
# Write content to file
with self.local_file.open('wb') as file_handle:
file_handle.write(content.content)
@staticmethod
def reset_loaded_database() -> None:
"""Reset (clear) this class's database of loaded remote files."""
PersistentDatabase(RemoteFile.LOADED_FILE).reset()
log.debug(f'Reset PersistentDatabase[{RemoteFile.LOADED_FILE}]')