Ctrl+CでタイトルとURLをコピー

Shift+C:除去文字列設定  Shift+T:後回しタイトル設定

As of 22.11.2020. See ბოლო ვერსია.

  1. // ==UserScript==
  2. // @name Ctrl+CでタイトルとURLをコピー
  3. // @description Shift+C:除去文字列設定  Shift+T:後回しタイトル設定
  4. // @match *://*/*
  5. // @version 0.6.3
  6. // @run-at document-idle
  7. // @grant GM.setClipboard
  8. // @grant GM_setValue
  9. // @grant GM_getValue
  10. // @grant GM_deleteValue
  11. // @namespace https://greasyfork.org/users/181558
  12. // ==/UserScript==
  13.  
  14. (function() {
  15. const cleanUrlFirst = 0; // 1ならページ読み込み時にURLのゴミ除去を行う
  16. const ADD_OPEN_MULTIPLE_URL_GUIDE = 0; // 1なら末尾にopepn multiple urlアドオンの紹介をつける
  17.  
  18. if (window != parent) return;
  19.  
  20. var mllID;
  21. var sakujoRE = pref("ctrlcsakujoRE") || "";
  22. var cckaisuu = 0;
  23. var sakujoTitleRE = pref("ctrlcsakujoTitleRE") || "";
  24.  
  25. if (cleanUrlFirst) window.history.pushState(null, null, modUrl());
  26.  
  27. // Shift+T ページタイトル部分後回し
  28. sakujotitle(sakujoTitleRE);
  29.  
  30. function sakujotitle(sakujoTitleRE) {
  31. if (sakujoTitleRE) {
  32. try {
  33. var hit = document.title.match(RegExp(sakujoTitleRE, "g"));
  34. if (hit) document.title = document.title.replace(RegExp(sakujoTitleRE, "g"), "") + " " + hit;
  35. } catch (e) { alert("Shift+T:\n文法エラーのようです\n\n設定値:\n" + sakujoTitleRE); }
  36. }
  37. }
  38. // 検索ワードをページタイトルの最初に付ける
  39. addtitle(/^https?:\/\/calil.jp\/local\/search/, "", '//form[@class="search"]/div/input|//input[@id="query"]'); // calil検索
  40. addtitle(/^https?:\/\/tv\.yahoo\.co\.jp\/search\/\?q=/, "", '//input[@class="generic_inputText floatl"]'); // yahooテレビ検索
  41. addtitle(/^https?:\/\/www\.nicovideo\.jp\/mylist_search\//, "", '//input[@id="search_united"]', "", "", " - マイリスト検索 "); // ニコ動マイリスト検索
  42. addtitle(/^https?:\/\/www\.jstage\.jst\.go\.jp\/result/, "", '//span[@class="search-parameter"]'); // J-STAGE詳細検索結果
  43. //addtitle(/^https?:\/\/www\.pinterest\.jp\/search\/pins\/.*q=/,"",'//input[@data-test-id="search-box-input"]|//input[@class="OpenSearchBoxInput" and @type="text"]'); // Pinterest詳細検索結果
  44.  
  45. if (document.title.indexOf("|") === -1) addtitle(/^https?:\/\/www\.suruga-ya\.jp\/search\?/, "", '//input[@id="searchText"]', '//div[@id="topicPath"]', /駿河屋TOP.≫.|駿河屋TOP/gi); // 駿河屋検索
  46.  
  47. document.addEventListener("keydown", function(e) { //キー入力
  48. if (/input|textarea/i.test(e.target.tagName)) return;
  49. if (e.shiftKey && !e.altKey && !e.ctrlKey && e.which == 84) { // shift+T ページタイトル部分後回し文字列設定
  50. var sample = "ありません";
  51. if (location.href.indexOf("://www.nicovideo.jp") !== -1) sample = "キーワードで動画検索 |キーワードで|」動画|人気の「";
  52. if (location.href.indexOf("://www.amazon.co.jp") !== -1) sample = "Amazon.co.jp: |Amazon.co.jp: |Amazon \\|\\s|Amazon|";
  53. if (location.href.indexOf("auctions.yahoo.co.jp") !== -1) sample = "ヤフオク! -";
  54. if (location.href.indexOf("kakaku.com/") !== -1) sample = "価格.com - ";
  55. if (location.href.indexOf("//www.yodobashi.com/") !== -1) sample = "ヨドバシ.com - ";
  56. if (location.href.indexOf("//www.sukima.me/book/title/") !== -1) sample = "^\\[.*\\]";
  57. var str = prompt("shift+T:\r\n\"" + document.domain + "\" でページタイトルの中で後ろに移動したい文字列を正規表現で入力してください\r\n\r\nこのサイトでのお薦め設定例:\r\n" + sample + "\r\n\r\n現在値:" + (sakujoTitleRE || "なし") + "\n\n", sakujoTitleRE || "");
  58. sakujoTitleRE = str === null ? sakujoTitleRE : str;
  59. if (sakujoTitleRE != "") {
  60. pref("ctrlcsakujoTitleRE", sakujoTitleRE);
  61. sakujotitle(sakujoTitleRE);
  62. } else {
  63. pref("ctrlcsakujoTitleRE", "");
  64. }
  65. return;
  66. }
  67. if (e.shiftKey && !e.altKey && !e.ctrlKey && e.which == 67) { // shift+C 除去文字列設定
  68. var str = prompt("shift+C:\r\n\"" + document.domain + "\" で Ctrl+C 押下時タイトルやURLや選択文字列から除去したい文字列を正規表現で入力してください\r\n\r\n現在値:" + sakujoRE + "\r\n", sakujoRE);
  69. sakujoRE = str === null ? sakujoRE : str;
  70. if (sakujoRE != "") {
  71. pref("ctrlcsakujoRE", sakujoRE);
  72. } else {
  73. pref("ctrlcsakujoRE", "");
  74. }
  75. return;
  76. }
  77. if (!e.shiftKey && !e.altKey && e.ctrlKey && e.which == 67) { // ctrl+c
  78. if (window.getSelection() != "") {
  79. // 選択文字列がある
  80. var selection = window.getSelection().toString();
  81. if (sakujoRE) { // 除去文字列があれば除去してコピーも自前(なければブラウザにさせる)
  82. selection = tryReplace(selection, sakujoRE, "Shift+C");
  83. if (window.getSelection().toString() !== selection) {
  84. copy2cb(selection);
  85. e.preventDefault();
  86. }
  87. }
  88. } else {
  89.  
  90. // 選択文字列がない
  91.  
  92. var doc = location.href;
  93. var txt1 = doc;
  94. var txt2 = txt1;
  95. var opt = "";
  96.  
  97. var txt2 = modUrl();
  98. //if (txt1 != txt2) opt += "(パラメータ除去)";
  99.  
  100. if (/www\.youtube\.com\/embed\//.test(txt1)) txt2 = txt1.replace(/\?.*/, "").replace(/embed\//, "watch?v="); // youtube埋め込みを正規のページに
  101.  
  102. var ret = (navigator.platform.indexOf("Win") != -1) ? "\r\n" : "\n";
  103. var title = document.title.replace(/ https?:.*/, "");
  104. title = tryReplace(title, sakujoRE, "Shift+C");
  105.  
  106. // YouTube動画視聴画面なら
  107. if (location.href.match(/^https?:\/\/www\.youtube\.com\/watch\?v\=/)) { let te = eleget0('//h1[@class="title style-scope ytd-video-primary-info-renderer"]/yt-formatted-string[@force-default-style="" and @class="style-scope ytd-video-primary-info-renderer"]'); if (te) { title = te.innerText + " - YouTube"; } }
  108.  
  109.  
  110. if (location.href.match(/^https?:\/\/www\.pinterest\.jp\/search\/pins\/.*q=/gmi)) {
  111. //opt += "(検索キー挿入)";
  112. title = eleget0('//input[@data-test-id="search-box-input"]|//input[@class="OpenSearchBoxInput" and @type="text"]').value + " | " + title;
  113. } // Pinterest詳細検索結果
  114.  
  115. if (cckaisuu % 1 == 0) {
  116. var txt = title + ret + txt2 + ret;
  117. var bal = "<B>" + title + "</B><BR>" + txt2;
  118. }
  119. var sort = "";
  120.  
  121. // 列挙するタイプのサイトなら
  122. if (/seiga\.nicovideo\.jp\/my\/manga\/favorite|webcomics\.jp\/mylist|webcomics\.jp\/$|webcomics.jp\/total$|webcomics\.jp\/bookmark|webcomics\.jp\/ranking|www.nicovideo.jp\/my\/watchlater|www\.nicovideo\.jp\/my\/mylist|seiga\.nicovideo\.jp\/my\/clip|www\.nicovideo\.jp\/my\/fav\/|www\.nicovideo\.jp\/my\/channel|www\.nicovideo\.jp\/my\/community|www\.nicovideo\.jp\/my\/top\/all|\/\/www\.netoff\.co\.jp\/cart_param/.test(txt1)) {
  123. var rekkyo = ['//span[@class="VideoMediaObject-bodyTitle"]/../..', '//div[@class="title"]/a', '//div[@class="entry-title"]/a[1]', '//div[@class="mylistVideo"]/h5/a', '//div[@class="illust_box_li cfix"]/div/div[@class="text_ttl"]/a', '//div[@class="outer"]/div/h5/a', '//div[@class="outer"]/h5/a', '//div[@class="log-target-info"]/a', '//div[@class="mylistVideo MylistItem-videoDetail"]/h5/a|//div[@id="mainWrap"]/div[@id="main"]/ul[contains(@class,"itemList")]/li[@class="clearfix"]/dl/dd/p/a'];
  124. txt = ""; //title+ret;
  125. txt2 = "";
  126. var num = 0;
  127. for (let target of rekkyo) {
  128. var ele = elegeta(target);
  129. if (cckaisuu % 4 == 1) {
  130. sort = " 名前↓";
  131. ele.sort(function(a, b) { return (a.innerText > b.innerText) ? 1 : -1; });
  132. }
  133. if (cckaisuu % 4 == 2) {
  134. sort = " URL↓";
  135. ele.sort(function(a, b) { return (a.href.split(/\/\//g)[1]) > (b.href.split(/\/\//g)[1]) ? 1 : -1; });
  136. }
  137. if (cckaisuu % 4 == 3) {
  138. sort = " URL↑";
  139. ele.sort(function(a, b) { return (a.href.split(/\/\//g)[1]) < (b.href.split(/\/\//g)[1]) ? 1 : -1; });
  140. }
  141. for (let a of ele) {
  142. if (a.offsetHeight) { // 非表示じゃないやつだけ
  143. var cleanurl = a.href.replace(/\?track=.*|\?_topic=.*/g, "")
  144. txt += a.innerText.replace(/\n/gm, " ") + ret + cleanurl + ret;
  145. txt2 += a.innerText + "<BR>" + cleanurl + "<BR>";
  146. num++;
  147. }
  148. }
  149. }
  150. title += " " + num + "件" + sort;
  151. txt = title + ret + txt;
  152. if (ADD_OPEN_MULTIPLE_URL_GUIDE) txt += "\nOpen Multiple URLs - Google 検索\nhttps://www.google.co.jp/search?q=Open%20Multiple%20URLs&lr=lang_ja\n";
  153. var bal = "<B>" + title + "</B><BR>" + txt2;
  154. popup("項目の列挙<br>" + title);
  155. } else {
  156. popup("タイトルとURL<BR>" + opt);
  157. }
  158.  
  159. // クリップボードにコピー
  160. copy2cb(txt);
  161. e.preventDefault();
  162. }
  163. cckaisuu++;
  164. return;
  165. }
  166. },
  167. false);
  168. return;
  169.  
  170. function elegeta(xpath) {
  171. var ele = document.evaluate(xpath, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
  172. var array = [];
  173. for (var i = 0; i < ele.snapshotLength; i++) array[i] = ele.snapshotItem(i);
  174. return array;
  175. }
  176.  
  177. function eleget0(xpath) {
  178. var ele = document.evaluate(xpath, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
  179. return ele.snapshotLength > 0 ? ele.snapshotItem(0) : "";
  180. }
  181.  
  182. // タイトルに足す
  183. function addtitle(url, txt1, xpath, optionxpath = "", optionReplaceRE = /$^/, separator = " - ") {
  184. if (url.test(location.href)) {
  185. var ele = eleget0(xpath).value;
  186. if (!ele) {
  187. ele = eleget0(xpath).innerText;
  188. }
  189. var ret = ele.trim() > "" ? ele.trim() + separator : "";
  190. if (optionxpath && eleget0(optionxpath)) {
  191. ret += "" + (eleget0(optionxpath).innerText.trim().replace(optionReplaceRE, "")) + " ";
  192. }
  193. document.title = ret + document.title;
  194. }
  195. return;
  196. }
  197.  
  198. // クリップボードにコピー
  199. function copy2cb(txt) {
  200. GM.setClipboard(txt);
  201. }
  202.  
  203. function deleteParam(cutREs, txt1) { //余計なパラメータを除去
  204. var para = txt1.split(/[&?#]/);
  205. var txt2 = para[0] + "?";
  206. var j = 0;
  207. for (var i = 1; i < para.length; i++) {
  208. for (let reptxt of cutREs) {
  209. para[i] = para[i].replace(new RegExp("^" + reptxt + ".*"), "");
  210. }
  211. if (para[i] !== "") {
  212. txt2 += (j++ > 0 ? "&" : "") + para[i];
  213. }
  214. }
  215. return txt2.replace(/\?$/, ""); //行末が?なら削除
  216. }
  217.  
  218. function modUrl() {
  219. var txt1 = location.href;
  220. var txt2 = txt1;
  221.  
  222. if (/^https?:\/\/www\.amazon\.co\.jp\/|^https?:\/\/www\.amazon\.com\//.test(txt1) && (txt1.indexOf("/dp/product/") != -1)) // Amazonのパラメータ除去
  223. txt2 = "https://" + document.domain + "/dp/" + txt1.substr(txt1.indexOf("/dp/product/") + 12, 10);
  224. else if (/^https?:\/\/www\.amazon\.co\.jp\/|^https?:\/\/www\.amazon\.com\//.test(txt1) && (txt1.indexOf("/dp/") != -1)) // Amazonのパラメータ除去
  225. txt2 = "https://" + document.domain + "/dp/" + txt1.substr(txt1.indexOf("/dp/") + 4, 10);
  226. // txt2 = "https://" + document.domain + "/dp/" + txt1.replace(/.+\/dp\/(product\/)?([0-9A-Z]{10,10}).+/, "$2");
  227. if (/^https?:\/\/www\.amazon\.co\.jp\/|^https?:\/\/www\.amazon\.com\//.test(txt1) && (txt1.indexOf("/ASIN/") != -1)) // Amazonのパラメータ除去
  228. txt2 = "https://www.amazon.co.jp/dp/" + txt1.substr(txt1.indexOf("/ASIN/") + 6, 10);
  229. if (/^https?:\/\/www\.amazon\.co\.jp\/|^https?:\/\/www\.amazon\.com\//.test(txt1) && (txt1.indexOf("/gp/product/") != -1)) // Amazonのパラメータ除去
  230. txt2 = "https://www.amazon.co.jp/dp/" + txt1.substr(txt1.indexOf("/gp/product/") + 12, 10);
  231. if (/^https?:\/\/www\.amazon\.co\.jp\/gp\/customer-reviews\//.test(txt1)) // Amazonのカスタマーレビューのパラメータ除去
  232. txt2 = deleteParam(["ref=", "ie=", "ASIN="], txt1).replace(/\/ref=.*/, "");
  233. txt1 = txt1.replace(/(^https?:\/\/www\.amazon\.co\.jp\/)(.*)(product-reviews\/)/, "$1$3");
  234. if (txt1.match(/^https?:\/\/www\.amazon\.co\.jp\/.*product-reviews\//)) // Amazonのカスタマーレビューのパラメータ除去
  235. txt2 = deleteParam(["ref=", "ie=", "ASIN="], txt1).replace(/\/ref=.*/, "");
  236.  
  237. if (/^https?:\/\/www\.google\.co\.jp\/search\?|^https?:\/\/www\.google\.com\/search\?/.test(txt1)) // google検索結果のパラメータ除去
  238. txt2 = deleteParam(["ei=", "oq=", "gs_l=", "hl=", "source=", "sa=", "ved=", "biw=", "bih=", "dpr=", "ie=", "oe=", "client=", "aqs=", "sourceid=", "btgG=", "lr="], txt1);
  239.  
  240. if (/^https?:\/\/books\.google\.co\.jp\/books\?/.test(txt1)) // Googleブックス検索のパラメータ除去
  241. txt2 = deleteParam(["souce=", "ots=", "sig=", "hl=", "sa=", "ved=", "f=", "lpg=", "dq=", "source=", "f=", "v=", cckaisuu % 2 == 0 ? "$^" : "q="], txt1); // q=を残すと検索ワードは残る
  242.  
  243. if (/^https?:\/\/www\.ted\.com\/talks/.test(txt1)) // TEDのパラメータ除去
  244. txt2 = deleteParam(["awesm=", "utm_medium=", "share=", "utm_source=", "utm_campaign=", "utm_content=", "source=", "embed=", "t-", "frm_id=", "device_id=", "fb_action_ids=", "action_type_map=", "action_object_map=", "fb_source=", "fb_action_types", "action_ref_map=", "ref=", "refid=", "_ft_=", "guid="], txt1);
  245.  
  246. if (/^https?:\/\/translate\.google\.com\/translate|^https?:\/\/translate\.googleusercontent\.com\/translate_c/.test(txt2)) { // google翻訳のパラメータ除去
  247. txt2 = (txt2.match(/^https?:\/\/translate\.google\.com\/translate|^https?:\/\/translate\.googleusercontent\.com\/translate_c/)[0] + txt2.match(/[\?&]u=[^&]*/)).replace(/&/, "?");
  248. }
  249.  
  250. if (/^https?:\/\/seiga\.nicovideo\.jp\/comic|^https?:\/\/seiga\.nicovideo\.jp\/manga\/list|^https?:\/\/seiga\.nicovideo\.jp\/watch\/mg/.test(txt1)) txt2 = txt1.replace(/([\&\?]?[\&\?]track=.*)|(\?_topic.*)|(\?ct_now$)/, ""); // 静画(マンガ)のパラメータ除去
  251.  
  252. if (/^https?:\/\/www\.nicovideo\.jp\/watch/.test(txt1)) txt2 = txt1.replace(/\?.*$/, ""); // ニコ動のパラメータ除去
  253. if (/^https?:\/\/www\.nicovideo\.jp\/user/.test(txt1)) txt2 = txt1.replace(/\?_topic.*/, ""); // ニコ動のパラメータ除去
  254. if (/^https?:\/\/www\.nicovideo\.jp\/tag\//.test(txt1)) txt2 = txt1.replace(/[\?&]ref=[^&]*/, ""); // ニコ動のパラメータ除去
  255. if (/^https?:\/\/www\.nicovideo\.jp\/search\//.test(txt1)) txt2 = txt1.replace(/\?f_range=0\&l_range=0\&opt_md=\&start=\&end=|[\?&]track=[^&]*/, ""); // ニコ動のパラメータ除去
  256. if (/^https?:\/\/www\.ebay\.com\/itm\/.*\?hash=/.test(txt1)) txt2 = txt1.replace(/\?hash=.*$/, ""); // eBayのパラメータ除去
  257. if (/^https?:\/\/ja.aliexpress.com\/item\/.*?.html\?spm=/.test(txt1)) txt2 = txt1.replace(/\?spm=.*$/, ""); // AliExpressのパラメータ除去
  258. if (/^https?:\/\/www.mercari.com\/jp\/items\/m51992587701\/\?_s=/.test(txt1)) txt2 = txt1.replace(/\/\?_s=.*$/, ""); // メルカリのパラメータ除去
  259.  
  260. return txt2;
  261. }
  262.  
  263. function tryReplace(str, re, title) {
  264. try {
  265. str = str.replace(RegExp(re, "gm"), "");
  266. } catch (e) { alert(title + ":\n文法エラーのようです\n\n設定値:\n" + re); }
  267. return str;
  268. }
  269.  
  270. function pref(name, store = undefined) { // pref(name,data)で書き込み(数値でも文字列でも配列でもオブジェクトでも可)、pref(name)で読み出し
  271. var domain = (location.href.match(/^https?:\/{2,}(.*?)(?:\/|\?|#|$)/)[1] || location.href);
  272. if (store === undefined) { // 読み出し
  273. let data = GM_getValue(domain + " ::: " + name)
  274. if (data == undefined) return store; // 値がないなら終わり
  275. if (data.substr(0, 1) === "[") { // 配列なのでJSONで返す
  276. try { return JSON.parse(data || '[]'); } catch (e) {
  277. console.log("データベースがバグってるのでクリアします\n" + e);
  278. pref(name, []);
  279. return;
  280. }
  281. } else return data;
  282. }
  283. if (store === "" || store === [] || store === null) { // 書き込み、削除
  284. GM_deleteValue(domain + " ::: " + name);
  285. return store;
  286. } else if (typeof store === "string") { // 書き込み、文字列
  287. GM_setValue(domain + " ::: " + name, store);
  288. return store;
  289. } else { // 書き込み、配列
  290. try { GM_setValue(domain + " ::: " + name, JSON.stringify(store)); } catch (e) {
  291. console.log("データベースがバグってるのでクリアします\n" + e);
  292. pref(name, "");
  293. }
  294. return store;
  295. }
  296. }
  297.  
  298. function popup(text) {
  299. var e = document.getElementById("cccbox");
  300. if (e) { e.remove(); }
  301. if (mllID) { clearTimeout(mllID); }
  302. var ele = document.body.appendChild(document.createElement("span"));
  303. ele.innerHTML = '<span id="cccbox" style="all:initial; position: fixed; right:0em; top:0em; z-index:2147483647; opacity:1; font-size:90%; font-weight:bold; margin:0px 1px; text-decoration:none !important; text-align:center; padding:1px 6px 1px 6px; border-radius:12px; background-color:#6080ff; color:white; white-space: nowrap;"">' + text + '</span>';
  304. mllID = setTimeout(function() { var ele = document.getElementById("cccbox"); if (ele) ele.remove(); }, 5000);
  305. }
  306.  
  307. })();