Zhihu Link Archiver

Adds a button beside Zhihu answer/article links to archive them to Archive.org

安裝腳本?
作者推薦腳本

您可能也會喜歡 Zhihu archive

安裝腳本
  1. // ==UserScript==
  2. // @name Zhihu Link Archiver
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.3
  5. // @author Jarrett Ye
  6. // @license MIT
  7. // @description Adds a button beside Zhihu answer/article links to archive them to Archive.org
  8. // @match https://www.zhihu.com/*
  9. // @match https://zhuanlan.zhihu.com/*
  10. // @icon https://www.google.com/s2/favicons?domain=zhihu.com
  11. // @grant none
  12. // ==/UserScript==
  13.  
  14. function createArchiveZhihuButton(link) {
  15. const button = document.createElement('a');
  16. button.textContent = '保存到 Archive';
  17. button.className = 'archive-zhihu-button';
  18. button.style.cssText = `
  19. margin-left: 10px;
  20. padding: 2px;
  21. background-color: #0084ff;
  22. text-align: center;
  23. color: white;
  24. min-width: 82px;
  25. border-radius: 3px;
  26. font-size: 12px;
  27. text-decoration: none;
  28. transition: all 0.3s ease;
  29. `;
  30. button.addEventListener('click', (e) => {
  31. e.preventDefault();
  32. const archiveLink = link.replace('.zhihu.com', '.fxzhihu.com');
  33. window.open('https://web.archive.org/save/' + archiveLink, '_blank');
  34. button.textContent = '已打开';
  35. setTimeout(() => {
  36. button.textContent = '保存到 Archive';
  37. }, 1000);
  38. });
  39. button.href = 'javascript:void(0)';
  40. return button;
  41. }
  42.  
  43. (function () {
  44. 'use strict';
  45.  
  46. function addArchiveZhihuButton() {
  47. const answerItems = target.querySelectorAll('.ContentItem.AnswerItem');
  48. answerItems.forEach(item => {
  49. if (item.querySelector('.archive-zhihu-button')) return;
  50.  
  51. let link = item.querySelector('.ContentItem-title a');
  52. if (!link) {
  53. link = item.querySelector('.ContentItem-time a');
  54. }
  55. if (!link) {
  56. link = item.querySelector('meta[itemprop="url"]').baseURI;
  57. } else {
  58. link = link.href;
  59. }
  60. const actions = item.querySelector('.ContentItem-actions');
  61. actions.insertBefore(createArchiveZhihuButton(link), actions.firstChild.nextSibling);
  62. });
  63.  
  64. const articleItems = target.querySelectorAll('.ContentItem.ArticleItem');
  65. articleItems.forEach(item => {
  66. if (item.querySelector('.archive-zhihu-button')) return;
  67. let link = item.querySelector('.ContentItem-title a');
  68. if (!link) {
  69. link = item.querySelector('.ContentItem-time a');
  70. }
  71. const actions = item.querySelector('.ContentItem-actions');
  72. actions.insertBefore(createArchiveZhihuButton(link.href), actions.firstChild.nextSibling);
  73. });
  74.  
  75. const pinItems = target.querySelectorAll('.ContentItem.PinItem');
  76. pinItems.forEach(item => {
  77. if (item.querySelector('.archive-zhihu-button')) return;
  78. let link = item.querySelector('.ContentItem-title a');
  79. if (!link) {
  80. link = item.querySelector('.ContentItem-time a');
  81. }
  82. const actions = item.querySelectorAll('.ContentItem-actions')[1];
  83. actions.insertBefore(createArchiveZhihuButton(link.href), actions.firstChild.nextSibling);
  84. });
  85. }
  86.  
  87. if (window.location.hostname.startsWith('zhuanlan.zhihu.com')) {
  88. const actions = document.querySelector('.ContentItem-actions');
  89. actions.insertBefore(createArchiveZhihuButton(window.location.href), actions.firstChild.nextSibling);
  90. return;
  91. }
  92.  
  93. const target = document.querySelector('.ListShortcut');
  94. if (!target) {
  95. return;
  96. }
  97. // Run the function initially
  98. addArchiveZhihuButton();
  99.  
  100. // Create a MutationObserver to watch for changes in the DOM
  101. const observer = new MutationObserver(addArchiveZhihuButton);
  102.  
  103. // Start observing the document with the configured parameters
  104. observer.observe(target, { childList: true, subtree: true });
  105. })();