Async Frontmatter Update

What I’m trying to do

I’m using the media db plugin to import movies, series and books to my vault. But since media db does not fill the streamingServices field for movies and series I decided to do it myself.

I coded a basic script using a template but I can’t get it to work, unfortunately…

<%*
tp.hooks.on_all_templates_executed(async () => {
  const propertyName = "streamingServices";
  const API_KEY = "xxx";
  const file = tp.file.find_tfile(tp.file.path(true));
  // Update front matter using Obsidian API

  await app.fileManager.processFrontMatter(file, async (frontmatter) => {
    const imdb_id = frontmatter.id;
    if (imdb_id) {
      //const providers = ["a","b","c"]; This works
      const providers = await getProviders(imdb_id); //but this does not...
      frontmatter[propertyName] = providers;  //this also returns as expected an array ['Netflix', 'Disney Plus', 'TV+']
      console.log("Streaming services:", providers); // works fine same as above
      console.log("Streaming services:", frontmatter[propertyName]);
    } else {
      console.log("No IMDB ID found in the front matter");
    }
  });
  async function getProviders(imdb_id) {
    console.log("Getting providers");
    console.log(imdb_id);
    try {
      // Get movie ID from IMDB ID
      const idResponse = await fetch(
        `https://api.themoviedb.org/3/movie/${imdb_id}/external_ids?api_key=${API_KEY}`
      );
      if (!idResponse.ok) {
        throw new Error("Network response was not OK");
      }
      const idInfo = await idResponse.json();
      const movie_id = idInfo.id;
      // Get providers for the movie
      const providersResponse = await fetch(
        `https://api.themoviedb.org/3/movie/${movie_id}/watch/providers?api_key=${API_KEY}`
      );
      if (!providersResponse.ok) {
        throw new Error("Network response was not OK");
      }
      const movies = await providersResponse.json();
      const serviceArray = movies.results.TR?.flatrate;
      if (serviceArray === undefined) {
        console.log("No streaming services found");
        return [];
      }
      const return_array = serviceArray.map((element) => element.provider_name);
      return return_array;
    } catch (error) {
      console.error(
        "There has been a problem with your fetch operation:",
        error
      );
    }
  }
});
-%>

Things I have tried

I have tried to use app.vault.read() approach which I’ve seen here. But still no chance. I have also searched the web for like 10 hours but either I got too much tunnel visioned or it is not possible to do so.

TLDR; I want to add custom properties to #movie files after I create them with templater(media db but it uses templater)
But the property is dependent of an API call.

I would try making the call to processFrontMatter without those async calls. In other words, prepare what you want to write before you call that function. This would be a safer approach instead of nesting the async calls like you’re currently doing.

1 Like

Thanks for your response.

I tried this:

<%*
const propertyName = "streamingServices";
const file = tp.file.find_tfile(tp.file.path(true));
const services = tp.user.my_script("tt0137523");
console.log(services);
await app.fileManager.processFrontMatter(file, (frontmatter) => {
      frontmatter[propertyName] = services; 
      console.log(frontmatter[propertyName]);
      console.log(services);
  });
-%>

I put my logic into my_script.js file and got the data just fine. services returns a Promise which has [[PromiseResult]]: Array(3) which has the right info. Also other console.logs return the same Promise but none of them changes the property, unfortunately.

Edit: typo.

I finally solved it. It is not elegant but gets the job done.
For anyone out there faces the same problem here is my solution:

const propertyName = "streamingServices";
const API_KEY = "xxx";
const file = await tp.file.find_tfile(tp.file.path(true));

async function fetchFrontmatter() { 
//Getting the id from the file
  const activeFile = app.workspace.getActiveFile();
  if (!activeFile) {
    new Notice("No active file.");
    return;
  }
  const fileContent = await app.vault.read(activeFile);
  const frontmatterRegex = /^---\n([\s\S]*?)\n---/;
  const match = frontmatterRegex.exec(fileContent);
  if (!match) {
    new Notice("No frontmatter found in the active file.");
    return;
  }
  const frontmatter = match[1];
  const frontmatterLines = frontmatter.split("\n");
  const frontmatterData = {};
  frontmatterLines.forEach((line) => {
    const [key, value] = line.split(":").map((part) => part.trim());
    frontmatterData[key] = value;
  });
  return frontmatterData;
}
const frontmatterData = await fetchFrontmatter();
if (!frontmatterData) {
  return;
}
const imdb_id = frontmatterData["id"];
const providers = async () => {
  console.log("Getting providers");
  try {
    // Get providers for the movie
    const providersResponse = await fetch(
      `https://api.themoviedb.org/3/movie/${imdb_id}/watch/providers?api_key=${API_KEY}`
    );
    if (!providersResponse.ok) {
      throw new Error("Network response was not OK");
    }
    const movies = await providersResponse.json();
    const serviceArray = movies.results.TR?.flatrate;
    if (serviceArray === undefined) {
      console.log("No streaming services found");
      return [];
    }
    const return_array = serviceArray.map((element) => element.provider_name);
    return return_array;
  } catch (error) {
    console.error("There has been a problem with your fetch operation:", error);
  }
};
const result = await providers();
tp.hooks.on_all_templates_executed(async () => {
  await app.fileManager.processFrontMatter(file, (frontmatter) => {
    frontmatter["streamingServices"] = result;
    console.log(frontmatter["streamingServices"]);
  });
});

1 Like

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.