Skip to content

Instantly share code, notes, and snippets.

@sadalsvvd
Last active April 10, 2023 19:54
Show Gist options
  • Save sadalsvvd/8a404106dc79958f88c634270c28fc32 to your computer and use it in GitHub Desktop.
Save sadalsvvd/8a404106dc79958f88c634270c28fc32 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Twitter Archive Viewer</title>
<!-- Include a CSS library for basic styling (Bootstrap) -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<!-- Include a JavaScript library for DOM manipulation (jQuery) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<div class="container">
<h1>Twitter Archive Viewer</h1>
<div id="tweets"></div>
</div>
<script src="./formatted_tweets.js"></script>
<script>
// Load the JSON file with the FilteredTweetArray data
const filteredTweetArray = window.tweets;
// Define a function to render tweets recursively, including children
function renderTweet(tweet, isChild) {
const borderClass = isChild ? '' : 'border-bottom';
let tweetHtml = `
<div class="tweet ${borderClass}" style="border-color: #555 !important;">
<p>${isChild ? '' : new Date(tweet.created_at).toISOString() + ' | '}F: ${tweet.favorite_count} | RT: ${tweet.retweet_count} | ${tweet.in_reply_to_screen_name ? `Reply to: ${tweet.in_reply_to_screen_name}` : ''}</p>
<p>${tweet.full_text}</p>
`;
if (tweet.children.length > 0) {
tweetHtml += '<div class="children">';
tweet.children.forEach(child => {
tweetHtml += renderTweet(child, true);
});
tweetHtml += '</div>';
}
tweetHtml += '</div>';
return tweetHtml;
}
// Call the function to render the tweets and insert them into the HTML
let tweetsHtml = '';
filteredTweetArray.forEach(tweet => {
tweetsHtml += renderTweet(tweet, false);
});
$('#tweets').html(tweetsHtml);
</script>
</body>
</html>
// This creates a tree.json file out of your data
const fs = require('fs');
// Note: you have to rename tweets.js to tweets.json and remove the leading
const tweetData = require('./tweets.json');
function buildTweetTree(tweetDataArray) {
const idToTweetMap = {};
const roots = [];
// Step 4: Map tweets by their ID
tweetDataArray.forEach(({ tweet }) => {
tweet.children = [];
idToTweetMap[tweet.id_str] = tweet;
});
// Step 5: Build the tree structure
tweetDataArray.forEach(({ tweet }) => {
if (tweet.in_reply_to_status_id) {
const parentTweet = idToTweetMap[tweet.in_reply_to_status_id_str];
if (parentTweet) {
parentTweet.children.push(tweet);
}
} else {
roots.push(tweet);
}
});
// Step 6: Return the roots array
return roots;
}
function filterTweetProperties(tweet) {
const filteredTweet = {
id: tweet.id,
full_text: tweet.full_text,
favorite_count: tweet.favorite_count,
retweet_count: tweet.retweet_count,
created_at: tweet.created_at,
in_reply_to_status_id: tweet.in_reply_to_status_id,
in_reply_to_screen_name: tweet.in_reply_to_screen_name,
children: [],
};
if (tweet.extended_entities) {
filteredTweet.media = filterMediaProperties(tweet.extended_entities.media);
}
if (tweet.children && tweet.children.length > 0) {
filteredTweet.children = tweet.children.map(filterTweetProperties);
}
return filteredTweet;
}
function filterMediaProperties(media) {
return {
media_url_https: media.media_url_https,
type: media.type,
source_user_id: media.source_user_id,
display_url: media.display_url,
};
}
function buildFilteredTweetTree(tweetDataArray) {
const tweetTree = buildTweetTree(tweetDataArray);
const filteredTweetTree = tweetTree.map(filterTweetProperties);
return filteredTweetTree;
}
const roots = buildFilteredTweetTree(tweetData);
fs.writeFileSync('formatted_tweets.json', JSON.stringify(roots, null, 4), 'utf8');

Escaping Twitter (getting your archive readable)

So! Trying to get off Twitter? OR maybe just want to explore your data? I wrote a script that turns your Twitter archive into a default readable page. Twitter offers you a page for this, but it breaks threads, so I used ChatGPT to reformat the data and build a dead simple web builder. I'll share the loose structure of how I got ChatGPT to do this, but the other files here are the final scripts so that you don't have to fiddle with tweaking them yourself.

  1. Download your data here: https://twitter.com/settings/download_your_data (it usually takes a day or two for this to be ready)
  2. Feed ChatGPT 4 (not 3.5) some of the sample tweets from ARCHIVE/tweets.js and have it generate types
  3. Instruct GPT-4 to create a script which merges tweets into a tree structure, preserving the parent-child relationship for threads, and throw away extra unnecessary fiels
  4. Instruct GPT-4 to create an HTML page using that script
  5. Open and enjoy!

Technically you don't need to filter out the data, but it makes the process faster and easier to work with post-transformation.

Prerequisites

Detailed Instructions for these scripts

Assuming you don't mess around with creating your own ChatGPT script, here is how you use this gist.

  1. Download your archive
  2. Copy your tweets.js from ARCHIVE/data/tweets.js to ARCHIVE/tweets.json
  3. Edit tweets.json to delete the leading window.YTD.tweets.part0 = . Once you do that, your tweets.json file is now valid JSON
  4. Copy my compile.js script to ARCHIVE/compile.js
  5. Run compile.json with Node (run Node from your command line of choice). If you don't know how to use a command line:
  6. The previous command generates a formatted_tweets.json file. Open it and add window.tweets = , then save the file as formatted_tweets.js. This is the file that our basic browser will use.
  7. Copy my compile.html file to ARCHIVE/compile.html and double click it to open it. If you've correctly done everything, compile.html will pull the formatted_tweets.js file from the same directory, and show you a view that looks like this:

image

You of course can tweak any of the scripts, run them through ChatGPT-4, ask for modifications, and so on. I set up mine in a way that has enough utility for my needs (copying them out and structuring them), but you can now use your dataset to generate markdown files, or upload somewhere, or whatever.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment