FEAT: add auto clear env variable
This commit is contained in:
parent
28207bcd41
commit
4e86729206
5 changed files with 66 additions and 3 deletions
7
FAQ.md
7
FAQ.md
|
|
@ -47,6 +47,7 @@ or the `environment:` section in `compose.yaml` file.
|
|||
| YTP_ALLOW_INTERNAL_URLS | Allow requests to internal URLs | `false` |
|
||||
| YTP_SIMPLE_MODE | Switch default interface to Simple mode. | `false` |
|
||||
| YTP_STATIC_UI_PATH | Path to custom static UI files. | `(not_set)` |
|
||||
| YTP_AUTO_CLEAR_HISTORY_DAYS | Number of days after which completed download history is cleared. | `0` |
|
||||
|
||||
> [!NOTE]
|
||||
> To raise the maximum workers for specific extractor, you need to add a ENV variable that follows the pattern `YTP_MAX_WORKERS_FOR_<EXTRACTOR_NAME>`.
|
||||
|
|
@ -54,8 +55,12 @@ or the `environment:` section in `compose.yaml` file.
|
|||
> The limit should not exceed the `YTP_MAX_WORKERS` value as it will be ignored.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> The env variable `YTP_SIMPLE_MODE` only control what being displayed for first time visitor, the users can still switch between the two modes via the WebUI settings page.
|
||||
> The env variable `YTP_SIMPLE_MODE` only control what being displayed for first time visitor, the users can still switch between the two modes via the WebUI settings page.
|
||||
|
||||
## Notes about YTP_AUTO_CLEAR_HISTORY_DAYS
|
||||
|
||||
- `0` days means no automatic clearing of the download history. lowest value that will trigger the clearing is `1` day.
|
||||
- This setting will **NOT** delete the downloaded files, it will only clear the history from the database.
|
||||
|
||||
# Browser extensions & bookmarklets
|
||||
|
||||
|
|
|
|||
|
|
@ -140,6 +140,15 @@ class DownloadQueue(metaclass=Singleton):
|
|||
func=self._check_live,
|
||||
id=f"{__class__.__name__}.{__class__._check_live.__name__}",
|
||||
)
|
||||
|
||||
if self.config.auto_clear_history_days > 0:
|
||||
Scheduler.get_instance().add(
|
||||
# timer="8 */1 * * *",
|
||||
timer="* * * * *",
|
||||
func=self._delete_old_history,
|
||||
id=f"{__class__.__name__}.{__class__._delete_old_history.__name__}",
|
||||
)
|
||||
|
||||
# app.on_shutdown.append(self.on_shutdown)
|
||||
|
||||
async def test(self) -> bool:
|
||||
|
|
@ -1262,6 +1271,48 @@ class DownloadQueue(metaclass=Singleton):
|
|||
LOG.exception(e)
|
||||
LOG.error(f"Failed to retry item '{item_ref}'. {e!s}")
|
||||
|
||||
async def _delete_old_history(self) -> None:
|
||||
"""
|
||||
Automatically delete old download history based on user specified days.
|
||||
0 or negative value disables this feature.
|
||||
"""
|
||||
if self.config.auto_clear_history_days < 0 or self.is_paused() or self.done.empty():
|
||||
return
|
||||
|
||||
cutoff_date: datetime = datetime.now(UTC) - timedelta(days=self.config.auto_clear_history_days)
|
||||
items_to_delete: list[tuple[str, ItemDTO]] = []
|
||||
|
||||
for key, download in self.done.items():
|
||||
info: ItemDTO = download.info
|
||||
if not info or not info.timestamp:
|
||||
continue
|
||||
|
||||
if "finished" != info.status or not info.filename:
|
||||
continue
|
||||
|
||||
try:
|
||||
timestamp_seconds: float = info.timestamp / 1e9
|
||||
item_datetime: datetime = datetime.fromtimestamp(timestamp_seconds, tz=UTC)
|
||||
if item_datetime < cutoff_date:
|
||||
items_to_delete.append((key, info))
|
||||
except (OSError, ValueError, OverflowError) as e:
|
||||
LOG.error(f"Failed to parse timestamp '{info.timestamp}' for item '{info.title}': {e}")
|
||||
|
||||
titles: list[str] = []
|
||||
for key, info in items_to_delete:
|
||||
item_name: str = info.title or info.id or info._id
|
||||
self._notify.emit(
|
||||
Events.ITEM_DELETED,
|
||||
data=info,
|
||||
title="Download Cleared",
|
||||
message=f"'{item_name}' record removed from history.",
|
||||
)
|
||||
titles.append(item_name)
|
||||
self.done.delete(key)
|
||||
|
||||
if titles:
|
||||
LOG.info(f"Automatically cleared '{', '.join(titles)}' from download history due to age.")
|
||||
|
||||
def _handle_task_exception(self, task: asyncio.Task) -> None:
|
||||
if task.cancelled():
|
||||
return
|
||||
|
|
|
|||
|
|
@ -482,6 +482,9 @@ def check_id(file: Path) -> bool | str:
|
|||
id: str | None = match.groupdict().get("id")
|
||||
|
||||
try:
|
||||
if not file.parent.exists():
|
||||
return False
|
||||
|
||||
for f in file.parent.iterdir():
|
||||
if id not in f.stem:
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -192,6 +192,9 @@ class Config(metaclass=Singleton):
|
|||
playlist_items_concurrency: int = 4
|
||||
"""The number of concurrent playlist items to be processed at same time."""
|
||||
|
||||
auto_clear_history_days: int = 0
|
||||
"""Number of days after which completed download history is automatically cleared. 0 to disable."""
|
||||
|
||||
pictures_backends: list[str] = [
|
||||
"https://unsplash.it/1920/1080?random",
|
||||
"https://picsum.photos/1920/1080",
|
||||
|
|
@ -230,6 +233,7 @@ class Config(metaclass=Singleton):
|
|||
"playlist_items_concurrency",
|
||||
"download_path_depth",
|
||||
"download_info_expires",
|
||||
"auto_clear_history_days",
|
||||
)
|
||||
"The variables that are integers."
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@
|
|||
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
<div class="navbar-item has-dropdown" v-if="config.app.file_logging || config.app.console_enabled">
|
||||
<div class="navbar-item has-dropdown" v-if="config.app?.file_logging || config.app?.console_enabled">
|
||||
<a class="navbar-link" @click="(e: MouseEvent) => openMenu(e)">
|
||||
<span class="icon"><i class="fas fa-tools" /></span>
|
||||
<span>Other</span>
|
||||
|
|
@ -111,7 +111,7 @@
|
|||
|
||||
<div class="navbar-dropdown">
|
||||
<NuxtLink class="navbar-item" to="/logs" @click.prevent="(e: MouseEvent) => changeRoute(e)"
|
||||
v-if="config.app.file_logging">
|
||||
v-if="config.app?.file_logging">
|
||||
<span class="icon"><i class="fa-solid fa-file-lines" /></span>
|
||||
<span>Logs</span>
|
||||
</NuxtLink>
|
||||
|
|
|
|||
Loading…
Reference in a new issue