Ë
    äÝ¶jÐ]  ã                  óð  — d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlmZ ddlmZmZ ddlmZ ddlZ ej*                  ej,                  d¬«        ej.                  d	«      Z ed
«      Zedz  Zedz  Zedz  Zedz  Zedz  dz  Z ed«      Zedz  dz  Z dZ!dZ"eeefD ]  Z#e#jI                  dd¬«       Œ g d¢Z%d5d„Z&d6d„Z'd7d„Z(d8d„Z)d9d„Z*d:d„Z+d;d„Z,d<d „Z-d=d!„Z.d>d"„Z/d?d@d#„Z0dAd$„Z1dAd%„Z2dBd&„Z3dCd'„Z4dDd(„Z5dEd)„Z6dFd*„Z7dGd+„Z8dHd,„Z9d7d-„Z:d.Z; G d/„ d0«      Z<d7d1„Z=e>d2k(  r;ddl?Z? e@e?j‚                  «      d3kD  re?j‚                  d3   d4k(  r e:«        y e=«        yy)Iz6Private YouTube Shorts generator dashboard and worker.é    )ÚannotationsN)ÚPath)Úparse_qsÚurlparse)Úmake_serverz%%(asctime)s %(levelname)s %(message)s)ÚlevelÚformatÚyoutube_generatorz/root/workspaceÚytshortsÚyoutube_generator_datazgenerator.dbÚmediaÚfootageÚsourcesz"/root/.agent-reach-venv/bin/yt-dlpÚshorts_datazyoutube-cookies.txtz*https://www.youtube.com/@OrbitalNCG/videoszen-US-EmmaNeuralT©ÚparentsÚexist_ok))zThe Player Who Knew My BaseaÔ  Someone joined my Minecraft server and immediately asked why I kept moving my chests. I had never seen their username before. I ignored them, but five minutes later, a single torch appeared outside my base. Then another appeared beside the river. The torches formed a trail through the forest and ended at a buried staircase. At the bottom was a room filled with maps of my builds. Every map had one section circled in red. I followed the circles and found a hidden tunnel underneath my storage room. The tunnel opened into a perfect copy of my base, down to the last flower pot. A sign waited by the door: I BUILT THIS FOR YOU. Behind me, footsteps echoed. The stranger typed one message: "You finally found the safe base.")z The Last Jump Was Not In The Mapaê  I was one jump away from finishing the hardest parkour map on the server when the course changed. A block appeared behind me, sealing the path back. Then the next platform vanished. I thought the map was broken, so I checked the timer. It was still counting. Ahead, a row of invisible blocks stretched over the void. I could not see them, but every few seconds, one flashed for half a second. I started jumping on the flashes. The first three worked. The fourth nearly sent me into the darkness. At the final platform, a sign appeared with my username on it. It said, YOU ARE NOT THE FIRST PLAYER HERE. The exit opened, but it led back to the beginning. This time, the timer read zero, and something was standing where the finish line used to be.)zThe Chest That Refilled Itselfa  Every night, one chest in my Minecraft base refilled itself with exactly one diamond. I thought my friends were messing with me, so I locked the room with iron doors and covered the floor in pressure plates. The next morning, the diamond was there. No plates had moved. No doors had opened. I placed a camera mod in the corner and waited. At midnight, the torchlight flickered. A shadow appeared beside the chest, but there was no player attached to it. The shadow placed a diamond, turned toward the camera, and disappeared through the wall. I followed the wall outside and found a one-block tunnel leading underground. At the end was a second base, abandoned except for a sign: I PROMISED I WOULD PAY YOU BACK. The username on the sign belonged to the first player who ever joined my server.c                 ó<   — t        t        j                  «       «      S )N)ÚintÚtime© ó    ú$/root/workspace/youtube_generator.pyÚnowr   M   s   € ÜŒt�y‰y‹{ÓÐr   c                 óf   — t        j                  t        d¬«      } t         j                  | _        | S )Né   ©Útimeout)Úsqlite3ÚconnectÚDBÚRowÚrow_factory©Údbs    r   Ú
db_connectr&   Q   s"   € Ü	�‰œ RÔ	(€BÜ—[‘[€B„NØ€Ir   c                 ód   — t        «       5 } | j                  d«       d d d «       y # 1 sw Y   y xY w)Na  
        CREATE TABLE IF NOT EXISTS settings (key TEXT PRIMARY KEY, value TEXT NOT NULL);
        CREATE TABLE IF NOT EXISTS jobs (
          id TEXT PRIMARY KEY, source_url TEXT NOT NULL, story_mode TEXT NOT NULL,
          reddit_text TEXT NOT NULL DEFAULT '', status TEXT NOT NULL, message TEXT NOT NULL DEFAULT '',
          title TEXT NOT NULL DEFAULT '', story TEXT NOT NULL DEFAULT '',
          source_video TEXT NOT NULL DEFAULT '', source_license TEXT NOT NULL DEFAULT '',
          source_credit TEXT NOT NULL DEFAULT '', output_path TEXT NOT NULL DEFAULT '',
          created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL
        );
        INSERT OR IGNORE INTO settings(key,value) VALUES ('source_url', 'https://www.youtube.com/@OrbitalNCG/videos');
        INSERT OR IGNORE INTO settings(key,value) VALUES ('story_mode', 'original');
        INSERT OR IGNORE INTO settings(key,value) VALUES ('voice', 'en-US-AvaNeural');
        INSERT OR IGNORE INTO settings(key,value) VALUES ('auto_enabled', '0');
        )r&   Úexecutescriptr$   s    r   Úinit_dbr)   W   s1   € Ü	‹ð ˜Ø
