Attempt to fix up some really bad code.
Ideally this would be rewritten to use less jquery stuff, and have proper async.
This commit is contained in:
+217
-138
@@ -4,157 +4,236 @@
|
|||||||
// @author Big Duckie
|
// @author Big Duckie
|
||||||
// @copyright 2025, Big Duckie (https://bigduckie.dev)
|
// @copyright 2025, Big Duckie (https://bigduckie.dev)
|
||||||
// @license MIT
|
// @license MIT
|
||||||
// @version 2025.1.13
|
// @version 2025.6.6
|
||||||
// @description Adds a sidebar to download songs from Bandcamp.
|
// @description Adds a sidebar to download songs from Bandcamp.
|
||||||
// @include *://*.bandcamp.com/*
|
// @include *://*.bandcamp.com/*
|
||||||
// @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js
|
// @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js
|
||||||
// @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js
|
// @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.9.1/jszip.min.js
|
||||||
// @grant GM_xmlhttpRequest
|
// @grant GM_xmlhttpRequest
|
||||||
// @grant GM_notification
|
|
||||||
// @grant GM_addStyle
|
// @grant GM_addStyle
|
||||||
// @grant GM_download
|
// @grant GM_download
|
||||||
|
// @connect bcbits.com
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
|
||||||
// Register Globals
|
// Register Globals
|
||||||
var sidebar_visible = false;
|
let tracklist = TralbumData.trackinfo;
|
||||||
var tracklist = TralbumData.trackinfo;
|
unsafeWindow.GM_download = GM_download;
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// Sidebar construction
|
// Sidebar construction
|
||||||
$("body")
|
jQuery("body")
|
||||||
.append(
|
.append(jQuery("<div/>")
|
||||||
$("<div/>")
|
.addClass("dl-sidebar-container dl-sidebar dl-color-1 hidden")
|
||||||
.addClass("dl-sidebar-container dl-sidebar dl-color-1 hidden")
|
.append(jQuery("<p/>").text("Click the files to download, or use the download album button."))
|
||||||
.append(
|
.append(jQuery("<ol/>").addClass("dl-tracklist"))
|
||||||
$("<p/>").text(
|
.append(jQuery("<div/>")
|
||||||
"Click the files to download, or use the download album button."
|
.addClass("dl-all-button dl-progress dl-color-2")
|
||||||
)
|
.append(jQuery("<div/>").addClass("dl-progress-bar"))
|
||||||
)
|
.append(jQuery("<div/>").addClass("dl-progress-text").text("Download Album"))))
|
||||||
.append($("<ol/>").addClass("dl-tracklist"))
|
.append(jQuery("<div/>")
|
||||||
.append(
|
.addClass("dl-sidebar-toggle dl-sidebar dl-color-1 hidden")
|
||||||
$("<div/>")
|
.text("Bandcamp Downloader"));
|
||||||
.addClass("dl-all-button dl-progress dl-color-2")
|
|
||||||
.append($("<div/>").addClass("dl-progress-bar"))
|
|
||||||
.append(
|
|
||||||
$("<div/>").addClass("dl-progress-text").text("Download Album")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.append(
|
|
||||||
$("<div/>")
|
|
||||||
.addClass("dl-sidebar-toggle dl-sidebar dl-color-1 hidden")
|
|
||||||
.text("Bandcamp Downloader")
|
|
||||||
);
|
|
||||||
|
|
||||||
tracklist.forEach((track) => {
|
|
||||||
$(".dl-tracklist").append(
|
|
||||||
$("<li/>")
|
|
||||||
.attr("id", "track-" + track.track_num)
|
|
||||||
.append(
|
|
||||||
$("<a/>")
|
|
||||||
.addClass("dl-link custom-color")
|
|
||||||
.attr("data-url", track.file["mp3-128"])
|
|
||||||
.attr("data-trackid", tracklist.indexOf(track))
|
|
||||||
.text(track.title)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Style sidebar to match page
|
|
||||||
GM_addStyle(
|
|
||||||
".dl-sidebar-toggle{font-family:biolinum;left:0;top:50px;position:fixed;transform:rotate(90deg);transform-origin:left bottom 0;border-top-right-radius:5px;border-top-left-radius:5px;margin:0;padding:5px;z-index:5001;background:inherit;border:1px solid #000000;border-bottom:none;cursor:pointer}.dl-sidebar-toggle.active{left:400px}.dl-sidebar-container{width:390px;min-height:300px;left:-400px;top:50px;max-height:500px;overflow-y:scroll;padding:5px;position:fixed;z-index:5000;border:1px solid #000000;border-left:none;user-select:none;cursor:default}.dl-sidebar-container.active{left:0}.dl-all-button{margin-left:0;margin-right:0;cursor:pointer;background-color:rgb(255, 255, 255);color:rgb(0, 0, 0);border-color:rgb(0, 0, 0)}.dl-progress{position:relative;z-index:5001}.dl-progress,.dl-progress-bar,.dl-progress-text{height:25px;left:0;right:0;top:0;bottom:0}.dl-progress-bar{width:0;overflow:hidden;z-index:5002;-moz-transition:width 0.2s linear;-webkit-transition:width 0.2s linear;-o-transition:width 0.2s linear;transition:width 0.2s linear;background-color:rgb(0, 0, 0)}.dl-progress-text{text-align:center;z-index:5003;position:absolute;line-height:25px;color:inherit}.dl-sidebar{opacity:1;transition:opacity 1s, left 0.5s}.dl-sidebar.hidden{opacity:0}.dl-sidebar::-webkit-scrollbar{width:10px}.dl-sidebar::-webkit-scrollbar-track{background:rgb(0, 0, 0)}.dl-sidebar::-webkit-scrollbar-thumb{background:rgb(255, 255, 255)}"
|
|
||||||
);
|
|
||||||
|
|
||||||
$(".dl-color-1").css({
|
|
||||||
"background-color": $("#pgBd").css("background-color"),
|
|
||||||
color: $("#pgBd").css("color"),
|
|
||||||
"border-color": $("#pgBd").css("color"),
|
|
||||||
});
|
|
||||||
$(".dl-color-2").css({
|
|
||||||
"background-color": $("#follow-unfollow").css("background-color"),
|
|
||||||
color: $("#follow-unfollow").css("color"),
|
|
||||||
"border-color": $("#follow-unfollow").css("border-color"),
|
|
||||||
});
|
|
||||||
$(".dl-progress-bar").css({
|
|
||||||
"background-color": $("#pgFt").css("background-color"),
|
|
||||||
});
|
|
||||||
|
|
||||||
$(".dl-sidebar").removeClass("hidden");
|
|
||||||
|
|
||||||
// Handle events
|
|
||||||
$(".dl-sidebar-toggle").click((e) => {
|
|
||||||
$(".dl-sidebar").toggleClass("active");
|
|
||||||
});
|
|
||||||
|
|
||||||
$(".dl-link").click((e) => {
|
|
||||||
GM_download(
|
|
||||||
$(e.target).attr("data-url"),
|
|
||||||
`[${pad(tracklist[$(e.target).attr("data-trackid")].track_num, 2)}] ${
|
|
||||||
TralbumData.artist
|
|
||||||
} - ${tracklist[$(e.target).attr("data-trackid")].title}.mp3`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
$(".dl-all-button").click((e) => {
|
|
||||||
downloadAlbum();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Main functions
|
|
||||||
function downloadAlbum() {
|
|
||||||
// Emergency polyfill
|
|
||||||
var Promise = window.Promise;
|
|
||||||
if (!Promise) {
|
|
||||||
Promise = JSZip.external.Promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch binary data using GM_xmlhttprequest
|
|
||||||
function urlToPromise(url) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
GM_xmlhttpRequest({
|
|
||||||
method: "GET",
|
|
||||||
url: url,
|
|
||||||
responseType: "arraybuffer",
|
|
||||||
onload: (response) => {
|
|
||||||
resolve(response.response);
|
|
||||||
},
|
|
||||||
onerror: (response) => {
|
|
||||||
reject(response.response);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var zip = new JSZip();
|
|
||||||
|
|
||||||
tracklist.forEach((track) => {
|
tracklist.forEach((track) => {
|
||||||
zip.file(
|
jQuery(".dl-tracklist").append(jQuery("<li/>")
|
||||||
`[${track.track_num}] ${TralbumData.artist} - ${track.title}.mp3`,
|
.attr("id", "track-" + track.track_num)
|
||||||
urlToPromise(track.file["mp3-128"]),
|
.append(jQuery("<a/>")
|
||||||
{ binary: true }
|
.addClass("dl-link custom-color")
|
||||||
);
|
.attr("data-url", track.file["mp3-128"])
|
||||||
|
.attr("data-trackid", tracklist.indexOf(track))
|
||||||
|
.text(track.title)));
|
||||||
});
|
});
|
||||||
|
|
||||||
zip
|
function css(strings) {
|
||||||
.generateAsync({ type: "blob" }, (metadata) => {
|
return strings;
|
||||||
$(".dl-progress-bar").css("width", `${metadata.percent}%`);
|
}
|
||||||
})
|
|
||||||
.then(
|
|
||||||
(blob) => {
|
|
||||||
GM_download(
|
|
||||||
URL.createObjectURL(blob),
|
|
||||||
`${BandData.name} - ${TralbumData.current.title}.zip`
|
|
||||||
);
|
|
||||||
},
|
|
||||||
(e) => {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Supporting functions
|
// Style sidebar to match page
|
||||||
function pad(n, width = 3, z = 0) {
|
GM_addStyle(css`.dl-sidebar-toggle {
|
||||||
return (String(z).repeat(width) + String(n)).slice(String(n).length);
|
font-family: biolinum;
|
||||||
}
|
left: 0;
|
||||||
})();
|
top: 50px;
|
||||||
|
position: fixed;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
transform-origin: left bottom 0;
|
||||||
|
border-top-right-radius: 5px;
|
||||||
|
border-top-left-radius: 5px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 5px;
|
||||||
|
z-index: 5001;
|
||||||
|
background: inherit;
|
||||||
|
border: 1px solid #000000;
|
||||||
|
border-bottom: none;
|
||||||
|
cursor: pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
.dl-sidebar-toggle.active {
|
||||||
|
left: 400px
|
||||||
|
}
|
||||||
|
|
||||||
|
.dl-sidebar-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 390px;
|
||||||
|
min-height: 300px;
|
||||||
|
left: -400px;
|
||||||
|
top: 50px;
|
||||||
|
max-height: 500px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
padding: 5px;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 5000;
|
||||||
|
border: 1px solid #000000;
|
||||||
|
border-left: none;
|
||||||
|
user-select: none;
|
||||||
|
cursor: default
|
||||||
|
}
|
||||||
|
|
||||||
|
.dl-sidebar-container.active {
|
||||||
|
left: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.dl-tracklist {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dl-all-button {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: rgb(255, 255, 255);
|
||||||
|
color: rgb(0, 0, 0);
|
||||||
|
border-color: rgb(0, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
.dl-progress {
|
||||||
|
position: relative;
|
||||||
|
z-index: 5001
|
||||||
|
}
|
||||||
|
|
||||||
|
.dl-progress,
|
||||||
|
.dl-progress-bar,
|
||||||
|
.dl-progress-text {
|
||||||
|
height: 25px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.dl-progress-bar {
|
||||||
|
width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: 5002;
|
||||||
|
-moz-transition: width 0.2s linear;
|
||||||
|
-webkit-transition: width 0.2s linear;
|
||||||
|
-o-transition: width 0.2s linear;
|
||||||
|
transition: width 0.2s linear;
|
||||||
|
background-color: rgb(0, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
.dl-progress-text {
|
||||||
|
text-align: center;
|
||||||
|
z-index: 5003;
|
||||||
|
position: absolute;
|
||||||
|
line-height: 25px;
|
||||||
|
color: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
.dl-sidebar {
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 1s, left 0.5s
|
||||||
|
}
|
||||||
|
|
||||||
|
.dl-sidebar.hidden {
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.dl-sidebar::-webkit-scrollbar {
|
||||||
|
width: 10px
|
||||||
|
}
|
||||||
|
|
||||||
|
.dl-sidebar::-webkit-scrollbar-track {
|
||||||
|
background: rgb(0, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
.dl-sidebar::-webkit-scrollbar-thumb {
|
||||||
|
background: rgb(255, 255, 255)
|
||||||
|
}`);
|
||||||
|
|
||||||
|
jQuery(".dl-color-1").css({
|
||||||
|
"background-color": jQuery("#pgBd").css("background-color"),
|
||||||
|
color: jQuery("#pgBd").css("color"),
|
||||||
|
"border-color": jQuery("#pgBd").css("color"),
|
||||||
|
});
|
||||||
|
jQuery(".dl-color-2").css({
|
||||||
|
"background-color": jQuery("#follow-unfollow").css("background-color"),
|
||||||
|
color: jQuery("#follow-unfollow").css("color"),
|
||||||
|
"border-color": jQuery("#follow-unfollow").css("border-color"),
|
||||||
|
});
|
||||||
|
jQuery(".dl-progress-bar").css({
|
||||||
|
"background-color": jQuery("#recommendations_container").css("background-color"),
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery(".dl-sidebar").removeClass("hidden");
|
||||||
|
|
||||||
|
// Handle events
|
||||||
|
jQuery(".dl-sidebar-toggle").click((e) => {
|
||||||
|
jQuery(".dl-sidebar").toggleClass("active");
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery(".dl-link").click((e) => {
|
||||||
|
GM_download(jQuery(e.target).attr("data-url"), `[${pad(tracklist[jQuery(e.target).attr("data-trackid")].track_num, 2)}] ${TralbumData.artist} - ${tracklist[jQuery(e.target).attr("data-trackid")].title}.mp3`);
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery(".dl-all-button").click((e) => {
|
||||||
|
console.debug("downloading album");
|
||||||
|
downloadAlbum();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Main functions
|
||||||
|
function downloadAlbum() {
|
||||||
|
let zip = new JSZip();
|
||||||
|
|
||||||
|
tracklist.forEach((track) => {
|
||||||
|
console.debug("downloading track", track);
|
||||||
|
zip.file(
|
||||||
|
`[${track.track_num}] ${TralbumData.artist} - ${track.title}.mp3`,
|
||||||
|
urlToPromise(track.file["mp3-128"]));
|
||||||
|
});
|
||||||
|
|
||||||
|
console.debug("generating zip");
|
||||||
|
zip.generateAsync({type: "blob"}, (metadata) => {
|
||||||
|
console.debug("processing zip");
|
||||||
|
jQuery(".dl-progress-bar").css("width", `${metadata.percent}%`);
|
||||||
|
})
|
||||||
|
.then((blob) => {
|
||||||
|
let url = URL.createObjectURL(blob);
|
||||||
|
console.debug("compiled zip", url);
|
||||||
|
|
||||||
|
GM_download(url, `${TralbumData.artist} - ${TralbumData.current.title}.zip`);
|
||||||
|
}, (e) => {
|
||||||
|
console.error(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supporting functions
|
||||||
|
function pad(n, width = 3, z = 0) {
|
||||||
|
return (String(z).repeat(width) + String(n)).slice(String(n).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
function urlToPromise(url) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
GM.xmlHttpRequest({
|
||||||
|
method: "GET", url: url, responseType: "blob", onload: (response) => {
|
||||||
|
console.debug("fetched song", url, response.response);
|
||||||
|
resolve(response.response);
|
||||||
|
}, onerror: (response) => {
|
||||||
|
reject(response.response);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
||||||
Reference in New Issue
Block a user