{"id":3802,"date":"2025-10-09T11:30:48","date_gmt":"2025-10-09T04:30:48","guid":{"rendered":"https:\/\/bknpdiperjuangan.id\/?page_id=3802"},"modified":"2025-12-12T20:11:57","modified_gmt":"2025-12-12T13:11:57","slug":"daftar-video-kreatif","status":"publish","type":"page","link":"https:\/\/bknpdiperjuangan.id\/en\/daftar-video-kreatif\/","title":{"rendered":"Daftar Video Kreatif"},"content":{"rendered":"<!DOCTYPE html>\n<html lang=\"id\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Dashboard Penjurian Video Festival<\/title>\n    <script src=\"https:\/\/cdn.tailwindcss.com\"><\/script>\n    <!-- Import Font Inter dari Google Fonts -->\n    <link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@100..900&#038;display=swap\" rel=\"stylesheet\">\n    <style>\n        \/* Menggunakan font Inter untuk tampilan bersih dan modern *\/\n        body { font-family: 'Inter', sans-serif; }\n        \n        \/* Mengatur style scrollbar yang lebih halus *\/\n        .video-list::-webkit-scrollbar {\n            width: 8px;\n        }\n        .video-list::-webkit-scrollbar-thumb {\n            background-color: #fca5a5; \/* Red-300 yang lebih terang *\/\n            border-radius: 4px;\n        }\n        .video-list::-webkit-scrollbar-track {\n            background: #fefefe;\n        }\n\n        \/* Kelas untuk item daftar video yang lebih menonjol *\/\n        .video-item {\n            transition: all 0.2s ease-in-out;\n            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\n        }\n        .video-item:hover {\n            transform: translateY(-2px);\n            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n        }\n\n        \/* Penyesuaian Responsif Kustom: Mengurangi ukuran font judul video di mobile *\/\n        .video-item .video-title {\n            \/* Menghapus truncate agar judul bisa multi-baris di mobile *\/\n            white-space: normal;\n            overflow: hidden;\n            text-overflow: ellipsis;\n            font-size: 1.125rem; \/* text-xl *\/\n        }\n        @media (max-width: 639px) { \/* Maksimum ukuran mobile (sm) *\/\n            .video-item .video-title {\n                font-size: 1rem; \/* text-lg *\/\n                \/* Memastikan judul bisa mengambil lebar penuh dan multi-baris *\/\n                display: block; \n            }\n        }\n    <\/style>\n<\/head>\n<!-- Mengubah body menjadi bg-white agar menyatu dengan background WordPress -->\n<body class=\"bg-white min-h-screen flex flex-col\">\n\n    <!-- Header kustom dihapus agar tidak duplikasi dengan header WordPress dan mencegah dorongan ke bawah -->\n    \n    <!-- Perubahan: Mengubah max-w-4xl menjadi max-w-6xl untuk melebarkan container -->\n    <!-- Menambahkan px-2 untuk padding horizontal kecil di mobile agar tidak terlalu mepet tepi -->\n    <main class=\"flex-grow container mx-auto max-w-6xl px-2 sm:px-4\">\n        <div class=\"mb-4 mt-4\">\n            <!-- MENGURANGI MARGIN ATAS (mt-0) agar judul benar-benar di bagian atas main container. -->\n            <h2 class=\"text-2xl sm:text-3xl font-bold text-red-700 mt-0\">Daftar Video Kreatif<\/h2>          \n        <\/div>\n        \n        <!-- Memberi padding di sini untuk menjaga jarak konten dari tepi box -->\n        <div class=\"bg-white p-4 sm:p-8 rounded-xl shadow-2xl border border-red-100\">\n            <!-- Search Input dengan Style Baru -->\n            <div class=\"search-container mb-6\">\n                <div class=\"relative\">\n                    <!-- Penyesuaian padding vertikal di mobile: py-2.5 vs py-3 di desktop -->\n                    <input type=\"text\" id=\"videoSearch\" placeholder=\"Cari Judul Video atau Nama Peserta...\" \n                        onkeyup=\"filterVideos()\" \n                        class=\"w-full pl-4 pr-4 py-2.5 sm:py-3 text-base sm:text-lg border-2 border-red-300 rounded-xl focus:outline-none focus:ring-4 focus:ring-red-100 focus:border-red-500 transition duration-300\">\n                <\/div>\n            <\/div>\n            \n            <!-- Daftar Video -->\n            <ul class=\"video-list space-y-4 overflow-y-auto\" id=\"videoList\" style=\"max-height: 70vh;\">\n                <!-- Status Awal -->\n                <li class=\"p-4 text-center text-gray-500 font-medium bg-red-50 rounded-lg\" id=\"video-list-status\">Memuat daftar video&#8230;<\/li>\n            <\/ul>\n        <\/div>\n    <\/main>\n    \n    <!-- Footer Sederhana -->\n    <footer class=\"text-center py-4 text-xs text-gray-400 border-t mt-8\">\n        Data diperbarui otomatis setiap 10 detik.\n    <\/footer>\n    \n<script>\n    \/\/ --- 1. Konfigurasi URL Google Sheets & Indeks Kolom (DIPERTAHANKAN) ---\n    \n    \/\/ \ud83d\udea8 PENTING: GANTI URL INI - URL CSV dari SHEET DAFTAR VIDEO MASTER\n    const MASTER_VIDEO_LIST_URL = 'https:\/\/docs.google.com\/spreadsheets\/d\/e\/2PACX-1vQRsksOMLsQepyiFDIXpKOa-jjjmR5BmtFiznc6a7XrLOeDqVnq001N5JpP-MHGXL58ehE2wOwd7F97\/pub?gid=935828414&single=true&output=csv'; \n    \n    \/\/ \ud83d\udea8 PENTING: GANTI URL INI - URL CSV dari SHEET DATA PENILAIAN JURI\n    const JURY_RATING_URL = 'https:\/\/docs.google.com\/spreadsheets\/d\/e\/2PACX-1vS--iUMpQrZ39tJYxrEPGiwVVBhlLhpVStogstUF4qQc9UoKSEKsVNzNiRl5ByTJ05KhSQ20Zl5q7DS\/pub?gid=0&single=true&output=csv'; \n\n    \/\/ Indeks untuk Sheet Penilaian Juri (Sesuai gambar Sheet Anda: Kolom B dan G)\n    const JURY_NAMA_JURI_INDEX = 1;  \/\/ Kolom B\n    const JURY_ID_VIDEO_INDEX = 6;   \/\/ Kolom G\n    const MIN_JURY_COLUMNS = Math.max(JURY_NAMA_JURI_INDEX, JURY_ID_VIDEO_INDEX) + 1; \n\n    \/\/ Indeks untuk Sheet Master Video (Sesuai gambar Sheet Master: Kolom A, B, dan C)\n    const MASTER_JUDUL_INDEX = 0;    \/\/ Kolom A\n    const MASTER_ID_VIDEO_INDEX = 1;   \/\/ Kolom B\n    const MASTER_NAMA_PESERTA_INDEX = 2; \/\/ Kolom C: Nama Lengkap\n    const MIN_MASTER_COLUMNS = 3;      \n    \n    const MAX_JURI_DISPLAY = 2; \/\/ KUOTA JURI MAKSIMAL: 2\n    \n    \/\/ \ud83d\udca1 KONFIGURASI POLLING: Otomatis memuat ulang data setiap 5 detik.\n    const POLLING_INTERVAL_MS = 5000; \/\/ 5.000 milidetik = 5 detik\n\n    const CSV_REGEX = \/(\".*?\"|[^,]+)(?=,|$)\/g;\n    let currentFilter = ''; \/\/ Menyimpan filter pencarian saat ini\n\n    \/\/ --- 2. Fungsi Utility ---\n    \n    function cleanCSVValue(value) {\n        if (!value) return '';\n        \/\/ Membersihkan spasi, menghapus tanda kutip di awal\/akhir, dan mengatasi karakter khusus\n        value = value.trim().replace(\/^\"|\"$\/g, '');\n        return value.replace(\/\\\\\/g, '\\\\\\\\').replace(\/\"\/g, '\\\\\"').replace(\/\\n\/g, ' ');\n    }\n\n    window.filterVideos = function() {\n        var input = document.getElementById('videoSearch');\n        currentFilter = input.value.toUpperCase();\n        \n        var ul = document.getElementById('videoList');\n        if (!ul) return;\n        \n        var li = ul.querySelectorAll('.video-item'); \/\/ Hanya ambil item video\n        var foundCount = 0;\n        \n        \/\/ Sembunyikan status sebelum filter\n        const statusElement = document.getElementById('video-list-status');\n        if (statusElement) statusElement.style.display = 'none';\n\n        for (var i = 0; i < li.length; i++) {\n            var titleElement = li[i].querySelector('.video-title');\n            \/\/ Ambil elemen nama peserta untuk filter\n            var participantElement = li[i].querySelector('.video-participant-name'); \n            \n            if (titleElement || participantElement) {\n                const titleText = titleElement ? (titleElement.textContent || titleElement.innerText).toUpperCase() : '';\n                \/\/ Ambil teks nama peserta\n                const participantText = participantElement ? (participantElement.textContent || participantElement.innerText).toUpperCase() : ''; \n                \n                \/\/ Filter berdasarkan Judul ATAU Nama Peserta\n                if (titleText.indexOf(currentFilter) > -1 || participantText.indexOf(currentFilter) > -1) {\n                    li[i].style.display = \"flex\"; \n                    foundCount++;\n                } else {\n                    li[i].style.display = \"none\";\n                }\n            }\n        }\n        \n        \/\/ Tampilkan status jika tidak ada hasil\n        if (foundCount === 0 && li.length > 0) {\n            if (statusElement) {\n                statusElement.textContent = 'Tidak ada video yang cocok dengan pencarian Anda.';\n                statusElement.style.display = 'block';\n                statusElement.className = 'p-4 text-center text-red-500 font-medium bg-red-50 rounded-lg';\n            }\n        }\n    };\n    \n    \/\/ --- 3. Fungsi Utama: Load Data dan Gabungkan ---\n    async function loadVideoList() {\n        const videoListUl = document.getElementById('videoList');\n        \/\/ Tampilkan status loading\n        if (videoListUl.innerHTML === '' || videoListUl.innerHTML.includes('Memuat daftar video')) {\n            videoListUl.innerHTML = `<li class=\"p-4 text-center text-gray-500 font-medium bg-red-50 rounded-lg\" id=\"video-list-status\">Memuat data penilaian...<\/li>`;\n        }\n\n        const randomParam = '&t=' + new Date().getTime(); \n\n        try {\n            \/\/ TAHAP 1: Ambil dan Kelompokkan Data Penilaian Juri\n            const ratingResponse = await fetch(JURY_RATING_URL + randomParam);\n            if (!ratingResponse.ok) throw new Error('JURY_RATING_URL (Penilaian Juri) gagal dimuat.');\n            const ratingCsvText = await ratingResponse.text();\n            \n            const groupedRatings = {};\n            const ratingRows = ratingCsvText.trim().split('\\n');\n            \n            for (let i = 1; i < ratingRows.length; i++) {\n                const columns = ratingRows[i].trim().match(CSV_REGEX) || [];\n                if (columns.length >= MIN_JURY_COLUMNS) {\n                    const namaJuri = cleanCSVValue(columns[JURY_NAMA_JURI_INDEX]);\n                    const idVideo = cleanCSVValue(columns[JURY_ID_VIDEO_INDEX]);\n\n                    if (namaJuri && idVideo) {\n                        if (!groupedRatings[idVideo]) {\n                            groupedRatings[idVideo] = new Set();\n                        }\n                        groupedRatings[idVideo].add(namaJuri);\n                    }\n                }\n            }\n\n            \/\/ TAHAP 2: Ambil Daftar Video Master\n            const masterResponse = await fetch(MASTER_VIDEO_LIST_URL + randomParam);\n            if (!masterResponse.ok) throw new Error('MASTER_VIDEO_LIST_URL (Daftar Video) gagal dimuat.');\n            const masterCsvText = await masterResponse.text();\n            \n            const masterRows = masterCsvText.trim().split('\\n');\n            videoListUl.innerHTML = ''; \/\/ Kosongkan UL untuk rendering data baru\n\n            if (masterRows.length <= 1) {\n                videoListUl.innerHTML = `<li class=\"p-4 text-center text-blue-500 font-medium bg-blue-50 rounded-lg\" id=\"video-list-status\">Data daftar video kosong.<\/li>`;\n                return;\n            }\n\n            \/\/ TAHAP 3: Gabungkan dan Render\n            for (let i = 1; i < masterRows.length; i++) {\n                const columns = masterRows[i].trim().match(CSV_REGEX) || [];\n\n                if (columns.length >= MIN_MASTER_COLUMNS) {\n                    const judulKarya = cleanCSVValue(columns[MASTER_JUDUL_INDEX]);\n                    const idVideo = cleanCSVValue(columns[MASTER_ID_VIDEO_INDEX]);\n\t\t\t\t\tconst namaPeserta = cleanCSVValue(columns[MASTER_NAMA_PESERTA_INDEX]); \n\n                    if (!judulKarya || !idVideo) continue;\n\n                    const juriSet = groupedRatings[idVideo] || new Set();\n                    const allJudges = Array.from(juriSet);\n                    \n                    const juriArray = allJudges.slice(0, MAX_JURI_DISPLAY); \n                    \n                    let moreJuriText = '';\n                    if (allJudges.length > MAX_JURI_DISPLAY) {\n                        const count = allJudges.length - MAX_JURI_DISPLAY;\n                        moreJuriText = `<span class=\"text-gray-500 font-medium ml-1\"> (+${count} lagi)<\/span>`;\n                    }\n                    \n                    let juriDisplay = '';\n                    if (juriArray.length > 0) {\n                        const juriList = juriArray\n                            .map(j => `<span class=\"bg-green-100 text-green-700 text-xs font-semibold px-2 py-0.5 rounded-full\">${j}<\/span>`)\n                            .join(' ');\n                        juriDisplay = `\n                            <div class=\"mt-2 flex flex-wrap gap-2 items-center text-sm text-gray-600\">\n                                <span class=\"font-medium\">Dinilai oleh:<\/span> ${juriList}${moreJuriText}\n                            <\/div>\n                        `;\n                    } else {\n                        juriDisplay = `<div class=\"mt-2 text-sm text-red-500 font-medium\">Belum ada penilaian.<\/div>`;\n                    }\n                    \n                    let actionButton = '';\n                    let statusColor = '';\n                    if (allJudges.length < MAX_JURI_DISPLAY) {\n                        const encodedJudul = encodeURIComponent(judulKarya.trim());\n\t\t\t\t\t\tconst encodedNamaPeserta = encodeURIComponent(namaPeserta.trim());\n\t\t\t\t\t\t\n                        actionButton = `\n                            <a href=\"\/penjurian-video-dokumenter-festival-desa-2025\/?idvidio=${idVideo}&#038;hidden-judul=${encodedJudul}&#038;hidden-peserta=${encodedNamaPeserta}\" target=\"_blank\" \n                               class=\"whitespace-nowrap text-sm font-bold text-white bg-red-600 hover:bg-red-700 py-2 px-4 rounded-xl shadow-md transition duration-200\">\n                                \ud83d\udcdd Nilai Video\n                            <\/a>\n                        `;\n                        statusColor = 'bg-red-50 border-red-300';\n                    } else {\n                        actionButton = `\n                            <span class=\"whitespace-nowrap text-sm font-bold text-green-700 py-2 px-4 bg-green-100 rounded-xl\">\n                                \u2705 Penilaian Selesai\n                            <\/span>\n                        `;\n                        statusColor = 'bg-green-50 border-green-300';\n                    }\n\n                    const newRow = document.createElement('li');\n                    \n                    \/\/ Style item daftar baru: Card yang lebih menonjol\n                    newRow.className = `video-item flex flex-col sm:flex-row justify-between items-start sm:items-center p-4 ${statusColor} rounded-xl transition duration-200 border-2`;\n                    \n                    newRow.innerHTML = `\n                        <!-- Mengganti flex-grow min-w-0 mr-0 sm:mr-4 mb-3 sm:mb-0 menjadi lebar penuh di mobile -->\n                        <div class=\"flex-grow w-full sm:w-auto sm:mr-4 mb-3 sm:mb-0\">\n                            <span class=\"video-title text-xl font-extrabold text-gray-900 block\">${judulKarya}<\/span>\n                            <!-- Menghapus ID Video dan hanya menampilkan Nama Peserta -->\n                            <span class=\"video-participant-name text-sm text-gray-600 block mt-1\">Peserta: ${namaPeserta}<\/span>\n                            ${juriDisplay} \n                        <\/div>\n                        <div class=\"action-link flex-shrink-0 w-full sm:w-auto\">\n                            ${actionButton}\n                        <\/div>\n                    `;\n                    \n                    videoListUl.appendChild(newRow);\n                }\n            }\n\n            \/\/ Panggil filterVideos setelah data dimuat untuk menerapkan filter yang mungkin sudah ada\n            filterVideos(); \n\n        } catch (error) {\n            console.error('Terjadi kesalahan selama memuat data:', error);\n            let errorMessage = `ERROR: Gagal memuat data. Pesan: ${error.message}`;\n            \n            if (error.message.includes('Failed to fetch')) {\n                errorMessage += ` Pastikan SEMUA Sheet sudah dipublikasikan ke web (File > Share > Publish to web) dan URL sudah benar.`;\n            }\n\n            \/\/ Tampilkan pesan error di list status\n            const statusElement = document.getElementById('video-list-status');\n            if (statusElement) {\n                statusElement.textContent = errorMessage;\n                statusElement.style.display = 'block';\n                statusElement.className = 'p-4 text-center text-white font-bold bg-red-600 rounded-lg';\n            } else {\n                videoListUl.innerHTML = `<li class=\"p-4 text-center text-white font-bold bg-red-600 rounded-lg\" id=\"video-list-status\">${errorMessage}<\/li>`;\n            }\n        }\n    }\n    \n    \/\/ --- 4. Fungsi Polling dan Initial Load ---\n\n    function startPolling() {\n        \/\/ Panggil fungsi sekali saat startup\n        loadVideoList(); \n        \n        \/\/ Panggil fungsi berulang kali setiap interval\n        setInterval(loadVideoList, POLLING_INTERVAL_MS);\n    }\n\n    document.addEventListener('DOMContentLoaded', function() {\n        startPolling();\n    });\n<\/script>\n<\/body>\n<\/html>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>","protected":false},"excerpt":{"rendered":"<p>Dashboard Penjurian Video Festival Daftar Video Kreatif Memuat daftar video&#8230; Data diperbarui otomatis setiap 10 detik.<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"inline_featured_image":false,"footnotes":""},"class_list":["post-3802","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/bknpdiperjuangan.id\/en\/wp-json\/wp\/v2\/pages\/3802","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bknpdiperjuangan.id\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/bknpdiperjuangan.id\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/bknpdiperjuangan.id\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bknpdiperjuangan.id\/en\/wp-json\/wp\/v2\/comments?post=3802"}],"version-history":[{"count":89,"href":"https:\/\/bknpdiperjuangan.id\/en\/wp-json\/wp\/v2\/pages\/3802\/revisions"}],"predecessor-version":[{"id":4294,"href":"https:\/\/bknpdiperjuangan.id\/en\/wp-json\/wp\/v2\/pages\/3802\/revisions\/4294"}],"wp:attachment":[{"href":"https:\/\/bknpdiperjuangan.id\/en\/wp-json\/wp\/v2\/media?parent=3802"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}