Skip to content

Instantly share code, notes, and snippets.

@JohannMG
Last active November 8, 2019 20:43
Show Gist options
  • Save JohannMG/2c9313ecf562427c43e6fd45a632a117 to your computer and use it in GitHub Desktop.
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
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