preview player & content edit preview ok

This commit is contained in:
jr-k 2024-07-10 22:30:20 +02:00
parent a142def001
commit bd4f97335d
10 changed files with 172 additions and 95 deletions

File diff suppressed because one or more lines are too long

View File

@ -164,5 +164,13 @@ form {
button {
margin-left: 25px;
}
&.actions-left {
justify-content: flex-start;
button {
margin-left: 0;
}
}
}
}

View File

@ -14,8 +14,55 @@
margin: 20px 20px 20px 10px;
}
}
.page-panel.right-panel {
flex: 1;
align-self: stretch;
display: flex;
flex-direction: column;
overflow: hidden;
justify-content: flex-start;
align-items: center;
padding: 20px;
h3 {
color: white;
padding: 10px;
margin-bottom: 20px;
font-size: 16px;
span {
border-width: 1px;
border-style: solid;
border-radius: 2px;
padding: 4px 10px;
margin-left: 5px;
}
i {
font-size: 16px;
}
}
.iframe-wrapper {
display: flex;
flex-direction: column;
width: 100%;
position: relative;
padding-top: 56.25%; /* 16:9 aspect ratio */
overflow: hidden;
border-radius: $baseRadius;
outline: 4px solid rgba($white, .1);
iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: none;
}
}
}
}
}

View File

@ -32,6 +32,9 @@ $colors: (
danger: $danger,
purple: $sweetPurple,
youtube: $youtube,
neutral: $neutralGrey,
white: $white,
black: $black,
);
// Classes

View File

@ -15,6 +15,78 @@ from src.model.enum.AnimationSpeed import animation_speed_duration
class PlayerController(ObController):
def register(self):
self._app.add_url_rule('/', 'player', self.player, methods=['GET'])
self._app.add_url_rule('/use/<playlist_slug_or_id>', 'player_use', self.player, methods=['GET'])
self._app.add_url_rule('/player/default', 'player_default', self.player_default, methods=['GET'])
self._app.add_url_rule('/player/playlist', 'player_playlist', self.player_playlist, methods=['GET'])
self._app.add_url_rule('/player/playlist/use/<playlist_slug_or_id>', 'player_playlist_use', self.player_playlist, methods=['GET'])
def player(self, playlist_slug_or_id: str = ''):
preview_content_id = request.args.get('preview_content_id')
playlist_slug_or_id = self._get_dynamic_playlist_id(playlist_slug_or_id)
current_playlist = self._model_store.playlist().get_one_by("slug = ? OR id = ?", {
"slug": playlist_slug_or_id,
"id": playlist_slug_or_id
})
if playlist_slug_or_id and not current_playlist:
return abort(404)
playlist_id = current_playlist.id if current_playlist else None
items = self._get_playlist(playlist_id=playlist_id, preview_content_id=preview_content_id)
return render_template(
'player/player.jinja.html',
items=items,
default_slide_duration=0 if items['preview_mode'] else self._model_store.variable().get_one_by_name('default_slide_duration').eval(),
polling_interval=self._model_store.variable().get_one_by_name('polling_interval'),
slide_animation_enabled=self._model_store.variable().get_one_by_name('slide_animation_enabled'),
slide_animation_entrance_effect=self._model_store.variable().get_one_by_name('slide_animation_entrance_effect'),
slide_animation_exit_effect=self._model_store.variable().get_one_by_name('slide_animation_exit_effect'),
slide_animation_speed=self._model_store.variable().get_one_by_name('slide_animation_speed'),
animation_speed_duration=animation_speed_duration
)
def player_default(self):
return render_template(
'player/default.jinja.html',
ipaddr=get_ip_address(),
time_with_seconds=self._model_store.variable().get_one_by_name('default_slide_time_with_seconds')
)
def player_playlist(self, playlist_slug_or_id: str = ''):
playlist_slug_or_id = self._get_dynamic_playlist_id(playlist_slug_or_id)
current_playlist = self._model_store.playlist().get_one_by("slug = ? OR id = ?", {
"slug": playlist_slug_or_id,
"id": playlist_slug_or_id
})
playlist_id = current_playlist.id if current_playlist else None
return jsonify(self._get_playlist(playlist_id=playlist_id))
def _get_dynamic_playlist_id(self, playlist_slug_or_id: Optional[str]) -> str:
if not playlist_slug_or_id and self._model_store.variable().get_one_by_name('fleet_player_enabled'):
node_player = self._model_store.node_player().get_one_by("host = '{}' and enabled = {}".format(
get_safe_remote_addr(self.get_remote_addr()),
True
))
if node_player and node_player.group_id:
node_player_group = self._model_store.node_player_group().get(node_player.group_id)
playlist_slug_or_id = node_player_group.playlist_id
return playlist_slug_or_id
@staticmethod
def get_remote_addr() -> str:
if request.headers.get('X-Forwarded-For'):
return request.headers['X-Forwarded-For'].split(',')[0].strip()
else:
return request.remote_addr
def _get_playlist(self, playlist_id: Optional[int] = 0, preview_content_id: Optional[int] = None) -> dict:
enabled_slides = []
preview_mode = False
@ -83,73 +155,3 @@ class PlayerController(ObController):
}
return playlists
def register(self):
self._app.add_url_rule('/', 'player', self.player, methods=['GET'])
self._app.add_url_rule('/use/<playlist_slug_or_id>', 'player_use', self.player, methods=['GET'])
self._app.add_url_rule('/player/default', 'player_default', self.player_default, methods=['GET'])
self._app.add_url_rule('/player/playlist', 'player_playlist', self.player_playlist, methods=['GET'])
self._app.add_url_rule('/player/playlist/use/<playlist_slug_or_id>', 'player_playlist_use', self.player_playlist, methods=['GET'])
def player(self, playlist_slug_or_id: str = ''):
preview_content_id = request.args.get('preview_content_id')
playlist_slug_or_id = self._get_dynamic_playlist_id(playlist_slug_or_id)
current_playlist = self._model_store.playlist().get_one_by("slug = ? OR id = ?", {
"slug": playlist_slug_or_id,
"id": playlist_slug_or_id
})
if playlist_slug_or_id and not current_playlist:
return abort(404)
playlist_id = current_playlist.id if current_playlist else None
return render_template(
'player/player.jinja.html',
items=json.dumps(self._get_playlist(playlist_id=playlist_id, preview_content_id=preview_content_id)),
default_slide_duration=self._model_store.variable().get_one_by_name('default_slide_duration'),
polling_interval=self._model_store.variable().get_one_by_name('polling_interval'),
slide_animation_enabled=self._model_store.variable().get_one_by_name('slide_animation_enabled'),
slide_animation_entrance_effect=self._model_store.variable().get_one_by_name('slide_animation_entrance_effect'),
slide_animation_exit_effect=self._model_store.variable().get_one_by_name('slide_animation_exit_effect'),
slide_animation_speed=self._model_store.variable().get_one_by_name('slide_animation_speed'),
animation_speed_duration=animation_speed_duration
)
def player_default(self):
return render_template(
'player/default.jinja.html',
ipaddr=get_ip_address(),
time_with_seconds=self._model_store.variable().get_one_by_name('default_slide_time_with_seconds')
)
def player_playlist(self, playlist_slug_or_id: str = ''):
playlist_slug_or_id = self._get_dynamic_playlist_id(playlist_slug_or_id)
current_playlist = self._model_store.playlist().get_one_by("slug = ? OR id = ?", {
"slug": playlist_slug_or_id,
"id": playlist_slug_or_id
})
playlist_id = current_playlist.id if current_playlist else None
return jsonify(self._get_playlist(playlist_id=playlist_id))
def _get_dynamic_playlist_id(self, playlist_slug_or_id: Optional[str]) -> str:
if not playlist_slug_or_id and self._model_store.variable().get_one_by_name('fleet_player_enabled'):
node_player = self._model_store.node_player().get_one_by("host = '{}' and enabled = {}".format(
get_safe_remote_addr(self.get_remote_addr()),
True
))
if node_player and node_player.group_id:
node_player_group = self._model_store.node_player_group().get(node_player.group_id)
playlist_slug_or_id = node_player_group.playlist_id
return playlist_slug_or_id
@staticmethod
def get_remote_addr() -> str:
if request.headers.get('X-Forwarded-For'):
return request.headers['X-Forwarded-For'].split(',')[0].strip()
else:
return request.remote_addr

View File

@ -136,6 +136,9 @@ class ContentManager(ModelManager):
if content.type == ContentType.YOUTUBE:
form['location'] = get_yt_video_id(form['location'])
elif content.type == ContentType.URL:
if not form['location'].startswith('http'):
form['location'] = "https://{}".format(form['location'])
self._db.update_by_id(self.TABLE_NAME, id, self.pre_update(form))
self.post_update(id)

View File

@ -44,3 +44,16 @@ class ContentType(Enum):
return 'fa-link'
return 'fa-file'
@staticmethod
def get_color_icon(value: Enum) -> ContentInputType:
if value == ContentType.PICTURE:
return 'info'
elif value == ContentType.VIDEO:
return 'success'
elif value == ContentType.YOUTUBE:
return 'youtube'
elif value == ContentType.URL:
return 'danger'
return 'neutral'

View File

@ -20,7 +20,7 @@
</head>
<body>
<div id="IntroSlide" class="slide" style="z-index: 10000;">
{% if default_slide_duration.eval() > 0 and not items['preview_mode'] %}
{% if default_slide_duration > 0 %}
<iframe src="/player/default"></iframe>
{% endif %}
</div>
@ -36,8 +36,8 @@
<script type="text/javascript">
// Backend config
let items = {{items | safe}};
const introDuration = {{ default_slide_duration.eval() * 1000 }};
let items = {{ json_dumps(items) | safe}};
const introDuration = {{ default_slide_duration * 1000 }};
const playlistCheckResolutionMs = {{ polling_interval.eval() * 1000 }};
// Backend flag updates
@ -59,7 +59,7 @@
let pauseClockValue = null;
// Animations
const animate = {{ 'true' if slide_animation_enabled.eval() else 'false' }};
const animate = {{ 'true' if slide_animation_enabled.eval() and not items.preview_mode else 'false' }};
const animate_speed = "animate__{{ slide_animation_speed.eval()|default("normal") }}";
const animation_speed_duration = {{ animation_speed_duration[slide_animation_speed.eval()] if slide_animation_enabled.eval() else 0 }};
const animate_transitions = [
@ -83,6 +83,10 @@
// Functions
const itemCheck = setInterval(function() {
if (items['preview_mode']) {
return;
}
fetch('/player/playlist' + (items['playlist_id'] ? '/use/'+items['playlist_id'] : '')).then(function(response) {
if (response.ok) {
return response.json();

View File

@ -78,24 +78,31 @@
</div>
</div>
<button type="submit" class="folder-edit btn-info">
<i class="fa fa-save icon-left"></i>
{{ l.common_save }}
</button>
<div class="actions actions-left">
<button type="submit" class="folder-edit btn-info">
<i class="fa fa-save icon-left"></i>
{{ l.common_save }}
</button>
</div>
</form>
</div>
<div class="preview-holder">
Hi
</div>
</div>
</div>
</div>
<div class="page-panel right-panel">
{% set icon = enum_content_type.get_fa_icon(content.type) %}
{% set color = enum_content_type.get_color_icon(content.type) %}
<h3>
<span class="{{ color }} border-{{ color }}">
<i class="fa {{ icon }} {{ color }}"></i> {{ t(content.type) }}
</span>
</h3>
<div class="iframe-wrapper">
<iframe src="{{ url_for('player', preview_content_id=content.id) }}"></iframe>
</div>
</div>
</div>

View File

@ -177,17 +177,7 @@
{% for content in contents[working_folder.id|default(None)]|default([]) %}
{% set icon = enum_content_type.get_fa_icon(content.type) %}
{% if content.type.value == 'picture' %}
{% set icon = icon ~ ' info' %}
{% elif content.type.value == 'video' %}
{% set icon = icon ~ ' success' %}
{% elif content.type.value == 'url' %}
{% set icon = icon ~ ' danger' %}
{% elif content.type.value == 'youtube' %}
{% set icon = icon ~ ' youtube' %}
{% endif %}
{% set icon = enum_content_type.get_fa_icon(content.type) ~ ' ' ~ enum_content_type.get_color_icon(content.type) %}
<li class="draggable" data-path="{{ working_folder_path }}" data-id="{{ content.id }}" data-folder="0">
<a href="{{ url_for('slideshow_content_show', content_id=content.id) }}" target="_blank" class="explr-link explr-item-selectable">