| 119 | return self._length |
| 120 | |
| 121 | def read(self, ll: int | None = None) -> bytes: |
| 122 | if self._force_download: |
| 123 | return self.read_aux(ll=ll) |
| 124 | |
| 125 | file_begin = self._pos |
| 126 | file_end = self._pos + ll if ll is not None else self.get_length() |
| 127 | assert file_end != -1, f"Remote file is empty or doesn't exist: {self._url}" |
| 128 | # We have to align with chunks we store. Position is the begginiing of the latest chunk that starts before or at our file |
| 129 | position = (file_begin // CHUNK_SIZE) * CHUNK_SIZE |
| 130 | response = b"" |
| 131 | while True: |
| 132 | self._pos = position |
| 133 | chunk_number = self._pos / CHUNK_SIZE |
| 134 | file_name = hash_url(self._url) + "_" + str(chunk_number) |
| 135 | full_path = os.path.join(Paths.download_cache_root(), str(file_name)) |
| 136 | data = None |
| 137 | # If we don't have a file, download it |
| 138 | if not os.path.exists(full_path): |
| 139 | data = self.read_aux(ll=CHUNK_SIZE) |
| 140 | with atomic_write(full_path, mode="wb", overwrite=True) as new_cached_file: |
| 141 | new_cached_file.write(data) |
| 142 | prune_cache(file_name) |
| 143 | else: |
| 144 | with open(full_path, "rb") as cached_file: |
| 145 | data = cached_file.read() |
| 146 | |
| 147 | response += data[max(0, file_begin - position): min(CHUNK_SIZE, file_end - position)] |
| 148 | |
| 149 | position += CHUNK_SIZE |
| 150 | if position >= file_end: |
| 151 | self._pos = file_end |
| 152 | return response |
| 153 | |
| 154 | def read_aux(self, ll: int | None = None) -> bytes: |
| 155 | if ll is None: |