From e845ca3b61d6320440175a7b0d9144191912c621 Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Tue, 2 Jul 2024 15:55:20 +0700 Subject: [PATCH 01/44] fix ava style --- scripts/_ufs_statistic.css | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/_ufs_statistic.css b/scripts/_ufs_statistic.css index 68ff0c30..281ad85f 100644 --- a/scripts/_ufs_statistic.css +++ b/scripts/_ufs_statistic.css @@ -9,6 +9,10 @@ canvas { max-height: 500px; } +li { + position: relative; +} + li:hover { background: #555; color: white; @@ -16,14 +20,13 @@ li:hover { li a { display: inline-block; - position: relative; } li a img { width: 30px; transition: all 0.2s ease; position: absolute; - left: 0; + right: 0; top: 0; } From 0072fcadf4cc390ce2f624ec1352432c0aeefccf Mon Sep 17 00:00:00 2001 From: HoangTran <99.hoangtran@gmail.com> Date: Wed, 3 Jul 2024 03:38:23 +0700 Subject: [PATCH 02/44] . --- scripts/backup/fb-proxy.js | 39 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/scripts/backup/fb-proxy.js b/scripts/backup/fb-proxy.js index bb388a6c..30a090f7 100644 --- a/scripts/backup/fb-proxy.js +++ b/scripts/backup/fb-proxy.js @@ -1,3 +1,12 @@ +function uuidv4() { + let h = new Date().getTime(); + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (i) { + let F = (h + 16 * Math.random()) % 16 | 0; + h = Math.floor(h / 16); + return (i == "x" ? F : (3 & F) | 8).toString(16); + }); +} + (function () { "use strict"; (function () { @@ -17,25 +26,11 @@ return code.slice(code.indexOf("{") + 1, code.lastIndexOf("}")) || ""; })(code), fnParams = (function (code) { - let i = code.replace(b, ""), + let i = code.replace(commentRegex, ""), F = i.slice(i.indexOf("(") + 1, i.indexOf(")")).match(s); return F === null && (F = []), F; })(code), - uuid = - "id_" + - (function () { - let h = new Date().getTime(); - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace( - /[xy]/g, - function (i) { - var F = (h + 16 * Math.random()) % 16 | 0; - return ( - (h = Math.floor(h / 16)), - (i == "x" ? F : (3 & F) | 8).toString(16) - ); - } - ); - })(); + uuid = "id_" + uuidv4(); let y = `window['__fnCache']["${uuid}"]= function(${fnParams}){${fnBody}}`, c = document.createElement("script"); try { @@ -48,7 +43,7 @@ return v.appendChild(c), v.removeChild(c), window.__fnCache[`${uuid}`]; } window.__fnCache = window.__fnCache || {}; - let b = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm, + let commentRegex = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm, s = /([^\s,]+)/g; function m(r, f, u = !1) { const w = f.split(/\.|\[(\d+)\]/).filter(Boolean); @@ -66,19 +61,19 @@ w = {}, y = {}, c = {}; - let v = window.__d; + let modified__d = window.__d; window.__d && - (~v.toString().indexOf("__d_stub") + (~modified__d.toString().indexOf("__d_stub") ? delete window.__d - : (v = new Proxy(window.__d, { + : (modified__d = new Proxy(window.__d, { apply: (e, t, d) => ((d = i(d)), e.apply(t, d)), }))), Object.defineProperty(window, "__d", { get: function () { - return v; + return modified__d; }, set: function (e) { - v = new Proxy(e, { + modified__d = new Proxy(e, { apply: (t, d, p) => ((p = i(p)), t.apply(d, p)), }); }, From 9f986c5d8974cef6d8ce7e6c8a74ed02d71b714b Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Wed, 3 Jul 2024 13:16:40 +0700 Subject: [PATCH 03/44] WIP --- scripts/backup/fb-proxy.js | 710 ++++++++++++++++++++----------------- 1 file changed, 379 insertions(+), 331 deletions(-) diff --git a/scripts/backup/fb-proxy.js b/scripts/backup/fb-proxy.js index 30a090f7..4d0efc85 100644 --- a/scripts/backup/fb-proxy.js +++ b/scripts/backup/fb-proxy.js @@ -1,4 +1,4 @@ -function uuidv4() { +function make_uuid() { let h = new Date().getTime(); return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (i) { let F = (h + 16 * Math.random()) % 16 | 0; @@ -10,15 +10,15 @@ function uuidv4() { (function () { "use strict"; (function () { - function n(r) { - return r + function decodeModuleName(encoded) { + return encoded .split("") .reverse() .map((f) => String.fromCharCode(f.charCodeAt(0) - 1)) .join(""); } - function l(r) { - const [f, u = "default"] = n(r).split("|"); + function getModuleName(encoded) { + const [f, u = "default"] = decodeModuleName(encoded).split("|"); return [f, u]; } function cacheFunction(code) { @@ -30,7 +30,7 @@ function uuidv4() { F = i.slice(i.indexOf("(") + 1, i.indexOf(")")).match(s); return F === null && (F = []), F; })(code), - uuid = "id_" + uuidv4(); + uuid = "id_" + make_uuid(); let y = `window['__fnCache']["${uuid}"]= function(${fnParams}){${fnBody}}`, c = document.createElement("script"); try { @@ -53,20 +53,23 @@ function uuidv4() { if (((y = c), (c = c[w[v]]), c === void 0)) return u ? y : void 0; return u ? y : c; } - ((r) => { + (() => { if (window.GZUAwCFuFf) return; window.GZUAwCFuFf = !0; - const f = {}, + const moduleCached = {}, u = {}, w = {}, - y = {}, + isModuleLoaded = {}, c = {}; let modified__d = window.__d; window.__d && (~modified__d.toString().indexOf("__d_stub") ? delete window.__d : (modified__d = new Proxy(window.__d, { - apply: (e, t, d) => ((d = i(d)), e.apply(t, d)), + apply: (target, thisArg, argumentsList) => ( + (argumentsList = i(argumentsList)), + target.apply(thisArg, argumentsList) + ), }))), Object.defineProperty(window, "__d", { get: function () { @@ -74,89 +77,100 @@ function uuidv4() { }, set: function (e) { modified__d = new Proxy(e, { - apply: (t, d, p) => ((p = i(p)), t.apply(d, p)), + apply: (target, thisArg, argumentsList) => ( + (argumentsList = i(argumentsList)), + target.apply(thisArg, argumentsList) + ), }); }, }); - const h = []; + const moduleNames = []; function i(e) { - let [t, d, p] = e; + let [moduleName, dependencies, callback] = e; return ( - typeof t != "string" || - h.includes(t) || - (h.push(t), - (e[2] = (function (_, S) { - if (!w[S]) return _; - const k = w[S]; + typeof moduleName != "string" || + moduleNames.includes(moduleName) || + (moduleNames.push(moduleName), + (e[2] = (function (orig, _moduleName) { + if (!w[_moduleName]) return orig; + const k = w[_moduleName]; k.sort((a, A) => a.options.order - A.options.order); const E = k.find((a) => a.options.skipOthers); return cacheFunction( E - ? E.replacement(_.toString()) - : k.reduce((a, A) => (a = A.replacement(a)), _.toString()) + ? E.replacement(orig.toString()) + : k.reduce((a, A) => (a = A.replacement(a)), orig.toString()) ); - })(e[2], t)), - (e[2] = (function (_, S) { - return u[S] - ? new Proxy(_, { - apply(k, E, a) { - if (a[5] && a[5].dependencies) - for (let x = 0; x < a[5].dependencies.length; x++) - a.push(a[5].dependencies[x].exports); - const A = k.apply(E, a); + })(e[2], moduleName)), + (e[2] = (function (orig, _moduleName) { + return u[_moduleName] + ? new Proxy(orig, { + apply(target, thisArg, argsList) { + if (argsList[5] && argsList[5].dependencies) + for ( + let i = 0; + i < argsList[5].dependencies.length; + i++ + ) + argsList.push(argsList[5].dependencies[i].exports); + const res = target.apply(thisArg, argsList); return ( - u[S].map((x) => { - x(a); + u[_moduleName].map((x) => { + x(argsList); }), - A + res ); }, }) - : _; - })(e[2], t)), - (e[2] = (function (_, S) { - if (!f[S] || f[S].length === 0) return _; - const k = f[S]; + : orig; + })(e[2], moduleName)), + (e[2] = (function (orig, _moduleName) { + if ( + !moduleCached[_moduleName] || + moduleCached[_moduleName].length === 0 + ) + return orig; + const k = moduleCached[_moduleName]; k.sort((a, A) => a.options.order - A.options.order); const E = k.reduce((a, A) => { const x = A.options.definerPath; return (a[x] = a[x] || []), a[x].push(A), a; }, {}); - return new Proxy(_, { - apply(a, A, x) { - const L = a.apply(A, x); - if (x[5] && x[5].dependencies) - for (let j = 0; j < x[5].dependencies.length; j++) - x.push(x[5].dependencies[j].exports); - const q = x[3], - Q = (0, x[2])("CometErrorBoundary.react"), + return new Proxy(orig, { + apply(target, thisArg, argsList) { + const L = target.apply(thisArg, argsList); + if (argsList[5] && argsList[5].dependencies) + for (let j = 0; j < argsList[5].dependencies.length; j++) + argsList.push(argsList[5].dependencies[j].exports); + const _import = argsList[3], + Q = (0, argsList[2])("CometErrorBoundary.react"), B = (j) => (console.error(j), "Error"); for (let j in E) { - const U = m(x, j, !0), + const U = m(argsList, j, !0), G = j.split(".").pop(), - K = m(x, j); - U[G] = function (...D) { - const Y = K.apply(K, D), - R = D[0], + K = m(argsList, j); + U[G] = function (...callingArgs) { + const sourceCmp = K.apply(K, callingArgs), + payload = callingArgs[0], { useState: M, useEffect: W, jsx: T, Fragment: O, - } = q("react"), + } = _import("react"), [Z, X] = M(0), V = () => { - if (!E[j]) return I(Y); + if (!E[j]) return I(sourceCmp); const g = E[j].find((z) => z.options.skipOthers); if (g && g.component) return T(g.fallback ? Q : O, { fallback: g.fallback, children: T(g.component, { - payload: R, - SourceCmp: Y, - lastCmp: I(Y), - definedArgs: x, - callingArgs: D, + payload: payload, + SourceCmp: sourceCmp, + lastCmp: I(sourceCmp), + definedArgs: argsList, + callingArgs: callingArgs, extraPayloadFromDefiner: g.options.extraPayload, proxyCount: 0, removeThisModuleProxy() { @@ -167,32 +181,34 @@ function uuidv4() { }); let $ = 0; return E[j].reduce( - (z, P) => ( + (lastCmp, P) => ( P.component && - ((z = T(P.fallback ? Q : O, { + ((lastCmp = T(P.fallback ? Q : O, { fallback: P.fallback, children: T(P.component, { - payload: R, - SourceCmp: Y, - lastCmp: z, + payload: payload, + SourceCmp: sourceCmp, + lastCmp: lastCmp, extraPayloadFromDefiner: P.options.extraPayload, proxyCount: $, - definedArgs: x, - callingArgs: D, + definedArgs: argsList, + callingArgs: callingArgs, removeThisModuleProxy() { const N = E[j].indexOf(P); if (~N) { const J = k.indexOf(P); - E[j].splice(N, 1), k.splice(J, 1), C(S); + E[j].splice(N, 1), + k.splice(J, 1), + C(_moduleName); } }, }), })), $++), - z + lastCmp ), - I(Y) + I(sourceCmp) ); }; function I(g) { @@ -202,7 +218,7 @@ function uuidv4() { } return ( W(() => { - const g = F(S, () => { + const g = F(_moduleName, () => { X(Math.random()); }); return () => g(); @@ -217,8 +233,8 @@ function uuidv4() { return L; }, }); - })(e[2], t)), - y[t] && console.log(t, e)), + })(e[2], moduleName)), + isModuleLoaded[moduleName] && console.log(moduleName, e)), e ); } @@ -235,260 +251,289 @@ function uuidv4() { function C(e) { if (c[e]) for (let t of c[e]) t(); } - (r.zKjQYvgSmF = function (e) { - return window.require(n(e)); - }), - (r.zKjQYvcSmF = (e, t, d) => { - const [p, _] = l(e); - f[p] || console.error(`Undefined module ${p} from ${_} #1`); - const S = f[p].find((E) => E.extensionId === _); - if (!S) return console.error(`Undefined module ${p} from ${_} #2`); - const { fallback: k } = d || {}; - (S.component = t), (S.fallback = k), C(p); - }), - (r.zKjQYVcSmF = (e, t) => { - const d = Object.assign( - { - order: 10, - skipOthers: !1, - beforeInject: () => !0, - afterInject: () => {}, - extraPayload: void 0, - definerPath: "[6].default", - }, - t - ), - [p, _] = l(e); - (f[p] = f[p] || []), - f[p].push({ - extensionId: _, - moduleName: p, - options: d, - component: void 0, - fallback: void 0, - }); - }), - (r.zKjQYwcSmF = (e) => { - y[n(e)] = !0; - }), - (r.zKjQYvcSfF = (e, t, d) => { - const p = Object.assign( - { - order: 10, - skipOthers: !1, - }, - d - ), - [_, S] = l(e); - (w[_] = w[_] || []), - w[_].push({ - moduleName: _, - options: p, - replacement: t, - }); - }), - (r.zKGQYvcSmF = (e, t) => { - (e = n(e)), (u[e] = u[e] || []), u[e].push(t); - }), - r.zKjQYvcSfF("umvbgfe}spssf.cg", (e) => - e.replace( - 'debugjs.")', - 'debugjs.");console.error(b.stackFrames.slice(0,10).map(e=>e.text).join("\\n"))' - ) - ), - r.zKjQYvcSfF("umvbgfe}djttbmd/epsq.NPEudbfS", (e) => - e.replace(/Error\(\w\(418\)\)/g, "void 0") - ), - r.zKjQYvcSfF("umvbgfe}fvfvRitjmcvQzbmfS0fsput0fnjuovs.zbmfs", (e) => + window._require = function (e) { + return window.require(decodeModuleName(e)); + }; + window.zKjQYvcSmF = (e, t, d) => { + const [moduleName, _] = getModuleName(e); + moduleCached[moduleName] || + console.error(`Undefined module ${moduleName} from ${_} #1`); + const S = moduleCached[moduleName].find((E) => E.extensionId === _); + if (!S) + return console.error(`Undefined module ${moduleName} from ${_} #2`); + const { fallback } = d || {}; + S.component = t; + S.fallback = fallback; + C(moduleName); + }; + window.zKjQYVcSmF = (e, t) => { + const d = Object.assign( + { + order: 10, + skipOthers: !1, + beforeInject: () => !0, + afterInject: () => {}, + extraPayload: void 0, + definerPath: "[6].default", + }, + t + ); + const [p, _] = getModuleName(e); + moduleCached[p] = moduleCached[p] || []; + moduleCached[p].push({ + extensionId: _, + moduleName: p, + options: d, + component: void 0, + fallback: void 0, + }); + }; + window.zKjQYwcSmF = (e) => { + isModuleLoaded[decodeModuleName(e)] = !0; + }; + window.cheatFbModule_replaceCode = (e, replacement, d) => { + const options = Object.assign( + { + order: 10, + skipOthers: !1, + }, + d + ); + const [moduleName, S] = getModuleName(e); + w[moduleName] = w[moduleName] || []; + w[moduleName].push({ + moduleName: moduleName, + options: options, + replacement: replacement, + }); + }; + window.cheatFbModule_overrideCode = (encodedModuleName, t) => { + encodedModuleName = decodeModuleName(encodedModuleName); + u[encodedModuleName] = u[encodedModuleName] || []; + u[encodedModuleName].push(t); + }; + // 'fb-error|default' + window.cheatFbModule_replaceCode("umvbgfe}spssf.cg", (e) => + e.replace( + 'debugjs.")', + 'debugjs.");console.error(b.stackFrames.slice(0,10).map(e=>e.text).join("\\n"))' + ) + ); + // 'ReactDOM-prod.classic|default' + window.cheatFbModule_replaceCode("umvbgfe}djttbmd/epsq.NPEudbfS", (e) => + e.replace(/Error\(\w\(418\)\)/g, "void 0") + ); + // 'relay-runtime/store/RelayPublishQueue|default' + window.cheatFbModule_replaceCode( + "umvbgfe}fvfvRitjmcvQzbmfS0fsput0fnjuovs.zbmfs", + (e) => e.replace( /,(\w)=new\(b\("relay-runtime\/mutations\/RelayRecordSourceProxy"/, ',$1=window["RlbiULLGWt"]=new(b("relay-runtime/mutations/RelayRecordSourceProxy"' ) - ), - r.zKjQYvcSfF( - "umvbgfe}fvfvRitjmcvQzbmfS0fsput0fnjuovs.zbmfs", - (e) => - (e = e.replace( - /;(\w)\.commitPayload=function\(([\w,]+)\){/, - ";$1.commitPayload=function($2){try{if(arguments[0]){if(arguments[0]?.request?.variables?.__relay_internal__pv__CometUFIReactionEnableShortNamerelayprovider === true) return;};}catch(e){console.log('relayStoreCommitPayload',e)};" - )) - ); - })(window), - ((r) => { - r.vTUNhjwVvX || - ((r.vTUNhjwVvX = !0), - (r.zKjqYvcSmF = (f, u, w) => { - const y = r.RlbiULLGWt, - c = typeof f == "string" ? y.get(f) : f; - if (c === void 0) return c; - let v = ((h = u.replace(/\[(\d+)\]/g, ".$1")), - h.replace(/\((.*?)\.(.*?)\)/g, "($1_*_*_*_*_$2)")).split("."); - var h; - v = v.map((e) => - (function (t) { - return t.replaceAll("_*_*_*_*_", "."); - })(e) - ); - let i = c; - for (let e = 0; e < v.length; e++) { - const t = v[e]; - if (t === "*") return i; - if (t.indexOf("^^") === 0) { - const [d, p] = F(t.substring(2)); - if (((i = i.getLinkedRecords(d, p)), i === void 0)) - return C(t), i; - } else if (t.indexOf("^") === 0) { - const [d, p] = F(t.substring(1)); - if (((i = i.getLinkedRecord(d, p)), i == null)) return C(t), i; - } else if (t.match(/^\d+$/)) { - if (((i = i[parseInt(t)]), i == null)) return C(t), i; - } else { - const [d, p] = F(t); - if (((i = i.getValue(d, p)), i == null)) return C(t), i; - } - } - return i; - function F(e) { - const [t, d] = e.split("{"); - if (!d) return [t, {}]; - if (!w) throw new Error("args undefined"); - return [t, w[d.substring(0, d.length - 1)] || {}]; + ); + // 'relay-runtime/store/RelayPublishQueue|default' + window.cheatFbModule_replaceCode( + "umvbgfe}fvfvRitjmcvQzbmfS0fsput0fnjuovs.zbmfs", + (e) => + (e = e.replace( + /;(\w)\.commitPayload=function\(([\w,]+)\){/, + ";$1.commitPayload=function($2){try{if(arguments[0]){if(arguments[0]?.request?.variables?.__relay_internal__pv__CometUFIReactionEnableShortNamerelayprovider === true) return;};}catch(e){console.log('relayStoreCommitPayload',e)};" + )) + ); + })(); + (() => { + window.vTUNhjwVvX || + ((window.vTUNhjwVvX = !0), + (window.zKjqYvcSmF = (f, u, w) => { + const y = window.RlbiULLGWt, + c = typeof f == "string" ? y.get(f) : f; + if (c === void 0) return c; + let v = ((h = u.replace(/\[(\d+)\]/g, ".$1")), + h.replace(/\((.*?)\.(.*?)\)/g, "($1_*_*_*_*_$2)")).split("."); + var h; + v = v.map((e) => + (function (t) { + return t.replaceAll("_*_*_*_*_", "."); + })(e) + ); + let i = c; + for (let e = 0; e < v.length; e++) { + const t = v[e]; + if (t === "*") return i; + if (t.indexOf("^^") === 0) { + const [d, p] = F(t.substring(2)); + if (((i = i.getLinkedRecords(d, p)), i === void 0)) + return C(t), i; + } else if (t.indexOf("^") === 0) { + const [d, p] = F(t.substring(1)); + if (((i = i.getLinkedRecord(d, p)), i == null)) return C(t), i; + } else if (t.match(/^\d+$/)) { + if (((i = i[parseInt(t)]), i == null)) return C(t), i; + } else { + const [d, p] = F(t); + if (((i = i.getValue(d, p)), i == null)) return C(t), i; } - function C(e) { - ~r.location.search.indexOf("debug") && - console.warn("undefined value", { - id: f, - path: u, - args: w, - currentPath: e, - }); - } - })); - })(window), - ((r) => { - if (window.xmxlgxMDjA) return; - window.xmxlgxMDjA = !0; - let f = {}; - r.zKGQYvcSmF("sf{jmbjsfTbubEfmqnjTsiy", (u) => { - const w = u[4].exports.default; - u[4].exports.default = function (...y) { - const c = y[0].fb_api_req_friendly_name; - return ( - c && f[c] && (y[0] = f[c].reduce((v, h) => (v = h(v)), y[0])), - w.apply(w, y) - ); - }; - }), - (r.zkjQYvcSmF = (u, w) => { - (u = n(u)), (f[u] = f[u] || []), f[u].push(w); - }); - })(window); - })(), - window.zKjQYvcSfF( - "lppcfdbg.spg.offtov}topjujojgfEcpKXBN", - (n) => ( - (n = n.replace( - /markThreadAsRead:function.*?{/, - "markThreadAsRead:function(){return;" - )), - n - ) - ), - window.zKjQYvcSfF( - "lppcfdbg.spg.offtov}fubuThojqzUfsvdfTXBN", - (n) => ((n = n.replaceAll("sendChatStateFromComposer", "none")), n) - ), - window.zKGQYvcSmF("spubdjeoJhojqzUeofTTM", (n) => { - if (n[4].exports) - if (n[4].exports.default) { - const l = n[4].exports.default; - n[4].exports.default = function (...o) { - var b, s; - return ( - (o[2] = !( - (s = - (b = window == null ? void 0 : window.unseen_for_facebook) == - null - ? void 0 - : b.DISABLE_TYPING) != null && s.enable - )), - l.apply(l, o) - ); - }; - } else { - const l = n[4].exports; - n[4].exports = function (...o) { - var b, s; - return ( - (o[2] = !( - (s = - (b = window == null ? void 0 : window.unseen_for_facebook) == - null - ? void 0 - : b.DISABLE_TYPING) != null && s.enable - )), - l.apply(l, o) - ); - }; - } - }), - window.zKGQYvcSmF("3WebfSebfsiUlsbNdjutjnjuqPTM", (n) => { - if (n[4].exports) - if (n[4].exports.default) { - const l = n[4].exports.default; - n[4].exports.default = function (...o) { - var s, m; - let b = o[o.length - 1]; - return (m = - (s = window == null ? void 0 : window.unseen_for_facebook) == null - ? void 0 - : s.DISABLE_READ) != null && m.enable - ? b.resolve([]) - : l.apply(l, o); - }; - } else { - const l = n[4].exports; - n[4].exports = function (...o) { - var s, m; - let b = o[o.length - 1]; - return (m = - (s = window == null ? void 0 : window.unseen_for_facebook) == null - ? void 0 - : s.DISABLE_READ) != null && m.enable - ? b.resolve([]) - : l.apply(l, o); - }; - } - }), - window.zKGQYvcSmF("mqnJ3WebfSebfsiUlsbNdjutjnjuqPTM", (n) => { - if (n[4].exports) - if (n[4].exports.default) { - const l = n[4].exports.default; - n[4].exports.default = function (...o) { - var s, m; - let b = o[o.length - 1]; - return (m = - (s = window == null ? void 0 : window.unseen_for_facebook) == null - ? void 0 - : s.DISABLE_READ) != null && m.enable - ? b.resolve([]) - : l.apply(l, o); - }; - } else { - const l = n[4].exports; - n[4].exports = function (...o) { - var s, m; - let b = o[o.length - 1]; - return (m = - (s = window == null ? void 0 : window.unseen_for_facebook) == null - ? void 0 - : s.DISABLE_READ) != null && m.enable - ? b.resolve([]) - : l.apply(l, o); - }; - } - }), - window.zKGQYvcSmF("cfXmqnJ3WebfSebfsiUlsbNdjutjnjuqPTM", (n) => { + } + return i; + function F(e) { + const [t, d] = e.split("{"); + if (!d) return [t, {}]; + if (!w) throw new Error("args undefined"); + return [t, w[d.substring(0, d.length - 1)] || {}]; + } + function C(e) { + ~window.location.search.indexOf("debug") && + console.warn("undefined value", { + id: f, + path: u, + args: w, + currentPath: e, + }); + } + })); + })(); + (() => { + if (window.xmxlgxMDjA) return; + window.xmxlgxMDjA = !0; + let f = {}; + // 'xhrSimpleDataSerializer' + window.cheatFbModule_overrideCode("sf{jmbjsfTbubEfmqnjTsiy", (u) => { + const w = u[4].exports.default; + u[4].exports.default = function (...y) { + const c = y[0].fb_api_req_friendly_name; + return ( + c && f[c] && (y[0] = f[c].reduce((v, h) => (v = h(v)), y[0])), + w.apply(w, y) + ); + }; + }); + window.zkjQYvcSmF = (u, w) => { + u = decodeModuleName(u); + f[u] = f[u] || []; + f[u].push(w); + }; + })(); + })(); + + // 'MAWJobDefinitions|unseen-for-facebook' + window.cheatFbModule_replaceCode( + "lppcfdbg.spg.offtov}topjujojgfEcpKXBN", + (n) => ( + (n = n.replace( + /markThreadAsRead:function.*?{/, + "markThreadAsRead:function(){return;" + )), + n + ) + ); + + // 'MAWSecureTypingState|unseen-for-facebook' + window.cheatFbModule_replaceCode( + "lppcfdbg.spg.offtov}fubuThojqzUfsvdfTXBN", + (n) => ((n = n.replaceAll("sendChatStateFromComposer", "none")), n) + ); + + // LSSendTypingIndicator + window.cheatFbModule_overrideCode("spubdjeoJhojqzUeofTTM", (n) => { + if (n[4].exports) + if (n[4].exports.default) { + const l = n[4].exports.default; + n[4].exports.default = function (...o) { + var b, s; + return ( + (o[2] = !( + (s = + (b = window == null ? void 0 : window.unseen_for_facebook) == + null + ? void 0 + : b.DISABLE_TYPING) != null && s.enable + )), + l.apply(l, o) + ); + }; + } else { + const l = n[4].exports; + n[4].exports = function (...o) { + var b, s; + return ( + (o[2] = !( + (s = + (b = window == null ? void 0 : window.unseen_for_facebook) == + null + ? void 0 + : b.DISABLE_TYPING) != null && s.enable + )), + l.apply(l, o) + ); + }; + } + }); + + // 'LSOptimisticMarkThreadReadV2' + window.cheatFbModule_overrideCode("3WebfSebfsiUlsbNdjutjnjuqPTM", (n) => { + if (n[4].exports) + if (n[4].exports.default) { + const l = n[4].exports.default; + n[4].exports.default = function (...o) { + var s, m; + let b = o[o.length - 1]; + return (m = + (s = window == null ? void 0 : window.unseen_for_facebook) == null + ? void 0 + : s.DISABLE_READ) != null && m.enable + ? b.resolve([]) + : l.apply(l, o); + }; + } else { + const l = n[4].exports; + n[4].exports = function (...o) { + var s, m; + let b = o[o.length - 1]; + return (m = + (s = window == null ? void 0 : window.unseen_for_facebook) == null + ? void 0 + : s.DISABLE_READ) != null && m.enable + ? b.resolve([]) + : l.apply(l, o); + }; + } + }); + + // 'LSOptimisticMarkThreadReadV2Impl' + window.cheatFbModule_overrideCode("mqnJ3WebfSebfsiUlsbNdjutjnjuqPTM", (n) => { + if (n[4].exports) + if (n[4].exports.default) { + const l = n[4].exports.default; + n[4].exports.default = function (...o) { + var s, m; + let b = o[o.length - 1]; + return (m = + (s = window == null ? void 0 : window.unseen_for_facebook) == null + ? void 0 + : s.DISABLE_READ) != null && m.enable + ? b.resolve([]) + : l.apply(l, o); + }; + } else { + const l = n[4].exports; + n[4].exports = function (...o) { + var s, m; + let b = o[o.length - 1]; + return (m = + (s = window == null ? void 0 : window.unseen_for_facebook) == null + ? void 0 + : s.DISABLE_READ) != null && m.enable + ? b.resolve([]) + : l.apply(l, o); + }; + } + }); + + // 'LSOptimisticMarkThreadReadV2ImplWeb' + window.cheatFbModule_overrideCode( + "cfXmqnJ3WebfSebfsiUlsbNdjutjnjuqPTM", + (n) => { if (n[4].exports) if (n[4].exports.default) { const l = n[4].exports.default; @@ -515,15 +560,18 @@ function uuidv4() { : l.apply(l, o); }; } - }), - window.zKjQYvcSfF( - "lppcfdbg.spg.offtov}udbfs/sfojbuopDufldvCftofqtvTtfjspuT", - (n) => ( - (n = n.replace( - /,onCardSeen:(\w),/g, - ",onCardSeen:window?.unseen_for_facebook?.DISABLE_STORIES_SEEN?.enable ? ()=>{} : $1," - )), - n - ) - ); + } + ); + + // 'StoriesSuspenseBucketContainer.react|unseen-for-facebook' + window.cheatFbModule_replaceCode( + "lppcfdbg.spg.offtov}udbfs/sfojbuopDufldvCftofqtvTtfjspuT", + (n) => ( + (n = n.replace( + /,onCardSeen:(\w),/g, + ",onCardSeen:window?.unseen_for_facebook?.DISABLE_STORIES_SEEN?.enable ? ()=>{} : $1," + )), + n + ) + ); })(); From e0b50f12bc2f1c74cf3f22d093049bb89617654e Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Wed, 3 Jul 2024 18:26:18 +0700 Subject: [PATCH 04/44] new script --- scripts/backup/auto-like-fb.js | 57 ++++++ scripts/backup/fb-proxy.js | 356 ++++++++++++++++----------------- 2 files changed, 235 insertions(+), 178 deletions(-) create mode 100644 scripts/backup/auto-like-fb.js diff --git a/scripts/backup/auto-like-fb.js b/scripts/backup/auto-like-fb.js new file mode 100644 index 00000000..3e22998b --- /dev/null +++ b/scripts/backup/auto-like-fb.js @@ -0,0 +1,57 @@ +javascript: (async function () { + function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + function focusTo(element) { + element.dispatchEvent( + new MouseEvent("pointerover", { + view: window, + bubbles: true, + cancelable: true, + }) + ); + } + + function scrollToBottom() { + window.scrollTo(0, document.body.scrollHeight, { behavior: "smooth" }); + } + + const doneKey = "auto-like-done"; + const btns = []; + while (true) { + if (!btns.length) { + let curBtns = Array.from( + document.querySelectorAll("[aria-label='Bày tỏ cảm xúc']:not(li *)") + ); + let added = 0; + for (let btn of curBtns) { + if (btn.getAttribute(doneKey) === null) { + btns.push(btn); + btn.setAttribute(doneKey, true); + added++; + } + } + if (added === 0) break; + } + + for (let btn of btns) { + btn.scrollIntoView({ + block: "center", + behavior: "smooth", + }); + btn.click(); + await sleep(500); + let loveBtn = document.querySelector("[aria-label='Yêu thích']"); + if (loveBtn) { + focusTo(loveBtn); + await sleep(500); + loveBtn.click(); + await sleep(500); + } + btns.splice(btns.indexOf(btn), 1); + } + scrollToBottom(); + await sleep(1000); + } + alert("xong"); +})(); diff --git a/scripts/backup/fb-proxy.js b/scripts/backup/fb-proxy.js index 4d0efc85..f4b95028 100644 --- a/scripts/backup/fb-proxy.js +++ b/scripts/backup/fb-proxy.js @@ -11,6 +11,7 @@ function make_uuid() { "use strict"; (function () { function decodeModuleName(encoded) { + return encoded; return encoded .split("") .reverse() @@ -18,8 +19,9 @@ function make_uuid() { .join(""); } function getModuleName(encoded) { - const [f, u = "default"] = decodeModuleName(encoded).split("|"); - return [f, u]; + const [moduleName, extensionId = "default"] = + decodeModuleName(encoded).split("|"); + return [moduleName, extensionId]; } function cacheFunction(code) { const fnBody = (function (code) { @@ -87,156 +89,154 @@ function make_uuid() { const moduleNames = []; function i(e) { let [moduleName, dependencies, callback] = e; - return ( - typeof moduleName != "string" || - moduleNames.includes(moduleName) || - (moduleNames.push(moduleName), - (e[2] = (function (orig, _moduleName) { - if (!w[_moduleName]) return orig; - const k = w[_moduleName]; - k.sort((a, A) => a.options.order - A.options.order); - const E = k.find((a) => a.options.skipOthers); - return cacheFunction( - E - ? E.replacement(orig.toString()) - : k.reduce((a, A) => (a = A.replacement(a)), orig.toString()) - ); - })(e[2], moduleName)), - (e[2] = (function (orig, _moduleName) { - return u[_moduleName] - ? new Proxy(orig, { - apply(target, thisArg, argsList) { - if (argsList[5] && argsList[5].dependencies) - for ( - let i = 0; - i < argsList[5].dependencies.length; - i++ - ) - argsList.push(argsList[5].dependencies[i].exports); - const res = target.apply(thisArg, argsList); - return ( - u[_moduleName].map((x) => { - x(argsList); - }), - res - ); - }, - }) - : orig; - })(e[2], moduleName)), - (e[2] = (function (orig, _moduleName) { - if ( - !moduleCached[_moduleName] || - moduleCached[_moduleName].length === 0 - ) - return orig; - const k = moduleCached[_moduleName]; - k.sort((a, A) => a.options.order - A.options.order); - const E = k.reduce((a, A) => { - const x = A.options.definerPath; - return (a[x] = a[x] || []), a[x].push(A), a; - }, {}); - return new Proxy(orig, { + + if (typeof moduleName != "string" || moduleNames.includes(moduleName)) + return; + + moduleNames.push(moduleName); + e[2] = (function (orig, _moduleName) { + if (!w[_moduleName]) return orig; + const k = w[_moduleName]; + k.sort((a, A) => a.options.order - A.options.order); + const E = k.find((a) => a.options.skipOthers); + return cacheFunction( + E + ? E.replacement(orig.toString()) + : k.reduce((a, A) => (a = A.replacement(a)), orig.toString()) + ); + })(e[2], moduleName); + + e[2] = (function (orig, _moduleName) { + return u[_moduleName] + ? new Proxy(orig, { apply(target, thisArg, argsList) { - const L = target.apply(thisArg, argsList); if (argsList[5] && argsList[5].dependencies) - for (let j = 0; j < argsList[5].dependencies.length; j++) - argsList.push(argsList[5].dependencies[j].exports); - const _import = argsList[3], - Q = (0, argsList[2])("CometErrorBoundary.react"), - B = (j) => (console.error(j), "Error"); - for (let j in E) { - const U = m(argsList, j, !0), - G = j.split(".").pop(), - K = m(argsList, j); - U[G] = function (...callingArgs) { - const sourceCmp = K.apply(K, callingArgs), - payload = callingArgs[0], - { - useState: M, - useEffect: W, - jsx: T, - Fragment: O, - } = _import("react"), - [Z, X] = M(0), - V = () => { - if (!E[j]) return I(sourceCmp); - const g = E[j].find((z) => z.options.skipOthers); - if (g && g.component) - return T(g.fallback ? Q : O, { - fallback: g.fallback, - children: T(g.component, { + for (let i = 0; i < argsList[5].dependencies.length; i++) + argsList.push(argsList[5].dependencies[i].exports); + const res = target.apply(thisArg, argsList); + return ( + u[_moduleName].map((x) => { + x(argsList); + }), + res + ); + }, + }) + : orig; + })(e[2], moduleName); + + e[2] = (function (orig, _moduleName) { + if ( + !moduleCached[_moduleName] || + moduleCached[_moduleName].length === 0 + ) + return orig; + const k = moduleCached[_moduleName]; + k.sort((a, A) => a.options.order - A.options.order); + const E = k.reduce((a, A) => { + const x = A.options.definerPath; + return (a[x] = a[x] || []), a[x].push(A), a; + }, {}); + return new Proxy(orig, { + apply(target, thisArg, argsList) { + const L = target.apply(thisArg, argsList); + if (argsList[5] && argsList[5].dependencies) + for (let j = 0; j < argsList[5].dependencies.length; j++) + argsList.push(argsList[5].dependencies[j].exports); + const _import = argsList[3], + Q = (0, argsList[2])("CometErrorBoundary.react"), + B = (j) => (console.error(j), "Error"); + for (let j in E) { + const U = m(argsList, j, !0), + G = j.split(".").pop(), + K = m(argsList, j); + U[G] = function (...callingArgs) { + const sourceCmp = K.apply(K, callingArgs), + payload = callingArgs[0], + { + useState: M, + useEffect: W, + jsx: T, + Fragment: O, + } = _import("react"), + [Z, X] = M(0), + V = () => { + if (!E[j]) return I(sourceCmp); + const g = E[j].find((z) => z.options.skipOthers); + if (g && g.component) + return T(g.fallback ? Q : O, { + fallback: g.fallback, + children: T(g.component, { + payload: payload, + SourceCmp: sourceCmp, + lastCmp: I(sourceCmp), + definedArgs: argsList, + callingArgs: callingArgs, + extraPayloadFromDefiner: g.options.extraPayload, + proxyCount: 0, + removeThisModuleProxy() { + const z = E[j].indexOf(g); + ~z && E[j].splice(z, 1); + }, + }), + }); + let $ = 0; + return E[j].reduce( + (lastCmp, P) => ( + P.component && + ((lastCmp = T(P.fallback ? Q : O, { + fallback: P.fallback, + children: T(P.component, { payload: payload, SourceCmp: sourceCmp, - lastCmp: I(sourceCmp), + lastCmp: lastCmp, + extraPayloadFromDefiner: P.options.extraPayload, + proxyCount: $, definedArgs: argsList, callingArgs: callingArgs, - extraPayloadFromDefiner: g.options.extraPayload, - proxyCount: 0, removeThisModuleProxy() { - const z = E[j].indexOf(g); - ~z && E[j].splice(z, 1); + const N = E[j].indexOf(P); + if (~N) { + const J = k.indexOf(P); + E[j].splice(N, 1), + k.splice(J, 1), + C(_moduleName); + } }, }), - }); - let $ = 0; - return E[j].reduce( - (lastCmp, P) => ( - P.component && - ((lastCmp = T(P.fallback ? Q : O, { - fallback: P.fallback, - children: T(P.component, { - payload: payload, - SourceCmp: sourceCmp, - lastCmp: lastCmp, - extraPayloadFromDefiner: - P.options.extraPayload, - proxyCount: $, - definedArgs: argsList, - callingArgs: callingArgs, - removeThisModuleProxy() { - const N = E[j].indexOf(P); - if (~N) { - const J = k.indexOf(P); - E[j].splice(N, 1), - k.splice(J, 1), - C(_moduleName); - } - }, - }), - })), - $++), - lastCmp - ), - I(sourceCmp) - ); - }; - function I(g) { - return g && g.$1 && typeof g.$1 == "function" - ? T(g, g.props) - : g; - } - return ( - W(() => { - const g = F(_moduleName, () => { - X(Math.random()); - }); - return () => g(); - }, []), - T(Q, { - fallback: B, - children: V(), - }) + })), + $++), + lastCmp + ), + I(sourceCmp) ); }; + function I(g) { + return g && g.$1 && typeof g.$1 == "function" + ? T(g, g.props) + : g; } - return L; - }, - }); - })(e[2], moduleName)), - isModuleLoaded[moduleName] && console.log(moduleName, e)), - e - ); + return ( + W(() => { + const g = F(_moduleName, () => { + X(Math.random()); + }); + return () => g(); + }, []), + T(Q, { + fallback: B, + children: V(), + }) + ); + }; + } + return L; + }, + }); + })(e[2], moduleName); + + isModuleLoaded[moduleName] && console.log(moduleName, e); + return e; } function F(e, t) { return ( @@ -255,12 +255,18 @@ function make_uuid() { return window.require(decodeModuleName(e)); }; window.zKjQYvcSmF = (e, t, d) => { - const [moduleName, _] = getModuleName(e); + const [moduleName, extensionId] = getModuleName(e); moduleCached[moduleName] || - console.error(`Undefined module ${moduleName} from ${_} #1`); - const S = moduleCached[moduleName].find((E) => E.extensionId === _); + console.error( + `Undefined module ${moduleName} from ${extensionId} #1` + ); + const S = moduleCached[moduleName].find( + (E) => E.extensionId === extensionId + ); if (!S) - return console.error(`Undefined module ${moduleName} from ${_} #2`); + return console.error( + `Undefined module ${moduleName} from ${extensionId} #2` + ); const { fallback } = d || {}; S.component = t; S.fallback = fallback; @@ -278,10 +284,10 @@ function make_uuid() { }, t ); - const [p, _] = getModuleName(e); + const [p, extensionId] = getModuleName(e); moduleCached[p] = moduleCached[p] || []; moduleCached[p].push({ - extensionId: _, + extensionId: extensionId, moduleName: p, options: d, component: void 0, @@ -312,29 +318,29 @@ function make_uuid() { u[encodedModuleName] = u[encodedModuleName] || []; u[encodedModuleName].push(t); }; - // 'fb-error|default' - window.cheatFbModule_replaceCode("umvbgfe}spssf.cg", (e) => + + window.cheatFbModule_replaceCode("b-error|default", (e) => e.replace( 'debugjs.")', 'debugjs.");console.error(b.stackFrames.slice(0,10).map(e=>e.text).join("\\n"))' ) ); - // 'ReactDOM-prod.classic|default' - window.cheatFbModule_replaceCode("umvbgfe}djttbmd/epsq.NPEudbfS", (e) => + + window.cheatFbModule_replaceCode("ReactDOM-prod.classic|default", (e) => e.replace(/Error\(\w\(418\)\)/g, "void 0") ); - // 'relay-runtime/store/RelayPublishQueue|default' + window.cheatFbModule_replaceCode( - "umvbgfe}fvfvRitjmcvQzbmfS0fsput0fnjuovs.zbmfs", + "relay-runtime/store/RelayPublishQueue|default", (e) => e.replace( /,(\w)=new\(b\("relay-runtime\/mutations\/RelayRecordSourceProxy"/, ',$1=window["RlbiULLGWt"]=new(b("relay-runtime/mutations/RelayRecordSourceProxy"' ) ); - // 'relay-runtime/store/RelayPublishQueue|default' + window.cheatFbModule_replaceCode( - "umvbgfe}fvfvRitjmcvQzbmfS0fsput0fnjuovs.zbmfs", + "relay-runtime/store/RelayPublishQueue|default", (e) => (e = e.replace( /;(\w)\.commitPayload=function\(([\w,]+)\){/, @@ -396,29 +402,29 @@ function make_uuid() { (() => { if (window.xmxlgxMDjA) return; window.xmxlgxMDjA = !0; - let f = {}; - // 'xhrSimpleDataSerializer' - window.cheatFbModule_overrideCode("sf{jmbjsfTbubEfmqnjTsiy", (u) => { - const w = u[4].exports.default; - u[4].exports.default = function (...y) { - const c = y[0].fb_api_req_friendly_name; + let cache = {}; + window.cheatFbModule_overrideCode("xhrSimpleDataSerializer", (u) => { + const orig = u[4].exports.default; + u[4].exports.default = function (...args) { + const name = args[0].fb_api_req_friendly_name; return ( - c && f[c] && (y[0] = f[c].reduce((v, h) => (v = h(v)), y[0])), - w.apply(w, y) + name && + cache[name] && + (args[0] = cache[name].reduce((v, h) => (v = h(v)), args[0])), + orig.apply(orig, args) ); }; }); window.zkjQYvcSmF = (u, w) => { u = decodeModuleName(u); - f[u] = f[u] || []; - f[u].push(w); + cache[u] = cache[u] || []; + cache[u].push(w); }; })(); })(); - // 'MAWJobDefinitions|unseen-for-facebook' window.cheatFbModule_replaceCode( - "lppcfdbg.spg.offtov}topjujojgfEcpKXBN", + "MAWJobDefinitions|unseen-for-facebook", (n) => ( (n = n.replace( /markThreadAsRead:function.*?{/, @@ -428,14 +434,12 @@ function make_uuid() { ) ); - // 'MAWSecureTypingState|unseen-for-facebook' window.cheatFbModule_replaceCode( - "lppcfdbg.spg.offtov}fubuThojqzUfsvdfTXBN", + "MAWSecureTypingState|unseen-for-facebook", (n) => ((n = n.replaceAll("sendChatStateFromComposer", "none")), n) ); - // LSSendTypingIndicator - window.cheatFbModule_overrideCode("spubdjeoJhojqzUeofTTM", (n) => { + window.cheatFbModule_overrideCode("LSSendTypingIndicator", (n) => { if (n[4].exports) if (n[4].exports.default) { const l = n[4].exports.default; @@ -470,8 +474,7 @@ function make_uuid() { } }); - // 'LSOptimisticMarkThreadReadV2' - window.cheatFbModule_overrideCode("3WebfSebfsiUlsbNdjutjnjuqPTM", (n) => { + window.cheatFbModule_overrideCode("LSOptimisticMarkThreadReadV2", (n) => { if (n[4].exports) if (n[4].exports.default) { const l = n[4].exports.default; @@ -500,8 +503,7 @@ function make_uuid() { } }); - // 'LSOptimisticMarkThreadReadV2Impl' - window.cheatFbModule_overrideCode("mqnJ3WebfSebfsiUlsbNdjutjnjuqPTM", (n) => { + window.cheatFbModule_overrideCode("LSOptimisticMarkThreadReadV2Impl", (n) => { if (n[4].exports) if (n[4].exports.default) { const l = n[4].exports.default; @@ -530,9 +532,8 @@ function make_uuid() { } }); - // 'LSOptimisticMarkThreadReadV2ImplWeb' window.cheatFbModule_overrideCode( - "cfXmqnJ3WebfSebfsiUlsbNdjutjnjuqPTM", + "LSOptimisticMarkThreadReadV2ImplWeb", (n) => { if (n[4].exports) if (n[4].exports.default) { @@ -563,9 +564,8 @@ function make_uuid() { } ); - // 'StoriesSuspenseBucketContainer.react|unseen-for-facebook' window.cheatFbModule_replaceCode( - "lppcfdbg.spg.offtov}udbfs/sfojbuopDufldvCftofqtvTtfjspuT", + "StoriesSuspenseBucketContainer.react|unseen-for-facebook", (n) => ( (n = n.replace( /,onCardSeen:(\w),/g, From a84abacfb9cb44f3b9da9424aad6b2659c8d6ff8 Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Wed, 3 Jul 2024 18:32:45 +0700 Subject: [PATCH 05/44] no smooth --- scripts/backup/auto-like-fb.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/backup/auto-like-fb.js b/scripts/backup/auto-like-fb.js index 3e22998b..e1277934 100644 --- a/scripts/backup/auto-like-fb.js +++ b/scripts/backup/auto-like-fb.js @@ -13,7 +13,9 @@ javascript: (async function () { } function scrollToBottom() { - window.scrollTo(0, document.body.scrollHeight, { behavior: "smooth" }); + window.scrollTo(0, document.body.scrollHeight, { + // behavior: "smooth", + }); } const doneKey = "auto-like-done"; @@ -37,7 +39,7 @@ javascript: (async function () { for (let btn of btns) { btn.scrollIntoView({ block: "center", - behavior: "smooth", + // behavior: "smooth", }); btn.click(); await sleep(500); @@ -51,7 +53,7 @@ javascript: (async function () { btns.splice(btns.indexOf(btn), 1); } scrollToBottom(); - await sleep(1000); + await sleep(3000); } alert("xong"); })(); From e8c28934706efea1cb12e7820616dcdaa037458a Mon Sep 17 00:00:00 2001 From: HoangTran <99.hoangtran@gmail.com> Date: Thu, 4 Jul 2024 00:35:28 +0700 Subject: [PATCH 06/44] WIP --- scripts/backup/m38u_detector.js | 820 ++++++++++++++++++++++++ scripts/fb_downloadWatchingVideo.js | 13 +- scripts/youtube_localDownloader.js | 430 +++++++++++++ scripts/youtube_localDownloader_main.js | 2 +- working_note.md | 6 +- 5 files changed, 1260 insertions(+), 11 deletions(-) create mode 100644 scripts/backup/m38u_detector.js diff --git a/scripts/backup/m38u_detector.js b/scripts/backup/m38u_detector.js new file mode 100644 index 00000000..e0066ae8 --- /dev/null +++ b/scripts/backup/m38u_detector.js @@ -0,0 +1,820 @@ +// ==UserScript== +// @name m3u8视频侦测下载器【自动嗅探】 +// @name:zh-CN m3u8视频侦测下载器【自动嗅探】 +// @name:zh-TW m3u8視頻偵測下載器【自動嗅探】 +// @name:en M3U8 Video Detector and Downloader +// @version 1.4.1 +// @description 自动检测页面m3u8视频并进行完整下载。检测到m3u8链接后会自动出现在页面右上角位置,点击下载即可跳转到m3u8下载器。 +// @description:zh-CN 自动检测页面m3u8视频并进行完整下载。检测到m3u8链接后会自动出现在页面右上角位置,点击下载即可跳转到m3u8下载器。 +// @description:zh-TW 自動檢測頁面m3u8視頻並進行完整下載。檢測到m3u8鏈接後會自動出現在頁面右上角位置,點擊下載即可跳轉到m3u8下載器。 +// @description:en Automatically detect the m3u8 video of the page and download it completely. Once detected the m3u8 link, it will appear in the upper right corner of the page. Click download to jump to the m3u8 downloader. +// @icon https://tools.thatwind.com/favicon.png +// @author allFull +// @namespace https://tools.thatwind.com/ +// @homepage https://tools.thatwind.com/tool/m3u8downloader +// @match *://*/* +// @exclude *://www.diancigaoshou.com/* +// @require https://cdn.jsdelivr.net/npm/m3u8-parser@4.7.1/dist/m3u8-parser.min.js +// @connect * +// @grant unsafeWindow +// @grant GM_openInTab +// @grant GM.openInTab +// @grant GM_getValue +// @grant GM.getValue +// @grant GM_setValue +// @grant GM.setValue +// @grant GM_deleteValue +// @grant GM.deleteValue +// @grant GM_xmlhttpRequest +// @grant GM.xmlHttpRequest +// @grant GM_download +// @run-at document-start +// ==/UserScript== + +(function () { + "use strict"; + + const mgmapi = { + addStyle(s) { + let style = document.createElement("style"); + style.innerHTML = s; + document.documentElement.appendChild(style); + }, + async getValue(name, defaultVal) { + return await (typeof GM_getValue === "function" + ? GM_getValue + : GM.getValue)(name, defaultVal); + }, + async setValue(name, value) { + return await (typeof GM_setValue === "function" + ? GM_setValue + : GM.setValue)(name, value); + }, + async deleteValue(name) { + return await (typeof GM_deleteValue === "function" + ? GM_deleteValue + : GM.deleteValue)(name); + }, + openInTab(url, open_in_background = false) { + return (typeof GM_openInTab === "function" ? GM_openInTab : GM.openInTab)( + url, + open_in_background + ); + }, + xmlHttpRequest(details) { + return ( + typeof GM_xmlhttpRequest === "function" + ? GM_xmlhttpRequest + : GM.xmlHttpRequest + )(details); + }, + download(details) { + return this.openInTab(details.url); + + if (typeof GM_download === "function") { + this.message( + "下载中,请留意浏览器下载弹窗\nDownloading, pay attention to the browser's download pop-up.", + 3000 + ); + return GM_download(details); + } else { + this.openInTab(details.url); + } + }, + copyText(text) { + copyTextToClipboard(text); + function copyTextToClipboard(text) { + // 复制文本 + var copyFrom = document.createElement("textarea"); + copyFrom.textContent = text; + document.body.appendChild(copyFrom); + copyFrom.select(); + document.execCommand("copy"); + copyFrom.blur(); + document.body.removeChild(copyFrom); + } + }, + message(text, disappearTime = 5000) { + const id = "f8243rd238-gm-message-panel"; + let p = document.querySelector(`#${id}`); + if (!p) { + p = document.createElement("div"); + p.id = id; + p.style = ` + position: fixed; + bottom: 20px; + right: 20px; + display: flex; + flex-direction: column; + align-items: end; + z-index: 999999999999999; + `; + (document.body || document.documentElement).appendChild(p); + } + let mdiv = document.createElement("div"); + mdiv.innerText = text; + mdiv.style = ` + padding: 3px 8px; + border-radius: 5px; + background: black; + box-shadow: #000 1px 2px 5px; + margin-top: 10px; + font-size: small; + color: #fff; + text-align: right; + `; + p.appendChild(mdiv); + setTimeout(() => { + p.removeChild(mdiv); + }, disappearTime); + }, + }; + + if ( + location.host === "tools.thatwind.com" || + location.host === "localhost:3000" + ) { + mgmapi.addStyle("#userscript-tip{display:none !important;}"); + + // 对请求做代理 + const _fetch = unsafeWindow.fetch; + unsafeWindow.fetch = async function (...args) { + try { + let response = await _fetch(...args); + if (response.status !== 200) throw new Error(response.status); + return response; + } catch (e) { + // 失败请求使用代理 + if (args.length == 1) { + console.log(`请求代理:${args[0]}`); + return await new Promise((resolve, reject) => { + let referer = new URLSearchParams(location.hash.slice(1)).get( + "referer" + ); + let headers = {}; + if (referer) { + referer = new URL(referer); + headers = { + origin: referer.origin, + referer: referer.href, + }; + } + mgmapi.xmlHttpRequest({ + method: "GET", + url: args[0], + responseType: "arraybuffer", + headers, + onload(r) { + resolve({ + status: r.status, + headers: new Headers( + r.responseHeaders + .split("\n") + .filter((n) => n) + .map((s) => s.split(/:\s*/)) + .reduce((all, [a, b]) => { + all[a] = b; + return all; + }, {}) + ), + async text() { + return r.responseText; + }, + async arrayBuffer() { + return r.response; + }, + }); + }, + onerror() { + reject(new Error()); + }, + }); + }); + } else { + throw e; + } + } + }; + + return; + } + + // iframe 信息交流 + // 目前只用于获取顶部标题 + window.addEventListener("message", async (e) => { + if (e.data === "3j4t9uj349-gm-get-title") { + let name = `top-title-${Date.now()}`; + await mgmapi.setValue(name, document.title); + e.source.postMessage(`3j4t9uj349-gm-top-title-name:${name}`, "*"); + } + }); + + function getTopTitle() { + return new Promise((resolve) => { + window.addEventListener("message", async function l(e) { + if (typeof e.data === "string") { + if (e.data.startsWith("3j4t9uj349-gm-top-title-name:")) { + let name = e.data.slice("3j4t9uj349-gm-top-title-name:".length); + await new Promise((r) => setTimeout(r, 5)); // 等5毫秒 确定 setValue 已经写入 + resolve(await mgmapi.getValue(name)); + mgmapi.deleteValue(name); + window.removeEventListener("message", l); + } + } + }); + window.top.postMessage("3j4t9uj349-gm-get-title", "*"); + }); + } + + { + // 请求检测 + // const _fetch = unsafeWindow.fetch; + // unsafeWindow.fetch = function (...args) { + // if (checkUrl(args[0])) doM3U({ url: args[0] }); + // return _fetch(...args); + // } + + const _r_text = unsafeWindow.Response.prototype.text; + unsafeWindow.Response.prototype.text = function () { + return new Promise((resolve, reject) => { + _r_text + .call(this) + .then((text) => { + resolve(text); + if (checkContent(text)) doM3U({ url: this.url, content: text }); + }) + .catch(reject); + }); + }; + + const _open = unsafeWindow.XMLHttpRequest.prototype.open; + unsafeWindow.XMLHttpRequest.prototype.open = function (...args) { + this.addEventListener("load", () => { + try { + let content = this.responseText; + if (checkContent(content)) doM3U({ url: args[1], content }); + } catch {} + }); + // checkUrl(args[1]); + return _open.apply(this, args); + }; + + function checkUrl(url) { + url = new URL(url, location.href); + if (url.pathname.endsWith(".m3u8") || url.pathname.endsWith(".m3u")) { + // 发现 + return true; + } + } + + function checkContent(content) { + if (content.trim().startsWith("#EXTM3U")) { + return true; + } + } + + // 检查纯视频 + setInterval(doVideos, 1000); + } + + const rootDiv = document.createElement("div"); + rootDiv.style = ` + position: fixed; + z-index: 9999999999999999; + opacity: 0.9; + `; + rootDiv.style.display = "none"; + document.documentElement.appendChild(rootDiv); + + const shadowDOM = rootDiv.attachShadow({ mode: "open" }); + const wrapper = document.createElement("div"); + shadowDOM.appendChild(wrapper); + + // 指示器 + const bar = document.createElement("div"); + bar.style = ` + text-align: right; + `; + bar.innerHTML = ` + + + + + + + + `; + + wrapper.appendChild(bar); + + // 样式 + const style = document.createElement("style"); + + style.innerHTML = ` + .number-indicator{ + position:relative; + } + + .number-indicator::after{ + content: attr(data-number); + position: absolute; + bottom: 0; + right: 0; + color: #40a9ff; + font-size: 14px; + font-weight: bold; + background: #000; + border-radius: 10px; + padding: 3px 5px; + } + + .copy-link:active{ + color: #ccc; + } + + .download-btn:hover{ + text-decoration: underline; + } + .download-btn:active{ + opacity: 0.9; + } + + .m3u8-item{ + color: white; + margin-bottom: 5px; + display: flex; + flex-direction: row; + background: black; + padding: 3px 10px; + border-radius: 3px; + font-size: 14px; + user-select: none; + } + + [data-shown="false"] { + opacity: 0.8; + zoom: 0.8; + } + + [data-shown="false"]:hover{ + opacity: 1; + } + + [data-shown="false"] .m3u8-item{ + display: none; + } + + `; + + wrapper.appendChild(style); + + const barBtn = bar.querySelector(".number-indicator"); + + // 关于显隐和移动 + + (async function () { + let shown = await GM_getValue("shown", true); + wrapper.setAttribute("data-shown", shown); + + let x = await GM_getValue("x", 10); + let y = await GM_getValue("y", 10); + + x = Math.min(innerWidth - 50, x); + y = Math.min(innerHeight - 50, y); + + if (x < 0) x = 0; + if (y < 0) y = 0; + + rootDiv.style.top = `${y}px`; + rootDiv.style.right = `${x}px`; + + barBtn.addEventListener("mousedown", (e) => { + let startX = e.pageX; + let startY = e.pageY; + + let moved = false; + + let mousemove = (e) => { + let offsetX = e.pageX - startX; + let offsetY = e.pageY - startY; + if (moved || Math.abs(offsetX) + Math.abs(offsetY) > 5) { + moved = true; + rootDiv.style.top = `${y + offsetY}px`; + rootDiv.style.right = `${x - offsetX}px`; + } + }; + let mouseup = (e) => { + let offsetX = e.pageX - startX; + let offsetY = e.pageY - startY; + + if (moved) { + x -= offsetX; + y += offsetY; + mgmapi.setValue("x", x); + mgmapi.setValue("y", y); + } else { + shown = !shown; + mgmapi.setValue("shown", shown); + wrapper.setAttribute("data-shown", shown); + } + + removeEventListener("mousemove", mousemove); + removeEventListener("mouseup", mouseup); + }; + addEventListener("mousemove", mousemove); + addEventListener("mouseup", mouseup); + }); + })(); + + let count = 0; + let shownUrls = []; + + function doVideos() { + for (let v of Array.from(document.querySelectorAll("video"))) { + if ( + v.duration && + v.src && + v.src.startsWith("http") && + !shownUrls.includes(v.src) + ) { + const src = v.src; + + shownUrls.push(src); + showVideo({ + type: "video", + url: new URL(src), + duration: `${Math.ceil((v.duration * 10) / 60) / 10} mins`, + download() { + const details = { + url: src, + name: (() => { + let name = new URL(src).pathname.split("/").slice(-1)[0]; + if (!/\.\w+$/.test(name)) { + if (name.match(/^\s*$/)) name = Date.now(); + name = name + ".mp4"; + } + return name; + })(), + headers: { + // referer: location.origin, // 不允许该头 + origin: location.origin, + }, + onerror(e) { + mgmapi.openInTab(src); + }, + }; + mgmapi.download(details); + }, + }); + } + } + } + + async function doM3U({ url, content }) { + url = new URL(url); + + if (shownUrls.includes(url.href)) return; + + // 解析 m3u + content = content || (await (await fetch(url)).text()); + + const parser = new m3u8Parser.Parser(); + parser.push(content); + parser.end(); + const manifest = parser.manifest; + + if (manifest.segments) { + let duration = 0; + manifest.segments.forEach((segment) => { + duration += segment.duration; + }); + manifest.duration = duration; + } + + showVideo({ + type: "m3u8", + url, + duration: manifest.duration + ? `${Math.ceil((manifest.duration * 10) / 60) / 10} mins` + : manifest.playlists + ? `多(Multi)(${manifest.playlists.length})` + : "未知(unknown)", + async download() { + mgmapi.openInTab( + `https://tools.thatwind.com/tool/m3u8downloader#${new URLSearchParams( + { + m3u8: url.href, + referer: location.href, + filename: (await getTopTitle()) || "", + } + )}` + ); + }, + }); + } + + async function showVideo({ type, url, duration, download }) { + let div = document.createElement("div"); + div.className = "m3u8-item"; + div.innerHTML = ` + ${type} + ${url.pathname} + ${duration} + 下载(Download) + `; + + div.querySelector(".copy-link").addEventListener("click", () => { + // 复制链接 + mgmapi.copyText(url.href); + mgmapi.message("已复制链接 (link copied)", 2000); + }); + + div.querySelector(".download-btn").addEventListener("click", download); + + rootDiv.style.display = "block"; + + count++; + + shownUrls.push(url.href); + + bar.querySelector(".number-indicator").setAttribute("data-number", count); + + wrapper.appendChild(div); + } +})(); + +(function () { + "use strict"; + + const reg = /magnet:\?xt=urn:btih:\w{10,}([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/; + + let l = navigator.language || "en"; + if (l.startsWith("en-")) l = "en"; + else if (l.startsWith("zh-")) l = "zh-CN"; + else l = "en"; + + const T = { + en: { + play: "Play", + }, + "zh-CN": { + play: "播放", + }, + }[l]; + + whenDOMReady(() => { + addStyle(` + button[data-wtmzjk-mag-url]{ + all: initial; + border: none; + outline: none; + background: none; + background: #f7d308; + background: #08a6f7; + margin: 2px 8px; + border-radius: 3px; + color: white; + cursor: pointer; + display: inline-flex; + height: 1.6em; + padding: 0 .8em; + align-items: center; + justify-content: center; + transition: background .15s; + text-decoration: none; + border-radius: 0.8em; + font-size: small; + } + button[data-wtmzjk-mag-url]>svg{ + height: 60%; + fill: white; + pointer-events: none; + } + button[data-wtmzjk-mag-url]:hover{ + background: #fae157; + background: #39b9f9; + } + button[data-wtmzjk-mag-url]:active{ + background: #dfbe07; + background: #0797df; + } + button[data-wtmzjk-mag-url]>span{ + pointer-events: none; + font-size: small;margin-right: .5em;font-weight:bold;color:white !important; + } + `); + window.addEventListener("click", onEvents, true); + window.addEventListener("mousedown", onEvents, true); + window.addEventListener("mouseup", onEvents, true); + + watchBodyChange(work); + }); + + function onEvents(e) { + if (e.target.hasAttribute("data-wtmzjk-mag-url")) { + e.preventDefault(); + e.stopPropagation(); + if (e.type == "click") { + let a = document.createElement("a"); + a.href = + "https://www.diancigaoshou.com/#" + + new URLSearchParams({ + url: e.target.getAttribute("data-wtmzjk-mag-url"), + }); + a.target = "_blank"; + a.click(); + } + } + } + + function createWatchButton(url, isForPlain = false) { + let button = document.createElement("button"); + button.setAttribute("data-wtmzjk-mag-url", url); + if (isForPlain) button.setAttribute("data-wtmzjk-button-for-plain", ""); + button.innerHTML = `${T.play}`; + return button; + } + + function hasPlainMagUrlThatNotHandled() { + let m = document.body.textContent.match(new RegExp(reg, "g")); + return ( + document.querySelectorAll(`[data-wtmzjk-button-for-plain]`).length != + (m ? m.length : 0) + ); + } + + function work() { + if (!document.body) return; + if (hasPlainMagUrlThatNotHandled()) { + for (let node of getAllTextNodes(document.body)) { + if ( + node.nextSibling && + node.nextSibling.hasAttribute && + node.nextSibling.hasAttribute("data-wtmzjk-mag-url") + ) + continue; + let text = node.nodeValue; + if (!reg.test(text)) continue; + let match = text.match(reg); + if (match) { + let url = match[0]; + let p = node.parentNode; + p.insertBefore( + document.createTextNode(text.slice(0, match.index + url.length)), + node + ); + p.insertBefore(createWatchButton(url, true), node); + p.insertBefore( + document.createTextNode(text.slice(match.index + url.length)), + node + ); + p.removeChild(node); + } + } + } + for (let a of Array.from( + document.querySelectorAll( + [ + "href", + "value", + "data-clipboard-text", + "data-value", + "title", + "alt", + "data-url", + "data-magnet", + "data-copy", + ] + .map((n) => `[${n}*="magnet:?xt=urn:btih:"]`) + .join(",") + ) + )) { + if ( + a.nextSibling && + a.nextSibling.hasAttribute && + a.nextSibling.hasAttribute("data-wtmzjk-mag-url") + ) + continue; // 已经添加 + if (reg.test(a.textContent)) continue; + for (let attr of a.getAttributeNames()) { + let val = a.getAttribute(attr); + if (!reg.test(val)) continue; + let url = val.match(reg)[0]; + a.parentNode.insertBefore(createWatchButton(url), a.nextSibling); + } + } + } + + function watchBodyChange(onchange) { + let timeout; + let observer = new MutationObserver(() => { + if (!timeout) { + timeout = setTimeout(() => { + timeout = null; + onchange(); + }, 200); + } + }); + observer.observe(document.documentElement, { + childList: true, + subtree: true, + attributes: true, + characterData: true, + }); + } + + function getAllTextNodes(parent) { + var re = []; + if ( + [ + "STYLE", + "SCRIPT", + "BASE", + "COMMAND", + "LINK", + "META", + "TITLE", + "XTRANS-TXT", + "XTRANS-TXT-GROUP", + "XTRANS-POPUP", + ].includes(parent.tagName) + ) + return re; + for (let node of parent.childNodes) { + if (node.childNodes.length) re = re.concat(getAllTextNodes(node)); + else if ( + Text.prototype.isPrototypeOf(node) && + !node.nodeValue.match(/^\s*$/) + ) + re.push(node); + } + return re; + } + + function whenDOMReady(f) { + if (document.body) f(); + else window.addEventListener("DOMContentLoaded", f); + } + + function addStyle(s) { + let style = document.createElement("style"); + style.innerHTML = s; + document.documentElement.appendChild(style); + } +})(); diff --git a/scripts/fb_downloadWatchingVideo.js b/scripts/fb_downloadWatchingVideo.js index 9c78dc6a..1e1128fc 100644 --- a/scripts/fb_downloadWatchingVideo.js +++ b/scripts/fb_downloadWatchingVideo.js @@ -31,18 +31,13 @@ export default { let listVideoId = await shared.getListVideoIdInWebsite(); if (!listVideoId?.length > 0) throw Error("Không tìm thấy video"); - for (let videoId of listVideoId) { - if (!videoId) continue; - - setLoadingText("Đang lấy token dtsg..."); - let dtsg = await fb_videoDownloader.getDtsg(); + setLoadingText("Đang lấy token dtsg..."); + let dtsg = await fb_videoDownloader.getDtsg(); + for (let videoId of listVideoId) { setLoadingText("Đang tìm video url..."); let videoUrl = await fb_videoDownloader.getLinkFbVideo(videoId, dtsg); - - if (!videoUrl) continue; - - UfsGlobal.Utils.downloadURL(videoUrl, "fb_video.mp4"); + if (videoUrl) UfsGlobal.Utils.downloadURL(videoUrl, "fb_video.mp4"); } } catch (e) { alert("ERROR: " + e); diff --git a/scripts/youtube_localDownloader.js b/scripts/youtube_localDownloader.js index eeef4ab3..cbb07d30 100644 --- a/scripts/youtube_localDownloader.js +++ b/scripts/youtube_localDownloader.js @@ -1,3 +1,6 @@ +import { UfsGlobal } from "./content-scripts/ufs_global.js"; +const { promiseAllStepN } = UfsGlobal.Utils; + export default { icon: "https://www.youtube.com/s/desktop/accca349/img/favicon_48x48.png", name: { @@ -32,4 +35,431 @@ export default { window.open("/scripts/youtube_localDownloader.html"); }, }, + + pageScript: { + onDocumentEnd: () => { + try { + onDocumentEnd(); + } catch (e) { + console.error(e); + } + }, + }, }; + +async function onDocumentEnd() { + const LANG_FALLBACK = "en"; + const LOCALE = { + en: { + togglelinks: "Show/Hide Links", + stream: "Stream", + adaptive: "Adaptive (No Sound)", + videoid: "Video ID: ", + inbrowser_adaptive_merger: + "Online Adaptive Video & Audio Merger (FFmpeg)", + dlmp4: "Download high-resolution mp4 in one click", + get_video_failed: + "Failed to get video infomation for unknown reason, refresh the page may work.", + live_stream_disabled_message: + "Local YouTube Downloader is not available for live stream", + }, + }; + for (const [lang, data] of Object.entries(LOCALE)) { + if (lang === LANG_FALLBACK) continue; + for (const key of Object.keys(LOCALE[LANG_FALLBACK])) { + if (!(key in data)) { + data[key] = LOCALE[LANG_FALLBACK][key]; + } + } + } + const findLang = (l) => { + l = l.replace("-Hant", ""); // special case for zh-Hant-TW + // language resolution logic: zh-tw --(if not exists)--> zh --(if not exists)--> LANG_FALLBACK(en) + l = l.toLowerCase().replace("_", "-"); + if (l in LOCALE) return l; + else if (l.length > 2) return findLang(l.split("-")[0]); + else return LANG_FALLBACK; + }; + const getLangCode = () => { + const html = document.querySelector("html"); + if (html) { + return html.lang; + } else { + return navigator.language; + } + }; + const $ = (s, x = document) => x.querySelector(s); + const $el = (tag, opts) => { + const el = document.createElement(tag); + Object.assign(el, opts); + return el; + }; + + const load = async (playerResponse) => { + try { + debugger; + const basejs = + (typeof ytplayer !== "undefined" && + "config" in ytplayer && + ytplayer.config.assets + ? "https://" + location.host + ytplayer.config.assets.js + : "web_player_context_config" in ytplayer + ? "https://" + + location.host + + ytplayer.web_player_context_config.jsUrl + : null) || $('script[src$="base.js"]').src; + const res = await fetch(basejs); + const text = await res.text(); + const decsig = parseDecsig(text); + const id = parseQuery(location.search).v; + const data = parseResponse(id, playerResponse, decsig); + console.log("video loaded: %s", id); + app.isLiveStream = + data.playerResponse.playabilityStatus.liveStreamability != null; + app.id = id; + app.stream = data.stream; + app.adaptive = data.adaptive; + app.details = data.details; + + const actLang = getLangCode(); + if (actLang != null) { + const lang = findLang(actLang); + console.log("youtube ui lang: %s", actLang); + console.log("ytdl lang:", lang); + app.lang = lang; + } + } catch (err) { + alert(app.strings.get_video_failed); + console.error("load", err); + } + }; + + const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + + const parseDecsig = (data) => { + try { + if (data.startsWith("var script")) { + // they inject the script via script tag + const obj = {}; + // const document = { + // createElement: () => obj, + // head: { appendChild: () => {} }, + // }; + eval(data); + data = obj.innerHTML; + } + const fnnameresult = /=([a-zA-Z0-9\$_]+?)\(decodeURIComponent/.exec(data); + const fnname = fnnameresult[1]; + const _argnamefnbodyresult = new RegExp( + escapeRegExp(fnname) + "=function\\((.+?)\\){((.+)=\\2.+?)}" + ).exec(data); + const [_, argname, fnbody] = _argnamefnbodyresult; + const helpernameresult = /;([a-zA-Z0-9$_]+?)\..+?\(/.exec(fnbody); + const helpername = helpernameresult[1]; + const helperresult = new RegExp( + "var " + escapeRegExp(helpername) + "={[\\s\\S]+?};" + ).exec(data); + const helper = helperresult[0]; + console.log(`parsedecsig result: %s=>{%s\n%s}`, argname, helper, fnbody); + return new Function([argname], helper + "\n" + fnbody); + } catch (e) { + console.error("parsedecsig error: %o", e); + console.info("script content: %s", data); + console.info( + 'If you encounter this error, please copy the full "script content" to https://pastebin.com/ for me.' + ); + } + }; + const parseQuery = (s) => + [...new URLSearchParams(s).entries()].reduce( + (acc, [k, v]) => ((acc[k] = v), acc), + {} + ); + const parseResponse = (id, playerResponse, decsig) => { + console.log(`video %s playerResponse: %o`, id, playerResponse); + let stream = []; + if (playerResponse.streamingData.formats) { + stream = playerResponse.streamingData.formats.map((x) => + Object.assign({}, x, parseQuery(x.cipher || x.signatureCipher)) + ); + console.log(`video %s stream: %o`, id, stream); + for (const obj of stream) { + if (obj.s) { + obj.s = decsig(obj.s); + obj.url += `&${obj.sp}=${encodeURIComponent(obj.s)}`; + } + } + } + + let adaptive = []; + if (playerResponse.streamingData.adaptiveFormats) { + adaptive = playerResponse.streamingData.adaptiveFormats.map((x) => + Object.assign({}, x, parseQuery(x.cipher || x.signatureCipher)) + ); + console.log(`video %s adaptive: %o`, id, adaptive); + for (const obj of adaptive) { + if (obj.s) { + obj.s = decsig(obj.s); + obj.url += `&${obj.sp}=${encodeURIComponent(obj.s)}`; + } + } + } + console.log(`video %s result: %o`, id, { stream, adaptive }); + return { + stream, + adaptive, + details: playerResponse.videoDetails, + playerResponse, + }; + }; + + // video downloader + const xhrDownloadUint8Array = async ({ url, contentLength }, progressCb) => { + if (typeof contentLength === "string") + contentLength = parseInt(contentLength); + progressCb({ + loaded: 0, + total: contentLength, + speed: 0, + }); + const chunkSize = 65536; + const getBuffer = (start, end) => + fetch(url + `&range=${start}-${end ? end - 1 : ""}`).then((r) => + r.arrayBuffer() + ); + const data = new Uint8Array(contentLength); + let downloaded = 0; + const tasks = []; + const startTime = Date.now(); + + for (let start = 0; start < contentLength; start += chunkSize) { + const exceeded = start + chunkSize > contentLength; + const curChunkSize = exceeded ? contentLength - start : chunkSize; + const end = exceeded ? null : start + chunkSize; + tasks.push(() => { + console.log("dl start", url, start, end); + return getBuffer(start, end) + .then((buf) => { + console.log("dl done", url, start, end); + downloaded += curChunkSize; + data.set(new Uint8Array(buf), start); + const ds = (Date.now() - startTime + 1) / 1000; + progressCb({ + loaded: downloaded, + total: contentLength, + speed: downloaded / ds, + }); + }) + .catch((err) => { + console.error("Download error"); + }); + }); + } + await promiseAllStepN(6, tasks); + return data; + }; + + let ffWorkerLoaded = false, + ffWorker; + const mergeVideo = async (video, audio) => { + if (!ffWorkerLoaded) { + await UfsGlobal.DOM.injectScriptSrcAsync( + "https://unpkg.com/@ffmpeg/ffmpeg@0.6.1/dist/ffmpeg.min.js" + ); + ffWorker = FFmpeg.createWorker({ + logger: (m) => console.log(m.message), + }); + ffWorkerLoaded = true; + } + await ffWorker.write("video.mp4", video); + await ffWorker.write("audio.mp4", audio); + await ffWorker.run("-i video.mp4 -i audio.mp4 -c copy output.mp4", { + input: ["video.mp4", "audio.mp4"], + output: "output.mp4", + }); + const { data } = await ffWorker.read("output.mp4"); + await ffWorker.remove("output.mp4"); + return data; + }; + + // ===================== MAIN ====================== + await UfsGlobal.DOM.injectScriptSrc( + "https://unpkg.com/vue@2.6.10/dist/vue.js" + ); + const template = `
+ + +
`; + const app = new Vue({ + data() { + return { + hide: true, + id: "", + isLiveStream: false, + stream: [], + adaptive: [], + details: null, + dark: false, + lang: findLang(getLangCode()), + }; + }, + computed: { + strings() { + return LOCALE[this.lang.toLowerCase()]; + }, + }, + methods: { + dlmp4() { + // openDownloadModel(this.adaptive, this.details.title); + }, + formatStreamText(vid) { + return [vid.qualityLabel, vid.quality].filter((x) => x).join(": "); + }, + formatAdaptiveText(vid) { + let str = [vid.qualityLabel, vid.mimeType].filter((x) => x).join(": "); + if (vid.mimeType.includes("audio")) { + str += ` ${Math.round(vid.bitrate / 1000)}kbps`; + } + return str; + }, + }, + template, + }); + + // attach element + const shadowHost = $el("div"); + const shadow = shadowHost.attachShadow + ? shadowHost.attachShadow({ mode: "closed" }) + : shadowHost; // no shadow dom + console.log("shadowHost: %o", shadowHost); + const container = $el("div"); + shadow.appendChild(container); + app.$mount(container); + + // hook fetch response + const ff = fetch; + window.fetch = (...args) => { + if (args[0] instanceof Request) { + return ff(...args).then((resp) => { + if (resp.url.includes("player")) { + debugger; + resp.clone().json().then(load); + } + return resp; + }); + } + return ff(...args); + }; + + // attach element + const it = setInterval(() => { + const el = + $("ytd-watch-metadata") || + $("#info-contents") || + $("#watch-header") || + $(".page-container:not([hidden]) ytm-item-section-renderer>lazy-list"); + if (el && !el.contains(shadowHost)) { + el.appendChild(shadowHost); + clearInterval(it); + } + }, 100); + + // init + const firstResp = window?.ytplayer?.config?.args?.raw_player_response; + debugger; + if (firstResp) { + load(firstResp); + } + + const css = ` +.hide{ +display: none; +} +.t-center{ +text-align: center; +} +.d-flex{ +display: flex; +} +.f-1{ +flex: 1; +} +.fs-14px{ +font-size: 14px; +} +.of-h{ +overflow: hidden; +} +.box{ +padding-top: .5em; +padding-bottom: .5em; +border-bottom: 1px solid var(--yt-border-color); +font-family: Arial; +} +.box-toggle{ +margin: 3px; +user-select: none; +-moz-user-select: -moz-none; +} +.ytdl-link-btn{ +display: block; +border: 1px solid !important; +border-radius: 3px; +text-decoration: none !important; +outline: 0; +text-align: center; +padding: 2px; +margin: 5px; +color: black; +} +a, .div-a{ +text-decoration: none; +color: var(--yt-button-color, inherit); +} +a:hover, .div-a:hover{ +color: var(--yt-spec-call-to-action, blue); +} +.box.dark{ +color: var(--yt-endpoint-color, var(--yt-spec-text-primary)); +} +.box.dark .ytdl-link-btn{ +color: var(--yt-endpoint-color, var(--yt-spec-text-primary)); +} +.box.dark .ytdl-link-btn:hover{ +color: rgba(200, 200, 255, 0.8); +} +.box.dark .box-toggle:hover{ +color: rgba(200, 200, 255, 0.8); +} +.c-pointer{ +cursor: pointer; +} +.lh-20{ +line-height: 20px; +} +`; + shadow.appendChild($el("style", { textContent: css })); +} diff --git a/scripts/youtube_localDownloader_main.js b/scripts/youtube_localDownloader_main.js index a00337d8..c61517f8 100644 --- a/scripts/youtube_localDownloader_main.js +++ b/scripts/youtube_localDownloader_main.js @@ -40,7 +40,7 @@ const xhrDownloadUint8Array = async ({ url, contentLength }, progressCb) => { }); }) .catch((err) => { - console.log("Download error"); + console.error("Download error", err); }); }); } diff --git a/working_note.md b/working_note.md index 98439369..7963f56e 100644 --- a/working_note.md +++ b/working_note.md @@ -1,9 +1,13 @@ # WORKING NOTES -## 30/05/2024 - 01/07/2024 +## 01/07/2024 - ? + +- [ ] check down video - [ ] analyze this +## 30/05/2024 - 01/07/2024 + - [x] check linux compatible -> relative path in manifest + file name camelcase - [x] modify responseText xhr => hard From 7c0817a3d01c967e4dc5f28995ee885675349a5d Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Thu, 4 Jul 2024 18:10:05 +0700 Subject: [PATCH 07/44] new dtsg get method --- scripts/fb_GLOBAL.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/scripts/fb_GLOBAL.js b/scripts/fb_GLOBAL.js index 6e05e8f2..2e752f44 100644 --- a/scripts/fb_GLOBAL.js +++ b/scripts/fb_GLOBAL.js @@ -546,6 +546,41 @@ export async function getFbdtsg() { RegExp(/"name":"fb_dtsg","value":"([^"]+)/).exec(text)?.[1] ); }, + function () { + return new Promise(function (resolve, reject) { + fetch("https://www.facebook.com/settings?tab=account§ion=name&view") + .then(function (response) { + if (response.status !== 200) { + console.log( + "Looks like there was a problem. Status Code: " + + response.status + ); + reject(response.status); + } + response.text().then((r) => { + const regex = /name="fb_dtsg" value="\s*(.*?)\s*"/g; + const html = r; + var newReg = new RegExp( + /DTSGInitData(?:.*?):"(.*?)",(?:.*?):"(.*?)"/ + ); + var newReg1 = new RegExp(/\"fb_dtsg\",\"value\"\:\"(.+?)\"}/); + var reg = new RegExp( + regex.source + "|" + newReg.source + "|" + newReg1.source + ); + var dtsgMatches = html.match(reg); + if (!dtsgMatches || !dtsgMatches.hasOwnProperty(1)) { + resolve(""); + } + resolve(dtsgMatches[3]); + //resolve(dtsgMatches[1] || dtsgMatches[2] || dtsgMatches[3]); + }); + }) + .catch(function (err) { + console.log("Fetch Error :-S", err); + reject(err); + }); + }); + }, () => require("DTSG_ASYNC").getToken(), // TODO: trace xem tại sao method này trả về cấu trúc khác 2 method trên ]; for (let m of methods) { From 609a82ede52d939e1a4dbfe7f68e29577a30d526 Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Thu, 4 Jul 2024 18:19:43 +0700 Subject: [PATCH 08/44] get fbdtsg_ag and friends --- scripts/fb_GLOBAL.js | 132 +++++++++++++++++++++++++++++++------------ working_note.md | 2 + 2 files changed, 99 insertions(+), 35 deletions(-) diff --git a/scripts/fb_GLOBAL.js b/scripts/fb_GLOBAL.js index 2e752f44..8efcbe50 100644 --- a/scripts/fb_GLOBAL.js +++ b/scripts/fb_GLOBAL.js @@ -238,6 +238,68 @@ export async function fetchAllAddedFriendsSince( return allFriends; } +//https://web.facebook.com/ajax/typeahead/first_degree.php?viewer=100075867577015&rsp=search&max_results=13&q=s&session_id=0.7324328179909558&fb_dtsg_ag=AQwWeyg6g3SN6ZcrmAy6uVrA3HAMBgbFAse89jki-JZ8t9iK:24:1672755996&jazoest=24821&__dyn=1KQEGiFo525Ujwh8-t0BBBgS5UqxKcwRwAxu3-Uco6q3q327Hw9e5orx60lW4o3Bw4Ewk9EdEnw65xO2O1Vwro7ifw5Zx62K2G0g26E52229wcq0C9EdE2IzU2Xwp82vwAwmE2ewnE2Lx-220jG3qazo11E2ZwrU6C2-0z836w&__csr=&__req=b&__a=AYltv4PwLKfRaPOm3vXywmuQ7w-cOgesCW15eyelU6wut5KA1ngiReAq53QySzrSQ2h7opM7jRkZK9XgPIIB-ek2Vx9Z70y5FAKyLiR-ISfqpA&__user=100075867577015 +//https://www.facebook.com/ajax/typeahead/first_degree.php?viewer=100075867577015&token=v7&filter[0]=user&options[0]=friends_only&options[1]=nm&fb_dtsg_ag=NAcM4Va03WgxUC9_454ocvAxZhjX-dlrZVyWsjooAcffVe-I9YvzAVw:24:1672755996&__user=100075867577015&__a=1&__req=d&__rev=1686870533469 +//https://web.facebook.com/ajax/typeahead/first_degree.php?viewer=100075867577015&token=v7&filter[0]=user&options[0]=friends_only&options[1]=nm&fb_dtsg_ag=AQwWeyg6g3SN6ZcrmAy6uVrA3HAMBgbFAse89jki-JZ8t9iK:24:1672755996&__a=1&__user=100075867577015 +export async function getFriendsAsync(uid, fbs) { + var urll = "https://www.facebook.com/ajax/typeahead/first_degree.php?"; + (urll += "viewer=" + uid), + (urll += + "&token=v7&filter[0]=user&options[0]=friends_only&options[1]=nm&fb_dtsg_ag=" + + fbs + + "&__user=" + + uid), + (urll += "&__a=1&__req=d&__rev=" + new Date().getTime()); + var d = await fetch(urll); + if ( + (!d.statusText && d.status && 200 != d.status) || + (!d.status && d.statusText && "OK" != d.statusText) + ) + return console.log("Fail here"); + var t = await d.text(); + var e = t.replace("for (;;);", ""); + var e = JSON.parse(e); + if (e.error) { + return new Error("err"); + } + if (e.redirect) { + d = await fetch(urll.replace("www", "web")); + if ( + (!d.statusText && d.status && 200 != d.status) || + (!d.status && d.statusText && "OK" != d.statusText) + ) + return console.log("Fail here"); + var t = await d.text(); + var e = t.replace("for (;;);", ""); + e = JSON.parse(e); + if (e.error) { + return new Error("err"); + } + } + var res = {}; + var f = {}; + var name = ""; + let photo = ""; + for (var g in e.payload.entries) { + var h = e.payload.entries[g]; + if (h.uid != uid) { + f[h.uid] = { + uid: h.uid, + name: h.names[0], + photo: h.photo, + }; + } + if (h.uid == uid) { + name = h.names[0]; + photo = h.photo; + } + } + res.f = f; + res.name = name; + res.photo = photo; + return res; +} + // ============================================================================= // ================================= Messages ================================== // ============================================================================= @@ -546,41 +608,6 @@ export async function getFbdtsg() { RegExp(/"name":"fb_dtsg","value":"([^"]+)/).exec(text)?.[1] ); }, - function () { - return new Promise(function (resolve, reject) { - fetch("https://www.facebook.com/settings?tab=account§ion=name&view") - .then(function (response) { - if (response.status !== 200) { - console.log( - "Looks like there was a problem. Status Code: " + - response.status - ); - reject(response.status); - } - response.text().then((r) => { - const regex = /name="fb_dtsg" value="\s*(.*?)\s*"/g; - const html = r; - var newReg = new RegExp( - /DTSGInitData(?:.*?):"(.*?)",(?:.*?):"(.*?)"/ - ); - var newReg1 = new RegExp(/\"fb_dtsg\",\"value\"\:\"(.+?)\"}/); - var reg = new RegExp( - regex.source + "|" + newReg.source + "|" + newReg1.source - ); - var dtsgMatches = html.match(reg); - if (!dtsgMatches || !dtsgMatches.hasOwnProperty(1)) { - resolve(""); - } - resolve(dtsgMatches[3]); - //resolve(dtsgMatches[1] || dtsgMatches[2] || dtsgMatches[3]); - }); - }) - .catch(function (err) { - console.log("Fetch Error :-S", err); - reject(err); - }); - }); - }, () => require("DTSG_ASYNC").getToken(), // TODO: trace xem tại sao method này trả về cấu trúc khác 2 method trên ]; for (let m of methods) { @@ -592,6 +619,41 @@ export async function getFbdtsg() { return null; } +export async function getFbDtsgAg() { + return new Promise(function (resolve, reject) { + fetch("https://www.facebook.com/settings?tab=account§ion=name&view") + .then(function (response) { + if (response.status !== 200) { + console.log( + "Looks like there was a problem. Status Code: " + response.status + ); + reject(response.status); + } + response.text().then((r) => { + const regex = /name="fb_dtsg" value="\s*(.*?)\s*"/g; + const html = r; + var newReg = new RegExp( + /DTSGInitData(?:.*?):"(.*?)",(?:.*?):"(.*?)"/ + ); + var newReg1 = new RegExp(/\"fb_dtsg\",\"value\"\:\"(.+?)\"}/); + var reg = new RegExp( + regex.source + "|" + newReg.source + "|" + newReg1.source + ); + var dtsgMatches = html.match(reg); + if (!dtsgMatches || !dtsgMatches.hasOwnProperty(1)) { + resolve(""); + } + resolve(dtsgMatches[3]); + //resolve(dtsgMatches[1] || dtsgMatches[2] || dtsgMatches[3]); + }); + }) + .catch(function (err) { + console.log("Fetch Error :-S", err); + reject(err); + }); + }); +} + // ============================================================================= // =================================== Story =================================== // ============================================================================= diff --git a/working_note.md b/working_note.md index 7963f56e..07520cd0 100644 --- a/working_note.md +++ b/working_note.md @@ -2,6 +2,8 @@ ## 01/07/2024 - ? +- [ ] analyze this + - [ ] check down video - [ ] analyze this From 8e3264c4f0a85a13da51bb40d84bd00a99e89ea5 Mon Sep 17 00:00:00 2001 From: HoangTran <99.hoangtran@gmail.com> Date: Thu, 4 Jul 2024 22:53:37 +0700 Subject: [PATCH 09/44] youtube thumbnail + captions --- popup/tabs.js | 3 +- scripts/_index.js | 3 +- scripts/youtube_downloadVideo.js | 15 +- scripts/youtube_getVideoCaption.js | 117 ++++++ scripts/youtube_getVideoThumbnail.js | 53 +++ scripts/youtube_localDownloader.html | 16 - scripts/youtube_localDownloader.js | 465 ------------------------ scripts/youtube_localDownloader_main.js | 132 ------- 8 files changed, 181 insertions(+), 623 deletions(-) create mode 100644 scripts/youtube_getVideoCaption.js create mode 100644 scripts/youtube_getVideoThumbnail.js delete mode 100644 scripts/youtube_localDownloader.html delete mode 100644 scripts/youtube_localDownloader.js delete mode 100644 scripts/youtube_localDownloader_main.js diff --git a/popup/tabs.js b/popup/tabs.js index bc56c510..c9ff666e 100644 --- a/popup/tabs.js +++ b/popup/tabs.js @@ -498,8 +498,9 @@ const tabs = [ { ...CATEGORY.youtube, scripts: [ - // s.youtube_localDownloader, s.youtube_downloadVideo, + s.youtube_getVideoThumbnail, + s.youtube_getVideoCaption, s.youtube_toggleLight, s.pictureInPicture, s.pip_fullWebsite, diff --git a/scripts/_index.js b/scripts/_index.js index 03de5a6d..b6885f8a 100644 --- a/scripts/_index.js +++ b/scripts/_index.js @@ -131,7 +131,6 @@ export { default as vuiz_createLogo } from "./vuiz_createLogo.js"; export { default as vuiz_getLink } from "./vuiz_getLink.js"; export { default as ggdrive_downloadPdf } from "./ggdrive_downloadPdf.js"; export { default as ggdrive_downloadPresentation } from "./ggdrive_downloadPresentation.js"; -export { default as youtube_localDownloader } from "./youtube_localDownloader.js"; export { default as twitter_downloadButton } from "./twitter_downloadButton.js"; export { default as spotify_downloadButton } from "./spotify_downloadButton.js"; export { default as ggdrive_downloadDoc } from "./ggdrive_downloadDoc.js"; @@ -168,3 +167,5 @@ export { default as showImageOnHoverLink } from "./showImageOnHoverLink.js"; export { default as fb_allInOne } from "./fb_allInOne.js"; export { default as fb_getPostReactionCount } from "./fb_getPostReactionCount.js"; export { default as bypass_learnAnything } from "./bypass_learnAnything.js"; +export { default as youtube_getVideoThumbnail } from "./youtube_getVideoThumbnail.js"; +export { default as youtube_getVideoCaption } from "./youtube_getVideoCaption.js"; diff --git a/scripts/youtube_downloadVideo.js b/scripts/youtube_downloadVideo.js index bbda9be4..b678e12d 100644 --- a/scripts/youtube_downloadVideo.js +++ b/scripts/youtube_downloadVideo.js @@ -14,14 +14,6 @@ export default { contentScript: { onClick: function () { - // https://stackoverflow.com/a/8260383/11898496 - function getIdFromYoutubeURL(url) { - let regExp = - /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/; - let match = url.match(regExp); - return match && match[1].length == 11 ? match[1] : false; - } - let options = [ { name: "y2mate.com", @@ -79,3 +71,10 @@ export default { }, }, }; + +// https://stackoverflow.com/a/8260383/11898496 +export function getIdFromYoutubeURL(url) { + let regExp = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/; + let match = url.match(regExp); + return match && match[1].length == 11 ? match[1] : false; +} diff --git a/scripts/youtube_getVideoCaption.js b/scripts/youtube_getVideoCaption.js new file mode 100644 index 00000000..47d8f9af --- /dev/null +++ b/scripts/youtube_getVideoCaption.js @@ -0,0 +1,117 @@ +import { BADGES } from "./helpers/badge.js"; + +export default { + icon: '', + name: { + en: "Get Youtube video's captions", + vi: "Lấy phụ đề video trên Youtube", + }, + description: { + en: "Get all captions of playing youtube video", + vi: "Tải về tất cả phụ đề của video youtube đang xem", + }, + badges: [BADGES.new], + changeLogs: { + "2024-07-04": "init", + }, + + whiteList: ["https://*.youtube.com/*"], + + pageScript: { + onClick: () => { + function renderCaptions(captions) { + const id = "ufs_youtube_getVideoCaption"; + const exist = document.getElementById(id); + if (exist) exist.remove(); + + const div = document.createElement("div"); + div.id = id; + div.innerHTML = ` + +
+ +

Captions


+ +
+ `; + const button = div.querySelector("button"); + button.onclick = () => { + div.remove(); + }; + document.documentElement.appendChild(div); + } + + const methods = [ + () => + document.getElementsByTagName("ytd-app")[0].data.playerResponse + .captions.playerCaptionsTracklistRenderer.captionTracks, + () => + ytplayer.config.args.raw_player_response.captions + .playerCaptionsTracklistRenderer.captionTracks, + ]; + + for (let f of methods) { + try { + let captions = f(); + if (captions) { + renderCaptions(captions); + return; + } + } catch (e) { + console.error(e); + } + } + }, + }, +}; diff --git a/scripts/youtube_getVideoThumbnail.js b/scripts/youtube_getVideoThumbnail.js new file mode 100644 index 00000000..29850be7 --- /dev/null +++ b/scripts/youtube_getVideoThumbnail.js @@ -0,0 +1,53 @@ +import { BADGES } from "./helpers/badge.js"; +import { getIdFromYoutubeURL } from "./youtube_downloadVideo.js"; + +export default { + icon: '', + name: { + en: "Get Youtube video's thumbnail", + vi: "Lấy thumbnail video trên Youtube", + }, + description: { + en: "Get largest thumbnail of playing youtube video", + vi: "Tải về hình thumbnail độ phân giải lớn nhất của video youtube đang xem", + }, + badges: [BADGES.new], + changeLogs: { + "2024-07-04": "init", + }, + + whiteList: ["https://*.youtube.com/*"], + + pageScript: { + onClick: () => { + const methods = [ + () => + document + .getElementsByTagName("ytd-app")[0] + .data.playerResponse.videoDetails.thumbnail.thumbnails.sort( + (a, b) => b.width * b.height - a.width * a.height + )[0].url, + () => + ytplayer.config.args.raw_player_response.videoDetails.thumbnail.thumbnails.sort( + (a, b) => b.width * b.height - a.width * a.height + )[0].url, + () => + `https://i.ytimg.com/vi/${getIdFromYoutubeURL( + location.href + )}/maxresdefault.jpg`, + ]; + + for (let f of methods) { + try { + let url = f(); + if (url) { + window.open(url, "_blank"); + return; + } + } catch (e) { + console.error(e); + } + } + }, + }, +}; diff --git a/scripts/youtube_localDownloader.html b/scripts/youtube_localDownloader.html deleted file mode 100644 index 01691e77..00000000 --- a/scripts/youtube_localDownloader.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - Useful Script - YouTube Local Downloader - - - - - - - - - diff --git a/scripts/youtube_localDownloader.js b/scripts/youtube_localDownloader.js deleted file mode 100644 index cbb07d30..00000000 --- a/scripts/youtube_localDownloader.js +++ /dev/null @@ -1,465 +0,0 @@ -import { UfsGlobal } from "./content-scripts/ufs_global.js"; -const { promiseAllStepN } = UfsGlobal.Utils; - -export default { - icon: "https://www.youtube.com/s/desktop/accca349/img/favicon_48x48.png", - name: { - en: "Youtube local downloader", - vi: "Youtube tải video local", - }, - description: { - en: "", - vi: "", - }, - - whiteList: ["https://*youtube.com/*"], - - popupScript: { - onClick: async () => { - const { runScriptInCurrentTab } = await import("./helpers/utils.js"); - - const yt_data = await runScriptInCurrentTab(() => { - return document.getElementsByTagName("ytd-app")[0].data.playerResponse; - }); - - if (!yt_data) { - alert("Không tìm thấy video data"); - return; - } - - localStorage.setItem( - "ufs_youtube_localDownloader", - JSON.stringify(yt_data) - ); - - window.open("/scripts/youtube_localDownloader.html"); - }, - }, - - pageScript: { - onDocumentEnd: () => { - try { - onDocumentEnd(); - } catch (e) { - console.error(e); - } - }, - }, -}; - -async function onDocumentEnd() { - const LANG_FALLBACK = "en"; - const LOCALE = { - en: { - togglelinks: "Show/Hide Links", - stream: "Stream", - adaptive: "Adaptive (No Sound)", - videoid: "Video ID: ", - inbrowser_adaptive_merger: - "Online Adaptive Video & Audio Merger (FFmpeg)", - dlmp4: "Download high-resolution mp4 in one click", - get_video_failed: - "Failed to get video infomation for unknown reason, refresh the page may work.", - live_stream_disabled_message: - "Local YouTube Downloader is not available for live stream", - }, - }; - for (const [lang, data] of Object.entries(LOCALE)) { - if (lang === LANG_FALLBACK) continue; - for (const key of Object.keys(LOCALE[LANG_FALLBACK])) { - if (!(key in data)) { - data[key] = LOCALE[LANG_FALLBACK][key]; - } - } - } - const findLang = (l) => { - l = l.replace("-Hant", ""); // special case for zh-Hant-TW - // language resolution logic: zh-tw --(if not exists)--> zh --(if not exists)--> LANG_FALLBACK(en) - l = l.toLowerCase().replace("_", "-"); - if (l in LOCALE) return l; - else if (l.length > 2) return findLang(l.split("-")[0]); - else return LANG_FALLBACK; - }; - const getLangCode = () => { - const html = document.querySelector("html"); - if (html) { - return html.lang; - } else { - return navigator.language; - } - }; - const $ = (s, x = document) => x.querySelector(s); - const $el = (tag, opts) => { - const el = document.createElement(tag); - Object.assign(el, opts); - return el; - }; - - const load = async (playerResponse) => { - try { - debugger; - const basejs = - (typeof ytplayer !== "undefined" && - "config" in ytplayer && - ytplayer.config.assets - ? "https://" + location.host + ytplayer.config.assets.js - : "web_player_context_config" in ytplayer - ? "https://" + - location.host + - ytplayer.web_player_context_config.jsUrl - : null) || $('script[src$="base.js"]').src; - const res = await fetch(basejs); - const text = await res.text(); - const decsig = parseDecsig(text); - const id = parseQuery(location.search).v; - const data = parseResponse(id, playerResponse, decsig); - console.log("video loaded: %s", id); - app.isLiveStream = - data.playerResponse.playabilityStatus.liveStreamability != null; - app.id = id; - app.stream = data.stream; - app.adaptive = data.adaptive; - app.details = data.details; - - const actLang = getLangCode(); - if (actLang != null) { - const lang = findLang(actLang); - console.log("youtube ui lang: %s", actLang); - console.log("ytdl lang:", lang); - app.lang = lang; - } - } catch (err) { - alert(app.strings.get_video_failed); - console.error("load", err); - } - }; - - const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); - - const parseDecsig = (data) => { - try { - if (data.startsWith("var script")) { - // they inject the script via script tag - const obj = {}; - // const document = { - // createElement: () => obj, - // head: { appendChild: () => {} }, - // }; - eval(data); - data = obj.innerHTML; - } - const fnnameresult = /=([a-zA-Z0-9\$_]+?)\(decodeURIComponent/.exec(data); - const fnname = fnnameresult[1]; - const _argnamefnbodyresult = new RegExp( - escapeRegExp(fnname) + "=function\\((.+?)\\){((.+)=\\2.+?)}" - ).exec(data); - const [_, argname, fnbody] = _argnamefnbodyresult; - const helpernameresult = /;([a-zA-Z0-9$_]+?)\..+?\(/.exec(fnbody); - const helpername = helpernameresult[1]; - const helperresult = new RegExp( - "var " + escapeRegExp(helpername) + "={[\\s\\S]+?};" - ).exec(data); - const helper = helperresult[0]; - console.log(`parsedecsig result: %s=>{%s\n%s}`, argname, helper, fnbody); - return new Function([argname], helper + "\n" + fnbody); - } catch (e) { - console.error("parsedecsig error: %o", e); - console.info("script content: %s", data); - console.info( - 'If you encounter this error, please copy the full "script content" to https://pastebin.com/ for me.' - ); - } - }; - const parseQuery = (s) => - [...new URLSearchParams(s).entries()].reduce( - (acc, [k, v]) => ((acc[k] = v), acc), - {} - ); - const parseResponse = (id, playerResponse, decsig) => { - console.log(`video %s playerResponse: %o`, id, playerResponse); - let stream = []; - if (playerResponse.streamingData.formats) { - stream = playerResponse.streamingData.formats.map((x) => - Object.assign({}, x, parseQuery(x.cipher || x.signatureCipher)) - ); - console.log(`video %s stream: %o`, id, stream); - for (const obj of stream) { - if (obj.s) { - obj.s = decsig(obj.s); - obj.url += `&${obj.sp}=${encodeURIComponent(obj.s)}`; - } - } - } - - let adaptive = []; - if (playerResponse.streamingData.adaptiveFormats) { - adaptive = playerResponse.streamingData.adaptiveFormats.map((x) => - Object.assign({}, x, parseQuery(x.cipher || x.signatureCipher)) - ); - console.log(`video %s adaptive: %o`, id, adaptive); - for (const obj of adaptive) { - if (obj.s) { - obj.s = decsig(obj.s); - obj.url += `&${obj.sp}=${encodeURIComponent(obj.s)}`; - } - } - } - console.log(`video %s result: %o`, id, { stream, adaptive }); - return { - stream, - adaptive, - details: playerResponse.videoDetails, - playerResponse, - }; - }; - - // video downloader - const xhrDownloadUint8Array = async ({ url, contentLength }, progressCb) => { - if (typeof contentLength === "string") - contentLength = parseInt(contentLength); - progressCb({ - loaded: 0, - total: contentLength, - speed: 0, - }); - const chunkSize = 65536; - const getBuffer = (start, end) => - fetch(url + `&range=${start}-${end ? end - 1 : ""}`).then((r) => - r.arrayBuffer() - ); - const data = new Uint8Array(contentLength); - let downloaded = 0; - const tasks = []; - const startTime = Date.now(); - - for (let start = 0; start < contentLength; start += chunkSize) { - const exceeded = start + chunkSize > contentLength; - const curChunkSize = exceeded ? contentLength - start : chunkSize; - const end = exceeded ? null : start + chunkSize; - tasks.push(() => { - console.log("dl start", url, start, end); - return getBuffer(start, end) - .then((buf) => { - console.log("dl done", url, start, end); - downloaded += curChunkSize; - data.set(new Uint8Array(buf), start); - const ds = (Date.now() - startTime + 1) / 1000; - progressCb({ - loaded: downloaded, - total: contentLength, - speed: downloaded / ds, - }); - }) - .catch((err) => { - console.error("Download error"); - }); - }); - } - await promiseAllStepN(6, tasks); - return data; - }; - - let ffWorkerLoaded = false, - ffWorker; - const mergeVideo = async (video, audio) => { - if (!ffWorkerLoaded) { - await UfsGlobal.DOM.injectScriptSrcAsync( - "https://unpkg.com/@ffmpeg/ffmpeg@0.6.1/dist/ffmpeg.min.js" - ); - ffWorker = FFmpeg.createWorker({ - logger: (m) => console.log(m.message), - }); - ffWorkerLoaded = true; - } - await ffWorker.write("video.mp4", video); - await ffWorker.write("audio.mp4", audio); - await ffWorker.run("-i video.mp4 -i audio.mp4 -c copy output.mp4", { - input: ["video.mp4", "audio.mp4"], - output: "output.mp4", - }); - const { data } = await ffWorker.read("output.mp4"); - await ffWorker.remove("output.mp4"); - return data; - }; - - // ===================== MAIN ====================== - await UfsGlobal.DOM.injectScriptSrc( - "https://unpkg.com/vue@2.6.10/dist/vue.js" - ); - const template = `
- - -
`; - const app = new Vue({ - data() { - return { - hide: true, - id: "", - isLiveStream: false, - stream: [], - adaptive: [], - details: null, - dark: false, - lang: findLang(getLangCode()), - }; - }, - computed: { - strings() { - return LOCALE[this.lang.toLowerCase()]; - }, - }, - methods: { - dlmp4() { - // openDownloadModel(this.adaptive, this.details.title); - }, - formatStreamText(vid) { - return [vid.qualityLabel, vid.quality].filter((x) => x).join(": "); - }, - formatAdaptiveText(vid) { - let str = [vid.qualityLabel, vid.mimeType].filter((x) => x).join(": "); - if (vid.mimeType.includes("audio")) { - str += ` ${Math.round(vid.bitrate / 1000)}kbps`; - } - return str; - }, - }, - template, - }); - - // attach element - const shadowHost = $el("div"); - const shadow = shadowHost.attachShadow - ? shadowHost.attachShadow({ mode: "closed" }) - : shadowHost; // no shadow dom - console.log("shadowHost: %o", shadowHost); - const container = $el("div"); - shadow.appendChild(container); - app.$mount(container); - - // hook fetch response - const ff = fetch; - window.fetch = (...args) => { - if (args[0] instanceof Request) { - return ff(...args).then((resp) => { - if (resp.url.includes("player")) { - debugger; - resp.clone().json().then(load); - } - return resp; - }); - } - return ff(...args); - }; - - // attach element - const it = setInterval(() => { - const el = - $("ytd-watch-metadata") || - $("#info-contents") || - $("#watch-header") || - $(".page-container:not([hidden]) ytm-item-section-renderer>lazy-list"); - if (el && !el.contains(shadowHost)) { - el.appendChild(shadowHost); - clearInterval(it); - } - }, 100); - - // init - const firstResp = window?.ytplayer?.config?.args?.raw_player_response; - debugger; - if (firstResp) { - load(firstResp); - } - - const css = ` -.hide{ -display: none; -} -.t-center{ -text-align: center; -} -.d-flex{ -display: flex; -} -.f-1{ -flex: 1; -} -.fs-14px{ -font-size: 14px; -} -.of-h{ -overflow: hidden; -} -.box{ -padding-top: .5em; -padding-bottom: .5em; -border-bottom: 1px solid var(--yt-border-color); -font-family: Arial; -} -.box-toggle{ -margin: 3px; -user-select: none; --moz-user-select: -moz-none; -} -.ytdl-link-btn{ -display: block; -border: 1px solid !important; -border-radius: 3px; -text-decoration: none !important; -outline: 0; -text-align: center; -padding: 2px; -margin: 5px; -color: black; -} -a, .div-a{ -text-decoration: none; -color: var(--yt-button-color, inherit); -} -a:hover, .div-a:hover{ -color: var(--yt-spec-call-to-action, blue); -} -.box.dark{ -color: var(--yt-endpoint-color, var(--yt-spec-text-primary)); -} -.box.dark .ytdl-link-btn{ -color: var(--yt-endpoint-color, var(--yt-spec-text-primary)); -} -.box.dark .ytdl-link-btn:hover{ -color: rgba(200, 200, 255, 0.8); -} -.box.dark .box-toggle:hover{ -color: rgba(200, 200, 255, 0.8); -} -.c-pointer{ -cursor: pointer; -} -.lh-20{ -line-height: 20px; -} -`; - shadow.appendChild($el("style", { textContent: css })); -} diff --git a/scripts/youtube_localDownloader_main.js b/scripts/youtube_localDownloader_main.js deleted file mode 100644 index c61517f8..00000000 --- a/scripts/youtube_localDownloader_main.js +++ /dev/null @@ -1,132 +0,0 @@ -import { UfsGlobal } from "./content-scripts/ufs_global.js"; - -const { formatSize, promiseAllStepN } = UfsGlobal.Utils; -const { injectScriptSrc } = UfsGlobal.DOM; - -const xhrDownloadUint8Array = async ({ url, contentLength }, progressCb) => { - if (typeof contentLength === "string") - contentLength = parseInt(contentLength); - progressCb({ - loaded: 0, - total: contentLength, - speed: 0, - }); - const chunkSize = 65536; - const getBuffer = (start, end) => - fetch(url + `&range=${start}-${end ? end - 1 : ""}`).then((r) => - r.arrayBuffer() - ); - const data = new Uint8Array(contentLength); - let downloaded = 0; - const tasks = []; - const startTime = Date.now(); - - for (let start = 0; start < contentLength; start += chunkSize) { - const exceeded = start + chunkSize > contentLength; - const curChunkSize = exceeded ? contentLength - start : chunkSize; - const end = exceeded ? null : start + chunkSize; - tasks.push(() => { - console.log("dl start", url, start, end); - return getBuffer(start, end) - .then((buf) => { - console.log("dl done", url, start, end); - downloaded += curChunkSize; - data.set(new Uint8Array(buf), start); - const ds = (Date.now() - startTime + 1) / 1000; - progressCb({ - loaded: downloaded, - total: contentLength, - speed: downloaded / ds, - }); - }) - .catch((err) => { - console.error("Download error", err); - }); - }); - } - await promiseAllStepN(6, tasks); - return data; -}; - -window.onload = () => { - const yt_data = JSON.parse( - localStorage.getItem("ufs_youtube_localDownloader") ?? "{}" - ); - - console.log(yt_data); - - const streamingData = [ - ...(yt_data.streamingData?.formats || []), - ...(yt_data.streamingData?.adaptiveFormats || []), - ].filter((_) => _.url); - - const videoDetails = yt_data.videoDetails; - const videos = streamingData.filter((d) => d.mimeType.includes("video")); - const audios = streamingData.filter((d) => d.mimeType.includes("audio")); - const captions = - yt_data.captions?.playerCaptionsTracklistRenderer?.captionTracks || []; - - console.log(captions); - - // video details - const detailDiv = document.createElement("div"); - const thumbs = videoDetails.thumbnail?.thumbnails || []; - const lastThumbnail = thumbs[thumbs.length - 1]; - - detailDiv.innerHTML = ` - -

${videoDetails.title}

-

${videoDetails.author}

-

${videoDetails.shortDescription}

`; - document.body.appendChild(detailDiv); - - // video - for (let video of videos) { - const button = document.createElement("button"); - button.style = "display:block;margin-bottom:5px"; - button.innerHTML = ` - ${video.qualityLabel} - - ${video.width}x${video.height} - - ${formatSize(video.contentLength, 2)} - ${video.audioQuality ? "" : " (no audio)"}`; - button.onclick = () => { - let data = xhrDownloadUint8Array(video, (progress) => { - console.log(progress); - }); - // saveAs(video.url, "video.mp4", { - // onprogress: (e) => { - // console.log(e); - // }, - // }); - }; - document.body.appendChild(button); - } - - // audio - for (let audio of audios) { - const div = document.createElement("div"); - div.innerHTML = ` - -

- ${audio.audioTrack?.displayName || audio.audioQuality} - - ${formatSize(audio.contentLength, 2)} -

- `; - document.body.appendChild(div); - } - - // caption - for (let caption of captions) { - const div = document.createElement("div"); - div.innerHTML = ` -

${caption.name?.simpleText}

- - Download - - `; - document.body.appendChild(div); - } -}; From b15dea9a5a507c45b768aa368ccb2d0c6fd25942 Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Fri, 5 Jul 2024 18:40:10 +0700 Subject: [PATCH 10/44] find fb by phone/mail - WIP --- popup/index.js | 2 +- popup/tabs.js | 2 +- scripts/_test.js | 74 ++++++++++++++++++++++++++++++++++++++++ scripts/fb_GLOBAL.js | 39 +++++++++++++++++++++ scripts/helpers/utils.js | 2 +- working_note.md | 4 +++ 6 files changed, 120 insertions(+), 3 deletions(-) diff --git a/popup/index.js b/popup/index.js index 366af5b6..8e9be596 100644 --- a/popup/index.js +++ b/popup/index.js @@ -39,7 +39,7 @@ import { viewScriptSource, } from "./helpers/utils.js"; import { checkPass } from "../scripts/auto_lockWebsite.js"; -import _ from "../md/exportScriptsToMd.js"; +// import _ from "../md/exportScriptsToMd.js"; const settingsBtn = document.querySelector(".settings"); const openInNewTabBtn = document.querySelector(".open-in-newtab"); diff --git a/popup/tabs.js b/popup/tabs.js index c9ff666e..98c5aaa6 100644 --- a/popup/tabs.js +++ b/popup/tabs.js @@ -36,7 +36,7 @@ const tabs = [ { ...CATEGORY.search, scripts: [ - // s._test, + s._test, // s._ufs_statistic, s.similarWeb, s.similarWeb_bypassLimit, diff --git a/scripts/_test.js b/scripts/_test.js index 140501e6..986166a3 100644 --- a/scripts/_test.js +++ b/scripts/_test.js @@ -1,4 +1,5 @@ import { UfsGlobal } from "./content-scripts/ufs_global.js"; +import { fetchGraphQl, getFbdtsg } from "./fb_GLOBAL.js"; export default { icon: "", @@ -12,6 +13,79 @@ export default { }, popupScript: { + onClick: async () => { + function getAverageRGB(img) { + var blockSize = 5, // only visit every 5 pixels + defaultRGB = { r: 0, g: 0, b: 0 }, // for non-supporting envs + canvas = document.createElement("canvas"), + context = canvas.getContext && canvas.getContext("2d"), + data, + width, + height, + i = -4, + length, + rgb = { r: 0, g: 0, b: 0 }, + count = 0; + + if (!context) { + return defaultRGB; + } + + height = canvas.height = + img.naturalHeight || img.offsetHeight || img.height; + width = canvas.width = img.naturalWidth || img.offsetWidth || img.width; + + context.drawImage(img, 0, 0); + + try { + data = context.getImageData(0, 0, width, height); + } catch (e) { + /* security error, img on diff domain */ + return defaultRGB; + } + + length = data.data.length; + + while ((i += blockSize * 4) < length) { + ++count; + rgb.r += data.data[i]; + rgb.g += data.data[i + 1]; + rgb.b += data.data[i + 2]; + } + + // ~~ used to floor values + rgb.r = ~~(rgb.r / count); + rgb.g = ~~(rgb.g / count); + rgb.b = ~~(rgb.b / count); + + return rgb; + } + + function getAverageRGBFromUrl(url) { + return new Promise((resolve, reject) => { + let img = new Image(); + img.src = url; + img.onload = () => { + let rgb = getAverageRGB(img); + resolve(rgb); + }; + img.onerror = (error) => { + alert("Error: " + JSON.stringify(error)); + console.log(error); + reject(); + }; + }); + } + + getAverageRGBFromUrl( + "https://scontent.fsgn2-7.fna.fbcdn.net/v/t39.30808-1/352545274_2285354618338828_3224207586206963955_n.jpg?stp=dst-jpg_p480x480&ccb=1-7&_nc_sid=0ecb9b&_nc_ohc=7D3Usqt8u2UQ7kNvgEeWxht&_nc_ht=scontent.fsgn2-7.fna&oh=00_AYAeunf-6BuCakj2L59wVi8mNA5QuGlLuVQ6eROL5UKC8A&oe=668D93B9" + ).then(console.log); + + getAverageRGBFromUrl( + "https://www.facebook.com/profile/pic.php?cuid=AYjse6TURBs86Oy-7iO2UdCZFqYOhyemrWC2KV8yPo6ABGAHCWi87GNGtXwITHZJRPIOPLMTbuZetu6t3T9WQllYE5xhBm4t5rAZVKC1IGjSqGbJiwr9z4g-bDx6bHAPuqqXgfCaH4Yml-_UAAJgEGdftXSGc4uCKUer8j3oCtpLakjxWAOTYeNAzt-rWWp0fNtY03PE0XzLzPqKEI8leoS_08eYd_V9L4O_P1lwGxHyMA&square_px=64" + ).then(console.log); + }, + // selenium automation get album's images _onClick: async () => { const { openWebAndRunScript } = await import("./helpers/utils.js"); diff --git a/scripts/fb_GLOBAL.js b/scripts/fb_GLOBAL.js index 8efcbe50..d1ce0c11 100644 --- a/scripts/fb_GLOBAL.js +++ b/scripts/fb_GLOBAL.js @@ -119,6 +119,45 @@ export async function getUidFromUrl(url) { } return null; } +export async function searchUser(keyword, exact_match = true) { + const res = await fetchGraphQl( + { + doc_id: 7561210460668291, + variables: { + count: 5, + allow_streaming: false, + args: { + callsite: "COMET_GLOBAL_SEARCH", + config: { + exact_match: exact_match, + high_confidence_config: null, + intercept_config: null, + sts_disambiguation: null, + watch_config: null, + }, + experience: { + client_defined_experiences: [], + encoded_server_defined_params: null, + fbid: null, + type: "PEOPLE_TAB", + }, + filters: [], + text: keyword, + }, + cursor: null, + feedbackSource: 23, + fetch_filters: true, + renderLocation: "search_results_page", + scale: 2, + stream_initial_count: 0, + useDefaultActor: false, + }, + }, + await getFbdtsg() + ); + const json = JSON.parse(res); + console.log(json); +} // ============================================================================= // =================================== Friend ================================== diff --git a/scripts/helpers/utils.js b/scripts/helpers/utils.js index 883de28f..acb7b7b7 100644 --- a/scripts/helpers/utils.js +++ b/scripts/helpers/utils.js @@ -142,7 +142,7 @@ export function runFunc(fnPath = "", params = [], global = {}) { export async function trackEvent(scriptId) { console.log("trackEvent", scriptId, version); - // return; + return; try { let res = await fetch( // "http://localhost:3000/count", diff --git a/working_note.md b/working_note.md index 07520cd0..cb50c651 100644 --- a/working_note.md +++ b/working_note.md @@ -2,6 +2,10 @@ ## 01/07/2024 - ? +- [ ] get fb profile pic + +- [ ] find fb account using phone or email + - [ ] analyze this - [ ] check down video From a719d9b3aab69d5390bcc814e8f9acc445f7e1b1 Mon Sep 17 00:00:00 2001 From: yuran1811 Date: Sat, 6 Jul 2024 16:49:00 +0700 Subject: [PATCH 11/44] =?UTF-8?q?fix:=20=F0=9F=90=9B=20fix=20fireship=5Fvi?= =?UTF-8?q?p=20script?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/fireship_vip.js | 79 ++++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/scripts/fireship_vip.js b/scripts/fireship_vip.js index b2fa36ab..384535f1 100644 --- a/scripts/fireship_vip.js +++ b/scripts/fireship_vip.js @@ -1,23 +1,23 @@ export default { - icon: "https://fireship.io/img/favicon.png", + icon: 'https://fireship.io/img/favicon.png', name: { - en: "Fireship - PRO unlocked", - vi: "Fireship - Mở khoá PRO", + en: 'Fireship - PRO unlocked', + vi: 'Fireship - Mở khoá PRO', }, description: { - en: "Unlock all Fireship PRO courses/lessons (saved $399 USD)", - vi: "Mở khoá tất cả khoá học/bài giảng PRO trên Fireship (tiết kiệm $399 USD)", + en: 'Unlock all Fireship PRO courses/lessons (saved $399 USD)', + vi: 'Mở khoá tất cả khoá học/bài giảng PRO trên Fireship (tiết kiệm $399 USD)', }, - infoLink: "https://fireship.io/", + infoLink: 'https://fireship.io/', - whiteList: ["https://fireship.io/*"], + whiteList: ['https://fireship.io/*'], - contentScript: { + pageScript: { onDocumentIdle: () => { // ==UserScript== // @name Freeship // @namespace lemons - // @version 1.7 + // @version 1.8 // @description Unlock all Fireship PRO courses/lessons. // @author lemons // @match https://fireship.io/* @@ -27,31 +27,54 @@ export default { // @updateURL https://update.greasyfork.org/scripts/455330/Freeship.meta.js // ==/UserScript== - // prettier-ignore - setInterval(async () => { - document.querySelectorAll("[free=\"\"]").forEach(el => el.setAttribute("free", true)) // set all elements with the attribute free set to "" to true + console.log('use fireship_vip.js'); - if (document.querySelector("if-access [slot=\"granted\"]")) { // replace HOW TO ENROLL to YOU HAVE ACCESS - document.querySelector("if-access [slot=\"denied\"]").remove() - document.querySelector("if-access [slot=\"granted\"]").setAttribute("slot", "denied") + const unlock = async () => { + // set all elements with the attribute free set to "" to true + document.querySelectorAll('[free=""]').forEach((el) => el.setAttribute('free', true)); + + if (document.querySelector('if-access [slot="granted"]')) { + // replace HOW TO ENROLL to YOU HAVE ACCESS + document.querySelector('if-access [slot="denied"]').remove(); + document.querySelector('if-access [slot="granted"]').setAttribute('slot', 'denied'); } - if (document.querySelector("video-player")?.shadowRoot?.querySelector(".vid")?.innerHTML) return; // return if no video player - const vimeoId = Number(atob(document.querySelector("global-data").vimeo)); // get id for vimeo video - const youtubeId = atob(document.querySelector("global-data").youtube); // get id for vimeo video + // return if no video player + if (document.querySelector('video-player')?.shadowRoot?.querySelector('.vid')?.innerHTML) return; + + // get id for vimeo video + const vimeoId = Number(atob(document.querySelector('global-data').vimeo || btoa(''))); - if (youtubeId) { // if there is an id, - document.querySelector("video-player").setAttribute("free", true) // set free to true - document.querySelector("video-player").shadowRoot.querySelector(".vid").innerHTML = `` // set video - return; + // get id for vimeo video + const youtubeId = atob(document.querySelector('global-data').youtube || btoa('')); + + if (youtubeId) { + // if there is an id, + document.querySelector('video-player').setAttribute('free', true); // set free to true + document + .querySelector('video-player') + .shadowRoot.querySelector( + '.vid' + ).innerHTML = ``; // set video + return; } - if (vimeoId) { // if there is an id, - document.querySelector("video-player").setAttribute("free", true) // set free to true - const html = (await fetch(`https://vimeo.com/api/oembed.json?url=https%3A%2F%2Fvimeo.com%2F${vimeoId}&id=${vimeoId}`).then(r=>r.json())).html - document.querySelector("video-player").shadowRoot.querySelector(".vid").innerHTML = html // set video - return; + if (vimeoId) { + // if there is an id, + document.querySelector('video-player').setAttribute('free', true); // set free to true + const html = ( + await fetch( + `https://vimeo.com/api/oembed.json?url=https%3A%2F%2Fvimeo.com%2F${vimeoId}&id=${vimeoId}` + ).then((r) => r.json()) + ).html; + document.querySelector('video-player').shadowRoot.querySelector('.vid').innerHTML = html; // set video + return; } - }, 500) + }; + + window.onload = unlock(); + window.addEventListener('flamethrower:router:end', unlock); }, }, }; From 6d45c029de622d65dd9ac49509a94e05bb05cfdc Mon Sep 17 00:00:00 2001 From: yuran1811 Date: Sat, 6 Jul 2024 17:55:05 +0700 Subject: [PATCH 12/44] =?UTF-8?q?feat:=20=E2=9C=A8=20add=20script=20to=20r?= =?UTF-8?q?ender=20youtube=20video=20download=20buttons=20for=20each=20vid?= =?UTF-8?q?eo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- popup/tabs.js | 1 + scripts/_index.js | 1 + scripts/youtube_downloadVideoUI.js | 114 +++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 scripts/youtube_downloadVideoUI.js diff --git a/popup/tabs.js b/popup/tabs.js index bc56c510..a755bfb2 100644 --- a/popup/tabs.js +++ b/popup/tabs.js @@ -500,6 +500,7 @@ const tabs = [ scripts: [ // s.youtube_localDownloader, s.youtube_downloadVideo, + s.youtube_downloadVideoUI, s.youtube_toggleLight, s.pictureInPicture, s.pip_fullWebsite, diff --git a/scripts/_index.js b/scripts/_index.js index 03de5a6d..8ad67e89 100644 --- a/scripts/_index.js +++ b/scripts/_index.js @@ -168,3 +168,4 @@ export { default as showImageOnHoverLink } from "./showImageOnHoverLink.js"; export { default as fb_allInOne } from "./fb_allInOne.js"; export { default as fb_getPostReactionCount } from "./fb_getPostReactionCount.js"; export { default as bypass_learnAnything } from "./bypass_learnAnything.js"; +export { default as youtube_downloadVideoUI } from "./youtube_downloadVideoUI.js"; diff --git a/scripts/youtube_downloadVideoUI.js b/scripts/youtube_downloadVideoUI.js new file mode 100644 index 00000000..a9c22a7b --- /dev/null +++ b/scripts/youtube_downloadVideoUI.js @@ -0,0 +1,114 @@ +import { BADGES } from './helpers/badge.js'; + +export default { + icon: `https://www.youtube.com/s/desktop/ff71ea81/img/favicon_48x48.png`, + name: { + en: 'Render buttons to download youtube video/audio', + vi: 'Tạo các nút để tải video/audio youtube', + }, + description: { + en: 'Bypass age restriction, without login', + vi: 'Tải cả video giới hạn độ tuổi, không cần đăng nhập', + }, + badges: [BADGES.new], + + contentScript: { + onDocumentIdle: () => { + setTimeout(function () { + // https://stackoverflow.com/a/8260383/11898496 + function getIdFromYoutubeURL(url) { + let regExp = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/; + let match = url.match(regExp); + return match && match[1].length == 11 ? match[1] : false; + } + + const colors = { + default: '#272727', + green: '#2fb024', + red: '#e62e2e', + blue: '#3034bd', + }; + + const providers = [ + { + name: 'savefrom.net', + color: colors.green, + func: (url) => url.replace('youtube', 'ssyoutube'), + }, + { + name: '10downloader.com', + color: colors.blue, + func: (url) => url.replace('youtube', '000tube'), + }, + { + name: 'y2mate.com', + color: colors.red, + func: (url) => url.replace('youtube', 'youtubepp'), + }, + { + name: 'yt5s.com', + color: colors.blue, + func: (url) => url.replace('youtube', 'youtube5s'), + }, + { + name: 'yt1s.com', + color: colors.red, + func: (url) => 'https://yt1s.com/vi/youtube-to-mp4?q=' + url, + }, + { + name: 'tubemp3.to', + color: colors.default, + func: (url) => 'https://tubemp3.to/' + url, + }, + { + name: '10downloader.com', + color: colors.default, + func: (url) => 'https://10downloader.com/download?v=' + url, + }, + { + name: '9xbuddy.com', + color: colors.default, + func: (url) => 'https://9xbuddy.com/process?url=' + url, + }, + { + name: 'ymp4.com', + color: colors.default, + func: (url) => 'https://ymp4.download/en50/?url=' + url, + }, + { + name: 'getlinks.vip', + color: colors.default, + func: (url) => 'https://getlinks.vip/vi/youtube/' + getIdFromYoutubeURL(url), + }, + ]; + + const videoUrl = window.location.href; + + const genDownloadLinkFromProvider = (provider, url) => + /* html */ + `${provider.name}`; + + let intervalId = setInterval(function () { + const container = document.querySelector('#above-the-fold #title > h1'); + if (!container) return; + + clearInterval(intervalId); + + const links = providers.map((provider) => genDownloadLinkFromProvider(provider, videoUrl)); + + container.insertAdjacentHTML( + 'afterend', + /* html */ + `
+ ${links.join('')} +
` + ); + }, 500); + }, 500); + }, + }, +}; From 628ca2aea871136148656f8822950ce804709ba0 Mon Sep 17 00:00:00 2001 From: yuran1811 Date: Sat, 6 Jul 2024 18:30:11 +0700 Subject: [PATCH 13/44] =?UTF-8?q?feat:=20=E2=9C=A8=20add=20search=20select?= =?UTF-8?q?ion=20text=20with=20youglish?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/_index.js | 1 + scripts/youglish_search.js | 47 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 scripts/youglish_search.js diff --git a/scripts/_index.js b/scripts/_index.js index 8ad67e89..ed941092 100644 --- a/scripts/_index.js +++ b/scripts/_index.js @@ -169,3 +169,4 @@ export { default as fb_allInOne } from "./fb_allInOne.js"; export { default as fb_getPostReactionCount } from "./fb_getPostReactionCount.js"; export { default as bypass_learnAnything } from "./bypass_learnAnything.js"; export { default as youtube_downloadVideoUI } from "./youtube_downloadVideoUI.js"; +export { default as youglish_search } from "./youglish_search.js"; diff --git a/scripts/youglish_search.js b/scripts/youglish_search.js new file mode 100644 index 00000000..36d6e7da --- /dev/null +++ b/scripts/youglish_search.js @@ -0,0 +1,47 @@ +import { BADGES } from './helpers/badge.js'; + +const contextMenuId = 'youglish-search'; + +export default { + icon: '', + name: { + en: 'YouGlish search', + vi: 'Tìm kiếm trên YouGlish', + }, + description: { + en: "Master English pronunciation naturally! Learn how to pronounce tricky sounds like a native with YouGlish's real-world clips. No more dictionary confusion, just real English in context. (from 'youglish.com')", + vi: 'Làm chủ phát âm tiếng Anh một cách tự nhiên! Học cách phát âm những âm thanh khó khăn như người bản xứ với các đoạn video thực tế từ YouGlish. Không còn bối rối với từ điển, chỉ có tiếng Anh thực sự trong ngữ cảnh. (từ "youglish.com")', + }, + badges: [BADGES.new], + changeLogs: { + '2024-07-06': 'init', + }, + + popupScript: { + onClick: () => window.close(), + }, + + backgroundScript: { + runtime: { + onInstalled: () => { + chrome.contextMenus.create({ + title: 'YouGlish Search', + contexts: ['selection'], + id: contextMenuId, + parentId: 'root', + }); + }, + }, + contextMenus: { + onClicked: ({ info }, context) => { + if (info.menuItemId == contextMenuId) { + const content = (info.selectionText || '').trim().toLowerCase(); + if (!content.length) return; + + const link = `https://youglish.com/pronounce/${content}/english`; + chrome.tabs.create({ url: link }); + } + }, + }, + }, +}; From bd17a9f596ccf5e2aaad502f5105438e50176c48 Mon Sep 17 00:00:00 2001 From: yuran1811 Date: Sat, 6 Jul 2024 21:11:59 +0700 Subject: [PATCH 14/44] =?UTF-8?q?feat:=20=E2=9C=A8=20enhance=20ui=20with?= =?UTF-8?q?=20dropdown=20and=20youtube-like=20ui?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit new file: scripts/youtube_downloadVideoUI.css modified: scripts/youtube_downloadVideoUI.js --- scripts/youtube_downloadVideoUI.css | 33 ++++++++++++++++++ scripts/youtube_downloadVideoUI.js | 52 +++++++++++++++++++++++------ 2 files changed, 75 insertions(+), 10 deletions(-) create mode 100644 scripts/youtube_downloadVideoUI.css diff --git a/scripts/youtube_downloadVideoUI.css b/scripts/youtube_downloadVideoUI.css new file mode 100644 index 00000000..c3e8a20d --- /dev/null +++ b/scripts/youtube_downloadVideoUI.css @@ -0,0 +1,33 @@ +.ufs-ytDownloadVideoUI__btn { + color: #f1f1f1; + display: inline-block; + padding: 2px 12px; + border-radius: 6px; + text-decoration: none; + font-weight: bold; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + -webkit-tap-highlight-color: transparent; +} + +.ufs-ytDownloadVideoUI__btn:hover { + background-color: #333; +} + +.ufs-ytDownloadVideoUI__container { + background-color: #272727; + z-index: 999; + position: absolute; + top: 45px; + left: 0; + + display: none; + flex-flow: column; + justify-content: start; + align-items: start; + + overflow: hidden auto; + width: max-content; + max-height: 250px; + padding: 8px; + border-radius: 12px; +} diff --git a/scripts/youtube_downloadVideoUI.js b/scripts/youtube_downloadVideoUI.js index a9c22a7b..124dec10 100644 --- a/scripts/youtube_downloadVideoUI.js +++ b/scripts/youtube_downloadVideoUI.js @@ -1,3 +1,4 @@ +import { UfsGlobal } from './content-scripts/ufs_global.js'; import { BADGES } from './helpers/badge.js'; export default { @@ -17,8 +18,8 @@ export default { setTimeout(function () { // https://stackoverflow.com/a/8260383/11898496 function getIdFromYoutubeURL(url) { - let regExp = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/; - let match = url.match(regExp); + const regExp = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/; + const match = url.match(regExp); return match && match[1].length == 11 ? match[1] : false; } @@ -84,13 +85,18 @@ export default { const videoUrl = window.location.href; + const downloadIcon = ` + + + `; + const genDownloadLinkFromProvider = (provider, url) => /* html */ - `${provider.name}`; + ` + ${provider.name} + `; + + injectCss(); let intervalId = setInterval(function () { const container = document.querySelector('#above-the-fold #title > h1'); @@ -98,17 +104,43 @@ export default { clearInterval(intervalId); + document.addEventListener('click', () => { + const el = document.querySelector('#ufs-ytDownloadBtn__container'); + if (el && el.style.display === 'flex') el.style.display = 'none'; + }); + const links = providers.map((provider) => genDownloadLinkFromProvider(provider, videoUrl)); container.insertAdjacentHTML( 'afterend', /* html */ - `
- ${links.join('')} -
` + ` + ` ); }, 500); }, 500); }, }, }; + +function injectCss(path = '/scripts/youtube_downloadVideoUI.css', id = 'ufs-yt_downloadVideoUI-css') { + if (!document.querySelector('#' + id)) { + UfsGlobal.Extension.getURL(path).then((url) => { + UfsGlobal.DOM.injectCssFile(url, id); + }); + } +} From 25890b234a811c206617ea7886247259fb45895b Mon Sep 17 00:00:00 2001 From: yuran1811 Date: Sat, 6 Jul 2024 21:54:53 +0700 Subject: [PATCH 15/44] =?UTF-8?q?fix:=20=F0=9F=90=9B=20fix=20link=20button?= =?UTF-8?q?=20and=20ymp4=20download=20url?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/youtube_downloadVideoUI.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/youtube_downloadVideoUI.js b/scripts/youtube_downloadVideoUI.js index 124dec10..e45792c0 100644 --- a/scripts/youtube_downloadVideoUI.js +++ b/scripts/youtube_downloadVideoUI.js @@ -74,7 +74,7 @@ export default { { name: 'ymp4.com', color: colors.default, - func: (url) => 'https://ymp4.download/en50/?url=' + url, + func: (url) => 'https://ymp4.download/?url=' + url, }, { name: 'getlinks.vip', @@ -92,7 +92,11 @@ export default { const genDownloadLinkFromProvider = (provider, url) => /* html */ - ` + ` ${provider.name} `; @@ -118,7 +122,7 @@ export default {

Captions


+
+ Auto translate `; - const button = div.querySelector("button"); - button.onclick = () => { - div.remove(); + div.onclick = async (e) => { + if (e.target == div) div.remove(); + if (e.target.tagName == "A") { + const type = e.target.getAttribute("data-type"); + if (type) { + e.preventDefault(); + downloadCaption(e.target.getAttribute("href"), type, title); + } + } }; document.documentElement.appendChild(div); } + async function downloadCaption(url, type, title) { + try { + const res = await fetch(url, { + headers: { + contentType: "text/xml", + }, + }); + const text = await res.text(); + const xml = parseXml(text); + + const transcript = xml.getElementsByTagName("transcript")[0]; + const texts = Array.from(transcript.getElementsByTagName("text")); + + if (type === "txt") { + const data = texts + .map((t) => decodeHtmlEntities(t.textContent)) + .join("\n"); + alert(data); + // UfsGlobal.Utils.downloadData(data, title + ".txt"); + } else if (type === "srt") { + const data = texts + .map((t, i) => { + // 1 + // 00:00:00,120 --> 00:00:01,880 + // mùa tuyển sinh sắp đến rồi nên là hôm + let index = i + 1; + let start = Number(t.getAttribute("start")); + let dur = Number(t.getAttribute("dur")); + let end = start + dur; + return ( + index + + "\n" + + formatTimeToSRT(start) + + " --> " + + formatTimeToSRT(end) + + "\n" + + decodeHtmlEntities(t.textContent) + ); + }) + .join("\n\n"); + UfsGlobal.Utils.downloadData(data, title + ".srt"); + } + } catch (e) { + alert(e); + console.error(e); + } + } + + const pad = (num, len = 2) => num.toString().padStart(len, "0"); + + // 6.120 -> 00:00:06,120 + function formatTimeToSRT(seconds) { + // Get hours, minutes, and seconds + const hours = Math.floor(seconds / 3600); + const minutes = Math.floor((seconds % 3600) / 60); + const secs = Math.floor(seconds % 60); + const milliseconds = Math.floor((seconds % 1) * 1000); + // Format the time string + return `${pad(hours)}:${pad(minutes)}:${pad(secs)},${pad( + milliseconds, + 3 + )}`; + } + + var textArea = document.createElement("textarea"); + function decodeHtmlEntities(text) { + textArea.innerHTML = text; + return textArea.innerHTML; + } + const methods = [ - () => - document.getElementsByTagName("ytd-app")[0].data.playerResponse - .captions.playerCaptionsTracklistRenderer.captionTracks, - () => - ytplayer.config.args.raw_player_response.captions - .playerCaptionsTracklistRenderer.captionTracks, + () => document.getElementsByTagName("ytd-app")[0].data.playerResponse, + () => ytplayer.config.args.raw_player_response, ]; for (let f of methods) { try { - let captions = f(); + let p = f(); + let captions = + p.captions.playerCaptionsTracklistRenderer.captionTracks; + let title = p.videoDetails?.title || document.title; + if (captions) { - renderCaptions(captions); + renderCaptions(captions, title); return; } } catch (e) { console.error(e); } } + + alert("No captions found"); }, }, }; From 1b3d85413d3497c56e83a8592347d068d636d818 Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Sun, 7 Jul 2024 00:25:57 +0700 Subject: [PATCH 17/44] fix + merge youtube download video --- popup/tabs.js | 1 - scripts/_index.js | 1 - ...dVideoUI.css => youtube_downloadVideo.css} | 8 +- scripts/youtube_downloadVideo.js | 192 ++++++++++++++---- scripts/youtube_downloadVideo.png | Bin 0 -> 21113 bytes scripts/youtube_downloadVideoUI.js | 150 -------------- 6 files changed, 153 insertions(+), 199 deletions(-) rename scripts/{youtube_downloadVideoUI.css => youtube_downloadVideo.css} (80%) create mode 100644 scripts/youtube_downloadVideo.png delete mode 100644 scripts/youtube_downloadVideoUI.js diff --git a/popup/tabs.js b/popup/tabs.js index cc8f5929..98c5aaa6 100644 --- a/popup/tabs.js +++ b/popup/tabs.js @@ -499,7 +499,6 @@ const tabs = [ ...CATEGORY.youtube, scripts: [ s.youtube_downloadVideo, - s.youtube_downloadVideoUI, s.youtube_getVideoThumbnail, s.youtube_getVideoCaption, s.youtube_toggleLight, diff --git a/scripts/_index.js b/scripts/_index.js index 2a6047d3..261f03b4 100644 --- a/scripts/_index.js +++ b/scripts/_index.js @@ -167,7 +167,6 @@ export { default as showImageOnHoverLink } from "./showImageOnHoverLink.js"; export { default as fb_allInOne } from "./fb_allInOne.js"; export { default as fb_getPostReactionCount } from "./fb_getPostReactionCount.js"; export { default as bypass_learnAnything } from "./bypass_learnAnything.js"; -export { default as youtube_downloadVideoUI } from "./youtube_downloadVideoUI.js"; export { default as youglish_search } from "./youglish_search.js"; export { default as youtube_getVideoThumbnail } from "./youtube_getVideoThumbnail.js"; export { default as youtube_getVideoCaption } from "./youtube_getVideoCaption.js"; diff --git a/scripts/youtube_downloadVideoUI.css b/scripts/youtube_downloadVideo.css similarity index 80% rename from scripts/youtube_downloadVideoUI.css rename to scripts/youtube_downloadVideo.css index c3e8a20d..3ae13c73 100644 --- a/scripts/youtube_downloadVideoUI.css +++ b/scripts/youtube_downloadVideo.css @@ -1,19 +1,21 @@ -.ufs-ytDownloadVideoUI__btn { +.ufs-ytDownloadVideo__btn { color: #f1f1f1; display: inline-block; padding: 2px 12px; border-radius: 6px; text-decoration: none; font-weight: bold; + width: 100%; + text-align: left; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -webkit-tap-highlight-color: transparent; } -.ufs-ytDownloadVideoUI__btn:hover { +.ufs-ytDownloadVideo__btn:hover { background-color: #333; } -.ufs-ytDownloadVideoUI__container { +.ufs-ytDownloadVideo__dropdown { background-color: #272727; z-index: 999; position: absolute; diff --git a/scripts/youtube_downloadVideo.js b/scripts/youtube_downloadVideo.js index b678e12d..3ee23217 100644 --- a/scripts/youtube_downloadVideo.js +++ b/scripts/youtube_downloadVideo.js @@ -1,3 +1,4 @@ +import { UfsGlobal } from "./content-scripts/ufs_global.js"; import { BADGES } from "./helpers/badge.js"; export default { @@ -7,60 +8,35 @@ export default { vi: "Tải video/audio youtube", }, description: { - en: "Bypass age restriction, without login", - vi: "Tải cả video giới hạn độ tuổi, không cần đăng nhập", + en: `Bypass age restriction, without login +
    +
  • Click once to download current video
  • +
  • Enable autorun to render download button
  • +
`, + vi: `Tải cả video giới hạn độ tuổi, không cần đăng nhập +
    +
  • Bấm 1 lần để tải video hiện tại
  • +
  • Bật tự chạy để hiển thị nút tải
  • +
`, + img: "/scripts/youtube_downloadVideo.png", }, - badges: [BADGES.hot], + badges: [BADGES.new], + + whiteList: ["https://*.youtube.com/*"], contentScript: { onClick: function () { - let options = [ - { - name: "y2mate.com", - func: (url) => url.replace("youtube.com", "youtubepp.com"), - }, - { - name: "yt1s.com", - func: (url) => "https://yt1s.com/vi/youtube-to-mp4?q=" + url, - }, - { - name: "yt5s.com", - func: (url) => url.replace("youtube.com", "youtube5s.com"), - }, - { - name: "tubemp3.to", - func: (url) => "https://tubemp3.to/" + url, - }, - { - name: "10downloader.com", - func: (url) => "https://10downloader.com/download?v=" + url, - }, - { - name: "9xbuddy.com", - func: (url) => "https://9xbuddy.com/process?url=" + url, - }, - { - name: "getlinks.vip", - func: (url) => - "https://getlinks.vip/vi/youtube/" + getIdFromYoutubeURL(url), - }, - { - name: "ymp4.com", - func: (url) => "https://ymp4.download/en50/?url=" + url, - }, - ]; - let choose = prompt( "Tải video youtube: \n\n" + - options.map((_, i) => `${i}: ${_.name}`).join("\n") + + providers.map((_, i) => `${i}: ${_.name}`).join("\n") + "\n\nNhập lựa chọn:", 0 ); - if (choose != null && choose >= 0 && choose < options.length) { + if (choose != null && choose >= 0 && choose < providers.length) { let url = prompt("Nhập link youtube:", location.href); if (url) { - url = options[choose].func(url); + url = providers[choose].func(url); let myWin = window.open( url, "Download Youtube Video", @@ -69,12 +45,140 @@ export default { } } }, + + onDocumentIdle: () => { + const downloadIcon = ` + + + `; + + injectCss(); + + let intervalId = setInterval(function () { + const container = document.querySelector("#above-the-fold #title > h1"); + if (!container) return; + + clearInterval(intervalId); + + document.addEventListener("click", (e) => { + const el = document.querySelector("#ufs-ytDownloadBtn__dropdown"); + if (e.target !== el || (el && el.style.display === "flex")) + el.style.display = "none"; + }); + + const links = providers.map( + (provider) => /* html */ ` + + ${provider.name} + ` + ); + + const div = document.createElement("div"); + div.id = "ufs-ytDownloadBtn__container"; + div.innerHTML = /* html */ ` + `; + + const button = div.querySelector("button"); + button.addEventListener("click", (e) => { + e.stopPropagation(); + const el = document.querySelector("#ufs-ytDownloadBtn__dropdown"); + if (!el) return; + el.style.display = el.style.display == "flex" ? "none" : "flex"; + }); + + const options = div.querySelectorAll("a"); + options.forEach((option) => { + option.addEventListener("click", (e) => { + e.stopPropagation(); + const providerName = option.getAttribute("data-provider"); + const provider = providers.find((p) => p.name === providerName); + if (!provider) return; + const url = provider.func(window.location.href); + window.open(url, "_blank"); + }); + }); + + container.insertAdjacentElement("afterend", div); + }, 500); + }, }, }; // https://stackoverflow.com/a/8260383/11898496 export function getIdFromYoutubeURL(url) { - let regExp = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/; - let match = url.match(regExp); + const regExp = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/; + const match = url.match(regExp); return match && match[1].length == 11 ? match[1] : false; } + +const providers = [ + { + name: "y2mate.com", + func: (url) => url.replace("youtube", "youtubepp"), + }, + { + name: "yt5s.com", + func: (url) => url.replace("youtube", "youtube5s"), + }, + { + name: "yt1s.com", + func: (url) => "https://yt1s.com/vi/youtube-to-mp4?q=" + url, + }, + { + name: "tubemp3.to", + func: (url) => "https://tubemp3.to/" + url, + }, + { + name: "10downloader.com", + func: (url) => "https://10downloader.com/download?v=" + url, + }, + { + name: "9xbuddy.com", + func: (url) => "https://9xbuddy.com/process?url=" + url, + }, + { + name: "ymp4.com", + func: (url) => "https://ymp4.download/?url=" + url, + }, + { + name: "savefrom.net", + func: (url) => url.replace("youtube", "ssyoutube"), + }, + { + name: "10downloader.com", + func: (url) => url.replace("youtube", "000tube"), + }, + { + name: "getlinks.vip", + func: (url) => + "https://getlinks.vip/vi/youtube/" + getIdFromYoutubeURL(url), + }, +]; + +function injectCss( + path = "/scripts/youtube_downloadVideo.css", + id = "ufs-yt_downloadVideo-css" +) { + if (!document.querySelector("#" + id)) { + UfsGlobal.Extension.getURL(path).then((url) => { + UfsGlobal.DOM.injectCssFile(url, id); + }); + } +} diff --git a/scripts/youtube_downloadVideo.png b/scripts/youtube_downloadVideo.png new file mode 100644 index 0000000000000000000000000000000000000000..b8d34a8e5e3c6a9c1f107c881ed226c1d60802db GIT binary patch literal 21113 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 literal 0 HcmV?d00001 diff --git a/scripts/youtube_downloadVideoUI.js b/scripts/youtube_downloadVideoUI.js deleted file mode 100644 index e45792c0..00000000 --- a/scripts/youtube_downloadVideoUI.js +++ /dev/null @@ -1,150 +0,0 @@ -import { UfsGlobal } from './content-scripts/ufs_global.js'; -import { BADGES } from './helpers/badge.js'; - -export default { - icon: `https://www.youtube.com/s/desktop/ff71ea81/img/favicon_48x48.png`, - name: { - en: 'Render buttons to download youtube video/audio', - vi: 'Tạo các nút để tải video/audio youtube', - }, - description: { - en: 'Bypass age restriction, without login', - vi: 'Tải cả video giới hạn độ tuổi, không cần đăng nhập', - }, - badges: [BADGES.new], - - contentScript: { - onDocumentIdle: () => { - setTimeout(function () { - // https://stackoverflow.com/a/8260383/11898496 - function getIdFromYoutubeURL(url) { - const regExp = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/; - const match = url.match(regExp); - return match && match[1].length == 11 ? match[1] : false; - } - - const colors = { - default: '#272727', - green: '#2fb024', - red: '#e62e2e', - blue: '#3034bd', - }; - - const providers = [ - { - name: 'savefrom.net', - color: colors.green, - func: (url) => url.replace('youtube', 'ssyoutube'), - }, - { - name: '10downloader.com', - color: colors.blue, - func: (url) => url.replace('youtube', '000tube'), - }, - { - name: 'y2mate.com', - color: colors.red, - func: (url) => url.replace('youtube', 'youtubepp'), - }, - { - name: 'yt5s.com', - color: colors.blue, - func: (url) => url.replace('youtube', 'youtube5s'), - }, - { - name: 'yt1s.com', - color: colors.red, - func: (url) => 'https://yt1s.com/vi/youtube-to-mp4?q=' + url, - }, - { - name: 'tubemp3.to', - color: colors.default, - func: (url) => 'https://tubemp3.to/' + url, - }, - { - name: '10downloader.com', - color: colors.default, - func: (url) => 'https://10downloader.com/download?v=' + url, - }, - { - name: '9xbuddy.com', - color: colors.default, - func: (url) => 'https://9xbuddy.com/process?url=' + url, - }, - { - name: 'ymp4.com', - color: colors.default, - func: (url) => 'https://ymp4.download/?url=' + url, - }, - { - name: 'getlinks.vip', - color: colors.default, - func: (url) => 'https://getlinks.vip/vi/youtube/' + getIdFromYoutubeURL(url), - }, - ]; - - const videoUrl = window.location.href; - - const downloadIcon = ` - - - `; - - const genDownloadLinkFromProvider = (provider, url) => - /* html */ - ` - ${provider.name} - `; - - injectCss(); - - let intervalId = setInterval(function () { - const container = document.querySelector('#above-the-fold #title > h1'); - if (!container) return; - - clearInterval(intervalId); - - document.addEventListener('click', () => { - const el = document.querySelector('#ufs-ytDownloadBtn__container'); - if (el && el.style.display === 'flex') el.style.display = 'none'; - }); - - const links = providers.map((provider) => genDownloadLinkFromProvider(provider, videoUrl)); - - container.insertAdjacentHTML( - 'afterend', - /* html */ - ` - ` - ); - }, 500); - }, 500); - }, - }, -}; - -function injectCss(path = '/scripts/youtube_downloadVideoUI.css', id = 'ufs-yt_downloadVideoUI-css') { - if (!document.querySelector('#' + id)) { - UfsGlobal.Extension.getURL(path).then((url) => { - UfsGlobal.DOM.injectCssFile(url, id); - }); - } -} From 1f5ed9f51f652706acfd1c4c65915bb54307ae7d Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Sun, 7 Jul 2024 01:04:42 +0700 Subject: [PATCH 18/44] fix --- scripts/youtube_getVideoCaption.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/youtube_getVideoCaption.js b/scripts/youtube_getVideoCaption.js index 0563a098..6278d785 100644 --- a/scripts/youtube_getVideoCaption.js +++ b/scripts/youtube_getVideoCaption.js @@ -68,7 +68,8 @@ export default { }
-

Captions


+

Useful-scripts: Youtube captions


+

${title}


From 0e38b0d75dab798e0c02093978aa4a428ba24bdd Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Mon, 8 Jul 2024 05:16:21 +0700 Subject: [PATCH 25/44] persist cookie --- scripts/youtube_changeCountry.js | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/scripts/youtube_changeCountry.js b/scripts/youtube_changeCountry.js index 2f695939..92315d54 100644 --- a/scripts/youtube_changeCountry.js +++ b/scripts/youtube_changeCountry.js @@ -86,17 +86,36 @@ export default { function changeCountry(value, persist) { if (value) { - location.href = - "https://www.youtube.com/feed/trending?persist_gl=" + - (persist ? "1" : "0") + - ("&gl=" + value); + let href = "https://www.youtube.com/feed/trending"; + if (persist) { + if (value !== "default") { + var date = new Date(); + date.setTime(date.getTime() + 3.154e10); + + document.cookie = + "s_gl=" + + value + + "; path=/; domain=.youtube.com; expires=" + + date.toGMTString(); + } else { + document.cookie = + "s_gl=0; path=/; domain=.youtube.com; expires=Thu, 01 Jan 1970 00:00:01 GMT"; + } + + window.location.href = href; + } else { + href += `?persist_gl=0&gl=${value}`; + window.location.href = href; + } } } function getCurrentCountry() { const code = window?.ytInitialData?.topbar?.desktopTopbarRenderer?.countryCode || - window.yt?.config_?.GL; + window.yt?.config_?.GL || + // regex in cookie + document.cookie.match(/s_gl=([^;]+)/)?.[1]; return code || "default"; } From e7ea8d5e30fe6480e383a4cc5fd20a6771e214be Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Mon, 8 Jul 2024 18:20:53 +0700 Subject: [PATCH 26/44] WIP auto like --- scripts/fb_autoLike.js | 120 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 scripts/fb_autoLike.js diff --git a/scripts/fb_autoLike.js b/scripts/fb_autoLike.js new file mode 100644 index 00000000..c8988d53 --- /dev/null +++ b/scripts/fb_autoLike.js @@ -0,0 +1,120 @@ +export default { + icon: "", + name: { + en: "", + vi: "", + }, + description: { + en: "", + vi: "", + img: "", + }, + + changeLogs: { + "2024-07-08": "init", + }, + + whiteList: [], + + contentScript: { + onClick: async () => { + function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + function focusTo(element) { + element.dispatchEvent( + new MouseEvent("pointerover", { + view: window, + bubbles: true, + cancelable: true, + }) + ); + } + + function scrollToBottom() { + window.scrollTo(0, document.body.scrollHeight, { + // behavior: "smooth", + }); + } + + const Reactions = { + Like: { + en: "Like", + vi: "Thích", + emoji: "👍", + }, + Love: { + en: "Love", + vi: "Yêu thích", + emoji: "❤️", + }, + Care: { + en: "Care", + vi: "Nghiện", + emoji: "😊", + }, + Haha: { + en: "Haha", + vi: "Há", + emoji: "😂", + }, + Wow: { + en: "Wow", + vi: "Wow", + emoji: "😮", + }, + Sad: { + en: "Sad", + vi: "Buồn", + emoji: "😢", + }, + Angry: { + en: "Angry", + vi: "Khóc", + emoji: "😡", + }, + }; + + const doneKey = "auto-like-done"; + const btns = []; + while (true) { + if (!btns.length) { + let curBtns = Array.from( + document.querySelectorAll( + "[aria-label='Bày tỏ cảm xúc']:not(li *), [aria-label='React']:not(li *)" + ) + ); + let added = 0; + for (let btn of curBtns) { + if (btn.getAttribute(doneKey) === null) { + btns.push(btn); + btn.setAttribute(doneKey, true); + added++; + } + } + if (added === 0) break; + } + + for (let btn of btns) { + btn.scrollIntoView({ + block: "center", + // behavior: "smooth", + }); + btn.click(); + await sleep(500); + let loveBtn = document.querySelector("[aria-label='Yêu thích']"); + if (loveBtn) { + focusTo(loveBtn); + await sleep(500); + loveBtn.click(); + await sleep(500); + } + btns.splice(btns.indexOf(btn), 1); + } + scrollToBottom(); + await sleep(3000); + } + alert("xong"); + }, + }, +}; From a598c1fbc2416a05e3fd915f870b09b38fd740ae Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Mon, 8 Jul 2024 18:35:52 +0700 Subject: [PATCH 27/44] fb auto like - WIP --- popup/tabs.js | 1 + scripts/_index.js | 1 + scripts/fb_autoLike.js | 15 ++++++++------- scripts/youtube_changeCountry.js | 4 +++- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/popup/tabs.js b/popup/tabs.js index b0909248..4614c839 100644 --- a/popup/tabs.js +++ b/popup/tabs.js @@ -306,6 +306,7 @@ const tabs = [ // s.fb_downloadWallMediaFromPosts, // s.fb_getAllAlbumInformation, createTitle("--- Hot ---", "--- Nổi bật ---"), + s.fb_autoLike, s.fb_revealDeletedMessages, s.fb_moreReactionStory, s.fb_toggleLight, diff --git a/scripts/_index.js b/scripts/_index.js index cd4c59ed..492beea0 100644 --- a/scripts/_index.js +++ b/scripts/_index.js @@ -171,3 +171,4 @@ export { default as youglish_search } from "./youglish_search.js"; export { default as youtube_getVideoThumbnail } from "./youtube_getVideoThumbnail.js"; export { default as youtube_getVideoCaption } from "./youtube_getVideoCaption.js"; export { default as youtube_changeCountry } from "./youtube_changeCountry.js"; +export { default as fb_autoLike } from "./fb_autoLike.js"; diff --git a/scripts/fb_autoLike.js b/scripts/fb_autoLike.js index c8988d53..9179bb13 100644 --- a/scripts/fb_autoLike.js +++ b/scripts/fb_autoLike.js @@ -1,15 +1,16 @@ +import { BADGES } from "./helpers/badge.js"; + export default { - icon: "", + icon: '', name: { - en: "", - vi: "", + en: "Auto like post on Facebook", + vi: "Tự động thích bài đăng Facebook", }, description: { - en: "", - vi: "", - img: "", + en: "Auto like post on Facebook. Support all reactions, all post types (page, group, user, feed, ...)", + vi: "Tự động thả cảm xúc cho bài đăng trên Facebook. Hỗ trợ mọi cảm xúc, mọi loài bài đăng (trang, nhóm, người dùng, new feed, ...)", }, - + badges: [BADGES.new], changeLogs: { "2024-07-08": "init", }, diff --git a/scripts/youtube_changeCountry.js b/scripts/youtube_changeCountry.js index 92315d54..a1cdfdf5 100644 --- a/scripts/youtube_changeCountry.js +++ b/scripts/youtube_changeCountry.js @@ -1,3 +1,5 @@ +import { BADGES } from "./helpers/badge.js"; + export default { icon: '', name: { @@ -8,7 +10,7 @@ export default { en: "Change youtube country to view content in other country", vi: "Đổi quốc gia youtube để xem nội dung youtube bên các nước khác", }, - + badges: [BADGES.new], changeLogs: { "2024-07-07": "init", }, From e9f28f77981637534c3f66bc9b4fe96b4e197f50 Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Tue, 9 Jul 2024 00:13:08 +0700 Subject: [PATCH 28/44] auto like/unlike - nice --- scripts/content-scripts/ufs_global.js | 3 +- scripts/fb_autoLike.js | 238 ++++++++++++++++++-------- 2 files changed, 166 insertions(+), 75 deletions(-) diff --git a/scripts/content-scripts/ufs_global.js b/scripts/content-scripts/ufs_global.js index e63a90b2..c2d8862e 100644 --- a/scripts/content-scripts/ufs_global.js +++ b/scripts/content-scripts/ufs_global.js @@ -561,9 +561,10 @@ function notify({ } return false; }, - setText(text) { + setText(text, duration) { if (div) { div.innerHTML = createTrustedHtml(text); + if (duration) closeAfter(duration); return true; } return false; diff --git a/scripts/fb_autoLike.js b/scripts/fb_autoLike.js index 9179bb13..59a537c3 100644 --- a/scripts/fb_autoLike.js +++ b/scripts/fb_autoLike.js @@ -1,3 +1,4 @@ +import { UfsGlobal } from "./content-scripts/ufs_global.js"; import { BADGES } from "./helpers/badge.js"; export default { @@ -7,21 +8,30 @@ export default { vi: "Tự động thích bài đăng Facebook", }, description: { - en: "Auto like post on Facebook. Support all reactions, all post types (page, group, user, feed, ...)", - vi: "Tự động thả cảm xúc cho bài đăng trên Facebook. Hỗ trợ mọi cảm xúc, mọi loài bài đăng (trang, nhóm, người dùng, new feed, ...)", + en: `Auto like post on Facebook. +
    +
  • Support all post types (page, group, user, feed, ...)
  • +
  • Support bulk remove/add reactions
  • +
  • Support all reaction types
  • +
`, + vi: `Tự động thả cảm xúc cho bài đăng trên Facebook. +
    +
  • Hỗ trợ mọi loại bài đăng (trang, nhóm, người dùng, new feed, ...)
  • +
  • Hỗ trợ gỡ/thêm cảm xúc hàng loạt
  • +
  • Hỗ trợ mọi loại cảm xúc
  • +
`, }, badges: [BADGES.new], changeLogs: { "2024-07-08": "init", }, - whiteList: [], + // whiteList: ["https://*.facebook.com/*"], + + pageScript: { + onClick: () => { + const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); - contentScript: { - onClick: async () => { - function sleep(ms) { - return new Promise((resolve) => setTimeout(resolve, ms)); - } function focusTo(element) { element.dispatchEvent( new MouseEvent("pointerover", { @@ -33,89 +43,169 @@ export default { } function scrollToBottom() { - window.scrollTo(0, document.body.scrollHeight, { - // behavior: "smooth", - }); + window.scrollTo(0, document.body.scrollHeight, { behavior: "smooth" }); + } + + function rand(min, max) { + return Math.floor(Math.random() * (max - min + 1) + min); + } + + function isRunning(value) { + if (!(typeof value === "boolean")) + return window.ufs_fb_autoLike_running; + else window.ufs_fb_autoLike_running = value; } const Reactions = { - Like: { - en: "Like", - vi: "Thích", - emoji: "👍", - }, - Love: { - en: "Love", - vi: "Yêu thích", - emoji: "❤️", - }, - Care: { - en: "Care", - vi: "Nghiện", - emoji: "😊", - }, - Haha: { - en: "Haha", - vi: "Há", - emoji: "😂", - }, - Wow: { - en: "Wow", - vi: "Wow", - emoji: "😮", - }, - Sad: { - en: "Sad", - vi: "Buồn", - emoji: "😢", + like: { vi: "Thích", en: "Like", emoji: "👍" }, + love: { vi: "Yêu thích", en: "Love", emoji: "❤️" }, + care: { vi: "Thương thương", en: "Care", emoji: "🤗" }, + haha: { vi: "Haha", en: "Haha", emoji: "😂" }, + wow: { vi: "Wow", en: "Wow", emoji: "😮" }, + sad: { vi: "Buồn", en: "Sad", emoji: "😢" }, + angry: { vi: "Phẫn nộ", en: "Angry", emoji: "😠" }, + }; + + const Types = { + addReact: { + vi: "Bày tỏ cảm xúc", + en: "React", + name: "Thả cảm xúc - Add reaction", }, - Angry: { - en: "Angry", - vi: "Khóc", - emoji: "😡", + removeReact: { + vi: "Gỡ ", + en: "Remove ", + name: "Gỡ cảm xúc - Remove reaction", }, }; - const doneKey = "auto-like-done"; - const btns = []; - while (true) { - if (!btns.length) { - let curBtns = Array.from( - document.querySelectorAll( - "[aria-label='Bày tỏ cảm xúc']:not(li *), [aria-label='React']:not(li *)" - ) - ); - let added = 0; - for (let btn of curBtns) { - if (btn.getAttribute(doneKey) === null) { - btns.push(btn); - btn.setAttribute(doneKey, true); - added++; - } + async function startAutoLike( + type = Types.addReact, + reaction = Reactions.love, + maxPosts = Infinity + ) { + isRunning(true); + + const notify = UfsGlobal.DOM.notify({ + msg: "Đang chuẩn bị ...", + duration: 999999, + }); + + let count = 0; + + const btns = []; + UfsGlobal.DOM.onElementsAdded( + [type.en, type.vi] + .map((_) => `[aria-label*='${_}']:not(li *)`) + .join(", "), + (nodes) => { + btns.push(...nodes); } - if (added === 0) break; - } + ); - for (let btn of btns) { + let scrollTried = 0; + while (true) { + if (!isRunning()) { + alert("Stopped Auto react !\n\nĐã dừng tự động thích!"); + break; + } + if (!btns.length) { + scrollTried++; + if (scrollTried > 50) break; + notify.setText("Scrolling to bottom... " + scrollTried, 99999); + scrollToBottom(); + await sleep(2000); + continue; + } + scrollTried = 0; + + const btn = btns.shift(); btn.scrollIntoView({ block: "center", - // behavior: "smooth", + behavior: "smooth", }); btn.click(); - await sleep(500); - let loveBtn = document.querySelector("[aria-label='Yêu thích']"); - if (loveBtn) { - focusTo(loveBtn); - await sleep(500); - loveBtn.click(); + + if (type === Types.addReact) { await sleep(500); + + let reactBtn = document.querySelector( + [reaction.en, reaction.vi] + .map((_) => `[aria-label='${_}']`) + .join(", ") + ); + console.log(reactBtn); + if (reactBtn) { + focusTo(reactBtn); + await sleep(50); + reactBtn.click(); + await sleep(50); + } } - btns.splice(btns.indexOf(btn), 1); + + let waitFor = rand(2000, 5000); + count++; + if (count >= maxPosts) break; + notify.setText( + type.name + + ": " + + count + + "/" + + (count + btns.length) + + " - waiting: " + + (waitFor / 1000).toFixed(1) + + "s", + 99999 + ); + + await sleep(waitFor); } - scrollToBottom(); - await sleep(3000); + + let text = type.name + ": " + count + " posts"; + notify.setText(text, 5000); + isRunning(false); + alert(text); + } + + if (isRunning()) { + return isRunning(false); + } + + const typeIndex = prompt( + "Bạn muốn?\n" + + Object.entries(Types) + .map(([key, value], i) => i + ": " + value.name) + .join("\n"), + 0 + ); + let selectedType = Types[Object.keys(Types)[typeIndex]]; + let selectedReact; + if (typeIndex === null || !selectedType) return; + + if (typeIndex == 0) { + let reactIndex = prompt( + "Chọn reaction:\n" + + Object.entries(Reactions) + .map( + ([key, value], i) => + i + ": " + value.emoji + " " + value.en + " - " + value.vi + ) + .join("\n"), + 1 + ); + selectedReact = Reactions[Object.keys(Reactions)[reactIndex]]; + if (reactIndex == null || !selectedReact) return; } - alert("xong"); + + let max = prompt( + "Thả bao nhiêu bài post? - Max post?: (0 = tất cả/all) ", + 0 + ); + if (max == null) return; + if (max == 0) max = Infinity; + else max = parseInt(max); + + startAutoLike(selectedType, selectedReact, max); }, }, }; From 6140d49f6338514a611050fb0b7062400eeab21e Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Tue, 9 Jul 2024 00:13:13 +0700 Subject: [PATCH 29/44] remove log --- scripts/fb_revealDeletedMessages.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/fb_revealDeletedMessages.js b/scripts/fb_revealDeletedMessages.js index 5ccb8043..31b0513a 100644 --- a/scripts/fb_revealDeletedMessages.js +++ b/scripts/fb_revealDeletedMessages.js @@ -200,7 +200,7 @@ export default { ) { const have_msg_id = /(?=mid\.\$)(.*?)(?=\\")/.exec(utf8_str); if (have_msg_id) { - console.log("reveal deleted ", utf8_str); + // console.log("reveal deleted ", utf8_str); let dataStr = utf8_str.slice(utf8_str.indexOf("{")); let data = JSON.parse(dataStr); let payload = JSON.parse(data?.["payload"]); @@ -262,10 +262,10 @@ export default { else if ( confirm( `Bạn có chắc muốn xóa tất cả ${len} tin nhắn` + - ` đã được lưu bởi chức năng này?\n\n` + - `+ Chỉ nên xóa khi thấy đã lưu quá nhiều tin nhắn.\n` + - `+ Sau khi xóa, nếu có người thu hồi tin nhắn, mà tin đó chưa được lưu\n` + - ` thì bạn sẽ ko biết được nội dung tin nhắn.` + ` đã được lưu bởi chức năng này?\n\n` + + `+ Chỉ nên xóa khi thấy đã lưu quá nhiều tin nhắn.\n` + + `+ Sau khi xóa, nếu có người thu hồi tin nhắn, mà tin đó chưa được lưu\n` + + ` thì bạn sẽ ko biết được nội dung tin nhắn.` ) ) { window.ufs_rvdfm_all_msgs = {}; From 00a244eb9fa0d1b49efcc895addef914251232e6 Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Tue, 9 Jul 2024 00:54:31 +0700 Subject: [PATCH 30/44] fix --- scripts/fb_autoLike.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/scripts/fb_autoLike.js b/scripts/fb_autoLike.js index 59a537c3..d4e3b798 100644 --- a/scripts/fb_autoLike.js +++ b/scripts/fb_autoLike.js @@ -95,8 +95,15 @@ export default { const btns = []; UfsGlobal.DOM.onElementsAdded( - [type.en, type.vi] - .map((_) => `[aria-label*='${_}']:not(li *)`) + ["en", "vi"] + .map((l) => + type === Types.removeReact + ? Object.values(Reactions).map( + (r) => `[aria-label='${type[l]}${r[l]}']:not(li *)` + ) + : `[aria-label='${type[l]}']:not(li *)` + ) + .flat() .join(", "), (nodes) => { btns.push(...nodes); @@ -124,6 +131,7 @@ export default { block: "center", behavior: "smooth", }); + await sleep(500); btn.click(); if (type === Types.addReact) { @@ -134,16 +142,15 @@ export default { .map((_) => `[aria-label='${_}']`) .join(", ") ); - console.log(reactBtn); if (reactBtn) { focusTo(reactBtn); - await sleep(50); + await sleep(100); reactBtn.click(); - await sleep(50); + await sleep(100); } } - let waitFor = rand(2000, 5000); + let waitFor = rand(1000, 4000); count++; if (count >= maxPosts) break; notify.setText( From 3e062977cc25a8c8f55828f4d6e8a8d036fe3446 Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Tue, 9 Jul 2024 12:24:26 +0700 Subject: [PATCH 31/44] chrome.download + fix fb_storySaver --- scripts/content-scripts/ufs_global.js | 32 +++++++++++---- scripts/douyin_downloadWachingVideo.js | 24 +---------- scripts/fb_downloadWatchingVideo.js | 14 ++++++- scripts/fb_storySaver.js | 54 ++++++++++++++++--------- scripts/screenshotFullPage.js | 8 ++-- scripts/screenshotVisiblePage.js | 8 ++-- scripts/tiktok_downloadWatchingVideo.js | 11 ++++- scripts/webToPDF.js | 9 ++--- working_note.md | 2 + 9 files changed, 98 insertions(+), 64 deletions(-) diff --git a/scripts/content-scripts/ufs_global.js b/scripts/content-scripts/ufs_global.js index c2d8862e..b9363100 100644 --- a/scripts/content-scripts/ufs_global.js +++ b/scripts/content-scripts/ufs_global.js @@ -143,6 +143,12 @@ function runInContentScript(fnPath, params) { }); } function runInBackground(fnPath, params) { + if (typeof chrome?.runtime?.sendMessage == "function") { + return chrome.runtime.sendMessage({ + action: "ufs-runInBackground", + data: { fnPath, params }, + }); + } return sendToContentScript("ufs-runInBackground", { fnPath, params, @@ -165,15 +171,31 @@ async function fetchByPassOrigin(url, options = {}) { function getURL(filePath) { return runInContentScript("chrome.runtime.getURL", [filePath]); } -function download(options) { - return runInBackground("chrome.downloads.download", [options]); -} function trackEvent(scriptId) { return runInBackground("trackEvent", [scriptId]); } function waitForTabToLoad(tabId) { return runInBackground("utils.waitForTabToLoad", [tabId]); } + +// https://developer.chrome.com/docs/extensions/reference/api/downloads#type-DownloadOptions +/** + * A function to trigger a download using chrome.downloads API. + * + * @param {Object} options - The options for the download operation. + * @param {string} options.url - The URL to download. + * @param {string} [options.body] - Post body. + * @param {{name: string, value: string}[]} [options.headers] - Extra HTTP headers to send with the request if the URL uses the HTTP[s] protocol. Each header is represented as a dictionary containing the keys name and either value or binaryValue, restricted to those allowed by XMLHttpRequest. + * @param {'GET'|'POST'} [options.method] - The HTTP method to use for the download. + * @param {string} [options.filename] - A file path relative to the Downloads directory to contain the downloaded file, possibly containing subdirectories. + * @param {string} [options.saveAs] - Use a file-chooser to allow the user to select a filename regardless of whether filename is set or already exists. + * @param {'uniquify'|'overwrite'|'prompt'} [options.conflictAction] - The action to take if filename already exists. + * @return {Promise} - A promise that resolves to the ID of the created download. + */ +function download(options) { + return runInBackground("chrome.downloads.download", [options]); +} + // #endregion // #region DOM @@ -1834,9 +1856,7 @@ function downloadBlob(blob, filename) { a.href = blobUrl; a.download = filename; a.style.display = "none"; - document.body.appendChild(a); a.click(); - document.body.removeChild(a); URL.revokeObjectURL(blobUrl); } // https://stackoverflow.com/a/15832662/11898496 @@ -1846,9 +1866,7 @@ function downloadURL(url, name) { link.target = "_blank"; link.download = name; link.href = url; - document.body.appendChild(link); link.click(); - document.body.removeChild(link); } function downloadData(data, filename, type = "text/plain") { let file = new Blob([data], { type: type }); diff --git a/scripts/douyin_downloadWachingVideo.js b/scripts/douyin_downloadWachingVideo.js index 2e3fdee0..0b67b56d 100644 --- a/scripts/douyin_downloadWachingVideo.js +++ b/scripts/douyin_downloadWachingVideo.js @@ -1,3 +1,5 @@ +import { UfsGlobal } from "./content-scripts/ufs_global.js"; + export default { icon: "https://www.douyin.com/favicon.ico", name: { @@ -12,18 +14,10 @@ export default { popupScript: { onClick: async function () { - const { UfsGlobal } = await import("./content-scripts/ufs_global.js"); const { runScriptInCurrentTab, showLoading } = await import( "./helpers/utils.js" ); - // const { - // downloadURL, - // downloadBlob, - // getBlobFromUrlWithProgress, - // formatSize, - // } = UfsGlobal.Utils; - const { closeLoading, setLoadingText } = showLoading( "Đang tìm video url..." ); @@ -36,21 +30,7 @@ export default { alert("Không tìm thấy video nào."); } else { setLoadingText("Đang tải video..."); - // downloadURL(src, "douyin_video.mp4"); window.open(src); - // const blob = await getBlobFromUrlWithProgress( - // src, - // ({ loaded, total, speed }) => { - // const percent = ((loaded / total) * 100) | 0; - // setLoadingText( - // `Đang tải video...
` + - // `Vui lòng không tắt popup
` + - // `${formatSize(loaded)}/${formatSize(total)} (${percent}%)` + - // ` - ${formatSize(speed)}/s` - // ); - // } - // ); - // await downloadBlob(blob, "douyin_video.mp4"); } closeLoading(); }, diff --git a/scripts/fb_downloadWatchingVideo.js b/scripts/fb_downloadWatchingVideo.js index 1e1128fc..35b0577e 100644 --- a/scripts/fb_downloadWatchingVideo.js +++ b/scripts/fb_downloadWatchingVideo.js @@ -29,15 +29,25 @@ export default { ); try { let listVideoId = await shared.getListVideoIdInWebsite(); - if (!listVideoId?.length > 0) throw Error("Không tìm thấy video"); + if (!listVideoId?.length > 0) throw Error("Không tìm thấy video nào"); setLoadingText("Đang lấy token dtsg..."); let dtsg = await fb_videoDownloader.getDtsg(); + let downloaded = 0; for (let videoId of listVideoId) { setLoadingText("Đang tìm video url..."); let videoUrl = await fb_videoDownloader.getLinkFbVideo(videoId, dtsg); - if (videoUrl) UfsGlobal.Utils.downloadURL(videoUrl, "fb_video.mp4"); + if (videoUrl) { + downloaded++; + UfsGlobal.Extension.download({ + url: videoUrl, + filename: "fb_video.mp4", + }); + } + } + if (downloaded === 0) { + alert("Không tìm thấy link video"); } } catch (e) { alert("ERROR: " + e); diff --git a/scripts/fb_storySaver.js b/scripts/fb_storySaver.js index 3d95be19..6c15778c 100644 --- a/scripts/fb_storySaver.js +++ b/scripts/fb_storySaver.js @@ -11,7 +11,7 @@ export default { vi: "Tải facebook story / video bình luận bạn đang xem", }, - contentScript: { + pageScript: { onClick: function () { // Source code extracted from: https://chrome.google.com/webstore/detail/story-saver/mafcolokinicfdmlidhaebadidhdehpk @@ -22,45 +22,55 @@ export default { if (videos[i].offsetHeight === 0) continue; let reactKey = ""; let keys = Object.keys(videos[i]); - for (let key of keys) { - if (key.indexOf("__reactFiber") != -1) { - reactKey = key.split("__reactFiber")[1]; + for (let j = 0; j < keys.length; j++) { + if (keys[j].indexOf("__reactFiber") != -1) { + reactKey = keys[j].split("__reactFiber")[1]; break; } } let storyUrl; try { - //prettier-ignore - storyUrl = videos[i].parentElement.parentElement.parentElement.parentElement['__reactProps' + reactKey].children[0].props.children.props.implementations[1].data.hdSrc; + storyUrl = + videos[i].parentElement.parentElement.parentElement.parentElement[ + "__reactProps" + reactKey + ].children[0].props.children.props.implementations[1].data.hdSrc; } catch (e) {} if (storyUrl == null) { try { - //prettier-ignore - storyUrl = videos[i].parentElement.parentElement.parentElement.parentElement['__reactProps' + reactKey].children[0].props.children.props.implementations[1].data.sdSrc; + storyUrl = + videos[i].parentElement.parentElement.parentElement.parentElement[ + "__reactProps" + reactKey + ].children[0].props.children.props.implementations[1].data.sdSrc; } catch (e) {} } if (storyUrl == null) { try { - //prettier-ignore - storyUrl = videos[i].parentElement.parentElement.parentElement.parentElement['__reactProps' + reactKey].children.props.children.props.implementations[1].data.hdSrc; + storyUrl = + videos[i].parentElement.parentElement.parentElement.parentElement[ + "__reactProps" + reactKey + ].children.props.children.props.implementations[1].data.hdSrc; } catch (e) {} } if (storyUrl == null) { try { - //prettier-ignore - storyUrl = videos[i].parentElement.parentElement.parentElement.parentElement['__reactProps' + reactKey].children.props.children.props.implementations[1].data.sdSrc; + storyUrl = + videos[i].parentElement.parentElement.parentElement.parentElement[ + "__reactProps" + reactKey + ].children.props.children.props.implementations[1].data.sdSrc; } catch (e) {} } if (storyUrl == null) { try { - //prettier-ignore - storyUrl = videos[i]['__reactFiber' + reactKey].return.stateNode.props.videoData.$1.hd_src; + storyUrl = + videos[i]["__reactFiber" + reactKey].return.stateNode.props + .videoData.$1.hd_src; } catch (e) {} } if (storyUrl == null) { try { - //prettier-ignore - storyUrl = videos[i]['__reactFiber' + reactKey].return.stateNode.props.videoData.$1.sd_src; + storyUrl = + videos[i]["__reactFiber" + reactKey].return.stateNode.props + .videoData.$1.sd_src; } catch (e) {} } if (storyUrl != null) { @@ -69,16 +79,24 @@ export default { } let storyImgUrl = Array.from( - document.querySelectorAll('div[data-id] img[draggable="false"]') + document.querySelectorAll('img[draggable="false"]') ).find((_) => _.alt)?.src; if (storyImgUrl) { listUrls.push({ url: storyImgUrl, type: "img" }); } + let profile_pic = document.querySelector( + "a[role=link][tabindex='0'][href*='https://www.facebook']>img" + ); + let username = profile_pic?.alt || "fb_story"; + if (!listUrls.length) { alert("Không tìm thấy facebook story nào trong trang web."); } else if (listUrls.length === 1) { - UfsGlobal.Utils.downloadURL(listUrls[0].url, "fb_story_video.mp4"); + UfsGlobal.Extension.download({ + url: listUrls[0].url, + filename: username + (listUrls[0].type === "img" ? ".jpg" : ".mp4"), + }); } else { let w = window.open("", "", "width=500,height=700"); w.document.write( diff --git a/scripts/screenshotFullPage.js b/scripts/screenshotFullPage.js index e9ac24fd..8b1d7323 100644 --- a/scripts/screenshotFullPage.js +++ b/scripts/screenshotFullPage.js @@ -45,10 +45,10 @@ export default { console.log(img); setLoadingText("Đang lưu ảnh..."); - UfsGlobal.Utils.downloadURL( - "data:image/png;base64," + img.data, - "fullpage.png" - ); + UfsGlobal.Extension.download({ + url: "data:image/png;base64," + img.data, + filename: "fullpage.png", + }); } await detachDebugger(tab); } catch (e) { diff --git a/scripts/screenshotVisiblePage.js b/scripts/screenshotVisiblePage.js index 1639104c..55788a42 100644 --- a/scripts/screenshotVisiblePage.js +++ b/scripts/screenshotVisiblePage.js @@ -72,10 +72,10 @@ export default { console.log(img); setLoadingText("Đang lưu ảnh..."); - UfsGlobal.Utils.downloadURL( - "data:image/png;base64," + img.data, - "webpage.png" - ); + UfsGlobal.Extension.download({ + url: "data:image/png;base64," + img.data, + filename: "webpage.png", + }); await detachDebugger(tab); } catch (e) { diff --git a/scripts/tiktok_downloadWatchingVideo.js b/scripts/tiktok_downloadWatchingVideo.js index 9fb790a2..5d804a9c 100644 --- a/scripts/tiktok_downloadWatchingVideo.js +++ b/scripts/tiktok_downloadWatchingVideo.js @@ -84,8 +84,15 @@ export default { setLoadingText( t({ vi: `Đang tải video ${title}...`, en: `Downloading ${title}...` }) ); - const { formatSize, downloadBlob } = UfsGlobal.Utils; - const blob = await UfsGlobal.Utils.getBlobFromUrlWithProgress( + + // UfsGlobal.Extension.download({ + // url: link, + // filename: title + ".mp4", + // }); + + const { formatSize, downloadBlob, getBlobFromUrlWithProgress } = + UfsGlobal.Utils; + const blob = await getBlobFromUrlWithProgress( link, ({ loaded, total, speed }) => { let desc = diff --git a/scripts/webToPDF.js b/scripts/webToPDF.js index aea283df..6acd42d6 100644 --- a/scripts/webToPDF.js +++ b/scripts/webToPDF.js @@ -33,11 +33,10 @@ export default { }); await detachDebugger(tab); - // https://stackoverflow.com/a/59352848/11898496 - UfsGlobal.Utils.downloadURL( - "data:application/pdf;base64," + res.data, - "web.pdf" - ); + UfsGlobal.Extension.download({ + url: "data:application/pdf;base64," + res.data, + filename: "web.pdf", + }); } catch (e) { if ( confirm( diff --git a/working_note.md b/working_note.md index 37367701..f6189b3e 100644 --- a/working_note.md +++ b/working_note.md @@ -2,6 +2,8 @@ ## 01/07/2024 - ? +- [ ] hotfix - use chrome.downloads instead of library + - [x] get fb profile pic -> dont know now cuid was generated - [x] find fb account using phone or email -> too hard, fb not always show user's avatar/name From 7f976af23fc57546c8a96d936384e2d61285cce6 Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Tue, 9 Jul 2024 14:27:07 +0700 Subject: [PATCH 32/44] fix WL --- scripts/fb_autoLike.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/fb_autoLike.js b/scripts/fb_autoLike.js index d4e3b798..fcd7bfb7 100644 --- a/scripts/fb_autoLike.js +++ b/scripts/fb_autoLike.js @@ -26,7 +26,7 @@ export default { "2024-07-08": "init", }, - // whiteList: ["https://*.facebook.com/*"], + whiteList: ["https://*.facebook.com/*"], pageScript: { onClick: () => { From 560f0d26fe2481311851c90ab84a108d9c7c24ba Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Tue, 9 Jul 2024 15:01:34 +0700 Subject: [PATCH 33/44] fix style --- scripts/magnify_image.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/magnify_image.css b/scripts/magnify_image.css index 62c38be6..12c79e4e 100644 --- a/scripts/magnify_image.css +++ b/scripts/magnify_image.css @@ -220,6 +220,11 @@ opacity: 1; } +#ufs-magnify-image-hover-div.hide { + opacity: 0; + display: block !important; +} + #ufs-magnify-image-hover-div.hide:not(:hover) { opacity: 0; transition: all 0.2s 2s ease; From 54021e1c9dc10ade107083eafb1d1e4d690a6430 Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Tue, 9 Jul 2024 22:50:23 +0700 Subject: [PATCH 34/44] fix --- scripts/fb_autoLike.js | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/scripts/fb_autoLike.js b/scripts/fb_autoLike.js index fcd7bfb7..8194dc1a 100644 --- a/scripts/fb_autoLike.js +++ b/scripts/fb_autoLike.js @@ -94,12 +94,13 @@ export default { let count = 0; const btns = []; - UfsGlobal.DOM.onElementsAdded( + const unobserver = UfsGlobal.DOM.onElementsAdded( ["en", "vi"] .map((l) => type === Types.removeReact ? Object.values(Reactions).map( - (r) => `[aria-label='${type[l]}${r[l]}']:not(li *)` + (r) => + `[aria-label='${type[l]}${r[l]}']:not(li *):not([hidden] *)` ) : `[aria-label='${type[l]}']:not(li *)` ) @@ -131,24 +132,6 @@ export default { block: "center", behavior: "smooth", }); - await sleep(500); - btn.click(); - - if (type === Types.addReact) { - await sleep(500); - - let reactBtn = document.querySelector( - [reaction.en, reaction.vi] - .map((_) => `[aria-label='${_}']`) - .join(", ") - ); - if (reactBtn) { - focusTo(reactBtn); - await sleep(100); - reactBtn.click(); - await sleep(100); - } - } let waitFor = rand(1000, 4000); count++; @@ -166,8 +149,27 @@ export default { ); await sleep(waitFor); + + btn.click(); + + if (type === Types.addReact) { + await sleep(500); + + let reactBtn = document.querySelector( + [reaction.en, reaction.vi] + .map((_) => `[aria-label='${_}']`) + .join(", ") + ); + if (reactBtn) { + focusTo(reactBtn); + await sleep(100); + reactBtn.click(); + await sleep(100); + } + } } + unobserver?.(); let text = type.name + ": " + count + " posts"; notify.setText(text, 5000); isRunning(false); From 5de39b9c7abc94cecb1f3615802a5836576dcffb Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Wed, 10 Jul 2024 10:02:38 +0700 Subject: [PATCH 35/44] fix url valid --- scripts/content-scripts/ufs_global.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/content-scripts/ufs_global.js b/scripts/content-scripts/ufs_global.js index b9363100..463e518e 100644 --- a/scripts/content-scripts/ufs_global.js +++ b/scripts/content-scripts/ufs_global.js @@ -156,8 +156,8 @@ function runInBackground(fnPath, params) { } async function fetchByPassOrigin(url, options = {}) { try { - let _url = url; - let urlObject = new URL(url); + let _url = makeUrlValid(url); + let urlObject = new URL(_url); // https://stackoverflow.com/a/9375786/23648002 if (location.hostname == urlObject?.hostname) { _url = urlObject.pathname; @@ -925,6 +925,9 @@ function makeUrlValid(url) { if (url.startsWith("//")) { url = "https:" + url; } + if (url.startsWith("/")) { + url = location.origin + url; + } return url; } function getWatchingVideoSrc() { @@ -1299,6 +1302,7 @@ async function getLargestImageSrc(imgSrc, webUrl) { } // bypass redirect + imgSrc = makeUrlValid(imgSrc); let redirectedUrl = await getRedirectedUrl(imgSrc); if (redirectedUrl) { imgSrc = redirectedUrl; From 19abee62a977927162466bbe519e288daefd1912 Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Wed, 10 Jul 2024 12:55:56 +0700 Subject: [PATCH 36/44] fix dev --- manifest.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index d03cd309..90a4dc54 100644 --- a/manifest.json +++ b/manifest.json @@ -66,7 +66,8 @@ "https://hoangtran0410.github.io/*", "https://useful-scripts-extension.github.io/*", "https://facebook-all-in-one.com/*", - "http://localhost:5173/*" + "http://localhost:5173/*", + "http://127.0.0.1:5173/*" ] } } From aa12b04f8afc8425cda7187c1df4ca8d63d55ac9 Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Thu, 11 Jul 2024 01:20:12 +0700 Subject: [PATCH 37/44] test --- manifest.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 90a4dc54..dd421ff0 100644 --- a/manifest.json +++ b/manifest.json @@ -67,7 +67,9 @@ "https://useful-scripts-extension.github.io/*", "https://facebook-all-in-one.com/*", "http://localhost:5173/*", - "http://127.0.0.1:5173/*" + "http://127.0.0.1:5173/*", + "http://localhost:5500/*", + "http://127.0.0.1:5500/*" ] } } From 2d32f76bf57472198a6e9487cdc72fc6c37612f2 Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Thu, 11 Jul 2024 15:09:55 +0700 Subject: [PATCH 38/44] click to enable/disable current website --- scripts/smoothScroll.js | 170 +++++++++++++++++++--------------------- 1 file changed, 80 insertions(+), 90 deletions(-) diff --git a/scripts/smoothScroll.js b/scripts/smoothScroll.js index 096323b0..8583f78f 100644 --- a/scripts/smoothScroll.js +++ b/scripts/smoothScroll.js @@ -8,11 +8,17 @@ export default { }, description: { en: `Scroll smoothly on all websites with your mouse and keyboard.
- Smooth like when you scroll this extension.

- Support middle click to scroll.`, +
    +
  • Suggested if you use mouse (turn off if use touchpad)
  • +
  • Click to Disable/Enable for current website
  • +
  • Support middle click to scroll
  • +

`, vi: `Cuộn chuột siêu mượt cho mọi trang web.
- Mượt như khi cuộn chuột trong extension này vậy.

- Hỗ trợ scroll khi bấm chuột giữa.`, +
    +
  • Khuyên dùng với chuột (tắt nếu dùng touchpad)
  • +
  • Bấm để Tắt/Mở cho trang web hiện tại
  • +
  • Hỗ trợ bấm chuột giữa để cuộn trang
  • +

`, video: "https://www.smoothscroll.net/mac/img/vid/Demo-Mac-720p.mp4", }, badges: [BADGES.hot], @@ -28,107 +34,90 @@ export default { ], changeLogs: { + "2024-07-11": "click to disable/enable for current site", "2024-05-26": "init", }, popupScript: { - onEnable: async () => { - const { t } = await import("../popup/helpers/lang.js"); - const { runScriptInTab, getAllTabs: getAllAvailableTabs } = await import( - "./helpers/utils.js" - ); - const tabs = await getAllAvailableTabs(); - let count = 0; - for (let tab of tabs) { - try { - runScriptInTab({ - target: { - tabId: tab.id, - allFrames: true, - }, - func: enableSmoothScroll, - world: "ISOLATED", - }); - count++; - } catch (e) { - console.error(e); - } - } - if (count) - Swal.fire({ - icon: "success", - title: t({ - vi: "Đã bật Cuộn chuột Siêu mượt", - en: "Super smooth scroll enabled", - }), - html: t({ - vi: - `Đã tự BẬT cho ${count} tab đang mở

` + - "Bạn có thể dùng ngay không cần tải lại trang.", - en: - `Enabled smooth scroll for ${count} opening tabs

` + - "Dont need to reload websites.", - }), - }); - }, - onDisable: async () => { - const { t } = await import("../popup/helpers/lang.js"); - const { runScriptInTab, getAllTabs: getAllAvailableTabs } = await import( - "./helpers/utils.js" - ); - const tabs = await getAllAvailableTabs(); - let count = 0; - for (let tab of tabs) { - try { - runScriptInTab({ - target: { - tabId: tab.id, - allFrames: true, - }, - func: () => { - window.ufs_smoothScroll_disable?.(); - }, - world: "ISOLATED", - }); - count++; - } catch (e) { - console.error(e); - } - } - if (count) - Swal.fire({ - icon: "success", - title: t({ - vi: "Đã tắt Cuộn chuột Siêu mượt", - en: "Super smooth scroll disabled", - }), - html: t({ - vi: - `Đã tự TẮT cho ${count} tab đang mở

` + - "Không cần tải lại trang.", - en: - `Disabled smooth scroll for ${count} opening tabs

` + - "Dont need to reload websites.", - }), - }); - }, + onEnable: () => setEnableForAllTab(true), + onDisable: () => setEnableForAllTab(false), }, contentScript: { - onDocumentStart_: (details) => { - enableSmoothScroll(); + onDocumentStart_: enableSmoothScroll, + onClick_: () => { + if (typeof window.ufs_smoothScroll_disable === "function") { + window.ufs_smoothScroll_disable(); + localStorage.setItem("ufs_smoothScroll_disable", 1); + if (window === window.top) + alert("DISABLED smooth scroll for this site: " + location.hostname); + } else { + localStorage.setItem("ufs_smoothScroll_disable", 0); + enableSmoothScroll(); + if (window === window.top) + alert("ENABLED smooth scroll for this site: " + location.hostname); + } }, }, }; +async function setEnableForAllTab(enable) { + const { t } = await import("../popup/helpers/lang.js"); + const { runScriptInTab, getAllTabs: getAllAvailableTabs } = await import( + "./helpers/utils.js" + ); + const tabs = await getAllAvailableTabs(); + let count = 0; + for (let tab of tabs) { + try { + runScriptInTab({ + target: { + tabId: tab.id, + allFrames: true, + }, + func: enable + ? enableSmoothScroll + : () => { + window.ufs_smoothScroll_disable?.(); + }, + world: "ISOLATED", + }); + count++; + } catch (e) { + console.error(e); + } + } + let text = enable + ? { vi: "Bật", en: "Enabled" } + : { vi: "Tắt", en: "Disabled" }; + + if (count) + Swal.fire({ + icon: "success", + title: t({ + vi: "Đã " + text.vi + " Cuộn chuột Siêu mượt", + en: "Super smooth scroll " + text.en, + }), + html: t({ + vi: + `Đã tự ${text.vi} cho ${count} tab đang mở

` + + "Bạn có thể dùng ngay không cần tải lại trang.", + en: + `${text.en} smooth scroll for ${count} opening tabs

` + + "Dont need to reload websites.", + }), + }); +} + // TODO: -// + setting page -// + horizontal scroll -// + fix window.scrollTo with behavior: "smooth" -// + check excluded +// [ ] setting page +// [ ] horizontal scroll +// [x] fix window.scrollTo with behavior: "smooth" +// [x] check excluded // https://chromewebstore.google.com/detail/smoothscroll/nbokbjkabcmbfdlbddjidfmibcpneigj export function enableSmoothScroll() { + if (localStorage.getItem("ufs_smoothScroll_disable") == 1) return; // ======================================================================= // ============================ sscr.js ================================== // ======================================================================= @@ -979,6 +968,7 @@ export function enableSmoothScroll() { window.ufs_smoothScroll_disable = () => { cleanup(); cleanupMiddlemouse(); + window.ufs_smoothScroll_disable = null; }; return window.ufs_smoothScroll_disable; From 2b8fe3e5ef2f335710d7126f87e6e505d8317c7c Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Thu, 11 Jul 2024 17:34:22 +0700 Subject: [PATCH 39/44] hotfix --- scripts/passwordGenerator.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/passwordGenerator.js b/scripts/passwordGenerator.js index 27e99918..c1cf4aae 100644 --- a/scripts/passwordGenerator.js +++ b/scripts/passwordGenerator.js @@ -8,6 +8,9 @@ export default { en: "You only have to remember 1 password", vi: "Bạn chỉ còn cần phải nhớ 1 mật khẩu", }, + changeLogs: { + "2024-07-11": "hotfix", + }, contentScript: { onClick: function () { @@ -125,6 +128,7 @@ export default { " + Tự động điền vào trang web khi nhập đúng Mật_khẩu_Chính\n" + "\nNhập Mật_khẩu_Chính của bạn:" ); + let host, sld, domain, D; if (master != "" && master != null) { host = document.location.href.match(/http(s*):\/\/([^/]+)/)[2]; if ( From 0705944d821a999304d46c4b1756b74b16bfe150 Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Fri, 12 Jul 2024 11:58:37 +0700 Subject: [PATCH 40/44] save file new API --- working_note.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/working_note.md b/working_note.md index f6189b3e..fb9188f8 100644 --- a/working_note.md +++ b/working_note.md @@ -2,6 +2,8 @@ ## 01/07/2024 - ? +- [ ] savefile using new api + - [ ] hotfix - use chrome.downloads instead of library - [x] get fb profile pic -> dont know now cuid was generated From 18461b5516461222def0ca57113295ea89a549ca Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Fri, 12 Jul 2024 16:30:15 +0700 Subject: [PATCH 41/44] lot of new things to try --- working_note.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/working_note.md b/working_note.md index fb9188f8..64682214 100644 --- a/working_note.md +++ b/working_note.md @@ -2,6 +2,14 @@ ## 01/07/2024 - ? +- [ ] take a look at + +- [ ] ffmpeg in browser + +- [ ] youtube reverse api??? + +- [ ] add this beautiful video downloader tool + - [ ] savefile using new api - [ ] hotfix - use chrome.downloads instead of library From 079cc9ecb8849fa6049d7854c4826bcd5bd7f859 Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Fri, 12 Jul 2024 16:58:50 +0700 Subject: [PATCH 42/44] cobalt --- popup/tabs.js | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/popup/tabs.js b/popup/tabs.js index 4614c839..625880a9 100644 --- a/popup/tabs.js +++ b/popup/tabs.js @@ -36,7 +36,7 @@ const tabs = [ { ...CATEGORY.search, scripts: [ - s._test, + // s._test, // s._ufs_statistic, s.similarWeb, s.similarWeb_bypassLimit, @@ -120,6 +120,32 @@ const tabs = [ ...CATEGORY.download, scripts: [ createTitle("--- All in one ---", "--- Tổng hợp ---"), + { + id: "recommend_cobalt", + icon: "https://cobalt.tools/favicon.ico", + name: { + en: "Cobalt - Media downloader", + vi: "Cobalt - Tải video/nhạc", + }, + description: { + en: "Support youtube, tiktok, instagram, twitter/x, bilibili, twitch, vimeo, soundcloud, dailymotion, pinterest, reddit, tumblr, ...", + vi: "Hỗ trợ youtube, tiktok, instagram, twitter/x, bilibili, twitch, vimeo, soundcloud, dailymotion, pinterest, reddit, tumblr, ...", + }, + badges: [BADGES.recommend, BADGES.new], + buttons: [ + { + icon: '', + name: { + vi: "Github", + en: "Github", + }, + onClick: () => window.open("https://github.com/imputnet/cobalt"), + }, + ], + popupScript: { + onClick: () => window.open("https://cobalt.tools/"), + }, + }, s.saveAllVideo, s.vuiz_getLink, s.savevideo_me, From 6dfae4ac9e8f38e5b8ee4c1efeaef6e3091658a9 Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Sat, 13 Jul 2024 00:43:32 +0700 Subject: [PATCH 43/44] new web --- popup/tabs.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/popup/tabs.js b/popup/tabs.js index 625880a9..625f7f60 100644 --- a/popup/tabs.js +++ b/popup/tabs.js @@ -1038,6 +1038,20 @@ const recommendTab = { window.open("https://github.com/HoangTran0410/FBMediaDownloader"), }, }, + // https://www.nirsoft.net/ + { name: { en: "--- Tools ---", vi: "--- Công cụ hay ---" } }, + { + id: "recommend_nirsoft", + icon: "https://www.nirsoft.net/favicon.ico", + name: { en: "Nirsoft", vi: "Nirsoft" }, + description: { + en: "A unique collection of small and useful freeware utilities", + vi: "Tổng hợp bộ công cụ nhanh, nhẹ, miễn phí dành cho windows", + }, + popupScript: { + onClick: () => window.open("https://www.nirsoft.net/"), + }, + }, { name: { en: "--- Extensions ---", vi: "--- Extensions hay ---" } }, { id: "recommend_CRXViewer", From 86de8fec6c4d4f7a724d73dfd850041b4c38577e Mon Sep 17 00:00:00 2001 From: "hoang.tran12" <99.hoangtran@gmail.com> Date: Sun, 14 Jul 2024 20:15:12 +0700 Subject: [PATCH 44/44] 1.69 --- README-en.md | 3 +- README.md | 3 +- manifest.json | 2 +- md/CHANGELOGS.md | 26 ++ md/LIST_SCRIPTS_EN.md | 516 +++++++++++++++++++++++---------------- md/LIST_SCRIPTS_VI.md | 516 +++++++++++++++++++++++---------------- popup/tabs.js | 46 +++- scripts/helpers/utils.js | 2 +- working_note.md | 4 +- 9 files changed, 685 insertions(+), 433 deletions(-) diff --git a/README-en.md b/README-en.md index 80b58a83..f4975c91 100644 --- a/README-en.md +++ b/README-en.md @@ -29,11 +29,12 @@ An extension includes a lot of small extensions. Make your life easier. Current Versions: -- **v1.68**: big facebook update (01/07/2024) +- **v1.69**: small update (14/07/2024)
Old versions +- v1.68: big facebook update (01/07/2024) - v1.67 - huge update (29/05/2024) - v1.66 - big update (27/04/2024) - v1.65-hotfix (08/04/2024) diff --git a/README.md b/README.md index eb9dc982..07526738 100644 --- a/README.md +++ b/README.md @@ -29,11 +29,12 @@ Xem [Lịch sử cập nhật](/md/CHANGELOGS.md) Phiên bản hiện tại: -- **v1.68**: bản cập nhật facebook lớn (01/07/2024) +- **v1.69**: small update (14/07/2024)
Xem phiên bản cũ hơn +- v1.68: bản cập nhật facebook lớn (01/07/2024) - v1.67 - bản cập nhật siêu lớn (29/05/2024) - v1.66 - bản cập nhật lớn (27/04/2024) - v1.65-hotfix (08/04/2024) diff --git a/manifest.json b/manifest.json index dd421ff0..e698f238 100644 --- a/manifest.json +++ b/manifest.json @@ -4,7 +4,7 @@ "name": "Useful Scripts", "description": "Scripts that can make your life faster and better", "homepage_url": "https://github.com/HoangTran0410/useful-script", - "version": "1.68", + "version": "1.69", "icons": { "16": "./assets/icon16.png", "32": "./assets/icon32.png", diff --git a/md/CHANGELOGS.md b/md/CHANGELOGS.md index 3484ad4c..b39999ae 100644 --- a/md/CHANGELOGS.md +++ b/md/CHANGELOGS.md @@ -1,5 +1,31 @@ ## Change logs +
+ v1.69 - 14/07/2024 + +- Facebook + - Auto like for facebook [source](/scripts/fb_autoLike.js) + - Fix download watching video [source](/scripts/fb_downloadWatchingVideo.js) + - Fix download story [source](/scripts/fb_storySaver.js) + +- Youtube: + - change country [source](/scripts/youtube_changeCountry.js) + - download thumbnail [source](/scripts/youtube_getVideoThumbnail.js) + - show/download captions [source](/scripts/youtube_getVideoCaption.js) + +- Smooth scroll: + - click to disable/enable for current website [source](/scripts/smoothScroll.js) + +- Merge request + - [fix: 🐛 fix fireship_vip script](https://github.com/HoangTran0410/useful-script/pull/28) + - [feat: youglish search + ](https://github.com/HoangTran0410/useful-script/pull/30) + - [feat: youtube download video UI](https://github.com/HoangTran0410/useful-script/pull/31) + - [style: 🪄 beautify ui for viewScriptSource](https://github.com/HoangTran0410/useful-script/pull/32) +- More shortcuts: google trend, time.is, aiforthat, cobalt, nirsoft + +
+
v1.68 - 01/07/2024 - cập nhật facebook lớn diff --git a/md/LIST_SCRIPTS_EN.md b/md/LIST_SCRIPTS_EN.md index 3df950f5..bbab297b 100644 --- a/md/LIST_SCRIPTS_EN.md +++ b/md/LIST_SCRIPTS_EN.md @@ -1,7 +1,31 @@ ### Search
- 1. Find alternative web + 1. There's an AI for that + + [View source](/scripts/recommend_theresanaiforthat.js) + + Collection of thousand of AI tools. Easy to search by category + +
+
+ 2. Time.is - Check your time + + [View source](/scripts/recommend_timeis.js) + + Exact time for any time zone. + +
+
+ 3. Google trending - See what trending now + + [View source](/scripts/recommend_googleTrending.js) + + See what people are searching on Google. Top treding every day, realtime. + +
+
+ 4. Find alternative web [View source](/scripts/similarWeb.js) @@ -9,7 +33,7 @@
- 2. Bypass limit in SimilarWeb + 5. Bypass limit in SimilarWeb [View source](/scripts/similarWeb_bypassLimit.js) @@ -19,7 +43,7 @@
- 3. Find shared login + 6. Find shared login [View source](/scripts/search_sharedAccount.js) @@ -27,7 +51,7 @@
- 4. Internet archive - Free library + 7. Internet archive - Free library [View source](/scripts/recommend_archive.js) @@ -37,7 +61,7 @@
- 5. Wappalyzer - view website stacks + 8. Wappalyzer - view website stacks [View source](/scripts/recommend_wappalyzer.js) @@ -45,7 +69,7 @@
- 6. Who.is + 9. Who.is [View source](/scripts/whois.js) @@ -53,7 +77,7 @@
- 7. See web meta info (SEO) + 10. See web meta info (SEO) [View source](/scripts/viewWebMetaInfo.js) @@ -61,7 +85,7 @@
- 8. Top global treding music? + 11. Top global treding music? [View source](/scripts/recommend_search_musicTreding.js) @@ -69,7 +93,7 @@
- 9. Where to find papers/books/pdf/... + 12. Where to find papers/books/pdf/... [View source](/scripts/search_paperWhere.js) @@ -77,7 +101,7 @@
- 10. Search guitar chords + 13. Search guitar chords [View source](/scripts/search_hopamchuan.js) @@ -85,7 +109,7 @@
- 11. Dowfor - Check web die + 14. Dowfor - Check web die [View source](/scripts/checkWebDie.js) @@ -93,7 +117,7 @@
- 12. DownDetector - View report web crash + 15. DownDetector - View report web crash [View source](/scripts/downDetector.js) @@ -101,7 +125,7 @@
- 13. Open wayback url + 16. Open wayback url [View source](/scripts/openWaybackUrl.js) @@ -109,7 +133,7 @@
- 14. Archive the current Page online + 17. Archive the current Page online [View source](/scripts/archiveToday.js) @@ -117,7 +141,7 @@
- 15. Search Userscripts + 18. Search Userscripts [View source](/scripts/recommend_search_userscript.js) @@ -129,7 +153,15 @@ --- All in one ---
- 16. Save All Video + 19. Cobalt - Media downloader + + [View source](/scripts/recommend_cobalt.js) + + Support youtube, tiktok, instagram, twitter/x, bilibili, twitch, vimeo, soundcloud, dailymotion, pinterest, reddit, tumblr, ... + +
+
+ 20. Save All Video [View source](/scripts/saveAllVideo.js) @@ -137,7 +169,7 @@
- 17. Vuiz - Get link audio/video/album + 21. Vuiz - Get link audio/video/album [View source](/scripts/vuiz_getLink.js) @@ -145,7 +177,7 @@
- 18. SaveVideo - Download video + 22. SaveVideo - Download video [View source](/scripts/savevideo_me.js) @@ -153,7 +185,7 @@
- 19. Get audio/video (luanxt) + 23. Get audio/video (luanxt) [View source](/scripts/getLinkLuanxt_newtab.js) @@ -163,7 +195,7 @@ --- Photos ---
- 20. Twitter X - Add download button + 24. Twitter X - Add download button [View source](/scripts/twitter_downloadButton.js) @@ -173,7 +205,7 @@
- 21. Download favicon from website + 25. Download favicon from website [View source](/scripts/getFavicon.js) @@ -181,7 +213,7 @@
- 22. Picviewer CE+ download images + 26. Picviewer CE+ download images [View source](/scripts/recommend_picviewer_ce+.js) @@ -191,7 +223,7 @@
- 23. File-converter.io - change image type + 27. File-converter.io - change image type [View source](/scripts/recommend_file_converter.js) @@ -201,7 +233,7 @@
- 24. Squoosh.app - compress images + 28. Squoosh.app - compress images [View source](/scripts/recommend_squoosh_app.js) @@ -211,7 +243,7 @@ --- Music ---
- 25. Spotify - Add download button + 29. Spotify - Add download button [View source](/scripts/spotify_downloadButton.js) @@ -221,7 +253,7 @@
- 26. Soundcloud - Add download button + 30. Soundcloud - Add download button [View source](/scripts/soundcloud_downloadMusic.js) @@ -231,7 +263,7 @@
- 27. Nhaccuatui music/lyric downloader + 31. Nhaccuatui music/lyric downloader [View source](/scripts/nhaccuatui_downloader.js) @@ -239,7 +271,7 @@
- 28. Zingmp3 music dowloader (API) + 32. Zingmp3 music dowloader (API) [View source](/scripts/zingmp3_downloadMusic.js) @@ -247,7 +279,7 @@
- 29. Show all audio in website + 33. Show all audio in website [View source](/scripts/showTheAudios.js) @@ -257,7 +289,7 @@ --- Videos ---
- 30. Download watching video + 34. Download watching video [View source](/scripts/download_watchingVideo.js) @@ -265,7 +297,7 @@
- 31. Vimeo - video downloader + 35. Vimeo - video downloader [View source](/scripts/vimeo_downloader.js) @@ -273,7 +305,7 @@
- 32. Show all videos in website + 36. Show all videos in website [View source](/scripts/showTheVideos.js) @@ -283,7 +315,7 @@ --- Document ---
- 33. Studocu - Download documents + 37. Studocu - Download documents [View source](/scripts/studocu_downs.js) @@ -291,7 +323,7 @@
- 34. Scribd - Download documents + 38. Scribd - Download documents [View source](/scripts/scribd_downloadDocuments.js) @@ -299,7 +331,7 @@
- 35. Download free from tailieu.vn + 39. Download free from tailieu.vn [View source](/scripts/tailieu_vn.js) @@ -307,7 +339,7 @@
- 36. DocDownloader - Download document + 40. DocDownloader - Download document [View source](/scripts/recommend_docsdownloader.js) @@ -315,7 +347,7 @@
- 37. Export bookmarks to file + 41. Export bookmarks to file [View source](/scripts/bookmark_exporter.js) @@ -323,7 +355,7 @@
- 38. Bookmark Sidebar + 42. Bookmark Sidebar [View source](/scripts/recommend_BookmarkSidebar.js) @@ -335,7 +367,7 @@ --- Download ---
- 39. Google drive - generate direct link + 43. Google drive - generate direct link [View source](/scripts/ggdrive_generateDirectLink.js) @@ -343,7 +375,7 @@
- 40. GG Drive - Download PDF + 44. GG Drive - Download PDF [View source](/scripts/ggdrive_downloadPdf.js) @@ -351,7 +383,7 @@
- 41. GG Drive - Download PowerPoint (Slides/Presentation) + 45. GG Drive - Download PowerPoint (Slides/Presentation) [View source](/scripts/ggdrive_downloadPresentation.js) @@ -359,7 +391,7 @@
- 42. GG Drive - Download Document (to PDF) + 46. GG Drive - Download Document (to PDF) [View source](/scripts/ggdrive_downloadDoc.js) @@ -367,7 +399,7 @@
- 43. GG Drive - Download Sheet (copy Text) + 47. GG Drive - Download Sheet (copy Text) [View source](/scripts/ggdrive_copySheetText.js) @@ -375,7 +407,7 @@
- 44. GG Drive - Download video + 48. GG Drive - Download video [View source](/scripts/ggdrive_downloadVideo.js) @@ -383,7 +415,7 @@
- 45. Google - Download all your data + 49. Google - Download all your data [View source](/scripts/google_downloadAllYourData.js) @@ -393,7 +425,7 @@ --- Bulk Download ---
- 46. GGDrive - Download all videos in folder + 50. GGDrive - Download all videos in folder [View source](/scripts/ggDrive_downloadAllVideosInFolder.js) @@ -403,7 +435,7 @@ --- More ---
- 47. Google search advanced + 51. Google search advanced [View source](/scripts/recommend_googleAdvanced.js) @@ -411,7 +443,7 @@
- 48. Check total indexed pages + 52. Check total indexed pages [View source](/scripts/search_totalIndexedPages.js) @@ -419,7 +451,7 @@
- 49. Google site search + 53. Google site search [View source](/scripts/search_googleSite.js) @@ -427,7 +459,7 @@
- 50. Google shortcuts + 54. Google shortcuts [View source](/scripts/googleShortcuts.js) @@ -435,7 +467,7 @@
- 51. View Google cache of website + 55. View Google cache of website [View source](/scripts/googleCache.js) @@ -443,7 +475,7 @@
- 52. Google mirror - I'm elgooG + 56. Google mirror - I'm elgooG [View source](/scripts/google_mirror.js) @@ -455,7 +487,7 @@ --- All in one ---
- 53. Facebook - All In One + 57. Facebook - All In One [View source](/scripts/fb_allInOne.js) @@ -465,7 +497,7 @@ --- Download ---
- 54. Download watching fb video + 58. Download watching fb video [View source](/scripts/fb_downloadWatchingVideo.js) @@ -473,7 +505,7 @@
- 55. Download watching fb Story/Comment + 59. Download watching fb Story/Comment [View source](/scripts/fb_storySaver.js) @@ -481,7 +513,7 @@
- 56. Download fb video/reel/watch from url + 60. Download fb video/reel/watch from url [View source](/scripts/fb_videoDownloader.js) @@ -489,7 +521,7 @@
- 57. Get avatar from fb user id + 61. Get avatar from fb user id [View source](/scripts/fb_getAvatarFromUid.js) @@ -497,7 +529,7 @@
- 58. Export saved facebook items + 62. Export saved facebook items [View source](/scripts/fb_exportSaved.js) @@ -507,7 +539,20 @@ --- Hot ---
- 59. Facebook - Reveal deleted messages + 63. Auto like post on Facebook + + [View source](/scripts/fb_autoLike.js) + + Auto like post on Facebook. +
    +
  • Support all post types (page, group, user, feed, ...)
  • +
  • Support bulk remove/add reactions
  • +
  • Support all reaction types
  • +
+ +
+
+ 64. Facebook - Reveal deleted messages [View source](/scripts/fb_revealDeletedMessages.js) @@ -515,7 +560,7 @@
- 60. Facebook Story - More reactions + 65. Facebook Story - More reactions [View source](/scripts/fb_moreReactionStory.js) @@ -525,7 +570,7 @@
- 61. Turn off light facebook newfeed + 66. Turn off light facebook newfeed [View source](/scripts/fb_toggleLight.js) @@ -533,7 +578,7 @@
- 62. Hide facebook new feed + 67. Hide facebook new feed [View source](/scripts/fb_toggleNewFeed.js) @@ -541,7 +586,7 @@
- 63. Stop new feed facebook + 68. Stop new feed facebook [View source](/scripts/fb_stopNewFeed.js) @@ -552,7 +597,7 @@
- 64. 👀 Block seen story facebook + 69. 👀 Block seen story facebook [View source](/scripts/fb_blockSeenStory.js) @@ -560,7 +605,7 @@
- 65. Show facebook post reaction count + 70. Show facebook post reaction count [View source](/scripts/fb_getPostReactionCount.js) @@ -570,7 +615,7 @@
- 66. Facebook - Who is typing to you? + 71. Facebook - Who is typing to you? [View source](/scripts/fb_whoIsTyping.js) @@ -580,7 +625,7 @@ --- Statistic ---
- 67. Facebook - View your friends's joined groups + 72. Facebook - View your friends's joined groups [View source](/scripts/fb_searchGroupForOther.js) @@ -588,7 +633,7 @@
- 68. Facebook - View your friend's liked pages + 73. Facebook - View your friend's liked pages [View source](/scripts/fb_searchPageForOther.js) @@ -596,7 +641,7 @@
- 69. Facebook - Find all posts of your friends + 74. Facebook - Find all posts of your friends [View source](/scripts/fb_searchPostsForOther.js) @@ -606,7 +651,7 @@ --- Access Token ---
- 70. Check fb access token + 75. Check fb access token [View source](/scripts/fb_checkToken.js) @@ -614,7 +659,7 @@
- 71. Get fb token EAAB (instagram) + 76. Get fb token EAAB (instagram) [View source](/scripts/fb_getTokenFacebook.js) @@ -622,7 +667,7 @@
- 72. Get fb token EAADo1 (messenger) + 77. Get fb token EAADo1 (messenger) [View source](/scripts/fb_getTokenMessage.js) @@ -630,7 +675,7 @@
- 73. Get fb token EAAG (business_locations) + 78. Get fb token EAAG (business_locations) [View source](/scripts/fb_getTokenBussinessLocation.js) @@ -638,7 +683,7 @@
- 74. Get fb token EAAB (campaigns) + 79. Get fb token EAAB (campaigns) [View source](/scripts/fb_getTokenCampaigns.js) @@ -646,7 +691,7 @@
- 75. Get fb token from cookie (ffb.vn) + 80. Get fb token from cookie (ffb.vn) [View source](/scripts/fb_getTokenFfb.js) @@ -656,7 +701,7 @@ --- Get ID ---
- 76. Get fb User ID + 81. Get fb User ID [View source](/scripts/fb_getUid.js) @@ -664,7 +709,7 @@
- 77. Get fb Page ID + 82. Get fb Page ID [View source](/scripts/fb_getPageId.js) @@ -672,7 +717,7 @@
- 78. Get fb Group ID + 83. Get fb Group ID [View source](/scripts/fb_getGroupId.js) @@ -680,7 +725,7 @@
- 79. Get fb Album ID + 84. Get fb Album ID [View source](/scripts/fb_getAlbumId.js) @@ -688,7 +733,7 @@
- 80. Get all fb Album ID from current page + 85. Get all fb Album ID from current page [View source](/scripts/fb_getAllAlbumIdFromCurrentWebsite.js) @@ -696,7 +741,7 @@
- 81. Get fb User ID from url + 86. Get fb User ID from url [View source](/scripts/fb_getUidFromUrl.js) @@ -704,7 +749,7 @@
- 82. Get all fb User ID from search page + 87. Get all fb User ID from search page [View source](/scripts/fb_getAllUidFromFbSearch.js) @@ -712,7 +757,7 @@
- 83. Get all fb User ID from group + 88. Get all fb User ID from group [View source](/scripts/fb_getAllUidOfGroupMembers.js) @@ -722,7 +767,7 @@ --- Shortcut ---
- 84. View your facebook saved + 89. View your facebook saved [View source](/scripts/fb_openSaved.js) @@ -730,7 +775,7 @@
- 85. View your memories on facebook + 90. View your memories on facebook [View source](/scripts/fb_openMemories.js) @@ -738,7 +783,7 @@
- 86. View your ads activities + 91. View your ads activities [View source](/scripts/fb_openAdsActivities.js) @@ -746,7 +791,7 @@
- 87. Check your activities on Facebook + 92. Check your activities on Facebook [View source](/scripts/fb_openAllActivities.js) @@ -754,7 +799,7 @@
- 88. Video you watched on facebook + 93. Video you watched on facebook [View source](/scripts/fb_openVideoActivities.js) @@ -762,7 +807,7 @@
- 89. Events joined on facebook + 94. Events joined on facebook [View source](/scripts/fb_openPassEvents.js) @@ -770,7 +815,7 @@
- 90. Facebook friend's birthdays + 95. Facebook friend's birthdays [View source](/scripts/fb_openBirthdays.js) @@ -778,7 +823,7 @@
- 91. Change language facebook + 96. Change language facebook [View source](/scripts/fb_openChangeLanguage.js) @@ -786,7 +831,7 @@
- 92. Recover facebook account + 97. Recover facebook account [View source](/scripts/fb_openAccountHacked.js) @@ -797,7 +842,7 @@ ### Instagram
- 93. Get insta user info (uid, avatar, ...) + 98. Get insta user info (uid, avatar, ...) [View source](/scripts/insta_getUserInfo.js) @@ -805,7 +850,7 @@
- 94. Add Instagram download button + 99. Add Instagram download button [View source](/scripts/insta_injectDownloadBtn.js) @@ -815,7 +860,7 @@
- 95. Insta - Anonymous story viewer + 100. Insta - Anonymous story viewer [View source](/scripts/insta_anonymousStoryViewer.js) @@ -825,7 +870,7 @@ --- Bulk Download ---
- 96. Get all media of insta user (API) + 101. Get all media of insta user (API) [View source](/scripts/insta_getAllUserMedia.js) @@ -833,7 +878,7 @@
- 97. Insta - Export all following/followers + 102. Insta - Export all following/followers [View source](/scripts/insta_getFollowForOther.js) @@ -844,65 +889,97 @@ ### Youtube
- 98. Download youtube video/audio + 103. Picture in Picture + + [View source](/scripts/pictureInPicture.js) + + Watch videos in a floating window + +
+
+ 104. Download youtube video/audio [View source](/scripts/youtube_downloadVideo.js) - Bypass age restriction, without login + Bypass age restriction, without login +
    +
  • Click once to download current video
  • +
  • Enable autorun to render download button
  • +
+ + ![](/scripts/youtube_downloadVideo.png)
- 99. Toggle light youtube + 105. Get Youtube video's captions - [View source](/scripts/youtube_toggleLight.js) + [View source](/scripts/youtube_getVideoCaption.js) - Toggle light on/off to focus to youtube video + - Click to get all captions of playing youtube video
- Enable autorun to show realtime captions (transcript)
+ + ![](/scripts/youtube_getVideoCaption.png)
- 100. Picture in Picture + 106. Return youtube dislike - [View source](/scripts/pictureInPicture.js) + [View source](/scripts/youtube_viewDislikes.js) - Watch videos in a floating window + Returns ability to see dislikes of youtube video/short
- 101. PIP full website + 107. Youtube nonstop - [View source](/scripts/pip_fullWebsite.js) + [View source](/scripts/youtube_nonstop.js) - Picture in picture mode for full website + Kiss the annoying "Video paused. Continue watching?" confirmation goodbye! + + ![](/scripts/youtube_nonstop.png)
- 102. PIP for canvas + 108. Youtube change country - [View source](/scripts/pip_canvas.js) + [View source](/scripts/youtube_changeCountry.js) - Picture in picture mode for canvas + Change youtube country to view content in other country
- 103. Return youtube dislike + 109. Get Youtube video's thumbnail - [View source](/scripts/youtube_viewDislikes.js) + [View source](/scripts/youtube_getVideoThumbnail.js) - Returns ability to see dislikes of youtube video/short + Get largest thumbnail of playing youtube video
- 104. Youtube nonstop + 110. Toggle light youtube - [View source](/scripts/youtube_nonstop.js) + [View source](/scripts/youtube_toggleLight.js) - Kiss the annoying "Video paused. Continue watching?" confirmation goodbye! + Toggle light on/off to focus to youtube video - ![](/scripts/youtube_nonstop.png) +
+
+ 111. PIP full website + + [View source](/scripts/pip_fullWebsite.js) + + Picture in picture mode for full website
- 105. Improve YouTube - 85+ features + 112. PIP for canvas + + [View source](/scripts/pip_canvas.js) + + Picture in picture mode for canvas + +
+
+ 113. Improve YouTube - 85+ features [View source](/scripts/recommend_improve_youtube.js) @@ -914,7 +991,7 @@ --- Tiktok ---
- 106. Tiktok - Download watching video + 114. Tiktok - Download watching video [View source](/scripts/tiktok_downloadWatchingVideo.js) @@ -922,7 +999,7 @@
- 107. Tiktok - Download video from URL + 115. Tiktok - Download video from URL [View source](/scripts/tiktok_downloadVideo.js) @@ -930,7 +1007,7 @@
- 108. Tiktok - Batch download + 116. Tiktok - Batch download [View source](/scripts/tiktok_batchDownload.js) @@ -942,7 +1019,7 @@ --- Douyin ---
- 109. Douyin - Download watching video + 117. Douyin - Download watching video [View source](/scripts/douyin_downloadWachingVideo.js) @@ -950,7 +1027,7 @@
- 110. Douyin - Download all user videos + 118. Douyin - Download all user videos [View source](/scripts/douyin_downloadAllVideoUser.js) @@ -962,7 +1039,7 @@ --- Utility ---
- 111. Web timer + 119. Web timer [View source](/scripts/web_timer.js) @@ -973,7 +1050,7 @@
- 112. Auto lock websites + 120. Auto lock websites [View source](/scripts/auto_lockWebsite.js) @@ -985,17 +1062,20 @@
- 113. Super smooth scroll + 121. Super smooth scroll [View source](/scripts/smoothScroll.js) Scroll smoothly on all websites with your mouse and keyboard.
- Smooth like when you scroll this extension.

- Support middle click to scroll.
+
    +
  • Suggested if you use mouse (turn off if use touchpad)
  • +
  • Click to Disable/Enable for current website
  • +
  • Support middle click to scroll
  • +

- 114. Magnify any Image + 122. Magnify any Image [View source](/scripts/magnify_image.js) @@ -1018,7 +1098,7 @@
- 115. Auto - view largest image + 123. Auto - view largest image [View source](/scripts/auto_redirectLargestImageSrc.js) @@ -1032,7 +1112,7 @@
- 116. Show image on hover link + 124. Show image on hover link [View source](/scripts/showImageOnHoverLink.js) @@ -1040,7 +1120,7 @@
- 117. Prevent tracking url + 125. Prevent tracking url [View source](/scripts/remove_tracking_in_url.js) @@ -1053,7 +1133,7 @@
- 118. Don't close browser with last tab + 126. Don't close browser with last tab [View source](/scripts/prevent_closeBrowser_lastTab.js) @@ -1062,7 +1142,7 @@
- 119. Block trackers, spy and malware + 127. Block trackers, spy and malware [View source](/scripts/chongLuaDao.js) @@ -1074,7 +1154,7 @@
- 120. Shorten URL + 128. Shorten URL [View source](/scripts/shortenURL.js) @@ -1082,7 +1162,7 @@
- 121. Unshorten link + 129. Unshorten link [View source](/scripts/unshorten.js) @@ -1090,7 +1170,7 @@
- 122. Create invisible message + 130. Create invisible message [View source](/scripts/createInvisibleText.js) @@ -1100,7 +1180,7 @@ --- Automation ---
- 123. Web to PDF + 131. Web to PDF [View source](/scripts/webToPDF.js) @@ -1108,7 +1188,7 @@
- 124. Screenshot full webpage + 132. Screenshot full webpage [View source](/scripts/screenshotFullPage.js) @@ -1116,7 +1196,7 @@
- 125. Screenshot webpage + 133. Screenshot webpage [View source](/scripts/screenshotVisiblePage.js) @@ -1124,7 +1204,7 @@
- 126. Scroll to very end + 134. Scroll to very end [View source](/scripts/scrollToVeryEnd.js) @@ -1132,7 +1212,7 @@
- 127. Extract all Emails from website + 135. Extract all Emails from website [View source](/scripts/getAllEmailsInWeb.js) @@ -1140,7 +1220,7 @@
- 128. Enable/Disable Hack T-Rex Dino Game + 136. Enable/Disable Hack T-Rex Dino Game [View source](/scripts/dino_hack.js) @@ -1148,7 +1228,7 @@
- 129. Password generator + 137. Password generator [View source](/scripts/passwordGenerator.js) @@ -1158,7 +1238,7 @@ --- Tools ---
- 130. Text to QRCode + 138. Text to QRCode [View source](/scripts/textToQrCode.js) @@ -1166,7 +1246,7 @@
- 131. Text to Speech (j2team) + 139. Text to Speech (j2team) [View source](/scripts/textToSpeech.js) @@ -1174,7 +1254,7 @@
- 132. Audio output switcher + 140. Audio output switcher [View source](/scripts/changeAudioOutput.js) @@ -1182,7 +1262,7 @@
- 133. Send - Share file faster + 141. Send - Share file faster [View source](/scripts/send_shareFiles.js) @@ -1190,7 +1270,7 @@
- 134. Vuiz - create logo WAP online + 142. Vuiz - create logo WAP online [View source](/scripts/vuiz_createLogo.js) @@ -1198,7 +1278,7 @@
- 135. Performance Analyzer + 143. Performance Analyzer [View source](/scripts/performanceAnalyzer.js) @@ -1206,7 +1286,7 @@
- 136. IT Tools - All for Developers + 144. IT Tools - All for Developers [View source](/scripts/recommend_ItTools.js) @@ -1214,7 +1294,7 @@
- 137. CopyIcon - FREE emoji, icon, generator + 145. CopyIcon - FREE emoji, icon, generator [View source](/scripts/recommend_copyicon.js) @@ -1222,7 +1302,7 @@
- 138. Beautify Tools + 146. Beautify Tools [View source](/scripts/recommend_beautifytools.js) @@ -1243,7 +1323,7 @@ --- Github ---
- 139. Github - Go to any commit + 147. Github - Go to any commit [View source](/scripts/github_goToAnyCommit.js) @@ -1251,7 +1331,7 @@
- 140. Github - HTML preview + 148. Github - HTML preview [View source](/scripts/github_HTMLPreview.js) @@ -1259,7 +1339,7 @@
- 141. Github - Open repo pages + 149. Github - Open repo pages [View source](/scripts/github_openRepoPages.js) @@ -1269,7 +1349,7 @@
- 142. Github - Open repo in github.dev + 150. Github - Open repo in github.dev [View source](/scripts/githubdev.js) @@ -1277,7 +1357,7 @@
- 143. Github - Open repo in github1s.com + 151. Github - Open repo in github1s.com [View source](/scripts/github1s.js) @@ -1285,7 +1365,7 @@
- 144. Cloc - count line of code + 152. Cloc - count line of code [View source](/scripts/recommend_cloc.js) @@ -1295,7 +1375,7 @@
- 145. Refined GitHub + 153. Refined GitHub [View source](/scripts/recommend_refined_github.js) @@ -1305,7 +1385,7 @@ --- Shopping ---
- 146. Shopee - Top variation + 154. Shopee - Top variation [View source](/scripts/shopee_topVariation.js) @@ -1315,7 +1395,7 @@
- 147. Shopee - Total spend money + 155. Shopee - Total spend money [View source](/scripts/shopee_totalSpendMoney.js) @@ -1323,7 +1403,7 @@
- 148. Shopee - Export order history (Excel) + 156. Shopee - Export order history (Excel) [View source](/scripts/shopee_totalSpendMoney_excel.js) @@ -1331,7 +1411,7 @@
- 149. Tiki - Total spend money? + 157. Tiki - Total spend money? [View source](/scripts/tiki_totalSpendMoney.js) @@ -1339,7 +1419,7 @@
- 150. Beecost + 158. Beecost [View source](/scripts/recommend_Beecost.js) @@ -1349,7 +1429,7 @@ --- PDF ---
- 151. FastDoc - Convert PDF/Photo to Word/Excel + 159. FastDoc - Convert PDF/Photo to Word/Excel [View source](/scripts/recommend_fastDoc.js) @@ -1357,7 +1437,7 @@
- 152. SmartPDF - Tools for PDF + 160. SmartPDF - Tools for PDF [View source](/scripts/recommend_smartPDF.js) @@ -1365,7 +1445,7 @@
- 153. PDF Stuffs - Tools for PDF + 161. PDF Stuffs - Tools for PDF [View source](/scripts/recommend_pdfstuffs.js) @@ -1377,7 +1457,7 @@ --- Unlock web ---
- 154. Hack Duck race + 162. Hack Duck race [View source](/scripts/duckRace_cheat.js) @@ -1387,7 +1467,7 @@
- 155. Hack Wheel of Names + 163. Hack Wheel of Names [View source](/scripts/wheelOfNames_hack.js) @@ -1395,7 +1475,7 @@
- 156. Read full medium article + 164. Read full medium article [View source](/scripts/medium_readFullArticle.js) @@ -1403,7 +1483,7 @@
- 157. Medium - Fix vietnamese font + 165. Medium - Fix vietnamese font [View source](/scripts/medium_fixVietnameseFont.js) @@ -1415,7 +1495,7 @@
- 158. Fireship - PRO unlocked + 166. Fireship - PRO unlocked [View source](/scripts/fireship_vip.js) @@ -1423,7 +1503,7 @@
- 159. Studocu - Bypass preview + 167. Studocu - Bypass preview [View source](/scripts/studocu_bypassPreview.js) @@ -1431,7 +1511,7 @@
- 160. Scribd - bypass preview + 168. Scribd - bypass preview [View source](/scripts/scribd_bypassPreview.js) @@ -1439,17 +1519,27 @@
- 161. Studyphim - Watch free movies + 169. Studyphim - Watch free movies [View source](/scripts/studyphim_unlimited.js) Watch movies on Studyphim for free without login +
+
+ 170. Mở khoá Learn Anything + + [View source](/scripts/bypass_learnAnything.js) + + View learn-anything.xyz content without become a member + + ![](/scripts/bypass_LearnAnything.png) +
--- Unlock function ---
- 162. Enable/Disable allow copy + 171. Enable/Disable allow copy [View source](/scripts/simpleAllowCopy.js) @@ -1463,7 +1553,7 @@
- 163. Detect Zero-Width Characters + 172. Detect Zero-Width Characters [View source](/scripts/detect_zeroWidthCharacters.js) @@ -1471,7 +1561,7 @@
- 164. Inject script to website + 173. Inject script to website [View source](/scripts/injectScriptToWebsite.js) @@ -1479,7 +1569,7 @@
- 165. Show hidden fields + 174. Show hidden fields [View source](/scripts/showHiddenFields.js) @@ -1487,7 +1577,7 @@
- 166. View cookies + 175. View cookies [View source](/scripts/viewCookies.js) @@ -1495,7 +1585,7 @@
- 167. Remove cookies + 176. Remove cookies [View source](/scripts/removeCookies.js) @@ -1505,7 +1595,7 @@ --- Other ---
- 168. Make browser super fast + 177. Make browser super fast [View source](/scripts/recommend_chromeFlags.js) @@ -1513,7 +1603,7 @@
- 169. View saved wifi passwords + 178. View saved wifi passwords [View source](/scripts/recommend_viewSavedWifiPass.js) @@ -1521,7 +1611,7 @@
- 170. Leak check - your password has been leaked? + 179. Leak check - your password has been leaked? [View source](/scripts/recommend_leakCheck.js) @@ -1533,7 +1623,7 @@ --- Hot ---
- 171. Darkmode for pdf + 180. Darkmode for pdf [View source](/scripts/darkModePDF.js) @@ -1541,7 +1631,7 @@
- 172. Toggle edit page + 181. Toggle edit page [View source](/scripts/toggleEditPage.js) @@ -1549,7 +1639,7 @@
- 173. Show FPS + 182. Show FPS [View source](/scripts/showFPS.js) @@ -1557,7 +1647,7 @@
- 174. Show FPS - ver 2 + 183. Show FPS - ver 2 [View source](/scripts/showFps_v2.js) @@ -1565,7 +1655,7 @@
- 175. Hide/Show password field + 184. Hide/Show password field [View source](/scripts/toggle_passwordField.js) @@ -1573,7 +1663,7 @@
- 176. Dark reader + 185. Dark reader [View source](/scripts/recommend_DarkReader.js) @@ -1581,7 +1671,7 @@
- 177. CSS Portal - Empowered your CSS skills + 186. CSS Portal - Empowered your CSS skills [View source](/scripts/recommend_cssportal.js) @@ -1589,7 +1679,7 @@
- 178. CSS Loaders - 600+ css loader + 187. CSS Loaders - 600+ css loader [View source](/scripts/recommend_cssloaders.js) @@ -1597,7 +1687,7 @@
- 179. UIverse - Open-Source UI elements + 188. UIverse - Open-Source UI elements [View source](/scripts/recommend_uiverse.js) @@ -1607,7 +1697,7 @@ --- View ---
- 180. Font Rendering - better font display + 189. Font Rendering - better font display [View source](/scripts/recommend_fontRendering.js) @@ -1615,7 +1705,7 @@
- 181. What font + 190. What font [View source](/scripts/whatFont.js) @@ -1623,7 +1713,7 @@
- 182. Show all javascript events + 191. Show all javascript events [View source](/scripts/visualEvent.js) @@ -1631,7 +1721,7 @@
- 183. View all images in web + 192. View all images in web [View source](/scripts/listAllImagesInWeb.js) @@ -1639,7 +1729,7 @@
- 184. View all links + 193. View all links [View source](/scripts/viewAllLinks.js) @@ -1647,7 +1737,7 @@
- 185. View scripts used + 194. View scripts used [View source](/scripts/viewScriptsUsed.js) @@ -1655,7 +1745,7 @@
- 186. View stylesheet used + 195. View stylesheet used [View source](/scripts/viewStylesUsed.js) @@ -1663,7 +1753,7 @@
- 187. CSS selector viewer + 196. CSS selector viewer [View source](/scripts/cssSelectorViewer.js) @@ -1673,7 +1763,7 @@ --- Remove ---
- 188. Remove all colors in web + 197. Remove all colors in web [View source](/scripts/removeColours.js) @@ -1681,7 +1771,7 @@
- 189. Remove stylesheet + 198. Remove stylesheet [View source](/scripts/removeStylesheet.js) @@ -1689,7 +1779,7 @@
- 190. Remove images + 199. Remove images [View source](/scripts/removeImages.js) @@ -1697,7 +1787,7 @@
- 191. Remove bloat (iframe, embed) + 200. Remove bloat (iframe, embed) [View source](/scripts/removeBloat.js) @@ -1707,7 +1797,7 @@ --- Table ---
- 192. Add sort to table + 201. Add sort to table [View source](/scripts/table_addSortTable.js) @@ -1715,7 +1805,7 @@
- 193. Add number columns + 202. Add number columns [View source](/scripts/table_addNumberColumn.js) @@ -1723,7 +1813,7 @@
- 194. Swap rows and columns + 203. Swap rows and columns [View source](/scripts/table_swapRowAndColumn.js) @@ -1733,7 +1823,7 @@ --- More ---
- 195. Highlight internal/external link + 204. Highlight internal/external link [View source](/scripts/internalOrExternalLink.js) @@ -1743,7 +1833,7 @@
- 196. Get window size + 205. Get window size [View source](/scripts/getWindowSize.js) @@ -1751,7 +1841,7 @@
- 197. Let it snow + 206. Let it snow [View source](/scripts/letItSnow.js) diff --git a/md/LIST_SCRIPTS_VI.md b/md/LIST_SCRIPTS_VI.md index 59b988b2..34a456eb 100644 --- a/md/LIST_SCRIPTS_VI.md +++ b/md/LIST_SCRIPTS_VI.md @@ -1,7 +1,31 @@ ### Tìm kiếm
- 1. Tìm trang web tương tự + 1. There's an AI for that - Tìm AI + + [Xem mã nguồn](/scripts/recommend_theresanaiforthat.js) + + Tổng hợp hàng ngàn công cụ AI hiện có. Dễ dàng tìm kiếm theo chủ đề + +
+
+ 2. Time.is - Kiểm tra thời gian + + [Xem mã nguồn](/scripts/recommend_timeis.js) + + Đồng hồ chính xác nhất. Kiểm tra đồng hồ trên máy của bạn nhanh hay chậm. + +
+
+ 3. Google trending - Nội dung nổi bật + + [Xem mã nguồn](/scripts/recommend_googleTrending.js) + + Xem mọi người đang tìm gì trên google. Thống kê từng ngày, thời gian thực. + +
+
+ 4. Tìm trang web tương tự [Xem mã nguồn](/scripts/similarWeb.js) @@ -9,7 +33,7 @@
- 2. SimilarWeb - không bị giới hạn + 5. SimilarWeb - không bị giới hạn [Xem mã nguồn](/scripts/similarWeb_bypassLimit.js) @@ -19,7 +43,7 @@
- 3. Tìm tài khoản miễn phí + 6. Tìm tài khoản miễn phí [Xem mã nguồn](/scripts/search_sharedAccount.js) @@ -27,7 +51,7 @@
- 4. Internet archive - Thư viện miễn phí + 7. Internet archive - Thư viện miễn phí [Xem mã nguồn](/scripts/recommend_archive.js) @@ -37,7 +61,7 @@
- 5. Wappalyzer - Web dùng công nghệ gì? + 8. Wappalyzer - Web dùng công nghệ gì? [Xem mã nguồn](/scripts/recommend_wappalyzer.js) @@ -45,7 +69,7 @@
- 6. Who.is + 9. Who.is [Xem mã nguồn](/scripts/whois.js) @@ -53,7 +77,7 @@
- 7. Xem thông tin meta của web (SEO) + 10. Xem thông tin meta của web (SEO) [Xem mã nguồn](/scripts/viewWebMetaInfo.js) @@ -61,7 +85,7 @@
- 8. Bài nhạc top treding toàn cầu? + 11. Bài nhạc top treding toàn cầu? [Xem mã nguồn](/scripts/recommend_search_musicTreding.js) @@ -69,7 +93,7 @@
- 9. Tìm bài báo/sách/pdf/...ở đâu? + 12. Tìm bài báo/sách/pdf/...ở đâu? [Xem mã nguồn](/scripts/search_paperWhere.js) @@ -77,7 +101,7 @@
- 10. Tìm hợp âm guitar + 13. Tìm hợp âm guitar [Xem mã nguồn](/scripts/search_hopamchuan.js) @@ -85,7 +109,7 @@
- 11. Dowfor - Kiểm tra web die + 14. Dowfor - Kiểm tra web die [Xem mã nguồn](/scripts/checkWebDie.js) @@ -93,7 +117,7 @@
- 12. DownDetector - Thống kê sự cố web + 15. DownDetector - Thống kê sự cố web [Xem mã nguồn](/scripts/downDetector.js) @@ -101,7 +125,7 @@
- 13. Xem wayback url của website + 16. Xem wayback url của website [Xem mã nguồn](/scripts/openWaybackUrl.js) @@ -109,7 +133,7 @@
- 14. Lưu trữ online trang hiện tại + 17. Lưu trữ online trang hiện tại [Xem mã nguồn](/scripts/archiveToday.js) @@ -117,7 +141,7 @@
- 15. Tìm Userscripts + 18. Tìm Userscripts [Xem mã nguồn](/scripts/recommend_search_userscript.js) @@ -129,7 +153,15 @@ --- Tổng hợp ---
- 16. Save All Video + 19. Cobalt - Tải video/nhạc + + [Xem mã nguồn](/scripts/recommend_cobalt.js) + + Hỗ trợ youtube, tiktok, instagram, twitter/x, bilibili, twitch, vimeo, soundcloud, dailymotion, pinterest, reddit, tumblr, ... + +
+
+ 20. Save All Video [Xem mã nguồn](/scripts/saveAllVideo.js) @@ -137,7 +169,7 @@
- 17. Vuiz - Get link nhạc/video/album + 21. Vuiz - Get link nhạc/video/album [Xem mã nguồn](/scripts/vuiz_getLink.js) @@ -145,7 +177,7 @@
- 18. SaveVideo - Tải video + 22. SaveVideo - Tải video [Xem mã nguồn](/scripts/savevideo_me.js) @@ -153,7 +185,7 @@
- 19. Tải nhạc/video (luanxt) + 23. Tải nhạc/video (luanxt) [Xem mã nguồn](/scripts/getLinkLuanxt_newtab.js) @@ -163,7 +195,7 @@ --- Ảnh ---
- 20. Twitter X - Thêm nút tải video/ảnh + 24. Twitter X - Thêm nút tải video/ảnh [Xem mã nguồn](/scripts/twitter_downloadButton.js) @@ -173,7 +205,7 @@
- 21. Tải favicon của trang web + 25. Tải favicon của trang web [Xem mã nguồn](/scripts/getFavicon.js) @@ -181,7 +213,7 @@
- 22. Picviewer CE+ tải ảnh + 26. Picviewer CE+ tải ảnh [Xem mã nguồn](/scripts/recommend_picviewer_ce+.js) @@ -191,7 +223,7 @@
- 23. File-converter.io - chuyển đổi ảnh + 27. File-converter.io - chuyển đổi ảnh [Xem mã nguồn](/scripts/recommend_file_converter.js) @@ -201,7 +233,7 @@
- 24. Squoosh.app - nén ảnh + 28. Squoosh.app - nén ảnh [Xem mã nguồn](/scripts/recommend_squoosh_app.js) @@ -211,7 +243,7 @@ --- Nhạc ---
- 25. Spotify - Thêm nút tải nhạc + 29. Spotify - Thêm nút tải nhạc [Xem mã nguồn](/scripts/spotify_downloadButton.js) @@ -221,7 +253,7 @@
- 26. Soundcloud - Thêm nút tải nhạc + 30. Soundcloud - Thêm nút tải nhạc [Xem mã nguồn](/scripts/soundcloud_downloadMusic.js) @@ -231,7 +263,7 @@
- 27. Nhaccuatui tải nhạc/lời + 31. Nhaccuatui tải nhạc/lời [Xem mã nguồn](/scripts/nhaccuatui_downloader.js) @@ -239,7 +271,7 @@
- 28. Zingmp3 tải nhạc (API) + 32. Zingmp3 tải nhạc (API) [Xem mã nguồn](/scripts/zingmp3_downloadMusic.js) @@ -247,7 +279,7 @@
- 29. Hiển thị mọi audio trong trang web + 33. Hiển thị mọi audio trong trang web [Xem mã nguồn](/scripts/showTheAudios.js) @@ -257,7 +289,7 @@ --- Video ---
- 30. Tải video đang xem + 34. Tải video đang xem [Xem mã nguồn](/scripts/download_watchingVideo.js) @@ -265,7 +297,7 @@
- 31. Vimeo - tải video + 35. Vimeo - tải video [Xem mã nguồn](/scripts/vimeo_downloader.js) @@ -273,7 +305,7 @@
- 32. Hiển thị mọi video có trong web + 36. Hiển thị mọi video có trong web [Xem mã nguồn](/scripts/showTheVideos.js) @@ -283,7 +315,7 @@ --- Tài liệu ---
- 33. Studocu - Tải documents + 37. Studocu - Tải documents [Xem mã nguồn](/scripts/studocu_downs.js) @@ -291,7 +323,7 @@
- 34. Scribd - Tải documents + 38. Scribd - Tải documents [Xem mã nguồn](/scripts/scribd_downloadDocuments.js) @@ -299,7 +331,7 @@
- 35. Tải miễn phí từ tailieu.vn + 39. Tải miễn phí từ tailieu.vn [Xem mã nguồn](/scripts/tailieu_vn.js) @@ -307,7 +339,7 @@
- 36. DocDownloader - Tải document + 40. DocDownloader - Tải document [Xem mã nguồn](/scripts/recommend_docsdownloader.js) @@ -315,7 +347,7 @@
- 37. Xuất bookmarks ra file + 41. Xuất bookmarks ra file [Xem mã nguồn](/scripts/bookmark_exporter.js) @@ -323,7 +355,7 @@
- 38. Bookmark Sidebar + 42. Bookmark Sidebar [Xem mã nguồn](/scripts/recommend_BookmarkSidebar.js) @@ -335,7 +367,7 @@ --- Tải xuống ---
- 39. Google drive - tạo link tải ngay + 43. Google drive - tạo link tải ngay [Xem mã nguồn](/scripts/ggdrive_generateDirectLink.js) @@ -343,7 +375,7 @@
- 40. GG Drive - Tải PDF + 44. GG Drive - Tải PDF [Xem mã nguồn](/scripts/ggdrive_downloadPdf.js) @@ -351,7 +383,7 @@
- 41. GG Drive - Tải PowerPoint (Slides) + 45. GG Drive - Tải PowerPoint (Slides) [Xem mã nguồn](/scripts/ggdrive_downloadPresentation.js) @@ -359,7 +391,7 @@
- 42. GG Drive - Tải Document (sang PDF) + 46. GG Drive - Tải Document (sang PDF) [Xem mã nguồn](/scripts/ggdrive_downloadDoc.js) @@ -367,7 +399,7 @@
- 43. GG Drive - Tải Sheet (copy nội dung) + 47. GG Drive - Tải Sheet (copy nội dung) [Xem mã nguồn](/scripts/ggdrive_copySheetText.js) @@ -375,7 +407,7 @@
- 44. GG Drive - Tải video + 48. GG Drive - Tải video [Xem mã nguồn](/scripts/ggdrive_downloadVideo.js) @@ -383,7 +415,7 @@
- 45. Google - Tải xuống dữ liệu của bạn + 49. Google - Tải xuống dữ liệu của bạn [Xem mã nguồn](/scripts/google_downloadAllYourData.js) @@ -393,7 +425,7 @@ --- Tải hàng loạt ---
- 46. GGDrive - Tải mọi video trong folder + 50. GGDrive - Tải mọi video trong folder [Xem mã nguồn](/scripts/ggDrive_downloadAllVideosInFolder.js) @@ -403,7 +435,7 @@ --- Khác ---
- 47. Google tìm kiếm nâng cao + 51. Google tìm kiếm nâng cao [Xem mã nguồn](/scripts/recommend_googleAdvanced.js) @@ -411,7 +443,7 @@
- 48. Xem các pages được google quét + 52. Xem các pages được google quét [Xem mã nguồn](/scripts/search_totalIndexedPages.js) @@ -419,7 +451,7 @@
- 49. Tìm kiếm trên trang web này + 53. Tìm kiếm trên trang web này [Xem mã nguồn](/scripts/search_googleSite.js) @@ -427,7 +459,7 @@
- 50. Google phím tắt + 54. Google phím tắt [Xem mã nguồn](/scripts/googleShortcuts.js) @@ -435,7 +467,7 @@
- 51. Xem Google cache của trang web + 55. Xem Google cache của trang web [Xem mã nguồn](/scripts/googleCache.js) @@ -443,7 +475,7 @@
- 52. Google mirror - I'm elgooG + 56. Google mirror - I'm elgooG [Xem mã nguồn](/scripts/google_mirror.js) @@ -455,7 +487,7 @@ --- Tất cả trong một ---
- 53. Facebook - All In One + 57. Facebook - All In One [Xem mã nguồn](/scripts/fb_allInOne.js) @@ -465,7 +497,7 @@ --- Tải xuống ---
- 54. Tải video fb đang xem + 58. Tải video fb đang xem [Xem mã nguồn](/scripts/fb_downloadWatchingVideo.js) @@ -473,7 +505,7 @@
- 55. Tải Story/Comment fb đang xem + 59. Tải Story/Comment fb đang xem [Xem mã nguồn](/scripts/fb_storySaver.js) @@ -481,7 +513,7 @@
- 56. Tải video/reel/watch fb từ url + 60. Tải video/reel/watch fb từ url [Xem mã nguồn](/scripts/fb_videoDownloader.js) @@ -489,7 +521,7 @@
- 57. Tải avatar từ fb user id + 61. Tải avatar từ fb user id [Xem mã nguồn](/scripts/fb_getAvatarFromUid.js) @@ -497,7 +529,7 @@
- 58. Xuất mục đã lưu trên facebook + 62. Xuất mục đã lưu trên facebook [Xem mã nguồn](/scripts/fb_exportSaved.js) @@ -507,7 +539,20 @@ --- Nổi bật ---
- 59. Facebook - Xem tin nhắn bị gỡ + 63. Tự động thích bài đăng Facebook + + [Xem mã nguồn](/scripts/fb_autoLike.js) + + Tự động thả cảm xúc cho bài đăng trên Facebook. +
    +
  • Hỗ trợ mọi loại bài đăng (trang, nhóm, người dùng, new feed, ...)
  • +
  • Hỗ trợ gỡ/thêm cảm xúc hàng loạt
  • +
  • Hỗ trợ mọi loại cảm xúc
  • +
+ +
+
+ 64. Facebook - Xem tin nhắn bị gỡ [Xem mã nguồn](/scripts/fb_revealDeletedMessages.js) @@ -515,7 +560,7 @@
- 60. Facebook Story - Thêm cảm xúc + 65. Facebook Story - Thêm cảm xúc [Xem mã nguồn](/scripts/fb_moreReactionStory.js) @@ -525,7 +570,7 @@
- 61. Tắt đèn newfeed facebook + 66. Tắt đèn newfeed facebook [Xem mã nguồn](/scripts/fb_toggleLight.js) @@ -533,7 +578,7 @@
- 62. Ẩn dòng thời gian facebook + 67. Ẩn dòng thời gian facebook [Xem mã nguồn](/scripts/fb_toggleNewFeed.js) @@ -541,7 +586,7 @@
- 63. Dừng dòng thời gian facebook + 68. Dừng dòng thời gian facebook [Xem mã nguồn](/scripts/fb_stopNewFeed.js) @@ -552,7 +597,7 @@
- 64. 👀 Chặn "Đã xem" story facebook + 69. 👀 Chặn "Đã xem" story facebook [Xem mã nguồn](/scripts/fb_blockSeenStory.js) @@ -560,7 +605,7 @@
- 65. Hiện tổng lượt thích bài viết facebook + 70. Hiện tổng lượt thích bài viết facebook [Xem mã nguồn](/scripts/fb_getPostReactionCount.js) @@ -570,7 +615,7 @@
- 66. Facebook - Ai đang nhắn cho bạn? + 71. Facebook - Ai đang nhắn cho bạn? [Xem mã nguồn](/scripts/fb_whoIsTyping.js) @@ -580,7 +625,7 @@ --- Thống kê ---
- 67. Facebook - Xem các nhóm bạn bè tham gia + 72. Facebook - Xem các nhóm bạn bè tham gia [Xem mã nguồn](/scripts/fb_searchGroupForOther.js) @@ -588,7 +633,7 @@
- 68. Facebook - Xem các trang bạn bè thích + 73. Facebook - Xem các trang bạn bè thích [Xem mã nguồn](/scripts/fb_searchPageForOther.js) @@ -596,7 +641,7 @@
- 69. Facebook - Tìm mọi bài viết của bạn bè + 74. Facebook - Tìm mọi bài viết của bạn bè [Xem mã nguồn](/scripts/fb_searchPostsForOther.js) @@ -606,7 +651,7 @@ --- Access Token ---
- 70. Kiểm tra fb access token + 75. Kiểm tra fb access token [Xem mã nguồn](/scripts/fb_checkToken.js) @@ -614,7 +659,7 @@
- 71. Lấy fb token EAAB (instagram) + 76. Lấy fb token EAAB (instagram) [Xem mã nguồn](/scripts/fb_getTokenFacebook.js) @@ -622,7 +667,7 @@
- 72. Lấy fb token EAADo1 (messenger) + 77. Lấy fb token EAADo1 (messenger) [Xem mã nguồn](/scripts/fb_getTokenMessage.js) @@ -630,7 +675,7 @@
- 73. Lấy fb token EAAG (business_locations) + 78. Lấy fb token EAAG (business_locations) [Xem mã nguồn](/scripts/fb_getTokenBussinessLocation.js) @@ -638,7 +683,7 @@
- 74. Lấy fb token EAAB (campaigns) + 79. Lấy fb token EAAB (campaigns) [Xem mã nguồn](/scripts/fb_getTokenCampaigns.js) @@ -646,7 +691,7 @@
- 75. Lấy fb token từ cookie (ffb.vn) + 80. Lấy fb token từ cookie (ffb.vn) [Xem mã nguồn](/scripts/fb_getTokenFfb.js) @@ -656,7 +701,7 @@ --- Lấy ID ---
- 76. Lấy fb User ID + 81. Lấy fb User ID [Xem mã nguồn](/scripts/fb_getUid.js) @@ -664,7 +709,7 @@
- 77. Lấy fb Page ID + 82. Lấy fb Page ID [Xem mã nguồn](/scripts/fb_getPageId.js) @@ -672,7 +717,7 @@
- 78. Lấy fb Group ID + 83. Lấy fb Group ID [Xem mã nguồn](/scripts/fb_getGroupId.js) @@ -680,7 +725,7 @@
- 79. Lấy fb Album ID + 84. Lấy fb Album ID [Xem mã nguồn](/scripts/fb_getAlbumId.js) @@ -688,7 +733,7 @@
- 80. Lấy tất cả fb album id từ trang hiện tại + 85. Lấy tất cả fb album id từ trang hiện tại [Xem mã nguồn](/scripts/fb_getAllAlbumIdFromCurrentWebsite.js) @@ -696,7 +741,7 @@
- 81. Lấy fb User ID từ URL + 86. Lấy fb User ID từ URL [Xem mã nguồn](/scripts/fb_getUidFromUrl.js) @@ -704,7 +749,7 @@
- 82. Lấy tất cả fb user ID từ trang tìm kiếm + 87. Lấy tất cả fb user ID từ trang tìm kiếm [Xem mã nguồn](/scripts/fb_getAllUidFromFbSearch.js) @@ -712,7 +757,7 @@
- 83. Lấy tất cả fb user ID từ group + 88. Lấy tất cả fb user ID từ group [Xem mã nguồn](/scripts/fb_getAllUidOfGroupMembers.js) @@ -722,7 +767,7 @@ --- Phím tắt ---
- 84. Xem mục đã lưu trên facebook + 89. Xem mục đã lưu trên facebook [Xem mã nguồn](/scripts/fb_openSaved.js) @@ -730,7 +775,7 @@
- 85. Xem kỷ niệm của bạn trên facebook + 90. Xem kỷ niệm của bạn trên facebook [Xem mã nguồn](/scripts/fb_openMemories.js) @@ -738,7 +783,7 @@
- 86. Xem các quảng cáo fb bạn đã xem + 91. Xem các quảng cáo fb bạn đã xem [Xem mã nguồn](/scripts/fb_openAdsActivities.js) @@ -746,7 +791,7 @@
- 87. Xem nhật ký hoạt động trên facebook + 92. Xem nhật ký hoạt động trên facebook [Xem mã nguồn](/scripts/fb_openAllActivities.js) @@ -754,7 +799,7 @@
- 88. Video bạn vừa xem trên facebook + 93. Video bạn vừa xem trên facebook [Xem mã nguồn](/scripts/fb_openVideoActivities.js) @@ -762,7 +807,7 @@
- 89. Sự kiện đã tham gia trên facebook + 94. Sự kiện đã tham gia trên facebook [Xem mã nguồn](/scripts/fb_openPassEvents.js) @@ -770,7 +815,7 @@
- 90. Sinh nhật bạn bè facebook + 95. Sinh nhật bạn bè facebook [Xem mã nguồn](/scripts/fb_openBirthdays.js) @@ -778,7 +823,7 @@
- 91. Đổi ngôn ngữ facebook + 96. Đổi ngôn ngữ facebook [Xem mã nguồn](/scripts/fb_openChangeLanguage.js) @@ -786,7 +831,7 @@
- 92. Khôi phục tài khoản facebook + 97. Khôi phục tài khoản facebook [Xem mã nguồn](/scripts/fb_openAccountHacked.js) @@ -797,7 +842,7 @@ ### Instagram
- 93. Lấy insta thông tin user (uid, avatar, ...) + 98. Lấy insta thông tin user (uid, avatar, ...) [Xem mã nguồn](/scripts/insta_getUserInfo.js) @@ -805,7 +850,7 @@
- 94. Thêm nút tải cho Instagram + 99. Thêm nút tải cho Instagram [Xem mã nguồn](/scripts/insta_injectDownloadBtn.js) @@ -815,7 +860,7 @@
- 95. Insta - Xem story ẩn danh + 100. Insta - Xem story ẩn danh [Xem mã nguồn](/scripts/insta_anonymousStoryViewer.js) @@ -825,7 +870,7 @@ --- Tải hàng loạt ---
- 96. Tải về tất cả media của insta user (API) + 101. Tải về tất cả media của insta user (API) [Xem mã nguồn](/scripts/insta_getAllUserMedia.js) @@ -833,7 +878,7 @@
- 97. Insta - Tải tất cả following/follower + 102. Insta - Tải tất cả following/follower [Xem mã nguồn](/scripts/insta_getFollowForOther.js) @@ -844,65 +889,97 @@ ### Youtube
- 98. Tải video/audio youtube + 103. Picture in Picture + + [Xem mã nguồn](/scripts/pictureInPicture.js) + + Xem video trong cửa sổ nổi + +
+
+ 104. Tải video/audio youtube [Xem mã nguồn](/scripts/youtube_downloadVideo.js) - Tải cả video giới hạn độ tuổi, không cần đăng nhập + Tải cả video giới hạn độ tuổi, không cần đăng nhập +
    +
  • Bấm 1 lần để tải video hiện tại
  • +
  • Bật tự chạy để hiển thị nút tải
  • +
+ + ![](/scripts/youtube_downloadVideo.png)
- 99. Tắt/Mở đèn youtube + 105. Lấy phụ đề video trên Youtube - [Xem mã nguồn](/scripts/youtube_toggleLight.js) + [Xem mã nguồn](/scripts/youtube_getVideoCaption.js) - Tắt/Mở đèn để tập trung xem video youtube + - Bấm để tải về tất cả phụ đề của video youtube đang xem
- Bật tự chạy để hiển thị phụ đề thời gian thực
+ + ![](/scripts/youtube_getVideoCaption.png)
- 100. Picture in Picture + 106. Hiện lượt không thích youtube - [Xem mã nguồn](/scripts/pictureInPicture.js) + [Xem mã nguồn](/scripts/youtube_viewDislikes.js) - Xem video trong cửa sổ nổi + Hiển thị số lượt không thích của video/short youtube
- 101. PIP toàn website + 107. Youtube nonstop - [Xem mã nguồn](/scripts/pip_fullWebsite.js) + [Xem mã nguồn](/scripts/youtube_nonstop.js) - Picture in picture: Xem toàn bộ website (thay vì chỉ video) trong của sổ nổi + Phát youtube không còn bị làm phiền bởi popup 'Video đã tạm dừng. Bạn có muốn xem tiếp?' của youtube. + + ![](/scripts/youtube_nonstop.png)
- 102. PIP cho canvas + 108. Đổi quốc gia Youtube - [Xem mã nguồn](/scripts/pip_canvas.js) + [Xem mã nguồn](/scripts/youtube_changeCountry.js) - Picture in picture: Xem canvas trong của sổ nổi + Đổi quốc gia youtube để xem nội dung youtube bên các nước khác
- 103. Hiện lượt không thích youtube + 109. Lấy thumbnail video trên Youtube - [Xem mã nguồn](/scripts/youtube_viewDislikes.js) + [Xem mã nguồn](/scripts/youtube_getVideoThumbnail.js) - Hiển thị số lượt không thích của video/short youtube + Tải về hình thumbnail độ phân giải lớn nhất của video youtube đang xem
- 104. Youtube nonstop + 110. Tắt/Mở đèn youtube - [Xem mã nguồn](/scripts/youtube_nonstop.js) + [Xem mã nguồn](/scripts/youtube_toggleLight.js) - Phát youtube không còn bị làm phiền bởi popup 'Video đã tạm dừng. Bạn có muốn xem tiếp?' của youtube. + Tắt/Mở đèn để tập trung xem video youtube - ![](/scripts/youtube_nonstop.png) +
+
+ 111. PIP toàn website + + [Xem mã nguồn](/scripts/pip_fullWebsite.js) + + Picture in picture: Xem toàn bộ website (thay vì chỉ video) trong của sổ nổi
- 105. Improve YouTube - 85+ chức năng + 112. PIP cho canvas + + [Xem mã nguồn](/scripts/pip_canvas.js) + + Picture in picture: Xem canvas trong của sổ nổi + +
+
+ 113. Improve YouTube - 85+ chức năng [Xem mã nguồn](/scripts/recommend_improve_youtube.js) @@ -914,7 +991,7 @@ --- Tiktok ---
- 106. Tiktok - Tải video đang xem + 114. Tiktok - Tải video đang xem [Xem mã nguồn](/scripts/tiktok_downloadWatchingVideo.js) @@ -922,7 +999,7 @@
- 107. Tiktok - Tải video từ URL + 115. Tiktok - Tải video từ URL [Xem mã nguồn](/scripts/tiktok_downloadVideo.js) @@ -930,7 +1007,7 @@
- 108. Tiktok - Tải hàng loạt + 116. Tiktok - Tải hàng loạt [Xem mã nguồn](/scripts/tiktok_batchDownload.js) @@ -942,7 +1019,7 @@ --- Douyin ---
- 109. Douyin - Tải video đang xem + 117. Douyin - Tải video đang xem [Xem mã nguồn](/scripts/douyin_downloadWachingVideo.js) @@ -950,7 +1027,7 @@
- 110. Douyin - Tải tất cả video người dùng + 118. Douyin - Tải tất cả video người dùng [Xem mã nguồn](/scripts/douyin_downloadAllVideoUser.js) @@ -962,7 +1039,7 @@ --- Tiện ích ---
- 111. Thời gian lướt web + 119. Thời gian lướt web [Xem mã nguồn](/scripts/web_timer.js) @@ -973,7 +1050,7 @@
- 112. Tự động khoá trang web + 120. Tự động khoá trang web [Xem mã nguồn](/scripts/auto_lockWebsite.js) @@ -985,17 +1062,20 @@
- 113. Cuộn chuột siêu mượt + 121. Cuộn chuột siêu mượt [Xem mã nguồn](/scripts/smoothScroll.js) Cuộn chuột siêu mượt cho mọi trang web.
- Mượt như khi cuộn chuột trong extension này vậy.

- Hỗ trợ scroll khi bấm chuột giữa.
+
    +
  • Khuyên dùng với chuột (tắt nếu dùng touchpad)
  • +
  • Bấm để Tắt/Mở cho trang web hiện tại
  • +
  • Hỗ trợ bấm chuột giữa để cuộn trang
  • +

- 114. Phóng to mọi hình ảnh + 122. Phóng to mọi hình ảnh [Xem mã nguồn](/scripts/magnify_image.js) @@ -1017,7 +1097,7 @@
- 115. Tự động - xem ảnh lớn nhất + 123. Tự động - xem ảnh lớn nhất [Xem mã nguồn](/scripts/auto_redirectLargestImageSrc.js) @@ -1031,7 +1111,7 @@
- 116. Hiện ảnh khi di chuột qua link + 124. Hiện ảnh khi di chuột qua link [Xem mã nguồn](/scripts/showImageOnHoverLink.js) @@ -1039,7 +1119,7 @@
- 117. Xoá theo dõi trong url + 125. Xoá theo dõi trong url [Xem mã nguồn](/scripts/remove_tracking_in_url.js) @@ -1052,7 +1132,7 @@
- 118. Không tắt trình duyệt khi tắt tab cuối + 126. Không tắt trình duyệt khi tắt tab cuối [Xem mã nguồn](/scripts/prevent_closeBrowser_lastTab.js) @@ -1061,7 +1141,7 @@
- 119. Chống lừa đảo + 127. Chống lừa đảo [Xem mã nguồn](/scripts/chongLuaDao.js) @@ -1073,7 +1153,7 @@
- 120. Rút gọn link + 128. Rút gọn link [Xem mã nguồn](/scripts/shortenURL.js) @@ -1081,7 +1161,7 @@
- 121. Giải mã link rút gọn + 129. Giải mã link rút gọn [Xem mã nguồn](/scripts/unshorten.js) @@ -1089,7 +1169,7 @@
- 122. Tạo tin nhắn tàng hình + 130. Tạo tin nhắn tàng hình [Xem mã nguồn](/scripts/createInvisibleText.js) @@ -1099,7 +1179,7 @@ --- Tự động ---
- 123. In web ra PDF + 131. In web ra PDF [Xem mã nguồn](/scripts/webToPDF.js) @@ -1107,7 +1187,7 @@
- 124. Chụp ảnh toàn bộ web + 132. Chụp ảnh toàn bộ web [Xem mã nguồn](/scripts/screenshotFullPage.js) @@ -1115,7 +1195,7 @@
- 125. Chụp ảnh web + 133. Chụp ảnh web [Xem mã nguồn](/scripts/screenshotVisiblePage.js) @@ -1123,7 +1203,7 @@
- 126. Cuộn trang xuống cuối cùng + 134. Cuộn trang xuống cuối cùng [Xem mã nguồn](/scripts/scrollToVeryEnd.js) @@ -1131,7 +1211,7 @@
- 127. Trích xuất mọi emails từ trang web + 135. Trích xuất mọi emails từ trang web [Xem mã nguồn](/scripts/getAllEmailsInWeb.js) @@ -1139,7 +1219,7 @@
- 128. Bật/Tắt Hack game T-Rex Dino + 136. Bật/Tắt Hack game T-Rex Dino [Xem mã nguồn](/scripts/dino_hack.js) @@ -1147,7 +1227,7 @@
- 129. Tạo mật khẩu cho trang web + 137. Tạo mật khẩu cho trang web [Xem mã nguồn](/scripts/passwordGenerator.js) @@ -1157,7 +1237,7 @@ --- Công cụ ---
- 130. Chữ sang QRCode + 138. Chữ sang QRCode [Xem mã nguồn](/scripts/textToQrCode.js) @@ -1165,7 +1245,7 @@
- 131. Văn bản thành Giọng nói (j2team) + 139. Văn bản thành Giọng nói (j2team) [Xem mã nguồn](/scripts/textToSpeech.js) @@ -1173,7 +1253,7 @@
- 132. Thay đổi đầu ra âm thanh + 140. Thay đổi đầu ra âm thanh [Xem mã nguồn](/scripts/changeAudioOutput.js) @@ -1181,7 +1261,7 @@
- 133. Send - Chia sẻ file nhanh + 141. Send - Chia sẻ file nhanh [Xem mã nguồn](/scripts/send_shareFiles.js) @@ -1189,7 +1269,7 @@
- 134. Vuiz - Tạo logo WAP online + 142. Vuiz - Tạo logo WAP online [Xem mã nguồn](/scripts/vuiz_createLogo.js) @@ -1197,7 +1277,7 @@
- 135. Phân tích hiệu suất + 143. Phân tích hiệu suất [Xem mã nguồn](/scripts/performanceAnalyzer.js) @@ -1205,7 +1285,7 @@
- 136. IT Tools - Vì tương lai Developer + 144. IT Tools - Vì tương lai Developer [Xem mã nguồn](/scripts/recommend_ItTools.js) @@ -1213,7 +1293,7 @@
- 137. CopyIcon - emoji, icon, svg miễn phí + 145. CopyIcon - emoji, icon, svg miễn phí [Xem mã nguồn](/scripts/recommend_copyicon.js) @@ -1221,7 +1301,7 @@
- 138. Beautify Tools + 146. Beautify Tools [Xem mã nguồn](/scripts/recommend_beautifytools.js) @@ -1242,7 +1322,7 @@ --- Github ---
- 139. Github - Đi tới commit bất kỳ + 147. Github - Đi tới commit bất kỳ [Xem mã nguồn](/scripts/github_goToAnyCommit.js) @@ -1250,7 +1330,7 @@
- 140. Github - xem trước file HTML + 148. Github - xem trước file HTML [Xem mã nguồn](/scripts/github_HTMLPreview.js) @@ -1258,7 +1338,7 @@
- 141. Github - Mở repo pages + 149. Github - Mở repo pages [Xem mã nguồn](/scripts/github_openRepoPages.js) @@ -1268,7 +1348,7 @@
- 142. Github - Mở repo trong github.dev + 150. Github - Mở repo trong github.dev [Xem mã nguồn](/scripts/githubdev.js) @@ -1276,7 +1356,7 @@
- 143. Github - Mở repo trong github1s.com + 151. Github - Mở repo trong github1s.com [Xem mã nguồn](/scripts/github1s.js) @@ -1284,7 +1364,7 @@
- 144. Cloc - đếm số dòng code + 152. Cloc - đếm số dòng code [Xem mã nguồn](/scripts/recommend_cloc.js) @@ -1294,7 +1374,7 @@
- 145. Refined GitHub + 153. Refined GitHub [Xem mã nguồn](/scripts/recommend_refined_github.js) @@ -1304,7 +1384,7 @@ --- Mua sắm ---
- 146. Shopee - Loại hàng mua nhiều nhất + 154. Shopee - Loại hàng mua nhiều nhất [Xem mã nguồn](/scripts/shopee_topVariation.js) @@ -1314,7 +1394,7 @@
- 147. Shopee - Thống kê chi tiêu + 155. Shopee - Thống kê chi tiêu [Xem mã nguồn](/scripts/shopee_totalSpendMoney.js) @@ -1322,7 +1402,7 @@
- 148. Shopee - Xuất lịch sử đơn hàng (Excel) + 156. Shopee - Xuất lịch sử đơn hàng (Excel) [Xem mã nguồn](/scripts/shopee_totalSpendMoney_excel.js) @@ -1330,7 +1410,7 @@
- 149. Tiki - Đã mua bao nhiêu tiền? + 157. Tiki - Đã mua bao nhiêu tiền? [Xem mã nguồn](/scripts/tiki_totalSpendMoney.js) @@ -1338,7 +1418,7 @@
- 150. Beecost + 158. Beecost [Xem mã nguồn](/scripts/recommend_Beecost.js) @@ -1348,7 +1428,7 @@ --- PDF ---
- 151. FastDoc - Chuyển PDF/Ảnh sang Word/Excel + 159. FastDoc - Chuyển PDF/Ảnh sang Word/Excel [Xem mã nguồn](/scripts/recommend_fastDoc.js) @@ -1356,7 +1436,7 @@
- 152. SmartPDF - Công cụ cho PDF + 160. SmartPDF - Công cụ cho PDF [Xem mã nguồn](/scripts/recommend_smartPDF.js) @@ -1364,7 +1444,7 @@
- 153. PDF Stuffs - Công cụ PDF + 161. PDF Stuffs - Công cụ PDF [Xem mã nguồn](/scripts/recommend_pdfstuffs.js) @@ -1376,7 +1456,7 @@ --- Mở khoá web ---
- 154. Hack Duck race + 162. Hack Duck race [Xem mã nguồn](/scripts/duckRace_cheat.js) @@ -1386,7 +1466,7 @@
- 155. Hack Wheel of Names + 163. Hack Wheel of Names [Xem mã nguồn](/scripts/wheelOfNames_hack.js) @@ -1394,7 +1474,7 @@
- 156. Đọc bài viết medium full + 164. Đọc bài viết medium full [Xem mã nguồn](/scripts/medium_readFullArticle.js) @@ -1402,7 +1482,7 @@
- 157. Medium - Fix font Tiếng Việt + 165. Medium - Fix font Tiếng Việt [Xem mã nguồn](/scripts/medium_fixVietnameseFont.js) @@ -1414,7 +1494,7 @@
- 158. Fireship - Mở khoá PRO + 166. Fireship - Mở khoá PRO [Xem mã nguồn](/scripts/fireship_vip.js) @@ -1422,7 +1502,7 @@
- 159. Studocu - Xem miễn phí VIP + 167. Studocu - Xem miễn phí VIP [Xem mã nguồn](/scripts/studocu_bypassPreview.js) @@ -1430,7 +1510,7 @@
- 160. Scribd - Xem miễn phí VIP + 168. Scribd - Xem miễn phí VIP [Xem mã nguồn](/scripts/scribd_bypassPreview.js) @@ -1438,17 +1518,27 @@
- 161. Studyphim - Xem miễn phí + 169. Studyphim - Xem miễn phí [Xem mã nguồn](/scripts/studyphim_unlimited.js) Xem phim miễn phí trên Studyphim không cần đăng nhập +
+
+ 170. Bypass Learn Anything + + [Xem mã nguồn](/scripts/bypass_learnAnything.js) + + Xem nội dung web learn-anything.xyz không cần đăng ký member + + ![](/scripts/bypass_LearnAnything.png) +
--- Mở khoá chức năng ---
- 162. Bật/Tắt cho phép sao chép + 171. Bật/Tắt cho phép sao chép [Xem mã nguồn](/scripts/simpleAllowCopy.js) @@ -1462,7 +1552,7 @@
- 163. Phát hiện ký tự ẩn (Zero-Width) + 172. Phát hiện ký tự ẩn (Zero-Width) [Xem mã nguồn](/scripts/detect_zeroWidthCharacters.js) @@ -1470,7 +1560,7 @@
- 164. Nhúng script vào trang web + 173. Nhúng script vào trang web [Xem mã nguồn](/scripts/injectScriptToWebsite.js) @@ -1478,7 +1568,7 @@
- 165. Hiện các thành phần web bị ẩn + 174. Hiện các thành phần web bị ẩn [Xem mã nguồn](/scripts/showHiddenFields.js) @@ -1486,7 +1576,7 @@
- 166. Xem cookies + 175. Xem cookies [Xem mã nguồn](/scripts/viewCookies.js) @@ -1494,7 +1584,7 @@
- 167. Xoá Cookies + 176. Xoá Cookies [Xem mã nguồn](/scripts/removeCookies.js) @@ -1504,7 +1594,7 @@ --- Khác ---
- 168. Tăng tốc tối đa trình duyệt + 177. Tăng tốc tối đa trình duyệt [Xem mã nguồn](/scripts/recommend_chromeFlags.js) @@ -1512,7 +1602,7 @@
- 169. Xem mật khẩu wifi đã lưu + 178. Xem mật khẩu wifi đã lưu [Xem mã nguồn](/scripts/recommend_viewSavedWifiPass.js) @@ -1520,7 +1610,7 @@
- 170. Leak check - lộ mật khẩu email? + 179. Leak check - lộ mật khẩu email? [Xem mã nguồn](/scripts/recommend_leakCheck.js) @@ -1532,7 +1622,7 @@ --- Nổi bật ---
- 171. Chế độ tối cho PDF + 180. Chế độ tối cho PDF [Xem mã nguồn](/scripts/darkModePDF.js) @@ -1540,7 +1630,7 @@
- 172. Bật/tắt chế độ chỉnh sửa website + 181. Bật/tắt chế độ chỉnh sửa website [Xem mã nguồn](/scripts/toggleEditPage.js) @@ -1548,7 +1638,7 @@
- 173. Hiện thị FPS + 182. Hiện thị FPS [Xem mã nguồn](/scripts/showFPS.js) @@ -1556,7 +1646,7 @@
- 174. Hiện thị FPS - ver 2 + 183. Hiện thị FPS - ver 2 [Xem mã nguồn](/scripts/showFps_v2.js) @@ -1564,7 +1654,7 @@
- 175. Ẩn/Hiện ô nhập mật khẩu + 184. Ẩn/Hiện ô nhập mật khẩu [Xem mã nguồn](/scripts/toggle_passwordField.js) @@ -1572,7 +1662,7 @@
- 176. Dark reader + 185. Dark reader [Xem mã nguồn](/scripts/recommend_DarkReader.js) @@ -1580,7 +1670,7 @@
- 177. CSS Portal - Nâng trình CSS + 186. CSS Portal - Nâng trình CSS [Xem mã nguồn](/scripts/recommend_cssportal.js) @@ -1588,7 +1678,7 @@
- 178. CSS Loaders - 600+ css loading + 187. CSS Loaders - 600+ css loading [Xem mã nguồn](/scripts/recommend_cssloaders.js) @@ -1596,7 +1686,7 @@
- 179. UIverse - Tổng hợp code UI xịn + 188. UIverse - Tổng hợp code UI xịn [Xem mã nguồn](/scripts/recommend_uiverse.js) @@ -1606,7 +1696,7 @@ --- Xem ---
- 180. Font Rendering - font chữ dễ nhìn + 189. Font Rendering - font chữ dễ nhìn [Xem mã nguồn](/scripts/recommend_fontRendering.js) @@ -1614,7 +1704,7 @@
- 181. Kiểm tra font chữ + 190. Kiểm tra font chữ [Xem mã nguồn](/scripts/whatFont.js) @@ -1622,7 +1712,7 @@
- 182. Xem tất cả tất cả javascript events + 191. Xem tất cả tất cả javascript events [Xem mã nguồn](/scripts/visualEvent.js) @@ -1630,7 +1720,7 @@
- 183. Xem mọi hình ảnh có trong website + 192. Xem mọi hình ảnh có trong website [Xem mã nguồn](/scripts/listAllImagesInWeb.js) @@ -1638,7 +1728,7 @@
- 184. Xem tất cả link + 193. Xem tất cả link [Xem mã nguồn](/scripts/viewAllLinks.js) @@ -1646,7 +1736,7 @@
- 185. Xem tất cả scripts + 194. Xem tất cả scripts [Xem mã nguồn](/scripts/viewScriptsUsed.js) @@ -1654,7 +1744,7 @@
- 186. Xem tất cả stylesheet + 195. Xem tất cả stylesheet [Xem mã nguồn](/scripts/viewStylesUsed.js) @@ -1662,7 +1752,7 @@
- 187. Trình kiểm tra css cục bộ + 196. Trình kiểm tra css cục bộ [Xem mã nguồn](/scripts/cssSelectorViewer.js) @@ -1672,7 +1762,7 @@ --- Xoá ---
- 188. Xoá màu website + 197. Xoá màu website [Xem mã nguồn](/scripts/removeColours.js) @@ -1680,7 +1770,7 @@
- 189. Xoá stylesheet + 198. Xoá stylesheet [Xem mã nguồn](/scripts/removeStylesheet.js) @@ -1688,7 +1778,7 @@
- 190. Xoá mọi hình ảnh + 199. Xoá mọi hình ảnh [Xem mã nguồn](/scripts/removeImages.js) @@ -1696,7 +1786,7 @@
- 191. Xoá mọi iframe/embed + 200. Xoá mọi iframe/embed [Xem mã nguồn](/scripts/removeBloat.js) @@ -1706,7 +1796,7 @@ --- Bảng ---
- 192. Thêm sắp xếp cho bảng + 201. Thêm sắp xếp cho bảng [Xem mã nguồn](/scripts/table_addSortTable.js) @@ -1714,7 +1804,7 @@
- 193. Thêm cột số thứ tự + 202. Thêm cột số thứ tự [Xem mã nguồn](/scripts/table_addNumberColumn.js) @@ -1722,7 +1812,7 @@
- 194. Đổi chỗ hàng và cột + 203. Đổi chỗ hàng và cột [Xem mã nguồn](/scripts/table_swapRowAndColumn.js) @@ -1732,7 +1822,7 @@ --- Khác ---
- 195. Tô màu cho link + 204. Tô màu cho link [Xem mã nguồn](/scripts/internalOrExternalLink.js) @@ -1742,7 +1832,7 @@
- 196. Lấy kích thước trang web + 205. Lấy kích thước trang web [Xem mã nguồn](/scripts/getWindowSize.js) @@ -1750,7 +1840,7 @@
- 197. Hiệu ứng tuyết rơi + 206. Hiệu ứng tuyết rơi [Xem mã nguồn](/scripts/letItSnow.js) diff --git a/popup/tabs.js b/popup/tabs.js index 625f7f60..9dc1a71a 100644 --- a/popup/tabs.js +++ b/popup/tabs.js @@ -38,6 +38,51 @@ const tabs = [ scripts: [ // s._test, // s._ufs_statistic, + { + id: "recommend_theresanaiforthat", + icon: "https://theresanaiforthat.com/favicon.ico", + name: { + en: "There's an AI for that", + vi: "There's an AI for that - Tìm AI", + }, + description: { + en: "Collection of thousand of AI tools. Easy to search by category", + vi: "Tổng hợp hàng ngàn công cụ AI hiện có. Dễ dàng tìm kiếm theo chủ đề", + }, + popupScript: { + onClick: () => window.open("https://theresanaiforthat.com/"), + }, + }, + { + id: "recommend_timeis", + icon: "https://time.is/favicon.ico", + name: { + en: "Time.is - Check your time", + vi: "Time.is - Kiểm tra thời gian", + }, + description: { + en: "Exact time for any time zone.", + vi: "Đồng hồ chính xác nhất. Kiểm tra đồng hồ trên máy của bạn nhanh hay chậm.", + }, + popupScript: { + onClick: () => window.open("https://time.is/"), + }, + }, + { + id: "recommend_googleTrending", + icon: "https://www.gstatic.com/trends/favicon.ico", + name: { + en: "Google trending - See what trending now", + vi: "Google trending - Nội dung nổi bật", + }, + description: { + en: "See what people are searching on Google. Top treding every day, realtime.", + vi: "Xem mọi người đang tìm gì trên google. Thống kê từng ngày, thời gian thực.", + }, + popupScript: { + onClick: () => window.open("https://trends.google.com/"), + }, + }, s.similarWeb, s.similarWeb_bypassLimit, s.search_sharedAccount, @@ -237,7 +282,6 @@ const tabs = [ s.studocu_downs, s.scribd_downloadDocuments, s.tailieu_vn, - { id: "recommend_docsdownloader", icon: "https://docsdownloader.com/assets/img/android-icon-192x192.png", diff --git a/scripts/helpers/utils.js b/scripts/helpers/utils.js index acb7b7b7..883de28f 100644 --- a/scripts/helpers/utils.js +++ b/scripts/helpers/utils.js @@ -142,7 +142,7 @@ export function runFunc(fnPath = "", params = [], global = {}) { export async function trackEvent(scriptId) { console.log("trackEvent", scriptId, version); - return; + // return; try { let res = await fetch( // "http://localhost:3000/count", diff --git a/working_note.md b/working_note.md index 64682214..3a4891ac 100644 --- a/working_note.md +++ b/working_note.md @@ -8,11 +8,11 @@ - [ ] youtube reverse api??? -- [ ] add this beautiful video downloader tool +- [x] add this beautiful video downloader tool - [ ] savefile using new api -- [ ] hotfix - use chrome.downloads instead of library +- [x] hotfix - use chrome.downloads instead of library => can not apply to all scripts - [x] get fb profile pic -> dont know now cuid was generated