Batch Process Multiple YouTube Links into Formatted YouTube Notes #1638
mjwSolver
started this conversation in
Templates Showcase
Replies: 3 comments 3 replies
|
Thank you so much for this! It is exactly what I was looking for and works perfectly. |
0 replies
|
Hmm. I can't find how the template knows to look at the /sources/youtube/Queue for YouTube Link.md file. |
3 replies
|
I've adjusted some settings and added some features. You can try them out. <%*
// --- CONFIGURATION ---
const outputFolder = "sources/youtube";
// --------------------
const notice = (msg) => new Notice(msg, 10000);
// --- Read all links from the file ---
const fileContent = tp.file.content;
if (!fileContent || fileContent.trim() === "") {
notice("❌ The file is empty.");
return;
}
const links = fileContent.split('\n').filter(link => link.trim() !== "");
if (links.length === 0) {
notice("❌ Could not find any links.");
return;
}
notice(`▶️ Starting to process ${links.length} links...`);
let createdCount = 0;
let skippedCount = 0;
for (const link of links) {
// --- 1. FETCH AND PARSE ---
let doc;
try {
// YOUR FIX APPLIED: Use the link directly without splitting it.
const page = await tp.obsidian.request({ url: link });
const p = new DOMParser();
doc = p.parseFromString(page, "text/html");
} catch (e) {
notice(`❌ Failed to fetch page for ${link}. Skipping.`);
skippedCount++;
continue;
}
const $ = (s) => doc.querySelector(s);
if (!$("meta[name='title']")) {
notice(`❌ Could not find video data for ${link}. Skipping.`);
skippedCount++;
continue;
}
// --- 2. EXTRACT AND FORMAT ---
const title = $("meta[name='title']").content;
const cleanTitle = title.replaceAll(/[^a-zA-Z0-9 ]/g, "").trim();
const fileName = `${cleanTitle}.md`;
const filePath = outputFolder ? `${outputFolder}/${fileName}` : fileName;
if (app.vault.getAbstractFileByPath(filePath)) {
skippedCount++;
continue;
}
const shortlinkUrl = $("link[rel='shortlinkUrl']").href;
const durationStr = $("meta[itemprop='duration']").content.slice(2, -1);
const uploadDate = $("meta[itemprop='uploadDate']").content;
const authorName = $("span[itemprop='author'] > link[itemprop='name']").getAttribute("content");
// Format Duration
const timeStr = (time) => time.toString().padStart(2, '0');
let [minutes, seconds] = durationStr.split("M");
let durationSummary = "Seconds";
let hours = Math.floor(Number(minutes) / 60);
minutes = (Number(minutes) % 60);
if (parseInt(minutes, 10) > 0) { durationSummary = "Minutes"; }
let formattedDuration = `${timeStr(minutes)}:${timeStr(seconds)}`;
let yamlDuration = "00:" + formattedDuration;
if (hours > 0) {
formattedDuration = `${timeStr(hours)}:` + formattedDuration;
durationSummary = "Hours";
yamlDuration = formattedDuration;
}
// Format Dates
const formatDate = (date) => {
let dateString = new Date(date.split('T')[0]).toDateString();
let [dayString, month, dayNumber, year] = dateString.split(' ');
let cleanDayNumber = dayNumber.replace(/^0+/, '');
return `${month} ${cleanDayNumber}, ${year}`;
};
const formatDateToISO = (date) => date.split('T')[0];
const finalUploadDate = formatDate(uploadDate);
const isoUploadDate = formatDateToISO(uploadDate);
// --- 3. BUILD THE NOTE CONTENT STRING ---
const newNoteContent = `---
title: [${title}](https://github.com/SilentVoid13/Templater/discussions/$%7BshortlinkUrl%7D)
url: ${shortlinkUrl}
channel: ${authorName}
published: ${isoUploadDate}
tags: src/youtube
duration: ${yamlDuration}
---
## ${title}
[${title}](${shortlinkUrl})
${formattedDuration} ${durationSummary} / ${finalUploadDate}

## Description
## Notes
## Transcript
`;
// --- 4. CREATE THE NOTE ---
try {
await app.vault.create(filePath, newNoteContent);
createdCount++;
} catch (e) {
notice(`❌ ERROR creating note for ${title}. Aborting.`);
return;
}
}
// --- FINAL SUMMARY ---
notice(`✅ Finished! Created ${createdCount} new notes. Skipped ${skippedCount}.`);
// Optional: Clear the queue file after processing
// await app.vault.modify(tp.file.file, "");
%> |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
📝 Quick Introduction
Taking YouTube notes is a staple of my self-study journey and I found that the Templater templates shared in a discussion to be very useful in retrieving the information (such as channel name and duration) but would work on one video at a time, when I have 10s of them.
I don't think there's any Queue / Batch Processing made for multiple YouTube links yet, so I'd like to share the code I made but incorporates a loop to go through all listed YouTube links from a separate markdown file to create a YouTube note one by one.
💡 Feature Highlights
tp.file.find_tfilecommand in the destination folder.☝️ Future Works
It's possible to extend this functionality to create multiple YouTube notes for videos inside a YouTube playlist, given the playlist link. It'll be a future side-project I would be working on.
The Template 📄
Prerequisites:
sources/youtubeworks for me and you can change it in the template later).Queue for YouTube Link.md)yt queue.md:Feel free to make changes to suit your template, but note that you need to define the properties in JavaScript outside of the string template, you can't include the Templater starting and ending tags (I don't know what they're called, but you get the idea).
🧑💻 How to use
yt queue.mdinto your Templater folderQueue for YouTube Link.mdand insert a few YouTube links (I've got some links prepped in the code block below for you to test it with)yt queueand press enter.Here's a few YouTube links that should help you test it out:
💭 After thought
I previously experimented by using the
tp.file.include()so I can dynamically include the different templates I want to use, for example my template for YouTube shorts and long form YouTube videos aren't the same, but I wasn't successful in implementing it, as passing the URL to the template was difficult, perhaps atp.userfunction as a work around - but I didn't want to stretch it that far.✌ Best of luck!
I hope this template helps out other people as it did for me. Thanks and best of luck in your endeavors!
Edit:
All reactions