PROGRAM UPLOADED VIDEO oleh ALMIGHTY CHATGPT!! PART-14: FINISHING FINAL SOURCE CODE

 <!-- Paste this entire block into Blogger post (HTML mode) -->

<style>

/* Styles Part 1 (main) */

.video-item { margin-bottom: 18px; }

.meta-title { margin-top:8px; font-style:italic; font-size:1.05rem; font-weight:bold; }

.meta-translation { color:#444; margin-bottom:6px; font-size:0.95rem; }

.comment-section { margin-top:10px; }

.comment-input { width:100%; min-height:65px; }

.comment-output { margin-top:8px; background:#f5f5f5; padding:6px; min-height:22px; border-radius:4px; }


/* Control Section */

#login-panel, #admin-panel {

  border: 2px solid #666; padding: 20px; border-radius: 10px;

  background: #f0f0f0; margin-bottom: 25px;

}

#admin-panel { display:none; }

#log-box {

  background:#fff; border:1px solid #aaa; padding:10px;

  max-height:200px; overflow-y:auto; margin-top:10px;

}


/* Additional comment */

.add-extra-label { margin-top:6px; display:block; cursor:pointer; }

.add-extra-box { display:none; width:100%; margin-top:6px; }

.add-extra-textarea { width:100%; resize:vertical; min-height:120px; }


/* balloon confirm */

.ballon-confirm {

  position:absolute;

  background:#fff;

  border:1px solid #888;

  padding:10px;

  border-radius:6px;

  box-shadow:0 2px 6px rgba(0,0,0,0.2);

  z-index:9999;

  max-width:300px;

  font-size:0.95rem;

}


/* Styles Part 2 (summary) */

#summary-sep { text-align:center; margin-top:40px; margin-bottom:10px; font-size:1.4rem; font-weight:bold; }

.sum-video-item { margin-bottom: 22px; }

.sum-comment-box {

  background:#f7f7f7; border:1px solid #aaa; padding:10px; border-radius:6px;

  min-height:40px; font-size:0.95rem;

}

.sum-extra-box {

  background:#fff; border:1px dashed #ccc; padding:8px; border-radius:4px; margin-top:8px;

  font-size:0.95rem;

}

</style>


<!--===========================

   CONTROL SECTION (LOGIN / ADMIN)

===========================-->

<div id="login-panel">

  <h3><b>CONTROL SECTION</b> — Login</h3>

  <label>Username:</label><br />

  <input id="user" type="text" /><br /><br />

  <label>Password:</label><br />

  <input id="pass" type="password" /><br /><br />

  <button id="login-btn">Login</button>

</div>


<div id="admin-panel">

  <h3><b>CONTROL SECTION</b> — Admin Panel</h3>

  <label><input name="comm" type="radio" value="enable" /> Enable All Comments</label><br />

  <label><input name="comm" type="radio" value="disable" /> Disable All Comments</label>

  <br /><br />

  <button id="logout-btn">Logout</button>

  <h4>Activity Log</h4>

  <div id="log-box"></div>

</div>


<!--===========================

   PART 1 — MAIN VIDEO LIST (editable comments)

===========================-->

<div id="video-list">


  <!--ITEM 1-->

  <div class="video-item" data-id="1" data-src="https://youtube.com/shorts/9WVxOv5J2m0">

    <br /><br />

    <iframe allowfullscreen frameborder="0" height="360" src="https://www.youtube.com/embed/9WVxOv5J2m0" width="100%"></iframe>

    <div class="auto-meta" data-id="meta-1"></div>


    <div class="comment-section">

      <h4>Leave a Comment:</h4>

      <textarea class="comment-input" id="com-input-1" placeholder="Type your comment..."></textarea><br />


      <label class="add-extra-label">

        <input type="checkbox" class="add-extra-checkbox"> Additional Comment

      </label>

      <div class="add-extra-box">

        <textarea rows="4" class="add-extra-textarea" placeholder="Additional detail..."></textarea>

      </div>


      <div class="comment-output" id="com-output-1"></div>

    </div>

    <hr />

  </div>


  <!--ITEM 2-->

  <div class="video-item" data-id="3" data-src="https://youtube.com/shorts/-w182IGAt84">

    <br /><br />

    <iframe allowfullscreen frameborder="0" height="360" src="https://www.youtube.com/embed/-w182IGAt84" width="100%"></iframe>

    <div class="auto-meta" data-id="meta-3"></div>


    <div class="comment-section">

      <h4>Leave a Comment:</h4>

      <textarea class="comment-input" id="com-input-3" placeholder="Type your comment..."></textarea><br />


      <label class="add-extra-label">

        <input type="checkbox" class="add-extra-checkbox"> Additional Comment

      </label>

      <div class="add-extra-box">

        <textarea rows="4" class="add-extra-textarea" placeholder="Additional detail..."></textarea>

      </div>


      <div class="comment-output" id="com-output-3"></div>

    </div>

    <hr />

  </div>


  <!--ITEM 3-->

  <div class="video-item" data-id="16" data-src="https://youtube.com/shorts/F2j9mWgxV0o">

    <br /><br />

    <iframe allowfullscreen frameborder="0" height="360" src="https://www.youtube.com/embed/F2j9mWgxV0o" width="100%"></iframe>

    <div class="auto-meta" data-id="meta-16"></div>


    <div class="comment-section">

      <h4>Leave a Comment:</h4>

      <textarea class="comment-input" id="com-input-16" placeholder="Type your comment..."></textarea><br />


      <label class="add-extra-label">

        <input type="checkbox" class="add-extra-checkbox"> Additional Comment

      </label>

      <div class="add-extra-box">

        <textarea rows="4" class="add-extra-textarea" placeholder="Additional detail..."></textarea>

      </div>


      <div class="comment-output" id="com-output-16"></div>

    </div>

    <hr />

  </div>


  <!--ITEM 4-->

  <div class="video-item" data-id="22" data-src="https://youtube.com/shorts/oqtJYTjAnnE">

    <br /><br />

    <iframe allowfullscreen frameborder="0" height="360" src="https://www.youtube.com/embed/oqtJYTjAnnE" width="100%"></iframe>

    <div class="auto-meta" data-id="meta-22"></div>


    <div class="comment-section">

      <h4>Leave a Comment:</h4>

      <textarea class="comment-input" id="com-input-22" placeholder="Type your comment..."></textarea><br />


      <label class="add-extra-label">

        <input type="checkbox" class="add-extra-checkbox"> Additional Comment

      </label>

      <div class="add-extra-box">

        <textarea rows="4" class="add-extra-textarea" placeholder="Additional detail..."></textarea>

      </div>


      <div class="comment-output" id="com-output-22"></div>

    </div>

    <hr />

  </div>


</div>


<!--===========================

   PART 2 — SUMMARY (read-only duplicate of Part1 comments)

===========================-->

<div id="summary-sep">SUMMARY</div>

<p style="font-style: italic; margin-bottom: 20px; text-align: center;">

  Ringkasan komentar (read-only) — menampilkan isi komentar yang telah disimpan di Part 1.

</p>


<div id="summary-video-list">


  <div class="sum-video-item" data-id="1">

    <iframe allowfullscreen frameborder="0" height="240" src="https://www.youtube.com/embed/9WVxOv5J2m0" width="100%"></iframe>

    <div class="sum-meta" data-id="sum-meta-1"></div>

    <h4>Comment (Read Only):</h4>

    <div class="sum-comment-box" id="sum-com-1"></div>

    <div class="sum-extra-box" id="sum-extra-1"></div>

    <hr />

  </div>


  <div class="sum-video-item" data-id="3">

    <iframe allowfullscreen frameborder="0" height="240" src="https://www.youtube.com/embed/-w182IGAt84" width="100%"></iframe>

    <div class="sum-meta" data-id="sum-meta-3"></div>

    <h4>Comment (Read Only):</h4>

    <div class="sum-comment-box" id="sum-com-3"></div>

    <div class="sum-extra-box" id="sum-extra-3"></div>

    <hr />

  </div>


  <div class="sum-video-item" data-id="16">

    <iframe allowfullscreen frameborder="0" height="240" src="https://www.youtube.com/embed/F2j9mWgxV0o" width="100%"></iframe>

    <div class="sum-meta" data-id="sum-meta-16"></div>

    <h4>Comment (Read Only):</h4>

    <div class="sum-comment-box" id="sum-com-16"></div>

    <div class="sum-extra-box" id="sum-extra-16"></div>

    <hr />

  </div>


  <div class="sum-video-item" data-id="22">

    <iframe allowfullscreen frameborder="0" height="240" src="https://www.youtube.com/embed/oqtJYTjAnnE" width="100%"></iframe>

    <div class="sum-meta" data-id="sum-meta-22"></div>

    <h4>Comment (Read Only):</h4>

    <div class="sum-comment-box" id="sum-com-22"></div>

    <div class="sum-extra-box" id="sum-extra-22"></div>

    <hr />

  </div>


</div>


<!--Firebase SDK (compat)-->

<script src="https://www.gstatic.com/firebasejs/9.22.2/firebase-app-compat.js"></script>

<script src="https://www.gstatic.com/firebasejs/9.22.2/firebase-database-compat.js"></script>


<script>

document.addEventListener("DOMContentLoaded", function(){


  /* ---------- helpers ---------- */

  function escapeHtml(s){

    return String(s || "").replace(/[&<>"']/g,

      m=>({"&":"&amp;","<":"&lt;",">":"&gt;","\"":"&quot;","'":"&#39;"}[m]));

  }

  function onClick(id, handler){

    const el = document.getElementById(id);

    if (el) el.addEventListener("click", handler);

  }


  /* ---------- Firebase config (INSERTED) ---------- */

  const firebaseConfig = {

    apiKey: "AIzaSyAF5r6Rvu-DmoV-vf47wYTZfarpVGmNYR0",

    authDomain: "ronin-11938.firebaseapp.com",

    databaseURL: "https://ronin-11938-default-rtdb.firebaseio.com",

    projectId: "ronin-11938",

    storageBucket: "ronin-11938.firebasestorage.app",

    messagingSenderId: "823368889742",

    appId: "1:823368889742:web:609e16ace214b94a0df",

    measurementId: "G-H2H8GSMQ94"

  };


  // init firebase

  firebase.initializeApp(firebaseConfig);

  const rdb = firebase.database();


  /* ---------- small local state mirrors ---------- */

  window.commentsDB = {}; // populated by listener

  window.currentCommentState = "enable";


  /* ---------- log utils (now stored in Firebase) ---------- */

  function addLogFirebase(text){

    const node = rdb.ref('logs').push();

    node.set({ text: text, ts: Date.now() });

  }

  function renderLogFromFirebase(snapshot){

    const val = snapshot ? (snapshot.val()||{}) : {};

    const arr = Object.values(val);

    arr.sort((a,b)=>b.ts - a.ts);

    const b = document.getElementById("log-box");

    if (b) b.innerHTML = arr.map(x=>`<div>[${new Date(x.ts).toLocaleString()}] ${escapeHtml(x.text)}</div>`).join("");

  }


  /* ---------- comment state (stored in Firebase) ---------- */

  function applyCommentState(state){

    const disabled = (state === "disable");

    window.currentCommentState = state;

    document.querySelectorAll(".comment-input").forEach(e=>{ e.disabled = disabled; e.readOnly = disabled; });

    document.querySelectorAll(".add-extra-textarea").forEach(e=>{ e.disabled = disabled; e.readOnly = disabled; });

    document.querySelectorAll(".add-extra-checkbox").forEach(e=>{ e.disabled = disabled; });

    // there are no submit buttons anymore, keep logs only

  }

  function setCommentStateFirebase(v){

    rdb.ref('config/comment_state').set(v);

    addLogFirebase(v === "enable" ? "Comments ENABLED" : "Comments DISABLED");

  }


  /* ---------- metadata & translate ---------- */

  const GOOGLE_TRANSLATE_ENDPOINT =

    "https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=en&dt=t&q=";


  async function translateSmartSingle(text){

    if (!text) return "";

    try{

      let r = await fetch(GOOGLE_TRANSLATE_ENDPOINT + encodeURIComponent(text));

      if (r.ok){

        let arr = await r.json();

        if (arr && arr[0]) {

          let out = "";

          for (let seg of arr[0]) if (seg[0]) out += seg[0];

          if (out.trim()) return out;

        }

      }

    }catch(e){}

    return text;

  }


  async function loadMetadataInto(box, videoURL){

    if (!box) return;

    box.innerHTML = "<i>Loading...</i>";

    try{

      let r = await fetch("https://www.youtube.com/oembed?url="+encodeURIComponent(videoURL)+"&format=json");

      if (!r.ok) throw 0;

      let meta = await r.json();

      let title = meta.title || "(no title)";

      box.innerHTML = `<p class="meta-title">${escapeHtml(title)}</p><p class="meta-translation"><b>English:</b> Translating...</p>`;

      let eng = await translateSmartSingle(title);

      const transEl = box.querySelector(".meta-translation");

      if (transEl) transEl.innerHTML = `<b>English:</b> ${escapeHtml(eng)}`;

    }catch(e){

      box.innerHTML = "<p>(Metadata unavailable)</p>";

    }

  }


  /* ---------- helpers for extra comment saving/deleting & balloon ---------- */

  function showBalloonConfirm(target, text, onYes, onNo){

    // remove existing balloons

    document.querySelectorAll('.ballon-confirm').forEach(e=>e.remove());

    const box = document.createElement("div");

    box.className = "ballon-confirm";

    box.innerHTML = `

      <div style="margin-bottom:8px">${escapeHtml(text)}</div>

      <div style="text-align:right">

        <button class="bc-yes">Yes</button>

        <button class="bc-no">No</button>

      </div>

    `;

    document.body.appendChild(box);

    const r = target.getBoundingClientRect();

    // position: prefer below, fallback to above if not enough space

    const topBelow = r.bottom + 6;

    const topAbove = r.top - box.offsetHeight - 6;

    box.style.left = Math.max(8, r.left) + "px";

    box.style.top = topBelow + "px";

    box.querySelector(".bc-yes").onclick = ()=>{ box.remove(); onYes(); };

    box.querySelector(".bc-no").onclick = ()=>{ box.remove(); onNo(); };

    // remove if click outside

    function outside(e){

      if (!box.contains(e.target) && e.target !== target) { box.remove(); document.removeEventListener('click', outside); }

    }

    setTimeout(()=>document.addEventListener('click', outside), 10);

  }


  function updateMainComment(id, val){

    rdb.ref('comments/'+id+'/text').set(val || "");

    rdb.ref('comments/'+id).update({ updatedAt: Date.now() });

  }


  function updateExtraComment(id, val){

    if (val === null) {

      rdb.ref('comments/'+id+'/text-area').remove();

    } else {

      rdb.ref('comments/'+id+'/text-area').set(val || "");

      rdb.ref('comments/'+id).update({ updatedAt: Date.now() });

    }

  }


  /* ---------- Firebase listeners to keep UI in sync ---------- */

  rdb.ref('comments').on('value', function(snapshot){

    const val = snapshot.val() || {};

    window.commentsDB = val;

    // render comments into Part1 and Part2

    document.querySelectorAll(".video-item").forEach(vi=>{

      const id = vi.getAttribute("data-id");

      if (!id) return;

      const ta = vi.querySelector(".comment-input");

      const out = vi.querySelector(".comment-output");

      const extraWrap = vi.querySelector(".add-extra-box");

      const extraTa = vi.querySelector(".add-extra-textarea");

      const extraCb = vi.querySelector(".add-extra-checkbox");

      const entry = val[id] || {};

      const text = entry.text || "";

      const extra = entry["text-area"] || "";

      if (ta && ta !== document.activeElement) ta.value = text; // don't overwrite when typing

      if (out) out.innerHTML = text ? `<p>${escapeHtml(text)}</p>` : "";

      // extra

      if (extraTa && extraCb && extraWrap){

        if (extra){

          extraCb.checked = true;

          extraWrap.style.display = "block";

          if (extraTa !== document.activeElement) extraTa.value = extra;

        } else {

          // if there's no stored extra, keep checkbox state if user currently typing; otherwise reset

          if (extraTa !== document.activeElement) extraTa.value = "";

          if (!extraTa || !extraTa.value) {

            extraCb.checked = false;

            extraWrap.style.display = "none";

          }

        }

      }

    });


    // summary: main and extra

    ["1","3","16","22"].forEach(id => {

      const b = document.getElementById("sum-com-" + id);

      const e = document.getElementById("sum-extra-" + id);

      const item = val[id] || {};

      if (b) b.innerHTML = item.text ? escapeHtml(item.text) : "<i>(No comment entered)</i>";

      if (e) e.innerHTML = item["text-area"] ? escapeHtml(item["text-area"]) : "";

    });

  });


  // comment_state listener

  rdb.ref('config/comment_state').on('value', function(snapshot){

    const state = snapshot.val() || "enable";

    // apply UI

    applyCommentState(state);

    const sel = document.querySelector(`input[name='comm'][value='${state}']`);

    if (sel) sel.checked = true;

  });


  // logs listener

  rdb.ref('logs').on('value', function(snapshot){

    renderLogFromFirebase(snapshot);

  });


  /* ---------- admin login UI (keeps same username/password UX as before) ---------- */

  const loginPanel = document.getElementById("login-panel");

  const adminPanel = document.getElementById("admin-panel");


  // preserve session per tab (not persistent cross-browser)

  function isLoggedIn(){

    return sessionStorage.getItem("manu_login") === "true";

  }


  if (isLoggedIn()){

    if (loginPanel) loginPanel.style.display = "none";

    if (adminPanel) adminPanel.style.display = "block";

    addLogFirebase("Auto login (session)");

  }


  onClick("login-btn", function(){

    const u = (document.getElementById("user")||{}).value || "";

    const p = (document.getElementById("pass")||{}).value || "";

    if (u === "manu" && p === "manu"){

      sessionStorage.setItem("manu_login","true");

      if (loginPanel) loginPanel.style.display = "none";

      if (adminPanel) adminPanel.style.display = "block";

      addLogFirebase("User manu logged in");

    } else {

      alert("Wrong username or password.");

    }

  });


  onClick("logout-btn", function(){

    addLogFirebase("User manu logged out");

    sessionStorage.setItem("manu_login","false");

    location.reload();

  });


  // radio change -> update Firebase config

  document.querySelectorAll("input[name='comm']").forEach(r=>{

    r.addEventListener("change", function(){

      const v = this.value;

      setCommentStateFirebase(v);

      applyCommentState(v);

    });

  });


  /* ---------- initialize metadata for both parts ---------- */

  document.querySelectorAll(".video-item").forEach(vi=>{

    const url = vi.getAttribute("data-src");

    const metaBox = vi.querySelector(".auto-meta");

    if (metaBox && url) loadMetadataInto(metaBox, url);

  });


  // summary meta boxes

  const idToUrl = {};

  document.querySelectorAll(".video-item").forEach(vi=>{

    const id = vi.getAttribute("data-id");

    const url = vi.getAttribute("data-src");

    if (id) idToUrl[id] = url;

  });

  document.querySelectorAll("[data-id^='sum-meta-'], .sum-meta").forEach(el=>{

    const parent = el.closest(".sum-video-item");

    if (!parent) return;

    const id = parent.getAttribute("data-id");

    const url = idToUrl[id];

    if (url) loadMetadataInto(el, url);

  });


  /* ---------- attach auto-save handlers that write to Firebase ---------- */

  document.querySelectorAll(".video-item").forEach(vi=>{

    const id = vi.getAttribute("data-id");

    if (!id) return;

    const ta = vi.querySelector(".comment-input");

    const extraWrap = vi.querySelector(".add-extra-box");

    const extraTa = vi.querySelector(".add-extra-textarea");

    const extraCb = vi.querySelector(".add-extra-checkbox");

    const out = vi.querySelector(".comment-output");


    // main textarea auto-save on input (debounce small)

    let mainTimer = null;

    if (ta){

      ta.addEventListener("input", function(){

        if (window.currentCommentState === "disable") return;

        clearTimeout(mainTimer);

        mainTimer = setTimeout(()=> updateMainComment(id, ta.value.trim()), 450);

      });

    }


    // extra textarea auto-save

    let extraTimer = null;

    if (extraTa){

      extraTa.addEventListener("input", function(){

        if (window.currentCommentState === "disable") return;

        clearTimeout(extraTimer);

        extraTimer = setTimeout(()=> updateExtraComment(id, extraTa.value.trim()), 450);

      });

    }


    // checkbox behaviour: show/hide extra box; on uncheck with content => confirm balloon and delete on yes

    if (extraCb){

      extraCb.addEventListener("change", function(){

        if (window.currentCommentState === "disable"){

          // prevent toggling while disabled

          extraCb.checked = !extraCb.checked;

          return;

        }

        if (extraCb.checked){

          if (extraWrap) extraWrap.style.display = "block";

        } else {

          const currentVal = (extraTa && extraTa.value) ? extraTa.value.trim() : "";

          if (currentVal){

            showBalloonConfirm(extraCb, "Remove additional comment? This will DELETE saved additional comment.", function(){

              // yes

              if (extraWrap) extraWrap.style.display = "none";

              if (extraTa) extraTa.value = "";

              updateExtraComment(id, null); // remove from firebase

            }, function(){

              // no

              extraCb.checked = true;

              if (extraWrap) extraWrap.style.display = "block";

            });

          } else {

            // no value, just hide and ensure deleted

            if (extraWrap) extraWrap.style.display = "none";

            updateExtraComment(id, null);

          }

        }

      });

    }

  });


  // ensure summary boxes show something on load if DB empty

  ["1","3","16","22"].forEach(id => {

    const b = document.getElementById("sum-com-" + id);

    if (b && (!b.innerHTML || b.innerHTML.trim()==="")) b.innerHTML = "<i>(No comment entered)</i>";

  });


}); // end DOMContentLoaded

</script>


Comments