Skip to content

Instantly share code, notes, and snippets.

@tinyapps
Forked from pukkandan/ytdlp_nest_comments.py
Last active October 15, 2025 19:09
Show Gist options
  • Save tinyapps/df2b6757a142ff93caf9c63d0ef38b11 to your computer and use it in GitHub Desktop.
Save tinyapps/df2b6757a142ff93caf9c63d0ef38b11 to your computer and use it in GitHub Desktop.
Convert YouTube comments from an info.json file (acquired via yt-dlp --write-comments) to HTML.
#!/usr/bin/env python3
"""
SPDX-License-Identifier: MIT https://opensource.org/licenses/MIT
Copyright © 2021 [email protected]
* Input file is an info.json (with comments) that yt-dlp (https://github.com/yt-dlp/yt-dlp) wrote
* Change FIELDS according to your needs
The output file will be in the format:
[{
'text': 'comment 1',
...
'replies': [{
'text': 'reply 1',
...
'replies': [...],
}, ...],
}, ...]
"""
import json
import argparse
from datetime import datetime
def get_fields(dct):
for name, fn in FIELDS.items():
val = fn(dct, name)
if val is not None:
yield name, val
def filter_func(comments):
return [dict(get_fields(c)) for c in comments]
FIELDS = {
'text': dict.get,
'author': dict.get,
'timestamp': lambda dct, name: dct.get(name) and datetime.strftime(
datetime.utcfromtimestamp(dct.get(name)), '%Y/%m/%d'),
'replies': lambda dct, name: filter_func(dct.get(name, [])) or None
}
parser = argparse.ArgumentParser()
parser.add_argument(
'--input-file', '-i',
dest='inputfile', metavar='FILE', required=True,
help='File to read info_dict from')
parser.add_argument(
'--output-file', '-o',
dest='outputfile', metavar='FILE', required=True,
help='File to write comments to')
args = parser.parse_args()
print('Reading file')
with open(args.inputfile, encoding='utf-8') as f:
info_dict = json.load(f)
comment_data = {c['id']: c for c in sorted(
info_dict['comments'], key=lambda c: c.get('timestamp') or 0)}
count = len(info_dict['comments'])
del info_dict
nested_comments = []
for i, (cid, c) in enumerate(comment_data.items(), 1):
print(f'Processing comment {i}/{count}', end='\r')
parent = nested_comments if c['parent'] == 'root' else comment_data[c['parent']].setdefault('replies', [])
parent.append(c)
print('\nWriting file')
with open(args.outputfile, 'w', encoding='utf-8') as f:
json.dump(filter_func(nested_comments), f, indent=4, ensure_ascii=False)
print('Done')
@m3jorri
Copy link

m3jorri commented Jul 14, 2024

Seems to work perfectly!

@tinyapps
Copy link
Author

Thanks for testing it @m3jorri, as well as for your kind feedback in @pukkandan's original gist.

@m3jorri
Copy link

m3jorri commented Jul 14, 2024

Thanks for your efforts and quick responses! If I may request a feature, would it be possible to add a dark mode toggle switch to the html output file?

@tinyapps
Copy link
Author

My pleasure, @m3jorri. While it's not a toggle switch, adding these few lines just above the closing style tag will display the HTML in dark mode-friendly format if the user environment is set to dark mode:

            @media (prefers-color-scheme: dark) {
                body {
                    background-color: #121212;
                    color: #e0e0e0;
                }
                .comment-box {
                    border-color: #444;
                }
            }

I've updated the gist as well. Thanks again for testing and offering feedback.

@m3jorri
Copy link

m3jorri commented Jul 14, 2024

That works, thanks

@hetszunyukapanyanyimonyok
Copy link

hetszunyukapanyanyimonyok commented Nov 28, 2024

Hello, @tinyapps
Thank you for your work, on this script!
(and to pukkandan too!)

Please if you have time and strength could you implement this:

  • Would it be possible to integrate the comment's up/down votes too?
  • To write comments in descending order based on upvotes (highest first)?

I wish I cold help but have no Idea.
Thanks again:
Hetsz.

@Hallavera
Copy link

To write comments in descending order based on upvotes (highest first)?

This is not necessary because it can be decided when the comments are downloaded with yt-dlp by specifying "youtube:comment_sort=top"

The up/down votes would be cool af to have.

Also idk how hard this is but if i was able to click a parent comment and only then show replies this would be the perfect script imo. This way replies would be hidden by default.

I wish i had the skills to make it happen.

Great script!

@MrKomodoDragon
Copy link

Also idk how hard this is but if i was able to click a parent comment and only then show replies this would be the perfect script imo. This way replies would be hidden by default.

I made a small change that adds collapsible replies here, in case anyone is interested:
https://gist.github.com/MrKomodoDragon/4a933e8deabb14f82f47eb44165fecfd

@Hallavera
Copy link

@MrKomodoDragon its exactly what i myself was missing. thanks for sharing man looks great!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment