MarkDown 雲剪筆記

將網頁內容轉換為 Markdown 格式的工具,支持複製、下載、發送到 GitHub 和 Obsidian 等功能。

目前為 2025-03-18 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name MarkDown Cloud Cut Notes
  3. // @name:ar ملاحظات قطع السحابة المتولد
  4. // @name:bg Бележки за изрязване на облак от Маркдаун
  5. // @name:cs Poznámky k cloudovému řezu Markdown
  6. // @name:da Markdown Cloud Cut Notes
  7. // @name:de Markdown Cloud Cut -Notizen
  8. // @name:el Σημειώσεις κοπής σύννεφων Markdown
  9. // @name:en MarkDown Cloud Cut Notes
  10. // @name:eo Markdown Cloud Cut Notes
  11. // @name:es Notas de corte de nube de markdown
  12. // @name:fi Markdown Cloud Cut Notes
  13. // @name:fr Notes de coupe de cloud de Markdown
  14. // @name:fr-CA Notes de coupe de cloud de Markdown
  15. // @name:he הערות Culd Cloud Markdown
  16. // @name:hr Markdown Cloud Cut Notes
  17. // @name:hu Markdown Cloud Cut jegyzetek
  18. // @name:id Markdown Cloud Cut Notes
  19. // @name:it Markdown Cloud Cut Notes
  20. // @name:ja マークダウンクラウドカットノート
  21. // @name:ka Markdown Cloud Cut Notes
  22. // @name:ko 마크 다운 클라우드 컷 메모
  23. // @name:nb Markdown Cloud Cut Notes
  24. // @name:nl Markdown Cloud Cut Notes
  25. // @name:pl Notatki z Cloud Cloud Cloud
  26. // @name:pt-BR Notas de corte na nuvem de marcação
  27. // @name:ro Note de tăiere a norului markdown
  28. // @name:ru Примечания к облаку отметки
  29. // @name:sk Poznámky k mraku cloudu
  30. // @name:sr Напомена Цлоуд Цлоуд Сцрет Нотес
  31. // @name:sv Markdown Cloud Cut -anteckningar
  32. // @name:th MARKDOWN Cloud Cut Notes
  33. // @name:tr Markdown bulut kesim notları
  34. // @name:ug ماركېل بۇلۇت ئۈزۈلۈپ قالدى
  35. // @name:uk Нотатки з вирізанням Cloud Cloud
  36. // @name:vi Markdown Cloud Cut Ghi chú
  37. // @name:zh MarkDown 云剪笔记
  38. // @name:zh-CN MarkDown 云剪笔记
  39. // @name:zh-HK MarkDown 雲剪筆記
  40. // @name:zh-SG MarkDown 云剪笔记
  41. // @name:zh-TW MarkDown 雲剪筆記
  42. // @description A tool that converts web content to Markdown format, supports features such as copying, downloading, and sending to GitHub and Obsidian.
  43. // @description:ar تقوم أداة بتحويل محتوى الويب إلى تنسيق Markdown ، ويدعم ميزات مثل نسخ وتنزيل وإرسال Github و Obsidian.
  44. // @description:bg Инструмент, който преобразува уеб съдържание във формат за маркиране, поддържа функции като копиране, изтегляне и изпращане на GitHub и Obsidian.
  45. // @description:cs Nástroj, který převádí webový obsah do formátu označení, podporuje funkce, jako je kopírování, stahování a odesílání do GitHubu a obsidiánu.
  46. // @description:da Et værktøj, der konverterer webindhold til Markdown -format, understøtter funktioner såsom kopiering, download og sender til GitHub og Obsidian.
  47. // @description:de Ein Tool, das Webinhalte in Markdown -Format umwandelt, unterstützt Funktionen wie das Kopieren, Herunterladen und Senden an GitHub und Obsidian.
  48. // @description:el Ένα εργαλείο που μετατρέπει το περιεχόμενο ιστού σε μορφή Markdown, υποστηρίζει χαρακτηριστικά όπως η αντιγραφή, η λήψη και η αποστολή στο GitHub και ο Obsidian.
  49. // @description:en A tool that converts web content to Markdown format, supports features such as copying, downloading, and sending to GitHub and Obsidian.
  50. // @description:eo Ilo, kiu konvertas retan enhavon al Markdown -formato, subtenas funkciojn kiel kopii, elŝuti kaj sendi al Github kaj Obsidian.
  51. // @description:es Una herramienta que convierte el contenido web en formato de Markdown, admite características como copiar, descargar y enviar a Github y Obsidian.
  52. // @description:fi Työkalu, joka muuntaa verkkosisällön merkinnän muotoon, tukee ominaisuuksia, kuten kopiointia, lataamista ja lähettämistä GitHubille ja Obsidianille.
  53. // @description:fr Un outil qui convertit le contenu Web au format Markdown, prend en charge des fonctionnalités telles que la copie, le téléchargement et l’envoi à GitHub et Obsidian.
  54. // @description:fr-CA Un outil qui convertit le contenu Web au format Markdown, prend en charge des fonctionnalités telles que la copie, le téléchargement et l’envoi à GitHub et Obsidian.
  55. // @description:he כלי שממיר תוכן אינטרנט לפורמט Markdown, תומך בתכונות כמו העתקה, הורדה ושליחה ל- Github ו- Obsidian.
  56. // @description:hr Alat koji pretvara web sadržaj u Markdown format, podržava značajke poput kopiranja, preuzimanja i slanja GitHub i Obsidian.
  57. // @description:hu Egy olyan eszköz, amely a webtartalmat Markdown formátumra konvertálja, támogatja azokat a funkciókat, mint például a másolást, a letöltést és a Github -nak és az Obsidian -nak küldését.
  58. // @description:id Alat yang mengonversi konten web ke format penurunan harga, mendukung fitur seperti menyalin, mengunduh, dan mengirim ke GitHub dan Obsidian.
  59. // @description:it Uno strumento che converte i contenuti Web in formato markdown, supporta funzionalità come la copia, il download e l’invio a Github e Obsidian.
  60. // @description:ja WebコンテンツをMarkdown形式に変換するツールは、GithubやObsidianへのコピー、ダウンロード、送信などの機能をサポートします。
  61. // @description:ka ინსტრუმენტი, რომელიც გარდაქმნის ვებ შინაარსს MarkDown ფორმატში, მხარს უჭერს ისეთ ფუნქციებს, როგორიცაა კოპირება, ჩამოტვირთვა და გაგზავნა Github და Obsidian.
  62. // @description:ko 웹 컨텐츠를 Markdown 형식으로 변환하는 도구는 복사, 다운로드 및 Github 및 Obsidian으로 전송과 같은 기능을 지원합니다.
  63. // @description:nb Et verktøy som konverterer nettinnhold til Markdown -format, støtter funksjoner som kopiering, nedlasting og sending til Github og Obsidian.
  64. // @description:nl Een tool die webinhoud converteert naar Markdown -indeling, ondersteunt functies zoals kopiëren, downloaden en verzenden naar GitHub en Obsidian.
  65. // @description:pl Narzędzie, które konwertuje treść sieci w formacie Markdown, obsługuje takie funkcje, jak kopiowanie, pobieranie i wysyłanie do Github i Obsidian.
  66. // @description:pt-BR Uma ferramenta que converte o conteúdo da Web em formato de marcação, suporta recursos como cópia, download e envio para o Github e Obsidian.
  67. // @description:ro Un instrument care convertește conținutul web în format markdown, acceptă funcții precum copierea, descărcarea și trimiterea către Github și Obsidian.
  68. // @description:ru Инструмент, который преобразует веб -контент в формат разметки, поддерживает такие функции, как копирование, загрузка и отправка в Github и Obsidian.
  69. // @description:sk Nástroj, ktorý prevádza webový obsah na formát Markdown, podporuje funkcie, ako je kopírovanie, sťahovanie a odosielanie spoločnosti GitHub a Obsidian.
  70. // @description:sr Алат који претвара Веб садржај у ознаку формата, подржава функције као што су копирање, преузимање и слање Гитхуб-а и Обсидијан.
  71. // @description:sv Ett verktyg som konverterar webbinnehåll till Markdown -format, stöder funktioner som kopiering, nedladdning och skickning till GitHub och Obsidian.
  72. // @description:th เครื่องมือที่แปลงเนื้อหาเว็บเป็นรูปแบบ Markdown รองรับคุณสมบัติต่าง ๆ เช่นการคัดลอกการดาวน์โหลดและการส่งไปยัง GitHub และ Obsidian
  73. // @description:tr Web içeriğini işaretleme biçimine dönüştüren bir araç, GitHub ve Obsidian’a kopyalama, indirme ve gönderme gibi özellikleri destekler.
  74. // @description:ug تور مەزمۇنىنى بەلگە قىلىپ بەلگە قىلالايدىغان بىر قورال گاتسىيە ۋە Obstidiation غا توپلاش ۋە ئەۋەتىش قاتارلىق ئىقتىدارلارنى قوللايدىغان ئىقتىدارلارنى قوللايدۇ.
  75. // @description:uk Інструмент, який перетворює веб -вміст у формат Markdown, підтримує такі функції, як копіювання, завантаження та надсилання в Github та Обсидіан.
  76. // @description:vi Một công cụ chuyển đổi nội dung web thành định dạng đánh dấu, hỗ trợ các tính năng như sao chép, tải xuống và gửi đến GitHub và Obsidian.
  77. // @description:zh 将网页内容转换为 Markdown 格式的工具,支持复制、下载、发送到 GitHub 和 Obsidian 等功能。
  78. // @description:zh-CN 将网页内容转换为 Markdown 格式的工具,支持复制、下载、发送到 GitHub 和 Obsidian 等功能。
  79. // @description:zh-HK 將網頁內容轉換為 Markdown 格式的工具,支持複製、下載、發送到 GitHub 和 Obsidian 等功能。
  80. // @description:zh-SG 将网页内容转换为 Markdown 格式的工具,支持复制、下载、发送到 GitHub 和 Obsidian 等功能。
  81. // @description:zh-TW 將網頁內容轉換為 Markdown 格式的工具,支持複製、下載、發送到 GitHub 和 Obsidian 等功能。
  82. // @author shiquda,人民的勤务员 <china.qinwuyuan@gmail.com>
  83. // @namespace https://github.com/ChinaGodMan/UserScripts
  84. // @supportURL https://github.com/ChinaGodMan/UserScripts/issues
  85. // @homepageURL https://github.com/ChinaGodMan/UserScripts
  86. // @license MIT
  87. // @grant GM_addStyle
  88. // @grant GM_registerMenuCommand
  89. // @grant GM_setClipboard
  90. // @grant GM_setValue
  91. // @grant GM_getValue
  92. // @require https://code.jquery.com/jquery-3.6.0.min.js
  93. // @require https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js
  94. // @require https://unpkg.com/turndown/dist/turndown.js
  95. // @require https://unpkg.com/@guyplusplus/turndown-plugin-gfm/dist/turndown-plugin-gfm.js
  96. // @require https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js
  97. // @match *://*/*
  98. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAABHNCSVQICAgIfAhkiAAABBdJREFUaIHtmluIVlUUx39pMup4Q1FrRi1CrMAaREUS75KlBhKKSGAKzkPRQ0lBPngjkIZeBMWHAccH8VIKJQTSIAgWVBQKglco7YYiitrYjONtjg/7G2bPPmt/nvOdtc8ndn5wQM/+77X+i73PnrPP/qCgoKCg4P/Bi8CGAHFfAj4JEDcTc4GodM1Ujt1aintcOW4mTtFT8GnFuAusuBGwSjF2xdQCdwlj7LwTt1kpbiYGAh30NtauEHe1EzMCtivEVeEEcXObM8bsFGIuyxhTjY3EzUXA4ArjNQmxHmSIp86zwH3iJvdWEGuoECcC9qs4VWQ3stGXU8b52hNnoppTJcYjG/05RYxJnhiHVZ0qcgjZ8OKE/X/x9J+t7lQJ3wj9lqDvUk/fNDOkKhxDNv5+mT5PAb97+r0d0qwG9nu1fV3DvKRIrPX0+SOwVzVOIxfQJGgHA20e/eocvKrwFnIBETDa0W716P7Ny6wWl5AL+cLS1Hs0EfBpnmY1eId4EfeBkZbmsKCJgHu5OlXkBr0Lsb+ITME/uo352tTjA3qKuATUWG1nkYv9M2ePqvSjZwV+17q/HP/ozsvZozpbgAvOvevIxR7N11oYRgLTrP+vxz+6r+TuLjBDkffNEdBSRV/B2IVcbCe9/1w9ETTgn8obq+grGEeQi70MPF1FX0FYiH90V5Y09Zht4hPBGeRi7VOKc8CM/K3pswb/6L7maB6r86NK6APcIl7oAWB6SdMPuGK1rcjfpg79MdNUGlmbz4X2N0OZ0lgkhmCOSF8FxgF1mDPdCR79JuCz0r/7Yz791Aq6m5gp/jdm43EO+J4qbi4WAD/ifz6lqwMY4MRpThnjH2Ad5lHIhT7Alx4zt/FvDHwvGGMw50aSvgv5UK278IYA9cU4KCQ/CyzBTOfhwPOY00Nb04aZ/hLuKF8HFgEvAGMxq/leIe8N4t/IVJkjJD3k0W5zdJvLxB2H+axj6/sKusVC/j3pSkjHN06yyx5dnaO7hdkplWMnyQr50NHdIdAo12CeGzvZex7tt44uyRfIsZhn1u5X79G6W8zXE1WQkjriC4hkaKqjuYZZ6JLgjnKrR/edo/soYfxUPEd8BKRpetzRrE2R4xmnb0TP66fNV47m4xQ5EjMC8zJgJ5ruaJY47TcryNPixDgmaH51NOUO6ipmIPHThIOOxv2ZUZrR7WY48VF+w2qvFdqDvYoeFZLNKrU1Ovc7MuRxPwWdsNpanbYuzIIXhFXEC76D2d795dzPspAME/I0In8T+yFDnkdS7uDavm4r5NqRII873YMwHv/7bfc1VynX1UfkCfHrXZFBwD7BQAfmtxpajAJOCnkuAPMrCZh1P1wDTMZsCv4DfsLsfLSZiNlItGOKvRggR0FBQcHjx0Ng/VhKUt8K3AAAAABJRU5ErkJggg==
  99. // @compatible chrome
  100. // @compatible firefox
  101. // @compatible edge
  102. // @compatible opera
  103. // @compatible safari
  104. // @compatible kiwi
  105. // @compatible qq
  106. // @compatible via
  107. // @compatible brave
  108. // @version 2025.03.18.0713
  109. // @created 2025-03-18 07:13:13
  110. // @modified 2025-03-18 07:13:13
  111. // ==/UserScript==
  112. /**
  113. * File: web-clipper.user.js
  114. * Project: UserScripts
  115. * File Created: 2025/03/18,Tuesday 07:13:13
  116. * Author: 人民的勤务员@ChinaGodMan (china.qinwuyuan@gmail.com)
  117. * -----
  118. * Last Modified: 2025/03/18,Tuesday 09:38:14
  119. * Modified By: 人民的勤务员@ChinaGodMan (china.qinwuyuan@gmail.com)
  120. * -----
  121. * License: MIT License
  122. * Copyright © 2024 - 2025 ChinaGodMan,Inc
  123. */
  124. //! https://gf.qytechs.cn/zh-CN/scripts/486888
  125. (function () {
  126. 'use strict'
  127. // GitHub 信息设置, GitHub settings
  128.  
  129. // 替换为你的GitHub令牌,Replace with your GitHub Token
  130. const github_token = ''
  131.  
  132. // 替换为你的GitHub仓库所有者,Replace with your GitHub repository owner
  133. const github_owner = '' // 比如 ChinaGodMan,Example: ChinaGodMan
  134.  
  135. // 替换为你的GitHub仓库名称,Replace with your GitHub repository name
  136. const github_repo = '' // 比如 UserScripts,Example: UserScripts
  137.  
  138. // User Config
  139. // Short cut
  140.  
  141. const shortCutUserConfig = {
  142. /* Example:
  143. "Shift": false,
  144. "Ctrl": true,
  145. "Alt": false,
  146. "Key": "m"
  147. */
  148. }
  149.  
  150. // Obsidian
  151. const obsidianUserConfig = {
  152. /* Example:
  153. "my note": [
  154. "Inbox/Web/",
  155. "Collection/Web/Reading/"
  156. ]
  157. */
  158. }
  159. const userLang =
  160. (navigator.languages && navigator.languages[0]) ||
  161. navigator.language ||
  162. 'en'
  163. const translations = {
  164. en: {
  165. copy: 'Copy to clipboard',
  166. copied: 'Copied successfully!',
  167. download_md: 'Download as MD',
  168. send_to_github: 'Send to Github',
  169. send_to_obsidian: 'Send to Obsidian',
  170. github_failed: 'Creation failed:',
  171. github_success: 'Creation succeeded:',
  172. configure: 'Please configure your GitHub information first',
  173. menu: 'Convert to Markdown',
  174. guide: `
  175. - Use **arrow keys** to select elements:
  176. - Up: Select parent element
  177. - Down: Select the first child element
  178. - Left: Select the previous sibling element
  179. - Right: Select the next sibling element
  180. - Use **scroll wheel** to zoom in and out:
  181. * Up: Select parent element
  182. - Down: Select the first child element
  183. - Click to select an element
  184. - Press \`Esc\` key to cancel selection
  185. `
  186. },
  187. 'zh-CN,zh,zh-SG': {
  188. copy: '复制到剪辑版',
  189. copied: '复制成功!',
  190. download_md: '下载为MD',
  191. send_to_github: '保存到GitHub',
  192. send_to_obsidian: '发送到Obsidian',
  193. github_failed: '创建失败:',
  194. github_success: '创建成功:',
  195. configure: '请先配置你的GitHub 信息',
  196. menu: '转换为Markdown',
  197. guide: `
  198. - 使用**方向键**选择元素
  199. - 上:选择父元素
  200. - 下:选择第一个子元素
  201. - 左:选择上一个兄弟元素
  202. - 右:选择下一个兄弟元素
  203. - 使用**滚轮**放大缩小
  204. - 上:选择父元素
  205. - 下:选择第一个子元素
  206. - 点击元素选择
  207. - 按下 \`Esc\` 键取消选择
  208. `
  209. },
  210. 'zh-TW,zh-HK,zh-MO': {
  211. copy: '複製到剪貼簿',
  212. copied: '複製成功!',
  213. download_md: '下載為MD',
  214. send_to_github: '保存到GitHub',
  215. send_to_obsidian: '發送到Obsidian',
  216. github_failed: '創建失敗:',
  217. github_success: '創建成功:',
  218. configure: '請先配置你的GitHub 信息',
  219. menu: '轉換為Markdown',
  220. guide: `
  221. - 使用**方向鍵**選擇元素
  222. - 上:選擇父元素
  223. - 下:選擇第一個子元素
  224. - 左:選擇上一個兄弟元素
  225. - 右:選擇下一個兄弟元素
  226. - 使用**滾輪**放大縮小
  227. - 上:選擇父元素
  228. - 下:選擇第一個子元素
  229. - 點擊元素選擇
  230. - 按下 \`Esc\` 鍵取消選擇
  231. `
  232. },
  233. vi: {
  234. copy: 'Sao chép vào clipboard',
  235. copied: 'Sao chép thành công!',
  236. download_md: 'Tải xuống dưới dạng MD',
  237. send_to_github: 'Gửi đến Github',
  238. send_to_obsidian: 'Gửi đến Obsidian',
  239. github_failed: 'Tạo thất bại:',
  240. github_success: 'Tạo thành công:',
  241. configure: 'Vui lòng cấu hình thông tin GitHub của bạn trước',
  242. menu: 'Chuyển đổi sang Markdown',
  243. guide: `
  244. - S dng **phím mũi tên** để chn các phn tử:
  245. - Lên: Chn phn t cha
  246. - Xung: Chn phn t con đầu tiên
  247. - Trái: Chn phn t anh em trước
  248. - Phi: Chn phn t anh em sau
  249. - S dng **bánh xe cun** để phóng to và thu nhỏ:
  250. - Lên: Chn phn t cha
  251. - Xung: Chn phn t con đầu tiên
  252. - Nhp để chn mt phn t
  253. - Nhn phím \`Esc\` để hy chn
  254. `
  255. },
  256. ja: {
  257. copy: 'クリップボードにコピー',
  258. copied: 'コピー成功!',
  259. download_md: 'MDとしてダウンロード',
  260. send_to_github: 'Githubに送信',
  261. send_to_obsidian: 'Obsidianに送信',
  262. github_failed: '作成失敗:',
  263. github_success: '作成成功:',
  264. configure: 'まずGitHub情報を設定してください',
  265. menu: 'Markdownに変換',
  266. guide: `
  267. - **矢印キー**を使用して要素を選択します:
  268. - 上: 親要素を選択
  269. - 下: 最初の子要素を選択
  270. - 左: 前の兄弟要素を選択
  271. - 右: 次の兄弟要素を選択
  272. - **スクロールホイール**を使用してズームインおよびズームアウトします:
  273. - 上: 親要素を選択
  274. - 下: 最初の子要素を選択
  275. - 要素をクリックして選択
  276. - \`Esc\`キーを押して選択をキャンセル
  277. `
  278. },
  279. ko: {
  280. copy: '클립보드에 복사',
  281. copied: '복사 성공!',
  282. download_md: 'MD로 다운로드',
  283. send_to_github: 'Github에 보내기',
  284. send_to_obsidian: 'Obsidian에 보내기',
  285. github_failed: '생성 실패:',
  286. github_success: '생성 성공:',
  287. configure: '먼저 GitHub 정보를 구성하십시오',
  288. menu: 'Markdown으로 변환',
  289. guide: `
  290. - **화살표 키**를 사용하여 요소를 선택합니다:
  291. - 위: 부모 요소 선택
  292. - 아래: 번째 자식 요소 선택
  293. - 왼쪽: 이전 형제 요소 선택
  294. - 오른쪽: 다음 형제 요소 선택
  295. - **스크롤 휠**을 사용하여 확대 축소합니다:
  296. - 위: 부모 요소 선택
  297. - 아래: 번째 자식 요소 선택
  298. - 요소를 선택하려면 클릭
  299. - 선택을 취소하려면 \`Esc\` 키를 누르십시오
  300. `
  301. },
  302. fr: {
  303. copy: 'Copier dans le presse-papiers',
  304. copied: 'Copié avec succès!',
  305. download_md: 'Télécharger en tant que MD',
  306. send_to_github: 'Envoyer à Github',
  307. send_to_obsidian: 'Envoyer à Obsidian',
  308. github_failed: 'Échec de la création:',
  309. github_success: 'Création réussie:',
  310. configure: 'Veuillez d\'abord configurer vos informations GitHub',
  311. menu: 'Convertir en Markdown',
  312. guide: `
  313. - Utilisez les **touches fléchées** pour sélectionner les éléments:
  314. - Haut: Sélectionner llément parent
  315. - Bas: Sélectionner le premier élément enfant
  316. - Gauche: Sélectionner llément frère précédent
  317. - Droite: Sélectionner llément frère suivant
  318. - Utilisez la **molette de défilement** pour zoomer et dézoomer:
  319. - Haut: Sélectionner llément parent
  320. - Bas: Sélectionner le premier élément enfant
  321. - Cliquez pour sélectionner un élément
  322. - Appuyez sur la touche \`Esc\` pour annuler la sélection
  323. `
  324. },
  325. it: {
  326. copy: 'Copia negli appunti',
  327. copied: 'Copiato con successo!',
  328. download_md: 'Scarica come MD',
  329. send_to_github: 'Invia a Github',
  330. send_to_obsidian: 'Invia a Obsidian',
  331. github_failed: 'Creazione fallita:',
  332. github_success: 'Creazione riuscita:',
  333. configure: 'Si prega di configurare prima le informazioni di GitHub',
  334. menu: 'Converti in Markdown',
  335. guide: `
  336. - Usa i **tasti freccia** per selezionare gli elementi:
  337. - Su: Seleziona l'elemento padre
  338. - Giù: Seleziona il primo elemento figlio
  339. - Sinistra: Seleziona l'elemento fratello precedente
  340. - Destra: Seleziona l'elemento fratello successivo
  341. - Usa la **rotella di scorrimento** per ingrandire e ridurre:
  342. - Su: Seleziona l'elemento padre
  343. - Giù: Seleziona il primo elemento figlio
  344. - Clicca per selezionare un elemento
  345. - Premi il tasto \`Esc\` per annullare la selezione
  346. `
  347. },
  348. de: {
  349. copy: 'In die Zwischenablage kopieren',
  350. copied: 'Erfolgreich kopiert!',
  351. download_md: 'Als MD herunterladen',
  352. send_to_github: 'An Github senden',
  353. send_to_obsidian: 'An Obsidian senden',
  354. github_failed: 'Erstellung fehlgeschlagen:',
  355. github_success: 'Erstellung erfolgreich:',
  356. configure: 'Bitte konfigurieren Sie zuerst Ihre GitHub-Informationen',
  357. menu: 'In Markdown konvertieren',
  358. guide: `
  359. - Verwenden Sie die **Pfeiltasten**, um Elemente auszuwählen:
  360. - Oben: Elternelement auswählen
  361. - Unten: Erstes Kindelement auswählen
  362. - Links: Vorheriges Geschwisterelement auswählen
  363. - Rechts: Nächstes Geschwisterelement auswählen
  364. - Verwenden Sie das **Scrollrad**, um hinein- und herauszuzoomen:
  365. - Oben: Elternelement auswählen
  366. - Unten: Erstes Kindelement auswählen
  367. - Klicken Sie, um ein Element auszuwählen
  368. - Drücken Sie die \`Esc\`-Taste, um die Auswahl abzubrechen
  369. `
  370. }
  371. }
  372. const getTranslations = (lang) => {
  373. for (const key in translations) {
  374. if (key === lang || key.split(',').includes(lang)) {
  375. return translations[key]
  376. }
  377. }
  378. return translations['en']
  379. }
  380. const translate = new Proxy(
  381. function (key) {
  382. const lang = userLang
  383. const strings = getTranslations(lang)
  384. return strings[key] || translations['en'][key]
  385. },
  386. {
  387. get(target, prop) {
  388. const lang = userLang
  389. const strings = getTranslations(lang)
  390. return strings[prop] || translations['en'][prop]
  391. }
  392. }
  393. )
  394.  
  395. // 全局变量
  396. var isSelecting = false
  397. var selectedElement = null
  398. let shortCutConfig, obsidianConfig
  399. // 读取配置
  400. // 初始化快捷键配置
  401. let storedShortCutConfig = GM_getValue('shortCutConfig')
  402. if (Object.keys(shortCutUserConfig).length !== 0) {
  403. GM_setValue('shortCutConfig', JSON.stringify(shortCutUserConfig))
  404. shortCutConfig = shortCutUserConfig
  405. } else if (storedShortCutConfig) {
  406. shortCutConfig = JSON.parse(storedShortCutConfig)
  407. }
  408.  
  409. // 初始化Obsidian配置
  410. let storedObsidianConfig = GM_getValue('obsidianConfig')
  411. if (Object.keys(obsidianUserConfig).length !== 0) {
  412. GM_setValue('obsidianConfig', JSON.stringify(obsidianUserConfig))
  413. obsidianConfig = obsidianUserConfig
  414. } else if (storedObsidianConfig) {
  415. obsidianConfig = JSON.parse(storedObsidianConfig)
  416. }
  417.  
  418. // HTML2Markdown
  419. function convertToMarkdown(element) {
  420. var html = element.outerHTML
  421. let turndownMd = turndownService.turndown(html)
  422. turndownMd = turndownMd.replaceAll('[\n\n]', '[]') // 防止 <a> 元素嵌套的暂时方法,并不完善
  423. return turndownMd
  424. }
  425.  
  426. // 预览
  427. function showMarkdownModal(markdown) {
  428. var $modal = $(`
  429. <div class="h2m-modal-overlay">
  430. <div class="h2m-modal">
  431. <textarea>${markdown}</textarea>
  432. <div class="h2m-preview">${marked.parse(markdown)}</div>
  433. <div class="h2m-buttons">
  434. <button class="h2m-copy">${translate.copy}</button>
  435. <button class="h2m-download">${translate.download_md}</button>
  436. <button class="h2m-github">${translate.send_to_github}</button>
  437. <select class="h2m-obsidian-select">${translate.send_to_obsidian}</select>
  438. </div>
  439. <button class="h2m-close">X</button>
  440. </div>
  441. </div>
  442. `)
  443.  
  444. $modal.find('.h2m-obsidian-select').append($('<option>').val('').text(`${translate.send_to_obsidian}`))
  445. for (const vault in obsidianConfig) {
  446. for (const path of obsidianConfig[vault]) {
  447. // 插入元素
  448. const $option = $('<option>')
  449. .val(`obsidian://advanced-uri?vault=${vault}&filepath=${path}`)
  450. .text(`${vault}: ${path}`)
  451. $modal.find('.h2m-obsidian-select').append($option)
  452. }
  453. }
  454.  
  455. $modal.find('textarea').on('input', function () {
  456. // console.log("Input event triggered");
  457. var markdown = $(this).val()
  458. var html = marked.parse(markdown)
  459. // console.log("Markdown:", markdown);
  460. // console.log("HTML:", html);
  461. $modal.find('.h2m-preview').html(html)
  462. })
  463.  
  464. $modal.on('keydown', function (e) {
  465. if (e.key === 'Escape') {
  466. $modal.remove()
  467. }
  468. })
  469.  
  470. $modal.find('.h2m-copy').on('click', function () { // 复制到剪贴板
  471. GM_setClipboard($modal.find('textarea').val())
  472. $modal.find('.h2m-copy').text(`${translate.copied}`)
  473. setTimeout(() => {
  474. $modal.find('.h2m-copy').text(`${translate.copy}`)
  475. }, 1000)
  476. })
  477. $modal.find('.h2m-github').on('click', function () {
  478. if (!github_token || !github_owner || !github_repo) {
  479. alert(`${translate.configure}`)
  480. return
  481. }
  482. const labels = ['web-clipper']//标签,可多项
  483. const markdown = $modal.find('textarea').val()
  484. const title = markdown.split('\n')[0]
  485. const body = markdown
  486. createIssue(github_token, github_owner, github_repo, title, body, labels)
  487. })
  488. $modal.find('.h2m-download').on('click', function () { // 下载
  489. var markdown = $modal.find('textarea').val()
  490. var blob = new Blob([markdown], { type: 'text/markdown' })
  491. var url = URL.createObjectURL(blob)
  492. var a = document.createElement('a')
  493. a.href = url
  494. // 当前页面标题 + 时间
  495. a.download = `${document.title}-${new Date().toISOString().replace(/:/g, '-')}.md`
  496. a.click()
  497. })
  498.  
  499. $modal.find('.h2m-obsidian-select').on('change', function () { // 发送到 Obsidian
  500. const val = $(this).val()
  501. if (!val) return
  502. const markdown = $modal.find('textarea').val()
  503. GM_setClipboard(markdown)
  504. const title = document.title.replaceAll(/[\\/:*?"<>|]/g, '_') // File name cannot contain any of the following characters: * " \ / < > : | ?
  505. const url = `${val}${title}.md&clipboard=true`
  506. window.open(url)
  507. })
  508.  
  509. $modal.find('.h2m-close').on('click', function () { // 关闭按钮 X
  510. $modal.remove()
  511. })
  512.  
  513. // 同步滚动
  514. // 获取两个元素
  515. var $textarea = $modal.find('textarea')
  516. var $preview = $modal.find('.h2m-preview')
  517. var isScrolling = false
  518.  
  519. // 当 textarea 滚动时,设置 preview 的滚动位置
  520. $textarea.on('scroll', function () {
  521. if (isScrolling) {
  522. isScrolling = false
  523. return
  524. }
  525. var scrollPercentage = this.scrollTop / (this.scrollHeight - this.offsetHeight)
  526. $preview[0].scrollTop = scrollPercentage * ($preview[0].scrollHeight - $preview[0].offsetHeight)
  527. isScrolling = true
  528. })
  529.  
  530. // 当 preview 滚动时,设置 textarea 的滚动位置
  531. $preview.on('scroll', function () {
  532. if (isScrolling) {
  533. isScrolling = false
  534. return
  535. }
  536. var scrollPercentage = this.scrollTop / (this.scrollHeight - this.offsetHeight)
  537. $textarea[0].scrollTop = scrollPercentage * ($textarea[0].scrollHeight - $textarea[0].offsetHeight)
  538. isScrolling = true
  539. })
  540.  
  541. $(document).on('keydown', function (e) {
  542. if (e.key === 'Escape' && $('.h2m-modal-overlay').length > 0) {
  543. $('.h2m-modal-overlay').remove()
  544. }
  545. })
  546.  
  547. $('body').append($modal)
  548. }
  549.  
  550. // 开始选择
  551. function startSelecting() {
  552. $('body').addClass('h2m-no-scroll') // 防止页面滚动
  553. isSelecting = true
  554. // 操作指南
  555. tip(marked.parse(translate.guide))
  556. }
  557.  
  558. // 结束选择
  559. function endSelecting() {
  560. isSelecting = false
  561. $('.h2m-selection-box').removeClass('h2m-selection-box')
  562. $('body').removeClass('h2m-no-scroll')
  563. $('.h2m-tip').remove()
  564. }
  565.  
  566. function tip(message, timeout = null) {
  567. var $tipElement = $('<div>')
  568. .addClass('h2m-tip')
  569. .html(message)
  570. .appendTo('body')
  571. .hide()
  572. .fadeIn(200)
  573. if (timeout === null) {
  574. return
  575. }
  576. setTimeout(function () {
  577. $tipElement.fadeOut(200, function () {
  578. $tipElement.remove()
  579. })
  580. }, timeout)
  581. }
  582.  
  583. // Turndown 配置
  584. var turndownPluginGfm = TurndownPluginGfmService
  585. var turndownService = new TurndownService({ codeBlockStyle: 'fenced' })
  586.  
  587. turndownPluginGfm.gfm(turndownService) // 引入全部插件
  588. // turndownService.addRule('strikethrough', {
  589. // filter: ['del', 's', 'strike'],
  590. // replacement: function (content) {
  591. // return '~' + content + '~'
  592. // }
  593. // });
  594.  
  595. // turndownService.addRule('latex', {
  596. // filter: ['mjx-container'],
  597. // replacement: function (content, node) {
  598. // const text = node.querySelector('img')?.title;
  599. // const isInline = !node.getAttribute('display');
  600. // if (text) {
  601. // if (isInline) {
  602. // return '$' + text + '$'
  603. // }
  604. // else {
  605. // return '$$' + text + '$$'
  606. // }
  607. // }
  608. // return '';
  609. // }
  610. // });
  611.  
  612. // 添加CSS样式
  613. GM_addStyle(`
  614. .h2m-selection-box {
  615. border: 2px dashed #f00;
  616. background-color: rgba(255, 0, 0, 0.2);
  617. }
  618. .h2m-no-scroll {
  619. overflow: hidden;
  620. z-index: 9997;
  621. }
  622. .h2m-modal {
  623. position: fixed;
  624. top: 50%;
  625. left: 50%;
  626. transform: translate(-50%, -50%);
  627. width: 80%;
  628. height: 80%;
  629. background: white;
  630. border-radius: 10px;
  631. display: flex;
  632. flex-direction: row;
  633. z-index: 9999;
  634. }
  635. .h2m-modal-overlay {
  636. position: fixed;
  637. top: 0;
  638. left: 0;
  639. width: 100%;
  640. height: 100%;
  641. background: rgba(0, 0, 0, 0.5);
  642. z-index: 9998;
  643. }
  644. .h2m-modal textarea,
  645. .h2m-modal .h2m-preview {
  646. width: 50%;
  647. height: 100%;
  648. padding: 20px;
  649. box-sizing: border-box;
  650. overflow-y: auto;
  651. }
  652. .h2m-modal .h2m-buttons {
  653. position: absolute;
  654. bottom: 10px;
  655. right: 10px;
  656. }
  657. .h2m-modal .h2m-buttons button,
  658. .h2m-modal .h2m-obsidian-select {
  659. margin-left: 10px;
  660. background-color: #4CAF50; /* Green */
  661. border: none;
  662. color: white;
  663. padding: 13px 16px;
  664. border-radius: 10px;
  665. text-align: center;
  666. text-decoration: none;
  667. display: inline-block;
  668. font-size: 16px;
  669. transition-duration: 0.4s;
  670. cursor: pointer;
  671. }
  672. .h2m-modal .h2m-buttons button:hover,
  673. .h2m-modal .h2m-obsidian-select:hover {
  674. background-color: #45a049;
  675. }
  676. .h2m-modal .h2m-close {
  677. position: absolute;
  678. top: 10px;
  679. right: 10px;
  680. cursor: pointer;
  681. width: 25px;
  682. height: 25px;
  683. background-color: #f44336;
  684. color: white;
  685. font-size: 16px;
  686. border-radius: 50%;
  687. display: flex;
  688. justify-content: center;
  689. align-items: center;
  690. }
  691. .h2m-tip {
  692. position: fixed;
  693. top: 22%;
  694. left: 82%;
  695. transform: translate(-50%, -50%);
  696. background-color: white;
  697. border: 1px solid black;
  698. padding: 8px;
  699. z-index: 9999;
  700. border-radius: 10px;
  701. box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5);
  702. background-color: rgba(255, 255, 255, 0.7);
  703. }
  704. `)
  705.  
  706. // 注册(不可用)触发器
  707. shortCutConfig = shortCutConfig ? shortCutConfig : {
  708. 'Shift': false,
  709. 'Ctrl': true,
  710. 'Alt': false,
  711. 'Key': 'm'
  712. }
  713. $(document).on('keydown', function (e) {
  714. if (e.ctrlKey === shortCutConfig['Ctrl'] &&
  715. e.altKey === shortCutConfig['Alt'] &&
  716. e.shiftKey === shortCutConfig['Shift'] &&
  717. e.key.toUpperCase() === shortCutConfig['Key'].toUpperCase()) {
  718. e.preventDefault()
  719. startSelecting()
  720. }
  721. // else {
  722. // console.log(e.ctrlKey, e.altKey, e.shiftKey, e.key.toUpperCase());
  723. // }
  724. })
  725. // $(document).on('keydown', function (e) {
  726. // if (e.ctrlKey && e.key === 'm') {
  727. // e.preventDefault();
  728. // startSelecting()
  729. // }
  730. // });
  731.  
  732. GM_registerMenuCommand(`${translate.menu}`, function () {
  733. startSelecting()
  734. })
  735.  
  736. $(document).on('mouseover', function (e) { // 开始选择
  737. if (isSelecting) {
  738. $(selectedElement).removeClass('h2m-selection-box')
  739. selectedElement = e.target
  740. $(selectedElement).addClass('h2m-selection-box')
  741. }
  742. }).on('wheel', function (e) { // 滚轮事件
  743. if (isSelecting) {
  744. e.preventDefault()
  745. if (e.originalEvent.deltaY < 0) {
  746. selectedElement = selectedElement.parentElement ? selectedElement.parentElement : selectedElement // 扩大
  747. if (selectedElement.tagName === 'HTML' || selectedElement.tagName === 'BODY') {
  748. selectedElement = selectedElement.firstElementChild
  749. }
  750. } else {
  751. selectedElement = selectedElement.firstElementChild ? selectedElement.firstElementChild : selectedElement // 缩小
  752. }
  753. $('.h2m-selection-box').removeClass('h2m-selection-box')
  754. $(selectedElement).addClass('h2m-selection-box')
  755. }
  756. }).on('keydown', function (e) { // 键盘事件
  757. if (isSelecting) {
  758. e.preventDefault()
  759. if (e.key === 'Escape') {
  760. endSelecting()
  761. return
  762. }
  763. switch (e.key) { // 方向键:上下左右
  764. case 'ArrowUp':
  765. selectedElement = selectedElement.parentElement ? selectedElement.parentElement : selectedElement // 扩大
  766. if (selectedElement.tagName === 'HTML' || selectedElement.tagName === 'BODY') { // 排除HTML 和 BODY
  767. selectedElement = selectedElement.firstElementChild
  768. }
  769. break
  770. case 'ArrowDown':
  771. selectedElement = selectedElement.firstElementChild ? selectedElement.firstElementChild : selectedElement // 缩小
  772. break
  773. case 'ArrowLeft': // 寻找上一个元素,若是最后一个子元素则选择父元素的下一个兄弟元素,直到找到一个元素
  774. var prev = selectedElement.previousElementSibling
  775. while (prev === null && selectedElement.parentElement !== null) {
  776. selectedElement = selectedElement.parentElement
  777. prev = selectedElement.previousElementSibling ? selectedElement.previousElementSibling.lastChild : null
  778. }
  779. if (prev !== null) {
  780. if (selectedElement.tagName === 'HTML' || selectedElement.tagName === 'BODY') {
  781. selectedElement = selectedElement.firstElementChild
  782. }
  783. selectedElement = prev
  784. }
  785. break
  786. case 'ArrowRight':
  787. var next = selectedElement.nextElementSibling
  788. while (next === null && selectedElement.parentElement !== null) {
  789. selectedElement = selectedElement.parentElement
  790. next = selectedElement.nextElementSibling ? selectedElement.nextElementSibling.firstElementChild : null
  791. }
  792. if (next !== null) {
  793. if (selectedElement.tagName === 'HTML' || selectedElement.tagName === 'BODY') {
  794. selectedElement = selectedElement.firstElementChild
  795. }
  796. selectedElement = next
  797. }
  798. break
  799. }
  800.  
  801. $('.h2m-selection-box').removeClass('h2m-selection-box')
  802. $(selectedElement).addClass('h2m-selection-box') // 更新选中元素的样式
  803. }
  804. }
  805. ).on('mousedown', function (e) { // 鼠标事件,选择 mousedown 是因为防止点击元素后触发其他事件
  806. if (isSelecting) {
  807. e.preventDefault()
  808. var markdown = convertToMarkdown(selectedElement)
  809. showMarkdownModal(markdown)
  810. endSelecting()
  811. }
  812. })
  813. function createIssue(token, owner, repo, title, body, labels = []) {
  814. const url = `https://api.github.com/repos/${owner}/${repo}/issues`
  815. const issueData = {
  816. title: title,
  817. body: body,
  818. labels: labels
  819. }
  820. const xhr = new XMLHttpRequest()
  821. xhr.open('POST', url, true)
  822. xhr.setRequestHeader('Authorization', `token ${token}`)
  823. xhr.setRequestHeader('Accept', 'application/vnd.github+json')
  824. xhr.setRequestHeader('Content-Type', 'application/json')
  825. xhr.onreadystatechange = function () {
  826. if (xhr.readyState === 4) {
  827. if (xhr.status >= 200 && xhr.status < 300) {
  828. const response = JSON.parse(xhr.responseText)
  829. alert(`${translate.github_success}\n ${response.html_url}`)
  830.  
  831. } else {
  832. alert(`${translate.github_failed}\n ${xhr.status}\n ${xhr.statusText}\n ${xhr.responseText}`)
  833. console.error(`${translate.github_failed}`, xhr.status, xhr.statusText, xhr.responseText)
  834. }
  835. }
  836. }
  837. xhr.send(JSON.stringify(issueData))
  838. }
  839. })()

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址