ב"ה עשיתי כעת פתרון עצמאי, במקום לשנות לכל שנה בנפרד.
מועיל גם לשידור חי לפי פרשה וגם לניתוב לשלוחת האזנה לפי פרשה, קבוע.
ניתן לשנות כמובן כ"א לפי המערכת שלו, וכמובן להעלות לשרת ולפ"ז להגדיר את הAPI.
השארתי את ההסבר לכל הגדרה לנוחות העברה.
להלן הקוד להעלאה לשרת:
<?php
/**
* ===========================================================================
* parsha.php - ניתוב אוטומטי קבוע לפי פרשת השבוע (שידור + האזנה)
* ===========================================================================
* מטרה: להחליף את שתי טבלאות ה-go_to_folder_time הידניות (שדרשו עדכון שנתי)
* בשלוחת API אחת שמחשבת את פרשת השבוע מהלוח העברי - "הגדר ושכח" ל-50 שנה.
*
* שימוש כשלוחת ימות (type=api):
* שידור (שלוחה 90/08): api_link=https://********/yemot/parsha.php?mode=broadcast
* האזנה (שלוחה /10/.../01): api_link=https://********/yemot/parsha.php?mode=listen
*
* בדיקה ידנית בדפדפן:
* ?mode=listen&debug=1 -> JSON עם כל הפרטים לפרשה הנוכחית
* ?mode=broadcast&debug=1&date=2026-05-09 -> בדיקת תאריך ספציפי (בהר-בחקתי)
*
* איך זה עובד:
* - מחשב את "השבת הקרובה" (השבת שאליה מכוון שיעור השבוע).
* - מושך את לוח הפרשות/חגים מ-Hebcal (ארץ ישראל) ושומר בקאש מקומי.
* הקאש מתרענן אוטומטית פעם בשנה - אין שום עדכון ידני לעולם.
* - אם באותה שבת נקראת פרשה רגילה -> מנתב לשלוחת הפרשה.
* - אם השבת היא חג שאין בו פרשה רגילה (פסח/שבועות/ר"ה/יו"כ/סוכות) ->
* מנתב לשלוחת החג (בהאזנה). בשידור: הודעה שאין שידור בחג (ניתן להגדיר שלוחה).
* ===========================================================================
*/
date_default_timezone_set('Asia/Jerusalem');
define('PARSHA_ENGINE_VER', '1.1'); // סמן גרסה לאימות הפריסה
/* ---------------------------- הגדרות ---------------------------- */
$CONFIG = [
// בסיסי הנתיבים (מתאים לטבלאות הקיימות שלך)
'broadcast_base' => '/90/10', // שלוחות השידור (קונפרנס) לפי פרשה
'listen_base' => '/10/02', // שלוחות ההאזנה לפי פרשה
// שלוחות חג להאזנה (מתוך הרשימה שנתת)
'festival_listen' => [
'pesach' => '/301/04/01', // פסח (כולל חוה"מ)
'shavuot' => '/301/04/03', // שבועות
'rosh' => '/301/04/05/02', // ראש השנה
'kippur' => '/301/04/05/04', // יום הכיפורים
'sukkot' => '/301/04/05/05', // סוכות / שמע"צ / שמח"ת
],
// שלוחות חג לשידור. השאר ריק => הודעה "אין שידור בחג".
// אם תרצה שידור גם בחג, הוסף כאן, למשל: 'pesach' => '/90/10/XX'
'festival_broadcast' => [
],
'cache_file' => __DIR__ . '/parsha_cache.json',
'log_file' => __DIR__ . '/parsha_log.txt',
'fallback_msg' => 'השבוע אין פרשה לפי הסדר, ניתן להאזין לשיעורי החג',
'no_broadcast_chag_msg' => 'השבוע חג, אין שידור שיעור',
];
/*
* מיפוי פרשה (שם אנגלי מנורמל של Hebcal) => [מספר שלוחת שידור, נתיב שלוחת האזנה].
* הנתונים חולצו מהרשימות המדויקות שסיפקת (שלוחות /90/10 ו-/10/02).
*/
$PARSHA_MAP = [
// בראשית
'bereshit' => ['01', '01/01'],
'noach' => ['02', '01/02'],
'lechlecha' => ['03', '01/03'],
'vayera' => ['04', '01/04'],
'chayeisara' => ['05', '01/05'],
'toldot' => ['06', '01/06'],
'vayetzei' => ['07', '01/07'],
'vayishlach' => ['08', '01/08'],
'vayeshev' => ['09', '01/09'],
'miketz' => ['10', '01/10'],
'vayigash' => ['11', '01/11'],
'vayechi' => ['12', '01/12'],
// שמות
'shemot' => ['13', '02/01'],
'vaera' => ['14', '02/02'],
'bo' => ['15', '02/03'],
'beshalach' => ['16', '02/04'],
'yitro' => ['17', '02/05'],
'mishpatim' => ['18', '02/06'],
'terumah' => ['19', '02/07'],
'tetzaveh' => ['20', '02/08'],
'kitisa' => ['21', '02/09'],
'vayakhel' => ['22', '02/10'],
'pekudei' => ['23', '02/11'],
'vayakhelpekudei' => ['24', '02/12'],
// ויקרא
'vayikra' => ['25', '03/01'],
'tzav' => ['26', '03/02'],
'shmini' => ['27', '03/03'],
'tazria' => ['28', '03/04'],
'metzora' => ['29', '03/05'],
'tazriametzora' => ['35', '03/11'],
'achreimot' => ['30', '03/06'],
'kedoshim' => ['31', '03/07'],
'achreimotkedoshim' => ['36', '03/12'],
'emor' => ['32', '03/08'],
'behar' => ['33', '03/09'],
'bechukotai' => ['34', '03/10'],
'beharbechukotai' => ['37', '03/13'],
// במדבר
'bamidbar' => ['38', '04/01'],
'nasso' => ['39', '04/02'],
'behaalotcha' => ['40', '04/03'],
'shlach' => ['41', '04/04'],
'korach' => ['42', '04/05'],
'chukat' => ['43', '04/06'],
'balak' => ['44', '04/07'],
'pinchas' => ['45', '04/08'],
'matot' => ['46', '04/09'],
'masei' => ['47', '04/10'],
'matotmasei' => ['48', '04/11'],
// דברים
'devarim' => ['49', '05/01'],
'vaetchanan' => ['50', '05/02'],
'eikev' => ['51', '05/03'],
'reeh' => ['52', '05/04'],
'shoftim' => ['53', '05/05'],
'kiteitzei' => ['54', '05/06'],
'kitavo' => ['55', '05/07'],
'nitzavim' => ['56', '05/08'],
'vayeilech' => ['57', '05/09'],
'nitzavimvayeilech' => ['60', '05/12'],
'haazinu' => ['58', '05/10'],
'vezothaberachah' => ['59', '05/11'],
];
/* ---------------------------- קוד ---------------------------- */
function p_log($m) {
global $CONFIG;
if (!empty($CONFIG['log_file'])) {
@file_put_contents($CONFIG['log_file'], date('Y-m-d H:i:s') . " $m\n", FILE_APPEND);
}
}
/** ניקוי טקסט לתשובת ימות (הסרת תווים ששוברים את הפרוטוקול) */
function say_clean($text) {
$text = str_replace(['&', '=', '.', "\r", "\n"], [' ', ' ', ' ', ' ', ' '], $text);
return trim($text);
}
/** נרמול שם פרשה אנגלי לשם מפתח (אותיות/ספרות בלבד, אותיות קטנות) */
function normalize_parsha($title) {
$t = preg_replace('/^Parashat\s+/i', '', $title);
$t = strtolower($t);
return preg_replace('/[^a-z0-9]/', '', $t);
}
/** חותמת השבת הקרובה (השבת הראשונה שגדולה/שווה להיום) */
function coming_shabbat_ts($ts) {
$d = strtotime(date('Y-m-d', $ts));
$dow = (int)date('w', $d); // 0=ראשון .. 6=שבת
$add = (6 - $dow + 7) % 7; // 0 אם היום שבת
return $d + $add * 86400;
}
/** שליפת לוח פרשות+חגים מ-Hebcal (ארץ ישראל) לטווח תאריכים */
function fetch_hebcal($start, $end) {
$url = "https://www.hebcal.com/hebcal?cfg=json&v=1&s=on&maj=on&i=on"
. "&start=" . urlencode($start) . "&end=" . urlencode($end);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 20,
CURLOPT_SSL_VERIFYPEER => false, // תאימות NetFree/פרוקסי
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_USERAGENT => 'parsha/1.0',
]);
$raw = curl_exec($ch);
$err = curl_error($ch);
curl_close($ch);
if ($raw === false) { p_log("Hebcal fetch error: $err"); return null; }
$data = json_decode($raw, true);
if (!isset($data['items']) || !is_array($data['items'])) {
p_log('Hebcal: תשובה לא תקינה');
return null;
}
$items = [];
foreach ($data['items'] as $it) {
if (!isset($it['date'], $it['category'])) continue;
if ($it['category'] !== 'parashat' && $it['category'] !== 'holiday') continue;
$items[] = [
'date' => substr($it['date'], 0, 10),
'category' => $it['category'],
'title' => isset($it['title']) ? $it['title'] : '',
];
}
return $items;
}
function load_cache() {
global $CONFIG;
if (!is_file($CONFIG['cache_file'])) return null;
$d = json_decode(@file_get_contents($CONFIG['cache_file']), true);
return is_array($d) ? $d : null;
}
function save_cache($c) {
global $CONFIG;
@file_put_contents($CONFIG['cache_file'], json_encode($c, JSON_UNESCAPED_UNICODE));
}
/**
* מחזיר את רשימת הפריטים (פרשות+חגים) המכסה את השבת המבוקשת.
* במצב רגיל משתמש בקאש ומרענן פעם בשנה. במצב בדיקה (date=) לא נוגע בקאש.
*/
function items_for($shabbatTs, $isTest) {
global $CONFIG;
$D = date('Y-m-d', $shabbatTs);
if ($isTest) {
$items = fetch_hebcal(date('Y-m-d', $shabbatTs - 14 * 86400),
date('Y-m-d', $shabbatTs + 14 * 86400));
return $items !== null ? ['items' => $items] : null;
}
$cache = load_cache();
$covered = $cache && isset($cache['start'], $cache['end'])
&& $cache['start'] <= $D && $D <= $cache['end'];
if (!$covered) {
$start = date('Y-m-d', time() - 14 * 86400);
$end = date('Y-m-d', time() + 400 * 86400);
$items = fetch_hebcal($start, $end);
if ($items !== null) {
$cache = ['start' => $start, 'end' => $end, 'fetched_at' => date('c'), 'items' => $items];
save_cache($cache);
}
}
return $cache;
}
/** זיהוי חג משמעותי (שאין בו פרשה רגילה) מתוך רשימת חגים באותה שבת */
function festival_key($holidays) {
foreach ($holidays as $h) {
$t = $h['title'];
if (stripos($t, 'Pesach') !== false) return 'pesach';
if (stripos($t, 'Shavuot') !== false) return 'shavuot';
if (stripos($t, 'Rosh Hashana') !== false) return 'rosh';
if (stripos($t, 'Yom Kippur') !== false) return 'kippur';
if (stripos($t, 'Sukkot') !== false
|| stripos($t, 'Shmini Atzeret') !== false
|| stripos($t, 'Simchat Torah') !== false) return 'sukkot';
}
return null;
}
/** הלוגיקה המרכזית: קביעת היעד לפי התאריך והמצב */
function resolve_route($ts, $mode, $isTest) {
global $CONFIG, $PARSHA_MAP;
$sat = coming_shabbat_ts($ts);
$D = date('Y-m-d', $sat);
$res = ['shabbat' => $D, 'mode' => $mode];
$cache = items_for($sat, $isTest);
if (!$cache || empty($cache['items'])) {
$res['type'] = 'error';
return $res;
}
$par = null; $hol = [];
foreach ($cache['items'] as $it) {
if ($it['date'] !== $D) continue;
if ($it['category'] === 'parashat') $par = $it;
elseif ($it['category'] === 'holiday') $hol[] = $it;
}
// 1) פרשה רגילה
if ($par) {
$key = normalize_parsha($par['title']);
if (isset($PARSHA_MAP[$key])) {
$m = $PARSHA_MAP[$key];
$res['type'] = 'parsha';
$res['parsha'] = $par['title'];
$res['folder'] = $mode === 'broadcast'
? $CONFIG['broadcast_base'] . '/' . $m[0]
: $CONFIG['listen_base'] . '/' . $m[1];
return $res;
}
$res['type'] = 'unknown_parsha'; // לא אמור לקרות - להתראה בלוג
$res['parsha'] = $par['title'];
p_log('פרשה לא ממופה: ' . $par['title'] . ' (' . $key . ')');
return $res;
}
// 2) שבת-חג (אין פרשה רגילה)
$fkey = festival_key($hol);
if ($fkey) {
$res['festival'] = $fkey;
$res['holidays'] = array_column($hol, 'title');
if ($mode === 'broadcast') {
if (isset($CONFIG['festival_broadcast'][$fkey])) {
$res['type'] = 'festival';
$res['folder'] = $CONFIG['festival_broadcast'][$fkey];
} else {
$res['type'] = 'no_broadcast';
}
} else {
$res['type'] = 'festival';
$res['folder'] = $CONFIG['festival_listen'][$fkey];
}
return $res;
}
// 3) גיבוי
$res['type'] = 'none';
$res['holidays'] = array_column($hol, 'title');
return $res;
}
/* ---------------------------- ניתוב הבקשה ---------------------------- */
// קביעת המצב. אפשר לכפות מבחוץ עם $FORCE_MODE (ראה shidur.php) - הכי חסין,
// כי אין תלות בפרמטר URL שימות עלול לא להעביר. אחרת - זיהוי סובלני מה-mode.
if (isset($FORCE_MODE)) {
$mode = $FORCE_MODE === 'broadcast' ? 'broadcast' : 'listen';
} else {
$raw = isset($_REQUEST['mode']) ? strtolower((string)$_REQUEST['mode']) : '';
if (strpos($raw, 'broadcast') !== false || strpos($raw, 'shidur') !== false) {
$mode = 'broadcast';
} else {
$mode = 'listen';
}
}
$isTest = isset($_REQUEST['date']);
$ts = $isTest ? strtotime($_REQUEST['date']) : time();
if (!$ts) $ts = time();
$r = resolve_route($ts, $mode, $isTest);
// מצב בדיקה: החזרת JSON מפורט
if (isset($_REQUEST['debug'])) {
$r['engine_ver'] = PARSHA_ENGINE_VER;
$r['force_mode'] = isset($FORCE_MODE) ? $FORCE_MODE : '(none)';
header('Content-Type: application/json; charset=utf-8');
echo json_encode($r, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
exit;
}
// תשובת ימות
header('Content-Type: text/plain; charset=utf-8');
switch ($r['type']) {
case 'parsha':
case 'festival':
echo 'go_to_folder=' . $r['folder'];
break;
case 'no_broadcast':
echo 'id_list_message=t-' . say_clean($CONFIG['no_broadcast_chag_msg']) . '.';
break;
default:
p_log('גיבוי/שגיאה: ' . json_encode($r, JSON_UNESCAPED_UNICODE));
echo 'id_list_message=t-' . say_clean($CONFIG['fallback_msg']) . '.';
}