【移动端】微博优化

劫持自动跳转登录,修复用户主页正确跳转,伪装客户端,可查看名人堂日程表,解锁视频清晰度(1080p、2K、2K-60、4K、4K-60)

  1. // ==UserScript==
  2. // @name 【移动端】微博优化
  3. // @namespace https://github.com/WhiteSevs/TamperMonkeyScript
  4. // @version 2025.2.12
  5. // @author WhiteSevs
  6. // @description 劫持自动跳转登录,修复用户主页正确跳转,伪装客户端,可查看名人堂日程表,解锁视频清晰度(1080p、2K、2K-60、4K、4K-60)
  7. // @license GPL-3.0-only
  8. // @icon data:image/png;base64,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
  9. // @supportURL https://github.com/WhiteSevs/TamperMonkeyScript/issues
  10. // @match *://m.weibo.cn/*
  11. // @match *://huati.weibo.cn/*
  12. // @match *://h5.video.weibo.com/*
  13. // @match *://card.weibo.com/*
  14. // @match *://weibo.com/l/wblive/m/show/*
  15. // @require https://fastly.jsdelivr.net/gh/WhiteSevs/TamperMonkeyScript@86be74b83fca4fa47521cded28377b35e1d7d2ac/lib/CoverUMD/index.js
  16. // @require https://fastly.jsdelivr.net/npm/@whitesev/utils@2.6.1/dist/index.umd.js
  17. // @require https://fastly.jsdelivr.net/npm/@whitesev/domutils@1.4.8/dist/index.umd.js
  18. // @require https://fastly.jsdelivr.net/npm/@whitesev/pops@1.9.7/dist/index.umd.js
  19. // @require https://fastly.jsdelivr.net/npm/qmsg@1.2.8/dist/index.umd.js
  20. // @connect *
  21. // @connect m.weibo.cn
  22. // @connect www.weibo.com
  23. // @connect passport.weibo.com
  24. // @grant GM_getResourceText
  25. // @grant GM_getValue
  26. // @grant GM_info
  27. // @grant GM_registerMenuCommand
  28. // @grant GM_setValue
  29. // @grant GM_unregisterMenuCommand
  30. // @grant GM_xmlhttpRequest
  31. // @grant unsafeWindow
  32. // @run-at document-start
  33. // ==/UserScript==
  34.  
  35. (function (Qmsg, DOMUtils, Utils, pops) {
  36. 'use strict';
  37.  
  38. var __defProp = Object.defineProperty;
  39. var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  40. var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  41. var _a;
  42. var _GM_getResourceText = /* @__PURE__ */ (() => typeof GM_getResourceText != "undefined" ? GM_getResourceText : void 0)();
  43. var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
  44. var _GM_info = /* @__PURE__ */ (() => typeof GM_info != "undefined" ? GM_info : void 0)();
  45. var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
  46. var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
  47. var _GM_unregisterMenuCommand = /* @__PURE__ */ (() => typeof GM_unregisterMenuCommand != "undefined" ? GM_unregisterMenuCommand : void 0)();
  48. var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)();
  49. var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
  50. var _monkeyWindow = /* @__PURE__ */ (() => window)();
  51. const HttpxCookieManager = {
  52. $data: {
  53. /** 是否启用 */
  54. get enable() {
  55. return PopsPanel.getValue("httpx-use-cookie-enable");
  56. },
  57. /** 是否使用document.cookie */
  58. get useDocumentCookie() {
  59. return PopsPanel.getValue("httpx-use-document-cookie");
  60. },
  61. cookieRule: [
  62. {
  63. key: "httpx-cookie-weibo.com",
  64. hostname: /weibo.com/g
  65. }
  66. ]
  67. },
  68. /**
  69. * 补充cookie末尾分号
  70. */
  71. fixCookieSplit(str) {
  72. if (utils.isNotNull(str) && !str.trim().endsWith(";")) {
  73. str += ";";
  74. }
  75. return str;
  76. },
  77. /**
  78. * 合并两个cookie
  79. */
  80. concatCookie(targetCookie, newCookie) {
  81. if (utils.isNull(targetCookie)) {
  82. return newCookie;
  83. }
  84. targetCookie = targetCookie.trim();
  85. newCookie = newCookie.trim();
  86. targetCookie = this.fixCookieSplit(targetCookie);
  87. if (newCookie.startsWith(";")) {
  88. newCookie = newCookie.substring(1);
  89. }
  90. return targetCookie.concat(newCookie);
  91. },
  92. /**
  93. * 处理cookie
  94. * @param details
  95. * @returns
  96. */
  97. handle(details) {
  98. if (details.fetch) {
  99. return;
  100. }
  101. if (!this.$data.enable) {
  102. return;
  103. }
  104. let ownCookie = "";
  105. let url = details.url;
  106. if (url.startsWith("//")) {
  107. url = window.location.protocol + url;
  108. }
  109. let urlObj = new URL(url);
  110. if (this.$data.useDocumentCookie && urlObj.hostname.endsWith(
  111. window.location.hostname.split(".").slice(-2).join(".")
  112. )) {
  113. ownCookie = this.concatCookie(ownCookie, document.cookie.trim());
  114. }
  115. for (let index = 0; index < this.$data.cookieRule.length; index++) {
  116. let rule = this.$data.cookieRule[index];
  117. if (urlObj.hostname.match(rule.hostname)) {
  118. let cookie = PopsPanel.getValue(rule.key);
  119. if (utils.isNull(cookie)) {
  120. break;
  121. }
  122. ownCookie = this.concatCookie(ownCookie, cookie);
  123. }
  124. }
  125. if (utils.isNotNull(ownCookie)) {
  126. if (details.headers && details.headers["Cookie"]) {
  127. details.headers.Cookie = this.concatCookie(
  128. details.headers.Cookie,
  129. ownCookie
  130. );
  131. } else {
  132. details.headers["Cookie"] = ownCookie;
  133. }
  134. log.info("Httpx => 设置cookie:", details);
  135. }
  136. if (details.headers && details.headers.Cookie != null && utils.isNull(details.headers.Cookie)) {
  137. delete details.headers.Cookie;
  138. }
  139. }
  140. };
  141. const CommonUtil = {
  142. /**
  143. * 添加屏蔽CSS
  144. * @param args
  145. * @example
  146. * addBlockCSS("")
  147. * addBlockCSS("","")
  148. * addBlockCSS(["",""])
  149. */
  150. addBlockCSS(...args) {
  151. let selectorList = [];
  152. if (args.length === 0) {
  153. return;
  154. }
  155. if (args.length === 1 && typeof args[0] === "string" && args[0].trim() === "") {
  156. return;
  157. }
  158. args.forEach((selector) => {
  159. if (Array.isArray(selector)) {
  160. selectorList = selectorList.concat(selector);
  161. } else {
  162. selectorList.push(selector);
  163. }
  164. });
  165. return addStyle(`${selectorList.join(",\n")}{display: none !important;}`);
  166. },
  167. /**
  168. * 设置GM_getResourceText的style内容
  169. * @param resourceMapData 资源数据
  170. * @example
  171. * setGMResourceCSS({
  172. * keyName: "ViewerCSS",
  173. * url: "https://example.com/example.css",
  174. * })
  175. */
  176. setGMResourceCSS(resourceMapData) {
  177. let cssText = typeof _GM_getResourceText === "function" ? _GM_getResourceText(resourceMapData.keyName) : "";
  178. if (typeof cssText === "string" && cssText) {
  179. addStyle(cssText);
  180. } else {
  181. CommonUtil.loadStyleLink(resourceMapData.url);
  182. }
  183. },
  184. /**
  185. * 添加<link>标签
  186. * @param url
  187. * @example
  188. * loadStyleLink("https://example.com/example.css")
  189. */
  190. async loadStyleLink(url) {
  191. let $link = document.createElement("link");
  192. $link.rel = "stylesheet";
  193. $link.type = "text/css";
  194. $link.href = url;
  195. domUtils.ready(() => {
  196. document.head.appendChild($link);
  197. });
  198. },
  199. /**
  200. * 添加<script>标签
  201. * @param url
  202. * @example
  203. * loadStyleLink("https://example.com/example.js")
  204. */
  205. async loadScript(url) {
  206. let $script = document.createElement("script");
  207. $script.src = url;
  208. return new Promise((resolve) => {
  209. $script.onload = () => {
  210. resolve(null);
  211. };
  212. (document.head || document.documentElement).appendChild($script);
  213. });
  214. },
  215. /**
  216. * 将url修复,例如只有search的链接修复为完整的链接
  217. *
  218. * 注意:不包括http转https
  219. * @param url 需要修复的链接
  220. * @example
  221. * 修复前:`/xxx/xxx?ss=ssss`
  222. * 修复后:`https://xxx.xxx.xxx/xxx/xxx?ss=ssss`
  223. * @example
  224. * 修复前:`//xxx/xxx?ss=ssss`
  225. * 修复后:`https://xxx.xxx.xxx/xxx/xxx?ss=ssss`
  226. * @example
  227. * 修复前:`https://xxx.xxx.xxx/xxx/xxx?ss=ssss`
  228. * 修复后:`https://xxx.xxx.xxx/xxx/xxx?ss=ssss`
  229. * @example
  230. * 修复前:`xxx/xxx?ss=ssss`
  231. * 修复后:`https://xxx.xxx.xxx/xxx/xxx?ss=ssss`
  232. */
  233. fixUrl(url) {
  234. url = url.trim();
  235. if (url.match(/^http(s|):\/\//i)) {
  236. return url;
  237. } else {
  238. if (!url.startsWith("/")) {
  239. url += "/";
  240. }
  241. url = window.location.origin + url;
  242. return url;
  243. }
  244. },
  245. /**
  246. * http转https
  247. * @param url 需要修复的链接
  248. * @example
  249. * 修复前:
  250. * 修复后:
  251. * @example
  252. * 修复前:
  253. * 修复后:
  254. */
  255. fixHttps(url) {
  256. if (url.startsWith("https://")) {
  257. return url;
  258. }
  259. if (!url.startsWith("http://")) {
  260. return url;
  261. }
  262. let urlObj = new URL(url);
  263. urlObj.protocol = "https:";
  264. return urlObj.toString();
  265. }
  266. };
  267. const _SCRIPT_NAME_ = "【移动端】微博优化";
  268. const utils = Utils.noConflict();
  269. const domUtils = DOMUtils.noConflict();
  270. const __pops = pops;
  271. const log = new utils.Log(
  272. _GM_info,
  273. _unsafeWindow.console || _monkeyWindow.console
  274. );
  275. const SCRIPT_NAME = ((_a = _GM_info == null ? void 0 : _GM_info.script) == null ? void 0 : _a.name) || _SCRIPT_NAME_;
  276. const DEBUG = false;
  277. log.config({
  278. debug: DEBUG,
  279. logMaxCount: 2e4,
  280. autoClearConsole: true,
  281. tag: true
  282. });
  283. Qmsg.config(
  284. Object.defineProperties(
  285. {
  286. html: true,
  287. autoClose: true,
  288. showClose: false
  289. },
  290. {
  291. position: {
  292. get() {
  293. return PopsPanel.getValue("qmsg-config-position", "bottom");
  294. }
  295. },
  296. maxNums: {
  297. get() {
  298. return PopsPanel.getValue("qmsg-config-maxnums", 5);
  299. }
  300. },
  301. showReverse: {
  302. get() {
  303. return PopsPanel.getValue("qmsg-config-showreverse", true);
  304. }
  305. },
  306. zIndex: {
  307. get() {
  308. let maxZIndex = Utils.getMaxZIndex();
  309. let popsMaxZIndex = pops.config.InstanceUtils.getPopsMaxZIndex(maxZIndex).zIndex;
  310. return Utils.getMaxValue(maxZIndex, popsMaxZIndex) + 100;
  311. }
  312. }
  313. }
  314. )
  315. );
  316. const GM_Menu = new utils.GM_Menu({
  317. GM_getValue: _GM_getValue,
  318. GM_setValue: _GM_setValue,
  319. GM_registerMenuCommand: _GM_registerMenuCommand,
  320. GM_unregisterMenuCommand: _GM_unregisterMenuCommand
  321. });
  322. const httpx = new utils.Httpx(_GM_xmlhttpRequest);
  323. httpx.interceptors.request.use((data) => {
  324. HttpxCookieManager.handle(data);
  325. return data;
  326. });
  327. httpx.interceptors.response.use(void 0, (data) => {
  328. log.error("拦截器-请求错误", data);
  329. if (data.type === "onabort") {
  330. Qmsg.warning("请求取消");
  331. } else if (data.type === "onerror") {
  332. Qmsg.error("请求异常");
  333. } else if (data.type === "ontimeout") {
  334. Qmsg.error("请求超时");
  335. } else {
  336. Qmsg.error("其它错误");
  337. }
  338. return data;
  339. });
  340. httpx.config({
  341. logDetails: DEBUG
  342. });
  343. ({
  344. Object: {
  345. defineProperty: _unsafeWindow.Object.defineProperty
  346. },
  347. Function: {
  348. apply: _unsafeWindow.Function.prototype.apply,
  349. call: _unsafeWindow.Function.prototype.call
  350. },
  351. Element: {
  352. appendChild: _unsafeWindow.Element.prototype.appendChild
  353. },
  354. setTimeout: _unsafeWindow.setTimeout
  355. });
  356. const addStyle = utils.addStyle.bind(utils);
  357. const $ = document.querySelector.bind(document);
  358. const $$ = document.querySelectorAll.bind(document);
  359. const KEY = "GM_Panel";
  360. const ATTRIBUTE_INIT = "data-init";
  361. const ATTRIBUTE_KEY = "data-key";
  362. const ATTRIBUTE_DEFAULT_VALUE = "data-default-value";
  363. const ATTRIBUTE_INIT_MORE_VALUE = "data-init-more-value";
  364. const PROPS_STORAGE_API = "data-storage-api";
  365. const WeiBoApi = {
  366. /**
  367. * 获取组件播放信息
  368. * @param oid 格式:xxxx:xxxxxxxxxxx
  369. */
  370. async component(oid) {
  371. let postParams = {
  372. page: "/tv/show/" + oid
  373. };
  374. let postData = {
  375. data: JSON.stringify({ Component_Play_Playinfo: { oid } })
  376. };
  377. let api = `https://www.weibo.com/tv/api/component?${utils.toSearchParamsStr(
  378. postParams
  379. )}`;
  380. let response = await httpx.post(api, {
  381. data: utils.toSearchParamsStr(postData),
  382. headers: {
  383. Accept: "application/json, text/plain, */*",
  384. "Content-Type": "application/x-www-form-urlencoded",
  385. Host: "www.weibo.com",
  386. Origin: "https://www.weibo.com",
  387. "Page-Referer": postParams.page,
  388. Referer: "https://www.weibo.com" + postParams.page,
  389. "User-Agent": utils.getRandomPCUA()
  390. }
  391. });
  392. if (!response.status) {
  393. return;
  394. }
  395. let data = utils.toJSON(response.data.responseText);
  396. if (data["code"] !== "100000") {
  397. log.info(`获取播放信息失败`, response);
  398. Qmsg.error("获取播放信息失败");
  399. return;
  400. }
  401. let Component_Play_Playinfo = data["data"]["Component_Play_Playinfo"];
  402. return Component_Play_Playinfo;
  403. }
  404. };
  405. const VueUtils = {
  406. /**
  407. * 获取vue2实例
  408. * @param element
  409. * @returns
  410. */
  411. getVue(element) {
  412. if (element == null) {
  413. return;
  414. }
  415. return element["__vue__"] || element["__Ivue__"] || element["__IVue__"];
  416. },
  417. /**
  418. * 获取vue3实例
  419. * @param element
  420. * @returns
  421. */
  422. getVue3(element) {
  423. if (element == null) {
  424. return;
  425. }
  426. return element["__vueParentComponent"];
  427. },
  428. /**
  429. * 等待vue属性并进行设置
  430. * @param $target 目标对象
  431. * @param needSetList 需要设置的配置
  432. */
  433. waitVuePropToSet($target, needSetList) {
  434. if (!Array.isArray(needSetList)) {
  435. VueUtils.waitVuePropToSet($target, [needSetList]);
  436. return;
  437. }
  438. function getTarget() {
  439. let __target__ = null;
  440. if (typeof $target === "string") {
  441. __target__ = document.querySelector($target);
  442. } else if (typeof $target === "function") {
  443. __target__ = $target();
  444. } else if ($target instanceof HTMLElement) {
  445. __target__ = $target;
  446. }
  447. return __target__;
  448. }
  449. needSetList.forEach((needSetOption) => {
  450. if (typeof needSetOption.msg === "string") {
  451. log.info(needSetOption.msg);
  452. }
  453. function checkVue() {
  454. let target = getTarget();
  455. if (target == null) {
  456. return false;
  457. }
  458. let vueInstance = VueUtils.getVue(target);
  459. if (vueInstance == null) {
  460. return false;
  461. }
  462. let needOwnCheck = needSetOption.check(vueInstance);
  463. return Boolean(needOwnCheck);
  464. }
  465. utils.waitVueByInterval(
  466. () => {
  467. return getTarget();
  468. },
  469. checkVue,
  470. 250,
  471. 1e4
  472. ).then((result) => {
  473. if (!result) {
  474. if (typeof needSetOption.failWait === "function") {
  475. needSetOption.failWait(true);
  476. }
  477. return;
  478. }
  479. let target = getTarget();
  480. let vueInstance = VueUtils.getVue(target);
  481. if (vueInstance == null) {
  482. if (typeof needSetOption.failWait === "function") {
  483. needSetOption.failWait(false);
  484. }
  485. return;
  486. }
  487. needSetOption.set(vueInstance);
  488. });
  489. });
  490. },
  491. /**
  492. * 观察vue属性的变化
  493. * @param $target 目标对象
  494. * @param key 需要观察的属性
  495. * @param callback 监听回调
  496. * @param watchConfig 监听配置
  497. * @param failWait 当检测失败/超时触发该回调
  498. */
  499. watchVuePropChange($target, key, callback, watchConfig, failWait) {
  500. let config = utils.assign(
  501. {
  502. immediate: true,
  503. deep: false
  504. },
  505. watchConfig || {}
  506. );
  507. return new Promise((resolve) => {
  508. VueUtils.waitVuePropToSet($target, {
  509. check(vueInstance) {
  510. return typeof (vueInstance == null ? void 0 : vueInstance.$watch) === "function";
  511. },
  512. set(vueInstance) {
  513. let removeWatch = null;
  514. if (typeof key === "function") {
  515. removeWatch = vueInstance.$watch(
  516. () => {
  517. return key(vueInstance);
  518. },
  519. (newValue, oldValue) => {
  520. callback(vueInstance, newValue, oldValue);
  521. },
  522. config
  523. );
  524. } else {
  525. removeWatch = vueInstance.$watch(
  526. key,
  527. (newValue, oldValue) => {
  528. callback(vueInstance, newValue, oldValue);
  529. },
  530. config
  531. );
  532. }
  533. resolve(removeWatch);
  534. },
  535. failWait
  536. });
  537. });
  538. },
  539. /**
  540. * 前往网址
  541. * @param $vueNode 包含vue属性的元素
  542. * @param path 需要跳转的路径
  543. * @param [useRouter=false] 是否强制使用Vue的Router来进行跳转
  544. */
  545. goToUrl($vueNode, path, useRouter = false) {
  546. if ($vueNode == null) {
  547. Qmsg.error("跳转Url: $vueNode为空");
  548. log.error("跳转Url: $vueNode为空:" + path);
  549. return;
  550. }
  551. let vueObj = VueUtils.getVue($vueNode);
  552. if (vueObj == null) {
  553. Qmsg.error("获取vue属性失败", { consoleLogContent: true });
  554. return;
  555. }
  556. let $router = vueObj.$router;
  557. let isBlank = true;
  558. log.info("即将跳转URL:" + path);
  559. if (useRouter) {
  560. isBlank = false;
  561. }
  562. if (isBlank) {
  563. window.open(path, "_blank");
  564. } else {
  565. if (path.startsWith("http") || path.startsWith("//")) {
  566. if (path.startsWith("//")) {
  567. path = window.location.protocol + path;
  568. }
  569. let urlObj = new URL(path);
  570. if (urlObj.origin === window.location.origin) {
  571. path = urlObj.pathname + urlObj.search + urlObj.hash;
  572. } else {
  573. log.info("不同域名,直接本页打开,不用Router:" + path);
  574. window.location.href = path;
  575. return;
  576. }
  577. }
  578. log.info("$router push跳转Url:" + path);
  579. $router.push(path);
  580. }
  581. },
  582. /**
  583. * 手势返回
  584. * @param option 配置
  585. */
  586. hookGestureReturnByVueRouter(option) {
  587. function popstateEvent() {
  588. log.success("触发popstate事件");
  589. resumeBack(true);
  590. }
  591. function banBack() {
  592. log.success("监听地址改变");
  593. option.vueInstance.$router.history.push(option.hash);
  594. domUtils.on(_unsafeWindow, "popstate", popstateEvent);
  595. }
  596. async function resumeBack(isFromPopState = false) {
  597. domUtils.off(_unsafeWindow, "popstate", popstateEvent);
  598. let callbackResult = option.callback(isFromPopState);
  599. if (callbackResult) {
  600. return;
  601. }
  602. while (1) {
  603. if (option.vueInstance.$router.history.current.hash === option.hash) {
  604. log.info("后退!");
  605. option.vueInstance.$router.back();
  606. await utils.sleep(250);
  607. } else {
  608. return;
  609. }
  610. }
  611. }
  612. banBack();
  613. return {
  614. resumeBack
  615. };
  616. }
  617. };
  618. const VideoQualityMap_Mobile = {
  619. "流畅 360P": {
  620. label: "流畅",
  621. sign: 1,
  622. name: "mp4_ld_mp4"
  623. },
  624. "标清 480P": {
  625. label: "标清",
  626. sign: 2,
  627. name: "mp4_hd_mp4"
  628. },
  629. "高清 720P": {
  630. label: "高清",
  631. sign: 3,
  632. name: "mp4_720p_mp4"
  633. }
  634. };
  635. const VideoQualityMap_PC = {
  636. "高清 1080P": {
  637. label: "超清",
  638. sign: 4,
  639. name: "mp4_1080p_mp4"
  640. },
  641. "超清 2K": {
  642. label: "2K",
  643. sign: 5,
  644. name: "mp4_1440p_mp4"
  645. },
  646. "超清 2K60": {
  647. label: "2K-60",
  648. sign: 6,
  649. name: "mp4_1440p_60fps_mp4"
  650. },
  651. "超清 4K": {
  652. label: "4K",
  653. sign: 7,
  654. name: "mp4_2160p_mp4"
  655. },
  656. "超清 4K60": {
  657. label: "4K-60",
  658. sign: 7,
  659. name: "mp4_2160p_60fps_mp4"
  660. }
  661. };
  662. const VideoQualityMap = {
  663. ...VideoQualityMap_Mobile,
  664. ...VideoQualityMap_PC
  665. };
  666. class WeiBoUnlockQuality {
  667. constructor() {
  668. __publicField(this, "$src", VideoQualityMap_PC);
  669. __publicField(this, "$data", {
  670. newQualityNameList: [],
  671. videoQualityMap: new utils.Dictionary()
  672. });
  673. this.$data.newQualityNameList = [];
  674. this.$data.newQualityNameList.push(...Object.keys(this.$src));
  675. }
  676. /**
  677. * 锁定视频清晰度
  678. */
  679. lockVideoQuality() {
  680. let that = this;
  681. log.info("锁定视频清晰度");
  682. VueUtils.waitVuePropToSet(".video-player .mwb-video", [
  683. {
  684. msg: "等待获取属性 __vue__.player.controlBar.addChild",
  685. check(vueObj) {
  686. return typeof vueObj.player.controlBar.addChild === "function";
  687. },
  688. set(vueObj) {
  689. let oldAddChild = vueObj.player.controlBar.addChild;
  690. let userSetQuality = PopsPanel.getValue(
  691. "weibo-common-lockVideoQuality"
  692. );
  693. let userSetQualitySign = -1;
  694. Object.keys(VideoQualityMap).find((key) => {
  695. if (VideoQualityMap[key].name === userSetQuality) {
  696. userSetQualitySign = VideoQualityMap[key].sign;
  697. return true;
  698. } else {
  699. return false;
  700. }
  701. });
  702. let ownAddChild = function(...args) {
  703. let name = args[0];
  704. if (name === "qualityButton") {
  705. let qualityInfo = args[1];
  706. log.info("锁定视频清晰度", qualityInfo);
  707. qualityInfo["qualityList"].find((item) => {
  708. if (!(item.sign === 1 && that.$data.videoQualityMap.has(item.src))) {
  709. return false;
  710. }
  711. that.$data.videoQualityMap.get(item.src).forEach((videoQualityMapInfo) => {
  712. let findIndex = qualityInfo["qualityList"].findIndex(
  713. (qualityItem) => {
  714. return qualityItem.sign === videoQualityMapInfo.sign;
  715. }
  716. );
  717. if (findIndex === -1) {
  718. let newQuality = {
  719. label: videoQualityMapInfo.label,
  720. sign: videoQualityMapInfo.sign,
  721. src: videoQualityMapInfo.src
  722. };
  723. log.success("添加新的视频清晰度", newQuality);
  724. qualityInfo["qualityList"].push(newQuality);
  725. }
  726. });
  727. return true;
  728. });
  729. if (userSetQualitySign !== -1) {
  730. let findSign = qualityInfo["qualityList"].find(
  731. (item) => item["sign"] === userSetQualitySign
  732. );
  733. if (findSign) {
  734. qualityInfo["defaultSign"] = userSetQualitySign;
  735. } else {
  736. let signList = qualityInfo["qualityList"].map((item) => {
  737. if (item.sign <= userSetQualitySign) {
  738. return item.sign;
  739. }
  740. }).filter((item) => item);
  741. let userSetQualitySignLower = utils.getMaxValue(...signList);
  742. qualityInfo["defaultSign"] = userSetQualitySignLower;
  743. log.error(
  744. "该清晰度不存在,选择比该画质低的清晰度:" + userSetQualitySignLower
  745. );
  746. }
  747. } else {
  748. let signList = qualityInfo["qualityList"].map(
  749. (item) => item.sign
  750. );
  751. let maxSign = utils.getMaxValue(...signList);
  752. qualityInfo["defaultSign"] = maxSign;
  753. }
  754. }
  755. return oldAddChild.apply(this, args);
  756. };
  757. if (oldAddChild == ownAddChild) {
  758. return;
  759. }
  760. vueObj.player.controlBar.addChild = ownAddChild;
  761. log.success("成功覆盖属性 __vue__.player.controlBar.addChild");
  762. }
  763. }
  764. ]);
  765. }
  766. /**
  767. * 解锁更多视频清晰度
  768. */
  769. async unlockVideoHigherQuality() {
  770. let that = this;
  771. let taskQueue = [];
  772. $$(".weibo-media-wraps:not([data-unlock-quality])").forEach(
  773. ($ele) => {
  774. $ele.setAttribute("data-unlock-quality", "true");
  775. let taskFunc = function() {
  776. return new Promise((resolve, reject) => {
  777. VueUtils.waitVuePropToSet($ele, [
  778. {
  779. check(vueObj) {
  780. var _a2, _b, _c;
  781. if (typeof ((_a2 = vueObj == null ? void 0 : vueObj.item) == null ? void 0 : _a2.type) === "string" && ((_b = vueObj == null ? void 0 : vueObj.item) == null ? void 0 : _b.type) !== "video") {
  782. return true;
  783. }
  784. return typeof ((_c = vueObj == null ? void 0 : vueObj.item) == null ? void 0 : _c.object_id) === "string";
  785. },
  786. failWait() {
  787. resolve();
  788. },
  789. async set(vueObj) {
  790. try {
  791. if (vueObj.item.type !== "video") {
  792. return;
  793. }
  794. let object_id = vueObj.item.object_id;
  795. let urls = vueObj.item.urls;
  796. let componentInfo = await WeiBoApi.component(object_id);
  797. if (!componentInfo) {
  798. return;
  799. }
  800. if (!componentInfo.urls) {
  801. log.error("获取组件信息urls失败");
  802. Qmsg.error("获取组件信息urls失败");
  803. return;
  804. }
  805. if (typeof componentInfo.urls !== "object") {
  806. log.error("组件信息urls不是一个对象");
  807. Qmsg.error("组件信息urls不是一个对象");
  808. return;
  809. }
  810. if (!Object.keys(componentInfo.urls).length) {
  811. log.error("组件信息urls为空");
  812. Qmsg.error("组件信息urls为空");
  813. return;
  814. }
  815. Object.keys(componentInfo.urls).forEach((srcName) => {
  816. let src = componentInfo.urls[srcName];
  817. if (that.$data.newQualityNameList.includes(srcName)) {
  818. let mapInfo = {
  819. label: that.$src[srcName].label,
  820. name: that.$src[srcName].name,
  821. sign: that.$src[srcName].sign,
  822. src
  823. };
  824. let ld_mp4_url = urls["mp4_ld_mp4"];
  825. if (ld_mp4_url) {
  826. if (!that.$data.videoQualityMap.has(ld_mp4_url)) {
  827. that.$data.videoQualityMap.set(ld_mp4_url, [
  828. mapInfo
  829. ]);
  830. } else {
  831. let currentMapInfo = that.$data.videoQualityMap.get(ld_mp4_url);
  832. currentMapInfo.push(mapInfo);
  833. that.$data.videoQualityMap.set(
  834. ld_mp4_url,
  835. currentMapInfo
  836. );
  837. }
  838. }
  839. }
  840. if (srcName in VideoQualityMap) {
  841. let newSrcInfo = VideoQualityMap[srcName];
  842. if (newSrcInfo.name in urls) {
  843. } else {
  844. log.success("新增清晰度:", newSrcInfo);
  845. urls[newSrcInfo.name] = src;
  846. }
  847. } else {
  848. log.error("视频清晰度映射尚未补充", { srcName, src });
  849. }
  850. });
  851. } catch (error) {
  852. log.error(error);
  853. } finally {
  854. resolve();
  855. }
  856. }
  857. }
  858. ]);
  859. });
  860. };
  861. taskQueue.push(taskFunc);
  862. }
  863. );
  864. for (const taskIterator of taskQueue) {
  865. taskIterator();
  866. await utils.sleep(100);
  867. }
  868. }
  869. }
  870. const UISelect = function(text, key, defaultValue, data, callback, description) {
  871. let selectData = [];
  872. if (typeof data === "function") {
  873. selectData = data();
  874. } else {
  875. selectData = data;
  876. }
  877. let result = {
  878. text,
  879. type: "select",
  880. description,
  881. attributes: {},
  882. props: {},
  883. getValue() {
  884. return this.props[PROPS_STORAGE_API].get(key, defaultValue);
  885. },
  886. callback(event, isSelectedValue, isSelectedText) {
  887. let value = isSelectedValue;
  888. log.info(`选择:${isSelectedText}`);
  889. this.props[PROPS_STORAGE_API].set(key, value);
  890. if (typeof callback === "function") {
  891. callback(event, value, isSelectedText);
  892. }
  893. },
  894. data: selectData
  895. };
  896. Reflect.set(result.attributes, ATTRIBUTE_KEY, key);
  897. Reflect.set(result.attributes, ATTRIBUTE_DEFAULT_VALUE, defaultValue);
  898. Reflect.set(result.props, PROPS_STORAGE_API, {
  899. get(key2, defaultValue2) {
  900. return PopsPanel.getValue(key2, defaultValue2);
  901. },
  902. set(key2, value) {
  903. PopsPanel.setValue(key2, value);
  904. }
  905. });
  906. return result;
  907. };
  908. const UISwitch = function(text, key, defaultValue, clickCallBack, description, afterAddToUListCallBack) {
  909. let result = {
  910. text,
  911. type: "switch",
  912. description,
  913. attributes: {},
  914. props: {},
  915. getValue() {
  916. return Boolean(
  917. this.props[PROPS_STORAGE_API].get(key, defaultValue)
  918. );
  919. },
  920. callback(event, __value) {
  921. let value = Boolean(__value);
  922. log.success(`${value ? "开启" : "关闭"} ${text}`);
  923. this.props[PROPS_STORAGE_API].set(key, value);
  924. },
  925. afterAddToUListCallBack
  926. };
  927. Reflect.set(result.attributes, ATTRIBUTE_KEY, key);
  928. Reflect.set(result.attributes, ATTRIBUTE_DEFAULT_VALUE, defaultValue);
  929. Reflect.set(result.props, PROPS_STORAGE_API, {
  930. get(key2, defaultValue2) {
  931. return PopsPanel.getValue(key2, defaultValue2);
  932. },
  933. set(key2, value) {
  934. PopsPanel.setValue(key2, value);
  935. }
  936. });
  937. return result;
  938. };
  939. const UITextArea = function(text, key, defaultValue, description, changeCallBack, placeholder = "", disabled) {
  940. let result = {
  941. text,
  942. type: "textarea",
  943. attributes: {},
  944. props: {},
  945. description,
  946. placeholder,
  947. disabled,
  948. getValue() {
  949. return this.props[PROPS_STORAGE_API].get(key, defaultValue);
  950. },
  951. callback(event, value) {
  952. this.props[PROPS_STORAGE_API].set(key, value);
  953. }
  954. };
  955. Reflect.set(result.attributes, ATTRIBUTE_KEY, key);
  956. Reflect.set(result.attributes, ATTRIBUTE_DEFAULT_VALUE, defaultValue);
  957. Reflect.set(result.props, PROPS_STORAGE_API, {
  958. get(key2, defaultValue2) {
  959. return PopsPanel.getValue(key2, defaultValue2);
  960. },
  961. set(key2, value) {
  962. PopsPanel.setValue(key2, value);
  963. }
  964. });
  965. return result;
  966. };
  967. const SettingUICommon = {
  968. id: "weibo-panel-config-currency",
  969. title: "通用",
  970. forms: [
  971. {
  972. text: "",
  973. type: "forms",
  974. forms: [
  975. {
  976. type: "deepMenu",
  977. text: "Toast配置",
  978. forms: [
  979. {
  980. text: "",
  981. type: "forms",
  982. forms: [
  983. UISelect(
  984. "Toast位置",
  985. "qmsg-config-position",
  986. "bottom",
  987. [
  988. {
  989. value: "topleft",
  990. text: "左上角"
  991. },
  992. {
  993. value: "top",
  994. text: "顶部"
  995. },
  996. {
  997. value: "topright",
  998. text: "右上角"
  999. },
  1000. {
  1001. value: "left",
  1002. text: "左边"
  1003. },
  1004. {
  1005. value: "center",
  1006. text: "中间"
  1007. },
  1008. {
  1009. value: "right",
  1010. text: "右边"
  1011. },
  1012. {
  1013. value: "bottomleft",
  1014. text: "左下角"
  1015. },
  1016. {
  1017. value: "bottom",
  1018. text: "底部"
  1019. },
  1020. {
  1021. value: "bottomright",
  1022. text: "右下角"
  1023. }
  1024. ],
  1025. (event, isSelectValue, isSelectText) => {
  1026. log.info("设置当前Qmsg弹出位置" + isSelectText);
  1027. },
  1028. "Toast显示在页面九宫格的位置"
  1029. ),
  1030. UISelect(
  1031. "最多显示的数量",
  1032. "qmsg-config-maxnums",
  1033. 3,
  1034. [
  1035. {
  1036. value: 1,
  1037. text: "1"
  1038. },
  1039. {
  1040. value: 2,
  1041. text: "2"
  1042. },
  1043. {
  1044. value: 3,
  1045. text: "3"
  1046. },
  1047. {
  1048. value: 4,
  1049. text: "4"
  1050. },
  1051. {
  1052. value: 5,
  1053. text: "5"
  1054. }
  1055. ],
  1056. void 0,
  1057. "限制Toast显示的数量"
  1058. ),
  1059. UISwitch(
  1060. "逆序弹出",
  1061. "qmsg-config-showreverse",
  1062. false,
  1063. void 0,
  1064. "修改Toast弹出的顺序"
  1065. )
  1066. ]
  1067. }
  1068. ]
  1069. },
  1070. {
  1071. type: "deepMenu",
  1072. text: "Cookie配置",
  1073. forms: [
  1074. {
  1075. text: "",
  1076. type: "forms",
  1077. forms: [
  1078. UISwitch(
  1079. "启用",
  1080. "httpx-use-cookie-enable",
  1081. false,
  1082. void 0,
  1083. "启用后,将根据下面的配置进行添加cookie"
  1084. ),
  1085. UISwitch(
  1086. "使用document.cookie",
  1087. "httpx-use-document-cookie",
  1088. false,
  1089. void 0,
  1090. "自动根据请求的域名来获取对应的cookie"
  1091. ),
  1092. UITextArea(
  1093. "weibo.com",
  1094. "httpx-cookie-weibo.com",
  1095. "",
  1096. void 0,
  1097. void 0,
  1098. "Cookie格式:xxx=xxxx;xxx=xxxx"
  1099. )
  1100. ]
  1101. }
  1102. ]
  1103. }
  1104. ]
  1105. },
  1106. {
  1107. type: "forms",
  1108. text: "",
  1109. forms: [
  1110. {
  1111. text: "功能",
  1112. type: "deepMenu",
  1113. forms: [
  1114. {
  1115. text: "",
  1116. type: "forms",
  1117. forms: [
  1118. UISelect(
  1119. "视频清晰度",
  1120. "weibo-common-lockVideoQuality",
  1121. "",
  1122. [
  1123. {
  1124. value: "",
  1125. text: "自动"
  1126. },
  1127. ...(() => {
  1128. let result = [];
  1129. Object.keys(VideoQualityMap).forEach((name) => {
  1130. let value = VideoQualityMap[name];
  1131. result.push({
  1132. value: value.name,
  1133. text: name
  1134. });
  1135. });
  1136. return result;
  1137. })()
  1138. ],
  1139. void 0,
  1140. "设置视频清晰度,默认自动,其它的清晰度将自动被删除(强制固定选择的清晰度)"
  1141. ),
  1142. UISwitch(
  1143. "解锁更多清晰度",
  1144. "weibo-common-unlockVideoHigherQuality",
  1145. true,
  1146. void 0,
  1147. "自动请求PC端的视频清晰度,如果请求成功,将解锁更多的清晰度,如1080p、2K、2K-60、4K-60"
  1148. ),
  1149. UISwitch(
  1150. "点击图片关闭预览",
  1151. "weibo-common-clickImageToClosePreviewImage",
  1152. false,
  1153. void 0,
  1154. "当点击图片进入预览模式时,再点击当前预览的图片可退出预览"
  1155. )
  1156. ]
  1157. },
  1158. {
  1159. text: "函数禁用",
  1160. type: "forms",
  1161. forms: [
  1162. UISwitch(
  1163. "navigator.serviceWorker.register",
  1164. "weibo_hijack_navigator_service_worker_register",
  1165. true,
  1166. void 0,
  1167. "禁止注册serviceWorker"
  1168. )
  1169. ]
  1170. }
  1171. ]
  1172. },
  1173. {
  1174. text: "屏蔽",
  1175. type: "deepMenu",
  1176. forms: [
  1177. {
  1178. text: "",
  1179. type: "forms",
  1180. forms: [
  1181. UISwitch(
  1182. "【屏蔽】广告",
  1183. "weibo_remove_ads",
  1184. true,
  1185. void 0,
  1186. "包括【登录/注册按钮】、【小程序横幅推荐】"
  1187. ),
  1188. UISwitch(
  1189. "【屏蔽】底部工具栏",
  1190. "weibo_shield_bottom_bar",
  1191. false,
  1192. void 0,
  1193. "屏蔽聊天/关注按钮"
  1194. )
  1195. ]
  1196. }
  1197. ]
  1198. },
  1199. {
  1200. text: "拦截跳转",
  1201. type: "deepMenu",
  1202. forms: [
  1203. {
  1204. text: "注意:已登录的情况下请关闭下面的功能",
  1205. type: "forms",
  1206. forms: [
  1207. UISwitch(
  1208. "api/attitudes/create",
  1209. "weibo_apply_attitudes_create",
  1210. true
  1211. ),
  1212. UISwitch(
  1213. "点赞",
  1214. "weibo_apply_likes_update",
  1215. true,
  1216. void 0,
  1217. "未登录时,拦截点赞跳转登录"
  1218. ),
  1219. UISwitch(
  1220. "评论",
  1221. "weibo_apply_comments_create",
  1222. true,
  1223. void 0,
  1224. "未登录时,拦截评论跳转登录"
  1225. ),
  1226. UISwitch(
  1227. "关注",
  1228. "weibo_apply_friendships_create",
  1229. true,
  1230. void 0,
  1231. "未登录时,拦截关注跳转登录"
  1232. ),
  1233. UISwitch(
  1234. "转发",
  1235. "weibo_apply_statuses_repostTimeline",
  1236. true,
  1237. void 0,
  1238. "未登录时,拦截查看转发数据"
  1239. ),
  1240. UISwitch(
  1241. "回复",
  1242. "weibo_apply_comments_reply",
  1243. true,
  1244. void 0,
  1245. "未登录时,拦截回复跳转登录"
  1246. ),
  1247. UISwitch(
  1248. "优化跳转主页",
  1249. "weibo_apply_profile_info",
  1250. true,
  1251. void 0,
  1252. "未登录时,正确跳转至用户主页"
  1253. ),
  1254. UISwitch(
  1255. "下拉加载更多评论",
  1256. "weibo_apply_comments_hotflow",
  1257. true,
  1258. void 0,
  1259. "未登录时,拦截下拉加载更多评论跳转登录"
  1260. ),
  1261. UISwitch(
  1262. "楼中楼下拉加载更多评论",
  1263. "weibo_apply_comments_hotFlowChild",
  1264. true,
  1265. void 0,
  1266. "未登录时,拦截下拉加载更多评论跳转登录"
  1267. )
  1268. ]
  1269. }
  1270. ]
  1271. },
  1272. {
  1273. text: "网络请求",
  1274. type: "deepMenu",
  1275. forms: [
  1276. {
  1277. text: "",
  1278. type: "forms",
  1279. forms: [
  1280. UISwitch(
  1281. "/api/config",
  1282. "weibo_request_api_config",
  1283. true,
  1284. void 0,
  1285. "Api为获取用户数据,未登录时伪装为已登录"
  1286. ),
  1287. UISwitch(
  1288. "/comments/hot",
  1289. "weibo_request_comments_hot",
  1290. true,
  1291. void 0,
  1292. "Api为获取评论数据,未登录时伪装为成功获取评论数据"
  1293. ),
  1294. UISwitch(
  1295. "/status/push",
  1296. "weibo_request_status_push",
  1297. true,
  1298. void 0,
  1299. "Api为获取顶部的热点新闻信息流,这里是直接清空json"
  1300. )
  1301. ]
  1302. }
  1303. ]
  1304. },
  1305. {
  1306. text: "Vue-Router路由",
  1307. type: "deepMenu",
  1308. forms: [
  1309. {
  1310. text: "",
  1311. type: "forms",
  1312. forms: [
  1313. UISwitch(
  1314. "监听路由改变",
  1315. "weibo-listenRouterChange",
  1316. true,
  1317. void 0,
  1318. "监听路由改变,动态加载功能"
  1319. ),
  1320. UISwitch(
  1321. "修复用户主页正确跳转",
  1322. "weibo_router_profile_to_user_home",
  1323. true,
  1324. void 0,
  1325. "可以正确跳转至用户主页"
  1326. )
  1327. ]
  1328. }
  1329. ]
  1330. }
  1331. ]
  1332. }
  1333. ]
  1334. };
  1335. const SettingUIHuaTi = {
  1336. id: "weibo-panel-config-huati",
  1337. title: "话题",
  1338. forms: [
  1339. {
  1340. text: "功能",
  1341. type: "forms",
  1342. forms: [
  1343. UISwitch(
  1344. "伪装微博客户端",
  1345. "huati_weibo_masquerade_weibo_client_app",
  1346. true,
  1347. void 0,
  1348. "可以隐藏底部的【在微博内打开】"
  1349. )
  1350. ]
  1351. },
  1352. {
  1353. text: "网络请求(不一定能劫持到)",
  1354. type: "forms",
  1355. forms: [
  1356. UISwitch(
  1357. "/ajax/super/starschedule",
  1358. "huati_weibo_get_more_celebrity_calendar_information",
  1359. true,
  1360. void 0,
  1361. "Api为获取日程数据,开启后可获取正常日程数据"
  1362. )
  1363. ]
  1364. }
  1365. ]
  1366. };
  1367. const SettingUIVideo = {
  1368. id: "weibo-panel-config-video",
  1369. title: "视频",
  1370. forms: [
  1371. {
  1372. text: "功能",
  1373. type: "forms",
  1374. forms: [
  1375. UISelect(
  1376. "视频清晰度",
  1377. "weibo-video-quality",
  1378. "",
  1379. [
  1380. {
  1381. value: "",
  1382. text: "自动"
  1383. },
  1384. {
  1385. value: "mp4_ld_mp4",
  1386. text: "流畅360p"
  1387. },
  1388. {
  1389. value: "mp4_hd_mp4",
  1390. text: "标清480p"
  1391. },
  1392. {
  1393. value: "mp4_720p_mp4",
  1394. text: "高清720p"
  1395. },
  1396. {
  1397. value: "mp4_1080p_mp4",
  1398. text: "超清1080p"
  1399. }
  1400. ],
  1401. void 0,
  1402. "设置视频清晰度,默认自动,其它的清晰度将自动被删除(强制固定选择的清晰度)"
  1403. ),
  1404. UISwitch(
  1405. "解锁1080p",
  1406. "weibo-video-unlockVideo1080p",
  1407. true,
  1408. void 0,
  1409. "请求PC端的视频1080p链接,开启该功能↑选择的1080p才会生效"
  1410. )
  1411. ]
  1412. },
  1413. {
  1414. text: "屏蔽",
  1415. type: "forms",
  1416. forms: [
  1417. UISwitch(
  1418. "【屏蔽】底部工具栏",
  1419. "weibo_video_shield_bottom_toolbar",
  1420. true
  1421. ),
  1422. UISwitch("【屏蔽】相关推荐", "weibo_video_shield_recommend", true),
  1423. UISwitch("【屏蔽】热门评论", "weibo_video_shield_hot_comments", true)
  1424. ]
  1425. },
  1426. {
  1427. text: "webpack",
  1428. type: "forms",
  1429. forms: [
  1430. UISwitch(
  1431. "gotoApp",
  1432. "weibo_video_webpack_gotoApp",
  1433. true,
  1434. void 0,
  1435. "开启后阻止唤醒Scheme"
  1436. )
  1437. ]
  1438. }
  1439. ]
  1440. };
  1441. const SettingUIDetail = {
  1442. id: "weibo-panel-config-detail",
  1443. title: "正文",
  1444. forms: [
  1445. {
  1446. text: "功能",
  1447. type: "forms",
  1448. forms: [
  1449. UISwitch(
  1450. "修改发布时间显示为绝对时间",
  1451. "weibo-detail-setArticleAbsoluteTime",
  1452. false,
  1453. void 0,
  1454. "该功能全局生效包括但不限于微博正文、首页等"
  1455. )
  1456. ]
  1457. }
  1458. ]
  1459. };
  1460. const SettingUISearch = {
  1461. id: "weibo-panel-config-u",
  1462. title: "搜索",
  1463. forms: [
  1464. {
  1465. text: "功能",
  1466. type: "forms",
  1467. forms: [
  1468. UISwitch("自动聚焦搜索框", "weibo-search-autoFocusSearchInput", void 0),
  1469. UISwitch(
  1470. "新增【新标签页打开】按钮",
  1471. "weibo-search-addOpenBlankBtn",
  1472. false,
  1473. void 0,
  1474. "在每个card下面的按钮区域添加该按钮,方便快速在新标签页中打开"
  1475. )
  1476. ]
  1477. }
  1478. ]
  1479. };
  1480. const SettingUICardArticle = {
  1481. id: "weibo-panel-config-card-article",
  1482. title: "头条文章",
  1483. forms: [
  1484. {
  1485. text: "功能",
  1486. type: "forms",
  1487. forms: [
  1488. UISwitch(
  1489. "自动展开全文",
  1490. "card_weibo_com__autoExpandFullArticle",
  1491. true,
  1492. void 0,
  1493. "自动展开全文,屏蔽展开按钮"
  1494. ),
  1495. UISwitch(
  1496. "修复文章作者主页正确跳转",
  1497. "card_weibo_com__repairArticleUserHomeJump",
  1498. true,
  1499. void 0,
  1500. "避免跳转至用户主页时需登录"
  1501. )
  1502. ]
  1503. },
  1504. {
  1505. text: "屏蔽",
  1506. type: "forms",
  1507. forms: [
  1508. UISwitch(
  1509. "【屏蔽】评论",
  1510. "card_weibo_com__blockComment",
  1511. false,
  1512. void 0,
  1513. "屏蔽评论区"
  1514. )
  1515. ]
  1516. }
  1517. ]
  1518. };
  1519. const SettingUIHome = {
  1520. id: "weibo-panel-config-card-article",
  1521. title: "首页",
  1522. forms: [
  1523. {
  1524. text: "功能",
  1525. type: "forms",
  1526. forms: [
  1527. UISwitch(
  1528. "新增超话Tab",
  1529. "weibo-home-addSupertalkTab",
  1530. false,
  1531. void 0,
  1532. "在首页添加超话Tab,方便快速查看超话"
  1533. ),
  1534. UISwitch(
  1535. "新增【新标签页打开】按钮",
  1536. "weibo-home-addOpenBlankBtn",
  1537. false,
  1538. void 0,
  1539. "在每个card下面的按钮区域添加该按钮,方便快速在新标签页中打开"
  1540. )
  1541. ]
  1542. },
  1543. {
  1544. text: "网络拦截",
  1545. type: "forms",
  1546. forms: [
  1547. UISwitch(
  1548. "过滤掉信息流广告",
  1549. "weibo-request-blockArticleAds",
  1550. true,
  1551. void 0,
  1552. '夹杂在文章中间的"微博广告"'
  1553. )
  1554. ]
  1555. },
  1556. {
  1557. text: "屏蔽",
  1558. type: "forms",
  1559. forms: [
  1560. UISwitch(
  1561. "屏蔽消息数量",
  1562. "weibo-home-blockMessageCount",
  1563. false,
  1564. void 0,
  1565. "即登录后右上角的消息提示数"
  1566. )
  1567. ]
  1568. }
  1569. ]
  1570. };
  1571. const SettingUIOther = {
  1572. id: "weibo-panel-config-other",
  1573. title: "其它",
  1574. forms: [
  1575. {
  1576. text: "微博热搜",
  1577. type: "forms",
  1578. forms: [
  1579. UISwitch(
  1580. "新标签页打开",
  1581. "weibo-hot-search-openBlank",
  1582. false,
  1583. void 0,
  1584. "新标签页打开链接"
  1585. )
  1586. ]
  1587. }
  1588. ]
  1589. };
  1590. const PanelUISize = {
  1591. /**
  1592. * 一般设置界面的尺寸
  1593. */
  1594. setting: {
  1595. get width() {
  1596. return window.innerWidth < 550 ? "88vw" : "550px";
  1597. },
  1598. get height() {
  1599. return window.innerHeight < 450 ? "70vh" : "450px";
  1600. }
  1601. }
  1602. };
  1603. const __PopsPanel__ = {
  1604. data: null,
  1605. oneSuccessExecMenu: null,
  1606. onceExec: null,
  1607. listenData: null
  1608. };
  1609. const PopsPanel = {
  1610. /** 数据 */
  1611. $data: {
  1612. /**
  1613. * 菜单项的默认值
  1614. */
  1615. get data() {
  1616. if (__PopsPanel__.data == null) {
  1617. __PopsPanel__.data = new utils.Dictionary();
  1618. }
  1619. return __PopsPanel__.data;
  1620. },
  1621. /**
  1622. * 成功只执行了一次的项
  1623. */
  1624. get oneSuccessExecMenu() {
  1625. if (__PopsPanel__.oneSuccessExecMenu == null) {
  1626. __PopsPanel__.oneSuccessExecMenu = new utils.Dictionary();
  1627. }
  1628. return __PopsPanel__.oneSuccessExecMenu;
  1629. },
  1630. /**
  1631. * 成功只执行了一次的项
  1632. */
  1633. get onceExec() {
  1634. if (__PopsPanel__.onceExec == null) {
  1635. __PopsPanel__.onceExec = new utils.Dictionary();
  1636. }
  1637. return __PopsPanel__.onceExec;
  1638. },
  1639. /** 脚本名,一般用在设置的标题上 */
  1640. get scriptName() {
  1641. return SCRIPT_NAME;
  1642. },
  1643. /** 菜单项的总值在本地数据配置的键名 */
  1644. key: KEY,
  1645. /** 菜单项在attributes上配置的菜单键 */
  1646. attributeKeyName: ATTRIBUTE_KEY,
  1647. /** 菜单项在attributes上配置的菜单默认值 */
  1648. attributeDefaultValueName: ATTRIBUTE_DEFAULT_VALUE
  1649. },
  1650. /** 监听器 */
  1651. $listener: {
  1652. /**
  1653. * 值改变的监听器
  1654. */
  1655. get listenData() {
  1656. if (__PopsPanel__.listenData == null) {
  1657. __PopsPanel__.listenData = new utils.Dictionary();
  1658. }
  1659. return __PopsPanel__.listenData;
  1660. }
  1661. },
  1662. init() {
  1663. this.initPanelDefaultValue();
  1664. this.initExtensionsMenu();
  1665. },
  1666. /** 判断是否是顶层窗口 */
  1667. isTopWindow() {
  1668. return _unsafeWindow.top === _unsafeWindow.self;
  1669. },
  1670. initExtensionsMenu() {
  1671. if (!this.isTopWindow()) {
  1672. return;
  1673. }
  1674. GM_Menu.add([
  1675. {
  1676. key: "show_pops_panel_setting",
  1677. text: "⚙ 设置",
  1678. autoReload: false,
  1679. isStoreValue: false,
  1680. showText(text) {
  1681. return text;
  1682. },
  1683. callback: () => {
  1684. this.showPanel();
  1685. }
  1686. }
  1687. ]);
  1688. },
  1689. /** 初始化本地设置默认的值 */
  1690. initPanelDefaultValue() {
  1691. let that = this;
  1692. function initDefaultValue(config) {
  1693. if (!config.attributes) {
  1694. return;
  1695. }
  1696. let needInitConfig = {};
  1697. let key = config.attributes[ATTRIBUTE_KEY];
  1698. if (key != null) {
  1699. needInitConfig[key] = config.attributes[ATTRIBUTE_DEFAULT_VALUE];
  1700. }
  1701. let __attr_init__ = config.attributes[ATTRIBUTE_INIT];
  1702. if (typeof __attr_init__ === "function") {
  1703. let __attr_result__ = __attr_init__();
  1704. if (typeof __attr_result__ === "boolean" && !__attr_result__) {
  1705. return;
  1706. }
  1707. }
  1708. let initMoreValue = config.attributes[ATTRIBUTE_INIT_MORE_VALUE];
  1709. if (initMoreValue && typeof initMoreValue === "object") {
  1710. Object.assign(needInitConfig, initMoreValue);
  1711. }
  1712. let needInitConfigList = Object.keys(needInitConfig);
  1713. if (!needInitConfigList.length) {
  1714. log.warn("请先配置键", config);
  1715. return;
  1716. }
  1717. needInitConfigList.forEach((__key) => {
  1718. let __defaultValue = needInitConfig[__key];
  1719. if (that.$data.data.has(__key)) {
  1720. log.warn("请检查该key(已存在): " + __key);
  1721. }
  1722. that.$data.data.set(__key, __defaultValue);
  1723. });
  1724. }
  1725. function loopInitDefaultValue(configList) {
  1726. for (let index = 0; index < configList.length; index++) {
  1727. let configItem = configList[index];
  1728. initDefaultValue(configItem);
  1729. let childForms = configItem.forms;
  1730. if (childForms && Array.isArray(childForms)) {
  1731. loopInitDefaultValue(childForms);
  1732. }
  1733. }
  1734. }
  1735. let contentConfigList = this.getPanelContentConfig();
  1736. for (let index = 0; index < contentConfigList.length; index++) {
  1737. let leftContentConfigItem = contentConfigList[index];
  1738. if (!leftContentConfigItem.forms) {
  1739. continue;
  1740. }
  1741. let rightContentConfigList = leftContentConfigItem.forms;
  1742. if (rightContentConfigList && Array.isArray(rightContentConfigList)) {
  1743. loopInitDefaultValue(rightContentConfigList);
  1744. }
  1745. }
  1746. },
  1747. /**
  1748. * 设置值
  1749. * @param key 键
  1750. * @param value 值
  1751. */
  1752. setValue(key, value) {
  1753. let locaData = _GM_getValue(KEY, {});
  1754. let oldValue = locaData[key];
  1755. locaData[key] = value;
  1756. _GM_setValue(KEY, locaData);
  1757. if (this.$listener.listenData.has(key)) {
  1758. this.$listener.listenData.get(key).callback(key, oldValue, value);
  1759. }
  1760. },
  1761. /**
  1762. * 获取值
  1763. * @param key 键
  1764. * @param defaultValue 默认值
  1765. */
  1766. getValue(key, defaultValue) {
  1767. let locaData = _GM_getValue(KEY, {});
  1768. let localValue = locaData[key];
  1769. if (localValue == null) {
  1770. if (this.$data.data.has(key)) {
  1771. return this.$data.data.get(key);
  1772. }
  1773. return defaultValue;
  1774. }
  1775. return localValue;
  1776. },
  1777. /**
  1778. * 删除值
  1779. * @param key 键
  1780. */
  1781. deleteValue(key) {
  1782. let locaData = _GM_getValue(KEY, {});
  1783. let oldValue = locaData[key];
  1784. Reflect.deleteProperty(locaData, key);
  1785. _GM_setValue(KEY, locaData);
  1786. if (this.$listener.listenData.has(key)) {
  1787. this.$listener.listenData.get(key).callback(key, oldValue, void 0);
  1788. }
  1789. },
  1790. /**
  1791. * 监听调用setValue、deleteValue
  1792. * @param key 需要监听的键
  1793. * @param callback
  1794. */
  1795. addValueChangeListener(key, callback) {
  1796. let listenerId = Math.random();
  1797. this.$listener.listenData.set(key, {
  1798. id: listenerId,
  1799. key,
  1800. callback
  1801. });
  1802. return listenerId;
  1803. },
  1804. /**
  1805. * 移除监听
  1806. * @param listenerId 监听的id
  1807. */
  1808. removeValueChangeListener(listenerId) {
  1809. let deleteKey = null;
  1810. for (const [key, value] of this.$listener.listenData.entries()) {
  1811. if (value.id === listenerId) {
  1812. deleteKey = key;
  1813. break;
  1814. }
  1815. }
  1816. if (typeof deleteKey === "string") {
  1817. this.$listener.listenData.delete(deleteKey);
  1818. } else {
  1819. console.warn("没有找到对应的监听器");
  1820. }
  1821. },
  1822. /**
  1823. * 主动触发菜单值改变的回调
  1824. * @param key 菜单键
  1825. * @param newValue 想要触发的新值,默认使用当前值
  1826. * @param oldValue 想要触发的旧值,默认使用当前值
  1827. */
  1828. triggerMenuValueChange(key, newValue, oldValue) {
  1829. if (this.$listener.listenData.has(key)) {
  1830. let listenData = this.$listener.listenData.get(key);
  1831. if (typeof listenData.callback === "function") {
  1832. let value = this.getValue(key);
  1833. let __newValue = value;
  1834. let __oldValue = value;
  1835. if (typeof newValue !== "undefined" && arguments.length > 1) {
  1836. __newValue = newValue;
  1837. }
  1838. if (typeof oldValue !== "undefined" && arguments.length > 2) {
  1839. __oldValue = oldValue;
  1840. }
  1841. listenData.callback(key, __oldValue, __newValue);
  1842. }
  1843. }
  1844. },
  1845. /**
  1846. * 判断该键是否存在
  1847. * @param key 键
  1848. */
  1849. hasKey(key) {
  1850. let locaData = _GM_getValue(KEY, {});
  1851. return key in locaData;
  1852. },
  1853. /**
  1854. * 自动判断菜单是否启用,然后执行回调
  1855. * @param key
  1856. * @param callback 回调
  1857. * @param [isReverse=false] 逆反判断菜单启用
  1858. */
  1859. execMenu(key, callback, isReverse = false) {
  1860. if (!(typeof key === "string" || typeof key === "object" && Array.isArray(key))) {
  1861. throw new TypeError("key 必须是字符串或者字符串数组");
  1862. }
  1863. let runKeyList = [];
  1864. if (typeof key === "object" && Array.isArray(key)) {
  1865. runKeyList = [...key];
  1866. } else {
  1867. runKeyList.push(key);
  1868. }
  1869. let value = void 0;
  1870. for (let index = 0; index < runKeyList.length; index++) {
  1871. const runKey = runKeyList[index];
  1872. if (!this.$data.data.has(runKey)) {
  1873. log.warn(`${key} 键不存在`);
  1874. return;
  1875. }
  1876. let runValue = PopsPanel.getValue(runKey);
  1877. if (isReverse) {
  1878. runValue = !runValue;
  1879. }
  1880. if (!runValue) {
  1881. break;
  1882. }
  1883. value = runValue;
  1884. }
  1885. if (value) {
  1886. callback(value);
  1887. }
  1888. },
  1889. /**
  1890. * 自动判断菜单是否启用,然后执行回调,只会执行一次
  1891. * @param key
  1892. * @param callback 回调
  1893. * @param getValueFn 自定义处理获取当前值,值true是启用并执行回调,值false是不执行回调
  1894. * @param handleValueChangeFn 自定义处理值改变时的回调,值true是启用并执行回调,值false是不执行回调
  1895. */
  1896. execMenuOnce(key, callback, getValueFn, handleValueChangeFn) {
  1897. if (typeof key !== "string") {
  1898. throw new TypeError("key 必须是字符串");
  1899. }
  1900. if (!this.$data.data.has(key)) {
  1901. log.warn(`${key} 键不存在`);
  1902. return;
  1903. }
  1904. if (this.$data.oneSuccessExecMenu.has(key)) {
  1905. return;
  1906. }
  1907. this.$data.oneSuccessExecMenu.set(key, 1);
  1908. let __getValue = () => {
  1909. let localValue = PopsPanel.getValue(key);
  1910. return typeof getValueFn === "function" ? getValueFn(key, localValue) : localValue;
  1911. };
  1912. let resultStyleList = [];
  1913. let dynamicPushStyleNode = ($style) => {
  1914. let __value = __getValue();
  1915. let dynamicResultList = [];
  1916. if ($style instanceof HTMLStyleElement) {
  1917. dynamicResultList = [$style];
  1918. } else if (Array.isArray($style)) {
  1919. dynamicResultList = [
  1920. ...$style.filter(
  1921. (item) => item != null && item instanceof HTMLStyleElement
  1922. )
  1923. ];
  1924. }
  1925. if (__value) {
  1926. resultStyleList = resultStyleList.concat(dynamicResultList);
  1927. } else {
  1928. for (let index = 0; index < dynamicResultList.length; index++) {
  1929. let $css = dynamicResultList[index];
  1930. $css.remove();
  1931. dynamicResultList.splice(index, 1);
  1932. index--;
  1933. }
  1934. }
  1935. };
  1936. let changeCallBack = (currentValue) => {
  1937. let resultList = [];
  1938. if (currentValue) {
  1939. let result = callback(currentValue, dynamicPushStyleNode);
  1940. if (result instanceof HTMLStyleElement) {
  1941. resultList = [result];
  1942. } else if (Array.isArray(result)) {
  1943. resultList = [
  1944. ...result.filter(
  1945. (item) => item != null && item instanceof HTMLStyleElement
  1946. )
  1947. ];
  1948. }
  1949. }
  1950. for (let index = 0; index < resultStyleList.length; index++) {
  1951. let $css = resultStyleList[index];
  1952. $css.remove();
  1953. resultStyleList.splice(index, 1);
  1954. index--;
  1955. }
  1956. resultStyleList = [...resultList];
  1957. };
  1958. this.addValueChangeListener(
  1959. key,
  1960. (__key, oldValue, newValue) => {
  1961. let __newValue = newValue;
  1962. if (typeof handleValueChangeFn === "function") {
  1963. __newValue = handleValueChangeFn(__key, newValue, oldValue);
  1964. }
  1965. changeCallBack(__newValue);
  1966. }
  1967. );
  1968. let value = __getValue();
  1969. if (value) {
  1970. changeCallBack(value);
  1971. }
  1972. },
  1973. /**
  1974. * 父子菜单联动,自动判断菜单是否启用,然后执行回调,只会执行一次
  1975. * @param key 菜单键
  1976. * @param childKey 子菜单键
  1977. * @param callback 回调
  1978. * @param replaceValueFn 用于修改mainValue,返回undefined则不做处理
  1979. */
  1980. execInheritMenuOnce(key, childKey, callback, replaceValueFn) {
  1981. let that = this;
  1982. const handleInheritValue = (key2, childKey2) => {
  1983. let mainValue = that.getValue(key2);
  1984. let childValue = that.getValue(childKey2);
  1985. if (typeof replaceValueFn === "function") {
  1986. let changedMainValue = replaceValueFn(mainValue, childValue);
  1987. if (changedMainValue !== void 0) {
  1988. return changedMainValue;
  1989. }
  1990. }
  1991. return mainValue;
  1992. };
  1993. this.execMenuOnce(
  1994. key,
  1995. callback,
  1996. () => {
  1997. return handleInheritValue(key, childKey);
  1998. },
  1999. () => {
  2000. return handleInheritValue(key, childKey);
  2001. }
  2002. );
  2003. this.execMenuOnce(
  2004. childKey,
  2005. () => {
  2006. },
  2007. () => false,
  2008. () => {
  2009. this.triggerMenuValueChange(key);
  2010. return false;
  2011. }
  2012. );
  2013. },
  2014. /**
  2015. * 根据key执行一次
  2016. * @param key
  2017. */
  2018. onceExec(key, callback) {
  2019. if (typeof key !== "string") {
  2020. throw new TypeError("key 必须是字符串");
  2021. }
  2022. if (this.$data.onceExec.has(key)) {
  2023. return;
  2024. }
  2025. callback();
  2026. this.$data.onceExec.set(key, 1);
  2027. },
  2028. /**
  2029. * 显示设置面板
  2030. */
  2031. showPanel() {
  2032. __pops.panel({
  2033. title: {
  2034. text: `${SCRIPT_NAME}-设置`,
  2035. position: "center",
  2036. html: false,
  2037. style: ""
  2038. },
  2039. content: this.getPanelContentConfig(),
  2040. mask: {
  2041. enable: true,
  2042. clickEvent: {
  2043. toClose: true,
  2044. toHide: false
  2045. }
  2046. },
  2047. width: PanelUISize.setting.width,
  2048. height: PanelUISize.setting.height,
  2049. drag: true,
  2050. only: true,
  2051. style: (
  2052. /*css*/
  2053. `
  2054. aside.pops-panel-aside{
  2055. width: auto !important;
  2056. }
  2057. .pops-panel-textarea textarea{
  2058. height: 100px;
  2059. }
  2060. `
  2061. )
  2062. });
  2063. },
  2064. /**
  2065. * 获取配置内容
  2066. */
  2067. getPanelContentConfig() {
  2068. let configList = [
  2069. SettingUICommon,
  2070. SettingUIHome,
  2071. SettingUIDetail,
  2072. // SettingUIUserHome,
  2073. SettingUISearch,
  2074. SettingUIHuaTi,
  2075. SettingUIVideo,
  2076. SettingUICardArticle,
  2077. SettingUIOther
  2078. ];
  2079. return configList;
  2080. }
  2081. };
  2082. const blockAdsCSS$1 = "/* 底部中间的 登录/注册按钮 */\r\n#app div.main-wrap div.login-box,\r\n/* 主内容底部的小程序横幅推荐 */\r\n#app > div.lite-page-wrap > div > div.main > div > div.wrap,\r\n/* 底部悬浮的在微博内打开 */\r\n#app .woo-frame.blog-config-page div.weibo-btn-box,\r\n/* 顶部的新闻信息流 */\r\n#app .woo-frame div.woo-panel-container.news-banner,\r\n/* 夹杂在card中间的图片横幅,不确定是否会误伤其它正常内容 */\r\n.card .card-main .m-img-box > ul {\r\n display: none !important;\r\n}\r\n/* 搜索域名下的 */\r\n.card.m-panel:has(+ .simple),\r\n.card.m-panel.simple {\r\n display: none !important;\r\n}\r\n";
  2083. let _ajaxHooker_ = null;
  2084. const WeiBoNetWorkHook = {
  2085. get ajaxHooker() {
  2086. if (_ajaxHooker_ == null) {
  2087. log.info("启用ajaxHooker拦截网络");
  2088. _ajaxHooker_ = utils.ajaxHooker();
  2089. _ajaxHooker_.protect();
  2090. }
  2091. return _ajaxHooker_;
  2092. }
  2093. };
  2094. const WeiBoHook = {
  2095. /**
  2096. * 劫持Function.prototype.apply;
  2097. */
  2098. hookApply() {
  2099. log.info("劫持Function.prototype.apply");
  2100. let originApply = _unsafeWindow.Function.prototype.apply;
  2101. _unsafeWindow.Function.prototype.apply = function(...args) {
  2102. var _a2, _b;
  2103. let target = originApply;
  2104. if (args.length !== 2) {
  2105. return Reflect.apply(target, this, args);
  2106. }
  2107. if (args.length === 2 && !Array.isArray(args[1])) {
  2108. return Reflect.apply(target, this, args);
  2109. }
  2110. if (typeof args[1][0] !== "string") {
  2111. return Reflect.apply(target, this, args);
  2112. }
  2113. const ApiPath = args[1][0];
  2114. const ApiSearchParams = (_b = (_a2 = args[1]) == null ? void 0 : _a2[1]) == null ? void 0 : _b["params"];
  2115. if (ApiPath === "api/attitudes/create" && PopsPanel.getValue("weibo_apply_attitudes_create")) {
  2116. log.success("拦截跳转登录");
  2117. return new Promise((resolve) => {
  2118. resolve({
  2119. data: {}
  2120. });
  2121. });
  2122. } else if (ApiPath === "api/likes/update" && PopsPanel.getValue("weibo_apply_likes_update")) {
  2123. log.success("拦截点赞跳转登录");
  2124. return new Promise((resolve) => {
  2125. resolve({
  2126. data: {}
  2127. });
  2128. });
  2129. } else if (ApiPath === "api/comments/create" && PopsPanel.getValue("weibo_apply_comments_create")) {
  2130. log.success("拦截评论跳转登录");
  2131. return new Promise((resolve) => {
  2132. resolve({
  2133. data: {}
  2134. });
  2135. });
  2136. } else if (ApiPath === "api/friendships/create" && PopsPanel.getValue("weibo_apply_friendships_create")) {
  2137. log.success("拦截关注跳转登录");
  2138. return new Promise((resolve) => {
  2139. resolve({
  2140. data: {}
  2141. });
  2142. });
  2143. } else if (ApiPath === "api/comments/reply" && PopsPanel.getValue("weibo_apply_comments_reply")) {
  2144. log.success("拦截回复跳转登录");
  2145. return new Promise((resolve, reject) => {
  2146. resolve({
  2147. data: {
  2148. ok: 200
  2149. }
  2150. });
  2151. });
  2152. } else if (ApiPath.startsWith("profile/info") && PopsPanel.getValue("weibo_apply_profile_info")) {
  2153. log.success("优化跳转xx微博主页", ApiSearchParams);
  2154. let uidHomeUrl = `https://weibo.com/${ApiSearchParams["uid"]}`;
  2155. log.success("跳转微博主页:" + uidHomeUrl);
  2156. window.location.href = uidHomeUrl;
  2157. return null;
  2158. } else if (ApiPath === "comments/hotflow" && PopsPanel.getValue("weibo_apply_comments_hotflow")) {
  2159. if (!("id" in ApiSearchParams && "max_id_type" in ApiSearchParams && "mid" in ApiSearchParams) || "id" in ApiSearchParams && "max_id" in ApiSearchParams && "max_id_type" in ApiSearchParams && "mid" in ApiSearchParams) {
  2160. log.success("拦截下拉加载更多评论跳转登录", ApiSearchParams);
  2161. return new Promise((resolve) => {
  2162. resolve({
  2163. ok: 1,
  2164. data: {
  2165. data: [],
  2166. total_number: 0
  2167. }
  2168. });
  2169. });
  2170. }
  2171. } else if (ApiPath === "comments/hotFlowChild" && PopsPanel.getValue("weibo_apply_comments_hotFlowChild")) {
  2172. if ("max_id" in ApiSearchParams && ApiSearchParams["max_id"] !== 0) {
  2173. log.success(
  2174. "拦截评论中的评论下拉加载更多评论跳转登录",
  2175. ApiSearchParams
  2176. );
  2177. return new Promise((resolve) => {
  2178. resolve({
  2179. data: {
  2180. ok: 1,
  2181. data: [],
  2182. rootComment: [],
  2183. total_number: 0
  2184. }
  2185. });
  2186. });
  2187. }
  2188. } else if (ApiPath === "api/statuses/repostTimeline" && PopsPanel.getValue("weibo_apply_statuses_repostTimeline")) {
  2189. log.success("拦截查看转发数据,因为需登录", ApiSearchParams);
  2190. return new Promise((resolve) => {
  2191. resolve({
  2192. data: {
  2193. ok: 1,
  2194. data: {
  2195. data: [],
  2196. total_number: 0
  2197. }
  2198. }
  2199. });
  2200. });
  2201. } else ;
  2202. return Reflect.apply(target, this, args);
  2203. };
  2204. },
  2205. /**
  2206. * 拦截网络
  2207. */
  2208. hookNetWork() {
  2209. WeiBoNetWorkHook.ajaxHooker.hook(function(request) {
  2210. let requestUrl = CommonUtil.fixUrl(request.url);
  2211. log.info("[ajaxHookr] " + requestUrl);
  2212. if (requestUrl.startsWith("https://m.weibo.cn/api/config") && PopsPanel.getValue("weibo_request_api_config")) {
  2213. request.response = function(originResponse) {
  2214. let originResponseData = utils.toJSON(originResponse.responseText);
  2215. if (!originResponseData.data.login) {
  2216. log.error("由于未登录,伪装为已登录状态");
  2217. originResponseData.data.login = true;
  2218. originResponseData.data.uid = "";
  2219. originResponseData.preferQuickapp = 0;
  2220. Reflect.deleteProperty(originResponseData.data, "loginUrl");
  2221. Reflect.deleteProperty(originResponseData.data, "wx_callback");
  2222. Reflect.deleteProperty(originResponseData.data, "wx_authorize");
  2223. Reflect.deleteProperty(
  2224. originResponseData.data,
  2225. "passport_login_url"
  2226. );
  2227. originResponse.responseText = JSON.stringify(originResponseData);
  2228. }
  2229. };
  2230. } else if (requestUrl.startsWith("https://m.weibo.cn/comments/hot") && PopsPanel.getValue("weibo_request_comments_hot")) {
  2231. request.response = function(originResponse) {
  2232. let originResponseData = utils.toJSON(originResponse.responseText);
  2233. if (originResponseData.ok !== 1) {
  2234. log.error("由于尚未登录,获取不到更多评论数据", originResponseData);
  2235. originResponseData = {
  2236. ok: 1
  2237. };
  2238. originResponse.responseText = JSON.stringify(originResponseData);
  2239. }
  2240. };
  2241. } else if (requestUrl.startsWith("https://m.weibo.cn/status/push?") && PopsPanel.getValue("weibo_request_status_push")) {
  2242. request.response = function(originResponse) {
  2243. let originResponseData = utils.toJSON(originResponse.responseText);
  2244. Reflect.set(originResponse, "json", {});
  2245. log.info(`重构/status/push响应`, originResponseData);
  2246. originResponse.responseText = JSON.stringify(originResponseData);
  2247. };
  2248. } else if (requestUrl.startsWith("https://m.weibo.cn/api/container/getIndex") && PopsPanel.getValue("weibo-request-blockArticleAds")) {
  2249. request.response = function(originResponse) {
  2250. var _a2;
  2251. let originResponseData = utils.toJSON(originResponse.responseText);
  2252. let cards = originResponseData["data"]["cards"];
  2253. for (let index = 0; index < cards.length; index++) {
  2254. const card = cards[index];
  2255. let mblog = card == null ? void 0 : card.mblog;
  2256. if (mblog) {
  2257. let id = mblog.id;
  2258. let ad_state = mblog == null ? void 0 : mblog.ad_state;
  2259. let cardText = mblog == null ? void 0 : mblog.text;
  2260. (_a2 = mblog == null ? void 0 : mblog.page_info) == null ? void 0 : _a2.page_title;
  2261. if (ad_state) {
  2262. cards.splice(index, 1);
  2263. index--;
  2264. log.info(`移除广告urlhttps://m.weibo.cn/detail/` + id);
  2265. log.info(`移除广告card:` + cardText);
  2266. }
  2267. }
  2268. }
  2269. originResponse.responseText = JSON.stringify(originResponseData);
  2270. };
  2271. }
  2272. });
  2273. },
  2274. /**
  2275. * 劫持webpack
  2276. * @param webpackName 当前全局变量的webpack名
  2277. * @param mainCoreData 需要劫持的webpack的顶部core,例如:(window.webpackJsonp = window.webpackJsonp || []).push([["core:0"],{}])
  2278. * @param checkCallBack 如果mainCoreData匹配上,则调用此回调函数
  2279. */
  2280. hookWebpack(webpackName = "webpackJsonp", mainCoreData, checkCallBack) {
  2281. let originObject = void 0;
  2282. Object.defineProperty(_unsafeWindow, webpackName, {
  2283. get() {
  2284. return originObject;
  2285. },
  2286. set(newValue) {
  2287. log.success("成功劫持webpack,当前webpack名:" + webpackName);
  2288. originObject = newValue;
  2289. const originPush = originObject.push;
  2290. originObject.push = function(...args) {
  2291. let _mainCoreData = args[0][0];
  2292. if (mainCoreData == _mainCoreData || Array.isArray(mainCoreData) && Array.isArray(_mainCoreData) && JSON.stringify(mainCoreData) === JSON.stringify(_mainCoreData)) {
  2293. Object.keys(args[0][1]).forEach((keyName) => {
  2294. let originSwitchFunc = args[0][1][keyName];
  2295. args[0][1][keyName] = function(..._args) {
  2296. let result = originSwitchFunc.call(this, ..._args);
  2297. _args[0] = checkCallBack(_args[0]);
  2298. return result;
  2299. };
  2300. });
  2301. }
  2302. return originPush.call(this, ...args);
  2303. };
  2304. }
  2305. });
  2306. },
  2307. /**
  2308. * 拦截Vue Router跳转
  2309. */
  2310. hookVueRouter() {
  2311. VueUtils.waitVuePropToSet("#app", [
  2312. {
  2313. msg: "等待获取属性 __vue__.$router",
  2314. check(vueIns) {
  2315. var _a2;
  2316. return typeof ((_a2 = vueIns == null ? void 0 : vueIns.$router) == null ? void 0 : _a2.push) === "function";
  2317. },
  2318. set(vueIns) {
  2319. log.success("拦截Vue路由跳转");
  2320. let beforeEachFn = (to, from, next) => {
  2321. var _a2;
  2322. if (to.name === "profile") {
  2323. if (PopsPanel.getValue("weibo_router_profile_to_user_home")) {
  2324. let uid = (_a2 = to == null ? void 0 : to.params) == null ? void 0 : _a2.uid;
  2325. if (uid == null) {
  2326. log.error("获取uid失败");
  2327. Qmsg.error("获取uid失败");
  2328. return;
  2329. }
  2330. log.success(`修复跳转${uid}微博主页`);
  2331. let uidHomeUrl = `https://m.weibo.cn/u/${uid}`;
  2332. window.location.href = uidHomeUrl;
  2333. return;
  2334. }
  2335. } else if ((to == null ? void 0 : to.name) === "detail") ;
  2336. next();
  2337. };
  2338. vueIns.$router.beforeEach(beforeEachFn);
  2339. vueIns.$router.afterEach((to, from) => {
  2340. PopsPanel.execMenu("weibo-listenRouterChange", () => {
  2341. log.info("路由更新,重载功能");
  2342. WeiBo.init();
  2343. });
  2344. });
  2345. let ownHookIndex = vueIns.$router.beforeHooks.findIndex(
  2346. (item) => item == beforeEachFn
  2347. );
  2348. if (ownHookIndex !== -1) {
  2349. let ownHook = vueIns.$router.beforeHooks.splice(ownHookIndex, 1);
  2350. vueIns.$router.beforeHooks.splice(0, 0, ...ownHook);
  2351. } else {
  2352. log.error("$router未在beforeHooks内找到自定义的beforeEach");
  2353. }
  2354. }
  2355. }
  2356. ]);
  2357. },
  2358. /**
  2359. * 禁止Service Worker注册
  2360. */
  2361. hookServiceWorkerRegister() {
  2362. log.info("hook => navigator.serviceWorker.register");
  2363. _unsafeWindow.Object.defineProperty(
  2364. _unsafeWindow.navigator.serviceWorker,
  2365. "register",
  2366. {
  2367. get() {
  2368. return function(...args) {
  2369. log.success("劫持navigator.serviceWorker.register: ", args);
  2370. };
  2371. }
  2372. }
  2373. );
  2374. }
  2375. };
  2376. const WeiBoRouter = {
  2377. /**
  2378. * 移动端微博
  2379. * @returns
  2380. */
  2381. isMWeiBo() {
  2382. return window.location.hostname === "m.weibo.cn";
  2383. },
  2384. /**
  2385. * 移动端微博-首页
  2386. */
  2387. isMWeiBoHome() {
  2388. return this.isMWeiBo() && window.location.pathname === "/";
  2389. },
  2390. /**
  2391. * 移动端微博-微博正文
  2392. */
  2393. isMWeiBo_detail() {
  2394. return this.isMWeiBo() && window.location.pathname.startsWith("/detail/");
  2395. },
  2396. /**
  2397. * 移动端微博-微博正文
  2398. */
  2399. isMWeiBo_status() {
  2400. return this.isMWeiBo() && window.location.pathname.startsWith("/status/");
  2401. },
  2402. /**
  2403. * 移动端微博-用户主页
  2404. */
  2405. isMWeiBo_userHome() {
  2406. return this.isMWeiBo() && window.location.pathname.startsWith("/u/");
  2407. },
  2408. /**
  2409. * 移动端微博-搜索
  2410. */
  2411. isMWeiBo_search() {
  2412. return this.isMWeiBo() && window.location.pathname.startsWith("/search");
  2413. },
  2414. /**
  2415. * 移动端微博-微博热搜
  2416. */
  2417. isMWeiBo_HotSearch() {
  2418. let searchParams = new URLSearchParams(globalThis.location.search);
  2419. let containerid = searchParams.get("containerid");
  2420. return this.isMWeiBo() && window.location.pathname.startsWith("/p/index") && typeof containerid === "string" && containerid.startsWith("106003");
  2421. },
  2422. /**
  2423. * 话题
  2424. */
  2425. isHuaTi() {
  2426. return window.location.hostname === "huati.weibo.cn";
  2427. },
  2428. /**
  2429. * 视频页
  2430. */
  2431. isVideo() {
  2432. return window.location.hostname === "h5.video.weibo.com";
  2433. },
  2434. /**
  2435. * 头条
  2436. */
  2437. isCard() {
  2438. return window.location.hostname === "card.weibo.com";
  2439. },
  2440. /**
  2441. * 头条文章
  2442. */
  2443. isCardArticle() {
  2444. return this.isCard() && window.location.pathname.startsWith("/article/");
  2445. },
  2446. /**
  2447. * 微博直播页面
  2448. */
  2449. isLive() {
  2450. return window.location.hostname === "weibo.com" && window.location.pathname.startsWith("/l/wblive/m/show/");
  2451. }
  2452. };
  2453. const WeiBoHuaTi = {
  2454. init() {
  2455. PopsPanel.execMenu("huati_weibo_masquerade_weibo_client_app", () => {
  2456. this.isWeibo();
  2457. });
  2458. PopsPanel.execMenuOnce(
  2459. "huati_weibo_get_more_celebrity_calendar_information",
  2460. () => {
  2461. this.hookNetWorkWithGetMoreCelebrityCalendarInformation();
  2462. }
  2463. );
  2464. },
  2465. /**
  2466. * 伪装微博
  2467. */
  2468. isWeibo() {
  2469. log.info("伪装微博");
  2470. VueUtils.waitVuePropToSet("#loadMore", [
  2471. {
  2472. msg: "等待设置属性 __vue__.isWeibo",
  2473. check(vueObj) {
  2474. return typeof vueObj.isWeibo === "boolean";
  2475. },
  2476. set(vueObj) {
  2477. vueObj.isWeibo = true;
  2478. log.success("成功设置属性 __vue__.isWeibo=true");
  2479. }
  2480. }
  2481. ]);
  2482. },
  2483. /**
  2484. * 劫持请求让获取更多名人日历信息
  2485. */
  2486. hookNetWorkWithGetMoreCelebrityCalendarInformation() {
  2487. WeiBoNetWorkHook.ajaxHooker.hook((request) => {
  2488. log.info("ajaxHookr: ", request.url);
  2489. if (!request.url.startsWith("/ajax/super/starschedule?")) {
  2490. return;
  2491. }
  2492. request.response = async (res) => {
  2493. let getResp = await httpx.get(request.url, {
  2494. headers: {
  2495. Host: globalThis.location.hostname,
  2496. Accept: "application/json, text/plain, */*",
  2497. "X-Requested-With": "XMLHttpRequest",
  2498. "sec-ch-ua-mobile": "?1",
  2499. "User-Agent": utils.getRandomAndroidUA() + " Weibo (__weibo__)",
  2500. "sec-ch-ua-platform": "Android",
  2501. "Sec-Fetch-Site": "same-origin",
  2502. "Sec-Fetch-Mode": "cors",
  2503. "Sec-Fetch-Dest": "empty",
  2504. Referer: globalThis.location.href,
  2505. "Accept-Encoding": "gzip, deflate, br",
  2506. "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7"
  2507. }
  2508. });
  2509. res.response = getResp.data.responseText;
  2510. res.responseText = getResp.data.responseText;
  2511. };
  2512. });
  2513. }
  2514. };
  2515. const WeiBoVideoHook = {
  2516. init() {
  2517. this.hookWebpack();
  2518. },
  2519. /**
  2520. * 劫持webpack
  2521. */
  2522. hookWebpack() {
  2523. log.info("劫持webpack");
  2524. WeiBoHook.hookWebpack("webpackJsonp", "chunk-common", (webpackExports) => {
  2525. if (typeof (webpackExports == null ? void 0 : webpackExports.exports) === "object" && typeof webpackExports.exports["a"] === "object" && typeof webpackExports.exports["a"]["gotoApp"] === "function" && PopsPanel.getValue("weibo_video_webpack_gotoApp")) {
  2526. log.success("成功劫持webpack调用函数", webpackExports);
  2527. webpackExports.exports["a"]["gotoApp"] = function(...args) {
  2528. log.info("阻止唤醒App:", args);
  2529. };
  2530. return webpackExports;
  2531. }
  2532. });
  2533. }
  2534. };
  2535. const WeiBoVideo = {
  2536. init() {
  2537. PopsPanel.onceExec("weibo-video-init-hook", () => {
  2538. WeiBoVideoHook.init();
  2539. });
  2540. PopsPanel.execMenuOnce("weibo_video_shield_bottom_toolbar", () => {
  2541. return this.shieldBottomToolBar();
  2542. });
  2543. PopsPanel.execMenuOnce("weibo_video_shield_hot_comments", () => {
  2544. return this.shieldHotComments();
  2545. });
  2546. PopsPanel.execMenuOnce("weibo_video_shield_recommend", () => {
  2547. return this.shieldRecommend();
  2548. });
  2549. },
  2550. /** 【屏蔽】底部工具栏 */
  2551. shieldBottomToolBar() {
  2552. log.info("【屏蔽】底部工具栏");
  2553. return CommonUtil.addBlockCSS(".woo-toolBar");
  2554. },
  2555. /** 【屏蔽】相关推荐 */
  2556. shieldRecommend() {
  2557. log.info("【屏蔽】相关推荐");
  2558. return CommonUtil.addBlockCSS(
  2559. '#app .woo-panel[class*="Playdetail_card_"]:nth-child(2)'
  2560. );
  2561. },
  2562. /** 【屏蔽】热门评论 */
  2563. shieldHotComments() {
  2564. log.info("【屏蔽】热门评论");
  2565. return CommonUtil.addBlockCSS(
  2566. '#app .woo-panel[class*="Playdetail_card_"]:nth-child(3)'
  2567. );
  2568. }
  2569. };
  2570. const blockAdsCSS = "/* 文章内容的底部的广告 */\r\n#app .ad-wrap {\r\n display: none !important;\r\n}\r\n";
  2571. const WeiBoDetail = {
  2572. init() {
  2573. PopsPanel.onceExec("weibo-detail-blockAds", () => {
  2574. return addStyle(blockAdsCSS);
  2575. });
  2576. },
  2577. /**
  2578. * 设置正文显示的时间为绝对时间
  2579. */
  2580. setArticleAbsoluteTime() {
  2581. log.info(`监听并设置正文显示的时间为绝对时间`);
  2582. utils.mutationObserver(document.documentElement, {
  2583. config: {
  2584. subtree: true,
  2585. childList: true
  2586. },
  2587. immediate: true,
  2588. callback: () => {
  2589. function handleCardMainTime() {
  2590. Array.from(
  2591. $$(
  2592. ".card.m-panel .m-text-cut .time:not([data-gm-absolute-time])"
  2593. )
  2594. ).forEach(($time) => {
  2595. var _a2;
  2596. let $card = $time.closest(".card.m-panel");
  2597. let cardVueIns = VueUtils.getVue($card);
  2598. if (!cardVueIns) {
  2599. return;
  2600. }
  2601. let createTime = (_a2 = cardVueIns == null ? void 0 : cardVueIns.item) == null ? void 0 : _a2.created_at;
  2602. if (typeof createTime !== "string") {
  2603. return;
  2604. }
  2605. if ($time.innerText.includes("编辑")) {
  2606. return;
  2607. }
  2608. let createTimeObj = new Date(createTime);
  2609. let formatCreateTime = utils.formatTime(
  2610. createTimeObj,
  2611. "yyyy-MM-dd HH:mm:ss"
  2612. );
  2613. $time.innerText = formatCreateTime;
  2614. $time.setAttribute("data-gm-absolute-time", "true");
  2615. });
  2616. }
  2617. function handleCardLzlTime() {
  2618. let $litePageWrap = $(".lite-page-wrap");
  2619. let litePageWrapVueIns = VueUtils.getVue($litePageWrap);
  2620. if (litePageWrapVueIns) {
  2621. let curWeiboData = litePageWrapVueIns == null ? void 0 : litePageWrapVueIns.curWeiboData;
  2622. let $timeList = Array.from(
  2623. $$(
  2624. ".lite-page-comment .card .card-main .m-box .time"
  2625. )
  2626. );
  2627. if ($timeList.length === curWeiboData.commentLists.length + 1) {
  2628. $timeList.forEach(($time, index) => {
  2629. if ($time.hasAttribute("data-gm-absolute-time")) {
  2630. return;
  2631. }
  2632. if (index === 0) {
  2633. let createTimeObj = new Date(
  2634. curWeiboData.rootComment.created_at
  2635. );
  2636. let formatCreateTime = utils.formatTime(
  2637. createTimeObj,
  2638. "yyyy-MM-dd HH:mm:ss"
  2639. );
  2640. $time.innerText = formatCreateTime;
  2641. } else {
  2642. let createTimeObj = new Date(
  2643. curWeiboData.commentLists[index - 1].created_at
  2644. );
  2645. let formatCreateTime = utils.formatTime(
  2646. createTimeObj,
  2647. "yyyy-MM-dd HH:mm:ss"
  2648. );
  2649. $time.innerText = formatCreateTime;
  2650. }
  2651. $time.setAttribute("data-gm-absolute-time", "true");
  2652. });
  2653. } else {
  2654. if ($timeList.length !== 0) {
  2655. log.warn("楼中楼时间设置失败,数量不一致");
  2656. }
  2657. }
  2658. }
  2659. }
  2660. function handleCardCommentTime() {
  2661. Array.from(
  2662. $$(
  2663. ".comment-content .card .m-box .time:not([data-gm-absolute-time])"
  2664. )
  2665. ).forEach(($time) => {
  2666. var _a2, _b;
  2667. let $card = $time.closest(".card");
  2668. let $cardParent = $card.parentElement;
  2669. let cardVueIns = VueUtils.getVue($card) || VueUtils.getVue($cardParent);
  2670. if (!cardVueIns) {
  2671. return;
  2672. }
  2673. let createTime = (_a2 = cardVueIns == null ? void 0 : cardVueIns.item) == null ? void 0 : _a2.created_at;
  2674. if (typeof createTime !== "string") {
  2675. return;
  2676. }
  2677. let createTimeObj = new Date(createTime);
  2678. let formatCreateTime = utils.formatTime(
  2679. createTimeObj,
  2680. "yyyy-MM-dd HH:mm:ss"
  2681. );
  2682. $time.innerText = `${formatCreateTime} ${((_b = cardVueIns == null ? void 0 : cardVueIns.item) == null ? void 0 : _b.source) || ""}`;
  2683. $time.setAttribute("data-gm-absolute-time", "true");
  2684. });
  2685. }
  2686. let searchParams = new URLSearchParams(window.location.search);
  2687. if (WeiBoRouter.isMWeiBo_detail() || WeiBoRouter.isMWeiBo_status()) {
  2688. if (searchParams.has("cid")) {
  2689. handleCardLzlTime();
  2690. } else {
  2691. handleCardMainTime();
  2692. handleCardCommentTime();
  2693. }
  2694. } else {
  2695. handleCardMainTime();
  2696. }
  2697. }
  2698. });
  2699. }
  2700. };
  2701. const WeiBoSearch = {
  2702. init() {
  2703. PopsPanel.execMenuOnce("weibo-search-addOpenBlankBtn", () => {
  2704. this.addOpenBlankBtn();
  2705. });
  2706. domUtils.ready(() => {
  2707. PopsPanel.execMenu("weibo-search-autoFocusSearchInput", () => {
  2708. this.autoFocusSearchInput();
  2709. });
  2710. });
  2711. },
  2712. /**
  2713. * 自动聚焦搜索框
  2714. */
  2715. autoFocusSearchInput() {
  2716. log.info(`自动聚焦搜索框`);
  2717. utils.waitNode(`.ntop-nav input[type="search"]`).then(($input) => {
  2718. if (!$input) {
  2719. log.error("未找到搜索框");
  2720. Qmsg.error("未找到搜索框");
  2721. return;
  2722. }
  2723. let searchParams = new URLSearchParams(window.location.search);
  2724. if (!searchParams.has("containerid")) {
  2725. log.warn("不存在containerid参数");
  2726. return;
  2727. }
  2728. let containeridSearchParams = new URLSearchParams(
  2729. searchParams.get("containerid")
  2730. );
  2731. if (containeridSearchParams.has("q")) {
  2732. log.warn("containerid参数中存在q参数,是搜索结果页面");
  2733. return;
  2734. }
  2735. log.success(
  2736. "containerid参数中不存在q参数,所以是主搜索页面,聚焦输入框"
  2737. );
  2738. setTimeout(() => {
  2739. $input.focus();
  2740. }, 250);
  2741. });
  2742. },
  2743. /**
  2744. * 新增新标签页打开按钮
  2745. */
  2746. addOpenBlankBtn() {
  2747. utils.mutationObserver(document.documentElement, {
  2748. config: {
  2749. subtree: true,
  2750. childList: true
  2751. },
  2752. immediate: true,
  2753. callback() {
  2754. if (!WeiBoRouter.isMWeiBo_search()) {
  2755. return;
  2756. }
  2757. document.querySelectorAll(
  2758. ".card footer.m-ctrl-box:not(:has(.gm-open-blank))"
  2759. ).forEach(($footerCtrl) => {
  2760. if ($footerCtrl.querySelector(".gm-open-blank")) {
  2761. return;
  2762. }
  2763. let $ownDiyBtn = domUtils.createElement("div", {
  2764. innerHTML: (
  2765. /*html*/
  2766. `
  2767. <h4>新标签页打开</h4>
  2768. `
  2769. )
  2770. });
  2771. $ownDiyBtn.classList.add(
  2772. "m-diy-btn",
  2773. "m-box-col",
  2774. "m-box-center",
  2775. "m-box-center-a",
  2776. "gm-open-blank"
  2777. );
  2778. domUtils.on($ownDiyBtn, "click", (event) => {
  2779. var _a2;
  2780. utils.preventEvent(event);
  2781. let vueIns = VueUtils.getVue($footerCtrl);
  2782. if (!vueIns) {
  2783. Qmsg.error("没有找到对应的Vue实例");
  2784. return;
  2785. }
  2786. let id = (_a2 = vueIns == null ? void 0 : vueIns.item) == null ? void 0 : _a2.id;
  2787. if (typeof id !== "string") {
  2788. Qmsg.error("没有找到对应的id");
  2789. return;
  2790. }
  2791. let url = `${window.location.origin}/detail/${id}`;
  2792. log.info(`新标签页打开:${url}`);
  2793. window.open(url, "_blank");
  2794. });
  2795. let $diyBtnList = $footerCtrl.querySelectorAll(".m-diy-btn");
  2796. if ($diyBtnList.length) {
  2797. domUtils.after($diyBtnList[$diyBtnList.length - 1], $ownDiyBtn);
  2798. } else {
  2799. domUtils.append($footerCtrl, $ownDiyBtn);
  2800. }
  2801. });
  2802. }
  2803. });
  2804. }
  2805. };
  2806. const WeiBoCardArticle = {
  2807. init() {
  2808. PopsPanel.execMenuOnce("card_weibo_com__autoExpandFullArticle", () => {
  2809. return this.autoExpandFullArticle();
  2810. });
  2811. PopsPanel.execMenuOnce("card_weibo_com__blockComment", () => {
  2812. return this.blockComment();
  2813. });
  2814. PopsPanel.execMenuOnce("card_weibo_com__repairArticleUserHomeJump", () => {
  2815. this.repairArticleUserHomeJump();
  2816. });
  2817. },
  2818. /**
  2819. * 自动展开全文
  2820. */
  2821. autoExpandFullArticle() {
  2822. log.info("自动展开全文");
  2823. return [
  2824. addStyle(
  2825. /*css*/
  2826. `
  2827. .m-container-max .f-art,
  2828. .m-container-max .art-con-new{
  2829. height: unset !important;
  2830. overflow: unset !important;
  2831. }
  2832. `
  2833. ),
  2834. CommonUtil.addBlockCSS(".m-container-max .f-art-opt")
  2835. ];
  2836. },
  2837. /**
  2838. * 屏蔽评论
  2839. */
  2840. blockComment() {
  2841. log.info("【屏蔽】评论");
  2842. return CommonUtil.addBlockCSS(".m-container-max .m-panel1");
  2843. },
  2844. /**
  2845. * 修复文章用户主页跳转
  2846. */
  2847. repairArticleUserHomeJump() {
  2848. log.info("修复文章用户主页跳转");
  2849. domUtils.on(
  2850. document,
  2851. "click",
  2852. ".m-feed .f-art-user-v2",
  2853. (event) => {
  2854. let $click = event.target;
  2855. let jQueryEventName = Object.keys($click).find(
  2856. (key) => key.startsWith("jQuery")
  2857. );
  2858. if (!jQueryEventName) {
  2859. return;
  2860. }
  2861. utils.preventEvent(event);
  2862. let jQueryEvent = $click[jQueryEventName];
  2863. let data = jQueryEvent["events"]["click"][0]["data"];
  2864. log.success("跳转信息:", data);
  2865. let url = data["url"] || data["target_url"];
  2866. window.open(url, "_blank");
  2867. },
  2868. {
  2869. capture: true
  2870. }
  2871. );
  2872. }
  2873. };
  2874. const WeiBoHome = {
  2875. init() {
  2876. PopsPanel.execMenuOnce("weibo-home-blockMessageCount", () => {
  2877. return this.blockMessageCount();
  2878. });
  2879. PopsPanel.execMenuOnce("weibo-home-addOpenBlankBtn", () => {
  2880. this.addOpenBlankBtn();
  2881. });
  2882. domUtils.ready(() => {
  2883. PopsPanel.execMenuOnce("weibo-home-addSupertalkTab", () => {
  2884. this.addSupertalkTab();
  2885. });
  2886. });
  2887. },
  2888. /**
  2889. * 屏蔽右上角的信息红点(登录后)
  2890. */
  2891. blockMessageCount() {
  2892. log.info(`屏蔽右上角的信息红点(登录后)`);
  2893. return CommonUtil.addBlockCSS(".nav-right .m-bubble");
  2894. },
  2895. /**
  2896. * 新增Tab - 超话
  2897. */
  2898. addSupertalkTab() {
  2899. VueUtils.waitVuePropToSet(".main-top", {
  2900. check(vueObj) {
  2901. return Array.isArray(vueObj == null ? void 0 : vueObj.tabs);
  2902. },
  2903. set(vueObj) {
  2904. var _a2;
  2905. log.success(`添加顶部Tab - 超话`);
  2906. (_a2 = vueObj == null ? void 0 : vueObj.tabs) == null ? void 0 : _a2.push({
  2907. children: [
  2908. {
  2909. api: "api/container/getIndex?containerid=100803",
  2910. gid: "100803",
  2911. name: "超话社区",
  2912. type: 1
  2913. }
  2914. ]
  2915. });
  2916. return;
  2917. }
  2918. });
  2919. },
  2920. /**
  2921. * 新增新标签页打开按钮
  2922. */
  2923. addOpenBlankBtn() {
  2924. utils.mutationObserver(document.documentElement, {
  2925. config: {
  2926. subtree: true,
  2927. childList: true
  2928. },
  2929. immediate: true,
  2930. callback() {
  2931. if (!WeiBoRouter.isMWeiBoHome()) {
  2932. return;
  2933. }
  2934. document.querySelectorAll(
  2935. ".main-wrap .wb-item .card .f-footer-ctrl:not(:has(.gm-open-blank))"
  2936. ).forEach(($footerCtrl) => {
  2937. if ($footerCtrl.querySelector(".gm-open-blank")) {
  2938. return;
  2939. }
  2940. let $ownDiyBtn = domUtils.createElement("div", {
  2941. innerHTML: (
  2942. /*html*/
  2943. `
  2944. <h4>新标签页打开</h4>
  2945. `
  2946. )
  2947. });
  2948. $ownDiyBtn.classList.add(
  2949. "m-diy-btn",
  2950. "m-box-center-a",
  2951. "gm-open-blank"
  2952. );
  2953. domUtils.on($ownDiyBtn, "click", (event) => {
  2954. var _a2;
  2955. utils.preventEvent(event);
  2956. let vueIns = VueUtils.getVue($footerCtrl);
  2957. if (!vueIns) {
  2958. Qmsg.error("没有找到对应的Vue实例");
  2959. return;
  2960. }
  2961. let id = (_a2 = vueIns == null ? void 0 : vueIns.item) == null ? void 0 : _a2.id;
  2962. if (typeof id !== "string") {
  2963. Qmsg.error("没有找到对应的id");
  2964. return;
  2965. }
  2966. let url = `${window.location.origin}/detail/${id}`;
  2967. log.info(`新标签页打开:${url}`);
  2968. window.open(url, "_blank");
  2969. });
  2970. let $diyBtnList = $footerCtrl.querySelectorAll(".m-diy-btn");
  2971. if ($diyBtnList.length) {
  2972. domUtils.after($diyBtnList[$diyBtnList.length - 1], $ownDiyBtn);
  2973. } else {
  2974. domUtils.append($footerCtrl, $ownDiyBtn);
  2975. }
  2976. });
  2977. }
  2978. });
  2979. }
  2980. };
  2981. const WeiBoHotSearch = {
  2982. init() {
  2983. PopsPanel.execMenuOnce("weibo-hot-search-openBlank", () => {
  2984. this.openBlank();
  2985. });
  2986. },
  2987. /**
  2988. * 新标签页打开链接
  2989. */
  2990. openBlank() {
  2991. DOMUtils.on(
  2992. document,
  2993. "click",
  2994. ".card-list .card",
  2995. (event) => {
  2996. utils.preventEvent(event);
  2997. let vueIns = VueUtils.getVue(event.target);
  2998. if (!vueIns) {
  2999. log.error("没有找到对应的Vue实例", vueIns);
  3000. Qmsg.error("没有找到对应的Vue实例");
  3001. return;
  3002. }
  3003. let carddata = vueIns == null ? void 0 : vueIns.carddata;
  3004. if (typeof (carddata == null ? void 0 : carddata.scheme) !== "string") {
  3005. log.error("没有找到对应的scheme", vueIns);
  3006. Qmsg.error("没有找到对应的scheme");
  3007. return;
  3008. }
  3009. let scheme = carddata.scheme;
  3010. log.success(`新标签页打开:` + scheme);
  3011. window.open(scheme, "_blank");
  3012. },
  3013. {
  3014. capture: true
  3015. }
  3016. );
  3017. }
  3018. };
  3019. const blockCSS = "#app .bottombtn {\r\n display: none !important;\r\n}\r\n";
  3020. const WeiBoLive = {
  3021. init() {
  3022. addStyle(blockCSS);
  3023. }
  3024. };
  3025. const WeiBo = {
  3026. $data: {
  3027. weiBoUnlockQuality: new WeiBoUnlockQuality()
  3028. },
  3029. init() {
  3030. PopsPanel.execMenuOnce(
  3031. "weibo_hijack_navigator_service_worker_register",
  3032. () => {
  3033. WeiBoHook.hookServiceWorkerRegister();
  3034. }
  3035. );
  3036. PopsPanel.execMenuOnce("weibo-common-clickImageToClosePreviewImage", () => {
  3037. this.clickImageToClosePreviewImage();
  3038. });
  3039. if (WeiBoRouter.isMWeiBo()) {
  3040. log.info("Router: 移动端微博");
  3041. PopsPanel.onceExec("weibo-m-init", () => {
  3042. WeiBoHook.hookNetWork();
  3043. WeiBoHook.hookApply();
  3044. WeiBoHook.hookVueRouter();
  3045. });
  3046. PopsPanel.execMenuOnce("weibo_remove_ads", () => {
  3047. return this.blockAds();
  3048. });
  3049. PopsPanel.execMenuOnce("weibo_shield_bottom_bar", () => {
  3050. return this.shieldBottomBar();
  3051. });
  3052. this.$data.weiBoUnlockQuality.lockVideoQuality();
  3053. domUtils.ready(() => {
  3054. PopsPanel.execMenuOnce("weibo-common-unlockVideoHigherQuality", () => {
  3055. this.unlockVideoHigherQuality();
  3056. });
  3057. PopsPanel.execMenuOnce("weibo-detail-setArticleAbsoluteTime", () => {
  3058. WeiBoDetail.setArticleAbsoluteTime();
  3059. });
  3060. });
  3061. if (WeiBoRouter.isMWeiBoHome()) {
  3062. log.info(`Router: 移动端微博-首页`);
  3063. WeiBoHome.init();
  3064. } else if (WeiBoRouter.isMWeiBo_detail() || WeiBoRouter.isMWeiBo_status()) {
  3065. log.info("Router: 移动端微博-正文");
  3066. WeiBoDetail.init();
  3067. } else if (WeiBoRouter.isMWeiBo_userHome()) {
  3068. log.info("Router: 移动端微博-用户主页");
  3069. } else if (WeiBoRouter.isMWeiBo_search()) {
  3070. log.info("Router: 移动端微博-搜索");
  3071. WeiBoSearch.init();
  3072. } else if (WeiBoRouter.isMWeiBo_HotSearch()) {
  3073. log.info(`Router: 移动端微博-微博热搜`);
  3074. WeiBoHotSearch.init();
  3075. } else {
  3076. log.error("Router: 移动端微博未适配链接 => " + window.location.href);
  3077. }
  3078. } else if (WeiBoRouter.isHuaTi()) {
  3079. log.info("Router: 话题");
  3080. WeiBoHuaTi.init();
  3081. } else if (WeiBoRouter.isVideo()) {
  3082. log.info("Router: 视频页");
  3083. WeiBoVideo.init();
  3084. } else if (WeiBoRouter.isCard()) {
  3085. log.info("Router: 头条");
  3086. if (WeiBoRouter.isCardArticle()) {
  3087. log.info("Router: 头条文章");
  3088. WeiBoCardArticle.init();
  3089. } else {
  3090. log.error("Router: 头条未适配链接 => " + window.location.href);
  3091. }
  3092. } else if (WeiBoRouter.isLive()) {
  3093. log.info(`Router: 直播`);
  3094. WeiBoLive.init();
  3095. } else {
  3096. log.error("Router: 未适配 => " + window.location.href);
  3097. }
  3098. },
  3099. /**
  3100. * 屏蔽 广告
  3101. */
  3102. blockAds() {
  3103. log.info(`屏蔽 广告`);
  3104. return addStyle(blockAdsCSS$1);
  3105. },
  3106. /**
  3107. * 【屏蔽】底部工具栏
  3108. */
  3109. shieldBottomBar() {
  3110. log.info("【屏蔽】底部工具栏");
  3111. return CommonUtil.addBlockCSS(
  3112. "#app div.m-tab-bar.m-bar-panel.m-container-max"
  3113. );
  3114. },
  3115. /**
  3116. * 解锁微博视频高画质
  3117. **/
  3118. unlockVideoHigherQuality() {
  3119. let lock = new utils.LockFunction(() => {
  3120. this.$data.weiBoUnlockQuality.unlockVideoHigherQuality();
  3121. }, 15);
  3122. utils.mutationObserver(document.body, {
  3123. config: {
  3124. subtree: true,
  3125. childList: true
  3126. },
  3127. immediate: true,
  3128. callback: () => {
  3129. lock.run();
  3130. }
  3131. });
  3132. },
  3133. /**
  3134. * 设置监听事件,监听点击预览中的图片,从而关闭预览
  3135. */
  3136. clickImageToClosePreviewImage() {
  3137. let selectorList = [".pswp .pswp__item"];
  3138. selectorList.forEach((selector) => {
  3139. domUtils.on(document, "click", selector, (event) => {
  3140. event.target;
  3141. let $closeButton = $(".pswp .pswp__button--close");
  3142. if ($closeButton) {
  3143. $closeButton.click();
  3144. } else {
  3145. log.warn("未找到关闭预览按钮,使用history.back()");
  3146. window.history.back();
  3147. }
  3148. });
  3149. });
  3150. }
  3151. };
  3152. PopsPanel.init();
  3153. WeiBo.init();
  3154.  
  3155. })(Qmsg, DOMUtils, Utils, pops);