Last active
September 28, 2025 09:17
-
-
Save Spike-Leung/19986df42333b6419b2eadaa73526d7b to your computer and use it in GitHub Desktop.
org-protocol.user.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name org-protocol | |
| // @namespace https://gist.github.com/Spike-Leung/19986df42333b6419b2eadaa73526d7b | |
| // @version 0.0 | |
| // @description Use Alt + l for Org: capture and use Alt + h for Org: capture-html | |
| // @author Spike-Leung | |
| // @match *://*/* | |
| // @grant none | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| function generateMusic163Table() { | |
| const songRows = document.querySelectorAll('.m-record .j-flag ul li'); | |
| if (songRows.length === 0) return null; | |
| const baseURL = 'https://music.163.com'; | |
| let table = [ | |
| '| 歌曲 | 歌手 | 播放次数 |', | |
| '|------+----------+------|' | |
| ]; | |
| songRows.forEach(row => { | |
| const songLink = row.querySelector('.ttc .txt a'); | |
| const artistLink = row.querySelector('.ar a'); | |
| const playCountSpan = row.querySelector('.tops .times'); | |
| if (songLink && artistLink && playCountSpan) { | |
| const songTitle = songLink.querySelector('b').title; | |
| const songUrl = baseURL + songLink.getAttribute('href'); | |
| const artistName = artistLink.textContent; | |
| const artistUrl = baseURL + artistLink.getAttribute('href'); | |
| const playCount = playCountSpan.textContent.trim(); | |
| table.push(`| [[${songUrl}][${songTitle}]] | [[${artistUrl}][${artistName}]] | ${playCount} |`); | |
| } | |
| }); | |
| return table.join('\n'); | |
| } | |
| document.addEventListener('keydown', function(e) { | |
| // Alt + s: store-link | |
| // @see: https://orgmode.org/org.html#Protocols | |
| if (e.code === 'KeyS' && e.altKey && !e.shiftKey && !e.ctrlKey && !e.metaKey) { | |
| location.href = `org-protocol://store-link?${new URLSearchParams({url:location.href, title:document.title})}` | |
| } | |
| // Alt + m: 获取网易云听歌排行 | |
| if (e.code === 'KeyM' && e.altKey && !e.shiftKey && !e.ctrlKey && !e.metaKey) { | |
| if (location.hostname === 'music.163.com') { | |
| const table = generateMusic163Table(); | |
| if (table) { | |
| const params = new URLSearchParams({ | |
| template: 'm', // Use 'm' template | |
| url: window.location.href, | |
| title: document.title, | |
| body: table | |
| }); | |
| location.href = `org-protocol://capture?${params.toString()}`; | |
| } else { | |
| alert('未找到听歌排行数据,请确保在正确的页面使用此功能。'); | |
| } | |
| } | |
| } | |
| // Alt + l: capture | |
| if (e.code === 'KeyL' && e.altKey && !e.shiftKey && !e.ctrlKey && !e.metaKey) { | |
| location.href = `org-protocol://capture?${new URLSearchParams({ | |
| // you may need to change the template | |
| template: 'x', | |
| url: window.location.href, | |
| title: document.title, | |
| body: window.getSelection() | |
| })} | |
| `; | |
| } | |
| // Alt + h: capture html | |
| // @see: https://github.com/alphapapa/org-protocol-capture-html | |
| if (e.code === 'KeyH' && e.altKey && !e.shiftKey && !e.ctrlKey && !e.metaKey) { | |
| const params = new URLSearchParams(); | |
| params.set('template', 'w'); | |
| params.set('url', location.href); | |
| params.set('title', document.title || "[untitled page]"); | |
| params.set('body', (() => { | |
| let html = ""; | |
| if (typeof window.getSelection !== "undefined") { | |
| const sel = window.getSelection(); | |
| if (sel.rangeCount) { | |
| const container = document.createElement("div"); | |
| for (let i = 0, len = sel.rangeCount; i < len; ++i) { | |
| container.appendChild(sel.getRangeAt(i).cloneContents()); | |
| } | |
| html = container.innerHTML; | |
| } | |
| } else if (typeof document.selection !== "undefined") { | |
| if (document.selection.type === "Text") { | |
| html = document.selection.createRange().htmlText; | |
| } | |
| } | |
| const relToAbs = (href) => { | |
| const a = document.createElement("a"); | |
| a.href = href; | |
| const abs = `${a.protocol}//${a.host}${a.pathname}${a.search}${a.hash}`; | |
| a.remove(); | |
| return abs; | |
| }; | |
| const elementTypes = [['a', 'href'], ['img', 'src']]; | |
| const div = document.createElement('div'); | |
| div.innerHTML = html; | |
| elementTypes.forEach(([tag, attr]) => { | |
| const elements = div.getElementsByTagName(tag); | |
| for (let i = 0; i < elements.length; i++) { | |
| elements[i].setAttribute(attr, relToAbs(elements[i].getAttribute(attr))); | |
| } | |
| }); | |
| return div.innerHTML; | |
| })()); | |
| location.href = `org-protocol://capture-html?${params.toString()}`; | |
| } | |
| }, false); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment