├── Nlc.cn.js ├── Spc.org.cn.js ├── Jd.js ├── Dangdang.js ├── README.md ├── uRead.js ├── Ncpssd.js ├── CNKI.js ├── Superlib.js ├── BiliBili.js └── Douban.js /Nlc.cn.js: -------------------------------------------------------------------------------- 1 | { 2 | "translatorID": "33ed4133-f48b-45e4-8f00-9b8c22342c0b", 3 | "label": "nlc.cn", 4 | "creator": "018", 5 | "target": "https?://vpn2\\.nlc\\.cn/prx", 6 | "minVersion": "3.0", 7 | "maxVersion": "", 8 | "priority": 100, 9 | "inRepository": true, 10 | "translatorType": 4, 11 | "browserSupport": "gcsibv", 12 | "lastUpdated": "2020-12-28 03:38:46" 13 | } 14 | 15 | /* 16 | ***** BEGIN LICENSE BLOCK ***** 17 | 18 | Copyright © 2020 018 19 | 20 | This file is part of Zotero. 21 | 22 | Zotero is free software: you can redistribute it and/or modify 23 | it under the terms of the GNU Affero General Public License as published by 24 | the Free Software Foundation, either version 3 of the License, or 25 | (at your option) any later version. 26 | 27 | Zotero is distributed in the hope that it will be useful, 28 | but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 | GNU Affero General Public License for more details. 31 | 32 | You should have received a copy of the GNU Affero General Public License 33 | along with Zotero. If not, see . 34 | 35 | ***** END LICENSE BLOCK ***** 36 | */ 37 | 38 | // eslint-disable-next-line 39 | function attr(docOrElem,selector,attr,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.getAttribute(attr):null;}function text(docOrElem,selector,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.textContent:null;}function trim(content){return content.replace(/^[\xA0\s]+/gm, '').replace(/[\xA0\s]+$/gm, '').replace(/\n+/g, '\n').replace(/:\n+/g, ': ').replace(/]\n/g, ']').replace(/】\n/g, '】').replace(/\n\/\n/g, '/')} 40 | 41 | // https://aurimasv.github.io/z2csl/typeMap.xml#map-statute 42 | 43 | function detectWeb(doc, url) { 44 | return 'statute'; 45 | } 46 | 47 | function doWeb(doc, url) { 48 | scrape(doc, url); 49 | } 50 | 51 | 52 | 53 | function scrape(doc, url) { 54 | if (!url || url.length <= 0) { 55 | return; 56 | } 57 | 58 | var _doc = doc; 59 | var code = doc.querySelector('#content > div.detail_title > table > tbody span.th_title').textContent; 60 | var spcUrl = 'https://www.spc.org.cn/online/' + code.replace('/', '%252F').replace(' ', '%2520') + '/?'; 61 | ZU.processDocuments(spcUrl, (doc, url) => { 62 | var callback = (item) => { 63 | var a = _doc.querySelector('#content > div.detail_title > table > tbody > tr:nth-child(6) > td > a:nth-child(2)'); 64 | if (a) { 65 | item.attachments.push({ 66 | url: a.href, 67 | title: item.code, 68 | mimeType: 'application/pdf' 69 | }); 70 | } 71 | }; 72 | scrapeSpc(doc, url, callback); 73 | }); 74 | } 75 | 76 | function scrapeSpc(doc, url, callback) { 77 | if (!url || url.length <= 0) { 78 | return; 79 | } 80 | 81 | var itemType = detectWeb(doc, url); 82 | var item = new Zotero.Item(itemType); 83 | item.url = url; 84 | 85 | var ps = doc.querySelectorAll('#content > div.detailedinfo-main ul > li p'); 86 | for (var p of ps) { 87 | var tdTitle = p.textContent.replace(':', '').trim(); 88 | if (!p.nextElementSibling) { 89 | continue; 90 | } 91 | 92 | var tdContent= p.nextElementSibling.textContent.trim(); 93 | 94 | switch (tdTitle) { 95 | case '标准号': 96 | item.code = tdContent; 97 | break; 98 | case '标准名称': 99 | item.title = tdContent; 100 | break; 101 | case '英文名称': 102 | item.shortTitle = tdContent; 103 | break; 104 | case '出版语种': 105 | item.language = tdContent; 106 | break; 107 | case '标准状态': 108 | item.extra = tdContent; 109 | break; 110 | case '代替标准': 111 | case '替代以下标准': 112 | item.history = tdContent; 113 | break; 114 | case '实施日期': 115 | if (tdContent.length > 0) { 116 | item.dateEnacted = tdContent; 117 | } 118 | break; 119 | case '发布日期': 120 | if (!item.dateEnacted || item.dateEnacted.length === 0) { 121 | item.dateEnacted = tdContent; 122 | } 123 | break; 124 | case '标准ICS号': 125 | item.publicLawNumber = tdContent; 126 | break; 127 | case '中标分类号': 128 | item.codeNumber = tdContent; 129 | break; 130 | case '页数': 131 | item.pages = tdContent.replace(' 页', ''); 132 | break; 133 | case '起草人': 134 | for(var c of tdContent.split('、')) { 135 | item.creators.push({ 136 | lastName: c, 137 | creatorType: 'author', 138 | fieldMode: 1 139 | }); 140 | } 141 | break; 142 | case '发布部门': 143 | item.rights = tdContent; 144 | break; 145 | default: 146 | break; 147 | } 148 | 149 | //if (tdContent && tdContent.length > 0) { 150 | // abstractNote += tdTitle + ':' + tdContent + '\n'; 151 | //} 152 | } 153 | item.abstractNote = doc.querySelector('#content > div.detailedinfo-top > div.stand-detail-description').textContent.replace(/标准简介|文前页下载| |\n|\t|/g, '') 154 | .replace('读者对象:', '\n读者对象:') 155 | .replace('适用范围:暂无', ''); 156 | 157 | if (callback) { 158 | callback(item); 159 | } 160 | 161 | item.complete(); 162 | } 163 | 164 | /** BEGIN TEST CASES **/ 165 | var testCases = [ 166 | ] 167 | /** END TEST CASES **/ 168 | -------------------------------------------------------------------------------- /Spc.org.cn.js: -------------------------------------------------------------------------------- 1 | { 2 | "translatorID": "3cf79f02-f4af-4392-8b84-26c2bdae2607", 3 | "label": "spc.org.cn", 4 | "creator": "018", 5 | "target": "https?://www\\.spc\\.org\\.cn/online", 6 | "minVersion": "3.0", 7 | "maxVersion": "", 8 | "priority": 100, 9 | "inRepository": true, 10 | "translatorType": 4, 11 | "browserSupport": "gcsibv", 12 | "lastUpdated": "2020-12-28 09:47:37" 13 | } 14 | 15 | /* 16 | ***** BEGIN LICENSE BLOCK ***** 17 | 18 | Copyright © 2020 018 19 | 20 | This file is part of Zotero. 21 | 22 | Zotero is free software: you can redistribute it and/or modify 23 | it under the terms of the GNU Affero General Public License as published by 24 | the Free Software Foundation, either version 3 of the License, or 25 | (at your option) any later version. 26 | 27 | Zotero is distributed in the hope that it will be useful, 28 | but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 | GNU Affero General Public License for more details. 31 | 32 | You should have received a copy of the GNU Affero General Public License 33 | along with Zotero. If not, see . 34 | 35 | ***** END LICENSE BLOCK ***** 36 | */ 37 | 38 | // eslint-disable-next-line 39 | function attr(docOrElem,selector,attr,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.getAttribute(attr):null;}function text(docOrElem,selector,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.textContent:null;}function trim(content){return content.replace(/^[\xA0\s]+/gm, '').replace(/[\xA0\s]+$/gm, '').replace(/\n+/g, '\n').replace(/:\n+/g, ': ').replace(/]\n/g, ']').replace(/】\n/g, '】').replace(/\n\/\n/g, '/')} 40 | 41 | // https://aurimasv.github.io/z2csl/typeMap.xml#map-statute 42 | 43 | function detectWeb(doc, url) { 44 | return 'statute'; 45 | } 46 | 47 | function doWeb(doc, url) { 48 | scrapeSpc(doc, url); 49 | } 50 | 51 | function scrapeSpc(doc, url) { 52 | if (!url || url.length <= 0) { 53 | return; 54 | } 55 | 56 | var itemType = detectWeb(doc, url); 57 | var item = new Zotero.Item(itemType); 58 | item.url = url; 59 | 60 | var ps = doc.querySelectorAll('#content > div.detailedinfo-main ul > li p'); 61 | for (var p of ps) { 62 | var tdTitle = p.textContent.replace(':', '').trim(); 63 | if (!p.nextElementSibling) { 64 | continue; 65 | } 66 | 67 | var tdContent= p.nextElementSibling.textContent.trim(); 68 | 69 | switch (tdTitle) { 70 | case '标准号': 71 | item.code = tdContent; 72 | break; 73 | case '标准名称': 74 | item.title = tdContent; 75 | break; 76 | case '英文名称': 77 | item.shortTitle = tdContent; 78 | break; 79 | case '出版语种': 80 | item.language = tdContent; 81 | break; 82 | case '标准状态': 83 | item.extra = tdContent; 84 | break; 85 | case '代替标准': 86 | case '替代以下标准': 87 | item.history = tdContent; 88 | break; 89 | case '实施日期': 90 | if (tdContent.length > 0) { 91 | item.dateEnacted = tdContent; 92 | } 93 | break; 94 | case '发布日期': 95 | if (!item.dateEnacted || item.dateEnacted.length === 0) { 96 | item.dateEnacted = tdContent; 97 | } 98 | break; 99 | case '标准ICS号': 100 | item.publicLawNumber = tdContent; 101 | break; 102 | case '中标分类号': 103 | item.codeNumber = tdContent; 104 | break; 105 | case '页数': 106 | item.pages = tdContent.replace(' 页', ''); 107 | break; 108 | case '起草人': 109 | for(var c of tdContent.split('、')) { 110 | item.creators.push({ 111 | lastName: c, 112 | creatorType: 'author', 113 | fieldMode: 1 114 | }); 115 | } 116 | break; 117 | case '发布部门': 118 | item.rights = tdContent; 119 | break; 120 | default: 121 | break; 122 | } 123 | 124 | //if (tdContent && tdContent.length > 0) { 125 | // abstractNote += tdTitle + ':' + tdContent + '\n'; 126 | //} 127 | } 128 | item.abstractNote = doc.querySelector('#content > div.detailedinfo-top > div.stand-detail-description').textContent.replace(/标准简介|文前页下载| |\n|\t|/g, '') 129 | .replace('读者对象:', '\n读者对象:') 130 | .replace('适用范围:暂无', ''); 131 | 132 | item.complete(); 133 | } 134 | 135 | /** BEGIN TEST CASES **/ 136 | var testCases = [ 137 | { 138 | "type": "web", 139 | "url": "https://www.spc.org.cn/online/GB%252FT%252028039-2011/?", 140 | "items": [ 141 | { 142 | "itemType": "statute", 143 | "nameOfAct": "中国人名汉语拼音字母拼写规则", 144 | "creators": [ 145 | { 146 | "lastName": "厉兵", 147 | "creatorType": "author", 148 | "fieldMode": 1 149 | }, 150 | { 151 | "lastName": "史定国", 152 | "creatorType": "author", 153 | "fieldMode": 1 154 | }, 155 | { 156 | "lastName": "苏培成", 157 | "creatorType": "author", 158 | "fieldMode": 1 159 | }, 160 | { 161 | "lastName": "李乐毅", 162 | "creatorType": "author", 163 | "fieldMode": 1 164 | }, 165 | { 166 | "lastName": "万锦堃", 167 | "creatorType": "author", 168 | "fieldMode": 1 169 | } 170 | ], 171 | "dateEnacted": "2012-02-01", 172 | "abstractNote": "适用范围:本标准规定了使用汉语拼音字母拼写中国人名的规则,包括汉语人名的拼写规则和少数民族语人名的拼写规则。为了满足应用需要,同时给出了一些特殊场合的变通处理办法。本标准适用于文化教育、编辑出版、中文信息处理及其他方面的中国人名汉语拼音字母拼写。\n读者对象:文化教育、编辑出版、中文信息处理及其他方面的人员。", 173 | "code": "GB/T 28039-2011", 174 | "codeNumber": "A14", 175 | "extra": "现行", 176 | "language": "中文简体", 177 | "pages": "8 页", 178 | "publicLawNumber": "01.140.10", 179 | "rights": "中华人民共和国国家质量监督检验检疫总局、中国国家标准化管理委员会", 180 | "shortTitle": "The Chinese phonetic alphabet spelling rules for Chinese names", 181 | "url": "https://www.spc.org.cn/online/GB%252FT%252028039-2011/?", 182 | "attachments": [], 183 | "tags": [], 184 | "notes": [], 185 | "seeAlso": [] 186 | } 187 | ] 188 | }, 189 | { 190 | "type": "web", 191 | "url": "https://www.spc.org.cn/online/ISO%252081060-1%2520ed1.0%2520EN/", 192 | "items": [ 193 | { 194 | "itemType": "statute", 195 | "nameOfAct": "Non-invasive sphygmomanometers -- Part 1: Requirements and test methods for non-automated measurement type", 196 | "creators": [], 197 | "dateEnacted": "2011-12-17", 198 | "code": "ISO 81060-1 ed1.0 EN", 199 | "extra": "现行", 200 | "language": "EN", 201 | "pages": "37 页", 202 | "publicLawNumber": "11.040.10", 203 | "rights": "ISO", 204 | "url": "https://www.spc.org.cn/online/ISO%252081060-1%2520ed1.0%2520EN/", 205 | "attachments": [], 206 | "tags": [], 207 | "notes": [], 208 | "seeAlso": [] 209 | } 210 | ] 211 | } 212 | ] 213 | /** END TEST CASES **/ 214 | -------------------------------------------------------------------------------- /Jd.js: -------------------------------------------------------------------------------- 1 | { 2 | "translatorID": "30ad4aab-a919-49fc-82ac-58b9d45eceb8", 3 | "label": "Jd", 4 | "creator": "018", 5 | "target": "^https?://(search|item)\\.jd\\.com/", 6 | "minVersion": "3.0", 7 | "maxVersion": "", 8 | "priority": 100, 9 | "inRepository": true, 10 | "translatorType": 4, 11 | "browserSupport": "gcsibv", 12 | "lastUpdated": "2021-09-30 03:20:22" 13 | } 14 | 15 | /* 16 | ***** BEGIN LICENSE BLOCK ***** 17 | 18 | Copyright © 2020 018 19 | 20 | This file is part of Zotero. 21 | 22 | Zotero is free software: you can redistribute it and/or modify 23 | it under the terms of the GNU Affero General Public License as published by 24 | the Free Software Foundation, either version 3 of the License, or 25 | (at your option) any later version. 26 | 27 | Zotero is distributed in the hope that it will be useful, 28 | but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 | GNU Affero General Public License for more details. 31 | 32 | You should have received a copy of the GNU Affero General Public License 33 | along with Zotero. If not, see . 34 | 35 | ***** END LICENSE BLOCK ***** 36 | */ 37 | 38 | // eslint-disable-next-line 39 | function attr(docOrElem,selector,attr,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.getAttribute(attr):null;}function text(docOrElem,selector,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.textContent:null;}function trim(content){return content.replace(/^[\xA0\s]+/gm, '').replace(/[\xA0\s]+$/gm, '').replace(/\n+/g, '\n').replace(/:\n+/g, ': ').replace(/]\n/g, ']').replace(/】\n/g, '】').replace(/\n\/\n/g, '/')} 40 | // eslint-disable-next-line 41 | function getContentsFromURL(url){var xmlhttp=new XMLHttpRequest();xmlhttp.open("GET",url,false);xmlhttp.overrideMimeType("application/json");xmlhttp.send(null);return xmlhttp.responseText;} 42 | 43 | // https://aurimasv.github.io/z2csl/typeMap.xml#map-statute 44 | 45 | function detectWeb(doc, url) { 46 | if (url.includes('item')) { 47 | return 'book'; 48 | } else if (url.includes('search')) { 49 | return 'multiple'; 50 | } 51 | return ''; 52 | } 53 | 54 | function getSearchResults(doc) { 55 | var items = {}; 56 | var found = false; 57 | var rows = doc.querySelectorAll('#J_goodsList > ul:nth-child(1) > li.gl-item'); 58 | // Z.debug(rows.length); 59 | for (let row of rows) { 60 | let a = row.querySelector('.p-name a'); 61 | if (!a) { 62 | continue; 63 | } 64 | 65 | let em = a.querySelector('em'); 66 | var title = em.textContent.trim(); 67 | var url = a.href 68 | 69 | items[url] = title; 70 | } 71 | return items; 72 | } 73 | 74 | function doWeb(doc, url) { 75 | if (detectWeb(doc, url) == "multiple") { 76 | Zotero.selectItems(getSearchResults(doc), function (items) { 77 | // Z.debug(items); 78 | if (items) { 79 | ZU.processDocuments(Object.keys(items), scrapeSpc); 80 | } 81 | }); 82 | } 83 | else { 84 | scrapeSpc(doc, url); 85 | } 86 | } 87 | 88 | function scrapeSpc(document, url) { 89 | if (!url || url.length <= 0) { 90 | return; 91 | } 92 | 93 | var itemType = detectWeb(document, url); 94 | var newItem = new Zotero.Item(itemType); 95 | newItem.url = url; 96 | 97 | // 标题 98 | var title = document.querySelector('div.sku-name'); 99 | if (title) { 100 | newItem.title = title.innerText.trim(); 101 | } 102 | 103 | // 又名 104 | newItem.shortTitle = ''; 105 | 106 | // 作者 107 | var au = document.querySelector('#p-author'); 108 | if (au) { 109 | var authors = au.innerText.replace('著', '').trim().split(','); 110 | for (var a of authors) { 111 | newItem.creators.push({ 112 | lastName: a, 113 | creatorType: 'author', 114 | fieldMode: 1 115 | }); 116 | } 117 | } 118 | 119 | var sku; 120 | var describe = document.querySelector('div.p-parameter > ul'); 121 | if (describe) { 122 | var infos = describe.innerText; 123 | infos = infos.replace(/^[\xA0\s]+/gm, '') 124 | .replace(/[\xA0\s]+$/gm, '') 125 | .replace(/\n+/g, '\n') 126 | .replace(/:\n+/g, ': ') 127 | .replace(/]\n/g, ']') 128 | .replace(/】\n/g, '】') 129 | .replace(/\n\/\n/g, '/'); 130 | for (var section of Object.values(infos.split('\n'))) { 131 | if (!section || section.trim().length <= 0) continue; 132 | 133 | let index = section.indexOf(':'); 134 | if (index <= -1) continue; 135 | 136 | let key = section.substr(0, index).trim(); 137 | let value = section.substr(index + 1).trim(); 138 | switch (key) { 139 | case "ISBN": 140 | newItem.ISBN = value; 141 | break; 142 | case "出版社": 143 | newItem.publisher = value; 144 | break; 145 | case "品牌": 146 | if (!newItem.publisher) { 147 | newItem.publisher = value; 148 | } 149 | break; 150 | case "丛书名": 151 | newItem.series = value; 152 | break; 153 | case "出版时间": 154 | newItem.date = value; 155 | break; 156 | case "页数": 157 | newItem.numPages = value; 158 | break; 159 | case "商品编码": 160 | sku = value; 161 | break; 162 | } 163 | } 164 | } 165 | 166 | // 中图clc作为标签,需要安装油猴插件:https://greasyfork.org/zh-CN/scripts/408682 167 | var clc = text(document, '#clc'); 168 | if (clc) { 169 | newItem.archiveLocation = clc; 170 | } 171 | var subject = text(document, '#subject'); 172 | if (subject) { 173 | newItem.archive = subject; 174 | } 175 | 176 | // 简介 177 | var descrip = document.querySelector('[text="内容简介"] div.book-detail-content'); 178 | if (descrip) { 179 | newItem.abstractNote = descrip.innerText; 180 | } else if(sku) { 181 | var json = getContentsFromURL('https://dx.3.cn/desc/' + sku + '?encode=utf-8'); 182 | var showdesc = function(json) { 183 | var parser = new DOMParser() 184 | var xml = parser.parseFromString(json.content, 'text/html') 185 | var content = xml.querySelector('[text="内容简介"] .book-detail-content') 186 | if (content) { 187 | newItem.abstractNote = content.innerText; 188 | } 189 | }; 190 | eval(json); 191 | } 192 | 193 | newItem.complete(); 194 | } 195 | 196 | 197 | /** BEGIN TEST CASES **/ 198 | var testCases = [ 199 | { 200 | "type": "web", 201 | "url": "https://search.jd.com/Search?keyword=9787300256535&shop=1&click=1", 202 | "items": "multiple" 203 | }, 204 | { 205 | "type": "web", 206 | "url": "https://item.jd.com/12947770.html", 207 | "items": [ 208 | { 209 | "itemType": "book", 210 | "title": "个人理财(第11版)(金融学译丛)", 211 | "creators": [ 212 | { 213 | "lastName": "E.托马斯•", 214 | "creatorType": "author", 215 | "fieldMode": 1 216 | }, 217 | { 218 | "lastName": "加曼", 219 | "creatorType": "author", 220 | "fieldMode": 1 221 | }, 222 | { 223 | "lastName": "雷蒙德•", 224 | "creatorType": "author", 225 | "fieldMode": 1 226 | }, 227 | { 228 | "lastName": "E.福格", 229 | "creatorType": "author", 230 | "fieldMode": 1 231 | } 232 | ], 233 | "date": "2020-08-01", 234 | "ISBN": "9787300256535", 235 | "abstractNote": "《个人理财》时刻提醒读者记住一句至理名言:努力工作、学习、储蓄和投资,并且做好个人理财规划。\n本书修订至第11版,已成为世界范围内极有影响力的、知名的个人理财类图书。以“做什么、何时做以及怎样做”为主线,在个人理财方面为你出谋划策,指引你迈向成功。\n本书18章,分为五个部分,即理财规划、现金管理、收入和资产保护、投资以及退休和遗产规划。每个章节都力图阐述一些理财基本准则,以帮助读者在有生之年更好地进行个人理财。本修订版每章课后都安排了实践活动,新增了朱莉娅理财之旅连载故事,她成功的理财生涯贯穿整个具有挑战性的经济时期,在其故事的尾声,留给读者一个具有挑战性的问题: 根据她的想法,提出你的建议。\n《个人理财》(第11版)包括30多个新主题,新增100多个文本框、数十个新的名词以及海量的新扩展信息。新版本把个人理财中的各个知识碎片有机地连接起来,形成了一个具有全局性的知识体系,向读者展示了个人理财知识之间的内在联系。最后,预祝本书所有的读者都获得成功!", 236 | "libraryCatalog": "Jd", 237 | "numPages": "680", 238 | "publisher": "中国人民大学出版社", 239 | "series": "金融学译丛", 240 | "url": "https://item.jd.com/12947770.html", 241 | "attachments": [], 242 | "tags": [], 243 | "notes": [], 244 | "seeAlso": [] 245 | } 246 | ] 247 | } 248 | ] 249 | /** END TEST CASES **/ 250 | -------------------------------------------------------------------------------- /Dangdang.js: -------------------------------------------------------------------------------- 1 | { 2 | "translatorID": "ec98c7f1-1f76-43d1-a5fd-fc36428fba58", 3 | "label": "Dangdang", 4 | "creator": "018", 5 | "target": "^https?://(product|search)\\.dangdang\\.com/", 6 | "minVersion": "3.0", 7 | "maxVersion": "", 8 | "priority": 100, 9 | "inRepository": true, 10 | "translatorType": 4, 11 | "browserSupport": "gcsibv", 12 | "lastUpdated": "2022-01-24 06:22:02" 13 | } 14 | 15 | /* 16 | ***** BEGIN LICENSE BLOCK ***** 17 | 18 | Copyright © 2020 018 19 | 20 | This file is part of Zotero. 21 | 22 | Zotero is free software: you can redistribute it and/or modify 23 | it under the terms of the GNU Affero General Public License as published by 24 | the Free Software Foundation, either version 3 of the License, or 25 | (at your option) any later version. 26 | 27 | Zotero is distributed in the hope that it will be useful, 28 | but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 | GNU Affero General Public License for more details. 31 | 32 | You should have received a copy of the GNU Affero General Public License 33 | along with Zotero. If not, see . 34 | 35 | ***** END LICENSE BLOCK ***** 36 | */ 37 | 38 | // eslint-disable-next-line 39 | function attr(docOrElem,selector,attr,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.getAttribute(attr):null;}function text(docOrElem,selector,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.textContent:null;}function trim(content){return content.replace(/^[\xA0\s]+/gm, '').replace(/[\xA0\s]+$/gm, '').replace(/\n+/g, '\n').replace(/:\n+/g, ': ').replace(/]\n/g, ']').replace(/】\n/g, '】').replace(/\n\/\n/g, '/')} 40 | // eslint-disable-next-line 41 | function getContentsFromURL(url){try{var xmlhttp=new XMLHttpRequest();xmlhttp.open("GET",url,false);xmlhttp.overrideMimeType("application/json");xmlhttp.send(null);return xmlhttp.responseText;}catch(e){}} 42 | 43 | // https://aurimasv.github.io/z2csl/typeMap.xml#map-statute 44 | 45 | function detectWeb(doc, url) { 46 | if (url.includes('product')) { 47 | return 'book'; 48 | } else if (url.includes('search')) { 49 | return 'multiple'; 50 | } 51 | return ''; 52 | } 53 | 54 | 55 | function getSearchResults(doc) { 56 | var items = {}; 57 | var found = false; 58 | var rows = doc.querySelectorAll('#search_nature_rg ul li'); 59 | Z.debug('rows: ' + rows.length); 60 | for (let row of rows) { 61 | let a = row.querySelector('a'); 62 | if (!a) { 63 | continue; 64 | } 65 | 66 | var title = a.title.replace(/【.*】/g, ''); 67 | var url = a.href 68 | 69 | items[url] = title; 70 | } 71 | return items; 72 | } 73 | 74 | function doWeb(doc, url) { 75 | if (detectWeb(doc, url) == "multiple") { 76 | Zotero.selectItems(getSearchResults(doc), function (items) { 77 | // Z.debug(items); 78 | if (items) { 79 | ZU.processDocuments(Object.keys(items), scrapeSpc); 80 | } 81 | }); 82 | } 83 | else { 84 | scrapeSpc(doc, url); 85 | } 86 | } 87 | 88 | function scrapeSpc(document, url) { 89 | if (!url || url.length <= 0) { 90 | return; 91 | } 92 | 93 | var itemType = detectWeb(document, url); 94 | var newItem = new Zotero.Item(itemType); 95 | newItem.url = url; 96 | 97 | // 标题 98 | var title = document.querySelector('#product_info > div.name_info > h1'); 99 | if (title) { 100 | newItem.title = title.title; 101 | } 102 | 103 | // 又名 104 | newItem.shortTitle = ''; 105 | 106 | // 作者 107 | var au = document.querySelector('#author'); 108 | if (au) { 109 | var authors = au.innerText.replace('作者:', '').split(','); 110 | for (var a of authors) { 111 | newItem.creators.push({ 112 | lastName: a, 113 | creatorType: 'author', 114 | fieldMode: 1 115 | }); 116 | } 117 | } 118 | 119 | var lis = document.querySelectorAll('#detail_describe > ul li'); 120 | if (lis) { 121 | for (var li of lis) { 122 | if (li) { 123 | var section = li.innerText; 124 | let index = section.indexOf(':'); 125 | if (index <= -1) continue; 126 | 127 | let key = section.substr(0, index).trim(); 128 | let value = section.substr(index + 1).trim(); 129 | switch (key) { 130 | case "国际标准书号ISBN": 131 | newItem.ISBN = value; 132 | break; 133 | case "丛书名": 134 | newItem.series = value; 135 | break; 136 | } 137 | } 138 | } 139 | } 140 | 141 | // 页数 142 | newItem.numPages = ''; 143 | 144 | // 出版社 145 | var pub = document.querySelector('a[dd_name="出版社"]'); 146 | if (pub) { 147 | newItem.publisher = pub.innerText; 148 | } 149 | 150 | // 出版年 151 | var date = document.querySelector('#product_info > div.messbox_info > span:nth-child(3)'); 152 | if (date) { 153 | newItem.date = date.innerText.replace(/出版时间:/, '').trim(); 154 | } 155 | 156 | // 简介 157 | var descrip = document.querySelector('#content > div.descrip'); 158 | if (descrip) { 159 | newItem.abstractNote = descrip.innerText; 160 | } else { 161 | var element = Object.values(document.scripts).find(element => element.textContent.includes('prodSpuInfo')) 162 | if (element) { 163 | var pattern = /var prodSpuInfo = {.+}/ 164 | if (pattern.test(element.textContent)) { 165 | Z.debug(pattern.exec(element.textContent)[0]) 166 | eval(pattern.exec(element.textContent)[0]); 167 | if (prodSpuInfo) { 168 | var productId = prodSpuInfo.productId 169 | var categoryPath = prodSpuInfo.categoryPath 170 | var describeMap = prodSpuInfo.describeMap 171 | var template = prodSpuInfo.template 172 | var shopId = prodSpuInfo.shopId 173 | var url0 = 'http://product.dangdang.com/index.php?r=callback%2Fdetail&productId=' + productId + 174 | '&templateType=' + template + '&describeMap=' + encodeURIComponent(describeMap) + '&shopId=' + shopId + '&categoryPath=' + categoryPath 175 | 176 | var json = getContentsFromURL(url0); 177 | if (json) { 178 | var parser = new DOMParser() 179 | var xml = parser.parseFromString(JSON.parse(json).data.html, 'text/html') 180 | var content = xml.querySelector('#content') 181 | if (content) { 182 | newItem.abstractNote = content.innerText; 183 | } 184 | } 185 | } 186 | } 187 | } 188 | } 189 | 190 | // 中图clc作为标签,需要安装油猴插件:https://greasyfork.org/zh-CN/scripts/408682 191 | var clc = text(document, '#clc'); 192 | if (clc) { 193 | newItem.archiveLocation = clc; 194 | } 195 | var subject = text(document, '#subject'); 196 | if (subject) { 197 | newItem.archive = subject; 198 | } 199 | 200 | var span1 = document.querySelector('span[dd_name="全部评论"]'); 201 | var span2 = document.querySelector('span[dd_name="好评"]'); 202 | if( span1 && span2 && span1.innerText.match(/\d+/g) && span2.innerText.match(/\d+/g)) { 203 | newItem.extra = span1.innerText.match(/\d+/g) + '/' + span2.innerText.match(/\d+/g); 204 | } 205 | newItem.complete(); 206 | } 207 | 208 | 209 | 210 | 211 | 212 | /** BEGIN TEST CASES **/ 213 | var testCases = [ 214 | { 215 | "type": "web", 216 | "url": "http://product.dangdang.com/29113890.html", 217 | "items": [ 218 | { 219 | "itemType": "book", 220 | "title": "个人理财(第11版)(金融学译丛)", 221 | "creators": [ 222 | { 223 | "lastName": "E.托马斯?加曼 雷蒙德?E.福格", 224 | "creatorType": "author", 225 | "fieldMode": 1 226 | } 227 | ], 228 | "date": "2020年08月", 229 | "ISBN": "9787300256535", 230 | "abstractNote": "《个人理财》时刻提醒读者记住一句至理名言:努力工作、学习、储蓄和投资,并且做好个人理财规划。\n本书修订至第11版,已成为世界范围内极有影响力的、知名的个人理财类图书。以“做什么、何时做以及怎样做”为主线,在个人理财方面为你出谋划策,指引你迈向成功。\n本书18章,分为五个部分,即理财规划、现金管理、收入和资产保护、投资以及退休和遗产规划。每个章节都力图阐述一些理财基本准则,以帮助读者在有生之年更好地进行个人理财。本修订版每章课后都安排了实践活动,新增了朱莉娅理财之旅连载故事,她成功的理财生涯贯穿整个具有挑战性的经济时期,在其故事的尾声,留给读者一个具有挑战性的问题: 根据她的想法,提出你的建议。\n《个人理财》(第11版)包括30多个新主题,新增100多个文本框、数十个新的名词以及海量的新扩展信息。新版本把个人理财中的各个知识碎片有机地连接起来,形成了一个具有全局性的知识体系,向读者展示了个人理财知识之间的内在联系。*后,预祝本书所有的读者都获得成功!", 231 | "extra": "52/52", 232 | "libraryCatalog": "Dangdang", 233 | "publisher": "中国人民大学出版社", 234 | "series": "金融学译丛", 235 | "url": "http://product.dangdang.com/29113890.html", 236 | "attachments": [], 237 | "tags": [], 238 | "notes": [], 239 | "seeAlso": [] 240 | } 241 | ] 242 | }, 243 | { 244 | "type": "web", 245 | "url": "http://search.dangdang.com/?key=9787300256535&act=input", 246 | "items": "multiple" 247 | } 248 | ] 249 | /** END TEST CASES **/ 250 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 道格学社 2 | 3 | [知识管理训练营](https://mp.weixin.qq.com/s/2VzC1RMzwLij4NMaJm3EoQ)感谢每一位同学们的贡献!因为你们,Zotero会在中文世界会爆发出难以估量的潜力。我们每位学员知识与情报管理方式、智识生产的效率会发生天翻地覆的变化。 4 | 5 | > 知识的岛屿越大,无知的海岸线越长 6 | 7 | 我们的愿景是:群策群力,教学相长,**共建、共用中文世界最顶级的信息源。** 8 | 9 | 祝Zotero官方早日合并诸位的代码。 10 | 11 | - 致谢:01期学员[Felix](https://github.com/xuwd/translators)、02期学员[018](https://github.com/018/translators)、3期学员五弦琴。感谢他们贡献的脚本、插件和工具。 12 | 13 | ## A 课程核心资源与工具列表 14 | 15 | 16 | 1. **Translators** 17 | 18 | | 序号 |Translator     | 贡献者   | 备注 | 19 | | ---- | ------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | 20 | | 1 | douban.js | [Felix](https://github.com/xuwd)/[018](https://github.com/018) | 支持「[豆瓣](https://www.douban.com/)」标签下的图书批量抓取,图书评分/评价人数抓取,抓取框显示评分/评价人数(√ ),豆瓣电影单抓和批量,支持短标题,支持抓取CLC分类(需要配合油猴)等 | 21 | | 2 | BiliBili.js | [Felix](https://github.com/xuwd) | 支持「[B站](https://www.bilibili.com/)」视频单抓和批量,元数据包含:摘要、集数、节目名称、时长。
支持「[B站](https://www.bilibili.com/)」Bangumi内纪录片单抓和批量,元数据包含:摘要、集数、节目名称、时长 | 22 | | 3 | Ncpssd.js | [018](https://github.com/018) | 支持「[国家哲学社会科学文献中心](http://www.ncpssd.org/)」论文题录与PDF的单抓和批量 | 23 | | 4 | Superlib.js | [018](https://github.com/018/translators) | 支持「[全国图书馆参考咨询联盟](http://www.ucdrs.superlib.net/)」图书、会议论文、学位论文、期刊、专利。支持单抓和批量。批量抓取可能会失败,可以单抓或隔几个小时试试 | 24 | | 5 | cnki.js | [018](https://github.com/018) | 适配[中国知网](https://www.cnki.net/)改版页面,合并中文姓、名为创建者。获取知网引用数,显示在其他栏。 | 25 | | 6 | Nlc.cn.js | [018](https://github.com/018) | 注册[国家图书馆](http://read.nlc.cn/outRes/outResList?type=%E6%A0%87%E5%87%86%E4%B8%93%E5%88%A9)之后,可以下载「中国标准在线服务网」内的国家标准 | 26 | | 7. | Spc.org.cn.js | [018](https://github.com/018) | 抓取[中国标准在线服务网](https://www.spc.org.cn/index)元数据 | 27 | | 8. | jd.js | [018](https://github.com/018) | [京东](https://book.jd.com/)图书条目抓取 | 28 | | 9. | dangdang.js | [018](https://github.com/018) | [当当](http://book.dangdang.com/)图书条目抓取 | 29 | | 10. | uRead.js | [018](https://github.com/018) | [今日优读](http://uread.today/)数据抓取 | 30 | 31 | 2. **Tampermonkey脚本** 32 | 33 | | 序号 | 脚本下载地址 | 贡献者 | 备注 | 34 | | ---- | ------------------------------------------------------------ | ----------------------------------------- | ------------------------------------------------------------ | 35 | | 1 | [豆瓣中图分类法](https://greasyfork.org/zh-CN/scripts/408682) | [018](https://github.com/018/translators) | 如果存在中图分类,则会在豆瓣信息栏中多显示如“中图分类: B842.1 (B84 心理学 ▸ B842 心理过程、心理状态 ▸ B842.1 认知)”,方便对图书进行分类。 | 36 | | 2 | [全图联盟](https://greasyfork.org/zh-CN/scripts/408790-) | [018](https://github.com/018/translators) | 下载DPF少操作一步,「文章下载」替换成「PDF下载」,点击直接下载。也可辅助Zotero translator的Superlib.js,直接抓取PDF。增加图书的中图法分类功能。 | 37 | | 3. | [知了](https://greasyfork.org/zh-CN/scripts/419901-%E7%9F%A5%E4%BA%86) | [018](https://github.com/018/translators) | 在知网页面跳转、直接阅读和下载「社科论文」。使用需要注册并登陆「[国家哲学社会科学学术期刊数据库(NSSD)](http://www.ncpssd.org/) 」 | 38 | 39 | 3. **Zotero插件** 40 | 41 | | 序号 | 插件下载地址 |贡献者     | 备注 | 42 | | ---- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | 43 | | 1 | [zotcard](https://github.com/018/zotcard) | [018](https://github.com/018) | zotcard是一个快速写卡片,提供格式卡模板
1.提供六种预设格式卡:概念卡、人物卡、通用卡等,只需一步即可直接写卡。可自行调整
2.提个6个卡槽定制卡片内容,可自行调整。
3.可批量替换卡片内容
4.卡批量打开浮动编辑窗口,调整窗口方便拼卡成文。
5.可批量建卡 | 44 | | 2 | [zoturead](https://github.com/018/zoturead) | [018](https://github.com/018) | [今日优读](http://uread.today),帮助你更快学习。
1.更新豆瓣评分与知网引用数
2.自动图书目录
3.批量整理条目信息
4.下载试读、版权页和电子书
5.初始化学科分类或者中图分类
6.一键更新 Translator
7.今日优读网站相关:批量转化为今日优读,添加目录对比等等。
8.高级搜索:快速搜索今日优读、Zotero、豆瓣、全图联盟、京东、当当等。
9.辅助工具:修复中图分类号、学科号,根据学科号归档,定位书籍所在分类目录。 | 45 | | 3 | zotupdate | [018](https://github.com/018) | 功能已被整合进入zoturead | 46 | 47 | 4. 网页工具 48 | 49 | | 序号 | 网页 | 贡献者     | 备注 | 50 | | ---- | ------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------- | 51 | | 1 | [今日优读](http://uread.today/) | [018](https://github.com/018) | 1.快速目录对比
2.整合图书信息
3.提供电子书下载 | 52 | 53 | ## B. 友情链接 54 | 55 | | 序号 | 资源仓库 | 贡献者   | 备注 | 56 | | ---- | ------------------------------------------------------------ | ----------------------------------------------------------- | ------------------------------------------------------------ | 57 | | 1 | [职业生涯拓荒营](https://github.com/gezhongran/KM-Career) | 全体拓荒营学员 | 整理职业资源相关信息,记录拓荒过程,日志、报告,构建小型的职业情报信息中心。 | 58 | | 2 | [投资理财拓荒营](https://github.com/gezhongran/KM-Personal-Finance) | 全体拓荒营学员 | 整理个人财务管理相关信息,记录拓荒过程,日志、报告,构建小型的职业情报信息中心。 | 59 | | 3. | [积极心理学拓荒营](https://github.com/gezhongran/KM-Positive-Psychology) | 全体拓荒营学员 | 整理积极心理学相关信息,记录拓荒过程,日志、报告,构建小型的职业情报信息中心。 | 60 | 61 | ## C.彩蛋资源 62 | 63 | 1. **豆列书单清单** 64 | 65 | | 序号 | 以下豆列均由道格老师使用zotero进行图情分析和整理 | 66 | | ---- | ------------------------------------------------------------ | 67 | | 1 | [知识管理训练营专属礼物01(认知心理学)](https://www.douban.com/doulist/130393452/) | 68 | | 2 | [知识管理训练营专属礼物02(图书馆情报学)](https://www.douban.com/doulist/130592882/) | 69 | | 3 | [物理8.5](https://www.douban.com/doulist/129875523/ ) | 70 | | 4 | [数学9.0](https://www.douban.com/doulist/129808399/ ) | 71 | | 5 | [建筑/建筑史8.5]( https://www.douban.com/doulist/129807622/ ) | 72 | | 6 | [人类学8.5](https://www.douban.com/doulist/130013462/ ) | 73 | | 7 | [儿童文学9.0]( https://www.douban.com/doulist/130087268/ ) | 74 | | 8 | [个人财务管理(金融、投资、理财)](https://www.douban.com/doulist/134957534/) | 75 | | 9 | [个人理财、投资、金融(教材for目录对比)](https://www.douban.com/doulist/135952740/) | 76 | | 10 | [职业生涯管理](https://www.douban.com/doulist/131340410/) | 77 | 78 | 79 | --- 80 | **欢迎关注公众号:** 81 | 82 | ![欢迎关注公众号](https://tva1.sinaimg.cn/large/007S8ZIlgy1ghqq4mtus1j3076076wey.jpg) 83 | 84 | --- 85 | 86 | ### changelog: 87 | 88 | - 2022.02.22 更新Zotucard适配Zotero 6.0。暂时去掉功能:图片压缩、调整笔记行间距、调整笔记段间距、调整更换笔记背景。添加功能:默认卡模版的标题改为标题1、添加调整浮动窗口设置高度、添加批量建卡、添加笔记源代码。 89 | 90 | - 2022.02.14 更新Zoturead适配Zotero 6.0。 91 | 92 | - 2022.02.09 更新Douban.js,添加对[豆瓣游戏](https://www.douban.com/game/explore)页面的支持,包含批量和单抓。删除信息源网站连接。 93 | 94 | - 2021.12.27 修复Douban.js在标签下批量抓取失败问题。 95 | 96 | - 2021.12.14 Zotcard1.9.1发布添加卡片打印功能 97 | 98 | - 2021.11.17 更新Douban.js多选书籍时在书籍后面显示出版日期。uread.js修复了在搜索和优书的批量抓取。zoturead v1.3.0 发布,合并zotupdate插件功能 99 | 100 | - 2021.09.29 更新Jd.js, Douban.js,Dangdang.js,Superlib.js,配合[豆瓣中图分类法](https://greasyfork.org/zh-CN/scripts/408682)插件,直接抓中图分类号和学科分类号。 101 | 102 | - 2021.08.18 更新Cnki.js,增加知网通配性,适配“cnki-net”的图书馆代理下载、添加今日优读 103 | 104 | - 2021.08.08 添加ZotRead插件与uRead.js、更新优质信息源清单 105 | 106 | - 2021.08.01 Douban.js更新,品牌与出版社拆分,如“万千心理|中国轻工业出版社”,“万千心理”被放入“版权”元数据 107 | 108 | - 2021.07.15 更新使用说明、zotcard插件功能更新 109 | 110 | - 2021.04.19 修复ncpssd.js获取PDF Bug与修复Jd.js批量抓取时显示图书条目Bug 111 | 112 | - 2021.04.08 删除在线卡片制作工具 113 | 114 | - 2021.03.25 知了 v0.2.0 更新:改为只搜索国家哲学社会科学学术期刊数据库。zotupdate v1.0.7更新:完善拉目录机制,默认找不到目录会从京东查找,京东没有时从当当上查找。(当当只能拉去一半的目录,得自己补全。) 115 | 116 | - 2021.03.25 更新Jd.js和dangdang.js支持搜索时批量抓取,但当当批量时无法抓取摘要。 117 | 118 | - 2021.03.24 添加Jd.js和dangdang.js当前支持图书条目单抓,添加资源清单 119 | 120 | - 2021.02.20 添加理财拓荒营地址、更新其他资源 121 | 122 | - 2021.02.13 添加新豆列 123 | 124 | - 2021.01.19 修复Cnki.js的Bug 125 | 126 | - 2021.01.09 添加「知了」脚本 127 | 128 | - 2021.01.08 更新Cnki.js,可以获取知网的引用数 129 | 130 | - 2021.01.07 合并bilibili.js与bilibili bangumi.js,原先两个translators的功能可以由一个bilibili.js完成 131 | 132 | - 2020.12.28 添加Spc.org.cn.js,可以中国标准在线服务网元数据 133 | 134 | - 2020.12.28 添加 nlc.cn.js,可以抓取国图内标准在线网的标准一级下载 135 | 136 | - 2020.12.19 修复Douban.js的bug:当没有「展开全部时」,摘要部分抓取作者简介 137 | 138 | - 2020.11.13 更新zotero插件zotcard资源 139 | 140 | - 2020.10.27 更新zotero插件zotupdate资源 141 | 142 | - 2020.09.09 添加CNKI.js:1.适配知网改版后的页面 2.合并显示中文作者的「姓与名」。更新douban.js:更新superlib.js:「存档位置」可以抓取中图法分类 143 | 144 | - 2020.08.31 添加在线卡片制作工具 145 | 146 | - 2020.08.24 添加优质信息源-国研网、中经网、国家图书馆、职级对标,新增豆列清单 147 | 148 | - 2020.08.15 添加油猴superlib脚本,添加学员git仓库连接,彩蛋优质信息源整理,添加微词云 149 | 150 | - 2020.08.14 创建仓库,添加初始资源 151 | 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /uRead.js: -------------------------------------------------------------------------------- 1 | { 2 | "translatorID": "c32e2c38-e319-4c94-ab2e-7a0564147ec2", 3 | "label": "uRead", 4 | "creator": "018", 5 | "target": "https?://uread.today/((ubook)|(book)|(search))", 6 | "minVersion": "3.0", 7 | "maxVersion": "", 8 | "priority": 100, 9 | "inRepository": true, 10 | "translatorType": 4, 11 | "browserSupport": "gcsibv", 12 | "lastUpdated": "2021-11-24 07:21:19" 13 | } 14 | 15 | /* 16 | ***** BEGIN LICENSE BLOCK ***** 17 | 18 | Copyright © 2021 018 19 | 20 | This file is part of Zotero. 21 | 22 | Zotero is free software: you can redistribute it and/or modify 23 | it under the terms of the GNU Affero General Public License as published by 24 | the Free Software Foundation, either version 3 of the License, or 25 | (at your option) any later version. 26 | 27 | Zotero is distributed in the hope that it will be useful, 28 | but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 | GNU Affero General Public License for more details. 31 | 32 | You should have received a copy of the GNU Affero General Public License 33 | along with Zotero. If not, see . 34 | 35 | ***** END LICENSE BLOCK ***** 36 | */ 37 | 38 | function attr(docOrElem, selector, attr, index) { 39 | var elem = index ? docOrElem.querySelectorAll(selector).item(index) : docOrElem.querySelector(selector); 40 | return elem ? elem.getAttribute(attr) : null; 41 | } 42 | 43 | function text(docOrElem, selector, index) { 44 | var elem = index ? docOrElem.querySelectorAll(selector).item(index) : docOrElem.querySelector(selector); 45 | return elem ? elem.innerText : ''; 46 | } 47 | 48 | function value(docOrElem, selector, index) { 49 | var elem = index ? docOrElem.querySelectorAll(selector).item(index) : docOrElem.querySelector(selector); 50 | return elem ? elem.value : ''; 51 | } 52 | 53 | function trim(content) { 54 | return content.replace(/^[\xA0\s]+/gm, '') 55 | .replace(/[\xA0\s]+$/gm, '') 56 | .replace(/\n+/g, '\n') 57 | .replace(/:\n+/g, ': ') 58 | .replace(/]\n/g, ']') 59 | .replace(/】\n/g, '】') 60 | .replace(/\n\/\n/g, '/') 61 | } 62 | 63 | // https://aurimasv.github.io/z2csl/typeMap.xml#map-book 64 | function detectType(doc) { 65 | return 'book'; 66 | } 67 | 68 | function detectWeb(doc, url) { 69 | if (url.includes('/search') || url.includes('/ubook')) { 70 | return getSearchResults(doc, true) ? 'multiple' : false; 71 | } else { 72 | return detectType(doc); 73 | } 74 | 75 | return false; 76 | } 77 | 78 | function getSearchResults(doc, checkOnly) { 79 | var items = {}; 80 | var found = false; 81 | var rows = doc.querySelectorAll('#result-list .result-item'); 82 | for (let row of rows) { 83 | let a = row; 84 | 85 | if (checkOnly) return true; 86 | 87 | let url = a.href; 88 | 89 | let title = ZU.trimInternal(row.querySelector('.item-title').textContent); 90 | 91 | found = true; 92 | items[url] = title; 93 | } 94 | return found ? items : false; 95 | } 96 | 97 | function doWeb(doc, url) { 98 | if (detectWeb(doc, url) == "multiple") { 99 | let results = getSearchResults(doc, false); 100 | Z.debug('Zotero.selectItems results: ' + JSON.stringify(results)); 101 | Zotero.selectItems(results, function (items) { 102 | if (items) { 103 | Z.debug('Zotero.selectItems items: ' + JSON.stringify(items)); 104 | for (let item in items) { 105 | let u = getBookGetAPIURL(getDoi(item)); 106 | Z.debug('url: ' + u); 107 | Zotero.Utilities.HTTP.doGet(u, function (retString) { 108 | Z.debug('ret: ' + retString); 109 | scrapeJson(retString, item); 110 | }); 111 | } 112 | } else { 113 | Z.debug('Zotero.selectItems items: null'); 114 | } 115 | }); 116 | } else { 117 | scrape(doc, url); 118 | } 119 | } 120 | 121 | function scrape(doc, url) { 122 | var itemType = detectType(doc); 123 | var item = new Zotero.Item(itemType); 124 | 125 | var zoteroCapture = doc.getElementById('zotero-capture'); 126 | if (zoteroCapture && zoteroCapture.getAttribute('visibled')) { 127 | item.title = value(doc, '#zotero-title'); 128 | var creators = doc.querySelectorAll('.zotero-class-creators'); 129 | for (let creator of creators) { 130 | var creatorType = creator.querySelector('.creatorType'); 131 | var lastName = creator.querySelector('.lastName input'); 132 | item.creators.push({ 133 | lastName: lastName.value, 134 | creatorType: creatorType.getAttribute('creatorType'), 135 | fieldMode: 1 136 | }); 137 | } 138 | item.abstractNote = value(doc, '#zotero-abstractNote'); 139 | item.series = value(doc, '#zotero-series'); 140 | item.seriesNumber = value(doc, '#zotero-seriesNumber'); 141 | item.volume = value(doc, '#zotero-volume'); 142 | item.numberOfVolumes = value(doc, '#zotero-numberOfVolumes'); 143 | item.edition = value(doc, '#zotero-edition'); 144 | item.place = value(doc, '#zotero-place'); 145 | item.publisher = value(doc, '#zotero-publisher'); 146 | item.date = value(doc, '#zotero-date'); 147 | item.numPages = value(doc, '#zotero-numPages'); 148 | item.language = value(doc, '#zotero-language'); 149 | item.ISBN = value(doc, '#zotero-ISBN'); 150 | item.shortTitle = value(doc, '#zotero-shortTitle'); 151 | item.url = value(doc, '#zotero-url'); 152 | item.archive = value(doc, '#zotero-archive'); 153 | item.archiveLocation = value(doc, '#zotero-archiveLocation'); 154 | item.callNumber = value(doc, '#zotero-callNumber'); 155 | item.rights = value(doc, '#zotero-rights'); 156 | item.extra = value(doc, '#zotero-extra'); 157 | 158 | let zoteroNote1Enabled = doc.querySelector('#zotero-note1-enabled input'); 159 | if (zoteroNote1Enabled.checked) { 160 | let notes = '

初步评价

\n

'; 161 | let zoteroNote1 = doc.querySelector('#zotero-note1'); 162 | notes += zoteroNote1.value.replace(/\t/g, ' ') + '

'; 163 | 164 | item.notes.push({ 165 | note: notes 166 | }); 167 | } 168 | 169 | let zoteroNote2Enabled = doc.querySelector('#zotero-note2-enabled input'); 170 | if (zoteroNote2Enabled.checked) { 171 | let cover_url = doc.getElementById('zotero-coverurl'); 172 | let notes = '

目录

\n

'; 173 | let zoteroNote2 = doc.querySelector('#zotero-note2 textarea'); 174 | notes += zoteroNote2.value.replace(/\t/g, ' ').replace(/\n/g, '
') + '

'; 175 | 176 | item.notes.push({ 177 | note: notes 178 | }); 179 | } 180 | 181 | let zoteroNote3Enabled = doc.querySelector('#zotero-note3-enabled input'); 182 | if (zoteroNote3Enabled.checked) { 183 | let note3 = doc.getElementById('zotero-note3'); 184 | let notes = '

豆瓣短评

\n' + note3.outerHTML; 185 | item.notes.push({ 186 | note: notes 187 | }); 188 | } 189 | 190 | let zoteroTagsEnabled = doc.querySelector('#zotero-tags-enabled input'); 191 | if (zoteroTagsEnabled.checked) { 192 | var tags = doc.querySelectorAll('#zotero-tags .tag'); 193 | for (let tag of tags) { 194 | item.tags.push({ 195 | tag: tag.innerText.trim() 196 | }); 197 | } 198 | } 199 | 200 | let zoteroAttachment1Enabled = doc.querySelector('#zotero-attachment1-enabled input'); 201 | if (zoteroAttachment1Enabled && zoteroAttachment1Enabled.checked) { 202 | var a = doc.querySelector('#zotero-attachment1'); 203 | item.attachments.push({ 204 | title: a.textContent, 205 | url: a.href, 206 | linkMode: a.getAttribute('linkMode'), 207 | mimeType: a.getAttribute('mimeType') 208 | }); 209 | } 210 | let zoteroAttachment2Enabled = doc.querySelector('#zotero-attachment2-enabled input'); 211 | if (zoteroAttachment2Enabled && zoteroAttachment2Enabled.checked) { 212 | var a = doc.querySelector('#zotero-attachment2'); 213 | item.attachments.push({ 214 | title: a.textContent, 215 | url: a.href, 216 | linkMode: a.getAttribute('linkMode'), 217 | mimeType: a.getAttribute('mimeType') 218 | }); 219 | } 220 | let zoteroAttachment3Enabled = doc.querySelector('#zotero-attachment3-enabled input'); 221 | if (zoteroAttachment3Enabled && zoteroAttachment3Enabled.checked) { 222 | var a = doc.querySelector('#zotero-attachment3'); 223 | item.attachments.push({ 224 | title: a.textContent, 225 | url: a.href, 226 | linkMode: a.getAttribute('linkMode'), 227 | mimeType: a.getAttribute('mimeType') 228 | }); 229 | } 230 | } else { 231 | item.url = url; 232 | item.title = text(doc, '#title'); 233 | item.publisher = text(doc, '#publisher'); 234 | item.date = text(doc, '#date'); 235 | item.ISBN = text(doc, '#isbn'); 236 | item.numPages = text(doc, '#pages'); 237 | item.archiveLocation = text(doc, '#clcs a:last-child span:nth-child(2)'); 238 | item.archive = text(doc, '#subjects a:last-child').replace(/\D/g, ''); 239 | item.abstractNote = text(doc, '#abstractNote'); 240 | item.edition = item.title.replace(/[^(第\d+版)]/g, '').replace(/\(|\)|第|版/g, ''); 241 | 242 | var authors = doc.querySelectorAll('#author a'); 243 | for (let author of authors) { 244 | item.creators.push({ 245 | lastName: author.innerText, 246 | creatorType: 'author', 247 | fieldMode: 1 248 | }); 249 | } 250 | var translators = doc.querySelectorAll('#translator a'); 251 | for (let translator of translators) { 252 | item.creators.push({ 253 | lastName: translator.innerText, 254 | creatorType: 'translator', 255 | fieldMode: 1 256 | }); 257 | } 258 | var tags = doc.querySelectorAll('#tags a span'); 259 | for (let tag of tags) { 260 | item.tags.push(tag.innerText); 261 | } 262 | item.extra = text(doc, '#doubanscore .score-value') + '/' + (text(doc, '#doubanscore .comments-value')||'').replace(/\(|\)|[\u4e00-\u9fa5]/g, '') + '|' + text(doc, '#score') 263 | 264 | let cover_url = attr(doc, '#cover', 'src'); 265 | let u = getBookCataloguesAPIURL(getDoi(url)); 266 | Zotero.Utilities.HTTP.doGet(u, function (retString) { 267 | let ret = JSON.parse(retString); 268 | if (ret.resultcode !== 1) { 269 | return; 270 | } 271 | let notes = '

目录

\n

'; 272 | let maxtier = 1; 273 | for (let content of ret.data) { 274 | maxtier = Math.max(content.tier, maxtier); 275 | } 276 | for (let json of ret.data) { 277 | notes += ' '.repeat(json.tier - 1) + (maxtier > 1 && json.tier === 1 ? '' : '') + json.content + (maxtier > 1 && json.tier === 1 ? '' : '') + '
'; 278 | } 279 | notes += '

'; 280 | 281 | item.notes.push({ 282 | note: notes 283 | }); 284 | }); 285 | } 286 | 287 | item.complete(); 288 | } 289 | 290 | 291 | function scrapeJson(retString, url) { 292 | let ret = JSON.parse(retString); 293 | if (ret.resultcode !== 1) { 294 | return; 295 | } 296 | 297 | var item = new Zotero.Item('book'); 298 | let json = ret.data; 299 | item.url = url; 300 | item.title = json.title + (json.subtitle ? ('——' + json.subtitle) : '') + (json.edition && json.edition !== '1' && json.edition !== '一' ? `(第${json.edition}版)` : ''); 301 | item.publisher = json.publishers.join(','); 302 | item.date = json.date; 303 | item.ISBN = json.isbn; 304 | item.numPages = json.pages; 305 | item.archiveLocation = json.clc; 306 | item.archive = json.subject; 307 | item.abstractNote = json.abstract_note; 308 | item.edition = json.edition; 309 | 310 | for (let author of json.authors) { 311 | if (author.type === 1) { 312 | item.creators.push({ 313 | lastName: (author.prefix ? ('[' + author.prefix + ']') : '') + author.name, 314 | creatorType: 'author', 315 | fieldMode: 1 316 | }); 317 | } else if (author.type === 2) { 318 | item.creators.push({ 319 | lastName: author.name, 320 | creatorType: 'translator', 321 | fieldMode: 1 322 | }); 323 | } 324 | } 325 | for (let tag of json.tags) { 326 | item.tags.push(tag); 327 | } 328 | for (let score_ref of json.score_refs) { 329 | if (score_ref.domin === 'douban.com') { 330 | item.extra = score_ref.value + '/' + score_ref.comments; 331 | } 332 | } 333 | 334 | item.extra += (item.extra ? '|' : '') + json.score; 335 | 336 | let cover_url = json.cover_url; 337 | let u = getBookCataloguesAPIURL(getDoi(url)); 338 | Zotero.Utilities.HTTP.doGet(u, function (retString0) { 339 | let ret = JSON.parse(retString0); 340 | if (ret.resultcode !== 1) { 341 | return; 342 | } 343 | let notes = '

目录

\n

'; 344 | for (let json of ret.data) { 345 | notes += ' '.repeat(json.tier - 1) + (json.tier === 1 ? '' : '') + json.content + (json.tier === 1 ? '' : '') + '
'; 346 | } 347 | notes += '

'; 348 | 349 | item.notes.push({ 350 | note: notes 351 | }); 352 | }); 353 | 354 | item.complete(); 355 | } 356 | 357 | // http://uread.today/book?doi=8e141c7b94434767b62d6e2cb3caf392 358 | // http://api.uread.today/master/anon/book/get?doi=8e141c7b94434767b62d6e2cb3caf392 359 | // http://uread.today/book?doi=8e141c7b94434767b62d6e2cb3caf392 360 | // http://api.uread.today/master/anon/book/get?doi=8e141c7b94434767b62d6e2cb3caf392 361 | function getBookGetAPIURL(doi) { 362 | return `http://api.uread.today/master/anon/book/get?doi=${doi}`; 363 | } 364 | function getBookCataloguesAPIURL(doi) { 365 | return `http://api.uread.today/master/anon/book/list_catalogues?doi=${doi}`; 366 | } 367 | function getDoi(url) { 368 | if (!url) return false; 369 | 370 | var doi = url.match(/[?&]doi=([^&#]*)/i); 371 | 372 | /* eslint-disable no-undef */ 373 | return doi && doi[1] ? doi[1] : ''; 374 | } 375 | /** BEGIN TEST CASES **/ 376 | var testCases = [] 377 | /** END TEST CASES **/ 378 | -------------------------------------------------------------------------------- /Ncpssd.js: -------------------------------------------------------------------------------- 1 | { 2 | "translatorID": "5b731187-04a7-4256-83b4-3f042fa3eaa4", 3 | "label": "Ncpssd", 4 | "creator": "018", 5 | "target": "^https?://([^/]+\\.)?ncpssd\\.org/Literature/", 6 | "minVersion": "3.0", 7 | "maxVersion": "", 8 | "priority": 100, 9 | "inRepository": true, 10 | "translatorType": 4, 11 | "browserSupport": "gcsibv", 12 | "lastUpdated": "2020-08-08 23:03:26" 13 | } 14 | 15 | /* 16 | ***** BEGIN LICENSE BLOCK ***** 17 | 18 | Copyright © 2020 018 19 | 20 | This file is part of Zotero. 21 | 22 | Zotero is free software: you can redistribute it and/or modify 23 | it under the terms of the GNU Affero General Public License as published by 24 | the Free Software Foundation, either version 3 of the License, or 25 | (at your option) any later version. 26 | 27 | Zotero is distributed in the hope that it will be useful, 28 | but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 | GNU Affero General Public License for more details. 31 | 32 | You should have received a copy of the GNU Affero General Public License 33 | along with Zotero. If not, see . 34 | 35 | ***** END LICENSE BLOCK ***** 36 | */ 37 | 38 | // eslint-disable-next-line 39 | function opt(val) { 40 | if (val && val.length > 0) { 41 | return val; 42 | } 43 | else { 44 | return ''; 45 | } 46 | } 47 | 48 | function detectWeb(doc, url) { 49 | var dType = detectType(doc, url); 50 | if (dType) { 51 | return dType; 52 | } else if (getSearchResults(doc, true)) { 53 | return "multiple"; 54 | } 55 | return false; 56 | } 57 | 58 | function getSearchResults(doc, checkOnly) { 59 | var items = {}; 60 | var found = false; 61 | var rows = doc.querySelectorAll('#ul_articlelist li'); 62 | // Z.debug(rows.length); 63 | for (let row of rows) { 64 | let a = row.querySelector('.julei-list a'); 65 | if (!a) { 66 | continue; 67 | } 68 | 69 | if (checkOnly) return true; 70 | 71 | var id = a.getAttribute("data-id"); 72 | var type = a.getAttribute("data-name"); 73 | var barcodenum = a.getAttribute("data-barcodenum"); 74 | 75 | let url = getUrl(id, type, barcodenum); 76 | 77 | // Z.debug(url); 78 | let title = ZU.trimInternal(a.textContent); 79 | let downloads = row.querySelector('.number strong').textContent; 80 | let views = row.querySelector('.number strong+strong').textContent; 81 | 82 | found = true; 83 | items[url] = '[' + downloads + '/' + views + '] ' + title; 84 | } 85 | return found ? items : false; 86 | } 87 | 88 | function doWeb(doc, url) { 89 | if (detectWeb(doc, url) == "multiple") { 90 | Zotero.selectItems(getSearchResults(doc, false), function (items) { 91 | // Z.debug(items); 92 | for (var url in items) { 93 | // Z.debug('url:' + url); 94 | scrape(doc, url); 95 | } 96 | }); 97 | } 98 | else { 99 | scrape(doc, url); 100 | } 101 | } 102 | 103 | function scrapeAndParse(method, data, callback) { 104 | // Z.debug({ url }) 105 | var baseUrl = 'http://www.ncpssd.org'; 106 | var risRequest = baseUrl + '/ajax/articleinfoHandler.ashx?method=' + method; 107 | 108 | Zotero.Utilities.HTTP.doPost(risRequest, data, function (json) { 109 | if (callback && json) { 110 | callback(JSON.parse(json)); 111 | } 112 | }); 113 | } 114 | 115 | function getUrl(id, type, barcodenum) { 116 | var typename = ""; 117 | var barcodenum1 = barcodenum; 118 | if (type == "journalArticle") { 119 | typename = "5Lit5paH5pyf5YiK5paH56ug"; 120 | } 121 | if (type == "eJournalArticle") { 122 | typename = "5aSW5paH5pyf5YiK5paH56ug"; 123 | } 124 | if (type == "Ancient") { 125 | typename = "5Y+k57GN"; 126 | } 127 | if (type == "Book") { 128 | barcodenum1 = id; 129 | typename = "5aSW5paH5Zu+5Lmm"; 130 | } 131 | if (type == "LocalRecords") { 132 | typename = "5pa55b+X"; 133 | } 134 | if (type == "Conference") { 135 | typename = "5Lya6K6u6K665paH"; 136 | } 137 | if (type == "Degree") { 138 | typename = "5a2m5L2N6K665paH"; 139 | } 140 | 141 | /* eslint-disable no-undef */ 142 | return 'http://www.ncpssd.org/Literature/articleinfo.aspx?id=' + btoa(id) + "&type=" + btoa(type) + "&typename=" + typename + "&datatype=" + btoa(type) + "&nav=0&barcodenum=" + (barcodenum1 ? btoa(barcodenum1) : ''); 143 | } 144 | 145 | function getPdfUrl(pdfurl, type) { 146 | var pdftype = 0; 147 | if (type == "journalArticle") { 148 | pdftype = 1; 149 | } 150 | if (type == "eJournalArticle") { 151 | pdftype = 2; 152 | } 153 | if (type == "Ancient") { 154 | pdftype = 3; 155 | } 156 | if (type == "Book") { 157 | pdftype = 4; 158 | } 159 | 160 | return pdfurl.replace('www.nssd.org', 'www.nssd.cn') + '&type=' + pdftype; 161 | } 162 | 163 | // 中文期刊文章 164 | function scrapeJournalArticle(url) { 165 | var info = getFromURL(url); 166 | // Z.debug(info); 167 | if (info) { 168 | scrapeAndParse('getjournalarticletable', '{\'lngid\':\'' + info.id + '\'}', function (ret) { 169 | var json = ret[0]; 170 | // Z.debug(json); 171 | // https://aurimasv.github.io/z2csl/typeMap.xml#map-journalArticle 172 | var type = 'journalArticle'; 173 | var item = new Zotero.Item(type); 174 | 175 | item.url = url; 176 | 177 | item.title = json.title_c; 178 | 179 | item.date = (json.years ? (json.years + '年') : ''); 180 | item.volume = opt(json.vol); 181 | item.issue = opt(json.num); 182 | item.pages = json.pagecount + (json.beginpage > 0 ? ('(' + json.beginpage + (json.endpage ? ('-' + json.endpage + '页)') : ')')) : ''); 183 | 184 | switch (json.language) { 185 | case 1: 186 | item.language = '中文'; 187 | item.publicationTitle = '《' + json.media_c + '》' + (json.media_e && json.media_e.length > 0 ? ('(' + json.media_e + ')') : ''); 188 | item.abstractNote = json.remark_c; 189 | 190 | // Z.debug(item); 191 | // 标签 192 | var keywordcs = json.keyword_c; 193 | if (keywordcs && keywordcs.length > 0) { 194 | for (var kc of keywordcs.split(';')) { 195 | item.tags.push(kc); 196 | } 197 | } 198 | keywordes = json.keyword_e; 199 | if (keywordes && keywordes.length > 0) { 200 | for (var ke of keywordes.split(';')) { 201 | item.tags.push(ke); 202 | } 203 | } 204 | 205 | // 作者 206 | var creators1 = json.showwriter; 207 | for (var c1 of creators1.split(';')) { 208 | item.creators.push({ 209 | lastName: c1.replace(/\[.*]/g, ''), 210 | creatorType: 'author', 211 | fieldMode: 1 212 | }); 213 | } 214 | 215 | if (json.pdfurl) { 216 | item.attachments.push({ 217 | title: 'Full Text PDF', 218 | mimeType: 'application/pdf', 219 | url: getPdfUrl(json.pdfurl, type) 220 | }); 221 | } 222 | break; 223 | case 2: 224 | item.language = '外文'; 225 | item.publicationTitle = '《' + json.media_e + '》'; 226 | item.abstractNote = json.remark_c; 227 | 228 | // Z.debug(item); 229 | // 标签 230 | var keywordes = json.keyword_e; 231 | if (keywordes && keywordes.length > 0) { 232 | for (var k of keywordes.split(';')) { 233 | item.tags.push(k); 234 | } 235 | } 236 | 237 | // 作者 238 | var creators2 = json.showwriter; 239 | for (var c2 of creators2.split(',')) { 240 | item.creators.push({ 241 | lastName: c2.replace(/\[.*]/g, ''), 242 | creatorType: 'author', 243 | fieldMode: 1 244 | }); 245 | } 246 | break; 247 | default: 248 | break; 249 | } 250 | var showorgan = json.showorgan; 251 | if (showorgan && showorgan.length > 0) { 252 | for (var s of showorgan.split(';')) { 253 | if (!s || s.trim().length <= 0) continue; 254 | item.creators.push({ 255 | lastName: s, 256 | creatorType: 'author', 257 | fieldMode: 1 258 | }); 259 | } 260 | } 261 | 262 | item.complete(); 263 | }); 264 | } 265 | } 266 | 267 | // 外文期刊文章 268 | function scrapeEJournalArticle(url) { 269 | scrapeJournalArticle(url); 270 | } 271 | 272 | // 古籍 273 | function scrapeAncientBook(url) { 274 | var info = getFromURL(url); 275 | // Z.debug(info); 276 | // Z.debug(info.barcodenum); 277 | if (info && info.barcodenum) { 278 | scrapeAndParse('getancientbooktable', '{\'barcodenum\':' + info.barcodenum + '}', function (ret) { 279 | var json = ret[0]; 280 | // Z.debug(json); 281 | // https://aurimasv.github.io/z2csl/typeMap.xml#map-book 282 | var type = 'book'; 283 | var item = new Zotero.Item(type); 284 | 285 | item.url = url; 286 | 287 | item.title = json.title_c; 288 | item.ISBN = opt(json.isbn); 289 | item.publisher = opt(json.press); 290 | item.date = opt(json.pubdatenote); 291 | item.volume = opt(json.vol); 292 | item.issue = opt(json.num); 293 | 294 | item.language = '中文'; 295 | item.publicationTitle = json.media_c ? ('《' + json.media_c + '》') : ''; 296 | item.abstractNote = json.remark_c; 297 | 298 | // Z.debug(item); 299 | // 标签 300 | var keywordcs = json.keyword_c; 301 | if (keywordcs && keywordcs.length > 0) { 302 | for (var kc of keywordcs.split(';')) { 303 | item.tags.push(kc); 304 | } 305 | } 306 | 307 | // 作者 308 | var creators = json.showwriter; 309 | for (var c of creators.split(';')) { 310 | item.creators.push({ 311 | lastName: c.replace(/\[.*]/g, ''), 312 | creatorType: 'author', 313 | fieldMode: 1 314 | }); 315 | } 316 | 317 | var showorgan = json.showorgan; 318 | if (showorgan && showorgan.length > 0) { 319 | for (var s of showorgan.split(';')) { 320 | if (!s || s.trim().length <= 0) continue; 321 | item.creators.push({ 322 | lastName: s, 323 | creatorType: 'author', 324 | fieldMode: 1 325 | }); 326 | } 327 | } 328 | 329 | if (json.pdfurl) { 330 | item.attachments.push({ 331 | title: 'Full Text PDF', 332 | mimeType: 'application/pdf', 333 | url: getPdfUrl(json.pdfurl, type) 334 | }); 335 | } 336 | 337 | item.complete(); 338 | }); 339 | } 340 | } 341 | 342 | function scrape(doc, url) { 343 | var info = getFromURL(url); 344 | if (info) { 345 | var type = info.type; 346 | switch (type) { 347 | case 'journalArticle': 348 | scrapeJournalArticle(url); 349 | break; 350 | case 'eJournalArticle': 351 | scrapeEJournalArticle(url); 352 | break; 353 | case 'Ancient': 354 | scrapeAncientBook(url); 355 | break; 356 | 357 | default: 358 | break; 359 | } 360 | } 361 | } 362 | 363 | function detectType(doc, url) { 364 | var TYPE = { 365 | journalArticle: "journalArticle", 366 | eJournalArticle: "journalArticle", 367 | Ancient: "book", 368 | // Book: "book", 369 | // Conference: "thesis", 370 | // Degree: "thesis", 371 | // LocalRecords: "thesis" 372 | }; 373 | var info = getFromURL(url); 374 | // Z.debug(info); 375 | if (info) { 376 | return TYPE[info.type]; 377 | } 378 | 379 | return undefined; 380 | } 381 | 382 | function getFromURL(url) { 383 | if (!url) return false; 384 | 385 | var type = url.match(/[?&]type=([^&#]*)/i); 386 | var id = url.match(/[?&]id=([^&#]*)/i); 387 | var typename = url.match(/[?&]typename=([^&#]*)/i); 388 | var barcodenum = url.match(/[?&]barcodenum=([^&#]*)/i); 389 | if (!type || !type[1] || !id || !id[1] || !typename || !typename[1]) return false; 390 | 391 | /* eslint-disable no-undef */ 392 | return { 393 | type: atob(type[1]), 394 | id: atob(id[1]), 395 | typename: atob(typename[1]), 396 | barcodenum: (barcodenum && barcodenum[1] ? atob(barcodenum[1]) : '') 397 | }; 398 | } 399 | 400 | /** BEGIN TEST CASES **/ 401 | var testCases = [ 402 | { 403 | "type": "web", 404 | "url": "http://www.ncpssd.org/Literature/articleinfo.aspx?id=NzAwMTg3ODc4Mw==&type=am91cm5hbEFydGljbGU=&datatype=am91cm5hbEFydGljbGU=&typename=5Lit5paH5pyf5YiK5paH56ug&nav=0&barcodenum=", 405 | "items": [ 406 | { 407 | "itemType": "journalArticle", 408 | "title": "关键词法在大学英语词汇学习中应用效果的实证研究——以接受性和产出性测试为例", 409 | "creators": [ 410 | { 411 | "lastName": "朱珺", 412 | "creatorType": "author", 413 | "fieldMode": 1 414 | }, 415 | { 416 | "lastName": "杨继林", 417 | "creatorType": "author", 418 | "fieldMode": 1 419 | }, 420 | { 421 | "lastName": "徐方雯", 422 | "creatorType": "author", 423 | "fieldMode": 1 424 | }, 425 | { 426 | "lastName": "[1]上饶师范学院外国语学院,江西上饶334001", 427 | "creatorType": "author", 428 | "fieldMode": 1 429 | }, 430 | { 431 | "lastName": "[2]上饶师范学院教务处,江西上饶334001", 432 | "creatorType": "author", 433 | "fieldMode": 1 434 | } 435 | ], 436 | "abstractNote": "需要学习者在母语与目的语之间找到发音相同或相近的词汇,在两个词汇之间构建语音连接,并以心理意象的形式记忆,利用言语和表象的双重编码过程促进记忆。这种词汇信息处理方式与常见的语义语境法不同,两种词汇学习方法值得进一步比较,为大学英语词汇教学提供启示。采用关键词法和语义语境法进行组间对比研究,可以发现在接受性和产出性两项测验中,前者的成绩皆明显优于后者,说明采取关键词法更能促进英语词汇的短时记忆、长时记忆和理解。", 437 | "libraryCatalog": "ncpssd", 438 | "pages": "112-118", 439 | "publicationTitle": "《上饶师范学院学报》(上饶师范学院学报)", 440 | "url": "http://www.ncpssd.org/Literature/articleinfo.aspx?id=NzAwMTg3ODc4Mw==&type=am91cm5hbEFydGljbGU=&datatype=am91cm5hbEFydGljbGU=&typename=5Lit5paH5pyf5YiK5paH56ug&nav=0&barcodenum=", 441 | "attachments": [ 442 | { 443 | "title": "Full Text PDF", 444 | "mimeType": "application/pdf" 445 | } 446 | ], 447 | "tags": [ 448 | { 449 | "tag": "关键词法" 450 | }, 451 | { 452 | "tag": "短时记忆" 453 | }, 454 | { 455 | "tag": "语义语境法" 456 | }, 457 | { 458 | "tag": "长时记忆" 459 | } 460 | ], 461 | "notes": [], 462 | "seeAlso": [] 463 | } 464 | ] 465 | }, 466 | { 467 | "type": "web", 468 | "url": "http://www.ncpssd.org/Literature/articlelist.aspx?search=KElLVEU9IumVv+aXtuiusOW/hiIgT1IgSUtTVD0i6ZW/5pe26K6w5b+GIiBPUiBJS0VUPSLplb/ml7borrDlv4YiIE9SIElLU0U9IumVv+aXtuiusOW/hiIp&searchname=6aKY5ZCNL+WFs+mUruivjT0i6ZW/5pe26K6w5b+GIg==&nav=0", 469 | "items": "multiple" 470 | }, 471 | { 472 | "type": "web", 473 | "url": "http://www.ncpssd.org/Literature/articleinfo.aspx?id=Q0FTUzQyODE2Mjc2&type=ZUpvdXJuYWxBcnRpY2xl&typename=5aSW5paH5pyf5YiK5paH56ug&nav=1&langType=2", 474 | "items": [ 475 | { 476 | "itemType": "journalArticle", 477 | "title": "Patriot", 478 | "creators": [ 479 | { 480 | "lastName": "Ross, Rick", 481 | "creatorType": "author", 482 | "fieldMode": 1 483 | } 484 | ], 485 | "issue": "2531958", 486 | "language": "外文", 487 | "libraryCatalog": "ncpssd", 488 | "pages": "null", 489 | "publicationTitle": "《》(Wings of Gold)", 490 | "url": "http://www.ncpssd.org/Literature/articleinfo.aspx?id=Q0FTUzQyODE2Mjc2&type=ZUpvdXJuYWxBcnRpY2xl&typename=5aSW5paH5pyf5YiK5paH56ug&nav=1&langType=2", 491 | "attachments": [ 492 | { 493 | "title": "Full Text PDF", 494 | "mimeType": "application/pdf" 495 | } 496 | ], 497 | "tags": [], 498 | "notes": [], 499 | "seeAlso": [] 500 | } 501 | ] 502 | } 503 | ] 504 | /** END TEST CASES **/ 505 | -------------------------------------------------------------------------------- /CNKI.js: -------------------------------------------------------------------------------- 1 | { 2 | "translatorID": "5c95b67b-41c5-4f55-b71a-48d5d7183063", 3 | "label": "CNKI", 4 | "creator": "Aurimas Vinckevicius, Xingzhong Lin", 5 | "target": "^https?://([^/]+\\.)?cnki\\.|-net", 6 | "minVersion": "3.0", 7 | "maxVersion": "", 8 | "priority": 100, 9 | "inRepository": true, 10 | "translatorType": 4, 11 | "browserSupport": "gcs", 12 | "lastUpdated": "2021-08-17 10:07:45" 13 | } 14 | 15 | /* 16 | ***** BEGIN LICENSE BLOCK ***** 17 | 18 | CNKI(China National Knowledge Infrastructure) Translator 19 | Copyright © 2013 Aurimas Vinckevicius 20 | 21 | This file is part of Zotero. 22 | 23 | Zotero is free software: you can redistribute it and/or modify 24 | it under the terms of the GNU Affero General Public License as published by 25 | the Free Software Foundation, either version 3 of the License, or 26 | (at your option) any later version. 27 | 28 | Zotero is distributed in the hope that it will be useful, 29 | but WITHOUT ANY WARRANTY; without even the implied warranty of 30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31 | GNU Affero General Public License for more details. 32 | 33 | You should have received a copy of the GNU Affero General Public License 34 | along with Zotero. If not, see . 35 | 36 | ***** END LICENSE BLOCK ***** 37 | */ 38 | 39 | // Fetches RefWorks records for provided IDs and calls onDataAvailable with resulting text 40 | // ids should be in the form [{dbname: "CDFDLAST2013", filename: "1013102302.nh"}] 41 | function getRefWorksByID(ids, onDataAvailable) { 42 | if (!ids.length) return; 43 | var { dbname, filename, queryID, curRec } = ids.shift(); 44 | var postData = "formfilenames=" + encodeURIComponent(dbname + "!" + filename + "!1!0,") 45 | + '&hid_kLogin_headerUrl=/KLogin/Request/GetKHeader.ashx%3Fcallback%3D%3F' 46 | + '&hid_KLogin_FooterUrl=/KLogin/Request/GetKHeader.ashx%3Fcallback%3D%3F' 47 | + '&CookieName=FileNameS'; 48 | ZU.doPost('https://kns.cnki.net/kns/ViewPage/viewsave.aspx?displayMode=Refworks', postData, 49 | function (text) { 50 | var parser = new DOMParser(); 51 | var html = parser.parseFromString(text, "text/html"); 52 | var data = ZU.xpath(html, "//table[@class='mainTable']//td")[0].innerHTML 53 | .replace(/
/g, '\n') 54 | .replace(/^RT\s+Dissertation\/Thesis/gmi, 'RT Dissertation') 55 | .replace( 56 | /^(A[1-4]|U2)\s*([^\r\n]+)/gm, 57 | function (m, tag, authors) { 58 | authors = authors.split(/\s*[;,,]\s*/); // that's a special comma 59 | if (!authors[authors.length - 1].trim()) authors.pop(); 60 | return tag + ' ' + authors.join('\n' + tag + ' '); 61 | } 62 | ); 63 | onDataAvailable({dbname, filename, queryID, curRec}, data); 64 | // If more results, keep going 65 | if (ids.length) { 66 | getRefWorksByID(ids, onDataAvailable); 67 | } 68 | } 69 | ); 70 | } 71 | 72 | function getIDFromURL(url) { 73 | if (!url) return false; 74 | var dbname = url.match(/[?&]dbname=([^&#]*)/i); 75 | var filename = url.match(/[?&]filename=([^&#]*)/i); 76 | var queryID = url.match(/[?&]queryid=([^&#]*)/i); 77 | var curRec = url.match(/[?&]currec=([^&#]*)/i); 78 | if (!dbname || !dbname[1] || !filename || !filename[1]) return false; 79 | 80 | return { dbname: dbname[1], filename: filename[1], curRec: curRec ? curRec[1] : '', queryID: queryID ? queryID[1] : '', url: url }; 81 | } 82 | 83 | 84 | // 网络首发期刊信息并不能从URL获取dbname和filename信息 85 | // Get dbname and filename from pre-released article web page. 86 | function getIDFromRef(doc, url) { 87 | var func = ZU.xpath(doc, '//div[@class="link"]/a'); 88 | if (!func.length) { 89 | return false; 90 | } 91 | func = func[0].getAttribute('onclick'); 92 | var tmp = func.split(',')[1].split('!'); 93 | // Z.debug(func + tmp[0].slice(1)); 94 | return { dbname: tmp[0].slice(1), filename: tmp[1], url: url }; 95 | } 96 | 97 | function getIDFromPage(doc, url) { 98 | return getIDFromURL(url) 99 | || getIDFromURL(ZU.xpathText(doc, '//div[@class="zwjdown"]/a/@href')) 100 | || getIDFromRef(doc, url); 101 | } 102 | 103 | function getTypeFromDBName(dbname) { 104 | var dbType = { 105 | CJFQ: "journalArticle", 106 | CJFD: "journalArticle", 107 | CAPJ: "journalArticle", 108 | CDFD: "thesis", 109 | CMFD: "thesis", 110 | CLKM: "thesis", 111 | CCND: "newspaperArticle", 112 | CPFD: "conferencePaper", 113 | }; 114 | var db = dbname.substr(0, 4).toUpperCase(); 115 | if (dbType[db]) { 116 | return dbType[db]; 117 | } 118 | else { 119 | return false; 120 | } 121 | } 122 | 123 | function getItemsFromSearchResults(doc, url, itemInfo) { 124 | var iframe = doc.getElementById('iframeResult'); 125 | if (iframe) { 126 | var innerDoc = iframe.contentDocument || iframe.contentWindow.document; 127 | if (innerDoc) { 128 | doc = innerDoc; 129 | } 130 | } 131 | 132 | var links = ZU.xpath(doc, '//tr[not(.//tr) and .//a[@class="fz14"]]'); 133 | var aXpath = './/a[@class="fz14"]'; 134 | if (!links.length) { 135 | links = ZU.xpath(doc, '//table[@class="GridTableContent"]/tbody/tr[./td[2]/a]'); 136 | aXpath = './td[2]/a'; 137 | } 138 | 139 | if (!links.length) { 140 | if (url.match(/(kns8|KNS8)\/(defaultresult|AdvSearch)/i)) { 141 | return { '': '【提醒:不存在条目。】' }; 142 | } 143 | 144 | return false; 145 | } 146 | var items = {}; 147 | for (var i = 0, n = links.length; i < n; i++) { 148 | // Z.debug(links[i].innerHTML) 149 | var a = ZU.xpath(links[i], aXpath)[0]; 150 | var title = ZU.xpathText(a, './node()[not(name()="SCRIPT")]', null, ''); 151 | if (title) title = ZU.trimInternal(title); 152 | var id = getIDFromURL(a.href); 153 | // pre-released item can not get ID from URL, try to get ID from element.value 154 | if (!id) { 155 | var td1 = ZU.xpath(links[i], './td')[0]; 156 | var tmp = td1.value.split('!'); 157 | id = { dbname: tmp[0], filename: tmp[1], url: a.href }; 158 | } 159 | if (!title || !id) continue; 160 | if (itemInfo) { 161 | itemInfo[a.href] = { id: id }; 162 | } 163 | items[a.href] = title; 164 | } 165 | return items; 166 | } 167 | 168 | function detectWeb(doc, url) { 169 | // Z.debug(doc); 170 | var id = getIDFromPage(doc, url); 171 | var items = getItemsFromSearchResults(doc, url); 172 | 173 | if (id) { 174 | return getTypeFromDBName(id.dbname); 175 | } 176 | else if (items || url.match(/(kns8|KNS8)\/(defaultresult|AdvSearch)/i)) { 177 | return "multiple"; 178 | } 179 | else { 180 | return false; 181 | } 182 | } 183 | 184 | function doWeb(doc, url) { 185 | if (detectWeb(doc, url) == "multiple") { 186 | var itemInfo = {}; 187 | var items = getItemsFromSearchResults(doc, url, itemInfo); 188 | Z.selectItems(items, function (selectedItems) { 189 | if (!selectedItems) return; 190 | 191 | var itemInfoByTitle = {}; 192 | var ids = []; 193 | for (var url in selectedItems) { 194 | if (url && url.length > 0) { 195 | ids.push(itemInfo[url].id); 196 | itemInfoByTitle[selectedItems[url]] = itemInfo[url]; 197 | itemInfoByTitle[selectedItems[url]].url = url; 198 | } 199 | } 200 | scrape(ids, doc, url, itemInfoByTitle); 201 | }); 202 | } 203 | else { 204 | scrape([getIDFromPage(doc, url)], doc, url); 205 | } 206 | } 207 | 208 | function scrape(ids, doc, url, itemInfo) { 209 | getRefWorksByID(ids, function ({dbname, filename, queryID, curRec}, text) { 210 | var translator = Z.loadTranslator('import'); 211 | translator.setTranslator('1a3506da-a303-4b0a-a1cd-f216e6138d86'); // RefWorks Tagged 212 | text = text.replace(/IS (\d+)\nvo/, "IS $1\nVO"); 213 | translator.setString(text); 214 | 215 | translator.setHandler('itemDone', function (obj, newItem) { 216 | // split names 217 | for (var i = 0, n = newItem.creators.length; i < n; i++) { 218 | var creator = newItem.creators[i]; 219 | if (creator.firstName) continue; 220 | 221 | var lastSpace = creator.lastName.lastIndexOf(' '); 222 | if (creator.lastName.search(/[A-Za-z]/) !== -1 && lastSpace !== -1) { 223 | // western name. split on last space 224 | creator.firstName = creator.lastName.substr(0, lastSpace); 225 | creator.lastName = creator.lastName.substr(lastSpace + 1); 226 | } 227 | else { 228 | creator.firstName = ''; 229 | // Chinese name: first character is last name, the rest are first name (ignoring compound last names which are rare) 230 | creator.firstName = creator.lastName.substr(1); 231 | creator.lastName = creator.lastName.charAt(0); 232 | } 233 | } 234 | 235 | if (newItem.abstractNote) { 236 | newItem.abstractNote = newItem.abstractNote.replace(/\s*[\r\n]\s*/g, '\n'); 237 | } 238 | 239 | // clean up tags. Remove numbers from end 240 | for (var j = 0, l = newItem.tags.length; j < l; j++) { 241 | newItem.tags[j] = newItem.tags[j].replace(/:\d+$/, ''); 242 | } 243 | 244 | newItem.title = ZU.trimInternal(newItem.title); 245 | if (itemInfo) { 246 | var info = itemInfo[newItem.title]; 247 | if (!info) { 248 | Z.debug('No item info for "' + newItem.title + '"'); 249 | } 250 | else { 251 | newItem.url = info.url; 252 | } 253 | } 254 | else { 255 | newItem.url = url; 256 | } 257 | // CN 中国刊物编号,非refworks中的callNumber 258 | // CN in CNKI refworks format explains Chinese version of ISSN 259 | if (newItem.callNumber) { 260 | newItem.extra = 'CN ' + newItem.callNumber; 261 | } 262 | // don't download PDF/CAJ on searchResult(multiple) 263 | var webType = detectWeb(doc, url); 264 | if (webType && webType != 'multiple') { 265 | newItem.attachments = getAttachments(doc, newItem); 266 | } 267 | newItem.complete(); 268 | }); 269 | 270 | translator.translate(); 271 | }); 272 | } 273 | 274 | // get pdf download link 275 | function getPDF(doc, itemType) { 276 | // retrieve PDF links from CNKI oversea 277 | var pdf = itemType == 'thesis' 278 | ? ZU.xpath(doc, "//div[@id='DownLoadParts']/a[contains(text(), 'PDF')]") 279 | : ZU.xpath(doc, "//a[@name='pdfDown']"); 280 | return pdf.length ? pdf[0].href : false; 281 | } 282 | 283 | // caj download link, default is the whole article for thesis. 284 | function getCAJ(doc, itemType) { 285 | // //div[@id='DownLoadParts'] 286 | var caj = itemType == 'thesis' 287 | ? ZU.xpath(doc, "//div[@id='DownLoadParts']/a") 288 | : ZU.xpath(doc, "//a[@name='cajDown']"); 289 | return caj.length ? caj[0].href : false; 290 | } 291 | 292 | // add pdf or caj to attachments, default is pdf 293 | function getAttachments(doc, item) { 294 | var attachments = []; 295 | var pdfurl = getPDF(doc, item.itemType); 296 | var cajurl = getCAJ(doc, item.itemType); 297 | // Z.debug('pdf' + pdfurl); 298 | // Z.debug('caj' + cajurl); 299 | var loginUser = ZU.xpath(doc, "//input[@id='loginuserid']"); 300 | // Z.debug(doc.body.innerHTML); 301 | // Z.debug(loginUser[0].value); 302 | // Z.debug(loginUser.length); 303 | if (loginUser.length && loginUser[0].value) { 304 | if (pdfurl) { 305 | attachments.push({ 306 | title: "Full Text PDF", 307 | mimeType: "application/pdf", 308 | url: pdfurl 309 | }); 310 | } 311 | else if (cajurl) { 312 | attachments.push({ 313 | title: "Full Text CAJ", 314 | mimeType: "application/caj", 315 | url: cajurl 316 | }); 317 | } 318 | } 319 | 320 | return attachments; 321 | } 322 | 323 | /** BEGIN TEST CASES **/ 324 | var testCases = [ 325 | { 326 | "type": "web", 327 | "url": "http://kns.cnki.net/KCMS/detail/detail.aspx?dbcode=CJFQ&dbname=CJFDLAST2015&filename=SPZZ201412003&v=MTU2MzMzcVRyV00xRnJDVVJMS2ZidVptRmkva1ZiL09OajNSZExHNEg5WE5yWTlGWjRSOGVYMUx1eFlTN0RoMVQ=", 328 | "items": [ 329 | { 330 | "itemType": "journalArticle", 331 | "title": "基于部分酸水解-亲水作用色谱-质谱的黄芪多糖结构表征", 332 | "creators": [ 333 | { 334 | "lastName": "梁", 335 | "firstName": "图", 336 | "creatorType": "author" 337 | }, 338 | { 339 | "lastName": "傅", 340 | "firstName": "青", 341 | "creatorType": "author" 342 | }, 343 | { 344 | "lastName": "辛", 345 | "firstName": "华夏", 346 | "creatorType": "author" 347 | }, 348 | { 349 | "lastName": "李", 350 | "firstName": "芳冰", 351 | "creatorType": "author" 352 | }, 353 | { 354 | "lastName": "金", 355 | "firstName": "郁", 356 | "creatorType": "author" 357 | }, 358 | { 359 | "lastName": "梁", 360 | "firstName": "鑫淼", 361 | "creatorType": "author" 362 | } 363 | ], 364 | "date": "2014", 365 | "ISSN": "1000-8713", 366 | "abstractNote": "来自中药的水溶性多糖具有广谱治疗和低毒性特点,是天然药物及保健品研发中的重要组成部分。针对中药多糖结构复杂、难以表征的问题,本文以中药黄芪中的多糖为研究对象,采用\"自下而上\"法完成对黄芪多糖的表征。首先使用部分酸水解方法水解黄芪多糖,分别考察了水解时间、酸浓度和温度的影响。在适宜条件(4 h、1.5mol/L三氟乙酸、80℃)下,黄芪多糖被水解为特征性的寡糖片段。接下来,采用亲水作用色谱与质谱联用对黄芪多糖部分酸水解产物进行分离和结构表征。结果表明,提取得到的黄芪多糖主要为1→4连接线性葡聚糖,水解得到聚合度4~11的葡寡糖。本研究对其他中药多糖的表征具有一定的示范作用。", 367 | "issue": "12", 368 | "language": "中文;", 369 | "libraryCatalog": "CNKI", 370 | "pages": "1306-1312", 371 | "publicationTitle": "色谱", 372 | "url": "http://kns.cnki.net/KCMS/detail/detail.aspx?dbcode=CJFQ&dbname=CJFDLAST2015&filename=SPZZ201412003&v=MTU2MzMzcVRyV00xRnJDVVJMS2ZidVptRmkva1ZiL09OajNSZExHNEg5WE5yWTlGWjRSOGVYMUx1eFlTN0RoMVQ=", 373 | "volume": "32", 374 | "attachments": [], 375 | "tags": [ 376 | { 377 | "tag": "Astragalus" 378 | }, 379 | { 380 | "tag": "characterization" 381 | }, 382 | { 383 | "tag": "hydrophilic interaction liquid chromatography(HILIC)mass spectrometry(MS)" 384 | }, 385 | { 386 | "tag": "partial acid hydrolysis" 387 | }, 388 | { 389 | "tag": "polysaccharides" 390 | }, 391 | { 392 | "tag": "亲水作用色谱" 393 | }, 394 | { 395 | "tag": "多糖" 396 | }, 397 | { 398 | "tag": "表征" 399 | }, 400 | { 401 | "tag": "质谱" 402 | }, 403 | { 404 | "tag": "部分酸水解" 405 | }, 406 | { 407 | "tag": "黄芪" 408 | } 409 | ], 410 | "notes": [], 411 | "seeAlso": [] 412 | } 413 | ] 414 | }, 415 | { 416 | "type": "web", 417 | "url": "https://kns.cnki.net/KCMS/detail/detail.aspx?dbcode=CMFD&dbname=CMFD201701&filename=1017045605.nh&v=MDc3ODZPZVorVnZGQ3ZrV3JyT1ZGMjZHYk84RzlmTXFwRWJQSVI4ZVgxTHV4WVM3RGgxVDNxVHJXTTFGckNVUkw=", 418 | "items": [ 419 | { 420 | "itemType": "thesis", 421 | "title": "黄瓜共表达基因模块的识别及其特点分析", 422 | "creators": [ 423 | { 424 | "lastName": "林", 425 | "firstName": "行众", 426 | "creatorType": "author" 427 | } 428 | ], 429 | "date": "2015", 430 | "abstractNote": "黄瓜(Cucumis sativus L.)是我国最大的保护地栽培蔬菜作物,也是植物性别发育和维管束运输研究的重要模式植物。黄瓜基因组序列图谱已经构建完成,并且在此基础上又完成了全基因组SSR标记开发和涵盖330万个变异位点变异组图谱,成为黄瓜功能基因研究的重要平台和工具,相关转录组研究也有很多报道,不过共表达网络研究还是空白。本实验以温室型黄瓜9930为研究对象,选取10个不同组织,进行转录组测序,获得10份转录组原始数据。在对原始数据去除接头与低质量读段后,将高质量读段用Tophat2回贴到已经发表的栽培黄瓜基因组序列上。用Cufflinks对回贴后的数据计算FPKM值,获得10份组织的2...", 431 | "language": "中文;", 432 | "libraryCatalog": "CNKI", 433 | "thesisType": "硕士", 434 | "university": "南京农业大学", 435 | "url": "https://kns.cnki.net/KCMS/detail/detail.aspx?dbcode=CMFD&dbname=CMFD201701&filename=1017045605.nh&v=MDc3ODZPZVorVnZGQ3ZrV3JyT1ZGMjZHYk84RzlmTXFwRWJQSVI4ZVgxTHV4WVM3RGgxVDNxVHJXTTFGckNVUkw=", 436 | "attachments": [], 437 | "tags": [ 438 | { 439 | "tag": "co-expression" 440 | }, 441 | { 442 | "tag": "cucumber" 443 | }, 444 | { 445 | "tag": "network" 446 | }, 447 | { 448 | "tag": "transcriptome" 449 | }, 450 | { 451 | "tag": "共表达" 452 | }, 453 | { 454 | "tag": "网络" 455 | }, 456 | { 457 | "tag": "转录组" 458 | }, 459 | { 460 | "tag": "黄瓜" 461 | } 462 | ], 463 | "notes": [], 464 | "seeAlso": [] 465 | } 466 | ] 467 | } 468 | ] 469 | /** END TEST CASES **/ 470 | -------------------------------------------------------------------------------- /Superlib.js: -------------------------------------------------------------------------------- 1 | { 2 | "translatorID": "33553736-4ea9-4b1a-b1e1-d43b2a918156", 3 | "label": "Superlib", 4 | "creator": "018", 5 | "target": "https?://(book|jour)\\.ucdrs\\.superlib\\.net/(search|views/specific)", 6 | "minVersion": "3.0", 7 | "maxVersion": "", 8 | "priority": 100, 9 | "inRepository": true, 10 | "translatorType": 4, 11 | "browserSupport": "gcsibv", 12 | "lastUpdated": "2021-09-30 03:26:17" 13 | } 14 | 15 | /* 16 | ***** BEGIN LICENSE BLOCK ***** 17 | 18 | Copyright © 2020 018 19 | 20 | This file is part of Zotero. 21 | 22 | Zotero is free software: you can redistribute it and/or modify 23 | it under the terms of the GNU Affero General Public License as published by 24 | the Free Software Foundation, either version 3 of the License, or 25 | (at your option) any later version. 26 | 27 | Zotero is distributed in the hope that it will be useful, 28 | but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 | GNU Affero General Public License for more details. 31 | 32 | You should have received a copy of the GNU Affero General Public License 33 | along with Zotero. If not, see . 34 | 35 | ***** END LICENSE BLOCK ***** 36 | */ 37 | 38 | // eslint-disable-next-line 39 | function attr(docOrElem,selector,attr,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.getAttribute(attr):null;}function text(docOrElem,selector,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.textContent:null;}function trim(content){return content.replace(/^[\xA0\s]+/gm, '').replace(/[\xA0\s]+$/gm, '').replace(/\n+/g, '\n').replace(/:\n+/g, ': ').replace(/]\n/g, ']').replace(/】\n/g, '】').replace(/\n\/\n/g, '/')} 40 | 41 | // https://aurimasv.github.io/z2csl/typeMap.xml#map-book 42 | // https://aurimasv.github.io/z2csl/typeMap.xml#map-conferencePaper 43 | // https://aurimasv.github.io/z2csl/typeMap.xml#map-thesis 44 | // https://aurimasv.github.io/z2csl/typeMap.xml#map-journalArticle 45 | // https://aurimasv.github.io/z2csl/typeMap.xml#map-patent 46 | var TYPE_MAP = { 47 | 图书: 'book', 48 | 会议论文: 'conferencePaper', 49 | 学位论文: 'thesis', 50 | 期刊: 'journalArticle', 51 | 专利: 'patent' 52 | }; 53 | 54 | function doPerson(item, data) { 55 | // (日)本田晃一著;朱运程译 translator author 56 | if (!data || data.length <= 0) return; 57 | const persons = data.split(/;|;/g); 58 | for (var person of persons) { 59 | if (person.endsWith('著')) { 60 | item.creators.push({ 61 | lastName: person.trim().replace(/著/g, ''), 62 | creatorType: 'author', 63 | fieldMode: 1 64 | }); 65 | } else if (person.endsWith('译')) { 66 | item.creators.push({ 67 | lastName: person.trim().replace(/译/g, ''), 68 | creatorType: 'translator', 69 | fieldMode: 1 70 | }); 71 | } else { 72 | item.creators.push({ 73 | lastName: person, 74 | creatorType: 'author', 75 | fieldMode: 1 76 | }); 77 | } 78 | } 79 | } 80 | 81 | function doInventor(item, data) { 82 | if (!data || data.length <= 0) return; 83 | const persons = data.split(/,/g); 84 | for (var person of persons) { 85 | item.creators.push({ 86 | lastName: person, 87 | creatorType: 'inventor', 88 | fieldMode: 1 89 | }); 90 | } 91 | } 92 | 93 | function doTag(item, data) { 94 | if (!data || data.length <= 0) return; 95 | const tags = data.split(';'); 96 | for (var tag of tags) { 97 | item.tags.push(tag.trim()); 98 | } 99 | } 100 | 101 | function sourceType(doc) { 102 | var type = doc.querySelector('.on span').textContent; 103 | return type; 104 | } 105 | 106 | function detectType(doc) { 107 | return TYPE_MAP[sourceType(doc)]; 108 | } 109 | 110 | function detectWeb(doc, url) { 111 | if (url.includes('/search')) { 112 | return getSearchResults(doc, true) ? 'multiple' : false; 113 | } else { 114 | var dType = detectType(doc, url); 115 | if (dType) { 116 | return dType; 117 | } 118 | } 119 | 120 | return false; 121 | } 122 | 123 | function getSearchResults(doc, checkOnly, itemInfo) { 124 | var items = {}; 125 | var found = false; 126 | var rows = doc.querySelectorAll('.book1'); 127 | for (let row of rows) { 128 | let a = row.querySelector('td>table .px14'); 129 | if (!a) { 130 | a = row.querySelector('a'); 131 | } 132 | if (!a) { 133 | continue; 134 | } 135 | 136 | if (checkOnly) return true; 137 | 138 | let url = a.href; 139 | 140 | // Z.debug(url); 141 | let title = ZU.trimInternal(a.textContent); 142 | 143 | found = true; 144 | if (!found['']) { 145 | items[''] = '【提醒:存在失败的可能,请隔几个小时后试试,或单个抓取。】'; 146 | } 147 | 148 | if (itemInfo) { 149 | var download = row.querySelector('.get a'); 150 | if (download && download.textContent == 'PDF下载') { 151 | itemInfo[url] = { 152 | pdfurl: download.href 153 | }; 154 | } 155 | } 156 | if (title.startsWith('《') && title.endsWith('》')) { 157 | title = title.replace(/《|》/g, ''); 158 | } 159 | 160 | items[url] = title; 161 | } 162 | return found ? items : false; 163 | } 164 | 165 | function doWeb(doc, url) { 166 | if (detectWeb(doc, url) == "multiple") { 167 | var itemInfo = {}; 168 | Zotero.selectItems(getSearchResults(doc, false, itemInfo), function (items) { 169 | if (items) { 170 | if (items['']) { 171 | delete items['']; 172 | } 173 | scrapeItem(Object.keys(items), itemInfo); 174 | } 175 | }); 176 | } else { 177 | scrape(doc, url); 178 | } 179 | } 180 | 181 | function scrapeItem(items, itemInfo) { 182 | ZU.processDocuments(items, function (doc, url) { 183 | scrape(doc, url, itemInfo[url] ? itemInfo[url].pdfurl : null); 184 | }); 185 | } 186 | 187 | function scrape(doc, url, pdfurl) { 188 | if (!url || url.length <= 0) { 189 | return; 190 | } 191 | 192 | var itemType = detectType(doc); 193 | var item = new Zotero.Item(itemType); 194 | 195 | item.url = url; 196 | switch (sourceType(doc)) { 197 | case '图书': 198 | item.title = text(doc, '.tutilte'); 199 | var infos = text(doc, '.tubox dl'); 200 | infos = trim(infos); 201 | for (var section0 of Object.values(infos.split('\n'))) { 202 | if (!section0 || section0.trim().length <= 0) continue; 203 | 204 | let index = section0.indexOf('】'); 205 | if (index <= -1) continue; 206 | 207 | let key = section0.substr(0, index + 1).trim(); 208 | let value = section0.substr(index + 1).trim(); 209 | // Z.debug(key + ':' + value); 210 | switch (key) { 211 | case "【作 者】": 212 | doPerson(item, value); 213 | break; 214 | case "【出版项】": 215 | var vals = Object.values(value.split(/:|,/g)); 216 | item.publisher = vals[1]; 217 | item.date = vals[2]; 218 | break; 219 | case "【ISBN号】": 220 | item.ISBN = value; 221 | break; 222 | case "【形态项】": 223 | item.numPages = value; 224 | break; 225 | case "【中图法分类号】": 226 | item.archiveLocation = value; 227 | break; 228 | 229 | default: 230 | break; 231 | } 232 | } 233 | 234 | var clc = text(doc, '#clc'); 235 | if (clc) { 236 | item.archiveLocation = clc; 237 | } 238 | var subject = text(doc, '#subject'); 239 | if (subject) { 240 | item.archive = subject; 241 | } 242 | // 摘要 243 | item.abstractNote = text(doc, '.tu_content').replace(/内容提要:\n*/g, ''); 244 | break; 245 | case '期刊': 246 | item.title = ZU.trimInternal(text(doc, 'h1.title')); 247 | infos = doc.querySelectorAll('#m_top li'); 248 | for (var section1 of infos) { 249 | let content = ZU.trimInternal(section1.textContent); 250 | if (!content || content.length <= 0) continue; 251 | 252 | let index = content.indexOf('】'); 253 | if (index <= -1) continue; 254 | 255 | content = trim(content); 256 | let key = content.substr(0, index + 1).trim(); 257 | let value = content.substr(index + 1).trim(); 258 | switch (key) { 259 | case "【作 者】": 260 | doPerson(item, value); 261 | break; 262 | case "【刊 名】": 263 | item.publicationTitle = value; 264 | break; 265 | case "【期 号】": 266 | item.issue = value; 267 | break; 268 | case "【出版日期】": 269 | item.date = value; 270 | break; 271 | case "【摘 要】": 272 | item.abstractNote = value; 273 | break; 274 | case "【关键词】": 275 | doTag(item, value); 276 | break; 277 | case "【影响因子】": 278 | item.extra = '影响因子: ' + value; 279 | break; 280 | default: 281 | break; 282 | } 283 | } 284 | break; 285 | case '学位论文': 286 | item.title = ZU.trimInternal(text(doc, 'h1.title')); 287 | infos = doc.querySelectorAll('#m_top li'); 288 | for (var section5 of infos) { 289 | let content = ZU.trimInternal(section5.textContent); 290 | if (!content || content.length <= 0) continue; 291 | 292 | let index = content.indexOf('】'); 293 | if (index <= -1) continue; 294 | 295 | content = trim(content); 296 | let key = content.substr(0, index + 1).trim(); 297 | let value = content.substr(index + 1).trim(); 298 | switch (key) { 299 | case "【作 者】": 300 | doPerson(item, value); 301 | break; 302 | case "【学位授予单位】": 303 | item.university = value; 304 | break; 305 | case "【导师姓名】": 306 | item.creators.push({ 307 | lastName: value, 308 | creatorType: 'contributor', 309 | fieldMode: 1 310 | }); 311 | break; 312 | case "【学位年度】": 313 | item.date = value; 314 | break; 315 | case "【摘 要】": 316 | item.abstractNote = value.replace(/隐藏更多/g, ''); 317 | break; 318 | case "【关键词】": 319 | doTag(item, value); 320 | break; 321 | case "【学位名称】": 322 | item.type = value; 323 | break; 324 | default: 325 | break; 326 | } 327 | } 328 | break; 329 | case '会议论文': 330 | item.title = ZU.trimInternal(text(doc, 'h1.title')); 331 | infos = doc.querySelectorAll('#m_top li'); 332 | for (var section3 of infos) { 333 | let content = ZU.trimInternal(section3.textContent); 334 | if (!content || content.length <= 0) continue; 335 | 336 | let index = content.indexOf('】'); 337 | if (index <= -1) continue; 338 | 339 | content = trim(content); 340 | let key = content.substr(0, index + 1).trim(); 341 | let value = content.substr(index + 1).trim(); 342 | switch (key) { 343 | case "【作 者】": 344 | doPerson(item, value); 345 | break; 346 | case "【会议名称】": 347 | item.conferenceName = value; 348 | break; 349 | case "【会议录名称】": 350 | item.series = value; 351 | break; 352 | case "【日 期】": 353 | item.date = value; 354 | break; 355 | case "【摘 要】": 356 | item.abstractNote = value.replace(/隐藏更多/g, ''); 357 | break; 358 | case "【关键词】": 359 | doTag(item, value); 360 | break; 361 | case "【作者联系方式】": 362 | item.place = value; 363 | break; 364 | default: 365 | break; 366 | } 367 | } 368 | break; 369 | case '专利': 370 | item.title = ZU.trimInternal(text(doc, 'h1.title')); 371 | infos = doc.querySelectorAll('.content li'); 372 | for (var section4 of infos) { 373 | let content = ZU.trimInternal(section4.textContent); 374 | if (!content || content.length <= 0) continue; 375 | 376 | let index = content.indexOf('】'); 377 | if (index <= -1) continue; 378 | 379 | content = trim(content); 380 | let key = content.substr(0, index + 1).trim(); 381 | let value = content.substr(index + 1).trim(); 382 | switch (key) { 383 | case "【申请号】": 384 | item.applicationNumber = value; 385 | break; 386 | case "【申请人】": 387 | doInventor(item, value); 388 | break; 389 | case "【发明人】": 390 | doInventor(item, value); 391 | break; 392 | case "【申请日期】": 393 | item.filingDate = value; 394 | break; 395 | case "【地 址】": 396 | item.place = value; 397 | break; 398 | case "【专利类型】": 399 | item.extra = '专利类型: ' + value; 400 | break; 401 | case "【IPC号】": 402 | item.extra += '; IPC号: ' + value; 403 | break; 404 | case "【摘 要】": 405 | item.abstractNote = value; 406 | break; 407 | default: 408 | break; 409 | } 410 | } 411 | break; 412 | } 413 | 414 | if (item.title.startsWith('《') && item.title.endsWith('》')) { 415 | item.title = item.title.replace(/《|》/g, ''); 416 | } 417 | 418 | // 如果抓取失败,请配合油猴脚本使用:https://greasyfork.org/zh-CN/scripts/408790 419 | if (pdfurl) { 420 | item.attachments.push({ 421 | url: pdfurl, 422 | title: 'Full Text PDF', 423 | mimeType: 'application/pdf' 424 | }); 425 | } else { 426 | var download = doc.querySelector('.link a'); 427 | if (download && download.textContent == 'PDF下载') { 428 | item.attachments.push({ 429 | url: download.href, 430 | title: 'Full Text PDF', 431 | mimeType: 'application/pdf' 432 | }); 433 | } 434 | } 435 | 436 | item.complete(); 437 | } 438 | 439 | /** BEGIN TEST CASES **/ 440 | var testCases = [ 441 | { 442 | "type": "web", 443 | "url": "http://book.ucdrs.superlib.net/views/specific/2929/bookDetail.jsp?dxNumber=000018108791&d=F788C1F57DDBFD163B5EDCB5371550F0&fenlei=02140804", 444 | "items": [ 445 | { 446 | "itemType": "book", 447 | "title": "认知跃迁", 448 | "creators": [ 449 | { 450 | "lastName": "(日)本田晃一", 451 | "creatorType": "author", 452 | "fieldMode": 1 453 | }, 454 | { 455 | "lastName": "朱运程", 456 | "creatorType": "translator", 457 | "fieldMode": 1 458 | } 459 | ], 460 | "date": "2019.04", 461 | "ISBN": "9787221152459", 462 | "abstractNote": "在这个发展迅速的世界,每个人都承受着前所未有的压力和挑战。一个人想要取得成功,不是去苛求外部环境,而是要打破固有认知,扩展人生格局,形成更加高效的认知系统。作者将在成功人士身上得到的启发,通过验证形成了自己的认知。通过这些认知,作者将父亲负债累累濒临破产的企业转亏为盈,并积累下了巨额财富。本书将这些认知通过轻松幽默的语言,结合自己的经历阐述出来,为我们看待事物提供与众不同的视角,帮助我们重新认识自我、认清世界。通过本书可以迅速提高认知、扩展格局,快速找到事物本质,打破生活和事业中的困境,让我们成为一个有竞争力的人。", 463 | "libraryCatalog": "Superlib", 464 | "publisher": "贵州人民出版社", 465 | "url": "http://book.ucdrs.superlib.net/views/specific/2929/bookDetail.jsp?dxNumber=000018108791&d=F788C1F57DDBFD163B5EDCB5371550F0&fenlei=02140804", 466 | "attachments": [], 467 | "tags": [], 468 | "notes": [], 469 | "seeAlso": [] 470 | } 471 | ] 472 | }, 473 | { 474 | "type": "web", 475 | "url": "http://jour.ucdrs.superlib.net/views/specific/2929/thesisDetail.jsp?dxNumber=390107316149&d=73BC951F9D12D3EF5BFAD6281BFC35F0&sw=%E8%AE%A4%E7%9F%A5", 476 | "items": [ 477 | { 478 | "itemType": "thesis", 479 | "title": "认知是否具有现象性?", 480 | "creators": [ 481 | { 482 | "lastName": "孙玉婷", 483 | "creatorType": "author", 484 | "fieldMode": 1 485 | }, 486 | { 487 | "lastName": "蔡仲", 488 | "creatorType": "contributor", 489 | "fieldMode": 1 490 | } 491 | ], 492 | "date": "2019", 493 | "abstractNote": "意识有感官、身体感觉、情绪情感、认知等形式,前三种意识形式的每一种意识状态似乎都具有独特的现象特征,但是对于认知状态是否具有现象特征存在激烈争论。一方面,一些理论家认为现象特征是有意识的认知状态固有的现象属性;另一方面,另一些理论家则固守心灵哲学中的传统观点,认为有意识的认知状态不具有现象特征,并且将有意识的认知状态的现象特征还原到感官的现象特征上。本文基于以下几点采取支持认知现象学的立场。首先,我们能够通过内省立即知道我们自身所处的认知状态,而要解释这一事实,就必须承认认知状态的现象感受性,这也就是所谓的自我认识论证;其次,我们能够通过许多案例直观地体验认知的现象感受性,一些理论家基于这些经验实例,构造出巧妙的现象对比论证。这是一种非还原的认知现象学立场,也就是说,现象性是认知状态的固有属性,不可以还原到感官现象性上,现象意识的范围可以拓展到有意识的认知状态。当然,对于以上观点,认知现象学的反对者从不同方面提出质疑。对于自我认识论证,要么质疑内省的可靠性,要么否认我们对自身心理状态的认识特权,要么提出其它方式来解释这种认识特权;对于现象对比论证,还是要将案例中涉及的现象差异还原到心理意象的现象性上。对于反对者的这些做法,我们将指出其中的不足指出,因而他们并不能完成反对认知的现象性的目标,从而捍卫非还原的认知现象学观点。", 494 | "libraryCatalog": "Superlib", 495 | "thesisType": "硕士", 496 | "university": "南京大学", 497 | "url": "http://jour.ucdrs.superlib.net/views/specific/2929/thesisDetail.jsp?dxNumber=390107316149&d=73BC951F9D12D3EF5BFAD6281BFC35F0&sw=%E8%AE%A4%E7%9F%A5", 498 | "attachments": [], 499 | "tags": [ 500 | { 501 | "tag": "内省论证" 502 | }, 503 | { 504 | "tag": "现象对比论证" 505 | }, 506 | { 507 | "tag": "现象特征" 508 | }, 509 | { 510 | "tag": "自我认识论证" 511 | }, 512 | { 513 | "tag": "认知" 514 | } 515 | ], 516 | "notes": [], 517 | "seeAlso": [] 518 | } 519 | ] 520 | }, 521 | { 522 | "type": "web", 523 | "url": "http://jour.ucdrs.superlib.net/views/specific/2929/CPDetail.jsp?dxNumber=330107854501&d=FDBE0D57AC904E5720CCAD02A1BBDA49&sw=%E5%BA%94%E6%BF%80%E4%B8%8E%E8%AE%A4%E7%9F%A5%E7%9A%84ERP%E7%A0%94%E7%A9%B6", 524 | "items": [ 525 | { 526 | "itemType": "conferencePaper", 527 | "title": "慢性应激对注意控制影响的ERP证据及tDCS干预", 528 | "creators": [ 529 | { 530 | "lastName": "刘清衿", 531 | "creatorType": "author", 532 | "fieldMode": 1 533 | }, 534 | { 535 | "lastName": "刘永", 536 | "creatorType": "author", 537 | "fieldMode": 1 538 | }, 539 | { 540 | "lastName": "冷雪晨", 541 | "creatorType": "author", 542 | "fieldMode": 1 543 | }, 544 | { 545 | "lastName": "韩金凤", 546 | "creatorType": "author", 547 | "fieldMode": 1 548 | }, 549 | { 550 | "lastName": "王喜术", 551 | "creatorType": "author", 552 | "fieldMode": 1 553 | }, 554 | { 555 | "lastName": "夏锋", 556 | "creatorType": "author", 557 | "fieldMode": 1 558 | }, 559 | { 560 | "lastName": "陈红", 561 | "creatorType": "author", 562 | "fieldMode": 1 563 | } 564 | ], 565 | "date": "2019", 566 | "abstractNote": "慢性应激是指应激源持续时间超过30天或应激源持续时间较短,但对个体的影响在30天以上的应激。慢性应激不但会引起一系列身心疾病,也会影响大脑的认知功能,尤其是前额叶执行功能。测量、评估慢性应激的危害,并且找到对应的干预方法对人类心理健康十分重要。本研究即以重大考试(研究生入学考试)作为慢性应激源,以多个应激状态评估量表和血压等生理指标作为评定慢性应激的主客观指标,引用注意控制网络ANT范式,采用事件", 567 | "conferenceName": "第二十二届全国心理学学术会议", 568 | "libraryCatalog": "Superlib", 569 | "place": "西南大学心理学部;陆军军医大学西南医院全军肝胆外科研究所", 570 | "series": "第二十二届全国心理学学术会议摘要集", 571 | "url": "http://jour.ucdrs.superlib.net/views/specific/2929/CPDetail.jsp?dxNumber=330107854501&d=FDBE0D57AC904E5720CCAD02A1BBDA49&sw=%E5%BA%94%E6%BF%80%E4%B8%8E%E8%AE%A4%E7%9F%A5%E7%9A%84ERP%E7%A0%94%E7%A9%B6", 572 | "attachments": [], 573 | "tags": [ 574 | { 575 | "tag": "ERPs" 576 | }, 577 | { 578 | "tag": "tDCS" 579 | }, 580 | { 581 | "tag": "慢性应激" 582 | }, 583 | { 584 | "tag": "注意控制" 585 | } 586 | ], 587 | "notes": [], 588 | "seeAlso": [] 589 | } 590 | ] 591 | }, 592 | { 593 | "type": "web", 594 | "url": "http://jour.ucdrs.superlib.net/views/specific/2929/thesisDetail.jsp?dxNumber=390107059051&d=3F56D2F62968EC84A161D3152EBC23C5&sw=%E5%BA%94%E6%BF%80%E4%B8%8E%E8%AE%A4%E7%9F%A5%E7%9A%84ERP%E7%A0%94%E7%A9%B6", 595 | "items": [ 596 | { 597 | "itemType": "thesis", 598 | "title": "在校大学生特质焦虑人群情绪与认知冲突的ERP研究", 599 | "creators": [ 600 | { 601 | "lastName": "徐丹丹", 602 | "creatorType": "author", 603 | "fieldMode": 1 604 | }, 605 | { 606 | "lastName": "季淑梅", 607 | "creatorType": "contributor", 608 | "fieldMode": 1 609 | } 610 | ], 611 | "date": "2018", 612 | "abstractNote": "目前大多数研究者主要关注临床焦虑障碍的情绪、认知加工的特点,对于在应激条件下非临床的高特质焦虑得分者研究相对较少。而较高水平的焦虑易感倾向预示着高风险的焦虑障碍以及其它精神疾病。研究在校大学生特质焦虑人群对情绪、认知加工的特点,有助于焦虑症及其他精神疾病的早期诊断和预防。本文利用事件相关电位(Event-Related Potentials,ERP)技术,以高、低特质焦虑个体为研究对象,探讨在校大学生特质焦虑人群情绪冲突和认知冲突的ERP时空模式特点。本研究内容包含以下两部分:第一部分采用“词-面孔”Stroop范式,令16名高、低特质焦虑被试完成由“开心”和“悲伤”面孔及对应情绪词作为材料的情绪冲突任务,探讨在校大学生特质焦虑人群情绪冲突效应及冲突适应效应。对反应正确率的统计分析显示,高、低特质焦虑组均出现情绪冲突效应和冲突适应效应;在反应时上,高、低特质焦虑组均呈现情绪冲突效应,而高特质焦虑组无冲突适应效应,表明高特质焦虑人群冲突监控能力较弱。ERP结果显示,高特质焦虑组在前额区P100和中央顶区N450波幅上表现出冲突适应效应,表明早期注意和冲突监测能力增强;而高特质焦虑组前额区冲突慢电位SP波幅无冲突适应效应,表明对情绪冲突的反应选择及冲突解决能力减弱。第二部分:利用经典Simon范式,令16名高、低特质焦虑被试完成颜色-位置冲突任务,探讨在校大学生特质焦虑人群对空间位置认知冲突的解决和脑加工特征。行为结果表明,高、低特质焦虑组在反应时和正确率上表现出相同干扰模式的Simon效应。ERP结果表明,高特质焦虑组比低特质焦虑组在中央顶区的P300波幅的Simon效应量大,表现出更大的Simon效应;高特质焦虑组对冲突反应的N270和P300波幅小于低特质焦虑组,表明高特质焦虑人群对空间位置冲突加工的认知抑制能力下降。本研究通过情绪冲突和认知冲突揭示了在校大学生特质焦虑人群对冲突反应监控和抑制能力不足。", 613 | "libraryCatalog": "Superlib", 614 | "thesisType": "硕士", 615 | "university": "燕山大学", 616 | "url": "http://jour.ucdrs.superlib.net/views/specific/2929/thesisDetail.jsp?dxNumber=390107059051&d=3F56D2F62968EC84A161D3152EBC23C5&sw=%E5%BA%94%E6%BF%80%E4%B8%8E%E8%AE%A4%E7%9F%A5%E7%9A%84ERP%E7%A0%94%E7%A9%B6", 617 | "attachments": [], 618 | "tags": [ 619 | { 620 | "tag": "事件相关电位" 621 | }, 622 | { 623 | "tag": "冲突适应效应" 624 | }, 625 | { 626 | "tag": "情绪冲突" 627 | }, 628 | { 629 | "tag": "特质焦虑" 630 | }, 631 | { 632 | "tag": "认知冲突" 633 | } 634 | ], 635 | "notes": [], 636 | "seeAlso": [] 637 | } 638 | ] 639 | } 640 | ] 641 | /** END TEST CASES **/ 642 | -------------------------------------------------------------------------------- /BiliBili.js: -------------------------------------------------------------------------------- 1 | { 2 | "translatorID": "f9b132f7-8504-4a8f-b423-b61c8dae4783", 3 | "label": "BiliBili", 4 | "creator": "Felix Hui", 5 | "target": "https?://(search|www).bilibili.com/(video|bangumi|cheese|all)", 6 | "minVersion": "3.0", 7 | "maxVersion": "", 8 | "priority": 100, 9 | "inRepository": true, 10 | "translatorType": 4, 11 | "browserSupport": "gcsibv", 12 | "lastUpdated": "2020-12-19 07:48:50" 13 | } 14 | 15 | /* 16 | ***** BEGIN LICENSE BLOCK ***** 17 | 18 | Copyright © 2020 Felix Hui 19 | 20 | This file is part of Zotero. 21 | 22 | Zotero is free software: you can redistribute it and/or modify 23 | it under the terms of the GNU Affero General Public License as published by 24 | the Free Software Foundation, either version 3 of the License, or 25 | (at your option) any later version. 26 | 27 | Zotero is distributed in the hope that it will be useful, 28 | but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 | GNU Affero General Public License for more details. 31 | 32 | You should have received a copy of the GNU Affero General Public License 33 | along with Zotero. If not, see . 34 | 35 | ***** END LICENSE BLOCK ***** 36 | */ 37 | 38 | // API 參考: https://github.com/SocialSisterYi/bilibili-API-collect 39 | 40 | // eslint-disable-next-line 41 | function attr(docOrElem,selector,attr,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.getAttribute(attr):null;}function text(docOrElem,selector,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.textContent:null;} 42 | // eslint-disable-next-line 43 | function getContentsFromURL(url){var xmlhttp=new XMLHttpRequest();xmlhttp.open("GET",url,false);xmlhttp.overrideMimeType("application/json");xmlhttp.send(null);return xmlhttp.responseText;} 44 | 45 | /** 46 | * 根據 bvid 或 aid 獲取視頻信息 47 | * https://www.bilibili.com/video/BV1P7411R7bF 48 | * https://www.bilibili.com/video/av97308827 49 | */ 50 | function getInfoForVideo(url) { 51 | if (url.includes('/video/')) { 52 | var pattern, id; 53 | if ((pattern = /av\d+/).test(url)) { 54 | id = pattern.exec(url)[0].replace('av', ''); 55 | return getVideoInfo(null, id); 56 | } 57 | else if ((pattern = /BV[0-9a-zA-z]*/).test(url)) { 58 | id = pattern.exec(url)[0]; 59 | return getVideoInfo(id, null); 60 | } 61 | } 62 | return null; 63 | } 64 | 65 | /** 66 | * 根據 epid 獲取視頻信息(list) 67 | * https://www.bilibili.com/bangumi/play/ep250585 68 | */ 69 | function getInfoForEpisode(url) { 70 | if (!url.includes('/play/')) { 71 | return null; 72 | } 73 | var pattern, apiUrl, id; 74 | if ((pattern = /ep\d+/).test(url)) { 75 | id = pattern.exec(url)[0].replace('ep', ''); 76 | apiUrl = "?ep_id=" + id; 77 | } 78 | else if ((pattern = /ss\d+/).test(url)) { 79 | id = pattern.exec(url)[0].replace('ss', ''); 80 | apiUrl = "?season_id=" + id; 81 | } 82 | 83 | if (apiUrl) { 84 | var json, obj; 85 | if (url.includes('/bangumi/play/')) { 86 | apiUrl = 'https://api.bilibili.com/pgc/view/web/season' + apiUrl; 87 | json = getContentsFromURL(apiUrl); 88 | obj = JSON.parse(json); 89 | if (obj.code === 0) { 90 | // Z.debug(obj); 91 | return obj.result; 92 | } 93 | } 94 | else if (url.includes('/cheese/play/')) { 95 | apiUrl = 'https://api.bilibili.com/pugv/view/web/season' + apiUrl; 96 | json = getContentsFromURL(apiUrl); 97 | obj = JSON.parse(json); 98 | if (obj.code === 0) { 99 | // Z.debug(obj); 100 | return obj.data; 101 | } 102 | } 103 | } 104 | return null; 105 | } 106 | 107 | /** 108 | * 根據 mediaId 獲取視頻信息(list) 109 | * https://www.bilibili.com/bangumi/play/ep250585 110 | * https://www.bilibili.com/cheese/play/ep1491 111 | */ 112 | function getInfoForMedia(url) { 113 | if (url.includes('bangumi/media/')) { 114 | var pattern = /md\d+/; 115 | if (pattern.test(url)) { 116 | var id = pattern.exec(url)[0].replace('md', ''); 117 | var apiUrl = 'https://api.bilibili.com/pgc/review/user?media_id=' + id; 118 | var json = getContentsFromURL(apiUrl); 119 | var obj = JSON.parse(json); 120 | if (obj.code === 0) { 121 | // Z.debug(obj); 122 | apiUrl = 'https://api.bilibili.com/pgc/view/web/season?season_id=' + obj.result.media.season_id; 123 | json = getContentsFromURL(apiUrl); 124 | obj = JSON.parse(json); 125 | if (obj.code === 0) { 126 | // Z.debug(obj); 127 | return obj.result; 128 | } 129 | } 130 | } 131 | } 132 | return null; 133 | } 134 | 135 | /** 136 | * 根據查詢條件獲取視頻信息(list) 137 | * https://search.bilibili.com/all?keyword=%E3%80%90%E4%B8%AD%E5%AD%97%E3%80%91%E7%B2%89%E9%9B%84%E6%95%91%E5%85%B5%EF%BC%9A%E6%88%91%E4%BB%AC%E5%9C%A8%E6%97%A5%E6%9C%AC 138 | */ 139 | function getInfoForSearch(url) { 140 | if (!url.includes('//search.')) { 141 | return null; 142 | } 143 | var apiUrl = ''; 144 | var params = url.substring(url.indexOf('?') + 1); 145 | for (var item of params.split('&')) { 146 | switch (item.substring(0, item.indexOf('=')).toLowerCase()) { 147 | case 'search_type': 148 | case 'keyword': 149 | case 'order': 150 | case 'order_sort': 151 | case 'user_type': 152 | case 'duration': 153 | case 'tids': 154 | case 'category_id': 155 | case 'page': 156 | apiUrl += '&' + item; 157 | break; 158 | default: 159 | break; 160 | } 161 | } 162 | if (apiUrl.length >= 1) { 163 | apiUrl = apiUrl.substring(1); 164 | } 165 | apiUrl = 'https://api.bilibili.com/x/web-interface/search/all/v2?' + apiUrl; 166 | var json = getContentsFromURL(apiUrl); 167 | var obj = JSON.parse(json); 168 | if (obj.code === 0) { 169 | // Z.debug(obj); 170 | return obj.data; 171 | } 172 | return null; 173 | } 174 | 175 | /** 176 | * 獲取視頻分P列表信息 177 | * https://www.bilibili.com/bangumi/play/ep312267 178 | */ 179 | function getPlayList(bvid, aid) { 180 | var apiUrl = 'https://api.bilibili.com/x/player/pagelist'; 181 | if (bvid) { 182 | apiUrl += "?bvid=" + bvid; 183 | } 184 | else if (aid) { 185 | apiUrl += "?aid=" + aid; 186 | } 187 | else { 188 | return []; 189 | } 190 | 191 | var json = getContentsFromURL(apiUrl); 192 | var obj = JSON.parse(json); 193 | if (obj.code === 0) { 194 | obj = obj.data; 195 | var playList = {}; 196 | for (var item of obj) { 197 | playList[item.cid] = item; 198 | } 199 | return playList; 200 | } 201 | return null; 202 | } 203 | 204 | /** 205 | * 根據 bvid 或 aid 獲取視頻 tag 信息 206 | */ 207 | function getTags(bvid, aid) { 208 | var apiUrl = 'https://api.bilibili.com/x/tag/archive/tags'; 209 | if (bvid) { 210 | apiUrl += "?bvid=" + bvid; 211 | } 212 | else if (aid) { 213 | apiUrl += "?aid=" + aid; 214 | } 215 | else { 216 | return []; 217 | } 218 | var tags = []; 219 | var json = getContentsFromURL(apiUrl); 220 | var obj = JSON.parse(json); 221 | if (obj.code === 0) { 222 | obj = obj.data; 223 | for (var item of obj) { 224 | tags.push(item.tag_name); 225 | } 226 | } 227 | return tags; 228 | } 229 | 230 | /** 231 | * 獲取視頻描述 232 | */ 233 | function getVideoInfo(bvid, aid) { 234 | var apiUrl = 'https://api.bilibili.com/x/web-interface/view'; 235 | if (bvid) { 236 | apiUrl += "?bvid=" + bvid; 237 | } 238 | else if (aid) { 239 | apiUrl += "?aid=" + aid; 240 | } 241 | else { 242 | return null; 243 | } 244 | var json = getContentsFromURL(apiUrl); 245 | var obj = JSON.parse(json); 246 | if (obj.code === 0) { 247 | // Z.debug(obj); 248 | return obj.data; 249 | } 250 | return null; 251 | } 252 | 253 | function getSeasonInfo(url) { 254 | if (!url.includes("https")) { 255 | url = url.replace("http", "https"); 256 | } 257 | var str = getContentsFromURL(url); 258 | var pattern = /__INITIAL_STATE__=({.*});/; 259 | if (pattern.test(str)) { 260 | var json = pattern.exec(str)[1].trim(); 261 | // Z.debug(json); 262 | var obj = JSON.parse(json); 263 | return obj.mediaInfo; 264 | } 265 | return null; 266 | } 267 | 268 | function resolveForVideo(url) { 269 | var obj = getInfoForVideo(url); 270 | if (obj) { 271 | // Z.debug(JSON.stringify(obj)); 272 | var tags = getTags(obj.bvid); 273 | return { 274 | url: "https://www.bilibili.com/video/" + obj.bvid, 275 | title: obj.title, 276 | genre: obj.tname, 277 | runningTime: obj.duration, 278 | date: obj.pubdate, 279 | creators: [ 280 | obj.owner.name 281 | ], 282 | description: obj.desc, 283 | tags: tags, 284 | extra: obj.stat.like + "/" + obj.stat.view 285 | }; 286 | } 287 | return {}; 288 | } 289 | 290 | function resolveForVideoPages(obj) { 291 | var items = {}; 292 | // Z.debug(JSON.stringify(obj)); 293 | var url; 294 | var isFirst = true; 295 | var tags = null; 296 | var apiUrl = "https://www.bilibili.com/video/" + obj.bvid + '?p='; 297 | for (var pageInfo of obj.pages) { 298 | if (isFirst) { 299 | tags = getTags(pageInfo.bvid); 300 | } 301 | url = apiUrl + pageInfo.page; 302 | items[url] = { 303 | url: url, 304 | title: pageInfo.part, 305 | genre: obj.tname, 306 | runningTime: pageInfo.duration, 307 | date: obj.pubdate, 308 | creators: [ 309 | obj.owner.name 310 | ], 311 | description: obj.desc, 312 | episodeNumber: pageInfo.page, 313 | programTitle: pageInfo.part, 314 | tags: tags, 315 | extra: obj.stat.like + "/" + obj.stat.view 316 | }; 317 | isFirst = false; 318 | } 319 | return items; 320 | } 321 | 322 | function resolveForBangumi(obj) { 323 | var items = {}; 324 | // Z.debug(JSON.stringify(obj)); 325 | var seasonInfo = getSeasonInfo(obj.link); 326 | var tags = seasonInfo.styles.map(t => t.name); 327 | var areas = seasonInfo.areas.map(a => a.name).join("·"); 328 | var archive = ""; 329 | if (seasonInfo.staff) { 330 | archive += "STAFF:\n" + seasonInfo.staff; 331 | } 332 | if (seasonInfo.actors) { 333 | if (archive.length >= 1) { 334 | archive += "\n"; 335 | } 336 | archive += "ACTORS:\n" + seasonInfo.actors; 337 | } 338 | var creator; 339 | if (obj.up_info && obj.up_info.uname) { 340 | creator = obj.up_info.uname; 341 | } 342 | else { 343 | creator = seasonInfo.rights.copyright; 344 | } 345 | 346 | var runningTime, needGetRunningTime = false; 347 | var isFirst = true, playList = null; 348 | for (var episodeInfo of obj.episodes) { 349 | // get video duration 350 | runningTime = 0; 351 | if (isFirst) { 352 | playList = getPlayList(episodeInfo.bvid); 353 | needGetRunningTime = (!playList || playList.length !== obj.episodes.length); 354 | } 355 | if (playList && playList[episodeInfo.cid]) { 356 | runningTime = playList[episodeInfo.cid].duration; 357 | } 358 | items[episodeInfo.link] = { 359 | url: episodeInfo.link, 360 | title: episodeInfo.share_copy, 361 | shortTitle: seasonInfo.origin_name, 362 | genre: seasonInfo.type_name || episodeInfo.from, 363 | runningTime: runningTime, 364 | date: seasonInfo.publish.pub_date, 365 | creators: [creator], 366 | description: seasonInfo.evaluate, 367 | episodeNumber: episodeInfo.title, 368 | programTitle: episodeInfo.long_title, 369 | tags: tags, 370 | place: areas, 371 | archive: archive, 372 | rights: seasonInfo.rights.copyright, 373 | extra: seasonInfo.rating.score + "/" + seasonInfo.stat.views + "/" + seasonInfo.rating.count, 374 | aid: episodeInfo.aid, 375 | bvid: episodeInfo.bvid, 376 | cid: episodeInfo.cid, 377 | needGetRunningTime: needGetRunningTime 378 | }; 379 | isFirst = false; 380 | } 381 | return items; 382 | } 383 | 384 | function resolveForCheese(obj) { 385 | var items = {}; 386 | // Z.debug(JSON.stringify(obj)); 387 | var url; 388 | var isFirst = true; 389 | var tags = null; 390 | var apiUrl = 'https://www.bilibili.com/cheese/play/ep'; 391 | for (var episodeInfo of obj.episodes) { 392 | if (isFirst) { 393 | tags = getTags(episodeInfo.bvid); 394 | } 395 | url = apiUrl + episodeInfo.id; 396 | items[url] = { 397 | url: url, 398 | title: "[" + obj.title + "] " + episodeInfo.title, 399 | shortTitle: episodeInfo.title, 400 | genre: "cheese", 401 | runningTime: episodeInfo.duration, 402 | date: episodeInfo.release_date, 403 | creators: [obj.up_info.uname], 404 | description: obj.subtitle, 405 | episodeNumber: episodeInfo.index, 406 | programTitle: episodeInfo.title, 407 | tags: tags, 408 | extra: "0/" + obj.stat.play 409 | }; 410 | isFirst = false; 411 | } 412 | return items; 413 | } 414 | 415 | function resolveForSearch(obj) { 416 | var items = {}; 417 | var apiUrl; 418 | // Z.debug(JSON.stringify(obj)); 419 | obj = obj.result; 420 | var url; 421 | for (var resultInfo of obj) { 422 | switch (resultInfo.result_type) { 423 | case 'media_bangumi': 424 | case 'media_ft': 425 | apiUrl = 'https://www.bilibili.com/bangumi/media/md'; 426 | for (var subItem1 of resultInfo.data) { 427 | url = apiUrl + subItem1.media_id; 428 | items[url] = { 429 | url: url, 430 | title: '[' + subItem1.media_score.score + '/' + subItem1.media_score.user_count + '] ' + ZU.cleanTags(subItem1.title) 431 | }; 432 | } 433 | break; 434 | case 'video': 435 | apiUrl = 'https://www.bilibili.com/video/'; 436 | for (var subItem2 of resultInfo.data) { 437 | url = apiUrl + subItem2.bvid; 438 | items[url] = { 439 | url: url, 440 | title: ZU.cleanTags(subItem2.title) 441 | }; 442 | } 443 | break; 444 | default: 445 | break; 446 | } 447 | } 448 | return items; 449 | } 450 | 451 | function detectWeb(doc, url) { 452 | if (url.includes('/play/') || url.includes('/video/')) { 453 | if (getSearchResults(doc, url, true)) { 454 | return "multiple"; 455 | } 456 | else { 457 | return "tvBroadcast"; 458 | } 459 | } 460 | else if ((url.includes('//search.') || url.includes('/media/')) && getSearchResults(doc, url, true)) { 461 | return "multiple"; 462 | } 463 | return false; 464 | } 465 | 466 | /** 467 | * var resultItem = { 468 | * "url": { 469 | * "url": "", 470 | * "title": "", 471 | * "shortTitle": "", 472 | * "genre": "", 473 | * "runningTime": 0, 474 | * "date": 0, 475 | * "creators": [], 476 | * "description": "", 477 | * "episodeNumber": "", 478 | * "programTitle": "", 479 | * "tags": [] 480 | * "extra": "", // 評分/觀看次數/評分次數 481 | * } 482 | * } 483 | */ 484 | function getSearchResults(doc, url, checkOnly) { 485 | var items = []; 486 | var found = false; 487 | var obj; 488 | if (url.includes('/video/')) { 489 | // https://www.bilibili.com/video/BV1P7411R7bF 490 | // https://www.bilibili.com/video/av97308827 491 | obj = getInfoForVideo(url); 492 | if (!obj) { 493 | return found; 494 | } 495 | if (obj.pages && obj.pages.length >= 2) { 496 | found = true; 497 | if (checkOnly) return found; 498 | items = resolveForVideoPages(obj); 499 | } 500 | } 501 | else if (url.includes('/play/')) { 502 | obj = getInfoForEpisode(url); 503 | if (!obj) { 504 | return found; 505 | } 506 | if (url.includes('/bangumi/play/')) { 507 | // 紀錄片 508 | // https://www.bilibili.com/bangumi/play/ep250585 509 | if (obj.episodes && obj.episodes.length >= 2) { 510 | found = true; 511 | if (checkOnly) return found; 512 | // Z.debug(JSON.stringify(obj)); 513 | items = resolveForBangumi(obj); 514 | } 515 | } 516 | else if (url.includes('/cheese/play/')) { 517 | // 課程 518 | // https://www.bilibili.com/cheese/play/ep1491 519 | if (obj.episodes && obj.episodes.length >= 2) { 520 | found = true; 521 | if (checkOnly) return found; 522 | // Z.debug(JSON.stringify(obj)); 523 | items = resolveForCheese(obj); 524 | } 525 | } 526 | } 527 | else if (url.includes('/media/')) { 528 | // 紀錄片 529 | // https://www.bilibili.com/bangumi/media/md28227662/ 530 | obj = getInfoForMedia(url); 531 | if (obj && obj.episodes && obj.episodes.length >= 1) { 532 | found = true; 533 | if (checkOnly) return found; 534 | items = resolveForBangumi(obj); 535 | } 536 | } 537 | else if (url.includes('//search.')) { 538 | // 搜索 539 | // https://search.bilibili.com/all?keyword=%E9%AC%BC%E7%81%AD%E4%B9%8B%E5%88%83&from_source=nav_search&spm_id_from=666.25.b_696e7465726e6174696f6e616c486561646572.11 540 | obj = getInfoForSearch(url); 541 | if (!obj || obj.numResults <= 0) { 542 | return false; 543 | } 544 | found = true; 545 | if (checkOnly) return found; 546 | items = resolveForSearch(obj); 547 | } 548 | return found ? items : false; 549 | } 550 | 551 | function doWeb(doc, url) { 552 | if (detectWeb(doc, url) == "multiple") { 553 | var objItems = getSearchResults(doc, url, false); 554 | Zotero.selectItems(objItems, function (items) { 555 | if (items) { 556 | Object.keys(items).forEach((key) => { 557 | scrape(objItems[key], url); 558 | }); 559 | } 560 | }); 561 | } 562 | else { 563 | scrape(null, url); 564 | } 565 | } 566 | 567 | function scrape(obj, url) { 568 | if (url) { 569 | if (!obj) { 570 | obj = resolveForVideo(url); 571 | if (!obj) { 572 | return; 573 | } 574 | } 575 | if (url.includes('//search.')) { 576 | var objs = Object.values(getSearchResults(null, obj.url, false)); 577 | objs.forEach((objItem) => { 578 | scrape(objItem, objItem.url); 579 | }); 580 | return; 581 | } 582 | // get video duration 583 | if (url.includes('/bangumi/') && obj.needGetRunningTime) { 584 | var videoInfo = getVideoInfo(obj.bvid); 585 | if (videoInfo) { 586 | obj.runningTime = videoInfo.duration; 587 | obj.creators = [videoInfo.owner.name]; 588 | if (videoInfo.desc.length >= 5) { 589 | obj.description = videoInfo.desc; 590 | } 591 | } 592 | } 593 | } 594 | 595 | var item = new Zotero.Item("tvBroadcast"); 596 | 597 | // URL 598 | item.url = obj.url; 599 | 600 | // 标题 601 | item.title = obj.title; 602 | // item.title = text(doc, '#viewbox_report h1.video-title'); 603 | // Z.debug('title: ' + item.title); 604 | 605 | if (obj.place) { 606 | item.place = obj.place; 607 | } 608 | 609 | // 类型 610 | if (obj.genre) { 611 | item.libraryCatalog = obj.genre; 612 | } 613 | 614 | // 时长 615 | let hour = Math.floor(obj.runningTime / 3600 % 24); 616 | let min = Math.floor(obj.runningTime / 60 % 60); 617 | let sec = Math.floor(obj.runningTime % 60); 618 | item.runningTime = `${hour}:${min}:${sec}`; 619 | // item.runningTime = text(doc, 'span.bilibili-player-video-time-total'); 620 | // Z.debug('runningTime: ' + item.runningTime); 621 | 622 | // 发布时间 623 | if (isNaN(obj.date)) { 624 | item.date = obj.date; 625 | } 626 | else { 627 | item.date = ZU.strToISO(new Date(obj.date * 1000)); 628 | } 629 | // item.date = text(doc, '.video-data span:not([class])'); 630 | // Z.debug('date: ' + item.date); 631 | 632 | // 导演? 633 | obj.creators.forEach((author) => { 634 | if (author) { 635 | item.creators.push({ 636 | lastName: author, 637 | creatorType: "contributor", 638 | fieldMode: 1 639 | }); 640 | } 641 | }); 642 | // var author = text(doc, '#v_upinfo a.username'); 643 | // Z.debug('director: ' + author); 644 | 645 | // 摘要 646 | var description = obj.description; 647 | // var description = text(doc, '#v_desc div.info'); 648 | // Z.debug('description: ' + description); 649 | if (description) { 650 | item.abstractNote = ZU.cleanTags(description); 651 | } 652 | 653 | // 视频选集 654 | if (obj.episodeNumber) { 655 | item.episodeNumber = obj.episodeNumber; 656 | } 657 | if (obj.programTitle) { 658 | item.programTitle = obj.programTitle; 659 | } 660 | // var episodeInfo = doc.querySelector('#multi_page li[class*="on"] a'); 661 | // if (episodeInfo) { 662 | // // Z.debug('episodeInfo: ' + episodeInfo); 663 | // item.episodeNumber = text(episodeInfo, 'span.s1'); 664 | // item.programTitle = episodeInfo.title; 665 | // // item.url = episodeInfo.href; 666 | // } 667 | 668 | if (obj.archive) { 669 | item.archive = obj.archive; 670 | } 671 | 672 | if (obj.rights) { 673 | item.rights = obj.rights; 674 | } 675 | 676 | // 其他 677 | item.extra = obj.extra; 678 | 679 | // 标签 680 | if (obj.tags && obj.tags.length >= 1) { 681 | for (var tag of obj.tags) { 682 | item.tags.push(tag); 683 | } 684 | } 685 | 686 | item.complete(); 687 | } 688 | 689 | /** BEGIN TEST CASES **/ 690 | var testCases = [ 691 | { 692 | "type": "web", 693 | "url": "https://search.bilibili.com/all?keyword=%E3%80%90%E4%B8%AD%E5%AD%97%E3%80%91%E7%B2%89%E9%9B%84%E6%95%91%E5%85%B5%EF%BC%9A%E6%88%91%E4%BB%AC%E5%9C%A8%E6%97%A5%E6%9C%AC", 694 | "items": "multiple" 695 | }, 696 | { 697 | "type": "web", 698 | "url": "https://www.bilibili.com/cheese/play/ep1491", 699 | "items": "multiple" 700 | }, 701 | { 702 | "type": "web", 703 | "url": "https://www.bilibili.com/video/BV1mE41187KT?p=1", 704 | "items": "multiple" 705 | }, 706 | { 707 | "type": "web", 708 | "url": "https://www.bilibili.com/bangumi/media/md28227662/", 709 | "items": "multiple" 710 | } 711 | ] 712 | /** END TEST CASES **/ 713 | -------------------------------------------------------------------------------- /Douban.js: -------------------------------------------------------------------------------- 1 | { 2 | "translatorID": "d0a65ab7-b10c-4801-a906-05505fecc749", 3 | "label": "Douban", 4 | "creator": "Ace Strong, Felix Hui", 5 | "target": "https?://(www|book|movie)\\.douban\\.com/(subject|doulist|tag|explore|chart|tv|top|series|typerank|game)", 6 | "minVersion": "3.0", 7 | "maxVersion": "", 8 | "priority": 100, 9 | "inRepository": true, 10 | "translatorType": 4, 11 | "browserSupport": "gcsibv", 12 | "lastUpdated": "2022-02-08 16:26:40" 13 | } 14 | 15 | /* 16 | ***** BEGIN LICENSE BLOCK ***** 17 | 18 | Copyright © 2020 TAO Cheng, acestrong@gmail.com, Felix Hui, 018 19 | 20 | This file is part of Zotero. 21 | 22 | Zotero is free software: you can redistribute it and/or modify 23 | it under the terms of the GNU Affero General Public License as published by 24 | the Free Software Foundation, either version 3 of the License, or 25 | (at your option) any later version. 26 | 27 | Zotero is distributed in the hope that it will be useful, 28 | but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 | GNU Affero General Public License for more details. 31 | 32 | You should have received a copy of the GNU Affero General Public License 33 | along with Zotero. If not, see . 34 | 35 | ***** END LICENSE BLOCK ***** 36 | */ 37 | 38 | // eslint-disable-next-line 39 | function attr(docOrElem,selector,attr,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.getAttribute(attr):null;}function text(docOrElem,selector,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.textContent:null;} 40 | 41 | 42 | function value(docOrElem, selector, index) { 43 | var elem = index ? docOrElem.querySelectorAll(selector).item(index) : docOrElem.querySelector(selector); 44 | return elem ? elem.value : ''; 45 | } 46 | 47 | var TYPE_MAP = { 48 | book: 'book', 49 | movie: 'film', 50 | game: 'artwork', 51 | tv: 'tvBroadcast' 52 | }; 53 | 54 | function doPerson(item, data, creatorType) { 55 | if (!data || data.length <= 0) return; 56 | const persons = data.split('/'); 57 | for (var person of persons) { 58 | // item.creators.push(ZU.cleanAuthor(person.trim().replace(/(更多\.\.\.|. 著)/, ''), creatorType, true)); 59 | item.creators.push({ 60 | lastName: person.trim().replace(/(更多\.\.\.|. 著)/, ''), 61 | creatorType: creatorType, 62 | fieldMode: 1 63 | }); 64 | } 65 | } 66 | 67 | function doTag(item, data) { 68 | if (!data || data.length <= 0) return; 69 | const tags = data.split('/'); 70 | for (var tag of tags) { 71 | item.tags.push(tag.trim()); 72 | } 73 | } 74 | 75 | function detectType(doc, url) { 76 | var element = Object.values(doc.scripts).find(element => element.textContent.includes('answerObj')); 77 | if (element) { 78 | var pattern = /TYPE: '[a-zA-Z]+'/; 79 | if (pattern.test(element.textContent)) { 80 | var type = pattern.exec(element.textContent)[0].replace(/(TYPE:|')/g, '').trim(); 81 | if (TYPE_MAP[type]) { 82 | return TYPE_MAP[type]; 83 | } 84 | } 85 | } else if (url.includes('/game/')) { 86 | return TYPE_MAP['game']; 87 | } 88 | return false; 89 | } 90 | 91 | function getResults1(rows, funcTitle, funcRating, funcRatingPeople, filter) { 92 | if (!rows || rows.length <= 0) return false; 93 | 94 | var found = false, items = {}, titleTag; 95 | for (let row of rows) { 96 | if (filter && !filter(row)) continue; 97 | 98 | let year 99 | let abstract = row.querySelector('div.abstract') 100 | if (abstract) { 101 | if (abstract.textContent.match(/出版年:(.*)/)) { 102 | year = abstract.textContent.match(/出版年:(.*)/)[1].trim() 103 | } 104 | } else { 105 | let pub = row.querySelector('div.pub') 106 | if (pub) { 107 | let match = pub.textContent.match(/(\d{4}-\d{1,2}-?\d{0,2})/) 108 | if (match) { 109 | year = match[1] 110 | } 111 | } 112 | 113 | } 114 | titleTag = funcTitle(row); 115 | let href = titleTag.href; 116 | let title = ZU.trimInternal(titleTag.textContent); 117 | if (!href || !title) continue; 118 | 119 | found = true; 120 | var rating; 121 | if (funcRating) { 122 | rating = funcRating(row); 123 | if (!rating || rating.toString().trim().length <= 0) { 124 | rating = '0.0'; 125 | } 126 | } 127 | var ratingPeople; 128 | if (funcRatingPeople) { 129 | ratingPeople = funcRatingPeople(row); 130 | if (!ratingPeople || ratingPeople.toString().trim().length <= 0) { 131 | ratingPeople = 0; 132 | } 133 | } 134 | title = '[' + rating + '/' + ratingPeople + '] ' + title + (year ? '(' + year + ')' : ''); 135 | items[href] = title; 136 | } 137 | 138 | return found ? items : false; 139 | } 140 | 141 | function getResults2(rows, titleSelector, ratingSelector) { 142 | if (!rows || rows.length <= 0) return false; 143 | 144 | var found = false, items = {}, rating; 145 | for (let row of rows) { 146 | let href = row.href; 147 | let title = ZU.trimInternal(text(row, titleSelector)); 148 | if (!href || !title) continue; 149 | 150 | found = true; 151 | rating = ZU.trimInternal(text(row, ratingSelector)); 152 | if (!rating || rating.toString().trim().length <= 0) { 153 | rating = '0.0'; 154 | } 155 | title = '[' + rating + '] ' + title.replace(rating, ''); 156 | items[href] = title; 157 | } 158 | return found ? items : false; 159 | } 160 | 161 | function getResults3(rows, funcTitle, funcRating, funcRatingPeople) { 162 | if (!rows || rows.length <= 0) return false; 163 | 164 | var found = false, items = {}, titleTag; 165 | for (let row of rows) { 166 | titleTag = funcTitle(row); 167 | let href = titleTag.href; 168 | let title = ZU.trimInternal(titleTag.textContent); 169 | if (!href || !title) continue; 170 | 171 | found = true; 172 | var rating; 173 | if (funcRating) { 174 | rating = funcRating(row); 175 | if (!rating || rating.toString().trim().length <= 0) { 176 | rating = '0.0'; 177 | } 178 | } 179 | var ratingPeople; 180 | if (funcRatingPeople) { 181 | ratingPeople = funcRatingPeople(row); 182 | if (!ratingPeople || ratingPeople.toString().trim().length <= 0) { 183 | ratingPeople = 0; 184 | } 185 | } 186 | title = '[' + rating + '/' + ratingPeople + '] ' + title; 187 | items[href] = title; 188 | } 189 | 190 | return found ? items : false; 191 | } 192 | 193 | function detectWeb(doc, url) { 194 | if (url.includes('/subject/')) { 195 | return detectType(doc, url); 196 | } 197 | else if (url.includes('/game/')) { 198 | return url.includes('/game/explore') ? 'multiple' : TYPE_MAP['game']; 199 | } 200 | else { 201 | var element = doc.querySelector('div[class*="list-wp"]'); 202 | if (element) { 203 | Z.monitorDOMChanges(doc, { childList: true }); 204 | } 205 | if (getSearchResults(doc, url, true)) { 206 | return "multiple"; 207 | } 208 | } 209 | return false; 210 | } 211 | 212 | function getSearchResults(doc, url, checkOnly) { 213 | // 列表使用 AJAX 加载,调用该方法时还未完成加载 214 | // 检查时,不做列表的验证(只使用URL验证) 215 | if (checkOnly) return true; 216 | 217 | var rows, items; 218 | if (url.includes('movie.douban.com/chart')) { 219 | rows = doc.querySelectorAll('div.indent tr.item'); 220 | return getResults1(rows, (row) => { 221 | return row.querySelector('div.pl2 a'); 222 | }, (row) => { 223 | return text(row, 'span.rating_nums'); 224 | }, (row) => { 225 | return (text(row, 'span.rating_nums+span') || '').match(/\d+/); 226 | }); 227 | } 228 | else if (url.includes('movie.douban.com/top')) { 229 | rows = doc.querySelectorAll('ol.grid_view div.item'); 230 | items = getResults1(rows, (row) => { 231 | return row.querySelector('div.hd a'); 232 | }, (row) => { 233 | return text(row, 'div.bd div.star span.rating_num'); 234 | }, (row) => { 235 | return (text(row, 'div.bd div.star span.rating_num+span+span') || '').match(/\d+/); 236 | }); 237 | } 238 | else if (url.includes('www.douban.com/game/explore')) { 239 | rows = doc.querySelectorAll('.game-list ul li'); 240 | items = getResults3(rows, (row) => { 241 | return row.querySelector('.game-info .game-title a'); 242 | }, (row) => { 243 | return text(row, '.game-ratings strong'); 244 | }, (row) => { 245 | return (ZU.xpath(row, './/*[@class="game-ratings"]/text()')[0].textContent || '').match(/\d+/); 246 | }); 247 | } 248 | else if (url.includes('movie.douban.com/typerank')) { 249 | rows = doc.querySelectorAll('.movie-list-panel .movie-list-item'); 250 | items = getResults1(rows, (row) => { 251 | return row.querySelector('.movie-name-text a'); 252 | }, (row) => { 253 | return text(row, 'span.rating_num'); 254 | }, (row) => { 255 | return (text(row, 'span.rating_num+span') || '').match(/\d+/); 256 | }); 257 | } 258 | else if (url.includes('movie.douban.com/tag')) { 259 | rows = doc.querySelectorAll('div.list-wp a'); 260 | items = getResults2(rows, 'span.title', 'span.rate'); 261 | } 262 | else if (url.includes('movie.douban.com/explore') 263 | || url.includes('movie.douban.com/tv')) { 264 | rows = doc.querySelectorAll('div.list-wp a.item'); 265 | items = getResults2(rows, 'a p', 'a strong'); 266 | } 267 | else if (url.includes('.com/doulist/')) { 268 | rows = doc.querySelectorAll('div.article div.doulist-item'); 269 | items = getResults1(rows, (row) => { 270 | return row.querySelector('div.title a'); 271 | }, (row) => { 272 | return text(row, 'span.rating_nums'); 273 | }, (row) => { 274 | return (text(row, 'span.rating_nums+span') || '').match(/\d+/); 275 | }, (row) => { 276 | let source = text(row, 'div.source'); 277 | return source.includes('豆瓣读书') || source.includes('豆瓣电影'); 278 | }); 279 | } 280 | else if (url.includes('book.douban.com/tag') 281 | || url.includes('book.douban.com/series')) { 282 | rows = doc.querySelectorAll('li.subject-item'); 283 | items = getResults1(rows, (row) => { 284 | return row.querySelector('h2 a'); 285 | }, (row) => { 286 | return text(row, 'span.rating_nums'); 287 | }, (row) => { 288 | return (text(row, 'span.rating_nums+span') || '').match(/\d+/); 289 | }); 290 | } 291 | return items; 292 | } 293 | 294 | function doWeb(doc, url) { 295 | if (detectWeb(doc, url) == "multiple") { 296 | Zotero.selectItems(getSearchResults(doc, url, false), function (items) { 297 | if (items) ZU.processDocuments(Object.keys(items), scrape); 298 | }); 299 | } 300 | else { 301 | scrape(doc, url); 302 | } 303 | } 304 | 305 | function scrape(doc, url) { 306 | var itemType = detectType(doc, url); 307 | var item = new Zotero.Item(itemType); 308 | var zoteroCapture = doc.getElementById('zotero-capture'); 309 | if (zoteroCapture && zoteroCapture.getAttribute('visibled')) { 310 | item.title = value(doc, '#zotero-title'); 311 | var creators = doc.querySelectorAll('.zotero-class-creators'); 312 | for (let creator of creators) { 313 | var creatorType = creator.querySelector('.creatorType'); 314 | var lastName = creator.querySelector('.lastName input'); 315 | item.creators.push({ 316 | lastName: lastName.value, 317 | creatorType: creatorType.getAttribute('creatorType'), 318 | fieldMode: 1 319 | }); 320 | } 321 | item.abstractNote = value(doc, '#zotero-abstractNote'); 322 | item.series = value(doc, '#zotero-series'); 323 | item.seriesNumber = value(doc, '#zotero-seriesNumber'); 324 | item.volume = value(doc, '#zotero-volume'); 325 | item.numberOfVolumes = value(doc, '#zotero-numberOfVolumes'); 326 | item.edition = value(doc, '#zotero-edition'); 327 | item.place = value(doc, '#zotero-place'); 328 | item.publisher = value(doc, '#zotero-publisher'); 329 | item.date = value(doc, '#zotero-date'); 330 | item.numPages = value(doc, '#zotero-numPages'); 331 | item.language = value(doc, '#zotero-language'); 332 | item.ISBN = value(doc, '#zotero-ISBN'); 333 | item.shortTitle = value(doc, '#zotero-shortTitle'); 334 | item.url = value(doc, '#zotero-url'); 335 | item.archive = value(doc, '#zotero-archive'); 336 | item.archiveLocation = value(doc, '#zotero-archiveLocation'); 337 | item.callNumber = value(doc, '#zotero-callNumber'); 338 | item.rights = value(doc, '#zotero-rights'); 339 | item.extra = value(doc, '#zotero-extra'); 340 | 341 | let zoteroNote1Enabled = doc.querySelector('#zotero-note1-enabled input'); 342 | if (zoteroNote1Enabled.checked) { 343 | let notes = '

初步评价

\n

'; 344 | let zoteroNote1 = doc.querySelector('#zotero-note1'); 345 | notes += zoteroNote1.value.replace(/\t/g, ' ') + '

'; 346 | 347 | item.notes.push({ 348 | note: notes 349 | }); 350 | } 351 | 352 | let zoteroNote2Enabled = doc.querySelector('#zotero-note2-enabled input'); 353 | if (zoteroNote2Enabled.checked) { 354 | let cover_url = doc.getElementById('zotero-coverurl'); 355 | let notes = '

目录

\n

'; 356 | let zoteroNote2 = doc.querySelector('#zotero-note2'); 357 | notes += zoteroNote2.value.replace(/\t/g, ' ').replace(/\n/g, '
') + '

'; 358 | 359 | item.notes.push({ 360 | note: notes 361 | }); 362 | } 363 | 364 | let zoteroNote3Enabled = doc.querySelector('#zotero-note3-enabled input'); 365 | if (zoteroNote3Enabled.checked) { 366 | let note3 = doc.getElementById('zotero-note3'); 367 | let notes = '

豆瓣短评

\n' + note3.outerHTML; 368 | item.notes.push({ 369 | note: notes 370 | }); 371 | } 372 | 373 | let zoteroTagsEnabled = doc.querySelector('#zotero-tags-enabled input'); 374 | if (zoteroTagsEnabled.checked) { 375 | var tags = doc.querySelectorAll('#zotero-tags .tag'); 376 | for (let tag of tags) { 377 | item.tags.push({ 378 | tag: tag.innerText.trim() 379 | }); 380 | } 381 | } 382 | 383 | let zoteroAttachment1Enabled = doc.querySelector('#zotero-attachment1-enabled input'); 384 | if (zoteroAttachment1Enabled && zoteroAttachment1Enabled.checked) { 385 | var a = doc.querySelector('#zotero-attachment1'); 386 | item.attachments.push({ 387 | title: a.textContent, 388 | url: a.href, 389 | linkMode: a.getAttribute('linkMode'), 390 | mimeType: a.getAttribute('mimeType') 391 | }); 392 | } 393 | let zoteroAttachment2Enabled = doc.querySelector('#zotero-attachment2-enabled input'); 394 | if (zoteroAttachment2Enabled && zoteroAttachment2Enabled.checked) { 395 | var a = doc.querySelector('#zotero-attachment2'); 396 | item.attachments.push({ 397 | title: a.textContent, 398 | url: a.href, 399 | linkMode: a.getAttribute('linkMode'), 400 | mimeType: a.getAttribute('mimeType') 401 | }); 402 | } 403 | let zoteroAttachment3Enabled = doc.querySelector('#zotero-attachment3-enabled input'); 404 | if (zoteroAttachment3Enabled && zoteroAttachment3Enabled.checked) { 405 | var a = doc.querySelector('#zotero-attachment3'); 406 | item.attachments.push({ 407 | title: a.textContent, 408 | url: a.href, 409 | linkMode: a.getAttribute('linkMode'), 410 | mimeType: a.getAttribute('mimeType') 411 | }); 412 | } 413 | } else if (url.includes('/game/')) { 414 | // https://www.douban.com/game/26954652/ 415 | item.url = url; 416 | item.title = text(doc, '#content h1'); 417 | 418 | var infos = text(doc, '#content div.item-subject-info dl'); 419 | infos = infos.replace(/^[\xA0\s]+/gm, '') 420 | .replace(/[\xA0\s]+$/gm, '') 421 | .replace(/\n+/g, '\n') 422 | .replace(/:\n+/g, ': ') 423 | .replace(/]\n/g, ']') 424 | .replace(/】\n/g, '】') 425 | .replace(/\n\/\n/g, '/'); 426 | for (var section of Object.values(infos.split('\n'))) { 427 | if (!section || section.trim().length <= 0) continue; 428 | 429 | let index = section.indexOf(':'); 430 | if (index <= -1) continue; 431 | 432 | let key = section.substr(0, index).trim(); 433 | let value = section.substr(index + 1).trim(); 434 | switch (key) { 435 | // book 436 | case "开发商": 437 | doPerson(item, value, "author"); 438 | break; 439 | case "平台": 440 | item.artworkMedium = value; 441 | break; 442 | case "别名": 443 | item.shortTitle = value; 444 | break; 445 | case "发行商": 446 | item.rights = value; 447 | break; 448 | case "发行日期": 449 | item.date = value; 450 | break; 451 | case "类型": 452 | item.archive = value; 453 | break; 454 | default: 455 | break; 456 | } 457 | } 458 | 459 | item.abstractNote = text(doc, '#link-report p'); 460 | 461 | // 评分 & 评价人数 462 | var rating = text(doc, 'strong[property*="v:average"]'); 463 | if (rating && (rating = rating.trim()).length >= 1) { 464 | var ratingPeople = text(doc, 'div.rating_sum a.rating_people span[property="v:votes"]'); 465 | if (!ratingPeople || ratingPeople.toString().trim().length <= 0) { 466 | ratingPeople = 0; 467 | } 468 | item.extra = rating + "/" + ratingPeople; 469 | } 470 | } else { 471 | 472 | item.url = url; 473 | item.title = text(doc, 'h1 span[property="v:itemreviewed"]'); 474 | 475 | var pattern, episodeCount, runningTime, runningTimeUnit; 476 | var infos = text(doc, 'div[class*="subject"] div#info'); 477 | infos = infos.replace(/^[\xA0\s]+/gm, '') 478 | .replace(/[\xA0\s]+$/gm, '') 479 | .replace(/\n+/g, '\n') 480 | .replace(/:\n+/g, ': ') 481 | .replace(/]\n/g, ']') 482 | .replace(/】\n/g, '】') 483 | .replace(/\n\/\n/g, '/'); 484 | for (var section of Object.values(infos.split('\n'))) { 485 | if (!section || section.trim().length <= 0) continue; 486 | 487 | let index = section.indexOf(':'); 488 | if (index <= -1) continue; 489 | 490 | let key = section.substr(0, index).trim(); 491 | let value = section.substr(index + 1).trim(); 492 | switch (key) { 493 | // book 494 | case "作者": 495 | doPerson(item, value, "author"); 496 | break; 497 | case "译者": 498 | doPerson(item, value, "translator"); 499 | break; 500 | case "原作名": 501 | case "副标题": 502 | if (item.shortTitle && item.shortTitle.length >= 1) { 503 | item.shortTitle += " / " + value; 504 | } 505 | else { 506 | item.shortTitle = value; 507 | } 508 | break; 509 | case "ISBN": 510 | item.ISBN = value; 511 | break; 512 | case "页数": 513 | item.numPages = value; 514 | break; 515 | case "出版社": 516 | item.publisher = value; 517 | break; 518 | case "出品方": 519 | item.rights = value; 520 | break; 521 | case "丛书": 522 | item.series = value; 523 | break; 524 | case "出版年": 525 | item.date = value; 526 | break; 527 | // film & tvBroadcast 528 | case "导演": 529 | doPerson(item, value, "director"); 530 | break; 531 | case "编剧": 532 | doPerson(item, value, "scriptwriter"); 533 | break; 534 | case "主演": 535 | doPerson(item, value, "contributor"); 536 | break; 537 | case "类型": 538 | item.genre = value; 539 | doTag(item, value); 540 | break; 541 | case "制片国家/地区": 542 | if (itemType === 'tvBroadcast') { 543 | item.network = value; 544 | } 545 | else { 546 | item.distributor = value; 547 | } 548 | break; 549 | case "语言": 550 | item.language = value; 551 | break; 552 | case "上映日期": 553 | case "首播": 554 | // eslint-disable-next-line 555 | pattern = /\d+[-|\/]\d+[-|\/]\d+/; 556 | if (value && pattern.test(value)) { 557 | item.date = pattern.exec(value)[0]; 558 | } 559 | else { 560 | item.date = value; 561 | } 562 | break; 563 | case "季数": 564 | // item.season = value; 565 | break; 566 | case "集数": 567 | episodeCount = value; 568 | break; 569 | case "单集片长": 570 | pattern = /\d+/; 571 | if (value && pattern.test(value)) { 572 | runningTime = pattern.exec(value)[0]; 573 | runningTimeUnit = value.replace(runningTime, ""); 574 | } 575 | break; 576 | case "片长": 577 | item.runningTime = value; 578 | break; 579 | case "又名": 580 | item.shortTitle = value; 581 | break; 582 | case "IMDb链接": 583 | item.attachments.push({ 584 | url: "https://www.imdb.com/title/" + value, 585 | snapshot: false, 586 | title: "IMDb" 587 | }); 588 | break; 589 | default: 590 | break; 591 | } 592 | } 593 | 594 | if (runningTime && episodeCount) { 595 | item.runningTime = (runningTime * episodeCount).toString(); 596 | if (runningTimeUnit && runningTimeUnit.length >= 1) { 597 | item.runningTime += runningTimeUnit; 598 | } 599 | } 600 | 601 | // 摘要 602 | let abstractNote; 603 | switch (itemType) { 604 | case "book": 605 | var h2s = doc.querySelectorAll('div.related_info h2'); 606 | for (var i = 0; i < h2s.length; i++) { 607 | let h2 = h2s[i]; 608 | let span = h2.querySelector('span'); 609 | if (span && span.textContent === '内容简介') { 610 | var intro = h2.nextElementSibling.querySelector('.all div.intro'); 611 | if (!intro) { 612 | intro = h2.nextElementSibling.querySelector('div.intro'); 613 | } 614 | if (intro) { 615 | abstractNote = intro.textContent; 616 | } 617 | break; 618 | } 619 | } 620 | 621 | var doubanDir = Z.getHiddenPref('douban'); 622 | if (doubanDir && doubanDir.split(',').includes('dir')) { 623 | let id = getIDFromURL(url); 624 | let dir = text(doc, '#dir_' + id + '_full'); 625 | if (dir) { 626 | dir = dir.replace(/(([\xA0\s]*)\n([\xA0\s]*))+/g, '
').replace('· · · · · · (收起)', ''); 627 | let note1 = '

目录

\n

' + dir + '

'; 628 | item.notes.push({ 629 | note: note1 630 | }); 631 | } 632 | } 633 | break; 634 | default: 635 | abstractNote = text(doc, 'div.related-info span[class*="all"]'); 636 | if (!abstractNote) { 637 | abstractNote = text(doc, 'div.related-info span'); 638 | } 639 | break; 640 | } 641 | if (abstractNote) { 642 | item.abstractNote = abstractNote.trim().replace(/(([\xA0\s]*)\n([\xA0\s]*))+/g, '\n'); 643 | } 644 | 645 | // 标签 646 | // 豆瓣标签存在太多冗余(较理想方案是以图书在中图法中的分类作为标签) 647 | // 保留原作者(Ace Strong)对标签抓取,有需要可以自行去掉注释 648 | var doubanTags = Z.getHiddenPref('douban'); 649 | if (doubanTags && doubanTags.split(',').includes('tags')) { 650 | var tags = text(doc, 'div#db-tags-section div.indent'); 651 | if (tags) { 652 | tags = tags.replace(/((\s*)\n(\s*))+/g, '\n'); 653 | for (var tag of tags.split('\n')) { 654 | if (!tag || tag.trim().length <= 0) continue; 655 | item.tags.push(tag); 656 | } 657 | } 658 | } 659 | 660 | // 中图clc作为标签,需要安装油猴插件:https://greasyfork.org/zh-CN/scripts/408682 661 | var clc = text(doc, '#clc'); 662 | if (clc) { 663 | item.archiveLocation = clc; 664 | } 665 | var subject = text(doc, '#subject'); 666 | if (subject) { 667 | item.archive = subject; 668 | } 669 | 670 | // 评分 & 评价人数 671 | var rating = text(doc, 'strong[property*="v:average"]'); 672 | if (rating && (rating = rating.trim()).length >= 1) { 673 | var ratingPeople = text(doc, 'div.rating_sum a.rating_people span[property="v:votes"]'); 674 | if (!ratingPeople || ratingPeople.toString().trim().length <= 0) { 675 | ratingPeople = 0; 676 | } 677 | item.extra = rating + "/" + ratingPeople; 678 | } 679 | } 680 | 681 | item.complete(); 682 | } 683 | 684 | function getIDFromURL(url) { 685 | if (!url) return ''; 686 | 687 | var id = url.match(/subject\/.*\//g); 688 | if (!id) return ''; 689 | 690 | return id[0].replace(/subject|\//g, ''); 691 | }/** BEGIN TEST CASES **/ 692 | var testCases = [ 693 | { 694 | "type": "web", 695 | "url": "https://movie.douban.com/subject/1292052/", 696 | "items": [ 697 | { 698 | "itemType": "film", 699 | "title": "肖申克的救赎 The Shawshank Redemption", 700 | "creators": [ 701 | { 702 | "lastName": "弗兰克·德拉邦特", 703 | "creatorType": "director", 704 | "fieldMode": 1 705 | }, 706 | { 707 | "lastName": "弗兰克·德拉邦特", 708 | "creatorType": "scriptwriter", 709 | "fieldMode": 1 710 | }, 711 | { 712 | "lastName": "斯蒂芬·金", 713 | "creatorType": "scriptwriter", 714 | "fieldMode": 1 715 | }, 716 | { 717 | "lastName": "蒂姆·罗宾斯", 718 | "creatorType": "contributor", 719 | "fieldMode": 1 720 | }, 721 | { 722 | "lastName": "摩根·弗里曼", 723 | "creatorType": "contributor", 724 | "fieldMode": 1 725 | }, 726 | { 727 | "lastName": "鲍勃·冈顿", 728 | "creatorType": "contributor", 729 | "fieldMode": 1 730 | }, 731 | { 732 | "lastName": "威廉姆·赛德勒", 733 | "creatorType": "contributor", 734 | "fieldMode": 1 735 | }, 736 | { 737 | "lastName": "克兰西·布朗", 738 | "creatorType": "contributor", 739 | "fieldMode": 1 740 | }, 741 | { 742 | "lastName": "吉尔·贝罗斯", 743 | "creatorType": "contributor", 744 | "fieldMode": 1 745 | }, 746 | { 747 | "lastName": "马克·罗斯顿", 748 | "creatorType": "contributor", 749 | "fieldMode": 1 750 | }, 751 | { 752 | "lastName": "詹姆斯·惠特摩", 753 | "creatorType": "contributor", 754 | "fieldMode": 1 755 | }, 756 | { 757 | "lastName": "杰弗里·德曼", 758 | "creatorType": "contributor", 759 | "fieldMode": 1 760 | }, 761 | { 762 | "lastName": "拉里·布兰登伯格", 763 | "creatorType": "contributor", 764 | "fieldMode": 1 765 | }, 766 | { 767 | "lastName": "尼尔·吉恩托利", 768 | "creatorType": "contributor", 769 | "fieldMode": 1 770 | }, 771 | { 772 | "lastName": "布赖恩·利比", 773 | "creatorType": "contributor", 774 | "fieldMode": 1 775 | }, 776 | { 777 | "lastName": "大卫·普罗瓦尔", 778 | "creatorType": "contributor", 779 | "fieldMode": 1 780 | }, 781 | { 782 | "lastName": "约瑟夫·劳格诺", 783 | "creatorType": "contributor", 784 | "fieldMode": 1 785 | }, 786 | { 787 | "lastName": "祖德·塞克利拉", 788 | "creatorType": "contributor", 789 | "fieldMode": 1 790 | }, 791 | { 792 | "lastName": "保罗·麦克兰尼", 793 | "creatorType": "contributor", 794 | "fieldMode": 1 795 | }, 796 | { 797 | "lastName": "芮妮·布莱恩", 798 | "creatorType": "contributor", 799 | "fieldMode": 1 800 | }, 801 | { 802 | "lastName": "阿方索·弗里曼", 803 | "creatorType": "contributor", 804 | "fieldMode": 1 805 | }, 806 | { 807 | "lastName": "V·J·福斯特", 808 | "creatorType": "contributor", 809 | "fieldMode": 1 810 | }, 811 | { 812 | "lastName": "弗兰克·梅德拉诺", 813 | "creatorType": "contributor", 814 | "fieldMode": 1 815 | }, 816 | { 817 | "lastName": "马克·迈尔斯", 818 | "creatorType": "contributor", 819 | "fieldMode": 1 820 | }, 821 | { 822 | "lastName": "尼尔·萨默斯", 823 | "creatorType": "contributor", 824 | "fieldMode": 1 825 | }, 826 | { 827 | "lastName": "耐德·巴拉米", 828 | "creatorType": "contributor", 829 | "fieldMode": 1 830 | }, 831 | { 832 | "lastName": "布赖恩·戴拉特", 833 | "creatorType": "contributor", 834 | "fieldMode": 1 835 | }, 836 | { 837 | "lastName": "唐·麦克马纳斯", 838 | "creatorType": "contributor", 839 | "fieldMode": 1 840 | } 841 | ], 842 | "date": "1994-09-10(多伦多电影节) / 1994-10-14(美国)", 843 | "abstractNote": "20世纪40年代末,小有成就的青年银行家安迪(蒂姆·罗宾斯 Tim Robbins 饰)因涉嫌杀害妻子及她的情人而锒铛入狱。在这座名为鲨堡的监狱内,希望似乎虚无缥缈,终身监禁的惩罚无疑注定了安迪接下来灰暗绝望的人生。未过多久,安迪尝试接近囚犯中颇有声望的瑞德(摩根·弗 里曼 Morgan Freeman 饰),请求对方帮自己搞来小锤子。以此为契机,二人逐渐熟稔,安迪也仿佛在鱼龙混杂、罪恶横生、黑白混淆的牢狱中找到属于自己的求生之道。他利用自身的专业知识,帮助监狱管理层逃税、洗黑钱,同时凭借与瑞德的交往在犯人中间也渐渐受到礼遇。表面看来,他已如瑞德那样对那堵高墙从憎恨转变为处之泰然,但是对自由的渴望仍促使他朝着心中的希望和目标前进。而关于其罪行的真相,似乎更使这一切朝前推进了一步……\n   本片根据著名作家斯蒂芬·金(Stephen Edwin King)的原著改编。", 844 | "distributor": "美国", 845 | "extra": "9.7/2069725", 846 | "genre": "剧情 / 犯罪", 847 | "language": "英语", 848 | "libraryCatalog": "Douban Movie", 849 | "runningTime": "142分钟", 850 | "shortTitle": "月黑高飞(港) / 刺激1995(台) / 地狱诺言 / 铁窗岁月 / 消香克的救赎", 851 | "url": "https://movie.douban.com/subject/1292052/", 852 | "attachments": [], 853 | "tags": [ 854 | { 855 | "tag": "剧情" 856 | }, 857 | { 858 | "tag": "犯罪" 859 | } 860 | ], 861 | "notes": [], 862 | "seeAlso": [] 863 | } 864 | ] 865 | }, 866 | { 867 | "type": "web", 868 | "url": "https://movie.douban.com/tag/#/?sort=U&range=0,10&tags=%E7%94%B5%E5%BD%B1", 869 | "items": "multiple" 870 | }, 871 | { 872 | "type": "web", 873 | "url": "https://movie.douban.com/chart", 874 | "items": "multiple" 875 | }, 876 | { 877 | "type": "web", 878 | "url": "https://movie.douban.com/subject/26939247/", 879 | "items": [ 880 | { 881 | "itemType": "tvBroadcast", 882 | "title": "夏目友人帐 第六季 夏目友人帳 陸", 883 | "creators": [ 884 | { 885 | "lastName": "大森贵弘", 886 | "creatorType": "director", 887 | "fieldMode": 1 888 | }, 889 | { 890 | "lastName": "出合小都美", 891 | "creatorType": "director", 892 | "fieldMode": 1 893 | }, 894 | { 895 | "lastName": "绿川幸", 896 | "creatorType": "scriptwriter", 897 | "fieldMode": 1 898 | }, 899 | { 900 | "lastName": "村井贞之", 901 | "creatorType": "scriptwriter", 902 | "fieldMode": 1 903 | }, 904 | { 905 | "lastName": "神谷浩史", 906 | "creatorType": "contributor", 907 | "fieldMode": 1 908 | }, 909 | { 910 | "lastName": "井上和彦", 911 | "creatorType": "contributor", 912 | "fieldMode": 1 913 | }, 914 | { 915 | "lastName": "小林沙苗", 916 | "creatorType": "contributor", 917 | "fieldMode": 1 918 | }, 919 | { 920 | "lastName": "石田彰", 921 | "creatorType": "contributor", 922 | "fieldMode": 1 923 | }, 924 | { 925 | "lastName": "堀江一真", 926 | "creatorType": "contributor", 927 | "fieldMode": 1 928 | }, 929 | { 930 | "lastName": "木村良平", 931 | "creatorType": "contributor", 932 | "fieldMode": 1 933 | }, 934 | { 935 | "lastName": "菅沼久义", 936 | "creatorType": "contributor", 937 | "fieldMode": 1 938 | }, 939 | { 940 | "lastName": "泽城美雪", 941 | "creatorType": "contributor", 942 | "fieldMode": 1 943 | }, 944 | { 945 | "lastName": "佐藤利奈", 946 | "creatorType": "contributor", 947 | "fieldMode": 1 948 | }, 949 | { 950 | "lastName": "伊藤美纪 Miki Itô", 951 | "creatorType": "contributor", 952 | "fieldMode": 1 953 | }, 954 | { 955 | "lastName": "伊藤荣次", 956 | "creatorType": "contributor", 957 | "fieldMode": 1 958 | }, 959 | { 960 | "lastName": "诹访部顺一", 961 | "creatorType": "contributor", 962 | "fieldMode": 1 963 | } 964 | ], 965 | "date": "2017-04-11", 966 | "abstractNote": "与温柔友人们度过的,值得珍惜的每一天——\n   美丽而虚幻的,人与妖的物语。\n \n   从小就能看见妖怪的少年·夏目贵志,继承了祖母玲子的遗产“友人帐”,与自称保镖的猫咪老师一起,开始将名字返还给被束缚在友人帐中的妖怪。\n \n   通过与妖怪及与之相关的人们接触,开始摸索自己前进之路的夏目,在与心灵相通的朋友们帮助下,设法守护自己重要的每一天。", 967 | "distributor": "日本", 968 | "extra": "9.6/31280", 969 | "genre": "剧情 / 动画 / 奇幻", 970 | "language": "日语", 971 | "libraryCatalog": "Douban Movie", 972 | "runningTime": "264分钟", 973 | "shortTitle": "妖怪联络簿 六(台) / Natsume's Book of Friends 6 / Natsume Yuujinchou Roku", 974 | "url": "https://movie.douban.com/subject/26939247/", 975 | "attachments": [ 976 | { 977 | "snapshot": false, 978 | "title": "IMDb" 979 | } 980 | ], 981 | "tags": [ 982 | { 983 | "tag": "剧情" 984 | }, 985 | { 986 | "tag": "动画" 987 | }, 988 | { 989 | "tag": "奇幻" 990 | } 991 | ], 992 | "notes": [], 993 | "seeAlso": [] 994 | } 995 | ] 996 | }, 997 | { 998 | "type": "web", 999 | "url": "https://www.douban.com/game/26954660/", 1000 | "items": [ 1001 | { 1002 | "itemType": "artwork", 1003 | "title": "马力欧卡丁车8 豪华版 マリオカート8 デラックス", 1004 | "creators": [ 1005 | { 1006 | "lastName": "Nintendo EAD", 1007 | "creatorType": "author", 1008 | "fieldMode": 1 1009 | }, 1010 | { 1011 | "lastName": "Bandai Namco Entertainment", 1012 | "creatorType": "author", 1013 | "fieldMode": 1 1014 | } 1015 | ], 1016 | "date": "2017-04-28", 1017 | "abstractNote": "《马里奥赛车8 豪华版》。该版本是马里奥赛车8的加强版,会包括原作的追加下载内容以及一些新角色,新模式和新的对战赛道地图。本作于2017年4月28日在任天堂Switch推出。", 1018 | "archive": "游戏/竞速", 1019 | "artworkMedium": "Nintendo Switch", 1020 | "extra": "8.9/6348", 1021 | "libraryCatalog": "Douban", 1022 | "rights": "Nintendo", 1023 | "shortTitle": "马里奥赛车8 DX / Mario Kart 8 Deluxe", 1024 | "url": "https://www.douban.com/game/26954660/", 1025 | "attachments": [], 1026 | "tags": [], 1027 | "notes": [], 1028 | "seeAlso": [] 1029 | } 1030 | ] 1031 | } 1032 | ] 1033 | /** END TEST CASES **/ 1034 | --------------------------------------------------------------------------------