Initial commit
This commit is contained in:
parent
5a8186a46c
commit
15ff7e5b47
25 changed files with 2703 additions and 0 deletions
30
scripts/load-tags.js
Normal file
30
scripts/load-tags.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
// @ts-check
|
||||
|
||||
const domino = require("domino")
|
||||
const sqlite = require("better-sqlite3")
|
||||
|
||||
const db = new sqlite("bc-explorer.db", {fileMustExist: true})
|
||||
require("../db/migrate").migrate(db)
|
||||
Object.assign(require("../passthrough"), {db})
|
||||
const {from} = require("../db/orm")
|
||||
|
||||
const i = db.prepare("INSERT OR IGNORE INTO item_tag (item_id, tag) VALUES (?, ?)")
|
||||
|
||||
;(async () => {
|
||||
const untaggedItems = from("item").select("item_id", "item_title", "item_url").join("item_tag", "item_id", "left").and("WHERE tag IS NULL").all()
|
||||
console.log(`Downloading tags for ${untaggedItems.length} purchased items`)
|
||||
let processed = 1
|
||||
for (const {item_id, item_title, item_url} of untaggedItems) {
|
||||
const html = await fetch(item_url).then(res => res.text())
|
||||
const doc = domino.createDocument(html)
|
||||
// @ts-ignore
|
||||
const tags = [...doc.querySelectorAll(".tag").cache].map(e => e.textContent)
|
||||
console.log(`[${processed}/${untaggedItems.length}] tagging ${item_title} with ${tags.join(", ")}`)
|
||||
db.transaction(() => {
|
||||
for (const tag of tags) {
|
||||
i.run(item_id, tag)
|
||||
}
|
||||
})()
|
||||
processed++
|
||||
}
|
||||
})()
|
72
scripts/populate-albums-tracks.js
Normal file
72
scripts/populate-albums-tracks.js
Normal file
|
@ -0,0 +1,72 @@
|
|||
// @ts-check
|
||||
|
||||
const assert = require("assert/strict")
|
||||
const fs = require("fs")
|
||||
const sqlite = require("better-sqlite3")
|
||||
|
||||
const har = JSON.parse(fs.readFileSync("scripts/account.har", "utf8"))
|
||||
|
||||
;(async () => {
|
||||
const collection_summary = har.log.entries.find(e => e.request.url === "https://bandcamp.com/api/fan/2/collection_summary")
|
||||
assert(collection_summary)
|
||||
|
||||
const body = JSON.parse(collection_summary.response.content.text)
|
||||
const {fan_id} = body
|
||||
const count = Object.keys(body.collection_summary.tralbum_lookup).length
|
||||
|
||||
const newestPurchase = Object.values(body.collection_summary.tralbum_lookup).sort((a, b) => new Date(b.purchased).getTime() - new Date(a.purchased).getTime())[0]
|
||||
const fakeLastToken = `${Math.floor(new Date(newestPurchase.purchased).getTime() / 1000 + 1)}:${newestPurchase.item_id}:${newestPurchase.item_type}::`
|
||||
|
||||
const Cookie = collection_summary.request.headers.find(h => h.name === "Cookie").value
|
||||
assert(Cookie)
|
||||
|
||||
const items = await fetch("https://bandcamp.com/api/fancollection/1/collection_items", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Cookie
|
||||
},
|
||||
body: JSON.stringify({
|
||||
fan_id,
|
||||
older_than_token: fakeLastToken,
|
||||
count
|
||||
})
|
||||
}).then(res => res.json())
|
||||
console.log(`Found ${items.items.length} purchased items in your account`)
|
||||
|
||||
const db = new sqlite("bc-explorer.db")
|
||||
require("../db/migrate").migrate(db)
|
||||
|
||||
const columns = ["item_id", "item_type", "band_id", "added", "updated", "purchased", "featured_track", "why", "also_collected_count", "item_title", "item_url", "item_art_url", "band_name", "band_url", "featured_track_title", "featured_track_number", "featured_track_duration", "album_id", "album_title", "price", "currency", "label", "label_id"]
|
||||
const upsert_columns = ["added", "updated", "purchased"]
|
||||
const preparedItem = db.prepare(`INSERT OR IGNORE INTO item (${columns.join(", ")}) VALUES (${columns.map(x => "@" + x).join(", ")}) ON CONFLICT DO UPDATE SET ${upsert_columns.map(x => `${x} = @${x}`).join(", ")}`)
|
||||
db.transaction(() => {
|
||||
for (const item of items.items) {
|
||||
preparedItem.run({
|
||||
...item,
|
||||
purchased: new Date(item.purchased).getTime(),
|
||||
added: new Date(item.added).getTime(),
|
||||
updated: new Date(item.updated).getTime()
|
||||
})
|
||||
}
|
||||
})()
|
||||
const storedItemCount = db.prepare("SELECT count(*) AS count FROM item").pluck().get()
|
||||
console.log(`Stored ${storedItemCount} purchased items`)
|
||||
|
||||
const preparedTrack = db.prepare("INSERT OR IGNORE INTO track (item_id, track_id, title, artist, track_number, duration, mp3) VALUES (@item_id, @track_id, @title, @artist, @track_number, @duration, @mp3)")
|
||||
db.transaction(() => {
|
||||
for (const [key, tracklist] of Object.entries(items.tracklists)) {
|
||||
assert.match(key[0], /[at]/)
|
||||
for (const track of tracklist) {
|
||||
preparedTrack.run({
|
||||
item_id: key.slice(1),
|
||||
track_id: track.id,
|
||||
mp3: track.file?.["mp3-v0"],
|
||||
...track
|
||||
})
|
||||
}
|
||||
}
|
||||
})()
|
||||
const storedTrackCount = db.prepare("SELECT count(*) AS count FROM track").pluck().get()
|
||||
console.log(`Stored ${storedTrackCount} tracks`)
|
||||
console.log("To load tag data, please now run node ./scripts/load-tags.js")
|
||||
})()
|
Loading…
Add table
Add a link
Reference in a new issue