Last active
November 8, 2019 20:43
-
-
Save JohannMG/2c9313ecf562427c43e6fd45a632a117 to your computer and use it in GitHub Desktop.
Friend asked me how we could do a live stream with the Live but not the "stream": there was little to no reliable internet connection. I wrote this in a few hours
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from moviepy.editor import VideoFileClip | |
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip | |
import os.path | |
import sys | |
import time | |
import math | |
import ffmpy | |
''' | |
[ I wrote this in ~3 hours; it's a mess. Enjoy: ] | |
## Problem: Friend asked me how we could do a live stream with the Live but not the "stream": | |
there was little to no reliable internet connection. | |
## My hacky python solution: | |
- Record to live to disk a flv video file (using OBS) | |
- FLV record file specfically chosen b/c it's more durable on reading while being written to still. | |
- Write this python script that clips the last X (user input) seconds of the recording | |
- Convert that recording to mp4 for most messaging apps | |
- PostToService() sent to a messaging app to post the last clip. | |
- Return to waiting for user input | |
## Running | |
**Dependencies:** | |
- moviepy: https://zulko.github.io/moviepy/install.html | |
- ffmpy: https://pypi.org/project/ffmpy/ | |
**Execution:** | |
- Run in terminal with python 3, (I ran with 3.8.0) | |
- python3 SnipClip.py <directory for live recording file> <live recording file name+extension> | |
- e.g., `$ python3 SnipClip.py /Users/johannmg/streams/sniptest/ FileRecording.flv` | |
- notes: directory must end in `/` ( ... I wrote this fast and hacky) | |
**Posting:** | |
- Optional, method stubbed here. | |
- Available PostToService() method here to post to a service automatically after a clip is made | |
- You can also take the clips and drag them into most messaging apps | |
**Known Issues ( that I probably won't fix... ):** | |
- Depending on what service api helper you use, if posting takes too long the whole script will bail | |
- Running a large clip, you can't post while it transcodes the flv clip to mp4 | |
- If you stop and restart the application with the same clip, it will try to use indentical name to | |
other clips of the same length. You'll have to move / remove the first batch of clips. | |
- Probably more I'm forgetting right now | |
If you find any use of this script despite the KIs, ping me on twitter! :) @johann_mg | |
''' | |
# main run loop | |
def main(args): | |
clipCount = 0 | |
directory = args[0] | |
print (directory) | |
filename = args[1] | |
fileMadeTime = os.stat(directory+filename).st_birthtime | |
fileMadeTime = math.floor(fileMadeTime) | |
print(fileMadeTime) | |
## user wait runloop | |
while True: | |
clipCount +=1 | |
print(clipCount) | |
length = input("Next clip length (defaults to 10s)") | |
if length == '': | |
lengthInt = 10 | |
else: | |
lengthInt = int(length) | |
# make new clip | |
clipCount += 1 | |
newClip = captureClip(lengthInt, filename, fileMadeTime, directory, clipCount) | |
# transcode to flv to mp4 | |
mp4Clip = makeMp4(newClip) | |
print("MP4 IS DONE") | |
## delete priginal flv | |
os.remove(newClip) | |
## send to Telegram | |
PostToService(mp4Clip, lengthInt) | |
def captureClip(lengthInt, filename, fileMadeTime, dir, count): | |
now = math.floor(time.time()) | |
# unfinihsed files don't have length in their header: so we use the creation time to get the length | |
fileLengthSeconds = now - fileMadeTime | |
bufferSeconds = 2 #offset seconds from last — common case was pressing GO a little after moments we wanted to capture ended | |
clipTimeStartSeconds = fileLengthSeconds - lengthInt - bufferSeconds | |
clipTimeEndSeconds = fileLengthSeconds - bufferSeconds | |
videoFilePath = dir+filename | |
nowSigFigs = str(time.time())[:4] | |
newClipFilePath = dir + filename + "_CLIPPED" + paddedInt(count,3) + "-" + paddedInt(lengthInt,2) + "s_" + nowSigFigs[-4:] + ".flv" # OBS2019-11-04_18-56-06_CLIPPED-002-22s.flv | |
ffmpeg_extract_subclip(videoFilePath, clipTimeStartSeconds, clipTimeEndSeconds, newClipFilePath) | |
print ("created: " + newClipFilePath) | |
return newClipFilePath | |
def paddedInt(num, len): | |
return str(num).rjust(len, "0") | |
def makeMp4(originalClipFilePath): | |
# assumes .flv, replaces with mp4 | |
newClipFilePath = originalClipFilePath[:-3] + "mp4" | |
ff = ffmpy.FFmpeg( | |
inputs={originalClipFilePath: None}, | |
outputs={newClipFilePath: None} | |
) | |
ff.run() | |
return newClipFilePath | |
''' | |
Service we used was mp4 contianer only | |
''' | |
def PostToService(videoFile, duration): | |
# stub | |
if __name__ == "__main__": | |
"""PASS IN DIRECTORY with / , filename of main clip""" | |
import sys | |
main(sys.argv[1:]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment