diff --git a/apps/sanity/functions/syndicate-content/index.ts b/apps/sanity/functions/syndicate-content/index.ts index ffe86e37..d3b1281f 100644 --- a/apps/sanity/functions/syndicate-content/index.ts +++ b/apps/sanity/functions/syndicate-content/index.ts @@ -176,7 +176,7 @@ export const handler = documentEventHandler( } const mainImageUrl = - urlForImage(data.coverImage)?.width(1000).height(420).url() || ""; + urlForImage(data.coverImage)?.width(1280).url() || ""; const youtubeEmbed = data.youtube ? `{% youtube ${data.youtube.replace("live", "embed")} %}\n\n` @@ -209,6 +209,9 @@ export const handler = documentEventHandler( existingSyndication?.externalId || (data.devto ? data.devto.split("https://dev.to/").at(-1) : null); + let targetDevtoUrl = "https://dev.to/api/articles"; + let devtoMethod = "POST"; + if (existingDevtoId && !existingDevtoId.startsWith("simulated-")) { // Retrieve existing article ID from Dev.to to perform a PUT update const getArticleRes = await fetch( @@ -223,39 +226,42 @@ export const handler = documentEventHandler( if (getArticleRes.ok) { const articleData = (await getArticleRes.json()) as any; - res = await fetch(`https://dev.to/api/articles/${articleData.id}`, { - method: "PUT", - headers: { - "api-key": apiKey, - "Content-Type": "application/json", - }, - body: JSON.stringify(devtoArticlePayload), - }); - } else { - // If lookup failed, create as new article - res = await fetch("https://dev.to/api/articles", { - method: "POST", + if (articleData?.id) { + targetDevtoUrl = `https://dev.to/api/articles/${articleData.id}`; + devtoMethod = "PUT"; + } + } + } + + res = await fetch(targetDevtoUrl, { + method: devtoMethod, + headers: { + "api-key": apiKey, + "Content-Type": "application/json", + }, + body: JSON.stringify(devtoArticlePayload), + }); + + let errText = ""; + if (!res.ok) { + errText = await res.text(); + if (errText.toLowerCase().includes("organization")) { + delete devtoArticlePayload.article.organization_id; + res = await fetch(targetDevtoUrl, { + method: devtoMethod, headers: { "api-key": apiKey, "Content-Type": "application/json", }, body: JSON.stringify(devtoArticlePayload), }); + if (!res.ok) { + errText = await res.text(); + } } - } else { - // Create new article - res = await fetch("https://dev.to/api/articles", { - method: "POST", - headers: { - "api-key": apiKey, - "Content-Type": "application/json", - }, - body: JSON.stringify(devtoArticlePayload), - }); } if (!res.ok) { - const errText = await res.text(); throw new Error(`Dev.to API error (${res.status}): ${errText}`); } diff --git a/scripts/assets/php2shell-cover.jpg b/scripts/assets/php2shell-cover.jpg index a689bd7e..58a7281b 100644 Binary files a/scripts/assets/php2shell-cover.jpg and b/scripts/assets/php2shell-cover.jpg differ diff --git a/scripts/publish-php2shell-post.mjs b/scripts/publish-php2shell-post.mjs index 1dd3408d..a23c5705 100644 --- a/scripts/publish-php2shell-post.mjs +++ b/scripts/publish-php2shell-post.mjs @@ -90,7 +90,7 @@ export async function publishPhp2ShellPost() { console.log(`Uploading PHP2Shell cover and meme images to Sanity (${dataset})...`); const coverAssetId = await uploadImage( path.join(__dirname, "assets/php2shell-cover.jpg"), - "php2shell-cover.jpg" + "php2shell-excalidraw-cover.jpg" ); const memeAssetId = await uploadImage( path.join(__dirname, "assets/php2shell-meme.jpg"), @@ -444,7 +444,21 @@ sudo systemctl restart php8.4-fpm apache2` }; const mutations = [ - { createOrReplace: postDoc }, + { createIfNotExists: postDoc }, + { + patch: { + id: postDoc._id, + set: { + title: postDoc.title, + slug: postDoc.slug, + date: postDoc.date, + excerpt: postDoc.excerpt, + author: postDoc.author, + coverImage: postDoc.coverImage, + content: postDoc.content, + }, + }, + }, { patch: { id: "LzgcvqoNSwz5R8loykZyIB", set: { excerpt: "Learn how to customize your Slack workspace theme using SlackThemes.net and contribute custom color themes on GitHub." } } }, { patch: { id: "ZKdo3vLUqcb4sYreiCMc5A", set: { excerpt: "Learn how to inspect and debug Angular 9 components directly inside the Chrome DevTools console using the new ng global object." } } }, { patch: { id: "ZKdo3vLUqcb4sYreiCPNnI", set: { excerpt: "Join Alex Patterson and Brittney Postma with special guests Zach DeRose, Facundo Giuliani, Swyx, Jason Lengstorf, and Scott Tolinski for a year-end Holiday AMA." } } }, diff --git a/scripts/run-syndicate-post.mjs b/scripts/run-syndicate-post.mjs index 84f45514..fe7a5afb 100644 --- a/scripts/run-syndicate-post.mjs +++ b/scripts/run-syndicate-post.mjs @@ -84,7 +84,7 @@ async function run() { const devtoTags = ["webdev", "javascript", "beginners"]; if (doc._type === "podcast") devtoTags.push("podcast"); - const mainImageUrl = urlForImage(doc.coverImage)?.width(1000).height(420).url() || ""; + const mainImageUrl = urlForImage(doc.coverImage)?.width(1280).url() || ""; const youtubeEmbed = doc.youtube ? `{% youtube ${doc.youtube.replace("live", "embed")} %}\n\n` : ""; const devtoArticlePayload = { @@ -105,10 +105,39 @@ async function run() { } try { + const existingSyndication = await client.getDocument(syndicationDocId).catch(() => null); + let existingArticleId = + existingSyndication?.externalId && !String(existingSyndication.externalId).startsWith("simulated-") + ? String(existingSyndication.externalId) + : null; + + if (!existingArticleId && doc.devto) { + const pathSlug = doc.devto.split("https://dev.to/").at(-1); + if (pathSlug) { + const lookupRes = await fetch(`https://dev.to/api/articles/${pathSlug}`, { + headers: { + "api-key": devtoApiKey, + "Content-Type": "application/json", + }, + }); + if (lookupRes.ok) { + const lookupJson = await lookupRes.json(); + if (lookupJson?.id) { + existingArticleId = String(lookupJson.id); + } + } + } + } + + const method = existingArticleId ? "PUT" : "POST"; + const targetUrl = existingArticleId + ? `https://dev.to/api/articles/${existingArticleId}` + : "https://dev.to/api/articles"; + // First attempt with organization_id: 1009 - console.log("Sending POST to Dev.to API with organization_id: 1009..."); - let res = await fetch("https://dev.to/api/articles", { - method: "POST", + console.log(`Sending ${method} to ${targetUrl} with organization_id: 1009...`); + let res = await fetch(targetUrl, { + method, headers: { "api-key": devtoApiKey, "Content-Type": "application/json", @@ -124,8 +153,8 @@ async function run() { if (!res.ok && resText.toLowerCase().includes("organization")) { console.warn("Dev.to rejected organization_id 1009. Retrying under personal account without organization_id..."); delete devtoArticlePayload.article.organization_id; - res = await fetch("https://dev.to/api/articles", { - method: "POST", + res = await fetch(targetUrl, { + method, headers: { "api-key": devtoApiKey, "Content-Type": "application/json", @@ -181,7 +210,7 @@ async function run() { { name: "Beginner Developers", slug: "beginners" }, ]; - const hashnodeCoverImageUrl = urlForImage(doc.coverImage)?.width(1600).height(840).url() || ""; + const hashnodeCoverImageUrl = urlForImage(doc.coverImage)?.width(1600).url() || ""; const youtubeEmbed = doc.youtube ? `%[${doc.youtube.replace("live", "embed")}]\n\n` : ""; const articleInput = {