├── .config.json ├── .gitignore ├── .user ├── README.md ├── background.js ├── contentScript.js ├── example.md ├── handlers ├── batch_getyarn.js ├── batch_open_gzh.js ├── getyarn.js ├── gongzhonghao.js ├── instagram.js ├── itra.js ├── race_subscribe.js └── savefrom.js ├── img ├── itra-point.png ├── link-128.png ├── link-16.png ├── link-32.png ├── link-64.png ├── live-utmb.png ├── regis-utmb.png ├── wechat-link-1.png └── wechat-link-2.png ├── manifest.json ├── multimp.js ├── popup.html ├── popup.js └── util.js /.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "handlers": [{ 3 | "execCode": "copyAndRedirect('https://tiqu.cc/')", 4 | "urls": ["xiaohongshu.com/explore/", "xhslink.com", "tiktok.com", "douyin.com"] 5 | }, { 6 | "execCode": "copyAndRedirect('https://www.savethevideo.com/vimeo-downloader?url=' + window.location.href)", 7 | "urls": ["vimeo.com/"] 8 | }, { 9 | "execCode": "copyAndRedirect('https://snapany.com/zh/bilibili')", 10 | "urls": ["bilibili.com/video/"] 11 | }, { 12 | "execCode": "copyAndRedirect('https://savefrom.net/' + window.location.href)", 13 | "urls": ["facebook.com", "youtube.com", "fb.watch", "instagram.com"] 14 | }] 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.un~ 2 | .ropeproject/ 3 | -------------------------------------------------------------------------------- /.user: -------------------------------------------------------------------------------- 1 | zhupengbupt@gmail.com 2 | 840547631@qq.com 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 你们是不是在使用浏览器的时候,会在某些页面有些例行的操作,而这些操作如果能够一键执行,能够极大的提升你的效率。我们通过 Chrome 插件提供的能力,开发了*链接小助手*,以下就是目前 *链接小助手* 支持的功能: 2 | 3 | 1. 一键下载视频 4 | 5 | 目前支持 B站、小红书、Instagram、YouTube、Facebook 等。使用方式非常的简单,在浏览器访问你要下载的视频网页,点击 Chrome 右上角的插件图标即可,如果支持下载,则会自动跳转到下载页。 6 | 7 | 2. 公众号小程序链接自动转换功能 8 | 9 | 微信公众号后台编辑文章的过程中可以添加小程序,我数了一下至少需要经过 6 步才能添加完成,有时候都不知道小程序的访问路径而不知道怎么操作。 10 | 11 | 链接小助手帮助大家更方便的在公众号文章中添加小程序,借助 Chrome 插件提供一键轻松添加和排版小程序链接。你只需要在文章中填写浏览器上的链接,点击插件图标,小助手将自动转化为小程序可以识别的链接,效果如下: 12 | 13 | ![](img/wechat-link-1.png) 14 | 15 | ![](img/wechat-link-2.png) 16 | 17 | 3. 展示 itra & UTMB 越野跑赛事网站的额外信息 18 | 19 | 支持展示 utmb 报名、直播页面中赛事组别的分段爬升、距离等信息。 20 | 21 | ![](img/regis-utmb.png) 22 | 23 | ![](img/live-utmb.png) 24 | 25 | 支持展示查看 itra 中个人的单场比赛的分数。 26 | 27 | ![](img/itra-point.png) 28 | 29 | 更多其他使用场景欢迎提供建议或直接 Pull Requests。扫码关注如下微信公众号,获取工具定期更新推送。 30 | 31 | ![wechat](https://raw.githubusercontent.com/ZhuPeng/pic/master/mac/compress_github_qrcode.png) 32 | 33 | 34 | 35 | ## 安装和使用方式 36 | 37 | Chrome 应用商店安装:[链接](https://chrome.google.com/webstore/detail/%E5%B0%8F%E7%A8%8B%E5%BA%8F%E6%8E%92%E7%89%88%E5%B0%8F%E5%8A%A9%E6%89%8B/aigggkimjmfijjfbhonlblgajnoilbbb),也可以通过 [Release](https://github.com/ZhuPeng/mp-transform-public/releases) 下载进行本地安装。 38 | 39 | 安装完成后,浏览器右上角将出现如下 Logo。 40 | 41 | ![](img/link-128.png) 42 | 43 | 安装完成之后,使用时点击插件图标或者页面会自动展示相关信息。 44 | 45 | 46 | ## 已支持的小程序列表 47 | 48 | * [GitHub Trending Hub]() 49 | * [Readhub](https://readhub.cn/topics) 50 | * [哔哩哔哩](https://www.bilibili.com/) 51 | * [腾讯视频](https://v.qq.com/) 52 | * [CSDN](https://blog.csdn.net/) 53 | * [简书](https://www.jianshu.com/) 54 | * [知乎热榜](https://www.zhihu.com)、[知乎专栏](https://zhuanlan.zhihu.com) 55 | * [什么值得买](https://www.smzdm.com) 56 | * [百度网盘](https://pan.baidu.com): 分享链接为 https://pan.baidu.com/s/<随机字符串>,需要在末尾添加 #提取码#0#0,例如:https://pan.baidu.com/s/1EuJiHB-q2Lggrt28cjQISA#3tb7#0#0 57 | * [36氪Lite](https://36kr.com) 58 | * [掘金第三方版](https://juejin.im) 59 | * [V2EX For You](https://www.v2ex.com) 60 | * [豆瓣电影](https://movie.douban.com/)、[豆瓣读书](https://book.douban.com/)、[豆瓣音乐](https://music.douban.com/) 61 | * [腾讯新闻](https://new.qq.com/) 62 | * [文章助手](https://linux.cn/article-10838-1.html):未匹配的链接默认转换为文章助手小程序链接 63 | 64 | 其他小程序的支持正在开发中,如果你的小程序希望接入,欢迎扫描如下二维码联系作者。 65 | 66 | ![wechat](https://raw.githubusercontent.com/ZhuPeng/pic/master/mac/compress_github_qrcode.png) 67 | 68 | 69 | 70 | ## 小程序跳转 71 | 72 | 如果你是小程序开发人员,希望自己的小程序也能跳转如上小程序,可以复制仓库中的 [multimp.js](multimp.js) 到你的小程序源码中,具体使用方式可以参考:[链接代码](https://github.com/ZhuPeng/mp-githubtrending/blob/master/pages/component/md/md.js#L94),同时你需要在小程序的 `app.json` 中添加允许跳转的小程序列表参数 `navigateToMiniProgramAppIdList`,[参考链接代码](https://github.com/ZhuPeng/mp-githubtrending/blob/master/app.json#L60)。 73 | 74 | 75 | 76 | 77 | ## FAQ 78 | 79 | 有任何问题欢迎提交 Issue 和 PR,详情:[https://github.com/ZhuPeng/mp-transform-public](https://github.com/ZhuPeng/mp-transform-public) 80 | -------------------------------------------------------------------------------- /background.js: -------------------------------------------------------------------------------- 1 | chrome.extension.onMessage.addListener(function(request, sender, sendResponse) { 2 | console.log("Request comes from content script " + sender.tab.id); 3 | if (request.greeting === "close_tab"){ 4 | chrome.tabs.remove(sender.tab.id); 5 | } 6 | }); 7 | 8 | function getRemoteConfig() { 9 | return getWithCache(newDayKey('config'), 'https://raw.githubusercontent.com/ZhuPeng/mp-transform-public/master/.config.json'); 10 | } 11 | 12 | function checkIsPaid(email) { 13 | fetch('https://raw.githubusercontent.com/ZhuPeng/mp-transform-public/master/.user') 14 | .then(response => response.text()) 15 | .then(data => { 16 | console.log(data) 17 | if (data.indexOf(email) > -1) { 18 | console.log('user is paied') 19 | localStorage.setItem('isPaid', true); 20 | alert("恭喜你成为尊贵的付费用户,付费用户享有多种权益,详情咨询管理员。\n") 21 | return false 22 | } 23 | }) 24 | .catch(error => { 25 | console.log(error); 26 | }); 27 | } 28 | 29 | chrome.identity.getProfileUserInfo(function(userInfo) { 30 | console.log(userInfo); 31 | email = userInfo.email; 32 | 33 | var isPaid = localStorage.getItem('isPaid') || false; 34 | if (isPaid) {return} 35 | checkIsPaid(email) 36 | }); 37 | 38 | function limitUsage() { 39 | var key = 'usageCount' 40 | var usageCount = localStorage.getItem(key) || 0; 41 | usageCount++; 42 | localStorage.setItem(key, usageCount); 43 | 44 | if (usageCount <= 10) { 45 | return false; 46 | } 47 | 48 | var isPaid = localStorage.getItem('isPaid') || false; 49 | if (isPaid) {return false} 50 | 51 | checkIsPaid(email); 52 | alert("超过使用限制,请联系管理员开通付费服务\n用户名:" + email + "\n管理员(微信):15652961268\n") 53 | return true 54 | } 55 | 56 | var Handlers = [{ 57 | execScript: 'contentScript.js', 58 | urls: ['mp.weixin.qq.com/cgi-bin/appmsg?t=media/appmsg_edit'], 59 | }, { 60 | execScript: 'handlers/instagram.js', 61 | urls: ['instagram.com/tv/'], 62 | }, { 63 | execScript: 'handlers/savefrom.js', 64 | urls: ['en.savefrom.net'], 65 | }, { 66 | execScript: 'handlers/getyarn.js', 67 | urls: ['getyarn.io/yarn-clip'], 68 | }, { 69 | execScript: 'handlers/batch_getyarn.js', 70 | urls: ['getyarn.io/yarn-find?text='], 71 | }, { 72 | execScript: 'handlers/batch_open_gzh.js', 73 | urls: ['mp.weixin.qq.com/cgi-bin/appmsgpublish?sub=list'], 74 | },{ 75 | execCode: 'submit_cmd("cd ../liverace && python3 data.py subscribe_from_url \\"" + window.location.href + "\\"")', 76 | urls: ['https://live.utmb.world/', 'https://www.geexek.com/score/pscore?', 'https://sport.luojiweiye.com/web/h5/new_grade_cret.html', '/coureur.php?rech='], 77 | }, { 78 | execScript: 'handlers/gongzhonghao.js', 79 | urls: ['https://mp.weixin.qq.com/s?__biz=', 'https://mp.weixin.qq.com/s/'], 80 | }] 81 | 82 | chrome.browserAction.onClicked.addListener(function(tab) { 83 | console.log('browserAction Clicked: ' + tab.url); 84 | if (limitUsage() === true) {return} 85 | 86 | var remoteConfig = getRemoteConfig(); 87 | if (remoteConfig['handlers'].length > 0) { 88 | Handlers.push(...remoteConfig['handlers']); 89 | } 90 | for (var i = 0; i < Handlers.length; i++) { 91 | var h = Handlers[i]; 92 | for (var j = 0; j < h.urls.length; j++) { 93 | var url = h.urls[j]; 94 | if (tab.url.indexOf(url) > -1) { 95 | console.log('hit:', h); 96 | chrome.tabs.executeScript(null, {file: "util.js"}, function() { 97 | if (h.execScript !== undefined) { 98 | chrome.tabs.executeScript(null, {file: h.execScript}); 99 | } else if (h.execCode !== undefined) { 100 | chrome.tabs.executeScript(null, {code: h.execCode}, function() {}); 101 | } 102 | }); 103 | return 104 | } 105 | } 106 | } 107 | 108 | var supportUrls = ''; 109 | for (var i = 0; i < Handlers.length; i++) { 110 | var h = Handlers[i]; 111 | for (var j = 0; j < h.urls.length; j++) { 112 | supportUrls += '\n' + h.urls[j]; 113 | } 114 | } 115 | 116 | console.log("not support") 117 | alert("插件在不支持的页面运行\n\n\n支持的网站列表如下:" + supportUrls) 118 | }); 119 | -------------------------------------------------------------------------------- /contentScript.js: -------------------------------------------------------------------------------- 1 | var frame = document.getElementById("ueditor_0") 2 | var allSpans = frame && frame.contentWindow ? frame.contentWindow.document.getElementsByTagName("span") : [] 3 | // config 4 | var MPTag = 'data-miniprogram-appid=' 5 | var Count = [] 6 | 7 | var directTransform = [{ 8 | type: 'WechatLink', 9 | nickname: 'WechatLink', 10 | urlPrefix: 'https://mp.weixin.qq.com/s/', 11 | }, { 12 | nickname: 'iDayDayUP', 13 | appid: 'wx482958efb057c5a7', 14 | indexPage: 'pages/daily/daily', 15 | urlPrefix: 'https://idaydayup.com', 16 | genMPUrl: DefaultIndexMPWithPara, 17 | }, { 18 | nickname: 'Readhub', 19 | appid: 'wxd83c7f07a0b00f1b', 20 | urlPrefix: 'https://readhub.cn/topic', 21 | indexPage: 'pages/index', 22 | genMPUrl: function(meta, url) { 23 | var idx = url.indexOf(meta.urlPrefix) 24 | if (idx == -1) { return meta.indexPage } 25 | // Topic URL: https://readhub.cn/topic/7NgjG2U66fX 26 | // Index Page: https://readhub.cn/topics 27 | var topicID = url.slice(meta.urlPrefix.length+idx+1, url.length) 28 | if (topicID == "" || topicID == "/") { return meta.indexPage } 29 | return 'pages/detail?id=' + topicID 30 | }, 31 | }, { 32 | nickname: '哔哩哔哩', 33 | appid: 'wx7564fd5313d24844', 34 | urlPrefix: 'https://www.bilibili.com/video/av', 35 | indexPage: 'pages/index/index', 36 | genMPUrl: function(meta, url) { 37 | var idx = url.indexOf(meta.urlPrefix) 38 | if (idx == -1) {return meta.indexPage } 39 | // pages/video/video?avid=54809781 40 | // https://www.bilibili.com/video/av54809781?spm_id_from=333.334.b_62696c695f67756f636875616e67.51 41 | var qmark = url.indexOf('?') 42 | var start = meta.urlPrefix.length+idx 43 | var id = url.slice(start, qmark!=-1&&qmark>start ? qmark : url.length) 44 | if (id == "" || id == "/") { return meta.indexPage } 45 | return 'pages/video/video?avid=' + id 46 | }, 47 | }, { 48 | nickname: '哔哩哔哩', 49 | appid: 'wx7564fd5313d24844', 50 | urlPrefix: 'https://www.bilibili.com/BV', 51 | indexPage: 'pages/index/index', 52 | genMPUrl: GenBilibiliURL, 53 | }, { 54 | nickname: '哔哩哔哩', 55 | appid: 'wx7564fd5313d24844', 56 | urlPrefix: 'https://www.bilibili.com/video/BV', 57 | indexPage: 'pages/index/index', 58 | genMPUrl: GenBilibiliURL, 59 | }, { 60 | nickname: '腾讯视频', 61 | appid: 'wxa75efa648b60994b', 62 | urlPrefix: 'https://v.qq.com/x/cover/', 63 | indexPage: 'pages/index/index', 64 | genMPUrl: function(meta, url) { 65 | var idx = url.indexOf(meta.urlPrefix) 66 | if (idx == -1) {return meta.indexPage } 67 | // pages/play/index.html?cid=jeds18ea11rrnbg&parentParams= 68 | // https://v.qq.com/x/cover/jeds18ea11rrnbg.html 69 | // https://v.qq.com/x/cover/5vgz1duinuar746/r00314e3n1i.html 70 | var arr = url.split('/') 71 | var id = arr[arr.length-1] 72 | if (id.indexOf('.html') != -1) { 73 | id = id.slice(0, id.indexOf('.html')) 74 | } 75 | if (id == "" || id == "/") { return meta.indexPage } 76 | return 'pages/play/index?parentParams=&cid=' + id 77 | }, 78 | }, { 79 | nickname: 'CSDN', 80 | appid: 'wx2115aba2ed1f96b9', 81 | urlPrefix: 'https://blog.csdn.net', 82 | indexPage: 'pages/index/index', 83 | genMPUrl: function(meta, url) { 84 | var idx = url.indexOf(meta.urlPrefix) 85 | if (idx == -1 || url.indexOf('/article/details/') == -1) {return meta.indexPage } 86 | // pages/blog/article-detail?userName=qq_41753040&articleId=90633737&__key_=15599641012541 87 | // https://blog.csdn.net/qq_41753040/article/details/90633737 88 | var arr = url.slice(meta.urlPrefix.length, url.length).split('/') 89 | if (arr.length < 4) { return meta.indexPage } 90 | var username = arr[0] 91 | var id = arr[3] 92 | if (username == 0 || id == "" || id == "/") { return meta.indexPage } 93 | return 'pages/blog/article-detail?userName=' + username + '&articleId=' + id 94 | }, 95 | }, { 96 | nickname: '简书', 97 | appid: 'wx646159264d261dab', 98 | urlPrefix: 'https://www.jianshu.com', 99 | indexPage: 'pages/index', 100 | // https://www.jianshu.com/p/24d22539d45a 101 | genMPUrl: GenFormatOneMPUrl('p', 'pages/note?slug='), 102 | }, { 103 | nickname: '知乎热榜', 104 | appid: 'wxeb39b10e39bf6b54', 105 | urlPrefix: 'https://www.zhihu.com', 106 | indexPage: 'pages/index/index', 107 | // https://www.zhihu.com/question/329765131 108 | genMPUrl: GenFormatOneMPUrl('question', 'zhihu/question?id='), 109 | }, { 110 | nickname: '知乎热榜', 111 | appid: 'wxeb39b10e39bf6b54', 112 | urlPrefix: 'https://zhuanlan.zhihu.com', 113 | indexPage: 'pages/index/index', 114 | // https://zhuanlan.zhihu.com/p/63501230 115 | genMPUrl: GenFormatOneMPUrl('p', 'zhihu/article?id='), 116 | }, { 117 | nickname: '什么值得买', 118 | appid: 'wxeb5d1f826d7998df', 119 | urlPrefix: 'https://www.smzdm.com', 120 | indexPage: 'pages/index/index', 121 | // https://www.smzdm.com/p/14483467/ 122 | genMPUrl: GenFormatOneMPUrl('p', 'pages/haojia_details/haojia_details?id='), 123 | }, { 124 | nickname: '什么值得买', 125 | appid: 'wxeb5d1f826d7998df', 126 | urlPrefix: 'https://post.smzdm.com', 127 | indexPage: 'pages/index/index', 128 | // https://post.smzdm.com/p/ax08nrm2/ 129 | genMPUrl: GenFormatOneMPUrl('p', 'pages/haowen_details/haowen_details?type=11&id='), 130 | }, { 131 | nickname: '百度网盘', 132 | appid: 'wxdcd3d073e47d1742', 133 | urlPrefix: 'https://pan.baidu.com', 134 | indexPage: 'pages/netdisk_index/index', 135 | // https://pan.baidu.com/s/10v3OUqXpkBnpurKFLI40jQ 136 | genMPUrl: GenFormatOneMPUrl('s', 'pages/netdisk_share/share?scene='), 137 | }, { 138 | nickname: '36氪Lite', 139 | appid: 'wx23551bed0b72cd7f', 140 | urlPrefix: 'https://36kr.com', 141 | indexPage: 'pages/list/list', 142 | // https://36kr.com/p/5220102 143 | genMPUrl: GenFormatOneMPUrl('p', 'pages/detail/detail?id='), 144 | }, { 145 | nickname: '掘金第三方版', 146 | appid: 'wx0f72a9f832b78889', 147 | urlPrefix: 'https://juejin.im', 148 | indexPage: 'pages/launch/launch', 149 | // https://juejin.im/post/5d147765f265da1bb003d0dc 150 | genMPUrl: GenFormatOneMPUrl('post', 'pages/post/post?type=post&id='), 151 | }, { 152 | nickname: 'V2EX For You', 153 | appid: 'wx1b979cda6b085993', 154 | urlPrefix: 'https://www.v2ex.com', 155 | indexPage: 'pages/index/index', 156 | // https://www.v2ex.com/t/578260#reply22 157 | genMPUrl: function (meta, url) { 158 | var p = GenFormatOneMPUrl('t', 'pages/topic/index?topicId=')(meta, url) 159 | if (p.indexOf('#') != -1 ){ 160 | p = p.slice(0, p.indexOf('#')) 161 | } 162 | return p 163 | } 164 | }, { 165 | nickname: '豆瓣评分', 166 | appid: 'wx2f9b06c1de1ccfca', 167 | urlPrefix: 'https://movie.douban.com', 168 | indexPage: 'pages/index/index', 169 | // https://movie.douban.com/subject/26794435/?from=showing 170 | genMPUrl: GenFormatOneMPUrl('subject', 'pages/subject/subject?type=movie&id='), 171 | }, { 172 | nickname: '豆瓣评分', 173 | appid: 'wx2f9b06c1de1ccfca', 174 | urlPrefix: 'https://book.douban.com', 175 | indexPage: 'pages/index/index', 176 | // https://book.douban.com/subject/33442274/?icn=index-latestbook-subject 177 | genMPUrl: GenFormatOneMPUrl('subject', 'pages/subject/subject?type=book&id='), 178 | }, { 179 | nickname: '豆瓣评分', 180 | appid: 'wx2f9b06c1de1ccfca', 181 | urlPrefix: 'https://music.douban.com', 182 | indexPage: 'pages/index/index', 183 | // https://music.douban.com/subject/34780472/ 184 | genMPUrl: GenFormatOneMPUrl('subject', 'pages/subject/subject?type=music&id='), 185 | }, { 186 | nickname: '腾讯新闻', 187 | appid: 'wxb10c47503e8c8e01', 188 | urlPrefix: 'https://new.qq.com', 189 | indexPage: 'pages/main_page/main_page', 190 | // https://new.qq.com/omn/TWF20190/TWF2019081200847600.html 191 | genMPUrl: GenFormatLastPathMPUrl('pages/normal/index?atype=0&id='), 192 | }] 193 | 194 | function DefaultGenMPUrl(meta, url) { 195 | if (url == meta.urlPrefix) {return meta.indexPage} 196 | return url 197 | } 198 | 199 | function isGitHubPage(url) { 200 | return url.startsWith("https://github.com/") || url.startsWith("http://github.com/") 201 | } 202 | 203 | function DefaultIndexMPWithPara(meta, url) { 204 | var p = url.slice(meta.urlPrefix.length, url.length) 205 | return meta.indexPage + p 206 | } 207 | 208 | function GenBilibiliURL(meta, url) { 209 | var idx = url.indexOf(meta.urlPrefix) 210 | if (idx == -1) {return meta.indexPage } 211 | // pages/video/video?avid=54809781 212 | // https://www.bilibili.com/video/BV1dq4y127TF 213 | var qmark = url.indexOf('?') 214 | var start = meta.urlPrefix.length+idx 215 | var id = url.slice(start, qmark!=-1&&qmark>start ? qmark : url.length) 216 | if (id == "" || id == "/") { return meta.indexPage } 217 | var bvid = "BV" + id.replace(/\//, '') 218 | console.log('bvid:', bvid) 219 | 220 | // quote: https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/misc/bvid_desc.md 221 | const XOR_CODE = 23442827791579n; 222 | const MASK_CODE = 2251799813685247n; 223 | const MAX_AID = 1n << 51n; 224 | const BASE = 58n; 225 | 226 | const data = 'FcwAPNKTMug3GV5Lj7EJnHpWsx4tb8haYeviqBz6rkCy12mUSDQX9RdoZf'; 227 | 228 | const bvidArr = Array.from(bvid); 229 | [bvidArr[3], bvidArr[9]] = [bvidArr[9], bvidArr[3]]; 230 | [bvidArr[4], bvidArr[7]] = [bvidArr[7], bvidArr[4]]; 231 | bvidArr.splice(0, 3); 232 | const tmp = bvidArr.reduce((pre, bvidChar) => pre * BASE + BigInt(data.indexOf(bvidChar)), 0n); 233 | var avid = Number((tmp & MASK_CODE) ^ XOR_CODE); 234 | 235 | return 'pages/video/video?avid=' + avid 236 | } 237 | 238 | function parseGitHub(url) { 239 | if (!isGitHubPage(url)) { 240 | return ["", "", ""] 241 | } 242 | var arr = url.split('/') 243 | if (arr.length == 4){ 244 | return [arr[3], "", ""] 245 | } else if (arr.length == 5) { 246 | var repo = arr[4] 247 | if (repo.indexOf('#')) { 248 | repo = arr[4].split('#')[0] 249 | } 250 | return [arr[3], repo, ""] 251 | } else if (arr.length > 5) { 252 | var file = url.slice(("https://github.com/" + arr[3] + "/" + arr[4] + "/").length) 253 | return [arr[3], arr[4], file] 254 | } 255 | return ["", "", ""] 256 | } 257 | 258 | // url like: /xxx/yyy/zzz/. 259 | function GenFormatLastPathMPUrl(path) { 260 | function genMPUrl(meta, url) { 261 | var idx = url.indexOf(meta.urlPrefix) 262 | if (idx == -1) {return meta.indexPage } 263 | var arr = url.split('/') 264 | var lastpath = arr[arr.length-1].split('.')[0] 265 | if (lastpath == "") {return meta.indexPage} 266 | return path + lastpath 267 | } 268 | return genMPUrl 269 | } 270 | 271 | // url like: //, such as: https://zhuanlan.zhihu.com/p/63501230 272 | function GenFormatOneMPUrl(gap, path) { 273 | function genMPUrl(meta, url) { 274 | var idx = url.indexOf(meta.urlPrefix) 275 | if (idx == -1 || url.indexOf('/'+gap+'/') == -1) {return meta.indexPage } 276 | var arr = url.split('/') 277 | if (arr.length < 5) { return meta.indexPage } 278 | var id = arr[4] 279 | if (id == "") { return meta.indexPage } 280 | return path + id 281 | } 282 | return genMPUrl 283 | } 284 | 285 | function genFilterFunc(urlPrefix) { 286 | return function(item) { 287 | if (!item.innerHTML || item.innerHTML.indexOf(urlPrefix)==-1 || item.innerHTML.indexOf(MPTag)!=-1) {return false} 288 | return true 289 | } 290 | } 291 | 292 | function filterArr(arr, func) { 293 | var newArr = [] 294 | if (arr.length == 0) {return newArr} 295 | for (j=0; j‍' + text + '‍' 308 | } 309 | 310 | url = transItem.genMPUrl(transItem, url, text) 311 | return '' + text + '' 312 | } 313 | 314 | console.log('allSpans:', allSpans) 315 | for (i=0; i allLinks:', allLinks) 322 | 323 | filterArr(allLinks, function(item) { 324 | console.log(nickname, ' => detail:', item) 325 | var inH = item.innerHTML 326 | 327 | if (inH.startsWith(urlPrefix)) { 328 | item.innerHTML = mpLink(trans, inH, inH) 329 | } else if (item.firstChild) { 330 | var fch = item.firstChild 331 | if (fch.href && fch.href.startsWith(urlPrefix)) { 332 | item.innerHTML = mpLink(trans, fch.href, fch.innerText) 333 | } 334 | if (fch.innerText && fch.innerText.startsWith(urlPrefix)) { 335 | item.innerHTML = mpLink(trans, fch.innerText, fch.innerText) 336 | } 337 | } 338 | }) 339 | } 340 | if (Count.length == 0) {alert('无可转换为小程序的链接')} 341 | else { 342 | alert('转换小程序链接成功:\n'+Count.join('\n')); 343 | if (Count.length > 50) { 344 | alert('转换小程序链接超过50个,微信平台限制了最多50个') 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /example.md: -------------------------------------------------------------------------------- 1 | > 项目地址:https://github.com/ZhuPeng/mp-githubtrending 2 | 3 | 测试 [githubtrending](https://github.com/ZhuPeng/mp-githubtrending) hahahah 4 | 5 | * 测试 [githubtrending ](https://github.com/ZhuPeng/mp-githubtrending)hahahah 6 | 7 | 测试https://github.com/ZhuPeng/mp-githubtrending 8 | 9 | https://github.com/ZhuPeng/mp-githubtrending 10 | 11 | https://github.com/monitoror/monitoror/blob/develop/Makefile 12 | 13 | https://github.com/monitoror 14 | 15 | 16 | [https://readhub.cn/topic/7NgjG2U66fX](https://readhub.cn/topic/7NgjG2U66fX) 17 | 18 | [https://readhub.cn/topics](https://readhub.cn/topics) 19 | 20 | [https://www.bilibili.com/video/av54809781?spm_id_from=333.334.b_62696c695f67756f636875616e67.51](https://www.bilibili.com/video/av54809781?spm_id_from=333.334.b_62696c695f67756f636875616e67.51) 21 | 22 | [https://v.qq.com/x/cover/jeds18ea11rrnbg.html](https://v.qq.com/x/cover/jeds18ea11rrnbg.html) 23 | 24 | [https://v.qq.com/x/cover/5vgz1duinuar746/r00314e3n1i.html](https://v.qq.com/x/cover/5vgz1duinuar746/r00314e3n1i.html) 25 | 26 | [https://blog.csdn.net/qq_41753040/article/details/90633737](https://blog.csdn.net/qq_41753040/article/details/90633737) 27 | 28 | [https://www.jianshu.com/p/24d22539d45a](https://www.jianshu.com/p/24d22539d45a) 29 | 30 | [https://www.zhihu.com/question/329765131](https://www.zhihu.com/question/329765131) 31 | 32 | [https://zhuanlan.zhihu.com/p/63501230](https://zhuanlan.zhihu.com/p/63501230) 33 | 34 | [https://www.smzdm.com/p/14483467/](https://www.smzdm.com/p/14483467/) 35 | 36 | [https://post.smzdm.com/p/ax08nrm2/](https://post.smzdm.com/p/ax08nrm2/) 37 | 38 | [https://pan.baidu.com/s/1EuJiHB-q2Lggrt28cjQISA#3tb7#0#0](https://pan.baidu.com/s/1EuJiHB-q2Lggrt28cjQISA#3tb7#0#0) 39 | 40 | [https://36kr.com/p/5220102](https://36kr.com/p/5220102) 41 | 42 | [https://juejin.im/post/5d147765f265da1bb003d0dc](https://juejin.im/post/5d147765f265da1bb003d0dc) 43 | 44 | [https://www.v2ex.com/t/578192#reply103](https://www.v2ex.com/t/578192#reply103) 45 | 46 | [https://movie.douban.com/subject/26794435/](https://movie.douban.com/subject/26794435/) 47 | 48 | [https://book.douban.com/subject/33442274/?icn=index-latestbook-subject](https://book.douban.com/subject/33442274/?icn=index-latestbook-subject) 49 | 50 | [https://music.douban.com/subject/34780472/](https://music.douban.com/subject/34780472/) 51 | 52 | [https://new.qq.com/omn/20190812/20190812A0QBK300.html](https://new.qq.com/omn/20190812/20190812A0QBK300.html) 53 | 54 | 55 | -------------------------------------------------------------------------------- /handlers/batch_getyarn.js: -------------------------------------------------------------------------------- 1 | var elems = document.getElementsByClassName('video-match') 2 | console.log("elems:", elems) 3 | 4 | if (elems.length == 0) { 5 | alert('没有找到下载链接') 6 | } else { 7 | for (var i=0; i div > div.publish_content.publish_record_history > div:nth-child(1) > div:nth-child(1) > div') 2 | console.log("elems:", elems) 3 | 4 | if (elems.length == 0) { 5 | alert('没有找到下载链接') 6 | } else { 7 | for (var i=0; i -1) { 3 | crawelInfo() 4 | } 5 | }); 6 | 7 | var info = parseInfo() 8 | copyToClipboard(info['title'] + '\n\n' + info['intro'] + '\n\n开源项目地址:https://github.com/' + info['repo'] + '\n\n更多介绍:' + info['url']) 9 | 10 | function parseInfo() { 11 | console.log("获取json信息") 12 | var elem = {"website": "wechat", "type": "text"} 13 | elem['title'] = getTextWithSelector('#activity-name') 14 | var p = /项目地址:https:\/\/github.com\/(.*)/gi; 15 | elem['repo'] = (getTextByPattern(p).split('https://github.com/')[1] || '').split(' ')[0] || '' 16 | if (elem['repo'].length === 0) { 17 | elem['repo'] = getTextByPattern(/链接:https:\/\/github.com\/(.*)/gi).split('https://github.com/')[1].split(' ')[0] 18 | } 19 | elem['url'] = window.location.href.replace("?autoclose", '').replace('&autoclose', '') 20 | var intro = getElementByXpath(document, '//h4[2]/following-sibling::p[1]') 21 | if (intro == null) { 22 | intro = getElementByXpath(document, '//h6[2]/following-sibling::p[1]') 23 | } 24 | elem['intro'] = intro.innerText 25 | console.log(elem) 26 | // alert(JSON.stringify(elem)) 27 | return elem 28 | } 29 | 30 | function crawelInfo() { 31 | var elem = parseInfo() 32 | fetch('http://127.0.0.1:8082/api/add_doc', { 33 | method: 'POST', 34 | mode: 'no-cors', 35 | headers: { 36 | 'Accept': 'application/json', 37 | 'Access-Control-Allow-Origin': '*', 38 | 'Access-Control-Allow-Credentials': false, 39 | 'mode': 'no-cors', 40 | 'Content-Type': 'application/json' 41 | }, 42 | body: JSON.stringify(elem) 43 | }) 44 | .then(response => response) 45 | .catch(error => console.log('Error:', error)); 46 | 47 | setTimeout(function() { 48 | chrome.extension.sendMessage({greeting: "close_tab"}); 49 | }, 500); 50 | } 51 | -------------------------------------------------------------------------------- /handlers/instagram.js: -------------------------------------------------------------------------------- 1 | var scripts = document.getElementsByTagName('script') 2 | console.log("scripts:", scripts) 3 | 4 | for (i=0; i -1) { 22 | url = url.replace(domain, 'scontent.cdninstagram.com') 23 | } 24 | alert("下载视频链接:" + url) 25 | window.open(url) 26 | } 27 | 28 | function alertText(t) { 29 | alert(t) 30 | alert(t.slice(t.length-10, t.length)) 31 | } 32 | -------------------------------------------------------------------------------- /handlers/itra.js: -------------------------------------------------------------------------------- 1 | window.addEventListener('load', function() { 2 | if (urlContains('itra.run/api/RunnerSpace/GetRunnerSpace') && bodyContains('Latest Results')) { 3 | requestRaceResults(); 4 | } 5 | }); 6 | 7 | function requestRaceResults(page) { 8 | if (!page) { page = '1'; } 9 | var id = getTextWithSelector('#divShowResults p span b'); 10 | var url = 'https://itra.run/api/Race/GetRaceResultsData?runnerId=' + id + '&pageNumber=' + page + '&pageSize=10&raceYear=&categoryId=' 11 | console.log('fetch url:', url) 12 | fetch(url) 13 | .then(response => response.json()) 14 | .then(data => { 15 | console.log('fetch data:', data); 16 | var dictionary = Object.assign({}, ...data['raceResults'].map((x) => ({[x.date+x.name.replace(' ', ' ').trim()]: x}))); 17 | showScore(dictionary); 18 | }); 19 | } 20 | 21 | function showScore(raceResults) { 22 | console.log('showScore:', raceResults); 23 | loopSelectXpath("//div[@class='row table-body-row']", function(index, node) { 24 | var ch = node.children[8].children[1].children[0]; 25 | if (!ch.classList.contains('locked')) { 26 | return; 27 | } 28 | var date = node.children[0].innerText.trim(); 29 | var race = node.children[2].children[0].children[0].innerText.trim(); 30 | var score = 0; 31 | if (raceResults[date+race]) { score = raceResults[date+race]['score']; } 32 | console.log('parsed:', date, race, score); 33 | 34 | ch.classList.remove('locked'); 35 | ch.innerText = score; 36 | }); 37 | } 38 | 39 | bindClickWithTag(findTagWithText('a', 'Results'), function() { 40 | setTimeout(()=> { 41 | requestRaceResults(); 42 | bindClickWithTag(findTagWithText('button', 'Load More Results'), function() { 43 | setTimeout(()=> { 44 | var l = document.querySelectorAll('div[class="row table-body-row"]').length; 45 | requestRaceResults(Math.floor(l/10)); 46 | }, 4000); 47 | }) 48 | }, 4000) 49 | }) 50 | 51 | bindClickWithTag(findTagWithText('p', 'Time Charts'), function() { 52 | console.log('Time Charts clicked'); 53 | setTimeout(() => { 54 | showInter("//div[@role='row']//div[5]"); 55 | showInter("//div[@role='row']//div[6]"); 56 | }, 500) 57 | }) 58 | 59 | if (urlContains('https://live.utmb.world/') && urlContains('runners')) { 60 | var lastDist = 0; 61 | var lastGain = 0; 62 | loopSelectXpath("//div[contains(@class, 'runner-timing-point_liveTableRow')]", function(index, node){ 63 | var dist = Number(node.children[6].innerText.trim().split(' ')[0]); 64 | var gain = Number(node.children[7].innerText.trim().split(' ')[0]); 65 | var time = node.children[4].innerText.trim(); 66 | console.log('dist:', dist, 'time:', time); 67 | 68 | var ch = node.children[6].children[0]; 69 | if (dist - lastDist > 0.1) { 70 | console.log('inter dist:', dist - lastDist); 71 | ch.innerText = ch.innerText + ' +' + (dist - lastDist).toFixed(1); 72 | node.children[7].children[0].innerText = node.children[7].children[0].innerText + ' +' + (gain - lastGain).toFixed(0); 73 | } 74 | lastDist = dist; 75 | lastGain = gain; 76 | }); 77 | } 78 | 79 | function showInter(xpath){ 80 | console.log('showInterGain'); 81 | var result = document.evaluate(xpath, document, null, XPathResult.ANY_TYPE, null); 82 | var node = result.iterateNext() 83 | var lastGain = 0; 84 | var nodesToModify = []; 85 | while (node) { 86 | console.log('node:', node); 87 | var culGain = node.childNodes[0].innerText; 88 | console.log('culGain:', culGain); 89 | if (!Number.isInteger(Number(culGain))) { 90 | node = result.iterateNext(); 91 | continue; 92 | } 93 | var interGain = Number(culGain) - lastGain; 94 | console.log('interGain:', interGain); 95 | lastGain = culGain; 96 | nodesToModify.push({node: node, interGain: interGain, culGain: culGain}); 97 | node = result.iterateNext(); 98 | } 99 | nodesToModify.forEach(function(item, index, array) { 100 | if (index === array.length - 1) { 101 | item.node.childNodes[0].innerText = item.interGain + ' (total:' + item.culGain+')'; 102 | } else { 103 | item.node.childNodes[0].innerText = item.interGain; 104 | } 105 | }); 106 | } 107 | -------------------------------------------------------------------------------- /handlers/race_subscribe.js: -------------------------------------------------------------------------------- 1 | if (urlContains('geexek.com/score/pscore')) { 2 | const predictSwitch = document.querySelector('#predictSwitch'); 3 | var newNode = predictSwitch.cloneNode(false); 4 | newNode.innerText = '订阅通知'; 5 | predictSwitch.parentNode.insertBefore(newNode, predictSwitch); 6 | bindClickWithTag(newNode, subscribe_diaglog); 7 | } 8 | 9 | if (urlContains('live.utmb.world/')) { 10 | bindClickWithTag(getElementByXpath(document, '//div[@role="button"]'), subscribe_diaglog) 11 | } 12 | 13 | if (urlContains('/coureur.php')) { 14 | bindClickWithTag(getElementByXpath(document, '//a[@class="nofav"]'), subscribe_diaglog) 15 | } 16 | 17 | function subscribe_diaglog() { 18 | console.log('subscribe click with notify'); 19 | const dialog = document.createElement('dialog'); 20 | dialog.innerHTML = ` 21 | 69 |
70 |
71 |

72 | 73 | 74 | 75 | 76 |
77 |
78 | `; 79 | document.body.appendChild(dialog); 80 | dialog.showModal(); 81 | 82 | dialog.querySelector('#submit').addEventListener('click', () => { 83 | const email = dialog.querySelector('#email').value; 84 | console.log('Submitted information:', email); 85 | if (!email) { 86 | alert('Please input email'); 87 | } 88 | subscribe_notify(email); 89 | dialog.close(); 90 | }); 91 | 92 | dialog.querySelector('#cancel').addEventListener('click', () => { 93 | dialog.close(); 94 | }); 95 | } -------------------------------------------------------------------------------- /handlers/savefrom.js: -------------------------------------------------------------------------------- 1 | var link = document.getElementsByClassName('def-btn-box') 2 | console.log(link) 3 | 4 | for (i=0; i点击' 45 | console.log(link) 46 | } 47 | 48 | var directTransform = [{ 49 | nickname: '开源Books', 50 | appid: 'wxe60c5750c87916e0', 51 | indexPage: 'pages/bloglist/bloglist', 52 | urlPrefix: 'https://github.com', 53 | genMPUrl: function(meta, url) { 54 | var [owner, repo, filepath] = parseGitHub(url) 55 | console.log("parseGitHub url:", owner, repo, filepath) 56 | if (owner == "") { return meta.indexPage} 57 | else if (repo == "") { return 'pages/account/account?owner=' + owner } 58 | else if (filepath == "") { return 'pages/readme/readme?repo=' + owner + '/' + repo } 59 | else if (filepath.startsWith('issues/') || filepath.startsWith('pull/')) { 60 | var issue = 'https://api.github.com/repos/' + owner + '/' + repo + '/' + filepath.replace('pull/', 'issues/') 61 | return '/pages/issue/issue?issue='+issue 62 | } 63 | else { return 'pages/gitfile/gitfile?file=' + filepath + '&owner=' + owner + '&repo=' + repo } 64 | }, 65 | }, { 66 | nickname: 'iDayDayUP', 67 | appid: 'wx482958efb057c5a7', 68 | indexPage: 'pages/daily/daily', 69 | urlPrefix: 'https://idaydayup.com', 70 | genMPUrl: DefaultIndexMPWithPara, 71 | }, { 72 | nickname: '开源话题', 73 | appid: 'wx0b48bcbd26917a62', 74 | indexPage: 'pages/bloglist/bloglist', 75 | urlPrefix: 'https://opensourcetopic.com', 76 | genMPUrl: DefaultIndexMPWithPara, 77 | }, { 78 | nickname: 'Readhub', 79 | appid: 'wxd83c7f07a0b00f1b', 80 | urlPrefix: 'https://readhub.cn/topic', 81 | indexPage: 'pages/index', 82 | genMPUrl: function(meta, url) { 83 | var idx = url.indexOf(meta.urlPrefix) 84 | if (idx == -1) { return meta.indexPage } 85 | // Topic URL: https://readhub.cn/topic/7NgjG2U66fX 86 | // Index Page: https://readhub.cn/topics 87 | var topicID = url.slice(meta.urlPrefix.length+idx+1, url.length) 88 | if (topicID == "" || topicID == "/") { return meta.indexPage } 89 | return 'pages/detail?id=' + topicID 90 | }, 91 | }, { 92 | nickname: '哔哩哔哩', 93 | appid: 'wx7564fd5313d24844', 94 | urlPrefix: 'https://www.bilibili.com/video/av', 95 | indexPage: 'pages/index/index', 96 | genMPUrl: function(meta, url) { 97 | var idx = url.indexOf(meta.urlPrefix) 98 | if (idx == -1) {return meta.indexPage } 99 | // pages/video/video?avid=54809781 100 | // https://www.bilibili.com/video/av54809781?spm_id_from=333.334.b_62696c695f67756f636875616e67.51 101 | var qmark = url.indexOf('?') 102 | var start = meta.urlPrefix.length+idx 103 | var id = url.slice(start, qmark!=-1&&qmark>start ? qmark : url.length) 104 | if (id == "" || id == "/") { return meta.indexPage } 105 | return 'pages/video/video?avid=' + id 106 | }, 107 | }, { 108 | nickname: '哔哩哔哩', 109 | appid: 'wx7564fd5313d24844', 110 | urlPrefix: 'https://www.bilibili.com/BV', 111 | indexPage: 'pages/index/index', 112 | genMPUrl: GenBilibiliURL, 113 | }, { 114 | nickname: '哔哩哔哩', 115 | appid: 'wx7564fd5313d24844', 116 | urlPrefix: 'https://www.bilibili.com/video/BV', 117 | indexPage: 'pages/index/index', 118 | genMPUrl: GenBilibiliURL, 119 | }, { 120 | nickname: '腾讯视频', 121 | appid: 'wxa75efa648b60994b', 122 | urlPrefix: 'https://v.qq.com/x/cover/', 123 | indexPage: 'pages/index/index', 124 | genMPUrl: function(meta, url) { 125 | var idx = url.indexOf(meta.urlPrefix) 126 | if (idx == -1) {return meta.indexPage } 127 | // pages/play/index.html?cid=jeds18ea11rrnbg&parentParams= 128 | // https://v.qq.com/x/cover/jeds18ea11rrnbg.html 129 | // https://v.qq.com/x/cover/5vgz1duinuar746/r00314e3n1i.html 130 | var arr = url.split('/') 131 | var id = arr[arr.length-1] 132 | if (id.indexOf('.html') != -1) { 133 | id = id.slice(0, id.indexOf('.html')) 134 | } 135 | if (id == "" || id == "/") { return meta.indexPage } 136 | return 'pages/play/index?parentParams=&cid=' + id 137 | }, 138 | }, { 139 | nickname: 'CSDN', 140 | appid: 'wx2115aba2ed1f96b9', 141 | urlPrefix: 'https://blog.csdn.net', 142 | indexPage: 'pages/index/index', 143 | genMPUrl: function(meta, url) { 144 | var idx = url.indexOf(meta.urlPrefix) 145 | if (idx == -1 || url.indexOf('/article/details/') == -1) {return meta.indexPage } 146 | // pages/blog/article-detail?userName=qq_41753040&articleId=90633737&__key_=15599641012541 147 | // https://blog.csdn.net/qq_41753040/article/details/90633737 148 | var arr = url.slice(meta.urlPrefix.length, url.length).split('/') 149 | if (arr.length < 4) { return meta.indexPage } 150 | var username = arr[0] 151 | var id = arr[3] 152 | if (username == 0 || id == "" || id == "/") { return meta.indexPage } 153 | return 'pages/blog/article-detail?userName=' + username + '&articleId=' + id 154 | }, 155 | }, { 156 | nickname: '简书', 157 | appid: 'wx646159264d261dab', 158 | urlPrefix: 'https://www.jianshu.com', 159 | indexPage: 'pages/index', 160 | // https://www.jianshu.com/p/24d22539d45a 161 | genMPUrl: GenFormatOneMPUrl('p', 'pages/note?slug='), 162 | }, { 163 | nickname: '知乎热榜', 164 | appid: 'wxeb39b10e39bf6b54', 165 | urlPrefix: 'https://www.zhihu.com', 166 | indexPage: 'pages/index/index', 167 | // https://www.zhihu.com/question/329765131 168 | genMPUrl: GenFormatOneMPUrl('question', 'zhihu/question?id='), 169 | }, { 170 | nickname: '知乎热榜', 171 | appid: 'wxeb39b10e39bf6b54', 172 | urlPrefix: 'https://zhuanlan.zhihu.com', 173 | indexPage: 'pages/index/index', 174 | // https://zhuanlan.zhihu.com/p/63501230 175 | genMPUrl: GenFormatOneMPUrl('p', 'zhihu/article?id='), 176 | }, { 177 | nickname: '什么值得买', 178 | appid: 'wxeb5d1f826d7998df', 179 | urlPrefix: 'https://www.smzdm.com', 180 | indexPage: 'pages/index/index', 181 | // https://www.smzdm.com/p/14483467/ 182 | genMPUrl: GenFormatOneMPUrl('p', 'pages/haojia_details/haojia_details?id='), 183 | }, { 184 | nickname: '什么值得买', 185 | appid: 'wxeb5d1f826d7998df', 186 | urlPrefix: 'https://post.smzdm.com', 187 | indexPage: 'pages/index/index', 188 | // https://post.smzdm.com/p/ax08nrm2/ 189 | genMPUrl: GenFormatOneMPUrl('p', 'pages/haowen_details/haowen_details?type=11&id='), 190 | }, { 191 | nickname: '百度网盘', 192 | appid: 'wxdcd3d073e47d1742', 193 | urlPrefix: 'https://pan.baidu.com', 194 | indexPage: 'pages/netdisk_index/index', 195 | // https://pan.baidu.com/s/10v3OUqXpkBnpurKFLI40jQ 196 | genMPUrl: GenFormatOneMPUrl('s', 'pages/netdisk_share/share?scene='), 197 | }, { 198 | nickname: '36氪Lite', 199 | appid: 'wx23551bed0b72cd7f', 200 | urlPrefix: 'https://36kr.com', 201 | indexPage: 'pages/list/list', 202 | // https://36kr.com/p/5220102 203 | genMPUrl: GenFormatOneMPUrl('p', 'pages/detail/detail?id='), 204 | }, { 205 | nickname: '掘金第三方版', 206 | appid: 'wx0f72a9f832b78889', 207 | urlPrefix: 'https://juejin.im', 208 | indexPage: 'pages/launch/launch', 209 | // https://juejin.im/post/5d147765f265da1bb003d0dc 210 | genMPUrl: GenFormatOneMPUrl('post', 'pages/post/post?type=post&id='), 211 | }, { 212 | nickname: 'V2EX For You', 213 | appid: 'wx1b979cda6b085993', 214 | urlPrefix: 'https://www.v2ex.com', 215 | indexPage: 'pages/index/index', 216 | // https://www.v2ex.com/t/578260#reply22 217 | genMPUrl: function (meta, url) { 218 | var p = GenFormatOneMPUrl('t', 'pages/topic/index?topicId=')(meta, url) 219 | if (p.indexOf('#') != -1 ){ 220 | p = p.slice(0, p.indexOf('#')) 221 | } 222 | return p 223 | } 224 | }, { 225 | nickname: '豆瓣评分', 226 | appid: 'wx2f9b06c1de1ccfca', 227 | urlPrefix: 'https://movie.douban.com', 228 | indexPage: 'pages/index/index', 229 | // https://movie.douban.com/subject/26794435/?from=showing 230 | genMPUrl: GenFormatOneMPUrl('subject', 'pages/subject/subject?type=movie&id='), 231 | }, { 232 | nickname: '豆瓣评分', 233 | appid: 'wx2f9b06c1de1ccfca', 234 | urlPrefix: 'https://book.douban.com', 235 | indexPage: 'pages/index/index', 236 | // https://book.douban.com/subject/33442274/?icn=index-latestbook-subject 237 | genMPUrl: GenFormatOneMPUrl('subject', 'pages/subject/subject?type=book&id='), 238 | }, { 239 | nickname: '豆瓣评分', 240 | appid: 'wx2f9b06c1de1ccfca', 241 | urlPrefix: 'https://music.douban.com', 242 | indexPage: 'pages/index/index', 243 | // https://music.douban.com/subject/34780472/ 244 | genMPUrl: GenFormatOneMPUrl('subject', 'pages/subject/subject?type=music&id='), 245 | }, { 246 | nickname: '腾讯新闻', 247 | appid: 'wxb10c47503e8c8e01', 248 | urlPrefix: 'https://new.qq.com', 249 | indexPage: 'pages/main_page/main_page', 250 | // https://new.qq.com/omn/TWF20190/TWF2019081200847600.html 251 | genMPUrl: GenFormatLastPathMPUrl('pages/normal/index?atype=0&id='), 252 | }] 253 | 254 | function DefaultGenMPUrl(meta, url) { 255 | if (url == meta.urlPrefix) {return meta.indexPage} 256 | return url 257 | } 258 | 259 | function isGitHubPage(url) { 260 | return url.startsWith("https://github.com/") || url.startsWith("http://github.com/") 261 | } 262 | 263 | function DefaultIndexMPWithPara(meta, url) { 264 | var p = url.slice(meta.urlPrefix.length, url.length) 265 | return meta.indexPage + p 266 | } 267 | 268 | function parseGitHub(url) { 269 | if (!isGitHubPage(url)) { 270 | return ["", "", ""] 271 | } 272 | var arr = url.split('/') 273 | if (arr.length == 4){ 274 | return [arr[3], "", ""] 275 | } else if (arr.length == 5) { 276 | var repo = arr[4] 277 | if (repo.indexOf('#')) { 278 | repo = arr[4].split('#')[0] 279 | } 280 | return [arr[3], repo, ""] 281 | } else if (arr.length > 5) { 282 | var file = url.slice(("https://github.com/" + arr[3] + "/" + arr[4] + "/").length) 283 | return [arr[3], arr[4], file] 284 | } 285 | return ["", "", ""] 286 | } 287 | 288 | // url like: /xxx/yyy/zzz/. 289 | function GenFormatLastPathMPUrl(path) { 290 | function genMPUrl(meta, url) { 291 | var idx = url.indexOf(meta.urlPrefix) 292 | if (idx == -1) {return meta.indexPage } 293 | var arr = url.split('/') 294 | var lastpath = arr[arr.length-1].split('.')[0] 295 | if (lastpath == "") {return meta.indexPage} 296 | return path + lastpath 297 | } 298 | return genMPUrl 299 | } 300 | 301 | // url like: //, such as: https://zhuanlan.zhihu.com/p/63501230 302 | function GenFormatOneMPUrl(gap, path) { 303 | function genMPUrl(meta, url) { 304 | var idx = url.indexOf(meta.urlPrefix) 305 | if (idx == -1 || url.indexOf('/'+gap+'/') == -1) {return meta.indexPage } 306 | var arr = url.split('/') 307 | if (arr.length < 5) { return meta.indexPage } 308 | var id = arr[4] 309 | if (id == "") { return meta.indexPage } 310 | return path + id 311 | } 312 | return genMPUrl 313 | } 314 | 315 | function GenBilibiliURL(meta, url) { 316 | var idx = url.indexOf(meta.urlPrefix) 317 | if (idx == -1) {return meta.indexPage } 318 | // pages/video/video?avid=54809781 319 | // https://www.bilibili.com/video/BV1dq4y127TF 320 | var qmark = url.indexOf('?') 321 | var start = meta.urlPrefix.length+idx 322 | var id = url.slice(start, qmark!=-1&&qmark>start ? qmark : url.length) 323 | if (id == "" || id == "/") { return meta.indexPage } 324 | 325 | // quote: https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/other/bvid_desc.md 326 | var x = "BV" + id 327 | console.log('bvid:', x) 328 | var table = "fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF" 329 | var tr = {} 330 | for (var i=0; i<58; i++) { 331 | tr[table[i]] = i 332 | } 333 | var s = [11, 10, 3, 8, 4, 6] 334 | var xor = 177451812 // 固定异或值 335 | var add = 8728348608 //固定加法值 336 | 337 | var r = 0 338 | for (var i=0; i<6; i++) { 339 | r += tr[x[s[i]]] * 58 ** i 340 | } 341 | var aid = (r - add) ^ xor 342 | return 'pages/video/video?avid=' + aid 343 | } 344 | 345 | // Link('https://github.com/basecamp/dumpsterfire-2020') -------------------------------------------------------------------------------- /popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /popup.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhuPeng/mp-transform-public/b38fb68c2e06a8cfb943893525bb557b1afb9bd1/popup.js -------------------------------------------------------------------------------- /util.js: -------------------------------------------------------------------------------- 1 | copyToClipboard = str => { 2 | console.log("copyToClipboard"); 3 | const el = document.createElement('textarea'); 4 | el.value = str; 5 | el.setAttribute('readonly', ''); 6 | el.style.position = 'absolute'; 7 | el.style.left = '-9999px'; 8 | document.body.appendChild(el); 9 | el.select(); 10 | document.execCommand('copy'); 11 | document.body.removeChild(el); 12 | alert('复制内容到剪贴板:\n' + str); 13 | }; 14 | 15 | copyAndRedirect = str => { 16 | copyToClipboard(window.location.href) 17 | var target = str; 18 | alert('重定向跳转到 ' + target + ' 开始下载') 19 | window.open(target) 20 | }; 21 | 22 | function newDayKey(sufix) { 23 | var dt = new Date(); 24 | return dt.getFullYear() + '-' + (dt.getMonth() + 1) + dt.getDate() + '-' + sufix; 25 | } 26 | 27 | function getWithCache(key, url) { 28 | var cached = localStorage.getItem(key) || false; 29 | if (cached !== false) { 30 | var c = JSON.parse(cached) 31 | console.log('cached config:', c); 32 | return c; 33 | } 34 | 35 | fetch(url) 36 | .then(response => response.json()) 37 | .then(data => { 38 | console.log('fetch data:', data) 39 | localStorage.setItem(key, JSON.stringify(data)); 40 | }) 41 | .catch(error => { 42 | console.log('fetch json:', error); 43 | }); 44 | return {}; 45 | } 46 | 47 | function urlContains(str) { 48 | return window.location.href.indexOf(str) >= 0 49 | } 50 | 51 | function bodyContains(str) { 52 | return document.body.innerText.indexOf(str) >= 0 53 | } 54 | 55 | function loopSelectXpath(xpath, modifyFunc) { 56 | var result = document.evaluate(xpath, document, null, XPathResult.ANY_TYPE, null); 57 | var node = result.iterateNext() 58 | var nodesToModify = []; 59 | while (node) { 60 | console.log('node:', node, 'children:', node.children); 61 | nodesToModify.push({node: node}); 62 | node = result.iterateNext(); 63 | } 64 | nodesToModify.forEach(function(item, index, array) { 65 | modifyFunc(index, item.node); 66 | }); 67 | } 68 | 69 | // getTextWithSelector('#activity-name') 70 | function getTextWithSelector(selector) { 71 | const sel = document.querySelector(selector) 72 | var t = '' 73 | if (sel) { 74 | t = sel.innerText 75 | } 76 | console.log(selector, ' => ', t) 77 | return t 78 | } 79 | // var p = /项目地址:https:\/\/github.com\/(.*)/gi; getTextByPattern(p) 80 | function getTextByPattern(p) { 81 | console.log('match p:', p) 82 | var m = document.body.innerText.match(p) 83 | if (!m || m == null || m.length == 0) { 84 | return '' 85 | } 86 | return m[0] 87 | } 88 | 89 | function findTagWithText(tag, text) { 90 | var tags = document.querySelectorAll(tag); 91 | return Array.from(tags).find(t => t.textContent.trim() === text); 92 | } 93 | 94 | function bindClickWithTag(tag, handler) { 95 | if (tag) { 96 | console.log('found tag bindclick:', tag) 97 | tag.addEventListener('click', function() { 98 | console.log('click:', tag) 99 | handler(); 100 | }); 101 | } 102 | } 103 | 104 | function getElementByXpath(dom, path) { 105 | console.log('getElementByXpath', dom, path) 106 | return document.evaluate(path, dom, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; 107 | } 108 | 109 | function click(dom, path) { 110 | console.log('click xpath:', path) 111 | var element = getElementByXpath(dom, path); 112 | console.log(element) 113 | element.click(); 114 | } 115 | 116 | function input(dom, path, info) { 117 | console.log('input xpath:', path, info) 118 | var element = getElementByXpath(dom, path); 119 | console.log(element) 120 | element.setAttribute("value", info); 121 | element.value = info 122 | } 123 | 124 | function subscribe_notify(email) { 125 | submit_cmd("cd ../liverace && python3 data.py subscribe_from_url " + window.location.href + " " + email); 126 | } 127 | 128 | function submit_cmd(cmd) { 129 | var url = 'http://127.0.0.1:8083/submit' 130 | var data = { 131 | 'PROXYSERVER-IP': '116.198.206.22:8083', 132 | 'command': cmd, 133 | 'same_terminate': true 134 | } 135 | fetch(url, { 136 | method: 'POST', 137 | mode: 'no-cors', 138 | headers: { 139 | 'Accept': 'application/json', 140 | 'Access-Control-Allow-Origin': '*', 141 | 'Access-Control-Allow-Credentials': false, 142 | 'mode': 'no-cors', 143 | 'Content-Type': 'application/json' 144 | }, 145 | body: JSON.stringify(data) 146 | }).then(response => response) 147 | .catch(error => console.log('Error:', error)); 148 | alert('提交成功!'); 149 | } 150 | --------------------------------------------------------------------------------