Save citations to your library

Save all citations of a paper to your library

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Save citations to your library
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Save all citations of a paper to your library
// @author       yusanshi
// @license      MIT
// @match        https://scholar.google.com/scholar?*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=google.com
// @require      https://cdn.jsdelivr.net/gh/uzairfarooq/arrive@77ff92c058598997e7da9789376b7a666a6d40db/src/arrive.js
// @grant        GM.setValue
// @grant        GM.getValue
// ==/UserScript==
const sleepTime = 1000;
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const work = async (targetLibrary) => {
  await document.arrive('#gs_res_ccl_mid > div.gs_r.gs_or.gs_scl', {
    onceOnly: true,
    existing: true,
  });
  // Process the current page
  for (const e of document.querySelectorAll(
    '#gs_res_ccl_mid > div.gs_r.gs_or.gs_scl'
  )) {
    e.scrollIntoView();
    e.querySelector('div.gs_fl a.gs_or_sav span.gs_or_btn_lbl').click();
    await sleep(sleepTime);
    await document.arrive('#gs_md_albl-d.gs_vis div.gs_ldb_lbc', {
      onceOnly: true,
      existing: true,
    });

    let temp = [
      ...document.querySelectorAll('#gs_md_albl-d.gs_vis div.gs_ldb_lbc'),
    ].filter((a) => a.textContent === targetLibrary);
    if (temp.length === 0) {
      // create a new library
      document
        .querySelector('#gs_md_albl-d.gs_vis form span.gs_ldb_new_lb')
        .click();
      document.querySelector(
        '#gs_md_albl-d.gs_vis #gs_lbd_new_txt input'
      ).value = targetLibrary;
    } else {
      // select the old library
      temp = temp[0].querySelector('a');
      temp.scrollIntoView();
      if (!temp.classList.contains('gs_sel')) {
        temp.click();
      }
    }

    await sleep(sleepTime);
    document.querySelector('#gs_lbd_apl > span.gs_wr > span').click();
    await sleep(sleepTime);
  }

  const nextPage = document.querySelector(
    '#gs_n > center > table > tbody > tr > td > span.gs_ico_nav_current'
  ).parentElement.nextElementSibling;
  if (nextPage.innerText.trim() !== '') {
    nextPage.querySelector('a').click();
  }
};

(async function () {
  'use strict';

  document.body.insertAdjacentHTML(
    'beforeend',
    `<div
    style="
      position: fixed;
      bottom: 30px;
      right: 30px;
      background: rgba(240, 240, 240, 0.9);
      z-index: 1;
      padding: 5px;
      border: 1px solid #ccc;
      border-radius: 6px;
      display: flex;
      align-items: center;
    "
  >
    <label>Target library</label>
    <input type="text" id="targetLibrary" style="margin-left:6px;margin-right:10px" />
    <label>Current paper</label>
    <input type="text" id="currentPaper"  style="margin-left:6px;margin-right:10px" />
    <input
      type="checkbox"
      id="running"
      style="width: 16px; height: 16px"
    />
  </div>
  `
  );
  await document.arrive('#targetLibrary', {
    onceOnly: true,
    existing: true,
  });
  await document.arrive('#currentPaper', {
    onceOnly: true,
    existing: true,
  });
  await document.arrive('#running', {
    onceOnly: true,
    existing: true,
  });
  const targetLibraryInput = document.querySelector('#targetLibrary');
  const currentPaperInput = document.querySelector('#currentPaper');
  const runningCheckbox = document.querySelector('#running');

  targetLibraryInput.addEventListener('input', () => {
    GM.setValue('targetLibrary', targetLibraryInput.value.trim());
  });
  currentPaperInput.addEventListener('input', () => {
    GM.setValue('currentPaper', currentPaperInput.value.trim());
  });
  runningCheckbox.addEventListener('change', () => {
    GM.setValue('running', runningCheckbox.checked ? 'on' : 'off');
  });

  const targetLibrary = await GM.getValue('targetLibrary', '');
  const currentPaper = await GM.getValue('currentPaper', '');
  const running = await GM.getValue('running', 'off');

  targetLibraryInput.value = targetLibrary;
  currentPaperInput.value = currentPaper;
  runningCheckbox.checked = running === 'on';

  const params = new URL(window.location.href).searchParams;

  if (
    targetLibrary !== '' &&
    params.get('cites') === currentPaper &&
    params.get('q') === null &&
    running === 'on'
  ) {
    work(targetLibrary);
  }
})();