MediaWiki:Common-votd.js
MediaWiki interface page
More actions
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/* Any JavaScript here will be loaded for all users on every page load. */
/**
* BattlestarWiki — Video of the Day loader
* Append to MediaWiki:Common.js (after the main page JS block)
*
* Fetches from battlestarpegasus.com MediaCMS API.
* Selects a video deterministically by date.
* Supports manual override via Battlestar_Wiki:Video_of_the_Day/YYYY-MM-DD subpage.
*/
( function () {
'use strict';
var PEGASUS = 'https://battlestarpegasus.com';
var PAGE_SIZE = 50;
function esc( s ) {
return String( s || '' )
.replace( /&/g, '&' ).replace( /</g, '<' )
.replace( />/g, '>' ).replace( /"/g, '"' );
}
function dailySeed() {
var now = new Date();
return Math.floor( Date.UTC(
now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()
) / 86400000 );
}
function fmtDuration( secs ) {
secs = Math.round( secs || 0 );
var m = Math.floor( secs / 60 ), s = secs % 60;
return m + ':' + ( s < 10 ? '0' : '' ) + s;
}
function pegasusGet( path ) {
return fetch( PEGASUS + path, { headers: { Accept: 'application/json' } } )
.then( function ( r ) {
if ( !r.ok ) throw new Error( 'HTTP ' + r.status );
return r.json();
} );
}
function fetchAllVideos() {
return pegasusGet( '/api/v1/media/?media_type=video&ordering=add_date&page_size=' + PAGE_SIZE )
.then( function ( data ) {
var results = data.results || [];
if ( data.next ) {
return pegasusGet( '/api/v1/media/?media_type=video&ordering=add_date&page_size=' + PAGE_SIZE + '&page=2' )
.then( function ( d2 ) { return results.concat( d2.results || [] ); } );
}
return results;
} );
}
function fetchVideoDetail( token ) {
return pegasusGet( '/api/v1/media/' + token );
}
function renderVotd( container, media ) {
var token = media.friendly_token;
var watchUrl = media.url || ( PEGASUS + '/view?m=' + token );
var thumb = media.thumbnail_url ? PEGASUS + media.thumbnail_url : '';
var poster = media.poster_url ? PEGASUS + media.poster_url : thumb;
/* ── Build video URLs from API response ── */
var hlsSrc = '';
var mp4Src = '';
if ( media.hls_info && media.hls_info.master_file ) {
hlsSrc = PEGASUS + media.hls_info.master_file;
}
/* Prefer 720p MP4 fallback, cascade down */
var enc = media.encodings_info || {};
var mp4Res = [ '720', '480', '360', '1080', '240' ];
for ( var i = 0; i < mp4Res.length; i++ ) {
var r = enc[ mp4Res[i] ];
if ( r && r.h264 && r.h264.url && r.h264.status === 'success' ) {
mp4Src = PEGASUS + r.h264.url;
break;
}
}
/* ── Player HTML: <video> with poster ── */
var videoId = 'bsw-votd-video';
var playerHtml =
'<video id="' + videoId + '" ' +
'style="width:100%;aspect-ratio:16/9;display:block;background:#000" ' +
'controls playsinline preload="none" ' +
( poster ? 'poster="' + esc( poster ) + '"' : '' ) + '>' +
( mp4Src ? '<source src="' + esc( mp4Src ) + '" type="video/mp4">' : '' ) +
'</video>';
/* ── Description sidebar ── */
var tags = ( media.tags || [] ).slice( 0, 8 ).map( function ( t ) {
var label = typeof t === 'string' ? t : ( t.title || t.name || '' );
return label ? '<span class="bsw-votd-tag">' + esc( label ) + '</span>' : '';
} ).join( '' );
var stats = [];
if ( media.duration ) stats.push( '\u23f1 ' + fmtDuration( media.duration ) );
if ( media.views ) stats.push( '\ud83d\udc41 ' + media.views.toLocaleString() );
if ( media.size ) stats.push( media.size );
var desc = media.description || '';
var infoHtml =
'<div class="bsw-votd-title">' + esc( media.title || 'Untitled' ) + '</div>' +
( stats.length ? '<div class="bsw-votd-stats">' + stats.join( ' \u00b7 ' ) + '</div>' : '' ) +
( desc ? '<div class="bsw-votd-desc">' + desc + '</div>' : '' ) +
( tags ? '<div class="bsw-votd-tags">' + tags + '</div>' : '' ) +
'<div class="bsw-votd-actions">' +
'<a class="bsw-votd-watch" href="' + esc( watchUrl ) + '" target="_blank" rel="noopener">Watch on Battlestar Pegasus \u2197</a>' +
'<a class="bsw-votd-archive" href="/Battlestar_Wiki:Video_of_the_Day">Video archive</a>' +
'</div>';
/* Inject into DOM */
var playerEl = container.querySelector( '.bsw-votd-player' );
var infoEl = document.getElementById( 'bsw-votd-info' );
if ( playerEl ) {
playerEl.innerHTML = playerHtml;
/* Wire HLS.js if HLS src available and browser needs it */
if ( hlsSrc ) {
var videoEl = document.getElementById( videoId );
if ( videoEl ) {
if ( videoEl.canPlayType( 'application/vnd.apple.mpegurl' ) ) {
/* Native HLS (Safari) */
videoEl.src = hlsSrc;
} else {
/* Load hls.js dynamically from cdnjs */
var script = document.createElement( 'script' );
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.4.12/hls.min.js';
script.onload = function () {
if ( window.Hls && Hls.isSupported() ) {
var hls = new Hls( { startLevel: 3 } ); /* start at 720p */
hls.loadSource( hlsSrc );
hls.attachMedia( videoEl );
}
};
document.head.appendChild( script );
}
}
}
}
if ( infoEl ) {
infoEl.innerHTML = infoHtml;
infoEl.style.display = '';
}
}
function showVotdError( container, msg ) {
var playerEl = container.querySelector( '.bsw-votd-player' );
if ( playerEl ) {
playerEl.innerHTML =
'<div class="bsw-error" style="padding:1.5rem;text-align:center">' +
'Could not load video. ' +
'<a href="' + esc( PEGASUS ) + '" target="_blank" rel="noopener">Visit Battlestar Pegasus \u2197</a>' +
'</div>';
}
}
mw.hook( 'wikipage.content' ).add( function () {
var container = document.getElementById( 'bsw-votd-container' );
if ( !container ) return;
var dateStr = container.dataset.date || '';
var overrideEl = document.getElementById( 'bsw-votd-override' );
var override = overrideEl ? overrideEl.textContent.trim() : '';
var seed = ( function () {
if ( dateStr ) {
var p = dateStr.split( '-' );
return Math.floor( Date.UTC( +p[0], +p[1] - 1, +p[2] ) / 86400000 );
}
return dailySeed();
}() );
if ( override ) {
fetchVideoDetail( override )
.then( function ( media ) { renderVotd( container, media ); } )
.catch( function ( e ) { showVotdError( container, e.message ); } );
} else {
fetchAllVideos()
.then( function ( items ) {
if ( !items.length ) throw new Error( 'No videos available.' );
var pick = items[ seed % items.length ];
return fetchVideoDetail( pick.friendly_token );
} )
.then( function ( media ) { renderVotd( container, media ); } )
.catch( function ( e ) { showVotdError( container, e.message ); } );
}
} );
}() );