Skip to content

Instantly share code, notes, and snippets.

@aravindanve
Last active March 7, 2021 19:30
Show Gist options
  • Save aravindanve/2800fe099b43fe279d776438f10e37ef to your computer and use it in GitHub Desktop.
Save aravindanve/2800fe099b43fe279d776438f10e37ef to your computer and use it in GitHub Desktop.
Unsaved all saved instagram posts
/*
* unsaveAllInstagramPosts.js
* usage: visit https://instagram.com and run in the browser console (you must be logged in)
* version: 2021-03-07
* issues: does not unsave sponsored posts
*/
unsaveAllInstagramPosts = async () => {
const baseUrl = 'https://www.instagram.com';
// get user id and csrf token from cookie
const userId = document.cookie.match(/ds_user_id=([^;]+);/)[1];
const csrftoken = document.cookie.match(/csrftoken=([^;]+);/)[1];
// set request options
const credentials = 'include';
const headers = {
'x-csrftoken': csrftoken,
};
// text parser
const text = (it) => it.text();
// sleep
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// get possible query hashes for saved posts query
const queryHashes = await (async () => {
const baseBody = await fetch(baseUrl, {
method: 'GET',
credentials,
}).then(text);
const jsBundlePath = baseBody.match(
/(\/static\/bundles\/es6\/Consumer\.js[^"]+)/,
)[1];
const jsBundleUrl = baseUrl + jsBundlePath;
const jsBundleBody = await fetch(jsBundleUrl, {
method: 'GET',
credentials,
}).then(text);
// console.log({ jsBundleBody });
const queryIds = jsBundleBody
.match(/queryId:"[^"]*"/g)
.map((it) => it.match(/queryId:"([^"]*)"/)[1]);
// console.log({ queryIds });
return queryIds;
})();
// saved posts getter
const getSavedPosts = async (first, after) => {
console.log(`Fetching ${first} posts${after ? ` after ${after}` : ''}`);
for (const queryHash of queryHashes) {
const initialVariables = encodeURI(
JSON.stringify({ id: userId, first, after }),
);
const initialSavedPostsQueryUrl =
`${baseUrl}/graphql/query/` +
`?query_hash=${queryHash}&variables=${initialVariables}`;
let result = await fetch(initialSavedPostsQueryUrl, {
method: 'GET',
credentials,
headers,
})
.then((it) => it.json())
.catch(() => null);
if (result && result.data.user.edge_saved_media) {
return result.data.user.edge_saved_media;
}
}
};
let cursor;
while (true) {
const posts = await getSavedPosts(100, cursor);
console.log(`Saved posts remaining: ${posts.count}`);
if (posts.edges.length) {
cursor = undefined;
console.log(`Deleting ${posts.edges.length} posts`);
for (const postId of posts.edges.map((it) => it.node.id)) {
console.log(`Deleting post ${postId}`);
const unsavePostUrl = `https://www.instagram.com/web/save/${postId}/unsave/`;
await fetch(unsavePostUrl, {
method: 'POST',
credentials,
headers,
});
}
} else if (posts.page_info.has_next_page) {
cursor = posts.page_info.end_cursor;
console.log('No posts on this page, sleeping to avoid 429 errors');
await sleep(5000);
continue;
} else {
console.log('No more posts to delete!');
break;
}
}
};
unsaveAllInstagramPosts().then(console.log).catch(console.error);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment