X Video Download Normalization
Use this for X/Twitter video downloads when consistency matters more than preserving source filenames.
Workflow
- Save all X video downloads under one shared directory:
~/.Hermes/workspace/output/x_videos/
- Derive a generic filename from the account handle and tweet/status ID:
x_video_<handle>_<statusid>.mp4
- Download with
yt-dlpinto a temp subfolder first. - If the downloaded container is already
.mp4, move it into place. - If it is not
.mp4, convert it to mp4 with ffmpeg:- video:
libx264 - audio:
aac
- video:
- Remove the temp folder.
- Verify the result with:
ls -lhffprobe -show_entries format=duration,size:stream=codec_name,width,height -of json
Commands
Single X status URL
BASE="$HOME/.Hermes/workspace/output/x_videos"
TMP="$BASE/.tmp_<handle>_<statusid>"
mkdir -p "$TMP"
yt-dlp --no-playlist -o "$TMP/%(uploader)s_%(id)s.%(ext)s" "<x-url>"
RAW=$(find "$TMP" -maxdepth 1 -type f | head -1)
DEST="$BASE/x_video_<handle>_<statusid>.mp4"
EXT="${RAW##*.}"
if [ "$EXT" = "mp4" ]; then
mv -f "$RAW" "$DEST"
else
ffmpeg -y -i "$RAW" -c:v libx264 -c:a aac "$DEST"
fi
rm -rf "$TMP"
Verification
ls -lh "$DEST"
ffprobe -v error -show_entries format=duration,size:stream=codec_name,width,height -of json "$DEST"
Important notes
- Prefer
--no-playlistfor X URLs that include/video/1or when yt-dlp tries to treat the post as a playlist. - X status URLs may resolve internally to a different media item ID during download; preserve the user-facing status ID in the output filename anyway.
- Always report back the final saved path, duration, size, resolution, and codecs when available.
- Keep filenames generic and stable; do not reuse the long source title as the final local filename.
Pitfall: Slow HLS fragment downloads for large X videos
Some X/Twitter videos — especially long ones (30min+, 200MB+) — use HLS streaming with thousands of small fragments (e.g., 3386 fragments for a 450MB file). The default yt-dlp behavior downloads all fragments sequentially, which can take 20+ minutes on typical connections and is prone to timeout.
Signs you're hitting this:
[hlsnative] Total fragments: XXXXwith X > 1000- ETA is 10+ minutes and barely decreasing
- Download speed is ~300KB/s or below despite a good connection
Solution: Fall back to HTTP formats.
First, list available formats to find HTTP alternatives:
yt-dlp --no-playlist -F "<x-url>"
Look for http-XXX format IDs (e.g., http-832 for 640x360, http-2176 for 1280x720). These are single-file downloads that include both video and audio in one stream. They download much faster than HLS fragment streaming, though at a lower resolution/bitrate than the highest HLS option.
Then download with the chosen HTTP format:
yt-dlp --no-playlist -f 'http-832' \
-o "$TMP/%(uploader)s_%(id)s_http.%(ext)s" "<x-url>"
Real-world data point: A 447MB X video with 3386 HLS fragments (514k HLS) had ETA ~20min at 300KB/s. Falling back to http-832 (231MB, 640x360, with audio built in) finished in ~2 minutes.
Output standard
Return:
- final saved path
- file size
- duration
- resolution
- codecs
If multiple X videos are requested, batch them into the same shared directory and list each final file separately.