Skip to content

Instantly share code, notes, and snippets.

@thesephist
Last active May 11, 2022 00:40
Show Gist options
  • Save thesephist/68dbaef459c3ff5544f88da2d47c6f9c to your computer and use it in GitHub Desktop.
Save thesephist/68dbaef459c3ff5544f88da2d47c6f9c to your computer and use it in GitHub Desktop.
Instagram Saved Photos downloader
{
const UserID = '1227062513';
const PAGE_N = 1000;
function wait(timeout) {
return new Promise(res => setTimeout(res, timeout * 1000));
}
function createURL(after = '') {
const QUERY_HASH = '2ce1d673055b99250e93b6f88f878fde'; // seems to be a unique URL per GraphQL query type
return encodeURI(`https://www.instagram.com/graphql/query/?query_hash=${QUERY_HASH}&variables=${JSON.stringify({
id: UserID,
first: PAGE_N,
after: after,
})}`);
}
function createMediaURL(id) {
return `https://i.instagram.com/api/v1/media/${id}/info/`;
}
(async () => {
const Photos = [];
try {
let i = 0;
let cursor = '';
while (cursor != null) {
const resp = await fetch(createURL(cursor)).then(resp => resp.json());
const { page_info, edges } = resp.data.user.edge_saved_media;
console.log(edges);
for (const edge of edges) {
if (edge.node.__typename === 'GraphImage') {
Photos.push(edge.node.display_url);
} else {
const resp = await fetch(createMediaURL(edge.node.id), {
credentials: 'include',
headers: {
'x-asbd-id': '<redacted>',
'x-ig-app-id': '<redacted>',
'x-ig-www-claim': 'hmac.<redacted>',
}
}).then(resp => resp.json());
const media = (resp.items ? resp.items[0].carousel_media : []) || [];
for (const m of media) {
Photos.push(m.image_versions2.candidates[0].url);
}
console.log(media);
}
}
if (page_info.has_next_page) {
cursor = page_info.end_cursor;
} else {
cursor = null;
}
i++;
await wait(10);
console.log(cursor);
}
} catch(e) {}
console.log(Photos);
})();
}
std := import('std')
str := import('str')
fs := import('fs')
fmt := import('fmt')
path := import('path')
crypto := import('crypto')
debug := import('debug')
RespPath := './urls.txt'
DestDir := './instarch'
fn downloadURL(url) {
evt := req({ url: url })
if evt.type {
:error -> std.println('Failed download: ', evt.error)
_ -> {
name := fmt.format('{{0}}.jpg', crypto.uuid())
filePath := path.join(DestDir, name)
fs.writeFile(filePath, evt.resp.body)
std.println(
fmt.format('Saved: {{0}}...{{1}} -> {{2}}'
url |> std.slice(0, 32)
url |> std.slice(len(url) - 32)
name)
)
}
}
}
with fs.readFile(RespPath) fn(file) if file {
? -> std.println('Could not read ' + RespPath)
_ -> if urls := str.split(file, '\n') {
:error -> std.println('Could not parse file')
_ -> {
fmt.printf('{{0}} total URLs read.', len(urls))
urls |> with std.each() fn(url) {
downloadURL(url)
wait(0.5)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment