Last active
March 3, 2023 15:08
-
-
Save 0b5vr/070a33c7971300a3f194ed1b3af7de0a to your computer and use it in GitHub Desktop.
A deno script that downloads all files in the Slack export archive
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* A deno script that downloads all files in the Slack export archive | |
* 2023-03-03 | |
* | |
* Copyright (c) 2023 0b5vr | |
* SPDX-License-Identifier: MIT | |
* | |
* Usage: | |
* - Install deno - https://deno.land/ | |
* - `deno run --allow-read --allow-write --allow-net download.ts <export>` | |
* | |
* Ref: https://gist.github.com/marnitto/f9970c2bbf2798782c06bc2b9d58c0cc | |
*/ | |
import * as fs from "https://deno.land/[email protected]/fs/mod.ts"; | |
import * as path from "https://deno.land/[email protected]/path/mod.ts"; | |
async function downloadFile( | |
fileEntity: Record<string, unknown>, | |
downloadDir: string, | |
) { | |
const name = fileEntity["name"] as string | undefined; | |
if (name == null) { | |
console.log("π€ Skipping a file - The file entry does not have a name"); | |
return; | |
} | |
const id = fileEntity["id"] as string | undefined; | |
if (id == null) { | |
console.log(`π€ Skipping ${name} - The file entry does not have an id`); | |
return; | |
} | |
const url = fileEntity["url_private_download"] as string | undefined; | |
if (url == null) { | |
console.log(`π€ Skipping ${name} - The file entry does not have an URL`); | |
return; | |
} | |
console.log(`π₯ Downloading ${name}`); | |
fs.ensureDir(downloadDir); | |
const filepath = path.join(downloadDir, `${id}_${name}`); | |
const res = await fetch(url); | |
const dst = await Deno.open(filepath, { write: true, create: true }); | |
await res.body?.pipeTo(dst.writable); | |
} | |
const ignoreJsonList = new Set([ | |
"channels.json", | |
"integration_logs.json", | |
"users.json", | |
]); | |
async function main(): Promise<void> { | |
const exportDir = Deno.args[0]; | |
if (exportDir == null) { | |
throw new Error("Please specify an exported directory!"); | |
} | |
const exportDirStat = await Deno.stat(exportDir); | |
if (!exportDirStat.isDirectory) { | |
throw new Error("The given path is not a directory"); | |
} | |
const diaryEntryIter = fs.expandGlob(path.join(exportDir, "**/*.json")); | |
for await (const diaryEntry of diaryEntryIter) { | |
if (ignoreJsonList.has(diaryEntry.name)) { | |
console.log(`β© Skipping ${diaryEntry.name}`); | |
continue; | |
} | |
const diary = JSON.parse(await Deno.readTextFile(diaryEntry.path)); | |
if (!Array.isArray(diary)) { | |
console.log(`π€ Skipping ${diaryEntry.name} - The JSON is not an array`); | |
continue; | |
} | |
const diaryPathSplit = diaryEntry.path.split("\\"); | |
const date = diaryPathSplit[diaryPathSplit.length - 1].split(".")[0]; | |
const channel = diaryPathSplit[diaryPathSplit.length - 2]; | |
const downloadDir = path.join(exportDir, channel, date); | |
console.log(`π Processing ${downloadDir}`); | |
for (const messages of diary as Record<string, unknown>[]) { | |
const file = messages["file"] as Record<string, unknown> | undefined; | |
if (file != null) { | |
await downloadFile(file, downloadDir); | |
} | |
const files = messages["files"] as Record<string, unknown>[] | undefined; | |
if (files != null) { | |
for (const file of files) { | |
await downloadFile(file, downloadDir); | |
} | |
} | |
} | |
} | |
console.log("β Completed"); | |
} | |
main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment