music-kraken-core/src/music_kraken/objects/target.py

121 lines
3.4 KiB
Python
Raw Normal View History

2023-02-25 21:16:32 +00:00
from pathlib import Path
2023-06-15 16:22:00 +00:00
from typing import List, Tuple, TextIO
2023-06-22 10:44:46 +00:00
import logging
2023-04-04 18:58:22 +00:00
2023-03-31 07:47:03 +00:00
import requests
2023-04-04 15:20:27 +00:00
from tqdm import tqdm
2023-02-25 21:16:32 +00:00
2023-12-19 21:11:46 +00:00
from .parents import OuterProxy
2023-09-10 15:27:07 +00:00
from ..utils.config import main_settings, logging_settings
2023-09-13 16:55:04 +00:00
from ..utils.string_processing import fit_to_file_system
2023-02-25 21:16:32 +00:00
2023-06-22 10:44:46 +00:00
LOGGER = logging.getLogger("target")
2023-12-19 21:11:46 +00:00
class Target(OuterProxy):
2023-02-25 21:16:32 +00:00
"""
create somehow like that
```python
# I know path is pointless, and I will change that (don't worry about backwards compatibility there)
Target(file="song.mp3", path="~/Music/genre/artist/album")
```
"""
2023-12-20 08:55:09 +00:00
file: str
path: str
_default_factories = {
"file": str,
"path": str,
}
2023-09-14 21:35:37 +00:00
SIMPLE_STRING_ATTRIBUTES = {
"_file": None,
"_path": None
}
2023-09-14 21:35:37 +00:00
COLLECTION_STRING_ATTRIBUTES = tuple()
2023-02-25 21:16:32 +00:00
def __init__(
self,
file: str = None,
path: str = None,
dynamic: bool = False,
relative_to_music_dir: bool = False
) -> None:
2023-03-30 12:39:28 +00:00
super().__init__(dynamic=dynamic)
2023-09-13 16:55:04 +00:00
self._file: Path = Path(fit_to_file_system(file))
self._path: Path = fit_to_file_system(Path(main_settings["music_directory"], path) if relative_to_music_dir else Path(path))
2023-02-25 21:16:32 +00:00
self.is_relative_to_music_dir: bool = relative_to_music_dir
2023-03-30 12:39:28 +00:00
def __repr__(self) -> str:
return str(self.file_path)
2023-02-25 21:16:32 +00:00
@property
def file_path(self) -> Path:
return Path(self._path, self._file)
@property
def indexing_values(self) -> List[Tuple[str, object]]:
return [('filepath', self.file_path)]
2023-04-04 15:54:05 +00:00
@property
def exists(self) -> bool:
2023-03-30 14:10:48 +00:00
return self.file_path.is_file()
2023-04-05 09:54:02 +00:00
@property
def size(self) -> int:
"""
returns the size the downloaded autio takes up in bytes
returns 0 if the file doesn't exsit
"""
if not self.exists:
return 0
return self.file_path.stat().st_size
2023-04-04 15:54:05 +00:00
def create_path(self):
self._path.mkdir(parents=True, exist_ok=True)
2023-04-04 15:54:05 +00:00
2023-03-30 13:28:23 +00:00
def copy_content(self, copy_to: "Target"):
if not self.exists:
2023-06-22 10:44:46 +00:00
LOGGER.warning(f"No file exists at: {self.file_path}")
2023-03-30 13:28:23 +00:00
return
2023-04-04 15:54:05 +00:00
2023-03-30 13:28:23 +00:00
with open(self.file_path, "rb") as read_from:
copy_to.create_path()
2023-03-31 07:54:31 +00:00
with open(copy_to.file_path, "wb") as write_to:
2023-03-30 13:28:23 +00:00
write_to.write(read_from.read())
2023-03-31 07:47:03 +00:00
def stream_into(self, r: requests.Response, desc: str = None) -> bool:
if r is None:
return False
2023-04-04 15:54:05 +00:00
2023-03-31 07:47:03 +00:00
self.create_path()
2023-04-04 15:54:05 +00:00
2023-03-31 07:47:03 +00:00
total_size = int(r.headers.get('content-length'))
2023-04-04 15:54:05 +00:00
with open(self.file_path, 'wb') as f:
try:
2023-04-04 15:20:27 +00:00
"""
https://en.wikipedia.org/wiki/Kilobyte
> The internationally recommended unit symbol for the kilobyte is kB.
"""
with tqdm(total=total_size, unit='B', unit_scale=True, unit_divisor=1024, desc=desc) as t:
2023-09-10 15:27:07 +00:00
for chunk in r.iter_content(chunk_size=main_settings["chunk_size"]):
2023-04-04 15:54:05 +00:00
size = f.write(chunk)
t.update(size)
2023-04-04 18:58:22 +00:00
return True
2023-04-04 15:54:05 +00:00
except requests.exceptions.Timeout:
2023-09-10 15:27:07 +00:00
logging_settings["download_logger"].error("Stream timed out.")
return False
2023-06-15 16:22:00 +00:00
def open(self, file_mode: str, **kwargs) -> TextIO:
return self.file_path.open(file_mode, **kwargs)
2023-05-25 09:21:39 +00:00
def delete(self):
self.file_path.unlink(missing_ok=True)