-
-
Notifications
You must be signed in to change notification settings - Fork 161
Description
Describe the bug
I think #533 is not completely fixed.
One other comment before I get into this, I don't think this was happening until the latest release of quickadd a few weeks ago
I'm really sorry this is so long, but I think i need to provide enough details to either prove I'm correct or so you tell me I'm wrong.
I have a template which is used to add youtube videos to my vault. It is run by quickadd and passed the url of the video (via the clipboard), it collects the information from the video via templater user function (which calls the youtube api call), and then builds the note.
I believe the template is being called twice by quickadd.
The sequence is
click commander button in ribbon --> Quickadd -> Template -> tp.user.youtubeMetadata.js
and then it all backs back out.
Here's some more details:
- Here's the quickadd setup:
- The beginning of the template looks like:
const dir = 'SecondBrain/';
// 1. Generate a single runId at the very start
const runId = Date.now();
const log = (msg) => console.log(`[${runId}] ${msg}`);
log(`Template execution STARTED: ${runId}`);
log(`Filename path: ${tp.file.path()}`);
// 1. Grab raw clipboard
let url = await tp.system.clipboard();
if (!url) {
new Notice('Clipboard empty—nothing to process.', 4000);
return;
}
console.log(`[${runId}] URL → ${url}`);
log(`Fetching metadata…`);
const metadata = await tp.user.youtubeMetadata(url, tp);
log(`Metadata fetch complete.`);
// the rest is just building the page contents and moving it to the correct directory
The templater user script looks like:
/**
* Call with:
* const obj = await youtubeMetadata(url, tp);
*
* Returns an object with video metadata, or empty strings if not found.
*/
async function youtubeMetadata(url, tp) {
const runId = Date.now();
const log = (msg) => console.log(`[${runId}]: ${msg}`);
log(`youtubeMetadata Started-------------------------`)
// Normalize http → https
if (url.startsWith("http://")) {
url = url.replace("http://", "https://");
}
log(`YMD-1 - ${url}`)
// Regex to extract exactly 11-char YouTube IDs from:
// • https://youtu.be/92UhZbJJivU?si=...
// • https://www.youtube.com/shorts/5M2Nx9YnNvQ
// • https://www.youtube.com/watch?v=0bGuse8mcLw&t=15s
// • https://www.youtube.com/embed/abcdefghijkl
// Anything after the 11-char ID (e.g. &t=..., ?feature=share) is ignored.
const videoIdRegex = /(?:youtu\.be\/|\/shorts\/|v=|embed\/)([A-Za-z0-9_-]{11})/;
const match = url.match(videoIdRegex);
const videoId = match?.[1] ?? "";
log(`YMD-2 - Extracted videoId="${videoId}" from url="${url}"`);
let filename = "";
let title = "";
let authors = [];
let thumbUrl = "";
let sdThumbUrl = "";
if (videoId) {
// Use YouTube oEmbed endpoint for JSON metadata
const oembedUrl = `https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=${videoId}&format=json`;
try {
log(`YMD-3 - Fetching metadata for ${videoId}`);
const response = await fetch(oembedUrl);
log(`YMD-4 - After fetching metadata/before getting json response`);
if (response.ok) {
const data = await response.json();
log(`YMD-5 - After getting json response`);
filename = data.title || "";
title = tp.user.goodFilename(data.title || "");
authors = Array.isArray(data.author_name)
? data.author_name
: [data.author_name].filter(Boolean);
thumbUrl = data.thumbnail_url || "";
sdThumbUrl = `https://i.ytimg.com/vi/${videoId}/sddefault.jpg`;
} else {
console.warn(`${runId}: oEmbed fetch failed with ${response.status}`);
}
} catch (err) {
console.error(`${runId}]: Error fetching oEmbed for ${url}:`, err);
}
} else if (url.startsWith("https://")) {
// URL but no recognizable video ID → leave url intact
} else if (url.length < 125) {
// Treat as a plain title/filename, not a URL
filename = url;
title = tp.user.goodFilename(url);
url = "";
} else {
// Something bogus → clear out
url = "";
}
log(`YMD-6 - youtubeMetadata ended at ${Date.now()} (duration ${Date.now() - runId}ms)`);
return {
title,
authors,
channel: "",
published: "",
url,
thumbnail: thumbUrl,
sdThumbnail: sdThumbUrl,
keywords: "",
quotes: "",
keywordsList: "",
wikiLinks: "",
duration: "",
durSecs: "",
description: "",
fullDescription: "",
id: videoId
};
}
module.exports = youtubeMetadata;
When I run this, I get the following logs. The numbers in the square brackets are millisconds since epic. They are not the time when the log occurred, but rather the time when the template/function was invoked (some might call it a runId). So, it's easy to see which logs occurred as part of which call. I have bolded the parts where I believe we are in the first invocation of the template. The portions not bolded are the second invocation.
VM1633: [1751147227392] Template execution STARTED: 1751147227392
VM1633:20 [1751147227392] Filename path: D:\obsidian\obsidian/SecondBrain/Videos/Untitled2.md
VM1633:32 [1751147227392] URL → https://www.youtube.com/watch?v=g8JM3prvEf4&pp=0gcJCc4JAYcqIYzv
VM1633:20 [1751147227392] Fetching metadata…
VM1630:10 [1751147227393]: youtubeMetadata Started-------------------------
VM1630:10 [1751147227393]: YMD-1 - https://www.youtube.com/watch?v=g8JM3prvEf4&pp=0gcJCc4JAYcqIYzv
VM1630:10 [1751147227393]: YMD-2 - Extracted videoId="g8JM3prvEf4" from url="https://www.youtube.com/watch?v=g8JM3prvEf4&pp=0gcJCc4JAYcqIYzv"
VM1630:10 [1751147227393]: YMD-3 - Fetching metadata for g8JM3prvEf4
VM1637:20 [1751147227401] Template execution STARTED: 1751147227401
VM1637:20 [1751147227401] Filename path: D:\obsidian\obsidian/SecondBrain/Videos/Untitled2.md
VM1637:32 [1751147227401] URL → https://www.youtube.com/watch?v=g8JM3prvEf4&pp=0gcJCc4JAYcqIYzv
VM1637:20 [1751147227401] Fetching metadata…
VM1635:10 [1751147227402]: youtubeMetadata Started-------------------------
VM1635:10 [1751147227402]: YMD-1 - https://www.youtube.com/watch?v=g8JM3prvEf4&pp=0gcJCc4JAYcqIYzv
VM1635:10 [1751147227402]: YMD-2 - Extracted videoId="g8JM3prvEf4" from url="https://www.youtube.com/watch?v=g8JM3prvEf4&pp=0gcJCc4JAYcqIYzv"
VM1635:10 [1751147227402]: YMD-3 - Fetching metadata for g8JM3prvEf4
VM1630:10 [1751147227393]: YMD-4 - After fetching metadata/before getting json response
VM1635:10 [1751147227402]: YMD-4 - After fetching metadata/before getting json response
VM1630:10 [1751147227393]: YMD-5 - After getting json response
VM1630:10 [1751147227393]: YMD-6 - youtubeMetadata ended at 1751147227651 (duration 258ms)
VM1633:20 [1751147227392] Metadata fetch complete.
VM1633:20 [1751147227392] Fetched & applied metadata: Perplexity's new AI agents are INSANE (g8JM3prvEf4)
VM1633:20 [1751147227392] Sanitized filename: Perplexity's new AI agents are INSANE
VM1633:20 [1751147227392] Target path: SecondBrain/Videos/Perplexity's new AI agents are INSANE.md
VM1635:10 [1751147227402]: YMD-5 - After getting json response
VM1635:10 [1751147227402]: YMD-6 - youtubeMetadata ended at 1751147227652 (duration 250ms)
VM1637:20 [1751147227401] Metadata fetch complete.
VM1637:20 [1751147227401] Fetched & applied metadata: Perplexity's new AI agents are INSANE (g8JM3prvEf4)
VM1637:20 [1751147227401] Sanitized filename: Perplexity's new AI agents are INSANE
VM1637:20 [1751147227401] Target path: SecondBrain/Videos/Perplexity's new AI agents are INSANE.md
VM1633:20 [1751147227392] Moving note to final path SecondBrain/Videos/Perplexity's new AI agents are INSANE.md…
VM1637:20 [1751147227401] Moving note to final path SecondBrain/Videos/Perplexity's new AI agents are INSANE.md…
VM1637:20 [1751147227401] File move complete
VM1637:20 [1751147227401] Template execution COMPLETED
VM1633:20 [1751147227392] File move complete
VM1633:20 [1751147227392] Template execution COMPLETED
Again, the number in the square brackets is the milliseconds for when the template or the user function started. You'll notice that there are 4 of them. There should only be two.
Other things of note
- the file that was created by quickadd path is displayed in the logs. In both cases it is "untitled2". This doesn't makes sense if there were really two activations of quickadd as it should have created "untitled3" for the second call
- The logs show that the two invocations are running simultaneously.
- I can see that whenever a call is made to a routine requiring an 'await', the code switches between template invocations
- Sometimes when i run it, one invocation will realize that the new file already exists (and abort) and sometimes it doesn't. Feels like a timing thing, but not the fundamental problem.
To Reproduce
Steps to reproduce the behavior:
- Click on the commander button when there is a youtube video url in the clipboard.
- watch the logs in the developer console.
Expected behavior
The template and user function should run only once.
Screenshots
If applicable, add screenshots to help explain your problem.
Desktop (please complete the following information):
- OS: [e.g. iOS] Windows 11 (I always install updates)
- Browser [e.g. chrome, safari] (this is obsidian1.9.4; I use chrome, but I don't see how that's relevant,
- Version [e.g. 22] Quickadd 1.17.0
Smartphone (please complete the following information):
Not relevant
Additional context
Add any other context about the problem here.