Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save dbieber/c3198a1ceeb86fa823df305a76907afa to your computer and use it in GitHub Desktop.
Save dbieber/c3198a1ceeb86fa823df305a76907afa to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Arxiv PDF Title Updater for Hypothesis Pages
// @namespace http://tampermonkey.net/
// @version 1.2
// @description Update Arxiv PDF links titles on Hypothesis pages
// @author David Bieber + GPT-4
// @match *://*.hypothes.is/*
// @grant GM_xmlhttpRequest
// ==/UserScript==
(async function() {
'use strict';
// Utility function to extract ArxivIDs
function extractArxivIDs(links) {
const arxivIDs = [];
const arxivIDRegex = /(\d+\.\d+)(v\d+)?\.pdf/;
for (const link of links) {
const match = link.textContent.match(arxivIDRegex);
if (match) {
arxivIDs.push(match[1]);
}
}
console.log('ArxivIDs found on Hypothesis page:', arxivIDs);
return arxivIDs;
}
// Utility function to query the Arxiv API
async function queryArxivAPI(ids) {
return new Promise((resolve, reject) => {
const arxivAPI = `http://export.arxiv.org/api/query?id_list=${ids.join(',')}`;
GM_xmlhttpRequest({
method: 'GET',
url: arxivAPI,
onload: function(response) {
if (response.status >= 200 && response.status < 400) {
resolve(response.responseText);
} else {
reject(new Error('Error querying the Arxiv API'));
}
},
onerror: function() {
reject(new Error('Error querying the Arxiv API'));
},
});
});
}
// Utility function to split an array into chunks
function chunkArray(array, size) {
const chunks = [];
for (let i = 0; i < array.length; i += size) {
chunks.push(array.slice(i, i + size));
}
return chunks;
}
// Utility function to update the link titles on the Hypothesis page
function updateLinkTitles(links, titles) {
for (const link of links) {
const match = link.textContent.match(/(\d+\.\d+)(v\d+)?\.pdf/);
if (match) {
const arxivID = match[1];
if (titles.hasOwnProperty(arxivID)) {
link.textContent = titles[arxivID];
}
}
}
}
// Get all the links on the Hypothesis page
const links = document.querySelectorAll('a[data-ref="title"]');
// Extract the ArxivIDs
const arxivIDs = extractArxivIDs(links);
// Query the Arxiv API and update the link titles
if (arxivIDs.length > 0) {
try {
const titles = {};
const arxivIDChunks = chunkArray(arxivIDs, 10);
for (const chunk of arxivIDChunks) {
const responseText = await queryArxivAPI(chunk);
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(responseText, 'application/xml');
const entries = xmlDoc.getElementsByTagName('entry');
for (const entry of entries) {
const idElement = entry.querySelector('id');
const titleElement = entry.querySelector('title');
if (idElement && titleElement) {
let arxivID = idElement.textContent.split('/').pop();
// Remove version suffix (e.g., "v1")
arxivID = arxivID.replace(/v\d+$/, '');
const title = titleElement.textContent.trim();
titles[arxivID] = title;
}
}
}
console.log('Arxiv titles fetched:', titles);
updateLinkTitles(links, titles);
} catch (error) {
console.error('Failed to update Arxiv PDF link titles:', error);
}
}
})();
@kael
Copy link

kael commented Mar 18, 2023

The scope of the script can be narrowed to Hypothesis annotations pages only:

-// @match  *://*.hypothes.is/*
+// @match  https://hypothes.is/a/*
+// @match  https://hypothes.is/users/*
+// @match  https://hypothes.is/search
+// @match  https://hypothes.is/search?*

Currently, the script runs unnecessarily on pages like this one https://web.hypothes.is/


The list of selected links can be narrowed to the ones containing an URL pattern for arxiv PDF links only (with this syntax: [attr*=value]):

const link = document.querySelector('.search-bucket-stats__val.search-bucket-stats__url > a[href*="arxiv.org/pdf/"].link--plain')

In that case, you'll have to update the title of the related link by browsing upward through the DOM tree of the annotation container:

link.parentElement.parentElement.parentElement.parentElement.parentElement.querySelector('.search-result-bucket__title').textContent = "Arxiv PDF Title"

