Skip to content

Commit 1189d31

Browse files
authored
Merge pull request #538 from arabcoders/dev
Feat: add flag to ignore already archived items from showing in download history.
2 parents 163be08 + 4a3f031 commit 1189d31

File tree

10 files changed

+128
-131
lines changed

10 files changed

+128
-131
lines changed

FAQ.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ or the `environment:` section in `compose.yaml` file.
5555
| YTP_AUTO_CLEAR_HISTORY_DAYS | Number of days after which completed download history is cleared. | `0` |
5656
| YTP_DEFAULT_PAGINATION | The default number of items per page for history. | `50` |
5757
| YTP_TASK_HANDLER_RANDOM_DELAY | The maximum random delay in seconds before starting a task handler. | `60` |
58+
| YTP_IGNORE_ARCHIVED_ITEMS | Don't report archived items in the download history. | `false` |
5859

5960
> [!NOTE]
6061
> 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>`.

app/library/DownloadQueue.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ async def add(self, item: Item, already: set | None = None, entry: dict | None =
734734
# This sometimes can be different from the final extracted ID, so we need to verify again after extraction.
735735
if archive_id and item.is_archived():
736736
store_type, dlInfo = await self.get_item(archive_id=archive_id)
737-
if not store_type:
737+
if not store_type and not self.config.ignore_archived_items:
738738
dlInfo = Download(
739739
info=ItemDTO(
740740
id=archive_id.split()[1],
@@ -763,7 +763,7 @@ async def add(self, item: Item, already: set | None = None, entry: dict | None =
763763
)
764764
return {"status": "ok"}
765765

766-
message: str = f"The URL '{item.url}' is already downloaded and recorded in archive."
766+
message: str = f"The URL '{item.url}':'{archive_id}' is already downloaded and recorded in archive."
767767
LOG.warning(message)
768768
self._notify.emit(
769769
Events.LOG_INFO, data={"preset": item.preset}, title="Already Downloaded", message=message
@@ -827,7 +827,7 @@ async def add(self, item: Item, already: set | None = None, entry: dict | None =
827827
if store_type:
828828
break
829829

830-
if not store_type:
830+
if not store_type and not self.config.ignore_archived_items:
831831
new_archive_id = new_archive_id or extra_ids.pop(0)
832832
dlInfo = Download(
833833
info=ItemDTO(
@@ -855,7 +855,7 @@ async def add(self, item: Item, already: set | None = None, entry: dict | None =
855855
)
856856
return {"status": "ok"}
857857

858-
message: str = f"The URL '{item.url}' is already downloaded and recorded in archive."
858+
message: str = f"The URL '{item.url}':'{archive_ids.pop(0)}' is already downloaded and recorded in archive."
859859
LOG.warning(message)
860860
self._notify.emit(
861861
Events.LOG_INFO, data={"preset": item.preset}, title="Already Downloaded", message=message

app/library/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ class Config(metaclass=Singleton):
216216
task_handler_random_delay: float = 60.0
217217
"""The maximum random delay in seconds before starting a task handler."""
218218

219+
ignore_archived_items: bool = False
220+
"""Dont report archived items in the download history."""
221+
219222
pictures_backends: list[str] = [
220223
"https://unsplash.it/1920/1080?random",
221224
"https://picsum.photos/1920/1080",
@@ -280,6 +283,7 @@ class Config(metaclass=Singleton):
280283
"temp_disabled",
281284
"allow_internal_urls",
282285
"simple_mode",
286+
"ignore_archived_items",
283287
)
284288
"The variables that are booleans."
285289

ui/app/components/History.vue

Lines changed: 33 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,48 @@
11
<template>
2-
<div class="columns is-multiline is-mobile has-text-centered" v-if="hasItems">
3-
<div class="column is-half-mobile">
4-
<button type="button" class="button is-fullwidth is-ghost is-inverted"
5-
@click="masterSelectAll = !masterSelectAll">
6-
<span v-if="selectedElms.length > 0" class="mr-2 tag is-danger">
7-
{{ selectedElms.length }}
2+
<div class="columns is-multiline is-mobile has-text-centered is-justify-content-flex-end" v-if="hasItems">
3+
<div class="column is-narrow">
4+
<button type="button" class="button is-fullwidth" @click="masterSelectAll = !masterSelectAll"
5+
:class="{ 'has-text-primary': !masterSelectAll, 'has-text-danger': masterSelectAll }">
6+
<span class="icon">
7+
<i :class="!masterSelectAll ? 'fa-regular fa-square-check' : 'fa-regular fa-square'" />
88
</span>
9-
<span class="icon-text is-block">
10-
<span class="icon">
11-
<i :class="!masterSelectAll ? 'fa-regular fa-square-check' : 'fa-regular fa-square'" />
12-
</span>
13-
<span v-if="!masterSelectAll">Select All</span>
14-
<span v-else>Unselect All</span>
9+
<span v-if="!masterSelectAll">Select</span>
10+
<span v-else>Unselect</span>
11+
<span v-if="selectedElms.length > 0">
12+
&nbsp;(<u class="has-text-danger">{{ selectedElms.length }}</u>)
1513
</span>
1614
</button>
1715
</div>
18-
<div class="column is-half-mobile">
19-
<button type="button" class="button is-fullwidth is-link" @click="downloadSelected"
20-
:disabled="!hasDownloaded || !hasSelected"
21-
v-tooltip="!hasSelected || !hasDownloaded ? '' : 'Download items as zip'">
22-
<span class="icon-text is-block">
16+
<div class="column is-2-tablet is-5-mobile">
17+
<Dropdown label="Actions" icons="fa-solid fa-list">
18+
<a class="dropdown-item has-text-link" @click="(hasDownloaded && hasSelected) ? downloadSelected() : null"
19+
:style="{ opacity: (!hasDownloaded || !hasSelected) ? 0.5 : 1, cursor: (!hasDownloaded || !hasSelected) ? 'not-allowed' : 'pointer' }"
20+
v-tooltip="!hasSelected || !hasDownloaded ? '' : 'Download items as zip'">
2321
<span class="icon"><i class="fa-solid fa-compress-alt" /></span>
2422
<span>Download</span>
25-
</span>
26-
</button>
27-
</div>
28-
<div class="column is-half-mobile">
29-
<button type="button" class="button is-fullwidth is-danger" @click="deleteSelectedItems" :disabled="!hasSelected">
30-
<span class="icon-text is-block">
23+
</a>
24+
<a class="dropdown-item has-text-danger" @click="hasSelected ? deleteSelectedItems() : null"
25+
:style="{ opacity: !hasSelected ? 0.5 : 1, cursor: !hasSelected ? 'not-allowed' : 'pointer' }">
3126
<span class="icon"><i class="fa-solid fa-trash-can" /></span>
3227
<span>{{ config.app.remove_files ? 'Remove' : 'Clear' }}</span>
33-
</span>
34-
</button>
35-
</div>
36-
<div class="column is-half-mobile" v-if="hasCompleted">
37-
<button type="button" class="button is-fullwidth is-primary is-inverted" @click="clearCompleted">
38-
<span class="icon-text is-block">
28+
</a>
29+
<hr class="dropdown-divider" v-if="hasCompleted || hasIncomplete">
30+
<a v-if="hasCompleted" class="dropdown-item has-text-primary" @click="clearCompleted">
3931
<span class="icon"><i class="fa-solid fa-circle-check" /></span>
4032
<span>Clear Completed</span>
41-
</span>
42-
</button>
43-
</div>
44-
<div class="column is-half-mobile" v-if="hasIncomplete">
45-
<button type="button" class="button is-fullwidth is-info is-inverted" @click="clearIncomplete">
46-
<span class="icon-text is-block">
33+
</a>
34+
<a v-if="hasIncomplete" class="dropdown-item has-text-info" @click="clearIncomplete">
4735
<span class="icon"><i class="fa-solid fa-circle-xmark" /></span>
4836
<span>Clear Incomplete</span>
49-
</span>
50-
</button>
51-
</div>
52-
<div class="column is-half-mobile" v-if="hasIncomplete">
53-
<button type="button" class="button is-fullwidth is-warning is-inverted" @click="retryIncomplete">
54-
<span class="icon-text is-block">
37+
</a>
38+
<a v-if="hasIncomplete" class="dropdown-item has-text-warning" @click="retryIncomplete">
5539
<span class="icon"><i class="fa-solid fa-rotate-right" /></span>
5640
<span>Retry Incomplete</span>
57-
</span>
58-
</button>
41+
</a>
42+
</Dropdown>
5943
</div>
60-
<div class="column is-1-tablet">
61-
<button type="button" class="button is-fullwidth" @click="direction = direction === 'desc' ? 'asc' : 'desc'">
44+
<div class="column is-narrow">
45+
<button type="button" class="button" @click="direction = direction === 'desc' ? 'asc' : 'desc'">
6246
<span class="icon-text is-block">
6347
<span class="icon">
6448
<i class="fa-solid" :class="direction === 'desc' ? 'fa-arrow-down-a-z' : 'fa-arrow-up-a-z'" />
@@ -725,7 +709,10 @@ const clearCompleted = async () => {
725709
return
726710
}
727711
selectedElms.value = []
728-
await stateStore.deleteItems('history', { status: 'finished', removeFile: false })
712+
Promise.all([
713+
stateStore.deleteItems('history', { status: 'finished', removeFile: false }),
714+
stateStore.deleteItems('history', { status: 'skip', removeFile: false })
715+
])
729716
}
730717
731718
const clearIncomplete = async () => {

ui/app/components/Queue.vue

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,37 @@
11
<template>
2-
<div class="columns is-multiline is-mobile has-text-centered" v-if="filteredItems.length > 0">
3-
<div class="column is-half-mobile">
4-
<button type="button" class="button is-fullwidth is-ghost" @click="masterSelectAll = !masterSelectAll">
5-
<span v-if="selectedElms.length > 0" class="mr-2 tag is-danger">
6-
{{ selectedElms.length }}
2+
<div class="columns is-multiline is-mobile has-text-centered is-justify-content-flex-end"
3+
v-if="filteredItems.length > 0">
4+
<div class="column is-narrow">
5+
<button type="button" class="button" @click="masterSelectAll = !masterSelectAll"
6+
:class="{ 'has-text-primary': !masterSelectAll, 'has-text-danger': masterSelectAll }">
7+
<span class="icon">
8+
<i :class="!masterSelectAll ? 'fa-regular fa-square-check' : 'fa-regular fa-square'" />
79
</span>
8-
<span class="icon-text is-block">
9-
<span class="icon">
10-
<i class="fas" :class="!masterSelectAll ? 'fa-regular fa-square-check' : 'fa-regular fa-square'" />
11-
</span>
12-
<span v-if="!masterSelectAll">Select All</span>
13-
<span v-else> Unselect All</span>
10+
<span v-if="!masterSelectAll">Select</span>
11+
<span v-else>Unselect</span>
12+
<span v-if="selectedElms.length > 0">
13+
&nbsp;(<u class="has-text-danger">{{ selectedElms.length }}</u>)
1414
</span>
1515
</button>
1616
</div>
17-
<div class="column is-half-mobile" v-if="hasManualStart">
18-
<button type="button" class="button is-fullwidth is-success" :disabled="!hasSelected" @click="startItems">
19-
<span class="icon"><i class="fa-solid fa-circle-play" /></span>
20-
<span>Start</span>
21-
</button>
22-
</div>
23-
<div class="column is-half-mobile" v-if="hasPausable">
24-
<button type="button" class="button is-fullwidth is-warning is-background-warning-85" :disabled="!hasSelected"
25-
@click="pauseSelected">
26-
<span class="icon"><i class="fa-solid fa-pause" /></span>
27-
<span>Pause</span>
28-
</button>
29-
</div>
30-
<div class="column is-half-mobile">
31-
<button type="button" class="button is-fullwidth is-warning" :disabled="!hasSelected" @click="cancelSelected">
32-
<span class="icon"><i class="fa-solid fa-eject" /></span>
33-
<span>Cancel</span>
34-
</button>
17+
<div class="column is-2-tablet is-5-mobile">
18+
<Dropdown label="Actions" icons="fa-solid fa-list">
19+
<a v-if="hasManualStart" class="dropdown-item has-text-success" @click="hasSelected ? startItems() : null"
20+
:style="{ opacity: !hasSelected ? 0.5 : 1, cursor: !hasSelected ? 'not-allowed' : 'pointer' }">
21+
<span class="icon"><i class="fa-solid fa-circle-play" /></span>
22+
<span>Start</span>
23+
</a>
24+
<a v-if="hasPausable" class="dropdown-item has-text-warning" @click="hasSelected ? pauseSelected() : null"
25+
:style="{ opacity: !hasSelected ? 0.5 : 1, cursor: !hasSelected ? 'not-allowed' : 'pointer' }">
26+
<span class="icon"><i class="fa-solid fa-pause" /></span>
27+
<span>Pause</span>
28+
</a>
29+
<a class="dropdown-item has-text-warning" @click="hasSelected ? cancelSelected() : null"
30+
:style="{ opacity: !hasSelected ? 0.5 : 1, cursor: !hasSelected ? 'not-allowed' : 'pointer' }">
31+
<span class="icon"><i class="fa-solid fa-eject" /></span>
32+
<span>Cancel</span>
33+
</a>
34+
</Dropdown>
3535
</div>
3636
</div>
3737

ui/app/pages/browser/[...slug].vue

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -105,36 +105,36 @@
105105
</div>
106106
</div>
107107

108-
<div class="columns is-mobile is-multiline" v-if="config.app.browser_control_enabled && items && items.length > 0">
109-
<div class="column is-12-mobile">
110-
<button type="button" class="button is-fullwidth is-ghost is-inverted"
111-
@click="masterSelectAll = !masterSelectAll" :disabled="isLoading || items.length < 1">
112-
<span class="icon-text is-block">
113-
<span class="icon">
114-
<i :class="!masterSelectAll ? 'fa-regular fa-square-check' : 'fa-regular fa-square'" />
115-
</span>
116-
<span v-if="!masterSelectAll">Select All</span>
117-
<span v-else>Unselect All</span>
108+
<div class="columns is-mobile is-multiline is-justify-content-flex-end" v-if="config.app.browser_control_enabled && items && items.length > 0">
109+
<div class="column is-narrow">
110+
<button type="button" class="button" @click="masterSelectAll = !masterSelectAll"
111+
:class="{ 'has-text-primary': !masterSelectAll, 'has-text-danger': masterSelectAll }"
112+
:disabled="isLoading || items.length < 1">
113+
<span class="icon">
114+
<i :class="!masterSelectAll ? 'fa-regular fa-square-check' : 'fa-regular fa-square'" />
118115
</span>
119-
</button>
120-
</div>
121-
<div class="column is-half-mobile">
122-
<button type="button" class="button is-fullwidth is-danger" @click="deleteSelected"
123-
:disabled="selectedElms.length < 1 || isLoading || items.length < 1">
124-
<span class="icon-text is-block">
125-
<span class="icon"><i class="fa-solid fa-trash-can" /></span>
126-
<span>Delete {{ selectedElms.length > 0 ? selectedElms.length : '' }} items</span>
116+
<span v-if="!masterSelectAll">Select</span>
117+
<span v-else>Unselect</span>
118+
<span v-if="selectedElms.length > 0">
119+
&nbsp;(<u class="has-text-danger">{{ selectedElms.length }}</u>)
127120
</span>
128121
</button>
129122
</div>
130-
<div class="column is-half-mobile">
131-
<button type="button" class="button is-fullwidth is-link" @click="moveSelected"
132-
:disabled="selectedElms.length < 1 || isLoading || items.length < 1">
133-
<span class="icon-text is-block">
123+
<div class="column is-2-tablet is-5-mobile">
124+
<Dropdown label="Actions" icons="fa-solid fa-list">
125+
<a class="dropdown-item has-text-danger"
126+
@click="(selectedElms.length > 0 && !isLoading) ? deleteSelected() : null"
127+
:style="{ opacity: (selectedElms.length < 1 || isLoading) ? 0.5 : 1, cursor: (selectedElms.length < 1 || isLoading) ? 'not-allowed' : 'pointer' }">
128+
<span class="icon"><i class="fa-solid fa-trash-can" /></span>
129+
<span>Delete{{ selectedElms.length > 0 ? ` (${selectedElms.length})` : '' }}</span>
130+
</a>
131+
<a class="dropdown-item has-text-link"
132+
@click="(selectedElms.length > 0 && !isLoading) ? moveSelected() : null"
133+
:style="{ opacity: (selectedElms.length < 1 || isLoading) ? 0.5 : 1, cursor: (selectedElms.length < 1 || isLoading) ? 'not-allowed' : 'pointer' }">
134134
<span class="icon"><i class="fa-solid fa-arrows-alt" /></span>
135-
<span>Move {{ selectedElms.length > 0 ? selectedElms.length : '' }} items</span>
136-
</span>
137-
</button>
135+
<span>Move{{ selectedElms.length > 0 ? ` (${selectedElms.length})` : '' }}</span>
136+
</a>
137+
</Dropdown>
138138
</div>
139139
</div>
140140

ui/app/pages/conditions.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@
197197
<span class="icon"><i class="fa-solid fa-list" /></span>
198198
<span>Extras:
199199
<span v-for="(value, key) in cond.extras" :key="key" class="tag is-info mr-2">
200-
<strong>{{ key }}</strong>: {{ value }}
200+
<b>{{ key }}</b>: {{ value }}
201201
</span>
202202
</span>
203203
</p>

ui/app/pages/tasks.vue

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -72,36 +72,36 @@
7272
</div>
7373
</div>
7474

75-
<div class="columns is-multiline is-mobile" v-if="!toggleForm && filteredTasks && filteredTasks.length > 0">
76-
<div class="column">
77-
<button type="button" class="button is-fullwidth is-ghost is-inverted"
78-
@click="masterSelectAll = !masterSelectAll">
79-
<span class="icon-text is-block">
80-
<span class="icon">
81-
<i :class="!masterSelectAll ? 'fa-regular fa-square-check' : 'fa-regular fa-square'" />
82-
</span>
83-
<span v-if="!masterSelectAll">Select All</span>
84-
<span v-else>Unselect All</span>
75+
<div class="columns is-multiline is-mobile is-justify-content-flex-end" v-if="!toggleForm && filteredTasks && filteredTasks.length > 0">
76+
<div class="column is-narrow">
77+
<button type="button" class="button" @click="masterSelectAll = !masterSelectAll"
78+
:class="{ 'has-text-primary': !masterSelectAll, 'has-text-danger': masterSelectAll }">
79+
<span class="icon">
80+
<i :class="!masterSelectAll ? 'fa-regular fa-square-check' : 'fa-regular fa-square'" />
81+
</span>
82+
<span v-if="!masterSelectAll">Select</span>
83+
<span v-else>Unselect</span>
84+
<span v-if="selectedElms.length > 0">
85+
&nbsp;(<u class="has-text-danger">{{ selectedElms.length }}</u>)
8586
</span>
8687
</button>
8788
</div>
8889

89-
<div class="column">
90-
<button class="button is-purple is-fullwidth" @click="runConfirm()"
91-
:disabled="selectedElms.length < 1 || massRun" :class="{ 'is-loading': massRun }">
92-
<span class="icon"><i class="fa-solid fa-up-right-from-square" /></span>
93-
<span>Run Selected</span>
94-
</button>
95-
</div>
96-
97-
<div class="column">
98-
<button type="button" class="button is-fullwidth is-danger" @click="deleteConfirm()"
99-
:disabled="selectedElms.length < 1 || massDelete" :class="{ 'is-loading': massDelete }">
100-
<span class="icon-text is-block">
90+
<div class="column is-2-tablet is-5-mobile">
91+
<Dropdown label="Actions" icons="fa-solid fa-list">
92+
<a class="dropdown-item has-text-purple"
93+
@click="(selectedElms.length > 0 && !massRun) ? runConfirm() : null"
94+
:style="{ opacity: (selectedElms.length < 1 || massRun) ? 0.5 : 1, cursor: (selectedElms.length < 1 || massRun) ? 'not-allowed' : 'pointer' }">
95+
<span class="icon"><i class="fa-solid fa-up-right-from-square" /></span>
96+
<span>Run Selected</span>
97+
</a>
98+
<a class="dropdown-item has-text-danger"
99+
@click="(selectedElms.length > 0 && !massDelete) ? deleteConfirm() : null"
100+
:style="{ opacity: (selectedElms.length < 1 || massDelete) ? 0.5 : 1, cursor: (selectedElms.length < 1 || massDelete) ? 'not-allowed' : 'pointer' }">
101101
<span class="icon"><i class="fa-solid fa-trash-can" /></span>
102102
<span>Remove Selected</span>
103-
</span>
104-
</button>
103+
</a>
104+
</Dropdown>
105105
</div>
106106
</div>
107107

ui/app/stores/SocketStore.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ export const useSocketStore = defineStore('socket', () => {
159159
return;
160160
}
161161

162-
if (json.data?.folder) {
162+
if (json.data?.folders) {
163163
config.add('folders', json.data.folders)
164164
}
165165

ui/app/stores/StateStore.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,12 @@ export const useStateStore = defineStore('state', () => {
176176

177177
const getPagination = () => state.pagination
178178

179-
const setHistoryCount = (count: number) => state.pagination.total = count
179+
const setHistoryCount = (count: number) => {
180+
state.pagination.total = count
181+
if (count > 0 && !state.pagination.isLoaded) {
182+
state.pagination.isLoaded = false
183+
}
184+
}
180185

181186
/**
182187
* Delete items by specific IDs or status filter.

0 commit comments

Comments
 (0)