Greasy Fork is available in English.
用户登录后进入微博主页,获取超级话题并自动签到
// ==UserScript== // @name 微博超话自动签到 // @description 用户登录后进入微博主页,获取超级话题并自动签到 // @homepageURL https://github.com/Deuscx/WB_SIGN_EXT // @supportURL https://github.com/Deuscx/WB_SIGN_EXT/issues // @grant none // @version 2.0.4 // @author deus // @match https://weibo.com/* // @match https://www.weibo.com/* // @require https://cdn.jsdelivr.net/npm/@violentmonkey/dom@1 // @require https://cdn.jsdelivr.net/npm/@violentmonkey/[email protected] // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js // @namespace https://deuscx.github.io/ // ==/UserScript== (function() { "use strict"; var e = ".configContainer{display:flex;flex-direction:column;position:fixed;--bg-opacity:1;background-color:#fff;background-color:rgba(255,255,255,var(--bg-opacity));z-index:10;border-radius:.25rem;border-width:1px;--border-opacity:1;border-color:#cbd5e0;border-color:rgba(203,213,224,var(--border-opacity));padding:.75rem .5rem;max-width:190px;bottom:80px;right:0;transform:translateX(100%);transition-duration:.5s;transition-timing-function:cubic-bezier(.22,1,.36,1);transition-property:transform}.configContainer .cItem{font-size:.875rem;display:flex;justify-content:space-between;cursor:pointer}.configContainer .cItem .des{--text-opacity:1;color:#718096;color:rgba(113,128,150,var(--text-opacity))}#TIMEOUT{-webkit-appearance:none;-moz-appearance:none;appearance:none;display:inline-block;width:60px}.configContainer .action{padding-top:.5rem;padding-bottom:.5rem;border-radius:.25rem;background-color:#fff;cursor:pointer;position:absolute;top:50%;left:0;transform:translate3d(-100%,-50%,0)}.configContainer .action:hover{color:#ccc}.active{transform:translateX(0)}"; const t = (new Date).getTimezoneOffset() + 480; const n = Date.now; const isNewDay = e => { if (!e) return true; const n = new Date(e); n.setMinutes(n.getMinutes() + t); n.setHours(0, 0, 0, 0); const o = new Date; o.setMinutes(n.getMinutes() + t); return o - n > 864e5; }; const o = function() { const set = function(e, t) { localStorage.setItem(e, JSON.stringify(t)); }; const get = function(e) { const t = localStorage.getItem(e); try { return JSON.parse(t); } catch (e) { return t; } }; const remove = function(e) { localStorage.removeItem(e); }; const has = function(e) { return Reflect.has(localStorage, e); }; return { set: set, get: get, remove: remove, has: has }; }(); const r = (e => () => e++)(0); const a = "WB"; const c = `${a}_SIGNED_ARR`; const s = "WB_CONFIG"; const i = { SUCCESS: "success", ERROR: "error", INFO: "info", WARNING: "warning" }; let u = o.get(s); function ConfigPanel() { const handleAutoSign = e => { const t = e.target.checked; const n = Object.assign({}, u, { AUTO_SIGN: t }); u = n; o.set(s, u); }; const handleShowToast = e => { const t = e.target.checked; const n = Object.assign({}, u, { SHOW_TOAST: t }); u = n; o.set(s, u); }; const handleTimeout = e => { const t = e.target.value; const n = Object.assign({}, u, { TIMEOUT: t }); u = n; o.set(s, u); }; const toggleClassList = () => { document.querySelector(".configContainer").classList.toggle("active"); }; return VM.createElement(VM.Fragment, null, VM.createElement("div", { className: "configContainer" }, VM.createElement("label", { htmlFor: "AUTO_SIGN", className: "cItem" }, VM.createElement("span", { className: "des" }, "自动签到"), VM.createElement("input", { id: "AUTO_SIGN", type: "checkbox", onInput: handleAutoSign, checked: u.AUTO_SIGN })), VM.createElement("label", { htmlFor: "SHOW_TOAST", className: "cItem" }, VM.createElement("span", { className: "des" }, "是否展示气泡"), VM.createElement("input", { id: "SHOW_TOAST", type: "checkbox", onInput: handleShowToast, checked: u.SHOW_TOAST })), VM.createElement("label", { htmlFor: "TIMEOUT", className: "cItem" }, VM.createElement("span", { className: "des" }, "气泡展示时间"), VM.createElement("input", { id: "TIMEOUT", type: "number", onInput: handleTimeout, min: "0", value: parseInt(u.TIMEOUT, 10), placeholder: "单位为毫秒" })), VM.createElement("div", { className: "action", onClick: toggleClassList }, "收放")), VM.createElement("style", null, e)); } var l = ".msgContainer{position:fixed;background-color:initial;top:4rem;right:40px}@keyframes slide-in-right{0%{transform:translateX(1000px);opacity:0}to{transform:translateX(0);opacity:1}}@keyframes slide-out-right{0%{transform:translateX(0);opacity:1}to{transform:translateX(1000px);opacity:0}}.removing{animation:slide-out-right .5s cubic-bezier(.55,.085,.68,.53) both}.toastItem{background-color:#fff;background-color:rgba(255,255,255,var(--bg-opacity));border-width:1px;--border-opacity:1;border-color:#cbd5e0;border-color:rgba(203,213,224,var(--border-opacity));border-radius:.375rem;max-width:20rem;--text-opacity:1;color:#fff;color:rgba(255,255,255,var(--text-opacity));z-index:10;padding:1rem 1.5rem;cursor:pointer;--bg-opacity:1;background-color:#3182ce;background-color:rgba(49,130,206,var(--bg-opacity));opacity:.8;margin-bottom:.5rem;animation:slide-in-right .5s cubic-bezier(.25,.46,.45,.94) both}.toast-info{--bg-opacity:1;background-color:#63b3ed;background-color:rgba(99,179,237,var(--bg-opacity))}.toast-default{--bg-opacity:1;background-color:#3182ce;background-color:rgba(49,130,206,var(--bg-opacity))}.toast-success{--bg-opacity:1;background-color:#48bb78;background-color:rgba(72,187,120,var(--bg-opacity))}.toast-error{background-color:#ff5252}.toast-warning{--bg-opacity:1;background-color:#f6e05e;background-color:rgba(246,224,94,var(--bg-opacity))}"; const m = 8; let d = 0; const innerToast = e => { const {content: t, type: n, timeout: o} = e; function remove() { const t = document.querySelector(`[data-tid='${e.id}']`); t.classList.add("removing"); requestAnimationFrame((() => { t.parentNode.removeChild(t); d--; })); } o && setTimeout((() => { remove(); }), o); return VM.createElement(VM.Fragment, null, VM.createElement("div", { "data-tid": e.id, className: `toastItem toast-${n}`, onClick: remove }, t)); }; const ToastContainer = () => VM.createElement("div", { className: "msgContainer" }, VM.createElement("style", null, l)); const g = { type: i.INFO, timeout: 5e3 }; const toastFactory = () => { const e = ToastContainer(); const t = document.body.appendChild(e); const toast = (e, n) => { if (!o.get(s).SHOW_TOAST) return; const a = Object.assign({}, g, { id: r() }, n, { content: e }); if (d < m) { d++; t.appendChild(innerToast(a)); } }; toast.success = (e, t) => toast(e, Object.assign({}, t, { type: i.SUCCESS })); toast.error = (e, t) => toast(e, Object.assign({}, t, { type: i.ERROR })); toast.info = (e, t) => toast(e, Object.assign({}, t, { type: i.INFO })); toast.warn = (e, t) => toast(e, Object.assign({}, t, { type: i.WARNING })); return toast; }; const p = toastFactory(); const f = { AUTO_SIGN: true, SHOW_TOAST: true, TIMEOUT: 1e3 }; const b = axios.create({ baseURL: "https://weibo.com/", timeout: 1e3 * 5 }); b.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded"; b.interceptors.request.use((e => e), (e => Promise.error(e))); b.interceptors.response.use((e => e.status === 200 ? Promise.resolve(e) : Promise.reject(e)), (e => { const {response: t} = e; if (t) { console.log("发送请求失败", t); return Promise.reject(t); } if (!window.navigator.onLine) console.error("断网"); else return Promise.reject(e); })); class BaseFeature { constructor({name: e}) { this.launch = () => {}; this.name = e; } get store() { const e = o.get(this.name); if (e) return e; o.set(this.name, void 0); return; } set store(e) { o.set(this.name, e); } init() { return new Promise(((e, t) => { try { this.launch(); e(this); } catch (e) { console.log(`run ${this.name} error`); t(e); } })); } } function isCheck() { return o.get("isCheck") || false; } const h = o.get("lastCheck"); const signInterestAPI = e => b({ url: "p/aj/general/button", params: { ajwvr: 6, api: "http://i.huati.weibo.com/aj/super/checkin", texta: encodeURI("签到"), textb: encodeURI("已签到"), status: 0, id: e, __rnd: (new Date).getTime() } }); let y = o.get(c) || []; const signInterest = ({id: e, name: t}) => new Promise(((r, a) => { signInterestAPI(e).then((e => { const {data: s} = e; if (s.code === "100000") { window.toast.success(`[${t}签到成功]${s.msg} ---${s.data.alert_title}`); o.set("lastCheck", n()); y.push(t); y = Array.from(new Set(y)); o.set(c, y); } else { window.toast.warn(`[${t}超话签到]${s.msg}`); if (s.code !== 382004) a("error"); else { o.set("lastCheck", n()); y.push(t); y = Array.from(new Set(y)); o.set(c, y); } } r(); }), (e => { a(e); window.toast.error(`[${t}超话签到]签到失败,请检查网络`); })); })); function delay(e) { return new Promise((t => setTimeout(t, e))); } function getInterestNameAId(e = 1) { return new Promise(((t, n) => { b({ url: `ajax/profile/topicContent?tabid=231093_-_chaohua&page=${e}` }).then((o => { const {data: {data: r, ok: a}} = o; if (a !== 1) n({ err: "获取关注超话失败", data: r }); const c = r.list; const s = r.max_page; function extractId(e) { return e.slice(5); } const i = c.map((({oid: e, topic_name: t}) => ({ id: extractId(e), name: t }))); if (e < s) getInterestNameAId(e + 1).then((e => { t(i.concat(e)); })); else t(i); }), (e => { console.error(`[${a}]`, e); n("获取hash失败"); })); })); } class PromiseQueue { constructor({concurrency: e = 1, timeout: t = 0} = {}) { this.queue = []; this.running = 0; this.concurrency = e; this.timeout = t; } add(e) { return new Promise(((t, n) => { const wrappedFn = async () => { try { const n = e(); await delay(this.timeout); const o = await n; t(o); } catch (e) { n(e); } finally { this.running--; this.processQueue(); } }; this.queue.push(wrappedFn); this.processQueue(); })); } processQueue() { while (this.running < this.concurrency && this.queue.length > 0) { this.running++; const e = this.queue.shift(); e(); } } } class Interest extends BaseFeature { constructor() { super({ name: s }); this.launch = async () => { const e = super.store; if (!e.AUTO_SIGN) return; if (isCheck() && !isNewDay(h)) { window.toast.info("今日已签到"); return; } if (isNewDay(h)) { o.remove(c); o.set("isCheck", false); } let t = await getInterestNameAId(); const n = o.get(c); if (n && n.length) t = t.filter((e => !n.includes(e.name))); const r = new PromiseQueue({ concurrency: 1, timeout: 500 }); for (const {name: e, id: n} of t) await r.add((() => signInterest({ id: n, name: e }))); o.set("isCheck", true); }; } run() { this.init().then((e => {})); } } var w = new Interest; function initConfig() { if (!o.get(s)) o.set(s, f); } function initDOM() { return new Promise(((e, t) => { try { const e = ConfigPanel(); document.body.appendChild(e); } catch (e) { throw new Error("初始化DOM失败"); } })); } function BaseInit() { initConfig(); window.toast = p; } function OtherInit() { initDOM(); } function main() { BaseInit(); OtherInit(); w.run(); } main(); })();