Sample of an HTML annotation container
<div class="search-result-bucket js-search-bucket">

  
  <div class="search-result-bucket__header" data-ref="header">
    <div class="search-result-bucket__domain">
      <span class="search-result-bucket__domain-text">arxiv.org</span>
      <a class="link--plain search-result-bucket__domain-link" href="https://hyp.is/-LHVMsO4Ee2dSFv2v0O21Q/arxiv.org/pdf/2005.14165.pdf" rel="nofollow noopener" title="Visit annotations in context" target="_blank" data-ref="domainLink">
         arxiv.org
         <svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" class="svg-icon search-result-bucket__incontext-icon"><path d="M7.586 2H4V0h5.997A1.002 1.002 0 0 1 11 1.003V7H9V3.414l-7.293 7.293L.293 9.293 7.586 2Z" fill="currentColor" fill-rule="evenodd"></path></svg></a>
    </div>
    <div class="search-result-bucket__title-and-annotations-count">
        <a title="expand annotations for this url" data-ref="title" href="#" class="search-result-bucket__title" aria-expanded="false">
        
            2005.14165.pdf
        
        </a>
        <div title="1 annotations added" class="search-result-bucket__annotations-count">
          <div class="search-result-bucket__annotations-count-container">
              1
          </div>
        </div>
    </div>
  </div>

  
  <div class="search-result-bucket__content">
    <div class="search-result-bucket__annotation-cards-container" data-ref="content">
      <ol class="search-result-bucket__annotation-cards">
        
          <li class="annotation-card">
  <div class="annotation-card__header">
    <div class="annotation-card__username-timestamp">
      <a title="username" href="https://hypothes.is/users/Jindong" class="annotation-card__username">
        Jindong
      </a>
      <a title="date" href="https://hypothes.is/a/-LHVMsO4Ee2dSFv2v0O21Q" class="annotation-card__timestamp">
        16 Mar 2023
      </a>
    </div>
    <div class="annotation-card__share-info">
      
        <a title="group" href="https://hypothes.is/groups/__world__/public" class="annotation-card__groupname">
            in
            <svg xmlns="http://www.w3.org/2000/svg" width="120" height="120" class="svg-icon annotation-card__groups-icon"><g fill="currentColor" transform="translate(.508 7.627)" style="fill-rule:evenodd;stroke:none;stroke-width:1"><circle cx="36" cy="41" r="18"></circle><circle cx="84" cy="41" r="18"></circle><path d="M72 97.042h44V85s0-19-32-19c-9.065 0-15.562 1.525-20.218 3.71a24.324 24.324 0 0 1 3.278 3.213c2.135 2.536 3.518 5.274 4.291 8.027.276.984.456 1.908.558 2.756.066.553.091.99.091 1.294v12.042z"></path><path d="M4 97.042h64V85s0-19-32-19S4.004 85 4.004 85L4 97.042Z"></path></g></svg>
            Public
        </a>
      
      
    </div>
  </div>
  
    <blockquote title="Annotation quote" class="annotation-card__quote">
      Second, the potential to exploit spurious correlations in training data fundamentally grows with the expressivenessof the model and the narrowness of the training distribution.
    </blockquote>
  
  <div class="annotation-card__text">
    <p>This simply means overfitting.</p>
  </div>
  <div title="Tags" class="annotation-card__tags">
    
  </div>
  <footer class="annotation-card__footer">
    
      <a href="https://hyp.is/-LHVMsO4Ee2dSFv2v0O21Q/arxiv.org/pdf/2005.14165.pdf" rel="nofollow noopener" target="_blank" title="Visit annotation in context">
        <svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" class="svg-icon annotation-card__footer-link annotation-card__incontext-link"><path d="M7.586 2H4V0h5.997A1.002 1.002 0 0 1 11 1.003V7H9V3.414l-7.293 7.293L.293 9.293 7.586 2Z" fill="currentColor" fill-rule="evenodd"></path></svg>
      </a>
      <a href="#" title="Share this annotation" aria-haspopup="true" share-widget-config="{
          &quot;url&quot;: &quot;https://hyp.is/-LHVMsO4Ee2dSFv2v0O21Q/arxiv.org/pdf/2005.14165.pdf&quot;,
          &quot;private&quot;: false,
          &quot;group&quot;: true
        }">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" class="svg-icon annotation-card__footer-link"><path d="M6.86 9.328a2.496 2.496 0 0 0 0-1.656l3.092-2.209a2.5 2.5 0 1 0-.811-1.135L6.047 6.537a2.5 2.5 0 1 0 0 3.926l3.092 2.209a2.5 2.5 0 1 0 .811-1.135L6.86 9.328Z" fill="#A6A6A6" fill-rule="evenodd"></path></svg>
      </a>
    
  </footer>
