Skip to content

Commit

Permalink
Merge pull request #24 from rebane2001/v2
Browse files Browse the repository at this point in the history
V2 more stuff
  • Loading branch information
rebane2001 authored May 11, 2023
2 parents 9bf953f + 2a6ddec commit 89d513d
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 39 deletions.
24 changes: 14 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,25 @@ A lightweight static HTML generator for self-hosting yt-dlp video archives.
# Features
- Static HTML (fast and secure)
- Parses yt-dlp info.json format
- Channel pages (with thumbnails)
- Channel pages (with thumbnails, name history)
- Watch page (with stats, description etc)
- Download buttons (video, description, thumbnail, subtitles)
- Highlight deleted videos
- Client-side search
- Highlight deleted/unlisted videos
- Client-side search/sorting

# Usage
1. Clone this repo (or download as zip).
2. Rename the `default.json` file to `config.json` and edit the `ytpath`, `ytpathweb`, `webpath`, `outpath` and `removedvideosfile` variables to suit your setup.
3. Run `python3 hobune.py`, this will generate HTML files in your `outpath`.
2. Rename the `default.json` file to `config.json` and edit the variables to suit your setup:
- `site_name`: Name/Title of the site (e.g. "Hobune")
- `files_path`: Local path of the video files (e.g. "/var/www/html/files/")
- `files_web_path`: Web path of the video files (e.g. "/files/" or "https://example.com/files/")
- `web_root`: Web root path (e.g. "/" or "https://example.com/")
- `output_path`: Output path for the HTML files (e.g. "/var/www/html/")
- `add_html_ext`: Add HTML extension to links (e.g. link to /videos/foobar.html instead of /videos/foobar)
- `removed_videos_file`: A text file where each line ends with a removed video ID (optional, e.g. "~/removed_videos.txt")
- `unlisted_videos_file`: Unlisted videos file - similar to the removed videos file (optional)

3. Run `python3 hobune.py`, this will generate HTML files in your `output_path`.
4. (optionally) Configure your webserver to allow downloads from /dl URLs and HTML pages without extensions.

```
Expand All @@ -31,8 +40,3 @@ location /dl {
```

It is also recommended to edit the python script to suit your exact needs, since your setup probably won't be 1:1 same as the expected one.

# Notes (2022)
This codebase is a bit of a mess at the moment and I need to clean it up and refactor it at some point. Windows is not supported without code changes, although it can be made to work.

I've also added my comments code to this repo in an unorganized fashion. It is disabled by default, if you'd like to use it please read the contents of `comments.py`.
2 changes: 1 addition & 1 deletion custom/Example.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<div class="ui container main">
<div class="container">
<p>This is an example of a custom page</p>
</div>
19 changes: 12 additions & 7 deletions hobune/comments.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,33 @@ def getCommentsHTML(title, videoid):
with open(f"{comments_path}/{videoid}.jsonl", "r") as f:
header = json.loads(f.readline())
# Hacky workaround if you don't use my format of comments (w/header)
if not "time_fetched" in header:
if "time_fetched" not in header:
comments.append(header)
header = {"time_fetched": "N/A"}
for l in f:
comments.append(json.loads(l))
except Exception:
return False, 0
comments_html = f"""<div class="ui container main">
<h1 class="ui big header">{title}</h1>
<a href="/videos/{videoid}">Back to video page</a> | <a href="/comments/{videoid}.jsonl">Download comments jsonl</a>
<h2 class="ui header">Comments (archived {header["time_fetched"][:16].replace("T", " ")})</h2>
<div class="comments">\n"""
comments_html = ""
comments_count = 0
total_count = 0
for comment in comments:
comments_count += 1
total_count += 1
csnip = comment["snippet"]["topLevelComment"]["snippet"]
comment_html = getCommentHTML(csnip)
if "replies" in comment:
replies = ""
for reply in comment["replies"]["comments"][::-1]:
total_count += 1
replies += f'<div class="reply">{getCommentHTML(reply["snippet"])}</div>\n'
comment_html += f"<details><summary>Replies ({len(comment['replies']['comments'])})</summary>\n{replies}</details>"
comments_html += f'<div class="comment">{comment_html}</div>\n'
comments_html += "</div></div>"
comments_html = f"""<div class="container">
<h1>{title}</h1>
<a href="/videos/{videoid}">Back to video page</a> | <a href="/comments/{videoid}.jsonl">Download comments jsonl</a>
<h2>Comments (archived {header["time_fetched"][:16].replace("T", " ")}; {comments_count} top, {total_count} total comments)</h2>
<div class="comments">\n
{comments_html}
</div></div>"""
return comments_html, comments_count
18 changes: 6 additions & 12 deletions hobune/videos.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,9 @@
from hobune.util import generate_meta_tags, quote_url, no_traverse


def generate_download_button(name, url, tag=None, prefix="/dl"):
tag_part = ""
if tag:
tag_part = f"""
<a class="ui basic right pointing label">
{html.escape(tag)}
</a>"""
def generate_download_button(name, url, prefix="/dl"):
return f"""
<a href="{prefix}{url}">
{tag_part}
<div class="button download">
<i class="icon download"></i> {html.escape(name)}
</div>
Expand Down Expand Up @@ -53,7 +46,7 @@ def create_video_pages(config, channels, templates, html_ext):
with open(os.path.join(config.output_path, f"comments/{no_traverse(v['id'])}.html"), "w") as f:
f.write(templates["base"].format(title=html.escape(v['title'] + ' - Comments'), meta=page_meta,
content=comments_html))
comments_link = f'<p class="comments"><a href="/comments/{v["id"]}">View comments ({comments_count})</a></p>'
comments_link = f'<p class="comments"><a href="/comments/{v["id"]}{html_ext}">View comments ({comments_count})</a></p>'
# Set mp4 path
mp4path = f"{os.path.join(config.files_web_path + root[len(config.files_path):], base)}.mp4"
for ext in ["mp4", "webm", "mkv"]:
Expand All @@ -75,8 +68,8 @@ def create_video_pages(config, channels, templates, html_ext):
for ext in ["webm", "mkv"]:
if (alt_file := f"{base}.{ext}") in files:
alt_file_url = config.files_web_path + (os.path.join(root, alt_file))[len(config.files_path):]
download_buttons_html = generate_download_button("Download video", mp4path, tag="mp4") + \
generate_download_button("Download video", alt_file_url, tag=ext)
download_buttons_html = generate_download_button("Download mp4", mp4path) + \
generate_download_button(f"Download {ext}", alt_file_url)

# Description download
if (desc_file := f"{base}.description") in files:
Expand All @@ -92,11 +85,12 @@ def create_video_pages(config, channels, templates, html_ext):
if vtt.startswith(base):
vtt_url = os.path.join(config.files_web_path + root[len(config.files_path):], vtt)
vtt_tag = vtt[len(base) + 1:-len('.vtt')]
download_buttons_html += generate_download_button("Subtitles", vtt_url, tag=vtt_tag)
download_buttons_html += generate_download_button(f"Subtitles ({vtt_tag})", vtt_url)

# Create HTML
page_html = templates["video"].format(
title=html.escape(v['title']),
ytlink=f"<a class=\"ytlink\" href=https://www.youtube.com/watch?v={html.escape(v['id'])}>YT</a>",
description=html.escape(v['description']).replace('\n', '<br>'),
views=v['view_count'],
uploader_url=f"{config.web_root}channels/{html.escape(v['channel_id'])}{html_ext}" if is_full_channel(root) else f'{config.web_root}channels/other{html_ext}',
Expand Down
2 changes: 1 addition & 1 deletion hobune_v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Strikethrough means already implemented.
- ~~Make it work on Windows by default~~
- Dedupe videos by default
- Comments page should show comments count (both top-level and all)
- Link back to YouTube links whereever possible
~~- Link back to YouTube links wherever possible~~
- Make it easier to download everything, eg provide a wget command (maybe we could even download and generate a zip in JS for smaller channels?)
- Support generating comments even if video itself isn't present
- Cache folder listings (so we don't like /other a hundred thousand times)
Expand Down
16 changes: 10 additions & 6 deletions templates/hobune.css
Original file line number Diff line number Diff line change
Expand Up @@ -359,16 +359,20 @@ a {
padding: 7px 14px;
}

.ytlink {
font-size: 14px;
}

.tag {
font-size: 14px;
color: rgba(0,0,0,.6);
}

.rounded {
border-radius: 5px;
overflow: hidden;
}

.ui.footer.segment {
margin: 5em 0em 0em;
padding: 5em 0em;
}

.hide {
display: none!important;
}
Expand All @@ -390,7 +394,7 @@ a {
}

.comment p {
margin-bottom: 0;
margin: 0;
}

.comment .reply {
Expand Down
4 changes: 2 additions & 2 deletions templates/video.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="ui container main">
<div class="container">
<br>
<div class="ui">
<video controls poster="{thumbnail}" class="rounded video">
Expand All @@ -10,7 +10,7 @@
<div class="main">
<h1>{title}</h1>
{comments}
<h2 class="subtitle">Description</h2>
<h2 class="subtitle">Description {ytlink}</h2>
<p>{description}</p>
</div>
<div class="side">
Expand Down

0 comments on commit 89d513d

Please sign in to comment.