Compare commits
No commits in common. "master" and "vanity" have entirely different histories.
658 changed files with 381 additions and 385932 deletions
14
.gitignore
vendored
14
.gitignore
vendored
|
@ -1,6 +1,6 @@
|
|||
# generated types
|
||||
source/.astro
|
||||
source/node_modules
|
||||
web/.astro
|
||||
web/node_modules
|
||||
.minpluto/generated
|
||||
|
||||
# dependencies
|
||||
|
@ -13,16 +13,16 @@ yarn-error.log*
|
|||
pnpm-debug.log*
|
||||
|
||||
# environment variables
|
||||
source/.env
|
||||
source/.env.production
|
||||
web/.env
|
||||
web/.env.production
|
||||
|
||||
# macOS-specific files
|
||||
.DS_Store
|
||||
|
||||
# i18n
|
||||
/source/src/pages/en/
|
||||
/source/src/pages/jp/
|
||||
/source/src/pages/ru/
|
||||
/web/src/pages/en/
|
||||
/web/src/pages/jp/
|
||||
/web/src/pages/ru/
|
||||
|
||||
# other
|
||||
.minpluto/docker/supabase/.env
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
###########
|
||||
# Docker Volumes
|
||||
# All folders provided in `./supabase-volume/` must be included
|
||||
###########
|
||||
SUPABASE_ENTIRE_VOLUME="./supabase-volume/"
|
||||
|
||||
############
|
||||
# Secrets
|
||||
# YOU MUST CHANGE THESE BEFORE GOING INTO PRODUCTION
|
||||
############
|
||||
|
||||
POSTGRES_PASSWORD=5lgHamV44d8D1GN9LRS6b44VxREi4692
|
||||
JWT_SECRET=paxDX2xE00qFa4I1r6PKe15nIkB089I4
|
||||
ANON_KEY=9X43H6LKq3115zmZhZj95f2IJ104a603
|
||||
SERVICE_ROLE_KEY=K2G792rYBZR0kZvw9Zp6182zAwzxsdas
|
||||
DASHBOARD_USERNAME=mp_admin
|
||||
DASHBOARD_PASSWORD=ez116oqVWd4wHZUQNbgW3fA0m958FN09
|
||||
|
||||
############
|
||||
# Database - You can change these to any PostgreSQL database that has logical replication enabled.
|
||||
############
|
||||
|
||||
# default user is postgres
|
||||
POSTGRES_HOST=db
|
||||
POSTGRES_DB=postgres
|
||||
POSTGRES_PORT=1945
|
||||
|
||||
############
|
||||
# API Proxy - Configuration for the Kong Reverse proxy.
|
||||
############
|
||||
|
||||
KONG_HTTP_PORT=1942
|
||||
KONG_HTTPS_PORT=1943
|
||||
|
||||
############
|
||||
# API - Configuration for PostgREST.
|
||||
############
|
||||
|
||||
PGRST_DB_SCHEMAS=public,storage,graphql_public
|
||||
|
||||
############
|
||||
# Auth - Configuration for the GoTrue authentication server.
|
||||
############
|
||||
|
||||
## General
|
||||
SITE_URL=http://localhost:1930
|
||||
ADDITIONAL_REDIRECT_URLS=
|
||||
JWT_EXPIRY=3600
|
||||
DISABLE_SIGNUP=false
|
||||
API_EXTERNAL_URL=https://db.minpluto.org
|
||||
|
||||
## Mailer Config
|
||||
MAILER_URLPATHS_CONFIRMATION="/auth/v1/verify"
|
||||
MAILER_URLPATHS_INVITE="/auth/v1/verify"
|
||||
MAILER_URLPATHS_RECOVERY="/auth/v1/verify"
|
||||
MAILER_URLPATHS_EMAIL_CHANGE="/auth/v1/verify"
|
||||
|
||||
## Email auth
|
||||
ENABLE_EMAIL_SIGNUP=true
|
||||
ENABLE_EMAIL_AUTOCONFIRM=false
|
||||
SMTP_ADMIN_EMAIL=no-reply@sudovanilla.org
|
||||
SMTP_HOST=smtp.resend.com
|
||||
SMTP_PORT=587
|
||||
SMTP_USER=resend
|
||||
SMTP_PASS=re_XLbiDxHd_9Yucx4y9EwiacKgHrRowfJVU
|
||||
SMTP_SENDER_NAME=MinPluto
|
||||
ENABLE_ANONYMOUS_USERS=true
|
||||
|
||||
## Phone auth
|
||||
ENABLE_PHONE_SIGNUP=false
|
||||
ENABLE_PHONE_AUTOCONFIRM=false
|
||||
|
||||
############
|
||||
# Studio - Configuration for the Dashboard
|
||||
############
|
||||
|
||||
STUDIO_DEFAULT_ORGANIZATION=Default Organization
|
||||
STUDIO_DEFAULT_PROJECT=Default Project
|
||||
|
||||
STUDIO_PORT=1944
|
||||
SUPABASE_PUBLIC_URL=http://localhost:8000
|
||||
|
||||
# Enable webp support
|
||||
IMGPROXY_ENABLE_WEBP_DETECTION=true
|
||||
|
||||
############
|
||||
# Functions - Configuration for Functions
|
||||
############
|
||||
# NOTE: VERIFY_JWT applies to all functions. Per-function VERIFY_JWT is not supported yet.
|
||||
FUNCTIONS_VERIFY_JWT=false
|
||||
|
||||
############
|
||||
# Logs - Configuration for Logflare
|
||||
# Please refer to https://supabase.com/docs/reference/self-hosting-analytics/introduction
|
||||
############
|
||||
|
||||
LOGFLARE_LOGGER_BACKEND_API_KEY=your-super-secret-and-long-logflare-key
|
||||
|
||||
# Change vector.toml sinks to reflect this change
|
||||
LOGFLARE_API_KEY=your-super-secret-and-long-logflare-key
|
||||
|
||||
# Docker socket location - this value will differ depending on your OS
|
||||
DOCKER_SOCKET_LOCATION=/var/run/docker.sock
|
||||
|
||||
# Google Cloud Project details
|
||||
GOOGLE_PROJECT_ID=GOOGLE_PROJECT_ID
|
||||
GOOGLE_PROJECT_NUMBER=GOOGLE_PROJECT_NUMBER
|
|
@ -50,6 +50,7 @@ Cloudflare Pages | 🔘 | 🔘 |
|
|||
| Mullvad | ✅ | ❌ | ✅ | ✅ | 🔘 | 🔘 |
|
||||
| Tor | 🔘 | 🔘 | 🔘 | 🔘 | 🔘 | 🔘 |
|
||||
| Waterfox | ✅ | ✅ | ✅ | ✅ | 🔘 | 🔘 |
|
||||
| Zen | ✅ | ✅ | ✅ | ✅ | 🔘 | 🔘 |
|
||||
| **Outdated Browsers**|
|
||||
| Internet Explorer | ❌ | ✅ | ❌ | ✅ | 🔘 | 🔘 |
|
||||
|
||||
|
|
|
@ -1,41 +1,35 @@
|
|||
## To Do
|
||||
- [ ] i18n
|
||||
- [x] API
|
||||
- [ ] API
|
||||
- [ ] Languages
|
||||
- [x] English
|
||||
- [ ] English
|
||||
- [ ] Japanese
|
||||
- [ ] French
|
||||
- [ ] Spanish
|
||||
- [ ] Russian
|
||||
- [x] Data
|
||||
- [x] Track Events (Users should be opted-out by default, OpenPanel will be used)
|
||||
- [x] Make privacy policy adaptive
|
||||
- [x] Mobile Support
|
||||
- [ ] Server Configuration (.env)
|
||||
- [ ] Quality
|
||||
- [ ] Allow 1080p
|
||||
- [ ] Allow 4K
|
||||
- [ ] Allow 8K
|
||||
- [ ] Account System (Based on [Account System Demo](https://ark.sudovanilla.org/MinPluto/Account-System-Demo))
|
||||
- [x] Use Supabase Library
|
||||
- [ ] Data
|
||||
- [ ] Track Events
|
||||
- [ ] Make privacy policy adaptive
|
||||
- [ ] Account System
|
||||
- [ ] Use Supabase Library
|
||||
- [ ] Create Pages:
|
||||
- [ ] Subscription Feed
|
||||
- [ ] History (Maybe, maybe not)
|
||||
- [x] Login
|
||||
- [x] Register
|
||||
- [x] Account
|
||||
- [ ] History
|
||||
- [ ] Login
|
||||
- [ ] Register
|
||||
- [ ] Account
|
||||
- [ ] Preferences
|
||||
- [ ] Delete
|
||||
- [ ] Anomymous Account Creation
|
||||
- [x] Email Confirmation Code
|
||||
- [ ] Email Confirmation Code
|
||||
- [ ] Ability to:
|
||||
- [ ] Update Data
|
||||
- [x] Username
|
||||
- [ ] Username
|
||||
- [ ] Email
|
||||
- [ ] Pasword
|
||||
- [ ] Delete Account
|
||||
- [ ] API
|
||||
- [x] `/api/update/name`
|
||||
- [ ] `/api/update/name`
|
||||
- [ ] `/api/update/email`
|
||||
- [ ] `/api/update/password`
|
||||
- [ ] `/api/update/preference/ui/theme`
|
||||
|
@ -48,17 +42,17 @@
|
|||
- [ ] `/api/update/preference/instance/invidious/data`
|
||||
- [ ] `/api/update/preference/instance/safetwitch/media`
|
||||
- [ ] `/api/update/preference/instance/safetwitch/data`
|
||||
- [x] `/api/auth/login`
|
||||
- [x] `/api/auth/register`
|
||||
- [ ] `/api/auth/login`
|
||||
- [ ] `/api/auth/register`
|
||||
- [ ] `/api/auth/delete`
|
||||
- [x] `/api/auth/confirm`
|
||||
- [x] `/api/auth/logout`
|
||||
- [ ] `/api/auth/confirm`
|
||||
- [ ] `/api/auth/logout`
|
||||
- [ ] `/api/anon/create`
|
||||
- [ ] `/api/anon/delete`
|
||||
- [ ] `/api/anon/signout`
|
||||
- [ ] `/api/subscription/add`
|
||||
- [ ] `/api/subscription/remove`
|
||||
- [ ] Revamp Design and Layout ([UI Library Repo](https://ark.sudovanilla.org/MinPluto/UI-Library/))
|
||||
- [ ] Revamp Design and Layout
|
||||
- [ ] Use Header over Sidebar
|
||||
- [ ] Generic
|
||||
- [ ] Dropdown
|
||||
|
@ -68,7 +62,7 @@
|
|||
- [ ] Radio Buttons
|
||||
- [ ] Toast
|
||||
- [ ] Tooltip
|
||||
- [ ] Hovercard (For Creators) [Example](https://www.radix-vue.com/components/hover-card)
|
||||
- [ ] Hovercard (For Creators)
|
||||
- [ ] Scrollable Areas
|
||||
- [ ] KBD
|
||||
- [ ] Empty State
|
||||
|
@ -91,24 +85,24 @@
|
|||
- [ ] Discovery Pages
|
||||
- [ ] Animation
|
||||
- [ ] Automotive
|
||||
- [x] Comedy
|
||||
- [ ] Comedy
|
||||
- [ ] Courses
|
||||
- [ ] Educational
|
||||
- [ ] Family Friendly
|
||||
- [ ] Fashion
|
||||
- [ ] Fitness
|
||||
- [ ] Food
|
||||
- [x] Games
|
||||
- [ ] Games
|
||||
- [ ] Music
|
||||
- [ ] News
|
||||
- [ ] Podcasts
|
||||
- [ ] Science
|
||||
- [ ] Sports
|
||||
- [x] Tech
|
||||
- [ ] Tech
|
||||
- [ ] Web Series
|
||||
- [ ] Twitch Support
|
||||
- [x] API
|
||||
- [x] Video Player HLS Support (Required to play streams)
|
||||
- [ ] API
|
||||
- [ ] Video Player HLS Support
|
||||
- [ ] Polycentric Chat
|
||||
- [ ] Categories
|
||||
- [ ] Games
|
||||
|
@ -128,12 +122,12 @@
|
|||
- [ ] Search
|
||||
- [ ] Revamp Experience
|
||||
- [ ] Filters
|
||||
- [x] Auto Complete
|
||||
- [ ] Auto Complete
|
||||
- [ ] Video Player
|
||||
- [x] Dash Format (1080p/4K/8K)
|
||||
- [ ] Dash Format
|
||||
- [ ] 360° Support
|
||||
- [ ] Mobile Gestures
|
||||
- [x] Embed Page
|
||||
- [ ] Embed Page
|
||||
- [ ] Download
|
||||
- [ ] Share
|
||||
- [ ] Report
|
||||
|
@ -146,8 +140,6 @@
|
|||
- [ ] Theater Mode
|
||||
- [ ] Cast
|
||||
- [ ] Video Page
|
||||
- [ ] ~~Important Infomation Card ([Example](https://img.sudovanilla.org/pXqzT10.png))~~ Controversial, do not proceed
|
||||
- [ ] Viewers Note (Like Community Notes, in [experimental phase at YouTube](https://blog.youtube/news-and-events/new-ways-to-offer-viewers-more-context/))
|
||||
- [ ] Toggle:
|
||||
- [ ] Audio Only
|
||||
- [ ] Autoplay
|
||||
|
@ -168,4 +160,14 @@
|
|||
- [ ] Import/Export MinPluto User Settings
|
||||
- [ ] Feed Page
|
||||
- [ ] Universal Feed (YouTube and Twitch)
|
||||
- [ ] Subscription Management
|
||||
- [ ] Subscription Management
|
||||
- [ ] Frontend Support (Replace official links to frontend alternatives)
|
||||
- [ ] YouTube (Just use current instance)
|
||||
- [ ] Twitch (Just use current instance)
|
||||
- [ ] X
|
||||
- [ ] Reddit
|
||||
- [ ] Medium
|
||||
- [ ] Quora
|
||||
- [ ] StackOverflow
|
||||
- [ ] Wikipedia
|
||||
- [ ] Imgur
|
10
README.md
10
README.md
|
@ -6,14 +6,14 @@ MinPluto is a modern privacy frontend for YouTube and Twitch giving your persona
|
|||
___
|
||||
|
||||
## Docs
|
||||
- [FAQ](/.minpluto/docs/FAQ.md)
|
||||
- [API](/.minpluto/docs/API.md)
|
||||
- [Requirements](/.minpluto/docs/Requirements.md)
|
||||
- [Compatibility](/.minpluto/docs/Compatibility.md)
|
||||
- [FAQ](./.minpluto/docs/FAQ.md)
|
||||
- [API](./.minpluto/docs/API.md)
|
||||
- [Requirements](./.minpluto/docs/Requirements.md)
|
||||
- [Compatibility](./.minpluto/docs/Compatibility.md)
|
||||
- Develop, Build, Run
|
||||
- Selfhosting
|
||||
- Player
|
||||
|
||||
___
|
||||
|
||||
MinPluto is inspired by [Poke](https://poketube.fun/), Poke is a project by [Ashley](https://codeberg.org/ashley).
|
||||
MinPluto is inspired by [Poke](https://poketube.fun/), a project by [Ashley](https://codeberg.org/ashley).
|
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
3
bunfig.toml
Normal file
3
bunfig.toml
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Flurry and Zorn are on SudoVanilla Packages
|
||||
[install]
|
||||
registry = "https://npm.sudovanilla.org"
|
47
package.json
47
package.json
|
@ -1,12 +1,13 @@
|
|||
{
|
||||
"name": "minpluto",
|
||||
"version": "24.10.30",
|
||||
"version": "24.09.07",
|
||||
"description": "An open source frontend alternative to YouTube and Twitch.",
|
||||
"repository": "https://ark.sudovanilla.org/MinPluto/MinPluto",
|
||||
"author": "Korbs",
|
||||
"author": "Korbs <korbs@sudovanilla.org>",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"bugs": {
|
||||
"url": "https://ark.sudovanilla.org/MinPluto/MinPluto/issues"
|
||||
"url": "https://ark.sudovanilla.org/MinPluto/MinPluto/issues",
|
||||
"email": "support@minpluto.org"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -17,38 +18,32 @@
|
|||
"keywords": [
|
||||
"privacy",
|
||||
"frontend",
|
||||
"proxy",
|
||||
"downloader",
|
||||
"ytdl",
|
||||
"invidious",
|
||||
"safetwitch",
|
||||
"youtube",
|
||||
"twitch",
|
||||
"live",
|
||||
"stream"
|
||||
"astro",
|
||||
"proxy",
|
||||
"anonymous"
|
||||
],
|
||||
"scripts": {
|
||||
"start": "astro dev --config ./source/astro.mjs --host",
|
||||
"translate": "astro-i18next --config ./source/astro-i18next.config.mjs generate",
|
||||
"build": "astro build --config ./source/astro.js"
|
||||
"start": "astro dev --config ./web/astro.mjs --host",
|
||||
"translate": "astro-i18next --config ./web/astro-i18next.config.mjs generate",
|
||||
"build": "astro build --config ./web/astro.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^3.1.8",
|
||||
"@astrojs/node": "^8.3.4",
|
||||
"@astrojs/vue": "^4.5.2",
|
||||
"@iconoir/vue": "^7.9.0",
|
||||
"@astrojs/mdx": "^3.1.5",
|
||||
"@astrojs/node": "^8.3.3",
|
||||
"@astrojs/vue": "^4.5.0",
|
||||
"@iconoir/vue": "^7.8.0",
|
||||
"@minpluto/polestar": "^0.0.54-1",
|
||||
"@minpluto/zorn": "^0.4.51",
|
||||
"@nurodev/astro-bun": "^1.1.5",
|
||||
"@openpanel/sdk": "^1.0.0",
|
||||
"@supabase/supabase-js": "^2.45.6",
|
||||
"@xexiu/astro-modal": "^0.5.9",
|
||||
"astro": "^4.16.7",
|
||||
"astro-analytics": "^2.7.0",
|
||||
"astro-i18next": "^1.0.0-beta.21",
|
||||
"@supabase/supabase-js": "^2.45.3",
|
||||
"astro": "^4.15.4",
|
||||
"astro-tooltips": "^0.6.2",
|
||||
"astro-useragent": "^4.0.2",
|
||||
"rss-to-json": "^2.1.1",
|
||||
"undici": "^6.20.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"sass": "^1.80.4"
|
||||
"sass": "^1.78.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
/** @type {import('astro-i18next').AstroI18nextConfig} */
|
||||
export default {
|
||||
locales: ["en"]
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
import { defineConfig } from 'astro/config'
|
||||
import vue from '@astrojs/vue'
|
||||
import astroI18next from "astro-i18next"
|
||||
import mdx from '@astrojs/mdx'
|
||||
import bun from "@nurodev/astro-bun";
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// Project Structure
|
||||
cacheDir: './.minpluto/generated/astro/cache/',
|
||||
outDir: './.minpluto/generated/astro/dist/',
|
||||
publicDir: './source/src/public',
|
||||
root: './source',
|
||||
srcDir: './source/src',
|
||||
// Integrations and Plugins
|
||||
integrations: [mdx(), vue(), astroI18next()],
|
||||
// Security
|
||||
security: {
|
||||
checkOrigin: true
|
||||
},
|
||||
// Server Options
|
||||
server: {
|
||||
port: 1930,
|
||||
host: true
|
||||
},
|
||||
// Use Server-Side Rendering
|
||||
output: 'server',
|
||||
adapter: bun(),
|
||||
// Vite
|
||||
vite: {
|
||||
server: {
|
||||
hmr: true // Auto Reload
|
||||
}
|
||||
},
|
||||
// Experimental
|
||||
experimental: {
|
||||
directRenderScript: true,
|
||||
clientPrerender: true,
|
||||
serverIslands: true
|
||||
},
|
||||
prefetch: {
|
||||
prefetchAll: true,
|
||||
defaultStrategy: "viewport"
|
||||
},
|
||||
// Others
|
||||
devToolbar: {
|
||||
enabled: false
|
||||
}
|
||||
})
|
6
source/env.d.ts
vendored
6
source/env.d.ts
vendored
|
@ -1,6 +0,0 @@
|
|||
/// <reference types="astro/client" />
|
||||
declare namespace App {
|
||||
interface Locals {
|
||||
email: string
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
---
|
||||
const {
|
||||
Text,
|
||||
Color
|
||||
} = Astro.props
|
||||
---
|
||||
|
||||
<p style={'background: ' + Color + ';'} class="chip">{Text}</p>
|
||||
|
||||
<style lang="scss">
|
||||
.chip {
|
||||
font-size: 12px;
|
||||
border-radius: 3rem;
|
||||
padding: 4px 12px;
|
||||
width: max-content;
|
||||
}
|
||||
</style>
|
|
@ -1,44 +0,0 @@
|
|||
---
|
||||
// Properties
|
||||
const {
|
||||
ChannelId
|
||||
} = Astro.props
|
||||
|
||||
// Configuration
|
||||
import { DEFAULT_MEDIA_DATA_PROXY, DEFAULT_IMAGE_PROXY} from '@utils/GetConfig'
|
||||
|
||||
// Fetch
|
||||
const channel = await fetch(DEFAULT_MEDIA_DATA_PROXY + "/api/v1/channels/" + ChannelId).then((response) => response.json());
|
||||
---
|
||||
|
||||
<a class="sidebar-channel" href={'/channel/' + channel.authorId}>
|
||||
<img src={DEFAULT_IMAGE_PROXY + '/' + channel.authorThumbnails[5].url}/>
|
||||
<p>{channel.author}</p>
|
||||
</a>
|
||||
|
||||
<style lang="scss">
|
||||
.sidebar-channel {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin-bottom: 6px;
|
||||
border-radius: 6px;
|
||||
padding: 4px 24px;
|
||||
background: transparent;
|
||||
border: 2px transparent solid;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
font-size: 14px;
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 2px rgba(255, 255, 255, 0.05) solid;
|
||||
}
|
||||
img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
object-fit: cover;
|
||||
border-radius: 3rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,83 +0,0 @@
|
|||
---
|
||||
import { Xmark } from "@iconoir/vue"
|
||||
|
||||
const {
|
||||
Title,
|
||||
Description,
|
||||
Closable,
|
||||
CloseOnclick
|
||||
} = Astro.props
|
||||
---
|
||||
|
||||
<div class="dialog-backdrop"></div>
|
||||
<div id={'dialog-' + Title} class="dialog">
|
||||
<div class="dialog-header">
|
||||
<div class="dialog-header-title">
|
||||
<h2>{Title}</h2>
|
||||
<p>{Description}</p>
|
||||
</div>
|
||||
<div class="dialog-header-action">
|
||||
{Closable ? <button onclick={CloseOnclick}><Xmark/></button> : null}
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-content">
|
||||
<slot/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.dialog-backdrop {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 6;
|
||||
backdrop-filter: blur(10px) brightness(0.5) contrast(0.9);
|
||||
-webkit-backdrop-filter: blur(10px) brightness(0.5) contrast(0.9);
|
||||
}
|
||||
.dialog {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 7;
|
||||
width: 100%;
|
||||
top: 25%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: rgb(24 24 24);
|
||||
border: 2px rgba(255,255,255,0.05) solid;
|
||||
margin: auto;
|
||||
max-width: 600px;
|
||||
border-radius: 10px;
|
||||
flex-direction: column;
|
||||
padding-bottom: 24px;
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px 24px;
|
||||
.dialog-header-title {
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
margin: 0px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
margin: 0px;
|
||||
color: gray;
|
||||
}
|
||||
}
|
||||
.dialog-header-action button {
|
||||
background: transparent;
|
||||
color: white;
|
||||
border: none;
|
||||
aspect-ratio: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.dialog-content {
|
||||
padding: 0px 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,50 +0,0 @@
|
|||
---
|
||||
// Properties
|
||||
const {
|
||||
ChannelId
|
||||
} = Astro.props
|
||||
|
||||
// Configuration
|
||||
import { DEFAULT_MEDIA_DATA_PROXY, DEFAULT_IMAGE_PROXY} from '@utils/GetConfig'
|
||||
|
||||
// Fetch
|
||||
const channel = await fetch(DEFAULT_MEDIA_DATA_PROXY + "/api/v1/channels/" + ChannelId).then((response) => response.json());
|
||||
---
|
||||
|
||||
<a href={'/channel/' + channel.authorId} style={"background: url('" + DEFAULT_IMAGE_PROXY + '/' + channel.authorThumbnails[5].url} class="discovery-channel">
|
||||
<div class="dc-c">
|
||||
<img src={DEFAULT_IMAGE_PROXY + '/' + channel.authorThumbnails[5].url}/>
|
||||
<p>{channel.author}</p>
|
||||
</div>
|
||||
</a>
|
||||
<style lang="scss">
|
||||
.discovery-channel {
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
font-weight: bold;
|
||||
background-position: center !important;
|
||||
background-size: cover !important;
|
||||
.dc-c {
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
backdrop-filter: blur(24px) contrast(0.7) brightness(0.4);
|
||||
-webkit-backdrop-filter: blur(24px) contrast(0.7) brightness(0.4);
|
||||
img {
|
||||
width: 24%;
|
||||
align-self: center;
|
||||
border-radius: 10rem;
|
||||
padding: 30px;
|
||||
}
|
||||
p {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
width: 160px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,23 +0,0 @@
|
|||
---
|
||||
const { Name, OnClick } = Astro.props
|
||||
---
|
||||
|
||||
<div class="tr-dropdown">
|
||||
<a style="cursor: pointer;" onclick={OnClick} id={Name + '-dropdown-button'}>{Name}</a>
|
||||
<div style="display: none;" id={Name + '-dropdown-menu'} class="comp-dropdown">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.comp-dropdown {
|
||||
position: absolute;
|
||||
background: #0d0d0d;
|
||||
border-radius: 6px;
|
||||
border: 2px #464646 solid;
|
||||
width: max-content;
|
||||
a {
|
||||
padding: 12px 48px 12px 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,67 +0,0 @@
|
|||
---
|
||||
// Properties
|
||||
const {
|
||||
ID,
|
||||
Title,
|
||||
Creator,
|
||||
Views,
|
||||
UploadDate,
|
||||
Length
|
||||
} = Astro.props
|
||||
|
||||
// Configuration
|
||||
import {
|
||||
DEFAULT_MEDIA_DATA_PROXY,
|
||||
DEFAULT_IMAGE_PROXY
|
||||
} from '@utils/GetConfig'
|
||||
|
||||
// i18n
|
||||
import i18next, { t } from "i18next";
|
||||
|
||||
// Format Published Date
|
||||
const DateFormat = new Date(UploadDate * 1000).toLocaleDateString()
|
||||
|
||||
// Format Video Length
|
||||
// Thanks to "mingjunlu" for helping out with the time format
|
||||
const LengthFormat = new Date(Length * 1000).toISOString().slice(14, 19).split(':').map(Number).join(':')
|
||||
|
||||
// Format Views
|
||||
const ViewsConversion = Intl.NumberFormat('en', { notation: 'compact'})
|
||||
const ViewsFormat = ViewsConversion.format(Views)
|
||||
---
|
||||
|
||||
|
||||
<a href={'/watch?v=' + ID} class="music-item">
|
||||
<img src={DEFAULT_IMAGE_PROXY + '/https://i.ytimg.com/vi/' + ID + '/maxresdefault.jpg'}/>
|
||||
<p id="title">{Title}</p>
|
||||
<p id="artist">{Creator}</p>
|
||||
<p id="date">{DateFormat}</p>
|
||||
<p id="duration">{LengthFormat}</p>
|
||||
</a>
|
||||
|
||||
<style lang="scss">
|
||||
.music-item {
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
gap: 12px;
|
||||
grid-template-columns: 60px auto auto 80px 64px;
|
||||
#duration, #date {
|
||||
color: gray;
|
||||
}
|
||||
#artist, #duration, #date {
|
||||
text-align: right;
|
||||
}
|
||||
#title {
|
||||
font-weight: bold;
|
||||
}
|
||||
img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,94 +0,0 @@
|
|||
---
|
||||
import { Search } from "@iconoir/vue";
|
||||
import { t } from "i18next";
|
||||
---
|
||||
|
||||
<div class="search-bar">
|
||||
<form onsubmit="return Search()">
|
||||
<input
|
||||
type="search"
|
||||
placeholder={t("HEADER.SEARCH")}
|
||||
aria-label="Search for a video or stream"
|
||||
/>
|
||||
</form>
|
||||
<button onclick="Search()"><Search /></button>
|
||||
<div style="opacity: 0;" class="suggestions"></div>
|
||||
</div>
|
||||
|
||||
<!-- Search Scripts -->
|
||||
<script is:inline>
|
||||
/*
|
||||
@licstart The following is the entire license notice for the
|
||||
JavaScript code in this page.
|
||||
|
||||
Copyright (C) 2024 SudoVanilla
|
||||
|
||||
The JavaScript code in this page is free software: you can
|
||||
redistribute it and/or modify it under the terms of the GNU
|
||||
General Public License (GNU GPL) as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option)
|
||||
any later version. The code is distributed WITHOUT ANY WARRANTY;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
|
||||
|
||||
As additional permission under GNU GPL version 3 section 7, you
|
||||
may distribute non-source (e.g., minimized or compacted) forms of
|
||||
that code without the copy of the GNU GPL normally required by
|
||||
section 4, provided you include this license notice and a URL
|
||||
through which recipients can access the Corresponding Source.
|
||||
|
||||
|
||||
@licend The above is the entire license notice
|
||||
for the JavaScript code in this page.
|
||||
*/
|
||||
|
||||
// Focus input
|
||||
function FocusSearch() {
|
||||
document.querySelector('input[type="search"]').focus();
|
||||
}
|
||||
|
||||
// Trigger Search
|
||||
function Search() {
|
||||
var SearchQuery = document.querySelector('input[type="search"]').value;
|
||||
location.href = `/search?query=${SearchQuery}`;
|
||||
}
|
||||
|
||||
///// Suggestions /////
|
||||
// Dismiss when the end-user clicks else where
|
||||
document.body.addEventListener("click", function (evt) {
|
||||
document.querySelector(".suggestions").style.opacity = "0";
|
||||
});
|
||||
|
||||
// When the end-user starts typing, trigget the fetch function
|
||||
document
|
||||
.querySelector('input[type="search"]')
|
||||
.addEventListener("input", function (e) {
|
||||
if (e.target.value !== "") {
|
||||
document.querySelector(".suggestions").style.opacity = "1";
|
||||
GetResults();
|
||||
} else {
|
||||
null;
|
||||
}
|
||||
});
|
||||
|
||||
// Fetch
|
||||
function GetResults() {
|
||||
var SearchValue = document.querySelector('input[type="search"]').value;
|
||||
var YouTubeSuggestions = document.querySelector(".suggestions");
|
||||
fetch(
|
||||
`https://yt.sudovanilla.org/api/v1/search/suggestions?q=${SearchValue}`,
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
YouTubeSuggestions.innerHTML = ListOfSuggestionsYT(data);
|
||||
});
|
||||
}
|
||||
|
||||
// Create List
|
||||
function ListOfSuggestionsYT(data) {
|
||||
const text = data.suggestions
|
||||
.map((data) => `<a href="/search?query=${data}">${data}</a>`)
|
||||
.join("\n");
|
||||
return `${text}`;
|
||||
}
|
||||
</script>
|
|
@ -1,84 +0,0 @@
|
|||
---
|
||||
// Properties
|
||||
const {
|
||||
ID,
|
||||
Title,
|
||||
Creator,
|
||||
Views,
|
||||
UploadDate,
|
||||
Length
|
||||
} = Astro.props
|
||||
|
||||
// Configuration
|
||||
import {
|
||||
DEFAULT_MEDIA_DATA_PROXY,
|
||||
DEFAULT_IMAGE_PROXY
|
||||
} from '@utils/GetConfig'
|
||||
|
||||
// i18n
|
||||
import i18next, { t } from "i18next";
|
||||
|
||||
// Format Published Date
|
||||
const DateFormat = new Date(UploadDate * 1000).toLocaleDateString()
|
||||
|
||||
// Format Video Length
|
||||
// Thanks to "mingjunlu" for helping out with the time format
|
||||
const LengthFormat = null
|
||||
|
||||
// Format Views
|
||||
const ViewsConversion = Intl.NumberFormat('en', { notation: 'compact'})
|
||||
const ViewsFormat = ViewsConversion.format(Views)
|
||||
---
|
||||
|
||||
<a href={'/watch?v=' + ID} class="video-item">
|
||||
<div class="video-item-thumbnail">
|
||||
<img onload="this.style.opacity = '1'" src={DEFAULT_IMAGE_PROXY + '/https://i.ytimg.com/vi/' + ID + '/hqdefault.jpg'} loading="lazy"/>
|
||||
<p id="vi-length">{LengthFormat}</p>
|
||||
</div>
|
||||
<div class="video-item-details">
|
||||
<p id="vi-title">{Title}</p>
|
||||
<p id="vi-author">{t("WATCH.BY")} {Creator}</p>
|
||||
<p id="vi-viewCount">{ViewsFormat} {t("WATCH.VIEWS")} - {DateFormat}</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<style lang="scss">
|
||||
.video-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
.video-item-thumbnail {
|
||||
img {
|
||||
width: 100%;
|
||||
border-radius: 6px;
|
||||
aspect-ratio: 16/9;
|
||||
object-fit: cover;
|
||||
opacity: 0;
|
||||
transition: 0.3s opacity;
|
||||
}
|
||||
p#vi-length {
|
||||
margin: -41px 0px 0px 0px;
|
||||
background: rgba(0,0,0,0.75);
|
||||
padding: 12px 6px 6px 16px;
|
||||
width: max-content;
|
||||
border-radius: 50px 0px 6px 0px;
|
||||
position: relative;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.video-item-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
p {
|
||||
margin: 0px;
|
||||
&#vi-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
&#vi-author {
|
||||
color: darkgrey;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,17 +0,0 @@
|
|||
---
|
||||
import i18next,{ t, changeLanguage } from "i18next";
|
||||
import Base from "@layouts/Default.astro";
|
||||
|
||||
if (Astro.cookies.get("Telemtry").value === "Enabled") {
|
||||
var UserIsOptedIn = true
|
||||
}
|
||||
else if (Astro.cookies.get("Telemtry").value === "Disabled") {
|
||||
var UserIsOptedIn = false
|
||||
}
|
||||
---
|
||||
|
||||
{UserIsOptedIn ?
|
||||
<a style="color: white;text-decoration: none;margin-bottom: 6px;border-radius: 6px;padding: 8px 24px;background: #1a1a1a;font-size: 14px;border: 2px rgba(255, 255, 255, 0.25) solid;" href="/api/telemtry/disable">{t("TELEMTRY.OPTOUT")}</a>
|
||||
:
|
||||
<a style="color: white;text-decoration: none;margin-bottom: 6px;border-radius: 6px;padding: 8px 24px;background: #1a1a1a;font-size: 14px;border: 2px rgba(255, 255, 255, 0.25) solid;" href="/api/telemtry/enable">{t("TELEMTRY.OPTIN")}</a>
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
---
|
||||
const {
|
||||
Link,
|
||||
Name,
|
||||
Platform,
|
||||
Thumbnail,
|
||||
Ratio = "16:9" // "16:9" or "9:16"
|
||||
} = Astro.props
|
||||
---
|
||||
|
||||
|
||||
<a href={Link} style={"background-image: url('" + Thumbnail + "')"} class="goin-card">
|
||||
{
|
||||
()=> {
|
||||
if (Platform === "YouTube") {
|
||||
return <span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M549.7 124.1c-6.3-23.7-24.8-42.3-48.3-48.6C458.8 64 288 64 288 64S117.2 64 74.6 75.5c-23.5 6.3-42 24.9-48.3 48.6-11.4 42.9-11.4 132.3-11.4 132.3s0 89.4 11.4 132.3c6.3 23.7 24.8 41.5 48.3 47.8C117.2 448 288 448 288 448s170.8 0 213.4-11.5c23.5-6.3 42-24.2 48.3-47.8 11.4-42.9 11.4-132.3 11.4-132.3s0-89.4-11.4-132.3zm-317.5 213.5V175.2l142.7 81.2-142.7 81.2z"/></svg></span>
|
||||
} else if (Platform === "Twitch") {
|
||||
return <span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M391.2 103.5H352.5v109.7h38.6zM285 103H246.4V212.8H285zM120.8 0 24.3 91.4V420.6H140.1V512l96.5-91.4h77.3L487.7 256V0zM449.1 237.8l-77.2 73.1H294.6l-67.6 64v-64H140.1V36.6H449.1z"/></svg></span>
|
||||
}
|
||||
}
|
||||
}
|
||||
<div class="goin-card-content">
|
||||
<p>{Name}</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<style lang="scss">
|
||||
.goin-card {
|
||||
text-decoration: none;
|
||||
border-radius: 10px;
|
||||
background-size: cover !important;
|
||||
background-position: center !important;
|
||||
position: relative;
|
||||
span {
|
||||
svg {
|
||||
fill: white;
|
||||
width: 30px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
margin: 18px;
|
||||
}
|
||||
}
|
||||
.goin-card-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
height: 100%;
|
||||
place-content: center;
|
||||
border-radius: 10px;
|
||||
backdrop-filter: blur(3px) brightness(0.3) contrast(0.8);
|
||||
-webkit-backdrop-filter: blur(3px) brightness(0.3) contrast(0.8);
|
||||
p {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
margin: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
{
|
||||
()=> {
|
||||
if (Ratio === "16:9") {
|
||||
return <style is:inline>
|
||||
.goin-card {
|
||||
height: 170px !important
|
||||
}
|
||||
</style>
|
||||
} else if (Ratio === "9:16") {
|
||||
return <style is:inline>
|
||||
.goin-card {
|
||||
height: 328px !important
|
||||
}
|
||||
</style>
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
---
|
||||
// Properties
|
||||
const {
|
||||
FetchData,
|
||||
CategoryName,
|
||||
CategoryDescription,
|
||||
GradientHero
|
||||
} = Astro.props
|
||||
|
||||
// Configuration
|
||||
import {
|
||||
DEFAULT_MEDIA_DATA_PROXY,
|
||||
DEFAULT_IMAGE_PROXY
|
||||
} from '@utils/GetConfig'
|
||||
|
||||
|
||||
// Fetch
|
||||
const fetchFrom = DEFAULT_MEDIA_DATA_PROXY + '/api/v1/trending' + FetchData
|
||||
const response = await fetch(fetchFrom)
|
||||
const data = await response.json()
|
||||
---
|
||||
|
||||
|
||||
<div class="Td-row">
|
||||
{data.map((data) =>
|
||||
<img src={DEFAULT_IMAGE_PROXY + '/https://i.ytimg.com/vi/' + data.videoId + '/maxresdefault.jpg'}/>
|
||||
)}
|
||||
</div>
|
|
@ -1,66 +0,0 @@
|
|||
---
|
||||
// Environment Variables
|
||||
import {
|
||||
ANALYTICS,
|
||||
MATOMO_ID,
|
||||
MATOMO_SRC,
|
||||
PLAUSIBLE_DOMAIN,
|
||||
PLAUSIBLE_SRC,
|
||||
UMAMI_SRC,
|
||||
AMPLITUDE_APIKEY,
|
||||
METRICAL_APP,
|
||||
FATHOM_SITE,
|
||||
FATHOM_SRC,
|
||||
MINIAML_ID,
|
||||
SWETRIX_SRC,
|
||||
SWETRIX_API,
|
||||
SWETRIX_PROJECT_ID,
|
||||
SIMPLEANALYTICS_DOMAIN
|
||||
} from '@utils/GetConfig'
|
||||
|
||||
// Get Astro Analytics
|
||||
import {
|
||||
Fathom,
|
||||
Metrical,
|
||||
Plausible,
|
||||
Umami,
|
||||
Amplitude,
|
||||
Matomo,
|
||||
MinimalAnalytics
|
||||
} from 'astro-analytics'
|
||||
---
|
||||
|
||||
<!-- https://gist.sudovanilla.org/Korbs/fac0f5b99a6e43679c1d38d614721b5e -->
|
||||
{
|
||||
()=> {
|
||||
if (ANALYTICS === "None") {
|
||||
return null
|
||||
} else if (ANALYTICS === "Plausible") {
|
||||
<Plausible domain={PLAUSIBLE_DOMAIN} src={PLAUSIBLE_SRC + "/yoursript.js"} />
|
||||
} else if (ANALYTICS === "Umami") {
|
||||
<Umami id="4fb7fa4c-5b46-438d-94b3-3a8fb9bc2e8b" src={UMAMI_SRC + "/umami.js"} />
|
||||
} else if (ANALYTICS === "Amplitude") {
|
||||
<Amplitude apiKey={AMPLITUDE_APIKEY} />
|
||||
} else if (ANALYTICS === "Matomo") {
|
||||
<Matomo id={MATOMO_ID} src={MATOMO_SRC} />
|
||||
} else if (ANALYTICS === "Metrical") {
|
||||
<Metrical app={METRICAL_APP} />
|
||||
} else if (ANALYTICS === "Fathom") {
|
||||
<Fathom site={FATHOM_SITE} src={FATHOM_SRC} />
|
||||
} else if (ANALYTICS === "MinimalAnalytics") {
|
||||
<MinimalAnalytics id={MINIAML_ID} />
|
||||
} else if (ANALYTICS === "Swetrix") {
|
||||
<script is:inline src={SWETRIX_SRC} defer></script>
|
||||
<script is:inline>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
swetrix.init({SWETRIX_PROJECT_ID})
|
||||
swetrix.trackViews()
|
||||
})
|
||||
</script>
|
||||
<noscript><img src={SWETRIX_API + '/log/noscript?pid=' + SWETRIX_PROJECT_ID} alt="" referrerpolicy="no-referrer-when-downgrade" /></noscript>
|
||||
} else if (ANALYTICS === "Simple Analytics") {
|
||||
<script is:inline async defer data-hostname={SIMPLEANALYTICS_DOMAIN} src="https://scripts.simpleanalyticscdn.com/latest.js"></script>
|
||||
<noscript><img src={'https://queue.simpleanalyticscdn.com/noscript.gif?hostname=' + SIMPLEANALYTICS_DOMAIN} alt="" referrerpolicy="no-referrer-when-downgrade" /></noscript>
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
---
|
||||
// Configuration
|
||||
import {
|
||||
DEFAULT_PLAYER
|
||||
} from '@utils/GetConfig'
|
||||
---
|
||||
|
||||
{
|
||||
() => {
|
||||
if (DEFAULT_PLAYER === "Browser") {
|
||||
return (null)
|
||||
}
|
||||
if (DEFAULT_PLAYER === "Zorn") {
|
||||
return (
|
||||
<script is:inline src="/scripts/zorn.js"></script>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
---
|
||||
// i18n
|
||||
import i18next, { t } from "i18next";
|
||||
|
||||
// Cookies
|
||||
/// Set Default
|
||||
if (Astro.cookies.get("Language") === undefined) {
|
||||
Astro.cookies.set("Language", "EN", {path: "/",sameSite: 'strict'})
|
||||
} else {
|
||||
var UserLanguage = Astro.cookies.get("Language").value
|
||||
if (UserLanguage === "JP") {i18next.changeLanguage("jp")}
|
||||
else if (UserLanguage === "EN") {i18next.changeLanguage("en")}
|
||||
}
|
||||
if (Astro.cookies.get("Milieu") === undefined) {
|
||||
Astro.cookies.set("Milieu", "Enabled", {path: "/",sameSite: 'strict'})
|
||||
} else {
|
||||
var UserLanguage = Astro.cookies.get("Language").value
|
||||
if (UserLanguage === "JP") {i18next.changeLanguage("jp")}
|
||||
else if (UserLanguage === "EN") {i18next.changeLanguage("en")}
|
||||
}
|
||||
|
||||
/// Telemtry
|
||||
//// Users should be opted-out by default
|
||||
if (Astro.cookies.get("Telemtry") === undefined) {
|
||||
Astro.cookies.set("Telemtry", "Disabled", {path: "/",sameSite: 'strict'})
|
||||
}
|
||||
|
||||
// Properties
|
||||
const {
|
||||
Title,
|
||||
Description,
|
||||
EmbedId,
|
||||
EmbedVideo,
|
||||
EmbedImage,
|
||||
EmbedTitle,
|
||||
} = Astro.props
|
||||
|
||||
// Components
|
||||
import Analytics from "@components/global/Analytics.astro";
|
||||
import { Tooltips } from 'astro-tooltips';
|
||||
|
||||
// Configuration
|
||||
import {SERVER_DOMAIN} from '@utils/GetConfig'
|
||||
|
||||
// Embed
|
||||
const SWV = Astro.url.href.split("embed/").pop();
|
||||
|
||||
if (Astro.url.href.match('watch')) {
|
||||
var IsVideo = true
|
||||
} else if (Astro.url.href.match('embed')) {
|
||||
var IsVideo = false
|
||||
} else {
|
||||
var IsVideo = false
|
||||
}
|
||||
|
||||
// Track Events
|
||||
// TODO
|
||||
// Before re-enabling, create an "opt-in" solution
|
||||
// first for the end-user, as asking for consent
|
||||
// would be ideal. Astro Cookies can be used to
|
||||
// toggle the option, make sure end-users are
|
||||
// opted-out by default for privacy purposes.
|
||||
|
||||
// import { OpenpanelSdk } from '@openpanel/sdk';
|
||||
// const op = new OpenpanelSdk({
|
||||
// clientId: 'b4c27f56-18f5-4d66-bb62-cbf7f7161812',
|
||||
// clientSecret: 'sec_107558407af59a591b50',
|
||||
// });
|
||||
---
|
||||
|
||||
<head>
|
||||
<!-- Metadata -->
|
||||
<title>{Title}</title>
|
||||
<meta name="description" content={Description}>
|
||||
|
||||
<!-- Properties -->
|
||||
<meta charset="UTF-8">
|
||||
<meta name="theme-color" content="#111">
|
||||
<meta name="viewport" content="width=device-1200px, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=yes, viewport-fit=cover, width=device-width, height=device-height, target-densitydpi=device-dpi">
|
||||
<meta http-equiv="content-language" content="en-us">
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<script is:inline src="/service-worker.js"></script>
|
||||
<Tooltips interactive={false} delay={[15, 12]} />
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="apple-touch-icon" type="image/png" sizes="256x256" href="/images/logo/Favicon.png">
|
||||
<link rel="icon" type="image/png" sizes="256x256" href="/images/logo/Favicon.png">
|
||||
|
||||
<!-- Video Embed -->
|
||||
{IsVideo ?
|
||||
<meta property="og:type" content="video.other">
|
||||
<meta property="og:video:url" content={SERVER_DOMAIN + '/embed/' + EmbedId}>
|
||||
<meta property="og:video:type" content="text/html">
|
||||
<meta property="twitter:player" content={SERVER_DOMAIN + '/embed/' + EmbedId}>
|
||||
<meta property="og:video" content={EmbedVideo} />
|
||||
<meta property="og:title" content={EmbedTitle}>
|
||||
<meta property="og:image" content={EmbedImage}/>
|
||||
<meta property="og:site_name" content={'MinPluto - Privacy YouTube Frontend'}>
|
||||
:
|
||||
null
|
||||
}
|
||||
</head>
|
||||
<Analytics/>
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
import { HomeSimple, InputSearch, MediaVideoList, MoreHoriz, ProfileCircle, Safari, Settings } from "@iconoir/vue";
|
||||
|
||||
---
|
||||
|
||||
<div class="mobile-navigation">
|
||||
<a href="/"><HomeSimple/> <p>Home</p></a>
|
||||
<a href="#"><InputSearch/> <p>Search</p></a>
|
||||
<a href="#"><Safari/> <p>Explore</p></a>
|
||||
<a href="#"><MediaVideoList/> <p>Subscription</p></a>
|
||||
<a href="#"><Settings/> <p>Settings</p></a>
|
||||
<a href="#"><MoreHoriz/> <p>More</p></a>
|
||||
</div>
|
|
@ -1,253 +0,0 @@
|
|||
---
|
||||
// Configuration
|
||||
import {
|
||||
SIDEBAR_DISCOVER,
|
||||
SIDEBAR_CATEGORIES
|
||||
} from '@utils/GetConfig'
|
||||
|
||||
import {
|
||||
version
|
||||
} from '@root/package.json'
|
||||
|
||||
// Components
|
||||
import CreatorInSidebar from '@components/CreatorInSidebar.astro'
|
||||
import { ViewTransitions } from 'astro:transitions';
|
||||
import { slide } from "astro/virtual-modules/transitions.js";
|
||||
|
||||
// Icons
|
||||
import {
|
||||
GraphUp,
|
||||
Movie,
|
||||
MusicDoubleNote,
|
||||
Gamepad,
|
||||
AppleImac2021Side,
|
||||
EmojiTalkingHappy,
|
||||
PeaceHand,
|
||||
PlanetAlt,
|
||||
InputSearch,
|
||||
Settings,
|
||||
LogIn,
|
||||
LogOut
|
||||
} from '@iconoir/vue'
|
||||
|
||||
// i18n
|
||||
import i18next, { t } from "i18next"
|
||||
|
||||
// Supabase Data
|
||||
import { supabase } from "@library/supabase"
|
||||
const { data: { user } } = await supabase.auth.getUser()
|
||||
const id = user?.id
|
||||
|
||||
// Is the user logged in?
|
||||
if (Astro.cookies.get('sb-access-token') === undefined) {
|
||||
var Guest = true
|
||||
} else {
|
||||
var Guest = false
|
||||
}
|
||||
|
||||
// Get Channels
|
||||
const { data: channels, error } = await supabase
|
||||
.from('channels')
|
||||
.select('*')
|
||||
let { data: subs } = await supabase
|
||||
.from('subs')
|
||||
.select("*")
|
||||
.eq('UserSubscribed', id)
|
||||
---
|
||||
|
||||
<ViewTransitions transition:animate={slide} />
|
||||
<div class="sidebar">
|
||||
<div class="sidebar-top">
|
||||
<div class="sidebar-top-start">
|
||||
<a href='/'><img src="/images/logo/MinPluto - Logo.png"/></a>
|
||||
<div>
|
||||
<!-- {Guest ?
|
||||
<a title="Login" href="/login"><LogIn/></a>
|
||||
:
|
||||
<a title="Log Out" href="/api/auth/logout"><LogOut/></a>
|
||||
} -->
|
||||
<a title="Settings" href="#"><Settings/></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-top-end">
|
||||
<a href={'/'}><PlanetAlt/> {t("SIDEBAR.HOME")}</a>
|
||||
<a href="#"><InputSearch/> {t("HEADER.SEARCH")}</a>
|
||||
{SIDEBAR_CATEGORIES ?
|
||||
<h2>{t("SIDEBAR.TRENDING")}</h2>
|
||||
<a href={'/discover?category=trending&?platform=youtube'}><GraphUp/> {t("SIDEBAR.CATEGORY_LIST.POPULAR")}</a>
|
||||
<a href={'/discover?category=movies&?platform=youtube'}><Movie/> {t("SIDEBAR.CATEGORY_LIST.TRAILERS")}</a>
|
||||
<a href={'/discover?category=music&?platform=youtube'}><MusicDoubleNote/> {t("SIDEBAR.CATEGORY_LIST.MUSIC")}</a>
|
||||
<a href={'/discover?category=gaming&?platform=youtube'}><Gamepad/> {t("SIDEBAR.CATEGORY_LIST.GAMES")}</a>
|
||||
:
|
||||
null
|
||||
}
|
||||
{SIDEBAR_DISCOVER ?
|
||||
<h2>{t("SIDEBAR.DISCOVER")}</h2>
|
||||
<a href={'/discover/tech'}><AppleImac2021Side/> {t("SIDEBAR.DISCOVER_LIST.TECH")}</a>
|
||||
<a href="/discover/comedy"><EmojiTalkingHappy/> {t("SIDEBAR.DISCOVER_LIST.COMEDY")}</a>
|
||||
<a href="/discover/gaming"><Gamepad/> {t("SIDEBAR.DISCOVER_LIST.GAMES")}</a>
|
||||
:
|
||||
null
|
||||
}
|
||||
{Guest ?
|
||||
null
|
||||
:
|
||||
<h2>Following</h2>
|
||||
<span>
|
||||
{subs.map((channel) =>
|
||||
<CreatorInSidebar ChannelId={channel.Id}/>
|
||||
)}
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-bottom">
|
||||
<div class="sidebar-bottom-start">
|
||||
<a style="pointer-events: none;"><PeaceHand/> {t("SIDEBAR.FOOTER.ALPHA")}</a>
|
||||
</div>
|
||||
<div class="sidebar-bottom-end">
|
||||
<p id="version">v{version}</p>
|
||||
<a href="https://status.minpluto.org/" target="_blank">{t("SIDEBAR.FOOTER.STATUS")}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 224px;
|
||||
background: linear-gradient(315deg, #0e0e0e, #161616);
|
||||
color: white;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 0px 12px;
|
||||
hr {
|
||||
width: 32%;
|
||||
border: none;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
height: 4px;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
padding-left: 24px;
|
||||
}
|
||||
form {
|
||||
margin-bottom: 12px;
|
||||
input {
|
||||
background: transparent;
|
||||
border: 2px transparent solid;
|
||||
padding: 10px 24px;
|
||||
border-radius: 6px;
|
||||
color: white;
|
||||
transition: 0.3s background, 0.3s border;
|
||||
&:hover {
|
||||
background: rgb(255 255 255 / 05%);
|
||||
border: 2px rgba(255, 255, 255, 0.05) solid;
|
||||
transition: 0.3s background, 0.3s border;
|
||||
}
|
||||
&:focus {
|
||||
outline: none;
|
||||
background: rgb(255 255 255 / 07%);
|
||||
border: 2px rgba(255, 255, 255, 0.07) solid;
|
||||
transition: 0.3s background, 0.3s border;
|
||||
}
|
||||
svg {
|
||||
width: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.sidebar-top {
|
||||
.sidebar-top-start {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
padding: 32px 24px;
|
||||
justify-content: space-between;
|
||||
div {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
a {
|
||||
background: transparent;
|
||||
border-radius: 6px;
|
||||
padding: 5px 6px 3px 6px;
|
||||
aspect-ratio: 1;
|
||||
svg {
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
&:hover {
|
||||
background: #2d2d2d;
|
||||
}
|
||||
}
|
||||
}
|
||||
img {
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
.sidebar-top-end {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
.sidebar-bottom {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
.sidebar-bottom-end {
|
||||
text-align: center;
|
||||
padding-bottom: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0px 18px;
|
||||
}
|
||||
a {
|
||||
margin: 0px 4px;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
p#version {
|
||||
background: rgb(48, 48, 48);
|
||||
border-radius: 3rem;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
}
|
||||
.sidebar-top-end a, .sidebar-bottom-start a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin-bottom: 6px;
|
||||
border-radius: 6px;
|
||||
padding: 8px 24px;
|
||||
background: transparent;
|
||||
border: 2px transparent solid;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
font-size: 14px;
|
||||
&:hover {
|
||||
background: rgb(255 255 255 / 05%);
|
||||
border: 2px rgba(255, 255, 255, 0.05) solid;
|
||||
}
|
||||
svg {
|
||||
width: 18px;
|
||||
}
|
||||
&#sidebar-disable {
|
||||
filter: brightness(0.4);
|
||||
cursor: not-allowed;
|
||||
&:hover {
|
||||
background: transparent;
|
||||
border: 2px transparent solid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,50 +0,0 @@
|
|||
---
|
||||
const InstanceList = await fetch('https://codeberg.org/MinPluto/MinPluto/raw/branch/master/instances.json').then((response) => response.json());
|
||||
---
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>URL</th>
|
||||
<th>Official</th>
|
||||
<th>Region</th>
|
||||
<th>Uses Cloudflare</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{InstanceList.map((server) =>
|
||||
<tr>
|
||||
<td><a href={server[1].uri}>{server[1].uri}</a></td>
|
||||
<td>{server[1].official ? <p>Yes</p> : <p>No</p>}</td>
|
||||
<td>{server[1].region}</td>
|
||||
<td>{server[1].CLOUDFLARE ? <p>Yes</p> : <p>No</p>}</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<style>
|
||||
table {
|
||||
border: 1px solid #3d3846;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
table-layout: auto;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 1px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
border: 1px solid #3d3846;
|
||||
background-color: #000000;
|
||||
color: #ffffff;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
td {
|
||||
border: 1px solid #3d3846;
|
||||
background-color: #241f31;
|
||||
color: #f6f5f4;
|
||||
padding: 6px;
|
||||
}
|
||||
</style>
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
import {
|
||||
DEFAULT_MEDIA_PROXY,
|
||||
DEFAULT_MEDIA_DATA_PROXY,
|
||||
} from '@utils/GetConfig'
|
||||
|
||||
const InvidiousDataInfomation = await fetch(DEFAULT_MEDIA_DATA_PROXY + '/api/v1/stats').then((response) => response.json());
|
||||
---
|
||||
|
||||
|
||||
{InvidiousDataInfomation.map((server) =>
|
||||
<p>Version:</p>
|
||||
)}
|
|
@ -1,78 +0,0 @@
|
|||
---
|
||||
const {
|
||||
Name,
|
||||
Avatar,
|
||||
Link,
|
||||
Platform,
|
||||
Banner,
|
||||
Followers
|
||||
} = Astro.props
|
||||
---
|
||||
|
||||
<a href={Link} class={'search-creator'}>
|
||||
<div class="search-creator-media">
|
||||
<p>
|
||||
{
|
||||
()=> {
|
||||
if (Platform === "YouTube") {
|
||||
return <span>Subs: </span>
|
||||
} else if (Platform === "Twitch") {
|
||||
return <span>Followers: </span>
|
||||
}
|
||||
}
|
||||
}
|
||||
{Followers}
|
||||
</p>
|
||||
<img class="scm-banner" alt={Name + "'s banner"} src={Banner}/>
|
||||
<img class="scm-avatar" alt={Name + "'s avatar"} src={Avatar}/>
|
||||
</div>
|
||||
<div class="search-creator-meta">
|
||||
<p><strong>{Name}</strong></p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<style lang="scss">
|
||||
.search-creator {
|
||||
background: #181818;
|
||||
border-radius: 12px;
|
||||
padding: 4px;
|
||||
text-decoration: none;
|
||||
* {cursor: var(--pointer-cursor) !important}
|
||||
.search-creator-media {
|
||||
position: relative;
|
||||
p {
|
||||
position: absolute;
|
||||
right: 24px;
|
||||
background: black;
|
||||
border-radius: 1rem;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
.scm-banner {
|
||||
aspect-ratio: 16/9;
|
||||
width: 360px;
|
||||
height: 140px;
|
||||
object-fit: cover;
|
||||
border-radius: 12px;
|
||||
}
|
||||
.scm-avatar {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
bottom: -32px;
|
||||
border-radius: 3rem;
|
||||
border: 2px white solid;
|
||||
width: 80px;
|
||||
}
|
||||
}
|
||||
.search-creator-meta {
|
||||
padding-left: 104px;
|
||||
p {
|
||||
// Truncate
|
||||
max-width: 250px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,73 +0,0 @@
|
|||
---
|
||||
const {
|
||||
Title,
|
||||
Creator,
|
||||
Avatar,
|
||||
Link,
|
||||
Thumbnail,
|
||||
Views
|
||||
} = Astro.props
|
||||
---
|
||||
|
||||
<a href={Link} class='search-stream search-stream-platfom-twitch'>
|
||||
<div class="search-stream-media">
|
||||
<!-- <p>{Views}</p> -->
|
||||
<img onload="this.style.opacity = '1'" class="ssm-banner" alt='Stream Thumbnail' src={Thumbnail} loading="lazy"/>
|
||||
</div>
|
||||
<div class="search-stream-meta">
|
||||
<img onload="this.style.opacity = '1'" alt={Creator + "'s avatar"} src={Avatar} loading="lazy"/>
|
||||
<div>
|
||||
<p><strong>{Title}</strong></p>
|
||||
<p>{Creator}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<style lang="scss">
|
||||
.search-stream {
|
||||
background: #181818;
|
||||
border-radius: 12px;
|
||||
padding: 4px;
|
||||
text-decoration: none;
|
||||
* {cursor: var(--pointer-cursor) !important}
|
||||
.search-stream-media {
|
||||
position: relative;
|
||||
p {
|
||||
position: absolute;
|
||||
right: 24px;
|
||||
background: black;
|
||||
border-radius: 1rem;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
.ssm-banner {
|
||||
aspect-ratio: 16/9;
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 12px;
|
||||
opacity: 0;
|
||||
transition: 0.3s opacity;
|
||||
}
|
||||
}
|
||||
.search-stream-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
p {
|
||||
margin: 6px 0px;
|
||||
// Truncate
|
||||
max-width: 250px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: inherit;
|
||||
}
|
||||
img {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 3rem;
|
||||
opacity: 0;
|
||||
transition: 0.3s opacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,19 +0,0 @@
|
|||
---
|
||||
import {
|
||||
ANALYTICS
|
||||
} from '@utils/GetConfig'
|
||||
---
|
||||
|
||||
<!-- This can't be done in Markdown or MDX, hence why it's an Astro component -->
|
||||
{
|
||||
()=> {
|
||||
if (ANALYTICS === "false") {
|
||||
return null
|
||||
} else {
|
||||
return
|
||||
<h2>Information Collection and Use</h2>
|
||||
<p>This instance of MinPluto uses {ANALYTICS} for analytics, no personal informatin is collected about you. Data that is collected can not be used to identify you, along with devices or any other factors. </p>
|
||||
<p>All data collected with {ANALYTICS} is anonymous.</p>
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
---
|
||||
import {
|
||||
CLOUDFLARE
|
||||
} from '@utils/GetConfig'
|
||||
---
|
||||
|
||||
<!-- This can't be done in Markdown or MDX, hence why it's an Astro component -->
|
||||
{CLOUDFLARE ?
|
||||
<h2>Cloudflare Usage</h2>
|
||||
<p>This instance uses Cloudflare which means the following information is collected:</p>
|
||||
<ul>
|
||||
<li>Refers</li>
|
||||
<li>Paths</li>
|
||||
<li>Hosts</li>
|
||||
<li>Browser</li>
|
||||
<li>Operating System</li>
|
||||
<li>Device Type</li>
|
||||
<li>ASN</li>
|
||||
<li>User Agent</li>
|
||||
<li>Data Center</li>
|
||||
<li>Status Code</li>
|
||||
<li>IP Address</li>
|
||||
<li>HTTP Version</li>
|
||||
</ul>
|
||||
<p>This is shown in the "Analytics & Logs" portion in Cloudflare's Dashboard, this can't be turned off by the instance operator.</p>
|
||||
:
|
||||
null
|
||||
}
|
|
@ -1,148 +0,0 @@
|
|||
---
|
||||
// Cookies
|
||||
if (Astro.cookies.get("Milieu").value === "Enabled") {
|
||||
var Milieu = true
|
||||
} else {
|
||||
var Milieu = false
|
||||
}
|
||||
|
||||
// Icons
|
||||
import {
|
||||
ArrowUpRight,
|
||||
Backward15Seconds,
|
||||
Enlarge,
|
||||
Forward15Seconds,
|
||||
NavArrowRight,
|
||||
PlaySolid,
|
||||
Settings,
|
||||
SwitchOff,
|
||||
SwitchOn,
|
||||
} from "@iconoir/vue";
|
||||
---
|
||||
<div class="video-controls">
|
||||
<div class="vc-top">
|
||||
<p>The Mark On The Wall</p>
|
||||
</div>
|
||||
<div class="vc-bottom">
|
||||
<div class="vc-start">
|
||||
<button id="vc-playpause"><PlaySolid /></button>
|
||||
<button id="vc-backwards"><Backward15Seconds /></button>
|
||||
<button id="vc-forwards"><Forward15Seconds /></button>
|
||||
</div>
|
||||
<div class="vc-center">
|
||||
<div class="vc-seek">
|
||||
<span class="vc-progress-bar"></span>
|
||||
<input class="seek" id="seek" value="0" min="0" type="range" step="1">
|
||||
</div>
|
||||
<p class="timestamp">
|
||||
<span class="seek-tooltip" id="seek-tooltip">00:00</span>
|
||||
<span id="current">00:00</span>
|
||||
<span id="duration">00:00</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="vc-end">
|
||||
<button id="vc-settings" onclick="PlayerMenu_Settings()"><Settings /></button>
|
||||
<!-- <button><SoundHighSolid /></button> Should affect <audio>, not <video> -->
|
||||
<button id="vc-fullscreen"><Enlarge /></button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Menus -->
|
||||
<div id="settings" class="vc-menu">
|
||||
<button>Stats for Geeks</button>
|
||||
<hr/>
|
||||
<button>Open Video URL <ArrowUpRight/></button>
|
||||
<button>Download <ArrowUpRight/></button>
|
||||
<button>Embed <ArrowUpRight/></button>
|
||||
<hr/>
|
||||
{Milieu ?
|
||||
<button onclick="location.href = '/api/player/milieu/disable'" id="has-switch">Milieu <SwitchOn/></button>
|
||||
:
|
||||
<button onclick="location.href = '/api/player/milieu/enable'" id="has-switch">Milieu <SwitchOff/></button>
|
||||
}
|
||||
<!-- <button>Close Captions <NavArrowRight/></button> -->
|
||||
<button onclick="PlayerMenu_Quality()">Quality <NavArrowRight/></button>
|
||||
</div>
|
||||
<div id="quality-changer" class="vc-menu">
|
||||
<button onclick="ChangeQualtiy_1080()">1080p</button>
|
||||
<button onclick="ChangeQualtiy_720()">720p</button>
|
||||
<button onclick="ChangeQualtiy_360()">360p</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script is:inline>
|
||||
function PlayerMenu_HideAll() {
|
||||
document.querySelector('.vc-menu#settings').style.display = 'none'
|
||||
document.querySelector('.vc-menu#quality-changer').style.display = 'none'
|
||||
}
|
||||
function PlayerMenu_Settings() {
|
||||
PlayerMenu_HideAll()
|
||||
document.querySelector('.vc-menu#settings').style.display = 'flex'
|
||||
}
|
||||
function PlayerMenu_Quality() {
|
||||
PlayerMenu_HideAll()
|
||||
document.querySelector('.vc-menu#quality-changer').style.display = 'flex'
|
||||
}
|
||||
</script>
|
||||
|
||||
<script is:inline>
|
||||
function ChangeQualtiy_1080() {
|
||||
// Hide Menu
|
||||
PlayerMenu_HideAll()
|
||||
// Get Video
|
||||
var video = document.querySelector('video')
|
||||
var audio = document.querySelector('audio')
|
||||
// Get Source
|
||||
video.setAttribute('src', 'http://catactyl.home.ro:5006/The%20Mark%20On%20The%20Wall/1080.mp4')
|
||||
// Get Current Timestamp
|
||||
var CurrentTimestamp = document.querySelector("#seek").getAttribute('data-seek')
|
||||
// Go To Timestamp
|
||||
setTimeout(() => {
|
||||
video.pause();
|
||||
audio.pause();
|
||||
video.currentTime = CurrentTimestamp;
|
||||
audio.currentTime = CurrentTimestamp;
|
||||
video.play();
|
||||
audio.play();
|
||||
}, 0o100);
|
||||
}
|
||||
function ChangeQualtiy_720() {
|
||||
// Hide Menu
|
||||
PlayerMenu_HideAll()
|
||||
// Get Video
|
||||
var video = document.querySelector('video')
|
||||
var audio = document.querySelector('audio')
|
||||
// Get Source
|
||||
video.setAttribute('src', 'http://catactyl.home.ro:5006/The%20Mark%20On%20The%20Wall/720.mp4')
|
||||
// Get Current Timestamp
|
||||
var CurrentTimestamp = document.querySelector("#seek").getAttribute('data-seek')
|
||||
// Go To Timestamp
|
||||
setTimeout(() => {
|
||||
video.pause();
|
||||
audio.pause();
|
||||
video.currentTime = CurrentTimestamp;
|
||||
audio.currentTime = CurrentTimestamp;
|
||||
video.play();
|
||||
audio.play();
|
||||
}, 0o100);
|
||||
}
|
||||
function ChangeQualtiy_360() {
|
||||
// Hide Menu
|
||||
PlayerMenu_HideAll()
|
||||
// Get Video
|
||||
var video = document.querySelector('video')
|
||||
var audio = document.querySelector('audio')
|
||||
// Get Source
|
||||
video.setAttribute('src', 'http://catactyl.home.ro:5006/The%20Mark%20On%20The%20Wall/360.mp4')
|
||||
// Get Current Timestamp
|
||||
var CurrentTimestamp = document.querySelector("#seek").getAttribute('data-seek')
|
||||
// Go To Timestamp
|
||||
setTimeout(() => {
|
||||
video.pause();
|
||||
audio.pause();
|
||||
video.currentTime = CurrentTimestamp;
|
||||
audio.currentTime = CurrentTimestamp;
|
||||
video.play();
|
||||
audio.play();
|
||||
}, 0o100);
|
||||
}
|
||||
</script>
|
|
@ -1,101 +0,0 @@
|
|||
---
|
||||
// Properties
|
||||
const { Poster, Video, Audio } = Astro.props
|
||||
|
||||
// Cookies
|
||||
if (Astro.cookies.get("Milieu").value === "Enabled") {
|
||||
var Milieu = true
|
||||
} else {
|
||||
var Milieu = false
|
||||
}
|
||||
|
||||
// Components
|
||||
import Controls from '@components/video-player/Controls.astro'
|
||||
|
||||
// Styles
|
||||
import '@styles/player.scss'
|
||||
---
|
||||
|
||||
<div class="video-container">
|
||||
<canvas id="ambient-canvas-1"/>
|
||||
<canvas id="ambient-canvas-2"/>
|
||||
<video class="main-video" muted src={Video} poster={Poster} preload="auto"></video>
|
||||
<audio class="main-audio"><source src={Audio} type="audio/mp3"/></audio>
|
||||
<Controls/>
|
||||
</div>
|
||||
|
||||
<!-- Player Functions -->
|
||||
<script is:inline src="/player/controller.js"></script>
|
||||
<script is:inline src="/player/seek.js"></script>
|
||||
<script is:inline src="/player/sync.js"></script>
|
||||
|
||||
{Milieu ?
|
||||
<script is:inline>
|
||||
const AMvideo = document.querySelector("video")
|
||||
const oddCanvas = document.getElementById("ambient-canvas-1")
|
||||
const evenCanvas = document.getElementById("ambient-canvas-2")
|
||||
const oddCtx = oddCanvas.getContext("2d")
|
||||
const evenCtx = evenCanvas.getContext("2d")
|
||||
|
||||
const frameIntervalMs = 2000
|
||||
const canvasOpacity = "0.4"
|
||||
|
||||
let intervalId
|
||||
let oddFrame = true
|
||||
const drawFrame = () => {
|
||||
if (oddFrame) {
|
||||
oddCtx.drawImage(AMvideo, 0, 0, oddCanvas.width, oddCanvas.height)
|
||||
transitionToOddCanvas()
|
||||
} else {
|
||||
evenCtx.drawImage(AMvideo, 0, 0, evenCanvas.width, evenCanvas.height)
|
||||
transitionToEvenCanvas()
|
||||
}
|
||||
oddFrame = !oddFrame
|
||||
};
|
||||
|
||||
const transitionToOddCanvas = () => {
|
||||
oddCanvas.style.opacity = canvasOpacity
|
||||
evenCanvas.style.opacity = "0"
|
||||
}
|
||||
|
||||
const transitionToEvenCanvas = () => {
|
||||
evenCanvas.style.opacity = canvasOpacity
|
||||
oddCanvas.style.opacity = "0"
|
||||
}
|
||||
|
||||
const drawStart = () => {
|
||||
intervalId = window.setInterval(drawFrame, frameIntervalMs)
|
||||
}
|
||||
|
||||
const drawPause = () => {
|
||||
if (intervalId) window.clearInterval(intervalId)
|
||||
}
|
||||
|
||||
const init = () => {
|
||||
|
||||
//fixes a issue where firefox/chromium fails to load the ambinet mode and doesnt load it. - please dont remove this line lmao
|
||||
|
||||
AMvideo.pause();AMvideo.play();
|
||||
|
||||
// DO NOT REMOVE
|
||||
|
||||
AMvideo.addEventListener("play", drawStart, false)
|
||||
AMvideo.addEventListener("pause", drawPause, false)
|
||||
AMvideo.addEventListener("ended", drawPause, false)
|
||||
|
||||
oddCanvas.style.transition = evenCanvas.style.transition = `opacity ${frameIntervalMs}ms`
|
||||
}
|
||||
|
||||
const cleanup = () => {
|
||||
AMvideo.removeEventListener("play", drawStart)
|
||||
AMvideo.removeEventListener("pause", drawPause)
|
||||
AMvideo.removeEventListener("ended", drawPause)
|
||||
drawPause();
|
||||
}
|
||||
|
||||
window.addEventListener("load", init)
|
||||
window.addEventListener("unload", cleanup)
|
||||
</script>
|
||||
:
|
||||
null
|
||||
}
|
2
source/src/env.d.ts
vendored
2
source/src/env.d.ts
vendored
|
@ -1,2 +0,0 @@
|
|||
/// <reference path="../.astro/types.d.ts" />
|
||||
/// <reference types="astro/client" />
|
|
@ -1,58 +0,0 @@
|
|||
---
|
||||
// Properties
|
||||
const { Title, Description } = Astro.props
|
||||
|
||||
// Components
|
||||
import Head from '@components/global/Head.astro'
|
||||
|
||||
// Styles
|
||||
import '@styles/index.scss'
|
||||
import '@styles/mobile.scss'
|
||||
---
|
||||
|
||||
<Head Title='MinPluto' Description={Description}/>
|
||||
<div class="api-wait">
|
||||
<center><img src="/images/logo/MinPluto - Logo.png"/></center>
|
||||
<div class="progress-bar"><div class="progress-bar-value"></div></div>
|
||||
<slot/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.api-wait {
|
||||
position: fixed;
|
||||
top: 30%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: grid;
|
||||
gap: 64px;
|
||||
width: 360px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
height: 6px;
|
||||
background-color: rgba(5, 114, 206, 0.2);
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
|
||||
.progress-bar-value {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgb(5, 114, 206);
|
||||
animation: indeterminateAnimation 1s infinite linear;
|
||||
transform-origin: 0% 50%;
|
||||
}
|
||||
|
||||
@keyframes indeterminateAnimation {
|
||||
0% {
|
||||
transform: translateX(0) scaleX(0);
|
||||
}
|
||||
40% {
|
||||
transform: translateX(0) scaleX(0.4);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(100%) scaleX(0.5);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,22 +0,0 @@
|
|||
---
|
||||
// Properties
|
||||
const { Title, Description } = Astro.props;
|
||||
|
||||
// Components
|
||||
import Head from "@components/global/Head.astro";
|
||||
import MobileNav from "@components/global/MobileNav.astro";
|
||||
import Sidebar from "@components/global/Sidebar.astro";
|
||||
import Footer from "@components/global/Footer.astro";
|
||||
|
||||
// Styles
|
||||
import "@styles/index.scss";
|
||||
import "@styles/mobile.scss";
|
||||
---
|
||||
|
||||
<Head Title={Title} Description={Description} />
|
||||
<MobileNav />
|
||||
<Sidebar />
|
||||
<div class="content">
|
||||
<slot />
|
||||
</div>
|
||||
<Footer />
|
|
@ -1,29 +0,0 @@
|
|||
---
|
||||
// Properties
|
||||
const {
|
||||
Title,
|
||||
Description,
|
||||
EmbedId,
|
||||
EmbedVideo,
|
||||
EmbedImage,
|
||||
EmbedTitle
|
||||
} = Astro.props
|
||||
|
||||
// Components
|
||||
import Head from '@components/global/Head.astro'
|
||||
import Footer from '@components/global/Footer.astro'
|
||||
|
||||
// Styles
|
||||
import '@styles/embed.scss'
|
||||
---
|
||||
|
||||
<Head
|
||||
Title={Title}
|
||||
Description={Description}
|
||||
EmbedId={EmbedId}
|
||||
EmbedVideo={EmbedVideo}
|
||||
EmbedImage={EmbedImage}
|
||||
EmbedTitle={EmbedTitle}
|
||||
/>
|
||||
<slot/>
|
||||
<Footer/>
|
|
@ -1,34 +0,0 @@
|
|||
---
|
||||
// Properties
|
||||
const {
|
||||
Title,
|
||||
Message
|
||||
} = Astro.props
|
||||
---
|
||||
|
||||
<div class="error">
|
||||
<a href='/'><img src="/images/logo/MinPluto - Logo.png"/></a>
|
||||
<hr/>
|
||||
<div>
|
||||
<h2>{Title}</h2>
|
||||
<p>{Message}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style is:inline>
|
||||
body {
|
||||
background: black;
|
||||
color: white;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.error {
|
||||
position: fixed;
|
||||
max-width: 500px;
|
||||
margin: auto;
|
||||
margin-top: 90px;
|
||||
text-align: center;
|
||||
left: 50%;
|
||||
transform: translate(-50%);
|
||||
}
|
||||
</style>
|
|
@ -1,34 +0,0 @@
|
|||
---
|
||||
// Properties
|
||||
const { Title, Description } = Astro.props
|
||||
|
||||
// Components
|
||||
import Head from '@components/global/Head.astro'
|
||||
import MobileNav from '@components/global/MobileNav.astro'
|
||||
import Sidebar from '@components/global/Sidebar.astro'
|
||||
import Footer from '@components/global/Footer.astro'
|
||||
|
||||
// Styles
|
||||
import '@styles/index.scss'
|
||||
import '@styles/mobile.scss'
|
||||
---
|
||||
|
||||
<Head Title={Title} Description={Description}/>
|
||||
<MobileNav/>
|
||||
<Sidebar/>
|
||||
<div class="markdown">
|
||||
<slot/>
|
||||
</div>
|
||||
<Footer/>
|
||||
|
||||
<style lang="scss">
|
||||
.markdown {
|
||||
background: transparent;
|
||||
color: white;
|
||||
max-width: 700px;
|
||||
margin: auto;
|
||||
margin-top: 32px;
|
||||
margin-bottom: 32px;
|
||||
padding: 6px 24px;
|
||||
}
|
||||
</style>
|
|
@ -1,115 +0,0 @@
|
|||
---
|
||||
// Properties
|
||||
const { Title, Description } = Astro.props
|
||||
|
||||
// Components
|
||||
import Head from '@components/global/Head.astro'
|
||||
import MobileNav from '@components/global/MobileNav.astro'
|
||||
import Sidebar from '@components/global/Sidebar.astro'
|
||||
import Footer from '@components/global/Footer.astro'
|
||||
|
||||
// Styles
|
||||
import '@styles/index.scss'
|
||||
import '@styles/mobile.scss'
|
||||
import { CodeBrackets, EditPencil, EvPlugXmark, FloppyDisk, HelpCircle, InfoCircle, LogOut, Play, PrivacyPolicy, ProfileCircle, Server, UnionAlt, XmarkCircle } from '@iconoir/vue'
|
||||
---
|
||||
|
||||
<Head Title={Title} Description={Description}/>
|
||||
<MobileNav/>
|
||||
<Sidebar/>
|
||||
<div class="content settings-area">
|
||||
<div class="settings-sidebar">
|
||||
<div>
|
||||
<h2>General</h2>
|
||||
<a id="sidebar-disable" href="#"><EditPencil/> Customization</a>
|
||||
<a id="sidebar-disable" href="#"><Play/> Video Player</a>
|
||||
<a id="sidebar-disable" href="#"><CodeBrackets/> CSS/JS</a>
|
||||
<h2>You</h2>
|
||||
<a href="#"><ProfileCircle/> Account</a>
|
||||
<h2>Advanced</h2>
|
||||
<a id="sidebar-disable" href="#"><EvPlugXmark/> Reset</a>
|
||||
<a id="sidebar-disable" href="#"><FloppyDisk/> Backup & Restore</a>
|
||||
<a id="sidebar-disable" href="#"><XmarkCircle/> Delete Account</a>
|
||||
</div>
|
||||
<div>
|
||||
<a id="sidebar-disable" href="#"><HelpCircle/> Help</a>
|
||||
<a href="#"><UnionAlt/> Telemtry</a>
|
||||
<a href="#"><Server/> Instance</a>
|
||||
<a href="#"><PrivacyPolicy/> Privacy Policy</a>
|
||||
<hr/>
|
||||
<a href="#"><LogOut/> Log Out</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-content">
|
||||
<slot/>
|
||||
</div>
|
||||
</div>
|
||||
<Footer/>
|
||||
|
||||
<style is:inline>a[href="/settings"] {background: rgb(255 255 255 / 25%) !important;border: 2px rgba(255, 255, 255, 0.25) solid !important;}</style>
|
||||
<style lang="scss">
|
||||
.settings-area {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
position: relative;
|
||||
flex-wrap: wrap;
|
||||
align-items: stretch;
|
||||
min-height: 100vh;
|
||||
.settings-content {
|
||||
max-width: 750px;
|
||||
margin: 0px auto;
|
||||
}
|
||||
.settings-sidebar {
|
||||
background: #161616;
|
||||
width: 224px;
|
||||
color: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 0px 12px;
|
||||
div {
|
||||
position: sticky;
|
||||
}
|
||||
div:nth-child(1) {
|
||||
position: sticky;
|
||||
top: 0px;
|
||||
}
|
||||
div:nth-child(2) {
|
||||
position: sticky;
|
||||
bottom: 0px;
|
||||
}
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
padding-left: 12px;
|
||||
}
|
||||
a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin-bottom: 6px;
|
||||
border-radius: 6px;
|
||||
padding: 4px 12px;
|
||||
background: transparent;
|
||||
border: 2px transparent solid;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
font-size: 14px;
|
||||
&:hover {
|
||||
background: rgb(255 255 255 / 05%);
|
||||
border: 2px rgba(255, 255, 255, 0.05) solid;
|
||||
}
|
||||
svg {
|
||||
width: 18px;
|
||||
}
|
||||
&#sidebar-disable {
|
||||
filter: brightness(0.4);
|
||||
cursor: not-allowed;
|
||||
&:hover {
|
||||
background: transparent;
|
||||
border: 2px transparent solid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,20 +0,0 @@
|
|||
---
|
||||
import { changeLanguage } from "i18next";
|
||||
import Base from "@layouts/Default.astro";
|
||||
|
||||
|
||||
---
|
||||
|
||||
<Base Title="MinPluto" Description="">
|
||||
<div class="force-center">
|
||||
<h2>Error 404: Page Not Found</h2>
|
||||
<p>The page you've requested has either been moved or never existed. Double check the URL you're viewing.</p>
|
||||
</div>
|
||||
</Base>
|
||||
|
||||
<style>
|
||||
.force-center {
|
||||
text-align: center;
|
||||
padding-top: 10%;
|
||||
}
|
||||
</style>
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
import ErrorLayout from '@layouts/Error.astro'
|
||||
|
||||
// Fetch Error Output
|
||||
// https://github.com/withastro/astro/blob/main/packages/astro/src/core/errors/errors.ts#L5-L11
|
||||
interface Props {
|
||||
error: unknown
|
||||
}
|
||||
|
||||
const { error } = Astro.props
|
||||
---
|
||||
|
||||
<ErrorLayout Title={error.name} Message={error instanceof Error ? error.message : 'Unknown error'}/>
|
|
@ -1,53 +0,0 @@
|
|||
---
|
||||
import i18next,{ t, changeLanguage } from "i18next";
|
||||
import Base from "@layouts/Default.astro";
|
||||
|
||||
import '@styles/form.scss'
|
||||
---
|
||||
|
||||
<Base Title="MinPluto" Description="">
|
||||
<div class="force-center">
|
||||
<img src="/images/logo/MinPluto - Image Logo Full with Shadow.png"/>
|
||||
<hr/>
|
||||
<img src="/images/backgrounds/1.webp"/>
|
||||
</div>
|
||||
<form action="/api/auth/confirm" method="post">
|
||||
<div class="form-field">
|
||||
<label>Email</label>
|
||||
<input name="email" type="email" autocomplete="off" required/>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label>Code</label>
|
||||
<input name="code" type="text" autocomplete="off" required/>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<div></div>
|
||||
<div>
|
||||
<span></span>
|
||||
<button type="submit">Confirm</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Base>
|
||||
|
||||
<style is:global>
|
||||
img[src="/images/backgrounds/1.webp"] {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
left: 50%;
|
||||
transform: translate(-57%);
|
||||
-webkit-mask-image: linear-gradient(180deg, transparent 5%, rgb(0 0 0) 52%, rgb(0 0 0) 44%, transparent 95%);
|
||||
}
|
||||
@media only screen and (min-width: 875px) {
|
||||
img[src="/images/backgrounds/1.webp"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.force-center {
|
||||
text-align: center;
|
||||
padding-top: 10%;
|
||||
}
|
||||
.search-bar {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
|
@ -1,59 +0,0 @@
|
|||
---
|
||||
// i18n
|
||||
import i18next,{ t, changeLanguage } from "i18next";
|
||||
import Settings from "@layouts/Settings.astro";
|
||||
|
||||
// Supabase Data
|
||||
import { supabase } from "@library/supabase"
|
||||
const { data: { user } } = await supabase.auth.getUser()
|
||||
const ID = user?.id
|
||||
const Name = user?.user_metadata.name
|
||||
const Email = user?.email
|
||||
|
||||
// Styles
|
||||
import '@styles/form.scss'
|
||||
---
|
||||
|
||||
<Settings Title="Account" Description="Manage your account">
|
||||
<p>Account ID: {ID}</p>
|
||||
<form action="/api/update/name" method="post">
|
||||
<div class="form-field">
|
||||
<label>Username</label>
|
||||
<input name="name" type="text" autocomplete="off" value={Name} required/>
|
||||
</div>
|
||||
<div class="form-actions"><div></div><div><span></span><button type="submit">Update</button></div></div>
|
||||
</form>
|
||||
<form>
|
||||
<div class="form-field">
|
||||
<label>Email</label>
|
||||
<input name="email" type="email" autocomplete="off" value={Email} readonly/>
|
||||
</div>
|
||||
<div class="form-actions"><div></div><div><span></span><button type="submit">Update</button></div></div>
|
||||
</form>
|
||||
<form onkeypress="CheckPasswordConfirmation()">
|
||||
<div class="form-field">
|
||||
<label>Password</label>
|
||||
<input id="password" name="password" type="password" autocomplete="off" required/>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label>Confirm Password</label>
|
||||
<input id="confirm_password" name="password" type="password" autocomplete="off" required/>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<div>
|
||||
<a href="#">Forgot Password</a>
|
||||
</div>
|
||||
<div><span></span><button type="submit">Update</button></div>
|
||||
</div>
|
||||
</form>
|
||||
</Settings>
|
||||
|
||||
<script is:inline>
|
||||
function CheckPasswordConfirmation() {
|
||||
if (document.getElementById('confirm_password').value !== document.getElementById('password').value) {
|
||||
document.getElementById('confirm_password').setCustomValidity('Password Must be Matching.');
|
||||
} else {
|
||||
document.getElementById('confirm_password').setCustomValidity('');
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -1,20 +0,0 @@
|
|||
import type { APIRoute } from "astro"
|
||||
import { supabase } from "@library/supabase"
|
||||
|
||||
export const POST: APIRoute = async ({ request, redirect }) => {
|
||||
const formData = await request.formData()
|
||||
const EMAIL = formData.get("email")?.toString()
|
||||
const OTP = formData.get("code")?.toString()
|
||||
|
||||
if (!OTP) {
|
||||
return new Response("Code required", { status: 400 })
|
||||
}
|
||||
|
||||
const { error } = await supabase.auth.verifyOtp({type: 'email', token: OTP, email: EMAIL})
|
||||
|
||||
if (error) {
|
||||
return new Response(error.message, { status: 500 })
|
||||
}
|
||||
|
||||
return redirect("/login?=confirmed")
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
import type { APIRoute } from "astro"
|
||||
import { supabase } from "@library/supabase"
|
||||
|
||||
export const POST: APIRoute = async ({ request, cookies, redirect }) => {
|
||||
const formData = await request.formData()
|
||||
const email = formData.get("email")?.toString()
|
||||
const password = formData.get("password")?.toString()
|
||||
|
||||
if (!email || !password) {
|
||||
return new Response("Email and password are required", { status: 400 })
|
||||
}
|
||||
|
||||
const { data, error } = await supabase.auth.signInWithPassword({
|
||||
email,
|
||||
password,
|
||||
})
|
||||
|
||||
if (error) {
|
||||
return new Response(error.message, { status: 500 })
|
||||
}
|
||||
|
||||
const { access_token, refresh_token } = data.session
|
||||
cookies.set("sb-access-token", access_token, {
|
||||
sameSite: "strict",
|
||||
path: "/",
|
||||
secure: true,
|
||||
})
|
||||
cookies.set("sb-refresh-token", refresh_token, {
|
||||
sameSite: "strict",
|
||||
path: "/",
|
||||
secure: true,
|
||||
})
|
||||
|
||||
return redirect("/")
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
import type { APIRoute } from "astro"
|
||||
import { supabase } from "@library/supabase"
|
||||
import type { Provider } from "@supabase/supabase-js"
|
||||
|
||||
export const GET: APIRoute = async ({ cookies, redirect }) => {
|
||||
|
||||
if(cookies.get('anonymous-session')) {
|
||||
return redirect('/account/anon/end')
|
||||
} else {
|
||||
cookies.delete("sb-access-token", { path: "/" })
|
||||
cookies.delete("sb-refresh-token", { path: "/" })
|
||||
const { error } = await supabase.auth.signOut()
|
||||
}
|
||||
return redirect("/")
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
import type { APIRoute } from "astro"
|
||||
import { supabase } from "@library/supabase"
|
||||
|
||||
export const POST: APIRoute = async ({ request, redirect }) => {
|
||||
const formData = await request.formData()
|
||||
const name = formData.get("username")?.toString()
|
||||
const email = formData.get("email")?.toString()
|
||||
const password = formData.get("password")?.toString()
|
||||
|
||||
if (!email || !password || !name) {
|
||||
return new Response("Email and password are required", { status: 400 })
|
||||
}
|
||||
|
||||
const { error } = await supabase.auth.signUp({
|
||||
options: {
|
||||
emailRedirectTo: "http://localhost:1930/?=welcome",
|
||||
data: {
|
||||
name: name,
|
||||
ui_theme: "Default",
|
||||
ui_color: "Default",
|
||||
ui_zen: "false",
|
||||
ui_sidebar_size: "Normal",
|
||||
invidous_data: "https://yt.sudovanilla.org",
|
||||
invidous_media: "https://yt.sudovanilla.org",
|
||||
safetwitch_data: "https://twitch.sudovanilla.org",
|
||||
safetwitch_media: "https://twitch.sudovanilla.org",
|
||||
image_proxy: "https://ipx.sudovanilla.org",
|
||||
player_type: "Zorn"
|
||||
}
|
||||
},
|
||||
email,
|
||||
password,
|
||||
})
|
||||
|
||||
if (error) {
|
||||
return new Response(error.message, { status: 500 })
|
||||
}
|
||||
|
||||
return redirect("/account/confirm-your-email")
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
---
|
||||
// Layout
|
||||
import API from '@layouts/API.astro'
|
||||
|
||||
// API Action
|
||||
Astro.cookies.set("Language", "EN", {
|
||||
path: "/",
|
||||
sameSite: "strict"
|
||||
});
|
||||
|
||||
// Track Event
|
||||
import { OpenpanelSdk } from '@openpanel/sdk';
|
||||
const op = new OpenpanelSdk({
|
||||
clientId: 'b4c27f56-18f5-4d66-bb62-cbf7f7161812',
|
||||
clientSecret: 'sec_107558407af59a591b50',
|
||||
});
|
||||
if (Astro.cookies.get("Telemtry").value === "Enabled") {
|
||||
op.event('Language', { Language: 'English' });
|
||||
}
|
||||
else if (Astro.cookies.get("Telemtry").value === "Disabled") {
|
||||
null
|
||||
}
|
||||
|
||||
// Return
|
||||
return Astro.redirect("/");
|
||||
---
|
||||
<API Title="MinPluto" Description=""></API>
|
|
@ -1,27 +0,0 @@
|
|||
---
|
||||
// Layout
|
||||
import API from '@layouts/API.astro'
|
||||
|
||||
// API Action
|
||||
Astro.cookies.set("Language", "JP", {
|
||||
path: "/",
|
||||
sameSite: "strict"
|
||||
});
|
||||
|
||||
// Track Event
|
||||
import { OpenpanelSdk } from '@openpanel/sdk';
|
||||
const op = new OpenpanelSdk({
|
||||
clientId: 'b4c27f56-18f5-4d66-bb62-cbf7f7161812',
|
||||
clientSecret: 'sec_107558407af59a591b50',
|
||||
});
|
||||
if (Astro.cookies.get("Telemtry").value === "Enabled") {
|
||||
op.event('Language', { Language: 'Japanese' });
|
||||
}
|
||||
else if (Astro.cookies.get("Telemtry").value === "Disabled") {
|
||||
null
|
||||
}
|
||||
|
||||
// Return
|
||||
return Astro.redirect("/");
|
||||
---
|
||||
<API Title="MinPluto" Description=""></API>
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
import API from '@layouts/API.astro'
|
||||
Astro.cookies.set("Milieu", "Disabled", {
|
||||
path: "/",
|
||||
sameSite: "strict"
|
||||
});
|
||||
return Astro.redirect("/");
|
||||
---
|
||||
<API Title="MinPluto" Description=""></API>
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
// Layout
|
||||
import API from '@layouts/API.astro'
|
||||
|
||||
// API Action
|
||||
Astro.cookies.set("Milieu", "Enabled", {
|
||||
path: "/",
|
||||
sameSite: "strict"
|
||||
});
|
||||
|
||||
// Return
|
||||
return Astro.redirect("/telemtry");
|
||||
---
|
||||
<API Title="MinPluto" Description=""></API>
|
|
@ -1,24 +0,0 @@
|
|||
---
|
||||
import Base from "@layouts/Default.astro"
|
||||
const CreatorId = Astro.url.href.split("add?=").pop()
|
||||
import { supabase } from "@library/supabase"
|
||||
const { data: { user } } = await supabase.auth.getUser()
|
||||
const { data, error } = await supabase
|
||||
.from('subs')
|
||||
.insert([
|
||||
{
|
||||
UserSubscribed: user?.id,
|
||||
Id: CreatorId,
|
||||
Platform: "YouTube"
|
||||
},
|
||||
])
|
||||
.select()
|
||||
|
||||
return Astro.redirect("/channel/" + CreatorId)
|
||||
---
|
||||
|
||||
<Base Title="MinPluto">
|
||||
<div class="content">
|
||||
<p>One moment...</p>
|
||||
</div>
|
||||
</Base>
|
|
@ -1,21 +0,0 @@
|
|||
---
|
||||
import Base from "@layouts/Default.astro"
|
||||
const CreatorId = Astro.url.href.split("remove?=").pop()
|
||||
import { supabase } from "@library/supabase"
|
||||
const { data: { user } } = await supabase.auth.getUser()
|
||||
const id = user?.id
|
||||
const { data, error } = await supabase
|
||||
.from('subs')
|
||||
.delete()
|
||||
.eq('UserSubscribed', id)
|
||||
.eq('Id', CreatorId)
|
||||
.eq('Platform', 'YouTube')
|
||||
|
||||
return Astro.redirect("/channel/" + CreatorId)
|
||||
---
|
||||
|
||||
<Base Title="MinPluto">
|
||||
<div class="content">
|
||||
<p>One moment...</p>
|
||||
</div>
|
||||
</Base>
|
|
@ -1,24 +0,0 @@
|
|||
---
|
||||
import API from '@layouts/API.astro'
|
||||
Astro.cookies.set("Telemtry", "Disabled", {
|
||||
path: "/",
|
||||
sameSite: "strict"
|
||||
});
|
||||
return Astro.redirect("/telemtry");
|
||||
|
||||
// SDK
|
||||
import { OpenpanelSdk } from '@openpanel/sdk';
|
||||
const op = new OpenpanelSdk({
|
||||
clientId: 'b4c27f56-18f5-4d66-bb62-cbf7f7161812',
|
||||
clientSecret: 'sec_107558407af59a591b50',
|
||||
});
|
||||
|
||||
// Track Event
|
||||
if (Astro.cookies.get("Telemtry").value === "Enabled") {
|
||||
op.event('Language', { Language: 'English' });
|
||||
}
|
||||
else if (Astro.cookies.get("Telemtry").value === "Disabled") {
|
||||
null
|
||||
}
|
||||
---
|
||||
<API Title="MinPluto" Description=""></API>
|
|
@ -1,36 +0,0 @@
|
|||
---
|
||||
// Layout
|
||||
import API from '@layouts/API.astro'
|
||||
|
||||
// API Action
|
||||
Astro.cookies.set("Telemtry", "Enabled", {
|
||||
path: "/",
|
||||
sameSite: "strict"
|
||||
});
|
||||
|
||||
// SDK
|
||||
import { OpenpanelSdk } from '@openpanel/sdk';
|
||||
const op = new OpenpanelSdk({
|
||||
clientId: 'b4c27f56-18f5-4d66-bb62-cbf7f7161812',
|
||||
clientSecret: 'sec_107558407af59a591b50',
|
||||
});
|
||||
|
||||
// Track Event
|
||||
import { useUserAgent } from "astro-useragent";
|
||||
const uaString = Astro.request.headers.get("user-agent");
|
||||
const {
|
||||
os,
|
||||
browser,
|
||||
browserVersion,
|
||||
isDesktop,
|
||||
isMobile
|
||||
} = useUserAgent(uaString);
|
||||
op.event('Operating System', {OS: os})
|
||||
op.event('Browser', {Browser: browser + ' v' + browserVersion})
|
||||
op.event('Desktop', {Desktop: isDesktop})
|
||||
op.event('Mobile', {Mobile: isMobile})
|
||||
|
||||
// Return
|
||||
return Astro.redirect("/telemtry");
|
||||
---
|
||||
<API Title="MinPluto" Description=""></API>
|
|
@ -1,22 +0,0 @@
|
|||
import type { APIRoute } from "astro"
|
||||
import { supabase } from "@library/supabase"
|
||||
|
||||
export const POST: APIRoute = async ({ request, redirect }) => {
|
||||
const formData = await request.formData()
|
||||
const NewEmail = formData.get("email")?.toString()
|
||||
|
||||
if (!NewEmail) {
|
||||
return new Response("Error.", { status: 400 })
|
||||
}
|
||||
|
||||
const { error } = await supabase.auth.resend({
|
||||
type: 'email_change',
|
||||
email: NewEmail
|
||||
})
|
||||
|
||||
if (error) {
|
||||
return new Response(error.message, { status: 500 })
|
||||
}
|
||||
|
||||
return redirect("/account?=CheckEmail")
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
import type { APIRoute } from "astro"
|
||||
import { supabase } from "@library/supabase"
|
||||
|
||||
export const POST: APIRoute = async ({ request, redirect }) => {
|
||||
const formData = await request.formData()
|
||||
const name = formData.get("name")?.toString()
|
||||
|
||||
if (!name) {
|
||||
return new Response("Error.", { status: 400 })
|
||||
}
|
||||
|
||||
const { error } = await supabase.auth.updateUser({
|
||||
data: {name: name}
|
||||
})
|
||||
|
||||
if (error) {
|
||||
return new Response(error.message, { status: 500 })
|
||||
}
|
||||
|
||||
return redirect("/account?=NameUpdated")
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
---
|
||||
import Base from "@layouts/Default.astro";
|
||||
import Search from "@components/Search.astro";
|
||||
---
|
||||
|
||||
<Base Title="MinPluto" Description="">
|
||||
<br />
|
||||
<Search />
|
||||
</Base>
|
||||
|
||||
<style lang="scss" is:global is:inline>
|
||||
.search-bar {
|
||||
margin: auto;
|
||||
max-width: 500px;
|
||||
position: relative;
|
||||
input {
|
||||
color: white;
|
||||
background: #121212;
|
||||
border: 2px #242424 solid;
|
||||
padding: 6px 12px;
|
||||
border-radius: 6px;
|
||||
font-size: 16px;
|
||||
width: 100%;
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
button {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
color: #acacac;
|
||||
background: #242424;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 0px 12px;
|
||||
margin: 5px;
|
||||
font-size: 0px;
|
||||
}
|
||||
}
|
||||
.suggestions {
|
||||
display: grid;
|
||||
border-radius: 6px;
|
||||
border: 2px #242424 solid;
|
||||
background: #121212;
|
||||
margin-top: 6px;
|
||||
a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
padding: 4px 12px;
|
||||
font-size: 14px;
|
||||
&:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
import { t, changeLanguage } from "i18next";
|
||||
import Category from "@layouts/Category.astro";
|
||||
|
||||
|
||||
---
|
||||
|
||||
<Category GradientHero="#269753" FetchData="?type=gaming" CategoryName={t("SIDEBAR.CATEGORY_LIST.GAMES")} CategoryDescription={t("SIDEBAR.CATEGORY_LIST.GAMES_DESCRIPTION")}></Category>
|
||||
<style is:inline>a[href="/category/gaming"] {background: rgb(255 255 255 / 25%) !important;border: 2px rgba(255, 255, 255, 0.25) solid !important;}</style>
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
import { t, changeLanguage } from "i18next";
|
||||
import Category from "@layouts/Category.astro";
|
||||
|
||||
|
||||
---
|
||||
|
||||
<Category GradientHero="#ff4f4f" FetchData="?type=movies" CategoryName={t("SIDEBAR.CATEGORY_LIST.MOVIES")} CategoryDescription={t("SIDEBAR.CATEGORY_LIST.MOVIES_DESCRIPTION")}>
|
||||
</Category>
|
||||
<style is:inline>a[href="/category/movies"] {background: rgb(255 255 255 / 25%) !important;border: 2px rgba(255, 255, 255, 0.25) solid !important;}</style>
|
|
@ -1,111 +0,0 @@
|
|||
---
|
||||
import { t, changeLanguage } from "i18next";
|
||||
import Default from "@layouts/Default.astro";
|
||||
|
||||
|
||||
|
||||
// Configuration
|
||||
import {
|
||||
DEFAULT_MEDIA_DATA_PROXY
|
||||
} from '@utils/GetConfig'
|
||||
|
||||
// Components
|
||||
import MusicItem from '@components/MusicItem.astro'
|
||||
|
||||
// Fetch
|
||||
const fetchFrom = DEFAULT_MEDIA_DATA_PROXY + '/api/v1/trending?type=music'
|
||||
const response = await fetch(fetchFrom)
|
||||
const data = await response.json()
|
||||
|
||||
const heroItem = data.slice(0,1)
|
||||
---
|
||||
|
||||
<Default FetchData="?type=movies" Title={t("SIDEBAR.CATEGORY_LIST.MUSIC")} Description={t("SIDEBAR.CATEGORY_LIST.MUSIC_DESCRIPTION")}>
|
||||
<div class="category-hero">
|
||||
<div class="c-hero-content">
|
||||
<div style="width: 25%;">
|
||||
<h2>Music</h2>
|
||||
<p>Listen to the latest hits</p>
|
||||
</div>
|
||||
<div class="c-hero-video">
|
||||
{heroItem.map((data) =>
|
||||
<video autoplay muted src={DEFAULT_MEDIA_DATA_PROXY + '/latest_version?id=' + data.videoId + '&itag=22&local=true'}></video>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span id="gradient-header"></span>
|
||||
<div class="or-mu">
|
||||
<span></span>
|
||||
<p id="title">{t("MUSIC.TITLE")}</p>
|
||||
<p id="artist">{t("MUSIC.ARTIST")}</p>
|
||||
<p id="date">{t("MUSIC.UPLOADED")}</p>
|
||||
<p id="duration">{t("MUSIC.DURATION")}</p>
|
||||
</div>
|
||||
<div class="music-list">
|
||||
{data.map((data) =>
|
||||
<MusicItem
|
||||
ID={data.videoId}
|
||||
Title={data.title}
|
||||
Creator={data.author}
|
||||
Views={data.viewCount}
|
||||
UploadDate={data.published}
|
||||
Length={data.lengthSeconds}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Default>
|
||||
<style is:inline>a[href="/en /category/music"] {background: rgb(255 255 255 / 25%) !important;border: 2px rgba(255, 255, 255, 0.25) solid !important;}</style>
|
||||
|
||||
<style lang="scss">
|
||||
.category-hero {
|
||||
margin-top: -80px;
|
||||
background: linear-gradient(180deg, #502969, transparent);
|
||||
padding-top: 80px;
|
||||
.c-hero-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: auto;
|
||||
max-width: 1000px;
|
||||
justify-content: space-between;
|
||||
.c-hero-video {
|
||||
-webkit-mask-box-image: radial-gradient(rgb(0 0 0 / 50%), transparent);
|
||||
-webkit-mask-box-image: linear-gradient(90deg, black, rgba(0, 0, 0, 0));
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
video {
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
width: 75%;
|
||||
height: 100%;
|
||||
float: right;
|
||||
-webkit-mask-box-image: linear-gradient(270deg, black, transparent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.or-mu {
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
gap: 12px;
|
||||
grid-template-columns: 60px auto auto 80px 64px;
|
||||
max-width: 1000px;
|
||||
margin: auto;
|
||||
border-bottom: 1px #252525 solid;
|
||||
margin-bottom: 24px;
|
||||
position: sticky;
|
||||
top: 58px;
|
||||
background: black;
|
||||
#artist, #duration, #date {
|
||||
text-align: right;
|
||||
}
|
||||
#title {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
import { t, changeLanguage } from "i18next";
|
||||
import Category from "@layouts/Category.astro";
|
||||
|
||||
|
||||
---
|
||||
|
||||
<Category GradientHero="#ff650b" FetchData="" CategoryName={t("SIDEBAR.CATEGORY_LIST.TRENDING")} CategoryDescription={t("SIDEBAR.CATEGORY_LIST.TRENDING_DESCRIPTION")}></Category>
|
||||
<style is:inline>a[href="/category/trending"] {background: rgb(255 255 255 / 25%) !important;border: 2px rgba(255, 255, 255, 0.25) solid !important;}</style>
|
|
@ -1,183 +0,0 @@
|
|||
---
|
||||
import Base from "@layouts/Default.astro";
|
||||
|
||||
// i18n
|
||||
import i18next, { t, changeLanguage } from "i18next";
|
||||
|
||||
|
||||
// Configuration
|
||||
import { DEFAULT_MEDIA_DATA_PROXY, DEFAULT_IMAGE_PROXY, SERVER_DOMAIN } from '@utils/GetConfig'
|
||||
import { BrightStar, Donate, Download, ShareIos, ThumbsUp } from "@iconoir/vue";
|
||||
|
||||
// Components
|
||||
import Video from '@components/VideoItem.astro'
|
||||
|
||||
// Fetch
|
||||
const CreatorId = Astro.url.href.split("channel/").pop();
|
||||
const channel = await fetch(DEFAULT_MEDIA_DATA_PROXY + "/api/v1/channels/" + CreatorId).then((response) => response.json());
|
||||
const DescriptionFormat = channel.descriptionHtml.replaceAll("\n", " <br/> ");
|
||||
|
||||
// Is the user logged in?
|
||||
if (Astro.cookies.get('sb-access-token') === undefined) {
|
||||
var Guest = true
|
||||
} else {
|
||||
var Guest = false
|
||||
}
|
||||
|
||||
// User Subscription
|
||||
import { supabase } from "@library/supabase"
|
||||
const { data: { user } } = await supabase.auth.getUser()
|
||||
const id = user?.id
|
||||
let { data: subs } = await supabase
|
||||
.from('subs')
|
||||
.select("*")
|
||||
.eq('UserSubscribed', id)
|
||||
.eq('Id', CreatorId)
|
||||
|
||||
|
||||
if (Guest === false) {
|
||||
if (subs[0] === undefined) {
|
||||
var Subbed = false
|
||||
} else {
|
||||
var Subbed = true
|
||||
}
|
||||
}
|
||||
else {
|
||||
var Subbed = "NotLoggedIn"
|
||||
}
|
||||
---
|
||||
|
||||
<Base Title="MinPluto" Description="">
|
||||
<div class="channel-backdrop">
|
||||
<!-- <img src={channel.authorBanners[0].url}/> --> <!-- BROKEN -->
|
||||
</div>
|
||||
{Subbed ?
|
||||
<a href={'/api/subscription/remove?=' + CreatorId}>Unfollow</a>
|
||||
:
|
||||
<a href={'/api/subscription/add?=' + CreatorId}>Follow</a>
|
||||
}
|
||||
{
|
||||
()=> {
|
||||
if (Subbed === true) {
|
||||
return <a href={'/api/subscription/remove?=' + CreatorId}>Unfollow</a>
|
||||
} else if (Subbed === false) {
|
||||
return <a href={'/api/subscription/add?=' + CreatorId}>Follow</a>
|
||||
} else if(Subbed === "NotLoggedIn") {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
<div class="channel">
|
||||
<div class="channel-header">
|
||||
<div class="channel-banner">
|
||||
<!-- <img src={channel.authorBanners[0].url}/> --> <!-- BROKEN -->
|
||||
</div>
|
||||
<div class="channel-meta">
|
||||
<div>
|
||||
<img src={channel.authorThumbnails[1].url}/>
|
||||
<h2>{channel.author}</h2>
|
||||
<p>{channel.subCountText}</p>
|
||||
</div>
|
||||
<div>
|
||||
<!-- {channel.isFamilyFriendly ? <p id="family-friendly"><BrightStar/> {t("CHANNEL.FAMILY_FRIENDLY")}</p> : null} -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="channel-content">
|
||||
<!-- <div class="channel-tabs">
|
||||
<a href="#">{t("CHANNEL.HOME")}</a>
|
||||
<a href="#">{t("CHANNEL.VIDEOS")}</a>
|
||||
<a href="#">{t("CHANNEL.COMMUNITY")}</a>
|
||||
</div> -->
|
||||
<div class="channel-tab-content">
|
||||
<p><Fragment set:html={DescriptionFormat}/></p>
|
||||
<hr/>
|
||||
<h2>Latest Videos</h2>
|
||||
<div class="video-grid">
|
||||
{channel.latestVideos.map((data) =>
|
||||
<Video
|
||||
ID={data.videoId}
|
||||
Title={data.title}
|
||||
Creator={data.author}
|
||||
Views={data.viewCount}
|
||||
UploadDate={data.published}
|
||||
Length={data.lengthSeconds}
|
||||
/>
|
||||
)}
|
||||
<!-- <a>View All Latest Videos</a> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Base>
|
||||
|
||||
<style lang="scss">
|
||||
.channel-backdrop img {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: max-content;
|
||||
filter: blur(30px) contrast(0.8);
|
||||
z-index: -1;
|
||||
transform: scale(1.4);
|
||||
opacity: 0.3;
|
||||
display: none;
|
||||
}
|
||||
.channel {
|
||||
max-width: 1000px;
|
||||
margin: auto;
|
||||
.channel-header {
|
||||
.channel-banner {
|
||||
margin: 12px 0px;
|
||||
img {
|
||||
width: 100%;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
.channel-meta {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
#family-friendly {
|
||||
color: white;
|
||||
background: #3b003b;
|
||||
border: 1px #a500a5 solid;
|
||||
border-radius: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 6px 12px;
|
||||
gap: 12px;
|
||||
pointer-events: none;
|
||||
}
|
||||
div:nth-child(1) {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 12px;
|
||||
img {
|
||||
border-radius: 3rem;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.channel-content {
|
||||
.channel-tabs {
|
||||
padding-top: 24px;
|
||||
padding-bottom: 12px;
|
||||
cursor: default;
|
||||
a {
|
||||
text-decoration: none;
|
||||
font-size: 18px;
|
||||
padding: 12px 24px;
|
||||
border-radius: 24px;
|
||||
&:hover {
|
||||
background: rgba(41, 41, 41, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,112 +0,0 @@
|
|||
---
|
||||
// Layout
|
||||
import Base from "@layouts/Default.astro"
|
||||
|
||||
// i18n
|
||||
import { t, changeLanguage } from "i18next"
|
||||
|
||||
// Configuration
|
||||
import { DEFAULT_MEDIA_DATA_PROXY, DEFAULT_IMAGE_PROXY, DEFAULT_STREAM_DATA_PROXY } from '@utils/GetConfig'
|
||||
|
||||
// Components
|
||||
import Video from '@components/VideoItem.astro'
|
||||
import Stream from "@components/search/Stream.astro"
|
||||
|
||||
// Get URL Strings
|
||||
const SearchQueryWithParameters = Astro.url.href.split("&?").shift()
|
||||
const SearchQuery = SearchQueryWithParameters.split("discover?category=").pop()
|
||||
if (Astro.url.href.includes('?platform=youtube')) {var SelectedPlatform = "YouTube"}
|
||||
else if (Astro.url.href.includes('?platform=twitch')) {var SelectedPlatform = "Twitch"}
|
||||
var FullCategoryName = SearchQuery.charAt(0).toUpperCase() + SearchQuery.slice(1)
|
||||
|
||||
// Fetch
|
||||
if (Astro.url.href.includes('?platform=youtube')) {
|
||||
var PlatformYouTube = true
|
||||
var YouTubeCategory = DEFAULT_MEDIA_DATA_PROXY + '/api/v1/trending?type=' + SearchQuery
|
||||
var YouTubeFetch = await fetch(YouTubeCategory)
|
||||
var YouTubeData = await YouTubeFetch.json()
|
||||
}
|
||||
else if (Astro.url.href.includes('?platform=twitch')) {
|
||||
var PlatformTwitch = true
|
||||
var TwitchFetch = await fetch('https://twitch-backend.sudovanilla.org/api/discover/' + SearchQuery)
|
||||
var TwitchData = await TwitchFetch.json()
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
<Base Title='MinPluto'>
|
||||
<div class="discover-heading">
|
||||
{PlatformTwitch ?
|
||||
<div>
|
||||
<h2>{TwitchData.data.displayName}</h2>
|
||||
<p>{TwitchData.data.viewers} Viewers</p>
|
||||
</div>
|
||||
<p>{TwitchData.data.description}</p>
|
||||
<ul>
|
||||
<p>Tags: </p>
|
||||
{TwitchData.data.tags.map((tag) =>
|
||||
<li>{tag}</li>
|
||||
)}
|
||||
</ul>
|
||||
:
|
||||
null
|
||||
}
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="video-grid">
|
||||
{PlatformYouTube ?
|
||||
YouTubeData.map((video) =>
|
||||
<Video server:defer
|
||||
ID={video.videoId}
|
||||
Title={video.title}
|
||||
Creator={video.author}
|
||||
Views={video.viewCount}
|
||||
UploadDate={video.published}
|
||||
Length={video.lengthSeconds}
|
||||
/>
|
||||
)
|
||||
:
|
||||
null
|
||||
}
|
||||
{PlatformTwitch ?
|
||||
TwitchData.data.streams.map((channel) =>
|
||||
<Stream server:defer
|
||||
Title={channel.title}
|
||||
Creator={channel.username}
|
||||
Avatar={channel.streamer.pfp}
|
||||
Link={'/live?=' + channel.streamer.name}
|
||||
Thumbnail={channel.preview}
|
||||
View={channel.viewers}
|
||||
/>
|
||||
)
|
||||
:
|
||||
null
|
||||
}
|
||||
</div>
|
||||
</Base>
|
||||
|
||||
<style lang="scss">
|
||||
.discover-heading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0px 24px;
|
||||
div {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
ul {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0px;
|
||||
gap: 12px;
|
||||
li {
|
||||
background: #181818;
|
||||
list-style: none;
|
||||
padding: 12px 24px;
|
||||
border-radius: 3rem;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,129 +0,0 @@
|
|||
---
|
||||
import { t, changeLanguage } from "i18next";
|
||||
import Embed from "@layouts/Embed.astro";
|
||||
import "@styles/video.scss";
|
||||
|
||||
// Configuration
|
||||
import { DEFAULT_MEDIA_DATA_PROXY, DEFAULT_IMAGE_PROXY, SERVER_DOMAIN } from '@utils/GetConfig'
|
||||
|
||||
// Components
|
||||
import { Zorn } from "@minpluto/zorn"
|
||||
|
||||
// Fetch
|
||||
const SWV = Astro.url.href.split("embed/").pop();
|
||||
const video = await fetch(DEFAULT_MEDIA_DATA_PROXY + "/api/v1/videos/" + SWV).then((response) => response.json());
|
||||
|
||||
// Quality Check
|
||||
const EightKCheck = await fetch(DEFAULT_MEDIA_DATA_PROXY + '/latest_version?id=' + video.videoId + '&itag=571')
|
||||
if (EightKCheck.status == 200) {
|
||||
var EightK = true
|
||||
} else {
|
||||
var EightK = false
|
||||
}
|
||||
|
||||
const FourKCheck = await fetch(DEFAULT_MEDIA_DATA_PROXY + '/latest_version?id=' + video.videoId + '&itag=313')
|
||||
if (FourKCheck.status == 200) {
|
||||
var FourK = true
|
||||
} else {
|
||||
var FourK = false
|
||||
}
|
||||
|
||||
const TenEightyCheck = await fetch(DEFAULT_MEDIA_DATA_PROXY + '/latest_version?id=' + video.videoId + '&itag=303')
|
||||
if (TenEightyCheck.status == 200) {
|
||||
var TenEighty = true
|
||||
} else {
|
||||
var TenEighty = false
|
||||
}
|
||||
|
||||
const ThreeSixtyCheck = await fetch(DEFAULT_MEDIA_DATA_PROXY + '/latest_version?id=' + video.videoId + '&itag=134')
|
||||
if (ThreeSixtyCheck.status == 200) {var ThreeSixty = true}
|
||||
|
||||
if (EightK === true) { // 571
|
||||
var Quality = '571'
|
||||
} else if (FourK === true) { // 313
|
||||
var Quality = '313'
|
||||
} else if (TenEighty === true) { // 137
|
||||
var Quality = '303'
|
||||
} else if (ThreeSixty === true) { // 134
|
||||
var Quality = '134'
|
||||
}
|
||||
---
|
||||
|
||||
<Embed
|
||||
Title={video.title}
|
||||
EmbedId={video.videoId}
|
||||
EmbedVideo={DEFAULT_MEDIA_DATA_PROXY + '/latest_version?id=' + video.videoId + '&itag=22&local=true'}
|
||||
EmbedImage={DEFAULT_IMAGE_PROXY + '/https://i.ytimg.com/vi/' + video.videoId + '/maxresdefault.jpg'}
|
||||
EmbedTitle={video.title}
|
||||
>
|
||||
<div class="video-container">
|
||||
<Zorn
|
||||
Poster={DEFAULT_IMAGE_PROXY + '/https://i.ytimg.com/vi/' + video.videoId + '/maxresdefault.jpg'}
|
||||
Video={DEFAULT_MEDIA_DATA_PROXY + '/latest_version?id=' + video.videoId + '&itag=' + Quality + '&local=true'}
|
||||
Audio={DEFAULT_MEDIA_DATA_PROXY + '/latest_version?id=' + video.videoId + '&itag=140'}
|
||||
VideoAttributes="muted"
|
||||
AudioAttributes=""
|
||||
/>
|
||||
</div>
|
||||
</Embed>
|
||||
|
||||
<script is:inline>
|
||||
function DownloadDialogShow() {
|
||||
var DownloadDialog = document.querySelector('#dialog-Download')
|
||||
var BackdropDialog = document.querySelector('.dialog-backdrop')
|
||||
DownloadDialog.style.display = 'flex'
|
||||
BackdropDialog.style.display = 'inherit'
|
||||
}
|
||||
function DownloadDialogHide() {
|
||||
var DownloadDialog = document.querySelector('#dialog-Download')
|
||||
var BackdropDialog = document.querySelector('.dialog-backdrop')
|
||||
DownloadDialog.style.display = 'none'
|
||||
BackdropDialog.style.display = 'none'
|
||||
}
|
||||
function ShareDialogShow() {
|
||||
var ShareDialog = document.querySelector('#dialog-Share')
|
||||
var BackdropDialog = document.querySelector('.dialog-backdrop')
|
||||
ShareDialog.style.display = 'flex'
|
||||
BackdropDialog.style.display = 'inherit'
|
||||
}
|
||||
function ShareDialogHide() {
|
||||
var ShareDialog = document.querySelector('#dialog-Share')
|
||||
var BackdropDialog = document.querySelector('.dialog-backdrop')
|
||||
ShareDialog.style.display = 'none'
|
||||
BackdropDialog.style.display = 'none'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.video-container {
|
||||
max-width: 1000px;
|
||||
margin: auto;
|
||||
.zorn-player {
|
||||
border-radius: 10px;
|
||||
}
|
||||
.zorn-player-controls {
|
||||
border-radius: 0px 0px 10px 10px;
|
||||
}
|
||||
}
|
||||
.video-item {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
.dialog-downloads-list {
|
||||
display: grid;
|
||||
grid-gap: 12px;
|
||||
a {
|
||||
background: rgb(51 51 51);
|
||||
border: 2px rgba(255,255,255,0.05) solid;
|
||||
font-size: 18px;
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
padding: 9px 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
// Components
|
||||
import Trending from "@components/category/trending.astro";
|
||||
---
|
||||
<Trending FetchData=""/>
|
|
@ -1,158 +0,0 @@
|
|||
P---
|
||||
import i18next,{ t, changeLanguage } from "i18next";
|
||||
import Base from "@layouts/Default.astro";
|
||||
|
||||
// Configuration
|
||||
import {
|
||||
DEFAULT_MEDIA_DATA_PROXY,
|
||||
DEFAULT_IMAGE_PROXY,
|
||||
DEFAULT_STREAM_DATA_PROXY
|
||||
} from '@utils/GetConfig'
|
||||
import { FireFlame, Frame, Gamepad, GraphUp, Movie, MusicDoubleNote } from "@iconoir/vue";
|
||||
|
||||
// Components
|
||||
import Trending from "@components/category/trending.astro";
|
||||
import Chip from "@components/Chip.astro";
|
||||
import CategoryCard from "@components/category/CategoryCard.astro";
|
||||
|
||||
// Fetch
|
||||
const TrendingFetch = DEFAULT_MEDIA_DATA_PROXY + '/api/v1/trending'
|
||||
const TrendingResponse = await fetch(TrendingFetch)
|
||||
const TrendingData = await TrendingResponse.json()
|
||||
const TrendingSplit = TrendingData.slice(0, 1)
|
||||
|
||||
const MoviesFetch = DEFAULT_MEDIA_DATA_PROXY + '/api/v1/trending?type=movies'
|
||||
const MoviesResponse = await fetch(MoviesFetch)
|
||||
const MoviesData = await MoviesResponse.json()
|
||||
const MoviesSplit = MoviesData.slice(0, 1)
|
||||
|
||||
|
||||
const MusicFetch = DEFAULT_MEDIA_DATA_PROXY + '/api/v1/trending?type=music'
|
||||
const MusicResponse = await fetch(MusicFetch)
|
||||
const MusicData = await MusicResponse.json()
|
||||
const MusicSplit = MusicData.slice(0, 1)
|
||||
|
||||
|
||||
const GamingFetch = DEFAULT_MEDIA_DATA_PROXY + '/api/v1/trending?type=gaming'
|
||||
const GamingResponse = await fetch(GamingFetch)
|
||||
const GamingData = await GamingResponse.json()
|
||||
const GamingSplit = GamingData.slice(0, 1)
|
||||
|
||||
/// Twitch (/api/discover/)
|
||||
const TwitchDiscoverFetch = await fetch(DEFAULT_STREAM_DATA_PROXY + '/api/discover')
|
||||
const TwitchDiscoverData = await TwitchDiscoverFetch.json()
|
||||
---
|
||||
|
||||
<Base Title="MinPluto" Description="">
|
||||
<br/>
|
||||
<div class="category-select-grid" style="grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)) !important;">
|
||||
{TrendingSplit.map((data) =>
|
||||
<CategoryCard
|
||||
Link={'/discover?category=trending&?platform=youtube'}
|
||||
Name={t("SIDEBAR.CATEGORY_LIST.POPULAR")}
|
||||
Platform="YouTube"
|
||||
Thumbnail={DEFAULT_IMAGE_PROXY + '/' + 'https://img.youtube.com/' + '/vi/' + data.videoId + '/mqdefault.jpg'}
|
||||
Ratio="16:9"
|
||||
server:defer
|
||||
>
|
||||
<div slot="fallback" class="fl-sk-video" style="height: 328px;"></div>
|
||||
</CategoryCard>
|
||||
)}
|
||||
{MoviesSplit.map((data) =>
|
||||
<CategoryCard
|
||||
Link={'/discover?category=movies&?platform=youtube'}
|
||||
Name={t("SIDEBAR.CATEGORY_LIST.TRAILERS")}
|
||||
Platform="YouTube"
|
||||
Thumbnail={DEFAULT_IMAGE_PROXY + '/' + 'https://img.youtube.com/' + '/vi/' + data.videoId + '/mqdefault.jpg'}
|
||||
Ratio="16:9"
|
||||
server:defer
|
||||
>
|
||||
<div slot="fallback" class="fl-sk-video" style="height: 328px;"></div>
|
||||
</CategoryCard>
|
||||
)}
|
||||
{MusicSplit.map((data) =>
|
||||
<CategoryCard
|
||||
Link={'/discover?category=music&?platform=youtube'}
|
||||
Name={t("SIDEBAR.CATEGORY_LIST.MUSIC")}
|
||||
Platform="YouTube"
|
||||
Thumbnail={DEFAULT_IMAGE_PROXY + '/' + 'https://img.youtube.com/' + '/vi/' + data.videoId + '/mqdefault.jpg'}
|
||||
Ratio="16:9"
|
||||
server:defer
|
||||
>
|
||||
<div slot="fallback" class="fl-sk-video" style="height: 328px;"></div>
|
||||
</CategoryCard>
|
||||
)}
|
||||
{GamingSplit.map((data) =>
|
||||
<CategoryCard
|
||||
Link={'/discover?category=gaming&?platform=youtube'}
|
||||
Name={t("SIDEBAR.CATEGORY_LIST.GAMES")}
|
||||
Platform="YouTube"
|
||||
Thumbnail={DEFAULT_IMAGE_PROXY + '/' + 'https://img.youtube.com/' + '/vi/' + data.videoId + '/mqdefault.jpg'}
|
||||
Ratio="16:9"
|
||||
server:defer
|
||||
>
|
||||
<div slot="fallback" class="fl-sk-video" style="height: 328px;"></div>
|
||||
</CategoryCard>
|
||||
)}
|
||||
</div>
|
||||
<br/>
|
||||
<div id="twitch" class="category-select-grid">
|
||||
{TwitchDiscoverData.data.map((data) =>
|
||||
<CategoryCard
|
||||
Link={'/discover?category=' + data.name + '&?platform=twitch'}
|
||||
Name={data.displayName}
|
||||
Platform="Twitch"
|
||||
Thumbnail={DEFAULT_IMAGE_PROXY + '/' + data.image}
|
||||
Ratio="9:16"
|
||||
server:defer
|
||||
>
|
||||
<div slot="fallback" class="fl-sk-video" style="height: 328px;"></div>
|
||||
</CategoryCard>
|
||||
)}
|
||||
</div>
|
||||
<br/>
|
||||
</Base>
|
||||
|
||||
|
||||
<style is:inline>.sidebar-top-end a[href="/"] {background: rgb(255 255 255 / 25%) !important;border: 2px rgba(255, 255, 255, 0.25) solid !important;}</style>
|
||||
<style is:global lang="scss">
|
||||
@keyframes load {
|
||||
0% { background-position-x: -100px; }
|
||||
100% { background-position-x: -100%; }
|
||||
}
|
||||
.fl-sk-video {
|
||||
height: 183px;
|
||||
width: 100%;
|
||||
background-image: linear-gradient(90deg, #323232 0px, #4c4c4c 40px, #323232 80px);
|
||||
background-size: 600px;
|
||||
animation: load 2s linear infinite;
|
||||
border-radius: 6px;
|
||||
}
|
||||
img[src="/images/backgrounds/1.webp"] {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
left: 50%;
|
||||
transform: translate(-57%);
|
||||
-webkit-mask-image: linear-gradient(180deg, transparent 5%, rgb(0 0 0) 52%, rgb(0 0 0) 44%, transparent 95%);
|
||||
}
|
||||
@media only screen and (min-width: 875px) {
|
||||
img[src="/images/backgrounds/1.webp"] {
|
||||
display: none;
|
||||
}
|
||||
.category-select-grid {
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)) !important;
|
||||
}
|
||||
}
|
||||
.force-center {
|
||||
text-align: center;
|
||||
padding-top: 10%;
|
||||
}
|
||||
.category-select-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
grid-gap: 25px;
|
||||
max-width: 1600px;
|
||||
margin: auto;
|
||||
padding: 0px 24px;
|
||||
}
|
||||
</style>
|
|
@ -1,49 +0,0 @@
|
|||
---
|
||||
layout: '@layouts/Settings.astro'
|
||||
---
|
||||
|
||||
import {
|
||||
SERVER_ADMIN,
|
||||
SERVER_LOCATION,
|
||||
DEFAULT_MEDIA_PROXY,
|
||||
DEFAULT_MEDIA_DATA_PROXY,
|
||||
DEFAULT_STREAM_PROXY,
|
||||
DEFAULT_STREAM_DATA_PROXY,
|
||||
DEFAULT_IMAGE_PROXY,
|
||||
MODIFIED,
|
||||
CUSTOM_SOURCE_CODE,
|
||||
ANALYTICS,
|
||||
} from '@utils/GetConfig'
|
||||
|
||||
import Invidous from '@components/information/Invidious.astro'
|
||||
import InstanceList from '@components/information/InstanceList.astro'
|
||||
|
||||
MinPluto Instance Information
|
||||
-----------------------------
|
||||
|
||||
Server Operator: {SERVER_ADMIN}
|
||||
|
||||
Location: {SERVER_LOCATION}
|
||||
|
||||
Invidious Media Proxy: {DEFAULT_MEDIA_PROXY}
|
||||
|
||||
Invidious Data Proxy: {DEFAULT_MEDIA_DATA_PROXY}
|
||||
|
||||
SafeTwitch Data Proxy: {DEFAULT_STREAM_PROXY}
|
||||
|
||||
SafeTwitch Media Proxy: {DEFAULT_STREAM_DATA_PROXY}
|
||||
|
||||
Image Proxy: {DEFAULT_IMAGE_PROXY}
|
||||
|
||||
Modified: {MODIFIED}
|
||||
|
||||
{MODIFIED ? <p>Modified Source Code: {CUSTOM_SOURCE_CODE}</p> : null}
|
||||
|
||||
Analytics Software: {ANALYTICS}
|
||||
|
||||
___
|
||||
|
||||
MinPluto Instances
|
||||
---------------------------
|
||||
|
||||
<InstanceList/>
|
|
@ -1,191 +0,0 @@
|
|||
---
|
||||
// Layout
|
||||
import Base from "@layouts/Default.astro";
|
||||
import "@styles/video.scss";
|
||||
|
||||
// Environment Variables
|
||||
// const DEFAULT_IMAGE_PROXY = import.meta.env.DEFAULT_IMAGE_PROXY
|
||||
// const DEFAULT_STREAM_PROXY = import.meta.env.DEFAULT_STREAM_PROXY
|
||||
// const DEFAULT_STREAM_DATA_PROXY = import.meta.env.DEFAULT_STREAM_DATA_PROXY
|
||||
|
||||
// Components
|
||||
import { Zorn } from "@minpluto/zorn";
|
||||
import { ArrowDown } from "@iconoir/vue";
|
||||
|
||||
// Fetch
|
||||
const CreatorName = Astro.url.href.split("live?=").pop();
|
||||
const Creator = await fetch("https://twitch-backend.sudovanilla.org" + "/api/users/" + CreatorName,).then((response) => response.json());
|
||||
|
||||
// Check if the Creator is live
|
||||
if(Creator.data.isLive == true) {
|
||||
var IsLive = true
|
||||
} else if(Creator.data.isLive == false) {
|
||||
var IsLive = false
|
||||
}
|
||||
---
|
||||
|
||||
<Base>
|
||||
<noscript>
|
||||
<p>
|
||||
In order to watch a Twitch live stream on MinPluto, your browser is
|
||||
required to have JavaScript enabled.
|
||||
</p>
|
||||
<p>
|
||||
If your browser does not support JavaScript, try a modern web browser such
|
||||
as Firefox.
|
||||
</p>
|
||||
</noscript>
|
||||
|
||||
<div class="creator-tw-backdrop" style={"background-image: radial-gradient(ellipse farthest-side at center top, #" + Creator.data.colorHex + ", hsla(0, 0%, 0%, 0) 100%);"}></div>
|
||||
<div class="creator-tw">
|
||||
<div class="creator-tw-start">
|
||||
<img class="creator-tw-banner" src={"https://ipx.sudovanilla.org" + "/" + Creator.data.banner} />
|
||||
<div class="creator-tw-start-top">
|
||||
{IsLive ? <span id="streamer-online" class="tw-status">Online</span> : <span id="streamer-offline" class="tw-status">Offline</span>}
|
||||
<h2 style="margin: 24px 0px 6px 0px;">{Creator.data.username}</h2>
|
||||
<p style="margin: 0px;font-size: 12px;color: gray;">{Creator.data.followers} Followers</p>
|
||||
<br/>
|
||||
<p>{Creator.data.about}</p>
|
||||
<div class="creator-tw-socials">
|
||||
{Creator.data.socials.map((social) =>
|
||||
<a style={"background: #" + Creator.data.colorHex} href={social.url}>{social.name}</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div class="creator-tw-start-bottom"></div>
|
||||
</div>
|
||||
<div class="creator-tw-end">
|
||||
{IsLive ?
|
||||
<Zorn
|
||||
Live
|
||||
Video={"https://twitch-backend.sudovanilla.org" +
|
||||
"/proxy/stream/" +
|
||||
CreatorName +
|
||||
"/hls.m3u8"}
|
||||
/>
|
||||
:
|
||||
<div class="creator-is-offline">
|
||||
<p>Offline</p>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</Base>
|
||||
|
||||
{IsLive ?
|
||||
<style>
|
||||
.creator-tw {
|
||||
backdrop-filter: blur(24px) contrast(0.8) brightness(0.8);
|
||||
}
|
||||
.creator-tw-start::before, .creator-tw-banner {
|
||||
border-radius: 12px 0px 0px 12px;
|
||||
}
|
||||
</style>
|
||||
:
|
||||
<style>
|
||||
.creator-tw-start::before, .creator-tw-banner {
|
||||
border-radius: 12px;
|
||||
}
|
||||
</style>
|
||||
}
|
||||
|
||||
<style is:global lang="scss">
|
||||
.creator-tw-backdrop {
|
||||
background-color: transparent;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
}
|
||||
.creator-tw {
|
||||
border-radius: 12px;
|
||||
margin: 24px;
|
||||
display: grid;
|
||||
grid-template-columns: 300px auto;
|
||||
min-height: 500px;
|
||||
.creator-tw-start {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 24px;
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
backdrop-filter: blur(24px) contrast(0.8) brightness(0.8);
|
||||
}
|
||||
.creator-tw-banner {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
z-index: -2;
|
||||
}
|
||||
.tw-status {
|
||||
background: transparent;
|
||||
border-radius: 3rem;
|
||||
padding: 6px 12px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
#streamer-online {
|
||||
background: #c95050;
|
||||
}
|
||||
#streamer-offline {
|
||||
background: #454545;
|
||||
}
|
||||
.creator-tw-socials {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
flex-wrap: wrap;
|
||||
a {
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
border-radius: 3rem;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.creator-tw-end {
|
||||
position: relative;
|
||||
.video-container {
|
||||
video {
|
||||
border-radius: 0px 12px 12px 0px;
|
||||
}
|
||||
.video-controls {
|
||||
border-radius: 0px 0px 12px 0px !important;
|
||||
}
|
||||
}
|
||||
.creator-is-offline {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
font-size: 90px;
|
||||
letter-spacing: -0.014em;
|
||||
font-weight: 900;
|
||||
color: #ffffff4f;
|
||||
animation: 4.2s TextSpacingIn ease-in-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes TextSpacingIn {
|
||||
from {
|
||||
letter-spacing: 0.086em;
|
||||
opacity: 0.45;
|
||||
}
|
||||
to {
|
||||
letter-spacing: -0.014em;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,58 +0,0 @@
|
|||
---
|
||||
import i18next,{ t, changeLanguage } from "i18next";
|
||||
import Base from "@layouts/Default.astro";
|
||||
|
||||
import '@styles/form.scss'
|
||||
---
|
||||
|
||||
<Base Title="MinPluto" Description="">
|
||||
<div class="force-center">
|
||||
<img src="/images/logo/MinPluto - Image Logo Full with Shadow.png"/>
|
||||
<hr/>
|
||||
<img src="/images/backgrounds/1.webp"/>
|
||||
</div>
|
||||
<form action="/api/auth/login" method="post">
|
||||
<div class="form-field">
|
||||
<label>Email</label>
|
||||
<input name="email" type="email" autocomplete="off" required/>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label>Password</label>
|
||||
<input name="password" type="password" autocomplete="off" required/>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<div>
|
||||
<a aria-disabled="true" href="#">Forgot Password</a>
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="location.href = '/register/'">Create Account</button>
|
||||
<button type="submit">Login</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Base>
|
||||
<style is:inline>a[href="/login"] {background: rgb(255 255 255 / 25%) !important;border: 2px rgba(255, 255, 255, 0.25) solid !important;}</style>
|
||||
<style is:global>
|
||||
img[src="/images/backgrounds/1.webp"] {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
left: 50%;
|
||||
transform: translate(-57%);
|
||||
-webkit-mask-image: linear-gradient(180deg, transparent 5%, rgb(0 0 0) 52%, rgb(0 0 0) 44%, transparent 95%);
|
||||
}
|
||||
@media only screen and (min-width: 875px) {
|
||||
img[src="/images/backgrounds/1.webp"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.force-center {
|
||||
text-align: center;
|
||||
padding-top: 10%;
|
||||
}
|
||||
.search-bar {
|
||||
display: none !important;
|
||||
}
|
||||
form {
|
||||
max-width: 500px !important;
|
||||
}
|
||||
</style>
|
|
@ -1,66 +0,0 @@
|
|||
---
|
||||
import { t, changeLanguage } from "i18next";
|
||||
import Base from "@layouts/Default.astro";
|
||||
import { version } from "@root/package.json";
|
||||
|
||||
|
||||
---
|
||||
|
||||
<Base Title="MinPluto" Description="">
|
||||
<div class="ms">
|
||||
<img src="/images/logo/MinPluto - Image Logo Full with Shadow.png"/>
|
||||
<h2>MinPluto</h2>
|
||||
<p>{t("HOME.P1")}</p>
|
||||
<hr/>
|
||||
<p style="font-size: 14px;"><i>{t("HOME.P2")}</i></p>
|
||||
<hr/>
|
||||
<div style="display: flex; justify-content: space-evenly;">
|
||||
<a href="https://community.minpluto.org/" target="_blank">{t("SIDEBAR.FOOTER.STATUS")}</a>
|
||||
<a href="https://status.minpluto.org/" target="_blank">{t("SIDEBAR.FOOTER.FORUM")}</a>
|
||||
<a href="https://ark.sudovanilla.org/MinPluto/MinPluto" target="_blank">{t("SIDEBAR.FOOTER.SOURCE_CODE")}</a>
|
||||
</div>
|
||||
</div>
|
||||
<p id="version">v{version}</p>
|
||||
<img src="/images/backgrounds/1.webp"/>
|
||||
</Base>
|
||||
|
||||
<style>
|
||||
img[src="/images/backgrounds/1.webp"] {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
left: 50%;
|
||||
transform: translate(-57%);
|
||||
-webkit-mask-image: linear-gradient(180deg, transparent 5%, rgb(0 0 0) 52%, rgb(0 0 0) 44%, transparent 95%);
|
||||
}
|
||||
@media only screen and (min-width: 875px) {
|
||||
img[src="/images/backgrounds/1.webp"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.ms {
|
||||
margin-top: 20%;
|
||||
text-align: center;
|
||||
padding: 0px 24px;
|
||||
}
|
||||
a {
|
||||
color: white;
|
||||
}
|
||||
hr {
|
||||
width: 100px;
|
||||
border: none;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
height: 4px;
|
||||
border-radius: 1rem;
|
||||
margin: 24px auto;
|
||||
}
|
||||
p#version {
|
||||
position: fixed;
|
||||
bottom: 88px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
background: #232323;
|
||||
color: white;
|
||||
padding: 24px 0px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
|
@ -1,40 +0,0 @@
|
|||
---
|
||||
import { t, changeLanguage } from "i18next";
|
||||
import Base from "@layouts/Default.astro";
|
||||
import { HomeSimple, GraphUp, Movie, MusicDoubleNote, Gamepad, AppleImac2021Side, EmojiTalkingHappy, PizzaSlice, Treadmill, PeaceHand } from "@iconoir/vue";
|
||||
|
||||
|
||||
---
|
||||
|
||||
<Base Title="MinPluto" Description="">
|
||||
<div style="padding: 0px 24px;">
|
||||
<h2>Categories</h2>
|
||||
<div id="c" style="display: flex;flex-direction: column;gap: 24px;">
|
||||
<a href="/category/trending"><GraphUp/> {t("CATEGORY_LIST.TRENDING")}</a>
|
||||
<a href="/category/movies"><Movie/> {t("CATEGORY_LIST.MOVIES")}</a>
|
||||
<a href="/category/music"><MusicDoubleNote/> {t("CATEGORY_LIST.MUSIC")}</a>
|
||||
<a href="/category/gaming"><Gamepad/> {t("CATEGORY_LIST.GAMES")}</a>
|
||||
</div>
|
||||
</div>
|
||||
</Base>
|
||||
|
||||
<style lang="scss">
|
||||
#c a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
background: linear-gradient(45deg, #636363, #181818);
|
||||
padding: 48px 24px;
|
||||
font-size: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
border-radius: 10px;
|
||||
svg {
|
||||
position: absolute;
|
||||
right: 60px;
|
||||
width: 100px;
|
||||
height: 70px;
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,20 +0,0 @@
|
|||
---
|
||||
import { changeLanguage } from "i18next";
|
||||
import Base from "@layouts/Default.astro";
|
||||
|
||||
|
||||
---
|
||||
|
||||
<Base Title="MinPluto" Description="">
|
||||
<div class="force-center">
|
||||
<h2>No Internet Connection</h2>
|
||||
<p>It appears that you are offline, try connecting your device to the internet, and try again.</p>
|
||||
</div>
|
||||
</Base>
|
||||
|
||||
<style>
|
||||
.force-center {
|
||||
text-align: center;
|
||||
padding-top: 10%;
|
||||
}
|
||||
</style>
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
layout: '@layouts/Markdown.astro'
|
||||
---
|
||||
|
||||
Error
|
||||
-----------------------------
|
||||
Playlists are not yet supported in MinPluto.
|
|
@ -1,97 +0,0 @@
|
|||
---
|
||||
layout: "@layouts/Settings.astro"
|
||||
---
|
||||
|
||||
import {
|
||||
ANALYTICS
|
||||
} from '@utils/GetConfig'
|
||||
|
||||
import PrivacyPolicyAnalytics from '@components/text/PrivacyPolicyAnalytics.astro'
|
||||
import PrivacyPolicyCloudflare from '@components/text/PrivacyPolicyCloudflare.astro'
|
||||
import OptButtons from '@components/buttons/Telemtry.astro'
|
||||
|
||||
## Privacy Policy
|
||||
|
||||
### 3rd Party Services are Proxied
|
||||
|
||||
Any service in MinPluto that is 3rd party is proxied by this instance or another instance such as images, videos, fonts, scripts, and more. No personal information information is collected and no information is sent to any 3rd party.
|
||||
|
||||
<PrivacyPolicyAnalytics/>
|
||||
|
||||
<PrivacyPolicyCloudflare/>
|
||||
|
||||
### We Don't Know What You're Watching
|
||||
When you watch a video on a MinPluto instance with analytics enabled, the analytics software doesn't show what video are you watching. The query in the URL, which is the video ID, is not saved to analytics. What we see is only "/watch", not "/watch?=dQw4w9WgXcQ". This goes for anything else that may have a query in it.
|
||||
|
||||
### Telemtry
|
||||
Telemtry data is used in MinPluto to see metrics of usage on different features and other aspects. This is help SudoVanilla, the developer of MinPluto, make better and informed decisions on what needs priority.
|
||||
|
||||
By default, all users are opted-out for privacy purposes.
|
||||
|
||||
If you decide to opt-in, the following is tracked:
|
||||
|
||||
* Language
|
||||
* Browser Useragent
|
||||
* Operating System
|
||||
* Errors
|
||||
* Location
|
||||
* All settings, except for some
|
||||
* Platforms you've imported from
|
||||
|
||||
The following will not be tracked:
|
||||
|
||||
* Searches
|
||||
* Videos/Streams you watched
|
||||
* Subscribed Channels
|
||||
* Downloads
|
||||
* Shares
|
||||
* Embeds
|
||||
* Personal Information in your account, such as name and email
|
||||
* CSS/JS Customization
|
||||
* Themes
|
||||
|
||||
Note that this can change at anytime.
|
||||
|
||||
It is expected by the MinPluto developer that all telemtry data is sent to SudoVanilla's OpenPanel ananlytics. Note that the instance operator can easily change the destination of this, it is not expected.
|
||||
|
||||
<div style="text-align: right"><OptButtons/></div>
|
||||
|
||||
### Liability
|
||||
MinPluto and SudoVanilla take no responsibility for the use of our tool, or external instances provided by third parties. It is strongly recommended that you abide by the valid official regulations in your country. Furthermore, we refuse liability for any inappropriate use of MinPluto, such as illegal downloading.
|
||||
|
||||
MinPluto is licenced under AGPL v3, this software is included with a copy.
|
||||
|
||||
<hr/>
|
||||
```
|
||||
Copyright (C) 2024 SudoVanilla
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
```
|
||||
<hr/>
|
||||
|
||||
### Links to Other Sites
|
||||
|
||||
Channels and videos on MinPluto may contain links to other sites. If you click on a third-party link, you will be directed to that site. Note that these external sites are not operated by SudoVanilla, MinPluto, or the MinPluto instance. Therefore, I strongly advise you to review the privacy policy of these websites. I have no control over and assume no responsibility for the content, privacy policies, or practices of any third-party sites or services.
|
||||
|
||||
### Changes to This Privacy Policy
|
||||
|
||||
The developers of MinPluto, SudoVanilla, may update our privacy policy from time to time. Thus, you are advised to review this page periodically for any changes. I will notify you of any changes by posting the new privacy policy on this page.
|
||||
|
||||
This also goes for the instance itself.
|
||||
|
||||
This policy is effective as of March 7th, 2024.
|
||||
|
||||
### Contact Us
|
||||
|
||||
If you have any questions or suggestions about MinPluto's privacy policy, do not hesitate to contact me at hello@minpluto.org or to [submit an issue](https://ark.sudovanilla.org/MinPluto/MinPluto/issues).
|
|
@ -1,66 +0,0 @@
|
|||
---
|
||||
import i18next,{ t, changeLanguage } from "i18next";
|
||||
import Base from "@layouts/Default.astro";
|
||||
|
||||
import '@styles/form.scss'
|
||||
---
|
||||
|
||||
<Base Title="MinPluto" Description="">
|
||||
<div class="force-center">
|
||||
<img src="/images/logo/MinPluto - Image Logo Full with Shadow.png"/>
|
||||
<hr/>
|
||||
<img src="/images/backgrounds/1.webp"/>
|
||||
</div>
|
||||
<form action="/api/auth/register" method="post">
|
||||
<div class="form-field">
|
||||
<label>Username</label>
|
||||
<input name="username" type="text" autocomplete="off" required/>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label>Email</label>
|
||||
<input name="email" type="email" autocomplete="off" required/>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; gap: 6px;">
|
||||
<div style="width: 100%;" class="form-field">
|
||||
<label>Password</label>
|
||||
<input name="password" type="password" autocomplete="off" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<div>
|
||||
<a href="/privacy">Privacy Policy</a>
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="location.href = '/login'">Login</button>
|
||||
<button type="submit">Register</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Base>
|
||||
|
||||
<style is:global>
|
||||
img[src="/images/backgrounds/1.webp"] {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
left: 50%;
|
||||
transform: translate(-57%);
|
||||
-webkit-mask-image: linear-gradient(180deg, transparent 5%, rgb(0 0 0) 52%, rgb(0 0 0) 44%, transparent 95%);
|
||||
z-index: -1;
|
||||
opacity: 0.5;
|
||||
}
|
||||
@media only screen and (min-width: 875px) {
|
||||
img[src="/images/backgrounds/1.webp"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.force-center {
|
||||
text-align: center;
|
||||
padding-top: 10%;
|
||||
}
|
||||
.search-bar {
|
||||
display: none !important;
|
||||
}
|
||||
form {
|
||||
max-width: 500px !important;
|
||||
}
|
||||
</style>
|
|
@ -1,142 +0,0 @@
|
|||
---
|
||||
// Layout
|
||||
import Base from "@layouts/Default.astro"
|
||||
|
||||
// i18n
|
||||
import { t, changeLanguage } from "i18next"
|
||||
|
||||
// Configuration
|
||||
import { DEFAULT_MEDIA_DATA_PROXY, DEFAULT_IMAGE_PROXY, DEFAULT_STREAM_DATA_PROXY } from '@utils/GetConfig'
|
||||
|
||||
// Components
|
||||
import Video from '@components/VideoItem.astro'
|
||||
import DiscoverChannel from "@components/DiscoverChannel.astro"
|
||||
import Stream from "@components/search/Stream.astro"
|
||||
import { Group, Movie, Play, PlaylistPlay, ReportColumns, VideoCamera } from "@iconoir/vue"
|
||||
|
||||
// Fetch
|
||||
const SearchQueryWithParameters = Astro.url.href.split("&?").shift()
|
||||
const SearchQuery = SearchQueryWithParameters.split("search?query=").pop()
|
||||
|
||||
// Check Filters
|
||||
if (Astro.url.href.includes('?type=channel')) {
|
||||
var ShowChannels = true
|
||||
}
|
||||
else if (Astro.url.href.includes('?type=playlist')) {
|
||||
var ShowPlaylists = true
|
||||
}
|
||||
else if (Astro.url.href.includes('?type=stream')) {
|
||||
var ShowStreams = true
|
||||
}
|
||||
else if (Astro.url.href.includes('?type=all')) {
|
||||
var ShowAll = true
|
||||
}
|
||||
else {
|
||||
var ShowVideos = true
|
||||
}
|
||||
|
||||
/// Videos (YouTube)
|
||||
const VideoSearchResults = await fetch(DEFAULT_MEDIA_DATA_PROXY + "/api/v1/search?q=" + SearchQuery + '&page=1&date=none&type=video&duration=none&sort=relevance')
|
||||
const VideoSearch = await VideoSearchResults.json()
|
||||
|
||||
/// Playlists (YouTube)
|
||||
const PlaylistsSearchResults = await fetch(DEFAULT_MEDIA_DATA_PROXY + "/api/v1/search?q=" + SearchQuery + '&page=1&date=none&type=playlist&duration=none&sort=relevance')
|
||||
const PlaylistsSearch = await PlaylistsSearchResults.json()
|
||||
|
||||
// Streams (Twitch)
|
||||
const StreamSearchResults = await fetch(DEFAULT_STREAM_DATA_PROXY + "/api/search/?query=" + SearchQuery)
|
||||
const StreamSearch = await StreamSearchResults.json()
|
||||
|
||||
/// Channels (YouTube)
|
||||
const ChannelSearchResults = await fetch(DEFAULT_MEDIA_DATA_PROXY + "/api/v1/search?q=" + SearchQuery + '&page=1&date=none&type=channel&duration=none&sort=relevance')
|
||||
const ChannelSearch = await ChannelSearchResults.json()
|
||||
---
|
||||
|
||||
<Base Title='MinPluto Search'>
|
||||
<div class="search-tabs">
|
||||
<div>
|
||||
<!-- <a id="search-tab-all" href={'/search?query=' + SearchQuery + '&?type=all'}><ReportColumns/> All</a> -->
|
||||
<a id="search-tab-videos" href={'/search?query=' + SearchQuery}><Play/> Videos</a>
|
||||
<a id="search-tab-playlists" href={'/search?query=' + SearchQuery + '&?type=playlist'}><PlaylistPlay/> Playlists</a>
|
||||
<a id="search-tab-streams" href={'/search?query=' + SearchQuery + '&?type=stream'}><VideoCamera/> Streams</a>
|
||||
<a id="search-tab-creator" href={'/search?query=' + SearchQuery + '&?type=channel'}><Group/> Creators</a>
|
||||
</div>
|
||||
<div>
|
||||
{ShowVideos ? <a style="color: gray;" href={DEFAULT_MEDIA_DATA_PROXY + "/api/v1/search?q=" + SearchQuery + '&page=1&date=none&type=video&duration=none&sort=relevance'}>View JSON</a> : null}
|
||||
{ShowPlaylists ? <a style="color: gray;" href={DEFAULT_MEDIA_DATA_PROXY + "/api/v1/search?q=" + SearchQuery + '&page=1&date=none&type=playlist&duration=none&sort=relevance'}>View JSON</a> : null}
|
||||
{ShowStreams ? <a style="color: gray;" href={DEFAULT_STREAM_DATA_PROXY + "/api/search/?query=" + SearchQuery}>View JSON</a> : null}
|
||||
{ShowChannels ? <a style="color: gray;" href={DEFAULT_MEDIA_DATA_PROXY + "/api/v1/search?q=" + SearchQuery + '&page=1&date=none&type=channel&duration=none&sort=relevance'}>View JSON</a> : null}
|
||||
</div>
|
||||
</div>
|
||||
<!-- {ShowAll ? <style>#search-tab-all {background: white; color: black;}</style> : null} -->
|
||||
{ShowVideos ? <style>#search-tab-videos {background: white; color: black;}</style> : null}
|
||||
{ShowPlaylists ? <style>#search-tab-playlists {background: white; color: black;}</style> : null}
|
||||
{ShowStreams ? <style>#search-tab-streams {background: white; color: black;}</style> : null}
|
||||
{ShowChannels ? <style>#search-tab-creator {background: white; color: black;}</style> : null}
|
||||
<div class="video-grid">
|
||||
{ShowVideos ?
|
||||
VideoSearch.map((video) =>
|
||||
<Video
|
||||
ID={video.videoId}
|
||||
Title={video.title}
|
||||
Creator={video.author}
|
||||
Views={video.viewCount}
|
||||
UploadDate={video.published}
|
||||
Length={video.lengthSeconds}
|
||||
/>
|
||||
)
|
||||
:
|
||||
null
|
||||
}
|
||||
{ShowPlaylists ?
|
||||
PlaylistsSearch.map((playlist) =>
|
||||
<a href={'/playlist?list=' + playlist.playlistId}>{playlist.title}</a>
|
||||
)
|
||||
:
|
||||
null
|
||||
}
|
||||
{ShowChannels ?
|
||||
ChannelSearch.map((channel) =>
|
||||
<DiscoverChannel ChannelId={channel.authorId}/>
|
||||
)
|
||||
:
|
||||
null
|
||||
}
|
||||
{ShowStreams ?
|
||||
StreamSearch.data.relatedChannels.map((channel) =>
|
||||
<Stream
|
||||
Title={channel.stream.title}
|
||||
Creator={channel.username}
|
||||
Avatar={channel.pfp}
|
||||
Link={'/channel/twitch/' + channel.username}
|
||||
Thumbnail={channel.stream.preview}
|
||||
View={channel.stream.viewers}
|
||||
/>
|
||||
)
|
||||
:
|
||||
null
|
||||
}
|
||||
</div>
|
||||
</Base>
|
||||
|
||||
<style lang="scss">
|
||||
.search-tabs {
|
||||
max-width: 1000px;
|
||||
margin: 0px auto 16px auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
div {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
background: transparent;
|
||||
border-radius: 3rem;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,38 +0,0 @@
|
|||
---
|
||||
layout: '@layouts/Settings.astro'
|
||||
---
|
||||
|
||||
import OptButtons from '@components/buttons/Telemtry.astro'
|
||||
|
||||
MinPluto Telemtry
|
||||
-----------------
|
||||
|
||||
Telemtry data is used in MinPluto to see metrics of usage on different features and other aspects. This is to help SudoVanilla, the developer of MinPluto, make better and informed decisions on what needs priority.
|
||||
|
||||
By default, you're opted-out for privacy purposes.
|
||||
|
||||
If you decide to opt-in, the following is tracked:
|
||||
|
||||
* Language
|
||||
* Browser Useragent
|
||||
* Operating System
|
||||
* Errors
|
||||
* Location
|
||||
* All settings, except for some
|
||||
* Platforms you've imported from
|
||||
|
||||
The following will not be tracked:
|
||||
|
||||
* Searches
|
||||
* Videos/Streams you watched
|
||||
* Subscribed Channels
|
||||
* Downloads
|
||||
* Shares
|
||||
* Embeds
|
||||
* Personal Information in your account, such as name and email
|
||||
* CSS/JS Customization
|
||||
* Themes
|
||||
|
||||
Note that this can change at anytime.
|
||||
|
||||
<div style="text-align: right"><OptButtons/></div>
|
|
@ -1,19 +0,0 @@
|
|||
---
|
||||
import Base from "@layouts/Default.astro";
|
||||
import Player from "@components/video-player/Player.astro"
|
||||
---
|
||||
|
||||
<Base>
|
||||
<Player
|
||||
Video="http://catactyl.home.ro:5006/The%20Mark%20On%20The%20Wall/1080.mp4"
|
||||
Audio="http://catactyl.home.ro:5006/The%20Mark%20On%20The%20Wall/audio.mp4"
|
||||
/>
|
||||
</Base>
|
||||
|
||||
<style is:global>
|
||||
.video-container {
|
||||
width: 90%;
|
||||
margin: auto;
|
||||
margin-top: 92px;
|
||||
}
|
||||
</style>
|
|
@ -1,272 +0,0 @@
|
|||
---
|
||||
import { t, changeLanguage } from "i18next"
|
||||
import Base from "@layouts/Default.astro"
|
||||
import "@styles/video.scss"
|
||||
|
||||
// Configuration
|
||||
import { DEFAULT_MEDIA_PROXY, DEFAULT_MEDIA_DATA_PROXY, DEFAULT_IMAGE_PROXY, SERVER_DOMAIN } from '@utils/GetConfig'
|
||||
import { Donate, Download, ShareIos, ThumbsUp, MediaVideo } from "@iconoir/vue"
|
||||
|
||||
// Components
|
||||
import Dialog from '@components/Dialog.astro'
|
||||
import Video from '@components/VideoItem.astro'
|
||||
import { Zorn } from "@minpluto/zorn"
|
||||
|
||||
// Fetch
|
||||
const SWV = Astro.url.href.split("watch?v=").pop();
|
||||
const video = await fetch(DEFAULT_MEDIA_DATA_PROXY + "/api/v1/videos/" + SWV).then((response) => response.json());
|
||||
const comments = await fetch(DEFAULT_MEDIA_DATA_PROXY + "/api/v1/comments/" + SWV).then((response) => response.json());
|
||||
const Description = video.description;
|
||||
const UploadDate = video.published;
|
||||
const Views = video.viewCount;
|
||||
const VideoSeconds = video.lengthSeconds;
|
||||
let DescriptionFormat = Description.replaceAll("\n", " <br/> ");
|
||||
|
||||
var CheckComments = console.log(comments) // If not found, disable comment section
|
||||
|
||||
if (CheckComments = "{ error: 'Comments not found.' }") {
|
||||
var EnableComments = false
|
||||
} else {
|
||||
var EnableComments = true
|
||||
}
|
||||
|
||||
|
||||
// Format Published Date
|
||||
const DateFormat = new Date(UploadDate * 1000).toLocaleDateString();
|
||||
|
||||
// Format Video Length
|
||||
// Thanks to "mingjunlu" for helping out with the time format
|
||||
new Date(VideoSeconds * 1000)
|
||||
.toISOString()
|
||||
.slice(14, 19)
|
||||
.split(":")
|
||||
.map(Number)
|
||||
.join(":");
|
||||
|
||||
// Format Views
|
||||
const ViewsConversion = Intl.NumberFormat("en", { notation: "compact" });
|
||||
let ViewsFormat = ViewsConversion.format(Views);
|
||||
|
||||
// Quality Check
|
||||
const EightKCheck = await fetch(DEFAULT_MEDIA_DATA_PROXY + '/latest_version?id=' + video.videoId + '&itag=571')
|
||||
if (EightKCheck.status == 200) {
|
||||
var EightK = true
|
||||
} else {
|
||||
var EightK = false
|
||||
}
|
||||
|
||||
const FourKCheck = await fetch(DEFAULT_MEDIA_DATA_PROXY + '/latest_version?id=' + video.videoId + '&itag=313')
|
||||
if (FourKCheck.status == 200) {
|
||||
var FourK = true
|
||||
} else {
|
||||
var FourK = false
|
||||
}
|
||||
|
||||
const TenEightyCheck = await fetch(DEFAULT_MEDIA_DATA_PROXY + '/latest_version?id=' + video.videoId + '&itag=303')
|
||||
if (TenEightyCheck.status == 200) {
|
||||
var TenEighty = true
|
||||
} else {
|
||||
var TenEighty = false
|
||||
}
|
||||
|
||||
const ThreeSixtyCheck = await fetch(DEFAULT_MEDIA_DATA_PROXY + '/latest_version?id=' + video.videoId + '&itag=134')
|
||||
if (ThreeSixtyCheck.status == 200) {var ThreeSixty = true}
|
||||
|
||||
if (EightK === true) { // 571
|
||||
var Quality = '571'
|
||||
} else if (FourK === true) { // 313
|
||||
var Quality = '313'
|
||||
} else if (TenEighty === true) { // 137
|
||||
var Quality = '303'
|
||||
} else if (ThreeSixty === true) { // 134
|
||||
var Quality = '134'
|
||||
}
|
||||
---
|
||||
|
||||
<Base Title={video.title}>
|
||||
<Zorn
|
||||
Poster={DEFAULT_IMAGE_PROXY + '/https://i.ytimg.com/vi/' + video.videoId + '/maxresdefault.jpg'}
|
||||
Video={DEFAULT_MEDIA_DATA_PROXY + '/latest_version?id=' + video.videoId + '&itag=' + Quality + '&local=true'}
|
||||
Audio={DEFAULT_MEDIA_DATA_PROXY + '/latest_version?id=' + video.videoId + '&itag=140'}
|
||||
VideoAttributes="muted"
|
||||
AudioAttributes=""
|
||||
/>
|
||||
<div class="video-rea">
|
||||
<div class="rea-details">
|
||||
<p style="font-weight: bold; font-size: 24px;">{video.title}</p>
|
||||
<div class="rea-details-start">
|
||||
<a style="text-decoration: none;" href={video.authorUrl} class="rea-channel">
|
||||
<img src={DEFAULT_IMAGE_PROXY + "/" + video.authorThumbnails[1].url} />
|
||||
<div
|
||||
style="display: flex; flex-direction: column; align-items: left;"
|
||||
>
|
||||
<h2 style="margin: 0px; font-weight: bold; font-size: 18px;">{video.author}</h2>
|
||||
<p style="margin: 0px;" id="subs">
|
||||
{video.subCountText} Subscribers
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
<div style="display: flex; flex-direction: row; align-items: left;">
|
||||
<button onclick="DownloadDialogShow()"><Download /> Download</button>
|
||||
<button onclick={'location.href = "/embed/' + video.videoId + '/"'}><MediaVideo /> Embed</button>
|
||||
<button onclick="ShareDialogShow()"><ShareIos /> Share</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rea-details-end">
|
||||
<p id="views">{ViewsFormat} Views - {DateFormat}</p>
|
||||
<Fragment set:html={DescriptionFormat} />
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex; gap: 24px;">
|
||||
<div class="rea-comments">
|
||||
<h2>{t("WATCH.COMMENTS")}</h2>
|
||||
{EnableComments ?
|
||||
comments.comments.map((comment) => (
|
||||
<div class="comment">
|
||||
<img src={DEFAULT_IMAGE_PROXY + "/" + comment.authorThumbnails[0].url}/>
|
||||
<div>
|
||||
<p><a href={comment.authorUrl}>{comment.author}</a> - 2 Months Ago</p>
|
||||
<p>{comment.contentHtml}</p>
|
||||
<p><ThumbsUp /> {comment.likeCount}</p>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
:
|
||||
<p>Comments are disabled on this video.</p>
|
||||
<style is:global>
|
||||
.rea-comments {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
}
|
||||
</div>
|
||||
<div class="rea-recommendations">
|
||||
<h2>{t("WATCH.RELATED")}</h2>
|
||||
{
|
||||
video.recommendedVideos.map((data) => (
|
||||
<Video
|
||||
ID={data.videoId}
|
||||
Title={data.title}
|
||||
Creator={data.author}
|
||||
Views={data.viewCount}
|
||||
UploadDate={data.published}
|
||||
Length={data.lengthSeconds}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Base>
|
||||
|
||||
<script is:inline>
|
||||
function DownloadDialogShow() {
|
||||
var DownloadDialog = document.querySelector('#dialog-Download')
|
||||
var BackdropDialog = document.querySelector('.dialog-backdrop')
|
||||
DownloadDialog.style.display = 'flex'
|
||||
BackdropDialog.style.display = 'inherit'
|
||||
}
|
||||
function DownloadDialogHide() {
|
||||
var DownloadDialog = document.querySelector('#dialog-Download')
|
||||
var BackdropDialog = document.querySelector('.dialog-backdrop')
|
||||
DownloadDialog.style.display = 'none'
|
||||
BackdropDialog.style.display = 'none'
|
||||
}
|
||||
function ShareDialogShow() {
|
||||
var ShareDialog = document.querySelector('#dialog-Share')
|
||||
var BackdropDialog = document.querySelector('.dialog-backdrop')
|
||||
ShareDialog.style.display = 'flex'
|
||||
BackdropDialog.style.display = 'inherit'
|
||||
}
|
||||
function ShareDialogHide() {
|
||||
var ShareDialog = document.querySelector('#dialog-Share')
|
||||
var BackdropDialog = document.querySelector('.dialog-backdrop')
|
||||
ShareDialog.style.display = 'none'
|
||||
BackdropDialog.style.display = 'none'
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<script is:inline>
|
||||
// https://gist.github.com/michancio/59b9f3dc54b3ff4f6a84
|
||||
// Find elements
|
||||
var SyncVideo = document.querySelector('.main-video');
|
||||
var SyncAudio = document.querySelector('.main-audio');
|
||||
|
||||
// Object for synchronization of multiple media/sources
|
||||
if (typeof (window.MediaController) === 'function') {
|
||||
var controller = new MediaController();
|
||||
SyncVideo.controller = controller;
|
||||
SyncAudio.controller = controller;
|
||||
}
|
||||
else {controller = null}
|
||||
|
||||
// Run SyncAudio and SyncVideo simultaneously
|
||||
SyncVideo.addEventListener('play', function () {
|
||||
if (!controller && SyncAudio.paused) {
|
||||
SyncAudio.play();
|
||||
}
|
||||
}, false);
|
||||
|
||||
// Pause/Play and Buffering
|
||||
SyncVideo.addEventListener('waiting', () => { // If SyncVideo is buffering
|
||||
SyncAudio.pause()
|
||||
});
|
||||
SyncVideo.addEventListener('playing', () => { // If SyncVideo is done buffering
|
||||
SyncAudio.play()
|
||||
SyncTimestamp()
|
||||
});
|
||||
|
||||
SyncVideo.addEventListener('pause', function () {
|
||||
if (!controller && !SyncAudio.paused) {
|
||||
SyncAudio.pause();
|
||||
}
|
||||
}, false);
|
||||
|
||||
// When Media Ends
|
||||
SyncVideo.addEventListener('ended', function () {
|
||||
if (controller) {
|
||||
controller.pause();
|
||||
}
|
||||
else {
|
||||
SyncVideo.pause();
|
||||
SyncAudio.pause();
|
||||
}
|
||||
}, false);
|
||||
|
||||
// Seekbar
|
||||
function SyncTimestamp() {SyncAudio.currentTime = SyncVideo.currentTime}
|
||||
</script>
|
||||
|
||||
<style is:global lang="scss">
|
||||
.video-container {
|
||||
max-width: 100%;
|
||||
margin: 48px 24px 23px 24px;
|
||||
}
|
||||
.video-item {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.video-controls, video {
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
.dialog-downloads-list {
|
||||
display: grid;
|
||||
grid-gap: 12px;
|
||||
a {
|
||||
background: rgb(51 51 51);
|
||||
border: 2px rgba(255,255,255,0.05) solid;
|
||||
font-size: 18px;
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
padding: 9px 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
Binary file not shown.
Binary file not shown.
|
@ -1,86 +0,0 @@
|
|||
{
|
||||
"GLOBAL": {
|
||||
"MINPLUTO": "MinPluto"
|
||||
},
|
||||
"SIDEBAR": {
|
||||
"HOME": "Home",
|
||||
"TRENDING": "Trending",
|
||||
"CATEGORY_LIST": {
|
||||
"POPULAR": "Popular",
|
||||
"TRAILERS": "Trailers",
|
||||
"MUSIC": "Music",
|
||||
"GAMES": "Games"
|
||||
},
|
||||
"DISCOVER": "Discover",
|
||||
"DISCOVER_LIST": {
|
||||
"TECH": "Tech",
|
||||
"COMEDY": "Comedy",
|
||||
"FOOD": "Food",
|
||||
"GAMES": "Games",
|
||||
"FITNESS": "Fitness"
|
||||
},
|
||||
"FOOTER": {
|
||||
"ALPHA": "You're in Alpha",
|
||||
"STATUS": "Status",
|
||||
"FORUM": "Forum",
|
||||
"SOURCE_CODE": "Source Code"
|
||||
},
|
||||
"ACCOUNT": {
|
||||
"CUSTOMIZATION": "",
|
||||
"VIDEO_PLAYER": "",
|
||||
"CSS/JS": "",
|
||||
"ACCOUNT": "",
|
||||
"RESET": "",
|
||||
"BACKUP_RESTORE": "",
|
||||
"DELETE_ACCOUNT": "",
|
||||
"HEADERS": {
|
||||
"SETTINGS": "Settings",
|
||||
"YOU": "You",
|
||||
"ADVANCE": "Advance"
|
||||
}
|
||||
}
|
||||
},
|
||||
"HEADER": {
|
||||
"SEARCH": "Search",
|
||||
"FEEDBACK": "Feedback"
|
||||
},
|
||||
"FORM": {
|
||||
"EMAIL": "Email",
|
||||
"PASSWORD": "Password",
|
||||
"USERNAME": "Username",
|
||||
"CREATE_ACCOUNT": "Create Account",
|
||||
"FORGOT_PASSWORD": "Forgot Password",
|
||||
"LOGIN": "Login",
|
||||
"REGISTER": "Register",
|
||||
"UPDATE": "Update",
|
||||
"SUBMIT": "Submit"
|
||||
},
|
||||
"TELEMTRY": {
|
||||
"OPTIN": "Opt-In",
|
||||
"OPTOUT": "Opt-Out"
|
||||
},
|
||||
"HOME": {
|
||||
"P1": "Select a category or search something to get started.",
|
||||
"P2": "Currently, MinPluto is in alpha. Features are currently barebones or may not work as expected."
|
||||
},
|
||||
"WATCH": {
|
||||
"BY": "By",
|
||||
"VIEWS": "Views",
|
||||
"RELATED": "Related Videos",
|
||||
"COMMENTS": "Comments"
|
||||
},
|
||||
"CHANNELS": {
|
||||
"FAMILY_FRIENDLY": "Family Friendly",
|
||||
"HOME": "Home",
|
||||
"VIDEOS": "Videos",
|
||||
"COMMUNITY": "Community",
|
||||
"LATEST": "Latest Videos",
|
||||
"ABOUT": "About"
|
||||
},
|
||||
"MUSIC": {
|
||||
"TITLE": "Title",
|
||||
"ARTIST": "Artist",
|
||||
"UPLOADED": "Uploaded",
|
||||
"DURATION": "Duration"
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
{
|
||||
"name": "MinPluto",
|
||||
"short_name": "MinPluto",
|
||||
"description": "An open source frontend alternative to YouTube.",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#000000",
|
||||
"theme_color": "#000000",
|
||||
"categories": [
|
||||
"entertainment",
|
||||
"music"
|
||||
],
|
||||
"dir": "ltr",
|
||||
"orientation": "any",
|
||||
"display_override": [
|
||||
"window-controls-overlay"
|
||||
],
|
||||
"icons": [
|
||||
{
|
||||
"src": "/images/pwa/MinPluto - PWA Logo.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"screenshots": [
|
||||
{
|
||||
"src": "/images/pwa/Mobile.png",
|
||||
"type": "image/png",
|
||||
"sizes": "527x1004",
|
||||
"form_factor": "narrow"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,193 +0,0 @@
|
|||
var VideoContainer = document.querySelector('.video-container')
|
||||
var VideoControls = document.querySelector('.video-controls')
|
||||
var Player = document.querySelector('video')
|
||||
|
||||
// Icons
|
||||
var play_solid_default = '<?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff" stroke-width="1.5"><path d="M6.90588 4.53682C6.50592 4.2998 6 4.58808 6 5.05299V18.947C6 19.4119 6.50592 19.7002 6.90588 19.4632L18.629 12.5162C19.0211 12.2838 19.0211 11.7162 18.629 11.4838L6.90588 4.53682Z" fill="#ffffff" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>';
|
||||
var pause_solid_default = '<?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff" stroke-width="1.5" data-darkreader-inline-color="" style="--darkreader-inline-color: #e8e6e3;"><path d="M6 18.4V5.6C6 5.26863 6.26863 5 6.6 5H9.4C9.73137 5 10 5.26863 10 5.6V18.4C10 18.7314 9.73137 19 9.4 19H6.6C6.26863 19 6 18.7314 6 18.4Z" fill="#ffffff" stroke="#ffffff" stroke-width="1.5" data-darkreader-inline-fill="" data-darkreader-inline-stroke="" style="--darkreader-inline-fill: #ffffff; --darkreader-inline-stroke: #ffffff;"></path><path d="M14 18.4V5.6C14 5.26863 14.2686 5 14.6 5H17.4C17.7314 5 18 5.26863 18 5.6V18.4C18 18.7314 17.7314 19 17.4 19H14.6C14.2686 19 14 18.7314 14 18.4Z" fill="#ffffff" stroke="#ffffff" stroke-width="1.5" data-darkreader-inline-fill="" data-darkreader-inline-stroke="" style="--darkreader-inline-fill: #ffffff; --darkreader-inline-stroke: #ffffff;"></path></svg>';
|
||||
var PlayIcon = play_solid_default;
|
||||
var PauseIcon = pause_solid_default;
|
||||
|
||||
// Fullscreen
|
||||
function Fullscreen() {
|
||||
const Button_Fullscreen = document.getElementById("vc-fullscreen");
|
||||
function Toggle_Fullscreen() {
|
||||
if (document.fullscreenElement) {
|
||||
document.querySelector('.vc-top').style.opacity = '0'
|
||||
document.exitFullscreen();
|
||||
} else if (document.webkitFullscreenElement) {
|
||||
document.querySelector('.vc-top').style.opacity = '0'
|
||||
document.webkitExitFullscreen();
|
||||
} else if (VideoContainer.webkitRequestFullscreen) {
|
||||
document.querySelector('.vc-top').style.opacity = '1'
|
||||
VideoContainer.webkitRequestFullscreen();
|
||||
} else {
|
||||
document.querySelector('.vc-top').style.opacity = '1'
|
||||
VideoContainer.requestFullscreen();
|
||||
}
|
||||
}
|
||||
Button_Fullscreen.onclick = Toggle_Fullscreen;
|
||||
function Update_FullscreenButton() {
|
||||
if (document.fullscreenElement) {
|
||||
Button_Fullscreen.setAttribute("data-title", "Exit full screen (f)");
|
||||
} else {
|
||||
Button_Fullscreen.setAttribute("data-title", "Full screen (f)");
|
||||
}
|
||||
}
|
||||
Player.addEventListener("dblclick", () => {
|
||||
Toggle_Fullscreen()
|
||||
Update_FullscreenButton()
|
||||
});
|
||||
}
|
||||
|
||||
// Play/Pause
|
||||
function PlayPause() {
|
||||
const Button_PlayPause = document.querySelector(".video-controls #vc-playpause");
|
||||
Button_PlayPause.addEventListener("click", Toggle_PlayPause);
|
||||
Player.addEventListener("click", Toggle_PlayPause);
|
||||
Player.addEventListener("play", Update_PlayPauseButton);
|
||||
Player.addEventListener("pause", Update_PlayPauseButton);
|
||||
function Toggle_PlayPause() {
|
||||
if (Player.paused || Player.ended) {
|
||||
Player.play();
|
||||
} else {
|
||||
Player.pause();
|
||||
}
|
||||
}
|
||||
function Update_PlayPauseButton() {
|
||||
if (Player.paused) {
|
||||
Button_PlayPause.setAttribute("data-title", "Play (K)");
|
||||
Button_PlayPause.innerHTML = `${PlayIcon}`;
|
||||
} else {
|
||||
Button_PlayPause.setAttribute("data-title", "Pause (K)");
|
||||
Button_PlayPause.innerHTML = `${PauseIcon}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Skip Around
|
||||
function SkipAround() {
|
||||
const Button_SkipBack = document.querySelector(".video-controls #vc-backwards");
|
||||
const Button_SkipForth = document.querySelector(".video-controls #vc-forwards");
|
||||
Button_SkipBack.addEventListener("click", Toggle_SkipBack);
|
||||
Button_SkipForth.addEventListener("click", Toggle_SkipForth);
|
||||
function Toggle_SkipBack() {
|
||||
Skip(-10);
|
||||
}
|
||||
function Toggle_SkipForth() {
|
||||
Skip(10);
|
||||
}
|
||||
function Skip(value) {
|
||||
Player.currentTime += value;
|
||||
}
|
||||
}
|
||||
|
||||
// Hide Controls
|
||||
function AutoToggleControls() {
|
||||
function Hide_Controls2() {
|
||||
if (Player.paused) {
|
||||
return;
|
||||
} else {
|
||||
document.querySelector(".video-controls").classList.add("hide");
|
||||
}
|
||||
}
|
||||
function Show_Controls2() {
|
||||
document.querySelector(".video-controls").classList.remove("hide");
|
||||
}
|
||||
VideoControls.addEventListener("mouseenter", Show_Controls2);
|
||||
VideoControls.addEventListener("mouseleave", Hide_Controls2);
|
||||
var mouseTimer = null, cursorVisible = true;
|
||||
function Hide_Cursor() {
|
||||
mouseTimer = null;
|
||||
VideoContainer.style.cursor = "none";
|
||||
cursorVisible = false;
|
||||
Hide_Controls2();
|
||||
}
|
||||
document.onmousemove = function () {
|
||||
if (mouseTimer) {
|
||||
window.clearTimeout(mouseTimer);
|
||||
Show_Controls2();
|
||||
}
|
||||
if (!cursorVisible) {
|
||||
VideoContainer.style.cursor = "default";
|
||||
cursorVisible = true;
|
||||
}
|
||||
mouseTimer = window.setTimeout(Hide_Cursor, 3200);
|
||||
};
|
||||
}
|
||||
|
||||
// Keyboard Shortcuts
|
||||
function KeyboardShortcuts(events) {
|
||||
if (Player.hasAttribute("keyboard-shortcut-fullscreen")) {
|
||||
var Fullscreen_KeyboardShortcut = Player.getAttribute("keyboard-shortcut-fullscreen");
|
||||
} else {
|
||||
var Fullscreen_KeyboardShortcut = "f";
|
||||
}
|
||||
if (Player.hasAttribute("keyboard-shortcut-mute")) {
|
||||
var Mute_KeyboardShortcut = Player.getAttribute("keyboard-shortcut-mute");
|
||||
} else {
|
||||
var Mute_KeyboardShortcut = "m";
|
||||
}
|
||||
if (Player.hasAttribute("keyboard-shortcut-playpause")) {
|
||||
var PlayPause_KeyboardShortcut = Player.getAttribute("keyboard-shortcut-playpause");
|
||||
} else {
|
||||
var PlayPause_KeyboardShortcut = "k";
|
||||
}
|
||||
if (Player.hasAttribute("keyboard-shortcut-skipback")) {
|
||||
var SkipBack_KeyboardShortcut = Player.getAttribute("keyboard-shortcut-skipback");
|
||||
} else {
|
||||
var SkipBack_KeyboardShortcut = "j";
|
||||
}
|
||||
if (Player.hasAttribute("keyboard-shortcut-skipforth")) {
|
||||
var SkipForth_KeyboardShortcut = Player.getAttribute("keyboard-shortcut-skipforth");
|
||||
} else {
|
||||
var SkipForth_KeyboardShortcut = "l";
|
||||
}
|
||||
function keyboardShortcuts(event) {
|
||||
const { key } = event;
|
||||
if (key === PlayPause_KeyboardShortcut) {
|
||||
if (Player.paused || Player.ended) {
|
||||
Player.play();
|
||||
} else {
|
||||
Player.pause();
|
||||
}
|
||||
if (Player.paused) {
|
||||
Show_Controls();
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
Hide_Controls();
|
||||
}, 1200);
|
||||
}
|
||||
} else if (key === Mute_KeyboardShortcut) {
|
||||
Player.muted = !Player.muted;
|
||||
if (Player.muted) {
|
||||
volume.setAttribute("data-volume", volume.value);
|
||||
volume.value = 0;
|
||||
} else {
|
||||
volume.value = volume.dataset.volume;
|
||||
}
|
||||
} else if (key === Fullscreen_KeyboardShortcut) {
|
||||
if (document.fullscreenElement) {
|
||||
document.exitFullscreen();
|
||||
} else if (document.webkitFullscreenElement) {
|
||||
document.webkitExitFullscreen();
|
||||
} else if (VideoContainer.webkitRequestFullscreen) {
|
||||
VideoContainer.webkitRequestFullscreen();
|
||||
} else {
|
||||
VideoContainer.requestFullscreen();
|
||||
}
|
||||
} else if (key === SkipBack_KeyboardShortcut) {
|
||||
Player.currentTime += -10;
|
||||
} else if (key === SkipForth_KeyboardShortcut) {
|
||||
Player.currentTime += 10;
|
||||
}
|
||||
}
|
||||
document.addEventListener("keyup", keyboardShortcuts);
|
||||
}
|
||||
|
||||
// Init All Functions
|
||||
AutoToggleControls()
|
||||
Fullscreen()
|
||||
KeyboardShortcuts()
|
||||
PlayPause()
|
||||
SkipAround()
|
|
@ -1,81 +0,0 @@
|
|||
function Seek() {
|
||||
var Player = document.querySelector('video')
|
||||
const timeElapsed = document.getElementById("current");
|
||||
const duration = document.getElementById("duration");
|
||||
function formatTime(timeInSeconds) {
|
||||
const result = new Date(timeInSeconds * 1e3)
|
||||
.toISOString()
|
||||
.substr(11, 8);
|
||||
return {
|
||||
minutes: result.substr(3, 2),
|
||||
seconds: result.substr(6, 2),
|
||||
};
|
||||
}
|
||||
function initializeVideo() {
|
||||
const videoDuration = Math.round(Player.duration);
|
||||
const time = formatTime(videoDuration);
|
||||
duration.innerText = `${time.minutes}:${time.seconds}`;
|
||||
duration.setAttribute(
|
||||
"datetime",
|
||||
`${time.minutes}m ${time.seconds}s`,
|
||||
);
|
||||
}
|
||||
Player.addEventListener("loadedmetadata", initializeVideo);
|
||||
function updateTimeElapsed() {
|
||||
const time = formatTime(Math.round(Player.currentTime));
|
||||
timeElapsed.innerText = `${time.minutes}:${time.seconds}`;
|
||||
timeElapsed.setAttribute(
|
||||
"datetime",
|
||||
`${time.minutes}m ${time.seconds}s`,
|
||||
);
|
||||
}
|
||||
Player.addEventListener("timeupdate", updateTimeElapsed);
|
||||
const progressBar = document.querySelector(".vc-progress-bar");
|
||||
const seek = document.getElementById("seek");
|
||||
function initializeVideo() {
|
||||
const videoDuration = Math.round(Player.duration);
|
||||
seek.setAttribute("max", videoDuration);
|
||||
progressBar.setAttribute("max", videoDuration);
|
||||
const time = formatTime(videoDuration);
|
||||
duration.innerText = `${time.minutes}:${time.seconds}`;
|
||||
duration.setAttribute(
|
||||
"datetime",
|
||||
`${time.minutes}m ${time.seconds}s`,
|
||||
);
|
||||
}
|
||||
function updateProgress() {
|
||||
seek.value = Math.floor(Player.currentTime);
|
||||
document.querySelector('.vc-progress-bar').style.width = Player.currentTime / Player.duration * 100 + '%'
|
||||
}
|
||||
Player.addEventListener("timeupdate", updateProgress);
|
||||
const seekTooltip = document.getElementById("seek-tooltip");
|
||||
function updateSeekTooltip(event) {
|
||||
const skipTo = Math.round(
|
||||
(event.offsetX / event.target.clientWidth) *
|
||||
parseInt(event.target.getAttribute("max"), 10),
|
||||
);
|
||||
seek.setAttribute("data-seek", skipTo);
|
||||
const t = formatTime(skipTo);
|
||||
seekTooltip.textContent = `${t.minutes}:${t.seconds}`;
|
||||
const rect = Player.getBoundingClientRect();
|
||||
seekTooltip.style.left = `${event.pageX - rect.left}px`;
|
||||
seekTooltip.style.opacity = '1'
|
||||
document.querySelector('.vc-progress-bar').style.width = Player.currentTime / Player.duration * 100 + '%'
|
||||
seek.addEventListener('mouseleave', () => {
|
||||
seekTooltip.style.opacity = '0'
|
||||
})
|
||||
}
|
||||
seek.addEventListener("mousemove", updateSeekTooltip);
|
||||
function skipAhead(event) {
|
||||
const skipTo = event.target.dataset.seek
|
||||
? event.target.dataset.seek
|
||||
: event.target.value;
|
||||
Player.currentTime = skipTo;
|
||||
progressBar.value = skipTo;
|
||||
seek.value = skipTo;
|
||||
}
|
||||
seek.addEventListener("input", skipAhead);
|
||||
|
||||
initializeVideo();
|
||||
}
|
||||
Seek();
|
|
@ -1,64 +0,0 @@
|
|||
// https://gist.github.com/michancio/59b9f3dc54b3ff4f6a84
|
||||
// Find elements
|
||||
var SyncVideo = document.querySelector(".main-video");
|
||||
var SyncAudio = document.querySelector(".main-audio");
|
||||
|
||||
// Object for synchronization of multiple media/sources
|
||||
if (typeof window.MediaController === "function") {
|
||||
var controller = new MediaController();
|
||||
SyncVideo.controller = controller;
|
||||
SyncAudio.controller = controller;
|
||||
} else {
|
||||
controller = null;
|
||||
}
|
||||
|
||||
// Run SyncAudio and SyncVideo simultaneously
|
||||
SyncVideo.addEventListener(
|
||||
"play",
|
||||
function () {
|
||||
if (!controller && SyncAudio.paused) {
|
||||
SyncAudio.play();
|
||||
}
|
||||
},
|
||||
false,
|
||||
);
|
||||
|
||||
// Pause/Play and Buffering
|
||||
SyncVideo.addEventListener("waiting", () => {
|
||||
// If SyncVideo is buffering
|
||||
SyncAudio.pause();
|
||||
});
|
||||
SyncVideo.addEventListener("playing", () => {
|
||||
// If SyncVideo is done buffering
|
||||
SyncAudio.play();
|
||||
SyncTimestamp();
|
||||
});
|
||||
|
||||
SyncVideo.addEventListener(
|
||||
"pause",
|
||||
function () {
|
||||
if (!controller && !SyncAudio.paused) {
|
||||
SyncAudio.pause();
|
||||
}
|
||||
},
|
||||
false,
|
||||
);
|
||||
|
||||
// When Media Ends
|
||||
SyncVideo.addEventListener(
|
||||
"ended",
|
||||
function () {
|
||||
if (controller) {
|
||||
controller.pause();
|
||||
} else {
|
||||
SyncVideo.pause();
|
||||
SyncAudio.pause();
|
||||
}
|
||||
},
|
||||
false,
|
||||
);
|
||||
|
||||
// Seekbar
|
||||
function SyncTimestamp() {
|
||||
SyncAudio.currentTime = SyncVideo.currentTime;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
User-agent: Applebot
|
||||
User-agent: Googlebot
|
||||
User-agent: bingbot
|
||||
User-agent: Yandex
|
||||
User-agent: Yeti
|
||||
User-agent: Baiduspider
|
||||
User-agent: 360Spider
|
||||
User-agent: *
|
||||
Disallow: /
|
|
@ -1,2 +0,0 @@
|
|||
"use strict";var r=Object.defineProperty;var v=Object.getOwnPropertyDescriptor;var h=Object.getOwnPropertyNames;var w=Object.prototype.hasOwnProperty;var y=(e,n)=>{for(var t in n)r(e,t,{get:n[t],enumerable:!0})},S=(e,n,t,i)=>{if(n&&typeof n=="object"||typeof n=="function")for(let s of h(n))!w.call(e,s)&&s!==t&&r(e,s,{get:()=>n[s],enumerable:!(i=v(n,s))||i.enumerable});return e};var I=e=>S(r({},"__esModule",{value:!0}),e);var k={};y(k,{init:()=>T,trackEvent:()=>$});module.exports=I(k);var A=V(),E=N(),D=typeof window<"u"&&typeof window.fetch<"u",O=typeof chrome<"u"&&!!chrome.runtime?.id,p=u(),d=new Date,l={US:"https://us.aptabase.com",EU:"https://eu.aptabase.com",DEV:"http://localhost:3000",SH:""};function c(e){let n=new Date,t=n.getTime()-d.getTime();return Math.floor(t/1e3)>e&&(p=u()),d=n,p}function u(){let e=Math.floor(Date.now()/1e3).toString(),n=Math.floor(Math.random()*1e8).toString().padStart(8,"0");return e+n}function g(e){let n=e.split("-");return n.length!==3||l[n[1]]===void 0?(console.warn(`The Aptabase App Key "${e}" is invalid. Tracking will be disabled.`),!1):!0}function f(e,n){let t=e.split("-")[1];if(t==="SH"){if(!n?.host){console.warn("Host parameter must be defined when using Self-Hosted App Key. Tracking will be disabled.");return}return`${n.host}/api/v0/event`}return`${n?.host??l[t]}/api/v0/event`}async function b(e){if(!D&&!O){console.warn(`Aptabase: trackEvent requires a browser environment. Event "${e.eventName}" will be discarded.`);return}if(!e.appKey){console.warn(`Aptabase: init must be called before trackEvent. Event "${e.eventName}" will be discarded.`);return}try{let n=await fetch(e.apiUrl,{method:"POST",headers:{"Content-Type":"application/json","App-Key":e.appKey},credentials:"omit",body:JSON.stringify({timestamp:new Date().toISOString(),sessionId:e.sessionId,eventName:e.eventName,systemProps:{locale:e.locale??A,isDebug:e.isDebug??E,appVersion:e.appVersion??"",sdkVersion:e.sdkVersion},props:e.props})});if(n.status>=300){let t=await n.text();console.warn(`Failed to send event "${e.eventName}": ${n.status} ${t}`)}}catch(n){console.warn(`Failed to send event "${e.eventName}"`),console.warn(n)}}function V(){if(!(typeof navigator>"u"))return navigator.languages.length>0?navigator.languages[0]:navigator.language}function N(){return process.env.NODE_ENV==="development"?!0:typeof location>"u"?!1:location.hostname==="localhost"}var x=1*60*60,U="aptabase-web@0.4.2",m="",o,a;function T(e,n){g(e)&&(o=n?.apiUrl??f(e,n),m=e,a=n)}async function $(e,n){if(!o)return;let t=c(x);await b({apiUrl:o,sessionId:t,appKey:m,isDebug:a?.isDebug,appVersion:a?.appVersion,sdkVersion:U,eventName:e,props:n})}0&&(module.exports={init,trackEvent});
|
||||
//# sourceMappingURL=index.cjs.map
|
File diff suppressed because one or more lines are too long
|
@ -1,11 +0,0 @@
|
|||
type AptabaseOptions = {
|
||||
host?: string;
|
||||
apiUrl?: string;
|
||||
appVersion?: string;
|
||||
isDebug?: boolean;
|
||||
};
|
||||
|
||||
declare function init(appKey: string, options?: AptabaseOptions): void;
|
||||
declare function trackEvent(eventName: string, props?: Record<string, string | number | boolean>): Promise<void>;
|
||||
|
||||
export { AptabaseOptions, init, trackEvent };
|
|
@ -1,11 +0,0 @@
|
|||
type AptabaseOptions = {
|
||||
host?: string;
|
||||
apiUrl?: string;
|
||||
appVersion?: string;
|
||||
isDebug?: boolean;
|
||||
};
|
||||
|
||||
declare function init(appKey: string, options?: AptabaseOptions): void;
|
||||
declare function trackEvent(eventName: string, props?: Record<string, string | number | boolean>): Promise<void>;
|
||||
|
||||
export { AptabaseOptions, init, trackEvent };
|
|
@ -1,2 +0,0 @@
|
|||
var b=w(),m=y(),v=typeof window<"u"&&typeof window.fetch<"u",h=typeof chrome<"u"&&!!chrome.runtime?.id,r=d(),o=new Date,a={US:"https://us.aptabase.com",EU:"https://eu.aptabase.com",DEV:"http://localhost:3000",SH:""};function p(e){let n=new Date,t=n.getTime()-o.getTime();return Math.floor(t/1e3)>e&&(r=d()),o=n,r}function d(){let e=Math.floor(Date.now()/1e3).toString(),n=Math.floor(Math.random()*1e8).toString().padStart(8,"0");return e+n}function l(e){let n=e.split("-");return n.length!==3||a[n[1]]===void 0?(console.warn(`The Aptabase App Key "${e}" is invalid. Tracking will be disabled.`),!1):!0}function c(e,n){let t=e.split("-")[1];if(t==="SH"){if(!n?.host){console.warn("Host parameter must be defined when using Self-Hosted App Key. Tracking will be disabled.");return}return`${n.host}/api/v0/event`}return`${n?.host??a[t]}/api/v0/event`}async function u(e){if(!v&&!h){console.warn(`Aptabase: trackEvent requires a browser environment. Event "${e.eventName}" will be discarded.`);return}if(!e.appKey){console.warn(`Aptabase: init must be called before trackEvent. Event "${e.eventName}" will be discarded.`);return}try{let n=await fetch(e.apiUrl,{method:"POST",headers:{"Content-Type":"application/json","App-Key":e.appKey},credentials:"omit",body:JSON.stringify({timestamp:new Date().toISOString(),sessionId:e.sessionId,eventName:e.eventName,systemProps:{locale:e.locale??b,isDebug:e.isDebug??m,appVersion:e.appVersion??"",sdkVersion:e.sdkVersion},props:e.props})});if(n.status>=300){let t=await n.text();console.warn(`Failed to send event "${e.eventName}": ${n.status} ${t}`)}}catch(n){console.warn(`Failed to send event "${e.eventName}"`),console.warn(n)}}function w(){if(!(typeof navigator>"u"))return navigator.languages.length>0?navigator.languages[0]:navigator.language}function y(){return process.env.NODE_ENV==="development"?!0:typeof location>"u"?!1:location.hostname==="localhost"}var S=1*60*60,I="aptabase-web@0.4.2",g="",s,i;function D(e,n){l(e)&&(s=n?.apiUrl??c(e,n),g=e,i=n)}async function O(e,n){if(!s)return;let t=p(S);await u({apiUrl:s,sessionId:t,appKey:g,isDebug:i?.isDebug,appVersion:i?.appVersion,sdkVersion:I,eventName:e,props:n})}export{D as init,O as trackEvent};
|
||||
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
|
@ -1,778 +0,0 @@
|
|||
(() => {
|
||||
// src/assets/icons/play-solid.svg
|
||||
var play_solid_default = '<?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff" stroke-width="1.5"><path d="M6.90588 4.53682C6.50592 4.2998 6 4.58808 6 5.05299V18.947C6 19.4119 6.50592 19.7002 6.90588 19.4632L18.629 12.5162C19.0211 12.2838 19.0211 11.7162 18.629 11.4838L6.90588 4.53682Z" fill="#ffffff" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>';
|
||||
|
||||
// src/assets/icons/pause-solid.svg
|
||||
var pause_solid_default = '<?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff" stroke-width="1.5" data-darkreader-inline-color="" style="--darkreader-inline-color: #e8e6e3;"><path d="M6 18.4V5.6C6 5.26863 6.26863 5 6.6 5H9.4C9.73137 5 10 5.26863 10 5.6V18.4C10 18.7314 9.73137 19 9.4 19H6.6C6.26863 19 6 18.7314 6 18.4Z" fill="#ffffff" stroke="#ffffff" stroke-width="1.5" data-darkreader-inline-fill="" data-darkreader-inline-stroke="" style="--darkreader-inline-fill: #ffffff; --darkreader-inline-stroke: #ffffff;"></path><path d="M14 18.4V5.6C14 5.26863 14.2686 5 14.6 5H17.4C17.7314 5 18 5.26863 18 5.6V18.4C18 18.7314 17.7314 19 17.4 19H14.6C14.2686 19 14 18.7314 14 18.4Z" fill="#ffffff" stroke="#ffffff" stroke-width="1.5" data-darkreader-inline-fill="" data-darkreader-inline-stroke="" style="--darkreader-inline-fill: #ffffff; --darkreader-inline-stroke: #ffffff;"></path></svg>';
|
||||
|
||||
// src/assets/icons/maximize.svg
|
||||
var maximize_default = '<?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff"><path d="M7 4H4V7" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M17 4H20V7" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M7 20H4V17" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M17 20H20V17" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>';
|
||||
|
||||
// src/assets/icons/closed-captions-tag.svg
|
||||
var closed_captions_tag_default = '<?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" viewBox="0 0 24 24" stroke-width="1.5" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff" data-darkreader-inline-color="" style="--darkreader-inline-color: #e8e6e3;"><path d="M1 15V9C1 5.68629 3.68629 3 7 3H17C20.3137 3 23 5.68629 23 9V15C23 18.3137 20.3137 21 17 21H7C3.68629 21 1 18.3137 1 15Z" stroke="#ffffff" stroke-width="1.5" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: #ffffff;"></path><path d="M10.5 10L10.3284 9.82843C9.79799 9.29799 9.07857 9 8.32843 9V9C6.76633 9 5.5 10.2663 5.5 11.8284V12.1716C5.5 13.7337 6.76633 15 8.32843 15V15C9.07857 15 9.79799 14.702 10.3284 14.1716L10.5 14" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: #ffffff;"></path><path d="M18.5 10L18.3284 9.82843C17.798 9.29799 17.0786 9 16.3284 9V9C14.7663 9 13.5 10.2663 13.5 11.8284V12.1716C13.5 13.7337 14.7663 15 16.3284 15V15C17.0786 15 17.798 14.702 18.3284 14.1716L18.5 14" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: #ffffff;"></path></svg>';
|
||||
|
||||
// src/assets/icons/backward15-seconds.svg
|
||||
var backward15_seconds_default = '<?xml version="1.0" encoding="UTF-8"?><svg width="24px" stroke-width="1.5" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff"><path d="M3 13C3 17.9706 7.02944 22 12 22C16.9706 22 21 17.9706 21 13C21 8.02944 16.9706 4 12 4" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M9 9L9 16" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M15 9L13 9C12.4477 9 12 9.44772 12 10L12 11.5C12 12.0523 12.4477 12.5 13 12.5L14 12.5C14.5523 12.5 15 12.9477 15 13.5L15 15C15 15.5523 14.5523 16 14 16L12 16" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M12 4L4.5 4M4.5 4L6.5 2M4.5 4L6.5 6" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>';
|
||||
|
||||
// src/assets/icons/forward15-seconds.svg
|
||||
var forward15_seconds_default = '<?xml version="1.0" encoding="UTF-8"?><svg width="24px" stroke-width="1.5" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff"><path d="M21 13C21 17.9706 16.9706 22 12 22C7.02944 22 3 17.9706 3 13C3 8.02944 7.02944 4 12 4" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M12 4H19.5M19.5 4L17.5 2M19.5 4L17.5 6" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M9 9L9 16" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M15 9L13 9C12.4477 9 12 9.44772 12 10L12 11.5C12 12.0523 12.4477 12.5 13 12.5L14 12.5C14.5523 12.5 15 12.9477 15 13.5L15 15C15 15.5523 14.5523 16 14 16L12 16" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>';
|
||||
|
||||
// src/assets/icons/sound-high.svg
|
||||
var sound_high_default = '<?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" viewBox="0 0 24 24" stroke-width="1.5" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff" data-darkreader-inline-color="" style="--darkreader-inline-color: #e8e6e3;"><path d="M1 13.8571V10.1429C1 9.03829 1.89543 8.14286 3 8.14286H5.9C6.09569 8.14286 6.28708 8.08544 6.45046 7.97772L12.4495 4.02228C13.1144 3.5839 14 4.06075 14 4.85714V19.1429C14 19.9392 13.1144 20.4161 12.4495 19.9777L6.45046 16.0223C6.28708 15.9146 6.09569 15.8571 5.9 15.8571H3C1.89543 15.8571 1 14.9617 1 13.8571Z" stroke="#ffffff" stroke-width="1.5" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: #ffffff;"></path><path d="M17.5 7.5C17.5 7.5 19 9 19 11.5C19 14 17.5 15.5 17.5 15.5" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: #ffffff;"></path><path d="M20.5 4.5C20.5 4.5 23 7 23 11.5C23 16 20.5 18.5 20.5 18.5" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: #ffffff;"></path></svg>';
|
||||
|
||||
// src/assets/icons/sound-min.svg
|
||||
var sound_min_default = '<?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" viewBox="0 0 24 24" stroke-width="1.5" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff" data-darkreader-inline-color="" style="--darkreader-inline-color: #e8e6e3;"><path d="M3.5 13.8571V10.1429C3.5 9.03829 4.39543 8.14286 5.5 8.14286H8.4C8.59569 8.14286 8.78708 8.08544 8.95046 7.97772L14.9495 4.02228C15.6144 3.5839 16.5 4.06075 16.5 4.85714V19.1429C16.5 19.9392 15.6144 20.4161 14.9495 19.9777L8.95046 16.0223C8.78708 15.9146 8.59569 15.8571 8.4 15.8571H5.5C4.39543 15.8571 3.5 14.9617 3.5 13.8571Z" stroke="#ffffff" stroke-width="1.5" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: #ffffff;"></path><path d="M20.5 15L20.5 9" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: #ffffff;"></path></svg>';
|
||||
|
||||
// src/assets/icons/sound-off.svg
|
||||
var sound_off_default = '<?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" viewBox="0 0 24 24" stroke-width="1.5" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff" data-darkreader-inline-color="" style="--darkreader-inline-color: #e8e6e3;"><path d="M18 14L20.0005 12M22 10L20.0005 12M20.0005 12L18 10M20.0005 12L22 14" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: #ffffff;"></path><path d="M2 13.8571V10.1429C2 9.03829 2.89543 8.14286 4 8.14286H6.9C7.09569 8.14286 7.28708 8.08544 7.45046 7.97772L13.4495 4.02228C14.1144 3.5839 15 4.06075 15 4.85714V19.1429C15 19.9392 14.1144 20.4161 13.4495 19.9777L7.45046 16.0223C7.28708 15.9146 7.09569 15.8571 6.9 15.8571H4C2.89543 15.8571 2 14.9617 2 13.8571Z" stroke="#ffffff" stroke-width="1.5" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: #ffffff;"></path></svg>';
|
||||
|
||||
// src/assets/icons/refresh-double.svg
|
||||
var refresh_double_default = '<?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff" data-darkreader-inline-color="" style="--darkreader-inline-color: #e8e6e3;"><path d="M21.1679 8C19.6247 4.46819 16.1006 2 11.9999 2C6.81459 2 2.55104 5.94668 2.04932 11" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: #ffffff;"></path><path d="M17 8H21.4C21.7314 8 22 7.73137 22 7.4V3" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: #ffffff;"></path><path d="M2.88146 16C4.42458 19.5318 7.94874 22 12.0494 22C17.2347 22 21.4983 18.0533 22 13" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: #ffffff;"></path><path d="M7.04932 16H2.64932C2.31795 16 2.04932 16.2686 2.04932 16.6V21" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: #ffffff;"></path></svg>';
|
||||
|
||||
// src/get.js
|
||||
var ZornVideoPlayer = document.querySelector(".zorn-player");
|
||||
var VideoContainer = document.querySelector(".video-container");
|
||||
var VideoControls = document.querySelector(".zorn-player-controls");
|
||||
var PlayIcon = play_solid_default;
|
||||
var PauseIcon = pause_solid_default;
|
||||
var FullcreenIcon = maximize_default;
|
||||
var CaptionsIcon = closed_captions_tag_default;
|
||||
var Backward15Icon = backward15_seconds_default;
|
||||
var Forward15Icon = forward15_seconds_default;
|
||||
var VolumeHighIcon = sound_high_default;
|
||||
var VolumeMinIcon = sound_min_default;
|
||||
var VolumeOffIcon = sound_off_default;
|
||||
var RefreshIcon = refresh_double_default;
|
||||
|
||||
// src/themes/default.js
|
||||
function Title() {
|
||||
let VideoTitle = ZornVideoPlayer.getAttribute("video-title");
|
||||
document.querySelector(".zorn-title").innerHTML = VideoTitle;
|
||||
if (ZornVideoPlayer.hasAttribute("video-title")) {
|
||||
document.querySelector(".zorn-title").style.display = "inherit";
|
||||
} else {
|
||||
document.querySelector(".zorn-title").style.display = "none";
|
||||
}
|
||||
}
|
||||
var Controls = `
|
||||
<div oncontextmenu="return false" class="zorn-player-controls">
|
||||
<div class="row-2">
|
||||
<div class="video-progress">
|
||||
<progress id="progress-bar" value="0" min="0"></progress>
|
||||
<input class="seek" id="seek" value="0" min="0" type="range" step="1">
|
||||
<div class="seek-tooltip" id="seek-tooltip">00:00</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-1">
|
||||
<div class="row-1-start">
|
||||
<button id="play-pause">${PlayIcon}</button>
|
||||
<button id="skip-back">${Backward15Icon}</button>
|
||||
<button id="skip-forth">${Forward15Icon}</button>
|
||||
<div class="volume-controls">
|
||||
<button data-title="Mute (m)" class="volume-button" id="volume-button">${VolumeHighIcon}</button>
|
||||
<input class="volume" id="volume" value="1" type="range" max="1" min="0" step="0.01"/>
|
||||
</div>
|
||||
<div class="time">
|
||||
<time id="time-elapsed">00:00</time>
|
||||
<span> / </span>
|
||||
<time id="duration">00:00</time>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-1-center">
|
||||
</div>
|
||||
<div class="row-1-end">
|
||||
<button id="subtitles">${CaptionsIcon}</button>
|
||||
<button id="fullscreen">${FullcreenIcon}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
:root {
|
||||
--zorn-progress-bar-bg: rgba(100, 100, 100, 0.5);
|
||||
--zorn-progress-bar: rgba(255, 0, 0, 0.5);
|
||||
--zorn-thumb: red;
|
||||
--zorn-rounded-corners: 4px;
|
||||
}
|
||||
.zorn-context-menu {
|
||||
background: linear-gradient(45deg, #0a141c 0%, rgba(10, 20, 28, 1) 100%);
|
||||
border-radius: 6px;
|
||||
border: 1px rgba(255, 255, 255, 0.08) solid;
|
||||
}
|
||||
.zorn-context-menu ul {
|
||||
list-style: none;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
.zorn-context-menu ul li {
|
||||
padding: 8px 32px 8px 16px;
|
||||
margin: 4px;
|
||||
border-radius: 4px;
|
||||
font-family: arial;
|
||||
}
|
||||
.zorn-context-menu ul li:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
cursor: pointer;
|
||||
}
|
||||
.zorn-context-menu ul li i {
|
||||
font-size: 14px;
|
||||
margin-right: 12px;
|
||||
width: 12px;
|
||||
}
|
||||
.video-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
color: white;
|
||||
}
|
||||
.video-container .zorn-player-dialogs #buffering {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
padding: 0px 24px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.video-container .zorn-player-dialogs #buffering h2 {
|
||||
font-size: 52px;
|
||||
}
|
||||
.video-container .zorn-player-dialogs #invalid-src {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 24px;
|
||||
transform: translate(0px, -50%);
|
||||
padding: 0px 24px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.video-container .zorn-player-dialogs #invalid-src h2 {
|
||||
font-size: 52px;
|
||||
}
|
||||
.video-container .zorn-player {
|
||||
display: inline-flex;
|
||||
}
|
||||
.video-container .zorn-title {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
background: rgb(0 0 0 / 50%);
|
||||
width: auto;
|
||||
margin: 12px;
|
||||
padding: 12px 24px;
|
||||
border-radius: 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
.video-container .hide {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.video-container .zorn-player-title {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
background-image: linear-gradient(to top, rgba(12, 12, 12, 0), rgba(12, 12, 12, 0.75));
|
||||
padding: 12px 24px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.video-container .subtitles-menu {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 60px;
|
||||
bottom: 70px;
|
||||
background: #000 9;
|
||||
list-style: none;
|
||||
padding: 6px;
|
||||
border-radius: 6px;
|
||||
background: rgb(0 0 0 / 50%);
|
||||
}
|
||||
.video-container .subtitles-menu button {
|
||||
background-color: transparent;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
padding: 6px 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.video-container .subtitles-menu button:hover {
|
||||
background: #fff 29;
|
||||
}
|
||||
.video-container .subtitles-menu .hide {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.video-container .zorn-player-controls {
|
||||
display: inline-flex;
|
||||
right: 0;
|
||||
left: 0;
|
||||
padding: 10px;
|
||||
position: absolute;
|
||||
bottom: -1px;
|
||||
transition: all 0.2s ease;
|
||||
background-image: linear-gradient(to bottom, rgba(12, 12, 12, 0), rgba(12, 12, 12, 0.75));
|
||||
flex-direction: inherit;
|
||||
}
|
||||
.video-container .zorn-player-controls .row-1 {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
.video-container .zorn-player-controls .row-1-start {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.video-container .zorn-player-controls .row-1-center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.video-container .zorn-player-controls .row-1-end {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.video-container .zorn-player-controls button {
|
||||
aspect-ratio: 1;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
color: white;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
margin: 0px 6px;
|
||||
}
|
||||
.volume-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.video-container .zorn-player-controls .volume-controls:hover > #volume {
|
||||
opacity: 1;
|
||||
transition: 0.3s opacity, 0.3s width;
|
||||
margin: 0px;
|
||||
width: 72px;
|
||||
}
|
||||
.video-container .zorn-player-controls #volume {
|
||||
opacity: 0;
|
||||
transition: 0.3s opacity, 0.3s width;
|
||||
margin: 0px 12px 0px -6px;
|
||||
width: 0px;
|
||||
}
|
||||
.video-container .zorn-player-controls #volume-button svg {
|
||||
aspect-ratio: 1;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
fill: white;
|
||||
padding: 3px 0px 0px 0px;
|
||||
}
|
||||
.video-container .zorn-player-controls .video-progress {
|
||||
position: relative;
|
||||
height: 6.4px;
|
||||
margin: 24px 0px;
|
||||
width: 100%;
|
||||
}
|
||||
.video-container .zorn-player-controls progress {
|
||||
border-radius: 1rem;
|
||||
width: 100%;
|
||||
height: 8.4px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
.video-container .zorn-player-controls progress::-webkit-progress-bar {
|
||||
border-radius: 1rem;
|
||||
background: var(--zorn-progress-bar-bg);
|
||||
}
|
||||
.video-container .zorn-player-controls progress::-webkit-progress-value {
|
||||
background: var(--zorn-progress-bar);
|
||||
border-radius: 1rem;
|
||||
}
|
||||
.video-container .zorn-player-controls progress::-moz-progress-bar {
|
||||
border-radius: 1rem;
|
||||
background: var(--zorn-progress-bar-bg);
|
||||
}
|
||||
.video-container .zorn-player-controls .seek {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
}
|
||||
.video-container .zorn-player-controls .seek:hover + .seek-tooltip {
|
||||
display: block;
|
||||
}
|
||||
.video-container .zorn-player-controls .seek-tooltip {
|
||||
display: none;
|
||||
position: relative;
|
||||
top: -32px;
|
||||
margin-left: -30px;
|
||||
font-size: 12px;
|
||||
content: attr(data-title);
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
background-color: rgba(0, 0, 0, .5);
|
||||
border-radius: 4px;
|
||||
padding: 6px;
|
||||
width: fit-content;
|
||||
}
|
||||
.video-container .zorn-player-controls input[type=range] {
|
||||
height: 8.4px;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
}
|
||||
.video-container .zorn-player-controls input[type=range]:focus {
|
||||
outline: none;
|
||||
}
|
||||
.video-container .zorn-player-controls input[type=range]:focus::-webkit-slider-runnable-track {
|
||||
background: transparent;
|
||||
}
|
||||
.video-container .zorn-player-controls input[type=range]:focus::-moz-range-track {
|
||||
outline: none;
|
||||
}
|
||||
.video-container .zorn-player-controls input[type=range]::-webkit-slider-runnable-track {
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
border-radius: 1.3px;
|
||||
-webkit-appearance: none;
|
||||
transition: all 0.4s ease;
|
||||
}
|
||||
.video-container .zorn-player-controls input[type=range]::-webkit-slider-thumb {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
border-radius: 10px;
|
||||
background: var(--zorn-thumb);
|
||||
cursor: pointer;
|
||||
-webkit-appearance: none;
|
||||
margin-left: -1px;
|
||||
}
|
||||
.video-container .zorn-player-controls input[type=range]::-moz-range-track {
|
||||
width: 100%;
|
||||
height: 8.4px;
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
background: transparent;
|
||||
border-radius: 0;
|
||||
}
|
||||
.video-container .zorn-player-controls input[type=range].volume {
|
||||
height: 5px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.video-container .zorn-player-controls input[type=range].volume::-webkit-slider-runnable-track {
|
||||
background-color: transparent;
|
||||
}
|
||||
.video-container .zorn-player-controls input[type=range].volume::-webkit-slider-thumb {
|
||||
margin-left: 0;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
background: #fff;
|
||||
}
|
||||
.video-container .zorn-player-controls input[type=range].volume::-moz-range-thumb {
|
||||
border: 1px solid #fff;
|
||||
background: #fff;
|
||||
}
|
||||
.video-container .zorn-player-controls input[type="range"]::-moz-range-thumb {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
background: var(--zorn-thumb);
|
||||
cursor: pointer;
|
||||
}
|
||||
.video-container .zorn-player-controls .hide {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.video-container .zorn-player-controls #progress-bar {
|
||||
background: var(--zorn-progress-bar-bg);
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
}
|
||||
div#buffering {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
animation: 1s spin linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg)
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg)
|
||||
}
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
ZornVideoPlayer.insertAdjacentHTML("afterend", Controls);
|
||||
if (ZornVideoPlayer.getAttribute("layout") === "default") {
|
||||
Title();
|
||||
}
|
||||
|
||||
// src/events.js
|
||||
function Events() {
|
||||
ZornVideoPlayer.addEventListener("error", function(event) {
|
||||
document.querySelector("#invalid-src").style.display = "inherit";
|
||||
document.querySelector(".zorn-player-controls").style.display = "none";
|
||||
videoContainer.style.backgroundColor = "#101010";
|
||||
setTimeout(() => {
|
||||
ZornVideoPlayer.style.opacity = "0.10";
|
||||
document.querySelector("#buffering").style.display = "none";
|
||||
}, 168);
|
||||
}, true);
|
||||
ZornVideoPlayer.onwaiting = (event) => {
|
||||
document.querySelector("#buffering").style.display = "inherit";
|
||||
ZornVideoPlayer.style.transition = "5s opacity";
|
||||
ZornVideoPlayer.style.opacity = "0.25";
|
||||
};
|
||||
ZornVideoPlayer.oncanplaythrough = (event) => {
|
||||
document.querySelector("#buffering").style.display = "none";
|
||||
ZornVideoPlayer.style.transition = "0.3s opacity";
|
||||
ZornVideoPlayer.style.opacity = "1";
|
||||
};
|
||||
}
|
||||
|
||||
// src/functions/PlayPause.js
|
||||
function PlayPause() {
|
||||
const Button_PlayPause = document.querySelector(".zorn-player-controls #play-pause");
|
||||
Button_PlayPause.addEventListener("click", Toggle_PlayPause);
|
||||
ZornVideoPlayer.addEventListener("click", Toggle_PlayPause);
|
||||
ZornVideoPlayer.addEventListener("play", Update_PlayPauseButton);
|
||||
ZornVideoPlayer.addEventListener("pause", Update_PlayPauseButton);
|
||||
function Toggle_PlayPause() {
|
||||
if (ZornVideoPlayer.paused || ZornVideoPlayer.ended) {
|
||||
ZornVideoPlayer.play();
|
||||
} else {
|
||||
ZornVideoPlayer.pause();
|
||||
}
|
||||
}
|
||||
function Update_PlayPauseButton() {
|
||||
if (ZornVideoPlayer.paused) {
|
||||
Button_PlayPause.setAttribute("data-title", "Play (K)");
|
||||
Button_PlayPause.innerHTML = `${PlayIcon}`;
|
||||
} else {
|
||||
Button_PlayPause.setAttribute("data-title", "Pause (K)");
|
||||
Button_PlayPause.innerHTML = `${PauseIcon}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// src/functions/SkipAround.js
|
||||
function SkipAround() {
|
||||
const Button_SkipBack = document.querySelector(".zorn-player-controls #skip-back");
|
||||
const Button_SkipForth = document.querySelector(".zorn-player-controls #skip-forth");
|
||||
Button_SkipBack.addEventListener("click", Toggle_SkipBack);
|
||||
Button_SkipForth.addEventListener("click", Toggle_SkipForth);
|
||||
function Toggle_SkipBack() {
|
||||
Skip(-10);
|
||||
}
|
||||
function Toggle_SkipForth() {
|
||||
Skip(10);
|
||||
}
|
||||
function Skip(value) {
|
||||
ZornVideoPlayer.currentTime += value;
|
||||
}
|
||||
}
|
||||
|
||||
// src/functions/Fullscreen.js
|
||||
function Fullscreen() {
|
||||
const Button_Fullscreen = document.getElementById("fullscreen");
|
||||
function Toggle_Fullscreen() {
|
||||
if (document.fullscreenElement) {
|
||||
document.exitFullscreen();
|
||||
} else if (document.webkitFullscreenElement) {
|
||||
document.webkitExitFullscreen();
|
||||
} else if (VideoContainer.webkitRequestFullscreen) {
|
||||
VideoContainer.webkitRequestFullscreen();
|
||||
} else {
|
||||
VideoContainer.requestFullscreen();
|
||||
}
|
||||
}
|
||||
Button_Fullscreen.onclick = Toggle_Fullscreen;
|
||||
function Update_FullscreenButton() {
|
||||
if (document.fullscreenElement) {
|
||||
Button_Fullscreen.setAttribute("data-title", "Exit full screen (f)");
|
||||
} else {
|
||||
Button_Fullscreen.setAttribute("data-title", "Full screen (f)");
|
||||
}
|
||||
}
|
||||
ZornVideoPlayer.addEventListener("dblclick", () => {
|
||||
Toggle_Fullscreen();
|
||||
});
|
||||
}
|
||||
|
||||
// src/functions/Subtitles.js
|
||||
function Subtitles() {
|
||||
var subtitles = document.querySelector('.zorn-player-controls #subtitles')
|
||||
var subtitleMenuButtons = []
|
||||
var createMenuItem = function(id, lang, label) {
|
||||
var listItem = document.createElement('li')
|
||||
var button = listItem.appendChild(document.createElement('button'))
|
||||
button.setAttribute('id', id)
|
||||
button.className = 'subtitles-button'
|
||||
if (lang.length > 0) button.setAttribute('lang', lang)
|
||||
button.value = label
|
||||
button.setAttribute('data-state', 'inactive')
|
||||
button.appendChild(document.createTextNode(label))
|
||||
button.addEventListener('click', function(e) {
|
||||
subtitleMenuButtons.map(function(v, i, a) {
|
||||
subtitleMenuButtons[i].setAttribute('data-state', 'inactive')
|
||||
})
|
||||
var lang = this.getAttribute('lang')
|
||||
for (var i = 0; i < ZornVideoPlayer.textTracks.length; i++) {
|
||||
if (ZornVideoPlayer.textTracks[i].language == lang) {
|
||||
ZornVideoPlayer.textTracks[i].mode = 'showing'
|
||||
this.setAttribute('data-state', 'active')
|
||||
}
|
||||
else {
|
||||
ZornVideoPlayer.textTracks[i].mode = 'hidden'
|
||||
}
|
||||
}
|
||||
subtitlesMenu.style.display = 'none'
|
||||
})
|
||||
subtitleMenuButtons.push(button)
|
||||
return listItem
|
||||
}
|
||||
var subtitlesMenu
|
||||
if (ZornVideoPlayer.textTracks) {
|
||||
var df = document.createDocumentFragment()
|
||||
var subtitlesMenu = df.appendChild(document.createElement('ul'))
|
||||
subtitlesMenu.className = 'subtitles-menu'
|
||||
subtitlesMenu.appendChild(createMenuItem('subtitles-off', '', 'Off'))
|
||||
for (var i = 0; i < ZornVideoPlayer.textTracks.length; i++) {
|
||||
subtitlesMenu.appendChild(createMenuItem('subtitles-' + ZornVideoPlayer.textTracks[i].language, ZornVideoPlayer.textTracks[i].language, ZornVideoPlayer.textTracks[i].label))
|
||||
}
|
||||
VideoContainer.appendChild(subtitlesMenu)
|
||||
}
|
||||
subtitles.addEventListener('click', function(e) {
|
||||
if (subtitlesMenu) {
|
||||
subtitlesMenu.style.display = (subtitlesMenu.style.display == 'block' ? 'none' : 'block')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// src/functions/Volume.js
|
||||
function Volume() {
|
||||
const Button_Volume = document.getElementById("volume-button");
|
||||
const volume2 = document.getElementById("volume");
|
||||
function Update_Volme() {
|
||||
if (ZornVideoPlayer.muted) {
|
||||
ZornVideoPlayer.muted = false;
|
||||
}
|
||||
ZornVideoPlayer.volume = volume2.value;
|
||||
}
|
||||
volume2.addEventListener("input", Update_Volme);
|
||||
function Update_Volume_Icon() {
|
||||
Button_Volume.setAttribute("data-title", "Mute (M)");
|
||||
if (ZornVideoPlayer.muted || ZornVideoPlayer.volume === 0) {
|
||||
Button_Volume.innerHTML = `${VolumeOffIcon}`;
|
||||
Button_Volume.setAttribute("data-title", "Unmute (M)");
|
||||
} else if (ZornVideoPlayer.volume > 0 && ZornVideoPlayer.volume <= 0.5) {
|
||||
Button_Volume.innerHTML = `${VolumeMinIcon}`;
|
||||
} else {
|
||||
Button_Volume.innerHTML = `${VolumeHighIcon}`;
|
||||
}
|
||||
}
|
||||
ZornVideoPlayer.addEventListener("volumechange", Update_Volume_Icon);
|
||||
function Toggle_Mute() {
|
||||
ZornVideoPlayer.muted = !ZornVideoPlayer.muted;
|
||||
if (ZornVideoPlayer.muted) {
|
||||
volume2.setAttribute("data-volume", volume2.value);
|
||||
volume2.value = 0;
|
||||
} else {
|
||||
volume2.value = volume2.dataset.volume;
|
||||
}
|
||||
}
|
||||
Button_Volume.addEventListener("click", Toggle_Mute);
|
||||
}
|
||||
|
||||
// src/functions/Seek.js
|
||||
function Seek() {
|
||||
const timeElapsed = document.getElementById("time-elapsed");
|
||||
const duration = document.getElementById("duration");
|
||||
function formatTime(timeInSeconds) {
|
||||
const result = new Date(timeInSeconds * 1e3).toISOString().substr(11, 8);
|
||||
return {
|
||||
minutes: result.substr(3, 2),
|
||||
seconds: result.substr(6, 2)
|
||||
};
|
||||
}
|
||||
;
|
||||
function initializeVideo() {
|
||||
const videoDuration = Math.round(ZornVideoPlayer.duration);
|
||||
const time = formatTime(videoDuration);
|
||||
duration.innerText = `${time.minutes}:${time.seconds}`;
|
||||
duration.setAttribute("datetime", `${time.minutes}m ${time.seconds}s`);
|
||||
}
|
||||
ZornVideoPlayer.addEventListener("loadedmetadata", initializeVideo);
|
||||
function updateTimeElapsed() {
|
||||
const time = formatTime(Math.round(ZornVideoPlayer.currentTime));
|
||||
timeElapsed.innerText = `${time.minutes}:${time.seconds}`;
|
||||
timeElapsed.setAttribute("datetime", `${time.minutes}m ${time.seconds}s`);
|
||||
}
|
||||
ZornVideoPlayer.addEventListener("timeupdate", updateTimeElapsed);
|
||||
const progressBar = document.getElementById("progress-bar");
|
||||
const seek = document.getElementById("seek");
|
||||
function initializeVideo() {
|
||||
const videoDuration = Math.round(ZornVideoPlayer.duration);
|
||||
seek.setAttribute("max", videoDuration);
|
||||
progressBar.setAttribute("max", videoDuration);
|
||||
const time = formatTime(videoDuration);
|
||||
duration.innerText = `${time.minutes}:${time.seconds}`;
|
||||
duration.setAttribute("datetime", `${time.minutes}m ${time.seconds}s`);
|
||||
}
|
||||
function updateProgress() {
|
||||
seek.value = Math.floor(ZornVideoPlayer.currentTime);
|
||||
progressBar.value = Math.floor(ZornVideoPlayer.currentTime);
|
||||
}
|
||||
ZornVideoPlayer.addEventListener("timeupdate", updateProgress);
|
||||
const seekTooltip = document.getElementById("seek-tooltip");
|
||||
function updateSeekTooltip(event) {
|
||||
const skipTo = Math.round(event.offsetX / event.target.clientWidth * parseInt(event.target.getAttribute("max"), 10));
|
||||
seek.setAttribute("data-seek", skipTo);
|
||||
const t = formatTime(skipTo);
|
||||
seekTooltip.textContent = `${t.minutes}:${t.seconds}`;
|
||||
const rect = ZornVideoPlayer.getBoundingClientRect();
|
||||
seekTooltip.style.left = `${event.pageX - rect.left}px`;
|
||||
}
|
||||
seek.addEventListener("mousemove", updateSeekTooltip);
|
||||
function skipAhead(event) {
|
||||
const skipTo = event.target.dataset.seek ? event.target.dataset.seek : event.target.value;
|
||||
ZornVideoPlayer.currentTime = skipTo;
|
||||
progressBar.value = skipTo;
|
||||
seek.value = skipTo;
|
||||
}
|
||||
seek.addEventListener("input", skipAhead);
|
||||
initializeVideo();
|
||||
}
|
||||
|
||||
// src/dialogs/Buffering.js
|
||||
var BufferDialog = `
|
||||
<div id="buffering" class="zorn-dialog">
|
||||
${RefreshIcon}
|
||||
</div>
|
||||
`;
|
||||
ZornVideoPlayer.insertAdjacentHTML("afterend", BufferDialog);
|
||||
|
||||
// src/functions/AutoToggleControls.js
|
||||
function AutoToggleControls() {
|
||||
function Hide_Controls2() {
|
||||
if (ZornVideoPlayer.paused) {
|
||||
return;
|
||||
} else {
|
||||
document.querySelector(".zorn-player-controls").classList.add("hide");
|
||||
}
|
||||
}
|
||||
function Show_Controls2() {
|
||||
document.querySelector(".zorn-player-controls").classList.remove("hide");
|
||||
}
|
||||
ZornVideoPlayer.addEventListener("mouseenter", Show_Controls2);
|
||||
ZornVideoPlayer.addEventListener("mouseleave", Hide_Controls2);
|
||||
document.querySelector(".zorn-player-controls").addEventListener("mouseenter", Show_Controls2);
|
||||
document.querySelector(".zorn-player-controls").addEventListener("mouseleave", Hide_Controls2);
|
||||
var mouseTimer = null, cursorVisible = true;
|
||||
function Hide_Cursor() {
|
||||
mouseTimer = null;
|
||||
VideoContainer.style.cursor = "none";
|
||||
cursorVisible = false;
|
||||
Hide_Controls2();
|
||||
}
|
||||
document.onmousemove = function() {
|
||||
if (mouseTimer) {
|
||||
window.clearTimeout(mouseTimer);
|
||||
Show_Controls2();
|
||||
}
|
||||
if (!cursorVisible) {
|
||||
VideoContainer.style.cursor = "default";
|
||||
cursorVisible = true;
|
||||
}
|
||||
mouseTimer = window.setTimeout(Hide_Cursor, 3200);
|
||||
};
|
||||
}
|
||||
|
||||
// src/functions/KeyboardShortcuts.js
|
||||
function KeyboardShortcuts(events) {
|
||||
if (ZornVideoPlayer.hasAttribute("keyboard-shortcut-fullscreen")) {
|
||||
var Fullscreen_KeyboardShortcut = ZornVideoPlayer.getAttribute("keyboard-shortcut-fullscreen");
|
||||
} else {
|
||||
var Fullscreen_KeyboardShortcut = "f";
|
||||
}
|
||||
if (ZornVideoPlayer.hasAttribute("keyboard-shortcut-mute")) {
|
||||
var Mute_KeyboardShortcut = ZornVideoPlayer.getAttribute("keyboard-shortcut-mute");
|
||||
} else {
|
||||
var Mute_KeyboardShortcut = "m";
|
||||
}
|
||||
if (ZornVideoPlayer.hasAttribute("keyboard-shortcut-playpause")) {
|
||||
var PlayPause_KeyboardShortcut = ZornVideoPlayer.getAttribute("keyboard-shortcut-playpause");
|
||||
} else {
|
||||
var PlayPause_KeyboardShortcut = "k";
|
||||
}
|
||||
if (ZornVideoPlayer.hasAttribute("keyboard-shortcut-skipback")) {
|
||||
var SkipBack_KeyboardShortcut = ZornVideoPlayer.getAttribute("keyboard-shortcut-skipback");
|
||||
} else {
|
||||
var SkipBack_KeyboardShortcut = "j";
|
||||
}
|
||||
if (ZornVideoPlayer.hasAttribute("keyboard-shortcut-skipforth")) {
|
||||
var SkipForth_KeyboardShortcut = ZornVideoPlayer.getAttribute("keyboard-shortcut-skipforth");
|
||||
} else {
|
||||
var SkipForth_KeyboardShortcut = "l";
|
||||
}
|
||||
function keyboardShortcuts(event) {
|
||||
const { key } = event;
|
||||
if (key === PlayPause_KeyboardShortcut) {
|
||||
if (ZornVideoPlayer.paused || ZornVideoPlayer.ended) {
|
||||
ZornVideoPlayer.play();
|
||||
} else {
|
||||
ZornVideoPlayer.pause();
|
||||
}
|
||||
if (ZornVideoPlayer.paused) {
|
||||
Show_Controls();
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
Hide_Controls();
|
||||
}, 1200);
|
||||
}
|
||||
} else if (key === Mute_KeyboardShortcut) {
|
||||
ZornVideoPlayer.muted = !ZornVideoPlayer.muted;
|
||||
if (ZornVideoPlayer.muted) {
|
||||
volume.setAttribute("data-volume", volume.value);
|
||||
volume.value = 0;
|
||||
} else {
|
||||
volume.value = volume.dataset.volume;
|
||||
}
|
||||
} else if (key === Fullscreen_KeyboardShortcut) {
|
||||
if (document.fullscreenElement) {
|
||||
document.exitFullscreen();
|
||||
} else if (document.webkitFullscreenElement) {
|
||||
document.webkitExitFullscreen();
|
||||
} else if (VideoContainer.webkitRequestFullscreen) {
|
||||
VideoContainer.webkitRequestFullscreen();
|
||||
} else {
|
||||
VideoContainer.requestFullscreen();
|
||||
}
|
||||
} else if (key === SkipBack_KeyboardShortcut) {
|
||||
ZornVideoPlayer.currentTime += -10;
|
||||
} else if (key === SkipForth_KeyboardShortcut) {
|
||||
ZornVideoPlayer.currentTime += 10;
|
||||
}
|
||||
}
|
||||
document.addEventListener("keyup", keyboardShortcuts);
|
||||
}
|
||||
|
||||
// src/index.js
|
||||
Events();
|
||||
KeyboardShortcuts();
|
||||
PlayPause();
|
||||
AutoToggleControls();
|
||||
SkipAround();
|
||||
Fullscreen();
|
||||
Subtitles();
|
||||
Volume();
|
||||
Seek();
|
||||
Buffering();
|
||||
})();
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
// Service Worker is used to cache the offline page
|
||||
// if the end-user were to ever go offline. An offline page
|
||||
// should show up if their network condition is offline.
|
||||
// This is best practice for the Progress Web App and
|
||||
// provides a better user experience.
|
||||
|
||||
// Read more on this topic:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Guides/Offline_and_background_operation#offline_operation
|
||||
|
||||
'use strict'
|
||||
|
||||
var cacheVersion = 1
|
||||
var currentCache = {
|
||||
offline: 'offline-cache' + cacheVersion
|
||||
}
|
||||
const offlineUrl = 'offline'
|
||||
|
||||
this.addEventListener('install', event => {
|
||||
event.waitUntil(
|
||||
caches.open(currentCache.offline).then(function (cache) {
|
||||
return cache.addAll([
|
||||
offlineUrl
|
||||
])
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
this.addEventListener('fetch', event => {
|
||||
if (event.request.mode === 'navigate' || (event.request.method === 'GET' && event.request.headers.get('accept').includes('text/html'))) {
|
||||
event.respondWith(
|
||||
fetch(event.request.url).catch(error => {
|
||||
return caches.match(offlineUrl)
|
||||
})
|
||||
)
|
||||
}
|
||||
else {
|
||||
event.respondWith(caches.match(event.request)
|
||||
.then(function (response) {
|
||||
return response || fetch(event.request)
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue