<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="csrf-token" content="7SvTtzRMjHQ4u8lhybGhOXna6th4kB4kRjyJ0Dex">

    <title>YouTube to MP3 Converter - Yt2Conv</title>
<meta name="description" content="With Yt2Conv, you can convert YouTube videos to MP3 or MP4 and save high-quality media quickly. The process is simple, fast, and works on any device.">
<link rel="canonical" href="https://v1.yt2conv.com/marli">
<meta property="og:title" content="YouTube to MP3 Converter - Yt2Conv">
<meta property="og:description" content="With Yt2Conv, you can convert YouTube videos to MP3 or MP4 and save high-quality media quickly. The process is simple, fast, and works on any device.">
<meta property="og:type" content="Website">
<meta property="og:image" content="https://v1.yt2conv.com/logo.png">

<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://v1.yt2conv.com/logo.png">
<meta name="twitter:title" content="YouTube to MP3 Converter - Yt2Conv">
<meta name="twitter:description" content="With Yt2Conv, you can convert YouTube videos to MP3 or MP4 and save high-quality media quickly. The process is simple, fast, and works on any device.">
<script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","name":"YouTube to MP3 Converter - Yt2Conv","description":"With Yt2Conv, you can convert YouTube videos to MP3 or MP4 and save high-quality media quickly. The process is simple, fast, and works on any device.","url":"https://v1.yt2conv.com/marli"}</script>
    
        
    <link rel="shortcut icon" href="https://v1.yt2conv.com/favicon.ico">
    
    <link rel="preload" as="style" href="https://v1.yt2conv.com/build/assets/app-Hfo51zgX.css" /><link rel="modulepreload" as="script" href="https://v1.yt2conv.com/build/assets/app-CiZEzA8M.js" /><link rel="stylesheet" href="https://v1.yt2conv.com/build/assets/app-Hfo51zgX.css" data-navigate-track="reload" /><script type="module" src="https://v1.yt2conv.com/build/assets/app-CiZEzA8M.js" data-navigate-track="reload"></script>    <!-- Livewire Styles --><style >[wire\:loading][wire\:loading], [wire\:loading\.delay][wire\:loading\.delay], [wire\:loading\.inline-block][wire\:loading\.inline-block], [wire\:loading\.inline][wire\:loading\.inline], [wire\:loading\.block][wire\:loading\.block], [wire\:loading\.flex][wire\:loading\.flex], [wire\:loading\.table][wire\:loading\.table], [wire\:loading\.grid][wire\:loading\.grid], [wire\:loading\.inline-flex][wire\:loading\.inline-flex] {display: none;}[wire\:loading\.delay\.none][wire\:loading\.delay\.none], [wire\:loading\.delay\.shortest][wire\:loading\.delay\.shortest], [wire\:loading\.delay\.shorter][wire\:loading\.delay\.shorter], [wire\:loading\.delay\.short][wire\:loading\.delay\.short], [wire\:loading\.delay\.default][wire\:loading\.delay\.default], [wire\:loading\.delay\.long][wire\:loading\.delay\.long], [wire\:loading\.delay\.longer][wire\:loading\.delay\.longer], [wire\:loading\.delay\.longest][wire\:loading\.delay\.longest] {display: none;}[wire\:offline][wire\:offline] {display: none;}[wire\:dirty]:not(textarea):not(input):not(select) {display: none;}:root {--livewire-progress-bar-color: #2299dd;}[x-cloak] {display: none !important;}[wire\:cloak] {display: none !important;}dialog#livewire-error::backdrop {background-color: rgba(0, 0, 0, .6);}</style>
</head>
<body class="bg-neutral text-yt flex flex-col min-h-screen">
    <header>
        <nav>
            <div wire:snapshot="{&quot;data&quot;:[],&quot;memo&quot;:{&quot;id&quot;:&quot;ks0hhlsbFyruvAHJJbjY&quot;,&quot;name&quot;:&quot;components.navbar&quot;,&quot;path&quot;:&quot;marli&quot;,&quot;method&quot;:&quot;GET&quot;,&quot;release&quot;:&quot;a-a-a&quot;,&quot;children&quot;:[],&quot;scripts&quot;:[],&quot;assets&quot;:[],&quot;errors&quot;:[],&quot;locale&quot;:&quot;en&quot;},&quot;checksum&quot;:&quot;b648ad15b58b942b973cb1a55e8803a59460ab64ce20119519c466dd48961a5d&quot;}" wire:effects="[]" wire:id="ks0hhlsbFyruvAHJJbjY">
    <div class="navbar bg-base-100 shadow bg-custom-gradient p-0 columns-3">
        <div class="navbar-start">
            <a wire:navigate href="https://v1.yt2conv.com/marli" class="btn btn-ghost normal-case text-white px-5 text-xl">Yt2Conv</a>
        </div>
         <div class="navbar-end px-5 flex items-center gap-2">
            <!--[if BLOCK]><![endif]-->                <a wire:navigate href="https://v1.yt2conv.com/account/login" class="btn btn-ghost text-white hover:bg-white/10 dark:hover:bg-white/10 transition-colors">
                    Login
                </a>
            <!--[if ENDBLOCK]><![endif]-->            <button id="theme-toggle" type="button" class="btn btn-ghost text-white" aria-label="toggle-theme">
                <svg id="theme-toggle-light-icon" class="hidden fill-current text-yellow-500 w-7 h-7" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z"/></svg>
                <svg id="theme-toggle-dark-icon" class="hidden fill-current w-7 h-7" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z"/></svg>
            </button>
        </div>
    </div>
</div>
        </nav>
    </header>
    <div class="flex-1 flex flex-col">
        <main>
        <section id="header">
            <div>
                <div wire:snapshot="{&quot;data&quot;:{&quot;searchText&quot;:null,&quot;turnstileToken&quot;:null,&quot;showTurnstile&quot;:false,&quot;turnstileEnabled&quot;:true},&quot;memo&quot;:{&quot;id&quot;:&quot;LSdCNFdziQ7IrOgRUuyy&quot;,&quot;name&quot;:&quot;components.search-form&quot;,&quot;path&quot;:&quot;marli&quot;,&quot;method&quot;:&quot;GET&quot;,&quot;release&quot;:&quot;a-a-a&quot;,&quot;children&quot;:[],&quot;scripts&quot;:[],&quot;assets&quot;:[],&quot;errors&quot;:[],&quot;locale&quot;:&quot;en&quot;},&quot;checksum&quot;:&quot;c827f5abbdc191cb99a411622f99abe18110af3936d5c95af36750c149ee1e58&quot;}" wire:effects="[]" wire:id="LSdCNFdziQ7IrOgRUuyy">
    <div class="hero bg-banner pt-10 pb-10 md:pt-20 md:pb-20">
        <div class="hero-content w-full mx-w-1000">
            <div class="card w-full min-w-full">
                <div class="card-body p-0">
                    <h1 class="text-center font-bold text-white text-2xl md:text-3xl mb-4 md:mb-8">YouTube to MP3 Converter</h1>
                    <form wire:submit="search">
                        <div class="sm:relative flex bg-neutral my-4 p-4 py-3">
                            <input id="search-input" type="text" class="block p-4 h-20 input input-bordered focus:outline-0 bg-neutral rounded-none text-base placeholder:light:text-gray-600 w-full"
                                placeholder="Insert Youtube URL or Search..." wire:model.live="searchText">
                            <button name="search" aria-label="search" type="submit"
                                class="h-20 search-btn bg-banner sm:absolute sm:z-30 btn border-none text-white btn-sm sm:top-2 sm:right-3">
                                <svg xmlns="http://www.w3.org/2000/svg" class="btn-search-svg" viewBox="0 0 512 512"><path d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"></path></svg>
                            </button>
                        </div>
                        
                        
                        <!--[if BLOCK]><![endif]--><!--[if ENDBLOCK]><![endif]-->                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

<!--[if BLOCK]><![endif]-->    <!--[if ENDBLOCK]><![endif]-->            </div>
        </section>
        <section id="content">
            <div class="hero bg-neutral py-12">
    <div class="hero-content p-0">
        <div class="mx-w-1000">
            <h2 class="text-2xl md:text-3xl font-bold text-center mb-4">Yt2Conv: Best Youtube to MP3 Downloader</h2>
            <p class="text-center pb-4">Yt2Conv is the fastest YouTube to MP3 Converter that allows you to convert videos to high quality MP3 or MP4 music files, 100% free. 
            We guarantee that there will be no loss in video quality during the conversion to high resolution. Our web platform preserves the original quality of every converted video. Yt2conv is the best tool to download videos to your computer, mobile phone or tablets. When it comes to user friendliness, we eliminate the need for account creation when converting videos. Our site is not only swift but also secure.</p>
            <div class="grid sm:grid-cols-2 md:grid-cols-3 gap-4 md:gap-10 mt-4 md:mt-20">
                <div>
                    <div class="media-box text-center">
                        <div class="media-left">
                            <img src="https://v1.yt2conv.com/images/mobile.svg" class="max-w-17 mx-auto mb-3" alt="mobile friendly">
                        </div>
                        <div class="media-right">
                            <h3 class="mb-2 text-lg font-bold">Mobile friendly</h3>
                            <p class="text-sm">We all know that we spend a lot of time on our phone every day, that's why we offer you the best experience when converting your favorite youtube videos as MP3.</p>
                        </div>
                    </div>
                </div>
                <div>
                    <div class="media-box text-center">
                        <div class="media-left">
                            <img src="https://v1.yt2conv.com/images/unlimited.svg" class="max-w-17 mx-auto mb-3" alt="unlimited downloads">
                        </div>
                        <div class="media-right">
                            <h3 class="mb-2 text-lg font-bold">Unlimited Downloads</h3>
                            <p class="text-sm">Downloads occur at significantly accelerated speeds when you realize that there are no download limits. All MP3 files are saved at an exceptionally high rate, which is why we don't impose any download restrictions.</p>
                        </div>
                    </div>
                </div>
                <div>
                    <div class="media-box text-center">
                        <div class="media-left">
                            <img src="https://v1.yt2conv.com/images/fetch.svg" class="max-w-17 mx-auto mb-3" alt="video fetch">
                        </div>
                        <div class="media-right">
                            <h3 class="mb-2 text-lg font-bold">Auto Fetch</h3>
                            <p class="text-sm">Our service stands out as the best in the industry because we immediately fetch all the information from YouTube and make it available in .MP3 or MP4 format.</p>
                        </div>
                    </div>
                </div>
                <div>
                    <div class="media-box text-center">
                        <div class="media-left">
                            <img src="https://v1.yt2conv.com/images/mp3quality.svg" class="max-w-17 mx-auto mb-3" alt="Sound Quality">
                        </div>
                        <div class="media-right">
                            <h3 class="mb-2 text-lg font-bold">High Sound Quality</h3>
                            <p class="text-sm">We offer support for a range of audio quality options, catering to your specific requirements and the available storage on your device. You can select from the following settings: 64kbps, 128kbps, 192kbps, 256kbps, and 320kbps.</p>
                        </div>
                    </div>
                </div>
                <div>
                    <div class="media-box text-center">
                        <div class="media-left">
                            <img src="https://v1.yt2conv.com/images/video.svg" class="max-w-17 mx-auto mb-3" alt="video quality">
                        </div>
                        <div class="media-right">
                            <h3 class="mb-2 text-lg font-bold">Various Video Resolutions</h3>
                            <p class="text-sm">Our Video converter accommodates HD and HDR videos featuring a wide range of resolutions, including 360p, 480p, 720p HD, 1080p Full HD, 1440p 2k, 2160p 4k, and even 4320p 8k options for you to choose from.</p>
                        </div>
                    </div>
                </div>
                <div>
                    <div class="media-box text-center">
                        <div class="media-left">
                            <img src="https://v1.yt2conv.com/images/good_compatibility.svg" class="max-w-17 mx-auto mb-3" alt="mobile friendly">
                        </div>
                        <div class="media-right">
                            <h3 class="mb-2 text-lg font-bold">High Compatibility</h3>
                            <p class="text-sm">Our website fully supports all browsers available on the market, including Google Chrome, Firefox, Microsoft Edge, Opera, Safari, and is optimized for perfect performance on any device and operating system, including Windows, Android, MacOS and iOS.</p>
                        </div>
                    </div>
                </div>
                <div>
                    <div class="media-box text-center">
                        <div class="media-left">
                            <img src="https://v1.yt2conv.com/images/playlist.svg" class="max-w-17 mx-auto mb-3" alt="playlist support">
                        </div>
                        <div class="media-right">
                            <h3 class="mb-2 text-lg font-bold">Playlist Support</h3>
                            <p class="text-sm">Download entire YouTube playlists with ease! Our platform allows you to convert and download complete playlists in one go, saving you time and effort. Simply paste your playlist URL and we'll handle all the videos automatically, maintaining the same high quality for each file.</p>
                        </div>
                    </div>
                </div>
                <div>
                    <div class="media-box text-center">
                        <div class="media-left">
                            <img src="https://v1.yt2conv.com/images/trim-audio.svg" class="max-w-17 mx-auto mb-3" alt="trim audio">
                        </div>
                        <div class="media-right">
                            <h3 class="mb-2 text-lg font-bold">Trim Audio</h3>
                            <p class="text-sm">Cut MP3 online and customize your audio files using our built-in trim feature. Select the exact start and end points you want, and create perfect audio clips tailored to your needs. Whether you want just the chorus, a specific verse, or any portion of a song, our trim tool makes the process simple, precise, and fast.</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
        </section>
        <section id="info">
            <div class="hero pt-6 bg-neutral">
    <div class="hero-content p-0">
        <div class="mx-w-1000">
            <h4 class="text-2xl md:text-3xl text-yt font-bold text-center mb-6 md:mb-12">How to Use?</h4>
            <div class="grid md:grid-cols-3 lg:grid-cols-3 gap-0 md:gap-6 mb-6 md:mb-12">
                <div class="mb-4">
                    <div class="flex items-center">
                        <div class="mr-6 min-w-20 w-20 h-20 rounded-full number relative origin-center">
                            <div class="text-5xl font-semibold absolute">1</div>
                        </div>
                        <div>
                            <p class="text-sm text-yt">Insert the YouTube URL into the search box or search using keywords.</p>
                        </div>
                    </div>
                </div>
                <div class="mb-4">
                    <div class="flex items-center">
                        <div class="mr-6 min-w-20 w-20 h-20 rounded-full number relative origin-center two">
                            <div class="text-5xl font-semibold absolute">2</div>
                        </div>
                        <div>
                            <p class="text-sm text-yt">Choose the format MP3 / MP4 and the desired quality, then click the "Convert" button.</p>
                        </div>
                    </div>
                </div>
                <div class="mb-4">
                    <div class="flex items-center">
                        <div class="mr-6 min-w-20 w-20 h-20 rounded-full number relative origin-center three">
                            <div class="text-5xl font-semibold absolute">3</div>
                        </div>
                        <div>
                            <p class="text-sm text-yt">Wait until the conversion is completed and download it.</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
        </section>
    </main>
    </div>
    <footer class="bg-banner text-base-content mt-auto w-full">
    <div class="px-4 py-8 flex flex-col items-center">
        <ul class="flex flex-wrap justify-center gap-x-8 gap-y-2 text-sm md:text-base text-center">
            <li>
                <a wire:navigate href="https://v1.yt2conv.com/terms" class="link link-hover text-white">
                    Terms of use
                </a>
            </li>
            <li>
                <a wire:navigate href="https://v1.yt2conv.com/privacy" class="link link-hover text-white">
                    Privacy Policy
                </a>
            </li>
            <li>
                <a wire:navigate href="https://v1.yt2conv.com/contact" class="link link-hover text-white">
                    Contact Us
                </a>
            </li>
        </ul>

        <p class="mt-4 text-sm md:text-base text-center text-white">
            Copyright 2025 &copy; Yt2Conv
        </p>
    </div>
</footer>
    
    
    <div wire:snapshot="{&quot;data&quot;:{&quot;showPlayer&quot;:false,&quot;videoId&quot;:null,&quot;title&quot;:null},&quot;memo&quot;:{&quot;id&quot;:&quot;EYFbazJhtv2nBlOxCyR3&quot;,&quot;name&quot;:&quot;components.audio-player&quot;,&quot;path&quot;:&quot;marli&quot;,&quot;method&quot;:&quot;GET&quot;,&quot;release&quot;:&quot;a-a-a&quot;,&quot;children&quot;:[],&quot;scripts&quot;:[],&quot;assets&quot;:[],&quot;errors&quot;:[],&quot;locale&quot;:&quot;en&quot;},&quot;checksum&quot;:&quot;a2ee0bc003cc975c3ea7bda026ddbef42f323ab1e37297558f66b98025f051c7&quot;}" wire:effects="{&quot;listeners&quot;:[&quot;startPlayer&quot;]}" wire:id="EYFbazJhtv2nBlOxCyR3">
    <!--[if BLOCK]><![endif]--><!--[if ENDBLOCK]><![endif]-->
    <style>
        .waveform-bar {
            transition: height 0.3s ease;
            animation: waveform 1.5s ease-in-out infinite;
            animation-delay: calc(var(--i) * 0.05s);
        }
        
        @keyframes waveform {
            0%, 100% { transform: scaleY(0.5); }
            50% { transform: scaleY(1); }
        }
        
        .waveform-bar:nth-child(odd) {
            animation-duration: 1.2s;
        }
        
        .waveform-bar:nth-child(even) {
            animation-duration: 1.8s;
        }

        #audioPlayerContainer.minimized {
            padding-top: 0.75rem;
            padding-bottom: 0.75rem;
        }

        .player-title {
            max-width: 100%;
            overflow: hidden;
            text-overflow: ellipsis;
            word-wrap: break-word;
            word-break: break-word;
            hyphens: auto;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            line-height: 1.4;
        }

        @media (max-width: 640px) {
            .player-title {
                padding-left: 0.75rem;
                padding-right: 0.75rem;
                max-width: calc(100% - 1.5rem);
                font-size: 0.875rem;
            }
        }
        
        /* Waveform colors */
        [data-theme="light"] .waveform-bar-color {
            background-color: rgba(60, 148, 175, 0.3) !important;
        }
        [data-theme="dark"] .waveform-bar-color {
            background-color: rgba(255, 255, 255, 0.3) !important;
        }
        
        /* Progress bar colors - red as requested */
        .audio-player-progress {
            --range-shdw: 239 68 68; /* red-500 */
        }
        
        /* Webkit browsers (Chrome, Safari, Edge) */
        .audio-player-progress::-webkit-slider-thumb {
            background-color: #ef4444 !important;
            border-color: #ef4444 !important;
        }
        .audio-player-progress::-webkit-slider-runnable-track {
            background-color: #e5e7eb !important;
        }
        [data-theme="dark"] .audio-player-progress::-webkit-slider-runnable-track {
            background-color: #4b5563 !important;
        }
        
        /* Firefox */
        .audio-player-progress::-moz-range-thumb {
            background-color: #ef4444 !important;
            border-color: #ef4444 !important;
        }
        .audio-player-progress::-moz-range-track {
            background-color: #e5e7eb !important;
        }
        [data-theme="dark"] .audio-player-progress::-moz-range-track {
            background-color: #4b5563 !important;
        }
    </style>
</div>    
    <script>
        "dark"!==localStorage.getItem("theme")&&("theme"in localStorage||!window.matchMedia("(prefers-color-scheme: dark)").matches)?document.querySelector("#theme-toggle-dark-icon").classList.remove("hidden"):(document.documentElement.setAttribute("data-theme","dark"),document.querySelector("#theme-toggle-light-icon").classList.remove("hidden")),document.querySelector("#theme-toggle").addEventListener("click",()=>{document.querySelector("#theme-toggle-light-icon").classList.toggle("hidden"),document.querySelector("#theme-toggle-dark-icon").classList.toggle("hidden"),localStorage.getItem("theme")?"light"===localStorage.getItem("theme")?(document.documentElement.setAttribute("data-theme","dark"),localStorage.setItem("theme","dark")):(document.documentElement.setAttribute("data-theme","light"),localStorage.setItem("theme","light")):"dark"===document.documentElement.getAttribute("data-theme")?(document.documentElement.setAttribute("data-theme","light"),localStorage.setItem("theme","light")):(document.documentElement.setAttribute("data-theme","dark"),localStorage.setItem("theme","dark"))});
    </script>
    <script> window.addEventListener('livewire:navigated', () => {window.scrollTo({top: 0 });});</script>
    
    
    <script>
        // Initialize global conversion and download tracking
        window.activeConversionId = null;
        window.activeDownloadId = null;
    </script>
    
    <script>
        window.adBlockDetected = window.adBlockDetected || false;
    </script>
    
    <script src="/livewire/livewire.min.js?id=57eb113f"   data-csrf="7SvTtzRMjHQ4u8lhybGhOXna6th4kB4kRjyJ0Dex" data-update-uri="/livewire/update" data-navigate-once="true"></script>
    
    
    <script>
        (function() {
            // Function to register trim audio data
            function registerTrimAudioData() {
                // Use window.Alpine to ensure we use the same instance as Livewire
                const Alpine = window.Alpine || window.AlpineJS;
                if (!Alpine || !Alpine.data) {
                    return;
                }
                
                // Only register once
                if (Alpine.data('trimAudioData')) {
                    return;
                }
                
                Alpine.data('trimAudioData', (downloadUrl = '', downloadTitle = 'download') => ({
                showTrim: false,
                trimLoading: false,
                trimInProgress: false,
                trimError: null,
                trimHint: null,
                durationSeconds: null,
                startInput: '00:00',
                endInput: '00:00',
                startSeconds: 0,
                endSeconds: 0,
                ffmpegProgress: null,
                ffmpegInstance: null,
                ffmpegFetchFile: null,
                activeThumb: null,
                downloadedBlob: null,
                downloadUrl: downloadUrl,
                downloadTitle: downloadTitle,
                onDragBound: null,
                endDragBound: null,
                updatingFromDrag: false,

                get durationDisplay() {
                    if (!this.durationSeconds || this.durationSeconds <= 0) return '';
                    return this.formatTime(this.durationSeconds);
                },

                get rangeStyle() {
                    if (!this.durationSeconds || this.durationSeconds <= 0) return { left: '0%', width: '0%' };
                    const startPct = (this.startSeconds / this.durationSeconds) * 100;
                    const endPct = (this.endSeconds / this.durationSeconds) * 100;
                    return {
                        left: `${Math.max(0, Math.min(100, startPct))}%`,
                        width: `${Math.max(0, Math.min(100, endPct - startPct))}%`
                    };
                },

                get startThumbStyle() {
                    if (!this.durationSeconds || this.durationSeconds <= 0) {
                        return { left: '0%', transform: 'translateX(-50%) translateY(-50%)' };
                    }
                    const startPct = (this.startSeconds / this.durationSeconds) * 100;
                    return { 
                        left: `${Math.max(0, Math.min(100, startPct))}%`,
                        transform: 'translateX(-50%) translateY(-50%)'
                    };
                },

                get endThumbStyle() {
                    if (!this.durationSeconds || this.durationSeconds <= 0) {
                        return { left: '100%', transform: 'translateX(-50%) translateY(-50%)' };
                    }
                    const endPct = (this.endSeconds / this.durationSeconds) * 100;
                    return { 
                        left: `${Math.max(0, Math.min(100, endPct))}%`,
                        transform: 'translateX(-50%) translateY(-50%)'
                    };
                },

                get trimDisabled() {
                    if (this.trimLoading || this.trimInProgress) return true;
                    const start = this.startSeconds;
                    const end = this.endSeconds;
                    if (!Number.isFinite(start) || !Number.isFinite(end)) return true;
                    if (this.durationSeconds != null) {
                        if (start < 0 || end <= start || end > this.durationSeconds) return true;
                    }
                    return false;
                },

                get tickMarks() {
                    if (!this.durationSeconds || this.durationSeconds <= 0) return [];
                    const dur = this.durationSeconds;
                    const isClient = typeof window !== 'undefined';
                    const maxTicks = isClient && window.innerWidth < 640 ? 5 : 9;
                    let step = 30;
                    while (dur / step > maxTicks && step < 3600) {
                        step *= 2;
                    }
                    const ticks = [];
                    const roundedDur = Math.round(dur);
                    
                    for (let t = 0; t < roundedDur; t += step) {
                        ticks.push(Math.round(t));
                    }
                    
                    const lastTick = ticks[ticks.length - 1] || 0;
                    const minDiff = dur * 0.02;
                    if (roundedDur - lastTick >= minDiff) {
                        ticks.push(roundedDur);
                    } else if (ticks.length > 0) {
                        ticks[ticks.length - 1] = roundedDur;
                    } else {
                        ticks.push(roundedDur);
                    }
                    
                    const uniqueTicks = [...new Set(ticks)].sort((a, b) => a - b);
                    
                    return uniqueTicks.map(seconds => ({
                        seconds,
                        label: this.formatTime(seconds),
                        pct: (seconds / dur) * 100
                    }));
                },

                formatTime(seconds) {
                    if (!Number.isFinite(seconds) || seconds < 0) return '00:00';
                    const s = Math.max(0, Math.floor(seconds));
                    const m = Math.floor(s / 60).toString().padStart(2, '0');
                    const r = (s % 60).toString().padStart(2, '0');
                    return `${m}:${r}`;
                },

                parseTime(value) {
                    if (!value || typeof value !== 'string') return NaN;
                    const trimmed = value.trim();
                    if (!trimmed) return NaN;
                    const parts = trimmed.split(':').map(p => {
                        const num = parseInt(p.trim(), 10);
                        return isNaN(num) ? NaN : num;
                    });
                    if (parts.some(n => isNaN(n))) return NaN;
                    if (parts.length === 1) return parts[0];
                    if (parts.length === 2) return parts[0] * 60 + parts[1];
                    if (parts.length === 3) return parts[0] * 3600 + parts[1] * 60 + parts[2];
                    return NaN;
                },

                handleStartInputChange(value) {
                    if (this.updatingFromDrag) return;
                    const s = this.parseTime(value);
                    if (Number.isFinite(s) && s >= 0) {
                        this.startSeconds = Math.max(0, s);
                    }
                },

                handleEndInputChange(value) {
                    if (this.updatingFromDrag) return;
                    const e = this.parseTime(value);
                    if (this.durationSeconds && Number.isFinite(e) && e >= 0) {
                        this.endSeconds = Math.min(this.durationSeconds, e);
                    }
                },

                async fetchSourceBlob() {
                    if (this.downloadedBlob) return this.downloadedBlob;
                    if (!this.downloadUrl) throw new Error('No download URL');
                    const res = await fetch(this.downloadUrl, {
                        method: 'GET',
                        mode: 'cors',
                        credentials: 'omit'
                    });
                    if (!res.ok) throw new Error('Unable to fetch file');
                    this.downloadedBlob = await res.blob();
                    return this.downloadedBlob;
                },

                saveBlob(blob, filename) {
                    const href = URL.createObjectURL(blob);
                    const a = document.createElement('a');
                    a.href = href;
                    a.setAttribute('download', filename || 'download');
                    a.style.display = 'none';
                    document.body.appendChild(a);
                    a.click();
                    a.remove();
                    URL.revokeObjectURL(href);
                },

                async ensureDuration() {
                    if (this.durationSeconds) return;
                    this.trimLoading = true;
                    this.trimError = null;
                    try {
                        const blob = await this.fetchSourceBlob();
                        const url = URL.createObjectURL(blob);
                        await new Promise((resolve, reject) => {
                            const audio = new Audio();
                            audio.preload = 'metadata';
                            audio.onloadedmetadata = () => {
                                this.durationSeconds = Number.isFinite(audio.duration) ? audio.duration : null;
                                if (this.durationSeconds) {
                                    this.startSeconds = 0;
                                    this.endSeconds = this.durationSeconds;
                                    this.startInput = '00:00';
                                    this.endInput = this.formatTime(this.durationSeconds);
                                }
                                URL.revokeObjectURL(url);
                                resolve();
                            };
                            audio.onerror = () => {
                                URL.revokeObjectURL(url);
                                reject(new Error('Unable to read duration'));
                            };
                            audio.src = url;
                        });
                    } catch (e) {
                        this.trimError = e?.message || 'Unable to load duration';
                    } finally {
                        this.trimLoading = false;
                    }
                },

                async loadFfmpegScript() {
                    if (window.FFmpegWASM) return Promise.resolve();
                    return new Promise((resolve, reject) => {
                        const script = document.createElement('script');
                        script.src = '/ffmpeg/ffmpeg.js';
                        script.async = true;
                        script.onload = () => resolve();
                        script.onerror = () => reject(new Error('Failed to load ffmpeg script'));
                        document.head.appendChild(script);
                    });
                },

                async inlineFetchFile(file) {
                    if (typeof file === 'string') {
                        return new Uint8Array(await (await fetch(file)).arrayBuffer());
                    }
                    if (file instanceof File || file instanceof Blob) {
                        return new Uint8Array(await file.arrayBuffer());
                    }
                    return new Uint8Array();
                },

                async getFfmpeg() {
                    if (this.ffmpegInstance && this.ffmpegFetchFile) {
                        return { ffmpeg: this.ffmpegInstance, fetchFile: this.ffmpegFetchFile };
                    }
                    this.trimLoading = true;
                    this.ffmpegProgress = null;
                    await this.loadFfmpegScript();
                    const FFmpegWASM = window.FFmpegWASM;
                    if (!FFmpegWASM?.FFmpeg) {
                        this.trimLoading = false;
                        throw new Error('ffmpeg wasm failed to load');
                    }
                    const coreURL = '/ffmpeg/full-st/ffmpeg-core.js';
                    const wasmURL = '/ffmpeg/full-st/ffmpeg-core.wasm';
                    const ffmpeg = new FFmpegWASM.FFmpeg();
                    ffmpeg.on('log', () => {});
                    await ffmpeg.load({ coreURL, wasmURL });
                    ffmpeg.on('progress', ({ progress }) => {
                        const p = Number.isFinite(progress) ? Math.round(progress * 100) : 0;
                        this.ffmpegProgress = Math.max(0, Math.min(100, p));
                    });
                    this.ffmpegInstance = ffmpeg;
                    this.ffmpegFetchFile = this.inlineFetchFile;
                    this.trimLoading = false;
                    return { ffmpeg, fetchFile: this.inlineFetchFile };
                },

                onDrag(event) {
                    if (!this.activeThumb || !this.$refs.sliderTrack || !this.durationSeconds) return;
                    
                    // Only prevent default on touchmove if the event is cancelable
                    // This prevents the browser warning when scrolling is in progress
                    if ('touches' in event && event.type === 'touchmove' && event.cancelable) {
                        event.preventDefault();
                    }
                    
                    const rect = this.$refs.sliderTrack.getBoundingClientRect();
                    const clientX = 'touches' in event ? event.touches[0].clientX : event.clientX;
                    
                    let ratio = (clientX - rect.left) / rect.width;
                    ratio = Math.max(0, Math.min(1, ratio));
                    const sec = ratio * this.durationSeconds;

                    if (this.activeThumb === 'start') {
                        const newStart = Math.min(sec, this.endSeconds - 1);
                        this.startSeconds = Math.max(0, newStart);
                        this.updatingFromDrag = true;
                        this.startInput = this.formatTime(this.startSeconds);
                        this.$nextTick(() => {
                            this.updatingFromDrag = false;
                        });
                    } else {
                        const newEnd = Math.max(sec, this.startSeconds + 1);
                        this.endSeconds = Math.min(this.durationSeconds, newEnd);
                        this.updatingFromDrag = true;
                        this.endInput = this.formatTime(this.endSeconds);
                        this.$nextTick(() => {
                            this.updatingFromDrag = false;
                        });
                    }
                },

                endDrag() {
                    this.activeThumb = null;
                    if (this.onDragBound) {
                        window.removeEventListener('mousemove', this.onDragBound);
                        window.removeEventListener('touchmove', this.onDragBound);
                    }
                    if (this.endDragBound) {
                        window.removeEventListener('mouseup', this.endDragBound);
                        window.removeEventListener('touchend', this.endDragBound);
                    }
                },

                beginDragThumb(thumb, event) {
                    // Only prevent default if the event is cancelable
                    if (event.type !== 'touchstart' && event.cancelable) {
                        event.preventDefault();
                        event.stopPropagation();
                    }
                    
                    this.activeThumb = thumb;
                    
                    this.onDragBound = (e) => {
                        this.onDrag(e);
                    };
                    this.endDragBound = () => {
                        this.endDrag();
                    };
                    
                    window.addEventListener('mousemove', this.onDragBound);
                    window.addEventListener('touchmove', this.onDragBound, { passive: false });
                    window.addEventListener('mouseup', this.endDragBound);
                    window.addEventListener('touchend', this.endDragBound);
                    
                    this.onDrag(event);
                },

                beginDrag(event) {
                    if (!this.activeThumb && this.durationSeconds && this.$refs.sliderTrack) {
                        // Only prevent default if the event is cancelable
                        if (event.cancelable) {
                            event.preventDefault();
                            event.stopPropagation();
                        }
                        const rect = this.$refs.sliderTrack.getBoundingClientRect();
                        const clientX = 'touches' in event ? event.touches[0].clientX : event.clientX;
                        const ratio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
                        const sec = ratio * this.durationSeconds;
                        const distToStart = Math.abs(sec - this.startSeconds);
                        const distToEnd = Math.abs(sec - this.endSeconds);
                        const thumb = distToStart < distToEnd ? 'start' : 'end';
                        this.beginDragThumb(thumb, event);
                    }
                },

                async handleTrimDownload() {
                    this.trimError = null;
                    this.trimHint = null;
                    this.ffmpegProgress = null;
                    const start = this.startSeconds;
                    const end = this.endSeconds;
                    if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) {
                        this.trimError = 'Start/End must be valid times and end after start.';
                        return;
                    }
                    if (this.durationSeconds && end > this.durationSeconds + 0.5) {
                        this.trimError = 'End exceeds track duration.';
                        return;
                    }
                    let activeFfmpeg = null;
                    try {
                        this.trimInProgress = true;
                        const blob = await this.fetchSourceBlob();
                        const { ffmpeg, fetchFile } = await this.getFfmpeg();
                        if (!ffmpeg || !fetchFile) throw new Error('ffmpeg wasm failed to load');
                        activeFfmpeg = ffmpeg;
                        if (this.durationSeconds && this.durationSeconds > 1200) {
                            this.trimHint = 'Long tracks may process slowly on this device.';
                        }
                        const inputData = await fetchFile(blob);
                        await ffmpeg.writeFile('input.mp3', inputData);
                        this.ffmpegProgress = 5;
                        const duration = end - start;
                        await ffmpeg.exec(['-ss', `${start}`, '-t', `${duration}`, '-i', 'input.mp3', '-c', 'copy', 'output.mp3']);
                        const data = await ffmpeg.readFile('output.mp3');
                        if (!(data instanceof Uint8Array)) throw new Error('Unexpected FFmpeg output');
                        const outBlob = new Blob([data.buffer], { type: 'audio/mpeg' });
                        const baseTitle = this.downloadTitle || 'download';
                        const baseName = baseTitle.endsWith('.mp3')
                            ? baseTitle.replace(/\.mp3$/i, '')
                            : baseTitle;
                        const finalName = `${baseName}-trim.mp3`;
                        this.saveBlob(outBlob, finalName);
                        await Promise.allSettled([activeFfmpeg?.deleteFile('input.mp3'), activeFfmpeg?.deleteFile('output.mp3')]);
                    } catch (e) {
                        this.trimError = e?.message || 'Trim failed.';
                    } finally {
                        this.trimInProgress = false;
                    }
                },

                init() {
                    if (this.downloadUrl) {
                        this.showTrim = true;
                        this.ensureDuration();
                    }
                }
            }));
            }
            
            // Wait for Livewire to initialize Alpine
            function tryRegister() {
                if (typeof window.Alpine !== 'undefined' && window.Alpine.data) {
                    registerTrimAudioData();
                } else if (typeof window.Livewire !== 'undefined') {
                    // Livewire is loaded, wait a bit for Alpine
                    setTimeout(tryRegister, 50);
                } else {
                    // Wait for Livewire to load
                    setTimeout(tryRegister, 100);
                }
            }
            
            // Try to register immediately
            tryRegister();
            
            // Also register on alpine:init event (for when Alpine loads later)
            document.addEventListener('alpine:init', registerTrimAudioData);
            
            // Also try on Livewire init
            document.addEventListener('livewire:init', () => {
                setTimeout(registerTrimAudioData, 100);
            });
        })();
    </script>
    
    
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // Handle trim-request events globally
            window.addEventListener('trim-request', function(e) {
                if (!e.detail || !e.detail.tokenHash || !e.detail.statusId) return;
                
                const hash = e.detail.tokenHash;
                const statusId = e.detail.statusId;
                
                // Find trim component - try multiple methods
                const findAndUpdateComponent = () => {
                    let container = null;
                    
                    // Method 1: Try static attribute
                    container = document.querySelector('[data-token-hash="' + hash + '"]');
                    
                    // Method 2: Try dynamic attribute (Alpine.js bound)
                    if (!container) {
                        const dynamicContainers = document.querySelectorAll('[data-token-hash-dynamic]');
                        for (const dc of dynamicContainers) {
                            // Check parent Alpine.js context
                            let parent = dc.closest('[x-data]');
                            while (parent) {
                                if (parent.__x && parent.__x.$data) {
                                    const currentHash = parent.__x.$data.currentTokenHash || 
                                       (parent.__x.$data.openTrimTokenHash === hash ? hash : null);
                                    if (currentHash === hash) {
                                        container = dc;
                                        break;
                                    }
                                }
                                parent = parent.parentElement?.closest('[x-data]');
                            }
                            if (container) break;
                        }
                    }
                    
                    // Method 3: Find any visible trim component (fallback)
                    if (!container) {
                        const allTrimContainers = document.querySelectorAll('[data-token-hash-dynamic]');
                        for (const tc of allTrimContainers) {
                            const style = window.getComputedStyle(tc.closest('[x-show]') || tc);
                            if (style.display !== 'none') {
                                container = tc;
                                break;
                            }
                        }
                    }
                    
                    if (!container) return;
                    
                    // Wait a bit for Livewire to mount
                    setTimeout(() => {
                        const wireEl = container.querySelector('[wire\\:id]');
                        if (!wireEl || !window.Livewire) return;
                        
                        const wireId = wireEl.getAttribute('wire:id');
                        if (!wireId) return;
                        
                        const component = window.Livewire.find(wireId);
                        if (!component) return;
                        
                        const currentTaskId = component.get('taskId');
                        if (currentTaskId === '0' || !currentTaskId) {
                            if (component.call && typeof component.call === 'function') {
                                component.call('setTaskId', statusId);
                            } else if (component.set && typeof component.set === 'function') {
                                component.set('taskId', statusId);
                            }
                        }
                    }, 150);
                };
                
                // Try multiple times to account for Alpine.js reactivity
                findAndUpdateComponent();
                setTimeout(findAndUpdateComponent, 200);
                setTimeout(findAndUpdateComponent, 500);
            });
        });
    </script>
    
    
    <script>
        // Initialize variables on window object to prevent redeclaration errors on Livewire navigation
        if (typeof window.youtubePlayer === 'undefined') {
            window.youtubePlayer = null;
            window.isPlaying = false;
            window.updateInterval = null;
            window.pendingVideoId = null;
        }

        // Load YouTube IFrame API
        var tag = document.createElement('script');
        tag.src = "https://www.youtube.com/iframe_api";
        var firstScriptTag = document.getElementsByTagName('script')[0];
        firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

        function onYouTubeIframeAPIReady() {
            // API is ready, create player if there's a pending video
            if (window.pendingVideoId) {
                initYouTubePlayer(window.pendingVideoId);
                window.pendingVideoId = null;
            }
        }

        // Initialize YouTube player when Livewire event fires
        document.addEventListener('livewire:init', () => {
            Livewire.on('loadPlayer', (data) => {
                const videoId = data?.vid || data[0]?.vid || data;
                
                if (!videoId) return;
                
                // Wait for YouTube API to be ready
                if (typeof YT === 'undefined' || typeof YT.Player === 'undefined') {
                    setTimeout(() => {
                        initYouTubePlayer(videoId);
                    }, 500);
                } else {
                    initYouTubePlayer(videoId);
                }
            });
        });

        function initYouTubePlayer(videoId) {
            // Check if YouTube API is ready
            if (typeof YT === 'undefined' || typeof YT.Player === 'undefined') {
                window.pendingVideoId = videoId;
                return;
            }

            // Destroy existing player if it exists
            if (window.youtubePlayer) {
                try {
                    window.youtubePlayer.destroy();
                } catch (e) {
                    // Player cleanup error - silently handle
                }
                window.youtubePlayer = null;
            }

            // Wait for the player container to exist
            setTimeout(() => {
                const container = document.getElementById('youtubePlayer');
                if (!container) {
                    return;
                }

                // Create new YouTube player (audio-only, hidden)
                window.youtubePlayer = new YT.Player('youtubePlayer', {
                    height: '0',
                    width: '0',
                    videoId: videoId,
                    playerVars: {
                        'autoplay': 1,
                        'controls': 0,
                        'disablekb': 1,
                        'fs': 0,
                        'iv_load_policy': 3,
                        'modestbranding': 1,
                        'playsinline': 1,
                        'rel': 0,
                        'showinfo': 0,
                        'origin': window.location.origin
                    },
                    events: {
                        'onReady': onPlayerReady,
                        'onStateChange': onPlayerStateChange,
                        'onError': onPlayerError
                    }
                });
            }, 200);
        }

        function onPlayerReady(event) {
            if (event.target && typeof event.target.getDuration === 'function') {
                try {
                    const duration = event.target.getDuration();
                    if (duration && !isNaN(duration)) {
                        updateDuration(duration);
                        updatePlayPauseButton(true);
                        startProgressUpdate();
                    }
                } catch (e) {
                    // Player ready error - silently handle
                }
            }
        }

        function onPlayerStateChange(event) {
            if (event.data === YT.PlayerState.PLAYING) {
                window.isPlaying = true;
                updatePlayPauseButton(true);
                startProgressUpdate();
            } else if (event.data === YT.PlayerState.PAUSED) {
                window.isPlaying = false;
                updatePlayPauseButton(false);
                stopProgressUpdate();
            } else if (event.data === YT.PlayerState.ENDED) {
                window.isPlaying = false;
                updatePlayPauseButton(false);
                stopProgressUpdate();
            }
        }

        function onPlayerError(event) {
            // Handle errors gracefully
        }

        function updatePlayPauseButton(playing) {
            const playIcon = document.getElementById('playIcon');
            const pauseIcon = document.getElementById('pauseIcon');
            const playIconMin = document.getElementById('playIconMin');
            const pauseIconMin = document.getElementById('pauseIconMin');
            
            if (playIcon && pauseIcon) {
                if (playing) {
                    playIcon.classList.add('hidden');
                    pauseIcon.classList.remove('hidden');
                } else {
                    playIcon.classList.remove('hidden');
                    pauseIcon.classList.add('hidden');
                }
            }
            
            if (playIconMin && pauseIconMin) {
                if (playing) {
                    playIconMin.classList.add('hidden');
                    pauseIconMin.classList.remove('hidden');
                } else {
                    playIconMin.classList.remove('hidden');
                    pauseIconMin.classList.add('hidden');
                }
            }
        }

        function updateDuration(seconds) {
            const durationEl = document.getElementById('duration');
            if (durationEl) {
                durationEl.textContent = formatTime(seconds);
            }
        }

        function formatTime(seconds) {
            const mins = Math.floor(seconds / 60);
            const secs = Math.floor(seconds % 60);
            return `${mins}:${secs.toString().padStart(2, '0')}`;
        }

        function startProgressUpdate() {
            if (window.updateInterval) clearInterval(window.updateInterval);
            window.updateInterval = setInterval(() => {
                if (window.youtubePlayer && window.isPlaying && typeof window.youtubePlayer.getCurrentTime === 'function' && typeof window.youtubePlayer.getDuration === 'function') {
                    try {
                        const current = window.youtubePlayer.getCurrentTime();
                        const duration = window.youtubePlayer.getDuration();
                        if (current !== undefined && duration !== undefined && !isNaN(current) && !isNaN(duration)) {
                            updateProgress(current, duration);
                        }
                    } catch (e) {
                        stopProgressUpdate();
                    }
                }
            }, 100);
        }

        function stopProgressUpdate() {
            if (window.updateInterval) {
                clearInterval(window.updateInterval);
                window.updateInterval = null;
            }
        }

        // Flag to prevent progress update while user is seeking
        window.isSeeking = false;

        function updateProgress(current, duration) {
            if (window.isSeeking) return; // Don't update while user is dragging
            
            const progressBar = document.getElementById('progressBar');
            const currentTimeEl = document.getElementById('currentTime');
            
            if (progressBar) {
                const percent = (current / duration) * 100;
                progressBar.value = percent;
            }
            
            if (currentTimeEl) {
                currentTimeEl.textContent = formatTime(current);
            }
        }

        // Progress bar seek handler
        document.addEventListener('mousedown', (e) => {
            if (e.target.id === 'progressBar') {
                window.isSeeking = true;
            }
        });
        
        document.addEventListener('mouseup', (e) => {
            if (e.target.id === 'progressBar') {
                window.isSeeking = false;
            }
        });
        
        document.addEventListener('touchstart', (e) => {
            if (e.target.id === 'progressBar') {
                window.isSeeking = true;
            }
        });
        
        document.addEventListener('touchend', (e) => {
            if (e.target.id === 'progressBar') {
                window.isSeeking = false;
            }
        });
        
        document.addEventListener('input', (e) => {
            if (e.target.id === 'progressBar' && window.youtubePlayer && typeof window.youtubePlayer.getDuration === 'function' && typeof window.youtubePlayer.seekTo === 'function') {
                try {
                    const duration = window.youtubePlayer.getDuration();
                    if (duration && !isNaN(duration)) {
                        const seekTo = (e.target.value / 100) * duration;
                        window.youtubePlayer.seekTo(seekTo, true);
                        // Update current time display
                        const currentTimeEl = document.getElementById('currentTime');
                        if (currentTimeEl) {
                            currentTimeEl.textContent = formatTime(seekTo);
                        }
                    }
                } catch (err) {
                    // Seek error - silently handle
                }
            }
        });
        
        document.addEventListener('change', (e) => {
            if (e.target.id === 'progressBar') {
                window.isSeeking = false;
            }
        });

        // Play/Pause button handler
        document.addEventListener('click', (e) => {
            if (e.target.closest('#playPauseBtn') || e.target.closest('#playPauseBtnMin')) {
                if (window.youtubePlayer && typeof window.youtubePlayer.pauseVideo === 'function' && typeof window.youtubePlayer.playVideo === 'function') {
                    try {
                        if (window.isPlaying) {
                            window.youtubePlayer.pauseVideo();
                        } else {
                            window.youtubePlayer.playVideo();
                        }
                    } catch (err) {
                        // Play/Pause error - silently handle
                    }
                }
            }
            
            // Minimize/Maximize handlers
            if (e.target.closest('#minimizeBtn')) {
                minimizePlayer();
            }
            if (e.target.closest('#maximizeBtn')) {
                maximizePlayer();
            }
        });

        function minimizePlayer() {
            const container = document.getElementById('audioPlayerContainer');
            const fullView = document.getElementById('fullView');
            const minimizedView = document.getElementById('minimizedView');
            
            if (container && fullView && minimizedView) {
                container.classList.add('minimized');
                fullView.classList.add('hidden');
                minimizedView.classList.remove('hidden');
            }
        }

        function maximizePlayer() {
            const container = document.getElementById('audioPlayerContainer');
            const fullView = document.getElementById('fullView');
            const minimizedView = document.getElementById('minimizedView');
            
            if (container && fullView && minimizedView) {
                container.classList.remove('minimized');
                fullView.classList.remove('hidden');
                minimizedView.classList.add('hidden');
            }
        }
    </script>
    
    
    <script>
        // Listen for download-file event from Livewire
        document.addEventListener('livewire:init', () => {
            Livewire.on('download-file', (event) => {
                const url = Array.isArray(event) ? event[0]?.url || event[0] : event.url;
                const filename = Array.isArray(event) ? event[0]?.filename || null : event.filename;
                downloadFile(url, filename);
            });
        });
        
        function downloadFile(url, defaultFilename) {
            fetch(url, {
                credentials: 'same-origin',
                headers: {
                    'X-Requested-With': 'XMLHttpRequest',
                    'Accept': 'application/json, application/zip, */*'
                },
                cache: 'no-cache'
            })
                .then(res => {
                    // Check if response is JSON (redirect_url for excluded tracks)
                    const contentType = res.headers.get('Content-Type') || '';
                    if (contentType.includes('application/json')) {
                        return res.json().then(json => {
                            if (json.success && json.redirect_url) {
                                // For excluded tracks, redirect to external URL directly
                                window.location.href = json.redirect_url;
                                return null; // Don't continue with blob download
                            }
                            if (json.error) {
                                throw new Error(json.message || json.error || 'Download failed');
                            }
                            throw new Error('Unexpected JSON response');
                        });
                    }
                    
                    if (!res.ok) {
                        // Try to parse error message from response
                        return res.text().then(text => {
                            try {
                                const json = JSON.parse(text);
                                throw new Error(json.message || json.error || `HTTP ${res.status}: ${res.statusText}`);
                            } catch (e) {
                                throw new Error(`HTTP ${res.status}: ${res.statusText}`);
                            }
                        });
                    }
                    
                    // Try to read a real filename from Content-Disposition
                    let cd = res.headers.get('Content-Disposition') || '';
                    let fnStar = /filename\*\s*=\s*UTF-8''([^;]+)/i.exec(cd);
                    let fnBasic = /filename\s*=\s*"([^"]+)"/i.exec(cd);
                    let filename = fnStar?.[1]
                                 ? decodeURIComponent(fnStar[1])
                                 : fnBasic?.[1]
                                   ? fnBasic[1]
                                   : defaultFilename || decodeURIComponent(url.split('/').pop().split('?')[0]);
                    return res.blob().then(blob => ({ blob, filename }));
                })
                .then(result => {
                    // If result is null, it means we redirected (excluded track)
                    if (result === null) {
                        return;
                    }
                    
                    const { blob, filename } = result;
                    const link = document.createElement('a');
                    link.href = URL.createObjectURL(blob);
                    link.download = filename;
                    document.body.appendChild(link);
                    link.click();
                    document.body.removeChild(link);
                    URL.revokeObjectURL(link.href);
                })
                .catch(err => {
                    console.error('Download failed', err);
                    alert('Download failed: ' + err.message);
                });
        }
        
        /**
         * Download file with progress tracking
         */
        function startDownloadWithProgress(url, defaultFilename, fileSizeBytes) {
            const button = document.getElementById('download-zip-button');
            const buttonText = document.getElementById('download-button-text');
            const progressContainer = document.getElementById('download-progress-container');
            const progressBar = document.getElementById('download-progress-bar');
            const progressText = document.getElementById('download-progress-text');
            const statusText = document.getElementById('download-status-text');
            const bytesText = document.getElementById('download-bytes-text');
            const speedText = document.getElementById('download-speed-text');
            
            // Disable button and show progress
            if (button) {
                button.disabled = true;
            }
            if (progressContainer) {
                progressContainer.classList.remove('hidden');
            }
            if (statusText) {
                statusText.textContent = 'Starting download...';
            }
            
            let downloadedBytes = 0;
            let startTime = Date.now();
            let lastUpdateTime = startTime;
            let lastBytes = 0;
            
            // Format bytes to human-readable
            function formatBytes(bytes) {
                if (bytes === 0) return '0 B';
                const k = 1024;
                const sizes = ['B', 'KB', 'MB', 'GB'];
                const i = Math.floor(Math.log(bytes) / Math.log(k));
                return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
            }
            
            // Update progress display
            function updateProgress(bytesLoaded, totalBytes) {
                downloadedBytes = bytesLoaded;
                const percent = totalBytes ? Math.round((bytesLoaded / totalBytes) * 100) : 0;
                
                if (progressBar) {
                    progressBar.style.width = percent + '%';
                }
                if (progressText) {
                    progressText.textContent = percent + '%';
                }
                
                const now = Date.now();
                const timeDiff = (now - lastUpdateTime) / 1000; // seconds
                
                if (timeDiff >= 0.5 && bytesLoaded > lastBytes) { // Update speed every 0.5 seconds
                    const bytesDiff = bytesLoaded - lastBytes;
                    const speed = bytesDiff / timeDiff; // bytes per second
                    const speedFormatted = formatBytes(speed) + '/s';
                    
                    if (speedText) {
                        speedText.textContent = speedFormatted;
                    }
                    
                    lastUpdateTime = now;
                    lastBytes = bytesLoaded;
                }
                
                if (bytesText && totalBytes) {
                    bytesText.textContent = formatBytes(bytesLoaded) + ' / ' + formatBytes(totalBytes);
                }
                
                if (statusText) {
                    if (percent < 5) {
                        statusText.textContent = 'Preparing download...';
                    } else if (percent < 50) {
                        statusText.textContent = 'Downloading...';
                    } else if (percent < 95) {
                        statusText.textContent = 'Almost done...';
                    } else {
                        statusText.textContent = 'Finalizing...';
                    }
                }
            }
            
            fetch(url, {
                credentials: 'same-origin', // Include cookies for session auth
                headers: {
                    'X-Requested-With': 'XMLHttpRequest',
                    'Accept': 'application/zip, application/json, */*'
                }
            })
                .then(res => {
                    if (!res.ok) {
                        // Get error message from response if available
                        return res.text().then(text => {
                            let errorMsg = `HTTP ${res.status}: ${res.statusText}`;
                            try {
                                const json = JSON.parse(text);
                                errorMsg = json.message || json.error || errorMsg;
                            } catch (e) {
                                if (text && text.trim()) {
                                    errorMsg = text;
                                }
                            }
                            throw new Error(errorMsg);
                        });
                    }
                    
                    // Get file size from Content-Length header or use provided size
                    const contentLength = res.headers.get('Content-Length');
                    const totalBytes = contentLength ? parseInt(contentLength, 10) : (fileSizeBytes || 0);
                    
                    // Try to read filename from Content-Disposition
                    let cd = res.headers.get('Content-Disposition') || '';
                    let fnStar = /filename\*\s*=\s*UTF-8''([^;]+)/i.exec(cd);
                    let fnBasic = /filename\s*=\s*"([^"]+)"/i.exec(cd);
                    let filename = fnStar?.[1]
                                 ? decodeURIComponent(fnStar[1])
                                 : fnBasic?.[1]
                                   ? fnBasic[1]
                                   : defaultFilename || decodeURIComponent(url.split('/').pop().split('?')[0]);
                    
                    // Check if browser supports ReadableStream
                    if (!res.body || !res.body.getReader) {
                        // Fallback to blob method for older browsers
                        return res.blob().then(blob => {
                            updateProgress(blob.size, blob.size);
                            return { blob, filename };
                        });
                    }
                    
                    // Use streaming for progress tracking
                    const reader = res.body.getReader();
                    const chunks = [];
                    let receivedLength = 0;
                    
                    function pump() {
                        return reader.read().then(({ done, value }) => {
                            if (done) {
                                // All chunks received
                                const blob = new Blob(chunks);
                                updateProgress(blob.size, totalBytes || blob.size);
                                return { blob, filename };
                            }
                            
                            chunks.push(value);
                            receivedLength += value.length;
                            updateProgress(receivedLength, totalBytes);
                            
                            // Continue reading
                            return pump();
                        });
                    }
                    
                    return pump();
                })
                .then(({ blob, filename }) => {
                    // Hide progress, show completion
                    if (statusText) {
                        statusText.textContent = 'Download ready!';
                    }
                    
                    // Small delay to show 100% before triggering download
                    setTimeout(() => {
                        const link = document.createElement('a');
                        link.href = URL.createObjectURL(blob);
                        link.download = filename;
                        document.body.appendChild(link);
                        link.click();
                        document.body.removeChild(link);
                        URL.revokeObjectURL(link.href);
                        
                        // Reset UI
                        if (progressContainer) {
                            progressContainer.classList.add('hidden');
                        }
                        if (button) {
                            button.disabled = false;
                        }
                        if (buttonText) {
                            buttonText.textContent = 'Download All as ZIP';
                        }
                        if (progressBar) {
                            progressBar.style.width = '0%';
                        }
                    }, 300);
                })
                .catch(err => {
                    console.error('Download failed', err);
                    
                    // Reset UI on error
                    if (progressContainer) {
                        progressContainer.classList.add('hidden');
                    }
                    if (button) {
                        button.disabled = false;
                    }
                    if (buttonText) {
                        buttonText.textContent = 'Download All as ZIP';
                    }
                    if (statusText) {
                        statusText.textContent = 'Download failed';
                    }
                    
                    // Show user-friendly error message
                    let errorMessage = 'Download failed: ' + err.message;
                    if (err.message.includes('Unauthorized')) {
                        errorMessage = 'You are not authorized to download this file. Please log in again.';
                    } else if (err.message.includes('not found')) {
                        errorMessage = 'The download file was not found. Please try again.';
                    } else if (err.message.includes('not ready')) {
                        errorMessage = 'The ZIP file is still being generated. Please wait a moment and try again.';
                    }
                    
                    alert(errorMessage);
                });
        }
        
        /**
         * Download single file with progress tracking (for individual download buttons)
         */
        function startSingleDownloadWithProgress(url, defaultFilename, buttonId, progressContainerId, progressBarId, progressTextId, statusTextId, bytesTextId, speedTextId, buttonTextId, popupUrl) {
            // Check if another download or conversion is already active
            if (window.activeDownloadId || window.activeConversionId) {
                return false;
            }
            
            // Set active download ID and dispatch event
            window.activeDownloadId = buttonId;
            window.dispatchEvent(new CustomEvent('download-started'));
            
            // Handle ad popup for non-subscription users (similar to ads() method)
            if (popupUrl && popupUrl !== '') {
                window.open(popupUrl, '_blank');
            }
            const button = document.getElementById(buttonId);
            const buttonText = document.getElementById(buttonTextId);
            const progressContainer = document.getElementById(progressContainerId);
            const progressBar = document.getElementById(progressBarId);
            const progressText = document.getElementById(progressTextId);
            const statusText = document.getElementById(statusTextId);
            const bytesText = document.getElementById(bytesTextId);
            const speedText = document.getElementById(speedTextId);
            
            // Disable button and show progress
            if (button) {
                button.disabled = true;
            }
            if (progressContainer) {
                progressContainer.classList.remove('hidden');
            }
            if (statusText) {
                statusText.textContent = 'Starting download...';
            }
            
            let downloadedBytes = 0;
            let startTime = Date.now();
            let lastUpdateTime = startTime;
            let lastBytes = 0;
            
            // Format bytes to human-readable
            function formatBytes(bytes) {
                if (bytes === 0) return '0 B';
                const k = 1024;
                const sizes = ['B', 'KB', 'MB', 'GB'];
                const i = Math.floor(Math.log(bytes) / Math.log(k));
                return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
            }
            
            // Update progress display
            function updateProgress(bytesLoaded, totalBytes) {
                downloadedBytes = bytesLoaded;
                const percent = totalBytes ? Math.round((bytesLoaded / totalBytes) * 100) : 0;
                
                if (progressBar) {
                    progressBar.style.width = percent + '%';
                }
                if (progressText) {
                    progressText.textContent = percent + '%';
                }
                
                const now = Date.now();
                const timeDiff = (now - lastUpdateTime) / 1000; // seconds
                
                if (timeDiff >= 0.5 && bytesLoaded > lastBytes) { // Update speed every 0.5 seconds
                    const bytesDiff = bytesLoaded - lastBytes;
                    const speed = bytesDiff / timeDiff; // bytes per second
                    const speedFormatted = formatBytes(speed) + '/s';
                    
                    if (speedText) {
                        speedText.textContent = speedFormatted;
                    }
                    
                    lastUpdateTime = now;
                    lastBytes = bytesLoaded;
                }
                
                if (bytesText && totalBytes) {
                    bytesText.textContent = formatBytes(bytesLoaded) + ' / ' + formatBytes(totalBytes);
                }
                
                if (statusText) {
                    if (percent < 5) {
                        statusText.textContent = 'Preparing download...';
                    } else if (percent < 50) {
                        statusText.textContent = 'Downloading...';
                    } else if (percent < 95) {
                        statusText.textContent = 'Almost done...';
                    } else {
                        statusText.textContent = 'Finalizing...';
                    }
                }
            }
            
            fetch(url, {
                credentials: 'same-origin',
                headers: {
                    'X-Requested-With': 'XMLHttpRequest',
                    'Accept': 'application/json, application/zip, */*'
                },
                cache: 'no-cache'
            })
                .then(res => {
                    // Check if response is JSON (redirect_url for excluded tracks)
                    const contentType = res.headers.get('Content-Type') || '';
                    if (contentType.includes('application/json')) {
                        return res.json().then(json => {
                            if (json.success && json.redirect_url) {
                                // For excluded tracks, redirect to external URL directly
                                window.location.href = json.redirect_url;
                                return null;
                            }
                            if (json.error) {
                                throw new Error(json.message || json.error || 'Download failed');
                            }
                            throw new Error('Unexpected JSON response');
                        });
                    }
                    
                    if (!res.ok) {
                        return res.text().then(text => {
                            let errorMsg = `HTTP ${res.status}: ${res.statusText}`;
                            try {
                                const json = JSON.parse(text);
                                errorMsg = json.message || json.error || errorMsg;
                            } catch (e) {
                                if (text && text.trim()) {
                                    errorMsg = text;
                                }
                            }
                            throw new Error(errorMsg);
                        });
                    }
                    
                    // Get file size from Content-Length header
                    const contentLength = res.headers.get('Content-Length');
                    const totalBytes = contentLength ? parseInt(contentLength, 10) : null;
                    
                    // Try to read filename from Content-Disposition
                    let cd = res.headers.get('Content-Disposition') || '';
                    let fnStar = /filename\*\s*=\s*UTF-8''([^;]+)/i.exec(cd);
                    let fnBasic = /filename\s*=\s*"([^"]+)"/i.exec(cd);
                    let filename = fnStar?.[1]
                                 ? decodeURIComponent(fnStar[1])
                                 : fnBasic?.[1]
                                   ? fnBasic[1]
                                   : defaultFilename || decodeURIComponent(url.split('/').pop().split('?')[0]);
                    
                    // Check if browser supports ReadableStream
                    if (!res.body || !res.body.getReader) {
                        // Fallback to blob method for older browsers
                        return res.blob().then(blob => {
                            updateProgress(blob.size, blob.size);
                            return { blob, filename };
                        });
                    }
                    
                    // Use streaming for progress tracking
                    const reader = res.body.getReader();
                    const chunks = [];
                    let receivedLength = 0;
                    
                    function pump() {
                        return reader.read().then(({ done, value }) => {
                            if (done) {
                                // All chunks received
                                const blob = new Blob(chunks);
                                updateProgress(blob.size, totalBytes || blob.size);
                                return { blob, filename };
                            }
                            
                            chunks.push(value);
                            receivedLength += value.length;
                            updateProgress(receivedLength, totalBytes);
                            
                            // Continue reading
                            return pump();
                        });
                    }
                    
                    return pump();
                })
                .then(result => {
                    // If result is null, it means we redirected (excluded track)
                    if (result === null) {
                        // Clear active download and dispatch event
                        window.activeDownloadId = null;
                        window.dispatchEvent(new CustomEvent('download-ended'));
                        return;
                    }
                    
                    const { blob, filename } = result;
                    
                    // Hide progress, show completion
                    if (statusText) {
                        statusText.textContent = 'Download ready!';
                    }
                    
                    // Small delay to show 100% before triggering download
                    setTimeout(() => {
                        const link = document.createElement('a');
                        link.href = URL.createObjectURL(blob);
                        link.download = filename;
                        document.body.appendChild(link);
                        link.click();
                        document.body.removeChild(link);
                        URL.revokeObjectURL(link.href);
                        
                        // Reset UI
                        if (progressContainer) {
                            progressContainer.classList.add('hidden');
                        }
                        if (button) {
                            button.disabled = false;
                        }
                        if (buttonText) {
                            buttonText.textContent = 'Download';
                        }
                        if (progressBar) {
                            progressBar.style.width = '0%';
                        }
                        
                        // Clear active download and dispatch event
                        window.activeDownloadId = null;
                        window.dispatchEvent(new CustomEvent('download-ended'));
                    }, 300);
                })
                .catch(err => {
                    console.error('Download failed', err);
                    
                    // Reset UI on error
                    if (progressContainer) {
                        progressContainer.classList.add('hidden');
                    }
                    if (button) {
                        button.disabled = false;
                    }
                    if (buttonText) {
                        buttonText.textContent = 'Download';
                    }
                    if (statusText) {
                        statusText.textContent = 'Download failed';
                    }
                    
                    // Clear active download and dispatch event
                    window.activeDownloadId = null;
                    window.dispatchEvent(new CustomEvent('download-ended'));
                    
                    // Show user-friendly error message
                    let errorMessage = 'Download failed: ' + err.message;
                    if (err.message.includes('Unauthorized')) {
                        errorMessage = 'You are not authorized to download this file. Please log in again.';
                    } else if (err.message.includes('not found')) {
                        errorMessage = 'The download file was not found. Please try again.';
                    }
                    
                    alert(errorMessage);
                });
        }
    </script>
    
    <script async src="https://www.googletagmanager.com/gtag/js?id=G-TG8XL586JS"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'G-TG8XL586JS');
