Queue for tag downloads
This commit is contained in:
parent
be489e9a18
commit
5e9ea6db66
6 changed files with 58 additions and 8 deletions
9
package-lock.json
generated
9
package-lock.json
generated
|
@ -7,8 +7,9 @@
|
|||
"": {
|
||||
"name": "bc-explorer",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"license": "AGPL-3.0-only",
|
||||
"dependencies": {
|
||||
"@chriscdn/promise-semaphore": "^2.0.10",
|
||||
"@cloudrac3r/pug": "^4.0.4",
|
||||
"@iconify-json/iconoir": "^1.2.7",
|
||||
"@iconify/utils": "^2.3.0",
|
||||
|
@ -85,6 +86,12 @@
|
|||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@chriscdn/promise-semaphore": {
|
||||
"version": "2.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@chriscdn/promise-semaphore/-/promise-semaphore-2.0.10.tgz",
|
||||
"integrity": "sha512-NagoHAZEYISDYYprsHe+x2BEcD6GKhTpEreI8BM1qgtHOtCS3lbwRvvTQxzAxU8JVSmw7ep/ROLv3Ng/MPcMHg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@cloudrac3r/pug": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@cloudrac3r/pug/-/pug-4.0.4.tgz",
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"license": "AGPL-3.0-only",
|
||||
"dependencies": {
|
||||
"@chriscdn/promise-semaphore": "^2.0.10",
|
||||
"@cloudrac3r/pug": "^4.0.4",
|
||||
"@iconify-json/iconoir": "^1.2.7",
|
||||
"@iconify/utils": "^2.3.0",
|
||||
|
|
15
pug/home.pug
15
pug/home.pug
|
@ -6,6 +6,7 @@ html
|
|||
title BC Explorer
|
||||
link(rel="icon" href="/favicon.png")
|
||||
link(rel="stylesheet" type="text/css" href="/static/stacks.css")
|
||||
link(rel="stylesheet" type="text/css" href="/static/style.css")
|
||||
script(src="/static/htmx.js")
|
||||
meta(name="htmx-config" content='{"requestClass":"is-loading"}')
|
||||
body.themed.theme-system.overflow-y-scroll
|
||||
|
@ -30,3 +31,17 @@ html
|
|||
input.s-input.wmx3#username(name="account" placeholder="Enter your Bandcamp username here")
|
||||
button.s-btn.s-btn__filled.my16#submit-username Load collection
|
||||
#results.d-flex
|
||||
|
||||
.s-prose.mt32
|
||||
main
|
||||
h2 About BC Explorer
|
||||
p Explore your Bandcamp collection online!
|
||||
p You can easily search your whole collection and play it streaming rather than downloading every mp3 to your computer and using a media player.
|
||||
aside: p.fs-fine (you should download every mp3, though, because the Bandcamp TOS says they can take away your online access at any time)
|
||||
|
||||
footer.mt32.d-flex.fw-wrap.gx8.ai-center
|
||||
a(href="https://cadence.moe") Created by Cadence
|
||||
.s-award-bling.s-award-bling__silver.ml4
|
||||
a(href="https://gitdab.com/cadence/bc-explorer") BC Explorer source code
|
||||
.s-award-bling.s-award-bling__silver.ml4
|
||||
span Not affiliated with Bandcamp.
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
if downloader.total > 0 || downloader.outcome
|
||||
#tag-download
|
||||
if !downloader.running && !downloader.outcome
|
||||
if downloader.queuePosition > 0
|
||||
.s-notice.p16(role="status" hx-target="#tag-download" hx-select="#tag-download" hx-get=`/api/tag-download?account=${account}` hx-trigger="every 30s" hx-indicator="null")
|
||||
.d-flex.gx16.ai-center
|
||||
!= icons.get("cloud-download")
|
||||
.fl-grow1 Waiting to download...
|
||||
p.mt12.mb0 #{downloader.queuePosition} people are ahead of you in the queue.
|
||||
p.mt12.mb0 You can keep using BC Explorer and this will process in the background.
|
||||
title#title(hx-swap-oob="true") In queue | Tags | BC Explorer
|
||||
|
||||
else if !downloader.running && !downloader.outcome
|
||||
form.s-notice.s-notice__info.d-flex.ai-center.p8.gx16.pl16(role="status" hx-target="#tag-download" hx-select="#tag-download" hx-post="/api/tag-download")
|
||||
!= icons.get("info-circle")
|
||||
div Tag data needs to be downloaded. This will take a while.
|
||||
|
@ -28,7 +37,7 @@ if downloader.total > 0 || downloader.outcome
|
|||
!= icons.get("cloud-check")
|
||||
.fl-grow1 Tags downloaded.
|
||||
- downloader.resolve()
|
||||
a.s-btn.s-btn__outlined(href=and({arrange: "tag"}) hx-boost="true") Refresh
|
||||
a.s-btn.s-btn__outlined(href=and({arrange: "tag", shape: "grid"})) Refresh
|
||||
|
||||
else
|
||||
.s-notice.s-notice__danger.p8.gx16.pl16.d-flex.ai-center
|
||||
|
|
|
@ -82,7 +82,7 @@ async function loadCollection(inputUsername) {
|
|||
|
||||
// load full tracks/tags immediately if there's not too many
|
||||
const downloader = loadTags.downloadManager.check(account)
|
||||
if (downloader.total <= 5) loadTags.downloadManager.start(account)
|
||||
if (downloader.total > 0 && downloader.total <= 20 && loadTags.downloadManager.queue === 0) loadTags.downloadManager.start(account)
|
||||
|
||||
return {
|
||||
storedItemCount,
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
const domino = require("domino")
|
||||
const {getValidatedQuery, readValidatedBody, defineEventHandler} = require("h3")
|
||||
/** @type {import("@chriscdn/promise-semaphore")["default"]} */ // @ts-ignore
|
||||
const Semaphore = require("@chriscdn/promise-semaphore")
|
||||
|
||||
const {sync, db, router} = require("../passthrough")
|
||||
|
||||
|
@ -22,6 +24,7 @@ class TagDownloader extends sync.reloadClassMethods(() => TagDownloader) {
|
|||
this.untaggedItems = []
|
||||
this.total = this.untaggedItems.length
|
||||
this.running = false
|
||||
this.queuePosition = 0
|
||||
this.outcome = null
|
||||
this.check()
|
||||
}
|
||||
|
@ -32,8 +35,14 @@ class TagDownloader extends sync.reloadClassMethods(() => TagDownloader) {
|
|||
this.total = this.untaggedItems.length
|
||||
}
|
||||
|
||||
_setQueued(queuePosition) {
|
||||
if (this.running) return
|
||||
this.queuePosition = queuePosition
|
||||
}
|
||||
|
||||
async _start() {
|
||||
if (this.running) return
|
||||
this.queuePosition = 0
|
||||
this.running = true
|
||||
this.outcome = null
|
||||
this.processed = 0
|
||||
|
@ -79,7 +88,7 @@ class TagDownloader extends sync.reloadClassMethods(() => TagDownloader) {
|
|||
}
|
||||
this.outcome = "Success"
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
console.error(`error downloading tags for ${this.account} - ${e}`)
|
||||
this.outcome = e.toString()
|
||||
} finally {
|
||||
this.running = false
|
||||
|
@ -94,6 +103,8 @@ class TagDownloader extends sync.reloadClassMethods(() => TagDownloader) {
|
|||
const downloadManager = new class {
|
||||
/** @type {Map<string, TagDownloader>} */
|
||||
inProgressTagDownloads = sync.remember(() => new Map())
|
||||
semaphore = sync.remember(() => new Semaphore(1))
|
||||
queue = 0
|
||||
|
||||
/** @param {string} account */
|
||||
check(account) {
|
||||
|
@ -109,14 +120,21 @@ const downloadManager = new class {
|
|||
/** @param {string} account */
|
||||
start(account) {
|
||||
const downloader = this.check(account)
|
||||
downloader._start()
|
||||
downloader._setQueued(++this.queue)
|
||||
console.log(`requested tag download for ${account} - ${this.queue} in queue`)
|
||||
this.semaphore.request(() => downloader._start()).finally(() => {
|
||||
this.queue--
|
||||
for (const otherDownloader of this.inProgressTagDownloads.values()) {
|
||||
otherDownloader.queuePosition--
|
||||
}
|
||||
})
|
||||
return downloader
|
||||
}
|
||||
|
||||
/** @param {string} account */
|
||||
resolve(account) {
|
||||
const downloader = this.check(account)
|
||||
if (!downloader.running) {
|
||||
if (!downloader.running && downloader.queuePosition <= 0) {
|
||||
this.inProgressTagDownloads.delete(account)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue