+
    Fj                    &-   ^ RI HtHtHtHtHtHt ^ RIHt ^ RI	t	^ RI
t
^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt]! ]4      tRt]
P8                  ! R4      tRtRtRt R	t!]	PD                  PG                  ]R
4      t$]	PD                  PG                  ]$R4      t%]	PD                  PG                  ]$R4      t&]	PD                  PG                  ]$R4      t']	PD                  PG                  ]$R4      t(]	PD                  PG                  ]$R4      t)]	PD                  PG                  ]R4      t*Rt+R]	PD                  PG                  ]R4      R]	PD                  PG                  ]R4      R]	PD                  PG                  ]R4      R]	PD                  PG                  ]R4      R]	PD                  PG                  ]R4      /t,0 ERmt-RRRR/t.RRRR/t/RR /t0R!]	PD                  PG                  R"R#R$R%4      R&]	PD                  PG                  R"R#R$R'4      /t10 ERm]2! ^^%4       U u0 uF	  p R(V R) 2kK  	  up ,          t30 ERmt4R*]	PD                  PG                  R"R+R$R,4      ]	PD                  PG                  R"R$R,4      R,.R-]	PD                  PG                  R"R.R$R/4      ./t50 ERmt60 ERmt7ERt8^t9ERt:ERt;ERt<R0t=ERt>ERt?0 ERmt@]	PD                  P                  ]B4      tC]	PD                  PG                  ]R1R24      tD]	PD                  PG                  ]R3R44      tEERtFERtG^tHERtIERtJ]	PD                  PG                  ]R54      tK]	PD                  PG                  ]R64      tL]	PD                  PG                  ]R74      tM]	PD                  PG                  ]R1R84      tN]	P                  P                  R9R:4      tQ]	PD                  PG                  ]R;4      tR]	PD                  PG                  ]R<4      tS]	PD                  PG                  ]R=4      tT]U! ]	P                  P                  R>R?4      4      tV]U! ]	P                  P                  R@RA4      4      tW]	P                  P                  RBRC4      tXERRD ltYRERFRGRH]LRIRJ/RKRFRLRH])RIRM/RNRFRORH]*RIRP/RQRFRRRH]SRIRS//tZ^xt[RTt\]U! ]	P                  P                  RURV4      4      t]]U! ]	P                  P                  RW]^! ER4      4      4      t_]`;QJ d=    . RX ]	P                  P                  RYRZ4      P                  R[4       4       F  NK  	  5M6! RX ]	P                  P                  RYRZ4      P                  R[4       4       4      tb]U! ]	P                  P                  R\]^! ER4      4      4      tc]	P                  P                  R]R^4      td]	P                  P                  R_R`4      teRatfRbtg]	P                  P                  RcRd4      P                  4       P                  4       ER9  tj^tkRftl^<tmRgRhRiRj/tnRgRkRiRl/to]	P                  P                  RmRd4      P                  4       P                  4       ER9  tp]U! ]	P                  P                  RnRe4      4      tq]U! ]	P                  P                  RoRp4      4      tr]U! ]	P                  P                  RqRr4      4      ts]t! ^]u! ^]U! ]	P                  P                  RsRt4      4      4      4      tv]t! ^-]u! ^\]U! ]	P                  P                  RuRv4      4      4      4      tw]U! ]	P                  P                  RwRx4      4      txRy]y! ]v4      ,          tz]	P                  P                  RzRd4      P                  4       P                  4       ER9  t{]	P                  P                  R{Rd4      P                  4       P                  4       ER9  t|]	P                  P                  R|R}4      P                  4       t}]	P                  P                  R~R}4      P                  4       t~]	P                  P                  R]	PD                  PG                  ]R4      4      t]t! ^]u! ^]U! ]	P                  P                  RR4      4      4      4      t]t! ^]u! ER]U! ]	P                  P                  RR4      4      4      4      t]	P                  P                  RR4      t]	PD                  PG                  ]R4      t]	PD                  PG                  ]R4      t]	PD                  PG                  ]R4      t]	PD                  PG                  ]R4      tRt]	P                  P                  RR4      P                  4       ;'       g    Rt]U! ]	P                  P                  RR4      4      t]	P                  P                  RRd4      P                  4       P                  4       ER9  t]U! ]	P                  P                  RR4      4      t]	PD                  PG                  ]R4      tRRRR}RR}RRRR}RRRR/t]EP                  ! 4       tRFRRH]RIR/]ZR&   RFRRH]RIR/]ZR&   RFRRH]RIR/]ZR&   R tR tR tR tR tR tR tERR ltERR ltERR ltR tR tR tR t],EP=                  4        F  t]	EP@                  ! ]RR7       K  	  ]	EP@                  ! ]	PD                  PG                  ],R,          R"R#R$4      RR7       ]	EP@                  ! ]	PD                  PG                  ],R,          R"R#R4      RR7       ]	EP@                  ! ]	PD                  PG                  ],R,          R"R4      RR7       ]	EP@                  ! ]	PD                  PG                  ],R,          R"R+R$4      RR7       ]	EP@                  ! ]	PD                  PG                  ],R,          R"R.R$4      RR7       ]	EP@                  ! ]	PD                  PG                  ],R,          R"R$4      RR7       ]	EP@                  ! ]DRR7       ]	EP@                  ! ]ERR7       R t]EPD                  R 4       tR tR tR tERR ltERR ltR tR tR tR tR tR tR tR tR tR tR tR tR tR tERR ltERR ltR tERR ltR tR tR tERR ltERR ltR tR tR tR tR tERR ltERR ltR tERR ltR tERR ltERR ltR tERR ltR tR tR tERR ltERR lt][3R lt][3R ltR tR tERR ltR tR tR tR tR tR tR tR tR tR tR tR t ! R R4      t]! 4       tR tR tR tERR ltERR ltER  tERER ltERER lt ! ER ER4      t ! ER ER4      t ! ER ER4      t]! 4       t]! 4       t]! 4       tERER	 ltER
 tERER ltER tER tER tER tERER ltERER ltERER ltER tER tER Et ER EtER Et]EP                  ER4      ER 4       Et. ERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNEtER Et]EP                  ER4      ]EP                  ER4      ER 4       4       EtERER lEtER Et	ER  Et
ER! EtER" EtERER# lEtER$ EtER% EtER& Et]EP                  ER'4      ER( 4       Et]EP                  ER)4      ER* 4       Et]EP                  ER+4      ER, 4       Et]EP                  ER-4      ER. 4       Et]EP                  ER/4      ER0 4       Et]EP                  ER14      ER2 4       Et]EP                  ER34      ER4 4       Et]EP                  ER54      ER6 4       Et]EP                  ER74      ER8 4       Et]EP                  ER94      ER: 4       Et]EP                  ER;4      ER< 4       Et]EP                  ER=ER>.ER?7      ER@ 4       Et]EP                  ERAER>.ER?7      ERB 4       Et]EP                  ERC4      ERD 4       Et]EP                  ERE4      ERF 4       Et]EP                  ERG4      ERH 4       Et ]EP                  ERI4      ERJ 4       Et!]EP                  ERKER>.ER?7      ERL 4       Et"]EP                  ERM4      ERN 4       Et#]EP                  ERO4      ERP 4       Et$]EP                  ERQ4      ERR 4       Et%]EP                  ERSER>.ER?7      ERT 4       Et&]EP                  ERUER>.ER?7      ERV 4       Et']EP                  ERW4      ERX 4       Et(]EP                  ERYER>.ER?7      ERZ 4       Et)]EP                  ER[4      ER\ 4       Et*]EP                  ER]4      ER^ 4       Et+]EP                  ER_ER>.ER?7      ER` 4       Et,]EP                  ERaER>.ER?7      ERb 4       Et-]EP                  ERcER>.ER?7      ERd 4       Et.]EP                  ERe4      ERf 4       Et/]EP                  ERg4      ERh 4       Et0]EP                  ERi4      ERj 4       Et1]EP                  ERkER>.ER?7      ERl 4       Et2]EP                  ERmER>.ER?7      ERn 4       Et3]EP                  ERoER>.ER?7      ERp 4       Et4]EP                  ERqER>.ER?7      ERr 4       Et5]EP                  ERsER>.ER?7      ERt 4       Et6]EP                  ERuER>.ER?7      ERv 4       Et7]EP                  ERwER>.ER?7      ERx 4       Et8]EP                  ERyER>.ER?7      ERz 4       Et9]EP                  ER{ER>.ER?7      ER| 4       Et:]EP                  ER}ER>.ER?7      ER~ 4       Et;]EP                  ERER>.ER?7      ER 4       Et<]EP                  ERER>.ER?7      ER 4       Et=]EP                  ERER>.ER?7      ER 4       Et>]EP                  ERER>.ER?7      ER 4       Et?]EP                  ERER>.ER?7      ER 4       Et@]EP                  ERER>.ER?7      ER 4       EtA]EP                  ERER>.ER?7      ER 4       EtB]EP                  ERER>.ER?7      ER 4       EtC]EP                  ER4      ]EP                  ER4      ER 4       4       EtD]EP                  ER4      ]EP                  ER4      ER 4       4       EtE]EP                  ER4      ]EP                  ER4      ER 4       4       EtF]EP                  ER4      ]EP                  ER4      ER 4       4       EtG]EP                  ER4      ER 4       EtH]EP                  ER4      ER 4       EtI]EP                  ER4      ER 4       EtJ]EP                  ER4      ]EP                  ER4      ER 4       4       EtK]EP                  ER4      ER 4       EtL]EP                  ER4      ER 4       EtM]ER8X  d,   ]! ER4       ]! ER4       ]EP                  ]] RRER7       R# R# u up i (      )Flaskrequestredirectsend_from_directorymake_responseResponse)secure_filenameNz-TripServer Admin v34.0 two-app control server%Y-%m-%d %H:%M:%SzC:\TripServerz0.0.0.0i@  iJ  control_serverztripserver_control_server.pyzpending_admin_server.pyzrequest.jsonzstatus.jsonztripserver_control_server.logz tripserver_control_bootstrap.logTripServerControlServerJAPANUSAMoneyapp	MoneyHomeTripFormflight_introjapan-flight-intro.htmljapan_experiencejapan-experience.htmlusa_presentationusa2027-presentation.htmlusa_presentation_tvusa2027-presentation-tv.htmlusa_trip_tvusa2027-tv.html	usa_musicmediausa-presentationmusicusa-roadtrip-theme.mp3usa_music_part2usa-part2-theme.mp3zday-02djapan_experience_musicjapan-experiencejapan-theme.mp3japan_flight_musicjapan-flightflight-intro.mp3i@  backupsadmin_servertmpadmin_server_uploadszrestart_admin_server.cmdzadmin_restart.logzrestart_admin_server_helper.pyuploaded_filesTRIPSERVER_WATCHDOG_TASKTripServerAdminWatchdogztripserver_admin_watchdog.pyztripserver_watchdog.logztripserver_watchdog_state.txt$TRIPSERVER_WATCHDOG_INTERVAL_MINUTES5$TRIPSERVER_WATCHDOG_RESTART_COOLDOWN90TRIPSERVER_RESTART_TASKTripServerAdminRestartOncec                6   T ;'       g    \         P                  ;'       g    Rp\        P                  R8w  d   V#  \        P                  P                  V4      P                  4       p\        P                  P                  V4      pVR8X  d(   \        P                  P                  V4      '       d   V# V'       dH   \        P                  P                  VR4      p\        P                  P                  V4      '       d   V# R#   \         d    Tu # i ; i)aH  Return a no-console Python executable for Windows scheduled tasks when available.

Running the watchdog every few minutes with python.exe can flash a black console
window and steal focus. pythonw.exe runs the same script without a console.
On non-Windows or if pythonw.exe is not available, fall back to the normal
interpreter.
pythonntpythonw.exe)sys
executableosnamepathbasenamelowerdirnameexistsjoin	Exception)	preferredexebasefolder	candidates   &    0C:\TripServer\supervisor\pending_admin_server.pyget_pythonw_executablerL   ~   s     
1
1s~~
1
1C	ww$
ww$**,%= RWW^^C%8%8JV];Iww~~i((   
s+   A7D 5D 7D ?AD D DDrestartlabelu   לוג אתחול פאנלr?   noteuW   Restart helper, העלאת admin חדש, שחזור גיבוי ופעולות מחשב.controlu   לוג שרת בקרהuX   שרת הבקרה החיצוני שמפעיל ומעדכן את האדמין הראשי.control_bootstrapu!   לוג התקנת שרת בקרהu*   כתיבת והפעלת שרת הבקרה.watchdog   לוג Watchdogui   בדיקות Health, הפעלה אוטומטית של הפאנל, cooldown ושגיאות Task Scheduler.  TRIPSERVER_IMAGE_MAX_LONG_EDGE1920TRIPSERVER_IMAGE_TARGET_BYTESc              #   f   "   T F'  qP                  4       '       g   K  \        V4      x  K)  	  R # 5iN)stripint).0qs   & rK   	<genexpr>r^      s2       "M2~Q  CJ  CJ  CL&#a&&2~s   11TRIPSERVER_IMAGE_QUALITIESz88,86,84,82,80,78,TRIPSERVER_AUDIO_MAX_BYTESTRIPSERVER_AUDIO_MP3_BITRATE192k TRIPSERVER_AUDIO_MP3_SAMPLE_RATE44100zF.mp3,.wav,.m4a,.aac,.flac,.ogg,.opus,.wma,.webm,.mp4,audio/*,video/mp4z-.jpg,.jpeg,.png,.webp,.bmp,.tif,.tiff,image/*TRIPSERVER_ENABLE_POWER_ACTIONS10i  shutdownu
   כיבויrebootu   הפעלה מחדש   כיבוי מחשב   ריסטארט למחשבTRIPSERVER_ENABLE_WEBCAMTRIPSERVER_WEBCAM_INDEXTRIPSERVER_WEBCAM_WIDTH1280TRIPSERVER_WEBCAM_HEIGHT720TRIPSERVER_WEBCAM_FPS8TRIPSERVER_WEBCAM_JPEG_QUALITY78$TRIPSERVER_WEBCAM_MAX_STREAM_SECONDS1800      ?TRIPSERVER_ENABLE_CAMERA_AUDIO"TRIPSERVER_ENABLE_CAMERA_RECORDINGTRIPSERVER_FFMPEG_VIDEO_DEVICE TRIPSERVER_FFMPEG_AUDIO_DEVICE TRIPSERVER_CAMERA_RECORDINGS_DIRcamera_recordingsTRIPSERVER_CAMERA_RECORD_FPS15$TRIPSERVER_CAMERA_RECORD_MAX_SECONDS3600TRIPSERVER_CAMERA_AUDIO_BITRATE128kzcamera_setup.logzcamera_audio_stream.logcamera_live_hlszcamera_hls_stream.logu   התקןTRIPSERVER_OPENCV_PACKAGEzopencv-python)TRIPSERVER_OPENCV_INSTALL_TIMEOUT_SECONDS900%TRIPSERVER_CAMERA_AUTO_INSTALL_OPENCV,TRIPSERVER_CAMERA_AUTO_INSTALL_DELAY_SECONDS4zcamera_opencv_installed.okrunningF
started_atfinished_atoklast_messagemodeidleauto_requestedu'   לוג התקנת רכיבי מצלמהu@   התקנת OpenCV דרך pip ובדיקת רכיבי מצלמה.camera_setupu   לוג אודיו מצלמהuX   FFmpeg DirectShow, בחירת מיקרופון וניסיונות הפעלת אודיו.camera_audiou+   לוג שידור מצלמה מאוחד HLSui   FFmpeg DirectShow וידאו+אודיו בתהליך אחד, כדי למנוע נעילת התקני USB.
camera_hlsc                    T ;'       g    R P                  RR4      P                  R4      pV'       d   VP                  R4      '       d   R# VP                  R4       Uu. uF  q"'       g   K  VR9  g   K  VNK  	  ppV'       d)   \	        V4      \	        VP                  R4      4      8w  d   R# RP                  V4      # u upi )r}   \/	__MACOSX/N).z..)replacerZ   
startswithsplitlenrD   )raw_namerawppartss   &   rK   safe_zip_relpathr      s    >>r
"
"4
-
3
3C
8C#..--		#E1!Q0DQQEECJ#ciin"5588E? Fs    	C.C7Cc                 ~    \         P                  P                  T ;'       g    R 4      ^,          P                  4       # r}   )r=   r?   splitextrA   )filenames   &rK   file_extr      s+    77HNN+A.4466    c                      \        V R 4      ;_uu_ 4       pVP                  ^4      R8H  uuRRR4       #   + '       g   i     R# ; i  \         d     R# i ; i)rbs   NF)openreadrE   )r?   fhs   & rK   is_likely_jpeg_filer      sF    $771:0  s+   A	 5
A	 A	 A	 A	 	AAc           	         \        V R4      ;_uu_ 4       pVP                  R4      pRRR4       XP                  R4      '       d   R# \        ^ \	        ^ \        V4      ^,
          4      4       F0  pW#,          ^8X  g   K  W#^,           ,          ^,          ^8X  g   K/   R# 	  R#   + '       g   i     L; i  \         d     R# i ; i)zGFast MP3 sniffing: ID3 tag or MPEG audio frame sync near the beginning.r      Ns   ID3TF)r   r   r   rangemaxr   rE   )r?   r   dataidxs   &   rK   is_likely_mp3_filer      s    
$774=D ??6""C3t9q=12CyD d7md&:t%C 3    s?   B8 B%B8 	3B8 B8 B8 !B8 %B5	0B8 8CCc                  R   \         P                  P                  R 4      RRRR.p V  F|  pV'       g   K  \         P                  P	                  V4      V8X  d   \
        P                  ! V4      M(\         P                  P                  V4      '       d   TMRpV'       g   Kz  Vu # 	  R# )FFMPEG_PATHffmpegzC:\\ffmpeg\\bin\\ffmpeg.exez*C:\\Program Files\\ffmpeg\\bin\\ffmpeg.exez0C:\\Program Files (x86)\\ffmpeg\\bin\\ffmpeg.exeN)r=   environgetr?   r@   shutilwhichrC   )
candidatesrJ   founds      rK   find_ffmpeg_executabler     s    


}%&5;J  	+-77+;+;I+F)+SY'gigngnguguv  hA  hAZc  GK5L   r   c                      R RR\        \        4       4      R\        4       ;'       g    R/p  ^ RIpRV R &   V #   \         d
    RT R &    T # i ; i)pillowFr   ffmpeg_pathr}   NT)boolr   PILrE   )statusr   s     rK   media_engine_statusr     sc    x.D.F)GXnXpXvXvtvwF!x M  ! xM!s   	8 AAc                     \        V 4      p . ROp\        T 4      pT FA  pTR8  g   Y1R,          8X  d"   TR 8w  d   TR RT 2u # \        T4       R2u # TR,          pKC  	  R#   \         d    \        T 4      u # i ; i)B   z.1f z BN)r   KBMBGB)r[   rE   strfloat)numunitsvalueunits   &   rK   format_bytesr   '  s    #h $E#JE4<49,,0CKeC[$(NE
|2=NN 	  3xs   A% %A>=A>c                 
   \        V4       \        P                  P                  V 4      '       d    \        P                  P	                  V 4      M^ p ^ RIHpHp VP                  V 4      ;_uu_ 4       pVP                  4        RRR4       VP                  V 4      ;_uu_ 4       pVP                  V4      p\        VP                  4      pVP                  R9   g#   VP                  R8X  dc   RVP                  9   dR   VP                  R4      pVP!                  RVP                  R4      p	V	P#                  V4       V	P                  R4      pM"VP                  R8w  d   VP                  R4      pRp
VP                  '       d   \%        VP                  4      M^ p\&        '       d   V\&        8  d   \&        \)        V4      ,          p\%        ^\+        \-        VP                  ^ ,          V,          4      4      4      \%        ^\+        \-        VP                  ^,          V,          4      4      4      3pVP/                  WP0                  P2                  4      pRp
. p\4        ;'       g    RpV F  pV R	V R
2pVP7                  VR\+        V4      RRR7       VP9                  VV\        P                  P	                  V4      34       \        P                  P	                  V4      \:        8:  g   K   M	  V Uu. uF  pV^,          \:        8:  g   K  VNK  	  ppV'       d
   V^ ,          M\=        VR R7      pV F.  w  pppVV^,          8w  g   K   \        P>                  ! V4       K0  	  \        PB                  ! V^,          V4       \        P                  P	                  V4      pRRRV^ ,          RVRVRVR\        VP                  4      RV
R\%        ^ VV,
          4      /uuRRR4       #   + '       g   i     EL{; iu upi   \@         d     K  i ; i  + '       g   i     R# ; i  \D         d    \G        T 4      '       d|   TR
,           p\H        PJ                  ! T T4       \        PB                  ! TT4       \        P                  P	                  T4      pRRRRRTRTRRRRRRR\%        ^ TT,
          4      /u # \M        R4      h\L         d    h \@         d!   p\M        R\O        T4      ,           4      hRp?ii ; i) a  Create a real optimized JPG file; never writes a fake .jpg.

Smart behavior:
- Uses Pillow when installed.
- Applies EXIF orientation.
- Converts alpha/transparency to a white background.
- Downscales only when the long edge is larger than IMAGE_OPTIMIZER_MAX_LONG_EDGE.
- Uses progressive/optimized JPEG and a quality loop to reduce weight without aggressive damage.
- If Pillow is missing, accepts only true JPEG bytes and copies them safely.
)ImageImageOpsNRGBAPtransparencyRGBFTz.q.tmpJPEG)qualityoptimizeprogressivec                     V ^,          # )    )items   &rK   <lambda>.convert_or_copy_image_to_jpg.<locals>.<lambda>c  s    _cde_fr   keyr   optimized_jpgr   original_size
final_sizeoriginal_dimensionsfinal_dimensionsresizedsaved_bytescopied_real_jpeg_without_pillowsourceunknownzmPillow is not installed, so non-JPG images cannot be converted. Install Pillow with: py -m pip install pillowz%Image conversion/compression failed: )r   LA)   r   r   r   )X   T   P   )(ensure_parent_dirr=   r?   rC   getsizer   r   r   r   verifyexif_transposetuplesizer   infoconvertnewalpha_compositer   IMAGE_OPTIMIZER_MAX_LONG_EDGEr   r[   roundresize
ResamplingLANCZOSIMAGE_OPTIMIZER_QUALITIESsaveappendIMAGE_OPTIMIZER_TARGET_BYTESminremoverE   r   ImportErrorr   r   copy2
ValueErrorrepr)source_pathtarget_pathoriginal_namer   r   r   imgr   rgba
backgroundr   max_edgescalenew_sizetmp_candidates	qualitiesr   tmp_candidater   under_targetchosenr?   _sizer   
tmp_targetexcs   &&&                       rK   convert_or_copy_image_to_jpgr'  4  s    k"46GGNN;4O4OBGGOOK0UVMIN'ZZ$$JJL %ZZ$$))#.C"'/xx>)chh#o.TWT\T\B\{{6*"YYvtyy:NO
**40 ((/U"kk%(G(+s388}aH,,<Y1Y5hG3uSXXa[5-@'A#BCSCPUVYV^V^_`VadiViPjLkElmjj+;+;+C+CDN1AA\I$#.-r'$ ?Gtaef%%wrww}?]&^_77??=15QQ % .<g^TtAwJf?fDD^Lg(4\!_#nRf:gF(6$u6!9$		$ )7 JJvay+.5J6!9j%':"E#((O7s1mj&@A	O %$ %$$> h % G %$$b  J{++$v-JLLj1JJz;/5J98j%y"I5s1mj&@A	 	   I  J  	J  N@49LMMNs   !P6 4O7!P6 &C P""P"*CP"-BP"7P"?PP5P"P/A=P",
P6 7P		P6 P"P	P"P	P""P3	-P6 3P6 6BTT!
T,T-TTc                   \        V4       \        P                  P                  V 4      '       d    \        P                  P	                  V 4      M^ pV^ 8:  d   \        R4      hV\        8  d(   \        R\        V4       R\        \        4       24      h\        V 4      p\        4       pV'       Ed,   VR,           pVRRRRR	V R
RRR\        R\        V.p\        P                  ! VRR^R7      pVP                  ^ 8w  gJ   \        P                  P                  V4      '       d%   \        P                  P	                  V4      ^ 8:  dz    \        P                  P                  V4      '       d   \        P                  ! V4       \        RTP"                  ;'       g    TP$                  ;'       g    RR!R ,           4      h\        P                  P	                  V4      p	V'       d   V	\'        VR,          4      8  d    \        P                  ! V4       VR,           p
\(        P*                  ! W
4       \        P,                  ! W4       \        P                  P	                  V4      pRRRVRVR\/        ^ W;,
          4      RV/# \        P,                  ! Wa4       \        P                  P	                  V4      pRRRVRVR\/        ^ W;,
          4      RVR\        /# V'       dq   VR,           p
\(        P*                  ! W
4       \        P,                  ! W4       \        P                  P	                  V4      pRRRVRVR\/        ^ W;,
          4      RR/# \        R 4      h  \          d     ELi ; i  \          d     ELji ; i)"zStore uploaded audio as a real .mp3 file.

If FFmpeg exists, transcode supported audio/video containers to MP3.
If FFmpeg is missing, accept only files that are already real MP3 bytes, even if their extension is wrong.
u   קובץ האודיו ריק.u'   קובץ האודיו גדול מדי: u   . מגבלה: z.ffmpeg.tmp.mp3-y-hide_banner	-loglevelerror-i-vn-codec:a
libmp3lame-b:a-arTcapture_outputtexttimeoutz'FFmpeg failed to convert audio to MP3: zunknown errorNg?z	.copy.tmpr   )copied_existing_mp3_smaller_than_reencoder   r   r   r   converted_to_mp3_ffmpegbitratecopied_real_mp3_without_ffmpeg	not_foundzqFFmpeg is not installed, so this audio file cannot be converted to MP3. Install FFmpeg or upload a real MP3 file.P)r   r=   r?   rC   r   r  AUDIO_UPLOAD_MAX_BYTESr   r   r   AUDIO_MP3_BITRATEAUDIO_MP3_SAMPLE_RATE
subprocessrun
returncoder  rE   stderrstdoutr[   r   r  r   r   )r  r  r  r   source_is_mp3r   tmp_mp3cmdrA  converted_sizer%  r   s   &&&         rK   convert_or_copy_audio_to_mp3rI    s    k"46GGNN;4O4OBGGOOK0UVM899--B<P]C^B__mnz  |R  oS  nT  U  V  	V&{3M#%Fv 11+%(
 nnSD#N>>QbggnnW&=&=QXAY]^A^77>>'**IIg& F3::KvKvY\YcYcKvKvgvx}x~J  A  B  B1^c-$2F.GG		'" %{2JLL1JJz/5JGZgiu  xB  DQ  SV  WX  Zg  Zt  Su  w  AG  H  H


7(WW__[1
1?MS_akmz|  AB  DQ  D^  }_  ai  kq  s|  ~O  P  	P ;.
[-


:+WW__[1
8/=Zfhr  uB  DG  HI  KX  Ke  Df  hp  r}  ~  	~
  I  J  J9    s*   $M" 0M" M4 "M10M14NNc           
      X   \         P                  ! \        R R7       \        P                  ! R4      p\        V P                  ;'       g    R4      ;'       g    Rp\         P                  P                  \        RV R\         P                  ! 4        RV 24      pV P                  V4        \        W4      p\        YQV P                  ;'       g    R4      pRVR\         P                  P                  V4      R	\        V4      R
VRV/ \         P                  P                  V4      '       d   \         P                   ! V4       # #   \"         d     # i ; i   \         P                  P                  T4      '       d   \         P                   ! T4       i i   \"         d     i i ; i; i)Texist_ok%Y%m%d_%H%M%Saudio_uploadaudio__r}   r?   r  sha256backupr   )r=   makedirsADMIN_UPLOAD_TMP_DIRtimestrftimer	   r   r?   rD   getpidr  backup_existing_filerI  r   file_sha256rC   r  rE   )uploaded_filer  backup_groupstamp	safe_nametmp_pathbackup_pathr   s   &&&     rK   save_audio_upload_to_targetr`    s\   KK$t4MM/*E 6 6 H H.I[[^Iww||0F5'299;-qQZP[2\]Hx 	*;E,XMDZDZD`D`^`aVRWW__[-I8U`alUmow  zE  GN  PU  V	ww~~h''		(# ( 			ww~~h''		(# ( 		sC   .AE ;EEEF);FF)F&#F)%F&&F)c                 Z   \         P                  ! \        R R7       \        P                  ! R4      p\        V P                  ;'       g    R4      ;'       g    Rp\         P                  P                  \        RV R\         P                  ! 4        RV 24      p\         P                  P                  \        RV R\         P                  ! 4        R24      pV P                  V4        \        YgV P                  ;'       g    R4      p\        V4      p	. p
V F  p\         P                  P                  W4      p\        V4       \        W4      pVR,           p\        P                   ! W~4       \         P"                  ! W4       V
P%                  R	VR
VR\         P                  P'                  V4      R\        V4      RV/4       K  	  R\         P                  P'                  V4      RV	RV
RV/Wg3 FA  p \         P                  P)                  V4      '       d   \         P*                  ! V4       KA  KC  	  #   \,         d     KT  i ; i  Yg3 FS  p \         P                  P)                  T4      '       d   \         P*                  ! T4       KA  KC    \,         d     KQ  i ; i	  i ; i)TrK  rM  rN  audio_multi_rP  z_converted.mp3r}   r   relr?   r  rQ  rR  targetsr   )r=   rS  rT  rU  rV  r	   r   r?   rD   rW  r  rI  rY  r   rX  r   r  r   r  r   rC   r  rE   )rZ  base_folder	rel_pathsr[  r\  r]  
source_tmpconverted_tmpr   sharesultsrel_pathr  r_  r%  r   s   &&&&            rK   %save_audio_upload_to_multiple_targetsrl    s0   KK$t4MM/*E 6 6 H H.I[[^I2l5'299;-WXYbXc4deJGGLL!5eWAbiik]Zh7ijMz",ZH^H^HdHdbde-(!H'',,{=Kk*.{IK$v-JLL3JJz/NNE8V[&"''//ZeJfhpr}  J  sK  MU  Wb  c  d " 6#yRY[bdij,A77>>!$$IIaL % -  	 ,A77>>!$$IIaL % 	 -sI   ,I C.I :;H<<I
IJ*;JJ*J$	 J*#J$	$J*c                    V '       g   R # . pV P                  R4      '       d$   VP                  RV P                  R4       24       V P                  R4      e   V P                  R4      e   VP                  R\        V P                  R4      4       24       VP                  R\        V P                  R4      4       24       \        V P                  R4      ;'       g    ^ 4      pV^ 8  d   VP                  R\        V4       24       V P                  R	4      '       d$   VP                  R
V P                  R	4       24       V P                  R4      '       d$   VP                  RV P                  R4       24       V P                  R4      '       d$   VP                  RV P                  R4       24       V P                  R4      '       d$   VP                  RV P                  R4       24       V P                  R4      '       d$   VP                  RV P                  R4       24       RP	                  V4      # )r}   r   u   מצב עיבוד: r   r   u   גודל לפני: u   גודל אחרי: r   u   חיסכון: r   u   מידות מקור: r   u   מידות סופיות: r   u   איכות JPG: r9  u   ביטרייט MP3: r   zFFmpeg: 
)r   r  r   r[   rD   )r   linessaveds   &  rK   media_details_textrq    s   Eyy*599V+<*=>?yy!-%))L2I2U*<		/8R+S*TUV*<		,8O+P*QRSEIIm,11219LL>,u*=)>?@yy&'',UYY7L-M,NOPyy#$$0;M1N0OPQyy'		)(<'=>?yy+EIIi,@+ABCyyx		( 345699Ur   c                    V \         9  d   R # VP                  ;'       g    Rp\        V4      \        9  d   \	        R4      h\
        P                  P                  \        R,          RRR4      p\
        P                  ! VRR7       \
        P                  ! \        RR7       \        P                  ! R	4      p\
        P                  P                  \        R
V R\
        P                  ! 4        R\        V 4       24      pVP                  V4        \
        P                  P!                  V4      ^ 8:  d   \	        R4      h\
        P                  P!                  V4      \"        8  d   \	        R4      h\
        P                  P                  W0R,           4      p\%        VR4      p\'        WVV4      p\        R0,
           Fs  p	\
        P                  P                  W0V	,           4      p
\
        P                  P)                  V
4      '       g   KP   \%        V
R4       \
        P*                  ! V
4       Ku  	  R\
        P                  P                  RRRV R,           4      RVRVP/                  RR4      RVRVR\1        V4      R\
        P                  P!                  V4      / \
        P                  P)                  V4      '       d   \
        P*                  ! V4       # #   \,         d     EK0  i ; i  \,         d     # i ; i   \
        P                  P)                  T4      '       d   \
        P*                  ! T4       i i   \,         d     i i ; i; i)Nr}   uK   סיומת תמונה לא נתמכת. העלה JPG/JPEG/PNG/WebP/BMP/TIFF.r   r   r   imagesTrK  rM  
usa_image_rP  u   קובץ התמונה ריק.u&   קובץ התמונה גדול מדי..jpgUSA_images_singleUSA_images_single_old_extrc  r?   r   	optimizedrR  rQ  r  )USA_IMAGE_KEYSr   r   USA_IMAGE_EXTENSIONSr  r=   r?   rD   FOLDERSrS  rT  rU  rV  rW  r	   r  r   $USA_IMAGES_ZIP_MAX_SINGLE_FILE_BYTESrX  r'  rC   r  rE   r   rY  )	image_keyrZ  r  	image_dirr\  r^  r  r_  r   old_extold_paths   &&         rK   save_usa_presentation_imager    s   &!**00bM&::fggWU^W6H(SIKK	D)KK$t4MM/*Eww||0JugQryy{mSTUdenUoTp2qrHx 77??8$)<==77??8$'KKEFFggll9&.@A*;8KL,XMR+vh66Gww||I7/BCHww~~h''(3NOIIh' 7 rww||G-?9W]K]^`fhsu{  ~C  ~G  ~G  HN  P[  ~\  ^e  gl  nv  xC  EM  OZ  [f  Og  io  qs  qx  qx  q@  q@  AL  qM  N	ww~~h''		(# ( !   			ww~~h''		(# ( 		sh   C9L "K$6A0L ';K7$K4/L 3K44L 7LLM
;MMMMMMc                 h  a \         P                  P                  \        R ,          RRR4      o\         P                  ! SRR7       \
        P                  ! R4      p\         P                  P                  \        RV R24      p\         P                  P                  \        R	V 24      p\         P                  ! \        RR7       \         P                  ! VRR7       V P                  V4       \         P                  P                  V4      pV\        8  d&    \         P                  ! V4       \        R
V 24      h. p. p\        4       p \        P                   ! VR4      ;_uu_ 4       pVP#                  4        U	u. uF  qP%                  4       '       d   K  V	NK  	  p
p	\'        V
4      \(        8  d   \        R\'        V
4       24      h\+        R V
 4       4      pV\,        8  d   \        RV 24      hV
 EF  p	V	P.                  ;'       g    RP1                  RR4      p\         P                  P3                  V4      pV'       d/   VP5                  R4      '       g   VP5                  R4      '       d   K  V	P6                  \8        8  d   VP;                  VR,           4       K  \         P                  P=                  V4      w  rVP?                  4       pVPA                  4       pV\B        9  d   VP;                  VR,           4       EK  V\D        9  d   VP;                  VR,           4       EK=  W9   d   VP;                  VR,           4       EK^  VPG                  V4       \         P                  P                  W>V,           4      pVPI                  V	R4      ;_uu_ 4       p\I        VR4      ;_uu_ 4       p\J        PL                  ! VV4       RRR4       RRR4       \         P                  P                  SVR,           4      p \O        VR4       \Q        VVV4      p\B        R0,
           Ft  p\         P                  P                  SVV,           4      p\         P                  PS                  V4      '       g   KQ   \O        VR4       \         P                  ! V4       Kv  	  VP;                  VR,           R,           \U        VPW                  R^ 4      4      ,           R,           \U        VPW                  R ^ 4      4      ,           4       EK  	  RRR4        \         P                  ! V4        \J        PZ                  ! VRR"7       TP]                  4        TP]                  4        \_        T3R# l\D         4       4      pYVT3#   \         d     ELli ; iu up	i   + '       g   i     EL; i  + '       g   i     EL; i  \         d     EK  i ; i  \         d5   pTP;                  TR!,           \Y        T4      ,           4        Rp?EK  Rp?ii ; i  + '       g   i     EL; i  \         d     ELi ; i  \         d     ELi ; i   \         P                  ! T4       M  \         d     Mi ; i \J        PZ                  ! TRR"7       i   \         d     i i ; i; i)$r   r   r   rs  TrK  rM  usa_images_.zipusa_images_extract_zip_size_exceeded:rtoo_many_files:c              3   N   "   T F  p\        ^ VP                  4      x  K  	  R# 5ir   Nr   	file_sizer\   r  s   & rK   r^   3save_usa_presentation_images_zip.<locals>.<genexpr>Y       $NSDNN%;%;   #%zip_uncompressed_size_exceeded:r}   r   r   r   r       — גדול מדי    — סיומת לא נתמכתu"    — שם לא שייך למצגתu    — כפילות ב־ZIPwbNru  USA_images_zipUSA_images_zip_old_extu    — r   u    → r   u%    — לא הומר/נדחס ל־JPG: )ignore_errorsc              3      <"   T FZ  p\         P                  P                  \         P                  P                  SVR ,           4      4      '       d   KO  VR ,           x  K\  	  R# 5i)ru  N)r=   r?   rC   rD   )r\   r   r~  s   & rK   r^   r    sD     y^c277>>RTRYRYR^R^_hjmpvjvRwCx\S6\\^s   AA%A%)0r=   r?   rD   r{  rS  rU  rV  rT  r  r   USA_IMAGES_ZIP_MAX_BYTESr  rE   r  setzipfileZipFileinfolistis_dirr   USA_IMAGES_ZIP_MAX_FILESsum%USA_IMAGES_ZIP_MAX_UNCOMPRESSED_BYTESr   r   r@   r   r  r|  r  r   rZ   rA   rz  ry  addr   r   copyfileobjrX  r'  rC   r   r   r   rmtreesortsorted)rZ  r\  tmp_ziptmp_extractzip_sizeimportedskippedseenzfr  infostotal_uncompressedr   rH   stemextrg  r   desttargetr   r  r  r&  missingr~  s   &                        @rK    save_usa_presentation_images_zipr  >  s6   WU^W6H(SIKK	D)MM/*Eggll/;ugT1JKG'',,37J5'5RSKKK$t4KKd+wwww'H**	IIg -hZ899HG5D;__Wc**b&(kkmImd;;=TTmEI5z44 ?3u:,!?@@!$$N$N!N!$II #BCUBV!WXX MM//R88sCww''1ts33x7J7J;7W7W>>$HHNN4*@#@AGG,,T2	zz|iik22NN4*K#KL~-NN4*N#NO<NN4*E#EFWW\\+czB
WWT3''64
D3I3IT&&vt4 4J' i?^(1AB8VTRE#76(#B#B#%77<<	4'>#J77>>(33% 4X?W X "		( 3 $C OOD6MG$;l599UdfgKh>i$ils$s  wC  DI  DM  DM  NZ  \]  D^  w_  %_  `O  +f	IIg	MM+T: MMOLLNy^yyGg%%Q  		 J> 4J3I3I''' $- % $% ! ^NN4*Q#QTWX[T\#\]]^a +**j  		  			IIg 			MM+T: 		sT  V Y .X$V"V"#A0X$9X$X$%X$<D0X$,V;V'V;!/X$A3W"
"W,A*W"X$Y $X8 ;Y
 VV"X$'V82	V;;W	X$WW"WW""X!	-(X	X$X!	!X$$X5	/	Y 8YY
YYZ1Y54Z15Z Z1ZZ1Z Z1 Z.+Z1-Z..Z1TrK  rs  c                     R V P                   R&   RV P                   R&   RV P                   R&   V P                   P                  RR4       V P                   P                  RR4       V # )	z7no-store, no-cache, must-revalidate, max-age=0, privateCache-Controlno-cachePragmarh   ExpiresETagNzLast-Modified)headerspopresponses   &rK   no_cache_responser    sc    (aH_%!+HX"%HY&$/Or   c                     \        V 4      # rY   )r  r  s   &rK   add_global_no_cache_headersr    s    X&&r   c           	           \        \        WR ^ R7      4      p\        V4      #   \         d    \        \        Y4      4      p L,i ; i)F)conditionalmax_age)r   r   	TypeErrorr  )	directory	file_namer  s   && rK   serve_file_no_cacher    sN    L !4YW\fg!hi X&&  L !4Y!JKLs   $ AAc                   a ^ RI pVP                  4       p\        V R4      ;_uu_ 4       o\        V3R lR4       F  pVP	                  V4       K  	  RRR4       VP                  4       #   + '       g   i     TP                  4       # ; i)r   Nr   c                  &   < S P                  R4      # )r      )r   )r   s   rK   r   file_sha256.<locals>.<lambda>  s    "''+"6r   r   )hashlibrQ  r   iterupdate	hexdigest)r?   r  hchunkr   s   &   @rK   rY  rY    sh    A	dD		R6<EHHUO = 
 ;;= 
	 ;;=s   )A++B
	c                     \         P                  P                  V 4      pV'       d   \         P                  ! VR R7       R# R# )TrK  N)r=   r?   rB   rS  )r?   parents   & rK   r   r     s*    WW__T"F
FT* r   c                 V   \         P                  P                  V 4      '       d&   \         P                  P                  V 4      '       g   R # \        P
                  ! R4      p\        \        V4      4      ;'       g    Rp\        \         P                  P                  V 4      4      ;'       g    Rp\         P                  P                  \        V4      p\         P                  ! VRR7       \         P                  P                  WR RV 24      p\        P                  ! W4       V# )NrM  uploadsfileTrK  rP  )r=   r?   rC   isfilerU  rV  r	   r   r@   rD   UPLOAD_BACKUP_DIRrS  r   r  )r  r[  r\  
safe_groupr]  
backup_dirr_  s   &&     rK   rX  rX    s    77>>+&&bggnn[.I.IMM/*E \!23@@yJ 0 0 =>HH&I/<JKK
T*'',,zWAi[+ABK
LL*r   c           
        \        V4       \        P                  ! \        RR7       \        P
                  ! R4      p\        \        P                  P                  V4      4      ;'       g    Rp\        P                  P                  \        RV R\        P                  ! 4        RV 24      p V P                  V4       \        P                  P                  V4      pV^ 8:  d   \        R4      h\        W4      p\        P                  ! WQ4       \        P                  P                  V4      pW8w  d   \!        RV R	V 24      hR
VRVRVR\#        V4      / \        P                  P%                  V4      '       d   \        P&                  ! V4       # #   \(         d     # i ; i   \        P                  P%                  T4      '       d   \        P&                  ! T4       i i   \(         d     i i ; i; i)zPSave uploaded file atomically: tmp -> validate size -> backup old -> os.replace.TrK  rM  z
upload.bintmp_rP  uploaded file is emptyzsize mismatch after save: tmp=z, final=r?   r  rR  rQ  )r   r=   rS  rT  rU  rV  r	   r?   r@   rD   rW  r  r   r  rX  r   IOErrorrY  rC   r  rE   )	rZ  r  r[  r\  safe_targetr^  r  r_  r   s	   &&&      rK   atomic_save_uploadr    s   k"KK$t4MM/*E!"''"2"2;"?@PPLKww||0DqQ{m2\]H8$wwx(19566*;E


8)WW__[1
:4&UVVVZ;PXZefqZrs	ww~~h''		(# ( 			ww~~h''		(# ( 		sC   1B+F+ ;FF('F(+G;-;G*(G;*G85G;7G88G;c                 V   \         P                  P                  V R 4      p\         P                  P                  V4      '       d   R # \         P                  ! V 4       Uu. uF+  q"P                  4       P                  R4      '       g   K)  VNK-  	  ppV'       d
   V^ ,          # R# u upi )
index.htmlN).html.htm)r=   r?   rD   rC   listdirrA   endswith)folder_path
index_pathf
html_filess   &   rK   find_html_filer    su    k<8J	ww~~j!!ZZ4^4	8J8JK\8]!!4J^!} _s    &B&B&c                 p   0 Rmp\         P                  ! V 4       F  p\         P                  P                  W4      p\         P                  P	                  V4      '       g   KI  VP                  4       P                  4       V9   g   Kn   \         P                  ! V4       K  	  R#   \         d     K  i ; i)htmlN>   htmr  indexr   download	index.htm)	r=   r  r?   rD   r  rA   rZ   r  rE   )r  wrong_namesr>   	full_paths   &   rK   clean_wrong_main_filesr    s~    NK

;'GGLL3	ww~~i((::<;.		)$ (  s   
B&&B54B5c                 z   \         V ,          p\        P                  ! VR R7       VP                  ;'       g    Rp\	        V4      pV \
        9   d   \        V4       RpM+T;'       g"    R\        \        P                  ! 4       4       2p\        P                  P                  W%4      p\        WV  R2R7      pWW3# )TrK  r}   r  upload__mainr[  )r{  r=   rS  r   r	   APP_FOLDERSr  r[   rU  r?   rD   r  )rI   rZ  r  original_filenamer]  r   r  results   &&      rK   save_uploaded_filer  
  s    &/KKKd+%..44" 12I{+<<'#diik*:); <'',,{5KF8SXIYZFr   c                     V \         9  d   R # \        R,          p\        P                  ! VRR7       \         V ,          p\        P                  P                  W#4      p\        WRR7      pW53# )Nr   TrK  JAPAN_presentationsr  )JAPAN_PRESENTATION_FILESr{  r=   rS  r?   rD   r  )presentation_keyrZ  japan_folderr   r  r  s   &&    rK   save_japan_presentationr    sY    777#LKKt,'(89H'',,|6KI^_Fr   c                     V \         9  d   R # \        R,          p\        P                  ! VRR7       \         V ,          p\        P                  P                  W#4      p\        WRR7      pW53# )Nr   TrK  USA_presentationsr  )USA_PRESENTATION_FILESr{  r=   rS  r?   rD   r  )r  rZ  
usa_folderr   r  r  s   &&    rK   save_usa_presentationr	  '  sX    55JKK
T*%&67H'',,z4KI\]Fr   c                     V \         9  d   R # \        R,          p\         V ,          p\        P                  P	                  W#4      p\        WRR7      pW53# )Nr   	USA_musicr  )USA_MUSIC_FILESr{  r=   r?   rD   r`  )	music_keyrZ  r  rk  r  r  s   &&    rK   save_usa_musicr  2  sH    'Jy)HZ2I(P[\Fr   c                     V \         9  d   R # \         V ,          p\        P                  P                  \        R,          V4      p\        WRR7      pW$3# )Nr   USA_extra_htmlr  )USA_EXTRA_HTML_FILESr=   r?   rD   r{  r  )	extra_keyrZ  r   r  r  s   &&   rK   save_usa_extra_htmlr  =  sF    ,,#I.H'',,wu~x8KIYZFr   c                 :   \         P                  ! \        R R7       \        P                  ! R4      p\         P
                  P                  \        RV R\         P                  ! 4        24      pV P                  V4        \         P
                  P                  V4      pV^ 8:  d   \        R4      h\        V4      p. pV F  p	\         P
                  P                  W4      p
\        V
4       \        W4      pV
R,           p\        P                  ! W\4       \         P                   ! W4       VP#                  RV	RV
R	\         P
                  P                  V
4      R
\        V
4      RV/4       K  	  R	VR
VRV/ \         P
                  P%                  V4      '       d   \         P&                  ! V4       # #   \(         d     # i ; i   \         P
                  P%                  T4      '       d   \         P&                  ! T4       i i   \(         d     i i ; i; i)TrK  rM  multi_upload_rP  r  r   rc  r?   r  rQ  rR  rd  )r=   rS  rT  rU  rV  r?   rD   rW  r  r   r  rY  r   rX  r   r  r   r  rC   r  rE   )rZ  re  rf  r[  r\  r^  r  ri  rj  rk  r  r_  r%  s   &&&&         rK   save_file_to_multiple_targetsr  F  s   KK$t4MM/*Eww||0M%"))+2WXHx wwx(19566(#!H'',,{=Kk*.{IK$v-JLL.JJz/NNE8V[&"''//ZeJfhpr}  J  sK  MU  Wb  c  d " hY@	ww~~h''		(# ( 			ww~~h''		(# ( 		sC   C9G
 <;F99GG
H;H	H	HHHHc                 d    V \         9  d   R # \        V\        R,          \         V ,          R4      # )Nr   JAPAN_music)JAPAN_MUSIC_TARGETSrl  r{  )r  rZ  s   &&rK   save_japan_musicr  b  s2    ++0@PRefoRpr  A  Ar   c                    \        V 4      pV'       g   R # VP                  4       pRpW29   d&   VP                  V4      \        V4      ,           pWR  # VP	                  R4      '       d   V\        R4      R  # VP	                  R4      '       d   V\        R4      R  # RpWR9   d&   VP                  V4      \        V4      ,           pWR  # R # )Nz/media/images/media/images/zimages/z/images/)r   rA   r  r   r   )r   saferA   markerr   marker2s   &     rK   normalize_japan_image_relr   h  s    H%DJJLEFkk&!CK/Dz((C()**	""C	NO$$Gkk'"S\1Dzr   c                 	   \         P                  P                  \        R ,          RR4      p\         P                  ! VRR7       \
        P                  ! R4      p\         P                  P                  \        RV R24      p\         P                  ! \        RR7       V P                  V4       . . . rep \         P                  P                  V4      \        8  d,   \        R\         P                  P                  V4       24      h\        P                  ! VR	4      ;_uu_ 4       pVP                  4        Uu. uF  qP                  4       '       d   K  VNK  	  p	p\!        V	4      \"        8  d   \        R
\!        V	4       24      h\%        R V	 4       4      p
V
\&        8  d   \        RV
 24      hV	 EF  p\)        VP*                  4      p\         P                  P-                  VP*                  ;'       g    RP/                  RR4      4      pV'       g   VP1                  VR,           4       K~  VP2                  \4        8  d   VP1                  VR,           4       K  \7        V4      \8        9  d   VP1                  VR,           4       K  \;        V4      '       g   VP1                  VR,           4       EK  \         P                  P                  ! V.VP=                  R4      O5!  p\?        V4       \         P                  PA                  V4      '       d   VP1                  V4       \C        VR4       VR,           pVPE                  VR	4      ;_uu_ 4       p\E        VR4      ;_uu_ 4       p\F        PH                  ! VV4       RRR4       RRR4       \         P.                  ! W4       VP1                  V4       EK  	  RRR4        \         PJ                  ! V4       \O        T4      \O        T4      \O        T4      3# u upi   + '       g   i     L; i  + '       g   i     L; i  + '       g   i     Lr; i  \L         d     Lki ; i   \         PJ                  ! T4       i   \L         d     i i ; i; i)r   r   rs  TrK  rM  japan_images_r  r  r  r  c              3   N   "   T F  p\        ^ VP                  4      x  K  	  R# 5ir  r  r  s   & rK   r^   (save_japan_images_zip.<locals>.<genexpr>  r  r  r  r}   r   r   u,    — לא בתיקיית images/media/imagesr  r      — נתיב לא בטוחJAPAN_images_zipr   r  N)(r=   r?   rD   r{  rS  rU  rV  rT  r  r   JAPAN_IMAGES_ZIP_MAX_BYTESr  r  r  r  r  r   JAPAN_IMAGES_ZIP_MAX_FILESr  'JAPAN_IMAGES_ZIP_MAX_UNCOMPRESSED_BYTESr   r   r@   r   r  r  &JAPAN_IMAGES_ZIP_MAX_SINGLE_FILE_BYTESr   JAPAN_IMAGE_EXTENSIONSr   r   r   rC   rX  r   r   r  r  rE   r  )rZ  
image_rootr\  r  r  r  overwrittenr  r  r  r  rc  rH   r  r%  r   r  s   &                rK   save_japan_images_zipr.  |  s=   gg.BJKK
T*MM/*Eggll/=t1LMGKK$t4w%'R{H(77??7#&@@1"''//'2J1KLMM__Wc**b&(kkmImd;;=TTmEI5z66 ?3u:,!?@@!$$N$N!N!$KK #BCUBV!WXX/>ww'')<)<"(E(EdC(PQNN4*X#XY>>$JJNN3)?#?@C=(>>NN3)J#JK',,NN4*G#GHjB399S>B!&)77>>&))&&s+(1CD#f_
WWT3''64
D3I3IT&&vt4 4J'

:.$3  +D	IIg (VG_f[.AAAK J8 4J3I''; +*H  			IIg 		s   6A2Q (P2;PPBP2<P2EP2P4PP4P2Q Q P2PPP/*P22Q	=Q QQR Q/.R /Q=:R <Q==R c                 t   \        V4      pV'       g   R # VP                  4       pV R8X  dC   VP                  R4      '       d
   VR,          # VR	9   g   VP                  R4      '       d   V# R # V R8X  dC   VP                  R4      '       d
   VR,          # VR
9   g   VP                  R4      '       d   V# R # R # )Nr   zusa/:   NNzmedia/usa-presentation/r   zjapan/:   NNzmedia/>   r   r   r   >   r  r&   r   r   )r   rA   r   )tripr   r  rA   s   &&  rK   normalize_trip_package_relr3    s    H%DJJLEu}F##8O ddhmhxhx  zS  iT  iTKwH%%8Oiimrm}m}  G  nH  nHKr   c                 	   V R9  d   R# \         V ,          p\        P                  ! VRR7       \        P                  ! R4      p\        P
                  P                  \        V P                  4        RV R24      p\        P                  ! \        RR7       VP                  V4       . . . rvp \        P
                  P                  V4      \        8  d,   \        R\        P
                  P                  V4       24      h\        P                  ! VR4      ;_uu_ 4       pVP                  4        U	u. uF  qP!                  4       '       d   K  V	NK  	  p
p	\#        V
4      \$        8  d   \        R	\#        V
4       24      h\'        R
 V
 4       4      pV\(        8  d   \        RV 24      hV
 EF  p	\+        W	P,                  4      p\        P
                  P/                  V	P,                  ;'       g    RP1                  RR4      4      pV'       g"   VP3                  VR,           V ,           4       K  V	P4                  \6        8  d   VP3                  VR,           4       K  \9        V4      pV\:        9  d   VP3                  VR,           4       K  \=        V4      '       g   VP3                  VR,           4       EK  \        P
                  P                  ! V.VP?                  R4      O5!  p\A        V4       \        P
                  PC                  V4      '       d    VP3                  V4       \E        W R24       VR,           pVPG                  V	R4      ;_uu_ 4       p\G        VR4      ;_uu_ 4       p\H        PJ                  ! VV4       RRR4       RRR4       \        P0                  ! VV4       VP3                  V4       EK  	  RRR4        \        PL                  ! V4       \Q        T4      \Q        T4      \Q        T4      3# u up	i   + '       g   i     L; i  + '       g   i     L; i  + '       g   i     Lr; i  \N         d     Lki ; i   \        PL                  ! T4       i   \N         d     i i ; i; i)r   NTrK  rM  	_package_r  r  r  r  c              3   N   "   T F  p\        ^ VP                  4      x  K  	  R# 5ir  r  r  s   & rK   r^   (save_trip_package_zip.<locals>.<genexpr>  r  r  r  r}   r   r   u     — לא שייך לחבילת r  r  r%  _package_zipr   r     r   r   ))r{  r=   rS  rU  rV  r?   rD   rT  rA   r  r   TRIP_PACKAGE_ZIP_MAX_BYTESr  r  r  r  r  r   TRIP_PACKAGE_ZIP_MAX_FILESr  'TRIP_PACKAGE_ZIP_MAX_UNCOMPRESSED_BYTESr3  r   r@   r   r  r  &TRIP_PACKAGE_ZIP_MAX_SINGLE_FILE_BYTESr   TRIP_PACKAGE_EXTENSIONSr   r   r   rC   rX  r   r   r  r  rE   r  )r2  rZ  re  r\  r  r  r  r-  r  r  r  r  rc  rH   r  r  r%  r   r  s   &&                 rK   save_trip_package_zipr?    sR   ##$-KKKd+MM/*Eggll/DJJL>5'QU1VWGKK$t4w%'R{H(77??7#&@@1"''//'2J1KLMM__Wc**b&(kkmImd;;=TTmEI5z66 ?3u:,!?@@!$$N$N!N!$KK #BCUBV!WXX0}}Eww'')<)<"(E(EdC(PQNN4*L#Lt#ST>>$JJNN3)?#?@sm55NN3)J#JK',,NN4*G#GHkCCIIcNC!&)77>>&))&&s+(61FG#f_
WWT3''64
D3I3IT&&vt4 4J'

:v.$3  +D	IIg (VG_f[.AAAK J8 4J3I''; +*H  			IIg 		s   0A2Q "P85PPB=P8EP8$P%9PP%5P8Q Q P8P"P%%P50P88Q	Q QQRQ54R5R RRRc                    \         P                  P                  V 4      pR V RV/pV'       d   \         P                  P                  V 4      '       d    \         P                  P	                  V 4      VR&   \
        P                  ! R\
        P                  ! \         P                  P                  V 4      4      4      VR&   \        V 4      R,          VR&   V# V#   \         d   p\        T4      TR&    Rp?T# Rp?ii ; i)	r?   rC   r  r
   mtime:N   NrQ  r,  N)r=   r?   rC   r  r   rU  rV  	localtimegetmtimerY  rE   r  )r?   rC   r   r&  s   &   rK   describe_pathrE    s    WW^^D!FD(F+D"''..&&	&77??40DL MM*=t~~bggN^N^_cNd?efDM(.s3DN K4K  	& IDMK	&s   BC C>%C99C>c                     ^ p\         P                  P                  V 4      '       g   ^ # \         P                  ! V 4       F.  w  r4pV F"  pVe   \	        V4      V9   g   K  V^,          pK$  	  K0  	  V# )r   )r=   r?   isdirwalkr   )root
extensionstotaldirpathrP  	filenamesr>   s   &&     rK   count_filesrN  	  s_    E77==!#ID!Xd^z%A
  "/ Lr   c                    . p\         P                  P                  V 4      '       g   V# \         P                  ! V 4       F  w  r4pV Fx  pVe   \	        V4      V9   g   K  \         P                  P                  W64      p\         P                  P                  Wp4      P                  RR4      pVP                  V4       Kz  	  K  	  \        VR R7      # )Nr   r   c                 "    V P                  4       # rY   rA   xs   &rK   r   %list_relative_files.<locals>.<lambda>  s
    qwwyr   r   )
r=   r?   rG  rH  r   rD   relpathr   r  r  )	rI  rJ  filesrL  rP  rM  r>   fullrc  s	   &&       rK   list_relative_filesrX    s    E77==!#ID!Xd^z%Aww||G2ggood199$DS!	  "/ %011r   c                    \        T ;'       g    R 4      P                  4       P                  RR4      pVP                  R^4      ^ ,          P                  R^4      ^ ,          pVP	                  R4      '       d   VR,          pK"  V# )r}   r   r   ?#z./:r   NN)r   rZ   r   r   r   )r?   r   s   & rK   normalize_web_pathr\     sm    

O!!#++D#6EKKQ"((a03E


4
 
 b	Lr   c                
   T ;'       g,    \         P                  P                  \        R,          R4      p \         P                  P                  \        R,          RR4      p\	        V\
        4      pRV R\         P                  P                  V 4      R\        V4      R^ R	^ R
^ R^ R^ R^ R^ R^ R^ R. R. R. /pVR,          '       g   VR,          P                  R4       V#  \        V RRRR7      ;_uu_ 4       pVP                  4       pRRR4       \        P                  ! RX\        P                  4       Uu. uFH  qwP!                  ^4      P#                  4       '       g   K)  TP!                  ^4      P#                  4       NKJ  	  ppT'       gy   \        P                  ! RT\        P                  4       Uu. uFH  qwP!                  ^4      P#                  4       '       g   K)  TP!                  ^4      P#                  4       NKJ  	  pp. p	. p
. p. pT F  p\%        T4      pTP'                  R4      '       d    T	P                  T\        R4      R 4       KD  TP'                  R4      '       d   T
P                  T4       Kn  TP'                  R4      '       g   TP'                  R 4      '       d   TP                  T4       K  TP                  T4       K  	  \)        \+        T	4      R! R"7      pT Uu/ uF  pTP-                  4       TbK  	  ppT Uu0 uF  pTP-                  4       kK  	  ppT Uu. uF  pTP-                  4       T9  g   K  TNK  	  ppT Uu. uF  pTP-                  4       T9  g   K  TNK  	  ppTP/                  R\        T4      R	\        T	4      R
\        T
4      R\        T4      R\        T4      R\        T4      R\        T4      R\        T4      R\        \        P0                  ! R#T4      4      RTR$,          RTR$,          /4       TR,          ^ 8X  d   TR,          P                  R%4       TR,          '       d   TR,          P                  R&4       TR,          '       d   TR,          P                  R'4       T#   + '       g   i     EL; i  \         d5   pTR,          P                  R\        T4      ,           4       Tu Rp?# Rp?ii ; iu upi u upi u upi u upi u upi u upi )(zQCount images that Japan experience actually uses, not just files in media/images.r   r   r   rs  presentation_pathpresentation_existsfolder_imagesimage_slidesexternal_image_usesembedded_image_usesremote_image_usesother_src_usesunique_external_imagesmissing_external_imagesunused_folder_imageschapter_slidesnotesmissing_external_listunused_folder_listuy   קובץ המצגת japan-experience.html לא נמצא, לכן נספרו רק קבצים בתיקיית התמונות.r  utf-8ignoreencodingerrorsNu8   לא ניתן לקרוא את קובץ מצגת יפן: z"["\']src["\']\s*:\s*(["\'])(.*?)\1z\bsrc\s*:\s*(["\'])(.*?)\1r  z
data:imagezhttp://zhttps://c                 "    V P                  4       # rY   rQ  rR  s   &rK   r   3analyze_japan_presentation_images.<locals>.<lambda>\  s
    !'')r   r   z["\']chapter["\']\s*:\s*true:N(   Nu\   לא נמצאו src בשקפי מצגת יפן. ייתכן שמבנה המצגת השתנה.uc   יש תמונות שהמצגת מבקשת אבל אינן קיימות בתיקיית media/images.uQ   יש תמונות בתיקייה שאינן בשימוש במצגת הפעילה.)r=   r?   rD   r{  rX  r+  r  r   r  r   r   rE   r  refinditerSgrouprZ   r\  r   r  r  rA   r  findall)r^  r,  folder_filesr  r   	html_textr&  mrefsexternalembeddedremoteotherrefcleanunique_externalr  folder_lower
used_lowerrc  r  unuseds   &                     rK   !analyze_japan_presentation_imagesr  (  s@   )ddRWW\\'':JLc-dgg.BJ&z3IJL.rww~~.?@\*qqQ! !!1!bF" '((w   [  	\#S78LLPR	I M )+4Y[dfhfjfj(k  C(k1ovovwxoyoo  pBAGGAJ(kD  C,.KK8UW`bdbfbf,g~,gqkrkrstkuk{k{k}"
  ",g~HHFE"3'O,,OOE#o"6"789l++OOC i((E,<,<Z,H,HMM#LL  S]0CDO*67,QAGGIqL,L7%45_!'')_J5-QosL1PssoGQ)K\cSYY[
-Jcc\FK
MMD	s8}s8}S[#e* #o"6!3w<F#bjj)H)TUfSk  n"w}~'((w   E  	F$%%wrsMe MLL wY\`ad\eef C~$ 85QKsx   "R# 9R
R# :&S%%#S%:&S*%#S*3S/S42S9S9S>6S>R 	R#  R# #S".)SS"S"c                  :   \        4       p R V P                  R^ 4      RV P                  R^ 4      RV P                  R^ 4      RV P                  R^ 4      RV P                  R^ 4      RV P                  R^ 4      R	V P                  R	^ 4      R
V P                  R
R4      /# )image_slides_totalra  external_files_usedrb  embedded_imagesrc  r`  rg  rh  ri  r_  F)r  r   )usages    rK   compact_japan_usage_for_healthr  x  s    -/Eeii:uyy)>B599%:A>?A6!599-F#J		*@! D%))$4a8uyy)>F	 	r   c                  D	  a . oV3R  lp V ! R\         4       V ! R\        P                  P                  \        R,          R4      4       V ! R\        P                  P                  \        R,          R4      4       V ! R\        P                  P                  \        R,          R4      4       V ! R	\        P                  P                  \        R,          R
RRR4      4       V ! R\        P                  P                  \        R,          R
RRR4      4       V ! R\        P                  P                  \        R,          R4      4       V ! R\        P                  P                  \        R,          R4      4       V ! R\        P                  P                  \        R,          R4      4       V ! R\        P                  P                  \        R,          R4      4       V ! R\        P                  P                  \        R,          R
RRR4      4       V ! R\        P                  P                  \        R,          R
RRR4      4       V ! R\        P                  P                  \        R,          R4      4       V ! R \        P                  P                  \        R!,          R4      4       V ! R"\        P                  P                  \        R#,          R4      4       \        \        P                  P                  \        R,          R
RR$4      \        4      p\        4       pVR%,          pVR&,          ;'       d    VR',          ^ 8H  pV'       d   R(MR)pVR*,           R+VR,,           R-V R.VR/,           R0VR',           2	p\        R1R27      pVP                  R34      '       d   R4MR5pR6p	VR',          '       d-   R6P                  R7 VR8,          R9,           4       4      p
R:V
 R;2p	R6pVR/,          '       d^   R6P                  R< VR=,          R9,           4       4      pR6pVR/,          ^8  d   R>VR/,          ^,
           R?2pR@VR/,           RAV RBV RC2pRDV REVRF,           RGV RHV RIV RJ\        P                  ! \        4       RKV RLV	 V RMR6P                  S4       RN2# )Oc                   < \        V4      pVP                  R 4      '       d   RMRpVP                  R 4      '       d   RV9   d   VP                  R^ 4      R MRpVP                  RR4      pVP                  RR4      pSP                  R\        P                  ! V 4       R	V R	V R	\        P                  ! V4       R	\        P                  ! V4       R
\        P                  ! V4       R24       R# )rC   u   ✅ קייםu
   ❌ חסרr  r`   u   —rA  rQ  z<tr><td>	</td><td>z</td><td><code>z</code></td></tr>N)rE  r   r  html_libescape)rN   r?   r  r   r  rA  ri  rowss   &&     rK   r   render_admin_status.<locals>.add  s   T"#'88H#5#5<-1XXh-?-?FdN$((61%a(X]%(hhx'hxu56ixyQUPVV_`h`o`opu`v_w  xA  BJ  BQ  BQ  RU  BV  AW  Wf  go  gv  gv  w{  g|  f}  }N  O  	Pr   u   פאנל פעילu   טיול יפן ראשיr   r  u   פתיח טיסה יפןr   u   מצגת יפןr   u   מוזיקת מצגת יפןr   r%   r   r&   u   מוזיקת פתיח יפןr(   r)   u   טיול ארה״ב ראשיr   u   טיול ארה״ב TVr   u   מצגת ארה״בr   u   מצגת ארה״ב TVr   u   שיר ארה״ב חלק 1r   r    u   שיר ארה״ב חלק 2r"   u   תקציב טיוליםr   u   תקציב משפחתיr   u   טופס פתיחת טיולr   rs  r`  r_  rg  u   ✅ תקיןu   ⚠️ לבדיקהrb  u    קבצים חיצוניים + rc  u#    מוטמעות · בתיקייה: u    · לא בשימוש: rh  u    · חסרות: Finclude_logtask_installedONOFFr}   c              3   V   "   T F  pR \         P                  ! V4       R2x  K!  	  R# 5iz
<li><code>z</code></li>Nr  r  r\   rS  s   & rK   r^   &render_admin_status.<locals>.<genexpr>  s1        B  XARS*X__Q-?,@ M  XA   ')rk  :N   NuF   <div class='warn'><b>תמונות חסרות למצגת יפן</b><ul>z</ul></div>c              3   V   "   T F  pR \         P                  ! V4       R2x  K!  	  R# 5ir  r  r  s   & rK   r^   r    s&     }V|QRHOOA,>+?|LV|r  rl  u   <p>ועוד u+    קבצים שלא מוצגים כאן.</p>ue   <details class='details'><summary>תמונות בתיקיית יפן שלא בשימוש במצגת (z)</summary><ul>z</ul>z
</details>u  
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>סטטוס TripServer</title>
<style>
body{margin:0;background:#0f172a;color:white;font-family:Arial;padding:24px}.wrap{max-width:1180px;margin:auto}a{color:#93c5fd}table{width:100%;border-collapse:collapse;background:#1e293b;border-radius:18px;overflow:hidden}th,td{border-bottom:1px solid #334155;padding:10px;text-align:right;vertical-align:top}th{background:#111827;color:#bfdbfe}code{direction:ltr;display:block;white-space:normal;color:#fde68a}.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:14px;margin:18px 0}.card{background:#1e293b;border:1px solid #334155;border-radius:18px;padding:16px}.num{font-size:30px;font-weight:900;color:#fde68a}
.small{color:#cbd5e1;font-size:13px;line-height:1.5;margin-top:6px}.warn{background:rgba(127,29,29,.38);border:1px solid rgba(248,113,113,.35);color:#fecaca;border-radius:16px;padding:14px;margin:14px 0}.details{background:#111827;border:1px solid #334155;border-radius:16px;padding:14px;margin:14px 0;color:#cbd5e1}summary{cursor:pointer;font-weight:900;color:#fde68a}ul{margin:10px 0 0}
</style></head><body><div class="wrap"><a href="/admin">⬅ חזרה לפאנל</a><h1>סטטוס קבצים פעילים</h1><p>כאן רואים בפועל מה מותקן כרגע ב־C:\TripServer, כולל גודל, תאריך שינוי ו־SHA קצר. זה נועד למנוע מצב של “העליתי אבל אני רואה גרסה ישנה”.</p><div class="cards"><div class="card"><div>תמונות מצגת ארה״ב</div><div class="num">u   </div><div class="small">כרטיסיות העלאה מסונכרנות לשקפי ארה״ב.</div></div><div class="card"><div>מצגת יפן — תמונות בשימוש בפועל</div><div class="num">ra  z</div><div class="small">    · ug   </div></div><div class="card"><div>קבצים בתיקיית תמונות יפן</div><div class="num">u   </div><div class="small">זה מספר קבצים בתיקייה, לא מספר התמונות שהמצגת משתמשת בהן.</div></div><div class="card"><div>גרסת פאנל</div><div>zB</div></div><div class="card"><div>Watchdog</div><div class="num">uy   </div><div class="small">משימה מתוזמנת חיצונית לשמירת הפאנל באוויר.</div></div></div>u   <table><thead><tr><th>רכיב</th><th>מצב</th><th>גודל bytes</th><th>עודכן</th><th>SHA16</th><th>נתיב</th></tr></thead><tbody>z%</tbody></table></div></body></html>
)ADMIN_SERVER_PATHr=   r?   rD   r{  rN  rz  r  watchdog_statusr   r  r  ADMIN_PANEL_VERSION)r  usa_img_countjapan_usagejapan_img_countjapan_usage_okjapan_usage_badgejapan_usage_detailswatchdog_infowatchdog_labelmissing_htmlmissing_itemsunused_htmlunused_itemsmorer  s                 @rK   render_admin_statusr    s   DP ./"BGGLL1A<$PQ"BGGLL1AC\$]^277<<(8:QRS&WW5EwPbdkm~(  A&WW5EwP^`gi{(|}&WU^\(RS "'',,wu~?P"QRrww||GEN<WXY "'',,wu~?]"^_$bggll75>7L^`g  jB  'C  D$bggll75>7L^`gi~&  A!277<<
0C\#RS!277<<0Dl#ST&WZ5H,(WXWU^WFXZb ceyzM35K!/2O !67ggKHa<bfg<gN*8>S,-
..M,-
. /*+ ,)*@AB C"#<=>		@  $6M*../?@@TeNL,--   BWbczW{|  XA   B  B_`m_nnyzK)**ww}VabvVwx{V|}}-.3!+.D"E"J!KKvwD}  J  Ka  b  ~c  cr  s  r@  @E  FJ  EK  KU  VK LY  KZ  Zj
  k
v
  w
E  k
F  j
G  G`  ar  `s  sw  xK  wL  Ls  tC  sD  DC  DL  DS  DS  Tg  Dh  Ci  ik  lz  k{  {t  uA  tB  CN  BO  O^  _a  _f  _f  gk  _l  ^m m r   c                    \         P                  P                  V 4      pV^ 8:  d   R# V\        8  d   RRVR R\        R R23#  \        P
                  ! V RR7        \        T RRRR7      ;_uu_ 4       pTP                  R4      pR	R	R	4       . ROpT Uu. uF  qfX9  g   K  TNK  	  ppT'       d   RRRP                  T4      ,           3# R#   \        P                   d   pRR\        T4      ,           3u R	p?# R	p?i\         d   pRR
\        T4      ,           3u R	p?# R	p?ii ; i  + '       g   i     L; i  \         d   pRR\        T4      ,           3u R	p?# R	p?ii ; iu upi )r   Fu   הקובץ גדול מדי: r`   u    bytes. המגבלה היא  bytes.Tdoraiseu*   בדיקת קומפילציה נכשלה:
Nu$   שגיאה בבדיקת הקובץ:
r  rm  rn  ro  i u*   לא ניתן לקרוא את הקובץ:
u|   הקובץ עבר קומפילציה, אבל לא נראה כמו admin_server.py של TripServer. חסרים סימנים: , )Fu   הקובץ ריק.)
r   z
@app.routezapp.runBASE_DIR
ADMIN_PORTrestart_process_laterupload_admin_serverrun_self_test_suitebuild_watchdog_coder  TOK)r=   r?   r   ADMIN_MAX_UPLOAD_BYTES
py_compilecompilePyCompileErrorr   rE   r  r   r   rD   )r^  r  r&  r   contentrequired_tokenstokenr  s   &       rK   validate_admin_server_uploadr    s}   77??8$Dqy**$$4T!H<XYopqXrryzzzJ8T2P(C'(CCrggfoG D
 DO"1J/'5Iuu/GJ  U  X\  Xa  Xa  bi  Xj  j  j  	j! $$ OCc#hNNN J=S	IIIJ DC PCd3iOOOP Ks~   C E 6D.E E-%E-D+&C?9D+?D+D+D& D+&D+.D>	9E >E E*E%E*%E*c                 @   V'       d   R MRpV'       d   RMRp\         P                  ! V 4      p\         P                  ! V4      P                  RR4      p\         P                  ! V4      P                  RR4      pV'       d   RV R2MRp	R	V R
V RV RV RV RV	 R2# )z#16a34az#dc2626z#052e1bz#3f1d1drn  <br>z<pre>z</pre>r}   z
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>aD  </title>
<style>
body{margin:0;font-family:Arial;background:#0f172a;color:white;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px}
.card{width:min(780px,94vw);background:#1e293b;border-radius:24px;padding:26px;box-shadow:0 18px 70px rgba(0,0,0,.35)}
.badge{display:inline-block;background:z;border:1px solid a  ;color:white;border-radius:999px;padding:8px 14px;font-weight:bold;margin-bottom:12px}
h1{margin:0 0 12px;font-size:30px}
p{line-height:1.7;color:#e2e8f0}
pre{white-space:pre-wrap;direction:ltr;text-align:left;background:#020617;color:#fde68a;border:1px solid #334155;border-radius:14px;padding:14px;overflow:auto;max-height:360px}
a,button{display:inline-block;margin:8px 0 0 8px;background:#2563eb;color:white;border:0;border-radius:12px;padding:12px 16px;text-decoration:none;font-weight:bold;cursor:pointer}
button.restart{background:#ea580c}
.advanced-note{margin-top:10px;color:#cbd5e1;font-size:13px;line-height:1.55}
form{display:inline}
</style>
</head>
<body>
<div class="card">
<div class="badge">TripServer Admin</div>
<h1>z	</h1>
<p>z</p>
u  
<a href="/admin">חזרה לפאנל</a>
<form action="/restart_admin_server" method="post" onsubmit="return confirm('זו בדיקת אתחול מתקדמת. להפעיל מחדש את הפאנל עכשיו?')"><button class="restart">בדיקת אתחול פאנל — מתקדם</button></form>
<div class="advanced-note">לא חובה אחרי התקנת Watchdog. מיועד לבדיקה יזומה או אחרי עדכון/שחזור קובץ אדמין.</div>
</div>
</body>
</html>
)r  r  r   )
titlemessager   detailscolorbg
safe_titlesafe_messagesafe_detailsdetails_htmls
   &&&&      rK   admin_status_pager    s    IEiB'J??7+33D&AL??7+33D&AL3:U<./L 	| ) *,,>ug F L >  3   r   c                     \         P                  ! \        R R7       \        P                  ! R4      p\         P
                  P                  \        V  RV R24      p\        P                  ! \        V4       V# )TrK  rM  rP  .py)
r=   rS  ADMIN_BACKUP_DIRrU  rV  r?   rD   r   r  r  )prefixr\  r_  s   &  rK   backup_current_admin_serverr  	  sV    KK 40MM/*E'',,/F81UG31GHK
LL"K0r   c                     \         P                  ! \        R R7       \        P                  ! \         P                  P                  \        R4      4      p V '       g   R# \        V \         P                  P                  R7      # )TrK  zadmin_server_backup_*.pyNr   )r=   rS  r  globr?   rD   r   rD  )r*   s    rK   latest_admin_backupr    sM    KK 40ii%57QRSGwBGG,,--r   c                 X    \         P                  ! \        R R7       \        \        RRR7      ;_uu_ 4       pVP                  \        P                  ! R4      R,           \        V 4      ,           R,           4       RRR4       R#   + '       g   i     R# ; i  \         d     R# i ; i)	TrK  arm  rp  r
   z | control-bootstrap | rn  N)
r=   rS  r  r   CONTROL_BOOTSTRAP_LOG_PATHwriterU  rV  r   rE   r  r   s   & rK   log_control_bootstrapr    sv    
Ht,,cGDDHHT]]#67:SSVYZaVbbeiij EDDD /   6B AB<B B	B B B)(B)c                  j   \         P                  ;'       g    R p \        P                  P	                  V 4      P                  4       pVR8X  de   \        P                  P                  \        P                  P                  V 4      R4      p\        P                  P                  V4      '       d   V# V # )r8   z
python.exer:   )	r;   r<   r=   r?   r@   rA   rD   rB   rC   )rG   rH   rJ   s      rK   quiet_pythonw_pathr  #  sw    
..
$
$HC77C &&(D|GGLL!5}E	77>>)$$Jr   c                      R # )u%  # -*- coding: utf-8 -*-
import os, sys, time, json, shutil, subprocess, socket, threading, traceback
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from urllib.parse import urlparse
BASE_DIR = r"C:\TripServer"
ADMIN_PORT = 8000
CONTROL_PORT = 8010
ADMIN_SCRIPT = os.path.join(BASE_DIR, "admin_server.py")
CONTROL_DIR = os.path.join(BASE_DIR, "control_server")
PENDING_ADMIN = os.path.join(CONTROL_DIR, "pending_admin_server.py")
REQUEST_JSON = os.path.join(CONTROL_DIR, "request.json")
STATUS_JSON = os.path.join(CONTROL_DIR, "status.json")
LOG_PATH = os.path.join(CONTROL_DIR, "tripserver_control_server.log")
BACKUP_DIR = os.path.join(BASE_DIR, "backups", "admin_server")
PYTHON_EXE = sys.executable
if os.path.basename(PYTHON_EXE).lower() == "pythonw.exe":
    c = os.path.join(os.path.dirname(PYTHON_EXE), "python.exe")
    if os.path.exists(c): PYTHON_EXE = c
os.makedirs(CONTROL_DIR, exist_ok=True); os.makedirs(BACKUP_DIR, exist_ok=True)

def log(msg):
    try:
        with open(LOG_PATH, "a", encoding="utf-8") as f:
            f.write(time.strftime("%Y-%m-%d %H:%M:%S") + " | control-v34 | " + str(msg) + "\n")
    except Exception: pass

def write_status(**kw):
    data={"updated_at":time.strftime("%Y-%m-%d %H:%M:%S"),"control_port":CONTROL_PORT,"admin_port":ADMIN_PORT,"python":PYTHON_EXE}
    data.update(kw)
    try:
        with open(STATUS_JSON,"w",encoding="utf-8") as f: json.dump(data,f,ensure_ascii=False,indent=2)
    except Exception as e: log("status write failed "+repr(e))
    return data

def port_open(port):
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM); s.settimeout(0.7)
    try: return s.connect_ex(("127.0.0.1",int(port)))==0
    finally:
        try: s.close()
        except Exception: pass

def admin_ping_ok():
    try:
        import urllib.request
        with urllib.request.urlopen("http://127.0.0.1:%s/ping.json"%ADMIN_PORT,timeout=1.5) as r: return r.status==200
    except Exception: return False

def pids_on_port(port):
    pids=[]
    if os.name!="nt": return pids
    try:
        cp=subprocess.run(["netstat","-ano","-p","tcp"],capture_output=True,text=True,timeout=8)
        for line in (cp.stdout or "").splitlines():
            low=line.lower()
            if (":"+str(port)) in low and "listening" in low:
                parts=line.split(); pid=parts[-1] if parts else ""
                if pid.isdigit() and int(pid) not in pids: pids.append(int(pid))
    except Exception as e: log("pids_on_port failed "+repr(e))
    return pids

def kill_admin():
    pids=pids_on_port(ADMIN_PORT); log("kill_admin pids="+repr(pids))
    for pid in pids:
        if pid==os.getpid(): continue
        try:
            cp=subprocess.run(["taskkill","/PID",str(pid),"/F"],capture_output=True,text=True,timeout=12)
            log("taskkill pid=%s rc=%s out=%s err=%s"%(pid,cp.returncode,(cp.stdout or '').strip(),(cp.stderr or '').strip()))
        except Exception as e: log("taskkill failed pid=%s %r"%(pid,e))
    deadline=time.time()+8
    while time.time()<deadline:
        if not port_open(ADMIN_PORT): return True
        time.sleep(0.25)
    return not port_open(ADMIN_PORT)

def start_admin():
    log("starting admin "+ADMIN_SCRIPT+" python="+PYTHON_EXE)
    flags=0
    if os.name=="nt": flags|=getattr(subprocess,"CREATE_NEW_PROCESS_GROUP",0)|getattr(subprocess,"CREATE_NO_WINDOW",0)|0x00000008
    out=open(os.path.join(BASE_DIR,"admin_stdout.log"),"a",encoding="utf-8",errors="replace")
    proc=subprocess.Popen([PYTHON_EXE,ADMIN_SCRIPT],cwd=BASE_DIR,stdout=out,stderr=out,stdin=subprocess.DEVNULL,creationflags=flags)
    log("started admin pid="+str(proc.pid)); write_status(last_start_pid=proc.pid,last_action="start_admin"); return proc.pid

def compile_ok(path):
    try:
        src=open(path,"r",encoding="utf-8",errors="replace").read(); compile(src,path,"exec"); return True,"OK"
    except Exception as e: return False,repr(e)

def sha256(path):
    import hashlib
    h=hashlib.sha256()
    with open(path,"rb") as f:
        for chunk in iter(lambda:f.read(1024*1024),b""): h.update(chunk)
    return h.hexdigest()

def apply_update(reason="manual"):
    log("apply_update begin reason="+str(reason))
    if not os.path.exists(PENDING_ADMIN):
        msg="pending admin not found"; log(msg); write_status(last_action="apply_update",ok=False,error=msg); return False,msg
    ok,info=compile_ok(PENDING_ADMIN)
    if not ok:
        log("pending compile failed "+info); write_status(last_action="apply_update",ok=False,error=info); return False,info
    new_sha=sha256(PENDING_ADMIN); stamp=time.strftime("%Y%m%d_%H%M%S"); backup=os.path.join(BACKUP_DIR,"admin_server_backup_"+stamp+".py")
    try:
        if os.path.exists(ADMIN_SCRIPT): shutil.copy2(ADMIN_SCRIPT,backup)
    except Exception as e: log("backup failed "+repr(e))
    kill_admin()
    try:
        os.replace(PENDING_ADMIN,ADMIN_SCRIPT); log("admin replaced sha="+new_sha+" backup="+backup)
    except Exception as e:
        log("replace failed "+repr(e)); write_status(last_action="apply_update",ok=False,error=repr(e)); return False,repr(e)
    pid=start_admin(); time.sleep(2); ping=admin_ping_ok(); write_status(last_action="apply_update",ok=True,new_sha=new_sha,backup=backup,started_pid=pid,ping_ok=ping); return True,"updated pid=%s ping=%s"%(pid,ping)

def restart_admin(reason="manual"):
    kill_admin(); pid=start_admin(); time.sleep(2); ping=admin_ping_ok(); write_status(last_action="restart_admin",ok=True,started_pid=pid,ping_ok=ping); return True,"started pid=%s ping=%s"%(pid,ping)

def process_request_file():
    if not os.path.exists(REQUEST_JSON): return
    try:
        with open(REQUEST_JSON,"r",encoding="utf-8") as f: req=json.load(f)
    except Exception as e: log("bad request json "+repr(e)); return
    try: not_before=float(req.get("not_before",0) or 0)
    except Exception: not_before=0
    if time.time()<not_before: return
    try: os.remove(REQUEST_JSON)
    except Exception: pass
    action=req.get("action")
    if action=="apply_update": apply_update(req.get("reason","request"))
    elif action=="restart_admin": restart_admin(req.get("reason","request"))
    else: log("unknown action "+repr(action))

def poll_loop():
    log("poll loop started")
    while True:
        try:
            process_request_file()
            if not port_open(ADMIN_PORT): log("admin port closed; starting admin"); start_admin()
        except Exception as e: log("poll error "+repr(e)+"\n"+traceback.format_exc())
        time.sleep(2)

class Handler(BaseHTTPRequestHandler):
    server_version="TripServerControl/34"
    def _send(self,code,body,ctype="text/html; charset=utf-8"):
        if isinstance(body,str): body=body.encode("utf-8")
        self.send_response(code); self.send_header("Content-Type",ctype); self.send_header("Content-Length",str(len(body))); self.end_headers(); self.wfile.write(body)
    def do_GET(self):
        path=urlparse(self.path).path
        if path=="/ping.json": self._send(200,json.dumps({"ok":True,"admin_ping":admin_ping_ok(),"admin_port_open":port_open(ADMIN_PORT)},ensure_ascii=False),"application/json; charset=utf-8"); return
        if path=="/status.json":
            data={}
            try:
                if os.path.exists(STATUS_JSON): data=json.load(open(STATUS_JSON,"r",encoding="utf-8"))
            except Exception as e: data={"error":repr(e)}
            data.update({"ok":True,"admin_ping":admin_ping_ok(),"admin_port_open":port_open(ADMIN_PORT),"pids":pids_on_port(ADMIN_PORT)})
            self._send(200,json.dumps(data,ensure_ascii=False,indent=2),"application/json; charset=utf-8"); return
        if path=="/log":
            try: txt=open(LOG_PATH,"r",encoding="utf-8",errors="replace").read()[-20000:]
            except Exception as e: txt=repr(e)
            self._send(200,"<pre style='white-space:pre-wrap;direction:ltr'>"+txt.replace("<","&lt;")+"</pre>"); return
        html="""<html><head><meta charset='utf-8'><title>TripServer Control</title><style>body{font-family:Arial;background:#0b1220;color:#eef;direction:rtl;padding:30px}.card{max-width:760px;margin:auto;background:#111a2e;border:1px solid #334155;border-radius:22px;padding:24px}button{font-size:22px;padding:16px 22px;border-radius:16px;border:0;margin:8px;background:#2563eb;color:white}.danger{background:#dc2626}a{color:#93c5fd}</style></head><body><div class='card'><h1>TripServer Control Server</h1><p>שרת בקרה חיצוני לפורט 8000. לא תלוי באדמין הראשי.</p><form method='post' action='/restart'><button>הפעל/אתחל אדמין ראשי</button></form><form method='post' action='/apply-update'><button class='danger'>החל עדכון ממתין</button></form><p><a href='/status.json'>Status JSON</a> · <a href='/log'>Log</a></p></div></body></html>"""
        self._send(200,html)
    def do_POST(self):
        path=urlparse(self.path).path
        if path=="/restart": ok,msg=restart_admin("http"); self._send(200 if ok else 500,json.dumps({"ok":ok,"message":msg},ensure_ascii=False),"application/json; charset=utf-8"); return
        if path=="/apply-update": ok,msg=apply_update("http"); self._send(200 if ok else 500,json.dumps({"ok":ok,"message":msg},ensure_ascii=False),"application/json; charset=utf-8"); return
        self._send(404,"not found")
    def log_message(self,fmt,*args): log("http "+(fmt%args))
if __name__=="__main__":
    log("starting control server python="+sys.executable)
    write_status(last_action="control_start",ok=True)
    threading.Thread(target=poll_loop,daemon=True).start()
    srv=ThreadingHTTPServer(("0.0.0.0",CONTROL_PORT),Handler)
    log("listening on port "+str(CONTROL_PORT))
    srv.serve_forever()
r   r   r   rK   build_control_server_coder  -  s	     Q[r   c                       \         P                  P                  R \         R2RR7      ;_uu_ 4       p V P                  ^8H  uuRRR4       #   + '       g   i     R# ; i  \
         d     R# i ; i)zhttp://127.0.0.1:
/ping.jsonry   r6  NF)urllibr   urlopenCONTROL_PORTr   rE   )resps    rK   control_server_is_aliver  1  s\    ^^##&7~Z$PZ]#^^bf;;#% _^^^ s.   1A! A
A! A	A! A! !A0/A0c                 x    \         P                  ! \        R R7       \        4       pRp\         P                  P                  \        4      '       d#    \        \        RRRR7      P                  4       pW!8w  d\   \        V\        R4       \        \        RRR	7      ;_uu_ 4       pVP                  V4       RRR4       \        R
\        ,           4       \        4       p\         P                  R8X  Ed   \        P                   ! RRR\"        RRRRV R\         R2R.	R R ^R7      p\        RVP$                  : RVP&                  ;'       g    RP)                  4       : RVP*                  ;'       g    RP)                  4       : 24       \        P                   ! RRR\"        .R R ^R7      p\        RVP$                  : RVP&                  ;'       g    RP)                  4       : RVP*                  ;'       g    RP)                  4       : 24       \-        4       '       g   ^ p\         P                  R8X  d6   V\/        \        R^ 4      \/        \        R^ 4      ,          ^,          ,          p\        P0                  ! V\        .\2        \        P4                  \        P4                  \        P4                  VR7       \        RV,           4       R"#   \         d    Rp ELoi ; i  + '       g   i     EL9; i  \         d3   p\        R \7        T4      ,           4       R!\7        T4      3u Rp?# Rp?ii ; i)#TrK  Nr  rm  r   ro  execwr  zcontrol script written r9   schtasks/Create/TN/SCONLOGON/TR"" "/Fr3  zschtasks create rc=z out=r}   z err=/Runzschtasks run rc=CREATE_NO_WINDOWCREATE_NEW_PROCESS_GROUP)cwdstdinrD  rC  creationflagsz#direct control start requested via zbootstrap failed Fr  )r=   rS  CONTROL_DIRr  r?   rC   CONTROL_SCRIPT_PATHr   r   rE   r  r  r  r  r>   r@  rA  CONTROL_TASK_NAMErB  rD  rZ   rC  r  getattrPopenr  DEVNULLr  )	reasoncodecurrentr   pywcprA  flagsr&  s	   &        rK   bootstrap_control_serverr  9  s    
K$/(*77>>-..2C'R[\aac ?D-v6)3AAR B!";>Q"QR "77d?Y?PRWYbdimnornssv  xK  wL  LM  lN  PT  !U  fj  qu  A  BB!2==[][d[d[j[jhjZqZqZsvxvv  wF  wF  DF  vM  vM  vO  #P  Q..*fe=N!O`dkoy{|C!Y\YcYcYiYigiXpXpXruxuu  vF  vF  DF  uM  uM  uO  #P  Q&((Eww$-?CgjZtvwFxx  |F  F  Fc#67XZM_M_hrhzhz  DN  DV  DV  fk  l!"G#"MN'   BAA    1DI=>d3i su   AK< !K 51K< &K(8BK< %K< 5A K< %K< <CK< K%!K< $K%%K< (K9	3	K< <L9'L4.L94L9c                    \         P                  ! \        R R7       RT RTR\        P                  ! R4      R\        P                  ! 4       R,           R\         P
                  ! 4       R	T;'       g    \        /p\        \        R
RR7      ;_uu_ 4       p\        P                  ! W4R^R7       RRR4       V#   + '       g   i     T# ; i)TrK  actionr
  requested_atr
   
not_beforeg      @	admin_pidpending_admin_pathr  rm  r  Fensure_asciiindentN)r=   rS  r  rU  rV  rW  CONTROL_PENDING_ADMIN_PATHr   CONTROL_REQUEST_PATHjsondump)r  r
  pending_pathreqr   s   &&&  rK   write_control_requestr   Z  s    KKd+&&&9:diikC'RYY[lHH.HC 
"C'	:	:b		#a8 
;J 
;	:Js   B88C		c                 X    \         P                  ! \        R R7       \        \        RRR7      ;_uu_ 4       pVP                  \        P                  ! R4      R,           \        V 4      ,           R,           4       RRR4       R#   + '       g   i     R# ; i  \         d     R# i ; i	TrK  r  rm  r  r
    | rn  N)
r=   rS  r  r   ADMIN_RESTART_LOG_PATHr  rU  rV  r   rE   r  s   & rK   log_admin_restartr%  h  sr    
Ht,(#@@BHHT]]#67%?#g,NQUUV A@@@ r  c                   RP                  . RNRNRNRNRNRNRNR	NR
V : 2NRV: 2NRV: 2NR\        : 2NR\        : 2NR\        T;'       g    ^ 4      : 2NRV: 2NRV: 2NRV: 2NR	NRNRNRNRNRNRNRNR	NRNRNRNRNRNRNR	NR NRNR!NR"NRNR#NR	NR$NR%NR&NR'NR"NR(NR)NR	NR*NR+NR,NR-NRNR.NR/NR0NR1NR2NR3NR4NR5NR6NR7NR8NR9NR:NR;NR<NR=NR>NR	NR?NRNR@NRNR#NRANRBNR#NRNRCNRDNRENRFNRGNRHNRINR<NRJNR#NR	NRKNRLNRMNRNNRONRPNRQNRRNRSNRTNRUNR	NRVNRWNRXNRYNRZNR[NR\NR]NR^NR_NR`NRaNR_NRbNR	NRcNRdNReNRfNRgNRhNRiNRjNRkNRlNRmNRnNRoNRpNRqNR	NRrNRsNR	N4      R,           # )ta4  Build a simple and conservative restart helper.

v29 change: stop doing rollback/health gating inside the helper. The logs from
the real Windows machine showed the new Flask server starts, but the helper's
own health request sometimes times out and then incorrectly rolls back or
leaves the port in a bad state. Since uploaded admin files already pass
compile + TripServer validation before replacement, the safest behavior is:
wait, release port 8000, start admin_server.py, write logs, exit. Watchdog and
the browser then verify availability through /ping.json.
rn  # -*- coding: utf-8 -*-	import os
import sysimport subprocessimport timeimport socketzimport hashlibr}   script_path = python_exe = work_dir = log_path = admin_port = zcurrent_pid = zbackup_path = zexpected_sha = z	reason = def log(message):    try:=        os.makedirs(os.path.dirname(log_path), exist_ok=True)9        with open(log_path, 'a', encoding='utf-8') as fh:zd            fh.write(time.strftime('%Y-%m-%d %H:%M:%S') + ' | restart-v29 | ' + str(message) + '\n')    except Exception:        passzdef file_sha256(path):z    h = hashlib.sha256()z     with open(path, 'rb') as fh:z=        for chunk in iter(lambda: fh.read(1024 * 1024), b''):z            h.update(chunk)z    return h.hexdigest()def port_open():zS        with socket.create_connection(('127.0.0.1', int(admin_port)), timeout=0.7):            return True        return False!def wait_port_closed(timeout=12):$    deadline = time.time() + timeout!    while time.time() < deadline:        if not port_open():z        time.sleep(0.4)    return not port_open()def pids_on_port():    pids = []    if os.name != 'nt':        return pidsv        cp = subprocess.run(['netstat', '-ano', '-p', 'tcp'], capture_output=True, text=True, shell=False, timeout=10):        out = (cp.stdout or '') + '\n' + (cp.stderr or '')&        marker = ':' + str(admin_port)%        for line in out.splitlines():B            if marker not in line or 'listen' not in line.lower():                continue             parts = line.split()            if parts:                try:(                    pid = int(parts[-1])/                    if pid and pid not in pids:(                        pids.append(pid)!                except Exception:                    pass    except Exception as exc:+        log('netstat failed: ' + repr(exc))    return pidszdef kill_pid(pid):        pid = int(pid)&    if pid <= 0 or pid == os.getpid():zF        log('skip kill pid=' + str(pid) + ' self=' + str(os.getpid()))        if os.name == 'nt':zM            # No /T. Kill only the process that owns port 8000, never a tree.~            cp = subprocess.run(['taskkill', '/PID', str(pid), '/F'], capture_output=True, text=True, shell=False, timeout=12)z            log('taskkill pid=' + str(pid) + ' rc=' + str(cp.returncode) + ' out=' + ((cp.stdout or cp.stderr or '').strip()[:500]))%            return cp.returncode == 0        os.kill(pid, 9)        return Truez@        log('kill failed pid=' + str(pid) + ' err=' + repr(exc))zdef release_port():zR    # Give the old request time to finish and Flask to exit if it exits naturally.z    if wait_port_closed(10):z$        log('port closed naturally')z        returnz    pids = pids_on_port()zs    log('port still open; killing owners without rollback; current_pid=' + str(current_pid) + ' pids=' + str(pids))z    for pid in pids:z        kill_pid(pid)z    wait_port_closed(10)zW    log('port open after release=' + str(port_open()) + ' pids=' + str(pids_on_port()))zdef start_server():    flags = 0    if os.name == 'nt':z        flags = getattr(subprocess, 'CREATE_NEW_PROCESS_GROUP', 0) | getattr(subprocess, 'DETACHED_PROCESS', 0) | getattr(subprocess, 'CREATE_BREAKAWAY_FROM_JOB', 0)    env = os.environ.copy()/    env.setdefault('PYTHONIOENCODING', 'utf-8')9    os.makedirs(os.path.dirname(log_path), exist_ok=True);    with open(log_path, 'a', encoding='utf-8') as log_file:zu        log_file.write(time.strftime('%Y-%m-%d %H:%M:%S') + ' | restart-v29 | starting admin: ' + script_path + '\n')        log_file.flush()z        proc = subprocess.Popen([python_exe, script_path], cwd=work_dir, stdin=subprocess.DEVNULL, stdout=log_file, stderr=log_file, close_fds=(False if os.name == 'nt' else True), creationflags=flags, start_new_session=(os.name != 'nt'), env=env)zy        log_file.write(time.strftime('%Y-%m-%d %H:%M:%S') + ' | restart-v29 | started admin pid=' + str(proc.pid) + '\n')z    return proc.piddef main():z    log('simple restart started reason=' + str(reason) + ' script=' + script_path + ' python=' + python_exe + ' expected_sha=' + str(expected_sha) + ' backup=' + str(backup_path))z    time.sleep(2.5)z    if expected_sha:        try:z-            actual = file_sha256(script_path)zJ            log('active sha=' + actual + ' expected=' + str(expected_sha))z         except Exception as exc:z1            log('sha check failed: ' + repr(exc))z    release_port()z    start_server()zO    # Do not call /health or /ping here and do not roll back. Previous versionszL    # produced false timeout failures even though Flask was already running.zR    log('simple restart helper finished; browser/watchdog will verify /ping.json')z    return 0if __name__ == '__main__':    raise SystemExit(main()))rD   r$  r  r[   )script_path
python_exework_dircurrent_pidr_  expected_shar
  s   &&&&&&&rK   build_restart_helper_coderl  q  sH    99 J!JJ 	J 		J
 	J 	J 	J 	J (J 
~&J h\"J ,/0J 
~&J [--A.12J (J  ,)*!J" F:#J$ 	%J& 	'J( 	)J* 	H+J, 	D-J. 	p/J0 	 1J2 	3J4 	5J6 	!7J8 	#9J: 	+;J< 	H=J> 	&?J@ 	#AJB 	CJD 	EJF 	GJH 	^IJJ 	"KJL 	 MJN 	OJP 	QJR 	,SJT 	/UJV 	,WJX 	&YJZ 	"[J\ 	"]J^ 	%_J` 	aJb 	cJd 	eJf 	"gJh 	iJj 	kJl 	AmJn 	FoJp 	1qJr 	0sJt 	MuJv 	#wJx 	+yJz 	 {J| 	}J~ 	3J@ 	:AJB 	3CJD 	,EJF 	#GJH 	'IJJ 	6KJL 	MJN 	OJP 	QJR 	SJT 	!UJV 	 WJX 	YJZ 	1[J\ 	Q]J^ 	_J` 	aJb 	&cJd 	XeJf 	IgJh 	OiJj 	0kJl 	"mJn 	oJp 	'qJr 	KsJt 	uJv 	wJx 	yJz 	]{J| 	'}J~ 	/J@ 	AJB 	$CJD 	~EJF 	GJH 	 IJJ 	#KJL 	bMJN 	OJP 	QJR 	SJT 	"UJV 	pWJX 	&YJZ 	:[J\ 	D]J^ 	F_J` 	AaJb 	#cJd 	BeJf 	EgJh 	#iJj 	kJl 	mJn 	oJp 	~qJr 	sJt 	uJv 	wJx 	8yJz 	U{J| 	+}J~ 	<J@ 	AJB 	CJD 	ZEJF 	WGJH 	]IJJ 	KJL 	MJN 	%OJP 	'QJR 	SJ JT 
UJ Jr   c                 l     \        V R R4       R#   \         d   pR\        T4      3u Rp?# Rp?ii ; i)z<tripserver_restart_helper>r  FNr  r  rE   r  )helper_coder&  s   & rK   validate_restart_helper_sourcerp    s9     :FC  d3i     3.33c           	         \        WV\        P                  ! 4       W4V4      p\        V4      w  rxV'       g   \	        R V,           4      h\        \        4       \        \        RRR7      ;_uu_ 4       p	V	P                  V4       RRR4       \        P                  ! \        RR7       \        #   + '       g   i     L2; i)z%Generated restart helper is invalid: r  rm  r  NTr  )rl  r=   rW  rp  RuntimeErrorr   ADMIN_RESTART_HELPER_PATHr   r  r  r  )
rg  rh  ri  r_  rk  r
  ro  r   r  r   s
   &&&&&&    rK   write_restart_helperru    s    +KXryy{\gw}~K-k:HBBTIJJ/0	'w	?	?2
 
@0$?$$ 
@	?s   3B//B?	c                   \         P                  ! R4       \        P                  P	                  \
        4      p\        P                  ;'       g    Rp\        P                  P                  V4      ;'       g    \        p \        RV R\         RV RV R\        P                  ! 4        RV  R	V R
\        P                   24       \        W4WPWR7      p^ p\        P                  R8X  d>   \!        \"        R^ 4      \!        \"        R^ 4      ,          \!        \"        R^ 4      ,          p\"        P$                  ! WF.T\"        P&                  \"        P&                  \"        P&                  \        P                  R8X  d   RMRV\        P                  R8g  R7       \        RV,           4       \        P(                  ! ^ 4       R#   \*         Ed   p\        R\-        T4      ,           4        \"        P$                  ! YC.TR\        P                  R8g  R7       \        P(                  ! ^ 4        Rp?R#   \*         d   p	\        R\-        T	4      ,           4        \        P.                  ! YDT.4        Rp	?	 Rp?R#   \*         dE   p
\        R\-        T
4      ,           4       \        P(                  ! ^4        Rp
?
 Rp	?	 Rp?R# Rp
?
ii ; iRp	?	ii ; iRp?ii ; i)zHard self-restart for Windows/iPhone admin workflow.

v23: the helper can force-release a stuck port safely and roll back to the previous admin
backup if the newly uploaded admin does not pass /ping.json after boot.
g333333?r8   z hard restart requested | reason= | version=
 | script=
 | python= | pid=
 | backup= | expected_sha=z | argv=r_  rk  r
  r9   r   DETACHED_PROCESSCREATE_BREAKAWAY_FROM_JOBFTr  r  rD  rC  	close_fdsr  start_new_sessionzhard restart helper launched: zhard restart helper failed: )r  r  r  z direct restart fallback failed: zexecv fallback failed: N)rU  sleepr=   r?   abspathr  r;   r<   rB   r  r%  r  rW  argvru  r>   r  r@  r  r	  _exitrE   r  execv)r_  rk  r
  rg  rh  ri  helper_pathr  r&  exc2exc3s   &&&        rK   r  r    s    	JJsO''//"34K++8Jww{+77xH<VHKPcOddnozn{  |F  GQ  FR  RY  Z\  Zc  Zc  Ze  Yf  fp  q|  p}  }M  NZ  M[  [c  dg  dl  dl  cm  n  	o*;H  uA  Q77d?J(BAFQ[]oqrIssv}  I  Kf  hi  wj  jE%$$%%%% "4uT!ww$		
 	:[HI
 849DE		j6HPTikipiptxixzHHQKK 	@4:MN+%>?? !";d4j"HI		sh   EG KK/AH77KKJ 6K K1K
<K K
KKKKKc                   \         P                  R8w  d   \        R4      h\        V4      pRV RV  R2pRRR\        RVR	R
RRR.p\
        P                  ! VRRR^R7      pVP                  ;'       g    VP                  ;'       g    RP                  4       pVP                  ^ 8w  d0   \        RT;'       g    \        VP                  4      ,           4      h\
        P                  ! RRR\        .RRR^R7      pVP                  ;'       g    VP                  ;'       g    RP                  4       p	VP                  ^ 8w  d0   \        RT	;'       g    \        VP                  4      ,           4      h\        R\        ,           R,           V,           R,           V,           R,           V	,           4       R\        RVRVRV	/# )ad  Launch restart helper as an independent Windows Scheduled Task.

This is more reliable than subprocess.Popen from the Flask process because the
helper is not a child of the admin process it is about to kill. On Windows,
self-restart helpers launched as child processes can be terminated together
with the old server or stuck in the same job/process group.
r9   z3Task Scheduler restart is supported only on Windowsr  r  r  r  r  r  r  ONCEz/STz23:59r  TFr4  r5  shellr6  r}   zFailed to create restart task: r  zFailed to run restart task: z2restart helper launched via Task Scheduler | task=ry  z
 | create=z | run=taskr8   createrA  )r=   r>   rs  rL   RESTART_TASK_NAMEr@  rA  rD  rC  rZ   rB  r   r%  )
r  rh  ri  quiet_pythontask_command
create_cmd	cp_create
create_outcp_runrun_outs
   &&&       rK   #launch_restart_helper_via_schedulerr  E  s    
ww$PQQ)*5L|nC}A6L 	I |vwJ z$TQV`bcI""<<i&6&6<<"CCEJq <
@g@gcR[RfRfNghii^^Z8IJ[_fjrw  BD  EF}}3333::<GA9W=^=^FL]L]H^_``JM^^ammp||  @L  L  OY  Y  \e  e  ho  o  p%xxUZ\cddr   c                T   \         P                  P                  \        4      p\        P
                  ;'       g    Rp\         P                  P                  V4      ;'       g    \        p\        RV R\         RV RV R\         P                  ! 4        RV  RV 24       \        W4WPWR	7      p \        WdV4      pVR
,           \        VP                  R4      4      ,           R,           \        VP                  R4      4      ,           #   \         Ed   p\        R\!        T4      ,           4       ^ p	\         P"                  R8X  d>   \%        \&        R^ 4      \%        \&        R^ 4      ,          \%        \&        R^ 4      ,          p	\)        T4      p
\&        P*                  ! Y.T\&        P,                  \&        P,                  \&        P,                  \         P"                  R8X  d   RMRT	\         P"                  R8g  R7       \        RT,           4       TR,           u Rp?# Rp?ii ; i)a@  Launch a detached restart helper through Task Scheduler.

v27: this is the important architectural fix. The helper is no longer a
direct child of the Flask/admin process. It is started by Windows Task
Scheduler, then it can safely kill the old process on port 8000 and start the
new admin without dying with its parent.
r8   z%scheduler restart requested | reason=rw  rx  ry  rz  r{  r|  r}  z | task=r  zFTask Scheduler restart launch failed, falling back to detached Popen: r9   r   r~  r  FTr  z9restart helper launched through fallback detached Popen: z | fallback=detached-popenN)r=   r?   r  r  r;   r<   rB   r  r%  r  rW  ru  r  r   r   rE   r  r>   r  r@  rL   r  r	  )r_  rk  r
  rg  rh  ri  r  	task_infor&  r  r  s   &&&        rK   launch_safe_external_restartr  g  s     ''//"34K++8Jww{+77xH
/x{CVBWWabmannx  zD  yE  EL  MO  MV  MV  MX  LY  Yc  do  cp  p@  AM  @N  	O '{p|  MK:7QYZ	Z'#immF.C*DD|SVYZcZgZghpZqVrrr : 	beijmenno77d?J(BAFQ[]oqrIssv}  I  Kf  hi  wj  jE-j9'$$%%%% "4uT!ww$		
 	UXccd999):s    1AD H'DH"H'"H'c                   RP                  . RNRNRNRNRNRNRNR	NR
NRV : 2NRV: 2NRV: 2NR\        : 2NRR\        ,          : 2NR\        : 2NR\        : 2NR\        : 2NR
NRNRNRNRNRNRNRNR
NRNRNRNRNRNRNR NR!NR"NR#NRNR$NR
NR%NRNR&NR'NR(NRNRNR
NR)NRNR*NR+NRNR,NR
NR-NR.NR/NR0NRNR1NR2NR3NR4NR5NR6NR7NR8NR9NR:NR;NR<NR=NR>NR?NR@NRANR
NRBNRCNRDNRNRENRNR,NRFNRGNR,NRNRHNRINRJNRKNRLNRMNR?NRNNR,NR
NRONRPNRQNRRNR+NRSNRTNR
NRUNRNRVNRWNRXNRYNRZNR?NR[NR
NR\NRNR]NR^NRNR,NR
NR_NR`NRaNRbNR
NRcNRNRdNReNRfNR?NR[NR
NRgNRhNRiNRjNRkNRlNRmNRnNRoNRpNRqNRrNRsNRtNRuNRvNRwNRxNRyNRzNR{NR|NR}NR
NR~NRNRNRNRNRNRNRNRNRNRbNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNR?NRNRNR
NRNRNR
N4      R,           # )a)  Build a one-shot watchdog script for Windows Task Scheduler.

v28 change: if the port is open but /ping.json fails repeatedly, the watchdog
treats it as a stuck admin process, kills the process that owns port 8000, and
starts admin_server.py again. This is the case that forced a physical reboot.
rn  r'  r(  r)  r+  r,  r*  zimport urllib.requestzimport jsonr}   r-  r.  r/  r1  zhealth_url = zhttp://127.0.0.1:%s/ping.jsonr0  zstate_path = zcooldown_seconds = r2  r3  r4  r5  ze            fh.write(time.strftime('%Y-%m-%d %H:%M:%S') + ' | watchdog-v28 | ' + str(message) + '\n')r6  r7  zdef load_state():zD        raw = open(state_path, 'r', encoding='utf-8').read().strip()z        if not raw:z            return {}rd  z"            data = json.loads(raw)z9            return data if isinstance(data, dict) else {}z        except Exception:z-            return {'last_start': float(raw)}z        return {}zdef save_state(state):z?        os.makedirs(os.path.dirname(state_path), exist_ok=True)z;        with open(state_path, 'w', encoding='utf-8') as fh:z             json.dump(state, fh)r8  zS        with socket.create_connection(('127.0.0.1', int(admin_port)), timeout=2.0):r9  r:  r@  rA  rB  rC  rD  rE  rF  rG  rH  rI  rJ  rK  rL  rM  rN  rO  rP  rQ  rR  rS  rT  zdef kill_port_owner(pid):zM    # v23: avoid /T even in watchdog. If run-once was launched from the adminzL    # panel, /T could kill the watchdog child together with the stuck admin.rU  rV  zI        log('skip killing pid=' + str(pid) + ' self=' + str(os.getpid()))rW  rX  z            log('taskkill-port-owner pid=' + str(pid) + ' rc=' + str(cp.returncode) + ' out=' + ((cp.stdout or cp.stderr or '').strip()[:500]))rY  rZ  r[  zK        log('kill port owner failed pid=' + str(pid) + ' err=' + repr(exc))r;  r<  r=  r>  z        time.sleep(0.6)r?  zdef health_ok():zX        req = urllib.request.Request(health_url, headers={'Accept': 'application/json'})z>        with urllib.request.urlopen(req, timeout=4.0) as resp:zC            raw = resp.read(8192).decode('utf-8', errors='replace')z        data = json.loads(raw)zJ        return bool(data.get('ok')), 'OK' if data.get('ok') else raw[:500]z        return False, repr(exc)zdef recently_started(state):z2        last = float(state.get('last_start') or 0)z=        return (time.time() - last) < float(cooldown_seconds)zdef mark_started(state):z%    state['last_start'] = time.time()z    state['failure_count'] = 0z    save_state(state)zdef script_compiles():z        import py_compilez5        py_compile.compile(script_path, doraise=True)z        return True, 'OK'zdef launch_admin(state):r\  r]  zo        flags = getattr(subprocess, 'CREATE_NEW_PROCESS_GROUP', 0) | getattr(subprocess, 'DETACHED_PROCESS', 0)r^  r_  r`  ra  zv        log_file.write(time.strftime('%Y-%m-%d %H:%M:%S') + ' | watchdog-v28 | starting admin: ' + script_path + '\n')rb  z         proc = subprocess.Popen(z&            [python_exe, script_path],z            cwd=work_dir,z%            stdin=subprocess.DEVNULL,z            stdout=log_file,z            stderr=log_file,z;            close_fds=(False if os.name == 'nt' else True),z             creationflags=flags,z0            start_new_session=(os.name != 'nt'),z            env=env,z	        )zt        log_file.write(time.strftime('%Y-%m-%d %H:%M:%S') + ' | watchdog-v28 | started pid=' + str(proc.pid) + '\n')z    mark_started(state)rc  z    state = load_state()z    ok, info = health_ok()z
    if ok:z&        if state.get('failure_count'):z&            state['failure_count'] = 0z            save_state(state)z        return 0z9    fail_count = int(state.get('failure_count') or 0) + 1z'    state['failure_count'] = fail_countz    is_port_open = port_open()zl    log('health failed count=' + str(fail_count) + ' port_open=' + str(is_port_open) + ' info=' + str(info))z    if recently_started(state):z8        log('restart cooldown active; skip this minute')z        return 3z    if is_port_open:z        pids = pids_on_port()z        if fail_count < 2:zq            log('port is open but health failed; waiting for second failure before hard kill. pids=' + str(pids))z            return 2zS        log('port open + repeated health failure; killing stuck pids=' + str(pids))z        for pid in pids:z             kill_port_owner(pid)z        wait_port_closed(14)z'    if not os.path.exists(script_path):z5        log('admin script not found: ' + script_path)z        return 4z0    ok_compile, compile_info = script_compiles()z    if not ok_compile:zU        log('admin script does not compile; not starting. info=' + str(compile_info))z        return 5z        launch_admin(state)z        return 10z3        log('failed to launch admin: ' + repr(exc))z        return 6re  rf  )rD   r  WATCHDOG_LOG_PATHWATCHDOG_STATE_PATH%WATCHDOG_MIN_RESTART_INTERVAL_SECONDS)rg  rh  ri  s   &&&rK   r  r    s
    99 K!KK 	K 		K
 	K 	K 	 K 	K 	K (K 
~&K h\"K 
~&K 7*DGHK '*+K  +./!K" CFG#K$ 	%K& 	'K( 	)K* 	H+K, 	D-K. 	q/K0 	 1K2 	3K4 	5K6 	7K8 	9K: 	O;K< 	=K> 	 ?K@ 	AKB 	-CKD 	DEKF 	$GKH 	8IKJ 	 KKL 	MKN 	OKP 	!QKR 	SKT 	JUKV 	FWKX 	+YKZ 	 [K\ 	]K^ 	_K` 	aKb 	cKd 	^eKf 	"gKh 	 iKj 	kKl 	mKn 	oKp 	qKr 	"sKt 	uKv 	wKx 	AyKz 	F{K| 	1}K~ 	0K@ 	MAKB 	#CKD 	+EKF 	 GKH 	IKJ 	3KKL 	:MKN 	3OKP 	,QKR 	#SKT 	'UKV 	6WKX 	YKZ 	[K\ 	$]K^ 	X_K` 	WaKb 	cKd 	!eKf 	 gKh 	iKj 	1kKl 	TmKn 	oKp 	qKr 	&sKt 	IuKv 	ZwKx 	0yKz 	"{K| 	}K~ 	'K@ 	VAKB 	CKD 	EKF 	,GKH 	/IKJ 	,KKL 	&MKN 	"OKP 	"QKR 	%SKT 	UKV 	WKX 	YKZ 	c[K\ 	I]K^ 	N_K` 	)aKb 	UcKd 	'eKf 	*gKh 	iKj 	'kKl 	mKn 	=oKp 	HqKr 	 sKt 	uKv 	wKx 	#yKz 	0{K| 	)}K~ 	 K@ 	AKB 	!CKD 	EKF 	$GKH 	@IKJ 	$KKL 	'MKN 	*OKP 	QKR 	#SKT 	UKV 	"WKX 	zYKZ 	&[K\ 	:]K^ 	D_K` 	FaKb 	BcKd 	#eKf 	+gKh 	1iKj 	$kKl 	0mKn 	'oKp 	'qKr 	FsKt 	+uKv 	;wKx 	yKz 	{K| 	@}K~ 	"K@ 	AKB 	CKD 	#EKF 	%GKH 	IKJ 	1KKL 	1MKN 	(OKP 	QKR 	DSKT 	2UKV 	 WKX 	)YKZ 	w[K\ 	*]K^ 	C_K` 	aKb 	cKd 	(eKf 	%gKh 	|iKj 	kKl 	^mKn 	#oKp 	+qKr 	'sKt 	2uKv 	@wKx 	yKz 	;{K| 	!}K~ 	`K@ 	AKB 	CKD 	&EKF 	GKH 	'IKJ 	>KKL 	MKN 	OKP 	%QKR 	'SKT 	UK KV 
WK Kr   c                 l     \        V R R4       R#   \         d   pR\        T4      3u Rp?# Rp?ii ; i)z<tripserver_watchdog>r  FNr  rn  )watchdog_coder&  s   & rK   validate_watchdog_sourcer  d  s9     6?  d3i rq  c                  ,   \         P                  P                  \        4      p \        P
                  ;'       g    R p\         P                  P                  V 4      ;'       g    \        p\        WV4      p\        V4      w  rEV'       g   \        RV,           4      h\        \        4       \        \        RRR7      ;_uu_ 4       pVP                  V4       RRR4       \        P                   ! \        RR7       \        #   + '       g   i     L2; i)r8   z&Generated watchdog script is invalid: r  rm  r  NTr  )r=   r?   r  r  r;   r<   rB   r  r  r  rs  r   WATCHDOG_SCRIPT_PATHr   r  r  r  )rg  rh  ri  r   r   r  r   s          rK   write_watchdog_scriptr  l  s    ''//"34K++8Jww{+77xH (CF'/HBCdJKK*+	"C'	:	:b
 
;+T: 
;	:s   DD	c                      \        V R RRR7      ;_uu_ 4       pVP                  4       pRRR4       RP                  XV) R 4      P                  4       #   + '       g   i     L3; i  \         d     R# i ; i)r  rm  r   ro  Nr}   )r   	readlinesrD   rZ   rE   )r?   	max_linesr   ro  s   &&  rK   read_log_tailr  {  si    $gi@@BLLNE AwwuiZ[)*0022 A@  s'   A( A*A( A%	 A( (A76A7c                      \        V 4      pVe   \        W$4      pVe   \        W44      pV#   \         d    Tp L/i ; irY   )r[   rE   r   r  )r   default	min_value	max_valueparseds   &&&& rK   safe_intr    sM    U Y'Y'M  s   - ==c                    \         P                  V 4      pV'       g   R # VR,          p\        P                  P	                  V4      pV'       d    \        P                  P                  V4      M^ pV'       dI   \        P                  ! R\        P                  ! \        P                  P                  V4      4      4      MRpV'       d   \        W1R7      MRpRV RVR,          RVP                  RR	4      RVR
VRVR\        V4      RVRV/	# )Nr?   r
   u   לא קיים עדייןr  uM   אין עדיין לוג. הוא יווצר אחרי פעולה ראשונה.r   rN   rO   r}   rC   r  
size_labelupdatedtail)LOG_FILE_REGISTRYr   r=   r?   rC   r   rU  rV  rC  rD  r  r   )log_keyr  metar?   rC   r  r  r  s   &&      rK   log_file_summaryr    s      )D<DWW^^D!F$*277??4 D\bdmm/@P@PQU@V1WX  iCG7==3  DSDwg$&l4(7
 
r   c           
          \        V \        ^\        4      p . p\         F*  p\	        W R7      pV'       g   K  VP                  V4       K,  	  RRR\        R\        P                  ! R4      RV RV/# )	r  r  r   Tversion
checked_atr
   ro  logs)	r  LOG_TAIL_DEFAULT_LINESLOG_TAIL_MAX_LINESr  r  r  r  rU  rV  )r  itemsr   r  s   &   rK   build_logs_payloadr    sn    $:B@RSIE 94LL !
 	d&dmm$78 r   c                     \        \        P                  P                  R \        4      4      p . pV R,           EF  pVR,          '       d   RMRpVR,          '       d   RMRp\
        P                  ! VR,          ;'       g    R4      P                  R	R
4      pVP                  R\
        P                  ! VR,          4       R\
        P                  ! VR,          4       RV RV R\
        P                  ! VR,          4       R\
        P                  ! VR,          4       R\
        P                  ! VR,          4       RV R24       EK  	  RRP                  V4       R2# )ro  r  rC   r   warnu   קייםu   לא נוצר עדייןr  u   אין תוכן להצגה.rn  r  z>
<div class="log-card">
  <div class="log-head">
    <div><h2>rN   z</h2><p>rO   z"</p></div>
    <span class="badge ">u:   </span>
  </div>
  <div class="meta"><b>נתיב</b><code>r?   u6   </code></div>
  <div class="stats"><span>גודל: <b>r  u    </b></span><span>עודכן: <b>r  z</b></span></div>
  <pre>z</pre>
</div>up
  
<!DOCTYPE html>
<html lang="he" dir="rtl"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>לוגים TripServer</title>
<style>
body{margin:0;background:#07111f;color:white;font-family:Arial;padding:22px}.wrap{max-width:1120px;margin:auto}a{color:#dbeafe;text-decoration:none}.hero{background:linear-gradient(135deg,#1e3a8a,#0f172a 62%,#111827);border:1px solid #1d4ed8;border-radius:28px;padding:22px;margin-bottom:16px;box-shadow:0 20px 70px rgba(0,0,0,.28)}h1{margin:0 0 8px;font-size:34px}p{color:#cbd5e1;line-height:1.6}.actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px}.actions a{background:#2563eb;color:white;border-radius:999px;padding:10px 14px;font-weight:900}.actions a.secondary{background:#1e293b;border:1px solid #334155}.log-card{background:#101c31;border:1px solid #253650;border-radius:24px;padding:18px;margin:14px 0;box-shadow:0 18px 55px rgba(0,0,0,.22)}.log-head{display:flex;align-items:flex-start;justify-content:space-between;gap:14px}.log-head h2{margin:0 0 6px;font-size:24px}.badge{white-space:nowrap;border-radius:999px;padding:7px 11px;font-weight:900}.badge.ok{background:#14532d;color:#bbf7d0;border:1px solid #22c55e}.badge.warn{background:#451a03;color:#fed7aa;border:1px solid #f97316}.meta{margin-top:10px;color:#cbd5e1}code{direction:ltr;display:block;background:#0b1220;border:1px solid #334155;border-radius:12px;padding:10px;color:#fde68a;margin-top:6px;white-space:normal}.stats{display:flex;gap:12px;flex-wrap:wrap;color:#cbd5e1;margin:12px 0}.stats span{background:#0b1220;border:1px solid #334155;border-radius:999px;padding:8px 10px}pre{direction:ltr;text-align:left;white-space:pre-wrap;background:#020617;color:#fde68a;border:1px solid #334155;border-radius:16px;padding:14px;overflow:auto;max-height:420px;font-size:13px;line-height:1.55}@media(max-width:700px){body{padding:14px}.hero{padding:18px;border-radius:22px}h1{font-size:28px}.log-head{display:block}}
</style></head><body><div class="wrap"><div class="hero"><a href="/admin">⬅ חזרה לפאנל</a><h1>📜 מרכז לוגים</h1><p>צפייה נוחה בלוגי האדמין וה־Watchdog בלי לפתוח קבצים ידנית במחשב. המסך לקריאה בלבד ולא מוחק או משנה שום דבר.</p><div class="actions"><a href="/admin/logs">רענן</a><a class="secondary" href="/admin/logs?lines=250">הצג 250 שורות</a><a class="secondary" href="/admin/logs?lines=500">הצג 500 שורות</a><a class="secondary" href="/admin/logs.json" target="_blank">JSON טכני</a><a class="secondary" href="/admin/self-test">בדיקה עצמית</a></div></div>r}   </div></body></html>
)
r  r   argsr   r  r  r  r   r  rD   )payloadcardsr  	badge_cls
badge_textr  s         rK   render_admin_logsr    s}    !1!1';Q!RSGE NND	#'>>Z7Q
tF|LL/LMUUVZ\bc  ood7m,-Xhood6l6S5T U!{"ZL 1**2//$v,*G)H I))1l9K)L(MMmnvn}n}  C  DM  N  oO  nP Pv 	
 			  u

 v
x
  v
}
  v
}
  ~
C  v
D  u
E E r   c                     \         P                  R 8w  d   RRRRRRRR/#  \        P                  ! RRR	\        R
R.RRR^R7      p V P
                  ;'       g    V P                  ;'       g    RP                  4       pRRRV P                  ^ 8H  RV P                  ^ 8H  RV/#   \         d   pRRRRRRR\        T4      /u Rp?# Rp?ii ; i)r9   	supportedF	installedr   r  u*   Task Scheduler זמין רק על Windows.r  z/Queryr  z/FOLISTTr  r}   N)r=   r>   r@  rA  WATCHDOG_TASK_NAMErD  rC  rZ   rB  rE   r  )	completedoutputr&  s      rK   query_watchdog_taskr    s    	ww$UKeYP|}}ZNNJ%ASUZ\b#ctx  @D  LQ  []  ^	""<<i&6&6<<"CCET;	0D0D0I4QZQeQeijQjluw}~~ ZT;tUItTWyYYZs)   7B" B" -4B" "C
-C?C
C
c                     \        \        P                  P                  \        4      \
        P                  ;'       g    R \        P                  P                  \        P                  P                  \        4      4      ;'       g    \        4      p\        V4      w  r4\        P                  P                  \        4      pRpRpV'       d"    \        P                  ! \        RR7       RpRpV'       d   \!        4       M	RRRRR	RR
R/p	RTRTR\        RTRTRTR\"        RV	P%                  R4      RV	P%                  R4      RV	P%                  R
R4      R\&        R\(        R\+        \
        P                  ;'       g    R 4      R\,        RV '       d   \/        \,        4      /# R/#   \         d   p\        T4      p Rp?LRp?ii ; i)r8   Fu   לא נכתב עדייןTr  r  Nr  r  r   r  znot queried	source_oksource_statusrg  script_existsscript_compilesscript_status	task_nametask_supportedr  task_statusr}   interval_minutescooldown_secondsr  log_pathlog_tail)r  r=   r?   r  r  r;   r<   rB   r  r  rC   r  r  r  rE   r  r  r  r   WATCHDOG_INTERVAL_MINUTESr  rL   r  r  )
r  include_task	generatedr  source_infofile_existsfile_compiles	file_infor&  r  s
   &&        rK   r  r    s   #BGGOO4E$FHbHbZbdfdkdkdsdstvt{t{  uD  uD  EV  uW  eX  ed  ed  \d  eI5i@I''..!56KM*I	"3TB MI %1 {D+W[]acgir  uB  7CDY+='$((;/$((;/txx	2.5A.s~~/I/IJ%M"34  JL   	"S	I	"s    F' 'G2GGc                  &   \        4       p \        P                  R 8w  d	   RRRV  23# \        \        P
                  ;'       g    R4      pRV RV  R2pRRR	\        R
VRRR\        \        ^\        4      4      R.p\        P                  ! VRRR^R7      pVP                  ;'       g    VP                  ;'       g    RP                  4       pVP                  ^ 8w  d   RRT;'       g    RVP                   23# RR\        ^\        4       R2V3# )r9   Fu^   קובץ ה־Watchdog נכתב, אבל התקנת Task Scheduler נתמכת רק על Windows.zscript=r8   r  r  r  r  r  r  r  MINUTEz/MOr  Tr  r}   uJ   קובץ ה־Watchdog נכתב, אבל התקנת המשימה נכשלה.return code: uE   Watchdog שקט הותקן כמשימה מתוזמנת שרצה כל u>    דקות עם pythonw.exe, בלי חלון שחור קופץ.)r  r=   r>   rL   r;   r<   r  r   r   r  r@  rA  rD  rC  rZ   rB  )rg  r  r  rG  r  r  s         rK   install_watchdog_taskr    s   ')K	ww$v  {B  CN  BO  yP  P  	P *#..*D*DHEL|nC}A6Ly%);ULRWYachjmnqrs  vO  oP  kQ  SW  XCs4d%Y[\I88)"2"288b??AFq bdj  eU  eUp}  H  S  S  ~T  oU  U  	UXY\]^`yYzX{  |z  {  }C  C  Cr   c                  L   \         P                  R 8w  d   R# \        P                  ! RRR\        R.RRR^R7      p V P
                  ;'       g    V P                  ;'       g    RP                  4       pV P                  ^ 8w  d   RR	T;'       g    R
V P                   23# RRV3# )r9   Fr}   r  z/Deleter  r  Tr  uY   לא הצלחתי להסיר את משימת ה־Watchdog, או שהיא לא קיימת.r  u#   משימת ה־Watchdog הוסרה.)Fu5   הסרת Task Scheduler נתמכת רק על Windows.r}   )	r=   r>   r@  rA  r  rD  rC  rZ   rB  )r  r  s     rK   uninstall_watchdog_taskr    s    	ww$QQ
Iu>PRVWhlsw  @E  OQ  RI88)"2"288b??AFq qsy  td  td  @M  NW  Nb  Nb  Mc  ~d  d  	d6>>r   c                  b   \        4       p \        P                  ! \        P                  ;'       g    R V .RRR^R7      pVP
                  ;'       g    VP                  ;'       g    RP                  4       pVP                  R9   pTRVP                   R2T;'       g    \        \        4      3# )r8   TFr  r}   u0   Watchdog רץ פעם אחת והחזיר קוד r   >   r   r      
   )r  r@  rA  r;   r<   rD  rC  rZ   rB  r  r  )rg  r  r  r   s       rK   run_watchdog_once_nowr    s    ')K : :(KHY]dhpu  @B  CI88)"2"288b??AF				.BA)BVBVAWWXY[a  \F  \Fer  tE  fF  F  Fr   c                     \        R R7      p \        V P                  R4      4      p\        V P                  R4      4      ;'       d    \        V P                  R4      4      p\        V P                  R4      4      pV'       d   RMRpV'       d   V'       d   RMR	p\        P                  ! V P                  R
4      ;'       g    R4      p\        P                  ! V P                  R4      ;'       g    R4      P                  RR4      pV'       d   RMRpV'       d   RMRp	R\         RT RT RT R\        P                  ! V P                  RR4      4       RT	 R\        P                  ! V P                  RR4      4       RV P                  R4       R\        P                  ! V P                  R R4      4       R!V P                  R"4       R#T;'       g    R$ R%V R&2# )'Tr  r  r  r  r  u   מותקן ופעילu   לא מותקן עדייןr   r  r  r}   r  u   אין עדיין לוג.rn  r  u   ✅ קיים ותקיןu-   ⚠️ עדיין לא נכתב/לא תקיןu   ✅ מותקנתu   ⚠️ לא מותקנתu^  
<!DOCTYPE html>
<html lang="he" dir="rtl"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>TripServer Watchdog</title>
<style>
body{margin:0;background:#0f172a;color:white;font-family:Arial;padding:22px}.wrap{max-width:1050px;margin:auto}a{color:#bfdbfe;text-decoration:none}.hero{background:linear-gradient(135deg,#14532d,#0f172a 60%,#111827);border:1px solid #166534;border-radius:28px;padding:22px;margin-bottom:16px;box-shadow:0 20px 70px rgba(0,0,0,.28)}h1{margin:0 0 8px;font-size:34px}p{color:#cbd5e1;line-height:1.7}.badge{display:inline-block;border-radius:999px;padding:8px 14px;font-weight:900;margin:8px 0}.badge.ok{background:#064e3b;color:#bbf7d0;border:1px solid #22c55e}.badge.warn{background:#713f12;color:#fde68a;border:1px solid #f59e0b}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:14px}.card{background:#111827;border:1px solid #334155;border-radius:20px;padding:16px;margin-top:14px}.card b{display:block;font-size:18px;margin-bottom:8px}code,pre{direction:ltr;text-align:left;white-space:pre-wrap;word-break:break-word}pre{background:#020617;border:1px solid #334155;color:#fde68a;border-radius:14px;padding:13px;max-height:340px;overflow:auto}button{border:0;border-radius:14px;padding:13px 16px;font-weight:950;color:white;background:#2563eb;margin:8px 8px 0 0;cursor:pointer}button.orange{background:#ea580c}button.danger{background:#dc2626}.actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:12px}.actions a{display:inline-flex;background:#172033;border:1px solid #334155;border-radius:999px;padding:10px 14px;font-weight:900}.note{background:#0b1220;border:1px solid #334155;border-radius:18px;padding:14px;margin:14px 0;color:#cbd5e1;line-height:1.7}@media(max-width:700px){body{padding:14px}h1{font-size:28px}}
</style></head><body><div class="wrap"><div class="hero"><a href="/admin">⬅ חזרה לפאנל</a><h1>🛡️ Watchdog לשמירת פאנל האדמין</h1><p>שכבת ביטחון חיצונית: Windows מריץ סקריפט שקט כל כמה דקות. אם הפאנל לא עונה ב־localhost:uP   , הוא מפעיל מחדש את admin_server.py לבד.</p><span class="badge r  u   </span><div class="actions"><a href="/admin/self-test">בדיקה עצמית</a><a href="/admin/health">Health</a><a href="/admin/status">סטטוס קבצים</a></div></div>
<div class="grid"><div class="card"><b>סקריפט Watchdog</b><p>z
</p><code>rg  uB   </code></div><div class="card"><b>משימה מתוזמנת</b><p>u   </p><p>שם: <code>r  u!   </code></p><p>תדירות: כל r  u    דקות</p></div><div class="card"><b>הרצה שקטה</b><p>מותקן דרך <code>pythonw.exe</code> כדי לא לפתוח חלון CMD שחור ולא לגנוב פוקוס בזמן הקלדה.</p><code>r  z1</code></div><div class="card"><b>Cooldown</b><p>r  u   שניות בין ניסיונות הפעלה כדי למנוע לופ.</p></div></div>
<div class="note"><b>מה זה עושה בפועל?</b><br>ה־Watchdog לא מחליף קבצים, לא מכבה מחשב ולא עושה restart למחשב. הוא רק בודק אם פאנל האדמין חי, ואם לא — מפעיל את קובץ האדמין הפעיל מחדש. זה בדיוק הכיסוי למקרה שבו העלאת admin או restart נפלו ואתה לא רוצה ללכת פיזית למחשב.</div>
<div class="card"><b>פעולות</b><form action="/watchdog/install" method="post" onsubmit="return confirm('להתקין Watchdog מתוזמן שרץ שקט כל כמה דקות?')"><button>התקן / עדכן Watchdog</button></form><form action="/watchdog/run-once" method="post" onsubmit="return confirm('להריץ בדיקת Watchdog חד־פעמית עכשיו?')"><button class="orange">הרץ פעם אחת עכשיו</button></form><form action="/watchdog/uninstall" method="post" onsubmit="return confirm('להסיר את משימת ה־Watchdog?')"><button class="danger">הסר Watchdog</button></form></div>
<div class="card"><b>סטטוס Task Scheduler</b><pre>u   אין מידע.u;   </pre></div><div class="card"><b>לוג אחרון</b><pre>!</pre></div></div></body></html>
)r  r   r   r  r  r   r  )
r   r  	script_okr  state_badge	state_cls	task_textr  script_label
task_labels
             rK   render_admin_watchdogr    s   .FVZZ 012IVZZ01YYd6::FW;X6YIVZZ,-I-6)<XK!iVI

= 9 ? ?R@Ivzz*5TT9TU]]^bdjkH09,?nL'0#6PJr
 s}  r~  ~N  OX  NY  Y[  \g  [h hDDP>Q[\d\k\klrlvlv  xE  FH  mI  ]J  \K  KM  NX  MY  Yl  mu  m|  m|  }C  }G  }G  HS  TV  }W  mX  lY  Yz  {A  {E  {E  FX  {Y  zZ  Zm  nv  n}  n}  ~D	  ~H	  ~H	  I	W	  X	Z	  ~[	  n\	  m]	  ]	N
  O
U
  O
Y
  O
Y
  Z
l
  O
m
  N
n
 n
8 9B8W8WEW7X  YT  U]  T^ ^
 
r   c                  6    \         P                  ;'       g    R # r   )r   remote_addrr   r   rK   get_client_ipr  7  s    $$"$r   c                     \         P                  ! T ;'       g    R P                  R^4      ^ ,          4      pVP                  ^8H  ;'       d    V\         P                  ! R4      9   pVP                  ^8H  ;'       d    V\         P                  ! R4      9   pVP
                  ;'       g5    VP                  ;'       g!    VP                  ;'       g    T;'       g    T#   \         d     R# i ; i)r}   %z100.64.0.0/10zfd7a:115c:a1e0::/48F)		ipaddress
ip_addressr   r  
ip_networkis_loopback
is_privateis_link_localrE   )ip_textiptailscale_ipv4tailscale_ipv6s   &   rK   is_private_or_loopback_ipr
  <  s    !!7==b"7"7Q"?"BCqXXR93G3G3X-Xq^^R93G3GH]3^-^~~ffff"2B2BffnffXff s:   C! 3C! /C! ?,C! ,C!  C! 	C! C! !C0/C0c                      \         '       g   R# \        4       p \        V 4      '       g   R RV  23# \        P                  R8w  d   R# R# )FuW   פעולת מחשב חסומה מכתובת שאינה מקומית/רשת ביתית: r9   )Fuj   פעולות כיבוי/ריסטארט מחשב כבויות בהגדרת TRIPSERVER_ENABLE_POWER_ACTIONS.)Fu<   פעולות מחשב נתמכות כאן רק על Windows.r  )POWER_ACTIONS_ENABLEDr  r
  r=   r>   r  s    rK   power_action_allowedr  F  sR       C  	C	B$R((oprosttt	ww$TTr   c                      \        V 4      p\        \        \        \        V4      4      #   \         d
    \        p L1i ; irY   )r[   rE   POWER_DEFAULT_DELAY_SECONDSr   POWER_MIN_DELAY_SECONDSr  POWER_MAX_DELAY_SECONDS)	raw_valuedelays   & rK   normalize_power_delayr  Q  s>    ,I &,CU(KLL  ,+,s   + ??c           	         V R 8X  d   RpRpMV R8X  d   RpRpM\        R4      h\        V4      pRV 2pR VR\        V4      R	V.p\        P                  ! VR
R
RR7      pVP
                  ^ 8w  dB   \        VP                  ;'       g    VP                  ;'       g    RP                  4       4      h\        RV  RV R\        4        24       Y4VP                  P                  4       ;'       g    VP                  P                  4       3# )ri   z/srk   rj   z/rrl   zunknown power actionzTripServer Admin scheduled z/tz/cTFr4  r5  r  zshutdown command failedzPOWER z scheduled in zs by )r  r  r   r@  rA  rB  rs  rC  rD  rZ   r%  r  )r  delay_secondsr   rN   r  commentrG  r  s   &&      rK   run_power_commandr  Y  s    %	8	+/00!-0E+E73GtT3u:tW
=Cs4d%PIq I,,]]	0@0@]]D]ddfggvhnUG5@QRS))//1MMY5E5E5K5K5MMMr   c                  t   \         P                  ! R R.RRRR7      p \        R\        4        RV P                   RV P
                  P                  4        RV P                  P                  4        24       V P                  V P
                  ;'       g    V P                  ;'       g    R	P                  4       3# )
ri   z/aTFr  zPOWER cancel requested by z | rc=z | out=z | err=r}   )r@  rA  r%  r  rB  rD  rZ   rC  )r  s    rK   cancel_power_commandr  l  s    
D1$TY^_I2=?2C6)J^J^I__fgpgwgwg}g}g  gA  AH  IR  IY  IY  I_  I_  Ia  Hb  c  d)"2"2"L"Li6F6F"L"L"!S!S!UUUr   c                  f    \         '       g   R# \        4       p \        V 4      '       g   R RV  23# R# )Fuc   גישה למצלמה חסומה מכתובת שאינה מקומית/רשת ביתית/Tailscale: )FuE   מצלמת החדר כבויה בהגדרת TRIPSERVER_ENABLE_WEBCAM.r  )CAMERA_ENABLEDr  r
  r  s    rK   camera_access_allowedr  s  sC    >]]	B$R(({|~{  A  A  	Ar   c                      R \         RRRRR\        /p  ^ RIpRV R&   \        VRR4      V R&   V #   \         d   pRT R&   \        T4      T R	&    Rp?T # Rp?ii ; i)
enabledopencvFopencv_versionr}   camera_indexNT__version__r,  )r  CAMERA_INDEXcv2r  rE   r   )r   r'  r&  s      rK   camera_engine_statusr(  |  sv    5:JBP^`lmF#x#*3r#B  M  # xc(wM#s   / AAAc                   P   a  ] tR tRt o R tR tR tR tR tR t	R t
R	 tR
tV tR# )WebcamManageri  c                    \         P                  ! 4       V n        R V n        RV n        RV n        ^ V n        RV n        RV n        R # N        r}   F)		threadingRLocklockcap	opened_atlast_frame_atframes
last_errorstop_requestedselfs   &rK   __init__WebcamManager.__init__  s<    OO%	 #r   c                    ^ RI pV# r  )r'  )r8  r'  s   & rK   _import_cv2WebcamManager._import_cv2  s
    
r   c                   V P                  4       pV P                  e#   V P                  P                  4       '       d   V# RV n        \        P
                  R8X  d   \        VR^ 4      M^ pVP                  \        V4      p VP                  \        VR^4      \        4       VP                  \        VR^4      \        4       VP                  \        VR^4      \        4       V'       d   VP                  4       '       g6    VP                  4        R\         R2V n        \!        V P                  4      hW0n        \"        P"                  ! 4       V n        ^ V n        R	V n        V#   \         d     Li ; i  \         d     Lri ; i)
NFr9   	CAP_DSHOWCAP_PROP_FRAME_WIDTHCAP_PROP_FRAME_HEIGHTCAP_PROP_FPSu.   לא הצלחתי לפתוח מצלמה index=uW   . בדוק הרשאות Windows או מצלמה תפוסה באפליקציה אחרת.r}   )r<  r1  isOpenedr6  r=   r>   r  VideoCapturer&  r  CAMERA_WIDTHCAMERA_HEIGHT
CAMERA_FPSrE   releaser5  rs  rU  r2  r4  )r8  r'  backendr1  s   &   rK   _open_lockedWebcamManager._open_locked  sD    88DHH$5$5$7$7J#24''T/'#{A.q|W5	GGGC!7;\JGGGC!8!<mLGGGC3Z@ #,,.. !O|n  ]t  uDOt//
  		
  s%   A#E) E: )E76E7:FFc                d   V P                   ;_uu_ 4        V P                  e$   \        V P                  RR 4      ! 4       '       g	   RV n        MV P                  '       d   \	        R4      hV P                  4       pV P                  P                  4       w  r#V'       d   Vf3   \        P                  ! R4       V P                  P                  4       w  r#V'       d   Vf   RV n	        \	        V P                  4      hVP                  RV\        \        VR^4      4      \        .4      w  r$V'       g   R	V n	        \	        V P                  4      hV ;P                  ^,          un        \        P                  ! 4       V n        VP                  4       uuR R R 4       #   + '       g   i     R # ; i)
NrC  c                      R # Fr   r   r   rK   r   )WebcamManager.read_jpeg.<locals>.<lambda>  s    Ur   Fu"   המצלמה כובתה ידניתg333333?u,   לא התקבלה תמונה מהמצלמה.ru  IMWRITE_JPEG_QUALITYu4   קידוד תמונת המצלמה ל־JPG נכשל.)r0  r1  r  r6  rs  rJ  r   rU  r  r5  imencoder[   CAMERA_JPEG_QUALITYr4  r3  tobytes)r8  r'  r   frameencodeds   &    rK   	read_jpegWebcamManager.read_jpeg  s!   YYY
 xxwtxx]'S'U'U&+#$$$"#GHH##%CIB

4  HHMMO	"P"4??33,,vus73H^`a;b7cex6yzKB"X"4??33KK1K!%D??$/ YYYs   AF!A<FB5FF/	c                   V P                   ;_uu_ 4        R V n        V P                  e    V P                  P                  4        RV n        RV n        RRR4       R#   \         d     L%i ; i  + '       g   i     R# ; i)TNr-  )r0  r6  r1  rH  rE   r2  r7  s   &rK   stopWebcamManager.stop  sg    YYY"&Dxx#HH$$& DH DN Y
 !  YYs.   A/AA/A,)A/+A,,A//B 	c                   V P                   ;_uu_ 4        V P                  e    V P                  P                  4        RV n        RV n        RV n        RV n         RRR4       R#   \         d     L4i ; i  + '       g   i     R# ; i)zRelease stale webcam handles and allow the next stream to start.

This is intentionally lighter than a full camera reset: it does not stop
audio or recording. It is used before assigning a new MJPEG src in the UI.
Nr-  Fr}   T)r0  r1  rH  rE   r2  r6  r5  r7  s   &rK   prepare_new_stream WebcamManager.prepare_new_stream  ss     YYYxx#HH$$& DH DN"'D DO Y ! 	 YYs-   A7A&A7&A41A73A44A77B	c                    V P                  4        V P                  ;_uu_ 4        RV n        RV n        ^ V n        RV n        RRR4       R#   + '       g   i     R# ; i)z>Stop all current webcam capture state and clear sticky errors.Fr}   r-  NT)rY  r0  r6  r5  r4  r3  r7  s   &rK   force_resetWebcamManager.force_reset  sI    		YYY"'D DODK!$D	 
  Y
 s   AA	c                ~   V P                   ;_uu_ 4        \        V P                  R J;'       d    V P                  P                  4       4      pR\        RTR\
        R\        R\        R\        R\        RV P                  '       d6   \        P                  ! R	\        P                  ! V P                  4      4      MR
RV P                  '       d6   \        P                  ! R	\        P                  ! V P                  4      4      MR
RV P                  RV P                   /uuR R R 4       #   + '       g   i     R # ; i)Nr!  activer$  widthheightfpsjpeg_qualityr2  r
   r}   r3  r4  r5  )r0  r   r1  rC  r  r&  rE  rF  rG  rR  r2  rU  rV  rC  r3  r4  r5  r8  rb  s   & rK   r   WebcamManager.status  s    YYY$(($.FF4883D3D3FGF>&-z 3cgcqcqcqT]]+>t~~@^_wykok}k}k}/BDNNSWSeSeDf!g  DF$++doo YYYs   A2D+AD+AD++D<	)r1  r4  r5  r3  r0  r2  r6  N)__name__
__module____qualname____firstlineno__r9  r<  rJ  rV  rY  r\  r_  r   __static_attributes____classdictcell____classdict__s   @rK   r*  r*    s2     $4%4	!$ r   r*  c                     \         P                  ! \        R R7       \        \         P                  P                  \        R4      RRR7      ;_uu_ 4       pVP                  \        P                  ! R4      R,           \        V 4      ,           R,           4       R	R	R	4       R	#   + '       g   i     R	# ; i  \         d     R	# i ; i)
TrK  zcamera_security.logr  rm  r  r
   r#  rn  N)r=   rS  r  r   r?   rD   r  rU  rV  r   rE   r  s   & rK   log_camera_eventrr  	  s    
Ht,"'',,x)>?wWW[]HHT]]#67%?#g,NQUUV XWWW s1   AB8 AB$B8 $B5	/B8 5B8 8CCc                   a R. R. R. R. RR/ R/ /RRRR/o\        4       p V '       g   R	SR&   S# \        P                  R
8w  d   RSR&   S#  \        P                  ! V RRRRRRR.RRRR^R7      pVP
                  ;'       g    RR,           VP                  ;'       g    R,           pVR"R SR&   RpRpRpV3R lpV3R lpVP                  4        EFV  pVP                  4       p	RV	9   d	   RpRpRpK#  RV	9   d	   RpRpRpK2  \        P                  ! RV\        P                  R7      p
V
'       d+   V'       d#   V'       d   V! WTV
P                  ^4      4       K  \        P                  ! RV4      pV'       d<   VR#9   d5   R V	9  d.   VP                  ^4      P                  4       pV! W<4       TpTpK  \        P                  ! R!V\        P                  R7       FF  w  rVP                  4       R8X  d   RMRpV! WP                  4       4       VP                  4       pTpKH  	  EKY  	  S#   \         d   p\!        T4      SR&    Rp?S# Rp?ii ; i)$a  Return DirectShow audio/video devices available to FFmpeg on Windows.

v22 fix: FFmpeg on Windows usually prints devices under section headers like
"DirectShow audio devices" and then plain quoted names. Older builds only
looked for a non-standard `"name" (audio)` suffix, so microphones could be
missed even when they existed. This parser supports both formats and also
stores Alternative names, which are often more reliable than friendly names.
videoaudio	video_alt	audio_altalternativesr,  r}   r   u   FFmpeg לא נמצא.r9   uk   זיהוי התקני מצלמה/מיקרופון דרך DirectShow נתמך כאן בעיקר ב־Windows.r*  z-list_devicestrue-fdshowr-  dummyTrm  r   r4  r5  rp  rq  r6  rn  Nc                    < V '       d	   V'       g   R # V R8X  d   RMRpVSV,          9  d   SV,          P                  V4       R # R # )Nrt  ru  )r  )kindr>   bucketdevicess   && rK   
add_device(ffmpeg_dshow_devices.<locals>.add_device/	  s;    t $WWF76?*&&t, +r   c                    < V '       d   V'       d	   V'       g   R # V R8X  d   RMRpVSR,          P                  V / 4      V&   VSV,          9  d   SV,          P                  V4       R # R # )Nrt  rv  rw  rx  )
setdefaultr  )r  r>   alt
alt_bucketr  s   &&& rK   add_alt%ffmpeg_dshow_devices.<locals>.add_alt6	  s[    t3(,[JADGN#..tR8>'*--
#**3/ .r   zdirectshow video deviceszdirectshow audio deviceszAlternative name\s+"([^"]+)")r  z\]\s+"([^"]+)"zalternative namez"([^"]+)"\s+\((video|audio)\)i>   ru  rt  )r   r=   r>   r@  rA  rD  rC  
splitlinesrA   ru  searchIrx  rZ   ry  rE   r   )r   r  r   sectioncurrent_namecurrent_kindr  r  linelow	alt_match
name_matchr>   r  r&  r  s                  @rK   ffmpeg_dshow_devicesr  	  sd    GRb+r>\cegiprt[uw~  AC  EJ  LN  OG#%F2	ww$ I>$NN^_fdGTSZ[
	 %%2-1A1A1G1GRHUV	-	0 NN$D**,C)S0!##)S0!##		"A4rttTI\lIOOA4FG#4d;Jg);;@RZ]@]!''*0027)#& jj)I4WYW[W[\
"&**,'"9ww4.#zz|#	 ]5 %B N  $s8N$s>   6H/ H/ BH/ 3H/ ;H/ 8H/ <B1H/ /I:IIc                     T ;'       g    R P                  4       p\        P                  ! RV4      p0 RmpV Uu0 uF  p\        V4      ^8  g   K  WC9  g   K  VkK!  	  up# u upi )r}   u   [a-z0-9א-ת]+>   hdmicprousbarrayru  rt  cameradevicestreamwebcamcapture
microphone   מערך
   מצלמה   מיקרופון)rA   ru  ry  r   )r>   r5  tokensrY  ts   &    rK   _device_tokensr  b	  sY    JJBDZZ)40F qD?v!Q1AAAv???s   A"A"A"c                 ^  a T ;'       g    \        4       p \        '       d   R \        RRRRRR/.# \        ;'       g$    V P                  R4      ;'       g    R.^ ,          p\	        V4      p. pV P                  R	4      ;'       g    / P                  R
/ 4      p\        V P                  R
4      ;'       g    . 4       F  w  rV\	        V4      p^dV,
          pV'       d(   V'       d    V^\        W',          4      ,          ,          pVP                  4       o\        ;QJ d    V3R lR 4       F  '       g   K   RM	  RM! V3R lR 4       4      '       d
   V^,          pVP                  R VRRRVRR/4       VP                  V4      p	V	'       g   K  VP                  R V	RRV 2RV^,
          RR/4       K  	  VP                  R RR7       . p
\        4       pV FM  pVR ,          '       g   K  VR ,          V9  g   K$  V
P                  V4       VP                  VR ,          4       KO  	  V
# )r>   r   envscore  r  Frt  r}   rx  ru  c              3   ,   <"   T F	  qS9   x  K  	  R # 5irY   r   )r\   r  r  s   & rK   r^   -preferred_audio_candidates.<locals>.<genexpr>x	  s     a!`ACx!`s   Tfriendlyalternative for c                 &    V P                  R ^ 4      # )r  r   )r  s   &rK   r   ,preferred_audio_candidates.<locals>.<lambda>~	  s    AEE'1-r   r   reverse)r  r  logitechc920c922brior  )r  CAMERA_AUDIO_DEVICECAMERA_VIDEO_DEVICEr   r  	enumerater   rA   anyr  r  r  r  )r  rt  video_tokensr  rx  ir>   r  r  r  r  r  rowr  s   &            @rK   preferred_audio_candidatesr  i	  s   //-/G,hwUTYZ[[DDGKK$8$@$@RD!#DE!%(LDKK/552::7BGLW[[177R8%aFR#l3444Ejjl3a!`a333a!`aaaRKEVT8Z%PUVWt$3KKh2B4&0I7TY\]T]_dfjkl 9 	II-tI<F5Dv;;3v;d2MM#HHS[!  Mr   c                    T ;'       g    \        4       p \        '       d   R \        RRRRRR/.# V P                  R4      ;'       g    / P                  R/ 4      p. p\        V P                  R4      ;'       g    . 4       Fe  w  r4^dV,
          pVP	                  R VRR	RVRR/4       VP                  V4      pV'       g   KB  VP	                  R VRR
V 2RV^,
          RR/4       Kg  	  . p\        4       pV FM  p	V	R ,          '       g   K  V	R ,          V9  g   K$  VP	                  V	4       VP                  V	R ,          4       KO  	  V# )r>   r   r  r  r  r  Frx  rt  r  r  T)r  r  r   r  r  r  r  )
r  rx  r  r  r>   r  r  r  r  r  s
   &         rK   preferred_video_candidatesr  	  s8   //-/G,hwUTYZ[[KK/552::7BGLDW[[177R8aVT8Z%PUVWt$3KKh2B4&0I7TY\]T]_dfjkl 9 F5Dv;;3v;d2MM#HHS[!  Mr   c                      \        4       p \        V 4      p\        V 4      pWR &   W R&   V'       d   V^ ,          R,          MRpV'       d   V^ ,          R,          MRpW4V 3# )video_candidatesaudio_candidatesr>   r}   )r  r  r  )r  r  r  rt  ru  s        rK   selected_ffmpeg_devicesr  	  se    "$G1':1':"2"2+;Q'E+;Q'E  r   c                     . pV '       d   VP                  R V ,           4       V'       d   VP                  RV,           4       RP                  V4      # )zvideo=audio=:)r  rD   )video_deviceaudio_devicer   s   && rK   dshow_input_namer  	  s=    EX,-X,-88E?r   c           	          V '       d&   \         P                  P                  V 4      '       g   R # \        V R4      ;_uu_ 4       pVP	                  ^ \         P
                  4       VP                  4       pVP	                  \        ^ W1,
          4      4       VP                  4       P                  RRR7      pRRR4       XV) R #   + '       g   i     L; i  \         d     R # i ; i)r}   r   rm  r   rq  N)r=   r?   rC   r   seekSEEK_ENDtellr   r   decoderE   )r?   	max_charsr   r  r   s   &&   rK   tail_text_filer  	  s    
277>>$//$GGAr{{#779DGGC4+,-779##GI#>D	 
 YJK     s4   C $C C A3C8C C	C C('C(c                   `   a  ] tR tRt o R tR tR tR tRR ltR t	R t
R	 tR
 tR tRtV tR# )CameraAudioStreamManageri	  c                    \         P                  ! 4       V n        R V n        RV n        RV n        RV n        \        V n        R V n	        . V n
        R # )Nr-  r}   )r.  r/  r0  procr   r  r5  CAMERA_AUDIO_LOG_PATHr  
log_handlecandidates_triedr7  s   &rK   r9  !CameraAudioStreamManager.__init__	  sB    OO%		- "r   c                     V P                   '       d   V P                   P                  4        R T n         R #   \         d     Li ; irY   )r  closerE   r7  s   &rK   _close_log_locked*CameraAudioStreamManager._close_log_locked	  s=    	%%'   		s   7 7 AAc                X    \         P                  ! \        R R7       \        \        RRR7      ;_uu_ 4       pVP                  \        P                  ! R4      R,           \        V4      ,           R,           4       RRR4       R#   + '       g   i     R# ; i  \         d     R# i ; ir"  )
r=   rS  r  r   r  r  rU  rV  r   rE   r8  r  r   s   && rK   _append_audio_log_locked1CameraAudioStreamManager._append_audio_log_locked	  sr    	KK40+S7CCr':;eCc'lRUYYZ DCCC 		r  c                   \         P                  ! \        R R7       V P                  R\	        V4      ,           4       \        \        R4      pR*\        P                  ! R4      ,           R,           \	        V4      ,           R,           P                  RRR	7      p VP                  V4       VP                  4        VR
RRRRRRRRRV,           RRRRRRRRRRRR.p\         P                  R8X  d   \        \        R ^ 4      M^ p\        P                   ! V\        P"                  \        P$                  W6R!7      p\        P&                  ! R"4       VP)                  4       e    VP                  4        VP+                  4        \-        \        R$4      pV P                  R%\	        V4      ,           4       V P.                  P1                  R&VR'R(/4       R)\	        V4      ,           R,           VR+R# ,           V n        R,# V P.                  P1                  R&VR'R /4       Ws3#   \         d     ELqi ; i  \         d     Li ; i)-TrK  ztrying audio device: abrn  r
   z | ffmpeg audio start | device=rm  r   r  r*  -nostdinr+  warningrz  r{  
-rtbufsize64Mr-  r  r.  -acrg   r2  re   r/  r0  r1  96kmp3zpipe:1r9   r   r  rD  rC  r  g      ?Ni	  zdevice failed immediately: r  r   Fu;   FFmpeg לא הצליח לפתוח את המיקרופון: H
======================================================================
r<  NN)r=   rS  r  r  r   r   r  rU  rV  encoder  flushrE   r>   r  r@  r  r	  PIPEr  pollr  r  r  r  r5  )	r8  r   
audio_namelogfhheaderrG  r  r  errs	   &&&      rK   _start_candidate_locked0CameraAudioStreamManager._start_candidate_locked	  s7   
Ht,%%&=J&OP*D1(4==9L+MMPqqtw  yC  uD  D  GK  K  S  S  T[  dm  S  n	KKKKM NJY'<h6K5#ugz<QVX\^cem

 OQggY]o
,FJcd:+=+=joo^c  B

499;" !!6=C))*G#j/*YZ!!(((Je)LM[^abl^mmpttwz  |A  |B  xC  CDO$$h
D$%GH{-  		  s$   !H # H1 H.-H.1H?>H?c                    V P                   ;_uu_ 4        V'       d   V P                  4        V P                  4       uuR R R 4       #   + '       g   i     R # ; irY   )r0  stop_lockedstart_locked)r8  rM   s   &&rK   startCameraAudioStreamManager.start	  s2    YYY  "$$& YYYs   (AA	c                B   V P                   e)   V P                   P                  4       f   V P                   # \        '       g   \        R4      h\	        4       pV'       g   \        R4      h\        4       w  r#p\        V4      p. V n        V'       gB   VP                  R4      ;'       g    RR	R  pRV,           V n	        \        V P                  4      hRpV F  pVP                  R4      ;'       g    Rp	V	'       g   K(  V P                  W4      w  rV
eP   Wn         Wn        \        P                  ! 4       V n        Wn        RV n	        \        RV	 24       V P                   u # V P                  pK  	  R V n         V P!                  4        V'       g   Rp\        V4      h)
NuK   אודיו מצלמה כבוי בהגדרת TRIPSERVER_ENABLE_CAMERA_AUDIO.uJ   FFmpeg לא נמצא. נדרש FFmpeg כדי להזרים אודיו חי.r   r}   u   לא נמצא התקן מיקרופון ב־FFmpeg. בדוק הרשאות Windows או הגדר TRIPSERVER_FFMPEG_AUDIO_DEVICE.
r>   zaudio stream started | device=u`   כל ניסיונות פתיחת האודיו נכשלו. בדוק לוג אודיו מצלמה.i<)r  r  CAMERA_AUDIO_ENABLEDrs  r   r  r  r  r   r5  r  r  rU  r   r  rr  r  )r8  r   rP  ru  r  r   raw_tailr5  r  r>   r  r  s   &           rK   r  %CameraAudioStreamManager.start_locked 
  sd   99 TYY^^%5%=99##lmm')kll35'/8
 "E*00b%&9H b  em  mDOt//
C776?((bD66vDKD 	"'"&))+""$ #A$!HIyy J  	 {J:&&r   c              #    "    V P                   ;_uu_ 4        V P                  4       pR R R 4       Xe   VP                  4       fm   VP                  '       d   VP                  P	                  R4      MRpV'       g0   VP                  4       e   R\        \        R4      ,           V n        MVx  K  V P                  4        R #   + '       g   i     L; i  \         d     L2\         d@   p\        T4      T n        T P                  R\        T4      ,           4       Rx   R p?LvR p?ii ; i  T P                  4        i ; i5i)Nr   r   u5   שידור האודיו נסגר על ידי FFmpeg. @  zstream exception: )r0  r  r  rD  r   r  r  r5  GeneratorExitrE   r   r  r  rY  )r8  r  r  r&  s   &   rK   stream_chunks&CameraAudioStreamManager.stream_chunks$
  s     	((* "tyy{':26+++((.3yy{.*adr  tI  KO  eP  +P IIK!   	 	!#hDO))*>c*JKI	
 IIKsz   EC C/C $C >.C ,D1 -C 3EC	C D.#D1 %D..D./5D)$D1 )D..D1 1EEc                4   V P                   pR V n         Ve6   VP                  4       f$    VP                  4        VP                  ^R7       V P                  4        RV n        R #   \         d'     TP                  4         L7  \         d      LEi ; ii ; i)Nr  r-  )r  r  	terminatewaitrE   killr  r   r8  r  s   & rK   r  $CameraAudioStreamManager.stop_locked8
  s    yy			 3 		!	$ 	   IIK  s)   "A& &B2BBBBBc                    V P                   ;_uu_ 4        V P                  4        \        R 4       RRR4       R#   + '       g   i     R# ; i)zaudio stream stoppedN)r0  r  rr  r7  s   &rK   rY  CameraAudioStreamManager.stopG
  s,    YYY34 YYYs	   ;A	c                   V P                   ;_uu_ 4        \        V P                  R J;'       d    V P                  P                  4       R J 4      pR\        RTRV P
                  RV P                  '       d6   \        P                  ! R\        P                  ! V P                  4      4      MRRV P                  R\        R	V P                  /uuR R R 4       #   + '       g   i     R # ; i)
Naudio_enabledrb  r  r   r
   r}   r5  r  r  )r0  r   r  r  r   r  r   rU  rV  rC  r5  r  r  rg  s   & rK   r   CameraAudioStreamManager.statusL
  s    YYY$))4/LLDIINN4D4LMF!5&$++eietetetdmm,?PTP_P_A`az|doo1"D$9$9 YYYs   A"C8ACC)	)r  r  r5  r0  r  r  r  r   NrN  )ri  rj  rk  rl  r9  r  r  r  r  r  r  r  rY  r   rm  rn  ro  s   @rK   r  r  	  s>     #@'"'H(5
 r   r  c                   B   a  ] tR tRt o R tR tR	R ltR tR tRt	V t
R# )
CameraRecordingManageriZ
  c                    \         P                  ! 4       V n        R V n        RV n        RV n        RV n        RV n        RV n        RV n	        RV n
        R V n        R # r,  )r.  r/  r0  r  r   	file_pathr  r5  
with_audior  r  r  r7  s   &rK   r9  CameraRecordingManager.__init__[
  sQ    OO%		r   c                   V P                   ec   V P                   P                  4       eE    V P                  '       d   V P                  P                  4        R T n        R T n         RT n        R # R # R #   \         d     L(i ; i)Nr-  )r  r  r  r  rE   r   r7  s   &rK   _refresh_locked&CameraRecordingManager._refresh_lockedg
  sn    99 TYY^^%5%A???OO))+ #DODI!DO &B   s   A3 A3 3B Bc                   V P                   ;_uu_ 4        V P                  4        V P                  e(   V P                  P                  4       f   \	        R4      h\
        '       g   \	        R4      h\        4       pV'       g   \	        R4      h\        4       w  r4pV'       g   \	        R4      hV'       d   V'       g   \	        R4      h\        P                  ! \        RR7       \        P                  ! R4      p\        P                  P                  \        R	V R
24      p\        P                  P                  \        R	V R24      p\        Y1'       d   TMR4      p	VRRRRRRR\!        \"        4      R\$         R\&         2RV	R\!        \(        4      RRRRRRRR.p
V'       d   V
R R!R"\*        .,          p
M
V
R#.,          p
V
R$R%V.,          p
\-        VR&4      p\        P.                  R'8X  d   \1        \2        R(^ 4      M^ p\2        P4                  ! V
\2        P6                  \2        P8                  WR)7      V n        Wn        \        P                  ! 4       V n        Wpn        Wn         RV n!        \E        V4      V n#        W0n$        V'       d   TMRV n%        \M        R*\O        4        R+T R,T R-V PJ                  ;'       g    R. 24       VuuR R R 4       #   + '       g   i     R # ; i)/NuR   יש כבר הקלטה פעילה. עצור אותה לפני התחלה חדשה.uQ   הקלטת מצלמה כבויה בהגדרת TRIPSERVER_ENABLE_CAMERA_RECORDING.uP   FFmpeg לא נמצא. נדרש FFmpeg כדי להקליט וידאו/אודיו.uy   לא נמצא התקן מצלמה ב־FFmpeg. בדוק הרשאות Windows או הגדר TRIPSERVER_FFMPEG_VIDEO_DEVICE.ua   ביקשת הקלטה עם אודיו, אבל לא נמצא התקן מיקרופון ב־FFmpeg.TrK  rM  room_camera_.mp4z.ffmpeg.logr}   r*  r)  rz  r{  r  512M
-framerate-video_sizerS  r-  -t-c:vlibx264-presetveryfastz-crf23-pix_fmtyuv420p-c:aaacr1  -anz	-movflagsz
+faststartr  r9   r   r  zrecording started by  | file=	 | video=	 | audio=no-audio)(r0  r  r  r  rs  CAMERA_RECORDING_ENABLEDr   r  r=   rS  CAMERA_RECORDINGS_DIRrU  rV  r?   rD   r  r   CAMERA_RECORD_FPSrE  rF  CAMERA_RECORD_MAX_SECONDSCAMERA_AUDIO_BITRATEr   r>   r  r@  r  r  r	  r  r   r  r  r5  r   r  r  r  rr  r  )r8  r  r   rt  ru  r  r\  r  r  
input_namerG  r  r  s   &&           rK   r  CameraRecordingManager.startr
  s   YYY  "yy$)9)A"#wxx++"#vww+-F"#uvv$;$=!E'"  $_  `  `%"  $G  H  HKK-=MM/2EWW\\"7<wd9STFww||$9\%P[;\]H)%*"MJdG\6c"34m~UVWdVeEfj$,E(F	9j&$
T]	C v/CDDwKv66C4(ERTRYRY]aRaGJ0JANghM"((JOOJL^L^gl  KDI#O"iikDO#N$M DO":.DO %)3D4]_4EXfXU^_d^eenos  pA  pA  pO  pO  EO  oP  Q  RU YYYs&   AK'AK7K?HK
KK*	c                r   V P                   ;_uu_ 4        V P                  4        V P                  pVf!   V P                  ;'       g    RuuR R R 4       #  VP                  '       d6   VP                  P                  R4       VP                  P                  4         TP                  ^
R7        T P                  '       d   T P                  P                  4        R T n        R T n        RT n        \        R\        4        RT P                   24       T P                  uuR R R 4       #   \         d'     TP                  4         L  \         d      Li ; ii ; i  \         d'     TP                  4         L  \         d      Li ; ii ; i  \         d     Li ; i  + '       g   i     R # ; i)Nr}      qr  r-  zrecording stopped by r-  )r0  r  r  r  r  r  r  rE   r	  r
  r  r  r  r   rr  r  r  s   & rK   rY  CameraRecordingManager.stop
  s^   YYY  "99D|~~++	 Y
:::JJ$$T*JJ$$&		"	%???OO))+ #DODI!DO4]_4EXdnnM]^_>>= Y  NN$    IIK    1 YYs   3F%	F%D,)5D,E 2FFAF%,E8E
F%
E	EF%E	EF% F,E><F%>F		F
F%F	FF%F"F%!F""F%%F6	c                    V P                   ;_uu_ 4        V P                  4        \        V P                  R J;'       d    V P                  P	                  4       R J 4      pV P
                  '       dY   \        P                  P                  V P
                  4      '       d*   \        P                  P                  V P
                  4      M^ pR\        RTRV P
                  RV P
                  '       d*   \        P                  P                  V P
                  4      MRRTRV P                  '       d6   \        P                  ! R\        P                  ! V P                  4      4      MRR	V'       dB   V P                  '       d0   \!        \        P                  ! 4       V P                  ,
          4      M^ R
V P"                  RV P$                  RV P&                  RV P(                  RV P*                  /uuR R R 4       #   + '       g   i     R # ; i)Nrecording_enabledrb  r  r  r}   r  r   r
   elapsed_secondsr  r  r  r  r5  )r0  r  r   r  r  r  r=   r?   rC   r   r1  r@   r   rU  rV  rC  r[   r  r  r  r  r5  )r8  rb  r  s   &  rK   r   CameraRecordingManager.status
  sT   YYY  "$))4/LLDIINN4D4LMF6:nnnX\XfXfIgIg277??4>>2mnD#%=&T^^RWW--dnn=UWTeietetetdmm,?PTP_P_A`az|!TXTcTcTc3tyy{T__'D#Eijdoo 1 1 1 1DMMdoo	 YYYs2   AG<3.G<"AG<4>G<3>G<2G<A-G<<H	)
r  r  r5  r0  r  r  r  r   r  r  N)T)ri  rj  rk  rl  r9  r  r  rY  r   rm  rn  ro  s   @rK   r  r  Z
  s%     
	"+Z"B r   r  c                   b   a  ] tR tRt o RtR tR tR tR tRR lt	RR lt
R	 tR
 tR tRtV tR# )CameraHlsStreamManageri
  a\  Unified video+audio live stream using one FFmpeg DirectShow process.

Some USB webcams expose camera and microphone as one physical device. Opening
video through OpenCV and audio through a separate FFmpeg process can fail or
lock the device. HLS captures `video=...:audio=...` in one process, closer to
how Zoom/Teams uses the camera+mic together.
c                    \         P                  ! 4       V n        R V n        RV n        RV n        RV n        RV n        RV n        RV n	        R # )Nr-  r}   Tr   )
r.  r/  r0  r  r   r  r  r  r5  r   r7  s   &rK   r9  CameraHlsStreamManager.__init__
  sC    OO%			r   c                X    \         P                  ! \        R R7       \        \        RRR7      ;_uu_ 4       pVP                  \        P                  ! R4      R,           \        V4      ,           R,           4       RRR4       R#   + '       g   i     R# ; i  \         d     R# i ; i)	TrK  r  rm  r  r
   z	 | hls | rn  N)
r=   rS  r  r   CAMERA_HLS_LOG_PATHr  rU  rV  r   rE   r  s   && rK   _logCameraHlsStreamManager._log
  ss    	KK40)3AAR':;kICPWLX[__` BAAA 		r  c                    \         P                  ! \        R R7       \         P                  ! \        4       Fc  pVP	                  4       P                  R4      '       g   K*   \         P                  ! \         P                  P                  \        V4      4       Ke  	  R#   \         d     Kw  i ; i  \         d-   pT P                  R\        T4      ,           4        Rp?R# Rp?ii ; i)TrK  zclean hls dir failed: N).m3u8.tsr   )r=   rS  CAMERA_HLS_DIRr  rA   r  r  r?   rD   rE   rE  r  )r8  r>   r&  s   &  rK   _clean_dir_locked(CameraHlsStreamManager._clean_dir_locked
  s    		<KK6

>2::<(()ABB		"'',,~t"DE 3 %  	<II.c:;;	<s<   AB3 #8B!B3 !B0,B3 /B00B3 3C*>!C%%C*c           
        \          R\         2p. pVRRR3 F  pW29  g   K  VP                  V4       K  	  . p\        ^^^
3 F1  p \	        V4      pT^ 8  g   K  Y49  g   K   TP                  T4       K3  	  . pVR,           F)  pVP                  RV RV 2RVR	\        V4      .34       K+  	  V F  pVP                  RV R
2RV.34       K  	  V F$  pVP                  RV 2R	\        V4      .34       K&  	  VP                  R. 34       \        4       p. p	V F;  w  r\        V4      pW9  g   K  V	P                  W34       VP                  V4       K=  	  V	#   \
         d     EK*  i ; i)aq  Return DirectShow option fallbacks for webcams.

Some USB webcams, including EMEET models, work in OpenCV but reject a
forced FFmpeg DirectShow combination such as -video_size 1280x720
together with -framerate 15. FFmpeg then fails with: Could not set video
options. v25 tries progressively safer combinations and finally lets the
driver auto-negotiate the video mode.
rS  1280x720640x480	1920x1080:Nr  Nzsize=z,fps=r!  r   z	,auto-fpszauto-size,fps=zdriver-auto)
rE  rF  r  r3  r[   rE   r   r  r  r  )r8  preferred_sizecommon_sizesr   
fps_valuesr   re  r  r  uniquerN   optsr   s   &            rK   _hls_input_option_candidates3CameraHlsStreamManager._hls_input_option_candidates
  s    )>=/:#ZKHD'##D) I 
&B3D4y axD2!!$' 4 
b>>C~&6eC5AMSacoqtuxqyCz{| " DtfI68MNO !Cu5c#h7OPQ ="-.u%KE+Cum,	 &
 )  s   EE/.E/c                
   \        4       pV'       g   \        R 4      hV P                  4        \        P                  P                  \        R4      p\        P                  P                  \        R4      p\        W4      p\        P                  ! \        P                  P                  \        4      RR7       RpV P                  4        EF  w  rV P                  4        VRRRR	R
RRRR.
\        V	4      ,           RVRRRRRRRRR\        \        4      .,           p
V'       d   V
RRR\        RRRR.,          p
M
V
R .,          p
V
RR!R"RR#R$R%R&R'VV.,          p
\!        \        R(4      p RF\"        P$                  ! R*4      ,           R+,           V,           R,,           V,           R-,           R.P                  V
4      ,           R),           P'                  R/R0R17      pVP)                  V4       VP+                  4        \        P.                  R28X  d   \1        \2        R3^ 4      M^ p\2        P4                  ! V
\2        P6                  \2        P6                  WR47      p\"        P"                  ! 4       R5,           p\"        P"                  ! 4       V8  Ed%   VP9                  4       e   EM\        P                  P;                  V4      '       d   \        P                  P=                  V4      ^8  d   Wn        \"        P"                  ! 4       V n         Wn!        W n"        \G        V4      V n$        RV n%        V'       d   R7MR8V,           V n&        T PO                  R9V,           R:,           \        V4      ,           R;,           \        T;'       g    R<4      ,           4        R# \"        PP                  ! R=4       EK?   VP9                  4       f#   VPS                  4        VPU                  ^R>7        TPY                  4        \[        \        R?4      pR@T9   g   RAT9   d*   T PO                  RBT,           R,,           T,           4       EKt  T PO                  RBT,           R,,           T,           4       EK  	  RCV,           R),           V'       d   VRGR6 MR,           V n%        V PO                  RDV,           4       RE#   \,         d     ELi ; i  \,         d(     TPW                  4         L  \,         d      ELi ; ii ; i  \,         d     EL
i ; i)HuT   FFmpeg לא נמצא. נדרש FFmpeg לשידור וידאו+אודיו מאוחד.stream.m3u8zseg_%05d.tsTrK  r}   r*  r)  r  r+  r  rz  r{  r  r  r-  r#  r$  r%  	ultrafastz-tunezerolatencyr(  r)  z-rr*  r+  r1  r2  re   r  rg   r,  hlsz	-hls_timez-hls_list_sizer2   z
-hls_flagsz.delete_segments+omit_endlist+program_date_timez-hls_segment_filenamer  rn  r
   z | unified HLS start | mode=z	 | input=z
cmd=r   rm  r   r  r9   r   r  g       @Nzhls_av:zhls_video_only:zHLS started ok | mode=r.  r/  r0  gffffff?r  ih  zCould not set video optionszError opening inputz)HLS candidate failed; trying next | mode=u[   FFmpeg לא הצליח לפתוח שידור מאוחד אחרי כל מצבי DirectShow: z"HLS failed all candidates | input=Fr  i).r   rs  rK  r=   r?   rD   rJ  r  rS  rB   rD  rV  listr   r3  r5  r   rU  rV  r  r  r  rE   r>   r  r@  r  r	  r  rC   r   r  r   r  r  r   r  r5  r   rE  r  r	  r
  r  r  r  )r8  
video_namer  r   playlistsegment_patternr6  last_err
mode_labelinput_optionsrG  r  r  r  r  deadlines   &&&             rK   _start_ffmpeg_locked+CameraHlsStreamManager._start_ffmpeg_locked#  s   ')uvv 77<<>'',,~}E%j=

BGGOO$784H)-)J)J)L%J""$j+yg|V ]#$ j	9k7MItS1B-C'C v/CUGUZ\_``we[#/?N'	 C ,d3E04==AT3UUXvv  zD  D  GR  R  U_  _  bj  j  mp  mu  mu  vy  mz  z  }A  A  I  I  JQ  Zc  I  dF# KM''UY/GJ(BAF_`E##Cz/A/A*J\J\ej  ADyy{S(H))+(99;*77>>(++0IB0N $I&*iikDO(2%(2%&*:&6DO&(DO.8>OS] ]DIII6CkQTWXbTccfqqtw  yC  yQ  yQ  GQ  uR  R  S

4 99;&NN$IIaI( &&94@H,8<QU]<]		E
RU``cmmnIIAJNQ\\_iij} *M~ x  {E  E  HL  L  dl  PX  Y^  Y_  P`  rt  u		6CDQ  .  IIK    sO   +BR.44S )S5.R=<R= S2SS.)S2-S..S25TTc                \   V P                   ;_uu_ 4        V'       d   V P                  4        V P                  e(   V P                  P                  4       f    R R R 4       R# \        '       g   \        R4      h\        4       w  r4pV'       g   \        R4      h \        P                  4         \        P                  4        V'       d   \        '       d   \        V4      M. pV'       d   V'       d   RpVR,           FV  pVP                  R4      ;'       g    Rp	V	'       g   K(  V P                  W94      '       d    R R R 4       R# V P                  pKX  	  V P                  VR4      '       d   RV,           V n         R R R 4       R# \        T;'       g    V P                  ;'       g    R4      hV P                  VR4      '       d    R R R 4       R# \        V P                  ;'       g    R4      h  \         d     ELUi ; i  \         d     ELRi ; i  + '       g   i     R # ; i)	NTu<   מצלמה כבויה בהגדרת TRIPSERVER_ENABLE_WEBCAM.u|   לא נמצא התקן וידאו ב־FFmpeg. בדוק הרשאות מצלמה או הגדר TRIPSERVER_FFMPEG_VIDEO_DEVICE.r}   :N   Nr>   uc   האודיו נכשל ולכן הופעל וידאו בלבד. שגיאת אודיו אחרונה:
u   שידור מאוחד נכשל.)r0  r  r  r  r  rs  r  CAMERA_MANAGERrY  rE   CAMERA_AUDIO_STREAMr   r  r   re  r5  )
r8  r  rM   rt  ru  r  
audio_rowslast_audio_errorr  r  s
   &&&       rK   r  CameraHlsStreamManager.startp  s   YYY  "yy$)9)A	 Y
 ">"#abb$;$=!E'"  $b  c  c##%#((* AKOcOc3G<ikJj#% %b>>C!$!6!6BJ% 00CC#5 Y6 (,$ * ,,UB77 'M  P`  '`DO? Y@ ##3#k#kt#k#kJkll((33E YF tSS2STT/    ! YYs   AH#H/+HG60HHHH-H5%H
H&H
'H2HHH-HHH/H6HHHHHHHHH+	c                "   V P                   pR V n         Ve6   VP                  4       f$    VP                  4        VP                  ^R7       RV n        RV n        R #   \         d'     TP                  4         L.  \         d      L<i ; ii ; i)Nr  r-  r   )r  r  r	  r
  rE   r  r   r   r  s   & rK   r  "CameraHlsStreamManager.stop_locked  s    yy			 3 		!	$ 	  IIK  s)   "A B)A;;B
B	B

Bc                    V P                   ;_uu_ 4        V P                  4        V P                  R 4       RRR4       R#   + '       g   i     R# ; i)zHLS stoppedN)r0  r  rE  r7  s   &rK   rY  CameraHlsStreamManager.stop  s/    YYYIIm$ YYYs   "AA	c                   V P                   ;_uu_ 4        \        V P                  R J;'       d    V P                  P                  4       R J 4      p\        P
                  P                  \        R4      pRTRV P                  RV P                  RV P                  RV P                  RV P                  '       d6   \        P                  ! R\        P                  ! V P                  4      4      MR	R
\        P
                  P!                  V4      R\        P
                  P!                  V4      '       d    \        P
                  P#                  V4      M^ R\        R\$        RV P&                  /uuR R R 4       #   + '       g   i     R # ; i)NrY  rb  r   r  r  r  r   r
   r}   playlist_existsplaylist_sizedirr  r5  )r0  r   r  r  r=   r?   rD   rJ  r   r  r  r  r   rU  rV  rC  rC   r   rD  r5  )r8  rb  r_  s   &  rK   r   CameraHlsStreamManager.status  s   YYY$))4/LLDIINN4D4LMFww||NMBH&		doo 1 1 1 1eietetetdmm,?PTP_P_A`az|!277>>(#;bggnnX>V>V!:\]~/doo YYYs   B$E9:A:E959E99F
	)r  r5  r0  r   r  r   r  r  Nr   TT)ri  rj  rk  rl  __doc__r9  rE  rK  rV  re  r  r  rY  r   rm  rn  ro  s   @rK   r@  r@  
  sA     
<&PKZ$UL%
 r   r@  c                     \         P                  ! \        R R7       . p\        P                  ! \         P                  P                  \        R4      4       Ft  p VP                  R\         P                  P                  V4      RVR\         P                  P                  V4      R\         P                  P                  V4      /4       Kv  	  VP                  R R R7       VR	V  #   \         d     K  i ; i  \         d    . u # i ; i)
TrK  z*.mp4r>   r?   r  rA  c                 &    V P                  R ^ 4      # )rA  r  rR  s   &rK   r   (list_camera_recordings.<locals>.<lambda>  s    w!2r   r  N)r=   rS  r2  r  r?   rD   r  r@   r   rD  rE   r  )limitr  r?   s   &  rK   list_camera_recordingsr}    s    
)D9IIbggll+@'JKDBGG,,T2DBGGOOD1RWW--d3	  L 	

2D
AVe}    	s7   AC; A0C)C; )C84C; 7C88C; ;D
Dc                 .   \         P                  ! \        R R7       R\        P                  ! R4       RV  R2p \        \        RRR7      ;_uu_ 4       pVP                  V4       R	R	R	4       V#   + '       g   i     T# ; i  \         d     T# i ; i)
TrK  [r
   z] rn  r  rm  r  N)	r=   rS  r  rU  rV  r   CAMERA_SETUP_LOG_PATHr  rE   )r  r  r   s   &  rK   append_camera_setup_logr    s    KK4(t}}012"WIR@D'w??2HHTN @ K	 @? K  Ks/   B A1'B 1B	<B B BBc           	          \        ^\        R\        V 4      4      4      p \        P
                  P                  \        4      '       g   R#  \        \        RRRR7      ;_uu_ 4       pVP                  4       pRRR4       RP                  XV ) R 4      #   \         d    ^Pp  Li ; i  + '       g   i     L8; i  \         d   pRT 2u Rp?# Rp?ii ; i)	r  i,  r}   r  rm  r   ro  Nu+   שגיאה בקריאת לוג התקנה: )r   r  r[   rE   r=   r?   rC   r  r   r  rD   )ro  r   r   r&  s   &   rK   read_camera_setup_log_tailr    s    BCU,- 77>>/00C'wyQQUW<<>D RwwtUFG}%%  
 RQ  C<SEBBCsG   B B< (B)9B< B&%B&)B9	4B< <CCCCc                  t     ^ RI p R\        V RR4      3#   \         d   pR\        T4      3u Rp?# Rp?ii ; i)r   NTr%  r}   F)r'  r  rE   r   )r'  r&  s     rK   opencv_import_statusr    s<    WS-444 c#hs    7277c                  n   \        4       w  r\        4       ;'       g    R p\        ;_uu_ 4        \        \        4      pRRR4       RV RVR\        V4      RVR\        P                  RR\        P                   R	\         2R
\        R\        R\        R\        R\        RX/#   + '       g   i     Lm; i)r}   Nr"  opencv_infor   r   python_executablepip_commandr  z" -m pip install --upgrade opencv_packagesetup_log_pathmarker_pathauto_install_enabledauto_install_delay_seconds	installer)r  r   CAMERA_SETUP_LOCKdictCAMERA_SETUP_STATEr   r;   r<   CAMERA_OPENCV_PACKAGEr  CAMERA_SETUP_MARKER_PATHCAMERA_AUTO_INSTALL_OPENCV!CAMERA_AUTO_INSTALL_DELAY_SECONDS)r   r  r   states       rK   camera_setup_statusr    s    #%HB(*00bK		'( 
 	"t${#{S^^3>>**EF[E\]/// :$&GU  
	s   B$$B4	c            
         \         P                  ! \        P                  RRR.RRRR^<RR7      p V P                  ^ 8X  dK   \        R	V P                  ;'       g    V P                  ;'       g    R
P                  4       ,           4       R# \        R4        \         P                  ! \        P                  RRR.RRRR^RR7      p\        R\        VP                  4      ,           4       VP                  '       d    \        RVP                  RR ,           4       VP                  '       d    \        RVP                  RR ,           4       VP                  ^ 8H  #   \         d'   p\        R\        T4      ,           4        Rp?R# Rp?ii ; i)z@Make pip available in the same Python interpreter when possible.-mpipz	--versionTrm  r   Fr4  r5  rp  rq  r6  r  zpip available: r}   z-pip not available, trying ensurepip --upgrade	ensurepip	--upgradezensurepip return code: zensurepip stdout:
Nzensurepip stderr:
zensurepip exception: i)r@  rA  r;   r<   rB  r  rD  rC  rZ   r   rE   r  )checkepr&  s      rK   ensure_pip_availabler    sX   NNCNND%EVZaepw  AJ  TV  ^c  dE1 1U\\5W5WU\\5W5WUW4^4^4` `aKL
^^S^^T;L]ahlw~  HQ  [^  fk  l 9C<N NO999#$9BIIef<M$MN999#$9BIIef<M$MN}}!!  7$s) CDs   BE .-E F'FFc                 X    \         P                  ! \        R R7       \        \        RRR7      ;_uu_ 4       pVP                  \        P                  ! R4      R,           \        V 4      ,           R,           4       RRR4       R#   + '       g   i     R# ; i  \         d     R# i ; i)	TrK  r  rm  r  r
   r#  rn  N)
r=   rS  r  r   r  r  rU  rV  r   rE   )r  r   s   & rK   write_camera_setup_markerr  "  sq    
Ht,*C'BBbHHT]]#67%?#d)KdRS CBBB r  c                    \         ;_uu_ 4        \        P                  R RR\        P                  ! R4      RRRRRR	R
V /4       RRR4       \        R\        V 4      ,           4       \        R\        P                  ,           4       \        4       '       ga   Rp\        RV,           4       \         ;_uu_ 4        \        P                  R RR\        P                  ! R4      RRRVR
V /4       RRR4       R# \        P                  RRRR\        .p\        RRP                  V4      ,           4       RpRp \        P                  ! VRRRR\        RR7      p\        R\        VP                  4      ,           4       VP                   '       d    \        RVP                   R&R ,           4       VP"                  '       d    \        RVP"                  R&R ,           4       \%        4       w  r5VP                  ^ 8X  d0   V'       d(   RV,           p\        RV,           4       \'        V4       MLVP                  ^ 8X  d%   V'       g   RV,           p\        RV,           4       MR p\        RV,           4       Rp \         ;_uu_ 4        \        P                  R RR\        P                  ! R4      R\/        V4      RVR
V /4       RRR4       R#   + '       g   i     EL; i  + '       g   i     R# ; i  \        P(                   d     R!\         R"2p\        R#T,           4        L\*         d/   pR$\-        T4      ,           p\        R%T,           4        Rp?LRp?ii ; i  + '       g   i     R# ; i)'r   Tr   r
   r   r}   r   Fr   u   מתקין OpenCV...r   Nz OpenCV install requested | mode=zPython executable: ug   pip לא זמין וגם ensurepip לא הצליח. אי אפשר להתקין OpenCV אוטומטית.zERROR: r  r  installr  z	Command: r   rm  r   r  zpip return code: zpip stdout:
zpip stderr:
u   OpenCV הותקן וזוהה: z	SUCCESS: uE   pip הסתיים בהצלחה אבל import cv2 עדיין נכשל: z	WARNING: u;   pip נכשל. בדוק את הלוג במסך ההתקנה.u5   התקנת OpenCV עברה את מגבלת הזמן (u    שניות).z	TIMEOUT: u   שגיאה בהרצת pip: zEXCEPTION: i )r  r  r  rU  rV  r  r   r;   r<   r  r  rD   r@  rA  %CAMERA_OPENCV_INSTALL_TIMEOUT_SECONDSrB  rD  rC  r  r  TimeoutExpiredrE   r  r   )r   msgrG  r   r  r  r&  s   &      rK   run_opencv_install_workerr  +  s   		!!9dL$--PcBdfsuwy}  @E  GU  Wm  ou  w{  #|  	} 
>TJK1CNNBC!!w	C0%%y%ViHjlprw  zH  JM  OU  W[  '\  ] >>4	;@U
VCK#((3-78	B
C 5NN9
	 	  3c):N:N6O OP#Oi6F6Fvw6O$OP#Oi6F6Fvw6O$OP')1$2T9C#K#$56%c*!!Q&rY\``C#K#$56OC#IO4B 
	!!9e]DMMReDfhlnrsunv  yG  IL  NT  VZ  #[  	\ 
	_ 
		 @ $$ 3EFkEllyzc 12 5+d3i7 3445 
		sg   6K:4K!8BK5 AK5 &K5 ,K5 K5 !K5 =M#K	!K2	51M (M 1M 2$MM #M4	c                 r   \         ;_uu_ 4        \        P                  R 4      '       d   RuuRRR4       # \        P                  R RR\        P
                  ! R4      RRRRR	R
RV /4       RRR4       \        P                  ! \        RV /RRR7      pVP                  4        R#   + '       g   i     LB; i)r   FNTr   r
   r   r}   r   r   u   מתחיל התקנה...r   ztripserver-opencv-installer)r  kwargsr>   daemon)Fu)   התקנת OpenCV כבר רצה כרגע.)Tuu   התקנת OpenCV התחילה ברקע. אפשר לרענן את מסך המצלמה/התקנה ולבדוק לוג.)
r  r  r   r  rU  rV  r.  Threadr  r  )r   r  s   & rK   start_opencv_install_backgroundr  _  s    		!!),,E 
	 	!!9dL$--PcBdfsuwy}  @E  GU  Wq  sy  {  #@  	A 
 	 964.Wt  ~B  	CAGGI I  I 
	s   B&5B&&B6	c                 
  a  \         '       g   \        R 4       R# \        4       w  rV'       d`   \        ;_uu_ 4        \        P                  RRRR\        V4      ,           RR/4       RRR4       \        R\        V4      ,           4       R# \        ;_uu_ 4        R\        R	&   RRR4       V 3R
 lp\        P                  ! VRRR7      pVP                  4        R#   + '       g   i     L~; i  + '       g   i     LT; i)z>Auto install disabled by TRIPSERVER_CAMERA_AUTO_INSTALL_OPENCVr   Tr      OpenCV כבר זמין: r   readyNzalready available: r   c                  f  <  \         ^ 8  d   \        P                  ! \         4       \        4       w  rV '       d`   \	        R\        V4      ,           4       \        ;_uu_ 4        \        P                  RRRR\        V4      ,           RR/4       RRR4       R# \        R	\        S4      ,           R
,           \        V4      ,           4       \        R\        S4      ,           R7       R#   + '       g   i     R# ; i  \         d'   p\        R\        T4      ,           4        Rp?R# Rp?ii ; i)r   zavailable before auto install: r   Tr   r  r   r  Nz Auto install triggered | reason=z | cv2 import failed: zauto:r   z"Auto install scheduler exception: )r  rU  r  r  r  r   r  r  r  r  r  rE   r  )ok2info2r&  r
  s      rK   delayed_auto5maybe_start_camera_auto_install.<locals>.delayed_autou  s    	V014

<=-/JC)*KcRWj*XY&&&--tT>KehklqhrKrtz  }D  /E  F '#$FV$TWo$oruv{r|$|}+3v;1FG	 '&  	V#$H4PS9$TUU	VsB   
C? AC? %,C+C? AC? +C<	6C? <C? ?D0
D++D0z tripserver-opencv-auto-installer)r  r>   r  )Fu'   התקנה אוטומטית כבויה.)Fu   OpenCV כבר מותקן.)Tu7   התקנת OpenCV אוטומטית תתחיל ברקע.)r  r  r  r  r  r  r   r  r.  r  r  )r
  r   r  r  r  s   f    rK   maybe_start_camera_auto_installr  i  s    %% `a??#%HB	%%tT>C]`cdh`iCikqsz&{| !"7#d)"CD11		/3+, 
V 	3U^bcAGGIJJ-  
	s   ,C
C2C/	2D	c                     \        4       w  r\        4       pVP                  R / 4      p\        VP                  R4      4      pVP                  R4      '       d   RMRpVP                  R4      '       d   RMRpV'       d   RMVP                  R4      '       d   RMRpV '       d    V'       g   VP                  R4      '       d   RMRpV '       d   RMR	\        P
                  ! V4       R
2p	\        P
                  ! \        ^x4      4      ;'       g    Rp
RP                  . RNV NRNVP                  R4      '       d   RMR NRNV NRNVP                  R4      '       d   RMR NRNV NRNV'       d   RMVP                  R4      '       d   RMR NRNV	 NRN\        P
                  ! VP                  RR4      4       NRNVP                  R4      '       d   RMR NRN\        P
                  ! VP                  RR4      4       NRN\        P
                  ! \        VP                  R R4      4      4       NR!N\        P
                  ! VP                  R"4      ;'       g    R4       NR#N\        P
                  ! \        VP                  R$4      ;'       g    R%4      4       NR&N\        P
                  ! \        VP                  R'4      ;'       g    R4      4       NR(N\        P
                  ! \        VP                  R)4      ;'       g    R4      4       NR*N\        P
                  ! \        4       NR+NV
 NR,N4      # )-r  r   r"  r   r  r   r   disabledr}   '   <div class='warn'>גישה חסומה: </div>u$   אין עדיין לוג התקנה.u5	  
<!DOCTYPE html><html lang="he" dir="rtl"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>התקנת רכיבי מצלמה</title>
<style>
body{margin:0;background:#07111f;color:white;font-family:Arial,'Segoe UI',sans-serif;padding:18px}.wrap{max-width:1050px;margin:auto}a{color:#bfdbfe;text-decoration:none}.hero{background:linear-gradient(135deg,#0f766e,#0f172a 62%,#111827);border:1px solid #14b8a6;border-radius:28px;padding:22px;margin-bottom:16px;box-shadow:0 20px 70px rgba(0,0,0,.28)}h1{margin:0 0 8px;font-size:34px}p{color:#cbd5e1;line-height:1.7}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px}.card{background:#111827;border:1px solid #334155;border-radius:20px;padding:16px;margin-top:14px}.badge{display:inline-block;border-radius:999px;padding:8px 14px;font-weight:900;margin:8px 6px 0 0}.badge.ok{background:#064e3b;color:#bbf7d0;border:1px solid #22c55e}.badge.warn{background:#7f1d1d;color:#fecaca;border:1px solid #f87171}.badge.idle{background:#334155;color:#e2e8f0;border:1px solid #64748b}button,.btn{border:0;border-radius:14px;padding:13px 16px;font-weight:950;color:white;background:#2563eb;margin:8px 8px 0 0;cursor:pointer;display:inline-block}button:disabled{background:#475569;cursor:not-allowed;opacity:.55}.warn{background:#7f1d1d;border:1px solid #f87171;color:#fecaca;border-radius:16px;padding:13px;line-height:1.65;margin:12px 0}.good{background:#052e2b;border:1px solid #14b8a6;border-radius:16px;padding:13px;color:#ccfbf1;line-height:1.65;margin:12px 0}.note{background:#0b1220;border:1px solid #334155;border-radius:16px;padding:13px;color:#cbd5e1;line-height:1.65;margin:12px 0}code,pre{direction:ltr;text-align:left;white-space:pre-wrap;word-break:break-word}pre{background:#020617;border:1px solid #334155;color:#fde68a;border-radius:12px;padding:12px;overflow:auto;max-height:440px}@media(max-width:700px){body{padding:13px}h1{font-size:28px}}
</style></head><body><div class="wrap"><div class="hero"><a href="/admin/camera">⬅ חזרה למצלמה</a><h1>🧩 התקנת רכיבי מצלמה</h1><p>OpenCV מותקן אוטומטית חד־פעמית ברקע כאשר פאנל האדמין עולה. FFmpeg לא מותקן כאן; הוא רק מזוהה מהנתיב שכבר קיים אצלך.</p><span class="badge z
">OpenCV: 
   מותקן   חסר</span><span class="badge z
">FFmpeg:    זמין   לא נמצאz">Installer: u   רץ עכשיוu   הצלחה אחרונהu
   ממתין</span></div>u   
<div class="grid"><div class="card"><h2>התקנה אוטומטית חד־פעמית</h2><p>אם OpenCV חסר, הפאנל מריץ לבד את הפקודה:</p><pre>r  u   </pre><div class="note">אין כפתור התקנה נוסף. ההתקנה מופעלת ברקע אחרי עליית הפאנל, כדי שתוכל לעשות את זה מרחוק בלי CMD ידני.</div>ua   <div class="good">OpenCV כבר מותקן וזמין. אין צורך להתקין שוב.</div>uF   </div>
<div class="card"><h2>סטטוס</h2><p><b>Python:</b></p><pre>r  z</pre><p><b>OpenCV:</b> r  z</p><p><b>FFmpeg:</b></p><pre>r   u,   </pre><p><b>הודעה אחרונה:</b><br>r      איןu   </p><p><b>התחיל:</b> r   u   <br><b>הסתיים:</b> r   u   </p><p><a class="btn" href="/camera/setup">רענן</a><a class="btn" href="/camera/setup/status.json" target="_blank">JSON טכני</a></p></div></div>
<div class="card"><h2>לוג התקנה</h2><p>נתיב לוג: <code>z</code></p><pre>r  )
r  r  r   r   r  r  r  rD   r   r  )allowedr
  r   instr   opencv_badgeffmpeg_badge	run_badgeinstall_disabledallowed_blockr  s              rK   render_camera_setup_pager    s   +-OG "F::k2&D488I&'G!::h//4VL!::h//4VL!FI*1W

8@T@Tz[]!B)PQYQ`Q`agQhPiio'pM9#>?iiCiH  {  |H  {I	 IS	 dj  dn  dn  ow  dx  dx  T`  ~F  SG	 Ga	 bn  ao	 oy	 HN  HR  HR  S[  H\  H\  zD  bq  yr	 rL		 M	V	  L	W		 W	d		 z	A
  e	v	  e
i
  e
m
  e
m
  n
r
  e
s
  e
s
  H
a
  y
E  d	G	 GT	 Ub  Tc	cg	
 hp  hw  hw  x~  xB  xB  CP  QS  xT  hU  gV
 Vd
 LR  LV  LV  W_  L`  L`  eH  fh  di
i@ AIPVPZPZ[noqPr@s?t uM NV  N]  N]  ^a  bh  bl  bl  mz  {}  b~  ^  N@  MA A_ `h  `o  `o  pv  pz  pz  {H  pI  p\  p\  M\  `]  _^ ^J KS  KZ  KZ  [^  _c  _g  _g  hv  _w  _C  _C  {C  [D  KE  JF F` ai  ap  ap  qt  uy  u}  u}  ~J  uK  uQ  uQ  OQ  qR  aS  `T Tm nv  n}  n}  ~A  BF  BJ  BJ  KX  BY  B_  B_  ]_  ~`  na  mbbG HPWlGmFn o @H  II r   c                     \        4       w  rpR \        \        4       4      R\        4       ;'       g    RRV RVRVR\        P	                  4       R\
        P	                  4       R\        R	\        R
\        P	                  4       R\        /# )r   r   r}   r  r  r  audio_stream	recordingrecordings_diraudio_log_path
hls_streamhls_log_path)
r  r   r   rj  r   CAMERA_RECORDERr2  r  CAMERA_HLS_STREAMrD  )rt  ru  r  s      rK   camera_av_statusr    s    35E'$-/0-/5527+224_++-//'..0+ r   c               #     "   \         P                   ! 4       p   \        ^ 8  d'   \         P                   ! 4       V ,
          \        8  d   MB\        P                  4       pRV,           R,           x  \         P                  ! \
        4       Kt  \        P                  4        R#   \         d     L#\         d   p\        T4      \        n	         Rp?LFRp?ii ; i  \        P                  4        i ; i5i)Ts>   --frame
Content-Type: image/jpeg
Cache-Control: no-cache

s   
N)rU  CAMERA_MAX_STREAM_SECONDSri  rV  r  CAMERA_FRAME_INTERVAL_SECONDSr  rE   r   r5  rY  )startedrT  r&  s      rK   camera_stream_generatorr    s     iikG(1,$))+2GKd1d",,.E[^ccfmmmJJ45 	   -$'H!!- 	sY   C41B# 
C AB# C4#C.C 0C9C:CC CC C11C4c                     \        4       w  r\        4       p\        4       p\        P	                  4       pVP                  R / 4      pVP                  R/ 4      pVP                  R/ 4      ;'       g    / pV '       d   RMR\        P                  ! V4       R2pRp	VP                  R4      '       g   Rp	VP                  R4      '       g
   V	R	,          p	VP                  R
4      '       d   RMRp
VP                  R
4      '       d   RMRpVP                  R
4      '       d   VP                  R4      '       d   RMVP                  R
4      '       d   RMRpVP                  R
4      '       d   VP                  R4      '       d   RMRpVP                  R
4      '       d   RMRpVP                  R
4      '       d   RMRpV '       d   VP                  R4      '       g   RMRpV '       d   VP                  R4      '       g   RMRpV '       d   VP                  R4      '       g   RMRp\        ^4      pRP                  R V 4       4      ;'       g    RpRP                  VP                  R. 4      4      ;'       g    RpRP                  VP                  R. 4      4      ;'       g    RpRP                  . RNV NRNV
 NRNV NRNV NRNV NR NV NR!NV NV	 NR"NV NR#NV NR$NV NR%NV NR&N\        P                  ! \        4       NR'NV NR(N\        ^<,           NR)NV NR*NVP                  R4      '       d   R+MR, NR-NVP                  R4      '       d   R.MR/ NR0NV
 NR1N\        P                  ! VP                  R24      ;'       g    R4       NR3N\        P                  ! VP                  R44      ;'       g    VP                  R44      ;'       g    R4       NR5N\        P                  ! VP                  R64      ;'       g    VP                  R64      ;'       g    R4       NR7N\        P                  ! VP                  R84      ;'       g    \        4       NR9N\         NR:N\         NR;N\         NR<NVP                  R=4       NR>N\        P                  ! VP                  R?4      ;'       g    R@4       NRAN\!        VP                  RB4      ;'       g    ^ 4       NRCN\        P                  ! VP                  RD4      ;'       g5    VP                  RD4      ;'       g    VP                  RD4      ;'       g    R@4       NREN\        P                  ! V4       NRFN\        P                  ! V4       NRGN4      # )Hr  r  r  r}   r  r  r"  u   <div class='warn'><b>OpenCV לא מותקן.</b><br>הפאנל מנסה להתקין אותו אוטומטית. אפשר לראות את הלוג דרך: <a class='btn' href='/camera/setup'>🧩 סטטוס רכיבי מצלמה</a></div>r   u   <div class='warn'><b>FFmpeg לא נמצא.</b><br>שידור מאוחד וידאו+אודיו והקלטות דורשים FFmpeg ב־PATH או ב־<code>C:\ffmpeg\bin\ffmpeg.exe</code>.</div>rb     פעיל   כבויr   r   r  u   כלולu   וידאו בלבדu
   מקליטu   לא מקליטrecr  c              3   ,  "   T F  pR \         P                  ! VR,          4       R\        P                  ! R\        P                  ! VR,          4      4       R\        VR,          4       R\         P                  ! VR,          4       R2	x  K  	  R	# 5i)
z<div class='file-row'><div><b>r>   z</b><br><span>r
   rA  r  r  z6</span></div><a class='mini' href='/camera/recordings/u"   ' target='_blank'>פתח</a></div>Nr  r  rU  rV  rC  r   r\   r   s   & rK   r^   &render_admin_camera.<locals>.<genexpr>  s      D )f)F(G~VZVcVcdwy}  zH  zH  IM  NU  IV  zW  WX  VY  Y]  ^j  ko  pv  kw  ^x  ]y  yo  px  p  p  @D  EK  @L  pM  oN  Np  	q   BBuG   <div class='muted'>אין עדיין הקלטות בתיקייה.</div>r  rt  u   לא זוהו דרך FFmpegru  u  
<!DOCTYPE html>
<html lang="he" dir="rtl"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>מצלמת חדר</title>
<style>
body{margin:0;background:#07111f;color:white;font-family:Arial,'Segoe UI',sans-serif;padding:18px}.wrap{max-width:1120px;margin:auto}a{color:#bfdbfe;text-decoration:none}.hero{background:linear-gradient(135deg,#0f766e,#0f172a 62%,#111827);border:1px solid #14b8a6;border-radius:28px;padding:22px;margin-bottom:16px;box-shadow:0 20px 70px rgba(0,0,0,.28)}h1{margin:0 0 8px;font-size:34px}h2{margin:0 0 10px}p{color:#cbd5e1;line-height:1.7}.grid{display:grid;grid-template-columns:1.45fr .9fr;gap:16px}.card{background:#111827;border:1px solid #334155;border-radius:20px;padding:16px;margin-top:14px}.cam-box{background:#020617;border:1px solid #334155;border-radius:22px;overflow:hidden;min-height:280px;display:flex;align-items:center;justify-content:center}#hlsVideo,#cameraView{width:100%;height:auto;background:#020617;display:none}.placeholder{color:#94a3b8;text-align:center;padding:28px;line-height:1.7}button,.btn{border:0;border-radius:14px;padding:13px 16px;font-weight:950;color:white;background:#2563eb;margin:8px 8px 0 0;cursor:pointer;display:inline-block}button.stop{background:#dc2626}button.gray,.btn.gray{background:#475569}button.snap{background:#0f766e}button.record{background:#ea580c}button:disabled{background:#475569;cursor:not-allowed;opacity:.55}.badge{display:inline-block;border-radius:999px;padding:8px 14px;font-weight:900;margin:8px 6px 0 0}.badge.ok{background:#064e3b;color:#bbf7d0;border:1px solid #22c55e}.badge.idle{background:#334155;color:#e2e8f0;border:1px solid #64748b}.badge.rec{background:#7c2d12;color:#fed7aa;border:1px solid #fb923c}.warn{background:#7f1d1d;border:1px solid #f87171;color:#fecaca;border-radius:16px;padding:13px;line-height:1.65;margin:12px 0}.note{background:#0b1220;border:1px solid #334155;border-radius:16px;padding:13px;color:#cbd5e1;line-height:1.65;margin:12px 0}.good{background:#052e2b;border:1px solid #14b8a6;border-radius:16px;padding:13px;color:#ccfbf1;line-height:1.65;margin:12px 0}code,pre{direction:ltr;text-align:left;white-space:pre-wrap}pre{background:#020617;border:1px solid #334155;color:#fde68a;border-radius:12px;padding:10px;overflow:auto}.row{display:flex;justify-content:space-between;gap:10px;border-bottom:1px solid #263548;padding:9px 0;color:#cbd5e1}.row b{color:white}.file-row{display:flex;justify-content:space-between;gap:12px;align-items:center;border-bottom:1px solid #263548;padding:10px 0;color:#cbd5e1}.file-row span,.muted{color:#94a3b8}.mini{background:#1d4ed8;color:white;border-radius:10px;padding:8px 10px;font-weight:900;white-space:nowrap}label{display:block;color:#e2e8f0;margin-top:8px;font-weight:800}input[type=checkbox]{transform:scale(1.25);margin-left:8px}@media(max-width:850px){.grid{grid-template-columns:1fr}body{padding:13px}h1{font-size:28px}.file-row{align-items:flex-start}}
</style></head><body><div class="wrap"><div class="hero"><a href="/admin">⬅ חזרה לפאנל</a><h1>📷 מצלמת חדר</h1><p>v28 חוזר לברירת מחדל יציבה: וידאו דרך OpenCV/MJPEG, כי אצל EMEET SmartCam C965 הווידאו דרך FFmpeg DirectShow נכשל. האודיו מוזרם בנפרד דרך FFmpeg, וה־HLS המאוחד נשאר רק ככלי בדיקה מתקדם.</p><p><a class="btn gray" href="/camera/setup">סטטוס רכיבי מצלמה</a> <a class="btn gray" href="/admin/logs">לוגים</a></p><span class="badge u   ">שידור מאוחד: r  u   ">אודיו: u   ">הקלטה: r  uz  
<div class="grid"><div><div class="card"><h2>שידור חי וידאו + אודיו</h2><div class="cam-box"><video id="hlsVideo" controls playsinline webkit-playsinline></video><img id="cameraView" alt="שידור מצלמה"><div id="placeholder" class="placeholder">השידור כבוי.<br>לחץ “הפעל וידאו + אודיו”. הווידאו יעבוד דרך OpenCV, והאודיו דרך FFmpeg.</div></div><audio id="audioPlayer" controls playsinline style="width:100%;margin-top:12px;display:none"></audio><div id="cameraMsg" class="note" style="display:none"></div><div><button onclick="startStableMjpegAudio()" u   >הפעל וידאו + אודיו</button><button class="stop" onclick="stopStableStream()">כבה וידאו + אודיו</button><button class="snap" onclick="openSnapshot()" u  >פתח צילום רגעי</button><button class="gray" onclick="resetCameraDevices()">שחרור/איפוס מצלמה</button><button class="gray" onclick="location.reload()">רענן סטטוס</button></div><div class="note">מתקדם בלבד: אם תרצה לבדוק שוב HLS מאוחד דרך FFmpeg, השתמש בכפתור הבא. אצל המצלמה שלך הוא כנראה נכשל ולכן לא ברירת מחדל.</div><button class="gray" onclick="startUnifiedStream(true)" ua   >בדיקה מתקדמת: HLS מאוחד</button><button class="gray" onclick="startMjpegOnly()" u   >וידאו בלבד</button></div>
<div class="card"><h2>⏺️ הקלטה למחשב</h2><p>הקלטות נשמרות מקומית בתיקייה: <code>u   </code></p><form method="post" action="/camera/record/start"><label><input type="checkbox" name="with_audio" value="1" checked>כלול אודיו בהקלטה</label><button class="record" type="submit" u   >התחל הקלטה</button></form><form method="post" action="/camera/record/stop"><button class="stop" type="submit">עצור הקלטה</button></form><div class="good">משך הקלטה מקסימלי להגנה מדיסק מלא: uU    דקות.</div></div>
<div class="card"><h2>🎞️ הקלטות אחרונות</h2>u   <p><a class="btn gray" href="/camera/recordings">פתח רשימת הקלטות מלאה</a></p></div></div>
<div><div class="card"><h2>סטטוס טכני</h2><div class="row"><b>OpenCV</b><span>r  u   לא מותקןz1</span></div><div class="row"><b>FFmpeg</b><span>r  r  u7   </span></div><div class="row"><b>HLS פעיל</b><span>u5   </span></div><div class="row"><b>HLS מצב</b><span>r   u9   </span></div><div class="row"><b>וידאו HLS</b><span>r  u9   </span></div><div class="row"><b>אודיו HLS</b><span>r  u5   </span></div><div class="row"><b>לוג HLS</b><span>r  z7</span></div><div class="row"><b>Camera index</b><span>u;   </span></div><div class="row"><b>רזולוציה</b><span>   ×z7</span></div><div class="row"><b>Frames MJPEG</b><span>r4  uG   </span></div><div class="row"><b>קובץ הקלטה פעיל</b><span>r  r  u>   </span></div><div class="row"><b>גודל הקלטה</b><span>r  uB   </span></div><div class="row"><b>שגיאה אחרונה</b><span>r5  u_   </span></div></div>
<div class="card"><h2>התקנים שזוהו</h2><p><b>וידאו:</b><br>u   </p><p><b>אודיו:</b><br>u  </p><p class="muted">אם נבחר התקן לא נכון, אפשר להגדיר במערכת: <code>TRIPSERVER_FFMPEG_VIDEO_DEVICE</code> / <code>TRIPSERVER_FFMPEG_AUDIO_DEVICE</code>.</p><p><a class="btn gray" href="/camera/audio-test.json" target="_blank">בדיקת אודיו טכנית</a><a class="btn gray" href="/camera/hls/status.json" target="_blank">JSON HLS</a></p></div>
<div class="note"><b>הערת שימוש:</b> זה כולל אודיו והקלטה. ודא שכל מי שנמצא בבית יודע שהמערכת קיימת ומתי היא פעילה.</div></div></div></div>
<script>
function setMsg(id, text, isError=false){ const el=document.getElementById(id); if(!el)return; el.style.display=text?'block':'none'; el.textContent=text||''; el.className=isError?'warn':'note'; }
async function startStableMjpegAudio(){
  setMsg('cameraMsg','מפעיל וידאו יציב דרך OpenCV ואודיו דרך FFmpeg...');
  const audio=document.getElementById('audioPlayer');
  const video=document.getElementById('hlsVideo');
  const img=document.getElementById('cameraView');
  const ph=document.getElementById('placeholder');
  try{ await fetch('/camera/hls/stop', {method:'POST', cache:'no-store'}); }catch(e){}
  video.pause(); video.removeAttribute('src'); video.load(); video.style.display='none';
  // Start audio immediately from the user click, before async video prep can cause iPhone/Safari to block playback.
  try{
    audio.style.display='block';
    audio.src='/camera/audio-stream?restart=1&ts='+Date.now();
    audio.load();
    const p=audio.play();
    if(p && p.catch) p.catch(e=>setMsg('cameraMsg','הווידאו יופעל. אם אין אודיו, לחץ Play בנגן האודיו. '+e,false));
  }catch(e){ setMsg('cameraMsg','הווידאו יופעל, אך האודיו לא התחיל: '+e,false); }
  try{ await fetch('/camera/prepare-video', {method:'POST', cache:'no-store'}); }catch(e){}
  img.onload=()=>{ph.style.display='none'; img.style.display='block'; setMsg('cameraMsg','וידאו פעיל. האודיו בנגן הנפרד. אם אין קול, לחץ Play בנגן האודיו או פתח בדיקת אודיו טכנית.');};
  img.onerror=()=>setMsg('cameraMsg','שגיאת וידאו. לחץ שחרור/איפוס מצלמה ונסה שוב.',true);
  img.src='/camera/stream?ts='+Date.now();
}
async function stopStableStream(){
  try{ await fetch('/camera/hls/stop', {method:'POST', cache:'no-store'}); }catch(e){}
  try{ await fetch('/camera/audio-stop', {method:'POST', cache:'no-store'}); }catch(e){}
  try{ await fetch('/camera/stop', {method:'POST', cache:'no-store'}); }catch(e){}
  const audio=document.getElementById('audioPlayer'); audio.pause(); audio.removeAttribute('src'); audio.load(); audio.style.display='none';
  const video=document.getElementById('hlsVideo'); video.pause(); video.removeAttribute('src'); video.load(); video.style.display='none';
  const img=document.getElementById('cameraView'); img.style.display='none'; img.removeAttribute('src');
  document.getElementById('placeholder').style.display='block'; setMsg('cameraMsg','הווידאו והאודיו כובו.');
}

async function startUnifiedStream(withAudio){
  setMsg('cameraMsg','מפעיל שידור מאוחד דרך FFmpeg...');
  const video=document.getElementById('hlsVideo'); const img=document.getElementById('cameraView'); const ph=document.getElementById('placeholder');
  try{
    img.style.display='none'; img.removeAttribute('src');
    const res=await fetch('/camera/hls/start?audio='+(withAudio?'1':'0'), {method:'POST', cache:'no-store'});
    const data=await res.json().catch(()=>({ok:false,error:'תגובה לא קריאה מהשרת'}));
    if(!res.ok || !data.ok) throw new Error(data.error || ('HTTP '+res.status));
    ph.style.display='none'; video.style.display='block';
    video.src='/camera/hls/stream.m3u8?ts='+Date.now(); video.load();
    try{ await video.play(); setMsg('cameraMsg', data.with_audio ? 'שידור וידאו+אודיו פעיל.' : 'וידאו פעיל, אבל האודיו נכשל. בדוק לוג HLS.'); }
    catch(e){ setMsg('cameraMsg','השידור הופעל. באייפון לחץ Play בנגן אם הוא לא התחיל לבד. '+e, false); }
  }catch(e){ setMsg('cameraMsg','שגיאת שידור מאוחד: '+e, true); }
}
async function stopUnifiedStream(){
  try{ await fetch('/camera/hls/stop', {method:'POST', cache:'no-store'}); }catch(e){}
  const video=document.getElementById('hlsVideo'); video.pause(); video.removeAttribute('src'); video.load(); video.style.display='none';
  const img=document.getElementById('cameraView'); img.style.display='none'; img.removeAttribute('src');
  document.getElementById('placeholder').style.display='block'; setMsg('cameraMsg','השידור כובה.');
}
async function startMjpegOnly(){
  setMsg('cameraMsg','מפעיל גיבוי וידאו בלבד...');
  const video=document.getElementById('hlsVideo'); video.pause(); video.removeAttribute('src'); video.load(); video.style.display='none';
  const img=document.getElementById('cameraView'); const ph=document.getElementById('placeholder');
  try{ await fetch('/camera/prepare-video', {method:'POST', cache:'no-store'}); }catch(e){}
  img.onload=()=>{ph.style.display='none'; img.style.display='block'; setMsg('cameraMsg','וידאו בלבד פעיל.');};
  img.onerror=()=>setMsg('cameraMsg','שגיאת וידאו בלבד. לחץ שחרור/איפוס מצלמה ונסה שוב.',true);
  img.src='/camera/stream?ts='+Date.now();
}
function openSnapshot(){ window.open('/camera/snapshot?ts='+Date.now(), '_blank'); }
async function resetCameraDevices(){
  await stopUnifiedStream();
  try{ await fetch('/camera/audio-stop', {method:'POST', cache:'no-store'}); }catch(e){}
  try{ const res=await fetch('/camera/reset', {method:'POST', cache:'no-store'}); const data=await res.json(); setMsg('cameraMsg', data.message || 'איפוס בוצע.'); }catch(e){ setMsg('cameraMsg','שגיאת איפוס: '+e,true); }
}
</script>
</body></html>
)r  r(  r  ri  r   r   r  r  r}  rD   r2  r4  rD  r&  rE  rF  r   )r  r
  engineav
cam_status
rec_status
hls_statusr  r  engine_blockhls_texthls_cls
audio_text	audio_clsrec_textrec_clsdisabled_hlsdisabled_videodisabled_av
recordingsrec_rowsvideo_devicesaudio_devicess                          rK   render_admin_camerar    s
   +-OG!#F		B&&(JR(Jb)JffY#))rG!B)PQYQ`Q`agQhPiio'pML::h G66(  ]  	]'^^H55z:H nnX..dFG)~~h77JNN<<X<X  yC  yG  yG  HP  yQ  yQ_t  WaJ"x00Z^^L5Q5QW]I)~~h77|=NH!~~h//eVG&-RVVH5E5E:BL(/vzz(7K7KZRTN%,BFF84D4D*2K'+Jww   S S 
S  IIgkk'267XX;XMIIgkk'267XX;XMR R @	 R
 A	H	  @	I	R
 I	b	R
 c	k	  b	l	R
 l	F
R
 G
P
  F
Q
R
 Q
_
R
 `
j
  _
k
R
 k
ER
 FM  ENR
 N\R
 ]e  \fR
 fsR
 tA  sBR
 CO  BPR
Pz	R {	I
  z	J
R J
{R |J  {KR KzR {G  zHR HiR jx  iyRyxR yA  yH  yH  I^  y_  x`R `lR mx  lyR ye	R f		  A
C
  f	C
  e	D
RD
?R @HjRIXR iohrhrs{h|h|Xd  CT  XUR UFR UW  U[  U[  \d  Ue  Ue  GQ  kz  F{R {rR s{  r|R |qR rz  rA  rA  BL  BP  BP  QW  BX  B^  B^  \^  r_  q`R `YR Zb  Zi  Zi  jt  jx  jx  yG  jH  jh  jh  LN  LR  LR  Sa  Lb  jh  jh  fh  Zi  YjR jc	R d	l	  d	s	  d	s	  t	~	  t	B
  t	B
  C
Q
  t	R
  t	r
  t	r
  V
X
  V
\
  V
\
  ]
k
  V
l
  t	r
  t	r
  p
r
  d	s
  c	t
R t
iR jr  jy  jy  zD  zH  zH  IS  zT  zk  zk  Xk  jl  imR mdR eq  drR rmR nz  m{R {}R ~K  }LR LCR DN  DR  DR  S[  D\  C]R ]dR em  et  et  u  uC  uC  DO  uP  u\  u\  T\  e]  d^R ^\R ]i  jt  jx  jx  yD  jE  jJ  jJ  IJ  ]K  \LR LNR OW  O^  O^  _i  _m  _m  nz  _{  _G  _G  I  M  M  NZ  [  _G  _G  _i  _m  _m  nz  _{  _G  _G  G  OH  NIRILR MUOO\iLjKkR lIR JR  JY  JY  Zg  Jh  IiRHiR Rr   c                 |    \        \        V ,          4      pV'       g	   R V  R2R3# \        \        V ,          V4      # )zNo HTML file found in z folder  )r  r{  r  )rI   r  s   & rK   	serve_appr  2  s8    wv/I'xw7<<wv	::r   r   c                      R # )uJ  
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>מרכז ניהול</title>
<style>
body{margin:0;font-family:Arial;background:linear-gradient(135deg,#081229,#102447);color:white;min-height:100vh}
.hero{text-align:center;padding:50px 20px 20px}
.hero h1{font-size:42px;margin:0}
.hero p{color:#d8e6ff;font-size:18px}
.grid{width:min(1100px,92%);margin:40px auto;display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:22px}
.card{text-decoration:none;color:white;border-radius:28px;padding:28px;min-height:180px;box-shadow:0 10px 30px rgba(0,0,0,.25);transition:.2s transform,.2s box-shadow}
.card:hover{transform:translateY(-4px);box-shadow:0 16px 40px rgba(0,0,0,.35)}
.card h2{font-size:30px;margin:0 0 12px}
.card p{line-height:1.6;margin:0}
.icon{font-size:52px;margin-bottom:15px}
.admin{background:linear-gradient(135deg,#0f9b0f,#38ef7d)}
.money{background:linear-gradient(135deg,#5f2c82,#49a09d)}
.homebudget{background:linear-gradient(135deg,#11998e,#38ef7d)}
.japan{background:linear-gradient(135deg,#ff416c,#ff4b2b)}
.usa{background:linear-gradient(135deg,#0052d4,#4364f7,#6fb1fc)}
.footer{text-align:center;color:#b8c8e6;padding:25px}

.image-guide{margin:12px 0 16px;background:#0f172a;border:1px solid #334155;border-radius:14px;padding:12px;color:#e2e8f0}
.image-guide summary{cursor:pointer;font-weight:bold;color:#bfdbfe;margin-bottom:10px}
.image-guide-table{width:100%;border-collapse:collapse;margin-top:10px;font-size:14px}
.image-guide-table th,.image-guide-table td{border-bottom:1px solid #334155;padding:9px;text-align:right;vertical-align:top}
.image-guide-table th{color:#93c5fd;background:#111827}
.image-guide-table td:first-child{white-space:nowrap;color:#fde68a}


.image-upload-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:12px;margin-top:16px}
.image-upload-card{margin:0}
.image-file-input{position:absolute;opacity:0;width:1px;height:1px;pointer-events:none}
.image-upload-label{display:block;height:100%;cursor:pointer;background:#0f172a;border:1px solid #334155;border-radius:18px;padding:15px;transition:.18s transform,.18s border-color,.18s background;box-shadow:0 8px 22px rgba(0,0,0,.14)}
.image-upload-label:hover{transform:translateY(-2px);border-color:#60a5fa;background:#13213a}
.image-key{display:inline-flex;background:#1d4ed8;color:#dbeafe;border-radius:999px;padding:4px 9px;font-size:12px;font-weight:900;margin-bottom:8px}
.image-title{display:block;color:#fff;font-size:17px;font-weight:950;margin-bottom:7px;line-height:1.25}
.image-desc{display:block;color:#cbd5e1;font-size:14px;line-height:1.45;min-height:42px}
.upload-status{display:block;margin-top:12px;color:#fde68a;font-size:13px;font-weight:900;border-top:1px solid #334155;padding-top:10px}
@media(max-width:640px){.image-upload-grid{grid-template-columns:1fr}.image-title{font-size:16px}.image-desc{min-height:auto}}

.app-hero{background:radial-gradient(circle at top right,rgba(59,130,246,.35),transparent 35%),linear-gradient(135deg,#172554,#0f172a);border:1px solid #334155;border-radius:28px;padding:26px;margin-bottom:18px;box-shadow:0 20px 60px rgba(0,0,0,.25)}
.app-hero h1{text-align:right;margin:0 0 8px;font-size:36px;letter-spacing:-.8px}.app-hero p{margin:0;color:#cbd5e1;line-height:1.65}.top-actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:16px}.pill-link{display:inline-flex;align-items:center;gap:8px;background:#1d4ed8;color:white!important;text-decoration:none;border-radius:999px;padding:10px 14px;font-weight:900;border:1px solid #60a5fa}.pill-link.secondary{background:#334155;border-color:#475569}.dashboard-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:14px;margin:18px 0}.dash-card{background:linear-gradient(180deg,#1e293b,#111827);border:1px solid #334155;border-radius:22px;padding:16px;box-shadow:0 10px 32px rgba(0,0,0,.18)}.dash-card b{display:block;font-size:18px;margin-bottom:6px}.dash-card span{color:#cbd5e1;font-size:14px;line-height:1.5}.box{box-shadow:0 16px 44px rgba(0,0,0,.20);border:1px solid #334155}.box h2{font-size:25px;letter-spacing:-.4px}.box h3{color:#bfdbfe;margin-top:20px}.split-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px}.mini-panel{background:#0f172a;border:1px solid #334155;border-radius:16px;padding:14px}.mini-panel h3{margin-top:0}.danger-zone{background:linear-gradient(135deg,#451a1a,#1e293b)!important;border-color:#7f1d1d!important}.safe-zone{background:linear-gradient(135deg,#132f25,#1e293b)!important;border-color:#166534!important}.field-label{display:block;color:#cbd5e1;font-size:13px;font-weight:900;margin:12px 0 6px}select,input[type=text]{width:100%;box-sizing:border-box;padding:13px;background:#0f172a;color:white;border-radius:12px;border:1px solid #334155}label.check{display:flex;align-items:center;gap:8px;margin-top:12px;color:#e2e8f0;font-weight:bold}.small-danger{background:#991b1b!important}.cancel{background:#475569!important}.muted{color:#94a3b8;font-size:13px;line-height:1.6}.success-dot{display:inline-block;width:10px;height:10px;background:#22c55e;border-radius:50%;box-shadow:0 0 14px #22c55e;margin-left:8px}.quick-nav{box-shadow:0 12px 32px rgba(0,0,0,.22)}@media(max-width:720px){.wrap{width:min(100%,94%);padding:18px 0}.app-hero{padding:20px}.app-hero h1{font-size:28px}.quick-nav{overflow:auto;flex-wrap:nowrap}.quick-nav a{white-space:nowrap}.dashboard-grid{grid-template-columns:1fr}}


</style>
</head>
<body>
<div class="hero">
<h1>מרכז ניהול</h1>
<p>מערכת מרכזית לניהול קבצים, תקציבים ולוחות זמנים</p>
</div>
<div class="grid">
<a class="card admin" href="/admin"><div class="icon">📁</div><h2>ניהול קבצים</h2><p>העלאת קבצים ישירות למחשב.</p></a>
<a class="card money" href="/Moneyapp/"><div class="icon">💰</div><h2>תקציב טיולים</h2><p>ניהול תקציב חופשות וסנכרון נתונים.</p></a>
<a class="card homebudget" href="/MoneyHome/"><div class="icon">🏠</div><h2>תקציב משפחתי</h2><p>ניהול תקציב חודשי, Limits, הוצאות בפועל וארכיון חודשים.</p></a>
<a class="card admin" href="/TripForm/"><div class="icon">🧾</div><h2>טופס פתיחת טיול</h2><p>טופס קליטת נתונים לטיול חדש.</p></a>
<a class="card admin" href="/admin/camera"><div class="icon">📷</div><h2>מצלמת חדר</h2><p>צפייה חיה במצלמת המחשב, אודיו והקלטות דרך הפאנל.</p></a>
<a class="card japan" href="/JAPAN/"><div class="icon">🇯🇵</div><h2>טיול יפן</h2><p>לוז, ניווטים ומסמכי הטיול.</p></a>
<a class="card usa" href="/USA/"><div class="icon">🇺🇸</div><h2>טיול ארה״ב</h2><p>טיול בר מצווה 2027.</p></a>
</div>
<div class="footer">TripServer</div>
</body>
</html>
r   r   r   rK   homer  9  s    Cr   c                     . p \          F  w  rp\        P                  ! VR R7      p\        P                  ! VR R7      p\        P                  ! VR R7      p\        P                  ! VR,           V,           R,           V,           P                  4       R R7      pV P	                  RV: RV: RV: RV: RV: RV: R	V: R
24       K  	  RP                  V 4      # )T)quoter   z.
<form class="image-upload-card" data-search="zw" action="/upload_usa_image" method="post" enctype="multipart/form-data">
<input type="hidden" name="image_key" value="z2">
<input class="image-file-input" id="image-file-u  " type="file" name="file" accept=".jpg,.jpeg,.png,.webp,.bmp,.tif,.tiff,image/*" onchange="if(this.files && this.files.length){this.closest('form').querySelector('.upload-status').textContent='מעלה תמונה...';this.closest('form').submit();}">
<label for="image-file-z6" class="image-upload-label">
<span class="image-key">z"</span>
<span class="image-title">z!</span>
<span class="image-desc">um   </span>
<span class="upload-status">לחץ כאן ובחר תמונה מהטלפון</span>
</label>
</form>
rn  )USA_IMAGE_UI_ITEMSr  r  rA   r  rD   )r  r}  r  descsafe_keyr  	safe_descsearch_texts           rK   render_usa_image_upload_cardsr    s    E"4	$??9D9__U$7
OOD5	ooy3'>'Dt'K&R&R&T\`a Hh(J	S 	T #5" 99Ur   /adminz/admin/c                  2    R \        4       ,           R,           # )u'`  
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TripServer Admin</title>
<style>
:root{--bg:#07111f;--panel:#101c31;--panel2:#14233c;--line:#253650;--text:#f8fafc;--muted:#a8b3c7;--brand:#3b82f6;--brand2:#60a5fa;--good:#16a34a;--warn:#f59e0b;--bad:#dc2626;--glass:rgba(16,28,49,.74)}
*{box-sizing:border-box}body{margin:0;font-family:Arial,'Segoe UI',sans-serif;background:radial-gradient(circle at 85% -10%,rgba(59,130,246,.35),transparent 28%),radial-gradient(circle at 10% 10%,rgba(20,184,166,.18),transparent 24%),linear-gradient(180deg,#07111f,#0f172a 52%,#07111f);color:var(--text);min-height:100vh}a{color:inherit}.wrap{width:min(1180px,94%);margin:auto;padding:22px 0 48px}.app-shell{min-height:calc(100vh - 44px)}
.hero{display:grid;grid-template-columns:1fr auto;gap:16px;align-items:center;background:linear-gradient(135deg,rgba(30,64,175,.92),rgba(15,23,42,.88));border:1px solid rgba(147,197,253,.25);border-radius:30px;padding:22px;box-shadow:0 25px 70px rgba(0,0,0,.30);position:relative;overflow:hidden}.hero:after{content:"";position:absolute;inset:auto -60px -90px auto;width:260px;height:260px;border-radius:50%;background:rgba(96,165,250,.16)}.hero h1{margin:0 0 8px;font-size:clamp(28px,5vw,44px);letter-spacing:-1px}.hero p{margin:0;color:#dbeafe;line-height:1.65;max-width:760px}.hero-actions{display:flex;gap:10px;flex-wrap:wrap;justify-content:flex-end}.btn-link,.back-home{display:inline-flex;align-items:center;justify-content:center;gap:8px;text-decoration:none;border:1px solid rgba(148,163,184,.35);background:rgba(15,23,42,.65);border-radius:999px;padding:11px 15px;font-weight:900;white-space:nowrap}.btn-link:hover,.back-home:hover{border-color:var(--brand2);background:rgba(59,130,246,.22)}
.status-strip{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin:16px 0}.status-card{background:var(--glass);border:1px solid var(--line);border-radius:20px;padding:14px;box-shadow:0 16px 40px rgba(0,0,0,.18)}.status-card b{display:block;font-size:16px;margin-bottom:5px}.status-card span{color:var(--muted);font-size:13px;line-height:1.45}.dot{display:inline-block;width:10px;height:10px;background:#22c55e;border-radius:50%;box-shadow:0 0 16px #22c55e;margin-left:7px}.main-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:18px}.main-card{margin-top:0;border:1px solid var(--line);background:linear-gradient(180deg,rgba(30,41,59,.94),rgba(15,23,42,.98));border-radius:26px;padding:20px;text-align:right;cursor:pointer;color:white;box-shadow:0 20px 55px rgba(0,0,0,.24);min-height:160px;transition:.18s transform,.18s border-color,.18s background;position:relative;overflow:hidden}.main-card:after{content:"›";position:absolute;left:18px;bottom:10px;font-size:42px;color:rgba(191,219,254,.35);transform:rotate(180deg)}.main-card:hover{transform:translateY(-4px);border-color:var(--brand2);background:linear-gradient(180deg,rgba(37,99,235,.28),rgba(15,23,42,.98))}.main-card .icon{font-size:34px;margin-bottom:10px}.main-card h2{margin:0 0 8px;font-size:24px}.main-card p{margin:0;color:var(--muted);line-height:1.55}.main-card.danger-card{border-color:rgba(248,113,113,.45);background:linear-gradient(180deg,rgba(127,29,29,.65),rgba(15,23,42,.98))}.main-card.admin-card{border-color:rgba(251,191,36,.45)}
.screen{display:none;margin-top:18px}.screen.active{display:block}.section-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:20px 0 14px}.section-title h2{margin:0 0 6px;font-size:32px;letter-spacing:-.5px}.section-title p{margin:0;color:var(--muted);line-height:1.55}.section-actions{display:flex;gap:10px;flex-wrap:wrap}.back-btn{border:1px solid var(--line);background:#1e293b;color:white;border-radius:999px;padding:10px 14px;cursor:pointer;font-weight:900}.back-btn:hover{background:#334155}.sub-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px}.sub-card{background:linear-gradient(180deg,var(--panel),#0f172a);border:1px solid var(--line);border-radius:22px;padding:18px;cursor:pointer;min-height:126px;transition:.18s transform,.18s border-color}.sub-card:hover{transform:translateY(-3px);border-color:var(--brand2)}.sub-card h3{margin:0 0 8px;font-size:22px}.sub-card p{margin:0;color:var(--muted);line-height:1.55}.tool-panel{display:none;background:rgba(16,28,49,.92);border:1px solid var(--line);border-radius:26px;padding:20px;box-shadow:0 20px 60px rgba(0,0,0,.22);margin-top:16px}.tool-panel.active{display:block}.tool-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:14px}.tool-head h3{font-size:26px;margin:0 0 6px}.tool-head p{margin:0;color:var(--muted);line-height:1.55}.form-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px}.upload-box{background:#0b1220;border:1px solid #24344d;border-radius:18px;padding:16px}.upload-box h4{margin:0 0 8px;font-size:18px}.upload-box p{color:var(--muted);line-height:1.55;margin:8px 0 0;font-size:14px}.note{color:var(--muted);font-size:14px;line-height:1.65}.warning{background:rgba(127,29,29,.38);border:1px solid rgba(248,113,113,.35);color:#fecaca;border-radius:16px;padding:13px;line-height:1.6;margin:12px 0}.good{background:rgba(22,101,52,.30);border:1px solid rgba(74,222,128,.35);color:#bbf7d0;border-radius:16px;padding:13px;line-height:1.6;margin:12px 0}.mini-note{background:#0f172a;border:1px solid var(--line);border-radius:14px;padding:12px;color:#cbd5e1;line-height:1.6;font-size:14px}input[type=file],select,input[type=text]{width:100%;padding:14px;background:#07111f;color:white;border-radius:14px;border:1px solid #334155;font-size:15px}input[type=file]::file-selector-button{border:0;border-radius:10px;background:#1d4ed8;color:white;padding:10px 12px;margin-left:10px;font-weight:900}button{border:0;background:#2563eb;color:white;padding:13px 17px;border-radius:14px;font-size:15px;font-weight:950;cursor:pointer;margin-top:12px;box-shadow:0 12px 30px rgba(37,99,235,.20)}button:hover{filter:brightness(1.08)}button.orange{background:#ea580c}button.danger{background:#dc2626}button.cancel{background:#475569}.preview-links{display:flex;gap:10px;flex-wrap:wrap;margin-top:12px}.preview-links a{display:inline-flex;text-decoration:none;background:#172033;border:1px solid #334155;border-radius:12px;padding:10px 12px;font-weight:900;color:#dbeafe}.preview-links a:hover{border-color:var(--brand2)}.field-label{display:block;color:#cbd5e1;font-size:13px;font-weight:900;margin:12px 0 6px}label.check{display:flex;align-items:center;gap:8px;margin-top:12px;color:#e2e8f0;font-weight:bold}.danger-zone{background:linear-gradient(135deg,rgba(69,26,26,.72),rgba(16,28,49,.94))!important;border-color:rgba(248,113,113,.35)!important}.split-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px}.filter-bar{position:sticky;top:0;z-index:8;background:rgba(7,17,31,.92);backdrop-filter:blur(12px);border:1px solid var(--line);border-radius:18px;padding:12px;margin:10px 0 14px;display:grid;grid-template-columns:1fr auto;gap:10px;align-items:center}.jump-days{display:flex;gap:6px;flex-wrap:wrap;max-width:500px;justify-content:flex-end}.jump-days button{margin:0;padding:7px 9px;border-radius:10px;background:#1e293b;box-shadow:none;font-size:12px}.image-upload-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:12px}.image-upload-card{margin:0}.image-file-input{position:absolute;opacity:0;width:1px;height:1px;pointer-events:none}.image-upload-label{display:block;height:100%;cursor:pointer;background:#0b1220;border:1px solid #283950;border-radius:18px;padding:15px;transition:.18s transform,.18s border-color,.18s background;box-shadow:0 8px 22px rgba(0,0,0,.14)}.image-upload-label:hover{transform:translateY(-2px);border-color:#60a5fa;background:#13213a}.image-key{display:inline-flex;background:#1d4ed8;color:#dbeafe;border-radius:999px;padding:4px 9px;font-size:12px;font-weight:900;margin-bottom:8px}.image-title{display:block;color:#fff;font-size:17px;font-weight:950;margin-bottom:7px;line-height:1.25}.image-desc{display:block;color:#cbd5e1;font-size:14px;line-height:1.45;min-height:42px}.upload-status{display:block;margin-top:12px;color:#fde68a;font-size:13px;font-weight:900;border-top:1px solid #334155;padding-top:10px}.breadcrumb{display:flex;gap:8px;align-items:center;color:#bfdbfe;font-size:14px;margin:16px 0 0}.breadcrumb button{margin:0;background:transparent;border:1px solid #334155;box-shadow:none;padding:7px 10px}.mobile-footer{display:none;position:fixed;bottom:12px;right:12px;left:12px;z-index:20}.mobile-footer button{width:100%;box-shadow:0 12px 40px rgba(0,0,0,.35)}
@media(max-width:860px){.hero{grid-template-columns:1fr;padding:18px}.hero h1{font-size:30px}.hero p{font-size:14px;line-height:1.55}.hero-actions{justify-content:flex-start}.status-strip{display:none}.main-grid{grid-template-columns:repeat(2,1fr);gap:10px}.main-card{min-height:128px;padding:14px;border-radius:22px}.main-card .icon{font-size:27px;margin-bottom:7px}.main-card h2{font-size:20px;margin-bottom:6px}.main-card p{font-size:12.5px;line-height:1.38}.sub-grid,.form-grid,.split-grid{grid-template-columns:1fr}.section-head,.tool-head{display:block}.section-actions{margin-top:12px}.filter-bar{grid-template-columns:1fr}.jump-days{justify-content:flex-start;max-width:none}.wrap{width:min(100%,94%);padding:14px 0 72px}.mobile-footer{display:none}.image-upload-grid{grid-template-columns:1fr}.image-desc{min-height:auto}}@media(max-width:340px){.main-grid{grid-template-columns:1fr}.main-card{min-height:120px}}
</style>
</head>
<body>
<div class="wrap app-shell">
<div class="hero">
<div>
<h1><span class="dot"></span>TripServer Admin</h1>
<p>מסך ניהול לפי היגיון עבודה: בוחרים תחום, נכנסים לתת־קטגוריה, ואז מעלים רק את מה שצריך. בלי גלילה אינסופית ובלי לחפש ידיים ורגליים.</p>
</div>
<div class="hero-actions">
<a class="btn-link" href="/admin/status">📊 סטטוס קבצים</a>
<a class="btn-link" href="/admin/health">🩺 בדיקת מערכת</a>
<a class="btn-link" href="/admin/self-test">🧪 בדיקה עצמית מלאה</a>
<a class="btn-link" href="/admin/watchdog">🛡️ Watchdog</a>
<a class="btn-link" href="/admin/logs">📜 לוגים</a>
<a class="btn-link" href="/">🏠 ראשי</a>
</div>
</div>

<div id="screen-home" class="screen active">
<div class="status-strip">
<div class="status-card"><b>📁 העלאה בטוחה</b><span>שמירה זמנית, גיבוי, החלפה אטומית, גודל ו־SHA אחרי שמירה.</span></div>
<div class="status-card"><b>🔁 Restart לאדמין</b><span>עדכון admin מפעיל helper חיצוני, לוג ובדיקת פורט.</span></div>
<div class="status-card"><b>🧭 מבנה היררכי</b><span>מסך ראשי → תחום → תת־תחום → פעולה.</span></div>
<div class="status-card"><b>🖥️ מחשב</b><span>כיבוי/ריסטארט עם טיימר, אישור כתוב וביטול.</span></div>
<div class="status-card"><b>🛡️ Watchdog</b><span>בדיקה חיצונית כל דקה והפעלה אוטומטית אם האדמין נפל.</span></div>
<div class="status-card"><b>📜 לוגים</b><span>צפייה בלוגי restart ו־Watchdog מתוך הפאנל.</span></div>
</div>
<div class="main-grid">
<button class="main-card" onclick="showScreen('japan')"><div class="icon">🇯🇵</div><h2>יפן</h2><p>קובץ טיול, מצגות, תמונות ומוזיקה של יפן.</p></button>
<button class="main-card" onclick="showScreen('usa')"><div class="icon">🇺🇸</div><h2>ארצות הברית</h2><p>קובץ טיול, מצגת, TV, תמונות שקפים ומוזיקה.</p></button>
<button class="main-card" onclick="showScreen('budgets')"><div class="icon">💰</div><h2>תקציבים</h2><p>אפליקציית תקציב חופשה ואפליקציית תקציב חודשי/משפחתי.</p></button>
<button class="main-card" onclick="showScreen('tripform')"><div class="icon">🧾</div><h2>טופס פתיחת טיול</h2><p>טופס קליטת טיול חדש, שמירה כ־TripForm/index.html.</p></button>
<button class="main-card danger-card" onclick="showScreen('power')"><div class="icon">🖥️</div><h2>פעולות מחשב</h2><p>כיבוי, ריסטארט, טיימר וביטול פעולה מתוזמנת.</p></button>
<button class="main-card" onclick="showScreen('watchdog')"><div class="icon">🛡️</div><h2>Watchdog</h2><p>שמירת הפאנל חי: בדיקה שקטה כל כמה דקות, בלי חלון שחור קופץ, שחרור פורט תקוע והפעלה מחדש אם נפל.</p></button>
<a class="main-card" href="/admin/camera" style="text-decoration:none"><div class="icon">📷</div><h2>מצלמת חדר</h2><p>הפעלת מצלמת החדר, אודיו והקלטות — רק בלחיצה ידנית.</p></a>
<a class="main-card" href="/admin/logs" style="text-decoration:none"><div class="icon">📜</div><h2>לוגים</h2><p>צפייה בלוגי אתחול פאנל ו־Watchdog מתוך הדפדפן.</p></a>
<button class="main-card admin-card" onclick="showScreen('admin-tools')"><div class="icon">⚙️</div><h2>ניהול האדמין</h2><p>העלאת admin.py/admin_server.py, restart ושחזור גיבוי.</p></button>
</div>
</div>

<div id="screen-japan" class="screen">
<div class="section-head"><div class="section-title"><h2>🇯🇵 יפן</h2><p>בחר קודם מה אתה מעדכן: קובץ הטיול, המצגות או המדיה.</p></div><div class="section-actions"><button class="back-btn" onclick="showScreen('home')">⬅ חזרה למסך הראשי</button><a class="btn-link" href="/JAPAN/" target="_blank">פתח יפן</a></div></div>
<div class="sub-grid">
<div class="sub-card" onclick="showTool('japan','japan-trip')"><h3>📄 קובץ טיול יפן</h3><p>העלאת index.html או חבילת ZIP מלאה.</p></div>
<div class="sub-card" onclick="showTool('japan','japan-presentations')"><h3>🎬 מצגות יפן</h3><p>פתיח טיסה ומצגת יפן.</p></div>
<div class="sub-card" onclick="showTool('japan','japan-media')"><h3>🖼️🎵 מדיה יפן</h3><p>ZIP תמונות ושירי MP3.</p></div>
<div class="sub-card" onclick="window.open('/JAPAN/japan-experience.html','_blank')"><h3>🔎 בדיקה מהירה</h3><p>פתיחת מצגת יפן בחלון חדש.</p></div>
</div>
<div id="tool-japan-trip" class="tool-panel">
<div class="tool-head"><div><h3>📄 קובץ טיול יפן</h3><p>קובץ יחיד נשמר כ־JAPAN/index.html. ZIP מלא מעדכן גם מצגות ומדיה אם הן קיימות בחבילה.</p></div><button class="back-btn" onclick="hideTools('japan')">חזרה לתת־קטגוריות</button></div>
<div class="form-grid"><div class="upload-box"><h4>קובץ HTML ראשי</h4><form action="/upload/JAPAN" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".html,.htm"><button>העלה קובץ טיול יפן</button></form><p>יישמר כ־C:\TripServer\JAPAN\index.html</p></div><div class="upload-box"><h4>ZIP מלא יפן</h4><form action="/upload_trip_package/JAPAN" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".zip,application/zip,application/x-zip-compressed"><button>העלה ZIP מלא של יפן</button></form><p>מתאים לחבילה עם index.html, japan-experience.html, japan-flight-intro.html ותיקיית media.</p></div></div>
</div>
<div id="tool-japan-presentations" class="tool-panel">
<div class="tool-head"><div><h3>🎬 מצגות יפן</h3><p>שמות היעד קבועים כדי שהקישורים מתוך קובץ הטיול לא יישברו.</p></div><button class="back-btn" onclick="hideTools('japan')">חזרה לתת־קטגוריות</button></div>
<div class="form-grid"><div class="upload-box"><h4>✈️ פתיח טיסה</h4><form action="/upload_presentation/flight_intro" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".html,.htm"><button>העלה פתיח טיסה</button></form><p>יישמר כ־japan-flight-intro.html</p></div><div class="upload-box"><h4>🎌 מצגת יפן</h4><form action="/upload_presentation/japan_experience" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".html,.htm"><button>העלה מצגת יפן</button></form><p>יישמר כ־japan-experience.html</p></div></div>
<div class="preview-links"><a href="/JAPAN/japan-flight-intro.html" target="_blank">בדיקת פתיח</a><a href="/JAPAN/japan-experience.html" target="_blank">בדיקת מצגת</a></div>
</div>
<div id="tool-japan-media" class="tool-panel">
<div class="tool-head"><div><h3>🖼️🎵 מדיה יפן</h3><p>תמונות ושירים נשמרים לנתיבים שהמצגת מחפשת בפועל. ספירה מדויקת של תמונות בשימוש נמצאת במסך סטטוס קבצים.</p></div><button class="back-btn" onclick="hideTools('japan')">חזרה לתת־קטגוריות</button></div>
<div class="form-grid"><div class="upload-box"><h4>ZIP תמונות מצגת יפן</h4><form action="/upload_japan_images_zip" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".zip,application/zip,application/x-zip-compressed"><button>העלה ZIP תמונות יפן</button></form><p>הפאנל מסנן קובצי תמונה נתמכים. הספירה החשובה היא לא כמה קבצים יש בתיקייה, אלא כמה src מופיעים בפועל בתוך japan-experience.html. בחבילות/ZIP מלאים הוא לא משנה שמות קבצים כדי לא לשבור קישורים פנימיים במצגת.</p></div><div class="upload-box"><h4>🎵 שיר מצגת יפן</h4><form action="/upload_japan_music/japan_experience_music" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".mp3,.wav,.m4a,.aac,.flac,.ogg,.opus,.wma,.webm,.mp4,audio/*,video/mp4"><button>העלה japan-theme.mp3</button></form><p>כל קובץ אודיו נתמך יישמר כ־MP3 אמיתי בכל נתיבי ה־fallback של המצגת. המרה מלאה דורשת FFmpeg.</p></div><div class="upload-box"><h4>✈️ מוזיקת פתיח טיסה</h4><form action="/upload_japan_music/japan_flight_music" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".mp3,.wav,.m4a,.aac,.flac,.ogg,.opus,.wma,.webm,.mp4,audio/*,video/mp4"><button>העלה flight-intro.mp3</button></form><p>כל קובץ אודיו נתמך יישמר כ־MP3 אמיתי לנתיב מוזיקת פתיח הטיסה. המרה מלאה דורשת FFmpeg.</p></div></div>
</div>
</div>

<div id="screen-usa" class="screen">
<div class="section-head"><div class="section-title"><h2>🇺🇸 ארצות הברית</h2><p>אזור ארה״ב מחולק לקובץ טיול, מצגות, תמונות שקפים ומוזיקה/TV.</p></div><div class="section-actions"><button class="back-btn" onclick="showScreen('home')">⬅ חזרה למסך הראשי</button><a class="btn-link" href="/USA/" target="_blank">פתח ארה״ב</a></div></div>
<div class="sub-grid">
<div class="sub-card" onclick="showTool('usa','usa-trip')"><h3>📄 קובץ טיול</h3><p>HTML ראשי, ZIP מלא וגרסת טלוויזיה.</p></div>
<div class="sub-card" onclick="showTool('usa','usa-presentation')"><h3>🎬 מצגת</h3><p>מצגת עם סכומים וגרסת TV.</p></div>
<div class="sub-card" onclick="showTool('usa','usa-images')"><h3>🖼️ תמונות שקפים</h3><p>ZIP מלא או העלאה לפי שקף/יום.</p></div>
<div class="sub-card" onclick="showTool('usa','usa-music')"><h3>🎵 מוזיקה</h3><p>שיר חלק 1 ושיר חלק 2 של המצגת.</p></div>
</div>
<div id="tool-usa-trip" class="tool-panel">
<div class="tool-head"><div><h3>📄 קובץ טיול ארה״ב</h3><p>קובץ הטיול הראשי נשמר כ־USA/index.html. גרסת TV נשמרת בנפרד.</p></div><button class="back-btn" onclick="hideTools('usa')">חזרה לתת־קטגוריות</button></div>
<div class="form-grid"><div class="upload-box"><h4>HTML ראשי</h4><form action="/upload/USA" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".html,.htm"><button>העלה קובץ טיול ארה״ב</button></form><p>יישמר כ־C:\TripServer\USA\index.html</p></div><div class="upload-box"><h4>ZIP מלא ארה״ב</h4><form action="/upload_trip_package/USA" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".zip,application/zip,application/x-zip-compressed"><button>העלה ZIP מלא של ארה״ב</button></form><p>מתאים לחבילת Netlify/שרת עם index.html, מצגת, media ותמונות.</p></div><div class="upload-box"><h4>גרסת טלוויזיה</h4><form action="/upload_usa_extra_html/usa_trip_tv" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".html,.htm"><button>העלה קובץ ארה״ב TV</button></form><p>יישמר כ־usa2027-tv.html.</p></div></div>
</div>
<div id="tool-usa-presentation" class="tool-panel">
<div class="tool-head"><div><h3>🎬 מצגת ארה״ב</h3><p>המצגת הרגילה והמצגת המותאמת למסך טלוויזיה נשמרות בשמות קבועים.</p></div><button class="back-btn" onclick="hideTools('usa')">חזרה לתת־קטגוריות</button></div>
<div class="form-grid"><div class="upload-box"><h4>מצגת ארה״ב עם סכומים</h4><form action="/upload_usa_presentation/usa_presentation" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".html,.htm"><button>העלה מצגת ארה״ב</button></form><p>יישמר כ־usa2027-presentation.html</p></div><div class="upload-box"><h4>מצגת ארה״ב TV</h4><form action="/upload_usa_presentation/usa_presentation_tv" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".html,.htm"><button>העלה מצגת TV</button></form><p>יישמר כ־usa2027-presentation-tv.html</p></div></div>
<div class="preview-links"><a href="/USA/usa2027-presentation.html" target="_blank">בדיקת מצגת</a><a href="/USA/usa2027-presentation-tv.html" target="_blank">בדיקת מצגת TV</a></div>
</div>
<div id="tool-usa-images" class="tool-panel">
<div class="tool-head"><div><h3>🖼️ תמונות מצגת ארה״ב</h3><p>התיאורים כאן מסונכרנים לסדר השקפים בפועל: Disney Springs, ימי ים בקרוז, St. Maarten, St. Thomas ו־CocoCay.</p></div><button class="back-btn" onclick="hideTools('usa')">חזרה לתת־קטגוריות</button></div>
<div class="good">העלאה בודדת ו־ZIP שומרים תמיד JPG אמיתי בשם השקף, עם דחיסה חכמה והקטנה עדינה עד 1920px בצלע הארוכה. העלאת ZIP מקבלת שמות כמו day-01.jpg עד day-36.jpg וגם intro/budget/summary/extra.</div>
<div class="form-grid"><div class="upload-box"><h4>ZIP תמונות מלא</h4><form action="/upload_usa_images_zip" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".zip,application/zip,application/x-zip-compressed"><button>העלה ZIP תמונות ארה״ב</button></form><p>שמות נתמכים: intro, roadtrip-map, day-01 עד day-36, budget, summary ותמונות bonus.</p></div><div class="upload-box"><h4>בדיקת מצגת</h4><p>אחרי העלאת תמונות פתח את המצגת כדי לוודא שאין cache ישן.</p><div class="preview-links"><a href="/USA/usa2027-presentation.html?from=admin" target="_blank">פתח מצגת</a><a href="/admin/status" target="_blank">סטטוס תמונות</a></div></div></div>
<div class="filter-bar"><input id="imageSearch" type="text" placeholder="חיפוש שקף: יום 18, Disney Springs, קרוז, CocoCay..." oninput="filterImages()"><div class="jump-days"><button onclick="jumpImage('intro')">פתיחה</button><button onclick="jumpImage('day-01')">יום 1</button><button onclick="jumpImage('day-18')">יום 18</button><button onclick="jumpImage('day-28')">קרוז</button><button onclick="jumpImage('budget')">תקציב</button><button onclick="jumpImage('summary')">סיום</button></div></div>
<div class="image-upload-grid" id="usaImageGrid">
u1  
</div>
</div>
<div id="tool-usa-music" class="tool-panel">
<div class="tool-head"><div><h3>🎵 מוזיקת מצגת ארה״ב</h3><p>שני קבצי MP3 אמיתיים בלבד, כדי שהדפדפן ינגן בלי קובץ מזויף.</p></div><button class="back-btn" onclick="hideTools('usa')">חזרה לתת־קטגוריות</button></div>
<div class="form-grid"><div class="upload-box"><h4>שיר חלק 1 — Road Trip</h4><form action="/upload_usa_music/usa_music" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".mp3,.wav,.m4a,.aac,.flac,.ogg,.opus,.wma,.webm,.mp4,audio/*,video/mp4"><button>העלה שיר חלק 1</button></form><p>usa-roadtrip-theme.mp3 — ממיר ל־MP3 אם FFmpeg מותקן.</p></div><div class="upload-box"><h4>שיר חלק 2 — Orlando / Miami / Cruise</h4><form action="/upload_usa_music/usa_music_part2" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".mp3,.wav,.m4a,.aac,.flac,.ogg,.opus,.wma,.webm,.mp4,audio/*,video/mp4"><button>העלה שיר חלק 2</button></form><p>usa-part2-theme.mp3 — ממיר ל־MP3 אם FFmpeg מותקן.</p></div></div>
</div>
</div>

<div id="screen-budgets" class="screen">
<div class="section-head"><div class="section-title"><h2>💰 תקציבים</h2><p>שתי אפליקציות נפרדות: תקציב חופשה ותקציב חודשי/משפחתי.</p></div><div class="section-actions"><button class="back-btn" onclick="showScreen('home')">⬅ חזרה למסך הראשי</button></div></div>
<div class="form-grid"><div class="upload-box"><h4>💼 אפליקציית ניהול תקציב חופשה</h4><form action="/upload/Moneyapp" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".html,.htm"><button>העלה אפליקציית תקציב חופשה</button></form><p>יישמר כ־Moneyapp/index.html.</p><div class="preview-links"><a href="/Moneyapp/" target="_blank">פתח תקציב חופשה</a></div></div><div class="upload-box"><h4>🏠 אפליקציית תקציב חודשי / משפחתי</h4><form action="/upload/MoneyHome" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".html,.htm"><button>העלה תקציב חודשי</button></form><p>יישמר כ־MoneyHome/index.html.</p><div class="preview-links"><a href="/MoneyHome/" target="_blank">פתח תקציב חודשי</a></div></div></div>
</div>

<div id="screen-tripform" class="screen">
<div class="section-head"><div class="section-title"><h2>🧾 טופס פתיחת טיול</h2><p>טופס הקליטה ליצירת טיול חדש.</p></div><div class="section-actions"><button class="back-btn" onclick="showScreen('home')">⬅ חזרה למסך הראשי</button><a class="btn-link" href="/TripForm/" target="_blank">פתח טופס</a></div></div>
<div class="upload-box"><h4>העלאת טופס HTML</h4><form action="/upload/TripForm" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".html,.htm"><button>העלה טופס פתיחת טיול</button></form><p>יישמר כ־TripForm/index.html.</p></div>
</div>

<div id="screen-power" class="screen">
<div class="section-head"><div class="section-title"><h2>🖥️ פעולות מחשב</h2><p>פעולות Windows אמיתיות. הן מוגנות באישור כתוב, טיימר וחסימת גישה מחוץ לרשת מקומית.</p></div><div class="section-actions"><button class="back-btn" onclick="showScreen('home')">⬅ חזרה למסך הראשי</button></div></div>
<div class="tool-panel active danger-zone"><div class="warning"><strong>זהירות:</strong> כיבוי או ריסטארט מנתקים את השרת עד שהמחשב עולה מחדש. השתמש בטיימר ולא ב־0 שניות.</div><div class="split-grid"><div class="upload-box"><h4>⏻ כיבוי מחשב</h4><form action="/power/shutdown" method="post" onsubmit="return confirm('לקבוע כיבוי למחשב? אפשר לבטל עם כפתור ביטול לפני שהטיימר נגמר.')"><label class="field-label">טיימר לפני כיבוי</label><select name="delay"><option value="60">עוד דקה</option><option value="300">עוד 5 דקות</option><option value="900">עוד 15 דקות</option><option value="1800">עוד 30 דקות</option></select><label class="field-label">הקלד בדיוק: כיבוי</label><input type="text" name="confirm_text" autocomplete="off" placeholder="כיבוי"><label class="check"><input type="checkbox" name="ack" value="1"> אני מבין שזה יכבה את המחשב</label><button class="danger">קבע כיבוי מחשב</button></form></div><div class="upload-box"><h4>🔄 ריסטארט למחשב</h4><form action="/power/reboot" method="post" onsubmit="return confirm('לקבוע ריסטארט למחשב? אפשר לבטל עם כפתור ביטול לפני שהטיימר נגמר.')"><label class="field-label">טיימר לפני ריסטארט</label><select name="delay"><option value="60">עוד דקה</option><option value="300">עוד 5 דקות</option><option value="900">עוד 15 דקות</option><option value="1800">עוד 30 דקות</option></select><label class="field-label">הקלד בדיוק: הפעלה מחדש</label><input type="text" name="confirm_text" autocomplete="off" placeholder="הפעלה מחדש"><label class="check"><input type="checkbox" name="ack" value="1"> אני מבין שזה יפעיל את המחשב מחדש</label><button class="orange">קבע ריסטארט למחשב</button></form></div></div><form action="/power/cancel" method="post" onsubmit="return confirm('לבטל כיבוי/ריסטארט מתוזמן של Windows?')"><button class="cancel">בטל כיבוי/ריסטארט מתוזמן</button></form><p class="note">פעולות נרשמות ללוג C:\TripServer\admin_restart.log.</p></div>
</div>

<div id="screen-watchdog" class="screen">
<div class="section-head"><div class="section-title"><h2>🛡️ Watchdog</h2><p>שכבת ביטחון חיצונית שמחזירה את פאנל האדמין לאוויר אם הוא נפל.</p></div><div class="section-actions"><button class="back-btn" onclick="showScreen('home')">⬅ חזרה למסך הראשי</button><a class="btn-link" href="/admin/watchdog">מסך Watchdog מלא</a><a class="btn-link" href="/admin/self-test">בדיקה עצמית</a></div></div>
<div class="tool-panel active safe-zone"><div class="good"><strong>מטרה:</strong> לא ללכת פיזית למחשב אם השרת נפל. Windows יריץ סקריפט שקט דרך pythonw.exe כל כמה דקות, ואם /ping.json לא עונה — הוא ישחרר פורט תקוע במידת הצורך ויפעיל מחדש את admin_server.py.</div><div class="form-grid"><div class="upload-box"><h4>התקנה / עדכון</h4><form action="/watchdog/install" method="post" onsubmit="return confirm('להתקין או לעדכן את משימת ה־Watchdog?')"><button>התקן / עדכן Watchdog</button></form><p>נכתב אל C:\TripServer\tripserver_admin_watchdog.py ומותקן כ־Task Scheduler בשם TripServerAdminWatchdog.</p></div><div class="upload-box"><h4>בדיקה והרצה</h4><form action="/watchdog/run-once" method="post" onsubmit="return confirm('להריץ Watchdog פעם אחת עכשיו?')"><button class="orange">הרץ Watchdog עכשיו</button></form><div class="preview-links"><a href="/admin/watchdog">פתח סטטוס Watchdog</a></div><p>הרצה חד־פעמית לא מחליפה קבצים. אם השרת חי היא רק תצא תקין.</p></div><div class="upload-box"><h4>הסרה</h4><form action="/watchdog/uninstall" method="post" onsubmit="return confirm('להסיר את משימת ה־Watchdog המתוזמנת?')"><button class="danger">הסר Watchdog</button></form><p>מסיר רק את המשימה המתוזמנת. קובץ הסקריפט והלוג נשארים לצורך בדיקה.</p></div></div></div>
</div>

<div id="screen-admin-tools" class="screen">
<div class="section-head"><div class="section-title"><h2>⚙️ ניהול אפליקציית האדמין</h2><p>כאן מעדכנים את הקובץ שמפעיל את הפאנל עצמו.</p></div><div class="section-actions"><button class="back-btn" onclick="showScreen('home')">⬅ חזרה למסך הראשי</button><a class="btn-link" href="/admin/status">סטטוס</a><a class="btn-link" href="/admin/health">בדיקת מערכת</a><a class="btn-link" href="/admin/self-test">בדיקה עצמית מלאה</a><a class="btn-link" href="/admin/watchdog">Watchdog</a><a class="btn-link" href="/admin/logs">לוגים</a></div></div>
<div class="tool-panel active"><div class="warning"><strong>פעולה רגישה:</strong> עדכון admin_server.py מחליף את המנוע שמריץ את הפאנל. לכן יש בדיקת קומפילציה, גיבוי, החלפה אטומית ו־restart אוטומטי.</div><div class="good">הזרימה: העלאה → בדיקת Python → בדיקת סימני TripServer → גיבוי → החלפה → helper חיצוני → restart → לוג.</div><div class="form-grid"><div class="upload-box"><h4>העלאת admin חדש</h4><form action="/upload_admin_server" method="post" enctype="multipart/form-data" onsubmit="return confirm('להעלות admin_server.py חדש ולהחליף את קובץ הפאנל הפעיל אחרי בדיקה וגיבוי?')"><input type="file" name="file" accept=".py,text/x-python,text/plain"><button class="orange">העלה admin_server.py חדש</button></form><p>אם אצלך הקובץ נקרא admin.py, שמור את הקובץ החדש בשם הזה בהחלפה הידנית הראשונה.</p></div><div class="upload-box"><h4>פעולות תחזוקה</h4><form action="/restart_admin_server" method="post" onsubmit="return confirm('זו בדיקת אתחול מתקדמת. להפעיל מחדש את הפאנל עכשיו?')"><button class="orange">בדיקת אתחול פאנל — מתקדם</button></form><form action="/restore_admin_server_backup" method="post" onsubmit="return confirm('לשחזר את הגיבוי האחרון של admin_server.py?')"><button class="danger">שחזר גיבוי אחרון</button></form><div class="preview-links"><a href="/admin/self-test">🧪 הרץ בדיקה עצמית מלאה</a><a href="/admin/logs">📜 צפה בלוגים</a><a href="/admin/control">🛰️ שרת בקרה</a></div><p><b>הערה:</b> לא חובה אחרי התקנת Watchdog. בדיקת אתחול מיועדת רק לבדיקה יזומה או אחרי עדכון/שחזור אדמין.<br>גיבויים: C:\TripServer\backups\admin_server</p></div></div></div>
</div>

<div class="mobile-footer"><button onclick="showScreen('home')">🏠 חזרה למסך הראשי</button></div>
</div>
<script>
function showScreen(name){
  document.querySelectorAll('.screen').forEach(s=>s.classList.remove('active'));
  const el=document.getElementById('screen-'+name);
  if(el){el.classList.add('active'); location.hash=name==='home'?'':name; window.scrollTo({top:0,behavior:'smooth'});}
}
function hideTools(group){
  document.querySelectorAll('#screen-'+group+' .tool-panel').forEach(t=>t.classList.remove('active'));
  window.scrollTo({top:document.getElementById('screen-'+group).offsetTop-10,behavior:'smooth'});
}
function showTool(group, tool){
  hideTools(group);
  const el=document.getElementById('tool-'+tool);
  if(el){el.classList.add('active'); setTimeout(()=>el.scrollIntoView({behavior:'smooth',block:'start'}),70); location.hash=tool;}
}
function filterImages(){
  const q=(document.getElementById('imageSearch')?.value||'').toLowerCase().trim();
  document.querySelectorAll('#usaImageGrid .image-upload-card').forEach(card=>{card.style.display=!q||card.dataset.search.includes(q)?'block':'none';});
}
function jumpImage(key){
  const card=document.querySelector('#usaImageGrid input[value="'+key+'"]').closest('.image-upload-card');
  if(card){card.scrollIntoView({behavior:'smooth',block:'center'}); card.querySelector('.image-upload-label').style.borderColor='#fbbf24'; setTimeout(()=>card.querySelector('.image-upload-label').style.borderColor='',1600);}
}
window.addEventListener('load',()=>{const h=(location.hash||'').replace('#',''); if(['japan','usa','budgets','tripform','power','watchdog','admin-tools'].includes(h)) showScreen(h); if(h.startsWith('usa-')){showScreen('usa'); setTimeout(()=>showTool('usa',h),80);} if(h.startsWith('japan-')){showScreen('japan'); setTimeout(()=>showTool('japan',h),80);}});
</script>
</body>
</html>
)r  r   r   rK   adminr    s+    eJ $%Ke&J?)Kd dr   c                     V'       d   R pMVR8X  d   RpMRpT P                  RTRTRTRTR\        T;'       g    R	4      /4       R
# )passr  r  failcategoryr>   r   severityr  r}   N)r  r   )rj  r  r>   r   r  r  r   s   &&&&&& rK   add_self_test_resultr  F  sQ    		Y	NNH&H3w}}"% r   c                    W8X  d   R # T ;'       g    RP                  R4      P                  R4       Uu. uF  q"'       g   K  VNK  	  ppT;'       g    RP                  R4      P                  R4       Uu. uF  q"'       g   K  VNK  	  pp\        V4      \        V4      8w  d   R# \        W44       FI  w  rVVP	                  R4      '       d%   VP                  R4      '       d   V'       g    R# K@  WV8w  g   KH   R# 	  R # u upi u upi )Tr}   r   F<>)rZ   r   r   zipr   r  )ruler  part
rule_partsaction_parts	rule_partaction_parts   &&     rK   route_rule_matches_actionr  V  s    ~$(JJB#5#5c#:#@#@#EN#E4$$#EJN&,ll%9%9#%>%D%DS%IR%ITTDD%ILR
:#l++"%j"?	$$););C)@)@# #@  ORs   	DD7	DDc           	      h    \        \        \        P                  ! R T ;'       g    R4      4      4      # )z'<form[^>]+action=[\"\']([^\"\']+)[\"\']r}   )r  r  ru  ry  )r{  s   &rK   collect_admin_form_actionsr  h  s%    #bjj!KY__Z\]^__r   c                     \         P                  ! R T ;'       g    R4      p\        4       . r2V F1  pWB9   d   WC9  d   VP                  V4       VP	                  V4       K3  	  V# )z\bid=[\"\']([^\"\']+)[\"\']r}   )ru  ry  r  r  r  )r{  idsr  
duplicatesr   s   &    rK   collect_duplicate_idsr  l  sW    
**3Y__"
ECub*<D2d#  r   c            
      J   \         P                  ! \        R R7       \         P                  P	                  \        R\         P
                  ! 4        R\        \        P                  ! 4       4       R24      p  \        V RRR7      ;_uu_ 4       pVP                  R4       R	R	R	4       \        V R
RR7      ;_uu_ 4       pVP                  4       pR	R	R	4       XR8H  V 3 \         P                  P                  V 4      '       d   \         P                  ! V 4       # #   + '       g   i     L; i  + '       g   i     Lg; i  \         d     # i ; i   \         P                  P                  T 4      '       d   \         P                  ! T 4       i i   \         d     i i ; i; i)TrK  
self_test_rP  r   r  rm  r  zTripServer self testNr  )r=   rS  rT  r?   rD   rW  r[   rU  r   r  r   rC   r  rE   )	test_pathr   r   s      rK   check_temp_write_permissionr#  v  s*   KK$t41Z		}AcRVR[R[R]N^M__c3deI)S733rHH+, 4)S733r779D 4--y8	ww~~i((		)$ ) 4333  			ww~~i((		)$ ) 		sr   8E D E >D.E ;ED+	&E .D>	9E EEF";FF"FF"FF"c                p%  a8 \         P                   ! 4       p. p \        P                  ! \        RR7       \	        VRRR\        4        \        P                  ! \        P                  RRR	\        .RR^(R
7      p\	        TRRVP                  ^ 8H  VP                  ;'       g    VP                  ;'       g    RRR 4        \        \        4      w  rV\	        VRR\        V4      V4        \!        \"        P$                  P'                  \        4      \        P                  ;'       g    R\"        P$                  P)                  \"        P$                  P'                  \        4      4      ;'       g    \*        4      p\-        V4      w  r\	        VRR\        V4      V4        \/        \        \        P                  ;'       g    R\"        P$                  P)                  \"        P$                  P'                  \        4      4      ;'       g    \*        4      p	\1        V	4      w  r\	        VRRW4       \3        RR7      p\	        VRR\        VP5                  R4      4      RVP5                  R4       RVP5                  R4       24       \"        P6                  R8X  d;   \	        VRR\        VP5                  R4      4      VP5                  RR 4      RR7       M\	        VRR!RR"RR7        \9        \:        P=                  4       4       F5  w  r\	        VR$R%V R&2\"        P$                  P?                  V4      V4       K7  	   \A        4       w  r\	        VR$R'W4       R(\B        3R)\D        33 FK  w  pp \"        PF                  ! VRR*7       \	        VR$V\"        P$                  P?                  V4      V4       KM  	   \9        R+ \H        PJ                  PM                  4        4       4      p. R,NR-NR.NR/NR0NR1NR2NR3NR4NR5NR6NR7NR8NR9NR:NR;NR<NR=NR>NR?NR@NRANRBNRCNRDNRENRFNRGNRHNRINRJNRKNRLNRMNRNNRONRPNRQNRRNRSNRTNRUNpV Uu. uF  pVV9  g   K  VNK  	  pp\	        TRVRWV'       * V'       d   RXPO                  V4      M\Q        V4       RY24        \S        4       p\U        V4      p. pV FV  o8\V        ;QJ d    V83R[ lV 4       F  '       g   K   RM	  RM! V83R[ lV 4       4      '       d   KE  VPY                  S84       KX  	  \	        TRVR\V'       * V'       d   RXPO                  V4      M\Q        V4       R]24       \[        V4      p\	        TRVR^V'       * V'       d   RXPO                  V4      MR4       \	        VRVR_R0V9   R`4       \	        TRVRaR2V9   ;'       d    RbV9   Rc4       \	        VRVRdR3V9   Re4       \	        TRVRfR5V9   ;'       d    RgV9   Rh4       \	        TRVRiRjV9   ;'       d    RkV9   Rl4        \]        4       p\	        VRVRnRoV9   R4        \_        4       p\	        VRVRpRqV9   R4        \a        4       p\	        TRVRrRsV9   ;'       d    RtV9   R4        \c        4       p\	        TRuRvRgV9   ;'       d    R6V9   ;'       d    R9V9   R4       \e        4       p\	        TRuRw\        VP5                  Rx4      4      VP5                  Rx4      '       g   RyMRzVP5                  R{R 4       2RR7       \g        4       p\	        TRuR|R}V9   ;'       d    R~V9   R4       \	        TRuR\i        R4      ;'       d    \i        R4      '       * R4        \k        4       p\	        TRR\        VP5                  R4      4      VP5                  R4      '       g   RMR4       \	        TRR\        VP5                  R4      4      VP5                  R4      ;'       g    R4       V '       EdW    ^ RI6H7p  \"        P$                  PO                  \p        R4      p!\"        P$                  PO                  \p        R4      p"V Ps                  RRR4      Pu                  V!R4       \w        V!V"R4      p#\"        P$                  Py                  V"4      ;'       d    \{        V"4      p\	        VRRV\}        V#4      4       \"        P$                  PO                  \p        R4      \"        P$                  PO                  \p        R4      3 FA  p$ \"        P$                  Py                  V$4      '       d   \"        P~                  ! V$4       KA  KC  	   \Q        \        4      p%\         U&u0 uF  p&V&^ ,          kK  	  p'p&\	        VRRV%^,8H  \        V%4      4       \	        VRRV'\        \        4      8H  R\Q        V'4       R\Q        \        4       24       RPO                  R \         4       4      p(R U)u. uF  p)V)V(9   g   K  V)NK  	  p*p)\	        TRRV*'       * V*'       d   RXPO                  V*4      MR4       . ROp+V+ U)u. uF  p)V)V(9  g   K  V)NK  	  p,p)\	        TRRV,'       * V,'       d   RXPO                  V,4      MR4        \        4       p-V-P5                  R4      '       g#   \	        VRRRV-P5                  RR 4      RR7       M\	        VRRRV-P5                  RR 4      4       \	        VRRV-P5                  R^ 4      ^ 8  V-P5                  R^ 4       R24       \	        VRRV-P5                  R^ 4      ^ 8H  RV-P5                  R^ 4       24       \	        VRRR\]        4       9   R4         \:        P=                  4        UUu/ uF&  w  rV\"        P$                  PO                  VR4      bK(  	  p.ppV.P=                  4        UU"u. uF4  w  pp"V"P                  4       P                  R4      '       d   K-  V RV" 2NK6  	  p/pp"\	        TRRV/'       * V/'       d   RXPO                  V/4      MR4        . ROp0. ROp1\        ;QJ d    R V0 4       F  '       d   K   RM	  RM! R V0 4       4      p2\        ;QJ d    R V1 4       F  '       d   K   RM	  RM! R V1 4       4      p3\	        TRRT2;'       d    T3V2'       d   V3'       d   RMRV2 RV3 24        \	        TRR\i        R4      ;'       d2    \i        R4      ;'       d    \i        R4      ;'       d    \i        R4      R4       \	        VRR\i        R4      '       * R4       \	        TRR\        R4      \        8H  ;'       d    \        R4      \        8H  \         R\         R24       \        \         P                   ! 4       V,
          ^4      p4\        R V 4       4      p5\        R V 4       4      p6\        R V 4       4      p7RV7^ 8H  RV5RV6RV7R\Q        V4      RV4R\        R\        R\         P                  ! R4      RV/
#   \
         d$   p\	        TRRR\        T4      4        Rp?ELRp?ii ; i  \
         d&   p\	        TRRR\        T4      RR7        Rp?ELRp?ii ; i  \
         d$   p\	        TRRR\        T4      4        Rp?ELRp?ii ; i  \
         d$   p\	        TRRR\        T4      4        Rp?EL Rp?ii ; i  \
         d$   p\	        TRR#R\        T4      4        Rp?ELRp?ii ; i  \
         d$   p\	        TR$R'R\        T4      4        Rp?ELRp?ii ; i  \
         d%   p\	        TR$TR\        T4      4        Rp?EK  Rp?ii ; iu upi   \
         d&   p. p\	        TRVRZR\        T4      4        Rp?E
LRp?ii ; i  \
         d$   p\	        TRVRmR\        T4      4        Rp?E	LRp?ii ; i  \
         d$   p\	        TRVRnR\        T4      4        Rp?E	LRp?ii ; i  \
         d$   p\	        TRVRpR\        T4      4        Rp?E	LRp?ii ; i  \
         d$   p\	        TRVRrR\        T4      4        Rp?E	LRp?ii ; i  \
         d$   p\	        TRuRR\        T4      4        Rp?E	L7Rp?ii ; i  \
         d$   p\	        TRRR\        T4      4        Rp?ELRp?ii ; i  \
         d&   p\	        TRRR\        T4      RR7        Rp?EL>Rp?ii ; i  \
         d     EK  i ; i  \"        P$                  PO                  \p        R4      \"        P$                  PO                  \p        R4      3 FS  p$ \"        P$                  Py                  T$4      '       d   \"        P~                  ! T$4       KA  KC    \
         d     KQ  i ; i	  i ; iu up&i u up)i u up)i   \
         d$   p\	        TRRR\        T4      4        Rp?ELxRp?ii ; i  \
         d$   p\	        TRRR\        T4      4        Rp?ELRp?ii ; iu uppi u up"pi   \
         d$   p\	        TRRR\        T4      4        Rp?EL:Rp?ii ; i  \
         d$   p\	        TRRR\        T4      4        Rp?ELRp?ii ; i  \
         d$   p\	        TRRR\        T4      4        Rp?ELDRp?ii ; i)a5  Non-destructive self-test for the admin panel.

It checks code validity, routes/forms, folders, media engine availability,
presentation image mappings, power guards and restart-helper generation.
It intentionally does not upload real files, restart the server, shut down Windows,
or modify active trip files.
Tr  u   קודu>   קומפילציית Python לקובץ האדמין הפעילFNz-Werrorr  r  r3  u   קומפילציה עם Werrorr  r  )r  uF   בדיקת קובץ אדמין מול מנגנון upload_admin_serverr8   RestartuB   קוד helper חיצוני ל־restart עובר קומפילציהWatchdogu8   קוד Watchdog חיצוני עובר קומפילציהr  u)   סטטוס Watchdog ניתן לקריאהr  zscript_exists=r  z task_installed=r  r9   u'   Task Scheduler נתמך במחשב זהr  r  r}   u*   Task Scheduler בסביבה הנוכחיתuM   לא Windows — אצלך בשרת Windows זה אמור להיות נתמך.u   בדיקת Watchdogu   נתיביםu   תיקיית u    קיימתu:   כתיבה/מחיקה בתיקיית tmp של האדמיןu$   תיקיית גיבויי אדמיןu&   תיקיית גיבויי העלאותrK  c              3   L   "   T F  p\        VP                  4      x  K  	  R # 5irY   )r   r  )r\   r  s   & rK   r^   &run_self_test_suite.<locals>.<genexpr>  s     K2J$s499~~2Js   "$r   r  /admin/status/admin/health/admin/self-test/admin/self-test.json/admin/watchdog/admin/logs/admin/logs.json/admin/camera/camera/stream/camera/snapshot.jpg/camera/prepare-video/camera/reset/camera/stop/camera/status.json/camera/audio-stream/camera/audio-test.json/camera/audio-stop/camera/record/start/camera/record/stop/camera/recordings/healthr  /upload_admin_server/restart_admin_server/restore_admin_server_backup/watchdog/install/watchdog/uninstall/watchdog/run-once/upload/<folder>'/upload_presentation/<presentation_key>+/upload_usa_presentation/<presentation_key>/upload_usa_image/upload_usa_images_zip"/upload_usa_extra_html/<extra_key>/upload_japan_music/<music_key>/upload_japan_images_zip/upload_trip_package/<trip>/upload_usa_music/<music_key>/power/<action>/power/cancelu   ממשקu)   כל routes המרכזיים קיימיםr  z routesu&   קריאת routes מהאפליקציהc              3   <   <"   T F  p\        VS4      x  K  	  R # 5irY   )r  )r\   r  r  s   & rK   r^   r(    s     Q540v>>5s   u:   כל טפסי הפאנל מחוברים ל־route קייםu    טפסיםu-   אין IDs כפולים במסך האדמיןu4   כפתור בדיקה עצמית קיים בפאנלu   נבדק href=/admin/self-testu'   כפתור Watchdog קיים בפאנלzscreen-watchdogu6   נבדק href=/admin/watchdog ומסך screen-watchdogu)   כפתור לוגים קיים בפאנלu   נבדק href=/admin/logsu0   כפתור מצלמת חדר קיים בפאנלu   מצלמת חדרu   נבדק href=/admin/camerauD   כפתור אתחול מתקדם לא מוצג כפעולת חובהu-   בדיקת אתחול פאנל — מתקדםu*   לא חובה אחרי התקנת Watchdogu   נבדק ניסוח UXu   ניתוח HTML של הפאנלu,   מסך סטטוס נבנה ללא שגיאהu"   סטטוס קבצים פעיליםu(   מסך Health נבנה ללא שגיאהu   בדיקת מערכתu,   מסך לוגים נבנה ללא שגיאהu   מרכז לוגיםrS   r  u3   מסך מצלמת חדר נבנה ללא שגיאהu'   OpenCV זמין להפעלת מצלמהr"  uG   התקנה אוטומטית ברקע פעילה; בדוק /camera/setupzOpenCV r#  u9   מסך סטטוס רכיבי מצלמה נבנה תקיןu   התקנה אוטומטיתzpip installu<   מצלמה מוגנת לרשת פרטית/Tailscale בלבדz
100.64.1.2z8.8.8.8u)   Tailscale מותר, ציבורי חסוםu%   בדיקת מסך/מנוע מצלמהu   מדיהu2   Pillow זמין להמרת/דחיסת תמונותr   z"py -m pip install --upgrade Pillowu-   FFmpeg זמין להמרת אודיו ל־MP3r   r   u*   שים FFmpeg ב־C:\ffmpeg\bin\ffmpeg.exeu   בדיקת מנוע מדיה)r   zself_test_image.pngzself_test_image.jpgr   PNGzself_test.pngu1   סימולציית PNG → JPG בתיקיית tmpu
   ארה״בu8   44 כרטיסיות תמונות ארה״ב קיימותuI   כרטיסיות ארה״ב תואמות למפת שמות התמונותzui=z keys=rn  c              3   D   "   T F  pR P                  V4      x  K  	  R# 5i)r   N)rD   r  s   & rK   r^   r(  1  s     J7ItCHHTNN7Is    uI   אין תיאורים שגויים ידועים בתמונות ארה״בu7   תיאורי קרוז/אורלנדו מסונכרניםu&   בדיקת כרטיסיות ארה״בr_  u   יפןu'   מצגת יפן קיימת לניתוחr^  u6   מצגת יפן משתמשת בתמונות בפועלra  u    תמונותuA   אין תמונות חיצוניות חסרות למצגת יפןrg  u   חסרות: ub   ספירת תמונות יפן מוצגת כספירת שימוש ולא כספירת תיקייהu$   תמונות בשימוש בפועלu   ניתוח מצגת יפןr  r  u   העלאותu<   קבצים ראשיים נשמרים תמיד כ־index.htmlu'   מפת יעדי העלאה ראשייםc              3   <   "   T F  p\        V4      R Jx  K  	  R # 5irY   r   r  s   & rK   r^   r(  Q  s     M}!&q)5}   c              3   <   "   T F  p\        V4      R J x  K  	  R # 5irY   rT  r  s   & rK   r^   r(  R  s     M_(+t3_rU  u/   הגנת ZIP Slip / נתיבים מסוכניםzsafe=z unsafe=u
   אבטחהu)   זיהוי IP מקומי/בית/Tailscalez	127.0.0.1z192.168.1.10zfd7a:115c:a1e0::1u<   כתובת ציבורית נחסמת לפעולות מחשבu8   טווח טיימר כיבוי/ריסטארט מוגבלrh   999999-u    שניותu-   בדיקות אבטחת פעולות מחשבc              3   D   "   T F  qR ,          R8X  g   K  ^x  K  	  R# 5i)r   r
  Nr   r  s   & rK   r^   r(  _       Cwtx.F*Bw    
 c              3   D   "   T F  qR ,          R8X  g   K  ^x  K  	  R# 5i)r   r  Nr   r  s   & rK   r^   r(  `  rZ  r[  c              3   D   "   T F  qR ,          R8X  g   K  ^x  K  	  R# 5i)r   r  Nr   r  s   & rK   r^   r(  a  rZ  r[  r   passedwarningsfailedrK  r=  r  r   r  r
   rj  r<  )r  i  )   r      r   )Nassauu   נסאוu   פארק דיסני)zDisney Springsu   קרוז – יום ים 1u   קרוז – יום ים 2u   קרוז – יום ים 3zSt. Maartenz
St. ThomasCocoCay)r  zmedia/images/a.jpgzUSA/index.html)z	../x.htmlza/../../x.htmlz__MACOSX/a.jpg)PrU  r  r  r  r  rE   r  r@  rA  r;   r<   rB  rC  rD  r  r   rl  r=   r?   r  rB   r  rp  r  r  r  r   r>   r  r{  r  rG  r#  r  r  rS  appurl_map
iter_rulesrD   r   r  r  r  r  r  r  render_admin_healthr  r  r(  r  r
  r   r   r   rT  r  r  r'  rC   r   rq  r  r   r   r  ry  r  rA   r  allr  r  r  r  r  r  ADMIN_STARTED_ATrV  )9include_media_conversionr  rj  r&  r  validr  helper_sourcer   wd_codewd_okwd_info	wd_statusr   r  r?   rN   rulesexpected_routesroutemissing_routes
admin_htmlactionsmissing_actionsdup_idsstatus_htmlhealth_html	logs_htmlcamera_html
cam_engine
setup_htmlmedia_statusr   r   r  r   r   	usa_countr   usa_keysui_blobword	forbiddenrequiredmissing_wordsr  main_targetsbad_targetssafe_examplesunsafe_examplesok_safe	ok_unsafeelapsedr^  warnedr`  r  s9   &                                                       @rK   r  r    s1    iikGGD,d;Wh0prv  yJ  	Kx~~s~~y$N_`qu  }A  KM  NWh0PRVRaRaefRfimitit  jL  jLx|  yD  yD  jL  jL  HL  NS  NT  iU  	VL23DEWh0xz~  @E  {F  HL  	MI1"''//BS2TVYVdVdVpVphprtryry  sB  sB  CE  CJ  CJ  CR  CR  Sd  Ce  sf  sr  sr  jr  s1-@Wi1uw{|~w  BF  	G[%&79S9S8UWU\U\UdUdegeleletet  vG  fH  VI  VU  VU  MU  V1':Wj2lns}#6	Wj2]_cdmdqdqr}d~_  DR  S\  S`  S`  ap  Sq  Rr  rB  CL  CP  CP  Qa  Cb  Bc  Bd  	e77d? *6_aefofsfs  uE  gF  bG  IR  IV  IV  Wd  fh  Ii  t}  ~ *6bdi  l{  FO  P
 #7==?3WncU+6VXZX_X_XeXefqXrt  	A 4F.0Wn6rtv}
 
01AB	13DEt	SKKt, .%tATVZ[nK#++2H2H2JKK


*
,;
=O
Qh
j{
 ~K
 M_
 ap
 rB
 DZ
 \s
 uD
 FT
 Vk
 mC
 E^
 `t
 vL
 Nc
 ey

#
%;
=T
Vt
 wJ
 La
 cw
 
 !J
 Ly
  	
 ":	
 <`	

 .

 0J

 Li
 ,
 .?
 AP
 .=S_EU@R%%_SWj2]cq_q  Q_sws|s|  ~L  tM  hk  lq  hr  gs  sz  e{  	|
gW
,Z8F3Q5Q333Q5QQQ&&v.  	Wj2n  uD  qD  ds  FJ  FO  FO  P_  F`  |  @G  |H  {I  IT  yU  	V'
3Wj2agncn  GNptpypy  {B  qC  TX  	YWj2hj|  AK  kK  Mm  	nWj2[]nr|]|  ^a  ^a  BS  Wa  Ba  c[  	\Wj2]_lpz_z  }X  	YWj2dfu  zD  gD  gj  gj  I\  `j  Ij  lI  	JWj2x  {j  nx  {x  {w  {w  }i  mw  }w  yQ  	Rt)+Wj2`  cG  KV  cV  X\  	]p)+Wj2\^u  zE  _E  GK  	Lt%'	Wj2`bw  |E  cE  ch  ch  J[  _h  Jh  jn  	o	o)+Wl4ik~  CN  lN  lU  lU  Sc  gr  Sr  lU  lU  wF  JU  wU  W[  	\)+
Wl4]_cdndrdrs{d|_}  Q[  Q_  Q_  `h  Qi  Qi  @I  qx  yC  yG  yG  HX  Y[  y\  x]  o^  ir  	s-/
Wl4o  rO  S]  r]  r}  r}  bo  s}  b}  C  	DWl4r  uN  O[  u\  uI  uI  e~  H  eI  aI  Kv  	w
d*,Wj2fhlmym}m}  G  nH  iI  wC  wG  wG  HP  wQ  wQ  Ko  W[  	\Wj2acghthxhx  zB  iC  dD  FR  FV  FV  Wd  Fe  FV  FV  iV  	W
  	!WW\\"68MNFWW\\"68MNFIIfk+=>CCFER0QE'GG,?,GB *6ikm  pB  CH  pI  J ggll#79NOQSQXQXQ]Q]^r  uJ  RK  Lww~~a((		! ) Lp*+	(:;(:DGG(:;Wl4npy}p  BE  FO  BP  	QWl4  BJ  NQ  R`  Na  Ba  eh  il  mu  iv  hw  w}  ~A  BP  ~Q  }R  cS  	T))J7IJJ&Sg&SdW[_fWfTT&S	gWl4  FO  BO  ir  QU  QZ  QZ  [d  Qe  x|  	} h*2J($d'6I(JWl4m  tA  pA  _l  CG  CL  CL  MZ  C[  rv  	w
`79455 (4]_dfqfufu  wJ  LN  gO  Zc  d (4]_cepetet  vI  KM  fN  O (4lnyn}n}  M  OP  oQ  TU  oU  Ze  Zi  Zi  jx  z{  Z|  Y}  }J  WK  L (4w  zE  zI  zI  Jc  ef  zg  kl  zl  p|  }H  }L  }L  Mf  hi  }j  |k  nl  m (  5Y  [A  EX  EZ  [Z  \`  a
sOV}}_)#RWW\\$==_<H<N<N<P~<P[S&X^XdXdXfXoXop|X}(#ax(<P~Wn6t  {F  wF  bm  HL  HQ  HQ  R]  H^  sw  	x{NK#M}M###M}MMCM_MCCCM_MM	Wn6gipi~i~u~  IP  U^  AE  fk  ls  kt  t|  }F  |G  dH  	IwWl4_az  |G  bH  bU  bU  Mf  gu  Mv  bU  bU  {T  Ua  {b  bU  bU  g@  AT  gU  W[  	\Wl4r  yR  S\  y]  u]  _c  	dWl4n  qF  GJ  qK  Of  qf  qe  qe  k@  AI  kJ  Ne  ke  jA  iB  BC  D[  C\  \g  gh  	i DIIK')1-GCwCCFCwCCFCwCCFfk&F&W7&&dmm$787 Y  DWh0prwy}  B  zC  	D  	DD  xWh0PRWY]^aYbmvwwx  LWh0xz  BF  GJ  BK  	L  	LL  IWi1uw|  C  DG  H  	I  	II  [Wj2GPTUXPYZZ[  FWn6rty{  AD  |E  	F  	FF  	S .%S	RR	S T nWj2Z\acghkclmmn*  gWj2SUZ\`ad\effg  tWj2`bgimnqirsst  pWj2\^ceijmenoop  tWj2`bgimnqirsst  oWl4[]bdhildmnno  dWj2PRWY]^aYbccd  	Q *6ikprvwzr{  GP  Q  Q	Q ! 	 ggll#79NOQSQXQXQ]Q]^r  uJ  RK  Lww~~a((		! )  	 L < h K pWl4\^ceijmenoop  `Wh0LeUYZ]U^__`
 `~ sWn6_afhlmphqrrs  {Wn6ginptuxpyzz{  wWl4cejlpqtluvvws  /x 
Ax7 $x7 8
x7 )y* -=z +Az 40z % { A{ C{ { {= 5A|.>B}% 	} } ;}% ;~ ~ 4B+~  0~ ~ 0~ <	 : 6A@+ A@+  AA >AA BAA $AA 8AA BAB AB #CAB> 7;AC19AF7 AF("A8AF7 	AF-(AF-.7AF7 %	AF23AF29/AF7 )AAG( ,B#AG( AH% (,AHAH% **AHAH$0AH% $AI <AI AI 0%AI 	AI  AI (AI 7AJ AJ $AJ 7A5AJ x4x//x47y'y""y'*z5zz{	&{{	{:{55{:=|+|&&|+.}9}} }% %~0~~#	7227:A@(@A@#@#A@(@+AA@6AAAAAAAB
A'ABBAB
BAB;BAB6B6AB;B>AC.C	AC)C#AD C)AC.C.AD C1ADD ADDAAF%E;AFFAF%FAF	FAF%FAF	FAF%F(AF7 F7AG%GAG G AG%G(AHG3AHHAHHAH% H%AIH0AIIAIIAJI!AI?I?AJJAJ5JAJ0J0AJ5c                    a
 \         P                  P                  R 4      R8H  p \        V R7      pVR,          '       d   RMRpVR,          '       d   RMRp/ pVR,           F+  pVP	                  VR,          . 4      P                  V4       K-  	  R	 o
. pVP                  4        FL  w  rxR
P                  V
3R lV 4       4      p	VP                  R\        P                  ! V4       RV	 R24       KN  	  RV RV RVR,           RVR,           RVR,           RVR,           RVR,           R\        P                  ! VR,          4       R\        P                  ! VR,          4       RR
P                  V4       R 2# )!
conversionrg   rk  r   badu   הבדיקה עברהu   נמצאו כשליםrj  r  c                 R   V P                  R 4      pVR8X  d   RpRpRpMVR8X  d   RpRpRpMRpRpR	p\        P                  ! V P                  R
4      ;'       g    R4      P                  RR4      pRV RV RV R\        P                  ! V P                  RR4      4       RV R2# )r   r
  u   ✅   תקיןr  u   ⚠️u
   אזהרהu   ❌r  u   כשלr  r}   rn  r  z<tr class='z'><td>r   r  r>   z
</td></tr>)r   r  r  r   )r   r   markclsrN   r  s   &     rK   row_html(render_admin_self_test.<locals>.row_htmly  s    (#VDCEvDC EDCE//$((9"5";";<DDT6RSEvQugYxtxxX^_aOb?c>ddmnumv  wA  B  	Br   r}   c              3   4   <"   T F  pS! V4      x  K  	  R # 5irY   r   )r\   r   r  s   & rK   r^   )render_admin_self_test.<locals>.<genexpr>  s     8%$x~~%s   z<section class='group'><h2>u`   </h2><table><thead><tr><th>מצב</th><th>בדיקה</th><th>פירוט</th></tr></thead><tbody>z</tbody></table></section>u@
  
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>בדיקה עצמית TripServer</title>
<style>
body{margin:0;background:#0f172a;color:white;font-family:Arial;padding:22px}.wrap{max-width:1180px;margin:auto}a{color:#bfdbfe;text-decoration:none}.hero{background:linear-gradient(135deg,#1d4ed8,#0f172a 62%,#111827);border:1px solid #334155;border-radius:26px;padding:22px;margin-bottom:16px;box-shadow:0 20px 70px rgba(0,0,0,.25)}h1{margin:0 0 8px;font-size:34px}p{color:#cbd5e1;line-height:1.65}.badge{display:inline-block;border-radius:999px;padding:8px 14px;font-weight:900;margin-top:8px}.badge.ok{background:#064e3b;color:#bbf7d0;border:1px solid #22c55e}.badge.bad{background:#7f1d1d;color:#fecaca;border:1px solid #ef4444}.summary{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin:14px 0}.card{background:#1e293b;border:1px solid #334155;border-radius:18px;padding:14px}.num{font-size:30px;font-weight:950;color:#fde68a}.actions{display:flex;gap:10px;flex-wrap:wrap;margin:12px 0 0}.actions a{display:inline-flex;background:#1e293b;border:1px solid #475569;border-radius:999px;padding:10px 13px;font-weight:900}.group{background:#111827;border:1px solid #334155;border-radius:22px;padding:16px;margin:14px 0}.group h2{margin:0 0 12px;color:#dbeafe}table{width:100%;border-collapse:collapse;overflow:hidden;border-radius:14px}th,td{padding:10px;border-bottom:1px solid #334155;text-align:right;vertical-align:top}th{background:#0b1220;color:#bfdbfe}td:last-child{direction:ltr;text-align:left;color:#cbd5e1;word-break:break-word}tr.pass td:first-child{color:#bbf7d0;font-weight:900}tr.warn td:first-child{color:#fde68a;font-weight:900}tr.fail td:first-child{color:#fecaca;font-weight:900}.note{background:#0b1220;border:1px solid #334155;border-radius:16px;padding:13px;color:#cbd5e1;line-height:1.65}@media(max-width:700px){body{padding:14px}h1{font-size:28px}table,thead,tbody,tr,th,td{display:block}thead{display:none}tr{border:1px solid #334155;border-radius:14px;margin:10px 0;padding:8px}td{border:0;padding:7px}td:last-child{text-align:right;direction:rtl}}
</style></head><body><div class="wrap"><div class="hero"><a href="/admin">⬅ חזרה לפאנל</a><h1>🧪 בדיקה עצמית מלאה</h1><p>בדיקה לא־הרסנית של קוד, routes, טפסים, נתיבים, מדיה, מצגות, אבטחה ו־restart helper. היא לא מבצעת העלאות אמיתיות, לא מאתחלת את השרת ולא מכבה את המחשב.</p><span class="badge r  u  </span><div class="actions"><a href="/admin/self-test">הרץ שוב</a><a href="/admin/self-test?conversion=1">בדיקה כולל סימולציית המרת תמונה</a><a href="/admin/self-test.json" target="_blank">JSON טכני</a><a href="/admin/status">סטטוס קבצים</a><a href="/admin/health">Health</a></div></div><div class="summary"><div class="card"><div>סה״כ בדיקות</div><div class="num">rK  uB   </div></div><div class="card"><div>עברו</div><div class="num">r^  uF   </div></div><div class="card"><div>אזהרות</div><div class="num">r_  uD   </div></div><div class="card"><div>כשלים</div><div class="num">r`  u@   </div></div><div class="card"><div>משך</div><div class="num">r=  u/   s</div></div></div><div class="note">גרסה: r  u   <br>נבדק: r  r  r  )
r   r  r   r  r  r  r  rD   r  r  )include_conversionr  badge_classr  groupedr   groups_htmlr  r  r  r  s             @rK   render_admin_self_testr  p  s   !,,**<8C?!;MNG!$--$UK,3DMM(?VJG	""4
+R077= #B" K"==?ww8%8889R8S  Tt  uy  tz  zT  U  	V +b cn  bo  oq  r|  q}  }c  dk  ls  dt  cu  uw  x  @H  xI  wJ  JP  QX  Yc  Qd  Pe  ei  jq  rz  j{  i|  ||  }D  EV  }W  |X  XG  HP  HW  HW  X_  `i  Xj  Hk  Gl  lz  {C  {J  {J  KR  S_  K`  {a  zb  bh  ik  ip  ip  q|  i}  h~ ~ r   c            '      z   \        \        \        \        P                  ;'       g    R \
        P                  P                  \
        P                  P                  \        4      4      ;'       g    \        4      4      w  rRRRRR\        R\        R\        R\        R	\        R
\        \        4      R\!        4       R\"        RT RTR\%        RRR7      R\&        P)                  4        UUu/ uF7  w  r#VRVR,          R\
        P                  P+                  VR,          4      /bK9  	  uppR\-        4       /# u uppi )r8   r   TserviceTripServer Adminr  r   scripthostportusa_image_keysjapan_presentation_imagespower_actions_enabledrestart_helper_okrestart_helper_statusrR   F)r  r  r  r?   rC   media_engine)rp  rl  r  r;   r<   r=   r?   rB   r  r  r  rj  
ADMIN_HOSTr  r   ry  r  r  r  r  r  rC   r   )	helper_okhelper_infor   r  s       rK   health_payloadr    sf   ;<UVgiliwiw  jD  jD  |D  FH  FM  FM  FU  FU  VX  V]  V]  Ve  Ve  fw  Vx  Fy  FE  FE  }E  =F  GId%&&#

#n-#%C%E!6YOEJfwf}f}f  AfYbY\vtF|Xrww~~d6l7STTf  A+-  As   +=D7<c                     \        4       p V P                  R / 4      p\        VP                  R4      4      p\        VP                  R4      4      pVP                  R4      ;'       g    Rp\        V P                  R4      4      pV P                  R/ 4      pR<R lp\        P                  ! \        V 4      4      P                  R	R
4      P                  RR4      P                  RR4      pRP                  . RNV! R4       NRN\        P                  ! \        4       NRN\        P                  ! \        4       NRN\         NRN\        P                  ! \        4       NRNV! V P                  RR4      RR4       NRNV! VRR4       NRNV! VRR4       NR N\        P                  ! V4       NR!NV! VR"R#4       NR$NV'       d   R%MR& NR'NV! \        \        4      ^,8H  R(\        \        \        4      4      R),           4       NR*N\        \        4       NR+NT! VP                  R,4      ;'       d    VP                  R-^ 4      ^ 8H  RR.4       NR/NVP                  R0^ 4       NR1NVP                  R2^ 4       NR3NVP                  R4^ 4       NR5NVP                  R6^ 4       NR7NVP                  R8^ 4       NR9NVP                  R-^ 4       NR:NV NR;N4      # )=r  r   r   r   r  r  r  r  c                 D    V '       d   R MRpV '       d   TMTpRV RV R2# )r   r  z<span class="badge r  z</span>r   )r   text_oktext_badr  txts   &&&  rK   badge"render_admin_health.<locals>.badge  s)    deg$SEC588r   z, 'z,
 '{z{
 }z
}r}   uq  
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>בדיקת מערכת TripServer</title>
<style>
:root{--bg:#07111f;--panel:#101c31;--line:#253650;--muted:#a8b3c7;--blue:#60a5fa;--green:#22c55e;--red:#ef4444;--yellow:#fbbf24}
*{box-sizing:border-box}body{margin:0;font-family:Arial,'Segoe UI',sans-serif;background:radial-gradient(circle at 80% -10%,rgba(59,130,246,.35),transparent 28%),linear-gradient(180deg,#07111f,#0f172a);color:white;min-height:100vh;padding:20px}
.wrap{width:min(980px,94vw);margin:auto}.hero{background:linear-gradient(135deg,rgba(30,64,175,.9),rgba(15,23,42,.92));border:1px solid rgba(147,197,253,.25);border-radius:28px;padding:22px;box-shadow:0 25px 70px rgba(0,0,0,.32)}
h1{margin:0 0 8px;font-size:clamp(28px,5vw,42px)}p{color:#dbeafe;line-height:1.65;margin:8px 0}.actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px}a{display:inline-flex;align-items:center;justify-content:center;gap:8px;text-decoration:none;border:1px solid rgba(148,163,184,.35);background:rgba(15,23,42,.65);border-radius:999px;padding:11px 15px;font-weight:900;color:white}
a:hover{border-color:var(--blue);background:rgba(59,130,246,.22)}.grid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px;margin:18px 0}.card{background:rgba(16,28,49,.9);border:1px solid var(--line);border-radius:22px;padding:18px;box-shadow:0 16px 45px rgba(0,0,0,.22)}.card h2{margin:0 0 10px;font-size:22px}.line{display:flex;justify-content:space-between;gap:12px;border-top:1px solid #263852;padding-top:10px;margin-top:10px;color:#cbd5e1;direction:rtl}.ltr{direction:ltr;text-align:left;overflow-wrap:anywhere;color:#fde68a}.badge{display:inline-flex;border-radius:999px;padding:6px 10px;font-weight:900;font-size:13px}.badge.ok{background:rgba(22,101,52,.45);border:1px solid rgba(74,222,128,.45);color:#bbf7d0}.badge.bad{background:rgba(127,29,29,.45);border:1px solid rgba(248,113,113,.45);color:#fecaca}.note{background:rgba(15,23,42,.75);border:1px solid #334155;border-radius:18px;padding:14px;color:#cbd5e1;line-height:1.6}pre{white-space:pre-wrap;direction:ltr;text-align:left;background:#020617;color:#fde68a;border:1px solid #334155;border-radius:18px;padding:16px;overflow:auto;max-height:360px}
@media(max-width:760px){body{padding:14px}.grid{grid-template-columns:1fr}.hero{padding:18px;border-radius:24px}.card{padding:15px}.line{display:block}.ltr{margin-top:5px}}
</style>
</head>
<body><div class="wrap">
<div class="hero">
<h1>🩺 בדיקת מערכת</h1>
<p>זה מסך קריא לבני אדם. נקודת הקצה הטכנית עדיין קיימת ב־<span class="ltr">/health?json=1</span> למקרה שצריך בדיקה אוטומטית.</p>
<div class="actions"><a href="/admin">⬅ חזרה לפאנל</a><a href="/admin/status">📊 סטטוס קבצים</a><a href="/health?json=1" target="_blank">JSON טכני</a><a href="/admin/self-test">🧪 בדיקה עצמית מלאה</a><a href="/admin/watchdog">🛡️ Watchdog</a><a href="/admin/logs">📜 לוגים</a></div>
</div>
<div class="grid">
<div class="card"><h2>מצב שרת</h2><div>Tu-   </div><div class="line"><b>גרסה</b><span>u?   </span></div><div class="line"><b>עלה בתאריך</b><span>u4   </span></div><div class="line"><b>פורט</b><span>z0</span></div><div class="line"><b>Host</b><span>z:</span></div><div class="line"><b>Restart helper</b><span>r  Fu   תקולuE   </span></div></div>
<div class="card"><h2>מנוע מדיה</h2><div>u   Pillow תקיןu   Pillow חסרr   u   FFmpeg תקיןu   FFmpeg חסרu   </div><div class="line"><b>תמונות</b><span>המרה ודחיסה ל־JPG</span></div><div class="line"><b>אודיו</b><span>המרה ל־MP3</span></div><div class="line"><b>FFmpeg</b><span class="ltr">uI   </span></div></div>
<div class="card"><h2>פעולות מחשב</h2><div>r  r  u@   </div><div class="line"><b>כיבוי / ריסטארט</b><span>u   מופעל בפאנלu   מנוטרל בהגדרותu   </span></div><div class="line"><b>הגנות</b><span>POST, רשת מקומית, אישור כתוב, טיימר וביטול</span></div></div>
<div class="card"><h2>כיסוי מצגת ארה״ב</h2><div>u   44 שקפיםu    שקפיםu<   </div><div class="line"><b>תמונות שקפים</b><span>u   </span></div><div class="line"><b>העלאה</b><span>JPG/PNG/WebP וכו׳ → JPG דחוס</span></div></div>
<div class="card"><h2>כיסוי מצגת יפן</h2><div>r_  rg  u   לבדיקהuI   </div><div class="line"><b>תמונות בשימוש בפועל</b><span>r  uG   </span></div><div class="line"><b>קבצים חיצוניים</b><span>r  uG   </span></div><div class="line"><b>תמונות מוטמעות</b><span>r  uE   </span></div><div class="line"><b>קבצים בתיקייה</b><span>r`  uJ   </span></div><div class="line"><b>לא בשימוש / חסרות</b><span>rh  z / u  </span></div></div>
</div>
<div class="note"><b>מה קרה קודם?</b><br>לחצן Health פתח את נקודת הקצה הטכנית והציג JSON שחור. זה לא כשל בשרת — להפך, לפי הנתונים אצלך FFmpeg ו־Pillow זמינים — אבל זה לא מתאים ככפתור במסך ראשי. בגרסה הזו הכפתור מוביל למסך בדיקה קריא, וה־JSON נשאר רק לבדיקה טכנית.</div>
<h2>מידע טכני מלא</h2><pre>z</pre>
</div></body></html>
)r  r  )r  r   r   r  r  r   r   rD   r  rj  r  r  r   ry  )	r  r   	pillow_ok	ffmpeg_okr   power_okr  r  	json_texts	            rK   rh  rh    s   GKK+EUYYx()IUYYx()I))M*==oKGKK 789H++92>K9
 G-55eWEMMcSYZbbcfhmnI    .  . /4Dk]/ . ;h/ . iqhwhw  yL  iM  hN/ . NM/ . NV  N]  N]  ^n  No  Mp/ . pd/ . eo  dp/ . p`/ . ai  ap  ap  q{  a|  `}/ . }w/ . x}  ~E  ~I  ~I  J]  _d  ~e  gq  s}  x~  w/ .2/ 0 38	CTVe2f1g1 0 hi1 0 joox  {L  N]  j^  i_1 0 _q1 0 rz  rA  rA  BM  rN  qO1 0O61 2 7<HjR\6]5^3 2 __3 2 {C  `w  If  _g3 2g?3 4 @ESEX\^E^`oqtux  zH  vI  rJ  MZ  rZ  @[  ?\5 4 \X5 4 Y\  ]k  Yl  Xm5 4m;5 6 <AQfAg  B_  B_lwl{l{  }V  XY  mZ  ^_  m_  ak  m{  <|  ;}7 6 }F7 6 GR  GV  GV  Wk  mn  Go  Fp7 6 pw7 6 xC  xG  xG  H]  _`  xa  wb7 6 bi7 6 ju  jy  jy  zK  MN  jO  iP7 6 PU	7 6 V	a	  V	e	  V	e	  f	u	  w	x	  V	y	  U	z	7 6 z	D7 6 EP  ET  ET  Uk  mn  Eo  Dp7 6 ps7 6 t  tC  tC  D]  _`  ta  sb7 6b'7 < (1k= <2=   r   r+  c                      \        4       # rY   )r  r   r   rK   admin_self_testr    s    !##r   r,  c                  ^    \         P                  P                  R 4      R8H  p \        V R7      # )r  rg   r  )r   r  r   r  )r  s    rK   admin_self_test_jsonr    s(    !,,**<8C?8JKKr   z/pingc                      R ^RR/3# )r  r  zno-storer   r   r   rK   pingr    s    
333r   r  c            
      2    R RRRR\         R\        R\        /# )r   Tr  r  r  r   r  )r  rj  r  r   r   rK   	ping_jsonr    s/     $	#5yBUWceuw}  @J  K  Kr   r=  c                      \         P                  P                  R R4      p \         P                  P                  R4      R8w  d   RV 9   d   \	        R4      # \        4       # )Acceptr}   r  rg   z	text/htmlr*  )r   r  r   r  r   r  )accepts    rK   healthr    sJ    __  2.F||3&;&+@((r   z/health.jsonc                      \        4       # rY   )r  r   r   rK   health_jsonr    s    r   r*  c                      \        4       # rY   )rh  r   r   rK   admin_healthr          r   r)  c                      \        4       # rY   )r  r   r   rK   admin_statusr    r  r   z/admin/controlc                  h   \        R 4      w  r\        4       pRp \        P                  P	                  \
        4      '       d"   \        \
        RRRR7      P                  4       pRp \        P                  P	                  \        4      '       d%   \        \        RRRR7      P                  4       RR pRT'       d   RMR	 R
T'       d   RMR R\        P                  ! \        T 4      4       R\        P                  ! \        T4      4       R\         R\         R\        P                  ! T;'       g    R4       R\        P                  ! T;'       g    R4       R2p\        T4      #   \         d   p\        T4      p Rp?EL$Rp?ii ; i  \         d   p\        T4      p Rp?LRp?ii ; i)zcontrol-pager}   r  rm  r   ro  Na  <!doctype html><html lang='he' dir='rtl'><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'><title>TripServer Control</title><style>body{font-family:Arial;background:#071120;color:#eef;margin:0;padding:22px}.box{max-width:960px;margin:auto;background:#111827;border:1px solid #334155;border-radius:22px;padding:24px}a,button{display:inline-block;margin:8px;padding:14px 18px;border-radius:14px;background:#2563eb;color:white;text-decoration:none;border:0;font-size:18px}pre{direction:ltr;text-align:left;background:#020617;color:#facc15;padding:16px;border-radius:14px;white-space:pre-wrap;overflow:auto}.pill{display:inline-block;padding:8px 14px;border-radius:999px;background:z#166534z#991b1bu   }</style></head><body><div class='box'><a href='/admin'>⬅ חזרה</a><h1>שרת בקרה חיצוני</h1><div class='pill'>r  u   לא פעילz</div><p>Bootstrap: r#  u   </p><form action='/restart_admin_server' method='post'><button>אתחל פאנל ראשי דרך שרת הבקרה</button></form><a href='http://127.0.0.1:uM   /status.json' target='_blank'>Status מקומי</a><a href='http://127.0.0.1:u?   /log' target='_blank'>לוג מקומי</a><h2>Status</h2><pre>r  z</pre><h2>Log</h2><pre>z</pre></div></body></html>i)r  r  r=   r?   rC   CONTROL_STATUS_PATHr   r   rE   r  CONTROL_LOG_PATHr  r  r   r  r   )bootstrap_okbootstrap_infoalivestatus_textr&  r  r  s          rK   admin_control_pager    sh   #;N#K L#%EK577>>-..dCVX[fmv  ?A  ?F  ?F  ?HH277>>*++=Ms]dmv8w8|8|8~  @F  @G  9HX l  z  mv  EN  lO  OO  ^c  PZ  ix  Oy  yM  NV  N]  N]  ^a  bn  ^o  Np  Mq  qt  u}  uD  uD  EH  IW  EX  uY  tZ  Zv  wC  vD  DQ  R^  Q_  _^  _g  _n  _n  oz  oF  oF  ~F  _G  ^H  H_  `h  `o  `o  px  pD  pD  |D  `E  _F  F`  cD 449[4 1S	X1s6   A
E- ((F $F -F8F		FF1F,,F1r.  c                      \        4       # rY   )r  r   r   rK   
admin_logsr    s    r   r/  c                  \    \        \        P                  P                  R \        4      4      # )ro  )r  r   r  r   r  r   r   rK   admin_logs_jsonr  "  s    gll..w8NOPPr   z/camera/hls/startPOST)methodsc            
         \        4       w  rV '       g	   R RRV/R3# \        4       '       g	   R RRR/R3# \        P                  P	                  RR4      R8g  p \
        P                  VR	R
7      p\
        P                  4       pR \        V4      RRR\        VP	                  R4      4      RV/#   \         d0   pR RR\        T4      R\
        P                  4       /R3u Rp?# Rp?ii ; i)r   Fr,    u>   FFmpeg לא נמצא. נדרש FFmpeg לשידור מאוחד.  ru  rg   rh   T)r  rM   r_  z/camera/hls/stream.m3u8r  r   rT   N)r  r   r   r  r   r  r  r   r   rE   r   )r  r
  r  r   r   r&  s         rK   camera_hls_startr  '  s    +-OGeWf-s22!##eW&fgilll!!'3/36J[$$
D$I"))+d2h
,E|UYZ`ZdZdeqZrUsu}  @F  G  	G [eWc#h:K:R:R:TUWZZZ[s   AB/ /C):$C$C)$C)z/camera/hls/stopc                      \        4       w  rV '       g	   R RRV/R3# \        P                  4        R RR\        P                  4       /# )r   Fr,  r  Tr   )r  r  rY  r   r  r
  s     rK   camera_hls_stopr  7  sH    +-OGeWf-s22$"3":":"<==r   z/camera/hls/status.jsonc                  ~    \        4       w  rV '       g	   R RRV/R3# R RR\        P                  4       R\        4       /# )r   Fr,  r  Tr   r  )r  r  r   r  r  s     rK   camera_hls_status_jsonr  @  sD    +-OGeWf-s22$"3":":"<iI]I_``r   z/camera/hls/<path:filename>c                    \        4       w  rV'       g   VR 3# \        V 4      pV'       d-   RV9   g&   VP                  4       P                  R4      '       g   R# \	        \
        VRR7      pRVP                  R&   RVP                  R	&   VP                  4       P                  R4      '       d   R
VP                  R&   V# VP                  4       P                  R4      '       d   RVP                  R&   V# )r  r   rH  rI  F)r  .no-store, no-cache, must-revalidate, max-age=0r  r  r  z,application/vnd.apple.mpegurl; charset=utf-8Content-Typez
video/mp2t)rH  rI  )zinvalid hls file  )r  r   rA   r  r   rJ  r  )r   r  r
  r  r  s   &    rK   camera_hls_filer  H  s    +-OGs{H%D3$;djjl&;&;<L&M&M&&~tGD$TDLL!'DLLzz|W%%'U^$ K 
		u	%	%'3^$Kr   /camera/setupc                  `    \        4       w  rV '       g   \        R VRRR7      R3# \        4       # )u   גישה נחסמהFr0  r   back_urlr  )r  r  r  r  s     rK   camera_setup_pager  Z  s1    +-OG !65Sbcehhh#%%r   z/camera/setup/status.jsonc                  B    \        4       w  r\        4       pWR &   WR&   V# access_allowedaccess_reason)r  r  r  r
  r  s      rK   camera_setup_status_jsonr  b  s*    +-OG!#G '%ONr   z/camera/setup/opencvc            
         \        4       w  rV '       g   \        R VRRR7      R3# \        P                  P	                  R4      ;'       g    RP                  4       pV\        8w  d   \        RR\         2RRR7      R	3# \        4       P	                  R
4      '       d   \        RRRRR7      # \        RR7      w  r4\        V'       d   RMRVR,           VR\        \        4       4      R7      # )u   התקנת OpenCV נחסמהFr  r  r  confirmr}   u   אישור חסרu;   כדי להתקין OpenCV צריך לכתוב בדיוק: r  r"  u   OpenCV כבר מותקןu\   אין צורך להריץ התקנה נוספת. אפשר לחזור למסך המצלמה.Tr0  manualr  u   התקנת OpenCV התחילהu   התקנת OpenCV כבר רצהuZ   

פתח את מסך סטטוס רכיבי מצלמה כדי לעקוב אחרי הלוג.)r   r  r  )r  r  r   formr   rZ   CAMERA_SETUP_CONFIRM_TEXTr(  r  r   r  )r  r
  r  r  r  s        rK   camera_setup_opencvr  k  s3   +-OG !?E\klnqqq||	*00b779G++ !48s  uN  tO  7P  UZ  et  u  wz  z  	z!!(++ !;  >\  ae  p  @  	@6HEG=Noqx  |Z  rZ  _f  q@  JM  Na  Nc  Jd  e  er   r0  c                      \        4       # rY   )r  r   r   rK   admin_camerar  y  r  r   r6  c                      \        4       w  r\        P                  4       pVP                  \	        4       4       WR &   WR&   V# r  )r  ri  r   r  r(  r  s      rK   camera_status_jsonr  ~  s@    +-OG##%GNN')* '%ONr   r2  c                  2   \        4       w  rV '       g   VR 3# \        4       P                  R4      '       g   R	#  \        P	                  4       p\        V4      pRVP                  R&   RVP                  R&   V#   \         d   pRT 2R3u Rp?# Rp?ii ; i)
r  r"  z
image/jpegr  r  r  u   שגיאת מצלמה: rT   Nu?   OpenCV לא מותקן. הרץ: py -m pip install opencv-pythonr  )r  r(  r   ri  rV  r   r  rE   )r  r
  rT  r  r&  s        rK   camera_snapshotr    s    +-OGs{!%%h//UU4((* '+7(,\) 4(.334s   >A: :BBBBr3  c                      \        4       w  rV '       g   VR 3# \        P                  4        \        R\	        4        24       RRRR/# )r  zvideo prepare requested by r   Tr  z&camera video handle released and ready)r  ri  r\  rr  r  r  s     rK   camera_prepare_videor    sH    +-OGs{%%'2=?2CDE$	#KLLr   r4  c                  *   \        4       w  rV '       g   VR 3#  \        P                  4         \        P                  4        \
        P                  4        \        R\        4        24       RRRR/#   \         d     LRi ; i  \         d     LNi ; i)r  zfull camera reset requested by r   Tr  z'camera/audio/recording handles released)	r  rj  rY  rE   r  ri  r_  rr  r  r  s     rK   camera_resetr    s    +-OGs{  "  6}6GHI$	#LMM    s"   A3 B 3B BBBr1  c                      \        4       w  rV '       g   VR 3# \        4       P                  R4      '       g   R# \        \	        4       RRRRR/R7      # )	r  r"  z)multipart/x-mixed-replace; boundary=framer  r  X-Accel-Bufferingnomimetyper  r  )r  r(  r   r   r  r  s     rK   camera_streamr    sj    +-OGs{!%%h//UU+-8cn}  @p  rE  GK  nL  M  Mr   r5  c                  t    \        4       w  rV '       g   VR 3# \        P                  4        \        RRR4      # )r  u   מצלמה כובתהu   המצלמה שוחררה והזרם הופסק. אם נורית המצלמה עדיין דולקת, סגור גם את דף השידור בדפדפן ורענן.r0  )r  ri  rY  action_pager  s     rK   camera_stopr    sD    +-OGs{.  1U  Wf  g  gr   r7  c                  h   \        4       w  rV '       g   VR 3# \        4       '       g   R#  \        P                  P	                  R4      R8H  p\
        P                  VR7       \        \
        P                  4       RRR	R
R/R7      #   \         d   pR\        T4      ,           R3u Rp?# Rp?ii ; i)r  rM   rg   )rM   u   שגיאת אודיו: rT   Nz
audio/mpegr  r  r
  r  r  )uE   FFmpeg לא נמצא. נדרש FFmpeg כדי להזרים אודיו.r  )r  r   r   r  r   rj  r  rE   r   r   r  )r  r
  rM   r&  s       rK   camera_audio_streamr    s    +-OGs{!##[[9,,""9-4!!'!2 '557,Yh  k[  ]p  rv  Yw  x  x  9(3s83S889s   8B B1B,&B1,B1r8  c                     \        4       w  rV '       g	   R RRV/R3# \        4       pV'       g	   R RRR/R3# \        4       p\        V4      p. pVR,           F  pVP	                  R4      ;'       g    Rp\
        P
                  ! 4       pVR	R
RRRRRRRRV,           RRRRRR.p	 \        P                  ! V	RRRR^R7      p
TP                  RTRVP	                  R4      R V
P                  ^ 8H  RV
P                  R\        \
        P
                  ! 4       V,
          ^4      R V
P                  ;'       g    RR)R! /4       K  	  R \        ;QJ d    R" V 4       F  '       g   K   RM	  RM! R" V 4       4      R#VR$\        4       R%,          R&VR'VR(\         /#   \         d>   pTP                  RTRTP	                  R4      R RR\        T4      /4        R!p?EK  R!p?ii ; i)*r   Fr,  r  u   FFmpeg לא נמצאr  :Nr1  Nr>   r}   r*  r  r+  r  rz  r{  r  r  r-  r  r"  rg   r.  nullrX  Trm  r   r}  r  r   rB  secondsstderr_tailNc              3   B   "   T F  qP                  R 4      x  K  	  R# 5i)r   Nr  )r\   r  s   & rK   r^   )camera_audio_test_json.<locals>.<genexpr>  s     37aeeDkk7s   r   selected:Nr   Nr  rj  	audio_logr<  )r  r   r  r  r   rU  r@  rA  r  rB  r  rC  rE   r  r  r  r  )r  r
  r   r  r   rj  r  r>   r  rG  r  r&  s               rK   camera_audio_test_jsonr    s   +-OGeWf-s22#%FeW&<=sBB"$G+G4JG"~~wwv$$"))+~z;	4QXZfhmosu}  AE  vE  GK  MP  RW  Y]  _e  gj  k	k"s4dU\enxyzINNHdHcggh6GyOcOcghOhjv  yB  yM  yM  OX  Z_  `d  `i  `i  `k  nu  `u  wx  Zy  {H  KT  K[  K[  Ka  Ka  _a  ch  ci  Jj  k  l  ##373###3733XvzSjSlmoSpr{  ~E  GP  RY  [f  h}  ~  ~  	kNNHdHcggh6GuV]_cdg_hijj	ks   %BF4FG!1GGr9  c                  t    \        4       w  rV '       g   VR 3# \        P                  4        \        RRR4      # )r  u   אודיו כובהuC   שידור האודיו הופסק והמיקרופון שוחרר.r0  )r  rj  rY  r  r  s     rK   camera_audio_stopr    sA    +-OGs{,.s  vE  F  Fr   r:  c            
         \        4       w  rV '       g   \        R VRR7      R3#  \        P                  P	                  R4      R8H  p\
        P                  VR7      p\        RRV 2R	\        \
        P                  4       4      R
7      #   \         dJ   p\        T4      \
        n
        \        R\        T4      R\        \        4       4      R
7      R3u Rp?# Rp?ii ; i)u   הקלטה נחסמהFr   r  r  rg   )r  u   הקלטה התחילהu   ההקלטה נשמרת אל:
Tr   r  u   הקלטה לא התחילהrT   N)r  r  r   r  r   r  r  r   r   rE   r5  r  )r  r
  r  r  r&  s        rK   camera_record_startr"    s    +-OG !8&UKSPP{\\%%l3s:
 &&*&= !:>]^d]e<fkoy|  ~M  ~T  ~T  ~V  zW  X  	X {%(X" !?Se]`aqas]tuwzzz{s   A$B C>CCCr;  c            	      H   \        4       w  rV '       g   \        R VRR7      R3#  \        P                  4       p\        RRT;'       g    R 2R\	        \        P                  4       4      RR	7      #   \         d%   p\        R
\	        T4      RRR7      R3u Rp?# Rp?ii ; i)u    עצירת הקלטה נחסמהFr   r  u   הקלטה נעצרהu   קובץ ההקלטה:
u   לא היה קובץ פעילTr0  )r   r  r  u"   שגיאה בעצירת הקלטהr  rT   N)r  r  r  rY  r   r   rE   )r  r
  r  r&  s       rK   camera_record_stopr$    s    +-OG !CVPUVX[[[z %%' !8<TU[U~U~_~T  ;A  FJ  TW  Xg  Xn  Xn  Xp  Tq  |K  L  	L z !Es3xTYdstvyyyzs#   #A2 
'A2 2B!=BB!B!r<  c                      \        4       w  rV '       g   VR 3# RP                  R \        ^d4       4       4      ;'       g    RpR\        P                  ! \
        4       RV R2# )r  r}   c              3   ,  "   T F  pR \         P                  ! VR,          4       R\        P                  ! R\        P                  ! VR,          4      4       R\        VR,          4       R\         P                  ! VR,          4       R2	x  K  	  R	# 5i)
z?<div style='border-bottom:1px solid #334155;padding:12px 0'><b>r>   z$</b><br><span style='color:#94a3b8'>r
   rA  r  r  z'</span><br><a href='/camera/recordings/u)   ' target='_blank'>פתח/נגן</a></div>Nr  r  s   & rK   r^   )camera_recordings_page.<locals>.<genexpr>  s     /D J(//Z^_eZfJgIh  iM  NR  N[  N[  \o  qu  q  q  @D  EL  @M  qN  NO  MP  PT  Ua  bf  gm  bn  Uo  Tp  pW  X`  Xg  Xg  hl  ms  ht  Xu  Wv  v_  	`/r  u   <p>אין הקלטות.</p>u2  <!DOCTYPE html><html lang='he' dir='rtl'><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width,initial-scale=1'><title>הקלטות מצלמה</title><style>body{margin:0;background:#07111f;color:white;font-family:Arial;padding:18px}.wrap{max-width:900px;margin:auto}a{color:#93c5fd}.card{background:#111827;border:1px solid #334155;border-radius:22px;padding:18px}</style></head><body><div class='wrap'><a href='/admin/camera'>⬅ חזרה למצלמה</a><h1>🎞️ הקלטות מצלמה</h1><div class='card'><p>תיקייה: <code>z</code></p>z</div></div></body></html>)r  rD   r}  r  r  r2  )r  r
  r  s      rK   camera_recordings_pager(    s    +-OGs{77 *3/  ' ' 
' 	 J	  K	S	  K	Z	  K	Z	  [	p	  K	q	  J	r	  r	}	  ~	B
  }	C
  C
]
  `
  `
r   z"/camera/recordings/<path:filename>c                     \        4       w  rV'       g   VR 3# \        P                  P                  T ;'       g    R4      pVP	                  4       P                  R4      '       g   R# \        \        VRR7      # )r  r}   r  F)as_attachment)u   קובץ לא מורשהr  )r  r=   r?   r@   rA   r  r   r2  )r   r  r
  rH   s   &   rK   camera_recording_filer+    s`    +-OGs{77HNN+D::<  ((..4d%PPr   r-  c                      \        4       # rY   )r  r   r   rK   admin_watchdogr-  )  s     ""r   rA  c                  \   \        \        4       4      '       g   \        R R\        4        2RR7      R3#  \        4       w  rp\        V '       d   RMRWVR,           \	        \        RR7      4      ,           R	7      #   \         d%   p\        R
RR\        T4      R	7      R3u Rp?# Rp?ii ; i)u   התקנת Watchdog נחסמהE   הבקשה הגיעה מכתובת לא מקומית/לא Tailscale: Fr   r  u   Watchdog הותקןu   Watchdog לא הותקן

r  r!  u    שגיאה בהתקנת Watchdogu:   לא הצלחתי להתקין את שכבת ה־Watchdog.rT   N)r
  r  r  r  r   r  rE   r  r   r  r  r&  s       rK   watchdog_install_router2  .  s   $]_55 !A  FK  LY  L[  K\  D]  bg  h  jm  m  	me46W "!6B\^ev}  AG  wG  JM  N]  jo  Np  Jq  wq  r  	r e !C  FB  GL  VZ  [^  V_  `  be  e  	ees   AA< <B+B& B+&B+rB  c            	         \        \        4       4      '       g   \        R R\        4        2RR7      R3#  \        4       w  rp\        V '       d   RMRWVR7      #   \         d%   p\        RR	R\        T4      R7      R
3u Rp?# Rp?ii ; i)u   הסרת Watchdog נחסמהr/  Fr   r  u   Watchdog הוסרu   Watchdog לא הוסרr!  u   שגיאה בהסרת Watchdogu:   לא הצלחתי להסיר את משימת ה־Watchdog.rT   N)r
  r  r  r  rE   r  r1  s       rK   watchdog_uninstall_router4  9  s    $]_55 !?  DI  JW  JY  IZ  B[  `e  f  hk  k  	kc68W !4@XZaryzz c !AC  EJ  TX  Y\  T]  ^  `c  c  	cc   $A B
&B?B
B
rC  c            	         \        \        4       4      '       g   \        R R\        4        2RR7      R3#  \        4       w  rp\        V '       d   RMRWVR7      #   \         d%   p\        RR	R\        T4      R7      R
3u Rp?# Rp?ii ; i)u   הרצת Watchdog נחסמהr/  Fr   r  u   Watchdog הורץu   Watchdog נכשלr!  u   שגיאה בהרצת Watchdogu/   לא הצלחתי להריץ את ה־Watchdog.rT   N)r
  r  r  r  rE   r  r1  s       rK   watchdog_run_once_router7  D  s    $]_55 !?  DI  JW  JY  IZ  B[  `e  f  hk  k  	kX46W !4@SU\mtuu X !ACty~  IM  NQ  IR  S  UX  X  	XXr5  r>  c                     \         P                  P                  R 4      p V '       d   V P                  R8X  d   \	        RRRR7      R3# V P                  ;'       g    RpVP                  4       P                  R4      '       g   \	        RR	RR7      R3# \         P                  '       d:   \         P                  \        R
,           8  d   \	        RR\        R R2RR7      R3# \        P                  ! \        RR7       \        P                  ! \        RR7       \        P                  ! R4      p\        P                  P!                  \        RV R24      p V P#                  V4       \%        V4      w  rEV'       g(   \        P&                  ! V4       \	        RRRVR7      R3# \*        P,                  ! V\.        4       \1        \.        4      p\        P&                  ! V4       \3        R4      w  rx\5        RR\.        R7      p	R\.         RV R\6         RV RV R \8        P:                  ! V	R^R!7       R"\<         R#\>         2p\	        R$R%RVR7      #   \(         d     Li ; i  \(         d     Li ; i  \(         ds   p
 \        P                  PA                  T4      '       d   \        P&                  ! T4       M  \(         d     Mi ; i\	        R&R'R\C        T
4      R7      R(3u R)p
?
# R)p
?
ii ; i)*r  r}   u   לא נבחר קובץu-   בחר קובץ admin_server.py להעלאה.Fr   r  r     קובץ לא תקיןuE   ניתן להעלות כאן רק קובץ Python עם סיומת .pyi    קובץ גדול מדיu?   הקובץ גדול מהמותר. המגבלה היא בערך r`   r    TrK  rM  admin_server_upload_u%   העלאת admin_server.py נדחתהuS   הקובץ הפעיל לא הוחלף. נמצאה בעיה בקובץ שהעלית.r!  zadmin-uploadapply_updateadmin_upload_v34_control_server)r
  r  u   קובץ ממתין:
u   

SHA256 חדש:
z#

Control Server:
http://127.0.0.1:z/

Bootstrap:
r#  

Request:
r  u   

לוג בקרה:
u   
לוג התקנה:
u'   עדכון נשלח לשרת הבקרהu   הקובץ החדש עבר בדיקה ונשלח לשרת הבקרה החיצוני. הוא יבצע את ההחלפה והאתחול במקום האדמין הראשי.u'   שגיאה בעדכון admin_server.pyu&   הקובץ הפעיל לא הוחלף.rT   N)"r   rV  r   r   r  rA   r  content_lengthr  r=   rS  r  rT  rU  rV  r?   rD   r  r  r  rE   r   r  r  rY  r  r   r  r  dumpsr  r  rC   r  )r  r  r\  r^  rl  r  new_shar  r  r  r&  s              rK   r  r  P  sv   ==V$D4==B& !9;jotuwzzzMM''RM ))%00 !9  <C  HM  N  PS  S  	S'"8"8;QTZ;Z"Z !;?~  @V  WX  Y  Y`  >a  fk  l  nq  q  	qKKd+KK$t4MM/*Eww||04Hs2STHX		(5h?8$$%L  Od  in  x  @  BE  E  EX9:89YYx '?'O$#N;\  lF  G*+E*FFZ[bZc  dJ  KW  JX  Xi  jv  iw  wz  {I  zJ  JX  Y]  Yc  Yc  dg  v{  DE  YF  XG  G]  ^n  ]o  oE  F`  Ea  b !J  Mx  }A  KR  S  	S "d"
 $
  X	ww~~h''8)<$ !JLty~  IM  NQ  IR  S  UX  X  	X	Xs   &I8  I I8 '*I8 I' 'A.I8 I$!I8 #I$$I8 'I52I8 4I55I8 8K5;K ?K0 KK0KK0*K50K5r?  c                      \        R 4      w  r\        RRR7      p\        RRRRV  RV R	\        P                  ! VR
^R7       R\
         2R7      # )zmanual-restartrestart_admin manual_panel_restart_v34_control)r
  u'   אתחול נשלח לשרת הבקרהuy   שרת הבקרה החיצוני יאתחל את פאנל האדמין הראשי. המתן כמה שניות ורענן.TzControl bootstrap: r#  r?  Fr  z

Control log:
r!  )r  r   r  r  rA  r  )r  r  r  s      rK   restart_admin_serverrF  u  s    #;<L#M L
8Z
[CF  ID  IM  Yl  my  lz  z}  ~L  }M  M[  \`  \f  \f  gj  y~  GH  \I  [J  J\  ]m  \n  Wo  p  pr   r@  c            	      v   \        4       p V '       g   \        R RRR7      R3#  \        V 4      w  rV'       g   \        RRRVR7      R3# \        R	4      p\        P
                  ! V \        4       R
pRV  RV 2p\        RVRVR7      #   \         d%   p\        RRR\        T4      R7      R3u Rp?# Rp?ii ; i)u   אין גיבוי לשחזורuB   לא נמצא קובץ גיבוי בתיקיית הגיבויים.Fr   r  u'   הגיבוי האחרון לא תקיןuM   הגיבוי לא שוחזר כי הוא לא עבר בדיקת תקינות.r!  r  admin_server_before_restoreu   הגיבוי האחרון שוחזר אל admin_server.py. לחץ בדיקת אתחול פאנל — מתקדם כדי להפעיל אותו.u   שוחזר מתוך:
uT   

גיבוי בטיחות לגרסה שהייתה פעילה לפני השחזור:
u"   שחזור גיבוי הסתייםTu"   שגיאה בשחזור גיבויu   השחזור לא הושלם.rT   N)	r  r  r  r  r   r  r  rE   r  )r_  rl  r  safety_backupr  detr&  s          rK   restore_admin_server_backuprK  |  s#   %'K !A  DH  MR  S  UX  X  	X
J5kB$%N  Q`  ej  t{  |  ~A  A  A34QR["34 ^&{m  4K  LY  KZ  [ !Est]`aa J !EGfkpz~  @C  {D  E  GJ  J  	JJs#   %B	 
>B	 	B8B3-B83B8rD  c           	      6   V \         9  d   R# \        P                  P                  R4      pV'       d   VP                  R8X  d   R# V \
        9   d+   \        VP                  4      R9  d   \        RRRR7      R3#  \        W4      w  r#RVR	,           R
VR,          R RVR,           2pVP                  R4      '       d   VRVR,           2,          p\        RRV R2RVR7      #   \         d%   p\        RRR\        T4      R7      R3u Rp?# Rp?ii ; i)Folder not foundr  r}   r  r9  u;   לאזור הזה ניתן להעלות רק קובץ HTML.Fr      יעד:
r?      

גודל:
r  r`    bytes

SHA256:
rQ  rR     

גיבוי קודם:
u   העלאה הושלמהu%   הקובץ נשמר בהצלחה כ־uQ   . אם אתה רואה גרסה ישנה, פתח מחדש עם רענון מלא.Tr!  u   שגיאה בהעלאהu[   הקובץ לא נשמר. הקובץ הקודם נשאר במקומו אם היה קיים.rT   N)rM  r  zNo file selectedr     r  r  )r{  r   rV  r   r   r  r   r  r  rE   r  )rI   r  r   r  r  r&  s   &     rK   uploadrT    sj   W&&==V$D4==B&&&$--!8@Q!Q !9;x  ~C  D  FI  I  	I}-f;fVn-_VF^A<NNabhiqbrast::h3F84D3EFFG !:>cdlcm  n  =@  EI  SZ  [  	[ } !:  =Z  _d  nr  sv  nw  x  z}  }  	}}s   >A*C) )D4DDDrE  c                    \         P                  P                  R 4      pV'       d   VP                  R8X  d   R# \	        VP                  4      R9  d   \        RRRR7      R3# \        W4      pV'       g   R# Vw  r4RVR,           R	VR
,          R RVR,           2pVP                  R4      '       d   VRVR,           2,          p\        RRV 2RVR7      # )r  r}   r  r9  uE   ניתן להעלות כאן רק קובץ HTML של מצגת יפן.Fr   rN  r?   rO  r  r`   rP  rQ  rR  rQ  u   מצגת יפן הועלתה'   הקובץ נשמר בשם הקבוע: Tr!  rR  rS  )zPresentation type not foundr  )r   rV  r   r   r   r  r  r  r  rp  r   r  r  s   &     rK   upload_presentationrX    s    ==V$D4==B&&&&77 !9  <C  HM  N  PS  S  	S#$4;E11H&.)8JJ]^dem^n]opGzz(/x0@/ABB;?fgofp=qvz  EL  M  Mr   rF  c                    \         P                  P                  R 4      pV'       d   VP                  R8X  d   R# \	        VP                  4      R9  d   \        RRRR7      R3# \        W4      pV'       g   R# Vw  r4RVR,           R	VR
,          R RVR,           2pVP                  R4      '       d   VRVR,           2,          p\        RRV 2RVR7      # )r  r}   r  r9  uI   ניתן להעלות כאן רק קובץ HTML של מצגת ארה״ב.Fr   rN  r?   rO  r  r`   rP  rQ  rR  rQ  u    מצגת ארה״ב הועלתהrV  Tr!  rR  rS  )zUSA presentation type not foundr  )r   rV  r   r   r   r  r	  rW  s   &     rK   upload_usa_presentationrZ    s    ==V$D4==B&&&&77 !9  <G  LQ  R  TW  W  	W!"29E55H&.)8JJ]^dem^n]opGzz(/x0@/ABB?CjksjtAuz~  IP  Q  Qr   rG  c            	         \         P                  P                  R R4      P                  4       p \         P                  P                  R4      pV'       d   VP
                  R8X  d   R#  \        W4      pV'       g   R# RVR,           RVR,          R R	VR
,           RVR,           2pVP                  R4      '       d   VRVR,           2,          pVR\        VP                  R4      4      ,           ,          p\        RRVR,           2RVR7      #   \         d%   p\        RRR\        T4      R7      R3u Rp?# Rp?ii ; i)r}  r}   r  r  rN  r?   rO  r  r`   rP  rQ  u   

מצב שמירה:
r   rR  rQ  r0  r   u+   תמונת מצגת ארה״ב הועלתהu+   התמונה נשמרה בשם הקבוע: rc  Tr!  u"   שגיאה בהעלאת תמונהu   התמונה לא נשמרה. להמרה ודחיסה של PNG/WebP/BMP/TIFF צריך Pillow בשרת. JPG אמיתי יתקבל גם בלי Pillow.FNrR  )zUSA image key not foundr  )r   r  r   rZ   rV  r   r  rq  r  rE   r  )r}  r  r  r  r&  s        rK   upload_usa_imager\    s     b1779I==V$D4==B&&&
A,Y=11fVn-_VF^A<NNabhiqbras  tL  MS  TZ  M[  L\  ]::h3F84D3EFFG6.vzz'/BCCC !NR}  E  FK  L  ~M  QN  SW  ah  i  	i A !E  H^  ch  rv  wz  r{  |  ~A  A  	AAs,   *D ?AD AD E D?9E?ErH  c            	         \         P                  P                  R 4      p V '       d   V P                  R8X  d   R# V P                  ;'       g    RpVP	                  4       P                  R4      '       g   \        RRRR7      R3# \         P                  '       d:   \         P                  \        R ,           8  d   \        RR	\        R
 R2RR7      R3#  \        V 4      w  r#pRV'       d   RP                  V4      MR,           pV'       d'   VRRP                  VR,          4      ,           ,          pV'       d'   VRRP                  VR,          4      ,           ,          p\        RR\        V4       R2RVR7      #   \        P                   d    \        RRRR7      R3u # \         d%   p\        RRR\        T4      R7      R3u Rp?# Rp?i\          d%   p\        RRR\#        T4      R7      R3u Rp?# Rp?ii ; i)!r  r}   r  r  r9  uJ   ניתן להעלות כאן רק קובץ ZIP של תמונות מצגת.Fr   r:  1   קובץ התמונות גדול מהמגבלה: r`   r  r;  u*   נשמרו בתיקיית התמונות:
rn  u   לא נשמרו תמונות.   

דולגו:
Nx   Nu7   

לא נמצאו ב־ZIP, ולכן לא הוחלפו:
u$   ZIP תמונות ארה״ב נטען   נשמרו uO    תמונות למצגת. קבצים קיימים באותו שם הוחלפו.Tr!     ZIP לא תקיןW   הקובץ שהועלה אינו ZIP תקין או שלא ניתן לפתוח אותו.uC   הקובץ לא עומד במגבלות העלאה של הפאנל.Nu   שגיאה בהעלאת ZIP;   לא ניתן היה לעבד את קובץ התמונות.rT   rR  r  )r   rV  r   r   rA   r  r  r@  r  r  rD   r   r  
BadZipFiler  r   rE   r  )r  r  r  r  r  r  r&  s          rK   upload_usa_images_ziprg    sc   ==V$D4==B&&&MM''RM ))&11 !9  <H  MR  S  UX  X  	X'"8"8;SVa;a"a !;?p  rJ  KL  qM  MT  >U  Z_  `  be  e  	ea%Ed%K"7?Zb499XCV  iH  I*TYYwt}-EEEGSVZV_V_`ghl`mVnnnG 2#h-(wx	
 	
  ` !4  7P  UZ  [  ]`  `  	` ^ !46{  AF  PS  TW  PX  Y  [^  ^  	^ a !>@}  CH  RV  WZ  R[  \  ^a  a  	aasO   7E> -E> <AE> >%H %H .H /GH H H G;5H ;H rI  c                    \         P                  P                  R 4      pV'       d   VP                  R8X  d   R# \	        VP                  4      R9  d   \        RRRR7      R3# \        W4      pV'       g   R# Vw  r4RVR,           R	VR
,          R RVR,           2pVP                  R4      '       d   VRVR,           2,          p\        RRV 2RVR7      # )r  r}   r  r9  u0   ניתן להעלות כאן רק קובץ HTML.Fr   rN  r?   rO  r  r`   rP  rQ  rR  rQ  u'   קובץ ארה״ב נוסף הועלהrV  Tr!  rR  rS  )zUSA extra HTML type not foundr  )r   rV  r   r   r   r  r  )r  r  rp  r   r  r  s   &     rK   upload_usa_extra_htmlri    s    ==V$D4==B&&&&77 !9;mrwxz}}}	0E33H&.)8JJ]^dem^n]opGzz(/x0@/ABBFJqrzq{H|  BF  PW  X  Xr   rJ  c                 R   \         P                  P                  R 4      pV'       d   VP                  R8X  d   R# \         P                  '       dB   \         P                  \
        R,           8  d"   \        RR\        \
        4       R2RR7      R3# \        W4      pV'       g   R# RR	P                  VR
,           Uu. uF  q3R,          NK  	  up4      ,           RVR,           2,           pVR\        VP                  R4      4      ,           ,          p\        RRRVR7      # u upi )r  r}   %   קובץ מוזיקה גדול מדי/   קובץ האודיו גדול מהמגבלה: r   Fr   r;  u   נשמר אל:
rn  rd  r?   u   

SHA256 MP3 סופי:
rQ  r0  r   u    מוזיקת יפן הועלתהuU   הקובץ נשמר בכל הנתיבים שהמצגת מחפשת כ־MP3 אמיתי.Tr!  rR  r  )zJapan music type not foundr  )r   rV  r   r   r@  r=  r  r   r  rD   rq  )r  r  r  r   r  s   &    rK   upload_japan_musicrm    sT   ==V$D4==B&&&'"8"8;QT_;_"_ !HL{  }I  J`  }a  |b  bc  Kd  in  o  qt  t  	ti.F00 499viGX-YGXt6llGX-Y#ZZ_y  {A  BJ  {K  zL  ^M  MGv*6::g+>???G?  BY  ^b  ls  t  t .Zs   >D$
rK  c            	         \         P                  P                  R 4      p V '       d   V P                  R8X  d   R# V P                  ;'       g    RP	                  4       P                  R4      '       g   \        RRRR7      R3# \         P                  '       d:   \         P                  \        R ,           8  d   \        RR	\        R
 R2RR7      R3#  \        V 4      w  rpRV'       d   RP                  VR,          4      MR,           pV'       d'   VRRP                  VR,          4      ,           ,          pV'       d'   VRRP                  VR,          4      ,           ,          p\        RR\        V4       R2RVR7      #   \        P                   d    \        RRRR7      R3u # \         d%   p\        RRR\        T4      R7      R3u Rp?# Rp?ii ; i)!r  r}   r  r  r9  u:   ניתן להעלות כאן רק ZIP תמונות יפן.Fr   r:  r^  r`   r  r;     יובאו:
rn  :N   Nu   לא יובאו תמונות.(   

הוחלפו קבצים קיימים:
r`  r_  u    ZIP תמונות יפן נטעןrb  u(    תמונות תחת JAPAN/media/images.Tr!  rc  rd  u"   שגיאה בהעלאת ZIP יפןre  rT   NrR  r  )r   rV  r   r   rA   r  r  r@  r'  r.  rD   r   r  rf  rE   r  )r  r  r  r-  r  r&  s         rK   upload_japan_images_ziprr    s#   ==V$D4==B&&&MMR&&(11&99 !9;w  }B  C  EH  H  	H'"8"8;UXc;c"c !;?p  rL  MN  qO  OV  >W  \a  b  dg  g  	gh)>t)D&;!(TYYx~%>PopDtyyQ\]aQbGcccG*TYYwt}-EEEG !C{SVW_S`Ra  bJ  FK  PT  ^e  f  	f ` !4  7P  UZ  [  ]`  `  	` h !E  HE  JO  Y]  ^a  Yb  c  eh  h  	hhs7   >F -F AF %G*G3G4GGGrL  c           	      
   T ;'       g    R P                  4       p \        P                  P                  R4      pV R!9  d   R"# V'       d   VP                  R 8X  d   R## VP                  ;'       g    R P                  4       P                  R4      '       g   \        RRRR7      R3# \        P                  '       d:   \        P                  \        R$,           8  d   \        RR	\        R
 R2RR7      R3#  \        W4      w  r#pRV'       d   RP                  VR,          4      MR,           pV'       d'   VRRP                  VR,          4      ,           ,          pV'       d'   VRRP                  VR,          4      ,           ,          p\        RV  R2R\        V4       RV  R2RVR7      #   \        P                   d    \        RRRR7      R3u # \         d%   p\        RRR\!        T4      R7      R3u R p?# R p?ii ; i)%r}   r  r  r  r9  u=   ניתן להעלות כאן רק ZIP מלא של הטיול.Fr   r:  u!   ה־ZIP גדול מהמגבלה: r`   r  r;  ro  rn  :N   Nu   לא יובאו קבצים.rq  :N   Nr_  u   ZIP מלא של u	    נטעןrb  u    קבצים בתיקיית r   Tr!  rc  rd  u"   שגיאה בהעלאת ZIP מלאu9   לא ניתן היה לעבד את חבילת הטיול.rT   Nr9  )zTrip package type not foundr  rR  r  )upperr   rV  r   r   rA   r  r  r@  r:  r?  rD   r   r  rf  rE   r  )r2  r  r  r  r-  r  r&  s   &      rK   upload_trip_packagerw  -  sT   JJBD==V$D##114==B&&&MMR&&(11&99 !9;z  @E  F  HK  K  	K'"8"8;UXc;c"c !;?`a{|}`~  F  >G  LQ  R  TW  W  	Wf)>t)J&;!(TYYx~%>PmnDtyyQ\]aQbGcccG*TYYwt}-EEEG #3D6!C{SVW_S`Raa|  ~B  }C  CD  FE  JN  X_  `  	` ` !4  7P  UZ  [  ]`  `  	` f !E  HC  HM  W[  \_  W`  a  cf  f  	ffs7   7>F- 6-F- $AF- -%HHHG=7H=HrM  c                 `   \         P                  P                  R 4      pV'       d   VP                  R8X  d   R# \         P                  '       dB   \         P                  \
        R,           8  d"   \        RR\        \
        4       R2RR7      R3# \        W4      pV'       g   R# Vw  r4RVR	,           R
VR,          R RVR,           2pVP                  R4      '       d   VRVR,           2,          pVR\        VP                  R4      4      ,           ,          p\        RRV 2RVR7      # )r  r}   rk  rl  r   Fr   r;  rN  r?   rO  r  r`   rP  rQ  rR  rQ  r0  r   u$   מוזיקת ארה״ב הועלתהu+   הקובץ נשמר בנתיב הקבוע: Tr!  rR  r  )zUSA music type not foundr  )
r   rV  r   r   r@  r=  r  r   r  rq  )r  r  rp  r   r  r  s   &     rK   upload_usa_musicry  G  sV   ==V$D4==B&&&'"8"8;QT_;_"_ !HL{  }I  J`  }a  |b  bc  Kd  in  o  qt  t  	t9+E..H&.)8JJ]^dem^n]opGzz(/x0@/ABBv*6::g+>???GCGrs{r|E}  CG  QX  Y  Yr   rN  c           	      (   T ;'       g    R P                  4       P                  4       p V \        9  d   \        RRRR7      R3# \	        4       w  rV'       g   \        RVRR7      R3# \
        P                  P                  R4      R	8w  d   \        R
RRR7      R3# \        V ,          p\
        P                  P                  R4      ;'       g    R P                  4       pWC8w  d   \        RRV 2RR7      R3# \        \
        P                  P                  R4      4      p \        W4      w  rgpRT RT R\        4        RT;'       g    R 2p	\        RV R2RV	R7      #   \         d%   p
\        RRR\        T
4      R7      R3u Rp
?
# Rp
?
ii ; i)r}   u#   פעולת מחשב לא מוכרתu0   הפעולה המבוקשת אינה קיימת.Fr   r  u   פעולת מחשב נחסמהr  ackrg   u   חסר אישור פעולהus   כדי למנוע לחיצה בטעות, צריך לסמן שאתה מבין את המשמעות של הפעולה.r  confirm_textu%   מילת האישור לא נכונהuD   כדי לבצע את הפעולה צריך להקליד בדיוק: r  u   פעולה:
u   

תבוצע בעוד:
u$    שניות

כתובת מבקשת:
u   

פלט Windows:
r  u   פעולת מחשב נקבעהuq    נקבע בהצלחה. אפשר לבטל לפני סוף הטיימר דרך כפתור הביטול בפאנל.Tr!  u+   שגיאה בהפעלת פקודת מחשבuB   Windows לא קיבל את פקודת הכיבוי/ריסטארט.rT   N)rZ   rA   POWER_CONFIRM_TEXTr  r  r   r  r   r  r  r  rE   r  )r  r  r
  expectedr|  r  rN   final_delayr  r  r&  s   &          rK   power_actionr  Z  s;   ll!!#))+F'' !FHz  @E  F  HK  K  	K*,OG !A6eTVYYY||#% !?  Bw  |A  B  DG  G  	G!&)HLL$$^4::AACL !H  MQ  RZ  Q[  K\  af  g  il  l  	l!',,"2"27";<Ex%6v%E"F!%(B;-Ov  xE  xG  wH  H]  ^d  ^l  ^l  hl  ]m  n !AeW  M~  D  DH  RY  Z  	Z x !N  QU  Z_  im  nq  ir  s  ux  x  	xxs   "?E" "F-FFFrO  c                      \        4       w  rV '       g   \        R VRR7      R3# \        4       w  r#V^ 8H  pV'       d   RMRpV'       d   RMRp\        YVYC;'       g    RV 2R	7      # )
u'   ביטול פעולת מחשב נחסםFr   r  u-   פעולת מחשב מתוזמנת בוטלהu6   לא נמצאה פעולה מתוזמנת לביטולuG   אם היה כיבוי/ריסטארט בהמתנה — הוא בוטל.uk   Windows החזיר שאין כרגע כיבוי/ריסטארט בהמתנה, או שלא ניתן לבטל.r  r!  )r  r  r  )r  r
  rcr  r   r  r  s          rK   power_cancelr  u  sq    *,OG !JFW\]_bbb%'JB
'B?A;GEWY
S  `MCUB8V8VMRTQUBVWWr   z/JAPANz/JAPAN/c                      \        R 4      # r   r  r   r   rK   japanr    s     Wr   z/USAz/USA/c                      \        R 4      # r   r  r   r   rK   usar    s     Ur   z	/Moneyappz
/Moneyapp/c                      \        R 4      # r   r  r   r   rK   moneyappr         Z  r   z
/MoneyHomez/MoneyHome/c                      \        R 4      # r   r  r   r   rK   	moneyhomer    s     [!!r   z/JAPAN/<path:path>c                 0    \        \        R ,          V 4      # r  r  r{  r?   s   &rK   japan_staticr    s    ww/66r   z/USA/<path:path>c                 0    \        \        R ,          V 4      # r  r  r  s   &rK   
usa_staticr    s    wu~t44r   z/Moneyapp/<path:path>c                 0    \        \        R ,          V 4      # r  r  r  s   &rK   money_staticr        wz2D99r   z	/TripFormz
/TripForm/c                      \        R 4      # r   r  r   r   rK   tripformr    r  r   z/MoneyHome/<path:path>c                 0    \        \        R ,          V 4      # r  r  r  s   &rK   moneyhome_staticr    s    w{3T::r   z/TripForm/<path:path>c                 0    \        \        R ,          V 4      # r  r  r  s   &rK   tripform_staticr    r  r   __main__zadmin-startup)r  r  threadeduse_reloader>   r   r   r   r   r   >   introbudgetsummaryextra-dinerroadtrip-mapextra-big-surextra-mono-lakeextra-death-valley>   .bmpru  .png.tif.jpeg.tiff.webp>
   .aac.m4a.mp3r  .ogg.wav.wma.flac.opus.webmi   i  i   i  @i  @i  0>   .js.cssr  ru  r  r  .svg.txtr  r  .jsonr  i    i   i  i   rY   i 0 >   rh   r  offfalseip  r   )ru  )r  )Tr}   )admin_server_backup)startup)r  N)NNNr}   )NNr}   )NNmanual_restart)NNsafe_external_restart)   r  rw  )r}   r}   )i  )ra  )r   )r  )r  uB   🇺🇸 ארה״ב 2027 — אמריקה על פול ווליוםu7  Road Trip • Orlando • Miami • Cruise / 36 ימים של נופים, פארקים, קניות, קרוז ורגעים שגורמים להגיד: “רגע… לשם אנחנו באמת הולכים?” / מערב ארה״ב: סן פרנסיסקו , כביש 1, LA , קניונים, וגאס ויוסמיטי)r  uN   🗺️ מסלול הרוד טריפ — הסיפור הגדול, מלמעלהu  סן פרנסיסקו • כביש 1 • LA • וגאס • יוסמיטי / מפה אחת שמסבירה את כל הרעיון: מתחילים באוקיינוס, מטפסים לקניונים, נוגעים במדבר וחוזרים לטבע. / המסלול נותן את כל המנה: חופים, כבישים יפים, פארקים לאומיים, וגאס ויוסמיטי — בלי לנסות לדחוס כאן את כל הלו״ז.)zday-01uB   יום 1 — ✈️ נחיתה ישירה ב סן פרנסיסקוu   סן פרנסיסקו / נוחתים בעיר שיודעת לפתוח טיול עם סטייל. / נחיתה, התארגנות וטעימה ראשונה מהעיר)zday-02u2   יום 2 — 🌉 סן פרנסיסקו + Alcatrazu   סן פרנסיסקו / Alcatraz / יום של אייקונים: מפרץ, גשרים, אלקטרז ואווירה של סרט. / אלקטרז, תצפיות והעיר הכי פוטוגנית בצפון קליפורניה)zday-03u:   יום 3 — 🌊 סן פרנסיסקו → מונטרייu   מונטריי / 17-Mile Drive / עוברים למוד רוד־טריפ אמיתי: ים, כביש ונופים שמתחילים לעבוד עלינו חזק. / נסיעה דרומה, מונטריי וקטע חוף מהמם)zday-04u4   יום 4 — 🐋 Monterey Bay Whale Watch + Big Suru   מונטריי / Big Sur / היום שבו האוקיינוס נותן הופעה, ואם לוויתן קופץ — זה כבר בונוס קולנועי. / שייט לווייתנים ואז נופי Big Sur וכביש 1)r  u?   Road Trip Bonus — 🌉 Big Sur – Bixby Bridge + McWay Fallsu   כביש 1 / קליפורניה / כאן קליפורניה כבר לא רק יפה — היא מתחילה ממש להשוויץ. / גשר Bixby והחופים הדרמטיים של Big Sur הם מהשיאים המצולמים של כביש 1)zday-05u?   יום 5 — 🎡 סנטה מוניקה → לוס אנג׳לסu   Santa Monica / Los Angeles / נכנסים ל־ LA דרך סנטה מוניקה : חוף, טיילת, גלגל ענק ואווירת קליפורניה קלאסית. / Santa Monica Pier, חוף, טיילת וכניסה לאווירת לוס אנג׳לס)zday-06u8   יום 6 — 🎥 Warner Bros + Beverly Hills + Griffithu   לוס אנג׳לס / LA במצב קלאסי: אולפנים, בוורלי הילס ותצפית של סוף סרט. / Warner Bros , Beverly Hills ו־ Griffith)zday-07u1   יום 7 — 🏜️ לוס אנג׳לס → Zionu   מעבר למדבר / Utah / עוזבים עיר ונכנסים למרחבים. זה יום מעבר, אבל עם סוף ששווה את זה. / נסיעה ארוכה אל אזור Zion)r  u3   Road Trip Bonus — 🍔 Peggy Sue’s 50’s Dinerue  עצירת דרך אמריקאית / מדבר / באמצע כל הנופים הגדולים, מגיע רגע קטן ומושלם של אמריקה קלאסית: ניאון, מילקשייק ואווירת רוד־טריפ אמיתית. / עצירת דיינר שנותנת לטיול את הטעם של אמריקה הישנה והכיפית של הכביש)zday-08u,   יום 8 — 🏞️ Zion → Bryce → Pageu   Zion / Bryce / Page / יום טבע חזק במיוחד: צוקים, צבעים ומעברים שנראים לא אמיתיים. / Zion , Bryce והגעה ל־ Page)zday-09u2   יום 9 — 🧡 Antelope Canyon + Horseshoe Bendu   Page Arizona / זה היום של “וואו, לאן אתם הולכים?” — בדיוק זה. / Antelope Canyon ו־ Horseshoe Bend)zday-10u5   יום 10 — 🏜️ Page → Grand Canyon South Rimu   Grand Canyon / היום שבו המילה “גדול” מקבלת קנה מידה חדש. / נסיעה אל South Rim ומפגש עם הגרנד קניון)zday-11u-   יום 11 — 🎰 Grand Canyon → Las Vegasu   לאס וגאס / מהטבע הכי גדול — לעיר הכי מוגזמת. מעבר חד, אבל כיפי. / נסיעה לווגאס וכניסה לאורות של הסטריפ)zday-12u,   יום 12 — 🛍️ Vegas Outlets + Sphereu   לאס וגאס / וגאס יודעת לשלב שופינג, שואו ואורות ברמה לא סבירה. / אאוטלטים, Sphere והסטריפ)zday-13u)   יום 13 — ✨ Vegas Extra Day + Stripu   לאס וגאס / עוד יום בווגאס, כי כנראה יום אחד לא מספיק כדי להגזים כמו שצריך. / קניות, Strip , מלונות ותצוגות ערב)zday-14u1   יום 14 — 🏔️ Las Vegas → Mammoth Lakesu   Mammoth Lakes / נפרדים מהניאון וחוזרים לאוויר הרים כמו אנשים אחראיים. בערך. / נסיעה צפונה אל Mammoth Lakes)r  u%   Road Trip Bonus — 🔥 Death Valleyu$  בין וגאס ל־Mammoth / זה המעבר הכי חד במסלול: מווגאס המנצנצת אל מדבר עצום, שקט ובלתי נתפס. / עמק המוות מוסיף למסלול מרחבים אינסופיים, תצפיות דרמטיות ותחושת קצה של המערב)r  u6   Road Trip Bonus — 🏜️ Mono Lake / Eastern Sierrau  בדרך אל יוסמיטי / פה הרוד־טריפ משנה טון שוב: מדבר, הרים, אגם דרמטי ושמיים ענקיים — הכל בפריים אחד. / אזור Eastern Sierra מוסיף תחושת מרחב אדירה לפני הכניסה ליוסמיטי)zday-15u.   יום 15 — 🚗 Mammoth → Yosemite Valleyu   יוסמיטי / אחד מימי ה־וואו של הטיול. יוסמיטי נכנסת לפריים. / דרך נופית אל Yosemite Valley)zday-16u7   יום 16 — 🌲 Yosemite Highlights + Mariposa Groveu   יוסמיטי / Mariposa / יום של מפלים, גרניט ועצי סקויה שגורמים לך להרגיש בגודל של סיכה. / יוסמיטי קלאסי + Mariposa Grove)zday-17u1   יום 17 — ✈️ Yosemite → SFO → Orlandou   מעבר לאורלנדו / סוגרים פרק מערב ופותחים פרק פארקים. המזוודות עוד לא יודעות מה מחכה להן. / נסיעה לשדה וטיסה לאורלנדו)zday-18u7   יום 18 — 🛍️ התאוששות + Disney Springsu   אורלנדו / יום רך לפני שמתחילים לצרוח בפארקים. / התאוששות, Disney Springs ואווירה קלילה)zday-19u'   יום 19 — 🎢 Islands of Adventureu   Universal Orlando / כאן מתחיל פרק האדרנלין הרשמי. אקספרס ביד, חיוך בפנים. / צ׳ק־אין Premier ו־ Islands of Adventure)zday-20u7   יום 20 — 🎬 Universal Studios Florida + CityWalku   Universal Studios / יום Universal קלאסי: מתקנים, אווירה ו־ CityWalk לסיום. / Universal Studios Florida וערב CityWalk)zday-21u;   יום 21 — ⛳ מנוחה + Hollywood Drive-In Mini Golfu   אורלנדו / יום רגוע יותר, כי גם למשפחה עם אנרגיה צריך טעינה. / מנוחה, בריכה/קניות קלות ומיני גולף)zday-22u*   יום 22 — 🌌 Epic Universe + Expressu   Epic Universe / אחד הימים הכי מסקרנים בטיול — פארק חדש, גדול ומלא הייפ. / Epic Universe עם Express)zday-23u?   יום 23 — 🧗 פארק חבלים + בריכה / I‑Driveu   אורלנדו / קצת אקשן, קצת בריכה, קצת אורלנדו בלי לחץ. / פארק חבלים, בריכה או International Drive)zday-24u(   יום 24 — 🌊 Volcano Bay + Expressu~   Volcano Bay / מים, מגלשות ויום רענון שנראה כמו פרסומת לחופשה. / Volcano Bay עם Express)zday-25u5   יום 25 — 🎃 רגוע + Halloween Horror Nightsuu   Universal HHN / היום מתחיל רגוע ונגמר בפנים לבנות. / מנוחה ביום ו־HHN בערב)zday-26u7   יום 26 — 🚗 Orlando → Sawgrass Mills → Miamiu   Sawgrass / Miami / מחליפים פארקים בשופינג, ואז ממשיכים ל מיאמי . / Sawgrass Mills והמשך ל מיאמי)zday-27u,   יום 27 — 🌴 Miami Chill Before Cruiseu   מיאמי / מיאמי מורידה הילוך בסטייל לפני הקרוז. / חוף, אווירה, התארגנות ונשימה עמוקה)zday-28u<   יום 28 — 🚢 החזרת רכב ועלייה לקרוזu   נמל מיאמי / הרכב חוזר, האונייה מתחילה. החופשה עוברת למצב צף. / עלייה לקרוז ותחילת פרק הים)zday-29u-   יום 29 — 🌊 קרוז – יום ים 1u   בלב הים / יום ים ראשון: בריכה, אוכל, סיפון ונוף בלי סוף. / יום חופשי על האונייה)zday-30u-   יום 30 — 🌊 קרוז – יום ים 2u   בלב הים / עוד יום ים, כי למה לעצור משהו שעובד? / מתקני האונייה, אוכל ומנוחה)zday-31u!   יום 31 — 🏝️ St. Maartenu   St. Maarten / הקריביים נכנסים לתמונה בצבעים שלא נראים חוקיים. / יום עגינה ב־ St. Maarten)zday-32u.   יום 32 — 🐬 St. Thomas + Dolphin Splashu   St. Thomas / יום שיכול להפוך לזיכרון משפחתי חזק במיוחד. / St. Thomas ואטרקציית דולפינים)zday-33u-   יום 33 — 🌅 קרוז – יום ים 3uw   בלב הים / עוד קצת ים כדי לא להיגמל מהר מדי. / יום ים, סיפון, אוכל ונוף)zday-34u,   יום 34 — 🏖️ Perfect Day at CocoCayu   CocoCay / שם מחייב — ובמקרה הזה הוא לגמרי מתכוון לזה. / CocoCay , חוף, מים טורקיז ופארק מים)zday-35uE   יום 35 — 🏨 ירידה מהקרוז + לילה ליד השדהu   מיאמי / החופשה מתחילה להתקפל, אבל לא שוברים בבת אחת. / ירידה מהקרוז, התארגנות ולילה ליד השדה)zday-36u1   יום 36 — 🛫 טיסה חזרה לישראלu   הביתה / היום הפחות אהוב, אבל עם אלבום מטורף בזיכרון. / עלייה לטיסה חזרה לישראל)r  u3   💰 תקציב — המספרים, בלי דרמהu   תמונת מצב פיננסית / זה לא טיול קטן. זה פרויקט משפחתי עם נוף, פארקים, ים, שופינג וקרוז. / עלות כללית מוערכת: $81,297 ≈ ₪243,890)r  u;   🥂 סיום — אז לאן אתם באמת הולכים?u   טיול חלום משפחתי / אם מי שרואה את זה אומר “וואו” — הוא פשוט צודק. / מערב ארה״ב, אורלנדו, מיאמי וקרוז — בטיול אחד)r}   criticalrN  (O  flaskr   r   r   r   r   r   werkzeug.utilsr	   r=   rU  r;   ru  r   r  r.  r  r  r  r  r@  r   r  urllib.requestr  ri  re  r  rV  rj  r  r  r  r  r?   rD   r  r  r  r  r  r  r  r  r{  r  r  r  r  r  r   ry  rz  r  AUDIO_UPLOAD_EXTENSIONSr+  r'  r(  r)  r*  r:  r;  r<  r=  r>  r  __file__r  r  rT  r  r  r  r  r|  ADMIN_RESTART_CMD_PATHr$  rt  r  r   r   r  r  r  r  r[   r  r  r  rL   r  r  r  r  r   r  r  r   r  r=  r>  r?  MEDIA_AUDIO_ACCEPTMEDIA_IMAGE_ACCEPTrZ   rA   r  r  r  r  r}  POWER_LABELSr  r&  rE  rF  r   r  rG  rR  r  r   r  r   r1  r  r  r2  r3  r4  r5  r  r  rJ  rD  r  r  r  r  r  r  r  r/  r  r   r   r   r   r   r   r   r'  rI  r`  rl  rq  r  r  valuesr  rS  r  after_requestr  r  rY  r   rX  r  r  r  r  r  r	  r  r  r  r  r   r.  r3  r?  rE  rN  rX  r\  r  r  r  r  r  r  r  r  r  r  r  r  r   r%  rl  rp  ru  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r
  r  r  r  r  r  r(  r*  ri  rr  r  r  r  r  r  r  r  r  r  r@  r  rj  r  r}  r  r  r  r  r  r  r  r  r  r  r  r  r  r  rt  r  r   r  r  r  r  r  r  r#  r  r  r  rh  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r"  r$  r(  r+  r-  r2  r4  r7  r  rF  rK  rT  rX  rZ  r\  rg  ri  rm  rr  rw  ry  r  r  r  r  r  r  r  r  r  r  r  r  rA  )r  s   0rK   <module>r     s   Y X * 	  
 	          HoE ==!45 

ggll8%56ggll;0NO WW\\+7PQ ww||K@ ggll;> 77<<-LM WW\\(4VW -  RWW\\(G,	277<<%(Xz2h4Xz2 D -/  39  $ 
 g'97D\]rww||G-?J_`
 J  fk  lm  oq  fr  Ms  fr  ab  PT  UV  WZ  T[  N\  fr  Ms  sR  
W0';LM
Wg'89
 
Wng7IJ
  n T .   *; ')9 &.   *; ')9 &}  GGOOH- 77<<)^D ww||He5KL ( +  (9 %'7 $h0JK h0CD GGLL3ST GGLL96FG 
 ZZ^^$>@YZ ww||H.LM GGLL+DE ggll8-LM 

/UWZ [\ (+BJJNN;acg,h(i %
 JJNN#<>Z[ 6 5v?UW]  `y  z16;KV  Vp  q'#FPjlr  ua  b+V5F  Q|  }	     !$BJJNN3SU[$\ ] "2::>>2QSVWbSc#de !E  "M"**..A]_r2s2y2yz}2~  "MEE  "M"**..A]_r2s2y2yz}2~  "M  M RZZ^^,H#N^J_`a JJNN#A6J 

'I7S ] D  

'H#NTTV\\^  gB  B     # 
 %)  :C@FFHNNPXss2::>>";SAB2::>>";VDEBJJNN#=uEFCC

/F LMNO
"c"c"**..9Y[_*`&abc 

/UW] ^_  #eJ&7 7  zz~~&FLRRTZZ\d ::>>*NPSTZZ\bbd  mH  H jjnn%ErJPPR jjnn%ErJPPR 

'I277<<X`buKvw 3r3rzz~~6TVZ'[#\]^ C#bjjnnEkms6t2u$vw zz~~&GP  X/AB X/HI h(9:ggll8-DE & 

'BOTZZ\oo`o (+BJJNN;fhm,n(o %ZZ^^,SUXY__aggi  rM  M $'

7egj(k$l !77<<2NO b-TSXZhjlntv|  O  QV  W OO% %,.WY_avx~  AC  %D . !%,.LfVkms  vP  %Q . !#*,Y[acvx~  Al  #m , 7"
VNr>JB$:2%PW&r >>#KKKd+ $ BGGLL2DgNY] ^ BGGLL2DhOZ^ _ BGGLL)7H= M BGGLL)74FP[_ ` BGGLL)7NGLW[ \ BGGLL)7G<t L t ,  4 0 ' ''+
4
$8A(1Bh,3Bl

2M`;z8'T.Q[ BUn 	%'TeD&:RRh  	 )? , "8  4ZBC ?F2%
MN&V	x xv Pf@>*!X Xvx xve eP +, .0 (**C*(1\hIK>*"$pd; 3D DR _q  a  _q  cB  _q  D{  _q  }^  _q  `K  _q  Mp   _q  r }%  _q  %L+  _q  N+x.  _q  z.v2  _q  x2g9  _q  i9K=  _q  M=Y@  _q  [@C  _q  ADtG  _q  vGJK  _q  LKBO  _q  DOnR  _q  pRWX  _q  YXC^  _q  E^Ta  _q  VaYe  _q  [eli  _q  niEm  _q  Gmfp  _q  hpDt  _q  Ft|w  _q  ~wJ{  _q  L{q~  _q  s~kA  _q  mAiD  _q  kDBH  _q  DHTK  _q  VKAO  _q  COJR  _q  LRMU  _q  OULX  _q  NXY[  _q  [[Q^  _q  S^ca  _q  ea_e  _q  aenh  _q  phFm  _q  Hm^q  _q * 89e  eR $`"fR&P*/f $ $ "#L $L 74 4 <K K 9  >  ?! ! ?! !
   =  Q Q 1[ 2[ x0> 1> $%a &a () *" ?& & &' ( !F84
e 5
e ?! !  ! " !"4 #4  "VH5M 6M ?VH-N .N$ M M >F8,g -g !"x #x $%~ &~, &2F 3F !F84
{ 5
{  6(3z 4z  `
 !`
 /0Q 1Q # # 1e 2e  6(3c 4c &2X 3X !F84 X 5 XH "VH5p 6p )F8<J =J$ x0} 1}$ 4vhGM HM  86(KQ LQ  1A 2A$ #fX6a 7a< /&BX CX  ,vh?t @t %x8h 9h, (6(;f <f2 *VH=Y >Y$ vh/x 0x4 ?VH-X .X 89   67   ;<!  ! <="  "  7 !7 5 5 "#: $: ;<!  ! #$; %; "#: $: z_-#O4GG*t%GP gS Mss   )AZ