Basic Google Cast Support (#140)

* Added Start and Stop cast buttons.

* Modified from the internet.

* Code to initialize casting

* Added `video-item` id to video

* Renamed function to make more sense

* Renamed cast functions to make more sense

* Renamed cast functions to make more sense

* Changed console logging message.

* Make cast buttons appear if enabled in settings.

* Make cast scripts only load if enabled in settings

* add cast configuration form, #140

* fix spelling

Co-authored-by: simon <simobilleter@gmail.com>
This commit is contained in:
Nathan DeTar 2022-01-11 03:31:22 -08:00 committed by GitHub
parent edc9f3fe15
commit 45518dc3d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 128 additions and 6 deletions

View File

@ -31,7 +31,8 @@
"cache_dir": "/cache", "cache_dir": "/cache",
"videos": "/youtube", "videos": "/youtube",
"file_template": "%(id)s_%(title)s.mp4", "file_template": "%(id)s_%(title)s.mp4",
"colors": "dark" "colors": "dark",
"enable_cast": false
}, },
"scheduler": { "scheduler": {
"update_subscribed": false, "update_subscribed": false,

View File

@ -62,6 +62,12 @@ class ApplicationSettingsForm(forms.Form):
("1", "enable ryd integration"), ("1", "enable ryd integration"),
] ]
CAST_CHOICES = [
("", "-- change Cast integration --"),
("0", "disable Cast"),
("1", "enable Cast"),
]
subscriptions_channel_size = forms.IntegerField(required=False) subscriptions_channel_size = forms.IntegerField(required=False)
downloads_limit_count = forms.IntegerField(required=False) downloads_limit_count = forms.IntegerField(required=False)
downloads_limit_speed = forms.IntegerField(required=False) downloads_limit_speed = forms.IntegerField(required=False)
@ -78,6 +84,9 @@ class ApplicationSettingsForm(forms.Form):
downloads_integrate_ryd = forms.ChoiceField( downloads_integrate_ryd = forms.ChoiceField(
widget=forms.Select, choices=RYD_CHOICES, required=False widget=forms.Select, choices=RYD_CHOICES, required=False
) )
application_enable_cast = forms.ChoiceField(
widget=forms.Select, choices=CAST_CHOICES, required=False
)
class SchedulerSettingsForm(forms.Form): class SchedulerSettingsForm(forms.Form):

View File

@ -28,6 +28,17 @@
<link rel="stylesheet" href="{% static 'css/light.css' %}"> <link rel="stylesheet" href="{% static 'css/light.css' %}">
{% endif %} {% endif %}
<script type="text/javascript" src="{% static 'script.js' %}"></script> <script type="text/javascript" src="{% static 'script.js' %}"></script>
{% if cast %}
<script src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
<script>
window['__onGCastApiAvailable'] = function(isAvailable) {
if (isAvailable) {
initializeCastApi();
}
};
</script>
<script type="text/javascript" src="{% static 'cast-videos.js' %}"></script>
{% endif %}
</head> </head>
<body> <body>
<div class="main-content"> <div class="main-content">

View File

@ -102,6 +102,11 @@
<i>Before activating that, make sure you have a scraping sleep interval of at least 3 secs set to avoid ratelimiting issues.</i><br> <i>Before activating that, make sure you have a scraping sleep interval of at least 3 secs set to avoid ratelimiting issues.</i><br>
{{ app_form.downloads_integrate_ryd }} {{ app_form.downloads_integrate_ryd }}
</div> </div>
<div class="settings-item">
<p><span class="danger-zone">Untested!</span> Current Cast integration: <span class="settings-current">{{ config.application.enable_cast }}</span></p>
<i>Enabling Cast will load an additional JS library from google.</i><br>
{{ app_form.application_enable_cast }}
</div>
</div> </div>
<button type="submit" name="application-settings">Update Application Configurations</button> <button type="submit" name="application-settings">Update Application Configurations</button>
</form> </form>

View File

@ -6,12 +6,16 @@
<video <video
src="/media/{{ video.media_url }}" src="/media/{{ video.media_url }}"
poster="/cache/{{ video.vid_thumb_url }}" controls preload="false" poster="/cache/{{ video.vid_thumb_url }}" controls preload="false"
type='video/mp4' width="100%" playsinline> type='video/mp4' width="100%" playsinline id="video-item">
</video> </video>
</div> </div>
<div class="boxed-content"> <div class="boxed-content">
<div class="title-bar"> <div class="title-bar">
<h1>{{ video.title }}</h1> <h1>{{ video.title }}</h1>
{% if cast %}
<button onclick="startCast()">Start Cast</button>
<button onclick="stopCast()">Stop Cast</button>
{% endif %}
</div> </div>
<div class="info-box info-box-3"> <div class="info-box info-box-3">
<div class="info-box-item"> <div class="info-box-item">

View File

@ -590,10 +590,9 @@ class VideoView(View):
def get(self, request, video_id): def get(self, request, video_id):
"""get single video""" """get single video"""
es_url, colors = self.read_config(user_id=request.user.id) es_url, colors, cast = self.read_config(user_id=request.user.id)
url = f"{es_url}/ta_video/_doc/{video_id}" url = f"{es_url}/ta_video/_doc/{video_id}"
data = None look_up = SearchHandler(url, None)
look_up = SearchHandler(url, data)
video_hit = look_up.get_data() video_hit = look_up.get_data()
video_data = video_hit[0]["source"] video_data = video_hit[0]["source"]
try: try:
@ -614,6 +613,7 @@ class VideoView(View):
"playlist_nav": playlist_nav, "playlist_nav": playlist_nav,
"title": video_title, "title": video_title,
"colors": colors, "colors": colors,
"cast": cast,
} }
return render(request, "home/video.html", context) return render(request, "home/video.html", context)
@ -635,8 +635,9 @@ class VideoView(View):
"""read config file""" """read config file"""
config_handler = AppConfig(user_id) config_handler = AppConfig(user_id)
es_url = config_handler.config["application"]["es_url"] es_url = config_handler.config["application"]["es_url"]
cast = config_handler.config["application"]["enable_cast"]
colors = config_handler.colors colors = config_handler.colors
return es_url, colors return es_url, colors, cast
@staticmethod @staticmethod
def star_creator(rating): def star_creator(rating):

View File

@ -0,0 +1,91 @@
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);
};
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.");
}
}
function onInitSuccess() {
console.log("Initialization succeeded");
}
function onInitError() {
console.log("Initialization failed");
}
function startCast() {
console.log("Starting cast...");
chrome.cast.requestSession(onRequestSessionSuccess, onLaunchError);
}
function onRequestSessionSuccess(e) {
console.log("Successfully created session: " + e.sessionId);
session = e;
}
function onLaunchError() {
console.log("Error connecting to the Chromecast.");
}
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.');
}