From f7835f66048e4b3cb39a1bc08aa4a6ec16ae9430 Mon Sep 17 00:00:00 2001 From: Paillat Date: Sun, 2 Jul 2023 11:17:10 +0200 Subject: [PATCH] feat(audio_prompts): add default audio prompts for narrator feat(audio_prompts): add en_narrator_deep audio prompt for narrator feat(audio_prompts): add en_narrator_light_bg audio prompt for narrator fix(video.py): fix indentation and add prompt for generating thumbnail fix(montage.py): fix indentation and add prompt for generating thumbnail fix(montage.py): fix image download for wikimage slides fix(speak.py): remove unused import statement fix(speak.py): remove unused variable 'fakenames' feat(speak.py): add function 'remove_blank_moments' to remove silent parts from audio file feat(speak.py): add function 'optimize_string_groups' to optimize string groups for audio generation fix(speak.py): fix comment indentation in 'generate_voice' function fix(speak.py): remove unused imports in 'generate_voice' function fix(speak.py): remove unused variable 'reduced_noise' in 'generate_voice' function fix(speak.py): remove unused import statements in 'generate_voice' function fix(speak.py): remove unused import statement for 'logging' module fix(speak.py): remove unused print statements in 'main' function fix(speak.py): remove unused import statement for 'logging' module fix(speak.py): remove unused print statements in 'main' function fix(speak.py): fix(wiki_downloader.py): fix Google search URL to include correct query parameter fix(wiki_downloader.py): reduce sleep time after page load to 1 second fix(wiki_downloader.py): increase sleep time after image click to 5 seconds --- audio_prompts/default.npz | Bin 0 -> 40100 bytes audio_prompts/en_narrator_deep.npz | Bin 0 -> 55988 bytes audio_prompts/en_narrator_light_bg.npz | Bin 0 -> 40100 bytes classes/video.py | 5 +- generators/montage.py | 129 ++++++++++-------- generators/speak.py | 85 ++++++++++-- generators/thumbnail.py | 20 ++- main.py | 22 ++- .../Ghostrifter-Official-Lost-In-Thought.txt | 4 +- musics/When-I-Was-A-Boy.txt | 7 +- ...and-sensitivity-rendition-of-bachs-air.txt | 7 +- utils/uploader.py | 34 ++--- utils/wiki_downloader.py | 7 +- 13 files changed, 206 insertions(+), 114 deletions(-) create mode 100644 audio_prompts/default.npz create mode 100644 audio_prompts/en_narrator_deep.npz create mode 100644 audio_prompts/en_narrator_light_bg.npz diff --git a/audio_prompts/default.npz b/audio_prompts/default.npz new file mode 100644 index 0000000000000000000000000000000000000000..930d10da2e60e1f80b98254769b5054457ea88e2 GIT binary patch literal 40100 zcmeI42een!wXY9~iX~t{V-JXe6=Pz=f`Xv2D>s%{P$Sq2AfUz&E5@jp#NH)X1Gd-` zHAV$vjlGu;z}_|X*xvVX<}c&8pM>Ok?-=)ucNt?k>zZq>x#lW+@BeYYCbPEh+|v55 zYs-zx4{3R_Q_FN%prv!mh~4(vWyr|A2Jbv<_|W}^jqEvO*um{u=AEv#iKhNLdGoC| z8?arwmIGTx_1JZ{5rc>KShGuy-g~XyW5q5#b{{%?^yY%uDdD!{x18D*bVuJ zJ$D(l8~n1XuCdCB%dObukS_n}e{&rt#b+GP)c87%)#qW0 zv>J>q|4lr0o>qP4r(NZtU)95en!f|8pV$TWs`)>x;@)wYR>R;ms{Upz`SIm%t@78z z`;>gg1zL$)7H`FuSG(Yr8qXgVY}E%ZRB<%@o>cXbxt%=v}*lORU?6bbA>|3_2x>~%}#nq(L8UIt2 zx4A3tyOiCFGr;qfzx%77)oNYbSo1%=;yAh5NB)m?C4a5ml~x zqYsY0iK7p0>YIFr+TU)h_?!B{HNP*`eDq5Gihr@@@7Us(u6(^#>++Gx<1&R0to&?M z^%Q(#>6`T${)MW;;62O#BDHS+W9inw_MN2_r(N(06=&A#jPRN@-pO5B{XAOx%->tt zmegzTd?gQlrE9Aoc!%=0boJlFGm7KoD(DLqZuK{@#v6Qo?FTtmf={ja%zibfPWJ06 z&i^YPRqt6p!HMfH9a|fo-Tlk>*=1V!Gitm)DgP@Jj-SOE@~5gk2AATsn)mNlewz4% zn)jotzwEznm*3#TTWR^nxt@Lb@!J1`PpCM8v!4b(Saoznq;>R$HC z%17`HwO%)^{yWur9a!~|eJ1DQ!IhWbx94sZEIVf_zM}FtYptuFlzrAs;?6j}*`?K> zWA!(w+NHnLQ`%*|Bj2^gwPfWt_=#GG!GmjD-OFzO%5#-hOZLx8>K?OKjVt)3GK^jD zO%IoaKx2yPu)I45S zaR#qd{dcQ`1b3-CUQiR!#9NmC-0Q>NQF*zk{N=t8KDa5*J*bIm8UN${6h7^neA-7J zer7oKGxFDz&xlVy@fUtZ_OXjT_qE8I_{N&Q$gi#aC;V))v>N2z*2KBLA1D@wmw@jDfNLiy`m?H(_E_~Xj%>5{)z_OF-yz>@bbyTpG=@h=tLp>Q+4 zMN8hj@MVRMDZhU${Lc^BR<#emUh$dl$lI0w=#MFXGvm`f_On#G@H1;aGyU5YSNz@j zU+us05&tub=YRFB3*^5$UrRRX@4}j=+zwIhu^mNItg3$ zDL+dU?p69-3y&;+mlpn@D=5pZ)CNvP*pFFY!H6_Bl5O)&8?a$;VXtTy^ux zBJ1qbvYXL)7W??StNcAu@rKWS+Q0fgs{Gzv_|dX|t#I~_@Ozfu?8o8%UhVfRe1F*` zo=L@bF2BDoyXa3YeTTyLm0k3cD&CAIc|5Z0qEG&E#lEoGWxn1hKJ$5E@xQKq!)ISU zrS#iZKhcjXdGsA>JXbdCQ{U}NziR1UEq?Ffrxw3&;mmvX-J`4jUzPnm74Lf`U$EL; zU;3>|pZd!>NpzB0akWgmXu;$xrqFRFOrzd61p|HFzq=W>%@p!#{T z>~=4Hv*J5f-0zh9-NG4fli#82Q|~#Se_U~ISnc;N|GAGmU3~5fxxZ!q$o=c|YM)o= z!F{UV=$|WoZ23*yWWN4bezO1MJ`(*G6>s$I%U|}dTS}k#4xjxm{pJ35f5nmYA3pPO zO2zYX;b~<*qWX>f9>r&$%>I(POgveiE0mut3U5FGt*~1jIVfSX8%7$KYJrz&GFAn-?abl=4Td9 zQ~&Ss&G?(`oBEmY|8Dz#*M4UG|4-33*GH58y6d6oFZ_R1KI3mj>pS`x^%s5GH~Bno z?_T@SX@zgC^*O2bzq@OH$$d5F$?>IssoHfb{8ZVmQ-1P%89whZ!hcbI!e{@?b6xm} zGC+;eF@3PCf%X@_GCC_+ID8HQw?^o?7m*3o17BBs3 z)xJmZxxeK7N$#0>Udj87@OfX+v;2>){_?)(!IJ0s?7r$J=kF`UA6a&X7T&4wwS_Z3 zvCpf_+;^5MyTm)W#+B!xm#Uw{pZ6)bpWR;e@t1sj(U_M!FQ(q}JdyV|d49_J$awO; zEA@6x#hW-6DL&&{x#C%=Uc3J8M8o1%h5OA|9({cMxSwIJxr^3^4=l&I;YzGq4XOU zpM2;2QuJMG-opR6+U5EB?&1fPUGksr7g>Mn*Z4DEy{lc;OTNG4{`QaWM`f4y3weK# z^DO7p0c96H&+}PN&H0JHxhw9xFZpZ5nfD)aSAHfn#V7y7{1xQ+273Uo9$zNM#VX^{$rnbn*5CX$G+)5_l4io z{JvFq&%#-M9co^~FH`#L&$+*JExYYXpXZwmYkb|RPQvFr&-%;zy}TdGdP%+H{nGR0 zC-?a5H~AjATE($Y^_%Cd?6;Y>#Fzay^`84j?x%@2`()0CUe!p7~w?EiCC9&-P^ zrS#d4;y?RG#+Usm=XdUdr&Rl_uOrI;1{KHmihr%_av#ZkA?I!U=X?&I{=zr+$Lu%j zS3ik=*6MGOk|&=p);x7B+_!M@vt`+5f8Vdhk^Cl(^~(RB%Kon6yOqD3FP%!CdQ5%h zd|0sTbAP|P{G`6}{FnOrZN(G)@M=G?@U-ghm9pzve22o*$}aVtdPw~ZtN!!7Y*5*! z-%ZPJ?uUst=TYvDzc0IP)qa`sduriVDxQ^#kN>BtUFPGg;xm7_|K#~8{JQ0Do$~i~ z@mWu)&#b5H?;Dg|&XLqh@}1vbHTciACJj)fI z`dYdC-di}&9~+fj@*RIWmtFFgdTrKk?02g1$A0DV8~d@vXMae(Q-2><`_$2s)qmRO zJJ4$7C;3VIc@Gl*xetC?_Q_kG!*X8ttA1Cn`A$5UuiWS6E4%o=y8Pxob9uGT_%mN4 z%WlJJpL^)&8s9pl&wdqtm4<$5wU6Bc)nC@namBAucFlOQUQ&PiRKFQ-@}BzLs`RPf zVoo{eB^w|{W1LLYM1vL*+0hA_;Y@}Q~l;VyrI@9Wd5_hb}0YpFZ*idAuW3Is zf6e~CuD`DvU$g(_^Ty1^)6{=mf6e~?U4PB?2zPo~FLp ze>30B{+oQ$z8PQBzM1c)zRAzbU(?Yr+ar1^t(RsIW}!4KM3{g?jMef6*Xi}vY1Xy1^{ z!-LwFXZ}Ea0<;&Mn}93Pd1!jk8wKx$`~+l=gZ=pD0qZ4OdoPpP`J?X303Q~$_oamw zG28fo$(IbI%x)8B>kkKgXdD$Ch^S;g9!h zCwMRkevtQLcV}e&m`?CVbk4J5vPP^0^Wn>@G4SHC$n4Af1e-7WHho%ZG+crKNj74uv_@M90QD5-7PjrWO|M7+I{2P@a2Yr^$p8{?Y{*v=2@U9nNtqiiCN ztu8E?c9gf^WdiI(M%d066~9U~}JW>q{cnq;|$W9vkD%9_~2Y zBdmS*?$OvuPu~;J%?SJO?mq2!Hik~_JP%ezCjU6JeJXQbGMAAX`&ICrv1=Q1#?Tf! z248mj!qb;7?oVBj{Tb}Tmi{w7$6~!XM)w2fN^nf}<3}hzJk55FvF=G20^BFh~4BG;F&yxwrZUMGKb_IARzz^KQ)5u;2`+>`sXgdJf`2yA-)xC!99q0~Vp*`S_SA4;G z9eTlg_6o=r1blJm%gf&A?}GLZ5B;&2arA>e7O>8YV=eG{fb}m9$h#+m4|aXs`c?8a zZDaf2iQOOkgD=M@_~XQ-z`G*5lvo_=XYl?Jmbyov2Z3E1D*&g$J7?1Fl|p~?u5n-7 z3Fg>8V!9vQB)~sVIvMOAB27Z){EGd<1^cp3|7ghPobAz#L+<`6-5&fZFcmPbM2G}Rw z;PKdoo*AAUU)lu!GyB+x+rn41kL_3K{#hSwb&lh!#-gmP|Fns1bZNgkIr4{Dchk-} zc?sSRd#+3O`7eOvQ|zAaTv)gMz)S4@GY{bYWBW&uN&AepIC6h@`~k>)!u`p;!nXck zcryML2mA5d{lv8*^n`XkU1!ekkzn^M`|*dk%Rzglzl6>`<#s?H-t&#!{l;;)cb$W5 z5nyHHhXH+&skcszX{(a!-z5ACnzZ<->hp8gkdV@ofZ1yH|wvLzVlBdxbgm zhku?2&p{tbdq1QOMwdBs{uc&rLv|fDYeEaFLc4FYhc++M^MH-}??+(w5!a}`{s7ju zSa4kr0z5DL;aP8Fo-gaeyDvCr2Y_Ak_M^9iGKXymOs`qzwReu?@z{R zY_9oWY2y=&PiVU)97EQfy3kn{(P!PXm0JsM(I#Uw&;H2Ab<+)8HmGI%VY?~mc1MDP0`{XB`x8uUKz zT(3@h`FMtAM72k>t0`p*EY_VADX+-)_HdQ z_~CdcSpR$mdK-aFoePayZ$Ju+(?FBYBer$aX-hA2r4!|qOF98eYcPn^x z`Z5;pVt&LlMspwNiEb2fbL<%J2D>j9ueb?^B0n6s9XO(BW!AQ`=*8-rvZkGS*M~mS zwkcEJRwkcym^RAvEkqU@ar%f&`b#{K+ctFC#JBjXWVVU!>tOpeR>9}!m4Kb`?K$~v zbUT7CVvhQP??C7NaWV3N;631np!4kTF1H|X8M5KvN6T(c@D%jtf~O*X7J3>s#{h4_ zKM%}{>`mYYfHgM-*cG|^hG*|*wEZ(=Y_$6o`rF#ThuG{281J2c``{3;HcON|y0lZT zE_&s*724|5x0Oe4ACXUl9^b|;eMPT7Y31h8@sFX+P+%1Mk_=0owU9r_SNYfVI*QJMEuC{}Xs~>pQuF0Qd4!kW1UA za0&D|VCQdhbf=ZvJyMrclCb2V#v1uTR%tQ%dxtjizgtPLmR*veHNMH7moqY3!Z|_X5js4 zI|Z3xwNt-s8^R z=fe4a5PorJ_ZrU(>*g`!=YsD+w;nKAIkH)SYoLFE%>8E(@Xhen^wYq}@b*0baLriX zy8|0xdkC^ekhzB3-_?tK$0S|}{0^`R^wsD*({6)*L>u6BU{3hgY47`s)5_20$bG&& z7TFZQSUh80C(fnoXgg%%0P9Qn63EmEhr?Uf1ijkF}%BJ?UNinXlKd^9(rx+T7m` zy&>R!vMVxkJOsQ2yyM&x*vh_;3)Yx5bT0UP!1#VwZM|oG480lPJ<9WB7<%`YwE<%_ zPWO$+0dp-_>r0ewdwBEj`V&XzdaA)Y?I z7j277KU1K84ek7$3z+*u0iPY5%MZ{!3|Nc83D75lj|LwK_8pVYO|Ho=@aG=!7BbHt z*TYD_y~2ILy+@cn26+4MthC0hJ9W!~w?#Jq@Elwgo1?&v#dusp#;0%lFt66p+Q7+x z>*-DGonvEs7TIOMf5032^3X@n*7{YxBw#$wk$b6k8U2|z*T59)`k?<5u=bsoYmkdu zz|Q+qkn+~Lb8EwyWfhfIpY`1q3_t7JF)B5`c*E- z4+UQgHeO}cyI8q0ZESCUk!i0VW!kzfq-`6SwDxW7tY>}dFa6oxHp=vq{v#8&rL}kO z)OY$bp7fVkwQK8JA5Gu#u6H4Qw3SK!D`5ZTN$7^J{lKfx)^l$*;68Hy64>>!F>>#X z>tNRl_#NOG=346ub{#B-?EAnxfX`H}Z^Y9I@^W$FSUgH^c5&S;jKZAYubscnnXy-|+KjYdOdVjFFJ`0`ug!8JO^TD&J z1C~HOZ^^#}?Kx-MQ-PbH#rkt@&4XjJA9K7K*gax1zLq*Vch$V?6x;!RFcV zD08fykHe8oM(yOai1hye=bH6vfwgFoUw?JDP zo;%jUlgRuXiRbo7z`20$t;bfnM;;Q)WG^1C}2K{XMYXgS`{_F8xU0 z4S4(L4){FbdbTDVqhqz^TqDkxxe{kBSaa?Pu08A2^)v$53vf@K1zU5oF}&>r_mzo& z_364%b~)Jfvjuotuy@6Mp^e{lxeMTayf3_1-ZR%a(&qbM`}RzC|1kH?!3yy16`cX! z?K_sok-Kkv2)_il6JXBFyRk0=xQBbEbRW={{@qXP*Erpa-G>F^a4+)y^9)$u*F!&! z&Urr^_$7Ql_}#$o!COcB0It(3;Eh>d-ifXTu7fr=R|3Xq+=Gyd9Z!E`hro}Aeizz# zFrWJH{Lrs?vc?71q1d$`Hs@KJ%FLrUcEQebTRZm=+gjt+-g>|o;BNd|XV%A@!1;jt zm9^pi*$vwI5MBYyabNs+mvFq!v325k=sGwExwYV!9E*G1Rp9r*8v)jfb@E&2)xkdk z?+^C9?sMP`z?Xn~VYe0ixJKUt_JcM*){(xgnK{9JhuR11ynhUyg6%@k-fNvR&y2H? zi;evqK4YE;xEH5RXNC5@@GM{qzFWTmxCrP2?1JnTz%#8M_&sE{*$|(O z*}6CjnZMoW4>nJpq2|_mwPW!PV?5r+7X&6j{{S1$Vr`7i^W`LT9RTaax^z7H_lz@U zb9*{?Ua)6Te{{bA`&@5*4@UPGppSvbd|r47(7*k-R@Oo1*!KrN0ay>t-wD9n=v_Ci zQSauX;l~25GxPi`^nJiCn2ZLju_dvy%`j+V^;?E(QJHgLf42eFx@*JQ6s%Ln;ds2y zXukuXt@Hjl*ma=Z`j(egrrxtenQfFgCb1Bi_D|4OnYLLc@$H&Ymo=x{`iQ-Fo#Lgn z*LPc)HDEu@vrXHq(Zr@KcE;88)7E!l65B`Ow0&f;iB3E-aGrOiZ}Cv@G+=LFC&1^` zrIGt=;F;sT(F3qn{YJ7B^li{jfDZuvSZ#(w`z?1iu+Nn3z$d~F1P_9L7HogMciI8@ zZ@`{s{lVI)I|KM5wywSNko^wO-WUgByA$vicx97Iepkt@C294>COiamMRs|Cew6>T zboz@PFR?Wgoibw-CzjA@BcE8KYs&09@v1X6{kE0Ihgi9GZLxCS!&sY})An${ z_k4GQJ%gPGeV&8f`RW079G;oZ_XO}CkS~GUwZARcxiRnBtFxAW1O6HKEabC*t@|fv z?|r-{{Jp?~(2F744LAol51C`yAKEo?F?bk$9so{;cI|D7-1>GOat&Df^3On@4*e3g zn*%+8ZIC~VYy`SXfxDpHlRig&8+!La@0(Mhy(c&v}hBG@%;UL3zN*O7YX%y%Kb zgZCa}KJ8okQ;>ZGwl23uXFJ;n?k)Y$yEa^};>XZ?=D!5qyxO?0WuKe`ZM}Q%aBq~q z3EKA8!#h{j^Oay@SQ1|c1LoZ40O<|TZvuTOa40Yi-9yOSuSS-g_2AsC0!)FnFW0{B z9*o@@N`E7uonP+}p8`w5zX9+5?;LK7>|?;Sejc*D!6za29+`bu?0)1P_aa~|bt>LF zn6WMfxOZ%VUSB^2UWVQiP;Xq;tMhR*GUv%Ulu!L3q12D>iI$!=iB?!0=Q zxc_^GT?l>?z28c#KhJXG7zb~Tt+N%7`40Ia_$|Tb!aE<1)it62?8(lD>&{wqea#E@ z%$N_n0BsM39tG}&?r89?$c@Jc!Ni=z5^DpOxW_$$kWD^afNI zdf5q?_O|t$?FLw5j={ZYCv?u2*g2n!d^qp|_H%%b244#-3)prU?1ljAqVo=9uCIh& z3;s`F=iPN^jU0&1b>jN9e#FM~5Vpp<3%uvsY~W4cH-z?FolLt^phpAdL4Vf7{_w6T z>%#FF>nQZjrQrGQIqx_GW6^dzv~WDI2;g(Kb!|+_(%$;^{8neb=0&}IDYKn2b;hI2 zyotXGZ0oZ?+PX%S3C3oBZT)B)S=MUo-8=Q;c(jprEY@B6)>gXdTbaJCOZ#)&;`E(1 z_8D2m7@R)D%Ea0y*J9^wXZ&6V{W|mUN5J3U`s}+o@CG_#`#JC~@DVci=3AhBK7AT` z8L<0<>%+5bUht-X&wBl_`#tm?(02kqfVWl;&>nsP@B!e{fYX7;(5;B<0qnH70DLvF zqoIvwF6bX)XI#R~(C2}-1dLJsIN&*G_i$zM3xJh57Vn8`fPEg-=W_VeuW~_Nz0ecT zhwo9+-gfHbZ6{VAyR;3q56=X1eJ=Jt1Dh}NXTCib)Vsd*=QGhDVm=YSgTXz(6M!qQ z`5fN1&XIe;W6d6_;Q@U7T%MgKV1x?cu-Kj1rJ`(GKD9s2L!AK_z7uzgMh zp9XK=&qJFx?>Oe?Z0MEIStFld>s~ntFc15~Uk$bvZUEF@3s^hqo!5_n<1f_)a~h|bvbZ-36Yv0G=|fTOVSyYFAYJ~voX z)`+oaYfkl}oq2Qam2VEnKMgpqj@y3J2dumO0pk~}6?tuK7c8x<5V>~R+fM)Xsorsj zmD^sOV7$u3sYz);U)H2{i9wlQe}b{g>r;@{UR_(cyyI&tk3QJ-_d|SGOI@-55%eN} zcd{*k>ySCGe*xA497{iB(o4~1LFh5a&IH~8+<#6**BksO;Jb%!!uuX-4PZTN27*^X zZhyYZ^FHj_vAt_$e(?OrtOs*xUM>K}0M`C9=-WekW_5x0j;^h1(z*Ay8m=E}?>k`E z!}-W}2YbhJ-}Bv}wdWn+EP257_qjfS!_YldI&0Coau0BSyc$|;T*|C3_ej_NNbs-0 zo|8L(e+vEuGUIa2twYz1^JZJe>6zmF*u8Blc>Oz;bHILMbd9<{w1DmFw}8C+v-9B| z-3!|OT@%LUnD#*49&pdTkhaFL33A8zAoN^d=i7Pk9_70{$Nn1N9QoYqdbeL=&%W*c zYh4+Ob?5i}bAW|_cd<9V(SUdFq42)vG(Q_*>)zl#;NIsL^vGIwWtG3v>%DR+R=NKKA>r0(jpSD%5 z&85)RzUyKvGS`A@XAWe>;=DV*tAJhq#&I|JSLm&6-(7wI-4X0wd^oa`plvsO?!b=U zcIMvx&Aau#B_OSCE5QB1yU0g?_rlJ^vpstAH3r#n;2nY2kc~nA7PRZn`f%Mlo+G7^ zc?Vkx8}H1Efz9pDpod}C74Y1)U-L2rI2srYzbH1=k9l_OdsdiFb17Jp-W}cpyk|TE z?^=8vd;|QPfM?fUw6hka*M>H3^Kk*TJ+Qe3@Y|5_I(E+@=fs*Ze&gL9THn_GM)2!G z?*#TvI{^CI;Ormzc7F8XxXg!O%;x(0(5~NZ(7uB_0{lDp)scSyc24gBjK%r)K4cDr z^Q~&&bzf@d_F_y!`Q7$ zLHSr@Kcc<)z82njxE*X9?lamc_bjljSa7_lYiZ|Bu#LHCyDs#h%rR=)Rx-le9{V4NnOk3^ZJ2j`B@}_Tn8Mk)&ly*GvZ@k**TbX=f zlU8P1W%7~PS7gTGKKv78-uK6Y*T?o)a2N2W$Ob|SFJSAvZ5(hd@GS5murW5C2kw(T z*LlwQ-Rnho_dd^;VbHE=$IuyA3EK1b1?*h=D}na}{P#AX-FonMg59r-&sdCMZ|I*D zHlDibxR*qB7j{P?_YTkt zFjw}i-hI$DY0bEQ&jXwcy(4fx&;maSd=cQB+>gjLzb~}0ZUc0IeiJZ;*8%0?xv@3J zS3xg={zCY-!R~cpeHe#%8II1p+Sb|-y9Yf0z6EfPe;v8CV{L5=KdNk&#_j}Q59EET zuhpP81Jt?K{uFz2Y#;V#ANo2IndhvrXmcC9wWiHI(AK)|I<@y6@ep_r;C%XCKz>c^ zv=>_=M*-@^g1K;<>a2$JsNrh_+_wbW;Wm@ z_=VwDh4!4g64eC2@#$k(^qyqwbvK)Il;a@VqU>Vu`z&Uw<_u{u7V#dV{rhe{}xz;aJYbPIwdAT+@;Av%qo8kKFuB1G`Sl@9NN=AwJ`-33z|7e&0rKZXJ^~ z_gAoWax-n_0&j-Q{?va6n8)POxqbw&Mmiy%6?!c6BY^X_4g4I)2ZGl@b}w)Ya?dHp z?7nV2JOTb5GV|n^y*IcIPd|&m=FXVBgFg@US;MnXKb~ci;1AUoywB|Bz*x}(-oicT=A~SE!hqQKSXMbs{%)XO*b+&gr zV*A&B>PNa8a=|v{Rv)&rfBTcSKif-dXAFtyC}{gvr{9i1WYYGbPS8%9$mI2-PMNgW zcq6ml*em-JyziYqfnFWjGi55VJ`4W`_zS@L{R?<@bYr2{f&M12AGBwp?-?h+TkDt8 zc1iF7;P%KTfy=^r2iIwiA5Dv|ZZT#u&`g&1LWYrH{m8 z`#%A;UkDrL;uQQmkIlCL-%*bNY^SUjusi%6@Ex)J7PM#Ud&oU6eK-6Vcz1Z$*nz-$ zfakX{8)HA;y*YCG@GfG1k0Y1&Ts;Nd zrhv6+yzhY3ZHn#?!2BxjLmT@t25YG=NM8fdbp~70hk@S%8;3d9-g@(nX8k&D$0@Dd z1%Poo*Pj5%kL`VDp^f&}7AUu^I>GU)(~mWfcC#b5U;XJ{Tl%@HWF}cypL@! z=p%ri0%Op72XHMs0Y3`xj_Ws+e!wW~Jr`W_-vuuP?_4{NgTa@9t$EKoYvK#wW$206 zyFPqpeHnHW0pIQU?#MmJHQ;(OwqD@vfu7LT;PdEgb0@M6@UFL8pcexUMfW1SvAd`K z623dUYxEBEe*@14-yiv_;QQg<2h6d1!4Txmz4VjVyEnMkxc}+bS~h3qV18g*?0*P$ z{kbm9q1gEl-wAK5t|`~yIbfe#?g4z(bnQQg%ys@av~f%UoVzE1M}YO=olo}?b@p#v znV(mY-wnJ6xHtK3dS3L~g8Lv_13V7wJ<>V61ULrpPW}Nh$K$#(M%RpEwQtvjSl+qu z4zme(G1{yP7?*c7V_6&@n?f%Q?Oo+^@U?(vitF6mxbL`j{toXR@(ZwYWWNtWTN|HZ z(-r<&@I%1!(D#9@3-jvuhafXY#wO_VTEKY4u2a{m`7vkKz96lQ^D-KcRxTgxx^+*n zALBU{-Hw2H?gTha_iUdLtPS(!SRLQG(4M2_+FZ;IeE_t3-R{6hWYX?&wh?{-Z(P!j zLwX2c{hf$x5Vlj`cLUE4o)hdmEDu&T81VhJXNGg+Gr(@Z3dr9;E_mlPF4vK5=K!vN zc3)ltY#p})%-dmrYsP1fMX_^!T=TZ|>@!B=H(&a8KQdPL5$_h(!sYO%!cT=i7`!}i z9P}>%^Kc8`IkzHq=FN3wUabRb%QMn5*P7J7XO^)#pSPjE2-@+S4R0*=xfXa!_#XrJ z0V9x^OXo))=GXSpg0-|5_$=T(Xk+uegzwe=2zY*ZF8Ldh7O?W;AYE6kTd}q0+At61 z!~U#wb2tL}V052C`@X_=QO_dl0)GSeB*0pjiq3nSYh^QR+;iL~tiuby?jPpC97!v; zj_k|zq)ysCtx03jW^~EbDH99Ml{(jlb9q78xdx;&uiA#b7P&bSyJm9s*haZ_%JgXr z+S!MBv2XLPK7N!(W3P6aWvV{5!ne64cq?p}Pzp(f0qD-faHm|HXP5`%L`y bI;^-a{}0y(Y%-hs5;Z;R^n!orY`Omfa|VmH literal 0 HcmV?d00001 diff --git a/audio_prompts/en_narrator_deep.npz b/audio_prompts/en_narrator_deep.npz new file mode 100644 index 0000000000000000000000000000000000000000..93f70800e788f37fd64bbe1494f85f88d547936c GIT binary patch literal 55988 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 bI;^-a{}0y(Y%-hs5;Z;R^n!orY`Omfa|VmH literal 0 HcmV?d00001 diff --git a/classes/video.py b/classes/video.py index 736b53c..afb5518 100644 --- a/classes/video.py +++ b/classes/video.py @@ -48,7 +48,7 @@ class Video: script = await generate_script(self.idea['title'], self.idea['description']) script = json.loads(script) with open(os.path.join( self.path, "script.json"), "w") as f: - json.dump(script, f) + json.dump(script, f, indent=4) f.close() else: with open(os.path.join(self.path, "script.json"), "r") as f: @@ -60,7 +60,8 @@ class Video: "title": self.idea['title'], "description": self.idea['description'] + "\n\n" + credits, } - await generate_thumbnail( self.path, self.idea['title'], self.idea['description']) + if input("Do you want to generate a thumbnail ? (y/N) : ").lower() == "y": + await generate_thumbnail( self.path, self.idea['title'], self.idea['description']) videoid = await upload_video( self.path, self.idea['title'], self.metadata['description'], 28, "", "private", self.parent.path) printm(f"Your video is ready! You can find it in { self.path}") video_meta_file = { diff --git a/generators/montage.py b/generators/montage.py index bb24a15..02ddd7d 100644 --- a/generators/montage.py +++ b/generators/montage.py @@ -10,7 +10,7 @@ from moviepy.editor import concatenate_videoclips, CompositeAudioClip, concatena from moviepy.audio.io.AudioFileClip import AudioFileClip from moviepy.audio.fx.all import volumex, audio_fadein, audio_fadeout # type: ignore from utils.misc import getenv - +from utils.wiki_downloader import download_image as wiki_download_image unsplash_access = getenv("unsplash_access_key") if not unsplash_access: @@ -22,64 +22,82 @@ async def prepare(path): script = json.load(f) f.close() if not os.path.exists(path + "/slides"): os.mkdir(path + "/slides") - fresh = False - if not os.path.exists(path + "/audio"): - os.mkdir(path + "/audio") - fresh = True - with open("prompts/marp.md", 'r', encoding='utf-8') as f: + if not os.path.exists(path + "/audio"): os.mkdir(path + "/audio") + choosen_voice = random.choice(voices) + with open(os.path.join(os.getcwd(), "prompts", "marp.md"), 'r', encoding='utf-8') as f: marp = f.read() - f.close() - if fresh: - choosen_voice = random.choice(voices) - generator = VoiceGenerator(speaker=choosen_voice) - for i in range(len(script)): - audio_path = path + "/audio/audio" + str(i) + ".wav" - if not os.path.exists(audio_path): - generator.generate_voice(audio_path, script[i]['spoken']) - if "image" in script[i]: - if os.path.exists(path + "/slides/assets/slide" + str(i) + ".md"): - #skip this slide + f.close() + for i in range(len(script)): + audio_path = os.path.join(path, "audio", "audio" + str(i) + ".wav") + generator = None + if not os.path.exists(audio_path): + if not generator: + generator = VoiceGenerator(speaker=choosen_voice) + print("Generating audio for slide " + str(i)) + generator.generate_voice(audio_path, script[i]['spoken']) + if "image" in script[i]: + if os.path.exists(os.path.join(path, "slides", "slide" + str(i) + ".md")) and os.path.exists(os.path.join(path, "slides", "slide" + str(i) + ".png")): + #skip this slide + continue + if not os.path.exists(path + "/slides/assets"): + os.mkdir(path + "/slides/assets") + url= unsplash_url + script[i]['image'].replace("+", ",") + r = requests.get(url) + real_url = r.json()['urls']['raw'] + with open(path + "/slides/assets/slide" + str(i) + ".jpg", 'wb') as f: + f.write(requests.get(real_url).content) + f.close() + content = marp + f"\n\n![bg 70%](assets/slide{i}.jpg)" + with open(path + "/slides/slide" + str(i) + ".md", 'w', encoding='utf-8') as f: + f.write(content) + elif "wikimage" in script[i]: + if os.path.exists(os.path.join(path, "slides", "slide" + str(i) + ".md")) and os.path.exists(os.path.join(path, "slides", "slide" + str(i) + ".png")): + #skip this slide + continue + if not os.path.exists(path + "/slides/assets"): + os.mkdir(path + "/slides/assets") + r = 0 + while True: + try: + print("Trying to download image for slide " + str(i)) + wiki_download_image(script[i]['wikimage'], os.path.abspath(os.path.join(path, "slides", "assets", "slide" + str(i) + ".jpg"))) + print("Downloaded image for slide with wikiimage " + str(i)) + break + except: + r += 1 + if r > 5: + break continue - if not os.path.exists(path + "/slides/assets"): - os.mkdir(path + "/slides/assets") - url= unsplash_url + script[i]['image'] - r = requests.get(url) - real_url = r.json()['urls']['raw'] - with open(path + "/slides/assets/slide" + str(i) + ".jpg", 'wb') as f: - f.write(requests.get(real_url).content) - f.close() - content = marp + f"\n\n![bg 70%](assets/slide{i}.jpg)" - with open(path + "/slides/slide" + str(i) + ".md", 'w', encoding='utf-8') as f: - f.write(content) - elif "markdown" in script[i]: - if os.path.exists(path + "/slides/slide" + str(i) + ".md"): - #skip this slide - continue - with open(path + "/slides/slide" + str(i) + ".md", 'w', encoding='utf-8') as f: - f.write(marp + "\n\n" + script[i]['markdown']) - elif "huge" in script[i]: - #use fit - if os.path.exists(path + "/slides/slide" + str(i) + ".md"): - #skip this slide - continue - with open(path + "/slides/slide" + str(i) + ".md", 'w', encoding='utf-8') as f: - f.write(marp + "\n\n# " + script[i]['huge']) - else: - if os.path.exists(path + "/slides/slide" + str(i) + ".md"): - #skip this slide - continue - with open(path + "/slides/slide" + str(i) + ".md", 'w', encoding='utf-8') as f: - f.write(marp + "\n\n") # blank slide + content = marp + f"\n\n![bg 70%](assets/slide{i}.jpg)" + with open(path + "/slides/slide" + str(i) + ".md", 'w', encoding='utf-8') as f: + f.write(content) + elif "markdown" in script[i]: + if os.path.exists(path + "/slides/slide" + str(i) + ".md") and os.path.exists(path + "/slides/slide" + str(i) + ".png"): + #skip this slide + continue + with open(path + "/slides/slide" + str(i) + ".md", 'w', encoding='utf-8') as f: + f.write(marp + "\n\n" + script[i]['markdown']) + elif "huge" in script[i]: + #use fit + if os.path.exists(path + "/slides/slide" + str(i) + ".md") and os.path.exists(path + "/slides/slide" + str(i) + ".png"): + #skip this slide + continue + with open(path + "/slides/slide" + str(i) + ".md", 'w', encoding='utf-8') as f: + f.write(marp + "\n\n# " + script[i]['huge']) + else: + if os.path.exists(path + "/slides/slide" + str(i) + ".md") and os.path.exists(path + "/slides/slide" + str(i) + ".png"): + #skip this slide + continue + with open(path + "/slides/slide" + str(i) + ".md", 'w', encoding='utf-8') as f: + f.write(marp + "\n\n") # blank slide for i in range(len(script)): markdown_path = os.path.join(path, f"slides/slide{i}.md") markdown_path = os.path.abspath(markdown_path) image_path = os.path.join(path, f"slides/slide{i}.png") image_path = os.path.abspath(image_path) - if os.path.exists(markdown_path): - #skip this slide - continue - command = f'marp.exe "{markdown_path}" -o "{image_path}" --allow-local-files' - os.system(command) + if not os.path.exists(image_path): + command = f'marp.exe "{markdown_path}" -o "{image_path}" --allow-local-files' + os.system(command) return script def convert_seconds_to_time_string(seconds): @@ -113,8 +131,6 @@ async def mount(path, script): ]) length = complete_audio.duration total_length += length - print(script[i]) - print(script[i]['spoken']) srt = subs(length, total_length, script[i]['spoken'], srt, i) slide = ImageClip(path + "/slides/slide" + str(i) + ".png").set_duration(length) slide = slide.set_audio(complete_audio) @@ -122,7 +138,7 @@ async def mount(path, script): randmusic = random.choice(os.listdir("musics")) while randmusic.endswith(".txt"): randmusic = random.choice(os.listdir("musics")) randpath = "musics/" + randmusic - music = AudioFileClip(randpath).set_duration(total_length) + music = AudioFileClip(randpath) music = audio_fadein(music, 20) music = audio_fadeout(music, 20) music = volumex(music, 0.2) @@ -131,6 +147,7 @@ async def mount(path, script): for i in range(int(total_length / music.duration)): musics.append(music) music = concatenate_audioclips(musics) + music = music.set_duration(total_length) final_clip = concatenate_videoclips(clips, method="compose") existing_audio = final_clip.audio final_audio = CompositeAudioClip([existing_audio, music]) @@ -142,4 +159,4 @@ async def mount(path, script): f.close() return music_credit or "" else: - return None \ No newline at end of file + return "" \ No newline at end of file diff --git a/generators/speak.py b/generators/speak.py index 9b06176..83d8604 100644 --- a/generators/speak.py +++ b/generators/speak.py @@ -1,5 +1,5 @@ - import os +from pydub import AudioSegment, silence fakenames = { "Alexander": "p230", @@ -11,16 +11,70 @@ fakenames = { voices = ["Alexander", "Benjamin", "Amelia", "Katherine", "Johanne"] + +def remove_blank_moments(file_path, silence_thresh= -50, silence_chunk_len=500): + # Load audio file + audio = AudioSegment.from_wav(file_path) + + # Detect non-silent parts + nonsilent_data = silence.detect_nonsilent(audio, min_silence_len=silence_chunk_len, silence_thresh=silence_thresh) + + # Create new audio file + final_audio = AudioSegment.empty() + + # Iterate over non-silent parts and append to the final_audio with 0.5 seconds before and after each segment + for idx, (start_i, end_i) in enumerate(nonsilent_data): + start_i = max(0, start_i - 500) # 0.5 seconds before + end_i += 500 # 0.5 seconds after + + segment = audio[start_i:end_i] + + # Only append silence after the first segment + if idx > 0: + final_audio += AudioSegment.silent(duration=500) + + final_audio += segment + # Save the result + if not os.path.exists(os.path.abspath(os.path.join(os.getcwd(), "temp"))): + os.mkdir(os.path.abspath(os.path.join(os.getcwd(), "temp"))) + tempfile_path = os.path.abspath(os.path.join(os.getcwd(), "temp", "temp.wav")) + final_audio.export(tempfile_path, format="wav") + os.remove(file_path) + os.rename(tempfile_path, file_path) + + +def optimize_string_groups(strings): + optimized_groups = [] + current_group = [] + current_length = 0 + + for string in strings: + string_length = len(string) + len(current_group) # Account for spaces between strings + if current_length + string_length <= 100: + current_group.append(string) + current_length += string_length + else: + optimized_groups.append(' '.join(current_group)) # Join strings with spaces + current_group = [string] + current_length = len(string) + + if current_group: + optimized_groups.append(' '.join(current_group)) + + return optimized_groups + class VoiceGenerator: def __init__(self, mode="Bark", speaker=""): self.mode = mode self.speaker = speaker if mode == "Bark": os.environ["XDG_CACHE_HOME"] = os.path.join(os.getcwd(), "bark_cache") - from bark import preload_models, generation - + from bark import preload_models + print("Loading Bark voice generator") preload_models() - self.speaker = "v2/en_speaker_6" + #self.speaker = os.path.abspath(os.path.join(os.getcwd(), "audio_prompts", "en_male_professional_reader.npz")) + self.speaker = os.path.join(os.getcwd(), "audio_prompts", "en_narrator_light_bg.npz") + print(f"Generating voice for Bark with speaker {self.speaker}") else: from TTS.api import TTS model = "tts_models/en/vctk/vits" @@ -43,20 +97,27 @@ class VoiceGenerator: import numpy as np import nltk sentences = nltk.sent_tokenize(text) + sentences = optimize_string_groups(sentences) + print(sentences) pieces = [] silence = np.zeros(int(0.25 * SAMPLE_RATE)) # quarter second of silence for sentence in sentences: - audio_array = generate_audio(sentence, history_prompt=self.speaker) - pieces += [audio_array, silence.copy()] + if not sentence == "": + audio_array = generate_audio(sentence, history_prompt=self.speaker) + pieces += [audio_array, silence.copy()] audio_array = np.concatenate(pieces) soundfile.write(path, audio_array, SAMPLE_RATE, format="WAV", subtype="PCM_16") - rate, data = wavread(path) - reduced_noise = nr.reduce_noise(y=data, sr=rate) - os.remove(path) - wavwrite(path, rate, reduced_noise) + ''' + remove silence + ''' + remove_blank_moments(path) else: self.tts.tts_to_file(text=text, file_path=path, speaker=self.speaker, speed=1, emotion="Happy") if __name__ == "__main__": + import logging + logging.basicConfig(level=logging.INFO) + print("Testing voice generator") generator = VoiceGenerator() - generator.generate_voice("test/test_r.wav", "Hello there!") - generator.generate_voice("test/teste_r.wav", "This is a test. I like the words python, django and flask. Betty bought a bit of butter but the butter was bitter. So she bought some better butter to make the bitter butter better.") \ No newline at end of file + print("Loaded voice generator") +# generator.generate_voice("test/test_r.wav", "Hello there!") + generator.generate_voice("test/tast_timbernerslee.wav", "But his greatest claim to fame is undoubtedly his invention of the World Wide Web back in 1989. Can you imagine a world without the internet? [Laughs] No, thank you!") \ No newline at end of file diff --git a/generators/thumbnail.py b/generators/thumbnail.py index 64afedc..101452a 100644 --- a/generators/thumbnail.py +++ b/generators/thumbnail.py @@ -28,6 +28,11 @@ Answer without anything else, just with the 2 textes. Answer with text1 on the f Here is the title of the video: [TITLE] Here is the description of the video: [DESCRIPTION]''' + +# TODO: make jpg qith 90% quality default when generating the image to avoid having to convert it later + + + async def rand_gradient(image): randr = random.SystemRandom().randint(1, 20) randg = random.SystemRandom().randint(1, 20) @@ -110,11 +115,20 @@ async def generate_image(path, text1, text2): drawtext2.text((imgtext2.size[0]//8*2.5, imgtext2.size[1]//5*2), text2def, font=font2, fill=(textcolor2[0], textcolor2[1], textcolor2[2])) imgtext2 = imgtext2.rotate(5, expand=True) #paste the textes on the image - img.paste(bcg, (0, 0), bcg) + bcg = bcg.convert('RGBA') + #also set the bcg size to the image size + bcg = bcg.resize((1920, 1080)) + img.paste(bcg, (0, 0), bcg) # TODO: make it work with standard pngs (non rgba) img.paste(imgtext1, (0, 0-img.size[1]//8), imgtext1) if len(text1def.split("\n")) > 2: #if the text is too long, put the second text on the third line img.paste(imgtext2, (0, img.size[1]//8), imgtext2) else: img.paste(imgtext2, (0, 0), imgtext2) - img.save(path + "/miniature.png") - return path + "/miniature.png" \ No newline at end of file + #disable the alpha channel + img = img.convert('RGB') + img_path = os.path.abspath(os.path.join(path, "thumbnail.jpg")) + for quality in range(100, 0, -1): + img.save(img_path, quality=quality) + if os.path.getsize(img_path) < 2000000: + break + return img_path \ No newline at end of file diff --git a/main.py b/main.py index 55c3cff..828eaad 100644 --- a/main.py +++ b/main.py @@ -11,15 +11,15 @@ from utils.openaicaller import openai logging.basicConfig(level=logging.INFO) async def main(): - printm("Loading...") - await asyncio.sleep(1) - clear_screen() + #printm("Loading...") + #await asyncio.sleep(1) + #clear_screen() printm(loadingmessage) - await asyncio.sleep(4) - clear_screen() - await asyncio.sleep(1) + #await asyncio.sleep(4) + #clear_screen() + await asyncio.sleep(0.5) printm("Welcome in FABLE, the Film and Artistic Bot for Lively Entertainment!") - await asyncio.sleep(1) + await asyncio.sleep(0.5) printm(f"This program will generate for you complete {bcolors.FAIL}{bcolors.BOLD}YouTube{bcolors.ENDC} videos, as well as uploading them to YouTube.") if not os.path.exists('env.yaml'): printm("It looks like you don't have an OpenAI API key yet. Please paste it here:") @@ -57,9 +57,17 @@ async def main(): await channel.load(channel_name) printm("Now, let's create a video!") printm("Here are all the ideas you have:") + printm("0. Generate new ideas") for i, idea in enumerate(channel.ideas): printm(f"{i+1}. {idea['title']}") index = input("Which idea do you want to create a video for : ") + if index == "0": + printm("Generating new ideas...") + await channel.generate_ideas() + printm("Here are your new ideas:") + for i, idea in enumerate(channel.ideas): + printm(f"{i+1}. {idea['title']}") + index = input("Which idea do you want to create a video for : ") idea = channel.ideas[int(index)-1] video = await channel.generate_video(idea) printm("Done!") diff --git a/musics/Ghostrifter-Official-Lost-In-Thought.txt b/musics/Ghostrifter-Official-Lost-In-Thought.txt index d07e286..68bf08d 100644 --- a/musics/Ghostrifter-Official-Lost-In-Thought.txt +++ b/musics/Ghostrifter-Official-Lost-In-Thought.txt @@ -1,3 +1,3 @@ -Lost In Thought by Ghostrifter bit.ly/ghostrifter-yt +Lost In Thought by Ghostrifter Creative Commons — Attribution-NoDerivs 3.0 Unported — CC BY-ND 3.0 -Music promoted by https://www.chosic.com/free-music/all/ \ No newline at end of file +Music promoted by chosic \ No newline at end of file diff --git a/musics/When-I-Was-A-Boy.txt b/musics/When-I-Was-A-Boy.txt index ffcde35..b239dd2 100644 --- a/musics/When-I-Was-A-Boy.txt +++ b/musics/When-I-Was-A-Boy.txt @@ -1,4 +1,3 @@ -When I Was A Boy by Tokyo Music Walker | https://soundcloud.com/user-356546060 -Music promoted by https://www.chosic.com/free-music/all/ -Creative Commons CC BY 3.0 -https://creativecommons.org/licenses/by/3.0/ \ No newline at end of file +When I Was A Boy by Tokyo Music Walker +Music promoted by free-stock-music +Creative Commons CC BY 3.0 \ No newline at end of file diff --git a/musics/aila-scott-sin-and-sensitivity-rendition-of-bachs-air.txt b/musics/aila-scott-sin-and-sensitivity-rendition-of-bachs-air.txt index acff10d..07f6267 100644 --- a/musics/aila-scott-sin-and-sensitivity-rendition-of-bachs-air.txt +++ b/musics/aila-scott-sin-and-sensitivity-rendition-of-bachs-air.txt @@ -1,4 +1,3 @@ -Sin and Sensitivity (Rendition of Bach’s "Air") by Aila Scott • Johann Sebastian Bach | https://ailascott.com -Music promoted by https://www.free-stock-music.com -Creative Commons / Attribution 4.0 International (CC BY 4.0) -https://creativecommons.org/licenses/by/4.0/ \ No newline at end of file +Sin and Sensitivity (Rendition of Bach’s "Air") by Aila Scott • Johann Sebastian Bach +Music promoted by free-stock-music +Creative Commons / Attribution 4.0 International (CC BY 4.0) \ No newline at end of file diff --git a/utils/uploader.py b/utils/uploader.py index 53ecc1d..6908c4c 100644 --- a/utils/uploader.py +++ b/utils/uploader.py @@ -41,7 +41,10 @@ VALID_PRIVACY_STATUSES = ('public', 'private', 'unlisted') async def get_authenticated_service(credentialsPath="", force_refresh=False): CLIENT_SECRETS_FILE = "" try: - CLIENT_SECRETS_FILE=os.path.join(credentialsPath, "client_secret.json") + if os.path.exists(os.path.join(credentialsPath, "client_secret.json")): + CLIENT_SECRETS_FILE=os.path.join(credentialsPath, "client_secret.json") + else: + raise FileNotFoundError("No client_secret.json file found in the specified path !") except: listdir = os.listdir(credentialsPath) for file in listdir: @@ -146,25 +149,16 @@ async def upload_video(path, title, description, category, keywords, privacyStat 'keywords': keywords, 'privacyStatus': privacyStatus } - refresh = False - while True: - try: - youtube = await get_authenticated_service(credentials_path, force_refresh=refresh) - videoid = await initialize_upload(youtube, options) - await upload_thumbnail(videoid, path + "/miniature.png", credentials_path, youtube) - return videoid - except HttpError as e: - print('An HTTP error %d occurred:\n%s' % (e.resp.status, e.content)) - #escape the loop - break - except: - #refresh the token - if not refresh: - refresh = True - else: - #escape the loop - break - + youtube = await get_authenticated_service(credentials_path, force_refresh=False) + print("Uploading video...") + try: + videoid = await initialize_upload(youtube, options) + except: + youtube = await get_authenticated_service(credentials_path, force_refresh=True) + videoid = await initialize_upload(youtube, options) + thumb_path = os.path.abspath(os.path.join(path, "thumbnail.jpg")) + await upload_thumbnail(videoid, thumb_path, credentials_path, youtube) + return videoid async def upload_thumbnail(video_id, file, credentials_path="", youtube=None): diff --git a/utils/wiki_downloader.py b/utils/wiki_downloader.py index ab07663..86b08bc 100644 --- a/utils/wiki_downloader.py +++ b/utils/wiki_downloader.py @@ -13,7 +13,7 @@ def download_image(query, download_path): driver = uc.Chrome(options=options) try: - driver.get(f"https://www.google.com/search?site=&tbm=isch&source=hp&biw=1873&bih=990&tbs=isz:l&q=site:wikipedia.org+{query.replace(' ', '+')}") + driver.get(f"https://www.google.com/search?site=&tbm=isch&source=hp&biw=1873&bih=99&q=site:wikipedia.org+{query.replace(' ', '+')}") time.sleep(2) tos = driver.find_elements(By.CLASS_NAME, "VfPpkd-vQzf8d") @@ -21,11 +21,10 @@ def download_image(query, download_path): if to.text.lower() == "tout refuser": to.click() break - - time.sleep(10) + time.sleep(1) image = driver.find_element(By.CLASS_NAME, "rg_i") image.click() - time.sleep(2) + time.sleep(5) image = driver.find_element(By.CLASS_NAME, "r48jcc").get_attribute("src") or "" image_content = None