9

Recently, Youtube added the ability to break up their videos in the progress bar into sections called "chapters".

https://support.google.com/youtube/answer/9884579?hl=en

Currently I am able to get info about a video from the Youtube API. However, it doesn't seem like there's any info about a video's chapters, and I haven't found anything in the API documentation about chapters. Am I missing something, or is there simply no way to get chapter data yet?

5 Answers5

7

As far as I know, such data is in plain text in the description of the video.

So, you can use the following example:

Video used in this demonstration: Top 10 Monsters with 2500 Attack in YuGiOh

URL Request:

https://www.googleapis.com/youtube/v3/videos?part=snippet&id=NNgYId7b4j0&key=[YOUR_API_KEY]

Response:

{
    "kind": "youtube#videoListResponse",
    "etag": "YpVLmrSx1iP8hAJOnumaTBoKqqQ",
    "items": [
        {
            "kind": "youtube#video",
            "etag": "oIoJq5F3RHvBbtVohafaJ_1SThU",
            "id": "NNgYId7b4j0",
            "snippet": {
                "publishedAt": "2020-09-14T18:37:46Z",
                "channelId": "UC0roOaAn95Rtgoe078RkVXQ",
                "title": "Top 10 Monsters with 2500 Attack in YuGiOh",
                "description": "In this video we'll go over the best monsters that have 2500 attack, and attack threshold for a lot of boss monsters actually.\n\nCheck out my DnD channel @TheD&DLogs \n\n--The List--\nIntro: (0:00)\n10- Blue-Eyes Spirit Dragon: (0:00)\n9- Invoked Mechaba: (2:14)\n8- Number S39: Utopia the Lightning: (3:23)\n7- Earthbound Immortal Aslla Piscu: (4:35)\n6- Eldlich the golden Lord: (6:04)\n5- True King Lithosagym the Disaster: (7:34)\n4- Block Dragon: (8:54)\n3- Astrograph sorcerer: (10:25)\n2- Beatrice lady of the eternal: (12:36)\n1- Firewall Dragon: (14:37)\n- \n-----------------------------------------\n#yugioh #top10 \n\nDuels are all done on EDOpro, its completely free and updated all the time. If you want it, just look for the EDOpro discord and you'll find all you need to download it from there\n\nSome of the Video backgrounds in this video were made by \"Amitai Angor AA VFX\" https://www.youtube.com/dvdangor2011\n\n\nhttps://twitter.com/hirumared\nhttps://twitter.com/TheDuelLogs",
                "thumbnails": {
                    "default": {
                        "url": "https://i.ytimg.com/vi/NNgYId7b4j0/default.jpg",
                        "width": 120,
                        "height": 90
                    },
                    "medium": {
                        "url": "https://i.ytimg.com/vi/NNgYId7b4j0/mqdefault.jpg",
                        "width": 320,
                        "height": 180
                    },
                    "high": {
                        "url": "https://i.ytimg.com/vi/NNgYId7b4j0/hqdefault.jpg",
                        "width": 480,
                        "height": 360
                    },
                    "standard": {
                        "url": "https://i.ytimg.com/vi/NNgYId7b4j0/sddefault.jpg",
                        "width": 640,
                        "height": 480
                    },
                    "maxres": {
                        "url": "https://i.ytimg.com/vi/NNgYId7b4j0/maxresdefault.jpg",
                        "width": 1280,
                        "height": 720
                    }
                },
                "channelTitle": "TheDuelLogs",
                "tags": [
                    "yugioh",
                    "ygo",
                    "dev",
                    "pro",
                    "link",
                    "duels",
                    "auto-matic duels",
                    "online",
                    "current",
                    "ban",
                    "list",
                    "dueling",
                    "network",
                    "theduellogs",
                    "the",
                    "duel",
                    "logs",
                    "loggs",
                    "Yu",
                    "Gi",
                    "Oh!",
                    "YGOpro",
                    "gimmick",
                    "links",
                    "top ten",
                    "2020",
                    "edopro"
                ],
                "categoryId": "20",
                "liveBroadcastContent": "none",
                "localized": {
                    "title": "Top 10 Monsters with 2500 Attack in YuGiOh",
                    "description": "In this video we'll go over the best monsters that have 2500 attack, and attack threshold for a lot of boss monsters actually.\n\nCheck out my DnD channel @TheD&DLogs \n\n--The List--\nIntro: (0:00)\n10- Blue-Eyes Spirit Dragon: (0:00)\n9- Invoked Mechaba: (2:14)\n8- Number S39: Utopia the Lightning: (3:23)\n7- Earthbound Immortal Aslla Piscu: (4:35)\n6- Eldlich the golden Lord: (6:04)\n5- True King Lithosagym the Disaster: (7:34)\n4- Block Dragon: (8:54)\n3- Astrograph sorcerer: (10:25)\n2- Beatrice lady of the eternal: (12:36)\n1- Firewall Dragon: (14:37)\n- \n-----------------------------------------\n#yugioh #top10 \n\nDuels are all done on EDOpro, its completely free and updated all the time. If you want it, just look for the EDOpro discord and you'll find all you need to download it from there\n\nSome of the Video backgrounds in this video were made by \"Amitai Angor AA VFX\" https://www.youtube.com/dvdangor2011\n\n\nhttps://twitter.com/hirumared\nhttps://twitter.com/TheDuelLogs"
                },
                "defaultAudioLanguage": "en"
            }
        }
    ],
    "pageInfo": {
        "totalResults": 1,
        "resultsPerPage": 1
    }
}

Get the response:

response.items[0].snippet.description

Results:

"In this video we'll go over the best monsters that have 2500 attack, and attack threshold for a lot of boss monsters actually.

Check out my DnD channel @TheD&DLogs 

--The List--
Intro: (0:00)
10- Blue-Eyes Spirit Dragon: (0:00)
9- Invoked Mechaba: (2:14)
8- Number S39: Utopia the Lightning: (3:23)
7- Earthbound Immortal Aslla Piscu: (4:35)
6- Eldlich the golden Lord: (6:04)
5- True King Lithosagym the Disaster: (7:34)
4- Block Dragon: (8:54)
3- Astrograph sorcerer: (10:25)
2- Beatrice lady of the eternal: (12:36)
1- Firewall Dragon: (14:37)
- 
-----------------------------------------
#yugioh #top10 

Duels are all done on EDOpro, its completely free and updated all the time. If you want it, just look for the EDOpro discord and you'll find all you need to download it from there

Some of the Video backgrounds in this video were made by "Amitai Angor AA VFX" https://www.youtube.com/dvdangor2011


https://twitter.com/hirumared
https://twitter.com/TheDuelLogs"
Benjamin Loison
  • 3,782
  • 4
  • 16
  • 33
Mauricio Arias Olave
  • 2,259
  • 4
  • 25
  • 70
  • Note that as the YouTube UI shows, there might be a *cleanest* way to proceed by reverse-engineering, instead of applying a parser to the description, hoping that this parser is good enough for all YouTube video descriptions. – Benjamin Loison Sep 11 '22 at 17:18
  • @BenjaminLoison They are talking about using the official API, not scraping. It would also be much easier to write a text-to-chapter parser than any attempt at reverse engineering the youtube player. That's probably what you'd find at the heart if you did reverse it anyway. – Conor Reid Sep 29 '22 at 22:34
  • @ConorReid I know they are talking about the official API. As they mentioned the official API doesn't provide this feature so we can try to make a perfect text-to-chapter parser or just reverse-engineer the YouTube UI webpage of the video to get the chapters (title and timestamp) directly. I added [an answer](https://stackoverflow.com/a/73902612/7123660) showing how to proceed. I hope it shows you how easy it was to reverse-engineer as I mentioned. By the way I think that YouTube text-to-chapter parser is executed on servers and not on clients so there is no way to get the official parser code – Benjamin Loison Sep 29 '22 at 23:37
  • How generous, I have now also attached an answer showing how I am parsing them from text-to-chapter, The perfect solution I wanted just doesn't exist but mine seems to do better than the other solutions I've tested from github/npm – Conor Reid Sep 30 '22 at 00:42
7

One more time YouTube Data API v3 doesn't provide a basic feature.

I would suggest you to use my open-source YouTube operational API, indeed by requesting https://yt.lemnoslife.com/videos?part=chapters&id=VIDEO_ID you would get a JSON with the video chapters (titles and timestamps) you are looking for in item['chapters']['chapters'].

Example of result with YouTube video id NNgYId7b4j0:

{
    "kind": "youtube#videoListResponse",
    "etag": "NotImplemented",
    "items": [
        {
            "kind": "youtube#video",
            "etag": "NotImplemented",
            "id": "NNgYId7b4j0",
            "chapters": {
                "areAutoGenerated": false,
                "chapters": [
                    {
                        "title": "10- Blue-Eyes Spirit Dragon",
                        "time": 0,
                        "thumbnails": [
                            {
                                "url": "https:\/\/i.ytimg.com\/vi\/NNgYId7b4j0\/hqdefault_4000.jpg?sqp=-oaymwEiCKgBEF5IWvKriqkDFQgBFQAAAAAYASUAAMhCPQCAokN4AQ==&rs=AOn4CLCoTrvu0Yu-iNxb7o4II-pxi5WVbQ",
                                "width": 168,
                                "height": 94
                            },
                            {
                                "url": "https:\/\/i.ytimg.com\/vi\/NNgYId7b4j0\/hqdefault_4000.jpg?sqp=-oaymwEjCNACELwBSFryq4qpAxUIARUAAAAAGAElAADIQj0AgKJDeAE=&rs=AOn4CLCuupNwIgFIf9hXbjMsvpSGThFyhg",
                                "width": 336,
                                "height": 188
                            }
                        ]
                    },
                    {
                        "title": "9- Invoked Mechaba",
                        "time": 134,
                        "thumbnails": [
                            {
                                "url": "https:\/\/i.ytimg.com\/vi\/NNgYId7b4j0\/hqdefault_135933.jpg?sqp=-oaymwEiCKgBEF5IWvKriqkDFQgBFQAAAAAYASUAAMhCPQCAokN4AQ==&rs=AOn4CLBe94BKNpQXvM2dUl75LtcgX0N03w",
                                "width": 168,
                                "height": 94
                            },
                            {
                                "url": "https:\/\/i.ytimg.com\/vi\/NNgYId7b4j0\/hqdefault_135933.jpg?sqp=-oaymwEjCNACELwBSFryq4qpAxUIARUAAAAAGAElAADIQj0AgKJDeAE=&rs=AOn4CLBULUhlI1OOjJiW6mpFDUhPzh4Adw",
                                "width": 336,
                                "height": 188
                            }
                        ]
                    },
                    ...
                ]
            }
        }
    ]
}
Benjamin Loison
  • 3,782
  • 4
  • 16
  • 33
2

I am replying with this answer to help people such as myself who ended up on this video wanting to find a youtube chapter parser / extractor for text rather than where to find the chapter data. Just to add some further information, currently, there is no way to get the chapters from the official YouTube API, so the only way to get the chapters from a text-description response (like the YouTube API provides) is to parse it in some way:

My answer is in Javascript but it can easily be converted: The idea is to extract the MIN:SEC and HR:MIN:SEC timestamps then to generate the title we remove the word that includes them (So this would typically remove however people aesthetically wrap them too [00:00] or (00:00)

It's far from perfect, but in my experience it's better than the other solutions I've seen on github/npm at the time of writing this. You might want to also trim away starting and ending spaces and punctuational separators such as (-, :, ~, |) too

const parseChapters = (description) => {
  // Extract timestamps (either 00:00:00, 0:00:00, 00:00 or 0:00)
  const lines = description.split("\n")
  const regex = /(\d{0,2}:?\d{1,2}:\d{2})/g
  const chapters = []

  for (const line of lines) {
    // Match the regex and check if the line contains a matched regex
    const matches = line.match(regex)
    if (matches) {
      const ts = matches[0]
      const title = line
        .split(" ")
        .filter((l) => !l.includes(ts))
        .join(" ")

      chapters.push({
        timestamp: ts,
        title: title,
      })
    }
  }

  return chapters
}
Conor Reid
  • 578
  • 3
  • 16
2

Worth noting is that videos might have timestamps contained in a description as well as chapters, it might contain timestamps in the description but NOT have chapters, and it might have chapters but NOT timestamps in the description. One example of the last is The Dark Truth About Why Yoshi Sticks Out His Tongue. This means that looking at the description won't solve all cases.

For anyone else looking to solve the problem of extracting timestamps from a video description (or comment section for that matter, since sometimes they exist there and not in the description), and can live with the "issue" I illustrated in the paragraph above, here's a regex that I've refined over a long time building a project around this domain.

/.*?((?:([0-5]?[0-9]):)?([0-5]?[0-9]):([0-5][0-9])).*/g

It captures:

  1. The entire line of text, so that you can access the title (though you will have to clean it by removing the timestamp itself)
  2. Optionally, if there's an hour in the timestamp, that's a capture group
  3. Minutes are captured as a separate capture group
  4. Seconds are captured as a separate capture group
  5. Lastly, the entire timestamp is captured in a separate capture group

In addition, it doesn't matter where on the line the timestamp is.

An example of this regex can be viewed at https://regex101.com/r/UZwtox/1

UPDATE

I used parsing of the DOM in order to solve the problem of picking up Chapters from videos:

function parseChapters() {
  const allElements = Array.from(
    document.querySelectorAll(
      "#panels ytd-engagement-panel-section-list-renderer:nth-child(2) #content ytd-macro-markers-list-renderer #contents ytd-macro-markers-list-item-renderer #endpoint #details"
    )
  );

  const withTitleAndTime = allElements.map((node) => ({
    title: node.querySelector(".macro-markers")?.textContent,
    timestamp: node.querySelector("#time")?.textContent,
  }));

  const filtered = withTitleAndTime.filter(
    (element) =>
      element.title !== undefined &&
      element.title !== null &&
      element.timestamp !== undefined &&
      element.timestamp !== null
  );

  const withoutDuplicates = [
    ...new Map(filtered.map((node) => [node.timestamp, node])).values(),
  ];

  return withoutDuplicates;
}

This will return something like

// For videos that have chapters
[{title: "Overture", time: "0:00"}, {title: "Second highlight", time: "2:10"} ...]

// For videos that don't have chapters
[]

If you're interested in using this approach, make sure you're waiting for these selectors to appear, since this data is loaded asynchronously on the page.

0

Very late answer but it solved my problem.

You could use the code below. It's written in C# but it can easily be transcribed into another language. Since you can already get youtube video data, I assume you also have the description of the video.

        private static IEnumerable<string> GetChaptersFromDescription(string text)
        {
            var lines = text.Split("\n");
            var regex = new Regex(@"[0-9]:[0-9][0-9]");

            foreach (var line in lines)
            {
                if (regex.IsMatch(line))
                {
                    yield return line;
                }
            }
        }
Benjamin Loison
  • 3,782
  • 4
  • 16
  • 33
chandler
  • 71
  • 3
  • 9