Video enrichment: surface enriched YouTube data
- YouTube video cards show 👍/👎 like/dislike counts (from Return YouTube Dislike) next to views, threaded through ytEpisodeOf. - New GET /youtube/video/<id>/segments exposes stored SponsorBlock segments so the player can offer skips. Update config-shape test for the new keys/toggles.
This commit is contained in:
parent
21a1e5ddbb
commit
6f14f15dd6
3 changed files with 20 additions and 2 deletions
|
|
@ -36,6 +36,14 @@ def _server():
|
|||
|
||||
|
||||
def register_routes(bp):
|
||||
@bp.route("/youtube/video/<video_id>/segments", methods=["GET"])
|
||||
def video_youtube_segments(video_id):
|
||||
"""SponsorBlock crowd segments stored for a video (sponsor/intro/outro/…),
|
||||
so the player can offer skips. [] until the SponsorBlock worker enriches it."""
|
||||
from . import get_video_db
|
||||
return jsonify({"video_id": video_id,
|
||||
"segments": get_video_db().youtube_video_segments(video_id)})
|
||||
|
||||
@bp.route("/youtube/resolve", methods=["GET"])
|
||||
def video_youtube_resolve():
|
||||
"""Preview a pasted channel URL without committing. Returns the channel +
|
||||
|
|
|
|||
|
|
@ -334,12 +334,18 @@ def test_enrichment_config_save_load(tmp_path, monkeypatch):
|
|||
try:
|
||||
assert client.get("/api/video/enrichment/config").get_json() == {
|
||||
"tmdb_api_key": "", "tvdb_api_key": "", "omdb_api_key": "",
|
||||
"fanart_api_key": "", "opensubtitles_api_key": "",
|
||||
"ryd_enabled": True, "sponsorblock_enabled": True,
|
||||
"billboard_autoplay": True, "watch_region": "US"}
|
||||
client.post("/api/video/enrichment/config",
|
||||
json={"tmdb_api_key": "abc", "tvdb_api_key": "xyz", "omdb_api_key": "om",
|
||||
"fanart_api_key": "fa", "opensubtitles_api_key": "os",
|
||||
"ryd_enabled": False, "sponsorblock_enabled": True,
|
||||
"billboard_autoplay": False, "watch_region": "gb"})
|
||||
assert client.get("/api/video/enrichment/config").get_json() == {
|
||||
"tmdb_api_key": "abc", "tvdb_api_key": "xyz", "omdb_api_key": "om",
|
||||
"fanart_api_key": "fa", "opensubtitles_api_key": "os",
|
||||
"ryd_enabled": False, "sponsorblock_enabled": True,
|
||||
"billboard_autoplay": False, "watch_region": "GB"}
|
||||
assert db.get_setting("tmdb_api_key") == "abc" and db.get_setting("omdb_api_key") == "om"
|
||||
assert client.get("/api/video/prefs").get_json() == {
|
||||
|
|
|
|||
|
|
@ -975,7 +975,10 @@
|
|||
: '';
|
||||
var dur = ep.yt_duration ? '<span class="vd-ep-dur">' + esc(ep.yt_duration) + '</span>' : '';
|
||||
var meta = [];
|
||||
if (ep.view_count) { var yc = window.VideoYoutube; meta.push((yc ? yc.compactCount(ep.view_count) : ep.view_count) + ' views'); }
|
||||
var yc0 = window.VideoYoutube;
|
||||
if (ep.view_count) { meta.push((yc0 ? yc0.compactCount(ep.view_count) : ep.view_count) + ' views'); }
|
||||
if (ep.like_count) { meta.push('👍 ' + (yc0 ? yc0.compactCount(ep.like_count) : ep.like_count)); }
|
||||
if (ep.dislike_count) { meta.push('👎 ' + (yc0 ? yc0.compactCount(ep.dislike_count) : ep.dislike_count)); }
|
||||
if (ep.air_date) meta.push(fmtDate(ep.air_date));
|
||||
var wished = !!ep.owned;
|
||||
return '<div class="vd-ep vd-ep--yt" data-vd-ep-key="' + key + '" data-vd-yt-vid="' + esc(ep.youtube_id) + '">' +
|
||||
|
|
@ -1373,7 +1376,8 @@
|
|||
return { episode_number: i + 1, title: v.title, overview: v.description || '',
|
||||
air_date: v.published_at, owned: !!v.wished, has_still: false,
|
||||
still_url: ytProx(v.thumbnail_url), youtube_id: v.youtube_id,
|
||||
yt_duration: v.duration || '', view_count: v.view_count || 0 };
|
||||
yt_duration: v.duration || '', view_count: v.view_count || 0,
|
||||
like_count: v.like_count || 0, dislike_count: v.dislike_count || 0 };
|
||||
}
|
||||
function ytDurSecs(d) {
|
||||
if (!d) return 0;
|
||||
|
|
|
|||
Loading…
Reference in a new issue