102 lines
6.6 KiB
HTML
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>
|