{"id":28193985,"url":"https://github.com/thedrhax/twitch-utils","last_synced_at":"2026-04-11T23:16:06.102Z","repository":{"id":50485055,"uuid":"203480966","full_name":"TheDrHax/Twitch-Utils","owner":"TheDrHax","description":"Record, concatenate and synchronize Twitch live streams and remove background music","archived":false,"fork":false,"pushed_at":"2025-04-13T11:49:15.000Z","size":212,"stargazers_count":21,"open_issues_count":3,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-13T12:37:19.337Z","etag":null,"topics":["concatenation","ffmpeg","praat","spleeter","stream-recording","streamlink","twitch","video-synchronization","voice-separation"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TheDrHax.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-08-21T01:21:15.000Z","updated_at":"2025-04-13T11:49:19.000Z","dependencies_parsed_at":"2024-05-02T18:50:26.433Z","dependency_job_id":"b5346027-a731-4eb5-9170-b8fb84afbb76","html_url":"https://github.com/TheDrHax/Twitch-Utils","commit_stats":{"total_commits":92,"total_committers":1,"mean_commits":92.0,"dds":0.0,"last_synced_commit":"f016a8921263386e30efb3fe94c3268489ff3967"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheDrHax%2FTwitch-Utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheDrHax%2FTwitch-Utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheDrHax%2FTwitch-Utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheDrHax%2FTwitch-Utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TheDrHax","download_url":"https://codeload.github.com/TheDrHax/Twitch-Utils/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254535822,"owners_count":22087399,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["concatenation","ffmpeg","praat","spleeter","stream-recording","streamlink","twitch","video-synchronization","voice-separation"],"created_at":"2025-05-16T13:11:19.352Z","updated_at":"2026-03-04T00:34:48.755Z","avatar_url":"https://github.com/TheDrHax.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Python utils for Twitch [![PyPI version](https://badge.fury.io/py/tdh-twitch-utils.svg)](https://badge.fury.io/py/tdh-twitch-utils)\n\n```\npip3 install tdh-twitch-utils[all]\n```\n\nThis module supports partial installation:\n\n| Package | Scripts | Dependencies |\n| ------- | ------- | ------------ |\n| tdh-twitch-utils | [concat](#concat) | FFmpeg |\n| tdh-twitch-utils[record] | [concat](#concat), [record](#record) | FFmpeg, streamlink |\n| tdh-twitch-utils[offset] | [concat](#concat), [offset](#offset) | FFmpeg, praat-parselmouth |\n| tdh-twitch-utils[mute] | [concat](#concat), [mute](#mute) | FFmpeg, tensorflow, spleeter |\n| tdh-twitch-utils[all] | all of the above | all of the above |\n\nYou can also provide a list of extras in a single command:\n\n```\npip3 install tdh-twitch-utils[record,offset]\n```\n\n## concat\n\nThis script uses MPEG-TS timestamps to concatenate multiple\nvideo segments into a single file without re-encoding. It is\nmost useful for assembling partial stream recordings in case\nof interruption or error during stream download. Overlapping\nparts will be removed precisely with ffmpeg's concat demuxer.\n\n### Example\n\n```\n# download two overlapping segments (60 seconds each)\nVOD=\"YOUR VOD ID\"\nstreamlink -o 1.ts --hls-duration 60 \"twitch.tv/videos/$VOD\" best\nstreamlink -o 2.ts --hls-start-offset 30 --hls-duration 60 \"twitch.tv/videos/$VOD\" best\n\n# concatenate two segments into one video\ntwitch_utils concat 1.ts 2.ts -o result.mp4\n\n# create one segment\ntwitch_utils concat 1.ts 2.ts -o result.ts\n\n# pipe concatenated MPEG-TS stream to other applications\ntwitch_utils concat 1.ts 2.ts -o - | ffmpeg -i - -c copy result.mp4\n\n# preview result in mpv with seeking\ntwitch_utils concat 1.ts 2.ts -o - -f edl | mpv -\n# or...\nmpv $(twitch_utils concat 1.ts 2.ts -o - -f edl_uri)\n```\n\n## record\n\nThis script can be used to record live streams without waiting\nfor them to end. It starts to record live stream immediately,\nthen downloads VOD and concatenates them into full stream recording.\n\nMain features:\n* Start recording at any time - stream will be recorded from the beginning;\n* Monitor streamlink process for errors and skipped segments - and fix them;\n* Resume recording after restart of the script - it is possible as long as\nthe stream is still online and already downloaded parts are accessible;\n* Skip ads even without paid subscription - ad segments will be ignored by\nstreamlink and missing original segments will be downloaded from VOD;\n\nAlgorithm:\n1. Check if channel is live and VOD for current stream already exists;\n2. Get live VOD ID from Twitch API;\n3. Start downloading live stream into file `VOD.0.ts`;\n4. Wait 1 minute and start downloading VOD into file `VOD.1.ts`;\n5. Wait for VOD download to finish;\n6. Check the possibility of concatenation and download missing parts of the timeline;\n7. Wait for stream to finish;\n8. Restart stream recording in case of errors or skipped segments, wait 1 minute and go to step 6;\n9. Concatenate all parts via `concat` script (see above).\n\n### Example\n\n```\n# Record live stream of channel 'blackufa' using 2 threads\ntwitch_utils record -j 2 blackufa\n```\n\n## vod\n\nIn June 2025 Twitch added `EXT-X-PLAYLIST-TYPE:EVENT` option to VOD playlists.\nNow they are not static, and streamlink can't be used to download parts of VOD\nwith `--hls-start-offset`. However this means that we can now record the whole\nstream from the beginning by just downloading the VOD until it ends.\n\nThis script uses very simple HLS client implementation that can download\nVODs partially, continue after restart and assemble full recording from multiple\nparts.\n\n### Example\n\n```\n# Record currently live channel (VOD will be found automatically)\ntwitch_utils vod -c blackufa\n\n# Record a specific VOD by ID\ntwitch_utils vod -v 2496311779\n\n# Force a specific HLS playlist for VOD\ntwitch_utils vod -v 2496311779 -u https://.../m3u8\n\n# List available resolutions\ntwitch_utils vod -c blackufa -Q\n```\n\n## offset\n\nThis script performs cross-correlation of two audio files to find\noffset between them. First argument is cropped and used as template.\nSecond argument can have any duration -- it will be divided into\nseparate chunks to reduce memory usage (otherwise it wouldn't be\npossible to use exceptionally big files). Both arguments can be\nvideos or audio files -- audio track will be extracted and converted.\nYou can even use HTTP links if `ffprobe` is able to correctly determine\nsecond argument's duration.\n\n### Example\n\n```\n# Cut small segment from big video file (offset: 123 seconds)\nffmpeg -ss 123 -i YOUR_FILE.mp4 -t 60 -c copy template.mp4\n\n# Find offset of template.mp4 within YOUR_FILE.mp4\ntwitch_utils offset template.mp4 YOUR_FILE.mp4\n# ... returns 122.99997732426303\n\n# Same command, but result will be rounded to nearest integer\ntwitch_utils offset template.mp4 YOUR_FILE.mp4 --round\n# ... returns 123\n```\n\n## mute\n\nThis script attempts to separate streamer's voice from background music by using [Spleeter](https://github.com/deezer/spleeter). Only specified time ranges are affected. Output contains the same video, but without music in these parts.\n\nThe main purpose of this script is to remove automated Content-ID claims from the video on YouTube without muting the whole section.\n\nThe result is similar to \"Mute song only (beta)\" in YouTube Studio, but this script is much faster and can handle multiple time ranges at once.\n\nNote: Prebuilt binaries of Tensorflow require CPUs with AVX support.\n\n### Example\n\n```\n# Remove music from 5:00 to 8:00 and from 1:00:00 to 1:05:00\ntwitch_utils mute input.mp4 5:00~8:00 1:00:00~1:05:00 -o output.mp4\n```\n\n# Thanks\n\n* [TwitchRecover](https://github.com/TwitchRecover/TwitchRecover) for finding a way to download unlisted/broken VODs","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthedrhax%2Ftwitch-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthedrhax%2Ftwitch-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthedrhax%2Ftwitch-utils/lists"}