Squashed commit of the following:
commit 4fe0af4e6a4a15ee4796a857e79ad0fe9b72c0f1 Author: Dylan <dylanpdx@gmail.com> Date: Wed Dec 28 18:09:25 2022 +0000 Misc. changes to MP4 Looping function commit 42ef8845c38c5a74e56da3c5f035d5a6c091c86a Author: Dylan <dylanpdx@gmail.com> Date: Tue Dec 27 20:00:22 2022 +0000 Abandoning raw gif conversion for now; looping vid instead commit b61938b340a02ac8cfab02048b7e9deaf87edbf5 Author: Dylan <dylanpdx@gmail.com> Date: Tue Dec 27 19:38:58 2022 +0000 More work on WIP gif generation commit 3bc6e7e0da1ce6ae905c80bbbaaa55a68050de52 Author: Dylan <dylanpdx@gmail.com> Date: Mon Dec 26 14:46:46 2022 +0000 Experimental gif conversion
This commit is contained in:
parent
790779e8f3
commit
7ff1031627
1
.github/workflows/deploy.yml
vendored
1
.github/workflows/deploy.yml
vendored
@ -64,3 +64,4 @@ jobs:
|
||||
VXTWITTER_REPO: ${{ secrets.VXTWITTER_REPO }}
|
||||
VXTWITTER_URL: ${{ secrets.VXTWITTER_URL }}
|
||||
VXTWITTER_COMBINATION_METHOD: ${{ secrets.VXTWITTER_COMBINATION_METHOD }}
|
||||
VXTWITTER_GIF_CONVERT_API: ${{ secrets.VXTWITTER_GIF_CONVERT_API }}
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -10,4 +10,6 @@ _meta
|
||||
.serverless
|
||||
db/
|
||||
.coverage
|
||||
htmlcov/
|
||||
htmlcov/
|
||||
template
|
||||
build
|
||||
|
@ -2,7 +2,7 @@ import json
|
||||
import os
|
||||
|
||||
if ('RUNNING_TESTS' in os.environ):
|
||||
config= {"config":{"link_cache":"ram","database":"","table":"","color":"","appname": "vxTwitter","repo": "https://github.com/dylanpdx/BetterTwitFix","url": "https://vxtwitter.com","combination_method": "local"}}
|
||||
config= {"config":{"link_cache":"ram","database":"","table":"","color":"","appname": "vxTwitter","repo": "https://github.com/dylanpdx/BetterTwitFix","url": "https://vxtwitter.com","combination_method": "local","gifConvertAPI":""}}
|
||||
elif ('RUNNING_SERVERLESS' in os.environ and os.environ['RUNNING_SERVERLESS'] == '1'): # pragma: no cover
|
||||
config = {
|
||||
"config":{
|
||||
@ -13,7 +13,8 @@ elif ('RUNNING_SERVERLESS' in os.environ and os.environ['RUNNING_SERVERLESS'] ==
|
||||
"appname": os.environ["VXTWITTER_APP_NAME"],
|
||||
"repo": os.environ["VXTWITTER_REPO"],
|
||||
"url": os.environ["VXTWITTER_URL"],
|
||||
"combination_method": os.environ["VXTWITTER_COMBINATION_METHOD"] # can either be 'local' or a URL to a server handling requests in the same format
|
||||
"combination_method": os.environ["VXTWITTER_COMBINATION_METHOD"], # can either be 'local' or a URL to a server handling requests in the same format
|
||||
"gifConvertAPI":os.environ["VXTWITTER_GIF_CONVERT_API"]
|
||||
}
|
||||
}
|
||||
else:
|
||||
@ -29,7 +30,8 @@ else:
|
||||
"appname": "vxTwitter",
|
||||
"repo": "https://github.com/dylanpdx/BetterTwitFix",
|
||||
"url": "https://vxtwitter.com",
|
||||
"combination_method": "local" # can either be 'local' or a URL to a server handling requests in the same format
|
||||
"combination_method": "local", # can either be 'local' or a URL to a server handling requests in the same format
|
||||
"gifConvertAPI":""
|
||||
}
|
||||
}
|
||||
|
||||
|
30
gifConvert/Dockerfile
Normal file
30
gifConvert/Dockerfile
Normal file
@ -0,0 +1,30 @@
|
||||
FROM public.ecr.aws/lambda/python:3.8 AS builder
|
||||
RUN yum -y install git curl
|
||||
RUN yum -y groupinstall 'Development Tools'
|
||||
RUN git clone https://github.com/kohler/gifsicle
|
||||
WORKDIR gifsicle
|
||||
RUN autoreconf -i
|
||||
RUN ./configure --disable-gifview --disable-gifdiff
|
||||
RUN make
|
||||
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||
WORKDIR /var/task
|
||||
RUN git clone https://github.com/ImageOptim/gifski
|
||||
WORKDIR gifski
|
||||
RUN /root/.cargo/bin/cargo build --release
|
||||
|
||||
|
||||
FROM public.ecr.aws/lambda/python:3.8
|
||||
RUN yum -y update
|
||||
RUN yum -y install git && yum -y install wget && yum -y install tar.x86_64 && yum -y install xz && yum clean all
|
||||
RUN wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
|
||||
RUN tar -xvf ffmpeg-release-amd64-static.tar.xz
|
||||
RUN mv ff*/ffmpeg . && mv ff*/ffprobe . && rm *.tar.xz && rm -rf ff*/
|
||||
COPY --from=builder /var/task/gifsicle/src/gifsicle ./
|
||||
COPY --from=builder /var/task/gifski/target/release/gifski ./
|
||||
|
||||
# Copy function code
|
||||
COPY __init__.py ${LAMBDA_TASK_ROOT}/app.py
|
||||
COPY conv.sh ${LAMBDA_TASK_ROOT}/conv.sh
|
||||
|
||||
# Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)
|
||||
CMD [ "app.lambda_handler" ]
|
92
gifConvert/__init__.py
Normal file
92
gifConvert/__init__.py
Normal file
@ -0,0 +1,92 @@
|
||||
import base64
|
||||
import os
|
||||
import subprocess
|
||||
import json
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
def extractStatus(url):
|
||||
return ""
|
||||
|
||||
def get_video_frame_rate(filename):
|
||||
result = subprocess.run(
|
||||
[
|
||||
"./ffprobe",
|
||||
"-v",
|
||||
"error",
|
||||
"-select_streams",
|
||||
"v",
|
||||
"-of",
|
||||
"default=noprint_wrappers=1:nokey=1",
|
||||
"-show_entries",
|
||||
"stream=r_frame_rate",
|
||||
filename,
|
||||
],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
result_string = result.stdout.decode('utf-8').split()[0].split('/')
|
||||
fps = float(result_string[0])/float(result_string[1])
|
||||
return fps
|
||||
|
||||
def get_video_length_seconds(filename):
|
||||
result = subprocess.run(
|
||||
[
|
||||
"./ffprobe",
|
||||
"-v",
|
||||
"error",
|
||||
"-show_entries",
|
||||
"format=duration",
|
||||
"-of",
|
||||
"default=noprint_wrappers=1:nokey=1",
|
||||
filename,
|
||||
],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
result_string = result.stdout.decode('utf-8').split()[0]
|
||||
return float(result_string)
|
||||
|
||||
def loop_video_until_length(filename, length):
|
||||
# use stream_loop to loop video until it's at least length seconds long
|
||||
video_length = get_video_length_seconds(filename)
|
||||
if video_length < length:
|
||||
loops = int(length/video_length)
|
||||
new_filename = tempfile.mkstemp(suffix=".mp4")[1]
|
||||
out = subprocess.call(["./ffmpeg","-stream_loop",str(loops),"-i",filename,"-c","copy","-y",new_filename],stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT)
|
||||
return new_filename
|
||||
else:
|
||||
return filename
|
||||
|
||||
|
||||
|
||||
def lambda_handler(event, context):
|
||||
if ("queryStringParameters" not in event):
|
||||
return {
|
||||
"statusCode": 400,
|
||||
"body": "Invalid request."
|
||||
}
|
||||
|
||||
url = event["queryStringParameters"].get("url","")
|
||||
|
||||
# download video
|
||||
videoLocation = tempfile.mkstemp(suffix=".mp4")[1]
|
||||
subprocess.call(["wget","-O",videoLocation,url],stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT)
|
||||
|
||||
videoLocationLooped = loop_video_until_length(videoLocation, 30)
|
||||
if videoLocationLooped != videoLocation:
|
||||
os.remove(videoLocation)
|
||||
videoLocation = videoLocationLooped
|
||||
|
||||
with open(videoLocation, "rb") as image_file:
|
||||
encoded_string = base64.b64encode(image_file.read()).decode('ascii')
|
||||
os.remove(videoLocation)
|
||||
return {
|
||||
'statusCode': 200,
|
||||
"headers":
|
||||
{
|
||||
"Content-Type": "video/mp4"
|
||||
},
|
||||
'body': encoded_string,
|
||||
'isBase64Encoded': True
|
||||
}
|
64
gifConvert/conv.sh
Normal file
64
gifConvert/conv.sh
Normal file
@ -0,0 +1,64 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
usage(){
|
||||
echo "Usage: $0 [options] output"
|
||||
echo "Options:"
|
||||
echo " --help Show this help"
|
||||
echo " -u, --url URL of the video"
|
||||
echo " -w, --max-width Maximum width of the output"
|
||||
echo " -h, --max-height Maximum height of the output"
|
||||
echo " -t, --threads Number of threads to use"
|
||||
exit 1
|
||||
}
|
||||
|
||||
URL=""
|
||||
MAXW=400
|
||||
MAXH=267
|
||||
THREADS=1
|
||||
OUTPUT="out.gif"
|
||||
FPS=10
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--help)
|
||||
usage
|
||||
;;
|
||||
-u|--url)
|
||||
URL="$2"
|
||||
shift
|
||||
;;
|
||||
-w|--max-width)
|
||||
MAXW="$2"
|
||||
shift
|
||||
;;
|
||||
-h|--max-height)
|
||||
MAXH="$2"
|
||||
shift
|
||||
;;
|
||||
-t|--threads)
|
||||
THREADS="$2"
|
||||
shift
|
||||
;;
|
||||
-f|--fps)
|
||||
FPS="$2"
|
||||
shift
|
||||
;;
|
||||
-*)
|
||||
echo "Unknown option: $1"
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
OUTPUT="$1"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# make unique temp directory
|
||||
TEMPDIR=$( mktemp -d )
|
||||
|
||||
./ffmpeg -i "$URL" -vf "scale=if(gte(iw\,ih)\,min($MAXW\,iw)\,-2):if(lt(iw\,ih)\,min($MAXH\,ih)\,-2)" -threads $THREADS "$TEMPDIR/frame%04d.png"
|
||||
./gifski -o "$TEMPDIR/out.gif" --fast --fps $FPS --quality=90 $TEMPDIR/frame*.png
|
||||
#./gifsicle -O3 "$TEMPDIR/out.gif" -o "$OUTPUT"
|
||||
mv "$TEMPDIR/out.gif" "$OUTPUT"
|
||||
rm -rf "$TEMPDIR"
|
@ -26,6 +26,7 @@ provider:
|
||||
VXTWITTER_REPO: ${env:VXTWITTER_REPO, 'https://github.com/dylanpdx/BetterTwitFix'}
|
||||
VXTWITTER_URL: ${env:VXTWITTER_URL, 'https://vxtwitter.com'}
|
||||
VXTWITTER_COMBINATION_METHOD: ${env:VXTWITTER_COMBINATION_METHOD, 'local'}
|
||||
VXTWITTER_GIF_CONVERT_API: ${env:VXTWITTER_GIF_CONVERT_API, ''}
|
||||
|
||||
package:
|
||||
patterns:
|
||||
|
@ -454,9 +454,14 @@ def embed(video_link, vnf, image):
|
||||
appNamePost = " - Image " + str(image+1) + "/" + str(vnf['images'][4])
|
||||
image = vnf['images'][image]
|
||||
template = 'image.html'
|
||||
|
||||
if vnf['type'] == "Video":
|
||||
if vnf['isGif'] == True and config['config']['gifConvertAPI'] != "" and config['config']['gifConvertAPI'] != "none":
|
||||
vnf['url'] = f"{config['config']['gifConvertAPI']}/convert.mp4?url={vnf['url']}"
|
||||
appNamePost = " - GIF"
|
||||
urlDesc = urllib.parse.quote(textwrap.shorten(desc, width=220, placeholder="..."))
|
||||
template = 'video.html'
|
||||
|
||||
if vnf['type'] == "":
|
||||
urlDesc = urllib.parse.quote(textwrap.shorten(desc, width=220, placeholder="..."))
|
||||
template = 'video.html'
|
||||
|
Loading…
x
Reference in New Issue
Block a user