Parent directory

new_videos.templ

4978 bytes
  1package pages
  2
  3import (
  4	"fmt"
  5
  6	"github.com/TheEdgeOfRage/ytrssil-api/models"
  7)
  8
  9templ ProgressBar(video models.Video) {
 10	if video.ProgressSeconds > 0 {
 11		<div id={ fmt.Sprintf("progress-%s", video.ID) } class="progress" role="progressbar" style="height: 6px">
 12			<div class="progress-bar" style={ fmt.Sprintf("background: #b11; width: %d%%", video.ProgressPercentage()) }></div>
 13		</div>
 14	} else {
 15		<div id={ fmt.Sprintf("progress-%s", video.ID) } style="height: 6px"></div>
 16	}
 17}
 18
 19templ thumbnail(video models.Video) {
 20	<a
 21		target="_blank"
 22		rel="noopener"
 23		data-open-in-safari
 24		href={ templ.SafeURL(video.WatchURL()) }
 25		style="display: block; overflow: hidden; position: relative"
 26		if video.IsShort {
 27			class="pillarbox"
 28		}
 29	>
 30		if video.IsShort {
 31			<img
 32				src={ fmt.Sprintf("https://img.youtube.com/vi/%s/0.jpg", video.ID) }
 33				class="card-img-top"
 34				alt={ video.Title }
 35				style="width: 100%; aspect-ratio: 16/9; object-fit: contain;"
 36			/>
 37			<svg
 38				xmlns="http://www.w3.org/2000/svg"
 39				height="24"
 40				viewBox="0 0 24 24"
 41				width="24"
 42				focusable="false"
 43				style="pointer-events: none; width: 2rem; height: 2rem; z-index: 2; position: absolute; bottom: 0.5rem; left: 0.5rem;"
 44				fill="white"
 45			><path d="m13.974 2.052-8 4.7a4 4 0 00.385 7.097l.942.423-1.327.78a4 4 0 004.052 6.897l8-4.7a4.001 4.001 0 00-.384-7.096L16.7 9.73l1.326-.78a4 4 0 10-4.052-6.897ZM10 15V9l5 3-5 3Z"></path></svg>
 46		} else {
 47			<img
 48				src={ fmt.Sprintf("https://img.youtube.com/vi/%s/0.jpg", video.ID) }
 49				class="card-img-top"
 50				alt={ video.Title }
 51				style="width: 100%; aspect-ratio: 16/9; object-fit: cover;"
 52			/>
 53		}
 54		if video.IsLive {
 55			<span
 56				focusable="false"
 57				class="text-white bg-danger px-1 py-1 rounded fw-bold"
 58				style="pointer-events: none; z-index: 2; position: absolute; bottom: 0.2rem; right: 0.2rem;"
 59			>
 60				LIVE
 61			</span>
 62		} else {
 63			<span
 64				focusable="false"
 65				class="text-body bg-body bg-opacity-75 px-1 py-1 rounded"
 66				style="pointer-events: none; z-index: 2; position: absolute; bottom: 0.2rem; right: 0.2rem;"
 67			>
 68				{ video.Duration() }
 69			</span>
 70		}
 71	</a>
 72	@ProgressBar(video)
 73}
 74
 75templ VideoCard(video models.Video) {
 76	<div id={ fmt.Sprintf("video-card-%s", video.ID) } class="video-card col-md-3 p-2" data-title={ video.Title } data-channel-name={ video.ChannelName }>
 77		<div class="card">
 78			@thumbnail(video)
 79			<div class="card-body">
 80				<p class="card-title text-truncate mb-0">{ video.Title }</p>
 81				<p class="d-flex justify-content-between">
 82					<a
 83						target="_blank"
 84						rel="noopener"
 85						data-open-in-safari
 86						href={ fmt.Sprintf("https://www.youtube.com/channel/%s", video.ChannelID) }
 87						class="card-text fw-light link-light link-underline-opacity-0"
 88					>{ video.ChannelName }</a>
 89					<span>
 90						{ video.HumanizedPublishTime() }
 91					</span>
 92				</p>
 93				<div class="d-flex justify-content-between">
 94					<form
 95						data-signals="{progress: ''}"
 96						data-on:submit__prevent={ fmt.Sprintf("$progress = evt.target.querySelector('input').value; @patch('/videos/%s/progress')", video.ID) }
 97						class="d-flex"
 98					>
 99						<input type="text" placeholder="mm:ss/11m22s" class="form-control" style="width: 50%"/>
100						<button type="submit" class="btn btn-primary ms-3"><i class="bi bi-clock"></i></button>
101					</form>
102					<div class="d-flex gap-2">
103						if video.IsDownloaded() {
104							<a
105								href={ templ.SafeURL(fmt.Sprintf("/videos/%s/file", video.ID)) }
106								data-open-in-safari
107								class="btn btn-success"
108							>
109								<i class="bi bi-download"></i>
110							</a>
111						} else if video.IsDownloading() {
112							<button
113								class="btn btn-primary"
114								disabled
115								data-on-interval__duration.2s={ fmt.Sprintf("@get('/videos/%s/card')", video.ID) }
116							>
117								<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
118							</button>
119						} else if video.DownloadFailed() {
120						<button
121							type="button"
122							class="btn btn-danger"
123							title={ fmt.Sprintf("Download failed: %s", *video.DownloadError) }
124							data-video-id={ video.ID }
125							data-video-title={ video.Title }
126							onclick="openResolutionModal(this)"
127						>
128								<i class="bi bi-exclamation-triangle"></i>
129							</button>
130						} else {
131						<button
132							type="button"
133							class="btn btn-outline-primary"
134							data-video-id={ video.ID }
135							data-video-title={ video.Title }
136							onclick="openResolutionModal(this)"
137						>
138								<i class="bi bi-download"></i>
139							</button>
140						}
141						<button
142							data-on:click={ fmt.Sprintf("@patch('/videos/%s/watch')", video.ID) }
143							class="btn btn-danger"
144						>
145							<i class="bi bi-check-circle"></i>
146						</button>
147					</div>
148				</div>
149			</div>
150		</div>
151	</div>
152}
153
154templ NewVideosPage(videos []models.Video) {
155	@BaseLayout("ytrssil - New Videos", "new") {
156		<div class="row">
157			for _, video := range videos {
158				@VideoCard(video)
159			}
160		</div>
161	}
162}