Skip to content

Instantly share code, notes, and snippets.

@steffenz
Last active April 4, 2022 11:33
Show Gist options
  • Save steffenz/7750af0204a23720bdbef1f4f8808739 to your computer and use it in GitHub Desktop.
Save steffenz/7750af0204a23720bdbef1f4f8808739 to your computer and use it in GitHub Desktop.
Download all Snapchat Memories (Node)
/*
1. Go to https://accounts.snapchat.com/ and request download of your data.
2. Download zip-file (when ready) and locate json/memories_history.json
3. Create a new folder with this script and the memories_history.json file
4. Install node-fetch; npm install node-fetch@^2.6.6 (using older version to avoid having to import as module)
5. Run the script.
Files will be prefixed with the date and a unique ID (from Snapchat) to avoid overwriting (see more details below).
This script was originally inspired by this StackOverflow question (but has since diverged greatly); https://stackoverflow.com/questions/61058637/snapchat-download-all-memories-at-once
Now go get those memories before the links expire ;)
*/
const fetch = require('node-fetch');
const fs = require('fs');
// Folder to save all files in
const saveToFolder = './Memories';
// Helper-function to format numbers under 10 with leading zeros (helps with OCD).
const getNumberWithLeadingZero = (number) => number > 9 ? number : `0${number}`;
// Stupidly create the date manually (look ma, no library!)
const getDate = (date, spacer = '-') => `${date.getFullYear()}${spacer}${getNumberWithLeadingZero(date.getMonth()+1)}${spacer}${getNumberWithLeadingZero(date.getDate())}${spacer}${getNumberWithLeadingZero(date.getHours())}${spacer}${getNumberWithLeadingZero(date.getMinutes())}`;
(async () => {
// Create output folder if it doesn't exists
if(!fs.existsSync(saveToFolder)) { fs.mkdirSync(saveToFolder)}
// All memories resides within the "Saved Media" object at the time of writing.
const memories = JSON.parse(fs.readFileSync('memories_history.json'))['Saved Media'];
for (const memory of memories){
// Create a new Date object of the memory date.
const fileDate = new Date(Date.parse(memory['Date']));
// Make a request to get the actual media URL on AWS (slaps on required authentication etc)
const fileDownloadURLRequest = await fetch(memory['Download Link'], { method: 'POST' });
// The actual media URL - we'll parse the URL to be able to extract the unique filename.
// I did originally just use the date as filename, but if you've recorded multiple snaps at once (typically a video) they will all have the same timestamp and thus be overwritten until the last part ..
const fileDownloadUrl = new URL(await fileDownloadURLRequest.text());
// Get the actual data file from AWS
const fileContent = await fetch(fileDownloadUrl, { method: 'GET' });
// Last part of the URL contains filename, so let's split the string and pop the last item in the array.
const originalFileName = fileDownloadUrl.pathname.split('/').pop();
// Use helper to get pretty date (makes sorting/archiving easier), and slap on unique ID to avoid overwriting.
const newFileName = `${getDate(fileDate)}_${originalFileName}`;
// Create new file with the correct file name in our desired folder
const newFileStream = fs.createWriteStream(`${saveToFolder}/${newFileName}`);
// Pipe contents into file
fileContent.body.pipe(newFileStream);
// Notify when file is saved
newFileStream.on('finish', () => console.log(`💾 Saved ${newFileName}`));
// Print out errors (might need to be further improved if you experience errors)
newFileStream.on('error', (err) => console.error(err));
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment