// ==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 = `
×
`;
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');
}
}
}
});