PageSourceSearch

https://guvennesrleri.az/frq-templates/assets/js/video.js

js guvennesrleri.az collected 2026-09-24 11:01:14 UTC 14,436 bytes, 390 lines download raw bytes

1"use strict";
2
3let player;
4
5const CookieStoreV = {
6  get: function(n){ var m=document.cookie.match(new RegExp('(?:^|; )'+encodeURIComponent(n)+'=([^;]*)')); return m?decodeURIComponent(m[1]):null; },
7  set: function(n,v,days){ if(days===void 0) days=365; var d=new Date(); d.setTime(d.getTime()+days*864e5); document.cookie=encodeURIComponent(n)+"="+encodeURIComponent(v)+";expires="+d.toUTCString()+";path=/;SameSite=Lax"; }
8};
9function vGet(k){ try{return localStorage.getItem(k)??CookieStoreV.get(k);}catch(e){ return CookieStoreV.get(k); } }
10function vSet(k,v){ try{ localStorage.setItem(k,v); }catch(e){ CookieStoreV.set(k,v); } }
11
12function keyTime(id){ return "media:"+id+":t"; }  // currentTime
13function keyDur(id){  return "media:"+id+":d"; }  // duration
14function keyWatched(id){ return "media:"+id+":w"; } // "1" -> permanent watched
15
16function getVideoIdFrom(elOrUrl){
17  if (typeof elOrUrl === "string") return elOrUrl;
18  return (elOrUrl.getAttribute && (elOrUrl.getAttribute("data-media-id") || elOrUrl.getAttribute("data-video"))) ||
19         (elOrUrl.dataset && (elOrUrl.dataset.mediaId || elOrUrl.dataset.video)) || "";
20}
21function getVideoUrlFrom(el){
22  var url = (el.getAttribute && (el.getAttribute("data-video") || el.getAttribute("data-src") || el.getAttribute("href"))) ||
23            (el.dataset && (el.dataset.video || el.dataset.src)) || "";
24  url = (url || "").replace(/&/g,"&").trim();
25  return url || null;
26}
27function humanizeAz(sec){
28  if (!isFinite(sec) || sec <= 0) return "0 san";
29  sec = Math.floor(sec);
30  var h = Math.floor(sec/3600);
31  var m = Math.floor((sec%3600)/60);
32  var s = sec % 60;
33  var parts = [];
34  if (h > 0) parts.push(h + " saat");
35  if (m > 0) parts.push(m + " deq");
36  if (s > 0 || (h===0 && m===0)) parts.push(s + " san");
37  return parts.join(" ");
38}
39function setTotalOnce(el, sec){
40  if (!el || !isFinite(sec) || sec <= 0) return;
41  if (el.dataset && el.dataset.totalFixed === "1") return; // artıq yazılıb
42  el.textContent = humanizeAz(sec);
43  if (el.dataset) el.dataset.totalFixed = "1";
44}
45
46const metaQueue = [];
47let metaBusy = false;
48let metaVideoEl = null;
49
50function ensureMetaVideo() {
51  if (metaVideoEl) return metaVideoEl;
52  var v = document.createElement("video");
53  v.preload = "metadata";
54  v.muted = true; v.playsInline = true;
55  v.style.position = "absolute";
56  v.style.width = "1px";
57  v.style.height = "1px";
58  v.style.opacity = "0";
59  v.style.pointerEvents = "none";
60  document.body.appendChild(v);
61  metaVideoEl = v;
62  return v;
63}
64
65function enqueueDurationLoad(card){
66  var id = getVideoIdFrom(card);
67  var url = getVideoUrlFrom(card);
68  if (!id || !url) return;
69
70  var existing = parseFloat(vGet(keyDur(id)) || "0");
71  if (existing > 0) { setTotalOnce(card.querySelector(".total-time"), existing); return; }
72
73  // kart artıq növbədədirsə təkrar əlavə etmə
74  if (metaQueue.some(function(x){ return x && x.id === id; })) return;
75
76  metaQueue.push({ id:id, url:url, card:card });
77  drainMetaQueue();
78}
79
80function drainMetaQueue(){
81  if (metaBusy || metaQueue.length === 0) return;
82  metaBusy = true;
83
84  var job = metaQueue.shift();
85  var id = job.id, url = job.url, card = job.card;
86  var v = ensureMetaVideo();
87
88  var cleanup = function(){
89    v.src = "";
90    v.onloadedmetadata = null;
91    v.onerror = null;
92    metaBusy = false;
93    // Növbəti işi UI-nı bloklamadan başlat
94    setTimeout(drainMetaQueue, 0);
95  };
96
97  v.onloadedmetadata = function(){
98    var dur = v.duration && isFinite(v.duration) ? v.duration : 0;
99    if (dur > 0) {
100      vSet(keyDur(id), String(dur));
101      setTotalOnce(card.querySelector(".total-time"), dur);
102    }
103    cleanup();
104  };
105  v.onerror = cleanup;
106  v.src = url; // metadata yüklə
107}
108
109function findVideoCardById(id){
110  if(!id) return null;
111  var list = document.querySelectorAll(".media-card[data-video]");
112  for (var i=0;i<list.length;i++){
113    var c = list[i];
114    var cid = (c.getAttribute("data-media-id") || c.getAttribute("data-video") || "").trim();
115    if (cid === id) return c;
116  }
117  return null;
118}
119
120function updateVideoCardById(id){
121  var card = findVideoCardById(id);
122  if(!card) return;
123
124  var savedT = parseFloat(vGet(keyTime(id)) || "0");
125  var savedD = parseFloat(vGet(keyDur(id))  || "0");
126  var watched = vGet(keyWatched(id)) === "1";
127  var pct = savedD > 0 ? Math.min(100, (savedT / savedD) * 100) : 0;
128
129  var meta = card.querySelector(".media-meta");
130  if(!meta) return;
131
132  var remainEl = card.querySelector(".remaining-time");
133  var progBar  = card.querySelector(".progress-bar");
134  var progFill = progBar ? (progBar.querySelector(".progress-fill") || null) : null;
135  var statusTag= card.querySelector(".status-tag");
136
137  // 1) Həmişəlik Baxılıb və ya hazırda %>=95
138  if (watched || (savedD > 0 && pct >= 95)) {
139    if (!watched) vSet(keyWatched(id), "1");
140
141    if (!statusTag) {
142      var leftBox = meta.querySelector(".d-flex.gap-1") || meta.querySelector(".d-flex");
143      if (leftBox) {
144        statusTag = document.createElement("span");
145        statusTag.className = "status-tag";
146        leftBox.insertBefore(statusTag, leftBox.firstChild);
147      }
148    }
149    if (statusTag) statusTag.textContent = "Baxılıb";
150
151    if (remainEl && remainEl.parentNode) remainEl.parentNode.removeChild(remainEl);
152    if (progBar && progBar.parentNode)  progBar.parentNode.removeChild(progBar);
153    return;
154  }
155
156  // 2) Davam edir
157  if (savedD > 0 && pct > 0) {
158    if (statusTag && statusTag.parentNode) statusTag.parentNode.removeChild(statusTag);
159
160    if (!remainEl) {
161      remainEl = document.createElement("div");
162      remainEl.className = "remaining-time";
163      meta.appendChild(remainEl);
164    }
165    var remain = Math.max(0, savedD - savedT);
166    var txt = humanizeAz(remain);
167    remainEl.textContent = (txt === "0 san") ? "" : (txt + " qalıb");
168
169    if (!progBar) {
170      progBar = document.createElement("div");
171      progBar.className = "progress-bar";
172      progBar.innerHTML = '<div class="progress-fill" style="width:0%"></div>';
173      var mc = card.querySelector(".media-content");
174      if (mc) mc.appendChild(progBar);
175      progFill = progBar.querySelector(".progress-fill");
176    } else {
177      progFill = progBar.querySelector(".progress-fill") || progFill;
178    }
179    if (progFill) progFill.style.width = pct.toFixed(1) + "%";
180    return;
181  }
182
183  // 3) Baxılmayıb – status/remaining/progress olmasın
184  if (statusTag && statusTag.parentNode) statusTag.parentNode.removeChild(statusTag);
185  if (remainEl && remainEl.parentNode) remainEl.parentNode.removeChild(remainEl);
186  if (progBar && progBar.parentNode)  progBar.parentNode.removeChild(progBar);
187}
188
189function updateVideoCards(){
190  var list = document.querySelectorAll(".media-card[data-video]");
191  for (var i=0;i<list.length;i++){
192    var c = list[i];
193    enqueueDurationLoad(c);
194    var id = getVideoIdFrom(c);
195    if (id) updateVideoCardById(id);
196  }
197}
198
199var videoCardIO = new IntersectionObserver(function(entries){
200  for (var i=0;i<entries.length;i++){
201    var entry = entries[i];
202    if (!entry.isIntersecting) continue;
203    var card = entry.target;
204    videoCardIO.unobserve(card);
205    enqueueDurationLoad(card);
206    // metadata yazıldıqdan sonra UI update üçün biraz gecikme
207    setTimeout(function(c){ return function(){ updateVideoCardById(getVideoIdFrom(c)); }; }(card), 0);
208  }
209},{ root:null, rootMargin:"200px 0px", threshold:0 });
210
211function bootstrapInitialDurations(){
212  var all = Array.from(document.querySelectorAll(".media-card[data-video]"));
213  // İlk 8 kart -> dərhal; qalanlar -> görünəndə
214  for (var i=0;i<all.length;i++){
215    if (i < 8) enqueueDurationLoad(all[i]);
216    else videoCardIO.observe(all[i]);
217  }
218}
219
220var moV = new MutationObserver(function(muts){
221  var added = [];
222  for (var mi=0; mi<muts.length; mi++){
223    var m = muts[mi];
224    if (!m.addedNodes) continue;
225    for (var j=0;j<m.addedNodes.length;j++){
226      var n = m.addedNodes[j];
227      if (!(n instanceof Element)) continue;
228      if (n.matches && n.matches(".media-card[data-video]")) added.push(n);
229      var inner = n.querySelectorAll ? n.querySelectorAll(".media-card[data-video]") : [];
230      for (var k=0;k<inner.length;k++) added.push(inner[k]);
231    }
232  }
233  if (added.length){
234    for (var a=0;a<added.length;a++) {
235      enqueueDurationLoad(added[a]);
236      videoCardIO.observe(added[a]);
237    }
238    clearTimeout(moV._t);
239    moV._t = setTimeout(function(){
240      for (var a=0;a<added.length;a++){
241        var id = getVideoIdFrom(added[a]);
242        if (id) updateVideoCardById(id);
243      }
244    }, 50);
245  }
246});
247
248function findVideoUrlFromTrigger(trigger){
249  var carrier =
250    (trigger.closest && trigger.closest("[data-video]")) ||
251    (trigger.querySelector && trigger.querySelector("[data-video]")) ||
252    trigger;
253
254  var url =
255    (carrier.dataset && (carrier.dataset.video || carrier.dataset.src)) ||
256    (carrier.getAttribute && (carrier.getAttribute("data-video") || carrier.getAttribute("data-src") || carrier.getAttribute("href"))) ||
257    "";
258
259  url = (url || "").replace(/&amp;/g,"&").trim();
260  return url || null;
261}
262function loadSavedStart(id,fallbackStart,realDuration){
263  if (fallbackStart===void 0) fallbackStart = 0;
264  var savedT = parseFloat(vGet(keyTime(id)) || "0");
265  var savedD = parseFloat(vGet(keyDur(id))  || "0");
266  if (realDuration && savedD && Math.abs(savedD - realDuration) > 1) return fallbackStart || 0;
267  return savedT > 0 ? savedT : (fallbackStart || 0);
268}
269function flushSave(el,id){
270  if(!el) return;
271  vSet(keyTime(id), String(el.currentTime || 0));
272  vSet(keyDur(id),  String(el.duration   || 0));
273}
274
275document.addEventListener("DOMContentLoaded", function(){
276  bootstrapInitialDurations();  // ilk 8 dərhal, qalanlar görünəndə
277  updateVideoCards();           // status/progress 
278  moV.observe(document.body, { childList:true, subtree:true });
279
280  var modal = document.getElementById("videoModal");
281  if (!modal) return;
282
283  var overlay = modal.querySelector(".play-overlay");
284  var modalContent = modal.querySelector(".modal-content");
285
286  // boş link kliklərinin qarşısını al
287  document.addEventListener("click", function(e){
288    var trigger = e.target.closest ? e.target.closest("[data-bs-target='#videoModal']") : null;
289    if (!trigger) return;
290    if (trigger.matches && trigger.matches("a[href='#']")) e.preventDefault();
291  });
292
293  var activeMediaId = null;
294  var saveThrottleTs = 0;
295  var SAVE_INTERVAL_MS = 4000;
296
297  modal.addEventListener("show.bs.modal", function(e){
298    var trigger = e.relatedTarget;
299    if (!trigger) return;
300
301    var videoUrl = findVideoUrlFromTrigger(trigger);
302    var fallbackStart = parseFloat(trigger.getAttribute("data-current-time") || "0");
303    if (!videoUrl) { console.warn("Video tapılmadı.", trigger); return; }
304
305    // Köhnəni təmizlə
306    if (player) { try{player.destroy();}catch(_e){} player=null; }
307    var olds = modal.querySelectorAll("video#modal-video");
308    for (var oi=0; oi<olds.length; oi++){ try{olds[oi].pause();}catch(_e){} olds[oi].remove(); }
309
310    // Yeni video
311    var v = document.createElement("video");
312    v.id = "modal-video";
313    v.className = "plyr w-100 rounded-4";
314    v.setAttribute("preload","metadata");
315    v.setAttribute("playsinline","");
316    v.setAttribute("controls","");
317    var s = document.createElement("source");
318    s.src = videoUrl;
319    s.type = /\.webm(\?|$)/i.test(videoUrl) ? "video/webm" : "video/mp4";
320    v.appendChild(s);
321
322    var container = modal.querySelector(".position-relative") || modalContent;
323    if (overlay && container.contains(overlay)) container.insertBefore(v, overlay);
324    else container.appendChild(v);
325
326    activeMediaId = getVideoIdFrom(trigger) || videoUrl;
327
328    player = new Plyr(v, {
329      seekTime: 15,
330      controls: ['rewind','play','fast-forward','progress','current-time','duration','mute','volume','fullscreen']
331    });
332
333    // total-time
334    var card = findVideoCardById(activeMediaId) || { querySelector: function(){ return null; } };
335    var ensureDur = function(){
336      var dur = v.duration && isFinite(v.duration) ? v.duration : 0;
337      if (dur > 0) {
338        vSet(keyDur(activeMediaId), String(dur));
339        var totalEl = card.querySelector ? card.querySelector(".total-time") : null;
340        setTotalOnce(totalEl, dur);
341      }
342    };
343
344    v.addEventListener("loadedmetadata", function(){
345      ensureDur();
346      var start = loadSavedStart(activeMediaId, fallbackStart, v.duration);
347      if (start > 0 && start < (v.duration || Infinity)) v.currentTime = start;
348    });
349
350    v.addEventListener("timeupdate", function(){
351      var now = Date.now();
352      if (now - saveThrottleTs > SAVE_INTERVAL_MS) {
353        vSet(keyTime(activeMediaId), String(v.currentTime || 0));
354        vSet(keyDur(activeMediaId),  String(v.duration   || 0));
355        if (v.duration && v.currentTime / v.duration >= 0.95) vSet(keyWatched(activeMediaId),'1');
356        saveThrottleTs = now;
357        updateVideoCardById(activeMediaId);
358      }
359    });
360
361    v.addEventListener("ended", function(){
362      vSet(keyTime(activeMediaId), String(v.duration || 0));
363      vSet(keyDur(activeMediaId),  String(v.duration || 0));
364      vSet(keyWatched(activeMediaId),'1'); // permanent
365      updateVideoCardById(activeMediaId);
366    });
367
368    var visHandler = function(){ if (document.hidden) { flushSave(v, activeMediaId); updateVideoCardById(activeMediaId); } };
369    document.addEventListener("visibilitychange", visHandler);
370
371    modal.addEventListener("hidden.bs.modal", function(){
372      flushSave(v, activeMediaId);
373      setTimeout(function(){ updateVideoCardById(activeMediaId); }, 0);
374
375      if (player) { try{player.destroy();}catch(_e){} player=null; }
376      v.remove();
377      document.removeEventListener("visibilitychange", visHandler);
378      activeMediaId = null;
379    }, { once:true });
380
381    if (overlay) {
382      overlay.addEventListener("click", function overlayOnce(){
383        overlay.style.display = "none";
384        modal.classList.remove("hide-controls");
385        if (player) player.play();
386        overlay.removeEventListener("click", overlayOnce);
387      });
388    }
389  });
390});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.