// ==UserScript== // @name Pinback Next // @namespace https://www.octt.eu.org/ // @match https://*.pinterest.*/* // @grant none // @version 0.5.0 // @author OctoSpacc // @license MIT // @description The backup and export tool Pinterest forgot, finally revived! // @run-at context-menu // @grant GM_registerMenuCommand // @downloadURL none // ==/UserScript== GM_registerMenuCommand('Open Export Tool', function(){ var version = '0.5.0' , boards = {} , board = {} , pins = [] , pin_count = 0 , username; if (match = location.href.match(/^https:\/\/www\.pinterest\..*?\/([a-z0-9_]{1,30})/i)) { username = match[1]; getResource('Boards', { username: username, field_set_key: 'detailed' }, start); } else { alert('Log in and visit your profile (pinterest.com/username) or board to start'); return false; } function start(json) { if (document.querySelector('#pboverlay')) return false; var overlay = document.createElement('div'); overlay.id = 'pboverlay'; overlay.innerHTML = ` ×

Choose a board to export

Pinback v${version}

`; document.querySelector('body').appendChild(overlay); var select = document.querySelector('#pboverlay select'); var option = document.createElement('option'); option.text = '[ All public pins ]'; option.value = 'all'; select.add(option); Array.prototype.forEach.call(json.resource_response.data, function(b, i) { var option = document.createElement('option'); option.text = b.name; option.value = b.id; option.selected = (location.pathname == b.url); select.add(option); }); document.querySelector('#pboverlay button').onclick = function() { document.querySelector('#pboverlay .controls').innerHTML = ''; status('Exporting...'); var selected = select.querySelector('option:checked'); if (selected.value == 'all') { status('Exporting all pins...'); getResource('User', {username: username}, parseBoard); } else { status('Exporting ' + selected.text + '...'); getResource('Board', {board_id: selected.value}, parseBoard); } return false; }; document.querySelector('#pboverlay .close').onclick = function() { location.href = location.pathname; return false; }; } function parseBoard(json) { board = json.resource_response.data; getFeed(); } function getFeed(bookmarks) { if (board.type == 'user') { getResource('UserPins', { username: username, page_size: 25, bookmarks: bookmarks }, parseFeed); } else { getResource('BoardFeed', { board_id: board.id, page_size: 25, bookmarks: bookmarks }, parseFeed); } } function parseFeed(json) { json.resource_response.data.forEach(function(p, i) { if (p.type == 'pin') { if (!boards[p.board.name]) boards[p.board.name] = { id: p.board.id, name: p.board.name, url: "https://www.pinterest.com"+p.board.url, privacy: p.board.privacy, pins: [] } boards[p.board.name].pins.push({ id: p.id, link: p.link, description: p.description, url: "https://www.pinterest.com/pin/"+p.id, image: p.images.orig.url, color: p.dominant_color, longitude: (p.place && p.place.longitude) || null, latitude: (p.place && p.place.latitude) || null, pinner: p.pinner.username, privacy: p.privacy, date: Date.parse(p.created_at) }); progress(pin_count++, board.pin_count); } }) var bookmarks = json.resource.options.bookmarks; if (bookmarks[0] == '-end-') { done(); } else { getFeed(bookmarks); } } function getResource(resource, options, callback) { var xhr = new XMLHttpRequest(); xhr.onload = function () { if (xhr.status >= 200 && xhr.status < 300) { callback(JSON.parse(xhr.responseText)); } else { alert('An error has occurred.') console.log(JSON.parse(xhr.responseText)); } }; xhr.open('GET', ('/resource/' + resource + 'Resource/get/?data=' + encodeURIComponent(JSON.stringify({ options: options })))); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.setRequestHeader('Accept', 'application/json, text/javascript, */*, q=0.01'); xhr.send(); } function status(s) { document.querySelector('#pboverlay h1').innerText = s; } function progress(a, b) { status('Exporting ' + a + ' of ' + b + '...'); document.querySelector('#pboverlay meter').value = (a/b)*100; } function privacy(p) { return (p != 'public') ? 1 : 0; } function escapeHtml(unsafe) { return unsafe.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """).replace(/'/g, "'"); } function done() { status('Export complete!'); var data = ` Bookmarks

Bookmarks

`; for (var name in boards) { var b = boards[name]; data += `

${escapeHtml(b.name)}

\n

\n`; b.pins.forEach(function(p, i) { data += `

${escapeHtml(p.description?.trim() || p.link || p.url)}\n`; }); data += '

\n'; } data += '

'; var filename = (board.url || username).replace(/^\/|\/$/g, '').replace(/\//g,'-')+".html"; var blob = new Blob([data], { type: 'text/html' }); var url = URL.createObjectURL(blob); document.querySelector('#pboverlay .controls').innerHTML = `Save export file`; if (typeof(document.createElement('a').download) === 'undefined') { document.querySelector('#pboverlay .controls a').onclick = function() { alert('Choose File > Save As in your browser to save a copy of your export'); } } } });