Skip to content

Commit 2dee784

Browse files
committed
soundcloud
1 parent bb3706a commit 2dee784

File tree

9 files changed

+142
-80
lines changed

9 files changed

+142
-80
lines changed

popup/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ function createScriptButton(script, isFavorite = false) {
288288
// tooltip
289289
const tooltip = document.createElement("span");
290290
tooltip.classList.add("tooltiptext");
291-
tooltip.innerText = t(script.description);
291+
tooltip.innerHTML = t(script.description);
292292
button.appendChild(tooltip);
293293

294294
buttonContainer.appendChild(button);

popup/styles/style.css

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ a:hover {
319319
border-radius: 6px;
320320
padding: 5px;
321321
pointer-events: none;
322+
width: calc(100vw - 40px);
322323

323324
/* Position the tooltip */
324325
position: absolute;
@@ -536,4 +537,4 @@ a:hover {
536537
/* Handle on hover */
537538
::-webkit-scrollbar-thumb:hover {
538539
background: #555;
539-
}
540+
}

popup/tabs.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,22 +62,23 @@ const tabs = [
6262
{
6363
...CATEGORY.download,
6464
scripts: [
65-
s.getFavicon,
66-
s.download_watchingVideo,
65+
createTitle("--- All in one ---", "--- Tổng hợp ---"),
66+
s.savevideo_me,
67+
s.saveAllVideo,
6768
s.getLinkLuanxt,
6869
s.vuiz_getLink,
69-
s.saveAllVideo,
7070
// s.bookmark_exporter,
7171
createTitle("--- Music ---", "--- Nhạc ---"),
72-
s.showTheAudios,
73-
// s.soundcloud_downloadMusic,
72+
s.soundcloud_downloadMusic,
7473
s.nhaccuatui_downloader,
7574
s.zingmp3_downloadMusic,
75+
s.showTheAudios,
7676
createTitle("--- Videos ---", "--- Video ---"),
77-
s.savevideo_me,
77+
s.download_watchingVideo,
7878
s.vimeo_downloader,
7979
s.showTheVideos,
8080
createTitle("--- Photos ---", "--- Ảnh ---"),
81+
s.getFavicon,
8182
s.whatApp_storySaver,
8283
s.showTheImages,
8384
s.download_image,

scripts/content-scripts/scripts/ufs_global_webpage_context.js

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -151,27 +151,30 @@ const UsefulScriptGlobalPageContext = {
151151
return policy.createHTML(html);
152152
},
153153

154-
injectScriptSrc(srcs, callback) {
154+
injectScriptSrc(src, callback) {
155155
let policy = UsefulScriptGlobalPageContext.DOM.getTrustedPolicy();
156+
let jsSrc = policy.createScriptURL(src);
157+
let script = document.createElement("script");
158+
script.onload = function () {
159+
callback?.(true);
160+
};
161+
script.onerror = function (e) {
162+
callback?.(false, e);
163+
};
164+
script.src = jsSrc; // Assigning the TrustedScriptURL to src
165+
document.head.appendChild(script);
166+
},
156167

157-
let listSrcs = srcs;
158-
if (!Array.isArray(listSrcs)) {
159-
listSrcs = [listSrcs];
160-
}
161-
162-
for (let src of listSrcs) {
163-
let jsSrc = policy.createScriptURL(src);
164-
165-
let script = document.createElement("script");
166-
script.onload = function () {
167-
callback?.(true);
168-
};
169-
script.onerror = function (e) {
170-
callback?.(false, e);
171-
};
172-
script.src = jsSrc; // Assigning the TrustedScriptURL to src
173-
document.head.appendChild(script);
174-
}
168+
injectScriptSrcAsync(src) {
169+
return new Promise((resolve, reject) => {
170+
UsefulScriptGlobalPageContext.DOM.injectScriptSrc(src, (success, e) => {
171+
if (success) {
172+
resolve();
173+
} else {
174+
reject(e);
175+
}
176+
});
177+
});
175178
},
176179

177180
isElementInViewport(el) {
@@ -220,6 +223,17 @@ const UsefulScriptGlobalPageContext = {
220223
},
221224
},
222225
Utils: {
226+
hook(obj, name, callback) {
227+
const fn = obj[name];
228+
obj[name] = function (...args) {
229+
callback.apply(this, args);
230+
fn.apply(this, args);
231+
};
232+
return () => {
233+
// restore
234+
obj[name] = fn;
235+
};
236+
},
223237
// https://stackoverflow.com/a/38552302/11898496
224238
parseJwt(token) {
225239
var base64Url = token.split(".")[1];

scripts/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ import savevideo_me from "./savevideo_me.js";
125125
import bookmark_exporter from "./bookmark_exporter.js";
126126
import search_hopamchuan from "./search_hopamchuan.js";
127127
import ggdrive_generateDirectLink from "./ggdrive_generateDirectLink.js";
128-
// import soundcloud_downloadMusic from "./soundcloud_downloadMusic.js";
128+
import soundcloud_downloadMusic from "./soundcloud_downloadMusic.js";
129129
import fastDoc from "./fastDoc.js";
130130
import smartPDF from "./smartPDF.js";
131131
import studocu_dl from "./studocu_dl.js";
@@ -327,7 +327,7 @@ const allScripts = {
327327
bookmark_exporter: addBadge(bookmark_exporter, BADGES.beta),
328328
search_hopamchuan: search_hopamchuan,
329329
ggdrive_generateDirectLink: ggdrive_generateDirectLink,
330-
// soundcloud_downloadMusic: addBadge(soundcloud_downloadMusic, BADGES.new),
330+
soundcloud_downloadMusic: addBadge(soundcloud_downloadMusic, BADGES.new),
331331
fastDoc: fastDoc,
332332
smartPDF: smartPDF,
333333
studocu_dl: studocu_dl,

scripts/scribd_bypassPreview.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export default {
2-
icon: "https://www.scribd.com/favicon.ico",
2+
icon: "https://s-f.scribdassets.com/scribd.ico?014e86d16?v=5",
33
name: {
44
en: "Scribd - bypass preview",
55
vi: "Scribd - Xem miễn phí VIP",
Lines changed: 92 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,113 @@
1-
import { getCurrentTab } from "./helpers/utils.js";
2-
31
export default {
42
icon: "https://a-v2.sndcdn.com/assets/images/sc-icons/favicon-2cadd14bdb.ico",
53
name: {
6-
en: "Soundcloud - Download music",
7-
vi: "Soundcloud - Tải nhạc",
4+
en: "Soundcloud - Add download button",
5+
vi: "Soundcloud - Thêm nút tải nhạc",
86
},
97
description: {
10-
en: "Download music from soundcloud",
11-
vi: "Tải nhạc trên soundcloud",
8+
en: "Add download button on soundcloud (before like button). Use soundcloud API, no external service <img style='width:100%' src='/scripts/soundcloud_downloadMusic.png' />",
9+
vi: "Thêm nút tải nhạc trên soundcloud (trước nút like). Sử dụng trực tiếp soundcloud API <img style='width:100%' src='/scripts/soundcloud_downloadMusic.png' />",
1210
},
1311

14-
onClickExtension: async function () {
15-
let tab = await getCurrentTab();
16-
let url = prompt("Nhập link soundcloud: ", tab.url);
17-
if (url == null) return;
18-
},
19-
};
12+
whiteList: ["https://soundcloud.com/*"],
2013

21-
export const shared = {
22-
downloadSoundCloud: async function (url) {
23-
let client_id = await shared.getApiKey();
24-
let info = await shared.getResourceInfo(url, client_id);
25-
},
26-
getApiKey: async function () {
27-
let res = await fetch("https://soundcloud.com");
14+
infoLink:
15+
"https://greasyfork.org/en/scripts/394837-local-soundcloud-downloader",
2816

29-
let text = await res.text();
17+
onDocumentStart: async () => {
18+
function hook(obj, name, callback) {
19+
const fn = obj[name];
20+
obj[name] = function (...args) {
21+
callback.apply(this, args);
22+
fn.apply(this, args);
23+
};
24+
return () => {
25+
// restore
26+
obj[name] = fn;
27+
};
28+
}
3029

31-
// prettier-ignore
32-
let jsUrl =
33-
new RegExp('<script crossorigin="" src="(.+?)"></script>').exec(text)?.[-1] ||
34-
new RegExp('<script crossorigin src="(.+?)"></script>').exec(text)?.[-1];
30+
const btnId = "ufs-soundcloud-downloadBtn";
31+
const downloadBtn = document.createElement("button");
32+
downloadBtn.id = btnId;
33+
downloadBtn.textContent = "Download";
34+
downloadBtn.classList.add("sc-button");
35+
downloadBtn.classList.add("sc-button-medium");
36+
downloadBtn.classList.add("sc-button-responsive");
37+
downloadBtn.classList.add("sc-button-download");
38+
downloadBtn.classList.add("sc-button-cta");
3539

36-
res = await fetch(jsUrl);
37-
let jsCode = await res.text();
38-
let client_id = new RegExp('client_id:"(.+?)"').exec(jsCode)?.[1];
40+
setInterval(() => {
41+
if (!document.querySelector("#" + btnId)) {
42+
const par = document.querySelector(
43+
".listenEngagement__footer .sc-button-toolbar .sc-button-group"
44+
);
45+
if (par) {
46+
par.prepend(downloadBtn);
47+
}
48+
}
49+
}, [1000]);
3950

40-
return client_id;
41-
},
42-
getResourceInfo: async function (resource_url, client_id) {
43-
let res = await fetch(resource_url);
44-
let text = await res.text();
51+
let clientId;
52+
window.ufs_soundcloud_allData = new Map();
53+
54+
// listen for request => save track
55+
hook(XMLHttpRequest.prototype, "open", async (method, url) => {
56+
const u = new URL(url, document.baseURI);
57+
clientId = u.searchParams.get("client_id") || clientId;
58+
if (!clientId) return;
4559

46-
let x = UsefulScriptGlobalPageContext.Utils.escapeRegExp(
47-
"forEach(function(e){n(e)})}catch(e){}})},"
48-
);
49-
x = new RegExp(x + "(.*)\\);</script>").exec(text);
60+
const res = await fetch(
61+
`https://api-v2.soundcloud.com/resolve?url=${encodeURIComponent(
62+
location.href
63+
)}&client_id=${clientId}`
64+
);
65+
const json = await res.json();
5066

51-
// info = json.loads(x.group(1))[-1]['data'][0]
67+
if (json && json.id) {
68+
// save media
69+
if (json.media) {
70+
window.ufs_soundcloud_allData.set(json.id, json);
71+
}
72+
// save media from tracks
73+
json.tracks
74+
?.filter((track) => track.media)
75+
?.forEach((track) => {
76+
window.ufs_soundcloud_allData.set(track.id, track);
77+
});
5278

53-
// info = info['tracks'] if info.get('track_count') else [info]
79+
// add download button
80+
let songTitle = document
81+
.querySelector(".soundTitle__title")
82+
?.textContent?.trim();
5483

55-
// ids = [i['id'] for i in info if i.get('comment_count') is None]
56-
// ids = list(map(str, ids))
57-
// ids_split = ['%2C'.join(ids[i:i+10]) for i in range(0, len(ids), 10)]
58-
// api_url = 'https://api-v2.soundcloud.com/tracks?ids={ids}&client_id={client_id}&%5Bobject%20Object%5D=&app_version=1584348206&app_locale=en'
84+
let songInCache = Array.from(
85+
window.ufs_soundcloud_allData.values()
86+
).find((_) => _.title === songTitle);
5987

60-
// res = []
61-
// for ids in ids_split:
62-
// uri = api_url.format(ids=ids, client_id=client_id)
63-
// cont = get_content(uri, decoded=True)
64-
// res += json.loads(cont)
88+
const progressive = songInCache?.media?.transcodings?.find?.(
89+
(t) => t?.format?.protocol === "progressive"
90+
);
91+
if (progressive) {
92+
downloadBtn.textContent = "Download";
93+
downloadBtn.onclick = async (e) => {
94+
const res = await fetch(progressive.url + `?client_id=${clientId}`);
95+
const { url } = await res.json();
96+
window.open(url);
97+
};
98+
} else {
99+
downloadBtn.textContent = "Unsupported";
100+
downloadBtn.onclick = () => {
101+
alert("Sorry, downloading this music is currently unsupported.");
102+
};
103+
}
104+
}
105+
});
65106

66-
// res = iter(res)
67-
// info = [next(res) if i.get('comment_count') is None else i for i in info]
107+
// for (const f of ["pushState", "replaceState", "forward", "back", "go"]) {
108+
// hook(history, f, () => {
68109

69-
// return info
110+
// });
111+
// }
70112
},
71113
};
29.8 KB
Loading

working_note.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,7 @@
1919
- [ ] html2img khá ngon, nhưng chưa biết xài vô cái gì
2020

2121
- [ ] Crack tải pdf trên tailieugiangday.vn dễ vl
22+
23+
- [ ] Optimize import jszip
24+
25+
- [ ] làm cho xong soundcloud_downloadMusic hoặc xóa

0 commit comments

Comments
 (0)