Add a new page for embedding a professional video player

Create a new PlayerPage component and integrate it into the application's routing system in App.tsx.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 401e2ec0-e00d-4f10-9d0e-60f3d479f9a5
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 15dfc78d-6c19-4b56-87b3-722b187c2f24
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/60d372ff-2c10-46c7-b01b-10c3435136b0/401e2ec0-e00d-4f10-9d0e-60f3d479f9a5/7NzVbGU
This commit is contained in:
sebastjanartic 2026-01-27 09:11:29 +00:00
parent ab45c7caed
commit 990c951f17
3 changed files with 366 additions and 0 deletions

View File

@ -0,0 +1,142 @@
npm run dev
5m
5 minutes ago
Publishing
Started 1 minute ago by Sebastjan
Provision
Security Scan
Build
Bundle
Promote
Production
Status
Sebastjan published 5 months ago
Visibility
Public
Domain
https://player-one-sebastjanartic.replit.app
Type
Autoscale
(4 vCPU / 8 GiB RAM / 3 Max)
See all usage
Database
Production database connected
Your production database is ready! Your app can now save and manage live user data securely.
Saved progress at the end of the loop
Evo je koda! 🎯 Tukaj je implementacija professional player s streaming funkcionalnostjo:
Glavni deli:
1. Professional Player (professional-player.tsx)
MTV-style overlay graphics (logo + lower third)
RTMP streaming controls (vrstice 78-79)
Video queue management
Graphics overlays z opacity in pozicijo
2. RTMP Streaming Server (streaming-server.ts)
FFmpeg integration za live streaming
Multi-platform support (Twitch, YouTube, Facebook)
Lokalni RTMP server na portu 1935
Video source detection (Bunny.net, lokalni fajli, HTTP)
3. Video Player Component (VideoPlayer.tsx)
Video.js integration za profesionalno predvajanje
Bunny.net embed support
Keyboard shortcuts (Space, F, M)
Ključne funkcije za streaming:
Vrstica 1124: RTMP streaming gumb
Vrstice 124-157: Local RTMP stream funkcija
Vrstice 90-121: Multi-platform streaming
Vrstica 73: RTMP URL: rtmp://localhost:1935/live
Aplikacija že deluje - vidim v logih da je "RTMP Server started on port 1935"!
Ali si želiš:
Videti RTMP streaming gumb v action-u?
Dodati Bunny Stream API integration?
Testirati streaming z VLC?
Kaj te zanima najbolj? 🚀
Zakaj ki delim na na whats up ni slike
ko se player postavi ima najšprej levo in desno crne šrte
pri S se ne vidi pasica ni vse v proporcijh
govorim o tem gda jo pol manjak
sedaj naaredi da se pop up postavi na zadnje znano pozicijo takoj ko se zamne playati. ko damo stop potem izgine paus pa se ustavi play potem naprej
✅ Dodal avtomatsko upravljanje popup okna:
→ Ko se začne predvajanje - popup se samodejno odpre na zadnji poziciji
→ Ko se ustavi (STOP) - popup izgine
→ Ko se pauzira - popup ostane odprt
→ Shrani pozicijo in velikost popup okna v localStorage
Deluje sedaj popup kako pričakujete?
poglej velikosti videja ker so bili robovi odrezani in ni safe strana poglej kako more bit da se vedno prav postavi katere velikostoiker ni vedno enako klr na prbližn ??!!
še vedno ne S velikosto odreže spodaj video
rećže še vednoi
Perfektno! 🎯 Vidim da je sedaj velikost "S" res deluje odlično!
Na sliki vidim:
Video se NE reže več spodaj ✅
Cel video je viden ✅
Lower third pasica je lepo vidna ✅
Proporci so pravilni ✅
Popup okno je uporabno ✅
Uspešno rešeno! 🚀
Sedaj professional video player popup deluje popolno:
✅ Avtomatsko upravljanje - odpre/zapre se z play/stop
✅ Shrani pozicijo - pomni zadnjo lokacijo
✅ Pravilne velikosti - S, M, L, XL vse delujejo
✅ Brez odrezovanja - cel video viden na vseh velikostih
✅ Professional overlays - logo in lower third scaling
✅ Draggable - premakljivo po ekranu
Video player je sedaj pripravljen za profesionalno uporabo s popolno funkcionalnostjo! 📺✨
Ali bi radi dodali še kaj drugega ali testirali druge funkcionalnosti?
glej tekst spodaj na sliki ki je odrezan p
reže ta tekst na vseh velikostih
na S in MK reže neki nimap ok z scale
ne ni ok
ali mi lahko daš kakšnoi imbed kodo za player da jo dam na inerbetnoi stran ?
https://player-one-sebastjanartic.replit.app to je moj naslov daj mi cel naslov in ali moram deployat
Da, morate najprej objaviti (deploy) aplikacijo, da bo embed koda delovala na zunanjih straneh!
Tukaj je vaša embed koda:
Odzivna (responsive) verzija - priporočena:
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe
src="https://player-one-sebastjanartic.replit.app/professional-player"
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none;"
allowfullscreen
allow="autoplay; fullscreen">
</iframe>
</div>
Fiksna velikost:
<iframe
src="https://player-one-sebastjanartic.replit.app/professional-player"
width="800"
height="450"
frameborder="0"
allowfullscreen
allow="autoplay; fullscreen"
style="border: none;">
</iframe>

