您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
ツイートボタンの埋め込みテキストに情報を追加します
当前为
// ==UserScript== // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access // @name atcoder-hashtag-setter2 // @namespace https://github.com/hotarunx // @version 2.0.0 // @description ツイートボタンの埋め込みテキストに情報を追加します // @author hotarunx // @license MIT // @supportURL https://github.com/hotarunx/atcoder-hashtag-setter2/issues // @match https://atcoder.jp/contests/* // @exclude https://atcoder.jp/contests/ // @grant none // ==/UserScript== // AtCoderの問題ページをパースする /** * URLをパースする パラメータを消す \ * 例: in: https://atcoder.jp/contests/abc210?lang=en \ * 例: out: (5)['https:', '', 'atcoder.jp', 'contests', 'abc210'] */ const parseURL = (url) => { // 区切り文字`/`で分割する // ?以降の文字列を削除してパラメータを削除する return url.split("/").map((x) => x.replace(/\?.*/i, "")); }; const URL = parseURL(window.location.href); // /** * 表セル要素から、前の要素のテキストが引数と一致する要素を探す * 個別の提出ページで使うことを想定 * 例: searchSubmissionInfo(["問題", "Task"]) */ const searchSubmissionInfo = (key) => { const tdTags = document.getElementsByTagName("td"); const tdTagsArray = Array.prototype.slice.call(tdTags); return tdTagsArray.filter((elem) => { const prevElem = elem.previousElementSibling; const text = prevElem?.textContent; if (typeof text === "string") return key.includes(text); return false; })[0]; }; /** コンテストタイトル 例: AtCoder Beginner Contest 210 */ const contestTitle = document.getElementsByClassName("contest-title")[0]?.textContent ?? ""; /** コンテストID 例: abc210 */ const contestID = URL[4] ?? ""; /** * ページ種類 \ * 基本的にコンテストIDの次のパス * ### 例外 * 問題: task * 個別の提出: submission */ const pageType = (() => { if (URL.length < 6) return ""; if (URL.length >= 7 && URL[5] === "submissions" && URL[6] !== "me") return "submission"; if (URL.length >= 7 && URL[5] === "tasks") return "task"; return URL[5] ?? ""; })(); /** 問題ID 例: abc210_a */ const taskID = (() => { if (pageType === "task") { // 問題ページでは、URLから問題IDを取り出す return URL[6] ?? ""; } if (pageType === "submission") { // 個別の提出ページでは、問題リンクのURLから問題IDを取り出す // 提出情報の問題のURLを取得する const taskCell = searchSubmissionInfo(["問題", "Task"]); if (!taskCell) return ""; const taskLink = taskCell.getElementsByTagName("a")[0]; if (!taskLink) return ""; const taskUrl = parseURL(taskLink.href); const taskIDParsed = taskUrl[6] ?? ""; return taskIDParsed; } return ""; })(); /** 問題名 例: A - Cabbages */ const taskTitle = (() => { if (pageType === "task") { // 問題ページでは、h2から問題名を取り出す return (document .getElementsByClassName("h2")[0] ?.textContent?.trim() .replace(/\n.*/i, "") ?? ""); } if (pageType === "submission") { // 個別の提出ページでは、問題リンクのテキストから問題名を取り出す // 提出情報の問題のテキストを取得する const taskCell = searchSubmissionInfo(["問題", "Task"]); if (!taskCell) return ""; const taskLink = taskCell.getElementsByTagName("a")[0]; if (!taskLink) return ""; return taskLink.textContent ?? ""; } return ""; })(); /** 提出ユーザー 例: machikane */ const submissionsUser = (() => { if (pageType !== "submission") return ""; // 個別の提出ページのとき const userCell = searchSubmissionInfo(["ユーザ", "User"]); if (!userCell) return ""; return userCell?.textContent?.trim() ?? ""; })(); /** 提出結果 例: AC */ const judgeStatus = (() => { if (pageType !== "submission") return ""; // 個別の提出ページのとき const statusCell = searchSubmissionInfo(["結果", "Status"]); if (!statusCell) return ""; return statusCell?.textContent?.trim() ?? ""; })(); /** 得点 例: 100 */ const judgeScore = (() => { if (pageType !== "submission") return 0; // 個別の提出ページのとき const scoreCell = searchSubmissionInfo(["得点", "Score"]); if (!scoreCell) return 0; return parseInt(scoreCell?.textContent?.trim() ?? "0", 10); })(); /** 常設コンテストID一覧 */ const permanentContestIDs = [ "practice", "APG4b", "abs", "practice2", "typical90", "math-and-algorithm", "tessoku-book", ]; /** * 次を判定 * * コンテストが終了している * * コンテストが常設コンテスト */ var isContestOver = () => { if (permanentContestIDs.includes(contestID)) return true; return Date.now() > endTime.valueOf(); }; var html = "<a target=\"_blank\" href=\"\" rel=\"nofollow noopener\">\n <span class=\"a2a_svg a2a_s__default a2a_s_twitter\" style=\"background-color: rgb(230, 18, 114);\n width: 20px;\n line-height: 20px;\n height: 20px;\n background-size: 20px;\n border-radius: 3px;\n --darkreader-inline-bgcolor: #0c72b7;\" data-darkreader-inline-bgcolor=\"\">\n <svg focusable=\"false\" aria-hidden=\"true\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\">\n <path fill=\"#FFF\" d=\"M28 8.557a9.913 9.913 0 0 1-2.828.775 4.93 4.93 0 0 0 2.166-2.725 9.738 9.738 0 0 1-3.13 1.194 4.92 4.92 0 0 0-3.593-1.55 4.924 4.924 0 0 0-4.794 6.049c-4.09-.21-7.72-2.17-10.15-5.15a4.942 4.942 0 0 0-.665 2.477c0 1.71.87 3.214 2.19 4.1a4.968 4.968 0 0 1-2.23-.616v.06c0 2.39 1.7 4.38 3.952 4.83-.414.115-.85.174-1.297.174-.318 0-.626-.03-.928-.086a4.935 4.935 0 0 0 4.6 3.42 9.893 9.893 0 0 1-6.114 2.107c-.398 0-.79-.023-1.175-.068a13.953 13.953 0 0 0 7.55 2.213c9.056 0 14.01-7.507 14.01-14.013 0-.213-.005-.426-.015-.637.96-.695 1.795-1.56 2.455-2.55z\" data-darkreader-inline-fill=\"\" style=\"--darkreader-inline-fill: #e8e6e3\"></path>\n </svg> </span><span class=\"a2a_label\">Twitter2</span>\n</a>\n"; /** ツイートボタンのHTML要素 */ const a2akit = document.getElementsByClassName("a2a_kit")[0]; /** * ツイートボタンのテキストを取得する */ const getTweetButtonText = () => { if (!a2akit) return ""; return a2akit.getAttribute("data-a2a-title"); }; /** * ツイートボタンのテキストを変更する */ const setTweetButtonText = (text) => { if (!a2akit) return; a2akit.setAttribute("data-a2a-title", text); }; const addTweetSearchButton = (text) => { const searchURL = `https://twitter.com/search?q=${encodeURIComponent(text)}`; const parser = new DOMParser(); const doc = parser.parseFromString(html, "text/html"); const docA = doc.getElementsByTagName("a")[0]; docA.href = searchURL; a2akit.insertAdjacentElement("beforeend", docA); }; (() => { // ネタバレ防止のため、コンテスト終了前(常設コンテストを除く)は無効とする if (!isContestOver()) return; /** コンテストハッシュタグ 例: #AtCoder_abc210_a */ const contestHashtag = contestID ? ` #AtCoder_${contestID}` : ""; /** 問題ハッシュタグ 例: #AtCoder_abc210_a */ const taskHashtag = taskID ? ` #AtCoder_${taskID}` : ""; /** ユーザーハッシュタグ 例: #AtCoder_machikane */ const userHashtag = userScreenName ? ` #AtCoder_${userScreenName}` : ""; // ツイートボタンのテキストを取得する const textOrg = getTweetButtonText(); if (!textOrg) return; // ツイートボタンのテキストを編集 let text = textOrg + contestHashtag; if (pageType === "task") { // 問題ページ text = `${taskTitle} - ${contestTitle}${taskHashtag}${contestHashtag}${userHashtag}`; } else if (pageType === "submission") { // 個別の提出ページ text = `${taskTitle} - ${submissionsUser}の提出 - 結果 ${judgeStatus} ${judgeScore}点 - ${contestTitle}${taskHashtag}${contestHashtag}${userHashtag}`; } setTweetButtonText(text); // タグ検索ボタンを追加 /** 検索タグ 問題ハッシュタグ なければコンテストハッシュタグ */ const searchTag = taskHashtag || contestHashtag; addTweetSearchButton(searchTag.trim()); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址