├── .DS_Store ├── figure ├── logo.png ├── logo1.png ├── result.png └── instruction.jpg ├── LICENSE ├── README-ZH.md ├── README.md └── Overleaf-Bib-Helper.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLNLP-World/Overleaf-Bib-Helper/HEAD/.DS_Store -------------------------------------------------------------------------------- /figure/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLNLP-World/Overleaf-Bib-Helper/HEAD/figure/logo.png -------------------------------------------------------------------------------- /figure/logo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLNLP-World/Overleaf-Bib-Helper/HEAD/figure/logo1.png -------------------------------------------------------------------------------- /figure/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLNLP-World/Overleaf-Bib-Helper/HEAD/figure/result.png -------------------------------------------------------------------------------- /figure/instruction.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLNLP-World/Overleaf-Bib-Helper/HEAD/figure/instruction.jpg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Xunjian Yin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README-ZH.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Overleaf-Bib-Helper

4 |
5 | 6 |

7 | 一个用户脚本,用于增强 Overleaf 功能,支持在 Overleaf 编辑器中直接从 DBLP 和 Google Scholar 搜索文章并获取 BibTeX 条目。 8 |

9 | 10 |

11 | 12 | 从 Greasy Fork 安装 13 | 14 | 15 | 版本 16 | 17 | 18 | 许可证 19 | 20 | 21 | Stars 22 | 23 | 24 | Forks 25 | 26 | 27 | Issues 28 | 29 | 30 | 欢迎 PR 31 | 32 |

33 | 34 | --- 35 | 36 |
37 |

38 | 中文文档 • 39 | 安装 • 40 | 使用方法 • 41 | 支持的来源 • 42 | 故障排除 • 43 | 免责声明 • 44 | 更新日志 • 45 | 许可证 • 46 | 贡献 • 47 | 联系方式 • 48 | 组织者 • 49 | 贡献者 • 50 | 致谢 51 |

