aboutsummaryrefslogtreecommitdiff
path: root/src/routes/+page.svelte
diff options
context:
space:
mode:
Diffstat (limited to 'src/routes/+page.svelte')
-rw-r--r--src/routes/+page.svelte116
1 files changed, 116 insertions, 0 deletions
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
new file mode 100644
index 0000000..5aeed62
--- /dev/null
+++ b/src/routes/+page.svelte
@@ -0,0 +1,116 @@
+<script lang="ts">
+ import { browser } from '$app/environment';
+ import { parseM3U, type Channel } from '$lib/m3u';
+ import { onMount } from 'svelte';
+ import Masonry from 'svelte-bricks';
+
+ let channels: Channel[] = [];
+ let filter = '';
+
+ onMount(
+ async () =>
+ (channels = parseM3U(
+ await (await fetch('https://raw.githubusercontent.com/luongz/iptv-jp/main/jp.m3u')).text()
+ )
+ .filter((channel) => channel.tvgLogo)
+ .map((channel, index) => ({ ...channel, id: index })))
+ );
+</script>
+
+<input type="text" placeholder="Search" bind:value={filter} class="filter" />
+
+<div class="channels">
+ <Masonry
+ items={channels.filter((channel) => channel.tvgId.toLowerCase().includes(filter.toLowerCase()))}
+ minColWidth={(browser ? window.innerWidth < 768 : false) ? 150 : 200}
+ gap={15}
+ let:item
+ >
+ <div class="channel-container">
+ <a href={`https://hlsjs.video-dev.org/demo/?src=${item.url}`} target="_blank">
+ <img src={item.tvgLogo} alt="Channel icon" class="channel-icon" />
+ </a>
+
+ <span class="channel-title">
+ <a
+ href={`https://hlsjs.video-dev.org/demo/?src=${item.url}`}
+ target="_blank"
+ class="channel-title-primary"
+ >
+ {item.tvgId} ({item.groupTitle})
+ </a>
+
+ <br />
+
+ <a
+ href={'#'}
+ on:click={() => {
+ navigator.clipboard.writeText(item.url);
+ }}
+ >
+ Copy M3U8 URL
+ </a>
+ </span>
+ </div>
+ </Masonry>
+</div>
+
+<style>
+ a {
+ text-decoration: none;
+ color: #c6c6c6;
+ transition: color 0.1s ease-in-out;
+ }
+
+ a:hover {
+ color: #2a6496;
+ }
+
+ .channels {
+ padding: 0.5rem;
+ }
+
+ .channel-container {
+ background: #1d1d1d;
+ padding: 1rem;
+ border-radius: 2.5%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ text-align: center;
+ position: relative;
+ }
+
+ .channel-icon {
+ border-radius: 2.5%;
+ max-width: 100%;
+ max-height: 75%;
+ padding-bottom: 1rem;
+ }
+
+ .filter {
+ width: calc(100% - 3rem);
+ padding: 1rem;
+ border-radius: 7px;
+ border: none;
+ margin: 0.5rem;
+ background: #242424;
+ border: none;
+ color: #fff;
+ font-size: 1rem;
+ }
+
+ .filter:focus {
+ outline: none;
+ }
+
+ .channel-title-primary {
+ color: #fff;
+ }
+
+ :global(body) {
+ background-color: #121212;
+ color: #fff;
+ }
+</style>