0

How can I store the video title as a global variable?

ytdl.getBasicInfo(videoURL, function(err, info) {
  console.log(info.title)
});

I've looked through other questions/answers here, but I seem to always print the title successfully to console, but no matter how I define a variable, it is undefined.

Thanks so much for your help!

EDIT: This is current method I'm trying, as an example found from another user here:

var vidtitle;
function getTitleVideo (videoUrl){
   return new Promise ((resolve, reject) => {
      ytdl.getBasicInfo (videoUrl, (err, info) => {
            resolve (info.title)
      })
   })
}
vidtitle = getTitleVideo(`https://www.youtube.com/watch?v=${youtube_video_id}`);
  • `but no matter how I define a variable, it is undefined.` please include your attempts, and explain why each of them fails to satisfy your requirements. – Olian04 Apr 24 '20 at 18:23
  • I've edited to include my current attempt. – victorprofundus Apr 24 '20 at 18:28
  • In your example `getTitleVideo` returns a promise. If you haven't worked with promises before i would recommend reading up on them before moving forward: https://javascript.info/async – Olian04 Apr 24 '20 at 18:30

1 Answers1

1

getBasicInfo can be used with a callback or a promise.

Using a callback:

ytdl.getBasicInfo(videoURL, (err, info) => {
  // log any error
  if (err) return console.error(err);
  const {title} = info;
  /*
   * you must put all your code that uses the title here
   * if you try to make a global variable it may be undefined when you
   * run the rest of the synchronous code
   */
});

The const {title} = info; is a shorthand for const title = info.title;. You can read more about destructuring here.

Using a promise with then:

ytdl.getBasicInfo(videoURL)
  .then(({title}) => {
    // same as above you can only use the title here
  })
  // log any error
  .catch(console.error);

({title}) => {...} is also destructuring.

Using a promise with await (can only be used in an async function):

(async () => {
  try {
    const {title} = await ytdl.getBasicInfo(videoURL);
    // use title here
  } catch (err) {
    console.error(err);
  }
})();

Explanation

getBasicInfo is an example of an asynchronous function. That is, it takes time for it to execute (it needs to fetch the video info online).

Before ES2015 (ES6), people used callbacks to work with async functions. (Some people also used promise libraries like bluebird, but I won’t go into that here.) The callback function would execute once the async function has completed or has an error.

For example, Node.js’ require('http').get still uses callbacks:

const {get} = require('http');
get('http://example.com', function (res) {
  console.log(`The status code was ${res.statusCode}.`;
}).on('error', console.error);

In this example, the callback does not take an error and instead get returns a ClientRequest, which has an error event.

Another example using the deprecated request library (take from the readme):

const request = require('request');
request('http://www.google.com', function (error, response, body) {
  console.error('error:', error); // Print the error if one occurred
  console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
  console.log('body:', body); // Print the HTML for the Google homepage.
});

In ES2015, promises were added (as well as arrow functions). For example, you could create functions that return a promise like this:

// resolves after 500 ms
const doSomething = () => new Promise(resolve => setTimeout(resolve, 500));

// resolves with 'Hello, world!' after 500 ms
const getString = () =>
  new Promise(resolve => setTimeout(resolve, 500, 'Hello, world!'));

// rejects with the error 'Error!' after 500 ms
const rejectingPromise = () =>
  new Promise((resolve, reject) => setTimeout(reject, 500, new Error('Error!')))

// has a 50% chance to resolve and a 50% chance to reject
const mayReject = () => Math.random() > 0.5
  ? Promise.resolve('it worked!')
  : Promise.reject(new Error("it didn't work"));

// using with then and catch
doSomething()
  .then(() => {
    console.log('done');
    return getString();
  })
  .then(str => {
    console.log(str);
    return mayReject();
  })
  .then(str => {
    console.log(str)
    return rejectingPromise()
  })
  .catch(console.error);

You don’t have to reject with an Error but it’s good practice to do so.

In ES2016 (ES7), await and async functions were added. await is another way to "unwrap" a promise (pauses execution until the promise is resolved). await is only available in a function that has been marked as async.

// same stuff as before
const doSomething = () => new Promise(resolve => setTimeout(resolve, 500));
const getString = () => new Promise(resolve => setTimeout(resolve, 500, 'Hello, world!'));
const rejectingPromise = () => new Promise((resolve, reject) => setTimeout(reject, 500, new Error('Error!')));
const mayReject = () => Math.random() > 0.5 ? Promise.resolve('it worked!') : Promise.reject(new Error("it didn't work"));

// an async function
async function f() {}

// an async arrow function
const g = async () => {};

// an immediately invoked arrow function expression
// this does the same thing as the previous example with then/catch
(async () => {
  try {
    await doSomething();
    console.log('done');
    const str = await getString();
    console.log(str);
    // you don't have to assign it to a variable:
    console.log(await mayReject());
    await rejectingPromise();
  } catch (err) {
    console.error(err);
  }
})();

I recommend reading MDN’s article on asynchronous JS.

Lauren Yim
  • 12,700
  • 2
  • 32
  • 59
  • Thank you so much for this. It's exactly what I needed. I'm still fairly new to JS and promises confused me. I so appreciate your taking the time to give this thorough explanation. – victorprofundus Apr 26 '20 at 06:21