Files
parentzone_downloader/__pycache__/snapshot_downloader.cpython-313.pyc

738 lines
46 KiB
Plaintext
Raw Normal View History

2025-10-07 14:52:04 +01:00
<EFBFBD>
Uf<55>h <09><00><00><><00>SrSSKrSSKrSSKrSSKrSSKrSSKrSSKJrJr SSK J
r
SSK J r J r JrJr SSKJrJr SSKrSSKrSSKJr "SS 5rS
r\S :Xa\"\"55 gg!\a SrN,f=f) z<>
Snapshot Downloader for ParentZone
This script downloads snapshots (daily events) from the ParentZone API with pagination support
and generates a comprehensive markup file containing all the snapshot information.
<EFBFBD>N)<02>datetime<6D> timedelta)<01>Path)<04>List<73>Dict<63>Any<6E>Optional)<02> urlencode<64>urljoin)<01> AuthManagerc<00><><00>\rSrSrS,S\S\S\S\S\S \4 S
jjrS rS rS \ \\44Sjr
S/SSSS4S\ RS\ \S\S\S\S\S \ \\44SjjrS/SSS4S\ RS\ \S\S\S\S \ \ \\44 SjjrS\ \\4S\ RS \4SjrS\ \\4S\ RS \4SjrS\ \\4S \4SjrS\S \4S jrS\ RS!\ \\4S \\4S"jrS#\S \4S$jrS\ \ \\4S\S\S \4S%jrS\ \ \\4S\S\S \4S&jrS \4S'jrS \4S(jrS/SSS4S\ \S\S\S\S \4
S)jjrS*rS+r g)-<2D>SnapshotDownloader<65><00> snapshotsN<73>api_url<72>
output_dir<EFBFBD>api_key<65>email<69>password<72>
debug_modec <00><><00>URS5UlSUl[U5UlURR SSS9 URS- UlUR R SSS9 X0lX@lXPl SUl
X`l UR5 SSS S
S S S SSSSSS. Ul SSSSS.Ulg)a<
Initialize the snapshot downloader.
Args:
api_url: Base URL of the API
output_dir: Directory to save the snapshot files
api_key: API key for authentication
email: Email for login authentication
password: Password for login authentication
debug_mode: Enable detailed server response logging
<EFBFBD>/z /v1/postsT)<02>parents<74>exist_ok<6F>assetsNz!application/json, text/plain, */*z#en-GB,en-US;q=0.9,en;q=0.8,ro;q=0.7zhttps://parentzone.mezu=1, izA"Not;A=Brand";v="99", "Google Chrome";v="139", "Chromium";v="139"z?0z"macOS"<22>empty<74>corsz same-sitezuMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36z3.54.0) <0C>acceptzaccept-language<67>origin<69>priorityz sec-ch-uazsec-ch-ua-mobilezsec-ch-ua-platformzsec-fetch-destzsec-fetch-modezsec-fetch-sitez
user-agentzx-client-versionr)<04>total_snapshots<74> pages_fetched<65>failed_requests<74>generated_files)<0F>rstripr<00>snapshots_endpointrr<00>mkdir<69>
assets_dirrrr<00> auth_managerr<00> setup_logging<6E>headers<72>stats)<07>selfrrrrrrs <20>H/Users/tudorsitaru/projects/parentzone_downloader/snapshot_downloader.py<70>__init__<5F>SnapshotDownloader.__init__s<><00><00><1F>~<7E>~<7E>c<EFBFBD>*<2A><04> <0C>"-<2D><04><1F><1E>z<EFBFBD>*<2A><04><0F> <0C><0F><0F><1D><1D>d<EFBFBD>T<EFBFBD><1D>:<3A><1F>/<2F>/<2F>H<EFBFBD>4<><04><0F> <0C><0F><0F><1D><1D>d<EFBFBD>T<EFBFBD><1D>:<3A><1F> <0C><1A>
<EFBFBD> <20> <0A> <20><04><19>$<24><0F> <0A><1A><1A><1C>:<3A>D<>-<2D> <20>\<5C> $<24>"+<2B>%<25>$<24>)<29>R<02> (<28> 
<EFBFBD><04> <0C>" !<21><1E> <20> <20> 
<EFBFBD><04>
<EFBFBD>c<00><><00>URS- n[R"[RS[R"U5[R
"5/S9 [R "[5Ulg)zSetup logging configuration.z snapshots.logz)%(asctime)s - %(levelname)s - %(message)s)<03>level<65>format<61>handlersN) r<00>logging<6E> basicConfig<69>INFO<46> FileHandler<65> StreamHandler<65> getLogger<65>__name__<5F>logger)r-<00>log_files r.r*<00> SnapshotDownloader.setup_loggingWs[<00><00><17>?<3F>?<3F>_<EFBFBD>4<><08><0F><1B><1B><19>,<2C>,<2C>><3E><17>#<23>#<23>H<EFBFBD>-<2D><17>%<25>%<25>'<27><0E>
<EFBFBD><1E>'<27>'<27><08>1<><04> r1c<00><00>0# <00>UR(a<>UR(a<>[(a<>URR S5 [UR
5UlUR RURUR5IShv<01>N nU(aGURR S5 UR R5nSU;a USUl ggURRS5 [S5egggN{7f)z3Perform authentication if credentials are provided.z"Attempting login authentication...NzLogin authentication successful<75> x-api-keyzLogin authentication failed) rrr r=<00>inforr)<00>login<69>get_auth_headersr<00>error<6F> Exception)r-<00>success<73> auth_headerss r.<00> authenticate<74>SnapshotDownloader.authenticatees<><00><00><00> <0F>:<3A>:<3A>$<24>-<2D>-<2D>K<EFBFBD>K<EFBFBD> <10>K<EFBFBD>K<EFBFBD> <1C> <1C>A<> B<> +<2B>D<EFBFBD>L<EFBFBD>L<EFBFBD> 9<>D<EFBFBD> <1D> <20>-<2D>-<2D>3<>3<>D<EFBFBD>J<EFBFBD>J<EFBFBD><04> <0A> <0A>N<>N<>G<EFBFBD><16><14> <0B> <0B> <20> <20>!B<>C<>#<23>0<>0<>A<>A<>C<> <0C><1E>,<2C>.<2E>#/<2F> <0B>#<<3C>D<EFBFBD>L<EFBFBD>/<2F><15> <0B> <0B>!<21>!<21>"?<3F>@<40><1F> =<3D>><3E>><3E>-8<>-<2D>:<3A>O<01>s<00>BD<01>D<04>A<D<01>returnc<00>0<00>URR5nUR(aURUS'U$UR(aHURR 5(a)UR URR 55 U$)z Get headers with authentication.rA)r+<00>copyrr)<00>is_authenticated<65>updaterD)r-r+s r.rD<00>#SnapshotDownloader.get_auth_headersvso<00><00><16>,<2C>,<2C>#<23>#<23>%<25><07> <0F><<3C><<3C>#'<27><<3C><<3C>G<EFBFBD>K<EFBFBD> <20><17><0E><12> <1E> <1E>4<EFBFBD>#4<>#4<>#E<>#E<>#G<>#G<> <13>N<EFBFBD>N<EFBFBD>4<EFBFBD>,<2C>,<2C>=<3D>=<3D>?<3F> @<40><16>r1<00>z
2021-10-18<31>d<00>session<6F>type_ids<64> date_from<6F>date_to<74>cursor<6F>per_pagec
<00><00><># <00>Uc$[R"5RS5nUUS.nU(aXWS'UHnX<>S'M [USS9n URUR
SU 3n
U(a S USS
S 3OS n UR RS U SU
35 UR5n URX<>SS9IShv<01>N n U R5 U R5IShv<01>N nUR(GaJU(a S USS
S 3OS n [SU S35 [SU R35 [S[U R 535 [S[#U535 [S[%U[5(a['UR)55OS35 [S[+URS/5535 [SURSS535 [+URS/55S::a.[S5 [[R,"US[.S95 [S 5 URS/5nURS5nU(a S USS
S 3OS n UR RS![+U5S"U S#35 UR0S$==S%- ss'UsSSS5IShv<01>N $GNGN<>N !,IShv<01>N (df  g=f![2aPnU(a S USS
S 3OS n UR R5S&U SU35 UR0S'==S%- ss'eSnAff=f7f)(a<>
Fetch a single page of snapshots from the API using cursor-based pagination.
Args:
session: aiohttp session
type_ids: List of type IDs to filter by
date_from: Start date in YYYY-MM-DD format
date_to: End date in YYYY-MM-DD format
cursor: Cursor for pagination (None for first page)
per_page: Number of items per page
Returns:
Dictionary containing the API response
N<EFBFBD>%Y-%m-%d)<02>dateFrom<6F>dateTorWz typeIDs[]T)<01>doseq<65>?zcursor: <20>z...z
first pagezFetching snapshots (z): <20><00>r+<00>timeoutz
=== SERVER RESPONSE DEBUG (z) ===z Status Code: z Headers: zResponse Type: zResponse Keys: z
Not a dictz Posts count: <20>postszCursor: <20>None<6E>zFull Response Data:<3A><00><02>indent<6E>defaultz2==================================================z
Retrieved z snapshots (<28>)r"<00>zFailed to fetch snapshots (r#)r<00>now<6F>strftimer
rr&r=rBrD<00>get<65>raise_for_status<75>jsonr<00>print<6E>status<75>dictr+<00>type<70>
isinstance<EFBFBD>list<73>keys<79>len<65>dumps<70>strr,rFrE)r-rSrTrUrVrWrX<00>params<6D>type_id<69> query_string<6E>url<72> page_infor+<00>response<73>datar<00> cursor_value<75>es r.<00>fetch_snapshots_page<67>'SnapshotDownloader.fetch_snapshots_page<67>s
<00><00><00>( <13>?<3F><1E>l<EFBFBD>l<EFBFBD>n<EFBFBD>-<2D>-<2D>j<EFBFBD>9<>G<EFBFBD>"<22><1D>
<EFBFBD><06> <12>%<25>8<EFBFBD> <1C> <20>G<EFBFBD>#*<2A>Y<EFBFBD> <20> <20>!<21><16>t<EFBFBD>4<> <0C><15><1C><1C><0E>t<EFBFBD>6<>6<>7<>q<EFBFBD><1C><0E>G<><03>39<33>h<EFBFBD>v<EFBFBD>c<EFBFBD>r<EFBFBD>{<7B>m<EFBFBD>3<EFBFBD>/<2F>|<7C> <09> <0C> <0B> <0B><18><18>/<2F> <09>{<7B>#<23>c<EFBFBD>U<EFBFBD>C<>D<><16>'<27>'<27>)<29><07># <12><1E>{<7B>{<7B>3<EFBFBD><12>{<7B>D<>D<><08><18>)<29>)<29>+<2B>%<25>]<5D>]<5D>_<EFBFBD>,<2C><04><18>?<3F>?<3F>?<3F>?E<>(<28>6<EFBFBD>#<23>2<EFBFBD>;<3B>-<2D>s<EFBFBD> ;<3B><<3C>I<EFBFBD><19>9<>)<29><1B>E<EFBFBD>J<>K<><19>M<EFBFBD>(<28>/<2F>/<2F>):<3A>;<3B><<3C><19>I<EFBFBD>d<EFBFBD>8<EFBFBD>+;<3B>+;<3B>&<<3C>%=<3D>><3E>?<3F><19>O<EFBFBD>D<EFBFBD><14>J<EFBFBD><<3C>8<>9<><19>O<EFBFBD><1A>D<EFBFBD>RV<52>AW<41>AW<41>D<EFBFBD><14><19><19><1B>,=<3D>]i<>+j<>k<>l<><19>M<EFBFBD>#<23>d<EFBFBD>h<EFBFBD>h<EFBFBD>w<EFBFBD><02>.C<>*D<>)E<>F<>G<><19>H<EFBFBD>T<EFBFBD>X<EFBFBD>X<EFBFBD>h<EFBFBD><06>%?<3F>$@<40>A<>B<><1A>4<EFBFBD>8<EFBFBD>8<EFBFBD>G<EFBFBD>R<EFBFBD>0<>1<>Q<EFBFBD>6<><1D> 3<>5<><1D>d<EFBFBD>j<EFBFBD>j<EFBFBD><14>a<EFBFBD><13>E<>F<><19>(<28>O<EFBFBD>!<21>H<EFBFBD>H<EFBFBD>W<EFBFBD>b<EFBFBD>1<> <09>#<23>x<EFBFBD>x<EFBFBD><08>1<> <0C>;A<>h<EFBFBD>v<EFBFBD>c<EFBFBD>r<EFBFBD>{<7B>m<EFBFBD>3<EFBFBD>7<>|<7C> <09><14> <0B> <0B> <20> <20>:<3A>c<EFBFBD>)<29>n<EFBFBD>-=<3D>\<5C>)<29><1B>TU<54>!V<>W<><14>
<EFBFBD>
<EFBFBD>?<3F>+<2B>q<EFBFBD>0<>+<2B><1C>9E<01>D<>D<>,<2C>E<01>D<>D<>D<><44><<19> <12>7=<3D>(<28>6<EFBFBD>#<23>2<EFBFBD>;<3B>-<2D>s<EFBFBD>3<><<3C>I<EFBFBD> <10>K<EFBFBD>K<EFBFBD> <1D> <1D> ;<3B>I<EFBFBD>;<3B>c<EFBFBD>!<21><13>M<> N<> <10>J<EFBFBD>J<EFBFBD>(<28> )<29>Q<EFBFBD> .<2E> )<29> <11><>  <12>s<EFBFBD><00>B/M<01>2K;<00>K<06>K;<00>
$K!<03>.K<06>/GK!<03> K;<00>K<06>K;<00>M<01>K;<00>K!<03>K;<00>!K8<07>'K* <0C>( K8<07>4K;<00>7M<01>8K;<00>;
M<03>A M<03>M<03>M<01> max_pagesc
<00><00>z# <00>/nSnSnURRSUSU=(d S35 US- nU(a$X<>:<3A>aURRSU35 O<>URXX4U5IShv<01>N n U RS/5n
U RS 5n U
(dURRS
5 O<>UR U
5 UR
S ==[ U
5- ss'URRS US [ U
5S[ U5S35 U (dURRS5 OU nGM"URRS[ U535 U$GN![a,n URRSUS U 35 Sn A M]Sn A ff=f7f)a]
Fetch all snapshots across all pages using cursor-based pagination.
Args:
session: aiohttp session
type_ids: List of type IDs to filter by
date_from: Start date in YYYY-MM-DD format
date_to: End date in YYYY-MM-DD format
max_pages: Maximum number of pages to fetch (for testing)
Returns:
List of all snapshot dictionaries
NrzStarting snapshot fetch from <20> to rlrkzReached maximum pages limit: rcrWz+No more snapshots found (empty posts array)r!zPage <20>: z snapshots (total: rjz&Reached last page (no cursor returned)zError fetching page zTotal snapshots fetched: ) r=rBr<>rn<00>extendr,rxrFrE) r-rSrTrUrVr<><00> all_snapshotsrW<00>
page_countr<EFBFBD>r<00>
new_cursorr<EFBFBD>s r.<00>fetch_all_snapshots<74>&SnapshotDownloader.fetch_all_snapshots<74>s<><00><00><00>$<1B> <0A><15><06><16>
<EFBFBD> <0C> <0B> <0B><18><18>8<><19> <0B>4<EFBFBD><07>HX<48>SX<53>GY<47>Z<>[<5B><12> <16>!<21>O<EFBFBD>J<EFBFBD><18>Z<EFBFBD>3<><14> <0B> <0B> <20> <20>#@<40><19> <0B>!L<>M<><15> <16>!%<25>!:<3A>!:<3A><1B>y<EFBFBD>6<EFBFBD>"<12><12><08>
%<25>L<EFBFBD>L<EFBFBD><17>"<22>5<> <09>%<25>\<5C>\<5C>(<28>3<>
<EFBFBD> <20><18>K<EFBFBD>K<EFBFBD>$<24>$<24>%R<>S<><19><1D>$<24>$<24>Y<EFBFBD>/<2F><14>
<EFBFBD>
<EFBFBD>,<2C>-<2D><13>Y<EFBFBD><1E>?<3F>-<2D><14> <0B> <0B> <20> <20>5<EFBFBD><1A> <0C>B<EFBFBD>s<EFBFBD>9<EFBFBD>~<7E>6F<36>FY<46>Z]<5D>^k<>Zl<5A>Ym<59>mn<6D>!o<>p<>"<22><18>K<EFBFBD>K<EFBFBD>$<24>$<24>%M<>N<><19>$<24><06>?<13>J <0A> <0B> <0B><18><18>4<>S<EFBFBD><1D>5G<35>4H<34>I<>J<><1C><1C>=<12><>2<1D> <16><14> <0B> <0B>!<21>!<21>$8<><1A> <0C>B<EFBFBD>q<EFBFBD>c<EFBFBD>"J<>K<><15><> <16>s\<00>A"F;<01>%F<00>;E?<04><A F<00>F;<01>B
F<00>F;<01>F<00>,F;<01>?F<00>
F8<03> !F3<03>-F;<01>3F8<03>8F;<01>snapshotc<00><00>@# <00>URSS5nURSS5nURSS5nURSS5nU(aURU5OSnURS 05nU(aURS
S5OSn U(aURS S5OSn
U(a)[R"U S U
3R 55OSn URS 05n U (aU RS
S5OSn U (aI[R"U RS
S5S U RS S53R 55OSnU (a4U (a-[R"U SU S U
3R 55nO[R"SU35nURS05nU(a&[R"URSS55OSnSUSUSUSUSUSSURSS5(aSOSS3SU S:waSU S 3OSS!U(aS"US 3OSS!U(aS#US 3OSS$U(aUOS%S&UR X5IS'hv<01>N S!UR U5S(3nUR 5$N)7f))z<>
Format a single snapshot as HTML.
Args:
snapshot: Snapshot dictionary from API
Returns:
HTML string for the snapshot
<EFBFBD>id<69>unknown<77>notes<65><00> startTimert<00>Snapshot<6F>Unknown<77>author<6F>forename<6D>surname<6D> <20>childz by z Snapshot <20>activity<74>namez(
<div class="snapshot" id="snapshot-zP">
<div class="snapshot-header">
<h3 class="snapshot-title">z\</h3>
<div class="snapshot-meta">
<span class="snapshot-id">ID: z:</span>
<span class="snapshot-type">Type: z:</span>
<span class="snapshot-date">Date: z</span>
z<span class="snapshot-signed"><3E>signedFu
✓ Signedu ⏳ Pendingz</span>zW
</div>
</div>
<div class="snapshot-content">
u*<div class="snapshot-author">👤 Author: z</div>z
u(<div class="snapshot-child">👶 Child: u.<div class="snapshot-activity">🎯 Activity: z\
<div class="snapshot-description">
<div class="notes-content">z <em>No description provided</em>z'</div>
</div>
Nz#
</div>
</div>
)rn<00> format_date<74>html<6D>escape<70>strip<69>format_snapshot_media<69>format_snapshot_metadata)r-r<>rS<00> snapshot_id<69>content<6E>
start_time<EFBFBD> snapshot_type<70>
start_dater<EFBFBD><00>author_forename<6D>author_surname<6D> author_namer<65><00>child_forename<6D>
child_name<EFBFBD>titler<65><00> activity_name<6D> html_contents r.<00>format_snapshot_html<6D>'SnapshotDownloader.format_snapshot_htmls<><00><00><00><1F>l<EFBFBD>l<EFBFBD>4<EFBFBD><19>3<> <0B><1A>,<2C>,<2C>w<EFBFBD><02>+<2B><07><1D>\<5C>\<5C>+<2B>r<EFBFBD>2<>
<EFBFBD> <20> <0C> <0C>V<EFBFBD>Z<EFBFBD>8<> <0A>6@<01>T<EFBFBD>%<25>%<25>j<EFBFBD>1<>Y<EFBFBD>
<EFBFBD><1A><1C><1C>h<EFBFBD><02>+<2B><06>8><3E>&<26>*<2A>*<2A>Z<EFBFBD><12>4<>B<EFBFBD><0F>6<<3C><16><1A><1A>I<EFBFBD>r<EFBFBD>2<>"<22><0E>TZ<54>d<EFBFBD>k<EFBFBD>k<EFBFBD>_<EFBFBD>$5<>Q<EFBFBD>~<7E>6F<36>"G<>"M<>"M<>"O<>P<>`i<> <0B><19> <0C> <0C>W<EFBFBD>b<EFBFBD>)<29><05>6;<3B><15><19><19>:<3A>r<EFBFBD>2<><12><0E>gl<67>T<EFBFBD>[<5B>[<5B>E<EFBFBD>I<EFBFBD>I<EFBFBD>j<EFBFBD>"<22>$=<3D>#><3E>a<EFBFBD><05> <09> <09>)<29>UW<55>@X<>?Y<>!Z<>!`<60>!`<60>!b<>c<>rt<72>
<EFBFBD> <1A>o<EFBFBD><18>K<EFBFBD>K<EFBFBD>><3E>"2<>$<24><EFBFBD>6G<36>q<EFBFBD><1E>HX<48> Y<> _<> _<> a<>b<>E<EFBFBD><18>K<EFBFBD>K<EFBFBD>)<29>K<EFBFBD>=<3D> 9<>:<3A>E<EFBFBD><1C><<3C><<3C>
<EFBFBD>B<EFBFBD>/<2F><08>AI<41><04> <0B> <0B>H<EFBFBD>L<EFBFBD>L<EFBFBD><16><12>$<<3C>=<3D>r<EFBFBD> <0A>(<28>(3<>}<7D>5(<28>(-<2D>w<EFBFBD>//<2F>/:<3A>m<EFBFBD><3<>3@<40>/<2F>B3<>3=<3D>,<2C>?<11>1<>(<28>,<2C>,<2C>x<EFBFBD>Y^<5E>B_<42>B_<42>,<2C>er<65>1s<31>sz<73>{<7B>|<7C>} <0A>
R]<01>`i<>Qi<51>9<>+<2B><1D>f<EFBFBD> M<>oq<6F> r<>s <0A>NX<4E>7<>
<EFBFBD>|<7C>6<EFBFBD> J<>^`<60> a<>b <0A>Wd<57>=<3D>m<EFBFBD>_<EFBFBD>F<EFBFBD> S<>jl<6A> m<>n,<2C>8?<3F>G<EFBFBD>Df<44>+g<>h <0A><18>-<2D>-<2D>h<EFBFBD>@<40> @<40> A<>B <0A> <11> *<2A> *<2A>8<EFBFBD> 4<> 5<>6 <09>- <0C> <0C>6<1C>!<21>!<21>#<23>#<23> A<01>s<00>I0J<01>2J.<2E>3*Jc <00><00>F# <00>SnURS/5nUVs/sHoURS5S:XdMUPM nnU(Ga7US- nUS- nUS- nUGHnURX'5IShv<01>N n[R"URS S
55n U(aIUS - nUS US U S3- nUSU S3- nUSUR URSS55S3- nUS- nM<>URS5(a!UR
SURS5S3OSn
U
(dM<>US - nUS U
S U S3- nUSU S3- nUSUR URSS55S3- nUS- nGM US- nUVs/sHoURS5S:wdMUPM n nU (a<>US- nUS- nUS- nU H<>n URX,5IShv<01>N n[R"U RS S55n U RSS5nU(aUSUS U S!US"3- nMlU RS5(a!UR
SU RS5S3OSnU(aUSUS U S!US#3- nM<>US$U S!US%3- nM<> US&- nU$s snfGN's snfN<>7f)'z(Format media attachments for a snapshot.r<><00>mediart<00>imagez<div class="snapshot-images">
u<h4>📸 Images:</h4>
z<div class="image-grid">
N<EFBFBD>fileName<6D>Imagez<div class="image-item">
z <img src="z" alt="z" loading="lazy">
z <p class="image-caption">z</p>
z! <p class="image-meta">Updated: <20>updated<65></div>
r<EFBFBD><00>
/v1/media/<2F>/fullz (online)</p>
<EFBFBD></div>
</div>
z#<div class="snapshot-attachments">
u<h4>📎 Attachments:</h4>
z<ul class="attachment-list">
<EFBFBD>
Attachment<EFBFBD>mimeTyper<65>z <li><a href="z" target="_blank">z (z )</a></li>
z) - online</a></li>
z <li>z)</li>
z </ul>
</div>
)rn<00>download_media_filer<65>r<>r<>r)r-r<>rS<00>
media_htmlr<EFBFBD><00>m<>imagesr<73><00>
local_path<EFBFBD>
image_name<EFBFBD> image_url<72> attachments<74>
attachment<EFBFBD>attachment_name<6D>attachment_type<70>attachment_urls r.r<><00>(SnapshotDownloader.format_snapshot_mediaZs@<00><00><00><17>
<EFBFBD><19> <0C> <0C>W<EFBFBD>b<EFBFBD>)<29><05>"<22>?<3F>U<EFBFBD><01>e<EFBFBD>e<EFBFBD>F<EFBFBD>m<EFBFBD>w<EFBFBD>&><3E>!<21>U<EFBFBD><06>?<3F> <11> <16>;<3B> ;<3B>J<EFBFBD> <16>3<> 3<>J<EFBFBD> <16>6<> 6<>J<EFBFBD><1F><05>#'<27>#;<3B>#;<3B>G<EFBFBD>#K<>K<>
<EFBFBD>!<21>[<5B>[<5B><15><19><19>:<3A>w<EFBFBD>)G<>H<>
<EFBFBD><1D><1E>$><3E>?<3F>J<EFBFBD><1E>L<EFBFBD><1A> <0C>G<EFBFBD>J<EFBFBD><<3C>Ob<4F>"c<>c<>J<EFBFBD><1E>$?<3F>
<EFBFBD>|<7C>6<EFBFBD>"R<>R<>J<EFBFBD><1E>$E<>d<EFBFBD>FV<46>FV<46>W\<5C>W`<60>W`<60>aj<61>ln<6C>Wo<57>Fp<46>Eq<45>qw<71>"x<>x<>J<EFBFBD><1E>H<EFBFBD>-<2D>J<EFBFBD>V[<01>U^<5E>U^<5E>_c<5F>Ud<55>Ud<55>4<EFBFBD><<3C><<3C>.<2E>
<EFBFBD>5<EFBFBD>9<EFBFBD>9<EFBFBD>T<EFBFBD>?<3F>:K<>5<EFBFBD> Q<>jl<6A>I<EFBFBD> <20>y<EFBFBD>"<22>(B<>C<>
<EFBFBD>"<22> <0C>Y<EFBFBD>K<EFBFBD>w<EFBFBD>z<EFBFBD>l<EFBFBD>Re<52>&f<>f<>
<EFBFBD>"<22>(C<>J<EFBFBD><<3C><EFBFBD>&_<>_<>
<EFBFBD>"<22>(I<>$<24>JZ<4A>JZ<4A>[`<60>[d<>[d<>en<65>pr<70>[s<>Jt<4A>Iu<49>u{<7B>&|<7C>|<7C>
<EFBFBD>"<22><08>1<>
<EFBFBD>' <20>* <17>,<2C> ,<2C>J<EFBFBD>#(<28>D<>%<25>Q<EFBFBD>5<EFBFBD>5<EFBFBD><16>=<3D>G<EFBFBD>+C<>q<EFBFBD>%<25> <0B>D<> <16> <16>@<40> @<40>J<EFBFBD> <16>8<> 8<>J<EFBFBD> <16>:<3A> :<3A>J<EFBFBD>)<29>
<EFBFBD>#'<27>#;<3B>#;<3B>G<EFBFBD>#P<>P<>
<EFBFBD>"&<26>+<2B>+<2B>j<EFBFBD>n<EFBFBD>n<EFBFBD>Z<EFBFBD><1C>.V<>"W<><0F>",<2C>.<2E>.<2E><1A>Y<EFBFBD>"G<><0F><1D><1E>O<EFBFBD>J<EFBFBD><<3C>?Q<>Ra<52>Qb<51>bd<62>et<65>du<64>vB<02>#C<02>C<02>J<EFBFBD>`j<01>_m<5F>_m<5F>nr<6E>_s<5F>_s<5F><04> <0C> <0C>~<7E>Z<EFBFBD>
<EFBFBD><0E><0E>t<EFBFBD>@T<>?U<>UZ<55>%[<5B>y{<7B>N<EFBFBD>%<25>"<22><0F><0E>7G<37>GY<47>Zi<5A>Yj<59>jl<6A>m|<7C>l}<7D>~S<02>'T<02>T<02>
<EFBFBD>"<22><06><EFBFBD>.?<3F>r<EFBFBD>/<2F>AR<41>RZ<52>&[<5B>[<5B>
<EFBFBD>*<2A> <17>+<2B> +<2B>J<EFBFBD><19><19><>m@<01>L<01><>,E<01>Q<01>sM<00>J!<01>J<04>J<04>3J!<01>0J<06>1B8J!<01>-AJ!<01>J<04>J<04>$1J!<01>J<06>CJ!<01>J!c
<00><><00>SnUS- nUS- n/SQnUHupEURU5nU(dM[U[5(aSRSU55nUS- nUSUS [R
"[ U55S
3- nUS - nM<> US - nUS - nUS- nU[R
"[R"US[ S95- nUS- nUS- nUS- nU$)z*Format additional metadata for a snapshot.z <div class="snapshot-metadata">
u(<h4> Additional Information:</h4>
z<div class="metadata-grid">
))<02>code<64>Code)<02>frameworkIndicatorCountzFramework Indicators)r<>z Signed Status)rt<00>Typez, c3<00>8# <00>UHn[U5v<00> M g7f)N)rz)<02>.0<EFBFBD>vs r.<00> <genexpr><3E>>SnapshotDownloader.format_snapshot_metadata.<locals>.<genexpr><3E>s<00><00><00>%<<3C>e<EFBFBD><11>c<EFBFBD>!<21>f<EFBFBD>f<EFBFBD>e<EFBFBD>s<00>z<div class="metadata-item">
z
<strong>z :</strong> <20>
r<EFBFBD>z<details class="raw-data">
u&<summary>🔍 Raw JSON Data</summary>
z<pre class="json-data">
rfrgz
</pre>
z </details>
r<EFBFBD>) rnrurv<00>joinr<6E>r<>rzrpry)r-r<><00> metadata_html<6D>metadata_fields<64>field<6C>label<65>values r.r<><00>+SnapshotDownloader.format_snapshot_metadata<74>s <00><00>;<3B> <0A><15>D<>D<> <0A><15>8<>8<> <0A>
<EFBFBD><0F>,<2C>L<EFBFBD>E<EFBFBD><1C>L<EFBFBD>L<EFBFBD><15>'<27>E<EFBFBD><14>u<EFBFBD><1D>e<EFBFBD>T<EFBFBD>*<2A>*<2A> <20>I<EFBFBD>I<EFBFBD>%<<3C>e<EFBFBD>%<<3C><<3C>E<EFBFBD><1D>#@<40>A<> <0A><1D>:<3A>e<EFBFBD>W<EFBFBD>K<EFBFBD><04> <0B> <0B>C<EFBFBD>PU<50>J<EFBFBD>@W<>?X<>XZ<58>![<5B>[<5B> <0A><1D>8<EFBFBD>,<2C> <0A>,<2C> <16>7<>7<> <0A><15>B<>B<> <0A><15>4<>4<> <0A><15><14><1B><1B>T<EFBFBD>Z<EFBFBD>Z<EFBFBD><08><11>C<EFBFBD>%P<>Q<>Q<> <0A><15><1C>%<25> <0A><15><1E>'<27> <0A><15>+<2B>+<2B> <0A><1C>r1<00> date_stringc<00><><00>[R"URSS55nURS5$! Us$=f)z!Format a date string for display.<2E>Zz+00:00<30>%Y-%m-%d %H:%M:%S)r<00> fromisoformat<61>replacerm)r-r<><00>dts r.r<><00>SnapshotDownloader.format_date<74>sA<00><00> <1F><19>'<27>'<27> <0B>(;<3B>(;<3B>C<EFBFBD><18>(J<>K<>B<EFBFBD><15>;<3B>;<3B>2<>3<> 3<><33> <1F><1E> <1E>s<00>69<00>?r<>c<00><00><># <00>URS5nU(dgURSSU35nURU5nURU- nUR5(aSU3$URSUS3nUR
R SU35 UR5nURXgS S
9IShv<01>N nUR5 [R"US 5IShv<01>N n URRS 5Shv<01>N n
U RU
5IShv<01>N M$NsNEN#N
SSS5IShv<01>N O!,IShv<01>N (df  O=fUR
R S U35 SU3sSSS5IShv<01>N $!,IShv<01>N (df  g=f![a+n UR
RSUSU 35 Sn A gSn A ff=f7f)z<>
Download a media file to the assets folder.
Args:
session: aiohttp session for making requests
media: Media dictionary from API
Returns:
Relative path to downloaded file, or None if download failed
r<EFBFBD>Nr<4E><00>media_zassets/r<>r<>zDownloading media file: r`ra<00>wbi zSuccessfully downloaded media: zFailed to download media r<>)rn<00>_sanitize_filenamer(<00>existsrr=rBrDro<00>aiofiles<65>openr<6E><00> iter_chunked<65>writerFrE) r-rSr<><00>media_id<69>filename<6D>filepath<74> download_urlr+r<><00>f<>chunkr<6B>s r.r<><00>&SnapshotDownloader.download_media_file<6C>s<><00><00><00><19>9<EFBFBD>9<EFBFBD>T<EFBFBD>?<3F><08><17><17><18>9<EFBFBD>9<EFBFBD>Z<EFBFBD>6<EFBFBD>(<28><1A>)<<3C>=<3D><08><17>*<2A>*<2A>8<EFBFBD>4<><08><18>?<3F>?<3F>X<EFBFBD>-<2D><08> <13>?<3F>?<3F> <1C> <1C><1C>X<EFBFBD>J<EFBFBD>'<27> '<27><1F>,<2C>,<2C><1E>z<EFBFBD>(<28><1A>5<EFBFBD>A<> <0C> <18> <10>K<EFBFBD>K<EFBFBD> <1C> <1C>7<><08>z<EFBFBD>B<> C<><1A>+<2B>+<2B>-<2D>G<EFBFBD><1E>{<7B>{<7B><<3C>"<22>{<7B>M<>M<>QY<51><18>)<29>)<29>+<2B>$<24>=<3D>=<3D><18>4<EFBFBD>8<>8<>A<EFBFBD>'/<2F>'7<>'7<>'D<>'D<>T<EFBFBD>'J<>-<2D>e<EFBFBD><1F>g<EFBFBD>g<EFBFBD>e<EFBFBD>n<EFBFBD>,<2C>,<2C> N<01>9<>-<2D>,<2C>(K<01>9<>8<>8<>8<>8<>8<><38><15> <0B> <0B> <20> <20>#B<>8<EFBFBD>*<2A>!M<>N<>!<21><18>
<EFBFBD>+<2B>N<01>M<>M<>M<>M<>M<><4D><19> <18> <10>K<EFBFBD>K<EFBFBD> <1D> <1D> 9<>(<28><1A>2<EFBFBD>a<EFBFBD>S<EFBFBD>I<> J<><17><> <18>s<EFBFBD><00>A;G0<01>>AF8<00>D4<06>F8<00>,F<03>0D6<08>1F<03>4E<05>D<<06>D8
<EFBFBD>D<<06>E<05>-D:
<EFBFBD>.E<05>4F8<00>6F<03>8D<<06>:E<05><E<05>= F<03>E <06> F<03>E& <09>E<0E> E& <09>")F<03> F8<00>F<06>F8<00>G0<01>F5<07>$F' <0C>% F5<07>1F8<00>4G0<01>5F8<00>8
G-<03>!G(<03>#G0<01>(G-<03>-G0r<>c<00>t<00>SnUHnURUS5nM URS5nU(dSnU$)z1Sanitize filename by removing invalid characters.z <>:"/\|?*<2A>_z. <20>
media_file)r<>r<>)r-r<><00> invalid_chars<72>chars r.r<><00>%SnapshotDownloader._sanitize_filename<6D>sD<00><00>%<25> <0A>!<21>D<EFBFBD><1F>'<27>'<27><04>c<EFBFBD>2<>H<EFBFBD>"<22><1C>><3E>><3E>$<24>'<27><08><18>#<23>H<EFBFBD><17>r1c<00><00>d# <00>[USSS9nSUSUS3nURU- nURXBU5IShv<01>N n[USS S
9nUR U5 SSS5 UR
R S U35 URS ==S - ss'U$N`!,(df  NG=f7f)z<>
Generate an HTML file containing all snapshots.
Args:
snapshots: List of snapshot dictionaries
date_from: Start date
date_to: End date
Returns:
Path to the generated HTML file
c<00>&<00>URSS5$)Nr<4E>r<>)rn)<01>xs r.<00><lambda><3E>7SnapshotDownloader.generate_html_file.<locals>.<lambda>s<00><00>!<21>%<25>%<25> <0B>R<EFBFBD>0r1T)<02>key<65>reverse<73>
snapshots_<EFBFBD>_to_z.htmlN<6C>wzutf-8)<01>encodingzGenerated HTML file: r$rk)<08>sortedr<00>generate_html_templater<65>r<>r=rBr,) r-rrUrV<00>sorted_snapshotsr<73>r<>r<>r<>s r.<00>generate_html_file<6C>%SnapshotDownloader.generate_html_files<><00><00><00>"<22> <15>0<><18>
<EFBFBD><18> <20> <09>{<7B>$<24>w<EFBFBD>i<EFBFBD>u<EFBFBD>=<3D><08><17>?<3F>?<3F>X<EFBFBD>-<2D><08>"<22>8<>8<>9I<39>V]<5D>^<5E>^<5E> <0C><12>(<28>C<EFBFBD>'<27> 2<>a<EFBFBD> <0A>G<EFBFBD>G<EFBFBD>L<EFBFBD> !<21>3<> <0A> <0B> <0B><18><18>0<><18>
<EFBFBD>;<3B><<3C> <0C>
<EFBFBD>
<EFBFBD>$<24>%<25><11>*<2A>%<25><17><0F>_<01>3<> 2<>s(<00>:B0<01>B<04>B0<01> B<03>AB0<01>
B-<07>)B0c<00><00><># <00>Sn[R"SSS9n[R"SS9n[R"XVS9IShv<01>N nUR 5IShv<01>N UH%nUR X<>5IShv<01>N n XI- nUS- nM' SSS5IShv<01>N S US
US UR 5S US
US [U5S[R"5RS5SUS[U5SURSSUR5S3n
U
$N<>N<>N<>N<>!,IShv<01>N (df  N<>=f7f)z$Generate the complete HTML template.r<>rRr`<00><02>limit<69>limit_per_host<73><01>total<61><02> connectorrbNz
z<EFBFBD><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ParentZone Snapshots Backup - r<>z</title>
<style>
z<>
</style>
</head>
<body>
<div class="container">
<header class="page-header">
<h1>ParentZone Snapshots Backup</h1>
<div class="date-range">
<strong>Period:</strong> zu
</div>
<div class="stats">
<span class="stat-item">Total Snapshots: <strong>zL</strong></span>
<span class="stat-item">Generated: <strong>r<>aY</strong></span>
</div>
</header>
<nav class="navigation">
<button onclick="toggleAllDetails()">Toggle All Details</button>
<input type="text" id="searchBox" placeholder="Search snapshots..." onkeyup="searchSnapshots()">
</nav>
<main class="snapshots-container">
z<>
</main>
<footer class="page-footer">
<p>Generated by ParentZone Snapshot Downloader</p>
<p>Total snapshots: z | Pages fetched: r"z8</p>
</footer>
</div>
<script>
z
</script>
</body>
</html>) <0A>aiohttp<74> TCPConnector<6F> ClientTimeout<75> ClientSessionrIr<><00>get_css_stylesrxrrlrmr,<00>get_javascript_functions) r-rrUrV<00>snapshots_htmlrrbrSr<><00> snapshot_html<6D> html_templates r.r <00>)SnapshotDownloader.generate_html_template(sv<00><00><00>
<1C><0E><1C>(<28>(<28>s<EFBFBD>2<EFBFBD>F<> <09><19>'<27>'<27>b<EFBFBD>1<><07><1A>(<28>(<28>9<EFBFBD>N<>N<>RY<52><16>#<23>#<23>%<25> %<25> %<25>%<25><08>&*<2A>&?<3F>&?<3F><08>&R<> R<> <0A><1E>/<2F><0E><1E>&<26>(<28><0E>&<26> O<01>N<>*<2A>
+4<><1B>D<EFBFBD><17> <09>B <09> <0A> <1C> <1C> <1E><1F> *<2A>+4<><1B>D<EFBFBD><17> <09>BB<01>CF<01>i<EFBFBD>.<2E>AQ<41>R<<3C><D<>L<EFBFBD>L<EFBFBD>N<EFBFBD><S<><S<>Tg<54><h<>;i<>
j <0A><1C> <1C>!<21>
"%<25>Y<EFBFBD><1E> 0<>0B<30>4<EFBFBD>:<3A>:<3A>o<EFBFBD>C^<5E>B_<42>` <09>
<0E> &<26> &<26> (<28>)<29>*<08>O* <0B> <0A>X<1D><1C>mO<01> %<25>!S<01> O<01>N<>N<>N<>sm<00>AE<01>D!<06>E<01>
D)<03>D#<06>D)<03><D%<08>=D)<03> E<01>D'<04>BE<01>#D)<03>%D)<03>'E<01>)E<07>/D2 <0C>0 E<07><Ec<00><00>g)z!Get CSS styles for the HTML file.ai
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
line-height: 1.6;
color: #495057;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 50%, #f1f3f4 100%);
min-height: 100vh;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.page-header {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
padding: 30px;
border-radius: 15px;
margin-bottom: 30px;
box-shadow: 0 4px 20px rgba(108, 117, 125, 0.15);
border: 2px solid #dee2e6;
text-align: center;
}
.page-header h1 {
color: #495057;
margin-bottom: 10px;
font-size: 2.5em;
font-weight: 600;
}
.date-range {
font-size: 1.2em;
color: #6c757d;
margin-bottom: 15px;
}
.stats {
display: flex;
justify-content: center;
gap: 20px;
flex-wrap: wrap;
}
.stat-item {
color: #495057;
font-size: 1.1em;
}
.navigation {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
padding: 20px;
border-radius: 15px;
margin-bottom: 20px;
box-shadow: 0 2px 10px rgba(96, 125, 139, 0.1);
display: flex;
gap: 20px;
align-items: center;
flex-wrap: wrap;
}
.navigation button {
background: linear-gradient(135deg, #6c757d 0%, #495057 100%);
color: white;
border: none;
padding: 10px 20px;
border-radius: 12px;
cursor: pointer;
font-size: 1em;
}
.navigation button:hover {
background: linear-gradient(135deg, #495057 0%, #343a40 100%);
}
.navigation input {
flex: 1;
padding: 10px;
border: 2px solid #e0e0e0;
border-radius: 12px;
font-size: 1em;
}
.navigation input:focus {
outline: none;
border-color: #6c757d;
}
.snapshots-container {
display: flex;
flex-direction: column;
gap: 20px;
}
.snapshot {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-radius: 15px;
padding: 25px;
box-shadow: 0 2px 10px rgba(96, 125, 139, 0.1);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.snapshot:hover {
transform: translateY(-2px);
box-shadow: 0 4px 20px rgba(96, 125, 139, 0.15);
}
.snapshot-header {
margin-bottom: 20px;
border-bottom: 2px solid #e8eaf0;
padding-bottom: 15px;
}
.snapshot-title {
color: #495057;
font-size: 1.8em;
margin-bottom: 10px;
}
.snapshot-meta {
display: flex;
gap: 20px;
flex-wrap: wrap;
color: #6c757d;
font-size: 0.9em;
}
.snapshot-content > div {
margin-bottom: 15px;
}
.snapshot-author, .snapshot-child, .snapshot-activity {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
padding: 10px;
border-radius: 12px;
font-weight: 500;
}
.snapshot-description {
background: linear-gradient(135deg, #fafbfc 0%, #f0f8ff 100%);
padding: 20px;
border-radius: 12px;
border-left: 4px solid #6c757d;
}
.snapshot-description p {
margin-bottom: 10px;
line-height: 1.6;
}
.snapshot-description p:last-child {
margin-bottom: 0;
}
.snapshot-description br {
display: block;
margin: 10px 0;
content: " ";
}
.snapshot-description strong {
font-weight: bold;
color: #495057;
}
.snapshot-description em {
font-style: italic;
color: #6c757d;
}
.snapshot-description .notes-content {
/* Container for HTML notes content */
word-wrap: break-word;
overflow-wrap: break-word;
}
.snapshot-description span[style] {
/* Preserve inline styles from the notes HTML */
}
.snapshot-images {
margin: 20px 0;
}
.image-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-top: 10px;
}
.image-item {
text-align: center;
}
.image-item img {
max-width: 100%;
height: auto;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(96, 125, 139, 0.1);
max-height: 400px;
object-fit: contain;
background: linear-gradient(135deg, #fafbfc 0%, #f0f8ff 100%);
}
.image-caption {
margin-top: 5px;
font-size: 0.9em;
color: #6c757d;
font-weight: 500;
}
.image-meta {
margin-top: 3px;
font-size: 0.8em;
color: #95a5a6;
font-style: italic;
}
.snapshot-attachments {
margin: 20px 0;
}
.attachment-list {
list-style: none;
padding-left: 0;
}
.attachment-list li {
padding: 8px 0;
border-bottom: 1px solid #e8eaf0;
}
.attachment-list a {
color: #495057;
text-decoration: none;
}
.attachment-list a:hover {
text-decoration: underline;
}
.snapshot-metadata {
margin-top: 20px;
background: linear-gradient(135deg, #fafbfc 0%, #f0f8ff 100%);
padding: 20px;
border-radius: 12px;
}
.metadata-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 10px;
margin-top: 10px;
}
.metadata-item {
padding: 8px 0;
}
.raw-data {
margin-top: 15px;
}
.raw-data summary {
cursor: pointer;
font-weight: bold;
padding: 5px 0;
}
.json-data {
background: #2c3e50;
color: #ecf0f1;
padding: 15px;
border-radius: 12px;
overflow-x: auto;
font-size: 0.9em;
margin-top: 10px;
}
.page-footer {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
padding: 20px;
border-radius: 15px;
margin-top: 30px;
text-align: center;
box-shadow: 0 2px 10px rgba(96, 125, 139, 0.1);
color: #6c757d;
}
h4 {
color: #495057;
margin-bottom: 10px;
}
@media (max-width: 768px) {
.container {
padding: 10px;
}
.page-header h1 {
font-size: 2em;
}
.navigation {
flex-direction: column;
}
.stats {
flex-direction: column;
gap: 10px;
}
.snapshot-meta {
flex-direction: column;
gap: 5px;
}
}
<20><00>r-s r.r<00>!SnapshotDownloader.get_css_stylesks<00><00>E r1c<00><00>g)z+Get JavaScript functions for the HTML file.a<>
function toggleAllDetails() {
const details = document.querySelectorAll('details');
const allOpen = Array.from(details).every(detail => detail.open);
details.forEach(detail => {
detail.open = !allOpen;
});
}
function searchSnapshots() {
const searchTerm = document.getElementById('searchBox').value.toLowerCase();
const snapshots = document.querySelectorAll('.snapshot');
snapshots.forEach(snapshot => {
const text = snapshot.textContent.toLowerCase();
if (text.includes(searchTerm)) {
snapshot.style.display = 'block';
} else {
snapshot.style.display = 'none';
}
});
}
// Add smooth scrolling for internal links
document.addEventListener('DOMContentLoaded', function() {
// Add click handlers for snapshot titles to make them collapsible
const titles = document.querySelectorAll('.snapshot-title');
titles.forEach(title => {
title.style.cursor = 'pointer';
title.addEventListener('click', function() {
const content = this.closest('.snapshot').querySelector('.snapshot-content');
if (content.style.display === 'none') {
content.style.display = 'block';
this.style.opacity = '1';
} else {
content.style.display = 'none';
this.style.opacity = '0.7';
}
});
});
});
r"r#s r.r<00>+SnapshotDownloader.get_javascript_functions<6E>s<00><00>* r1c<00><00><># <00>Uc.[R"5[SS9-
RS5nUc$[R"5RS5nURR SUSU35 [ R"SSS 9n[ R"SS
9n[ R"XVS 9IShv<01>N nUR5IShv<01>N URXqX#U5IShv<01>N nU(d-URRS 5 SSS5IShv<01>N gURX<>U5IShv<01>N n UR5 U sSSS5IShv<01>N $N<>N<>NyNHN/N![a$n
URR!S U
35 eSn
A
ff=f!,IShv<01>N (df  g=f7f)a'
Download all snapshots and generate HTML file.
Args:
type_ids: List of type IDs to filter by (default: [15])
date_from: Start date in YYYY-MM-DD format
date_to: End date in YYYY-MM-DD format
max_pages: Maximum number of pages to fetch
Returns:
Path to generated HTML file
Nim)<01>daysrZz&Starting snapshot download for period r<>rRr`rrrz+No snapshots found for the specified periodz Error during snapshot download: )rrlrrmr=rBrrrrrIr<><00>warningr <00>print_statisticsrFrE) r-rTrUrVr<>rrbrSr<00> html_filer<65>s r.<00>download_snapshots<74>%SnapshotDownloader.download_snapshots<74>s<><00><00><00> <15> <1C>!<21><1C><1C><1E>)<29><13>*=<3D>=<3D>G<>G<>
<EFBFBD>S<>I<EFBFBD> <12>?<3F><1E>l<EFBFBD>l<EFBFBD>n<EFBFBD>-<2D>-<2D>j<EFBFBD>9<>G<EFBFBD> <0C> <0B> <0B><18><18>A<>)<29><1B>D<EFBFBD>QX<51>PY<50>Z<>[<5B><1C>(<28>(<28>s<EFBFBD>2<EFBFBD>F<> <09><19>'<27>'<27>b<EFBFBD>1<><07><1A>(<28>(<28>9<EFBFBD>N<>N<>RY<52> <16><1A>'<27>'<27>)<29>)<29>)<29>#'<27>":<3A>":<3A><1B>y<EFBFBD>9<EFBFBD>#<12><12> <09>!<21><18>K<EFBFBD>K<EFBFBD>'<27>'<27>(U<>V<><1F>O<01>N<>N<>#'<27>"9<>"9<>)<29>PW<50>"X<>X<> <09><15>%<25>%<25>'<27> <20>)O<01>N<>N<>*<2A><12> O<01>Y<01>O<01><>,<1D> <16><14> <0B> <0B>!<21>!<21>$D<>Q<EFBFBD>C<EFBFBD>"H<>I<><15><> <16><>-O<01>N<>N<>s<EFBFBD><00>B;F><01>=E'<06>>F><01>F$<03>E3<02>E)<06>E3<02>1E+<06>2&E3<02> F><01>$E-<04>%F><01>*E3<02>?E/<06>E3<02> F><01>!E1<06>"F><01>)E3<02>+E3<02>-F><01>/E3<02>1F><01>3
F!<05>=F<05>F!<05>!F$<03>$F;<07>*F- <0C>+ F;<07>7F>c<00>4<00>[S5 [S5 [S5 [SURS35 [SURS35 [SURS 35 [S
URS 35 [S5 g ) zPrint download statistics.z=
============================================================zSNAPSHOT DOWNLOAD STATISTICSz<============================================================zTotal snapshots downloaded: r!zPages fetched: r"zFailed requests: r#zGenerated files: r$N)rqr,r#s r.r*<00>#SnapshotDownloader.print_statisticss<><00><00> <0A>o<EFBFBD><1E> <0A>,<2C>-<2D> <0A>h<EFBFBD><0F> <0A>,<2C>T<EFBFBD>Z<EFBFBD>Z<EFBFBD>8I<38>-J<>,K<>L<>M<> <0A><0F><04>
<EFBFBD>
<EFBFBD>?<3F> ;<3B><<3C>=<3D>><3E> <0A>!<21>$<24>*<2A>*<2A>-><3E>"?<3F>!@<40>A<>B<> <0A>!<21>$<24>*<2A>*<2A>-><3E>"?<3F>!@<40>A<>B<> <0A>h<EFBFBD>r1) rrr(r)rrr+r=rrr&r,)<06>https://api.parentzone.merNNNF)!r<<00>
__module__<EFBFBD> __qualname__<5F>__firstlineno__rz<00>boolr/r*rIrrDrrr<00>intrr<>r<>r<>r<>r<>r<>r r<>r<>rr r rrr,r*<00>__static_attributes__r"r1r.rrs<><00><00>&A<>?C<>MR<4D>7
<EFBFBD><03>7
<EFBFBD> <20>7
<EFBFBD>9<<3C>7
<EFBFBD><1B>7
<EFBFBD>.1<EFBFBD>7
<EFBFBD>FJ<EFBFBD>7
<EFBFBD>r 2<>?<3F>" <17>$<24>s<EFBFBD>C<EFBFBD>x<EFBFBD>.<2E> <17>9;<3B>t<EFBFBD>2><3E>04<30>/3<>14<31> Q<12>'<27>2G<32>2G<32>Q<12>+/<2F><03>9<EFBFBD>Q<12>,/<2F>Q<12>+.<2E>Q<12>*-<2D> Q<12>
,/<2F> Q<12>
:><3E>c<EFBFBD>3<EFBFBD>h<EFBFBD><1E> Q<12>h8:<3A>d<EFBFBD>1=<3D>/3<>15<31> ><1D><17>1F<31>1F<31>><1D>*.<2E>s<EFBFBD>)<29>><1D>+.<2E>><1D>*-<2D>><1D>,/<2F> ><1D>;?<3F>t<EFBFBD>C<EFBFBD><13>H<EFBFBD>~<7E>:N<> ><1D>@D$<24>4<EFBFBD><03>S<EFBFBD><08>><3E>D$<24>G<EFBFBD>La<4C>La<4C>D$<24>fi<66>D$<24>L<<1A>D<EFBFBD><13>c<EFBFBD><18>N<EFBFBD><<1A>W<EFBFBD>Mb<4D>Mb<4D><<1A>gj<67><<1A>| <1D><14>c<EFBFBD>3<EFBFBD>h<EFBFBD><1E> <1D>C<EFBFBD> <1D>D<1F>s<EFBFBD><1F>s<EFBFBD><1F>/<18><17>1F<31>1F<31>/<18>t<EFBFBD>TW<54>Y\<5C>T\<5C>~<7E>/<18>bj<62>kn<6B>bo<62>/<18>b<18>3<EFBFBD><18>3<EFBFBD><18> "<18>$<24>t<EFBFBD>C<EFBFBD><13>H<EFBFBD>~<7E>2F<32>"<18>%(<28>"<18>36<33>"<18>;?<3F>"<18>HA<1D>d<EFBFBD>4<EFBFBD><03>S<EFBFBD><08>><3E>6J<36>A<1D>(+<2B>A<1D>69<36>A<1D>>A<>A<1D>FG <0C><03>G <0C>R
, <0C>#<23>, <0C>\?A<01>T<EFBFBD>04<30>T<EFBFBD>04<30>4<16><14>c<EFBFBD><19>4<16>*-<2D>4<16>?B<>4<16>*-<2D>4<16>9=<3D>4<16>l r1rc <00>:<00>[R"S[RSS9nURSSS9 URSSS9 URS S
S9 URS S S9 URS SS9 URSS[S/SS9 URSSSS9 URS[SS9 URSSSS9 URSSS S!9 UR 5nUR (d.UR(aUR(d [S"5 g#UR(aUR(d [S$5 g#UR(aUR(d [S%5 g#[URURUR URURURS&9nUR(a [S'5 [R"UR!UR"UR$UR&UR(S(95nU(a[S)U35 [S*5 g,[S+5 g,![*a [S-5 g#[,an[S.U35 SnAg#SnAff=f)/Nz6Download ParentZone snapshots and generate HTML reportaU
Examples:
# Download snapshots using API key
python3 snapshot_downloader.py --api-key YOUR_API_KEY
# Download snapshots using login credentials
python3 snapshot_downloader.py --email user@example.com --password password
# Download snapshots for specific date range
python3 snapshot_downloader.py --api-key KEY --date-from 2024-01-01 --date-to 2024-12-31
# Download only first 5 cursor pages (for testing)
python3 snapshot_downloader.py --api-key KEY --max-pages 5
# Specify output directory
python3 snapshot_downloader.py --api-key KEY --output-dir ./my_snapshots
)<03> description<6F>formatter_class<73>epilogz --api-keyzAPI key for authentication)<01>helpz--emailzEmail for login authenticationz
--passwordz!Password for login authenticationz --date-fromz5Start date in YYYY-MM-DD format (default: 1 year ago)z --date-toz.End date in YYYY-MM-DD format (default: today)z
--type-ids<64>+rQz%Type IDs to filter by (default: [15]))<04>nargsrtrir;z --output-dirrz5Directory to save snapshot files (default: snapshots))rir;z --max-pagesz5Maximum number of cursor pages to fetch (for testing))rtr;z --api-urlr0z7ParentZone API URL (default: https://api.parentzone.me)z--debug<75>
store_truez7Enable debug mode with detailed server response logging)<02>actionr;zGError: Either --api-key or both --email and --password must be providedrkz;Error: Password is required when using email authenticationz;Error: Email is required when using password authentication)rrrrrruC🔍 DEBUG MODE ENABLED - Detailed server responses will be printed)rTrUrVr<>u1
✅ Success! Snapshots downloaded and saved to: u8📁 Open the file in your browser to view the snapshotsu7⚠️ No snapshots were found for the specified periodru$
⚠️ Download interrupted by useru ❌ Error: )<17>argparse<73>ArgumentParser<65>RawDescriptionHelpFormatter<65> add_argumentr5<00>
parse_argsrrrrqrrr<00>debug<75>asyncio<69>runr,rTrUrVr<><00>KeyboardInterruptrF)<05>parser<65>args<67>
downloaderr+r<>s r.<00>mainrL$s<><00><00> <15> $<24> $<24>L<> <20><<3C><<3C> <0C><06>F<EFBFBD>, <0B><17><17><13> )<29><18><06>
 <0B><17><17><11> -<2D><18><06>
 <0B><17><17><14> 0<><18><06>
 <0B><17><17><15> D<><18><06>
 <0B><17><17><13> =<3D><18><06>
 <0B><17><17><14><11> <10><13><04> 4<> <18><06> <0B><17><17><16><1B> D<><18><06>  <0B><17><17><15> <10> D<><18><06>  <0B><17><17><13>+<2B> F<><18><06>  <0B><17><17><11><1B> F<><18><06> <12> <1C> <1C> <1E>D<EFBFBD> <10><<3C><<3C><14><1A><1A><04> <0A> <0A> <0A>W<>X<><10> <0B>z<EFBFBD>z<EFBFBD>$<24>-<2D>-<2D> <0A>K<>L<><10> <0B>}<7D>}<7D>T<EFBFBD>Z<EFBFBD>Z<EFBFBD> <0A>K<>L<><10>#<11>'<27><18>L<EFBFBD>L<EFBFBD><1B><EFBFBD><EFBFBD><18>L<EFBFBD>L<EFBFBD><16>*<2A>*<2A><19>]<5D>]<5D><1B>z<EFBFBD>z<EFBFBD> 
<EFBFBD>
<EFBFBD> <10>:<3A>:<3A> <11>W<> X<><1C>K<EFBFBD>K<EFBFBD>
<EFBFBD> =<3D> =<3D><19>]<5D>]<5D><1A>n<EFBFBD>n<EFBFBD><18>L<EFBFBD>L<EFBFBD><1A>n<EFBFBD>n<EFBFBD> !><3E>!
<EFBFBD> <0B> <09> <15> <11>F<>y<EFBFBD>k<EFBFBD>R<> S<> <11>L<> N<><11> <12>K<> L<><10><> <1C><11> <0A>5<>6<><10> <14><11> <0A> <0B>A<EFBFBD>3<EFBFBD><1F> <20><10><><11>s%<00>CI"<00> I"<00>"J<03>9 J<03>J<03>J<03>__main__)<1C>__doc__r@rFrrpr6<00>osrr<00>pathlibr<00>typingrrrr <00> urllib.parser
r r<>r<>r)r <00> ImportErrorrrLr<<00>exitr"r1r.<00><module>rUs~<00><01><04><10><0E><0E> <0B><0E> <09>(<28><18>,<2C>,<2C>+<2B> <0B><0F><17>(<28>
D<18>D<18>N B<11>J <0C>z<EFBFBD><19><08><14><16>L<EFBFBD><1A><>a$<13><17><16>K<EFBFBD><17>s<00>A.<00>.A9<03>8A9