diff --git a/assets/js/embed.js b/assets/js/embed.js index b11b5e5a..b5fa1b3f 100644 --- a/assets/js/embed.js +++ b/assets/js/embed.js @@ -1,6 +1,39 @@ 'use strict'; var video_data = JSON.parse(document.getElementById('video_data').textContent); +function get_compilation(compid) { + var compid_url; + compid_url = '/api/v1/compilations/' + compid + + '?index=' + video_data.index + + '&continuation' + video_data.id + + '&format=html&hl=' + video_data.preferences.locale; + + helpers.xhr('GET', compid_url, {retries: 5, entity_name: 'compilation'}, { + on200: function (response) { + if (!response.nextVideo) + return; + + player.on('ended', function () { + var url = new URL('https://example.com/embed/' + response.nextVideo); + + url.searchParams.set('list', compid); + if (!compid.startsWith('RD')) + url.searchParams.set('index', response.index); + if (video_data.params.autoplay || video_data.params.continue_autoplay) + url.searchParams.set('autoplay', '1'); + if (video_data.params.listen !== video_data.preferences.listen) + url.searchParams.set('listen', video_data.params.listen); + if (video_data.params.speed !== video_data.preferences.speed) + url.searchParams.set('speed', video_data.params.speed); + if (video_data.params.local !== video_data.preferences.local) + url.searchParams.set('local', video_data.params.local); + + location.assign(url.pathname + url.search); + }); + } + }); +} + function get_playlist(plid) { var plid_url; if (plid.startsWith('RD')) { @@ -43,6 +76,8 @@ function get_playlist(plid) { addEventListener('load', function (e) { if (video_data.plid) { get_playlist(video_data.plid); + } else if (video_data.compid) { + get_compilation(video_data.compid) } else if (video_data.video_series) { player.on('ended', function () { var url = new URL('https://example.com/embed/' + video_data.video_series.shift()); diff --git a/assets/js/watch.js b/assets/js/watch.js index 36506abd..809a9f19 100644 --- a/assets/js/watch.js +++ b/assets/js/watch.js @@ -102,6 +102,57 @@ function continue_autoplay(event) { } } +function get_compilation(compid) { + var compilation = document.getElementById('compilations'); + + compilation.innerHTML = spinnerHTMLwithHR; + + var compid_url; + compid_url = '/api/v1/compilations/' + compid + + '?index=' + video_data.index + + '&continuation=' + video_data.id + + '&format=html&hl=' + video_data.preferences.locale; + + helpers.xhr('GET', compid_url, {retries: 5, entity_name: 'compilation'}, { + on200: function (response) { + compilation.innerHTML = response.compilationHtml; + + if (!response.nextVideo) return; + + var nextVideo = document.getElementById(response.nextVideo); + nextVideo.parentNode.parentNode.scrollTop = nextVideo.offsetTop; + + player.on('ended', function () { + var url = new URL('https://example.com/watch?v=' + response.nextVideo); + + url.searchParams.set('list', compid); + if (!plid.startsWith('RD')) + url.searchParams.set('index', response.index); + if (video_data.params.autoplay || video_data.params.continue_autoplay) + url.searchParams.set('autoplay', '1'); + if (video_data.params.listen !== video_data.preferences.listen) + url.searchParams.set('listen', video_data.params.listen); + if (video_data.params.speed !== video_data.preferences.speed) + url.searchParams.set('speed', video_data.params.speed); + if (video_data.params.local !== video_data.preferences.local) + url.searchParams.set('local', video_data.params.local); + + location.assign(url.pathname + url.search); + }); + }, + onNon200: function (xhr) { + compilation.innerHTML = ''; + document.getElementById('continue').style.display = ''; + }, + onError: function (xhr) { + compilation.innerHTML = spinnerHTMLwithHR; + }, + onTimeout: function (xhr) { + compilation.innerHTML = spinnerHTMLwithHR; + } + }); + } + function get_playlist(plid) { var playlist = document.getElementById('playlist'); @@ -334,7 +385,8 @@ if (video_data.play_next) { addEventListener('load', function (e) { if (video_data.plid) get_playlist(video_data.plid); - + if (video_data.compid) + get_compilation(video_data.compid); if (video_data.params.comments[0] === 'youtube') { get_youtube_comments(); } else if (video_data.params.comments[0] === 'reddit') { diff --git a/src/invidious/database/migrations/0011_create_compilations_table.cr b/src/invidious/database/migrations/0011_create_compilations_table.cr new file mode 100644 index 00000000..30404183 --- /dev/null +++ b/src/invidious/database/migrations/0011_create_compilations_table.cr @@ -0,0 +1,49 @@ +module Invidious::Database::Migrations + class CreateCompilationsTable < Migration + version 8 + + def up(conn : DB::Connection) + if !privacy_type_exists?(conn) + conn.exec <<-SQL + CREATE TYPE public.compilation_privacy AS ENUM + ( + 'Unlisted', + 'Private' + ); + SQL + end + + conn.exec <<-SQL + CREATE TABLE IF NOT EXISTS public.compilations + ( + title text, + id text primary key, + author text, + description text, + video_count integer, + created timestamptz, + updated timestamptz, + privacy compilation_privacy, + index int8[] + ); + SQL + + conn.exec <<-SQL + GRANT ALL ON public.compilations TO current_user; + SQL + end + + private def privacy_type_exists?(conn : DB::Connection) : Bool + request = <<-SQL + SELECT 1 AS one + FROM pg_type + INNER JOIN pg_namespace ON pg_namespace.oid = pg_type.typnamespace + WHERE pg_namespace.nspname = 'public' + AND pg_type.typname = 'privacy' + LIMIT 1; + SQL + + !conn.query_one?(request, as: Int32).nil? + end + end +end