Last active
April 2, 2024 16:49
-
-
Save ment4list/4571644f7b49c1ae72c4ac1ec5ce9c91 to your computer and use it in GitHub Desktop.
Omnivore Articles to ePub via ScriptKit script
This file contains hidden or 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
// Name: Send to Kindle - Omnivore | |
// This is a script meant to be added to [ScriptKit](https://www.scriptkit.com/) to add your Omnivore articles as an epub. | |
// Email is sent via AppleScript | |
import "@johnlindquist/kit" | |
// Source: https://github.com/agrmohit/omnivore-epub/blob/main/main.ts | |
import epub from "epub-gen-memory"; | |
import { gql, GraphQLClient } from "graphql-request"; | |
import sanitizeHtml from "sanitize-html"; | |
const config = { | |
"endpoint": "https://api-prod.omnivore.app/api/graphql", | |
"title": "Omnivore Articles", | |
"author": "Omnivore", | |
"cover": "https://cdn.discordapp.com/attachments/779248028824764426/1149996974234423346/cover.jpg", | |
"description": "Articles from Omnivore", | |
"addLabelsInContent": false, | |
"addArticleLinkInContent": true, | |
"allowImages": true, | |
"outputFileName": "output.epub", | |
"maxArticleCount": 5, //,100 // itemsToFetch | |
"ignoredLabels": ["pdf"], | |
"ignoredLinks": ["https://www.youtu", "https://youtu"], | |
}; | |
const currentVersion = "v0.2.0"; | |
console.log(`ℹ Omnivore EPUB ${currentVersion}`); | |
console.log("ℹ️ Homepage: https://github.com/agrmohit/omnivore-epub"); | |
const OMNIVORE_API_KEY = await env("OMNIVORE_API_KEY"); | |
const OMNIVORE_ENDPOINT = config.endpoint; | |
const KINDLE_EMAIL_ADDRESS = await env("KINDLE_EMAIL_ADDRESS"); | |
if (!OMNIVORE_API_KEY) { | |
console.log("❌ Omnivore API token not set"); | |
console.log( | |
"❌ Get a token following instructions on: https://docs.omnivore.app/integrations/api.html#getting-an-api-token", | |
); | |
console.log("❌ When you have a token, insert it as value for 'token' field in 'config.json' file"); | |
// Deno.exit(1); | |
} | |
const graphQLClient = new GraphQLClient(OMNIVORE_ENDPOINT, { | |
headers: { | |
authorization: OMNIVORE_API_KEY, | |
}, | |
}); | |
async function checkForUpdates() { | |
const response = await fetch("https://api.github.com/repos/agrmohit/omnivore-epub/tags"); | |
const tags = await response.json(); | |
if (tags[0].name !== currentVersion) { | |
console.log("ℹ New update available"); | |
console.log(`ℹ ${currentVersion} --> ${tags[0].name}`); | |
} | |
} | |
async function getUnreadArticles() { | |
const query = gql` | |
{ | |
search(first: ${config.maxArticleCount}) { | |
... on SearchSuccess { | |
edges { | |
cursor | |
node { | |
title | |
slug | |
description | |
url | |
savedAt | |
language | |
subscription | |
isArchived | |
author | |
labels { | |
name | |
} | |
} | |
} | |
} | |
} | |
} | |
`; | |
var Label = { | |
name: '' | |
}; | |
var Edge = { | |
cursor: '', | |
node: { | |
title: '', | |
slug: '', | |
url: '', | |
savedAt: '', | |
language: '', | |
subscription: '', | |
isArchived: false, | |
author: '', | |
labels: [], | |
labelsArray: [], | |
} | |
}; | |
const data = await graphQLClient.request( | |
query, | |
); | |
return data.search.edges.map((e) => { | |
if (e.node.labels) { | |
e.node.labelsArray = e.node.labels.map((label) => label.name); | |
} | |
return e.node; | |
}); | |
} | |
async function getArticle(slug) { | |
// console.log(' getArticle() with slug' + slug ) | |
const query = gql`{ | |
article (username: "anonymous", slug: "${slug}") { | |
... on ArticleSuccess { | |
article { | |
id, slug, url, content | |
} | |
} | |
} | |
}`; | |
const data = await graphQLClient.request(query) | |
let allowedTags; | |
if (config.allowImages) { | |
allowedTags = sanitizeHtml.defaults.allowedTags.concat(["img"]); | |
} else { | |
allowedTags = sanitizeHtml.defaults.allowedTags.concat(); | |
} | |
if(!data) { | |
return { | |
title: 'None..', | |
content: '' | |
} | |
} | |
const sanitizedArticle = sanitizeHtml(data.article.article.content, { | |
allowedTags: allowedTags, | |
}); | |
return { | |
...data.article.article, | |
content: sanitizedArticle, | |
}; | |
} | |
async function makeMagazine() { | |
console.log("〰️ getting article list"); | |
const articles = await getUnreadArticles(); | |
console.log("🤖 done"); | |
const chapters = []; | |
for (const article of articles) { | |
if (!article.isArchived) { | |
console.log(`🌐 fetching ${article.title}`); | |
let content = (await getArticle(article.slug)).content; | |
if (article.labelsArray) { | |
if ( | |
config.ignoredLinks.some((url) => article.url.includes(url)) | |
|| article.labelsArray.find((label) => config.ignoredLabels.includes(label)) | |
) { | |
console.log("⚠️ article skipped"); | |
continue; | |
} | |
if (config.addLabelsInContent) { | |
content = `<b>Labels: ${article.labelsArray.join(", ")}</b>` + content; | |
} | |
} | |
if (config.addArticleLinkInContent) { | |
content = `<a href="${article.url}">Link to Article</a><br><br>` + content; | |
} | |
chapters.push({ | |
title: article.title, | |
author: article.author ?? "Omnivore", | |
content: content, | |
filename: article.slug, | |
}); | |
console.log(`✅ done`); | |
} | |
} | |
console.log('Done fetching content for articles... Writing ePub file... Please wait.') | |
const fileBuffer = await epub.default( | |
{ | |
title: config.title, | |
author: config.author, | |
cover: config.cover, | |
description: config.description, | |
ignoreFailedDownloads: true, | |
}, | |
chapters, | |
); | |
console.log("📚 Successfully created ebook"); | |
await writeFile(home('Downloads/output.epub'), fileBuffer) | |
// Send email via applescript | |
await applescript(` | |
-- Set your email details | |
set recipientAddress to "${KINDLE_EMAIL_ADDRESS}" | |
set emailSubject to "Omnivore Latest Articles for ${dateAsStr()}" | |
set emailBody to "Please see your epub attached" | |
-- Path to the file you want to attach | |
set attachmentPath to "${outputPath}" | |
-- Create a new outgoing message | |
tell application "Mail" | |
set newMessage to make new outgoing message with properties {subject:emailSubject, content:emailBody, visible:true} | |
-- Set the recipient | |
tell newMessage | |
make new to recipient with properties {address:recipientAddress} | |
-- Attach the file | |
make new attachment with properties {file name:attachmentPath} at after the last paragraph | |
end tell | |
-- Send the message | |
send newMessage | |
end tell | |
`); | |
} | |
await checkForUpdates(); | |
await makeMagazine(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment