hp / vidstack.html
daydreamer-json's picture
Edit vidstack.html
0bc16b3 verified
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://rsms.me/">
<link rel="stylesheet" href="https://rsms.me/inter/inter.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/daydreamer-json/SomeFontRepo@main/somefontrepo.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100;200;300;400;500;600;700;800;900&display=swap" rel="stylesheet">
<link rel="stylesheet prefetch" href="https://daydreamer-json-me.static.hf.space/apple_fonts.css">
<link rel="stylesheet" href="https://cdn.vidstack.io/player/theme.css">
<link rel="stylesheet" href="https://cdn.vidstack.io/player/video.css">
<script src="https://cdn.vidstack.io/player" type="module"></script>
<script src='https://unpkg.com/bignumber.js'></script>
<script src='https://unpkg.com/cbor-web'></script>
<style>
:root { font-family: 'Inter', sans-serif; }
@supports (font-variation-settings: normal) {
:root { font-family: 'Inter var', sans-serif; }
}
body {
margin: 0;
background-color: #000000;
width: 100vw;
height: 100vh;
font-family: 'SF Pro Text', 'Inter', 'Noto Sans JP', sans-serif;
}
.wrapper {
height: 100vh;
display: flex;
flex-direction: column;
}
#player {
flex-grow: 1;
top: 0;
left: 0;
height: 100%;
width: 100%;
font-family: 'SF Pro Text', 'Inter', 'Noto Sans JP', sans-serif;
overflow: hidden;
}
.vds-video-layout {
--video-font-family: 'Inter', 'Noto Sans JP', sans-serif !important;
--video-border-radius: 0px !important;
--video-border: 0px !important;
}
:where([data-media-provider], video, media-poster) {
border-radius: var(--video-border-radius);
border: var(--video-border);
}
:where([data-media-player][data-view-type=video]:not([data-fullscreen])) {
border-radius: var(--video-border-radius);
border: var(--video-border);
}
:where([data-media-player][data-view-type=video]) {
border-radius: var(--video-border-radius);
border: var(--video-border);
}
[data-media-provider] video {
width: 100%;
height: 100%;
object-fit: contain;
}
media-captions {
/* font-family: 'SDK_JP_Web', sans-serif; */
font-family: 'Inter', 'Noto Sans JP', sans-serif;
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.75), -1px 1px 0 rgba(0, 0, 0, 0.75), 1px -1px 0 rgba(0, 0, 0, 0.75), -1px -1px 0 rgba(0, 0, 0, 0.75);
}
footer.copyrightDisp {
position: fixed;
left: 0;
bottom: 0;
padding: 0;
margin: 0 0 10px 10px;
color: #ffffff80;
z-index: 2;
user-select: none;
}
</style>
</head>
<body>
<div class="wrapper">
<media-player
title=""
aspect-ratio="16/9"
crossorigin
id="player"
>
<media-provider id="player-media-outlet-el">
</media-provider>
<media-audio-layout></media-audio-layout>
<media-video-layout></media-video-layout>
</media-player>
</div>
<script>
const uiTranslation = {
"ja-JP": {
'Caption Styles': '字幕のスタイル',
'Captions look like this': '字幕はこのように見えます',
'Closed-Captions Off': '字幕オフ',
'Closed-Captions On': '字幕オン',
'Display Background': '背景を表示',
'Enter Fullscreen': '全画面表示',
'Enter PiP': 'PiP',
'Exit Fullscreen': '全画面表示を終了',
'Exit PiP': 'PiPを終了',
'Google Cast': 'Google Cast',
'Keyboard Animations': 'キーボードアニメーション',
'Seek Backward': '戻る',
'Seek Forward': '進む',
'Skip To Live': 'ライブへスキップ',
'Text Background': 'テキストの背景',
Accessibility: 'アクセシビリティ',
AirPlay: 'AirPlay',
Announcements: 'アナウンス',
Audio: '音声',
Auto: '自動',
Boost: 'ブースト',
Captions: '字幕',
Chapters: 'チャプター',
Color: '色',
Connected: '接続しました',
Connecting: '接続中',
Continue: '続ける',
Default: 'デフォルト',
Disabled: '無効',
Disconnected: '切断されました',
Download: 'ダウンロード',
Family: 'ファミリー',
Font: 'フォント',
Fullscreen: '全画面表示',
LIVE: 'LIVE',
Loop: 'ループ',
Mute: 'ミュート',
Normal: '標準',
Off: 'オフ',
Opacity: '不透明度',
Pause: '一時停止',
PiP: 'PiP',
Play: '再生',
Playback: '再生',
Quality: '画質',
Replay: 'リプレイ',
Reset: 'リセット',
Seek: 'シーク',
Settings: '設定',
Shadow: '影',
Size: 'サイズ',
Speed: '速度',
Text: 'テキスト',
Track: 'トラック',
Unmute: 'ミュート解除',
Volume: '音量',
}
};
const pageUUID = "d511b8f7-5579-41a6-8450-e9f958507f94";
let playerConfigObject = {
"volume": null,
"muted": null
};
window.volumeChangeEventCounter = 0;
window.addEventListener('load', async function(){
// const cbor = require('cbor-web');
// uiTranslation.cbor.ja = atob(uiTranslation.base64.ja);
// uiTranslation.json.ja = await cbor.decodeFirst(uiTranslation.cbor.ja);
document.oncontextmenu = function () {return false;}
window.player = document.querySelector('media-player');
for (let i = 0; i < Object.keys(uiTranslation).length; i++) {
if (window.navigator.language == Object.keys(uiTranslation)[i]) {
document.querySelector('media-video-layout').translations = uiTranslation[Object.keys(uiTranslation)[i]];
}
}
const pageUrlLocationHref = new URL(location.href);
const pageSearchParams = pageUrlLocationHref.searchParams;
if (pageSearchParams.has("url") === true && pageSearchParams.get("url") !== "") {
attachSourceToPlayer(pageSearchParams.get("url"));
if (pageSearchParams.has("subtitle") === true && pageSearchParams.get("subtitle") !== "") {
attachSubtitleSourceToPlayer(pageSearchParams.get("subtitle"));
}
} else {
const promptedUrl = prompt("Please input source URL");
if (promptedUrl === "") {
alert("Source not found");
} else {
attachSourceToPlayer(promptedUrl);
}
}
player.addEventListener('provider-change', (event) => {
const provider = event.detail;
if (provider?.type === 'hls') {
provider.library = 'https://cdn.jsdelivr.net/npm/hls.js@1.4.12/dist/hls.min.js';
provider.config = {
"debug": false,
"enableWorker": true,
"lowLatencyMode": true,
"backBufferLength": 90
};
window.provider = provider;
}
});
importConfigFromBrowser();
player.addEventListener('volume-change', (event) => {
volumeChangeSaveToConfig();
});
const { audioTracks } = player.state;
player.subscribe(({ audioTracks }) => {
mhyLangAutoSelect(JSON.stringify(audioTracks, '', ' '));
});
});
function attachSourceToPlayer (url) {
player.src = url;
player.title = url.match(/^(?:[^:\/?#]+:)?(?:\/\/[^\/?#]*)?(?:([^?#]*\/)([^\/?#]*))?(\?[^#]*)?(?:#.*)?$/)[2].match(/^(.+?)(\.[^.]+)?$/)[1];
}
function attachSubtitleSourceToPlayer (url) {
const outletElement = document.querySelector('#player-media-outlet-el');
const trackElement = document.createElement("track");
trackElement.src = url;
trackElement.kind = "subtitles";
trackElement.label = "Subtitle";
outletElement.appendChild(trackElement);
}
function volumeChangeSaveToConfig () {
if (volumeChangeEventCounter >= 0) {
playerConfigObject.volume = player.volume;
playerConfigObject.muted = player.muted;
saveConfigToBrowser();
}
volumeChangeEventCounter += 1;
}
function importConfigFromBrowser () {
if (window.localStorage && localStorage.getItem(`${pageUUID}`) !== null) {
playerConfigObject = JSON.parse(localStorage.getItem(`${pageUUID}`));
player.volume = playerConfigObject.volume;
player.muted = playerConfigObject.muted;
console.warn(`Loaded config from localStorage\n${pageUUID} = ${JSON.stringify(playerConfigObject, '', ' ')}`);
}
}
function saveConfigToBrowser () {
if (window.localStorage) {
localStorage.setItem(`${pageUUID}`, JSON.stringify(playerConfigObject));
console.warn(`Saved config to localStorage\n${pageUUID} = ${JSON.stringify(playerConfigObject, '', ' ')}`);
}
}
function mhyLangAutoSelect (audioTracks) {
const testBefore = [
{
"id": "0",
"label": "Chinese",
"language": "zh-CN",
"kind": "main"
},
{
"id": "1",
"label": "English",
"language": "en-US",
"kind": "main"
},
{
"id": "2",
"label": "Japanese",
"language": "ja-JP",
"kind": "main"
},
{
"id": "3",
"label": "Korean",
"language": "ko-KR",
"kind": "main"
}
];
if (audioTracks === JSON.stringify(testBefore, '', ' ')) {
for (let i = 0; i < testBefore.length; i++) {
if (window.navigator.language.slice(0,2) === testBefore[i].language.slice(0,2)) {
player.audioTracks[i].selected = true;
console.warn(`Player audio language has been automatically changed to\n${JSON.stringify(player.audioTracks[i], '', ' ')}`);
}
}
}
}
</script>
</body>
</html>