|
'use strict' |
|
|
|
// CONFIGURE YOUR SETTINGS HERE |
|
// Letterboxd username |
|
const LETTERBOXD_USERNAME = 'oan' |
|
|
|
// Which page should the script start on? |
|
// (if the importer fails somewhere) |
|
const LETTERBOXD_START_PAGE = 0 |
|
|
|
// Taste.io Authorization token |
|
// Too lazy to impl auth considering my account is facebook oauth'd |
|
const TOKEN = '' |
|
|
|
// Maps letterboxd 10 point rating scale to taste.io 4 point scale. |
|
// Adjust if desired |
|
const mapRating = function(rating) { |
|
// 1 2 3 4 5 6 7 8, 9, 10 |
|
return [null, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4][rating] |
|
} |
|
|
|
// Change to true if ratings should be updated |
|
const UPDATE_RATINGS = false |
|
|
|
// ================================================================= |
|
// DOING A CODE HERE DON'T BE LOOKIN DOWN THERE LESS U LOOKIN FOR IT |
|
|
|
const through2 = require('through2') |
|
const JSONStream = require('JSONStream') |
|
const got = require('got') |
|
const cookie = require('cookie') |
|
const Xray = require('x-ray') |
|
|
|
const x = Xray() |
|
|
|
const serializeCookie = function(obj) { |
|
return Object.keys(obj).map((key) => cookie.serialize(key, obj[key])).join('; ') |
|
} |
|
|
|
// Scrape my letterboxd watchlist |
|
const pageParam = (LETTERBOXD_START_PAGE > 0) ? `page/${LETTERBOXD_START_PAGE}/` : '' |
|
const url = `http://letterboxd.com/${LETTERBOXD_USERNAME}/films/${pageParam}` |
|
x(url, '.film-list', x('.poster-container', [{ |
|
rating: '@data-owner-rating', |
|
title: '.film-poster img@alt', |
|
}])) |
|
.paginate('.paginate-nextprev .next@href') |
|
.write() |
|
// Stream the scraped titles one by one |
|
.pipe(JSONStream.parse('*')) |
|
.pipe(through2.obj(function({title, rating}, enc, cb){ |
|
if(rating == 0) { |
|
console.log(`Skipping ${title}`) |
|
return cb(null) |
|
} |
|
|
|
console.log(`Rating ${title} as ${rating} -> ${mapRating(rating)}...`) |
|
|
|
got('https://www.taste.io/api/movies/search?q=' + encodeURIComponent(title), { headers: { |
|
Authorization: 'Bearer ' + TOKEN |
|
}, json: true }) |
|
|
|
.then(res => { |
|
if(!res.body.movies.length) return |
|
const movie = res.body.movies[0] |
|
if(!UPDATE_RATINGS && movie.user && movie.user.rating) { |
|
console.log(`Skipping ${title} (already rated)`) |
|
return |
|
} |
|
|
|
const cook = cookie.parse(res.headers['set-cookie'].join('; ')) |
|
|
|
return new Promise(resolve => { |
|
const req = got.post('https://www.taste.io/api/movies/' + movie.slug + '/rating', { |
|
headers: { |
|
Authorization: 'Bearer ' + TOKEN, |
|
Cookie: serializeCookie(cook), |
|
'X-XSRF-TOKEN': cook['XSRF-TOKEN'] |
|
}, |
|
body: { |
|
rating: mapRating(rating) |
|
}, |
|
json: true |
|
}).then(res => resolve(res)).catch(err => console.error(err, req.body)) |
|
}) |
|
}) |
|
|
|
.then(_ => { |
|
cb(null, 'Success!\n') |
|
}) |
|
.catch(err => { console.error(err); cb(err) }) |
|
})) |
|
|
|
// Pipe results to stdout! |
|
.pipe(process.stdout) |
|
.on('error', err => console.error(err)) |
@pedromgapt Full rewrite of the script could be found here https://github.com/johanhermansson/letterboxd-exporter
It's now separated into two separated scripts, one for exporting from Letterboxd, and another to import into Taste.io