[E/Ex-Hentai] AutoLogin

E/Ex - 共享帳號登入、自動獲取 Cookies、手動輸入 Cookies、本地備份以及查看備份,自動檢測登入

  1. // ==UserScript==
  2. // @name [E/Ex-Hentai] AutoLogin
  3. // @name:zh-TW [E/Ex-Hentai] 自動登入
  4. // @name:zh-CN [E/Ex-Hentai] 自动登入
  5. // @name:ja [E/Ex-Hentai] 自動ログイン
  6. // @name:ko [E/Ex-Hentai] 자동 로그인
  7. // @name:en [E/Ex-Hentai] AutoLogin
  8. // @version 0.0.33-Beta
  9. // @author Canaan HS
  10. // @description E/Ex - 共享帳號登入、自動獲取 Cookies、手動輸入 Cookies、本地備份以及查看備份,自動檢測登入
  11. // @description:zh-TW E/Ex - 共享帳號登入、自動獲取 Cookies、手動輸入 Cookies、本地備份以及查看備份,自動檢測登入
  12. // @description:zh-CN E/Ex - 共享帐号登录、自动获取 Cookies、手动输入 Cookies、本地备份以及查看备份,自动检测登录
  13. // @description:ja E/Ex - 共有アカウントでのログイン、クッキーの自动取得、クッキーの手动入力、ローカルバックアップおよびバックアップの表示、自动ログインの検出
  14. // @description:ko E/Ex - 공유 계정 로그인, 자동으로 쿠키 가져오기, 쿠키 수동 입력, 로컬 백업 및 백업 보기, 자동 로그인 감지
  15. // @description:en E/Ex - Shared account login, automatic cookie retrieval, manual cookie input, local backup, and backup viewing, automatic login detection
  16.  
  17. // @connect *
  18. // @match *://e-hentai.org/*
  19. // @match *://exhentai.org/*
  20. // @icon https://e-hentai.org/favicon.ico
  21.  
  22. // @license MIT
  23. // @namespace https://greasyfork.org/users/989635
  24.  
  25. // @run-at document-start
  26. // @grant GM_setValue
  27. // @grant GM_getValue
  28. // @grant GM_notification
  29. // @grant GM_xmlhttpRequest
  30. // @grant GM_getResourceText
  31. // @grant GM_registerMenuCommand
  32. // @grant GM_unregisterMenuCommand
  33. // @grant GM_addValueChangeListener
  34.  
  35. // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js
  36. // @require https://cdnjs.cloudflare.com/ajax/libs/blueimp-md5/2.19.0/js/md5.min.js
  37. // @require https://update.greasyfork.org/scripts/495339/1524580/ObjectSyntax_min.js
  38. // @require https://cdnjs.cloudflare.com/ajax/libs/jquery-jgrowl/1.4.9/jquery.jgrowl.min.js
  39. // @resource jgrowl-css https://cdnjs.cloudflare.com/ajax/libs/jquery-jgrowl/1.4.9/jquery.jgrowl.min.css
  40. // ==/UserScript==
  41.  
  42. (async () => {
  43. const domain = Syn.Device.Host;
  44. (async function ImportStyle() {
  45. let show_style, button_style, button_hover, jGrowl_style, acc_style;
  46. if (domain == "e-hentai.org") {
  47. button_hover = "color: #8f4701;";
  48. jGrowl_style = "background-color: #5C0D12; color: #fefefe;";
  49. show_style = "background-color: #fefefe; border: 3px ridge #34353b;";
  50. acc_style = "color: #5C0D12; background-color: #fefefe; border: 2px solid #B5A4A4;";
  51. button_style = "color: #5C0D12; border: 2px solid #B5A4A4; background-color: #fefefe;";
  52. } else if (domain == "exhentai.org") {
  53. button_hover = "color: #989898;";
  54. jGrowl_style = "background-color: #fefefe; color: #5C0D12;";
  55. show_style = "background-color: #34353b; border: 2px ridge #5C0D12;";
  56. acc_style = "color: #f1f1f1; background-color: #34353b; border: 2px solid #8d8d8d;";
  57. button_style = "color: #fefefe; border: 2px solid #8d8d8d; background-color: #34353b;";
  58. Syn.AddStyle(`
  59. body {
  60. padding: 2px;
  61. color: #f1f1f1;
  62. text-align: center;
  63. background: #34353b;
  64. }
  65. `);
  66. }
  67. Syn.AddStyle(`
  68. ${GM_getResourceText("jgrowl-css")}
  69. .jGrowl {
  70. ${jGrowl_style}
  71. top: 2rem;
  72. left: 50%;
  73. width: auto;
  74. z-index: 9999;
  75. font-size: 1.3rem;
  76. border-radius: 2px;
  77. text-align: center;
  78. white-space: nowrap;
  79. transform: translateX(-50%);
  80. }
  81. .modal-background {
  82. top: 50%;
  83. left: 50%;
  84. opacity: 0;
  85. width: 100%;
  86. height: 100%;
  87. z-index: 8888;
  88. overflow: auto;
  89. position: fixed;
  90. transition: 0.6s ease;
  91. background-color: rgba(0,0,0,0);
  92. transform: translate(-50%, -50%) scale(0.3);
  93. }
  94. .acc-modal {
  95. ${show_style}
  96. width: 18%;
  97. overflow: auto;
  98. margin: 11rem auto;
  99. border-radius: 10px;
  100. }
  101. .acc-select-flex {
  102. display: flex;
  103. align-items: center;
  104. flex-direction: initial;
  105. justify-content: space-around;
  106. }
  107. .acc-button-flex {
  108. display: flex;
  109. padding: 0 0 15px 0;
  110. justify-content: center;
  111. }
  112. .acc-select {
  113. ${acc_style}
  114. width: 10rem;
  115. padding: 4px;
  116. margin: 1.1rem 1.4rem 1.5rem 1.4rem;
  117. font-weight: bold;
  118. cursor: pointer;
  119. font-size: 1.2rem;
  120. text-align: center;
  121. border-radius: 5px;
  122. }
  123. .show-modal {
  124. ${show_style}
  125. width: 25%;
  126. padding: 1.5rem;
  127. overflow: auto;
  128. margin: 5rem auto;
  129. text-align: left;
  130. border-radius: 10px;
  131. border-collapse: collapse;
  132. }
  133. .modal-button {
  134. ${button_style}
  135. top: 0;
  136. margin: 3% 2%;
  137. font-size: 14px;
  138. font-weight: bold;
  139. border-radius: 3px;
  140. }
  141. .modal-button:hover, .modal-button:focus {
  142. ${button_hover}
  143. cursor: pointer;
  144. text-decoration: none;
  145. }
  146. .set-modal {
  147. ${show_style}
  148. width: 30%;
  149. padding: 0.3rem;
  150. overflow: auto;
  151. border-radius: 10px;
  152. text-align: center;
  153. border-collapse: collapse;
  154. margin: 2% auto 8px auto;
  155. }
  156. .set-box {
  157. display: flex;
  158. margin: 0.6rem;
  159. font-weight: bold;
  160. flex-direction: column;
  161. align-items: flex-start;
  162. }
  163. .set-list {
  164. width: 95%;
  165. font-weight: 550;
  166. font-size: 1.1rem;
  167. text-align: center;
  168. }
  169. hr {
  170. width: 98%;
  171. opacity: 0.2;
  172. border: 1px solid;
  173. margin-top: 1.3rem;
  174. }
  175. label {
  176. margin: 0.4rem;
  177. font-size: 0.9rem;
  178. }
  179. `);
  180. })();
  181. const Lang = (lang => {
  182. const Word = {
  183. Traditional: {},
  184. Simplified: {
  185. "🍪 共享登入": "🍪 共享登录",
  186. "🟢 啟用檢測": "🟢 启用检测",
  187. "🔴 禁用檢測": "🔴 禁用检测",
  188. "📂 展開菜單": "📂 展开菜单",
  189. "📁 摺疊菜單": "📁 折叠菜单",
  190. "📜 自動獲取": "📜 自动获取",
  191. "📝 手動輸入": "📝 手动输入",
  192. "🔍 查看保存": "🔍 查看保存",
  193. "🔃 手動注入": "🔃 手动注入",
  194. "🗑️ 清除登入": "🗑️ 清除登录",
  195. "帳戶": "账户",
  196. "更新": "更新",
  197. "登入": "登录",
  198. "確認選擇的 Cookies": "确认选择的 Cookies",
  199. "確認保存": "确认保存",
  200. "取消退出": "取消退出",
  201. "退出選單": "退出菜单",
  202. "保存成功!": "保存成功!",
  203. "更改保存": "更改保存",
  204. "變更通知": "变更通知",
  205. "已保存變更": "已保存变更",
  206. "設置 Cookies": "设置 Cookies",
  207. "要登入 Ex 才需要填寫": "要登录 Ex 才需要填写",
  208. "必填項目": "必填项目",
  209. "下方選填 也可不修改": "下方选填 也可不修改",
  210. "[確認輸入正確]按下退出選單保存": "[确认输入正确]按下退出菜单保存",
  211. "當前設置 Cookies": "当前设置 Cookies",
  212. "帳戶選擇": "账户选择",
  213. "未獲取到 Cookies !!\n\n請先登入帳戶": "未获取到 Cookies !!\n\n请先登录账户",
  214. "未檢測到可注入的 Cookies !!\n\n請從選單中進行設置": "未检测到可注入的 Cookies !!\n\n请从菜单中进行设置",
  215. "共享數據更新完成": "共享数据更新完成",
  216. "共享數據無需更新": "共享数据无需更新",
  217. "共享數據獲取失敗": "共享数据获取失败",
  218. "無保存的 Cookie, 無法啟用自動登入": "无保存的 Cookie,无法启用自动登录",
  219. "請求為空數據": "请求为空数据",
  220. "連線異常,更新地址可能是錯的": "连接异常,更新地址可能是错的",
  221. "請求錯誤: ": "请求错误: "
  222. },
  223. English: {
  224. "🍪 共享登入": "🍪 Shared Login",
  225. "🟢 啟用檢測": "🟢 Enable Detection",
  226. "🔴 禁用檢測": "🔴 Disable Detection",
  227. "📂 展開菜單": "📂 Expand Menu",
  228. "📁 摺疊菜單": "📁 Collapse Menu",
  229. "📜 自動獲取": "📜 Auto Retrieve",
  230. "📝 手動輸入": "📝 Manual Input",
  231. "🔍 查看保存": "🔍 View Saved",
  232. "🔃 手動注入": "🔃 Manual Injection",
  233. "🗑️ 清除登入": "🗑️ Clear Login",
  234. "帳戶": "Account",
  235. "更新": "Update",
  236. "登入": "Login",
  237. "確認選擇的 Cookies": "Confirm Selected Cookies",
  238. "確認保存": "Confirm Save",
  239. "取消退出": "Cancel Exit",
  240. "退出選單": "Exit Menu",
  241. "保存成功!": "Save Successful!",
  242. "更改保存": "Change Saved",
  243. "變更通知": "Change Notification",
  244. "已保存變更": "Changes Saved",
  245. "設置 Cookies": "Set Cookies",
  246. "要登入 Ex 才需要填寫": "Required for Ex Login",
  247. "必填項目": "Mandatory Field",
  248. "下方選填 也可不修改": "Optional Below, No Changes Needed",
  249. "[確認輸入正確]按下退出選單保存": "[Confirm Correct Input] Press Exit Menu to Save",
  250. "當前設置 Cookies": "Current Set Cookies",
  251. "帳戶選擇": "Account Selection",
  252. "未獲取到 Cookies !!\n\n請先登入帳戶": "No Cookies Retrieved !!\n\nPlease Login First",
  253. "未檢測到可注入的 Cookies !!\n\n請從選單中進行設置": "No Injectable Cookies Detected !!\n\nPlease Set in Menu",
  254. "共享數據更新完成": "Shared data update completed",
  255. "共享數據無需更新": "No need to update shared data",
  256. "共享數據獲取失敗": "Shared Data Retrieval Failed",
  257. "無保存的 Cookie, 無法啟用自動登入": "No saved cookies, unable to enable auto-login",
  258. "請求為空數據": "Request Contains No Data",
  259. "連線異常,更新地址可能是錯的": "Connection error, the update address may be incorrect",
  260. "請求錯誤: ": "Request Error: "
  261. },
  262. Korea: {
  263. "🍪 共享登入": "🍪 공유 로그인",
  264. "🟢 啟用檢測": "🟢 감지 활성화",
  265. "🔴 禁用檢測": "🔴 감지 비활성화",
  266. "📂 展開菜單": "📂 메뉴 확장",
  267. "📁 摺疊菜單": "📁 메뉴 축소",
  268. "📜 自動獲取": "📜 자동 가져오기",
  269. "📝 手動輸入": "📝 수동 입력",
  270. "🔍 查看保存": "🔍 저장 보기",
  271. "🔃 手動注入": "🔃 수동 주입",
  272. "🗑️ 清除登入": "🗑️ 로그인 지우기",
  273. "確認選擇的 Cookies": "선택한 쿠키 확인",
  274. "帳戶": "계정",
  275. "更新": "업데이트",
  276. "登入": "로그인",
  277. "確認保存": "저장 확인",
  278. "取消退出": "취소 종료",
  279. "退出選單": "메뉴 종료",
  280. "保存成功!": "저장 성공!",
  281. "更改保存": "변경 저장",
  282. "變更通知": "변경 알림",
  283. "已保存變更": "변경 사항 저장됨",
  284. "設置 Cookies": "쿠키 설정",
  285. "要登入 Ex 才需要填寫": "Ex 로그인에 필요",
  286. "必填項目": "필수 항목",
  287. "下方選填 也可不修改": "아래 선택 항목, 변경 필요 없음",
  288. "[確認輸入正確]按下退出選單保存": "[입력 정확성 확인] 메뉴 종료를 눌러 저장",
  289. "當前設置 Cookies": "현재 설정된 쿠키",
  290. "帳戶選擇": "계정 선택",
  291. "未獲取到 Cookies !!\n\n請先登入帳戶": "쿠키를 가져오지 못했습니다 !!\n\n먼저 로그인 해주세요",
  292. "未檢測到可注入的 Cookies !!\n\n請從選單中進行設置": "주입 가능한 쿠키를 감지하지 못했습니다 !!\n\n메뉴에서 설정해 주세요",
  293. "共享數據更新完成": "공유 데이터 업데이트 완료",
  294. "共享數據無需更新": "공유 데이터 업데이트 필요 없음",
  295. "共享數據獲取失敗": "공유 데이터 가져오기 실패",
  296. "無保存的 Cookie, 無法啟用自動登入": "저장된 쿠키가 없어 자동 로그인을 활성화할 수 없습니다",
  297. "請求為空數據": "요청 데이터가 비어 있습니다",
  298. "連線異常,更新地址可能是錯的": "연결 이상, 업데이트 주소가 잘못되었을 수 있습니다",
  299. "請求錯誤: ": "요청 오류: "
  300. },
  301. Japan: {
  302. "🍪 共享登入": "🍪 共有ログイン",
  303. "🟢 啟用檢測": "🟢 検出を有効化",
  304. "🔴 禁用檢測": "🔴 検出を無効化",
  305. "📂 展開菜單": "📂 メニュー展開",
  306. "📁 摺疊菜單": "📁 メニュー折りたたみ",
  307. "📜 自動獲取": "📜 自動取得",
  308. "📝 手動輸入": "📝 手動入力",
  309. "🔍 查看保存": "🔍 保存を表示",
  310. "🔃 手動注入": "🔃 手動注入",
  311. "🗑️ 清除登入": "🗑️ ログインクリア",
  312. "帳戶": "アカウント",
  313. "更新": "更新",
  314. "登入": "ログイン",
  315. "確認選擇的 Cookies": "選択したクッキーを確認",
  316. "確認保存": "保存を確認",
  317. "取消退出": "キャンセルして終了",
  318. "退出選單": "メニューを終了",
  319. "保存成功!": "保存成功!",
  320. "更改保存": "変更を保存",
  321. "變更通知": "変更通知",
  322. "已保存變更": "変更が保存されました",
  323. "設置 Cookies": "クッキーを設定",
  324. "要登入 Ex 才需要填寫": "Exログインに必要",
  325. "必填項目": "必須項目",
  326. "下方選填 也可不修改": "下の選択肢、変更の必要はありません",
  327. "[確認輸入正確]按下退出選單保存": "[入力が正しいことを確認] メニュー終了を押して保存",
  328. "當前設置 Cookies": "現在設定されているクッキー",
  329. "帳戶選擇": "アカウント選択",
  330. "未獲取到 Cookies !!\n\n請先登入帳戶": "クッキーを取得できませんでした!!\n\n先にログインしてください",
  331. "未檢測到可注入的 Cookies !!\n\n請從選單中進行設置": "注入可能なクッキーが検出されませんでした!!\n\nメニューから設定してください",
  332. "共享數據更新完成": "共有データの更新が完了しました",
  333. "共享數據無需更新": "共有データを更新する必要がありません",
  334. "共享數據獲取失敗": "共有データの取得に失敗しました",
  335. "無保存的 Cookie, 無法啟用自動登入": "保存された Cookie がないため、自動ログインを有効にできません",
  336. "請求為空數據": "リクエストが空データです",
  337. "連線異常,更新地址可能是錯的": "接続異常、更新されたアドレスが間違っている可能性があります",
  338. "請求錯誤: ": "リクエストエラー: "
  339. }
  340. }, Match = {
  341. ko: Word.Korea,
  342. ja: Word.Japan,
  343. "en-US": Word.English,
  344. "zh-CN": Word.Simplified,
  345. "zh-SG": Word.Simplified,
  346. "zh-TW": Word.Traditional,
  347. "zh-HK": Word.Traditional,
  348. "zh-MO": Word.Traditional
  349. }, ML = Match[lang] ?? Match["en-US"];
  350. return {
  351. Transl: Str => ML[Str] ?? Str
  352. };
  353. })(Syn.Device.Lang);
  354. const Ckop = (() => {
  355. let Cookie = undefined;
  356. const Today = new Date();
  357. Today.setFullYear(Today.getFullYear() + 1);
  358. const Expires = Today.toUTCString();
  359. const UnixUTC = new Date(0).toUTCString();
  360. let RequiredCookie = ["ipb_member_id", "ipb_pass_hash"];
  361. if (domain == "exhentai.org") RequiredCookie.unshift("igneous");
  362. return {
  363. Get: () => {
  364. return document.cookie.split("; ").reduce((acc, cookie) => {
  365. const [name, value] = cookie.split("=");
  366. acc[decodeURIComponent(name)] = decodeURIComponent(value);
  367. return acc;
  368. }, {});
  369. },
  370. Add: function (CookieObject) {
  371. Syn.Storage("DetectionTime", {
  372. type: localStorage,
  373. value: new Date().getTime()
  374. });
  375. for (Cookie of CookieObject) {
  376. document.cookie = `${encodeURIComponent(Cookie.name)}=${encodeURIComponent(Cookie.value)}; domain=.${domain}; path=/; expires=${Expires};`;
  377. }
  378. location.reload();
  379. },
  380. Delete: function () {
  381. Object.keys(this.Get()).forEach(Name => {
  382. document.cookie = `${Name}=; expires=${UnixUTC}; path=/;`;
  383. document.cookie = `${Name}=; expires=${UnixUTC}; path=/; domain=.${domain}`;
  384. });
  385. },
  386. ReAdd: function (Cookies) {
  387. this.Delete();
  388. this.Add(Cookies);
  389. },
  390. Verify: function (Cookies) {
  391. const Cookie = this.Get();
  392. const VCookie = new Set(Object.keys(Cookie));
  393. const Result = RequiredCookie.every(key => VCookie.has(key) && Cookie[key] !== "mystery");
  394. if (!Result) {
  395. this.ReAdd(Cookies);
  396. } else {
  397. Syn.Storage("DetectionTime", {
  398. type: localStorage,
  399. value: new Date().getTime()
  400. });
  401. }
  402. }
  403. };
  404. })();
  405. new class AutoLogin {
  406. constructor() {
  407. this.modal = null;
  408. this.Share = Syn.Store("g", "Share") ?? this.UpdateShared();
  409. this.on = async (element, type, listener) => {
  410. $(element).on(type, listener);
  411. };
  412. this.Growl = async (message, theme, life) => {
  413. $.jGrowl(`  ${message}  `, {
  414. theme: theme,
  415. life: life
  416. });
  417. };
  418. this.CreateDetection = () => {
  419. const detection = $(".modal-background");
  420. detection[0] && detection.remove();
  421. };
  422. this.CreateMenu = async () => {
  423. $(document.body).append(this.modal);
  424. requestAnimationFrame(() => {
  425. $(".modal-background").css({
  426. opacity: "1",
  427. "background-color": "rgba(0,0,0,0.7)",
  428. transform: "translate(-50%, -50%) scale(1)"
  429. });
  430. });
  431. };
  432. this.DeleteMenu = async () => {
  433. const modal = $(".modal-background");
  434. modal.css({
  435. opacity: "0",
  436. "pointer-events": "none",
  437. "background-color": "rgba(0,0,0,0)",
  438. transform: "translate(-50%, -50%) scale(0)"
  439. });
  440. setTimeout(() => {
  441. modal.remove();
  442. }, 1300);
  443. };
  444. this.GlobalMenuToggle = async () => {
  445. Syn.StoreListen(["Login", "Expand"], listen => {
  446. console.log(listen);
  447. listen.far && this.LoginToggle();
  448. });
  449. };
  450. this.LoginToggle = async () => {
  451. const cookie = Boolean(Syn.Store("gj", "E/Ex_Cookies"));
  452. const state = Syn.Store("g", "Login", cookie);
  453. const disp = state ? Lang.Transl("🟢 啟用檢測") : Lang.Transl("🔴 禁用檢測");
  454. Syn.Menu({
  455. [disp]: {
  456. func: () => {
  457. if (state) Syn.Store("s", "Login", false); else if (cookie) Syn.Store("s", "Login", true); else {
  458. alert(Lang.Transl("無保存的 Cookie, 無法啟用自動登入"));
  459. return;
  460. }
  461. this.LoginToggle();
  462. },
  463. close: false
  464. }
  465. }, "Check");
  466. Syn.Menu({
  467. [Lang.Transl("🍪 共享登入")]: {
  468. func: () => this.SharedLogin()
  469. }
  470. });
  471. this.MenuToggle();
  472. };
  473. this.MenuToggle = async () => {
  474. const state = Syn.Store("g", "Expand", false), disp = state ? Lang.Transl("📁 摺疊菜單") : Lang.Transl("📂 展開菜單");
  475. Syn.Menu({
  476. [disp]: {
  477. func: () => {
  478. state ? Syn.Store("s", "Expand", false) : Syn.Store("s", "Expand", true);
  479. this.MenuToggle();
  480. },
  481. hotkey: "c",
  482. close: false
  483. }
  484. }, "Switch");
  485. state ? this.Expand() : this.Collapse();
  486. };
  487. this.Expand = async () => {
  488. Syn.Menu({
  489. [Lang.Transl("📜 自動獲取")]: {
  490. func: () => this.GetCookieAutomatically()
  491. },
  492. [Lang.Transl("📝 手動輸入")]: {
  493. func: () => this.ManualSetting()
  494. },
  495. [Lang.Transl("🔍 查看保存")]: {
  496. func: () => this.ViewSaveCookie()
  497. },
  498. [Lang.Transl("🔃 手動注入")]: {
  499. func: () => this.CookieInjection()
  500. },
  501. [Lang.Transl("🗑️ 清除登入")]: {
  502. func: () => this.ClearLogin()
  503. }
  504. }, "Expand");
  505. };
  506. this.Collapse = async () => {
  507. for (let i = 1; i <= 5; i++) {
  508. GM_unregisterMenuCommand("Expand-" + i);
  509. }
  510. };
  511. }
  512. async Main() {
  513. const cookie = Syn.Store("gj", "E/Ex_Cookies");
  514. const login = Syn.Store("g", "Login", Boolean(cookie));
  515. if (login && cookie) {
  516. let CurrentTime = new Date(), DetectionTime = Syn.Storage("DetectionTime", {
  517. type: localStorage
  518. });
  519. DetectionTime = DetectionTime ? new Date(DetectionTime) : new Date(CurrentTime.getTime() + 11 * 60 * 1e3);
  520. const Conversion = Math.abs(DetectionTime - CurrentTime) / (1e3 * 60);
  521. if (Conversion >= 10) Ckop.Verify(cookie);
  522. }
  523. this.LoginToggle();
  524. this.GlobalMenuToggle();
  525. }
  526. async GetSharedDict() {
  527. return new Promise((resolve, reject) => {
  528. GM_xmlhttpRequest({
  529. method: "GET",
  530. responseType: "json",
  531. url: "https://raw.githubusercontent.com/Canaan-HS/Script-DataBase/main/Share/ExShare.json",
  532. onload: response => {
  533. if (response.status === 200) {
  534. const data = response.response;
  535. if (typeof data === "object" && Object.keys(data).length > 0) {
  536. resolve(data);
  537. } else {
  538. console.error(Lang.Transl("請求為空數據"));
  539. resolve({});
  540. }
  541. } else {
  542. console.error(Lang.Transl("連線異常,更新地址可能是錯的"));
  543. resolve({});
  544. }
  545. },
  546. onerror: error => {
  547. console.error(Lang.Transl("請求錯誤: "), error);
  548. resolve({});
  549. }
  550. });
  551. });
  552. }
  553. async UpdateShared() {
  554. const Shared = await this.GetSharedDict();
  555. if (Object.keys(Shared).length > 0) {
  556. const localHash = md5(JSON.stringify(Syn.Store("g", "Share", {})));
  557. const remoteHash = md5(JSON.stringify(Shared));
  558. if (localHash !== remoteHash) {
  559. this.Share = Shared;
  560. Syn.Store("s", "Share", Shared);
  561. this.Growl(Lang.Transl("共享數據更新完成"), "jGrowl", 1500);
  562. const modal = Syn.$$(".modal-background");
  563. if (modal) {
  564. setTimeout(() => {
  565. modal.remove();
  566. this.SharedLogin();
  567. }, 600);
  568. }
  569. } else {
  570. this.Growl(Lang.Transl("共享數據無需更新"), "jGrowl", 1500);
  571. }
  572. } else {
  573. Syn.Store("s", "Share", {});
  574. this.Growl(Lang.Transl("共享數據獲取失敗"), "jGrowl", 1500);
  575. }
  576. }
  577. async SharedLogin() {
  578. this.CreateDetection();
  579. const Share = this.Share, AccountQuantity = Object.keys(Share).length, Igneous = Ckop.Get().igneous;
  580. let Select = $(`<select id="account-select" class="acc-select"></select>`), Value;
  581. for (let i = 1; i <= AccountQuantity; i++) {
  582. if (Share[i][0].value == Igneous) {
  583. Value = i;
  584. }
  585. Select.append($("<option>").attr({
  586. value: i
  587. }).text(`${Lang.Transl("帳戶")} ${i}`));
  588. }
  589. this.modal = $(`
  590. <div class="modal-background">
  591. <div class="acc-modal">
  592. <h1>${Lang.Transl("帳戶選擇")}</h1>
  593. <div class="acc-select-flex">${Select.prop("outerHTML")}</div>
  594. <div class="acc-button-flex">
  595. <button class="modal-button" id="update">${Lang.Transl("更新")}</button>
  596. <button class="modal-button" id="login">${Lang.Transl("登入")}</button>
  597. </div>
  598. </div>
  599. </div>
  600. `);
  601. this.CreateMenu();
  602. Value && $("#account-select").val(Value);
  603. const self = this;
  604. self.on(".modal-background", "click", function (click) {
  605. click.stopImmediatePropagation();
  606. const target = click.target;
  607. if (target.id == "login") {
  608. Ckop.ReAdd(Share[+$("#account-select").val()]);
  609. } else if (target.id == "update") {
  610. self.UpdateShared();
  611. } else if (target.className == "modal-background") {
  612. self.DeleteMenu();
  613. }
  614. });
  615. }
  616. async GetCookieAutomatically() {
  617. let cookie_box = [];
  618. for (const [name, value] of Object.entries(Ckop.Get())) {
  619. cookie_box.push({
  620. name: name,
  621. value: value
  622. });
  623. }
  624. cookie_box.length > 1 ? this.Cookie_Show(JSON.stringify(cookie_box, null, 4)) : alert(Lang.Transl("未獲取到 Cookies !!\n\n請先登入帳戶"));
  625. }
  626. async Cookie_Show(cookies) {
  627. this.CreateDetection();
  628. this.modal = `
  629. <div class="modal-background">
  630. <div class="show-modal">
  631. <h1 style="text-align: center;">${Lang.Transl("確認選擇的 Cookies")}</h1>
  632. <pre><b>${cookies}</b></pre>
  633. <div style="text-align: right;">
  634. <button class="modal-button" id="save">${Lang.Transl("確認保存")}</button>
  635. <button class="modal-button" id="close">${Lang.Transl("取消退出")}</button>
  636. </div>
  637. </div>
  638. </div>
  639. `;
  640. this.CreateMenu();
  641. const self = this;
  642. self.on(".modal-background", "click", function (click) {
  643. click.stopImmediatePropagation();
  644. const target = click.target;
  645. if (target.id == "save") {
  646. Syn.Store("s", "E/Ex_Cookies", cookies);
  647. self.Growl(Lang.Transl("保存成功!"), "jGrowl", 1500);
  648. self.DeleteMenu();
  649. } else if (target.className == "modal-background" || target.id == "close") {
  650. self.DeleteMenu();
  651. }
  652. });
  653. }
  654. async ManualSetting() {
  655. this.CreateDetection();
  656. this.modal = `
  657. <div class="modal-background">
  658. <div class="set-modal">
  659. <h1>${Lang.Transl("設置 Cookies")}</h1>
  660. <form id="set_cookies">
  661. <div id="input_cookies" class="set-box">
  662. <label>[igneous]:</label><input class="set-list" type="text" name="igneous" placeholder="${Lang.Transl("要登入 Ex 才需要填寫")}"><br>
  663. <label>[ipb_member_id]:</label><input class="set-list" type="text" name="ipb_member_id" placeholder="${Lang.Transl("必填項目")}" required><br>
  664. <label>[ipb_pass_hash]:</label><input class="set-list" type="text" name="ipb_pass_hash" placeholder="${Lang.Transl("必填項目")}" required><hr>
  665. <h3>${Lang.Transl("下方選填 也可不修改")}</h3>
  666. <label>[sl]:</label><input class="set-list" type="text" name="sl" value="dm_2"><br>
  667. <label>[sk]:</label><input class="set-list" type="text" name="sk"><br>
  668. </div>
  669. <button type="submit" class="modal-button" id="save">${Lang.Transl("確認保存")}</button>
  670. <button class="modal-button" id="close">${Lang.Transl("退出選單")}</button>
  671. </form>
  672. </div>
  673. </div>
  674. `;
  675. this.CreateMenu();
  676. let cookie;
  677. const textarea = $("<textarea>").attr({
  678. style: "margin: 1.15rem auto 0 auto",
  679. rows: 18,
  680. cols: 40,
  681. readonly: true
  682. }), self = this;
  683. self.on("#set_cookies", "submit", function (submit) {
  684. submit.preventDefault();
  685. submit.stopImmediatePropagation();
  686. const cookie_list = Array.from($("#set_cookies .set-list")).map(function (input) {
  687. const value = $(input).val();
  688. return value.trim() !== "" ? {
  689. name: $(input).attr("name"),
  690. value: value
  691. } : null;
  692. }).filter(Boolean);
  693. cookie = JSON.stringify(cookie_list, null, 4);
  694. textarea.val(cookie);
  695. $("#set_cookies div").append(textarea);
  696. self.Growl(Lang.Transl("[確認輸入正確]按下退出選單保存"), "jGrowl", 3e3);
  697. });
  698. self.on(".modal-background", "click", function (click) {
  699. click.stopImmediatePropagation();
  700. const target = click.target;
  701. if (target.className == "modal-background" || target.id == "close") {
  702. click.preventDefault();
  703. cookie && Syn.Store("s", "E/Ex_Cookies", cookie);
  704. self.DeleteMenu();
  705. }
  706. });
  707. }
  708. async ViewSaveCookie() {
  709. this.CreateDetection();
  710. this.modal = `
  711. <div class="modal-background">
  712. <div class="set-modal">
  713. <h1>${Lang.Transl("當前設置 Cookies")}</h1>
  714. <div id="view_cookies" style="margin: 0.6rem"></div>
  715. <button class="modal-button" id="save">${Lang.Transl("更改保存")}</button>
  716. <button class="modal-button" id="close">${Lang.Transl("退出選單")}</button>
  717. </div>
  718. </div>
  719. `;
  720. this.CreateMenu();
  721. const cookie = Syn.Store("gj", "E/Ex_Cookies");
  722. const textarea = $("<textarea>").attr({
  723. rows: 20,
  724. cols: 50,
  725. id: "view_SC",
  726. style: "margin-top: 1.25rem;"
  727. }), self = this;
  728. textarea.val(JSON.stringify(cookie, null, 4));
  729. $("#view_cookies").append(textarea);
  730. self.on(".modal-background", "click", function (click) {
  731. click.stopImmediatePropagation();
  732. const target = click.target;
  733. if (target.id == "save") {
  734. GM_notification({
  735. title: Lang.Transl("變更通知"),
  736. text: Lang.Transl("已保存變更"),
  737. image: "https://cdn-icons-png.flaticon.com/512/5234/5234222.png",
  738. timeout: 3e3
  739. });
  740. Syn.Store("sj", "E/Ex_Cookies", JSON.parse($("#view_SC").val()));
  741. self.DeleteMenu();
  742. } else if (target.className == "modal-background" || target.id == "close") {
  743. self.DeleteMenu();
  744. }
  745. });
  746. }
  747. async CookieInjection() {
  748. try {
  749. Ckop.ReAdd(Syn.Store("gj", "E/Ex_Cookies"));
  750. } catch (error) {
  751. alert(Lang.Transl("未檢測到可注入的 Cookies !!\n\n請從選單中進行設置"));
  752. }
  753. }
  754. async ClearLogin() {
  755. Ckop.Delete();
  756. location.reload();
  757. }
  758. }().Main();
  759. })();