×Ñð ô 	÷÷ ñ ús   ‹&¦/c                 ó˜   — t        «       5 } | j                  d«      D �ci c]  }|d   |d   “Œ c}cd d d «       S c c}w # 1 sw Y   y xY w)NzSELECT key,value FROM settingsÚkeyÚvalue)r&   Úexecute)r%   Úrows     r   Úsettingsr/   j   sP   € Ü	‹ð b˜Ø46·J±JÐ?_Ó4`Öa¨S��E‘
˜C ™LÑ(Òa÷bñ bùÚa÷bð bús   ‹A Ÿ;¯A »A Á A	c           
     ó�   — t        j                  |d¬«      j                  «       } | |ddt        t	        |«      «      fg«       |gS )NF)Úensure_ascii)úContent-Typezapplication/json; charset=utf-8úContent-Length)ÚjsonÚdumpsÚencodeÚstrÚlen)ÚstartÚbodyÚstatusÚdatas       r   Újson_responser=   o   sE   € Ü�:‰:�d¨Ô/×6Ñ6Ó8€DÙ	ˆ&ÐFÐIYÔ[^Ô_bÐcgÓ_hÓ[iÐHjÐkÔlØˆ6€Mr   c                ó    — t        | j                  d«      xs d«      }|r| d   j                  |«      nd}t        j                  |xs d«      S )NÚCONTENT_LENGTHr   z
wsgi.inputs   {})r   ÚgetÚreadr4   Úloads)ÚenvironÚlengthÚraws      r   Ú	body_jsonrF   u   sG   € Ü�—‘Ð-Ó.Ò3°!Ó4€FÙ06ˆ'�,Ñ
×
$Ñ
$ VÔ
,¸E€CÜ�:‰:�c’l˜UÓ#Ð#r   c                 óÐ   — t        «       5 } | j                  d«      D �cg c]  }t        |«      ‘Œ }}d d d «       D ]  }|d   r	d|d   › d�nd|d<   Œ |S c c}w # 1 sw Y   Œ*xY w)Nz4SELECT * FROM jobs ORDER BY created_at DESC LIMIT 50Úoutput_pathú
/api/jobs/Úidú	/downloadÚ Údownload_url)r&   r-   Údict)r%   r.   Úrowss      r   Ú	jobs_listrP   {   s€   € Ü	‹ð i˜Ø%'§Z¡ZÐ0fÓ%gÖh˜c”�S•	ÐhˆÐh÷iàò ^ˆØCFÀ}ÒCU 
¨3¨t©9¨+°YÑ?Ð[]ˆˆNÒð^à€Kùò i÷ið iús   ‹AŸA±AÁAÁA%c                ó�   — t        | j                  «       «      }|j                  dv xr d|j                  v xs d|j                  v S )N>   ÚhttpÚhttpszyoutube.comzyoutu.be)r   ÚstripÚschemeÚnetloc)ÚurlÚps     r   Úvalid_sourcerY   ƒ   sA   € Ü�—‘“Ó€AØ�8‰8Ð(Ð(Òb¨m¸q¿x¹xÐ.GÒ.aÈ:ÐYZ×YaÑYaÐKaÐbr   c                óÞ  — t        | j                  d«      xs! t        «       j                  d«      xs t        «      j	                  «       }t        | j                  d«      xs t        «       j                  d«      xs d«      }t        |«      st        d«      ‚|dvrt        d«      ‚t        | j                  d«      xs d«      j	                  «       d d	 }|dk(  rt        |«      d
k  rt        d«      ‚t        j                  «       j                  d d }t        «       }t        «       5 }|j                  d||||d||f«       |j                  «        d d d «       |ddœS # 1 sw Y   ŒxY w)NÚ
source_urlÚ
story_modeÚoriginalz3Source must be a YouTube URL or channel videos URL.>   r]   Úreddit_textz+Story mode must be original or reddit_text.r^   rL   ià.  éP   z<Paste at least 80 characters of Reddit text for Reddit mode.é   zjINSERT INTO jobs(id,source_url,story_mode,reddit_text,status,created_at,updated_at) VALUES (?,?,?,?,?,?,?)Úqueued)rJ   r;   )r7   r@   r/   ÚDEFAULT_SOURCErT   rY   Ú
ValueErrorr8   ÚuuidÚuuid4Úhexr   r&   r-   Úcommit)ÚpayloadÚsourceÚmoder^   Újob_idÚstampr%   s          r   Ú
create_jobrm   ˆ   s?  € Ü�—‘˜\Ó*Ò\¬h«j¯n©n¸\Ó.JÒ\ÌnÓ]×cÑcÓe€FÜˆw�{‰{˜<Ó(ÒV¬H«J¯N©N¸<Ó,HÒVÈJÓW€DÜ˜ÔÜÐNÓOÐOØÐ.Ñ.ÜÐFÓGÐGÜ�g—k‘k -Ó0Ò6°BÓ7×=Ñ=Ó?ÀÀÐG€KØˆ}Ò¤ [Ó!1°BÒ!6ÜÐWÓXÐXÜ�Z‰Z‹\×Ñ˜c˜rÐ"€FÜ‹E€EÜ	‹ð ˜Ø
�
‰
ÐØ˜F D¨+°xÀÈÐNô	Pà
�	‰	Œ÷ð  HÑ-Ð-÷	ð ús   Ä,*E#Å#E,c                ó²   — | dk(  r3t        j                  dd|«      j                  «       }d}d|z   }||d d fS t        j                  t
        «      \  }}||fS )Nr^   z\s+ú zThe Story Nobody BelievedzCThis story sounds made up, but the ending is impossible to ignore. iPF  )ÚreÚsubrT   ÚrandomÚchoiceÚSTORIES)rj   r^   ÚcleanÚtitleÚstorys        r   Úchoose_storyrx   ›   sb   € Øˆ}ÒÜ—‘�v˜s KÓ0×6Ñ6Ó8ˆà+ˆØVÐY^Ñ^ˆØ�e˜F˜U�mÐ#Ð#Ü—=‘=¤Ó)�L€Eˆ5Ø�%ˆ<Ðr   c                ó4   — t        j                  | dd|¬«      S )NT)ÚtextÚcapture_outputr   )Ú
