Skip to content

Instantly share code, notes, and snippets.

@erunion
Created March 27, 2021 09:08
Show Gist options
  • Save erunion/e94ebfe85a6bdfab06b42f39da780c75 to your computer and use it in GitHub Desktop.
Save erunion/e94ebfe85a6bdfab06b42f39da780c75 to your computer and use it in GitHub Desktop.
Script used to remix Letterboxd and TMDB data for https://letterboxd.com/erunion/list/franchise-sequels-that-were-released-head/
const fetch = require('node-fetch');
const cheerio = require('cheerio');
const path = require('path');
const token = '<TMDB API KEY>';
const args = process.argv.slice(2);
const year = args.length ? args[0] : undefined;
if (!year) {
console.error(`USAGE: node ${path.basename(process.argv[1])} <YEAR>`);
process.exit();
}
(async () => {
console.log(`👨‍🏭 fetching letterboxd sequels for ${year}`)
const movies = [];
const url = `https://letterboxd.com/jlalibs/list/big-list-of-movie-sequels-franchises/year/${year}/by/release-earliest/`;
await fetch(url).then(res => res.text()).then(res => {
const $ = cheerio.load(res);
$('div.film-poster img.image').each((i, elem) => {
movies.push($(elem).attr('alt'));
});
});
movies.sort();
console.log(movies, '\n')
console.log(`👨‍🏭 searching tmdb`)
await Promise.all(
movies.map(movie => {
if (!movie.length) return;
// https://developers.themoviedb.org/3/search/search-movies
const url = `https://api.themoviedb.org/3/search/movie?${[
`api_key=${token}`,
`query=${encodeURIComponent(movie)}`,
].filter(q => q != false).join('&')}`;
return fetch(url).then(res => res.json()).then(json => {
if (!('results' in json)) {
return;
}
const table = {};
json.results.forEach(res => {
if (res.release_date === undefined) {
return;
} else if (year && !new RegExp(`^${year}-(.+)`).test(res.release_date)) {
return;
} else if (res.release_date === `${year}-01-01`) {
// Excluding any sequels that have a January 1st release date as that seems to generally be the default
// date in TMDB if there's no specific month or day. There might be some false positives getting filtered
// out because of this but it seems extremely likely.
return;
} else if (!movies.includes(res.title)) {
return;
}
if (!(res.release_date in table)) {
table[res.release_date] = [];
}
table[res.release_date].push(res.title)
});
return table;
});
})
)
.then(res => res.filter(r => r !== undefined))
.then(res => {
const grouped = {};
res.forEach(data => {
Object.keys(data).forEach(date => {
if (!(date in grouped)) {
grouped[date] = [];
}
grouped[date] = [
...new Set(
grouped[date].concat(data[date])
)
]
})
})
return grouped;
})
.then(res => {
return Object.keys(res).sort().reduce((obj, key) => {
obj[key] = res[key];
return obj;
}, {});
})
.then(res => {
console.log(res, '\n');
let showAlert = true;
Object.keys(res).forEach(date => {
if (res[date].length > 1) {
if (showAlert) {
console.log('-- 🚨 COMPETING SEQUELS FOUND 🚨 -- ', '\n');
}
console.log(date, res[date]);
showAlert = false;
}
});
})
})();
{
"dependencies": {
"cheerio": "^1.0.0-rc.5",
"node-fetch": "^2.6.1"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment