commit
9e54506dcc
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -41,5 +41,61 @@ jQuery(document).ready(function ($) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(document).on('click', '.cast-scan', function () {
|
||||||
|
showModal('modal-playlist-cast-scan');
|
||||||
|
const $modal = $('.modal-playlist-cast-scan:visible');
|
||||||
|
const $holder = $modal.find('.cast-devices');
|
||||||
|
const $loading = $modal.find('.loading');
|
||||||
|
|
||||||
|
$loading.removeClass('hidden');
|
||||||
|
$holder.removeClass('hidden');
|
||||||
|
$holder.html('');
|
||||||
|
$loading.html($loading.attr('data-loading'));
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
method: 'GET',
|
||||||
|
url: route_cast_scan,
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
success: function (response) {
|
||||||
|
$loading.addClass('hidden')
|
||||||
|
|
||||||
|
for (let i = 0; i < response.devices.length; i++) {
|
||||||
|
const device = response.devices[i];
|
||||||
|
$holder.append($('<li><a href="javascript:void(0)" class="cast-device" data-id="' + device.friendly_name + '"><i class="fa fa-brands fa-chromecast"></i>' + device.friendly_name + '</a></li>'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('click', '.cast-device', function () {
|
||||||
|
const $modal = $('.modal-playlist-cast-scan:visible');
|
||||||
|
const $holder = $modal.find('.cast-devices');
|
||||||
|
const $loading = $modal.find('.loading');
|
||||||
|
|
||||||
|
$holder.addClass('hidden');
|
||||||
|
$loading.removeClass('hidden');
|
||||||
|
$loading.html($loading.attr('data-casting'));
|
||||||
|
|
||||||
|
const id = $(this).attr('data-id');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: route_cast_url,
|
||||||
|
method: 'POST',
|
||||||
|
data: JSON.stringify({
|
||||||
|
device: id,
|
||||||
|
url: $('#playlist-preview-url').val()
|
||||||
|
}),
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
success: function (response) {
|
||||||
|
$loading.addClass('hidden');
|
||||||
|
hideModal();
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
$loading.addClass('hidden');
|
||||||
|
$holder.removeClass('hidden');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
main();
|
main();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -19,3 +19,17 @@
|
|||||||
transform: rotate(2deg);
|
transform: rotate(2deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes blinkfade {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -139,6 +139,30 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.highlighted:hover,
|
||||||
|
&.highlighted {
|
||||||
|
background-color: $seaBlue;
|
||||||
|
|
||||||
|
td {
|
||||||
|
font-weight: bold;
|
||||||
|
color: $gscaleF;
|
||||||
|
|
||||||
|
i.icon-legend {
|
||||||
|
color: $gscaleF;
|
||||||
|
}
|
||||||
|
|
||||||
|
span,
|
||||||
|
i.icon-value {
|
||||||
|
background-color: rgba($gscaleF, .3);
|
||||||
|
color: $gscaleF;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.description {
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -12,21 +12,71 @@
|
|||||||
color: $gscale6;
|
color: $gscale6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-playlist-qrcode {
|
.modal-playlist-cast-scan {
|
||||||
h2 {
|
h2 {
|
||||||
text-align: center;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qrcode-pic {
|
.alert {
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
img {
|
i {
|
||||||
border: 4px solid $gscale5;
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
color: $gscaleF;
|
||||||
|
animation-duration: 2s;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
animation-name: blinkfade;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.cast-devices {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
list-style: none;
|
||||||
|
border-bottom: 1px solid $gscale2;
|
||||||
border-radius: $baseRadius;
|
border-radius: $baseRadius;
|
||||||
|
|
||||||
|
a {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20px 15px;
|
||||||
|
color: $gscaleF;
|
||||||
|
align-self: stretch;
|
||||||
|
|
||||||
|
i {
|
||||||
|
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $gscale2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li:last-child {
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,7 +147,7 @@
|
|||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview-holder {
|
.preview-holder {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
@ -114,6 +164,7 @@
|
|||||||
.hover-only {
|
.hover-only {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $gkscaleC;
|
background: $gkscaleC;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -105,6 +105,7 @@
|
|||||||
"js_playlist_delete_confirmation": "Are you sure?",
|
"js_playlist_delete_confirmation": "Are you sure?",
|
||||||
"playlist_delete_has_slides": "Playlist has slides, please remove them before and retry",
|
"playlist_delete_has_slides": "Playlist has slides, please remove them before and retry",
|
||||||
"playlist_delete_has_node_player_groups": "Playlist is linked to a playgroup",
|
"playlist_delete_has_node_player_groups": "Playlist is linked to a playgroup",
|
||||||
|
"playlist_cast_warning": "Your <a href=\"%href%\" target=\"_blank\">external URL</a> must be served over https for this to work",
|
||||||
"fleet_node_player_page_title": "Players",
|
"fleet_node_player_page_title": "Players",
|
||||||
"fleet_node_player_button_add": "Add a player",
|
"fleet_node_player_button_add": "Add a player",
|
||||||
"fleet_node_player_panel_active": "Active players",
|
"fleet_node_player_panel_active": "Active players",
|
||||||
@ -236,6 +237,7 @@
|
|||||||
"common_pick_element": "Pick an element",
|
"common_pick_element": "Pick an element",
|
||||||
"common_untitled": "<untitled>",
|
"common_untitled": "<untitled>",
|
||||||
"common_loading": "Loading...",
|
"common_loading": "Loading...",
|
||||||
|
"common_casting": "Casting...",
|
||||||
"common_default_node_player_group": "Default Playgroup",
|
"common_default_node_player_group": "Default Playgroup",
|
||||||
"common_default_playlist": "Default Playlist",
|
"common_default_playlist": "Default Playlist",
|
||||||
"common_unknown_ipaddr": "Unknown IP address",
|
"common_unknown_ipaddr": "Unknown IP address",
|
||||||
|
|||||||
@ -105,6 +105,7 @@
|
|||||||
"js_playlist_delete_confirmation": "¿Estás seguro?",
|
"js_playlist_delete_confirmation": "¿Estás seguro?",
|
||||||
"playlist_delete_has_slides": "La playlist tiene diapositivas, por favor elimínelas antes y reintente",
|
"playlist_delete_has_slides": "La playlist tiene diapositivas, por favor elimínelas antes y reintente",
|
||||||
"playlist_delete_has_node_player_groups": "La playlist está asignada a un playgroup",
|
"playlist_delete_has_node_player_groups": "La playlist está asignada a un playgroup",
|
||||||
|
"playlist_cast_warning": "Tu <a href=\"%href%\" target=\"_blank\">URL externa</a> debe ser entregada en https para que esto funcione",
|
||||||
"fleet_node_player_page_title": "Reproductores",
|
"fleet_node_player_page_title": "Reproductores",
|
||||||
"fleet_node_player_button_add": "Agregar un reproductor",
|
"fleet_node_player_button_add": "Agregar un reproductor",
|
||||||
"fleet_node_player_panel_active": "Reproductores activos",
|
"fleet_node_player_panel_active": "Reproductores activos",
|
||||||
@ -237,6 +238,7 @@
|
|||||||
"common_pick_element": "Elige un elemento",
|
"common_pick_element": "Elige un elemento",
|
||||||
"common_untitled": "<sin-título>",
|
"common_untitled": "<sin-título>",
|
||||||
"common_loading": "Cargando...",
|
"common_loading": "Cargando...",
|
||||||
|
"common_casting": "Casting...",
|
||||||
"common_default_node_player_group": "Playgroup predeterminado",
|
"common_default_node_player_group": "Playgroup predeterminado",
|
||||||
"common_default_playlist": "Lista de reproducción predeterminada",
|
"common_default_playlist": "Lista de reproducción predeterminada",
|
||||||
"common_unknown_ipaddr": "Dirección IP desconocida",
|
"common_unknown_ipaddr": "Dirección IP desconocida",
|
||||||
|
|||||||
@ -106,6 +106,7 @@
|
|||||||
"js_playlist_delete_confirmation": "Êtes-vous sûr ?",
|
"js_playlist_delete_confirmation": "Êtes-vous sûr ?",
|
||||||
"playlist_delete_has_slides": "La playlist contient des slides, supprimez-les avant et réessayez",
|
"playlist_delete_has_slides": "La playlist contient des slides, supprimez-les avant et réessayez",
|
||||||
"playlist_delete_has_node_player_groups": "La playlist est attribuée à un playgroup",
|
"playlist_delete_has_node_player_groups": "La playlist est attribuée à un playgroup",
|
||||||
|
"playlist_cast_warning": "Votre <a href=\"%href%\" target=\"_blank\">URL externe</a> doit être servi en https pour que ça fonctionne",
|
||||||
"fleet_node_player_page_title": "Lecteurs",
|
"fleet_node_player_page_title": "Lecteurs",
|
||||||
"fleet_node_player_button_add": "Ajouter un lecteur",
|
"fleet_node_player_button_add": "Ajouter un lecteur",
|
||||||
"fleet_node_player_panel_active": "Players actifs",
|
"fleet_node_player_panel_active": "Players actifs",
|
||||||
@ -238,6 +239,7 @@
|
|||||||
"common_pick_element": "Choisissez un élément",
|
"common_pick_element": "Choisissez un élément",
|
||||||
"common_untitled": "<sans-titre>",
|
"common_untitled": "<sans-titre>",
|
||||||
"common_loading": "Chargement...",
|
"common_loading": "Chargement...",
|
||||||
|
"common_casting": "Casting...",
|
||||||
"common_default_node_player_group": "Playgroup par défaut",
|
"common_default_node_player_group": "Playgroup par défaut",
|
||||||
"common_default_playlist": "Playlist par défaut",
|
"common_default_playlist": "Playlist par défaut",
|
||||||
"common_unknown_ipaddr": "Adresse IP inconnue",
|
"common_unknown_ipaddr": "Adresse IP inconnue",
|
||||||
|
|||||||
@ -105,6 +105,7 @@
|
|||||||
"js_playlist_delete_confirmation": "Sei sicuro?",
|
"js_playlist_delete_confirmation": "Sei sicuro?",
|
||||||
"playlist_delete_has_slides": "Sono presenti slide nella playlist, annullale e riprova",
|
"playlist_delete_has_slides": "Sono presenti slide nella playlist, annullale e riprova",
|
||||||
"playlist_delete_has_node_player_groups": "La playlist è collegata ad un playgroup",
|
"playlist_delete_has_node_player_groups": "La playlist è collegata ad un playgroup",
|
||||||
|
"playlist_cast_warning": "Il tuo <a href=\"%href%\" target=\"_blank\">URL esterno</a> deve essere servito in https affinché funzioni",
|
||||||
"fleet_node_player_page_title": "Schermi",
|
"fleet_node_player_page_title": "Schermi",
|
||||||
"fleet_node_player_button_add": "Aggiungi allo schermo",
|
"fleet_node_player_button_add": "Aggiungi allo schermo",
|
||||||
"fleet_node_player_panel_active": "Schermi attivi",
|
"fleet_node_player_panel_active": "Schermi attivi",
|
||||||
@ -237,6 +238,7 @@
|
|||||||
"common_pick_element": "Scegli un elemento",
|
"common_pick_element": "Scegli un elemento",
|
||||||
"common_untitled": "<senza-titolo>",
|
"common_untitled": "<senza-titolo>",
|
||||||
"common_loading": "Caricamento...",
|
"common_loading": "Caricamento...",
|
||||||
|
"common_casting": "Casting...",
|
||||||
"common_default_node_player_group": "Playgroup di default",
|
"common_default_node_player_group": "Playgroup di default",
|
||||||
"common_default_playlist": "Default playlist",
|
"common_default_playlist": "Default playlist",
|
||||||
"common_unknown_ipaddr": "IP sconosciuto",
|
"common_unknown_ipaddr": "IP sconosciuto",
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
flask==2.3.3
|
flask==2.3.3
|
||||||
flask-restx==1.3.0
|
flask-restx==1.3.0
|
||||||
|
pychromecast==13.1.0
|
||||||
python-dotenv
|
python-dotenv
|
||||||
cron-descriptor
|
cron-descriptor
|
||||||
waitress
|
waitress
|
||||||
flask-login
|
flask-login
|
||||||
pysqlite3
|
pysqlite3
|
||||||
psutil
|
psutil
|
||||||
|
zeroconf
|
||||||
@ -1,7 +1,8 @@
|
|||||||
|
from typing import Optional
|
||||||
from flask import Flask, send_file, render_template_string, jsonify
|
from flask import Flask, send_file, render_template_string, jsonify, request
|
||||||
|
|
||||||
from src.interface.ObController import ObController
|
from src.interface.ObController import ObController
|
||||||
|
from src.util.UtilChromecast import fetch_friendly_names, cast_url
|
||||||
|
|
||||||
|
|
||||||
class CoreController(ObController):
|
class CoreController(ObController):
|
||||||
@ -9,6 +10,8 @@ class CoreController(ObController):
|
|||||||
def register(self):
|
def register(self):
|
||||||
self._app.add_url_rule('/manifest.json', 'manifest', self.manifest, methods=['GET'])
|
self._app.add_url_rule('/manifest.json', 'manifest', self.manifest, methods=['GET'])
|
||||||
self._app.add_url_rule('/favicon.ico', 'favicon', self.favicon, methods=['GET'])
|
self._app.add_url_rule('/favicon.ico', 'favicon', self.favicon, methods=['GET'])
|
||||||
|
self._app.add_url_rule('/cast-scan', 'cast_scan', self.cast_scan, methods=['GET'])
|
||||||
|
self._app.add_url_rule('/cast-url', 'cast_url', self.cast_url, methods=['POST'])
|
||||||
|
|
||||||
def manifest(self):
|
def manifest(self):
|
||||||
with open("{}/manifest.jinja.json".format(self.get_template_dir()), 'r') as file:
|
with open("{}/manifest.jinja.json".format(self.get_template_dir()), 'r') as file:
|
||||||
@ -19,4 +22,17 @@ class CoreController(ObController):
|
|||||||
return self._app.response_class(rendered_content, mimetype='application/json')
|
return self._app.response_class(rendered_content, mimetype='application/json')
|
||||||
|
|
||||||
def favicon(self):
|
def favicon(self):
|
||||||
return send_file("{}/favicon.ico".format(self.get_web_dir()), mimetype='image/x-icon')
|
return send_file("{}/favicon.ico".format(self.get_web_dir()), mimetype='image/x-icon')
|
||||||
|
|
||||||
|
def cast_scan(self):
|
||||||
|
return jsonify({
|
||||||
|
'devices': fetch_friendly_names(discovery_timeout=5)
|
||||||
|
})
|
||||||
|
|
||||||
|
def cast_url(self):
|
||||||
|
data = request.get_json()
|
||||||
|
success = cast_url(friendly_name=data.get('device'), url=data.get('url'))
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'success': success
|
||||||
|
})
|
||||||
|
|||||||
66
src/util/UtilChromecast.py
Normal file
66
src/util/UtilChromecast.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import time
|
||||||
|
import pychromecast
|
||||||
|
import zeroconf
|
||||||
|
|
||||||
|
from pychromecast.discovery import stop_discovery
|
||||||
|
from pychromecast import CastBrowser, SimpleCastListener, get_chromecast_from_host, Chromecast
|
||||||
|
from pychromecast.controllers import BaseController
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
APPLICATION_ID = '81585E3E'
|
||||||
|
|
||||||
|
|
||||||
|
class CastController(BaseController):
|
||||||
|
def __init__(self):
|
||||||
|
super(CastController, self).__init__("urn:x-cast:com.jrk.obscreen")
|
||||||
|
|
||||||
|
def load_url(self, url: str):
|
||||||
|
self.send_message({
|
||||||
|
'url': url,
|
||||||
|
'type': 'load'
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def _discover(discovery_timeout: int = 5):
|
||||||
|
zconf = zeroconf.Zeroconf()
|
||||||
|
browser = pychromecast.CastBrowser(pychromecast.SimpleCastListener(), zconf)
|
||||||
|
browser.start_discovery()
|
||||||
|
time.sleep(discovery_timeout)
|
||||||
|
stop_discovery(browser)
|
||||||
|
|
||||||
|
return browser
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_friendly_names(discovery_timeout: int = 5):
|
||||||
|
return [{"friendly_name": cast_info.friendly_name} for device, cast_info in _discover(discovery_timeout).devices.items()]
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_chromecast(friendly_name: str, discovery_timeout: int = 5) -> Optional[Chromecast]:
|
||||||
|
for uuid, cast_info in _discover(discovery_timeout).devices.items():
|
||||||
|
if cast_info.friendly_name == friendly_name:
|
||||||
|
try:
|
||||||
|
return get_chromecast_from_host((cast_info.host, cast_info.port, uuid, cast_info.model_name, cast_info.friendly_name))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def cast_url(friendly_name: str, url: str, discovery_timeout: int = 5) -> bool:
|
||||||
|
chromecast = fetch_chromecast(friendly_name, discovery_timeout)
|
||||||
|
|
||||||
|
if not chromecast:
|
||||||
|
return False
|
||||||
|
|
||||||
|
chromecast.wait()
|
||||||
|
chromecast.quit_app()
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
cast_controller = CastController()
|
||||||
|
chromecast.register_handler(cast_controller)
|
||||||
|
chromecast.start_app(APPLICATION_ID)
|
||||||
|
time.sleep(2)
|
||||||
|
cast_controller.load_url(url)
|
||||||
|
|
||||||
|
return True
|
||||||
@ -1 +1 @@
|
|||||||
2.3.0
|
2.3.1
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
{% set ns = namespace(last_section='') %}
|
{% set ns = namespace(last_section='') %}
|
||||||
{% for variable in variables %}
|
{% for variable in variables %}
|
||||||
{% set section_change = variable.section and ns.last_section != variable.section %}
|
{% set section_change = variable.section and ns.last_section != variable.section %}
|
||||||
|
{% set highlighted = request.args.get('highlight') == variable.name %}
|
||||||
|
|
||||||
{% if section_change %}
|
{% if section_change %}
|
||||||
{% if not loop.first %}</tbody><tbody>{% endif %}
|
{% if not loop.first %}</tbody><tbody>{% endif %}
|
||||||
@ -12,7 +13,7 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<tr class="variable-item variable-edit" data-level="{{ variable.id }}" data-entity="{{ variable.to_json() }}">
|
<tr class="variable-item variable-edit {{ 'highlighted' if highlighted }}" data-level="{{ variable.id }}" data-entity="{{ variable.to_json() }}">
|
||||||
<td class="description">
|
<td class="description">
|
||||||
{{ t(variable.description) }}
|
{{ t(variable.description) }}
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@ -100,9 +100,12 @@
|
|||||||
<button type="button" class="btn btn-naked copy-link" data-target-id="playlist-preview-url">
|
<button type="button" class="btn btn-naked copy-link" data-target-id="playlist-preview-url">
|
||||||
<i class="fa fa-copy"></i>
|
<i class="fa fa-copy"></i>
|
||||||
</button>
|
</button>
|
||||||
<a href="{{ preview_url }}" class="btn btn-neutral" target="_blank">
|
<a href="{{ preview_url }}" class="btn btn-info" target="_blank">
|
||||||
<i class="fa-solid fa-up-right-from-square"></i>
|
<i class="fa-solid fa-up-right-from-square"></i>
|
||||||
</a>
|
</a>
|
||||||
|
<button type="button" class="btn btn-neutral cast-scan">
|
||||||
|
<i class="fa fa-brands fa-chromecast"></i>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,8 @@
|
|||||||
{% block add_js %}
|
{% block add_js %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var route_slide_position = '{{ url_for('slideshow_slide_position') }}';
|
var route_slide_position = '{{ url_for('slideshow_slide_position') }}';
|
||||||
|
var route_cast_scan = '{{ url_for('cast_scan') }}';
|
||||||
|
var route_cast_url = '{{ url_for('cast_url') }}';
|
||||||
var choices_translations = {
|
var choices_translations = {
|
||||||
'loop': '{{ l.slideshow_slide_form_label_cron_scheduled_loop }}',
|
'loop': '{{ l.slideshow_slide_form_label_cron_scheduled_loop }}',
|
||||||
'datetime': '{{ l.slideshow_slide_form_label_cron_scheduled_datetime }}',
|
'datetime': '{{ l.slideshow_slide_form_label_cron_scheduled_datetime }}',
|
||||||
@ -127,7 +129,7 @@
|
|||||||
<div class="modals-outer">
|
<div class="modals-outer">
|
||||||
<div class="modals-inner">
|
<div class="modals-inner">
|
||||||
{% include 'playlist/modal/add.jinja.html' %}
|
{% include 'playlist/modal/add.jinja.html' %}
|
||||||
{% include 'playlist/modal/qrcode.jinja.html' %}
|
{% include 'playlist/modal/cast-scan.jinja.html' %}
|
||||||
|
|
||||||
{% with is_notification=True %}{% include 'slideshow/slides/modal/edit.jinja.html' %}{% endwith %}
|
{% with is_notification=True %}{% include 'slideshow/slides/modal/edit.jinja.html' %}{% endwith %}
|
||||||
{% with is_notification=False %}{% include 'slideshow/slides/modal/edit.jinja.html' %}{% endwith %}
|
{% with is_notification=False %}{% include 'slideshow/slides/modal/edit.jinja.html' %}{% endwith %}
|
||||||
|
|||||||
25
views/playlist/modal/cast-scan.jinja.html
Normal file
25
views/playlist/modal/cast-scan.jinja.html
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<div class="modal modal-playlist-cast-scan modal-playlist">
|
||||||
|
<h2>
|
||||||
|
Cast
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<i class="fa fa-warning"></i>
|
||||||
|
|
||||||
|
{{ l.playlist_cast_warning|replace('%href%', url_for('settings_variable_list', highlight='external_url'))|safe }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="loading" data-loading="{{ l.common_loading }}" data-casting="{{ l.common_casting }}">
|
||||||
|
{{ l.common_loading }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="cast-devices">
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="actions actions-right">
|
||||||
|
<button type="button" class="btn btn-naked modal-close">
|
||||||
|
<i class="fa fa-close icon-left"></i>{{ l.common_close }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -1,13 +0,0 @@
|
|||||||
<div class="modal modal-playlist-qrcode modal-playlist">
|
|
||||||
<h2>
|
|
||||||
{{ l.playlist_form_show_qrcode }}
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<div id="qrcode" class="qrcode-pic"></div>
|
|
||||||
|
|
||||||
<div class="actions actions-center">
|
|
||||||
<button type="button" class="btn btn-naked modal-close">
|
|
||||||
<i class="fa fa-close icon-left"></i>{{ l.common_close }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
Loading…
Reference in New Issue
Block a user