ytptube/app/DataStore.py
2024-02-02 18:07:24 +03:00

144 lines
4.5 KiB
Python

from collections import OrderedDict
import copy
from datetime import datetime, timezone
from email.utils import formatdate
import json
from sqlite3 import Connection
from Utils import calcDownloadPath
from Config import Config
from Download import Download
from ItemDTO import ItemDTO
class DataStore:
"""
Persistent queue.
"""
type: str = None
dict: OrderedDict[str, Download] = None
config: Config = None
connection: Connection
def __init__(self, type: str, connection: Connection):
self.dict = OrderedDict()
self.type = type
self.config = Config.get_instance()
self.connection = connection
def load(self) -> None:
for id, item in self.saved_items():
self.dict.update({id: Download(
info=item,
download_dir=calcDownloadPath(basePath=self.config.download_path, folder=item.folder),
temp_dir=self.config.temp_path,
output_template_chapter=self.config.output_template_chapter,
default_ytdl_opts=self.config.ytdl_options)
})
def exists(self, key: str = None, url: str = None) -> bool:
if not key and not url:
raise KeyError('key or url must be provided.')
if key and key in self.dict:
return True
for i in self.dict:
if (key and self.dict[i].info._id == key) or (url and self.dict[i].info.url == url):
return True
return False
def get(self, key: str, url: str = None) -> Download:
if not key and not url:
raise KeyError('key or url must be provided.')
for i in self.dict:
if (key and self.dict[i].info._id == key) or (url and self.dict[i].info.url == url):
return self.dict[i]
raise KeyError(f'{key=} or {url=} not found.')
def items(self) -> list[tuple[str, Download]]:
return self.dict.items()
def saved_items(self) -> list[tuple[str, ItemDTO]]:
items: list[tuple[str, ItemDTO]] = []
cursor = self.connection.execute(
f'SELECT "id", "data", "created_at" FROM "history" WHERE "type" = ? ORDER BY "created_at" ASC',
(self.type,)
)
for row in cursor:
rowDate = datetime.strptime(row['created_at'], '%Y-%m-%d %H:%M:%S')
data: dict = json.loads(row['data'])
key: str = data.pop('_id')
item: ItemDTO = ItemDTO(**data)
item._id = key
item.datetime = formatdate(rowDate.replace(tzinfo=timezone.utc).timestamp())
items.append((row['id'], item))
return items
def put(self, value: Download) -> Download:
self.dict.update({value.info._id: value})
self._updateStoreItem(self.type, value.info)
return self.dict[value.info._id]
def delete(self, key: str) -> None:
self.dict.pop(key, None)
self._deleteStoreItem(key)
def next(self) -> tuple[str, Download]:
return next(iter(self.dict.items()))
def empty(self):
return not bool(self.dict)
def hasDownloads(self):
if 0 == len(self.dict):
return False
for key in self.dict:
if self.dict[key].started() is False:
return True
return False
def getNextDownload(self) -> Download:
for key in self.dict:
if self.dict[key].started() is False and self.dict[key].is_canceled() is False:
return self.dict[key]
return None
def _updateStoreItem(self, type: str, item: ItemDTO) -> None:
sqlStatement = """
INSERT INTO "history" ("id", "type", "url", "data")
VALUES (?, ?, ?, ?)
ON CONFLICT DO UPDATE SET "type" = ?, "url" = ?, "data" = ?, created_at = ?
"""
stored = copy.deepcopy(item)
if hasattr(stored, 'datetime'):
try:
delattr(stored, 'datetime')
except AttributeError:
pass
if hasattr(stored, 'live_in') and stored.status == 'finished':
try:
delattr(stored, 'live_in')
except AttributeError:
pass
self.connection.execute(sqlStatement.strip(), (
stored._id, type, stored.url, stored.json(), type, stored.url,
stored.json(), datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S')
))
def _deleteStoreItem(self, key: str) -> None:
self.connection.execute('DELETE FROM "history" WHERE "type" = ? AND "id" = ?', (self.type, key,))