52 |
53 | 54 | ## 动机 55 | 撰写 LaTeX 文档时通常需要包含大量学术参考文献。手动搜索和格式化 BibTeX 条目非常耗时。Overleaf-Bib-Helper 通过将 DBLP 和 Google Scholar 的搜索功能集成到 Overleaf 界面中,简化了这一过程,使用户能够快速查找和复制 BibTeX 条目,省时省力。 56 | 57 | ## 功能 58 | - 在 Overleaf 中搜索 DBLP 或 Google Scholar 的学术文章。 59 | - 一键获取并复制 BibTeX 条目。 60 | - 可配置的结果数量(5、10、20 或 50 个结果)。 61 | - 可滚动的搜索结果列表,便于浏览。 62 | - 键盘快捷键:回车键搜索,Esc 键关闭弹出窗口。 63 | - 支持多个 Google Scholar 镜像以提高访问性。 64 | 65 | ## 更新日志 66 | - **2025-04-14**:新增 Google Scholar 高级搜索选项支持(v1.3)。 67 | - **2025-04-10**:新增对 cn.overleaf.com 和 cn.overleaf.com 域名的支持(v1.2)。 68 | - **2025-04-09**:初始版本,包含 DBLP 和 Google Scholar 的基本功能(v1.1)。 69 | 70 | ## 安装 71 | ### 步骤 1:安装 Tampermonkey 72 | Tampermonkey 是一个运行用户脚本(如 Overleaf-Bib-Helper)所需的浏览器扩展。请按照以下步骤操作: 73 | 1. **下载 Tampermonkey**: 74 | - **Chrome**:[Chrome 网上应用店](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo) 75 | - **Firefox**:[Mozilla 附加组件](https://addons.mozilla.org/en-US/firefox/addon/tampermonkey/) 76 | - **Edge**:[Microsoft Edge 附加组件](https://microsoftedge.microsoft.com/addons/detail/%E7%AF%A1%E6%94%B9%E7%8C%B4/iikmkjmpaadaobahmlepeloendndfphd) 77 | - **Safari**:[App Store](https://apps.apple.com/us/app/tampermonkey/id1482490089)(需要 macOS) 78 | 2. **启用 Tampermonkey**: 79 | - 安装完成后,点击浏览器工具栏中的 Tampermonkey 图标,确保其已启用。 80 | 3. **启用扩展的开发者模式**: 81 | - 对于 Chrome,前往扩展页面(`chrome://extensions/`)并启用开发者模式。 82 | 83 | ### 步骤 2:安装 Overleaf-Bib-Helper 84 | 您可以通过以下两种方式安装脚本: 85 | 86 | #### 选项 1:从 Greasy Fork 安装(推荐) 87 | 1. 访问 [Greasy Fork 页面](https://greasyfork.org/zh-CN/scripts/532304-overleaf-bib-helper)。 88 | 2. 点击 **“安装此脚本”** 按钮。 89 | 3. Tampermonkey 将打开一个确认窗口,点击 **“安装”** 添加脚本。 90 | 4. 脚本将在 Overleaf 项目页面(`https://www.overleaf.com/project/*`)自动激活。 91 | 5. 为保持脚本更新,请在 Tampermonkey 设置中启用自动更新。 92 | 93 | #### 选项 2:从 GitHub 安装 94 | 1. 前往 [GitHub 仓库](https://github.com/MLNLP-World/Overleaf-Bib-Helper)。 95 | 2. 打开仓库中的 `Overleaf-Bib-Helper.js` 文件。 96 | 3. 复制整个脚本内容。 97 | 4. 在浏览器中,点击 Tampermonkey 图标 > **“创建新脚本”**。 98 | 5. 将复制的代码粘贴到编辑器中,替换默认模板。 99 | 6. 在 Tampermonkey 编辑器中点击 **文件 > 保存**。 100 | 7. 脚本将在 Overleaf 项目页面上激活。 101 | 8. **注意**:从 GitHub 手动安装时,请定期检查仓库更新并重新安装。 102 | 103 | ## 使用方法 104 | ### 打开工具 105 | 1. 在浏览器中打开一个 Overleaf 项目(`https://www.overleaf.com/project/*`)。 106 | 2. 在 Overleaf 工具栏中查找新图标(一个类似文档的小图标)。 107 | 3. 点击图标打开搜索弹出窗口。 108 | 109 |
110 | 111 |
112 | 113 | ### 搜索文章 114 | 1. **输入查询**:在输入框中键入搜索词(例如文章标题、作者或关键词)。 115 | 2. **选择来源**:从“来源”下拉菜单中选择“DBLP”或“Google Scholar”。 116 | - **DBLP**:适合计算机科学文献,数据结构化。 117 | - **Google Scholar**:覆盖更广泛的学科,但可能需要 CAPTCHA 验证。 118 | 3. **设置结果数量**:从“结果”下拉菜单选择 5、10、20 或 50 个结果。 119 | 4. **开始搜索**: 120 | - 按 **回车键** 或点击放大镜图标。 121 | 5. 搜索结果将显示在输入框下方的可滚动列表中。 122 | 123 | ### 复制 BibTeX 124 | 1. 点击列表中的任一结果(例如“标题@作者”)。 125 | 2. BibTeX 条目将复制到剪贴板。 126 | 3. 将显示通知确认成功(“复制成功”)或报告错误(“复制失败”)。 127 | 128 |
129 | 130 |
131 | 132 | ### 关闭弹出窗口 133 | - 按 **Esc 键** 或再次点击工具栏图标。 134 | 135 | ## 支持的来源 136 | - **DBLP**:计算机科学领域的综合文献数据库,提供可靠的 BibTeX 条目。 137 | - **Google Scholar**:覆盖更广泛的学术搜索引擎,可能包含更近期或跨学科的内容,但可能需要用户验证(例如 CAPTCHA)。 138 | 139 | ## 故障排除 140 | - **脚本不起作用?** 141 | - 确保浏览器已为扩展启用 **开发者模式**。 142 | - 确保 Tampermonkey 已启用且脚本处于激活状态。 143 | - 确认您在 Overleaf 项目页面上。 144 | - 尝试从 Greasy Fork 重新加载或重新安装。 145 | - **没有结果?** 146 | - 检查查询是否有拼写错误。 147 | - 确保已授予插件搜索权限。 148 | - 尝试在 DBLP 和 Google Scholar 之间切换。 149 | - **Google Scholar 问题?** 150 | - 如果 CAPTCHA 阻止访问,请在打开的标签页中完成验证并重试。 151 | 152 | ## 免责声明 153 | 尽管 Overleaf-Bib-Helper 旨在提供无缝体验,但请注意,它依赖外部服务(DBLP 和 Google Scholar),这些服务的 API 可能发生变化或需要用户验证(例如 CAPTCHA)。请谨慎使用此工具,并在将检索的 BibTeX 条目纳入文档前始终进行验证。 154 | 155 | ## 许可证 156 | 本项目采用 MIT 许可证,详情见 [LICENSE.md](https://github.com/MLNLP-World/Overleaf-Bib-Helper/blob/main/LICENSE.md)。 157 | 158 | ## 贡献 159 | 欢迎 fork [GitHub 仓库](https://github.com/MLNLP-World/Overleaf-Bib-Helper),提交问题或通过拉取请求提出改进! 160 | 161 | ## 联系方式 162 | 如有任何问题或建议,请发送邮件至 [Xunjian Yin](mailto:xjyin@pku.edu.cn) 或在此处创建 GitHub 问题。 163 | 164 | ## 组织者 165 | 166 | 167 | ## 贡献者 168 | 169 | 170 | 171 | ## 致谢 172 | 受类似工具和学术界对高效参考管理的启发。 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Overleaf-Bib-Helper

