From 20cdfedb85b9d2cfb110343fa3ab989d471cbd61 Mon Sep 17 00:00:00 2001 From: Hitonabi Date: Fri, 24 Jul 2026 19:15:42 +0200 Subject: [PATCH] feat(installer): fertige .exe mit Rippy-Icon + ohne Konsolenfenster (statt .vbs) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commander-Einwand: .vbs ist abgekuendigt (Win11 24H2 Feature-on-Demand) und wird oft als gefaehrlich geflaggt. Loesung: echte .exe. - RippyWorkerSetup.exe (50 KB): install-gui.ps1 via ps2exe kompiliert — eingebettetes Rippy-Disc-Icon (deploy/worker-windows/rippy.ico), kein Konsolenfenster (-noConsole), WinForms (-STA). E2E getestet: Fenster oeffnet, conhost-Zaehler unveraendert (kein Konsolenfenster). Vorgebaut auf Windows (build-exe.ps1) + committet — eine Windows-.exe kann nicht von Linux (Rippy-Host) gebaut werden. WICHTIG: friert KEINE Versionen ein — HandBrake wird zur Laufzeit (GitHub latest) und der Worker-Code live von Rippy geholt; nur bei GUI-Aenderungen neu bauen. - API: GET /worker-setup/windows-exe (FileResponse); Dockerfile kopiert die .exe ins Image. .gitattributes: *.exe/*.ico als binary. - UI (Worker -> Windows): 'Installer herunterladen (.exe)' als Haupt-Weg (generisch, GUI fragt Adresse ab; die einzutragende IP wird als Hinweis angezeigt). .vbs-Erzeugung entfernt. CLI bleibt Profi-Alternative. Co-Authored-By: Claude Fable 5 --- .gitattributes | 2 + deploy/worker-windows/RippyWorkerSetup.exe | Bin 0 -> 50688 bytes deploy/worker-windows/build-exe.ps1 | 59 ++++++++++++++++++ deploy/worker-windows/rippy.ico | Bin 0 -> 5679 bytes docker/api/Dockerfile | 4 ++ docker/api/main.py | 20 +++++- docker/ui/src/components/WorkerVerwaltung.tsx | 46 ++++++-------- 7 files changed, 101 insertions(+), 30 deletions(-) create mode 100644 deploy/worker-windows/RippyWorkerSetup.exe create mode 100644 deploy/worker-windows/build-exe.ps1 create mode 100644 deploy/worker-windows/rippy.ico diff --git a/.gitattributes b/.gitattributes index 5aeb5d5..8510755 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,5 @@ # Shell-Skripte brauchen LF — mit CRLF scheitert der Interpreter im Container # ("/bin/sh^M: bad interpreter"). Wir entwickeln auf Windows, gebaut wird auf Linux. *.sh text eol=lf +*.exe binary +*.ico binary diff --git a/deploy/worker-windows/RippyWorkerSetup.exe b/deploy/worker-windows/RippyWorkerSetup.exe new file mode 100644 index 0000000000000000000000000000000000000000..e35558a669529feb4c2946c3b54d83c0f1c6e4db GIT binary patch literal 50688 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 *g zLRR{Z*7kL@>SBAzO8T+dZR{*EOUg%SKc3rSWa!po(LJMm55-Q@8;UVC$rbZbiwYdSSqGs*EW{8-%rYBICAW%B<)W6OjetEqV! zIUoJB4$HcXMm|zc&9t=4_$2LYM1K5L(no7$vk^mUqsizt-q;wkZ85gjo7`yr?Za{2 z$ilwB4lGnK!K*PB^yI6Wu=N-3C#NkVv5`=9=DKG^sYjEn09# zgq8%Pm3A6UV&;*x%aSIg3zBI!DQA3*Ve@G6w&fjdT?EBp8k?A1r*YXC!FNLD%ox%Cr>X${AznRqD@&w7JE zZwrP~rZXQ`fb5Yt%b<9=m|ak5#Obn2V@}t=XbrQH3r%ff$J!J!O{))Sor(T9R?ahx zg;KBuyM1X6nrgOVOI>5gJMP#Y$ELK7P01ieX>7`8Z=9c}bq=S3tFleCJCcI;F?NQs zc++`Q(;gdMdF+f}3ds8^7`^L4b#ES4+W)NpOK(p6p=*LI0GgdrILnH;T^qkTI7-4rwfs(aUlH? zWehiaQy$m?RlBQdvZQBqjkGG+bURSi?8ek~W2;KKS1lCEvNfaIuZwK!itHMu*Fmg0 zXijpI0%z^XdTTXn2#rMQK_g@THKNJL(7DkeEeO3dhm+C1)tJxI3l-DI;8oDR!KMV> zB<&uXq!oEa<2;D*tCo;qQt7l^kwJZTL|R}buWSQu2x%DkcEfy|whe?M@g30}cqNBj z)3l7Vmk9JAJNZthiqf!)l)b$p0-q#1OmNNMj>xv*_zo=`XLX%6p?j1b2d+f`mfS3}4n_9j?bo0- z1l^l1DHz-}9EFPt28V}mUlq&%v1vt|C@4C_Qcg&YHMv)Ayv)vtq_;!6*P0GAWp6ns=HuC#0pjN=rw3I%dK)4Q|9VB5d$@l>O6z1~dnZ+kqY&F=LwVY=bRjd5w^;7T@Zk&LsR#*oIIGbmqL zN8lt{F&|7CZ}I6p_b~i;S~xaj!XwRiF^`s566qVzHMAbh#QXZSS^e79s_EzV56#}n zlXJYq*SgwT+q-+$bakAbi1bHk#HrrLv)Ivva~tL@m^GWy5@TyqPg8SKcN_C!5K8U9 zHuI}*^)kj3(6qXp)6&S6oz48&v(uTZ>+D+5*40bz(odJuS2J~2 z`|8yjdV9K>HuNsTdUrE+byLss)467+O{eg5j^NcQs#?YVZJh7f!)}AL6&f1J z*ba^K)Me0jG{etA*NIe+IdS3vBgfisY#37pQ`157ZM8hAkm>u?NrCJ;uHF z!Am4YquwVKu6qr>z@++cA%6?9;YZ_lDZ`M*4UfnIn?=HMlpMhB-QbRLsSRG{2)7h4wDLvQ@mji(Y4$PQu|I48Y z6*PQaED{;g>Rs3fPvI~@5*`eOh4u2RRNOc!B6V4%&DxFy-d0{MHwF=gN<1RQcrtiS2A_1L8oJ;Py#1!b3OLHf=7;e(YP^)eRJtZ>(P3Y)zITbhdRhOb-!0*l z=;Dmje_LMKX3S=SQ|)b`1_|uLQN;8<;b`_wZx#<%Q~Ig2yQ2jqyUak=*}F{ZYgJ=S zmFD(xhftm}TOREjDL9vUJ_2R9%eD&PZa!s+k0gNO6P13Pb)B}RTYRHM-v2vo*_!rN#N7{k zvlDU6F}gjEe>i5VtXq7zJSP|EJJTD49|Q!i!JiL*I9M!j_E_x4AJOqCvM9xq&fX#| zeeXecF^Wq3&BGtjNED9kGCzvKPh`t9oU~<}QdKEa6gwmmYyfnLJ<1xzExx2&hVa)A zc8U7|?c&GEqX_>~nGfhv=YtZn693ay;`tlHPunPbHN!U;z6IzO&5p~!pLFy%Tw=e2 zC^vxO7T*K(iZZ9$X%}0Z%}&3#&^he%im!v>5}G-)a4P}m`^aT;PrgFs9zPPcfhkm~h1!%0OHE&}w6=|vPfpTk$%hM|+Et;5bY#Ap$<*Rdj!Z1WR;4WM6a z^b`LVnDRQqw*l=!DQ<>V_ZCNr?cz`|mG)ZY~80ouh^n0_0>zcBQaQLQT( zh8Q+7+)_poMj770@W%{)$?zpWwV~ zWhz;PAJ8t=P9^@)sYL(v)Vrp-#H)aId=*crYAT4br-Jye2DFQND@gJO3@2+8UZKs` z>>{FV0{o=*C@9x*_$v(W1@wwHwO;_f%TTGLun!OxRXGK^TEXE6!YDJKOMJGH^17>% z%J4meUE=RdnNsyMbz!4VO3zauD#R@K8p3iFkHDvGA_rkBUvszu*d$nk6*rd)v7WIK z!f^ZePGC0p0(?gVECneZQO%MH#Dy#~0ND!SE;F!cj9q77)8Qiu#8;5I2&eUHIPNaQ z6^R+57G)_A40{Vo63SO+>mpJSR-yi=xxLau~M7^ zSRh;q)o-PUqecbdnsVao6vL?1e02ffVs#PVnd)M|4Gaf}VoxA;?f!GsX23%XZ(w*Q z!^au^hT$6wKVVp3A^u8+4Gh~Du4LHDFv;*@hF=0S^EzVr52U@9;gbwsV)ze+9xKJp zWY_{|7wfE4=FJQvfQlHgJ`VU9hF@e#i|tMD9C2I=i+IrSABrO0cMwmFgZQhQUj-%L zT!3&r!_%DCg3|B24R_c7#rZtodkj4}ze8BdAxeeql1=MrT1pHj?D!^M9K9bvw z@Go;CfG_4zY*Rj!xg(!illbl8zVdTupu$LYrS_cSgXGm3;hz(l8o-z}gN88i$&z}t z5msA22HV8g_ncp|{s3`(26n&oX<#t}`?>WO7!CIr*fHyGfQ=Z~ht?M{njSPTuk9sZ z7aG`f+iUom{!<1v$95dpXCx-NY>lw}KN)d-wjTidn}O}IJq_$VgYzca+ZehpuA(}8 z&v~cKt`v()4eU|dFK|!ewFdSaV_%XO?92tu9~qe2?omp_j}2^^y<901&!n;G%2e?) zi8&kXFA7b(V_?heF9Cbcz&6=`Au2`nG+CB&?7snaih+&T8lcnF&{mPRC}YT6}9d$s}yM5)k(>CezInkEP>uWv2K$ee7ejCiQ%3_p7zf zI?hASe~;s?6gN9Qr8J85H55xSuTbWTt@JUgk?u4xFa~>!u><0#jxQ?sw78Zy4~SQQ zoh}vyC3dOvK4r0}4iP3xwnU`T*wbQ(_+c7*L}?PWT(|?`8fPQ!oqW&0?sq<+w1~a4 zrOfX-pH|w0qk(0LA39$X%S54p9drIlStd54IA(s!#n%}7p4jPnRaq{UllvCm6A9P* z$_g=HV3)gGYNz;q8Y@xPh-pih)A=P=mAXOHN=$sm)u3z;{fr$D&$~`V+;5GzR~b9K ziPPa4;UMC+r?Gj;W^uWJIdbPITf|ol%n$5r@qmF%&utXF;^%2BsP>8v(%3v@n+P<^ z9O`oys(s=b16u+q5pjosods;W_&#H#`St1!QP{%ioR8;jRik2+fxVg=1-90}-e>G= z1M}wTh}&*pm3a+HR16x}jJ#pQ4I9{kymNsakeF!8YZOs&fq|`K>>>jjVC-T8`vhZ` z7}!;L$C2(!j8Um?P|pz$NzD0&ydPjh{gHuvkoPpO-xyf&q#s}{@Unr;p7b=Ze;8Oh z;s%AKmFoUUXFuWwg~z}?fw;JsYGBtRE-q>f?AwUb#R3C+3URtvW?+9r+>q!oFyVe0 z*fs+zb^k!@61suSLEJ7u*RfFUorp__OAYKC#3jVF26hqRlHw}{b~ECV;w}Sw0C6et zkbxaV9KIjt-}ffH>9#AwY0R2`Sj}L*{MQ6N+BP_~{Nuo$Vks}>P`W+h7Y0V@_J|h@ zjMD8De>5;kw^wX#BQaNsHTk!wBf{AsvEBK%tLKVojL9B;o;c3wOzfW$6F(`}?dJ)N zrF>F62kd;&VqkBU@3HTPKt)`WPphVz04?I{fL8HsK%2N9&@R3U=n&5UI>oQ^G1!Wi z5O#@R0i|sKRK;n47SRG|6=wosE(3^}3!oyx{}S%tSjo8yVO8t}w1^7O}nB_7oX zU&i6jGyO!#Uts!|ndf#ui?|!mDjuAWu87B(^BLx(R8~Q$6!9$6|G@M&3RKN1-a*(V z3UEz@U6cSSq5@DA)qoaJ%arVV=P;#>c{)xAuVP9M!!67s!%_p1zmMtLnMY@st?iK$ zD4ztyDlR*LPVH#r_O*!{5NozewzLe7BJKi@Djo&2jA=V+WwSL;#`9B7`z)ZsR$;>5 zGhN5RoaRIXW%$Gv{NGdl$hn_P^VxJU)hk-X0;OL4w%QKZD9!?$r)*#tW*B9-i{S{v z0}L-=cqQO*aUEczxS1(UqF#MSy;a%j`<{A4+3ov*dXI9UZxPlEm-rf#9K<$?hr#(r z^%+ietMZ6%u?U0yXLxghHRAieMp46@HR37X-$D7c@34AQ`8(hUzQ}(~jEG!@K8EFh zd7L&+oKmP-b|LJtR0^8wM8)Za4ejFUr-04VJT%TMHYMO3v|Z zl&aaHs6Q`U4)|_ir{zVadsHfUDZ`^mST*<}S{zmGE!uB6qC8ggDNCvP)1pI` zcJ-B_&sl23>yXf-zE^Y|!bSd@0Z;RP&GL$}(%+zj)n5NMK^gY{7vTB+!_d`b3~%>8 z0Lp_5f9!t@W%xDt3&rpK&>q*KP~;c?$x{;rno`br8X2(X{i=RmBqyb zNpD9L(%a4AOz@1T8;e!zCF+I6cI8U-y5dI2ycwykQ|~QyS+7%n$a0=TEZM_xaVz96 zvmRAGC|(KZDp_egA__}h!|biH;k-1IlE+o^?(>CIU8_y z$zkIv~g$q?XA89obmkNRfGFeo1|#Z^kNUWR3W_i$@gGd!xC zS_*4amz8pTOE0$8h<*+yL4ShFe2=)Q^bk_rRQh-I9&tNj?-BPQwpu(~dX@DR@nk7! z=4YTBRi5SW9~l0%^m^+vkZ=>~YnyxEbVQ;w^4>4Sl?EQr~Cx4b_!AE1Kz5%PWgrPR%OMM=aIH+3i_rcIpvtO zj?3w>bUOUDS`N=)J6Xhbq9_-Gv($3`l)1K2%TrSp1O8%)9hBcqS!%1XP#-6m9iabX zN;jarYzyGBvOZg#Wo_9Wo1)O1j&dKh)$!c+EK8*9LhuZgeFkf&di8qbdqdF|LAjvp z78`LMK`OGkTa_!z?nbKVm}x4?jb&TaI?Q?JDRts}+ce zC^mc4Vz-yucUk^YR*mrV++$Xc@^;y4!lRIeqZTE124bz{v+TDr{Z{1y)`;``&yE!SDdi{1>_D2`aFroIL* zOV;v)rFQDY_ONB))CQE9=HMMnzsIt4s$F@;vK=tTa?aFa)?1MlHVL>4z3GOjpSQng z`P$J)<9lNaTk*tlCtHF6jB>t=I@S8!IBGn1g>u!HIucAquz%Gj*p} zf;qAi?YS3lxfliP5C;KQi;Dq!@NX+Pu_t#W;AX68ok;&hzya}Pz?irda7f$%m=bpZ z?!~`>=oIIP2LSiuzWOkqkjo~4zR;vM5fb#aWKDl|gS1D&YQMn0eqm?}!}RIuksa0>Q+=wE*$ScV-Q1-qZc2ropu zD%ufG|Mo;V;0o-zs<4zwz?EoA75`Spbiht=D&Sgpbw#XWxB(WR!h#5H#J}vJh)oQ) zVE!0*96>k!@wTfwXpP!-#-539gB8WHZt+aN_m814`YK-tc4K%548l;KWs zI_T#xjA55q!8&y@C~?t*unvf;s$ge|*ag_-yQ}bR^_b;N%YJLQZMrRJJKuiD{u}#o zyH&A>=M?NuW2d&!fo8-$$7k`h?x&e<_Ai82TGlLrB5DB>BZT((fJNNPN4}PA}rO zQ&or?1TlyMOo>=@n~)cN2zmF3;PYa1?p(CRhX;+w&`KPu-@&I-Lv&t(KKR5XNyb$n z6Gn#UQx&ngn;uksC?!*di7r?XtazDVEVrbYxzWpiA>Yh44@dD0YQks))OT5?#^tF~4*c0!U=U{MS*ty1GDJ}`n zmM{xpbYRIFmp#vIA+gqA?+Paywy=x3nbT98**W2B+ z7S!c!Eh~DPJJ*Y*j&)5Nx_dba7D72tvhI~lT|F&LD1up*-p*AW8+toeh_y`}?Kn1x zBa^s!ht4z#x-6)pEt_H%7#wSH@{u}4+p3=SrVbQ#HPx`CbJf!Ju9Zza?VYQ{vbI%i zUF|JdY~8{X-rLjEwX6*Z(jvOWing}ZncP=(_O^9(ksb*4wluA3Y3t}{Yc+60cduz# z-rLc+taDXwcUyNiWhr?{w@W+MtTK7qS8?Tfn_5~x?co!f25bAO?lnuH+;-HXw;91U zGea}c>ZUFz19v8+Q%GU5`;(!Hw8^xhV?^U)I-$TB0s3rjM?%M^FMQhvkzl2faipGT zDi#s=;H7swe{upETO~6OZ^va#j51#aZP8)IblM+APn<0{u%#!=%Y+1Rk0WKc(()t+ zqd283zr&LbX=x0%%dksp<~%u%@%5ri#?vHw3(f-xoFcdBEumz z?G8s{bh?k_;}WCQ10(q8AsjQ#qEPRoaw8^-f`sijtBDNQyPCb+K!x!kG?&{rK${fZ z6Ba=V9iz2zB+5N2YpQY=^M zS+YgJX&K;#|<#8q*=esAFhHa-$(Rh|v8-F?0iyzO~L6@o*ZQzp0?X zqeowZufo77Q2HbpK+8ZlLDx(%j^ku~I}vKdiF>g#GD1ghiIcy(#6?s|LNcReugQ7> zbCXwQ6_}hubN{W1)z~dvMNbqS`Ktz|lwh zLsLLG;UY-ofgl9|M~`hygL5yikH(jLdnUf~#w7#~Uu>A2%6CE8+P-0sw$sVJ3? zi+}@Nr~<1B-UOqoks-PfjaX}j`q9}1-+3fr+vqa4-Ov@^#?^ zMmj)0Xgo+;D;#l>-r@ zZ^Fr>2O;utl%gp)hGiX6MFc}u9SdcYTPTBaXlT1+HB})oLys9=qrsRUi$25#B8H=8 zftTS-92vMYr4~4k;Y5Uev!00V!0;5Ch_c0m1L)e3{GW`(t??2o-;Qj(|n)lFlOUJK}OAR8%?5D;iI-lztPBTIOINtuu4xw zw~sVOP_wKr#)Txe#rv~~7;xZ6hhzOD1tyWH*0}PYQ1+~HbD2@zUZ|X^K4B-ML1)5< zbc*q|o=!17f>NBM`|{8>anH_5HC|v=s_{{jYQoM>X(o(Frx-6Ponm|hr7-MzydR)6 zCyB~RHC|v=s_{{j%Ir}SWp=W->~!O0Qg&v#@o|(c%fg5?3#C}HJX*E#Y%q;vF{NqA zjHO1*M6{F?YvKd=zz^Txx9#o2V1S`LGjbV*E9b?%Cvu8D`jCr8c6_#k@~|;u%^OMV zj`Y`wDBG+U2F@{q;k`8B=J1fYP6ILR`-Zl6hj*uarExiIh}WI^P&cGv)t$r&IFTF( z$C{E&DIDE6@9q2QEbQOnL@fg0p~^EZY4!Bm4FKZH0Fq@gyCO6!X!j&i%DND z!ij`2oZut>*2wlSO~&@DjV4l<_lP~+ec?DaXKV;KjrtKWv?qBkO)3SxGs#rAuWx{f zdvLV}>bjGrV8~@4x;=$wQ!KR%GoV;|ye~G~AAu~MhT&FPT5d;BaGJ?r-XLc&veZNU zxMNw~R7$f8V^RVIm{UHel=nT7&bf+{^BH;3o}@bnIumV}`p~8m_b@@rn9l72 z9dLCjAvQ)5I;QE`hi)H>v|`$Bh)vUIA;!fVOQD@A+J=-@T`>c1Uh!3- zjGFgH&`KFM4GUV9nYohQnrSyfuF<6iNEcXQMhAxndF@I#XG-gHBPE=L*&#`WK~0j@ zIaBy{Y1XDcrv)J|%Vln`A=7%WbmSys7NxlIWB{hOmt*j83|uRh1@gPF%Mjrm#;l8y znGfS|_T|aU!yn3wS@MsiQ0dbeYVX5h7Hygc!-FJ~dS4V?x1Xt`gmhpf7FWjo%bYQ5 z3)-QEXqPQvYM7PRN26(03$@S(kuigS5!(2+MH&q4iAtT)y09zUAJq-c9((_uL}5*6d4%+%BY zj9cB|v=vNcgHjUnlTEfy^Ha8JjW z5->t$G@Q(uHZXN{1k+9|eUTx3eJnXKL4vzZ@9+rP;=zlpILG$rxSwG;rmN_!@l-=S z6XC5eFP7$pxhExO*BDNbH^)cB%w^2)v$l#dx1v6adJvSVQDDjtO#Rk<_>LASX_IuDS?X-*rmnz6%~u&v14U;XT;c~Vp@A8Yvr)q-Ny)652$L6Id0cDLiBuzPx83f&C;XM#vBgF`C_=;L0lAplM2` z_r$P2i>@C}(VQ?-m+qb>nIt_G5{u60>+Pi>AQm2J!R5utxfsCXP!V^1_TgeM5fQZ6 zgJC>-S9B4rKF`?J+dCWYc8y@2Xm3i6#QVtgz(uF&^;j5S1CFF*1}6-IyuLIRDx{ru zG`lp?OsR=(j&;nFH2YS+-~z4-M^lEScEerC&y6wfL@n5*;EnLaOXO@ncp{7GIwpR* ziurqz-b^Qj8Cr@V2bYAUae6C?nTQ#U5fyHf8ij`+_H5%w=*D=b3p2pnl$qe=@CKPG zJuwy6Phr}LJx@Z0k6r(ttZ@NsfNw5-#ga-{@lNFY$|LlPr zO-93a+8VfQ?MZ$Mg)xnbf}zc9AP!(d(paPr83jwyn`;_VlIw6+nGwhLADFL+7!gz- zvk@@Q+!4o{Z2Sujf;XP<{XI6?anB?K$mM2xCy7Eu$Vs5lqT8|bhavJlfDvO}M8M@< z)3bEGk)#WK3<7BqZUpJkqmw#m(I~fHo3I?A=@U8vrscSr%FLRmp{~e|;aE74xl<6P zfm^orqC??c5U~s|Amx;&dl*woEOMBV=?+{brlE@ZFuif>NsO$p3s(EIl1FzWA1SY?gUMi*1WR|` zI5oU#R==WPCpN*yq@mpn_IlhaGqTe36S%p^()=k6bWFBDW(&Z9#{zMU#-LwNDhVjKkL})m36US+qVVwM02#o#{mF*|cWQ+-gtrKU5#H1FS z@QFhf-nZ~!8KrnNOU2|6a>DrAi8!2%&Yy;pYx2MOcoI%e^UsVYoc_zkv-v4*JZ|!v zvP`@Myyl-NZz;~BaeQSL$~A}*Qtjz)2g;g4Xb^PLgQ(dD&V|f9iswF2HwLRuV`6bP zYM4Z7l1S&@bZ8?6tdAw?ke&p687Oi5C6G%W@D4mFm9U^)iYT{HoT;LGM#UCLM;RPV zI4{)?ZS?S|rv%c5Nt?NnTb9#>^MO5}4nektQ$vdZw}U@{=KyFi#Ds8$OV}t*EL(>d zDihUM@{t}=IA5rNlgb@Nxkwh-2T7&a@pd8{bVkuB6bn9nv$%w)SS`9m7wm{?i;XO{ ziXhG+>Re03HjMg;qHfSh14EG6g*fb-qCP>f2PvWmE1n>7+=~#^l{BbW@b7x=f36*c z)lf|xS!kREDHxw*fksV7Rn>4LZERu<{FGG`&v;gPY6xs@a!MUA%!-yKyB*x522(xS zIGLs_G8>sQHKfK>7{L)P7sB-4__8b%RXD6^N{=H?GPW~7RdR?ojxs2=ARTz~1rd&* z+@usL3t~W{x=||GOiB8%4)TV<5fjQJnPwaC9YU#~(vf+EIW`CyH9!bylQ1#GN9m~R zW^^Mg`*4TDD30K1Y^*8NU^((61Jck8Fvuwy4uxv`Ni@ZFBQ-T98Iv;WY)}F);j`Iz zx8SH?4KNMZ7Szd%*@92DYjCht$>~AbVaOM`)iB^L9CF1sP`OLF#AJYCQZ>436FN#a z#T3zp*eB#VNtS_(bP(q&n@|?nUgVUrTV6+9O{do{yVt2Ls2g?0om{6CfGOCCOi#ub z;{U{~HIO=h9H@n4YfPMnvWDjRkk!+xCwm^M&*7b2qOoo%7pEoOS;_ zf9>saS2Y&mpW!Pk@Z`BmoZd?Mzd-dAyhRDA>rsMikp=MZD8u_ZH=8N}*?g zN(J(qju_RhDV`=zTdrnRJg0ja@wdRCsT5u?iJpxnJDA-h#%&ECLjrXK8Z80g#Gi^k zH)>mwlOwF2cDK90tvZE8hVr1BBJWDYdzRDf&J}iNPENTED$a2Ti`%nCRq^yRx!tO2 zS5c=XJ8~}bZa{&zIP68$Pk4UrT1W+sc!I>@mX9)Tl!{ycCaSS_5b1W| zZy0}NUd>YE9Z}uhQMa3mu>U}wW<@cK@=Vg~-u)MuO`M}y4GaqOdTapuFL7!XDAyB2 zn|o(dzAo<|s_yjwZ^hqyD?}W^KaRWqN-Br96%-^KMbs!uI0T4DB9=1Y^OStl2C)AS zAjKhE%7o8z9UwtbR2)Hemb)E-w6Xs>)LilGzgbb0A{+8?JE3mXZ7)F6P8C*{;>pW* zIJ}kKN>3h4*Hh>%ktzN_+)lQEN%&_fW$UA)1)c>?CpEl{jZdJ? zCQ!~doyZ5rz4yOqb1B~ax01}fJek4!{5W8f4-bYQ?|~xk{@1D62TCQioGN~xk`Tl= zkgF3v)WBUr7522_&@BiKgv-Go6V=E^5Z9D=57fCi@qs$|XoNaF?UNlYZ;^MG_dt&K zz$E;Sp4yH)S%hri91S6bozGB8$F(b+ExIgeQX5 z^hDgG(x73~T=R&mPXvfhz=BbpXbzR`K-6#HGWcOv%I6mQ1a)hda1OIcCsA8zu8IEG=zFbC>N-{9K4tE4W>A1Uf2XUw4p}-}IKtCV!iG-iPMg6@{Q)i0tK~j&0!J0y{NK!6c4qL?>2>qfBy^O_{CQya%4+B21;u_@XiuB3612 zwwKvlmpAPjyhcF zh5s-()3+e>!@m@)h#u9y4*&Y%DjZBOPbgp;3jgRVB|P>BGcx#q!deE;4js?p69Vt9 zu+Wb1`3F8nABpgLI!f{3bfGQDPWu0|Fm5wKjnNAG-FPm?6B8)070(hpap&27JhFZY zO>e{%6VSycg!tM7bZWPUPD20H1a!*mIDs)gHXB;ckNZgi{$25LKS|K=C^?3CKJIff zfAinL$IB*y=j<1Sc$q3?{8l6W)hu~0t8);u7Sr-xz&1?XyYW>~C%zrR*8+e`5vJb* z);B(o1vC@OCtogtcq{(Q7~-d2EB+Kn4P$Yz)L8tqW8zIKRr*zPDq1?wbUcaaIIT|Q zl8hO|x2(%ic4f@sjAlviM(MtOD`bXxFGo~8~6qeX4Dp8kE_Qs=aDq+@|K3>~JjYLP8V;LAtS(OBN` zni{VsEWnVa39UoR%0aYrj5iJbUAjwFuUa5Vp99^)-KbQafKZ&OiX-jJ0421 zYgx0n$hA8fkx zaN%t)bjJVm-B*sBebw!6{qEtV^PUP#J$}pCH%yu`?aaHM-1*k;V!ls&bIPgtZ@qie zGtybu*7&u*{$O;`s#R}(>9yDyIbVw1SKmJ9{mN3>!SZu{!-HIG-n zy7cI~56pk=n;ml>pTGWFzla7`|E#3QcgBLBfBMec2j;IhX8r4@Qx&;W{PRQ3o-1B` z?1D}Ay`Kuc^_2&{c>J#AZyh=Qhd-}ee9y`=W?uT&=HnOtZOM&uU)VC`ta~q*uln2H z&Z~K{W_aNfE1x_6uRm-$cK^a(J(2p>-=6OLWr6kcKfe0#&t|-E^`{+E&afW;SwW=u z-m~6my`|y)v(C^jy)$&}H)d~1`qsM7{z-L?f1SOcrs$FL=dC<%MeEVIn`_@*6}WA< zGWU+Z#7^tV4_U9ODYw2k|1XWG+pkvj-?0Cj&DZ|(*+-JrkhRD6h*A-*EQfO$FCp`ttebUjNb= z_t>91IJ@WAYqxCryt2gk>_b2AZ@aAYN#7rySoGejpWD!S^xm@5u6p#~6TM|WF8|w| zIi(i&-XrbAuMp3`#8Lxay8JN3|#YaR;Xxe~Ys&)b`>S#tNK8_%2bcKdy^FIau^ z%WwF;G&^+DGRMlfx6QibinXP&?;lxSy7rl(bq|&_=XoN<>qox-*^*a!KjZ7X<3=IaG-u|lX+2Lq@&1jDe|++rWxtv7g)R5gzxVt# zv+`ef|0nTjzdiSxQ=j|6H$U;}UoQOgh2pzQzvC=f{d|1p@rCc5`o%LpIqQtQ!~cBe z^nH)MasIdOX+Qhod2igmXi@U5&z~25NUeUOF>p9GW!Vq^aP3zn|K#Cg`FB+BS@2@r zGuOX&+ugQrT(q_L!oYLkYku!9{K>K2)4t&DT>PJZ{NaUPwE3;ITZg)j>2F?j;nhnn zIQZi??mJr1_R8_!T<-53S#aRI-yOQ|j=bKz$6lTN=QUqEu-S&3ymsz_l1ol6s7^gI z*|~7)Zx6q4`R%8_^UlIubLJMr7d_PY-xU|HzxKPgRJ>OB{XMr_r~O_Dz5V{2x1Y1z z;=b|!YwtRvn%cH?0z`UInj)Tr97>Rm93TjUP(xEdMMSzF1VIou6a^A`6A9%22T%eC zB1Nk75)ef|AruisBuc0vQUwAeZ{zXY_wIP_$9+HV72tabb0(`PMn84keRAn@xeP_u4H_yS_#uId+HDD*owP@y(?%3Yy|$M8}vb=A&fE=h546!pa?fKK()eE!L$7N4g@KR_z%C z>z9AoOwA*Uqx~r<+PDd#Z;~i~3nrxxIh&#KcEiZCN|aArlS1#SDTqZ(`KiK6kyFBZ z`+hKjujPFyic3!Q90@w2_a{|Pyqay+W;h}WjIMNRPn{gvbWl#1hhAu5Yr3eZ|K%-o zQhWJ@UI}=>!hOp*t^!o)h|64(+`y0KpKfHeuV$(bKN!AwwZlVKvcTV+1ePIAo_|}W zc2hWG`8qj8Hu1%^o~2gKPq3&qY%ckm)bExjcy(TbDnq~`y!!w>KvepL_?<{-s6w4N z!0?xr|4JO@Ab;O7LSt68(@V(XWp?)kiC@1A&9px>_6@bUr&R7y%S1a^#>^g(i*$Lg z4mnmU``#+1)shySmt;M5_4VLDZXJY4Rd&YwJxIQ|#DN)6BQ;-m3v0TMF2d}7X2WvW zv+Hski&B9w9(;Xhwj)*<)uW93?&Yj?JigXoy~L|a3+KXQ4o0&~&*rH}WnILY|3FOq*_77kxQ(^qW;%v>3NUxk=kv>df10;sqf^`%dn|$ z0cp8ZO>YB(I^GcGxvsbQd-NVvTOJNEDWkzR)(?y4rcJj;fyU@wXQXPSQ`vQ5rs}j0 z^wZn?30CXUM8hJ>7KwS!nSOtUpg4or92a^tdO~-=xNFeUFDb7sxvVj#;w8$HIop0+ zg3l#MZKcKPM3Jh_S#6~INkLjhAIeiC`zjaxsP_T_rZGYAZ?MEJd>^pI>Ho@RGEn20 zhnURtZ&1RnF@~PlJ=P4>^@>{G@T+)Fe5#H=!hpKdXQQO_IT1!uy%kv7Bxa9Q#&EB_ zc7Sd@vB<^3^cIMlj(UwNJRx{f=j0E9BV3s_&4mh+JVDpgzPpdZXi-Y~Yi{Jcm;s60 zW7K{K(o)TD)7YQk)&9kSK8cIlSXlZ#{|v>T^2>AlHavW>{?kmCNFr{8k)IFMs#e<{ z7}7p*ok6!7{1&shNJ;wSh-=PQfUo-y);!{wRUBkDgYzC_;(Amz8SWd;{utPOySFja zLGTa39vrCU^Gu)Z4^re5yoG^{kJmH^6s(ZL@#HGu?X|8U~bFchX znNqc{Fl|oQ)(_|bin#?Qsi2lJ#<=1#h;37dBFq*o#@NhUILf zB;{MLATN^39PYWLtBk7)JU=q~+`N0K6EYEa?V3791KYuNxT_wq{~u7io{16QJi4D&mA$lx_ntDgf>BJT>JQ%c+m%IVOeuPzK~ zbz*9+AoH>#J3$ov)V5ONRnV*+H+x=V(3JwHpy4S_WQlpCRk+_d1@TEKu%06*e5=xI zQ2NnkYom6>ehC2(EgJ@}2ByH%!oOh_l64dw>{VCcg+G`3FXc9az0z5&FB^MEGgxjO>1K$yP(y zeglGrO@@JouN!MmkbUJO)Hem3@K%9-vbiOxbbLcOQ)f7@xiKYC5MPB`0Fo9azU!~? z5sWz%688`cY7q{KR_le)FD8&;C8kh<+uXb|xIY=v$eQ)3~K3m#hgN78A zUag#rA`kClx}yxmQg`XzT4VCqW#C2Bbw-EW8YK=ShLXgJyf5R8QI`POGZW%FzCXT+ zJItWXE9t!I0rdeKhIYCiuP(HO_0V}pBU)g?nE1kdX30l3i#x55>01sltb z$CAQ5CI)WTM8`_~k~kwCdz{sV$Mt9-Mv5c^m)t?j;_iGyG}>i#H86NryE6TQvF|>z zgYGi(y+hEa^^i4!2{9l<|P*R#n3(fm^r^2|K;G8nYi% z3eRaa{r>8;O@uW_Dd9mC3RreEW6ea;B27FXeEg*}TCNHGPw~kxW+UfHkP8#HJKa>| z3*+)-gGt3xNHG3g#6xp(;kkRr+~a)*`4Xb&47KY?PiLf0CZvs%EmrGTo+7Ds^>8_( zXj6yaXfS$2v(!ksH^u*LHheY&X86XppVa zw~?|)qZKJ<BvB+=&U?YDxiU`@GBJ4f8)LW5WUci~81(HM#6>^fq9HeEgi)v(Cf zQmd-JFCYq$(ayaa%bjz(?CuVfIM*|+eE3to9)|_XpiC2D65fC9U>?iccC^OWkBRWH zAmEV-5u&gjN5$RW1h^Q+_3yia#UeD=L)kspqa!%er)`SPUpUPa`7UrPZV9{s z;!N1#memrE?hC5A+p|cT7RU0iWx^EW51f#`@q481(dCV-;G;Xa;^q+jM_roWPQ2Tr zpz?1TA6e*<#&>jlGqP6Z;S}cT1p%pD(e849K|%WC{ZF=NP6Uz|f40rf>;h-i3E*cp zPv#?soOWEhV= zt%|?+tb^f!`{M=qWkXFO^*L)up3ND>UHi4|sv2Nn*L?J@T_S4+S%S=J7G4>nS>oK@ z{OCxt0577zl*sC})?D4Gu=rw8qN&?Yn?>sFXK+#8ZOu(vJ2g24rz2Xr=2|SL88w0ar+fc+F8c58>>+_^y}k-vn&W?s*XAlwCF= zodlwyUq`~A94-CsUqwoj(Ve(hJ1!0riV!S`uof{((&gChck}OzMt34(;vP09k_%xL z&tsgF6xV9-8jX)o35cns!^N-7BT0lK%jZq2S+oY1)rBhot{OIo8mHT5*3cQ=XFfaX z*(lx8tXqljnKB)_^b6@#Z{ULq zA$y#uD`(%4^>PzMBV-?IJK;#zU` zPtZ*QO$*mBsmQHK*Rbs#op`Y!mV@GbiA}whZEIy?sb|At7~zKJkI&YTmt%{+MQRUO zF?M{t*XO(5h{!NopE{NOVj+_F+@91eupZrcu4SmtN2mEL1?%K%>11_nq^s=(OOJl& z#$ccPL2`0klFIhu;*2cl zwPUGQ_1{5mez8nmqUnJ8W(c{Wq#FRAsBSo}hsfm}iB2bKZo;v61mT}b7<@9XU z9RWkC^#8Rnnnz}U$H)!GgPa5oQ*Z&nKK*O}@2u zYNCR@y#OS{AMnIl064KC9Om{D#Y+ngc+SeH!w4qfB5SD zjLiH?8o&w$`v)`QAIZT2LjFmkLt7&pb`$W5)q@SQ%xHI5SeHhjNKr8=_MgQ;>)`DMm_VRc8`A|QY0O-#DOPjw{SNJF0H5LBR2|xo) kg}+A#Abt$~e-8idJwW;kw~FrvcEZ2=!~948|8Ecc7q)FEod5s; literal 0 HcmV?d00001 diff --git a/deploy/worker-windows/build-exe.ps1 b/deploy/worker-windows/build-exe.ps1 new file mode 100644 index 0000000..34e5eeb --- /dev/null +++ b/deploy/worker-windows/build-exe.ps1 @@ -0,0 +1,59 @@ +# Baut rippy.ico + RippyWorkerSetup.exe aus install-gui.ps1 (ps2exe). +# +# WANN NEU BAUEN: nur wenn sich install-gui.ps1 (die Installer-Oberflaeche) +# aendert. NICHT bei MakeMKV-/HandBrake-Updates — die .exe holt HandBrake zur +# Laufzeit (GitHub latest) und den Worker-Code live von Rippy, friert also +# keine Versionen ein. +# AUSFUEHREN AUF WINDOWS (eine Windows-.exe kann nicht von Linux gebaut werden): +# powershell -ExecutionPolicy Bypass -File build-exe.ps1 +# Danach RippyWorkerSetup.exe committen (die API serviert sie). +$ErrorActionPreference = "Stop" +Add-Type -AssemblyName System.Drawing +Set-Location $PSScriptRoot + +$guiSrc = Join-Path $PSScriptRoot "install-gui.ps1" + +# 1. Rippy-Disc-Icon 256x256 zeichnen -> PNG -> ICO-Container +$bmp = New-Object System.Drawing.Bitmap 256, 256 +$g = [System.Drawing.Graphics]::FromImage($bmp) +$g.SmoothingMode = "AntiAlias" +$g.Clear([System.Drawing.Color]::Transparent) +$g.FillEllipse((New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(99, 102, 241))), 8, 8, 240, 240) +$g.FillEllipse((New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(147, 51, 234))), 40, 40, 176, 176) +$g.FillEllipse([System.Drawing.Brushes]::White, 104, 104, 48, 48) +$ms = New-Object System.IO.MemoryStream +$bmp.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png) +$png = $ms.ToArray() + +$icoStream = New-Object System.IO.MemoryStream +$bw = New-Object System.IO.BinaryWriter $icoStream +$bw.Write([UInt16]0); $bw.Write([UInt16]1); $bw.Write([UInt16]1) # ICONDIR +$bw.Write([Byte]0); $bw.Write([Byte]0); $bw.Write([Byte]0); $bw.Write([Byte]0) # 256x256, colors, res +$bw.Write([UInt16]1); $bw.Write([UInt16]32) # planes, bpp +$bw.Write([UInt32]$png.Length); $bw.Write([UInt32]22) # size, offset +$bw.Write($png); $bw.Flush() +[System.IO.File]::WriteAllBytes("$PSScriptRoot\rippy.ico", $icoStream.ToArray()) +Write-Host "rippy.ico erzeugt ($($png.Length) Bytes PNG)" + +# 2. ps2exe sicherstellen — TLS 1.2 ist der Fix fuer den NuGet-Bootstrap-Fehler +[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor 3072 +if (-not (Get-Module -ListAvailable ps2exe)) { + Write-Host "Bootstrappe NuGet + PSGallery ..." + try { Get-PackageProvider -Name NuGet -ErrorAction Stop | Out-Null } + catch { Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Scope CurrentUser | Out-Null } + Set-PSRepository -Name PSGallery -InstallationPolicy Trusted -ErrorAction SilentlyContinue + Write-Host "Installiere ps2exe ..." + Install-Module ps2exe -Scope CurrentUser -Force -AllowClobber +} +Import-Module ps2exe + +# 3. Kompilieren (WinForms -> noConsole + STA, Icon eingebettet) +Invoke-ps2exe -inputFile $guiSrc -outputFile "$PSScriptRoot\RippyWorkerSetup.exe" ` + -iconFile "$PSScriptRoot\rippy.ico" -noConsole -STA ` + -title "Rippy Worker Setup" -product "Rippy" -company "Rippy" -version "1.0.0.0" + +if (Test-Path "$PSScriptRoot\RippyWorkerSetup.exe") { + Write-Host "OK: RippyWorkerSetup.exe = $((Get-Item "$PSScriptRoot\RippyWorkerSetup.exe").Length) Bytes" +} else { + Write-Host "FEHLER: keine .exe erzeugt" +} diff --git a/deploy/worker-windows/rippy.ico b/deploy/worker-windows/rippy.ico new file mode 100644 index 0000000000000000000000000000000000000000..9e748d252480ca2425d56f91f10ec952830a1bf9 GIT binary patch literal 5679 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 literal 0 HcmV?d00001 diff --git a/docker/api/Dockerfile b/docker/api/Dockerfile index a1e80e9..5f7155f 100644 --- a/docker/api/Dockerfile +++ b/docker/api/Dockerfile @@ -22,5 +22,9 @@ COPY docker/api/ . # die Zielmaschine braucht weder git noch Docker. COPY docker/worker/*.py docker/worker/requirements.txt worker_dist/ COPY deploy/worker-windows/install.ps1 deploy/worker-windows/install-gui.ps1 worker_dist/ +# Vorgebaute .exe (Rippy-Icon, kein Konsolenfenster) — auf Windows via +# deploy/worker-windows/build-exe.ps1 erzeugt (Windows-.exe geht nicht von +# Linux). Nur bei GUI-Aenderungen neu bauen, nicht bei Tool-Updates. +COPY deploy/worker-windows/RippyWorkerSetup.exe worker_dist/ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--app-dir", "/app"] diff --git a/docker/api/main.py b/docker/api/main.py index f0fd9d5..932d25b 100644 --- a/docker/api/main.py +++ b/docker/api/main.py @@ -1091,14 +1091,30 @@ async def worker_setup_windows(): @app.get("/worker-setup/windows-gui") async def worker_setup_windows_gui(): - """Grafischer Windows-Installer (WinForms) — vom .bat-Launcher geladen und - gestartet, damit der Nutzer ein Fenster statt CLI bekommt.""" + """Grafischer Windows-Installer (WinForms, PowerShell-Quelle) — Rückfall + für Fortgeschrittene; der Normalweg ist die .exe unten.""" pfad = "worker_dist/install-gui.ps1" if not os.path.isfile(pfad): raise HTTPException(status_code=404, detail="GUI-Installer nicht im Image — API neu bauen") return FileResponse(pfad, media_type="text/plain", filename="rippy-worker-gui.ps1") +@app.get("/worker-setup/windows-exe") +async def worker_setup_windows_exe(): + """Fertige Windows-Installer-.exe (Rippy-Icon, kein Konsolenfenster). + + Vorgebaut auf Windows (deploy/worker-windows/build-exe.ps1) — eine + Windows-.exe lässt sich nicht auf Linux bauen. Generisch: die GUI fragt + die Rippy-Adresse selbst ab, HandBrake + Worker-Code kommen zur Laufzeit.""" + pfad = "worker_dist/RippyWorkerSetup.exe" + if not os.path.isfile(pfad): + raise HTTPException(status_code=404, detail="Installer-.exe nicht im Image — API neu bauen") + return FileResponse( + pfad, media_type="application/vnd.microsoft.portable-executable", + filename="RippyWorkerSetup.exe", + ) + + @app.get("/worker-setup/paket") async def worker_setup_paket(): """Worker-Quellcode als Zip — der Windows-Installer lädt ihn von hier. diff --git a/docker/ui/src/components/WorkerVerwaltung.tsx b/docker/ui/src/components/WorkerVerwaltung.tsx index d1c9e27..2cf85bc 100644 --- a/docker/ui/src/components/WorkerVerwaltung.tsx +++ b/docker/ui/src/components/WorkerVerwaltung.tsx @@ -91,28 +91,14 @@ export default function WorkerVerwaltung() { }) } - // Grafischer Installer: erzeugt eine .vbs CLIENT-seitig mit der eingetragenen - // LAN-IP (der Browser kennt sie, die API nicht sicher). Doppelklick startet - // via wscript PowerShell KOMPLETT VERSTECKT (kein Konsolenfenster) und lädt - // den WinForms-Installer von Rippy — nur das Installer-Fenster erscheint. - const guiInstallerHerunterladen = () => { - const host = rippyHost.trim() - if (!host) { toast('error', 'Erst die LAN-IP der Rippy-Maschine eintragen'); return } - const ps = `try { Invoke-WebRequest 'http://${host}/api/worker-setup/windows-gui' -OutFile ($env:TEMP + '\\rippy-gui.ps1') -UseBasicParsing; & ($env:TEMP + '\\rippy-gui.ps1') -RippyHost '${host}' } catch { Add-Type -AssemblyName System.Windows.Forms; [void][System.Windows.Forms.MessageBox]::Show($_.Exception.Message, 'Rippy Installer') }` - // VBScript verdoppelt innere Anführungszeichen; Fensterstil 0 = versteckt - const psEscaped = ps.replace(/"/g, '""') - const vbs = [ - "' Rippy Encoding-Worker - grafische Installation (ohne Konsolenfenster)", - 'Set sh = CreateObject("WScript.Shell")', - `sh.Run "powershell -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -STA -Command ""${psEscaped}""", 0, False`, - ].join('\r\n') - const blob = new Blob([vbs], { type: 'application/octet-stream' }) + // Fertige Installer-.exe (Rippy-Icon, kein Konsolenfenster) direkt laden. + // Generisch — die GUI fragt die Rippy-Adresse selbst ab. + const exeHerunterladen = () => { const a = document.createElement('a') - a.href = URL.createObjectURL(blob) - a.download = 'rippy-worker-setup.vbs' + a.href = '/api/worker-setup/windows-exe' + a.download = 'RippyWorkerSetup.exe' document.body.appendChild(a); a.click(); a.remove() - URL.revokeObjectURL(a.href) - toast('success', 'rippy-worker-setup.vbs heruntergeladen — doppelklicken zum Installieren') + toast('success', 'RippyWorkerSetup.exe wird heruntergeladen — doppelklicken zum Installieren') } return ( @@ -224,20 +210,24 @@ export default function WorkerVerwaltung() { ))} - {/* Windows: grafischer Installer als Haupt-Weg (Doppelklick statt CLI) */} + {/* Windows: fertige .exe als Haupt-Weg (Doppelklick, Icon, kein Konsolenfenster) */} {variante === 'windows' && (

- Einfachster Weg: grafischen Installer herunterladen, doppelklicken, - Fenster ausfüllen, „Installieren". Braucht nur Python 3.10+ auf dem PC — kein Docker, kein git. + Einfachster Weg: Installer (.exe) herunterladen, doppelklicken, + im Fenster Adresse + Name eintragen, „Installieren". Kein Konsolenfenster. + Braucht nur Python 3.10+ auf dem PC — kein Docker, kein git.

- +

+ Im Installer-Fenster als Rippy-Adresse eintragen: {rippyHost.trim() || ''} +

- Öffnet direkt das Installer-Fenster — kein Konsolenfenster. Windows warnt beim Doppelklick evtl. - („Windows hat Ihren PC geschützt") → „Weitere Informationen" → „Trotzdem ausführen". Die Datei - lädt den Installer nur von deiner Rippy-Maschine. + Windows warnt beim ersten Start evtl. („Windows hat Ihren PC geschützt", unbekannter Herausgeber) + → „Weitere Informationen" → „Trotzdem ausführen". Die .exe holt Worker-Code und HandBrake nur von + deiner Rippy-Maschine bzw. dem offiziellen HandBrake-Release.

)}