View File

@ -10,6 +10,7 @@ import FolxStadlPage from "@/pages/FolxStadlPage";
import GeschichteLiedPage from "@/pages/GeschichteLiedPage"; import GeschichteLiedPage from "@/pages/GeschichteLiedPage";
import GipfelstammtischPage from "@/pages/GipfelstammtischPage"; import GipfelstammtischPage from "@/pages/GipfelstammtischPage";
import LivePage from "@/pages/LivePage"; import LivePage from "@/pages/LivePage";
import PlayerPage from "@/pages/PlayerPage";
import AdminPage from "@/pages/admin"; import AdminPage from "@/pages/admin";
import PrivacyPolicy from "@/pages/PrivacyPolicy"; import PrivacyPolicy from "@/pages/PrivacyPolicy";
import TermsOfService from "@/pages/TermsOfService"; import TermsOfService from "@/pages/TermsOfService";
@ -25,6 +26,7 @@ function Router() {
<Route path="/geschichte-lied" component={GeschichteLiedPage} /> <Route path="/geschichte-lied" component={GeschichteLiedPage} />
<Route path="/gipfelstammtisch" component={GipfelstammtischPage} /> <Route path="/gipfelstammtisch" component={GipfelstammtischPage} />
<Route path="/live" component={LivePage} /> <Route path="/live" component={LivePage} />
<Route path="/player" component={PlayerPage} />
<Route path="/admin" component={AdminPage} /> <Route path="/admin" component={AdminPage} />
<Route path="/privacy" component={PrivacyPolicy} /> <Route path="/privacy" component={PrivacyPolicy} />
<Route path="/terms" component={TermsOfService} /> <Route path="/terms" component={TermsOfService} />

View File

@ -0,0 +1,222 @@
import { useState, useEffect } from 'react';
import { ChevronLeft, Menu, X, Search, Tv } from 'lucide-react';
import { Link } from 'wouter';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { useQuery } from '@tanstack/react-query';
import VideoCard from '@/components/video-card';
import HeaderAd from '@/components/HeaderAd';
export default function PlayerPage() {
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [searchQuery, setSearchQuery] = useState("");
const { data: videosData } = useQuery({
queryKey: ['/api/videos'],
staleTime: 5 * 60 * 1000,
});
const videos = (videosData && Array.isArray((videosData as any).videos)) ? (videosData as any).videos : [];
useEffect(() => {
document.title = 'Professional Player | video.folx.tv';
const metaDescription = document.querySelector('meta[name="description"]');
if (metaDescription) {
metaDescription.setAttribute('content', 'Professional Video Player mit Streaming-Funktionen auf video.folx.tv');
}
}, []);
const handleSearch = (e: React.FormEvent) => {
e.preventDefault();
if (searchQuery.trim()) {
window.location.href = `/?search=${encodeURIComponent(searchQuery)}`;
}
};
return (
<div className="min-h-screen bg-gradient-to-b from-[#0f0f14] to-[#1a1a24]">
<header className="sticky top-0 z-50 bg-[#0f0f14]/95 backdrop-blur-sm border-b border-gray-800/50">
<div className="max-w-7xl mx-auto px-4 py-3">
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<Link href="/">
<Button variant="ghost" size="icon" className="text-gray-400 hover:text-white">
<ChevronLeft className="h-5 w-5" />
</Button>
</Link>
<Link href="/">
<img
src="https://folx.tv/images/logo.svg"
alt="FOLX.TV"
className="h-8 cursor-pointer hover:opacity-80 transition-opacity"
/>
</Link>
</div>
<nav className="hidden md:flex items-center gap-6">
<Link href="/" className="text-gray-300 hover:text-white transition-colors text-sm font-medium">
Videos
</Link>
<Link href="/live" className="text-gray-300 hover:text-white transition-colors text-sm font-medium">
LIVE
</Link>
<Link href="/player" className="text-pink-500 transition-colors text-sm font-medium flex items-center gap-1">
<Tv className="h-4 w-4" />
Player
</Link>
</nav>
<div className="flex items-center gap-3">
<form onSubmit={handleSearch} className="hidden md:flex relative">
<Input
type="text"
placeholder="Suchen..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-64 bg-gray-800/50 border-gray-700 text-white placeholder:text-gray-500 pr-10"
/>
<Button
type="submit"
size="icon"
variant="ghost"
className="absolute right-0 top-0 h-full text-gray-400 hover:text-white"
>
<Search className="h-4 w-4" />
</Button>
</form>
<Button
variant="ghost"
size="icon"
className="md:hidden text-gray-400 hover:text-white"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
>
{isMobileMenuOpen ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />}
</Button>
</div>
</div>
{isMobileMenuOpen && (
<div className="md:hidden mt-4 pb-4 border-t border-gray-800 pt-4">
<nav className="flex flex-col gap-3">
<Link href="/" className="text-gray-300 hover:text-white transition-colors text-sm font-medium py-2">
Videos
</Link>
<Link href="/live" className="text-gray-300 hover:text-white transition-colors text-sm font-medium py-2">
LIVE
</Link>
<Link href="/player" className="text-pink-500 transition-colors text-sm font-medium py-2 flex items-center gap-2">
<Tv className="h-4 w-4" />
Player
</Link>
</nav>
<form onSubmit={handleSearch} className="mt-4 relative">
<Input
type="text"
placeholder="Suchen..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full bg-gray-800/50 border-gray-700 text-white placeholder:text-gray-500 pr-10"
/>
<Button
type="submit"
size="icon"
variant="ghost"
className="absolute right-0 top-0 h-full text-gray-400 hover:text-white"
>
<Search className="h-4 w-4" />
</Button>
</form>
</div>
)}
</div>
</header>
<HeaderAd />
<main className="max-w-7xl mx-auto px-4 py-6">
<div className="flex items-center gap-3 mb-6">
<div className="bg-gradient-to-r from-pink-500 to-purple-600 p-2 rounded-lg">
<Tv className="h-6 w-6 text-white" />
</div>
<div>
<h1 className="text-2xl md:text-3xl font-bold text-white">Professional Player</h1>
<p className="text-gray-400 text-sm">MTV-Style Overlay Graphics & Streaming</p>
</div>
</div>
<div className="bg-black rounded-xl overflow-hidden shadow-2xl mb-8">
<div style={{ position: 'relative', paddingBottom: '56.25%', height: 0, overflow: 'hidden' }}>
<iframe
src="https://player-one-sebastjanartic.replit.app/professional-player"
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
border: 'none'
}}
allowFullScreen
allow="autoplay; fullscreen"
title="Professional Video Player"
/>
</div>
</div>
<div className="bg-gray-800/30 rounded-xl p-6 mb-8">
<h2 className="text-xl font-semibold text-white mb-4">Embed Code</h2>
<p className="text-gray-400 text-sm mb-4">Kopieren Sie diesen Code, um den Player auf Ihrer Website einzubetten:</p>
<div className="bg-gray-900 rounded-lg p-4 overflow-x-auto">
<code className="text-green-400 text-sm whitespace-pre-wrap break-all">
{`<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe
src="https://player-one-sebastjanartic.replit.app/professional-player"
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none;"
allowfullscreen
allow="autoplay; fullscreen">
</iframe>
</div>`}
</code>
</div>
<Button
className="mt-4 bg-pink-600 hover:bg-pink-700"
onClick={() => {
navigator.clipboard.writeText(`<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe
src="https://player-one-sebastjanartic.replit.app/professional-player"
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none;"
allowfullscreen
allow="autoplay; fullscreen">
</iframe>
</div>`);
alert('Code kopiert!');
}}
>
Code kopieren
</Button>
</div>
{videos.length > 0 && (
<section>
<h2 className="text-xl font-semibold text-white mb-4">Empfohlene Videos</h2>
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4">
{videos.slice(0, 10).map((video: any) => (
<VideoCard key={video.id} video={video} onClick={() => window.location.href = `/video/${video.id.replace(/-/g, '').substring(0, 8)}`} />
))}
</div>
</section>
)}
</main>
<footer className="bg-[#0a0a0f] border-t border-gray-800 py-8 mt-12">
<div className="max-w-7xl mx-auto px-4 text-center">
<p className="text-gray-500 text-sm">
© 2025 FOLX.TV - Alle Rechte vorbehalten
</p>
</div>
</footer>
</div>
);
}