Untested! Current Cast integration: {{ config.application.enable_cast }}
- Enabling Cast will load an additional JS library from google.
+
Current Cast integration: {{ config.application.enable_cast }}
+ Enabling Cast will load an additional JS library from Google. HTTPS and a supported browser are required for this integration.
{{ app_form.application_enable_cast }}
@@ -293,4 +293,4 @@
{% endif %}
-{% endblock content %}
\ No newline at end of file
+{% endblock content %}
diff --git a/tubearchivist/home/templates/home/video.html b/tubearchivist/home/templates/home/video.html
index 9ed944e..a220fa8 100644
--- a/tubearchivist/home/templates/home/video.html
+++ b/tubearchivist/home/templates/home/video.html
@@ -11,11 +11,10 @@
-
{{ video.title }}
{% if cast %}
-
-
+
{% endif %}
+
{{ video.title }}
diff --git a/tubearchivist/home/views.py b/tubearchivist/home/views.py
index 62b22e7..ca83db9 100644
--- a/tubearchivist/home/views.py
+++ b/tubearchivist/home/views.py
@@ -111,6 +111,7 @@ class ArchivistViewConfig(View):
self.context = {
"colors": self.default_conf["application"]["colors"],
+ "cast": self.default_conf["application"]["enable_cast"],
"sort_by": self._get_sort_by(),
"sort_order": self._get_sort_order(),
"view_style": self._get_view_style(),
diff --git a/tubearchivist/static/cast-videos.js b/tubearchivist/static/cast-videos.js
index 1d6c9fd..c2b05ba 100644
--- a/tubearchivist/static/cast-videos.js
+++ b/tubearchivist/static/cast-videos.js
@@ -1,91 +1,82 @@
-var session = null;
-
function initializeCastApi() {
- var applicationID = chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID;
- var sessionRequest = new chrome.cast.SessionRequest(applicationID);
- var apiConfig = new chrome.cast.ApiConfig(sessionRequest,
- sessionListener,
- receiverListener);
- chrome.cast.initialize(apiConfig, onInitSuccess, onInitError);
-};
+ cast.framework.CastContext.getInstance().setOptions({
+ receiverApplicationId: chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID, // Use built in reciver app on cast device, see https://developers.google.com/cast/docs/styled_receiver if you want to be able to add a theme, splash screen or watermark. Has a $5 one time fee.
+ autoJoinPolicy: chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED
+ });
-function sessionListener(e) {
- session = e;
- console.log('New session');
- if (session.media.length != 0) {
- console.log('Found ' + session.media.length + ' sessions.');
- }
-}
-
-function receiverListener(e) {
- if( e === 'available' ) {
- console.log("Chromecast was found on the network.");
- }
- else {
- console.log("There are no Chromecasts available.");
+ var player = new cast.framework.RemotePlayer();
+ var playerController = new cast.framework.RemotePlayerController(player);
+
+ // Add event listerner to check if a connection to a cast device is initiated
+ playerController.addEventListener(
+ cast.framework.RemotePlayerEventType.IS_CONNECTED_CHANGED, function() {
+ castConnectionChange(player)
}
+ );
}
-function onInitSuccess() {
- console.log("Initialization succeeded");
+
+function castConnectionChange(player) {
+ // If cast connection is initialized start cast
+ if (player.isConnected) {
+ // console.log("Cast Connected.");
+ castStart();
+ } else if (!player.isConnected) {
+ // console.log("Cast Disconnected.");
+ }
}
-function onInitError() {
- console.log("Initialization failed");
+function castStart() {
+ var castSession = cast.framework.CastContext.getInstance().getCurrentSession();
+
+ // Check if there is already media playing on the cast target to prevent recasting on page reload or switching to another video page
+ if (!castSession.getMediaSession()) {
+ contentId = document.getElementById("video-item").src; // Get video URL
+ contentTitle = document.getElementById('video-title').innerHTML; // Get video title
+ contentImage = document.getElementById("video-item").poster; // Get video thumbnail URL
+ contentType = 'video/mp4'; // Set content type, only videos right now so it is hard coded
+ contentCurrentTime = document.getElementById("video-item").currentTime; // Get video's current position
+
+ mediaInfo = new chrome.cast.media.MediaInfo(contentId, contentType); // Create MediaInfo var that contains url and content type
+ // mediaInfo.streamType = chrome.cast.media.StreamType.BUFFERED; // Set type of stream, BUFFERED, LIVE, OTHER
+ mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata(); // Create metadata var and add it to MediaInfo
+ mediaInfo.metadata.title = contentTitle; // Set the video title
+ mediaInfo.metadata.images = [new chrome.cast.Image(contentImage)]; // Set the video thumbnail
+
+ var request = new chrome.cast.media.LoadRequest(mediaInfo); // Create request with the previously set MediaInfo.
+ // request.queueData = new chrome.cast.media.QueueData(); // See https://developers.google.com/cast/docs/reference/web_sender/chrome.cast.media.QueueData for playlist support.
+ request.currentTime = shiftCurrentTime(contentCurrentTime); // Set video start position based on the browser video position
+ // request.autoplay = false; // Set content to auto play, true by default
+ castSession.loadMedia(request).then(
+ function() {
+ castSuccessful();
+ },
+ function() {
+ castFailed(errorCode);
+ }
+ ); // Send request to cast device
+ }
}
-function startCast() {
- console.log("Starting cast...");
- chrome.cast.requestSession(onRequestSessionSuccess, onLaunchError);
+function shiftCurrentTime(contentCurrentTime) { // Shift media back 3 seconds to prevent missing some of the content
+ if (contentCurrentTime > 5) {
+ return(contentCurrentTime - 3);
+ } else {
+ return(0);
+ }
}
-function onRequestSessionSuccess(e) {
- console.log("Successfully created session: " + e.sessionId);
- session = e;
+function castSuccessful() {
+ // console.log('Cast Successful.');
+ document.getElementById("video-item").pause(); // Pause browser video on successful cast
}
-function onLaunchError() {
- console.log("Error connecting to the Chromecast.");
+function castFailed(errorCode) {
+ console.log('Error code: ' + errorCode);
}
-function onRequestSessionSuccess(e) {
- console.log("Successfully created session: " + e.sessionId);
- session = e;
- loadMedia();
-}
-
-function loadMedia() {
- if (!session) {
- console.log("No session.");
- return;
- }
-
- var videoSrc = document.getElementById("video-item").src;
- var mediaInfo = new chrome.cast.media.MediaInfo(videoSrc);
- mediaInfo.contentType = 'video/mp4';
-
- var request = new chrome.cast.media.LoadRequest(mediaInfo);
- request.autoplay = true;
-
- session.loadMedia(request, onLoadSuccess, onLoadError);
-}
-
-function onLoadSuccess() {
- console.log('Successfully loaded video.');
-}
-
-function onLoadError() {
- console.log('Failed to load video.');
-}
-
-function stopCast() {
- session.stop(onStopCastSuccess, onStopCastError);
-}
-
-function onStopCastSuccess() {
- console.log('Successfully stopped casting.');
-}
-
-function onStopCastError() {
- console.log('Error stopping cast.');
+window['__onGCastApiAvailable'] = function(isAvailable) {
+ if (isAvailable) {
+ initializeCastApi();
+ }
}
diff --git a/tubearchivist/static/css/style.css b/tubearchivist/static/css/style.css
index d745cc3..8a779d2 100644
--- a/tubearchivist/static/css/style.css
+++ b/tubearchivist/static/css/style.css
@@ -267,6 +267,14 @@ button:hover {
filter: var(--img-filter);
}
+#castbutton {
+ float: right;
+ width: 40px;
+ padding: 0 5px;
+ --disconnected-color: var(--accent-font-dark);
+ --connected-color: var(--accent-font-light);
+}
+
/* top of page */
.title-bar {
padding-top: 30px;
diff --git a/tubearchivist/static/script.js b/tubearchivist/static/script.js
index 2d5b465..a7c6b17 100644
--- a/tubearchivist/static/script.js
+++ b/tubearchivist/static/script.js
@@ -309,6 +309,7 @@ function createPlayer(button) {
videoPlayer.setAttribute('width', '100%');
videoPlayer.setAttribute('playsinline', true);
videoPlayer.setAttribute('poster', mediaThumb);
+ videoPlayer.setAttribute('id', 'video-item'); // Set ID to get URL for casting
playerElement.appendChild(videoPlayer);
// title bar
var titleBar = document.createElement('div');
@@ -335,7 +336,14 @@ function createPlayer(button) {
var videoTitleLink = document.createElement('a');
videoTitleLink.setAttribute('href', '/video/' + dataId + '/');
var videoTitle = document.createElement('h2');
+ videoTitle.setAttribute('id', "video-title"); // Set ID to get title for casting
videoTitle.innerText = mediaTitle;
+ var castScript = document.getElementById('cast-script'); // Get cast-script
+ if(typeof(castScript) != 'undefined' && castScript != null) { // Check if cast integration is enabled
+ var castButton = document.createElement("google-cast-launcher"); // Create cast button
+ castButton.setAttribute('id', "castbutton"); // Set ID to apply theme
+ titleBar.appendChild(castButton); // Add cast button to title
+ }
videoTitleLink.appendChild(videoTitle);
titleBar.appendChild(videoTitleLink);
// add titlebar