4 |
5 | 6 |

7 | A UserScript to enhance Overleaf by allowing article searches and BibTeX retrieval from DBLP and Google Scholar directly within the Overleaf editor. 8 |

9 | 10 |

11 | 12 | Install from Greasy Fork 13 | 14 | 15 | Version 16 | 17 | 18 | License 19 | 20 | 21 | Stars 22 | 23 | 24 | Forks 25 | 26 | 27 | Issues 28 | 29 | 30 | PRs Welcome 31 | 32 |

33 | 34 | --- 35 | 36 |
37 |

38 | 中文文档 • 39 | Installation • 40 | Usage • 41 | Supported Sources • 42 | Troubleshooting • 43 | Disclaimer • 44 | Changelog • 45 | License • 46 | Contributing • 47 | Contact • 48 | Organizers • 49 | Contributors • 50 | Acknowledgments 51 |

52 |
53 | 54 | 55 | 56 | 57 | ## Motivation 58 | Writing LaTeX documents often requires including numerous academic references. Manually searching for and formatting BibTeX entries can be time-consuming. Overleaf-Bib-Helper streamlines this process by integrating search functionality from DBLP and Google Scholar right into the Overleaf interface, allowing users to quickly find and copy BibTeX entries with minimal effort. 59 | 60 | ## Features 61 | - Search for academic articles from DBLP or Google Scholar within Overleaf. 62 | - Retrieve and copy BibTeX entries with a single click. 63 | - Configurable result counts (5, 10, 20, or 50 results). 64 | - Scrollable results list for easy browsing. 65 | - Keyboard shortcuts: Enter to search, Esc to close the popup. 66 | - Supports multiple Google Scholar mirrors for accessibility. 67 | 68 | ## Changelog 69 | - **2025-04-14**: Added support for advanced search options in Google Scholar (v1.3). 70 | - **2025-04-10**: Added support for cn.overleaf.com and cn.overleaf.com domains (v1.2). 71 | - **2025-04-09**: Initial release with basic functionality for DBLP and Google Scholar (v1.1). 72 | 73 | 74 | ## Installation 75 | ### Step 1: Install Tampermonkey 76 | Tampermonkey is a browser extension required to run UserScripts like Overleaf-Bib-Helper. Follow these steps: 77 | 1. **Download Tampermonkey**: 78 | - **Chrome**: [Chrome Web Store](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo) 79 | - **Firefox**: [Mozilla Add-ons](https://addons.mozilla.org/en-US/firefox/addon/tampermonkey/) 80 | - **Edge**: [Microsoft Edge Add-ons](https://microsoftedge.microsoft.com/addons/detail/%E7%AF%A1%E6%94%B9%E7%8C%B4/iikmkjmpaadaobahmlepeloendndfphd) 81 | - **Safari**: [App Store](https://apps.apple.com/us/app/tampermonkey/id1482490089) (requires macOS) 82 | 2. **Enable Tampermonkey**: 83 | - After installation, click the Tampermonkey icon in your browser’s toolbar and ensure it’s enabled. 84 | - Note: 85 | 3. **Enable Developer Mode for the Extension**: 86 | - For Chrome, go to the extensions page (`chrome://extensions/`) and enable Developer mode. 87 | 88 | ### Step 2: Install Overleaf-Bib-Helper 89 | You can install the script in one of two ways: 90 | 91 | #### Option 1: Install from Greasy Fork (Recommended) 92 | 1. Visit the [Greasy Fork page](https://greasyfork.org/zh-CN/scripts/532304-overleaf-bib-helper). 93 | 2. Click the **"Install this script"** button. 94 | 3. Tampermonkey will open a confirmation window. Click **"Install"** to add the script. 95 | 4. The script will automatically activate on Overleaf project pages (`https://www.overleaf.com/project/*`). 96 | 5. To keep the script updated, enable auto-updates in Tampermonkey settings. 97 | 98 | #### Option 2: Install from GitHub 99 | 1. Go to the [GitHub repository](https://github.com/MLNLP-World/Overleaf-Bib-Helper). 100 | 2. Open the `Overleaf-Bib-Helper.js` file in the repository. 101 | 3. Copy the entire script content. 102 | 4. In your browser, click the Tampermonkey icon > **"Create a new script"**. 103 | 5. Paste the copied code into the editor, replacing the default template. 104 | 6. Click **File > Save** in the Tampermonkey editor. 105 | 7. The script will be active on Overleaf project pages. 106 | 8. **Note:** For manual installations from GitHub, please check the repository periodically for updates and reinstall as needed. 107 | 108 | ## Usage 109 | ### Opening the Tool 110 | 1. Open an Overleaf project in your browser (`https://www.overleaf.com/project/*`). 111 | 2. Look for a new icon in the Overleaf toolbar (a small document-like icon). 112 | 3. Click the icon to open the search popup. 113 | 114 |
115 | 116 |
117 | 118 | ### Searching for Articles 119 | 1. **Enter a Query**: Type your search term (e.g., article title, author, or keywords) into the input field. 120 | 2. **Select Source**: Choose "DBLP" or "Google Scholar" from the "Source" dropdown. 121 | - **DBLP**: Best for computer science literature with structured data. 122 | - **Google Scholar**: Broader coverage across various fields but may require CAPTCHA verification. 123 | 3. **Set Result Count**: Select 5, 10, 20, or 50 results from the "Results" dropdown. 124 | 4. **Start Search**: 125 | - Press the **Enter** key or click the magnifying glass icon. 126 | 5. Results will appear in a scrollable list below the input field. 127 | 128 | ### Copying BibTeX 129 | 1. Click on any result in the list (e.g., "Title@Author"). 130 | 2. The BibTeX entry will be copied to your clipboard. 131 | 3. A notification will confirm success ("Copy successfully") or report an error ("Copy failed"). 132 | 133 |
134 | 135 |
136 | 137 | ### Closing the Popup 138 | - Press **Esc** or click the toolbar icon again. 139 | 140 | ## Supported Sources 141 | - **DBLP**: A comprehensive computer science bibliography providing reliable BibTeX entries. 142 | - **Google Scholar**: A broader academic search engine that may include more recent or interdisciplinary works but might require user verification (e.g., CAPTCHA). 143 | 144 | ## Troubleshooting 145 | - **Script Not Working?** 146 | - Ensure your browser has **developer mode** enabled for extensions. 147 | - Ensure Tampermonkey is enabled and the script is active. 148 | - Verify you’re on an Overleaf project page. 149 | - Reload or reinstall from Greasy Fork. 150 | - **No Results?** 151 | - Check your query for typos. 152 | - Ensure you have granted the plugin search permissions. 153 | - Try switching between DBLP and Google Scholar. 154 | - **Google Scholar Issues?** 155 | - If CAPTCHA blocks access, complete it in the opened tab and retry. 156 | 157 | ## Disclaimer 158 | While Overleaf-Bib-Helper aims to provide a seamless experience, please note that it relies on external services (DBLP and Google Scholar) which may change their APIs or require user verification (e.g., CAPTCHA). Use this tool at your own discretion and always verify retrieved BibTeX entries before including them in your documents. 159 | 160 | 161 | ## License 162 | This project is licensed under the MIT License - see [LICENSE.md](https://github.com/MLNLP-World/Overleaf-Bib-Helper/blob/main/LICENSE.md) for details. 163 | 164 | ## Contributing 165 | Feel free to fork the [GitHub repository](https://github.com/MLNLP-World/Overleaf-Bib-Helper), submit issues, or create pull requests with improvements! 166 | 167 | ## Contact 168 | Please email [Xunjian Yin](mailto:xjyin@pku.edu.cn) or create Github issues here if you have any questions or suggestions. 169 | 170 | ## Organizers 171 | 172 | 173 | ## Contributors 174 | 175 | 176 | 177 | 178 | ## Acknowledgments 179 | Inspired by similar tools and the academic community’s need for efficient reference management. 180 | 181 | -------------------------------------------------------------------------------- /Overleaf-Bib-Helper.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Overleaf-Bib-Helper 3 | // @namespace com.Xunjian.overleaf 4 | // @version 1.3 5 | // @description Enhances Overleaf by allowing article searches and BibTeX retrieval from DBLP and Google Scholar 6 | // @author Xunjian Yin 7 | // @match https://www.overleaf.com/project/* 8 | // @match https://cn.overleaf.com/project* 9 | // @match https://latex.pku.edu.cn/project/* 10 | // @icon https://www.overleaf.com/favicon.ico 11 | // @require https://cdn.jsdelivr.net/npm/@floating-ui/core@1.6.8 12 | // @require https://cdn.jsdelivr.net/npm/@floating-ui/dom@1.6.12 13 | // @require https://cdn.jsdelivr.net/npm/simple-notify@1.0.6/dist/simple-notify.min.js 14 | // @resource notifycss https://cdn.jsdelivr.net/npm/simple-notify/dist/simple-notify.css 15 | // @grant GM_setClipboard 16 | // @grant GM_xmlhttpRequest 17 | // @grant GM_getResourceText 18 | // @grant GM_addStyle 19 | // @grant GM_setValue 20 | // @grant GM_getValue 21 | // @grant GM_openInTab 22 | // @license MIT 23 | // ==/UserScript== 24 | 25 | (function () { 26 | 'use strict'; 27 | GM_addStyle(GM_getResourceText('notifycss')); 28 | injectScript(); 29 | setInterval(() => { 30 | if (!document.getElementById('toggleIcon')) { 31 | injectScript(); 32 | } 33 | }, 2000); 34 | })(); 35 | 36 | function injectScript() { 37 | waitUtil('div.ol-cm-toolbar-button-group.ol-cm-toolbar-end', el => { 38 | let iconBox = createToggleIcon(); 39 | el.appendChild(iconBox); 40 | 41 | let popupBox = createBox(); 42 | let oldPopup = document.querySelector("#popup"); 43 | if (oldPopup) { 44 | popupBox = oldPopup; 45 | } 46 | 47 | document.body.appendChild(popupBox); 48 | FloatingUIDOM.autoUpdate(iconBox, popupBox, () => { 49 | FloatingUIDOM.computePosition(iconBox, popupBox, { 50 | middleware: [FloatingUICore.shift(), FloatingUICore.flip(), FloatingUICore.offset(6)], 51 | }).then(({ x, y }) => { 52 | Object.assign(popupBox.style, { 53 | top: `${y}px`, 54 | left: `${x}px` 55 | }); 56 | }); 57 | }); 58 | 59 | iconBox.onclick = () => { 60 | togglePopup(popupBox); 61 | }; 62 | 63 | let searchIcon = document.getElementById('search-word'); 64 | let searchInput = document.querySelector('.search-input'); 65 | searchIcon.onclick = () => { 66 | queryArticle(); 67 | }; 68 | searchInput.onkeydown = (env) => { 69 | if (env.key === 'Enter') { 70 | queryArticle(); 71 | } 72 | }; 73 | 74 | // Global Esc key listener 75 | document.onkeydown = (env) => { 76 | if (env.key === 'Escape' && showBox) { 77 | togglePopup(popupBox); 78 | } 79 | }; 80 | 81 | let content = document.getElementById("search-content"); 82 | content.onclick = (env) => { 83 | if (env.target.className == 'scholar-data') { 84 | let source = document.getElementById("source").value; 85 | let id = env.target.getAttribute("data-cid"); 86 | if (source === "DBLP") { 87 | getBibTexDBLP(id).then(bib => { 88 | new Notify({ 89 | status: 'success', 90 | title: 'Copy successfully', 91 | text: 'Bib has been copied to clipboard', 92 | effect: 'slide', 93 | type: 'filled' 94 | }); 95 | GM_setClipboard(bib); 96 | }).catch(_ => { 97 | new Notify({ 98 | status: 'error', 99 | title: "Copy failed", 100 | text: "Failed to get BibTeX from DBLP", 101 | effect: "slide", 102 | type: "filled" 103 | }); 104 | }); 105 | } else if (source === "GoogleScholar") { 106 | getBibTexGoogleScholar(id).then(bib => { 107 | new Notify({ 108 | status: 'success', 109 | title: 'Copy successfully', 110 | text: 'Bib has been copied to clipboard', 111 | effect: 'slide', 112 | type: 'filled' 113 | }); 114 | GM_setClipboard(bib); 115 | }).catch(_ => { 116 | new Notify({ 117 | status: 'error', 118 | title: "Copy failed", 119 | text: "Failed to get BibTeX from Google Scholar", 120 | effect: "slide", 121 | type: "filled" 122 | }); 123 | }); 124 | } 125 | } 126 | }; 127 | }); 128 | } 129 | 130 | function togglePopup(popupBox) { 131 | showBox = !showBox; 132 | popupBox.style.display = showBox ? 'block' : 'none'; 133 | if (showBox) { 134 | document.querySelector('.search-input').focus(); // Optional: Focus input when popup opens 135 | } 136 | } 137 | 138 | function queryArticle() { 139 | let content = document.getElementById("search-content"); 140 | content.innerHTML = "Loading......"; 141 | let word = document.querySelector('input.search-input').value; 142 | let source = document.getElementById("source").value; 143 | let resultCount = document.getElementById("resultCount").value; 144 | if (source === "DBLP") { 145 | getArticleIDListDBLP(word, resultCount).then(lists => { 146 | if (lists.length === 0) { 147 | content.innerHTML = "No articles found."; 148 | throw new Error("No articles found"); 149 | } 150 | let searchText = ""; 151 | lists.forEach(article => { 152 | searchText += scholarContent(`${article.title}@${article.author}`, article.url); 153 | }); 154 | content.innerHTML = searchText; 155 | }).catch(err => { 156 | console.log("Error:", err); 157 | if (content.innerHTML !== "No articles found.") { 158 | content.innerHTML = "Failed to load articles."; 159 | } 160 | new Notify({ 161 | status: 'error', 162 | title: 'Request failed', 163 | text: 'Please check your query or try again later.', 164 | effect: 'slide', 165 | type: 'filled' 166 | }); 167 | }); 168 | } else if (source === "GoogleScholar") { 169 | let yearFrom = document.getElementById("yearFrom").value; 170 | let yearTo = document.getElementById("yearTo").value; 171 | let sortBy = document.getElementById("sortBy").value; 172 | getArticleIDListGoogleScholar(word, resultCount, yearFrom, yearTo, sortBy).then(lists => { 173 | if (lists.length === 0) { 174 | content.innerHTML = "No articles found."; 175 | throw new Error("No articles found"); 176 | } 177 | let searchText = ""; 178 | lists.forEach(article => { 179 | searchText += scholarContent(`${article.title}@${article.author}`, article.id); 180 | }); 181 | content.innerHTML = searchText; 182 | }).catch(err => { 183 | console.log("Error:", err); 184 | if (content.innerHTML !== "No articles found.") { 185 | content.innerHTML = "Failed to load articles."; 186 | } 187 | new Notify({ 188 | status: 'error', 189 | title: 'Request failed', 190 | text: 'Please check your query or try again later.', 191 | effect: 'slide', 192 | type: 'filled' 193 | }); 194 | }); 195 | } 196 | } 197 | 198 | function waitUtil(el, callback, timeout = 6000) { 199 | let query = setInterval(() => { 200 | let target = document.querySelector(el); 201 | if (target) { 202 | clearInterval(query); 203 | callback(target); 204 | } 205 | }); 206 | setTimeout(() => { 207 | clearInterval(query); 208 | }, timeout); 209 | } 210 | 211 | function createToggleIcon() { 212 | let iconBox = document.createElement('div'); 213 | iconBox.className = 'ol-cm-toolbar-button'; 214 | iconBox.style.display = 'flex'; 215 | iconBox.style.justifyContent = 'center'; 216 | iconBox.style.alignItems = 'center'; 217 | iconBox.id = "toggleIcon"; 218 | iconBox.innerHTML = ''; 219 | return iconBox; 220 | } 221 | 222 | function createBox() { 223 | let box = document.createElement('div'); 224 | box.id = "popup"; 225 | box.style = 'width:300px;background:#eef;padding:10px;border:1px solid #ccc;border-radius:5px;position:absolute;display:none;top:0px;left:0px'; 226 | box.innerHTML = ` 227 | 297 | 337 | `; 338 | 339 | 340 | let sourceSelect = box.querySelector("#source"); 341 | let countSelect = box.querySelector("#resultCount"); 342 | let gsOptions = box.querySelector("#gs-options"); 343 | 344 | sourceSelect.value = GM_getValue("searchSource", "DBLP"); 345 | countSelect.value = GM_getValue("resultCount", "5"); 346 | // Show/hide Google Scholar options based on source selection 347 | if (sourceSelect.value === "GoogleScholar") { 348 | gsOptions.style.display = "block"; 349 | } 350 | 351 | sourceSelect.addEventListener("change", () => { 352 | GM_setValue("searchSource", sourceSelect.value); 353 | // Show/hide Google Scholar options 354 | gsOptions.style.display = sourceSelect.value === "GoogleScholar" ? "block" : "none"; 355 | }); 356 | 357 | countSelect.addEventListener("change", () => GM_setValue("resultCount", countSelect.value)); 358 | 359 | return box; 360 | } 361 | 362 | function scholarContent(ref, cid) { 363 | return `
${ref}
`; 364 | } 365 | 366 | // DBLP Functions 367 | const dblpOrigin = "https://dblp.org"; 368 | function getArticleIDListDBLP(query, resultCount) { 369 | return new Promise((resolve, reject) => { 370 | let url = `https://dblp.org/search/publ/api?q=${encodeURIComponent(query)}&h=${resultCount}`; 371 | GM_xmlhttpRequest({ 372 | url: url, 373 | method: "GET", 374 | onload: response => { 375 | let parser = new DOMParser(); 376 | let doc = parser.parseFromString(response.responseText, 'text/xml'); 377 | let hits = doc.querySelectorAll('hit'); 378 | let articlesIDs = []; 379 | hits.forEach(hit => { 380 | let info = hit.querySelector('info'); 381 | let title = info.querySelector('title').textContent; 382 | let authors = Array.from(info.querySelectorAll('author')).map(a => a.textContent).join(', '); 383 | let url = info.querySelector('url').textContent; 384 | articlesIDs.push({ 385 | url: url, 386 | title: title, 387 | author: authors 388 | }); 389 | }); 390 | resolve(articlesIDs); 391 | }, 392 | onerror: err => { 393 | reject(err); 394 | } 395 | }); 396 | }); 397 | } 398 | 399 | function getBibTexURLDBLP(publicationURL) { 400 | let path = publicationURL.split("/rec/")[1].split(".html")[0]; 401 | return `${dblpOrigin}/rec/${path}.bib`; 402 | } 403 | 404 | function getBibTexDBLP(publicationURL) { 405 | return new Promise((resolve, reject) => { 406 | let bibtexURL = getBibTexURLDBLP(publicationURL); 407 | GM_xmlhttpRequest({ 408 | url: bibtexURL, 409 | method: "GET", 410 | onload: response => { 411 | if (response.status === 200) { 412 | resolve(response.responseText); 413 | } else { 414 | reject(new Error("Failed to fetch BibTeX from DBLP")); 415 | } 416 | }, 417 | onerror: err => { 418 | reject(err); 419 | } 420 | }); 421 | }); 422 | } 423 | 424 | // Google Scholar Functions 425 | const origins = ["https://scholar.google.com.hk", "https://scholar.lanfanshu.cn", "https://xs.vygc.top"]; 426 | let oldOrigins = GM_getValue("origins", []); 427 | const mergedArray = [...new Set([...origins, ...oldOrigins])]; 428 | GM_setValue("origins", mergedArray); 429 | let currentOrigin = () => GM_getValue("configure.origin", "https://scholar.google.com.hk"); 430 | 431 | function scholarURL(query, yearFrom, yearTo, sortBy) { 432 | let base = `${currentOrigin()}/scholar?hl=zh-CN&q=${encodeURIComponent(query)}&oq=a`; 433 | if (yearFrom) base += `&as_ylo=${yearFrom}`; 434 | if (yearTo) base += `&as_yhi=${yearTo}`; 435 | if (sortBy === 'date') base += `&scisbd=1`; 436 | return base; 437 | } 438 | 439 | //let scholarURL = query => `${currentOrigin()}/scholar?hl=zh-CN5&q=${query}&oq=a`; 440 | let scholarRefPageURL = id => `${currentOrigin()}/scholar?q=info:${id}:scholar.google.com/&output=cite&scirp=1&hl=zh-CN`; 441 | 442 | function getArticleIDListGoogleScholar(query, resultCount, yearFrom, yearTo, sortBy) { 443 | return new Promise((resolve, reject) => { 444 | GM_xmlhttpRequest({ 445 | url: scholarURL(query, yearFrom, yearTo, sortBy), 446 | method: "GET", 447 | onload: response => { 448 | let parser = new DOMParser(); 449 | let doc = parser.parseFromString(response.responseText, 'text/html'); 450 | let searchItems = doc.querySelectorAll('div[data-cid]'); 451 | let articlesIDs = []; 452 | searchItems.forEach((article, key) => { 453 | let cid = article.getAttribute('data-cid'); 454 | try { 455 | let title = article.querySelector("h3").textContent; 456 | let author = article.querySelector("div.gs_a").textContent; 457 | if (!cid.startsWith("gs") && key < resultCount) { 458 | articlesIDs.push({ 459 | id: cid, 460 | title: title, 461 | author: author 462 | }); 463 | } 464 | } catch (err) { 465 | console.log(err); 466 | } 467 | }); 468 | resolve(articlesIDs); 469 | }, 470 | onerror: err => { 471 | new Notify({ 472 | status: 'error', 473 | title: 'Request failed', 474 | text: 'Please verify your identification', 475 | effect: 'slide', 476 | type: 'filled' 477 | }); 478 | reject(err); 479 | } 480 | }); 481 | }); 482 | } 483 | 484 | function getRefPageGoogleScholar(id) { 485 | return new Promise((resolve, reject) => { 486 | GM_xmlhttpRequest({ 487 | url: scholarRefPageURL(id), 488 | method: "GET", 489 | onload: res => { 490 | resolve(res.response); 491 | }, 492 | onerror: err => { 493 | reject(err); 494 | } 495 | }); 496 | }); 497 | } 498 | 499 | function getBibTexGoogleScholar(id) { 500 | return new Promise((resolve, reject) => { 501 | getRefPageGoogleScholar(id).then(page => { 502 | let dom = document.createElement("div"); 503 | dom.innerHTML = page; 504 | let first = dom.querySelector("#gs_citi>a.gs_citi").href; 505 | return GM_xmlhttpRequest({ 506 | url: first, 507 | method: "GET", 508 | onload: (res) => { 509 | resolve(res.responseText); 510 | }, 511 | onerror: err => { 512 | reject(err); 513 | } 514 | }); 515 | }).catch(() => { 516 | new Notify({ 517 | status: 'error', 518 | title: 'Request failed', 519 | text: 'Please verify your identification.', 520 | effect: 'slide', 521 | type: 'filled' 522 | }); 523 | setTimeout(() => { 524 | GM_openInTab(currentOrigin()); 525 | }, 1000); 526 | throw new Error("Not find BibTeX"); 527 | }); 528 | }); 529 | } 530 | 531 | let showBox = false; 532 | --------------------------------------------------------------------------------