subprocessÚrun)Úargsr   s     r   Úrun_commandr   ¦   s   € Ü�>‰>˜$ T¸$ÈÔPÐPr   c                ód  — t        t        «      g}t        j                  «       r|dt        t        «      gz  }|dddddd| gz  }t        j                  d| «       t        |«      }|j                  d	k7  rt        |j                  d
d  xs d«      ‚t        j                  |j                  «      }t        |j                  d«      xs d«      }d|j                  «       vrt        d|xs d› d�«      ‚t        |j                  d«      xs! t        j                   «       j"                  d d «      |fS )Nú	--cookiesú--js-runtimesÚnodeú--remote-componentsú
ejs:githubú--no-playlistú--dump-single-jsonzProbing source metadata: %sr   é|üÿÿzCould not read YouTube source.ÚlicenserL   zcreative commonsz2Source rejected: license is not Creative Commons (Úmissingz).rJ   é   )r7   ÚYTDLPÚCOOKIESÚis_fileÚloggerÚinfor   Ú
returncodeÚRuntimeErrorÚstderrr4   rB   Ústdoutr@   Úlowerrd   re   rf   )rW   r~   Úresultr<   Úlicense_names        r   Úsource_metadatar˜   ª   s  € Ü”‹Jˆ<€DÜ‡�ÔØ�œc¤'›lÐ+Ñ+ˆØˆ_˜fÐ&;¸\È?Ð\pÐruÐvÑv€DÜ
‡K�KÐ-¨sÔ3Ü˜Ó€FØ×Ñ˜AÒÜ˜6Ÿ=™=¨¨Ð/ÒSÐ3SÓTÐTÜ�:‰:�f—m‘mÓ$€DÜ�t—x‘x 	Ó*Ò0¨bÓ1€LØ ×!3Ñ!3Ó!5Ñ5ÜÐOÐP\ÒPiÐ`iÐOjÐjlÐmÓnÐnÜˆt�x‰x˜‹~Ò5¤§¡£×!1Ñ!1°"°1Ð!5Ó6¸Ð<Ð<r   c           
     ó¼  — t        t        «      g}t        j                  «       r|dt        t        «      gz  }|dddddddd	| g	z  }t        j                  d
| «       t        |«      }|j                  dk7  rt        |j                  dd  xs d«      ‚t        j                  |j                  «      }|j                  d«      xs g D �cg c]  }|sŒ|j                  d«      sŒ|‘Œ }}|st        d«      ‚dd„}|D �cg c]  } ||«      sŒ|‘Œ }}|xs |}t        d„ |D «       |d   «      }	|	j                  d«      xs d|	d   › �}
t        |
«      S c c}w c c}w )Nr�   r‚   rƒ   r„   r…   z--flat-playlistr‡   z--playlist-endÚ10zScanning channel source: %sr   rˆ   zCould not scan source channel.ÚentriesrJ   z"No videos found in source channel.c                ó`   — t        | j                  dd«      «      j                  «       }d|v ryy)Nrv   rL   ÚverticalTF©r7   r@   r•   )Úentryrv   s     r   Úis_verticalz)choose_channel_video.<locals>.is_verticalÇ   s.   € Ü�E—I‘I˜g rÓ*Ó+×1Ñ1Ó3ˆØ˜ÑØØr   c              3  óx   K  — | ]2  }d t        |j                  dd«      «      j                  «       v sŒ/|–— Œ4 y­w)Úparkourrv   rL   Nrž   )Ú.0Úxs     r   ú	<genexpr>z'choose_channel_video.<locals>.<genexpr>Î   s0   è ø€ ÒV˜A¨´c¸!¿%¹%ÀÈÓ:LÓ6M×6SÑ6SÓ6UÒ)U”aÑVùs   ‚0:³:Úwebpage_urlú https://www.youtube.com/watch?v=)rŸ   rN   ÚreturnÚbool)r7   rŒ   r�   rŽ   r�   r�   r   r‘   r’   r“   r4   rB   r”   r@   Únextr˜   )rW   r~   r–   r<   r¤   r›   r    r�   ÚpoolÚ	preferredÚ	video_urls              r   Úchoose_channel_videor®   º   sl  € Ü”‹Jˆ<€DÜ‡�ÔØ�œc¤'›lÐ+Ñ+ˆØˆ_˜fÐ&;¸\ÐK\Ð^rð  uEð  GKð  MPð  Qñ  Q€DÜ
‡K�KÐ-¨sÔ3Ü˜Ó€FØ×Ñ˜AÒÜ˜6Ÿ=™=¨¨Ð/ÒSÐ3SÓTÐTÜ�:‰:�f—m‘mÓ$€DØŸ8™8 IÓ.Ò4°"ÖK�Qº¸q¿u¹uÀT½{ŠqÐK€GÐKÙÜÐ?Ó@Ð@óð
 #Ö5�a¡k°!¥n’Ð5€HÐ5ØÒ�w€DÜÑV ÔVÐX\Ð]^ÑX_Ó`€IØ—‘˜mÓ,ÒdÐ2RÐS\Ð]aÑSbÐRcÐ0d€IÜ˜9Ó%Ð%ùò Lùò 6s   Ã	EÃEÃ#EÃ>EÄEc                ó¬  — t         | › d�z  }t         | › d�z  }|j                  «       r5|j                  «       r%|t        j                  |j	                  «       «      fS |j                  d«      xs d| › �}t        t        «      g}t        j                  «       r|dt        t        «      gz  }|dddd	d
ddddddt        t         | › d�z  «      |gz  }t        j                  d| «       t        |d¬«      }|j                  dk7  s|j                  «       st        |j                  dd  xs d«      ‚|t        j                  |j	                  «       «      fS )Nz.mp4z
.info.jsonr¦   r§   r�   r‚   rƒ   r„   r…   r†   z--merge-output-formatÚmp4z-fzbv*[height>=1080]+ba/bv*+baz--write-info-jsonz-oz.%(ext)szDownloading source video: %sé  r   r   iüÿÿzSource download failed.)ÚSOURCESrŽ   r4   rB   Ú	read_textr@   r7   rŒ   r�   r�   r�   r   r‘   r’   r“   )Úvideo_idr<   ri   r�   rW   r~   r–   s          r   Údownload_sourcerµ   Ó   s?  € Ü˜(˜ 4Ð(Ñ(€FÜ˜�z Ð,Ñ,€DØ‡~�~Ô˜DŸL™LœNØ”t—z‘z $§.¡.Ó"2Ó3Ð3Ð3Ø
�(‰(�=Ó
!Ò
RÐ'GÈÀzÐ%R€CÜ”‹Jˆ<€DÜ‡�ÔØ�œc¤'›lÐ+Ñ+ˆØˆ_˜fÐ&;¸\È?Ø$ e¨TÐ3PØ  $¬¬G¸¸
À(Ð6KÑ,KÓ(LÈcðSñ S€Dô ‡K�KÐ.°Ô9Ü˜ tÔ,€FØ×Ñ˜AÒ V§^¡^Ô%5Ü˜6Ÿ=™=¨¨Ð0ÒMÐ4MÓNÐNØ”4—:‘:˜dŸn™nÓ.Ó/Ð/Ð/r   c                óL   — t        d| «      } dt        | dz  «      d›d| dz  d›�S )Nç        z0:é<   Ú02dú:z05.2f)Úmaxr   )Úsecondss    r   Úass_timer½   æ   s4   € Ü�#�wÓ€GØ”�G˜r‘MÓ" 3Ð' q¨°2©°eÐ(<Ð=Ð=r   c           
     óŽ  — d}g }t        dt        | «      d«      D �]  }| ||dz    }|dz   t        | «      k  r| |dz      d   n|dz   }t        |«      D ]×  \  }}|r|d   n|d   d   }	|dz   t        |«      k  r||dz      d   n|}
g }t        |«      D ]Y  \  }}t        j                  dd|d	   «      j                  «       }||k(  r|j                  d
|› d�«       ŒI|j                  |«       Œ[ |j                  dt        |	«      › dt        |
«      › d�dj                  |«      z   «       ŒÙ �Œ |dj                  |«      z   dz   S )Na*  [Script Info]
ScriptType: v4.00+
PlayResX: 1080
PlayResY: 1920
WrapStyle: 1
ScaledBorderAndShadow: yes

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default,Arial,96,&H00FFFFFF,&H000000FF,&H00101010,&H90000000,-1,0,0,0,100,100,1,0,1,7,3,2,50,50,470,1

[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
r   é   r9   g333333Ó?é   z[^\w'\-!?.,]rL   ÚwordzK{\c&H0000FFFF&\fscx128\fscy128\bord9\shad5\t(0,100,\fscx100\fscy100\bord7)}z%{\c&H00FFFFFF&\fscx100\fscy100\bord7}zDialogue: 0,ú,z,Default,,0,0,0,,{\fad(80,40)}ro   ú
)	Úranger8   Ú	enumeraterp   rq   ÚupperÚappendr½   Újoin)ÚwordsÚdurationÚheaderÚlinesÚiÚgroupÚ	group_endÚjrÁ   r9   ÚendÚpartsÚkÚitemrz   s                  r   Úmake_assrÕ   ë   s}  € ð K	€FØ€EÜ�1”c˜%“j !Ó$ó ~ˆØ�a˜˜A™�ˆØ-.°©U´S¸³ZÒ-?�E˜!˜a™%‘L Ò)ÀXÐPSÁ^ˆ	Ü  Ó'ò 
	~‰GˆAˆtÙ%&�D˜’M¨E°!©H°WÑ,=ˆEØ+,¨q©5´3°u³:Ò+=�%˜˜A™‘,˜wÒ'À9ˆCØˆEÜ$ UÓ+ò '‘��4Ü—v‘v˜o¨r°4¸±<Ó@×FÑFÓH�Ø˜’6Ø—L‘LÐ#yÐz~Ðyð  @kð  "lõ  mà—L‘L Õ&ð'ð �L‰L˜<¬°«Ð'8¸¼(À3»-¸ÐHiÐjÐmp×muÑmuÐv{Óm|Ñ|Õ}ò
	~ð~ð �D—I‘I˜eÓ$Ñ$ tÑ+Ð+r   c              ƒ  ó   K  — dd l }|j                  | t        ddd¬«      }g }g }|j                  «       2 3 d {  –—† }|d   dk(  r|j	                  |d   «       Œ&|d   dk(  sŒ/|j	                  |d	   |d
   dz  |d
   |d   z   dz  dœ«       ŒZ7 ŒU6 |st        d«      ‚|j                  dj                  |«      «       |d   d   dz   }||fS ­w)Nr   z-6%z-2HzÚWordBoundary)ÚrateÚpitchÚboundaryÚtypeÚaudior<   rz   Úoffseti€–˜ rÊ   )rÁ   r9   rÑ   z'Voice service returned no word timings.r   éÿÿÿÿrÑ   ç      à?)Úedge_ttsÚCommunicateÚVOICEÚstreamrÇ   r’   Úwrite_bytesrÈ   )rz   Úout_mp3rà   ÚcommunicaterÜ   rÉ   ÚchunkrÊ   s           r   Ú
synthesizerè   ÿ   s  è ø€ ÛØ×&Ñ& t¬U¸ÀfÐWeÐ&Óf€KØ€EØ€EØ"×)Ñ)Ó+÷ Tð TˆeØ�‰=˜GÒ#Ø�L‰L˜˜v™Õ'Ø�6‰]˜nÓ,Ø�L‰L %¨¡-¸%À¹/ÈJÑ:VÐ`eÐfnÑ`oÐrwð  yCñ  sDñ  aDð  HRñ  `Rñ  Sõ  Tð	TøÐ+ñ
 ÜÐDÓEÐEØ×Ñ˜Ÿ™ ›Ô(Ø�R‰y˜Ñ #Ñ%€HØ�(ˆ?Ðùs+   ‚3CµB¹BºB½&CÁ$+CÂBÂ=Cc                óø  — t         | z  }|j                  dd¬«       |dz  }|dz  }t        j                  t	        ||«      «      \  }}	|j                  t        ||	«      d¬«       |dz  }
t        dt        |j                  d	«      xs d
«      |	z
  dz
  «      }t        d|«      }t        |«      j                  dd«      j                  dd«      }g d‘d‘d‘d‘d‘|d›‘d‘t        |«      ‘d‘t        |«      ‘d‘d|› d�‘d‘d‘d‘d‘d‘d‘d ‘d!‘d"‘d#‘d$‘d%‘d&‘d'‘d(‘d)‘d*‘d+‘d,‘d-‘d.‘|	d/z   d›‘d0‘d1‘t        |
«      ‘}t        |d2¬3«      }|j                  d4k7  rt        |j                   d5d  xs d6«      ‚|
S )7NTr   z	voice.mp3zcaptions.asszutf-8)Úencodingzclip.mp4r·   rÊ   r¸   rÀ   g     Àr@ú\ú/rº   z\:Úffmpegz-yz-stream_loopz-1z-ssz.2fz-iz-vfzass=zD,scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920z-mapz0:v:0z1:a:0z-c:vÚlibx264z-presetÚfastz-crfÚ20z-pix_fmtÚyuv420pz-rÚ60z-c:aÚaacz-b:aÚ192kz-arÚ44100z-trß   z	-movflagsz
+faststartr±   r   r   iPûÿÿzRender failed.)ÚMEDIAÚmkdirÚasyncior}   rè   Ú
write_textrÕ   r»   Úfloatr@   Úminr7   Úreplacer   r‘   r’   r“   )rk   ri   rv   rw   ÚmetadataÚworkrÜ   ÚassrÉ   rÊ   ÚoutÚ	start_maxrÝ   Úass_pathÚcmdr–   s                   r   Úrenderr    sw  € Ü�6‰>€DØ‡J�J�t d€JÔ+Ø�;Ñ€EØ
�Ñ
€CÜ—k‘k¤*¨U°EÓ":Ó;�O€Eˆ8Ø‡N�N”8˜E 8Ó,°w€NÔ?Ø
�Ñ
€CÜ�Cœ˜xŸ|™|¨JÓ7Ò=¸2Ó>ÀÑIÈAÑMÓN€IÜ�˜	Ó"€FÜ�3‹x×Ñ  cÓ*×2Ñ2°3¸Ó>€Hð0ˆ8ð 0�Tð 0˜>ð 0¨4ð 0°ð 0¸6À#¸,ð 0Èð 0ÌsÐSYË{ð 0Ð\`ð 0ÔbeÐfkÓblð 0Øð0Ø˜˜
Ð"fÐgð0àð0àð0à"ð0à$+ð0à-3ð0à5>ð0à@Ið0àKQð0àSYð0à[_ð0ð ð0ð !ð0ð #'ð0ð )-ð0ð /5ð0ð 7<ð0ð >Dð0ð FLð0ð NSð0ð U\ð0ð ^bð0ð goÐqtÑftÐuxÐeyð0ð ð	0ð %ð	0ô '*¨#£hð	0€Cô
 ˜ dÔ+€FØ×Ñ˜AÒÜ˜6Ÿ=™=¨¨Ð0ÒDÐ4DÓEÐEØ€Jr   c                óì  — | d   }t        |dd¬«       	 t        j                  d|| d   «       d| d   v sd| d   v sd	| d   v r!t        | d   «      \  }}t	        ||«      \  }}n t        | d   «      \  }}t	        ||«      \  }}t        | d
   | d   «      \  }}t        |d|||j                  d|«      |j                  dd«      |j                  dd«      d¬«       t        j                  d||«       t        |||||«      }t        |dt        |«      d¬«       t        j                  d||«       y # t        $ r7}	t        j                  d|«       t        |dt        |	«      ¬«       Y d }	~	y d }	~	ww xY w)NrJ   Ú
processingz.Selecting licensed source and writing story...)r;   Úmessagez Processing job %s from source %sr[   z/@z	/channel/z/videosr\   r^   Ú	renderingrv   r‰   rL   ÚuploaderzSource creatorz/Rendering softer voice and animated captions...)r;   rv   rw   Úsource_videoÚsource_licenseÚsource_creditr  zRendering job %s: %sÚcompletezReady. Publishing is disabled.)r;   rH   r  zJob %s complete: %szJob %s failedÚerror)Ú
update_jobr�   r�   r®   rµ   r˜   rx   r@   r  r7   Ú	ExceptionÚ	exception)
Újobrk   r´   Úlistingri   rý   rv   rw   ÚoutputÚexcs
             r   Úprocess_jobr  &  s¶  € Ø�‰Y€FÜˆv˜lÐ4dÕeð=Ü�‰Ð6¸ÀÀLÑ@QÔRØ�3�|Ñ$Ñ$¨°s¸<Ñ7HÑ(HÈIÐY\Ð]iÑYjÑLjÜ 4°S¸Ñ5FÓ GÑˆH�gÜ.¨x¸ÓAÑˆF‘Hä!0°°\Ñ1BÓ!CÑˆH�hÜ.¨x¸ÓBÑˆF�HÜ# C¨Ñ$5°s¸=Ñ7IÓJ‰ˆˆuÜ�6 +°UÀ%ÐV^×VbÑVbÐcjÐltÓVuð  GO÷  GSñ  GSð  T]ð  _aó  Gbð  rz÷  r~ñ  r~ð  Ið  K[ó  r\ð  fWõ  	XÜ�‰Ð*¨F°EÔ:Ü˜ ¨¨u°hÓ?ˆÜ�6 *¼#¸f»+ÐOoÕpÜ�‰Ð)¨6°6Õ:øÜò =Ü×Ñ˜¨&Ô1Ü�6 '´3°s³8×<Ò<ûð=ús   •DD3 Ä3	E3Ä<-E.Å.E3c                óþ   — t        «       |d<   dj                  d„ |D «       «      }t        «       5 }|j                  d|› d�g |j	                  «       ¢| ‘­«       |j                  «        d d d «       y # 1 sw Y   y xY w)NÚ
updated_atz, c              3  ó&   K  — | ]	  }|› d �–— Œ y­w)z=?Nr   )r£   r+   s     r   r¥   zupdate_job.<locals>.<genexpr>>  s   è ø€ Ò4 c˜#˜˜b”zÑ4ùs   ‚zUPDATE jobs SET z WHERE id=?)r   rÈ   r&   r-   Úvaluesrg   )rk   r  Úfieldsr%   s       r   r  r  <  sp   € Ü›5€Fˆ<ÑØ�Y‰YÑ4¨VÔ4Ó4€FÜ	‹ð ˜Ø
�
‰
Ð% f X¨[Ð9Ð;U¸V¿]¹]»_Ð;UÈfÑ;UÔVØ
�	‰	Œ÷÷ ñ ús   °:A3Á3A<c                 óÜ   — t        «        	 t        «       5 } | j                  d«      j                  «       }d d d «       rt	        |«       nt        j                  d«       ŒV# 1 sw Y   Œ-xY w)NzDSELECT * FROM jobs WHERE status='queued' ORDER BY created_at LIMIT 1é   )r)   r&   r-   Úfetchoner  r   Úsleep)r%   r  s     r   Úworker_loopr   D  s]   € Ü„IØ
Ü‹\ð 	p˜RØ—*‘*ÐcÓd×mÑmÓoˆC÷	páÜ˜Õä�J‰J�qŒMð ÷	pð 	pús   – A"Á"A+u²  <!doctype html><html><head><meta name="viewport" content="width=device-width,initial-scale=1"><title>YouTube Story Generator</title><style>
:root{--bg:#080b12;--card:#111827;--line:#263248;--muted:#92a0b8;--accent:#61f2c2;--hot:#ffdb57}*{box-sizing:border-box}body{margin:0;background:radial-gradient(circle at top,#17243a 0,#080b12 48%);color:#f5f7fb;font:15px Inter,system-ui,sans-serif}main{max-width:1160px;margin:0 auto;padding:34px 20px 70px}h1{font-size:42px;line-height:1.05;margin:0 0 10px;letter-spacing:-1.5px}h1 span{color:var(--accent)}h2{margin:0 0 12px}.sub{color:var(--muted);max-width:760px;line-height:1.6}.grid{display:grid;grid-template-columns:1.05fr .95fr;gap:18px;margin-top:24px}.card{background:rgba(17,24,39,.9);border:1px solid var(--line);border-radius:18px;padding:22px;box-shadow:0 18px 55px #0004}label{display:block;color:#c9d3e5;margin:15px 0 7px}input,select,textarea{width:100%;background:#0a101c;color:#fff;border:1px solid #33435e;border-radius:10px;padding:12px;font:inherit}textarea{min-height:150px;resize:vertical}.row{display:flex;gap:10px;align-items:center}.btn{border:0;border-radius:10px;padding:12px 16px;background:var(--accent);color:#06110f;font-weight:800;cursor:pointer;margin-top:16px}.btn.secondary{background:#263248;color:#fff}.hint,.status{color:var(--muted);font-size:13px;line-height:1.5}.pill{display:inline-block;padding:5px 9px;border-radius:999px;background:#203149;color:#b9c9e5;font-size:12px}.job{border-top:1px solid var(--line);padding:15px 0}.job:first-child{border-top:0}.job h3{margin:0 0 6px}.complete{color:var(--accent)}.error{color:#ff8c8c}.processing{color:var(--hot)}a{color:var(--accent)}video{width:100%;max-height:480px;border-radius:12px;background:#000;margin-top:12px}@media(max-width:800px){.grid{grid-template-columns:1fr}h1{font-size:34px}}
</style></head><body><main><h1><span>Youtube</span> Story Generator</h1><p class="sub">Licensed Minecraft parkour source, softer narration, and high-impact word-pop captions. Original stories run by default. Reddit mode accepts text you provide. Public publishing stays disabled.</p><div class="grid"><section class="card"><h2>Make a clip</h2><label>Parkour source</label><input id="source" value="__SOURCE__"><p class="hint">Use a YouTube channel videos URL or a specific Creative Commons video URL. Source license is checked before download.</p><label>Story mode</label><select id="mode" onchange="toggleReddit()"><option value="original">Original thriller</option><option value="reddit_text">Reddit story text</option></select><div id="redditBox" style="display:none"><label>Reddit text</label><textarea id="redditText" placeholder="Paste story text here. It will be rewritten into narration."></textarea></div><button class="btn" onclick="createJob()">Generate clip</button><p id="notice" class="status"></p></section><section class="card"><h2>Style</h2><p><span class="pill">Soft voice</span> Emma Neural Â· âˆ’6% rate Â· âˆ’2Hz pitch</p><p><span class="pill">Pop captions</span> 3 words Â· 128% active word Â· thick outline Â· bounce + fade</p><p><span class="pill">Format</span> 1080Ã—1920 Â· 60 fps Â· H.264/AAC</p><p><span class="pill">Publishing</span> Disabled</p><h2 style="margin-top:26px">System</h2><div id="health" class="status">Loadingâ€¦</div></section></div><section class="card" style="margin-top:18px"><div class="row"><h2 style="flex:1">Jobs</h2><button class="btn secondary" onclick="load()">Refresh</button></div><div id="jobs">Loadingâ€¦</div></section></main><script>
function toggleReddit(){redditBox.style.display=mode.value==='reddit_text'?'block':'none'}
async function api(path,opt){let r=await fetch(path,opt);let j=await r.json();if(!r.ok)throw Error(j.error||'Request failed');return j}
async function createJob(){notice.textContent='Queuedâ€¦';try{let j=await api('/api/jobs',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({source_url:source.value,story_mode:mode.value,reddit_text:redditText.value})});notice.textContent='Job '+j.id+' queued. Worker will render it.';load()}catch(e){notice.textContent=e.message}}
async function load(){try{let h=await api('/api/health');health.innerHTML='Dashboard online Â· Worker '+(h.worker?'online':'offline')+' Â· Source auth '+(h.cookies?'ready':'missing');let data=await api('/api/jobs');jobs.innerHTML=data.length?data.map(j=>`<div class="job"><h3>${esc(j.title||'Queued story')}</h3><div class="status ${j.status}">${esc(j.status)} Â· ${esc(j.message||'')}</div>${j.source_video?`<p class="hint">Source: ${esc(j.source_video)}<br>Credit: ${esc(j.source_credit)} Â· ${esc(j.source_license)}</p>`:''}${j.download_url?`<a href="${j.download_url}">Download clip</a><video controls preload="metadata" src="${j.download_url}"></video>`:''}</div>`).join(''):'<p class="status">No jobs yet.</p>'}catch(e){health.textContent=e.message}}
function esc(x){return String(x).replace(/[&<>"']/g,m=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[m]))}load();setInterval(load,8000)
</script></body></html>c                  ó   — e Zd Zd„ Zy)ÚAppc           
     ó"  — t        «        |j                  dd«      }|j                  dd«      }|dk(  r"t        |ddt        j	                  «       dœ«      S |dk(  r|dk(  rt        |t        «       «      S |j                  d	«      r„|dk(  r|j                  d
«      sn|j                  d«      d   }t        «       5 }|j                  d|f«      j                  «       }d d d «       st        |ddid«      S t        |t        |«      «      S |dk(  r%|dk(  r 	 t        |t        t        |«      «      d«      S |j                  d	«      �r|j                  d
«      rý|j                  d«      d   }t        «       5 }|j                  d|f«      j                  «       }d d d «       r!|d   rt#        |d   «      j	                  «       st        |ddid«      S t#        |d   «      j%                  «       }	|	j'                  t(        «      st        |ddid«      S |	j+                  «       }
 |dddt!        t-        |
«      «      fdd|	j.                  › d�fg«       |
gS |dk(  rbt1        «       }t2        j5                  dt7        j8                  |j                  dt:        «      «      «      } |ddg«       |j=                  «       gS t        |dd id«      S # 1 sw Y   �ŒðxY w# t        $ r"}t        |dt!        |«      id«      cY d }~S d }~ww xY w# 1 sw Y   �ŒpxY w)!NÚ	PATH_INFOrì   ÚREQUEST_METHODÚGETz/api/healthT)ÚokÚworkerÚcookiesz	/api/jobsrI   rK   r¿   zSELECT * FROM jobs WHERE id=?r  zJob not foundz404 Not FoundÚPOSTz201 Createdz400 Bad Requestz'SELECT output_path FROM jobs WHERE id=?rH   zClip not readyzInvalid clip pathú200 OK)r2   z	video/mp4r3   zContent-Dispositionzinline; filename="ú"Ú
__SOURCE__r[   )r2   ztext/html; charset=utf-8z	not found)r)   r@   r=   r�   rŽ   rP   Ú
startswithÚendswithÚsplitr&   r-   r  rN   rm   rF   r  r7   r   ÚresolveÚis_relative_torö   Ú
read_bytesr8   Únamer/   ÚPAGErü   ÚhtmlÚescaperb   r6   )ÚselfrC   r9   ÚpathÚmethodrk   r%   r.   r  Útargetr<   ÚsÚpages                r   Ú__call__zApp.__call__[  s  € ÜŒ	Ø�{‰{˜;¨Ó,ˆØ—‘Ð-¨uÓ5ˆØ�=Ò Ü  ¨t¸tÔPW×P_ÑP_ÓPaÑ(bÓcÐcØ�;Ò 6¨U¢?Ü  ¬	«Ó4Ð4Ø�?‰?˜<Ô(¨V°uª_ÀTÇ]Á]ÐS^ÔE_Ø—Z‘Z “_ QÑ'ˆFÜ“ð X Ø—j‘jÐ!@À6À)ÓL×UÑUÓW�÷XáÜ$ U¨W°oÐ,FÈÓXÐXÜ  ¬¨S«	Ó2Ð2Ø�;Ò 6¨VÒ#3ðTÜ$ U¬J´yÀÓ7IÓ,JÈMÓZÐZð �?‰?˜<Õ(¨T¯]©]¸;Ô-GØ—Z‘Z “_ QÑ'ˆFÜ“ð b Ø—j‘jÐ!JÈVÈIÓV×_Ñ_Óa�÷bá˜c -Ò0¼¸SÀÑ=OÓ8P×8XÑ8XÔ8ZÜ$ U¨WÐ6FÐ,GÈÓYÐYÜ˜#˜mÑ,Ó-×5Ñ5Ó7ˆFØ×(Ñ(¬Ô/Ü$ U¨WÐ6IÐ,JÈOÓ\Ð\Ø×$Ñ$Ó&ˆDÙ�(Ð:Ð=MÌsÔSVÐW[ÓS\Ë~Ð<^Ðavð  {Mð  NT÷  NYñ  NYð  MZð  Z[ð  y\ð  a]ð  ^ô  _Ø�6ˆMØ�3Š;Ü“
ˆAÜ—<‘< ¬d¯k©k¸!¿%¹%ÀÌnÓ:]Ó.^Ó_ˆDÙ�(ÐIÐJÔKØ—K‘K“M�?Ð"Ü˜U W¨kÐ$:¸OÓLÐL÷7Xñ Xûô ò TÜ$ U¨W´c¸#³hÐ,?ÐARÓSÕSûðTú÷bñ bús6   Â9"K	ÄK Å4"LË	KË	LËK<Ë6LË<LÌLN)Ú__name__Ú
__module__Ú__qualname__r>  r   r   r   r"  r"  Z  s   „ ó%Mr   r"  c                 óx   — t        «        t        dd¬«       t        ddt        «       «      j	                  «        y )Nz-youtube generator listening on 127.0.0.1:8791T)Úflushz	127.0.0.1iW"  )r)   Úprintr   r"  Úserve_foreverr   r   r   ÚserverF  ƒ  s)   € Ü„IÜ	Ð
9ÀÕFÜ�˜T¤3£5Ó)×7Ñ7Õ9r   Ú__main__rÀ   r(  )r¨   r   )r¨   zsqlite3.Connection)r¨   ÚNone)r¨   zdict[str, str])r+  )r¨   rN   )r¨   ú
list[dict])rW   r7   r¨   r©   )rh   rN   r¨   rN   )rj   r7   r^   r7   r¨   ztuple[str, str])i„  )r~   z	list[str]r   r   r¨   zsubprocess.CompletedProcess)rW   r7   r¨   ztuple[str, dict])r´   r7   r<   rN   r¨   ztuple[Path, dict])r¼   rú   r¨   r7   )rÉ   rI  rÊ   rú   r¨   r7   )rz   r7   rå   r   r¨   ztuple[list[dict], float])rk   r7   ri   r   rv   r7   rw   r7   rý   rN   r¨   r   )r  zsqlite3.Rowr¨   rH  )rk   r7   r¨   rH  )BÚ__doc__Ú
__future__r   rø   r6  r4   Úosrr   rp   r   r|   r   rd   Úpathlibr   Úurllib.parser   r   Úwsgiref.simple_serverr   ÚloggingÚbasicConfigÚINFOÚ	getLoggerr�   ÚROOTÚPROJECTÚDATAr!   rö   r²   rŒ   r�   rb   râ   r9  r÷   rt   r   r&   r)   r/   r=   rF   rP   rY   rm   rx   r   r˜   r®   rµ   r½   rÕ   rè   r  r  r  r   r5  r"  rF  r?  Úsysr8   Úargvr   r   r   ú<module>rY     s´  ðá <Ý "ã Û Û Û 	Û Û 	Û Û Û Û Ý ß +Ý -ã Ø €× Ñ ˜'Ÿ,™,Ð/VÕ WØ	ˆ×	Ñ	Ð.Ó	/€áÐÓ€Ø
�Ñ
€ØÐ&Ñ&€Ø	ˆNÑ€Øˆw‰€Ø
�IÑ
 	Ñ
)€ÙÐ1Ó2€Ø
�Ñ
Ð!6Ñ
6€Ø=€Ø€à�5˜'Ð"ò ,€DØ‡J�J�t d€JÕ+ð,ò%€óPóóó&bó
ó$óócó
.ó&ôQó=ó &ó20ó&>ó
,ó(ó"ó,=ó,óð€÷&Mñ &MóR:ð ˆzÒÛÙ
ˆ3�8‰8ƒ}�qÒ˜SŸX™X a™[¨HÒ4Ù�á�ð r   