Dizi ve filmleri eşleştirme modu eklendi.
This commit is contained in:
@@ -69,7 +69,7 @@ let canPlayNext = false;
|
||||
function assetUrl(pathname) {
|
||||
if (!pathname) return null;
|
||||
const token = localStorage.getItem("token");
|
||||
return `${API}${pathname}?token=${token}`;
|
||||
return `${API}${pathname}?token=${token}&t=${Date.now()}`;
|
||||
}
|
||||
|
||||
function posterUrl(show) {
|
||||
@@ -250,7 +250,7 @@ let canPlayNext = false;
|
||||
|
||||
function mapEpisodeToPlayerItem(show, episode) {
|
||||
if (!show || !episode?.videoPath) return null;
|
||||
const name = episode.videoPath;
|
||||
const name = (episode.videoPath || "").replace(/^\/+/, "");
|
||||
const ext = name.split(".").pop()?.toLowerCase() || "";
|
||||
const inferredType = ext ? `video/${ext}` : "video/mp4";
|
||||
const size =
|
||||
@@ -276,6 +276,7 @@ let canPlayNext = false;
|
||||
|
||||
$: selectedName = selectedVideo?.name ?? "";
|
||||
$: encName = selectedName ? encodeURIComponent(selectedName) : "";
|
||||
$: downloadHref = encName ? `${API}/downloads/${encName}` : "#";
|
||||
$: selectedLabel = selectedVideo?.episode
|
||||
? `${selectedVideo.show.title} · ${formatEpisodeCode(
|
||||
selectedVideo.episode
|
||||
@@ -346,6 +347,18 @@ async function openVideoAtIndex(index) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Video element'in yüklendiğinden emin ol
|
||||
await tick();
|
||||
setTimeout(() => {
|
||||
if (videoEl) {
|
||||
console.log("Video element found after timeout:", videoEl);
|
||||
console.log("Video src:", videoEl.src);
|
||||
console.log("Video readyState:", videoEl.readyState);
|
||||
} else {
|
||||
console.error("Video element not found after timeout");
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function stopCurrentVideo() {
|
||||
@@ -375,7 +388,8 @@ async function openVideoAtIndex(index) {
|
||||
function getVideoURL() {
|
||||
if (!selectedName) return "";
|
||||
const token = localStorage.getItem("token");
|
||||
return `${API}/media/${encName}?token=${token}`;
|
||||
// selectedName zaten encode edilmiş, tekrar encode etme
|
||||
return `${API}/media/${selectedName}?token=${token}`;
|
||||
}
|
||||
|
||||
function playEpisodeFromCard(episode) {
|
||||
@@ -532,6 +546,16 @@ async function openVideoAtIndex(index) {
|
||||
const handleKey = (event) => {
|
||||
if (!showPlayerModal) return;
|
||||
if (isEditableTarget(event.target)) return;
|
||||
|
||||
const isCmd = event.metaKey || event.ctrlKey;
|
||||
if (isCmd && event.key.toLowerCase() === "a") {
|
||||
// Text input'larda çalıştırma
|
||||
if (isEditableTarget(event.target)) return;
|
||||
event.preventDefault();
|
||||
// TvShows sayfasında tümünü seçme işlevi yok, sadece engelleme yapıyoruz
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.key === "Escape") {
|
||||
event.preventDefault();
|
||||
closePlayer();
|
||||
@@ -787,8 +811,13 @@ async function openVideoAtIndex(index) {
|
||||
src={getVideoURL()}
|
||||
class="video-element"
|
||||
playsinline
|
||||
controls={false}
|
||||
preload="metadata"
|
||||
crossorigin="anonymous"
|
||||
type={selectedVideo?.type || "video/mp4"}
|
||||
on:timeupdate={updateProgress}
|
||||
on:loadedmetadata={async () => {
|
||||
console.log("Video metadata loaded");
|
||||
isPlaying = false;
|
||||
currentTime = 0;
|
||||
updateDuration();
|
||||
@@ -805,7 +834,37 @@ async function openVideoAtIndex(index) {
|
||||
isPlaying = false;
|
||||
}
|
||||
}}
|
||||
on:loadeddata={() => {
|
||||
console.log("Video data loaded");
|
||||
}}
|
||||
on:canplay={() => {
|
||||
console.log("Video can play");
|
||||
}}
|
||||
on:error={(e) => {
|
||||
console.error("Video error:", e);
|
||||
}}
|
||||
on:ended={() => (isPlaying = false)}
|
||||
on:loadstart={() => {
|
||||
console.log("Video load start");
|
||||
}}
|
||||
on:canplaythrough={() => {
|
||||
console.log("Video can play through");
|
||||
}}
|
||||
on:stalled={() => {
|
||||
console.log("Video stalled");
|
||||
}}
|
||||
on:suspend={() => {
|
||||
console.log("Video suspended");
|
||||
}}
|
||||
on:abort={() => {
|
||||
console.log("Video aborted");
|
||||
}}
|
||||
on:emptied={() => {
|
||||
console.log("Video emptied");
|
||||
}}
|
||||
on:waiting={() => {
|
||||
console.log("Video waiting");
|
||||
}}
|
||||
>
|
||||
{#if subtitleURL}
|
||||
<track
|
||||
@@ -860,7 +919,7 @@ async function openVideoAtIndex(index) {
|
||||
<i class="fa-solid fa-expand"></i>
|
||||
</button>
|
||||
<a
|
||||
href={selectedName ? `${API}/downloads/${selectedName}` : "#"}
|
||||
href={downloadHref}
|
||||
download={selectedName || undefined}
|
||||
class="control-btn"
|
||||
title="Download"
|
||||
@@ -1235,15 +1294,26 @@ async function openVideoAtIndex(index) {
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
border-radius: 16px;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(255, 255, 255, 0.3) rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.episode-list::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.episode-list::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.episode-list::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.episode-list::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.episode-card {
|
||||
@@ -1345,98 +1415,117 @@ async function openVideoAtIndex(index) {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* 🎞️ Film oynatıcı ile aynı düzen */
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
backdrop-filter: blur(4px);
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 5000;
|
||||
padding: 32px;
|
||||
z-index: 6000;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
width: min(960px, 95vw);
|
||||
background: #0f0f0f;
|
||||
border-radius: 16px;
|
||||
padding: 18px;
|
||||
width: 70%;
|
||||
height: 70%;
|
||||
background: #1a1a1a;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
color: #f5f5f5;
|
||||
position: relative;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0 30px rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
background: #2a2a2a;
|
||||
padding: 10px 16px;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.video-title {
|
||||
font-size: 16px;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.video-meta {
|
||||
font-size: 13px;
|
||||
color: #b5b5b5;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.custom-player {
|
||||
background: #000;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
justify-content: space-between;
|
||||
min-height: 0;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.video-element {
|
||||
flex: 1 1 auto;
|
||||
width: 100%;
|
||||
max-height: 60vh;
|
||||
height: auto;
|
||||
max-height: 100%;
|
||||
min-height: 0;
|
||||
object-fit: contain;
|
||||
background: #000;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.video-element:focus {
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.controls {
|
||||
background: #1c1c1c;
|
||||
padding: 10px 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 0 14px 14px;
|
||||
flex-shrink: 0;
|
||||
border-top: 1px solid #333;
|
||||
}
|
||||
|
||||
.top-controls {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.left-controls {
|
||||
display: inline-flex;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.control-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #f5f5f5;
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s ease;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.control-btn:hover {
|
||||
color: #f5b333;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.control-btn[disabled],
|
||||
.control-btn[disabled]:hover {
|
||||
color: rgba(245, 245, 245, 0.35);
|
||||
.control-btn[disabled] {
|
||||
opacity: 0.35;
|
||||
cursor: default;
|
||||
pointer-events: none;
|
||||
}
|
||||
@@ -1447,59 +1536,56 @@ async function openVideoAtIndex(index) {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.volume-slider,
|
||||
.progress-slider {
|
||||
appearance: none;
|
||||
.volume-slider {
|
||||
-webkit-appearance: none;
|
||||
width: 100px;
|
||||
height: 4px;
|
||||
border-radius: 2px;
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
#f5b333 var(--fill, 100%),
|
||||
rgba(255, 255, 255, 0.24) var(--fill, 100%)
|
||||
#ff3b30 calc(var(--fill, 100%) * 1%),
|
||||
rgba(255, 255, 255, 0.3) calc(var(--fill, 100%) * 1%)
|
||||
);
|
||||
border-radius: 999px;
|
||||
height: 4px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s ease;
|
||||
}
|
||||
|
||||
.volume-slider {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.progress-slider {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.volume-slider::-webkit-slider-thumb,
|
||||
.progress-slider::-webkit-slider-thumb {
|
||||
appearance: none;
|
||||
.volume-slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: #f5b333;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
margin-top: -4px;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.volume-slider::-webkit-slider-thumb:hover {
|
||||
transform: scale(1.3);
|
||||
}
|
||||
|
||||
.bottom-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
font-size: 13px;
|
||||
color: #d4d4d4;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.global-close-btn {
|
||||
position: absolute;
|
||||
top: 18px;
|
||||
right: 28px;
|
||||
background: rgba(0, 0, 0, 0.55);
|
||||
color: #f5f5f5;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
.progress-slider {
|
||||
flex: 1;
|
||||
cursor: pointer;
|
||||
font-size: 17px;
|
||||
accent-color: #27ae60;
|
||||
}
|
||||
|
||||
.time {
|
||||
color: #ccc;
|
||||
font-size: 13px;
|
||||
min-width: 90px;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@media (max-width: 860px) {
|
||||
|
||||
Reference in New Issue
Block a user