mirror of
https://github.com/svemagie/indiekit-endpoint-youtube.git
synced 2026-04-02 15:54:59 +02:00
fix: write like posts to GitHub store via postTemplate + store.createFile
Previously sync only inserted into MongoDB, causing "file not found" errors when Indiekit tried to read the post. Now generates markdown via publication.postTemplate() and writes to GitHub via publication.store.createFile(), matching the micropub endpoint's create flow. Reset also deletes store files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -236,8 +236,36 @@ export const likesController = {
|
||||
|
||||
const postsCollection = request.app.locals.application.collections?.get("posts");
|
||||
|
||||
const publication = request.app.locals.publication;
|
||||
|
||||
let deletedPosts = 0;
|
||||
if (postsCollection) {
|
||||
// Delete files from the store (GitHub) before removing from MongoDB
|
||||
if (publication?.store) {
|
||||
const likePosts = await postsCollection
|
||||
.find({
|
||||
"properties.post-type": "like",
|
||||
"properties.youtube-video-id": { $exists: true },
|
||||
})
|
||||
.toArray();
|
||||
|
||||
for (const post of likePosts) {
|
||||
try {
|
||||
const message = publication.storeMessageTemplate
|
||||
? publication.storeMessageTemplate({
|
||||
action: "delete",
|
||||
result: "deleted",
|
||||
fileType: "post",
|
||||
postType: "like",
|
||||
})
|
||||
: `Delete like post ${post.path}`;
|
||||
await publication.store.deleteFile(post.path, { message });
|
||||
} catch (err) {
|
||||
console.error(`[YouTube] Failed to delete ${post.path} from store:`, err.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = await postsCollection.deleteMany({
|
||||
"properties.post-type": "like",
|
||||
"properties.youtube-video-id": { $exists: true },
|
||||
|
||||
@@ -61,6 +61,28 @@ async function snapshotExistingLikes(db, client, accessToken, maxPages) {
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare template properties by stripping internal mp-* and post-type keys,
|
||||
* matching what Indiekit's micropub endpoint does before calling postTemplate.
|
||||
* @param {object} properties
|
||||
* @returns {object}
|
||||
*/
|
||||
function getTemplateProperties(properties) {
|
||||
const templateProperties = structuredClone(properties);
|
||||
const preserveMpProperties = ["mp-syndicate-to"];
|
||||
|
||||
for (const key in templateProperties) {
|
||||
if (key.startsWith("mp-") && !preserveMpProperties.includes(key)) {
|
||||
delete templateProperties[key];
|
||||
}
|
||||
if (key === "post-type") {
|
||||
delete templateProperties[key];
|
||||
}
|
||||
}
|
||||
|
||||
return templateProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync liked videos into the Indiekit posts collection.
|
||||
*
|
||||
@@ -71,7 +93,7 @@ async function snapshotExistingLikes(db, client, accessToken, maxPages) {
|
||||
* @param {object} opts
|
||||
* @param {import("mongodb").Db} opts.db
|
||||
* @param {object} opts.youtubeConfig - endpoint options
|
||||
* @param {object} opts.publication - Indiekit publication config
|
||||
* @param {object} opts.publication - Indiekit publication (with store, postTemplate, storeMessageTemplate)
|
||||
* @param {import("mongodb").Collection} [opts.postsCollection]
|
||||
* @param {number} [opts.maxPages=3] - max pages to fetch (50 likes/page)
|
||||
* @returns {Promise<{synced: number, skipped: number, total: number, baselined?: number, error?: string}>}
|
||||
@@ -163,9 +185,7 @@ export async function syncLikes({ db, youtubeConfig, publication, postsCollectio
|
||||
? likePostType.post.url.replace("{slug}", slug)
|
||||
: `${publicationUrl}/likes/${slug}/`;
|
||||
|
||||
const postDoc = {
|
||||
path: postPath,
|
||||
properties: {
|
||||
const postProperties = {
|
||||
"post-type": "like",
|
||||
"mp-slug": slug,
|
||||
"like-of": videoUrl,
|
||||
@@ -181,9 +201,31 @@ export async function syncLikes({ db, youtubeConfig, publication, postsCollectio
|
||||
"youtube-video-id": videoId,
|
||||
"youtube-channel": video.channelTitle,
|
||||
"youtube-thumbnail": video.thumbnail || "",
|
||||
},
|
||||
};
|
||||
|
||||
// Write markdown file to the store (e.g. GitHub)
|
||||
if (publication?.postTemplate && publication?.store) {
|
||||
try {
|
||||
const templateProperties = getTemplateProperties(postProperties);
|
||||
const content = await publication.postTemplate(templateProperties);
|
||||
const message = publication.storeMessageTemplate
|
||||
? publication.storeMessageTemplate({
|
||||
action: "create",
|
||||
result: "created",
|
||||
fileType: "post",
|
||||
postType: "like",
|
||||
})
|
||||
: `Create like post for ${videoId}`;
|
||||
|
||||
await publication.store.createFile(postPath, content, { message });
|
||||
} catch (storeError) {
|
||||
console.error(`[YouTube] Failed to write ${postPath} to store:`, storeError.message);
|
||||
// Continue — still insert into MongoDB so it isn't retried
|
||||
}
|
||||
}
|
||||
|
||||
// Insert into MongoDB posts collection
|
||||
const postDoc = { path: postPath, properties: postProperties };
|
||||
if (postsCollection) {
|
||||
await postsCollection.insertOne(postDoc);
|
||||
}
|
||||
@@ -233,7 +275,7 @@ export function startLikesSync(Indiekit, options) {
|
||||
if (!db) return;
|
||||
|
||||
const postsCollection = Indiekit.config?.application?.collections?.get("posts");
|
||||
const publication = Indiekit.config?.publication;
|
||||
const publication = Indiekit.publication || Indiekit.config?.publication;
|
||||
|
||||
try {
|
||||
const result = await syncLikes({
|
||||
|
||||
Reference in New Issue
Block a user