Repository: github.com/mafredri/safari-bookmarklets
Simply drag the link (bookmarklet) you want to you bookmarks (Favorites for easy access).
On iOS devices the installation process is more cumbersome, but possible. See below.
javascript:(function(){ /** * DuckStartGo * * Toggle between DuckDuckGo. Starpage.com and Google, maintaining the search * query. From DuckDuckGo to Startpage.com, from Startpage.com to Google and * from Google to DuckDuckGo. If none of these sites are active, search for the * highlighted text via DuckDuckGo. If no text is highlighted, simply navigate * to DuckDuckGo. * * Author: Mathias Fredriksson * Version: 0.0.3 */ function run(){switch(window.location.hostname.replace('www.','')){case'duckduckgo.com': return toStartpage(document.querySelector('[name=q]').value,!1);case'startpage.com': return toGoogle(document.querySelector('#q').value);case'google.com': return toDuckDuckGo(document.querySelector('[name=q]').value,!1);default:let t=document.getSelection().toString() ;if(''!==t)return toDuckDuckGo(t,!1)}window.location='https://www.duckduckgo.com'}function toStartpage(t,o){ if(o)return navigateViaForm('POST','https://www.startpage.com/sp/search',{q:t});t=encodeURIComponent(t), document.location=`https://www.startpage.com/sp/search?q=${t}`}function toDuckDuckGo(t,o){ if(o)return navigateViaForm('POST','https://www.duckduckgo.com/',{q:t});t=encodeURIComponent(t), document.location=`https://www.duckduckgo.com/?q=${t}`}function toGoogle(t){t=encodeURIComponent(t), document.location=`https://www.google.com/search?q=${t}`}function navigateViaForm(t,o,e){ const c=document.createElement('form');c.style.visibility='hidden',c.method=t,c.action=o;for(const t of Object.keys(e)){ const o=document.createElement('input');o.name=t,o.value=e[t],c.appendChild(o)}document.body.appendChild(c),c.submit()} run();})();void(0);
javascript:(function(){ /** * GoDoc * * Navigates to GoDoc from the current repository, e.g. on GitHub. * * Author: Mathias Fredriksson * Version: 0.0.0 */ const re=/\/((tree|blob|commits?|issues|pull|graphs|settings|network)\/[^/]+|(issues|pulls|projects|wiki|pulse|community|network|settings)$)/,loc=window.location ;window.location='https://godoc.org/'+loc.hostname+loc.pathname.replace(re,'');})();void(0);
javascript:(function(){ /** * Google Translate: Selection * * Translate only the selected text using automatic language detection. * Note: This is still a work-in-progress (WIP). * * Author: Mathias Fredriksson * Version: 0.0.1 */ async function main(){ const e=document.getSelection(),t=e.getRangeAt(0),n=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ALL) ;let o=[];for(;n.nextNode();){const t=n.currentNode;e.containsNode(t,!1)&&(o=[...o,t])} const a=o.filter(e=>e.nodeType===Node.TEXT_NODE&&''!==e.nodeValue.trim()),s=a.map((e,t)=>`${e.nodeValue.trim()}`).join('\n'),[r]=await translate(s) ;a.forEach((e,t)=>{e.nodeValue=r[t][0]})}function translate(e,t='en',n='auto'){ const o=`https://translate.googleapis.com/translate_a/single?client=gtx&sl=${n}&tl=${t}&dt=t&q=${e=encodeURI(e.replace(/\ /g,'+'))}` ;return new Promise((e,t)=>{const n=new XMLHttpRequest;n.onreadystatechange=function(){if(4===n.readyState){ if(200!==n.status)return void t(n.status);const o=JSON.parse(n.responseText);e(o)}},n.open('GET',o,!0),n.send(null)})} main();})();void(0);
javascript:(function(){ /** * Google Translate: Toolbar * * Inject a Google Translate toolbar into the current page, allows * toggling translate on/off but might disrupt the page layout and * doesn't translate as well as the "Google Translate" bookmarklet. * * Author: Mathias Fredriksson * Version: 0.0.1 */ const target=document.createElement('div');target.id='googleTranslateElement',document.body.prepend(target) ;const inject=document.createElement('script');function googleTranslateInit(){ const e=new google.translate.TranslateElement({pageLanguage:''},'googleTranslateElement');console.log(e)} inject.type='text/javascript', inject.src=window.location.protocol+'//translate.google.com/translate_a/element.js?cb=googleTranslateInit', window.googleTranslateInit=googleTranslateInit,document.head.append(inject);})();void(0);
javascript:(function(){ /** * Google Translate * * Translates the current page using automatic language detection. When * clicked on a translated page, will return to the original. * * Author: Mathias Fredriksson * Version: 0.0.1 */ function translate(){ const t='https://translate.google.com/translate?sl=auto&tl=en&js=y&prev=_t&hl=en&ie=UTF-8&edit-text=&u='+encodeURIComponent(window.location.href) ;window.location=t}function untranslate(){ let t=window.location.search.split('&').filter(t=>t.startsWith('u='))[0].slice(2);t=decodeURIComponent(t), window.location=t}function untranslateDomain(){ const t=window.location.href.includes('_x_tr_sch=http'),o=window.location.origin.replace('--','[dash]').replace('-','.').replace('[dash]','-').replace('.translate.goog','') ;let n=window.location.search.slice(1).split('&').filter(t=>!t.startsWith('_x_tr_')).join('&');n=n.length?`?${n}`:'' ;let e=window.location.href.replace(window.location.origin,o).replace(window.location.search,n) ;t&&(e=e.replace('https://','http://')),window.location=e} ['://translate.google.com','://translate.googleusercontent.com'].some(t=>window.location.origin.includes(t))?untranslate():window.location.origin.endsWith('.translate.goog')?untranslateDomain():translate();})();void(0);
javascript:(function(){ /** * Add to Pinboard * * Open a popup to bookmark the current page in Pinboard, information is * extracted from meta-tags where possible and some smarts are used for * constructing the title and description. If the document defines * keywords, tags will be pre-populated as well. * * Note: Wayback Machine proxies Window.open via Wombat.js which causes * a nested redirect and would break this bookmarklet. As a workaround, * the window.location is changed instead of opening a new window. * * Author: Mathias Fredriksson * Version: 0.0.3 */ const url=firstNonEmpty(location.href.startsWith('https://web.archive.org/web/')?location.href:'',metaP('og:url'),metaP('al:web:url'),location.href) ;let title=firstNonEmpty(metaID('title'),metaP('title'),metaP('og:title'),metaP('twitter:title'),query('h1','innerText'),query('title','innerText')),description=firstNonEmpty(metaID('description'),metaP('description'),metaP('og:description'),metaP('twitter:description'),metaN('description')) ;description&&(description=`Description: ${quote(description=description.replace(/\ Contribute to [^\ ]* development by creating an account on GitHub.$/,''))}`) ;let tags=[],keywords=firstNonEmpty(metaN('keywords')) ;keywords&&(tags=keywords.split(',').map(t=>t.trim()).filter(t=>''!==t)) ;const author=firstNonEmpty(metaID('author'),metaN('author')),siteName=firstNonEmpty(metaP('og:site_name')) ;author&&!title.includes(author)?title+=` | ${author}`:siteName&&!title.includes(siteName)&&(title+=` | ${siteName}`) ;let sel=document.getSelection().toString();''!==sel&&(sel=`Excerpt: ${quote(sel)}`), description&&sel?description=`${description}\n${sel}`:sel&&(description=sel) ;const queryParams=[['url',url],['title',title],['description',description],['tags',tags.join(',')]].map(t=>`${t[0]}=${encodeURIComponent(t[1])}`).join('&'),openURL=`https://pinboard.in/add?showtags=yes&${queryParams}` ;function firstNonEmpty(...t){const[e]=t.map(t=>t.trim()).filter(t=>''!==t);return e||''}function query(t,e){ const o=document.querySelector(t);return o?o[e]:''}function metaID(t){return query(`meta#${t}`,'content')} function metaN(t){return query(`meta[name="${t}"]`,'content')}function metaP(t){ let e=query(`meta[property="${t}"]`,'content');return e||(e=query(`meta[itemprop="${t}"]`,'content')),e} function quote(t){return`<blockquote>${t.trim()}</blockquote>`} url.startsWith('https://web.archive.org/web/')?window.location=openURL:open(openURL,'Pinboard','toolbar=no,scrollbars=yes,width=750,height=700');})();void(0);
javascript:(function(){ /** * Spotify to Apple Music * * Searches Apple Music for the song or album being viewed on Spotify. * * Author: Mathias Fredriksson * Version: 0.0.0 */ async function main(){ const[t,e,n]=['twitter:title','twitter:audio:artist_name','og:type'].map(t=>document.querySelector(`meta[property="${t}"]`).content) ;'music.song'===n?entity='song':'music.album'===n?entity='album':alert(`Unknown type: ${n}`) ;let r=`${t} ${e}`,a=await search(r);a||(r=r.replace(/\([^)]+\)/g,''),a=await search(r)),render(a)}function search(t){ const e=`https://itunes.apple.com/search?term=${t=encodeURI(t.replace(/\ /g,'+'))}&media=music&entity=${entity}` ;return new Promise((t,n)=>{const r=new XMLHttpRequest;r.onreadystatechange=function(){if(4===r.readyState){ if(200!==r.status)return void n(r.status);const e=JSON.parse(r.responseText);e.resultCount||t(null),t(e.results)}}, r.open('GET',e,!0),r.send(null)})}function render(t){let e=[] ;for(let n of t)e=[...e,`<p><a href="${n.collectionViewUrl}"><img src="${n.artworkUrl100}">${n.collectionName} - ${n.artistName}</a></p>`] ;document.write(e.join(''))}main();})();void(0);
javascript:(function(){ /** * Tori: Relinkify * * Relinkify sold links on Tori.fi. * * Author: Mathias Fredriksson * Version: 0.0.0 */ for(const e of Array.from(document.querySelectorAll('.adw_desc.gray_text'))){ const t=e.parentNode,o=e.childNodes[0],r=t.id.replace(/^item_/,''),a=o.textContent.replace(/\ /g,'_').replace(/\+/g,'_').replace(/[ÄÅ]/g,'A').replace(/[åä]/g,'a').replace('Ö','O').replace('ö','o').trim(),c=t.querySelectorAll('.cat_geo a')[0].textContent.trim().toLowerCase() ;console.log(r,a,c);const l=document.createElement('a');l.classList.add('item_link','nohistory'), l.href=`https://www.tori.fi/${c}/${a}_${r}.htm?aw=1`,l.textContent=o.textContent,e.insertBefore(l,o),o.remove()}})();void(0);
javascript:(function(){ /** * Wayback Machine * * Opens the latest snapshot of the current URL from Internet Archive. * Clicking the bookmarklet while viewing an archive redirects to the * live page. * * Author: Mathias Fredriksson * Version: 0.0.0 */ let loc=window.location.href;if('safari-resource:/ErrorPage.html'===loc){ const o=new RegExp('['+String.fromCharCode(8220)+String.fromCharCode(8221)+']','g') ;loc=(loc=document.querySelector('.error-message').textContent.split(o)[1]).replace(String.fromCharCode(8206),'')} function showArchive(o){o=encodeURI(o),window.location=`http://web.archive.org/web/submit?type=replay&url=${o}`} function showLive(o){(o=o.split('/').slice(5).join('/')).startsWith('http')||(o='http://'+o),window.location=o} loc.includes('://web.archive.org/web/')?showLive(loc):showArchive(loc);})();void(0);
javascript:(function(){ /** * YouTube PiP * * Enable YouTube PiP in macOS and on iOS devices. Additionally launches a * watchdog that keeps PiP * * Credits for the original code go to Code Everywhere, from: * https://codeeverywhere.ca/post.php?id=56#Enable-YouTube-picture-in-picture-on-iOS-14-Safari-with-this-Siri-Shortcut * * Author: Mathias Fredriksson * Version: 0.0.2 */ function enablePiP(e){let t=document.querySelector('.ytp-ad-skip-button-text');if(t)return t.click(), void setTimeout(()=>enablePiP(e),250);let i=document.querySelector('video');if(i.setAttribute('controls',!0), i!==window._pip_watchdog.video){const e=e=>setTimeout(()=>{window._pip_watchdog.video.setAttribute('controls',!0)},250) ;window._pip_watchdog.video=i,i.addEventListener('webkitpresentationmodechanged',t=>(e(t),t.stopPropagation()),!0), i.addEventListener('play',e),i.addEventListener('pause',e)}e&&setTimeout(()=>{ window._pip_watchdog.video.webkitSetPresentationMode('picture-in-picture')},250)}function run(){ if(window._pip_watchdog)return window._pip_watchdog.url=document.location.href,void enablePiP(!0);window._pip_watchdog={ url:document.location.href,video:null},enablePiP(!0),setInterval(()=>{ window._pip_watchdog.url!=document.location.href&&enablePiP(!1)},500)}run();})();void(0);
Installation instructions for iOS devices: