您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
用麻将脸回应泥潭吧!
当前为
// ==UserScript== // @name S1 Reaction 帖子回应服务 // @namespace https://github.com/rkanuj/s1-reaction // @version 0.0.1 // @author rkanuj // @description 用麻将脸回应泥潭吧! // @license MIT // @icon https://bbs.saraba1st.com/favicon.ico // @match https://*.saraba1st.com/2b/thread-* // @match https://*.saraba1st.com/2b/forum.php?*tid=* // @match https://*.saraba1st.com/2b/space-* // @match https://*.stage1st.com/2b/thread-* // @match https://*.stage1st.com/2b/forum.php?*tid=* // @match https://*.stage1st.com/2b/space-* // @grant GM_addStyle // ==/UserScript== (e=>{if(typeof GM_addStyle=="function"){GM_addStyle(e);return}const t=document.createElement("style");t.textContent=e,document.head.append(t)})(" .login.svelte-18l8ze5 .re-login-btn.svelte-18l8ze5.svelte-18l8ze5{width:240px}.login.svelte-18l8ze5 .re-login-btn.svelte-18l8ze5.svelte-18l8ze5:not(:last-child){margin-bottom:8px}.login.svelte-18l8ze5 .login-form.svelte-18l8ze5.svelte-18l8ze5{display:flex;flex-direction:column;width:240px}.login.svelte-18l8ze5 .login-form.svelte-18l8ze5>.svelte-18l8ze5:not(:last-child){margin-bottom:8px}.login.svelte-18l8ze5 .login-form.svelte-18l8ze5>input.svelte-18l8ze5,.login.svelte-18l8ze5 .login-form select.svelte-18l8ze5.svelte-18l8ze5{padding:4px;border:1px solid lightgray}.login.svelte-18l8ze5 .login-form .tips.svelte-18l8ze5.svelte-18l8ze5{font-size:.8em;color:#696969}.login.svelte-18l8ze5 .login-form .error-message.svelte-18l8ze5.svelte-18l8ze5{font-size:.8em;color:red}.modal-dialog.svelte-1pj07cj.svelte-1pj07cj{position:fixed;z-index:1001;top:50%;left:50%;overflow:auto;margin:0;padding:0;transform:translate(-50%,-50%);border:none;border-radius:8px;box-shadow:0 0 20px #696969}.modal-dialog.only-login-form.svelte-1pj07cj.svelte-1pj07cj{width:270px}.modal-dialog.svelte-1pj07cj.svelte-1pj07cj:not(.only-login-form){width:500px;height:80vh;max-height:580px}.modal-dialog.svelte-1pj07cj .dialog-header.svelte-1pj07cj{position:sticky;top:0;align-content:center;height:40px;padding:0 12px;border-bottom:1px solid lightgray;background-color:#fff}.modal-dialog.svelte-1pj07cj .dialog-header .dialog-title.svelte-1pj07cj{font-size:16px}.modal-dialog.svelte-1pj07cj .dialog-header .close-btn.svelte-1pj07cj{padding:0;cursor:pointer;border:none;background:none;font-size:12px;font-family:sans-serif;font-size:24px;position:absolute;top:4px;right:16px;transition:color .3s ease;color:gray}.modal-dialog.svelte-1pj07cj .dialog-header .close-btn.svelte-1pj07cj:hover{color:#000}.modal-dialog.svelte-1pj07cj .dialog-content.svelte-1pj07cj{display:flex;align-items:center;flex-direction:column;padding:12px}.modal-backdrop.svelte-1pj07cj.svelte-1pj07cj{position:fixed;z-index:1000;top:0;left:0;width:100%;height:100%;background:#0000004d}.smiles.svelte-5sdydp .smiles-type-btn.svelte-5sdydp{cursor:pointer;border:none;background:none;font-size:12px;font-family:sans-serif;padding:4px;border-top:1px dashed #022c80;border-right:1px dashed #022c80;background-color:buttonface}.smiles.svelte-5sdydp .smiles-type-btn.svelte-5sdydp:first-child{border-left:1px dashed #022c80}.smiles.svelte-5sdydp .smiles-type-btn.active.svelte-5sdydp{background-color:#fff}.smiles.svelte-5sdydp .smiles-table.svelte-5sdydp{overflow:auto;width:465px;height:180px;border:1px dashed #022c80}.smiles.svelte-5sdydp .smiles-table td.svelte-5sdydp{padding:2px}.smiles.svelte-5sdydp .smiles-table td img.svelte-5sdydp{width:32px}.user-info.svelte-12lgkya.svelte-12lgkya.svelte-12lgkya{font-size:14px;width:100%}.user-info.svelte-12lgkya .user.svelte-12lgkya.svelte-12lgkya:not(:last-child){margin-bottom:8px;padding-bottom:8px;border-bottom:1px dashed #022c80}.user-info.svelte-12lgkya .user.svelte-12lgkya>.svelte-12lgkya:not(:last-child){margin-bottom:8px}.user-info.svelte-12lgkya .user .remove-user-btn.svelte-12lgkya.svelte-12lgkya{padding:0;cursor:pointer;border:none;background:none;font-size:12px;font-family:sans-serif;font-weight:700;transition:color .3s ease;color:#ff4500}.user-info.svelte-12lgkya .user .remove-user-btn.svelte-12lgkya.svelte-12lgkya:hover{color:#8b0000}.user-info.svelte-12lgkya .user .token.svelte-12lgkya.svelte-12lgkya{color:#696969}.user-info.svelte-12lgkya .user .date.svelte-12lgkya.svelte-12lgkya{display:inline}.user-info.svelte-12lgkya .user .date.svelte-12lgkya>.svelte-12lgkya{color:green}.user-info.svelte-12lgkya .user .date.svelte-12lgkya>*.expired.svelte-12lgkya{color:red}.user-info.svelte-12lgkya .tips.svelte-12lgkya.svelte-12lgkya{font-size:.8em;color:#696969}.modal.svelte-81eduz .dialog-content>*:not(:last-child){margin-bottom:12px}.reacts.svelte-1bychbn.svelte-1bychbn{font-size:14px;display:grid;padding:4px 8px 0 0;border:1px dashed #022c80;grid-template-columns:repeat(auto-fill,minmax(56px,1fr))}.reacts.svelte-1bychbn .react.svelte-1bychbn{position:relative;display:flex;align-items:center;flex-direction:column;justify-content:space-between;padding:4px}.reacts.svelte-1bychbn .react img.svelte-1bychbn{width:32px}table.plhin .po.hin{border-top:none}.action-btn.svelte-yychvz.svelte-yychvz{padding:0;cursor:pointer;border:none;background:none;font-size:12px;font-family:sans-serif;font-weight:700;position:absolute;top:0;right:0;transition:color .3s ease}.action-btn.remove-react-btn.svelte-yychvz.svelte-yychvz{color:#ff4500}.action-btn.remove-react-btn.svelte-yychvz.svelte-yychvz:hover{color:#8b0000}.action-btn.plus-react-btn.svelte-yychvz.svelte-yychvz{color:#32cd32}.action-btn.plus-react-btn.svelte-yychvz.svelte-yychvz:hover{color:#006400}.add-react.svelte-yychvz.svelte-yychvz{position:relative;align-content:center;padding:8px}.add-react.svelte-yychvz .add-react-btn.svelte-yychvz{cursor:pointer;border:none;background:none;font-size:12px;font-family:sans-serif;width:100%;padding:4px;transition:background-color .3s ease;border-radius:8px;background-color:#d1d9c1}.add-react.svelte-yychvz .add-react-btn.svelte-yychvz:hover{background-color:#c2cdb5}.add-react.svelte-yychvz .add-react-btn.svelte-yychvz:active{background-color:#c3c5ae} "); (function () { 'use strict'; var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; function noop() { } function safe_not_equal(a, b) { return a != a ? b == b : a !== b || a && typeof a === "object" || typeof a === "function"; } function subscribe(store, ...callbacks) { if (store == null) { for (const callback of callbacks) { callback(void 0); } return noop; } const unsub = store.subscribe(...callbacks); return unsub.unsubscribe ? () => unsub.unsubscribe() : unsub; } function get_store_value(store) { let value; subscribe(store, (_) => value = _)(); return value; } const PUBLIC_VERSION = "4"; if (typeof window !== "undefined") (window.__svelte || (window.__svelte = { v: /* @__PURE__ */ new Set() })).v.add(PUBLIC_VERSION); const BASE_PATH = "http://localhost".replace(/\/+$/, ""); class Configuration { constructor(configuration = {}) { this.configuration = configuration; } set config(configuration) { this.configuration = configuration; } get basePath() { return this.configuration.basePath != null ? this.configuration.basePath : BASE_PATH; } get fetchApi() { return this.configuration.fetchApi; } get middleware() { return this.configuration.middleware || []; } get queryParamsStringify() { return this.configuration.queryParamsStringify || querystring; } get username() { return this.configuration.username; } get password() { return this.configuration.password; } get apiKey() { const apiKey = this.configuration.apiKey; if (apiKey) { return typeof apiKey === "function" ? apiKey : () => apiKey; } return void 0; } get accessToken() { const accessToken = this.configuration.accessToken; if (accessToken) { return typeof accessToken === "function" ? accessToken : async () => accessToken; } return void 0; } get headers() { return this.configuration.headers; } get credentials() { return this.configuration.credentials; } } const DefaultConfig = new Configuration(); const _BaseAPI = class _BaseAPI { constructor(configuration = DefaultConfig) { __publicField(this, "middleware"); __publicField(this, "fetchApi", async (url, init) => { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { fetchParams = await middleware.pre({ fetch: this.fetchApi, ...fetchParams }) || fetchParams; } } let response = void 0; try { response = await (this.configuration.fetchApi || fetch)(fetchParams.url, fetchParams.init); } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { response = await middleware.onError({ fetch: this.fetchApi, url: fetchParams.url, init: fetchParams.init, error: e, response: response ? response.clone() : void 0 }) || response; } } if (response === void 0) { if (e instanceof Error) { throw new FetchError(e, "The request failed and the interceptors did not return an alternative response"); } else { throw e; } } } for (const middleware of this.middleware) { if (middleware.post) { response = await middleware.post({ fetch: this.fetchApi, url: fetchParams.url, init: fetchParams.init, response: response.clone() }) || response; } } return response; }); this.configuration = configuration; this.middleware = configuration.middleware; } withMiddleware(...middlewares) { const next = this.clone(); next.middleware = next.middleware.concat(...middlewares); return next; } withPreMiddleware(...preMiddlewares) { const middlewares = preMiddlewares.map((pre) => ({ pre })); return this.withMiddleware(...middlewares); } withPostMiddleware(...postMiddlewares) { const middlewares = postMiddlewares.map((post) => ({ post })); return this.withMiddleware(...middlewares); } /** * Check if the given MIME is a JSON MIME. * JSON MIME examples: * application/json * application/json; charset=UTF8 * APPLICATION/JSON * application/vnd.company+json * @param mime - MIME (Multipurpose Internet Mail Extensions) * @return True if the given MIME is JSON, false otherwise. */ isJsonMime(mime) { if (!mime) { return false; } return _BaseAPI.jsonRegex.test(mime); } async request(context, initOverrides) { const { url, init } = await this.createFetchParams(context, initOverrides); const response = await this.fetchApi(url, init); if (response && (response.status >= 200 && response.status < 300)) { return response; } throw new ResponseError(response, "Response returned an error code"); } async createFetchParams(context, initOverrides) { let url = this.configuration.basePath + context.path; if (context.query !== void 0 && Object.keys(context.query).length !== 0) { url += "?" + this.configuration.queryParamsStringify(context.query); } const headers = Object.assign({}, this.configuration.headers, context.headers); Object.keys(headers).forEach((key) => headers[key] === void 0 ? delete headers[key] : {}); const initOverrideFn = typeof initOverrides === "function" ? initOverrides : async () => initOverrides; const initParams = { method: context.method, headers, body: context.body, credentials: this.configuration.credentials }; const overriddenInit = { ...initParams, ...await initOverrideFn({ init: initParams, context }) }; let body; if (isFormData(overriddenInit.body) || overriddenInit.body instanceof URLSearchParams || isBlob(overriddenInit.body)) { body = overriddenInit.body; } else if (this.isJsonMime(headers["Content-Type"])) { body = JSON.stringify(overriddenInit.body); } else { body = overriddenInit.body; } const init = { ...overriddenInit, body }; return { url, init }; } /** * Create a shallow clone of `this` by constructing a new instance * and then shallow cloning data members. */ clone() { const constructor = this.constructor; const next = new constructor(this.configuration); next.middleware = this.middleware.slice(); return next; } }; __publicField(_BaseAPI, "jsonRegex", new RegExp("^(:?application/json|[^;/ ]+/[^;/ ]+[+]json)[ ]*(:?;.*)?$", "i")); let BaseAPI = _BaseAPI; function isBlob(value) { return typeof Blob !== "undefined" && value instanceof Blob; } function isFormData(value) { return typeof FormData !== "undefined" && value instanceof FormData; } class ResponseError extends Error { constructor(response, msg) { super(msg); __publicField(this, "name", "ResponseError"); this.response = response; } } class FetchError extends Error { constructor(cause, msg) { super(msg); __publicField(this, "name", "FetchError"); this.cause = cause; } } function querystring(params, prefix = "") { return Object.keys(params).map((key) => querystringSingleKey(key, params[key], prefix)).filter((part) => part.length > 0).join("&"); } function querystringSingleKey(key, value, keyPrefix = "") { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { const multiValue = value.map((singleValue) => encodeURIComponent(String(singleValue))).join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } if (value instanceof Set) { const valueAsArray = Array.from(value); return querystringSingleKey(key, valueAsArray, keyPrefix); } if (value instanceof Date) { return `${encodeURIComponent(fullKey)}=${encodeURIComponent(value.toISOString())}`; } if (value instanceof Object) { return querystring(value, fullKey); } return `${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`; } class JSONApiResponse { constructor(raw, transformer = (jsonValue) => jsonValue) { this.raw = raw; this.transformer = transformer; } async value() { return this.transformer(await this.raw.json()); } } function PostBanUserOrTokenRequestAdminAuthPayloadFromJSON(json) { return PostBanUserOrTokenRequestAdminAuthPayloadFromJSONTyped(json); } function PostBanUserOrTokenRequestAdminAuthPayloadFromJSONTyped(json, ignoreDiscriminator) { if (json == null) { return json; } return { "uid": json["uid"], "iat": json["iat"], "exp": json["exp"] }; } function PostBanUserOrTokenRequestAdminAuthPayloadToJSON(value) { if (value == null) { return value; } return { "uid": value["uid"], "iat": value["iat"], "exp": value["exp"] }; } function PostBanUserOrTokenRequestAdminAuthFromJSON(json) { return PostBanUserOrTokenRequestAdminAuthFromJSONTyped(json); } function PostBanUserOrTokenRequestAdminAuthFromJSONTyped(json, ignoreDiscriminator) { if (json == null) { return json; } return { "token": json["token"], "payload": PostBanUserOrTokenRequestAdminAuthPayloadFromJSON(json["payload"]) }; } function PostBanUserOrTokenRequestAdminAuthToJSON(value) { if (value == null) { return value; } return { "token": value["token"], "payload": PostBanUserOrTokenRequestAdminAuthPayloadToJSON(value["payload"]) }; } function PostGenerateToken200ResponseFromJSON(json) { return PostGenerateToken200ResponseFromJSONTyped(json); } function PostGenerateToken200ResponseFromJSONTyped(json, ignoreDiscriminator) { if (json == null) { return json; } return { "success": json["success"], "result": PostBanUserOrTokenRequestAdminAuthFromJSON(json["result"]), "message": json["message"] }; } function PostGenerateTokenRequestToJSON(value) { if (value == null) { return value; } return { "uid": value["uid"], "sid": value["sid"], "exp": value["exp"] }; } function PostQueryPostReacts200ResponseResultInnerReactsInnerFromJSON(json) { return PostQueryPostReacts200ResponseResultInnerReactsInnerFromJSONTyped(json); } function PostQueryPostReacts200ResponseResultInnerReactsInnerFromJSONTyped(json, ignoreDiscriminator) { if (json == null) { return json; } return { "smiley": json["smiley"], "count": json["count"], "reacted": json["reacted"] }; } function PostQueryPostReacts200ResponseResultInnerFromJSON(json) { return PostQueryPostReacts200ResponseResultInnerFromJSONTyped(json); } function PostQueryPostReacts200ResponseResultInnerFromJSONTyped(json, ignoreDiscriminator) { if (json == null) { return json; } return { "pid": json["pid"], "reacts": json["reacts"].map(PostQueryPostReacts200ResponseResultInnerReactsInnerFromJSON) }; } function PostQueryPostReacts200ResponseFromJSON(json) { return PostQueryPostReacts200ResponseFromJSONTyped(json); } function PostQueryPostReacts200ResponseFromJSONTyped(json, ignoreDiscriminator) { if (json == null) { return json; } return { "success": json["success"], "result": json["result"].map(PostQueryPostReacts200ResponseResultInnerFromJSON), "message": json["message"] }; } function PostQueryPostReactsRequestAuthToJSON(value) { if (value == null) { return value; } return { "token": value["token"], "payload": PostBanUserOrTokenRequestAdminAuthPayloadToJSON(value["payload"]) }; } function PostQueryPostReactsRequestToJSON(value) { if (value == null) { return value; } return { "pids": value["pids"], "auth": PostQueryPostReactsRequestAuthToJSON(value["auth"]) }; } function PostQueryUserReacts200ResponseResultSentInnerFromJSON(json) { return PostQueryUserReacts200ResponseResultSentInnerFromJSONTyped(json); } function PostQueryUserReacts200ResponseResultSentInnerFromJSONTyped(json, ignoreDiscriminator) { if (json == null) { return json; } return { "smiley": json["smiley"], "count": json["count"] }; } function PostQueryUserReacts200ResponseResultFromJSON(json) { return PostQueryUserReacts200ResponseResultFromJSONTyped(json); } function PostQueryUserReacts200ResponseResultFromJSONTyped(json, ignoreDiscriminator) { if (json == null) { return json; } return { "sent": json["sent"].map(PostQueryUserReacts200ResponseResultSentInnerFromJSON), "received": json["received"].map(PostQueryUserReacts200ResponseResultSentInnerFromJSON) }; } function PostQueryUserReacts200ResponseFromJSON(json) { return PostQueryUserReacts200ResponseFromJSONTyped(json); } function PostQueryUserReacts200ResponseFromJSONTyped(json, ignoreDiscriminator) { if (json == null) { return json; } return { "success": json["success"], "result": PostQueryUserReacts200ResponseResultFromJSON(json["result"]), "message": json["message"] }; } function PostQueryUserReactsRequestToJSON(value) { if (value == null) { return value; } return { "uid": value["uid"] }; } function PostUpdatePostReact200ResponseFromJSON(json) { return PostUpdatePostReact200ResponseFromJSONTyped(json); } function PostUpdatePostReact200ResponseFromJSONTyped(json, ignoreDiscriminator) { if (json == null) { return json; } return { "success": json["success"], "result": json["result"].map(PostQueryPostReacts200ResponseResultInnerReactsInnerFromJSON), "message": json["message"] }; } function PostUpdatePostReactRequestToJSON(value) { if (value == null) { return value; } return { "pid": value["pid"], "uid2": value["uid2"], "smiley": value["smiley"], "auth": PostBanUserOrTokenRequestAdminAuthToJSON(value["auth"]) }; } function PostVerifyToken200ResponseFromJSON(json) { return PostVerifyToken200ResponseFromJSONTyped(json); } function PostVerifyToken200ResponseFromJSONTyped(json, ignoreDiscriminator) { if (json == null) { return json; } return { "success": json["success"], "result": json["result"], "message": json["message"] }; } class ReactApi extends BaseAPI { /** * Query reactions for post */ async postQueryPostReactsRaw(requestParameters, initOverrides) { const queryParameters = {}; const headerParameters = {}; headerParameters["Content-Type"] = "application/json"; const response = await this.request({ path: `/react/queryPost`, method: "POST", headers: headerParameters, query: queryParameters, body: PostQueryPostReactsRequestToJSON(requestParameters["postQueryPostReactsRequest"]) }, initOverrides); return new JSONApiResponse(response, (jsonValue) => PostQueryPostReacts200ResponseFromJSON(jsonValue)); } /** * Query reactions for post */ async postQueryPostReacts(requestParameters = {}, initOverrides) { const response = await this.postQueryPostReactsRaw(requestParameters, initOverrides); return await response.value(); } /** * Query reactions for user */ async postQueryUserReactsRaw(requestParameters, initOverrides) { const queryParameters = {}; const headerParameters = {}; headerParameters["Content-Type"] = "application/json"; const response = await this.request({ path: `/react/queryUser`, method: "POST", headers: headerParameters, query: queryParameters, body: PostQueryUserReactsRequestToJSON(requestParameters["postQueryUserReactsRequest"]) }, initOverrides); return new JSONApiResponse(response, (jsonValue) => PostQueryUserReacts200ResponseFromJSON(jsonValue)); } /** * Query reactions for user */ async postQueryUserReacts(requestParameters = {}, initOverrides) { const response = await this.postQueryUserReactsRaw(requestParameters, initOverrides); return await response.value(); } /** * Update reaction for post */ async postUpdatePostReactRaw(requestParameters, initOverrides) { const queryParameters = {}; const headerParameters = {}; headerParameters["Content-Type"] = "application/json"; const response = await this.request({ path: `/react/update`, method: "POST", headers: headerParameters, query: queryParameters, body: PostUpdatePostReactRequestToJSON(requestParameters["postUpdatePostReactRequest"]) }, initOverrides); return new JSONApiResponse(response, (jsonValue) => PostUpdatePostReact200ResponseFromJSON(jsonValue)); } /** * Update reaction for post */ async postUpdatePostReact(requestParameters = {}, initOverrides) { const response = await this.postUpdatePostReactRaw(requestParameters, initOverrides); return await response.value(); } } class TokenApi extends BaseAPI { /** * Generate a token for user */ async postGenerateTokenRaw(requestParameters, initOverrides) { const queryParameters = {}; const headerParameters = {}; headerParameters["Content-Type"] = "application/json"; const response = await this.request({ path: `/token/generate`, method: "POST", headers: headerParameters, query: queryParameters, body: PostGenerateTokenRequestToJSON(requestParameters["postGenerateTokenRequest"]) }, initOverrides); return new JSONApiResponse(response, (jsonValue) => PostGenerateToken200ResponseFromJSON(jsonValue)); } /** * Generate a token for user */ async postGenerateToken(requestParameters = {}, initOverrides) { const response = await this.postGenerateTokenRaw(requestParameters, initOverrides); return await response.value(); } /** * Verify a token if it is valid, without checking the ban list */ async postVerifyTokenRaw(requestParameters, initOverrides) { const queryParameters = {}; const headerParameters = {}; headerParameters["Content-Type"] = "application/json"; const response = await this.request({ path: `/token/verify`, method: "POST", headers: headerParameters, query: queryParameters, body: PostBanUserOrTokenRequestAdminAuthToJSON(requestParameters["postBanUserOrTokenRequestAdminAuth"]) }, initOverrides); return new JSONApiResponse(response, (jsonValue) => PostVerifyToken200ResponseFromJSON(jsonValue)); } /** * Verify a token if it is valid, without checking the ban list */ async postVerifyToken(requestParameters = {}, initOverrides) { const response = await this.postVerifyTokenRaw(requestParameters, initOverrides); return await response.value(); } } const subscriber_queue = []; function readable(value, start) { return { subscribe: writable(value, start).subscribe }; } function writable(value, start = noop) { let stop; const subscribers = /* @__PURE__ */ new Set(); function set(new_value) { if (safe_not_equal(value, new_value)) { value = new_value; if (stop) { const run_queue = !subscriber_queue.length; for (const subscriber of subscribers) { subscriber[1](); subscriber_queue.push(subscriber, value); } if (run_queue) { for (let i = 0; i < subscriber_queue.length; i += 2) { subscriber_queue[i][0](subscriber_queue[i + 1]); } subscriber_queue.length = 0; } } } } function update(fn) { set(fn(value)); } function subscribe2(run, invalidate = noop) { const subscriber = [run, invalidate]; subscribers.add(subscriber); if (subscribers.size === 1) { stop = start(set, update) || noop; } run(value); return () => { subscribers.delete(subscriber); if (subscribers.size === 0 && stop) { stop(); stop = null; } }; } return { set, update, subscribe: subscribe2 }; } class LocalStorage { static setUserInfoDict(value) { this.setItem("users", value); } static getUserInfoDict() { return this.getItem("users"); } static setSelectedUID(value) { this.setItem("users.selected", value); } static getSelectedUID() { return this.getItem("users.selected"); } static setSmilesList(value) { this.setItem("smiles", value); } static getSmilesList() { return this.getItem("smiles"); } static setItem(key, value) { localStorage.setItem(`${this.prefix}.${key}`, JSON.stringify(value)); } static getItem(key) { const item = localStorage.getItem(`${this.prefix}.${key}`); if (!item) { return null; } return JSON.parse(item); } } __publicField(LocalStorage, "prefix", "s1-reaction"); const userInfoDict = writable(LocalStorage.getUserInfoDict() || {}); userInfoDict.subscribe((value) => { LocalStorage.setUserInfoDict(value); }); const userInfoList = readable([], (set) => { return userInfoDict.subscribe((value) => { set(Object.values(value).toSorted((a, b) => a.uid - b.uid)); }); }); readable(true, (set) => { return userInfoList.subscribe((value) => { set(value.length === 0); }); }); const selectedUID = writable(LocalStorage.getSelectedUID()); selectedUID.subscribe((value) => { LocalStorage.setSelectedUID(value); }); readable(null, (set) => { return selectedUID.subscribe((value) => { if (value === null) { set(null); return; } const selected = get_store_value(userInfoDict)[value]; set(selected); }); }); const reactsDict = writable({}); const smilesList = writable(LocalStorage.getSmilesList() || []); smilesList.subscribe((value) => { LocalStorage.setSmilesList(value); }); readable([], (set) => { return smilesList.subscribe((value) => { const table = value.map((smiles) => { const list = []; smiles.list.forEach((item, i) => { if (i % 12 === 0) { list.push([]); } list[list.length - 1].push(item); }); return { typeid: smiles.typeid, type: smiles.type, list }; }); set(table); }); }); readable({}, (set) => { return smilesList.subscribe((value) => { const dict = {}; value.map((item) => { return item.list; }).flat().forEach((item) => { dict[item.code] = item.url; }); set(dict); }); }); function obj2form(data) { return Object.keys(data).map( (key) => { const value = data[key]; if (value === void 0) { return ""; } return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`; } ).filter((item) => item).join("&"); } function responseErrorHandle(e) { const response = (() => { if (e instanceof Response) { return e; } if (e.response && e.response instanceof Response) { return e.response; } })(); if (response) { return response.json(); } return { success: false, message: e instanceof Error ? e.message : String(e) }; } function extractId(str, regexp) { var _a; const idStr = ((_a = str.match(regexp)) == null ? void 0 : _a[1]) ?? ""; if (!idStr) { return null; } const id = parseInt(idStr, 10); if (isNaN(id)) { return null; } return id; } function justAlert(message) { alert(`[S1 Reaction]: ${message}`); } function justLogError(message) { console.error("[S1 Reaction]: ", message); } async function checkSmiles() { { const smiles = get_store_value(smilesList); if (smiles.length > 0) { return true; } } const response = await s1Api.getSmiles().catch(responseErrorHandle); if (!response.success) { justAlert("通过 S1 接口获取麻将脸表情列表失败"); if (response.message) { justLogError(response.message); } return false; } smilesList.set(response.data.slice(0, 6)); return true; } class S1Api extends BaseAPI { async postLogin(requestParameters, initOverrides) { const response = await this.postLoginRaw(requestParameters, initOverrides); return await response.value(); } async postLogout(requestParameters, initOverrides) { const response = await this.postLogoutRaw(requestParameters, initOverrides); return await response.value(); } async getSmiles(initOverrides) { const response = await this.getSmilesRaw(initOverrides); return await response.value(); } async postLoginRaw(requestParameters, initOverrides) { const queryParameters = {}; const headerParameters = {}; headerParameters["Content-Type"] = "application/x-www-form-urlencoded;charset=UTF-8"; const response = await this.request({ path: "/user/login", method: "POST", headers: headerParameters, query: queryParameters, body: obj2form(requestParameters) }, initOverrides); return new JSONApiResponse(response); } async postLogoutRaw(requestParameters, initOverrides) { const queryParameters = {}; const headerParameters = {}; headerParameters["Content-Type"] = "application/x-www-form-urlencoded;charset=UTF-8"; const response = await this.request({ path: "/user/logout", method: "POST", headers: headerParameters, query: queryParameters, body: obj2form(requestParameters) }, initOverrides); return new JSONApiResponse(response); } async getSmilesRaw(initOverrides) { const queryParameters = {}; const headerParameters = {}; const response = await this.request({ path: "/post/smiles", method: "GET", headers: headerParameters, query: queryParameters }, initOverrides); return new JSONApiResponse(response); } } const config = new Configuration({ basePath: "https://s1-reaction.beepers-topaz-0c.workers.dev" }); new TokenApi(config); const reactApi = new ReactApi(config); const s1Api = new S1Api(new Configuration({ basePath: "https://app.saraba1st.com/2b/api/app" })); function createPostMountElement(pid) { const tableRowElement = document.createElement("tr"); tableRowElement.classList.add("s1-reaction"); tableRowElement.classList.add("s1-reaction-post"); tableRowElement.setAttribute("data-id", String(pid)); const leftTableCellElement = document.createElement("td"); leftTableCellElement.classList.add("pls"); tableRowElement.append(leftTableCellElement); const tableCellElement = document.createElement("td"); tableCellElement.classList.add("plc"); tableRowElement.append(tableCellElement); return { containerElement: tableRowElement, mountElement: tableCellElement }; } async function postMode() { const postDataList = []; const postElements = document.querySelectorAll("table[id^=pid]"); postElements.forEach((postElement) => { const pid = extractId(postElement.id, /^pid(\d+)$/); if (pid === null) { return; } const userLinkElement = postElement.querySelector("a[href^=space-uid-]"); if (!userLinkElement) { return; } const uid = extractId(userLinkElement.getAttribute("href") || "", /^space-uid-(\d+).html$/); if (uid === null) { return; } const positionElement = postElement.querySelector(`tr[id=_postposition${pid}]`); if (!positionElement) { return; } const { containerElement, mountElement } = createPostMountElement(pid); positionElement.after(containerElement); postDataList.push({ pid, uid, target: mountElement }); }); if (postDataList.length === 0) { return; } const response = await reactApi.postQueryPostReacts({ postQueryPostReactsRequest: { pids: postDataList.map((item) => item.pid) } }).catch(responseErrorHandle); if (!response.success) { justAlert("获取帖子回应失败"); if (response.message) { justLogError(response.message); } return; } response.result.forEach((result) => { const dict = {}; dict[`pid${result.pid}`] = result.reacts.map((react) => { return { smiley: react.smiley, count: react.count, reacted: react.reacted > 0 }; }); reactsDict.set(dict); }); } async function userMode() { } (async () => { if (!await checkSmiles()) { return; } if (location.pathname.startsWith("/2b/space-")) { await userMode(); } else { await postMode(); } })(); })();