</script>

            <script>
            // Initialize Turnstile variables on window object to prevent redeclaration errors
            if (typeof window.playlistTurnstileSiteKey === 'undefined') {
                                window.playlistTurnstileSiteKey = '0x4AAAAAACLDFZqUgfj7-PJ2';
                            }
            if (typeof window.playlistTurnstileWidgetId === 'undefined') {
                window.playlistTurnstileWidgetId = null;
            }
            if (typeof window.playlistTurnstileToken === 'undefined') {
                window.playlistTurnstileToken = null;
            }

            // Helper function to get Livewire component instance
            function getSearchFormComponent() {
                if (!window.Livewire) {
                    return null;
                }
                
                // Find the component by looking for wire:id in the search form container
                // Try multiple selectors to find the component
                let searchForm = document.querySelector('form[wire\\:submit="search"]');
                if (!searchForm) {
                    searchForm = document.querySelector('[wire\\:id]');
                }
                
                if (!searchForm) {
                    return null;
                }
                
                // Get wire:id from the element or its parent
                let wireId = searchForm.getAttribute('wire:id');
                if (!wireId) {
                    const parent = searchForm.closest('[wire\\:id]');
                    if (parent) {
                        wireId = parent.getAttribute('wire:id');
                    }
                }
                
                if (!wireId) {
                    return null;
                }
                
                try {
                    return window.Livewire.find(wireId);
                } catch (e) {
                    return null;
                }
            }

            // Helper function to set turnstile token on Livewire component
            function setTurnstileToken(token) {
                const component = getSearchFormComponent();
                if (component) {
                    try {
                        if (component.set && typeof component.set === 'function') {
                            component.set('turnstileToken', token);
                        } else if (component.$wire && component.$wire.set) {
                            component.$wire.set('turnstileToken', token);
                        }
                    } catch (e) {
                        // Silently handle errors
                    }
                } else {
                    // Store token to set later when component is available
                    window.playlistTurnstileToken = token;
                }
            }

            // Load Turnstile script (same as login/register implementation)
            function loadPlaylistTurnstileScript() {
                return new Promise((resolve, reject) => {
                    // Check if script already loaded
                    if (window.turnstile) {
                        resolve();
                        return;
                    }

                    const script = document.createElement('script');
                    script.src = 'https://challenges.cloudflare.com/turnstile/v0/api.js';
                    script.async = true;
                    script.defer = true;
                    script.onload = () => resolve();
                    script.onerror = () => reject(new Error('Failed to load Turnstile script'));
                    document.head.appendChild(script);
                });
            }

            // Render Turnstile widget (same pattern as login/register)
            async function renderPlaylistTurnstile() {
                if (!window.playlistTurnstileSiteKey) return;

                const container = document.getElementById('playlist-turnstile-container');
                if (!container) return;

                // Simple check: if container has any children, widget already exists
                if (container.children.length > 0) {
                    return; // Widget already rendered
                }

                // Reset previous widget if it exists (cleanup)
                if (window.playlistTurnstileWidgetId && window.turnstile) {
                    try {
                        window.turnstile.remove(window.playlistTurnstileWidgetId);
                    } catch (e) {
                        // Ignore errors if widget doesn't exist
                    }
                    window.playlistTurnstileWidgetId = null;
                }

                // Container is empty, proceed with rendering
                try {
                    await loadPlaylistTurnstileScript();

                    if (!window.turnstile) {
                        showPlaylistTurnstileError('Turnstile script not loaded');
                        return;
                    }

                    // Double-check container is still empty before rendering (prevent race condition)
                    if (container.children.length > 0) {
                        return; // Widget appeared while loading script
                    }

                    // Render the widget (same as login/register)
                    window.playlistTurnstileWidgetId = window.turnstile.render(container, {
                        sitekey: window.playlistTurnstileSiteKey,
                        theme: 'auto',
                        size: 'normal',
                        callback: (token) => {
                            window.playlistTurnstileToken = token;
                            setTurnstileToken(token);
                            hidePlaylistTurnstileError();
                        },
                        'error-callback': (error) => {
                            window.playlistTurnstileToken = null;
                            setTurnstileToken(null);
                            showPlaylistTurnstileError('Turnstile verification failed. Please try again.');
                        },
                        'expired-callback': () => {
                            window.playlistTurnstileToken = null;
                            setTurnstileToken(null);
                            if (window.playlistTurnstileWidgetId && window.turnstile) {
                                window.turnstile.reset(window.playlistTurnstileWidgetId);
                            }
                        }
                    });
                } catch (error) {
                    showPlaylistTurnstileError('Failed to load Turnstile. Please refresh the page.');
                }
            }

            function showPlaylistTurnstileError(message) {
                const errorDiv = document.getElementById('playlist-turnstile-error');
                const errorText = document.getElementById('playlist-turnstile-error-text');
                if (errorDiv && errorText) {
                    errorText.textContent = message;
                    errorDiv.classList.remove('hidden');
                }
            }

            function hidePlaylistTurnstileError() {
                const errorDiv = document.getElementById('playlist-turnstile-error');
                if (errorDiv) {
                    errorDiv.classList.add('hidden');
                }
            }

            function resetPlaylistTurnstile() {
                if (window.playlistTurnstileWidgetId && window.turnstile) {
                    try {
                        window.turnstile.reset(window.playlistTurnstileWidgetId);
                    } catch (e) {
                        // Ignore errors
                    }
                }
                window.playlistTurnstileToken = null;
                setTurnstileToken(null);
            }

            // CRITICAL: Reset token on page load/refresh to prevent spam
            // Clear any stored token from previous page load
            window.playlistTurnstileToken = null;
            
            // Reset widget on page load
            if (window.playlistTurnstileWidgetId && window.turnstile) {
                try {
                    window.turnstile.remove(window.playlistTurnstileWidgetId);
                } catch (e) {
                    // Ignore errors
                }
                window.playlistTurnstileWidgetId = null;
            }
            
            // Helper function to check if URL is a playlist
            function isPlaylistUrl(url) {
                if (!url) return false;
                return /(?:list=)([a-zA-Z0-9_-]+)/.test(url);
            }

            // Initialize Turnstile when widget container appears (Livewire updates)
            document.addEventListener('livewire:init', () => {
                // Reset token on component mount (every page load/refresh)
                window.playlistTurnstileToken = null;
                
                Livewire.on('turnstile-reset', () => {
                    resetPlaylistTurnstile();
                    setTimeout(() => {
                        const container = document.getElementById('playlist-turnstile-container');
                        if (container) {
                            container.innerHTML = ''; // Clear container
                            renderPlaylistTurnstile();
                        }
                    }, 100);
                });
            });
            
            // Reset token on Livewire navigation (page refresh/navigation)
            document.addEventListener('livewire:navigated', () => {
                // Clear token and widget on navigation/refresh
                window.playlistTurnstileToken = null;
                if (window.playlistTurnstileWidgetId && window.turnstile) {
                    try {
                        window.turnstile.remove(window.playlistTurnstileWidgetId);
                    } catch (e) {
                        // Ignore errors
                    }
                }
                window.playlistTurnstileWidgetId = null;
            });
            

            // Function to check and render widget if needed
            function checkAndRenderPlaylistTurnstile() {
                const container = document.getElementById('playlist-turnstile-container');
                // Check if container exists, is visible, empty, and we have site key
                if (container && container.offsetParent !== null && container.children.length === 0 && window.playlistTurnstileSiteKey) {
                    renderPlaylistTurnstile();
                }
            }

            // Watch for Livewire updates and render widget when container appears
            document.addEventListener('livewire:update', function() {
                setTimeout(checkAndRenderPlaylistTurnstile, 150);
            });

            // Also watch for DOM changes (when showTurnstile becomes true)
            // Use window object to prevent redeclaration errors
            if (typeof window.playlistTurnstileObserver === 'undefined') {
                window.playlistTurnstileObserver = new MutationObserver(function(mutations) {
                    checkAndRenderPlaylistTurnstile();
                });
            }

            // Start observing when DOM is ready
            function initPlaylistTurnstileObserver() {
                const container = document.getElementById('playlist-turnstile-container');
                if (container && window.playlistTurnstileObserver) {
                    // Observe the parent to detect when container is added/removed
                    window.playlistTurnstileObserver.observe(container.parentElement || document.body, { 
                        childList: true, 
                        subtree: true,
                        attributes: true,
                        attributeFilter: ['class', 'style']
                    });
                    // Initial check
                    checkAndRenderPlaylistTurnstile();
                }
            }

            if (document.readyState === 'loading') {
                document.addEventListener('DOMContentLoaded', initPlaylistTurnstileObserver);
            } else {
                initPlaylistTurnstileObserver();
            }

            // Also check periodically (fallback for edge cases)
            if (typeof window.playlistTurnstileInterval === 'undefined') {
                window.playlistTurnstileInterval = setInterval(checkAndRenderPlaylistTurnstile, 500);
            }
        </script>
    
<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'a046b15aa8cb2adc',t:'MTc4MDIzNzk5Nw=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>
</html>
