PageSourceSearch

https://15half.com/assets/schedule-times.js?v=20260926-songs-before-movies-v1

js 15half.com collected 2026-10-09 22:39:32 UTC 2,454 bytes, 83 lines download raw bytes

1const TIME_ZONE = "Asia/Jerusalem";
2const RELEASE_HOUR = 18;
3const RELEASE_MINUTE = 45;
4
5const PROGRAM_ORDER = [
6  "hamoach",
7  "songs-quiz",
8  "film-ghosts",
9  "marketplace-price",
10  "daily-news",
11  "music-battle",
12];
13
14function israelParts(date) {
15  return Object.fromEntries(
16    new Intl.DateTimeFormat("en-CA", {
17      timeZone: TIME_ZONE,
18      year: "numeric",
19      month: "2-digit",
20      day: "2-digit",
21      hour: "2-digit",
22      minute: "2-digit",
23      hourCycle: "h23",
24    }).formatToParts(date).map((part) => [part.type, part.value]),
25  );
26}
27
28function israelDateKey(date) {
29  const parts = israelParts(date);
30  return `${parts.year}-${parts.month}-${parts.day}`;
31}
32
33export function scheduleTimeReleaseReached(now = new Date()) {
34  const parts = israelParts(now);
35  const hour = Number(parts.hour);
36  const minute = Number(parts.minute);
37  return hour > RELEASE_HOUR ||
38    (hour === RELEASE_HOUR && minute >= RELEASE_MINUTE);
39}
40
41export function authoritativeScheduleTimes(schedule, now = new Date()) {
42  if (!scheduleTimeReleaseReached(now) || !Array.isArray(schedule)) {
43    return null;
44  }
45
46  const today = israelDateKey(now);
47  const byProgram = new Map();
48  for (const slot of schedule) {
49    if (!PROGRAM_ORDER.includes(slot?.programKey)) continue;
50    const startsAt = new Date(slot?.startsAt ?? "");
51    const endsAt = new Date(slot?.endsAt ?? "");
52    if (
53      !Number.isFinite(startsAt.getTime()) ||
54      !Number.isFinite(endsAt.getTime()) ||
55      endsAt <= startsAt
56    ) {
57      return null;
58    }
59    if (israelDateKey(startsAt) !== today) continue;
60    if (
61      slot?.isPersisted !== true ||
62      !String(slot?.showPackageId ?? "").trim() ||
63      byProgram.has(slot.programKey)
64    ) {
65      return null;
66    }
67    byProgram.set(slot.programKey, { ...slot, startsAt, endsAt });
68  }
69
70  const order = PROGRAM_ORDER.filter(key => key !== "film-ghosts" || byProgram.has(key));
71  if (byProgram.size !== order.length) return null;
72  const ordered = order.map((programKey) => byProgram.get(programKey));
73  if (ordered.some((slot, index) =>
74    !slot || (index > 0 && slot.startsAt <= ordered[index - 1].startsAt)
75  )) {
76    return null;
77  }
78  // Once the full lineup has ended, this dialog represents the next
79  // broadcast. Do not keep presenting the completed day's exact times as if
80  // they were tomorrow's still-unproduced schedule.
81  if (now >= ordered[ordered.length - 1].endsAt) return null;
82  return ordered;
83}

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.