Files
lan-play/web/index.html
T
Ultradesu eb0d4fb1c5
Build and Publish / Build and Publish Docker Image (push) Successful in 10m8s
Init
2026-08-05 12:32:52 +01:00

102 lines
6.6 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Lan Play</title>
<link rel="stylesheet" href="/bootstrap-icons.min.css">
<link rel="stylesheet" href="/controlbar.css?v=14">
<link rel="stylesheet" href="/styles.css?v=20">
<script defer src="/dash.all.min.js"></script>
<script defer src="/controlbar.min.js?v=16"></script>
<script defer src="/js/api.js?v=20"></script>
<script defer src="/js/location.js?v=14"></script>
<script defer src="/js/preferences.js?v=15"></script>
<script defer src="/js/player.js?v=17"></script>
<script defer src="/js/library.js?v=20"></script>
<script defer src="/alpine.min.js"></script>
</head>
<body x-data="library" x-init="restoreLocation()" :class="{ 'player-open': selected }" @keydown.escape.window="infoOpen ? closeInfo() : closePlayer()" x-cloak>
<header>
<div><h1>Lan Play</h1><div class="path" x-text="currentPath || '/' "></div></div>
<div class="view-switch" role="group" aria-label="Library view">
<button type="button" title="Grid view" @click="setViewMode('grid')" :class="{ active: viewMode === 'grid' }"><i class="bi bi-grid-fill"></i></button>
<button type="button" title="Table view" @click="setViewMode('table')" :class="{ active: viewMode === 'table' }"><i class="bi bi-list-ul"></i></button>
<button type="button" title="System information" @click="openInfo()"><i class="bi bi-info-circle"></i></button>
</div>
</header>
<main>
<p x-show="loading">Loading…</p>
<p class="error" x-show="error" x-text="error"></p>
<div class="entries" x-show="viewMode === 'grid'">
<button type="button" class="directory" x-show="parentPath !== null" @click="browse(parentPath)"><span class="entry-preview">📁</span><span class="entry-name">..</span></button>
<template x-for="entry in entries" :key="entry.path">
<button type="button" @click="openEntry(entry)" :class="entry.kind"
@mouseenter="startPreview(entry)" @mouseleave="stopPreview(entry)"
@focus="startPreview(entry)" @blur="stopPreview(entry)">
<span class="entry-preview" :class="{ 'entry-preview-media': entry.kind === 'media' }" :style="previewStyle(entry)">
<i class="bi bi-arrow-repeat preview-spinner" x-show="entry.kind === 'media' && previewStates[entry.path] === 'loading'"></i>
<span x-show="entry.kind === 'directory' || previewStates[entry.path] !== 'ready'" x-text="entry.kind === 'directory' ? '📁' : (previewStates[entry.path] === 'error' ? '!' : '')"></span>
</span>
<span class="entry-name"><span class="entry-name-track" x-text="entry.name"></span></span>
</button>
</template>
</div>
<div class="entry-table-wrap" x-show="viewMode === 'table'">
<table class="entry-table">
<thead><tr><th>Preview</th><th>Name</th><th>Type</th></tr></thead>
<tbody>
<tr x-show="parentPath !== null" @click="browse(parentPath)" tabindex="0" @keydown.enter="browse(parentPath)"><td class="table-preview">📁</td><td>..</td><td>Folder</td></tr>
<template x-for="entry in entries" :key="entry.path">
<tr @click="openEntry(entry)" tabindex="0" @keydown.enter="openEntry(entry)"
@mouseenter="startPreview(entry)" @mouseleave="stopPreview(entry)"
@focus="startPreview(entry)" @blur="stopPreview(entry)">
<td><span class="table-preview" :class="{ 'entry-preview-media': entry.kind === 'media' }" :style="previewStyle(entry)">
<i class="bi bi-arrow-repeat preview-spinner" x-show="entry.kind === 'media' && previewStates[entry.path] === 'loading'"></i>
<span x-show="entry.kind === 'directory' || previewStates[entry.path] === 'error'" x-text="entry.kind === 'directory' ? '📁' : '!'"></span>
</span></td>
<td><span class="entry-name table-name"><span class="entry-name-track" x-text="entry.name"></span></span></td>
<td x-text="entry.kind === 'directory' ? 'Folder' : 'Video'"></td>
</tr>
</template>
</tbody>
</table>
</div>
</main>
<div class="info-backdrop" x-show="infoOpen" @click.self="closeInfo()" x-cloak>
<section class="info-dialog" role="dialog" aria-modal="true" aria-labelledby="info-title">
<button class="info-close" type="button" title="Close" aria-label="Close" @click="closeInfo()"><i class="bi bi-x-lg"></i></button>
<h2 id="info-title">System information</h2>
<div class="info-loading" x-show="infoLoading"><i class="bi bi-arrow-repeat preview-spinner"></i> Loading diagnostics…</div>
<p class="error" x-show="infoError" x-text="infoError"></p>
<dl class="info-grid" x-show="diagnostics && !infoLoading">
<dt>Application</dt><dd x-text="`${diagnostics.application} ${diagnostics.version} (${diagnostics.build})`"></dd>
<dt>Interface</dt><dd x-text="`UI ${diagnostics.interface}`"></dd>
<dt>dash.js</dt><dd x-text="diagnostics.dashjs"></dd>
<dt>Platform</dt><dd x-text="diagnostics.platform"></dd>
<dt>Display</dt><dd x-text="diagnostics.display"></dd>
<dt>FFmpeg</dt><dd><span x-text="diagnostics.ffmpeg.version"></span><small x-text="diagnostics.ffmpeg.path"></small></dd>
<dt>FFprobe</dt><dd><span x-text="diagnostics.ffprobe.version"></span><small x-text="diagnostics.ffprobe.path"></small></dd>
<dt>Media root</dt><dd x-text="diagnostics.media_root"></dd>
<dt>Listen address</dt><dd x-text="diagnostics.bind"></dd>
<dt>Browser APIs</dt><dd x-text="`MSE ${diagnostics.mediaSource ? 'yes' : 'no'} · Fullscreen ${diagnostics.fullscreen ? 'yes' : 'no'}`"></dd>
<dt>Browser</dt><dd class="info-browser" x-text="diagnostics.browser"></dd>
</dl>
</section>
</div>
<section class="player" x-ref="playerShell" x-show="selected" x-cloak>
<button class="player-close" type="button" aria-label="Close player" title="Close" @click="closePlayer()">
<i class="bi bi-x-lg" aria-hidden="true"></i>
</button>
<div class="video-wrapper" x-ref="videoWrapper">
<video x-ref="video" playsinline preload="metadata"></video>
<div class="player-title" x-text="mediaTitle()"></div>
<div class="player-status" :class="{ 'player-status-compact': playerLoadingCompact }" x-show="playerLoading" role="status">
<i class="bi bi-arrow-repeat player-spinner" aria-hidden="true"></i>
<span x-text="playerLoadingCompact ? 'Preparing stream at the new position…' : 'Preparing DASH stream…'"></span>
</div>
</div>
</section>
</body>
</html>