</li>
        
      </ol>
      
<div class="search-bucket-stats">
  
    <div class="search-bucket-stats__key">
      <svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" class="svg-icon search-bucket-stats__icon"><path d="M7.586 2H4V0h5.997A1.002 1.002 0 0 1 11 1.003V7H9V3.414l-7.293 7.293L.293 9.293 7.586 2Z" fill="currentColor" fill-rule="evenodd"></path></svg>
      <a class="search-bucket-stats__incontext-link" href="https://hyp.is/-LHVMsO4Ee2dSFv2v0O21Q/arxiv.org/pdf/2005.14165.pdf" rel="nofollow noopener" target="_blank">
         Visit annotations in context
       </a>
    </div>
    <div class="search-bucket-stats__val"></div>
  
  
  <h4 title="annotators" class="search-bucket-stats__key">
    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" class="svg-icon search-bucket-stats__icon"><g fill="currentColor" fill-rule="evenodd"><circle cx="8" cy="4" r="3"></circle><path d="M8 15c3 0 6-.567 6-3 0-1.433-4-4-6-4s-6 2.567-6 4c0 2.433 3 3 6 3Z"></path></g></svg>
    Annotators
  </h4>
  <ul class="search-bucket-stats__val">
    
      <li class="search-bucket-stats__username">
        <a class="link--plain" href="https://hypothes.is/users/Jindong">Jindong</a>
      </li>
    
  </ul>
  
    <h4 title="url" div="" class="search-bucket-stats__key">
      <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" class="svg-icon search-bucket-stats__icon"><g fill="currentColor" fill-rule="evenodd"><path d="M6.896 1.943a1.25 1.25 0 0 1 1.765 0l1.417 1.417a1.25 1.25 0 0 1 0 1.765L7.953 7.249a1.25 1.25 0 0 1-1.764 0l-.71-.71A.75.75 0 1 0 4.418 7.6l.71.711a2.75 2.75 0 0 0 3.886 0l2.124-2.124a2.75 2.75 0 0 0 0-3.886L9.721.882a2.75 2.75 0 0 0-3.886 0 .75.75 0 1 0 1.06 1.061Z"></path><path d="M5.125 10.078a1.25 1.25 0 0 1-1.765 0L1.943 8.66a1.25 1.25 0 0 1 0-1.765L4.067 4.77a1.25 1.25 0 0 1 1.765 0l.71.71a.75.75 0 1 0 1.06-1.06l-.71-.71a2.75 2.75 0 0 0-3.885 0L.882 5.835a2.75 2.75 0 0 0 0 3.886L2.3 11.138a2.75 2.75 0 0 0 3.886 0 .75.75 0 1 0-1.061-1.06Z"></path></g></svg>
      URL
    </h4>
    <div class="search-bucket-stats__val search-bucket-stats__url">
        <a class="link--plain" rel="nofollow noopener" href="https://arxiv.org/pdf/2005.14165.pdf" target="_blank">arxiv.org/pdf/2005.14165.pdf</a>
    </div>
  
  <div class="u-stretch">
  </div>
  <button class="search-bucket-stats__collapse-view" data-ref="collapseView" title="Collapse view">
    <svg xmlns="http://www.w3.org/2000/svg" width="11" height="13" class="svg-icon search-bucket-stats__collapse-view-icon"><g fill="none" fill-rule="evenodd"><path fill="#3F3F3F" d="M.55 5.086 5.5.136 6.914 1.55 1.964 6.5z"></path><path fill="#3F3F3F" d="M4.086 1.55 5.5.136l4.95 4.95L9.036 6.5z"></path><path d="M5.5 1.55v11.314" stroke="#3F3F3F" stroke-width="2"></path></g></svg>
    Collapse view
  </button>
</div>

    </div>
  </div>
</div>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment