<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://groupkos.com/dev/index.php?action=history&amp;feed=atom&amp;title=YouTube_UAP_News_Shorts_How-To</id>
	<title>YouTube UAP News Shorts How-To - Revision history</title>
	<link rel="self" type="application/atom+xml" href="http://groupkos.com/dev/index.php?action=history&amp;feed=atom&amp;title=YouTube_UAP_News_Shorts_How-To"/>
	<link rel="alternate" type="text/html" href="http://groupkos.com/dev/index.php?title=YouTube_UAP_News_Shorts_How-To&amp;action=history"/>
	<updated>2026-04-15T20:08:05Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.39.3</generator>
	<entry>
		<id>http://groupkos.com/dev/index.php?title=YouTube_UAP_News_Shorts_How-To&amp;diff=5457&amp;oldid=prev</id>
		<title>XenoEngineer: /* wav2short.sh – turn a .wav into a YouTube-Short with scrolling word captions */</title>
		<link rel="alternate" type="text/html" href="http://groupkos.com/dev/index.php?title=YouTube_UAP_News_Shorts_How-To&amp;diff=5457&amp;oldid=prev"/>
		<updated>2025-12-18T17:49:30Z</updated>

		<summary type="html">&lt;p&gt;&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;wav2short.sh – turn a .wav into a YouTube-Short with scrolling word captions&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 17:49, 18 December 2025&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l5&quot;&gt;Line 5:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 5:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;div style=&amp;quot;background-color:azure; border:1px outset azure; padding:0 20px; max-width:860px; margin:0 auto; &amp;quot;&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;div style=&amp;quot;background-color:azure; border:1px outset azure; padding:0 20px; max-width:860px; margin:0 auto; &amp;quot;&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;= wav2short.sh – turn a .wav into a YouTube-Short with scrolling word captions =&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;= wav2short.sh – turn a .wav into a YouTube-Short with scrolling word captions =&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;div style=&quot;float:right; width:425px;&quot;&gt;__TOC__&amp;lt;/div&gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;A retired Hypergeek’s minimal, fully-scriptable pipeline (Debian/Ubuntu, no GUI).&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;A retired Hypergeek’s minimal, fully-scriptable pipeline (Debian/Ubuntu, no GUI).&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>XenoEngineer</name></author>
	</entry>
	<entry>
		<id>http://groupkos.com/dev/index.php?title=YouTube_UAP_News_Shorts_How-To&amp;diff=5455&amp;oldid=prev</id>
		<title>XenoEngineer: Created page with &quot;Category:YouTube Category:UAP News Category:how to  &lt;div style=&quot;background-color:azure; border:1px outset azure; padding:0 20px; max-width:860px; margin:0 auto; &quot;&gt; = wav2short.sh – turn a .wav into a YouTube-Short with scrolling word captions =  A retired Hypergeek’s minimal, fully-scriptable pipeline (Debian/Ubuntu, no GUI).  == Prerequisites == * Debian/Ubuntu box (headless OK) * ffmpeg (repo version is fine) * Python ≥ 3.10 * pip packages: ** whisper...&quot;</title>
		<link rel="alternate" type="text/html" href="http://groupkos.com/dev/index.php?title=YouTube_UAP_News_Shorts_How-To&amp;diff=5455&amp;oldid=prev"/>
		<updated>2025-12-18T16:46:42Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;&lt;a href=&quot;/dev/index.php?title=Category:YouTube&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;Category:YouTube (page does not exist)&quot;&gt;Category:YouTube&lt;/a&gt; &lt;a href=&quot;/dev/index.php?title=Category:UAP_News&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;Category:UAP News (page does not exist)&quot;&gt;Category:UAP News&lt;/a&gt; &lt;a href=&quot;/dev/index.php?title=Category:How_to&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;Category:How to (page does not exist)&quot;&gt;Category:how to&lt;/a&gt;  &amp;lt;div style=&amp;quot;background-color:azure; border:1px outset azure; padding:0 20px; max-width:860px; margin:0 auto; &amp;quot;&amp;gt; = wav2short.sh – turn a .wav into a YouTube-Short with scrolling word captions =  A retired Hypergeek’s minimal, fully-scriptable pipeline (Debian/Ubuntu, no GUI).  == Prerequisites == * Debian/Ubuntu box (headless OK) * ffmpeg (repo version is fine) * Python ≥ 3.10 * pip packages: ** whisper...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;[[Category:YouTube]]&lt;br /&gt;
[[Category:UAP News]]&lt;br /&gt;
[[Category:how to]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;background-color:azure; border:1px outset azure; padding:0 20px; max-width:860px; margin:0 auto; &amp;quot;&amp;gt;&lt;br /&gt;
= wav2short.sh – turn a .wav into a YouTube-Short with scrolling word captions =&lt;br /&gt;
&lt;br /&gt;
A retired Hypergeek’s minimal, fully-scriptable pipeline (Debian/Ubuntu, no GUI).&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
* Debian/Ubuntu box (headless OK)&lt;br /&gt;
* ffmpeg (repo version is fine)&lt;br /&gt;
* Python ≥ 3.10&lt;br /&gt;
* pip packages:&lt;br /&gt;
** whisper-timestamped (word-level SRT)&lt;br /&gt;
** srt, Pillow, numpy, opencv-python&lt;br /&gt;
&lt;br /&gt;
== One-file script ==&lt;br /&gt;
Create &amp;lt;code&amp;gt;~/bin/wav2short.sh&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;chmod +x&amp;lt;/code&amp;gt; it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env bash&lt;br /&gt;
# wav2short.sh  &amp;lt;input.wav&amp;gt;  [duration=60]  [out.mp4]&lt;br /&gt;
WAV=$1&lt;br /&gt;
DUR=${2:-60}          # seconds of final clip&lt;br /&gt;
OUT=${3:-output.mp4}&lt;br /&gt;
W=1080                # vertical short: 1080x1920&lt;br /&gt;
H=1920&lt;br /&gt;
FONT=~/fonts/Inconsolata-Regular.ttf&lt;br /&gt;
FONTSIZE=75&lt;br /&gt;
LINES=7               # how many lines visible at once&lt;br /&gt;
FPS=30&lt;br /&gt;
&lt;br /&gt;
# 1. Whisper → word-level SRT (takes ~20 s on a 1-min clip)&lt;br /&gt;
python -m whisper_timestamped &amp;quot;$WAV&amp;quot; --language en --model base \&lt;br /&gt;
       --output_format srt --output_dir /tmp &amp;gt; /dev/null&lt;br /&gt;
SRT=/tmp/&amp;quot;$(basename &amp;quot;$WAV&amp;quot; .wav)&amp;quot;.srt&lt;br /&gt;
&lt;br /&gt;
# 2. Python burns the frames&lt;br /&gt;
python3 &amp;lt;&amp;lt; EOF&lt;br /&gt;
import srt, cv2, numpy as np, subprocess, math&lt;br /&gt;
from PIL import ImageFont, ImageDraw, Image&lt;br /&gt;
W, H, FPS, LINES, FONTSIZE = $W, $H, $FPS, $LINES, $FONTSIZE&lt;br /&gt;
FONT = ImageFont.truetype(&amp;quot;$FONT&amp;quot;, FONTSIZE)&lt;br /&gt;
sub = list(srt.parse(open(&amp;quot;$SRT&amp;quot;).read()))&lt;br /&gt;
dur  = $DUR&lt;br /&gt;
fourcc = cv2.VideoWriter_fourcc(*&amp;#039;mp4v&amp;#039;)&lt;br /&gt;
out = cv2.VideoWriter(&amp;#039;/tmp/caps.mp4&amp;#039;, fourcc, FPS, (W, H))&lt;br /&gt;
&lt;br /&gt;
def draw_frame(idx, active):&lt;br /&gt;
    img  = Image.new(&amp;#039;RGB&amp;#039;, (W, H), &amp;#039;black&amp;#039;)&lt;br /&gt;
    draw = ImageDraw.Draw(img)&lt;br /&gt;
    y0 = (H - LINES*FONTSIZE) // 2&lt;br /&gt;
    for i, w in enumerate(active[-LINES:], start=1-max(LINES,0)):&lt;br /&gt;
        y = y0 + (i+LINES-1)*FONTSIZE&lt;br /&gt;
        color = &amp;#039;yellow&amp;#039; if i==0 else &amp;#039;white&amp;#039;&lt;br /&gt;
        draw.text((W//2, y), w, font=FONT, fill=color, anchor=&amp;#039;ma&amp;#039;)&lt;br /&gt;
    return np.array(img)&lt;br /&gt;
&lt;br /&gt;
active = []              # rolling buffer of words on screen&lt;br /&gt;
for f in range(dur*FPS):&lt;br /&gt;
    t = f/FPS&lt;br /&gt;
    # add words whose start &amp;lt;= t&lt;br /&gt;
    while sub and sub[0].start.total_seconds() &amp;lt;= t:&lt;br /&gt;
        active.append(sub.pop(0).content.strip())&lt;br /&gt;
    # drop words that are off-screen&lt;br /&gt;
    active = active[-LINES:]&lt;br /&gt;
    out.write(draw_frame(f, active))&lt;br /&gt;
out.release()&lt;br /&gt;
EOF&lt;br /&gt;
&lt;br /&gt;
# 3. Mux audio and burn final&lt;br /&gt;
ffmpeg -y -i /tmp/caps.mp4 -i &amp;quot;$WAV&amp;quot; -t &amp;quot;$DUR&amp;quot; \&lt;br /&gt;
       -c:v libx264 -crf 18 -pix_fmt yuv420p -shortest &amp;quot;$OUT&amp;quot;&lt;br /&gt;
echo &amp;quot;Done → $OUT&amp;quot;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Usage ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
wav2short.sh mybook.wav 60 mybook_short.mp4&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Quick tweaks ==&lt;br /&gt;
* Longer clip: change &amp;lt;code&amp;gt;DUR&amp;lt;/code&amp;gt; argument&lt;br /&gt;
* Karaoke highlight: color the exact word inside &amp;lt;code&amp;gt;draw_frame()&amp;lt;/code&amp;gt;&lt;br /&gt;
* 4K vertical: set &amp;lt;code&amp;gt;W=2160 H=3840&amp;lt;/code&amp;gt; and bump &amp;lt;code&amp;gt;FONTSIZE&amp;lt;/code&amp;gt;&lt;br /&gt;
* Add waveform: insert ffmpeg &amp;lt;code&amp;gt;showwaves&amp;lt;/code&amp;gt; filter&lt;br /&gt;
* Stream live: replace last ffmpeg line with rtmp(s) url&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
100 % scriptable, &amp;lt; 100 lines, runs on CPU, perfect for a hammock-deployed Hypergeek.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;margin-left:3em; font:normal 14px terminal;&amp;quot;&amp;gt;&lt;br /&gt;
Prefers to stream straight to YouTube? Swap the last ffmpeg line for one that pushes to&lt;br /&gt;
rtmps://a.rtmp.youtube.com/...&lt;br /&gt;
&lt;br /&gt;
Why this satisfies the Hypergeek&lt;br /&gt;
Zero GUI, 100 % scriptable over SSH from his hammock.&lt;br /&gt;
Whisper-timestamped is small (74 MB) and runs on CPU; no GPU needed.&lt;br /&gt;
Every stage is a file (/tmp/caps.mp4, /tmp/foo.srt) so he can inspect, debug, or re-use.&lt;br /&gt;
One dependency install:&lt;br /&gt;
pip install whisper-timestamped srt Pillow numpy opencv-python&lt;br /&gt;
&lt;br /&gt;
.&lt;br /&gt;
Entire pipeline is &amp;lt; 100 lines—easy to memory-fit even on a 10-year-old ThinkPad.&lt;br /&gt;
Copy, tweak, upload, done.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
user&lt;br /&gt;
Enter user message...&lt;br /&gt;
Latency:&lt;br /&gt;
5,376 ms&lt;br /&gt;
Tokens/s:&lt;br /&gt;
228&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Clear&lt;br /&gt;
&lt;br /&gt;
Submit&lt;br /&gt;
Ctrl&lt;br /&gt;
&lt;br /&gt;
Python&lt;br /&gt;
&lt;br /&gt;
Copy&lt;br /&gt;
from groq import Groq&lt;br /&gt;
&lt;br /&gt;
client = Groq()&lt;br /&gt;
completion = client.chat.completions.create(&lt;br /&gt;
    model=&amp;quot;moonshotai/kimi-k2-instruct-0905&amp;quot;,&lt;br /&gt;
    messages=[&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;role&amp;quot;: &amp;quot;user&amp;quot;,&lt;br /&gt;
        &amp;quot;content&amp;quot;: &amp;quot;How does a smart, retired Ol&amp;#039; Hypergeek approach creating shorts for YouTube that are built from a wave file (audio only) and convert to a video of the words scrolling over the screen in sequence as read?\n&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;role&amp;quot;: &amp;quot;assistant&amp;quot;,&lt;br /&gt;
        &amp;quot;content&amp;quot;: &amp;quot;A smart, retired Ol’ Hypergeek doesn’t fight the toolchain—he glues it together with the lightest, most scriptable parts he already knows.  \nBelow is the exact “one-cup-of-coffee” pipeline he keeps in a single Bash script on the living-room NUC. It takes a .wav (or any audio), turns it into word-level timed text, then burns a 60-second (or any length) vertical-captioned video that YouTube Shorts will swallow whole.\n\n-------------------------------------------------\n1.  What he already has installed\n-------------------------------------------------\n- Debian/Ubuntu box (headless is fine)  \n- ffmpeg (stock repo version is enough)  \n- Python 3.10+  \n- pip packages:  \n  whisper-timestamped (git) – gives word-level SRT  \n  srt – tiny util to parse SRT inside Python  \n  Pillow – draw the text  \n  numpy – frame buffer math  \n- one monospace TTF he likes (Inconsolata-Regular.ttf lives in ~/fonts)\n\n-------------------------------------------------\n2.  The 30-line “do-it-now” script\n-------------------------------------------------\nSave as ~/bin/wav2short.sh and chmod +x it.\n\n```bash\n#!/usr/bin/env bash\n# wav2short.sh  &amp;lt;input.wav&amp;gt;  [duration=60]  [out.mp4]\nWAV=$1\nDUR=${2:-60}          # seconds of final clip\nOUT=${3:-output.mp4}\nW=1080                # vertical short: 1080x1920\nH=1920\nFONT=~/fonts/Inconsolata-Regular.ttf\nFONTSIZE=75\nLINES=7               # how many lines visible at once\nFPS=30\n\n# 1. Whisper → word-level SRT (takes ~20 s on a 1-min clip)\npython -m whisper_timestamped \&amp;quot;$WAV\&amp;quot; --language en --model base \\\n       --output_format srt --output_dir /tmp &amp;gt; /dev/null\nSRT=/tmp/\&amp;quot;$(basename \&amp;quot;$WAV\&amp;quot; .wav)\&amp;quot;.srt\n\n# 2. Python burns the frames\npython3 &amp;lt;&amp;lt; EOF\nimport srt, cv2, numpy as np, subprocess, math\nfrom PIL import ImageFont, ImageDraw, Image\nW, H, FPS, LINES, FONTSIZE = $W, $H, $FPS, $LINES, $FONTSIZE\nFONT = ImageFont.truetype(\&amp;quot;$FONT\&amp;quot;, FONTSIZE)\nsub = list(srt.parse(open(\&amp;quot;$SRT\&amp;quot;).read()))\ndur  = $DUR\nfourcc = cv2.VideoWriter_fourcc(*&amp;#039;mp4v&amp;#039;)\nout = cv2.VideoWriter(&amp;#039;/tmp/caps.mp4&amp;#039;, fourcc, FPS, (W, H))\n\ndef draw_frame(idx, active):\n    img  = Image.new(&amp;#039;RGB&amp;#039;, (W, H), &amp;#039;black&amp;#039;)\n    draw = ImageDraw.Draw(img)\n    y0 = (H - LINES*FONTSIZE) // 2\n    for i, w in enumerate(active[-LINES:], start=1-max(LINES,0)):\n        y = y0 + (i+LINES-1)*FONTSIZE\n        color = &amp;#039;yellow&amp;#039; if i==0 else &amp;#039;white&amp;#039;\n        draw.text((W//2, y), w, font=FONT, fill=color, anchor=&amp;#039;ma&amp;#039;)\n    return np.array(img)\n\nactive = []              # rolling buffer of words on screen\nfor f in range(dur*FPS):\n    t = f/FPS\n    # add words whose start &amp;lt;= t\n    while sub and sub[0].start.total_seconds() &amp;lt;= t:\n        active.append(sub.pop(0).content.strip())\n    # drop words that are off-screen\n    active = active[-LINES:]\n    out.write(draw_frame(f, active))\nout.release()\nEOF\n\n# 3. Mux audio and burn final\nffmpeg -y -i /tmp/caps.mp4 -i \&amp;quot;$WAV\&amp;quot; -t \&amp;quot;$DUR\&amp;quot; \\\n       -c:v libx264 -crf 18 -pix_fmt yuv420p -shortest \&amp;quot;$OUT\&amp;quot;\necho \&amp;quot;Done → $OUT\&amp;quot;\n```\n\nRun:\n```\nwav2short.sh mybook.wav 60 mybook_short.mp4\n```\nThree minutes later you have a 60-second vertical video with perfectly scrolling word-captions.\n\n-------------------------------------------------\n3.  Tweaks the Hypergeek keeps in his back pocket\n-------------------------------------------------\n- Longer than 60 s? Change the DUR argument; everything scales.  \n- Want highlighted karaoke word? Inside draw_frame() color the exact word instead of the whole line.  \n- Need 4K? Change W=2160, H=3840, bump FONTSIZE.  \n- Hates Python OpenCV? Replace the frame-writer with plain Pillow + ffmpeg’s rawvideo pipe (one line change).  \n- Wants burnt-in waveform? Add ffmpeg filter `showwaves=size=1080x200:colors=cyan` and overlay it at the bottom.  \n- Prefers to stream straight to YouTube? Swap the last ffmpeg line for one that pushes to `rtmps://a.rtmp.youtube.com/...`  \n\n-------------------------------------------------\n4.  Why this satisfies the Hypergeek\n-------------------------------------------------\n- Zero GUI, 100 % scriptable over SSH from his hammock.  \n- Whisper-timestamped is small (74 MB) and runs on CPU; no GPU needed.  \n- Every stage is a file (/tmp/caps.mp4, /tmp/foo.srt) so he can inspect, debug, or re-use.  \n- One dependency install: `pip install whisper-timestamped srt Pillow numpy opencv-python`.  \n- Entire pipeline is &amp;lt; 100 lines—easy to memory-fit even on a 10-year-old ThinkPad.\n\nCopy, tweak, upload, done.&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;role&amp;quot;: &amp;quot;user&amp;quot;,&lt;br /&gt;
        &amp;quot;content&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
    ],&lt;br /&gt;
    temperature=0.6,&lt;br /&gt;
    max_completion_tokens=4096,&lt;br /&gt;
    top_p=1,&lt;br /&gt;
    stream=True,&lt;br /&gt;
    stop=None&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
for chunk in completion:&lt;br /&gt;
    print(chunk.choices[0].delta.content or &amp;quot;&amp;quot;, end=&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>XenoEngineer</name></author>
	</entry>
</feed>