File size: 4,582 Bytes
c16a803
 
5296733
c16a803
40446f2
e4ed31e
6c154f8
c16a803
 
c358ea4
c16a803
 
40446f2
6c154f8
 
 
c16a803
6c154f8
 
79683ca
6c154f8
 
79683ca
c047e75
e4ed31e
cbd85fc
 
6c154f8
 
 
 
 
3c753ee
6c154f8
 
c16a803
6c154f8
79683ca
6c154f8
 
 
 
 
 
6f1f7b0
c358ea4
a8cf125
 
c358ea4
a8cf125
 
 
 
 
 
 
 
c358ea4
15d3f13
6c154f8
c16a803
 
 
 
 
6f1f7b0
c16a803
 
 
 
 
6c154f8
 
c16a803
 
 
 
 
b7e494d
c16a803
b7e494d
 
c16a803
b7e494d
6c154f8
c16a803
6c154f8
 
c16a803
 
ffe2496
c358ea4
15d3f13
 
 
 
6c154f8
 
 
 
52cd85c
6c154f8
 
 
 
 
 
c358ea4
15d3f13
b7e494d
15d3f13
 
 
 
 
b7e494d
6c154f8
c358ea4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import logging
import shutil
import tempfile
import subprocess
from pathlib import Path
from moviepy.editor import VideoFileClip
import gradio as gr
import requests
from urllib.parse import urlparse
from web3.storage import Web3Storage

logging.basicConfig(level=logging.INFO)

def download_file(url, destination):
    """Downloads a file from a url to a destination."""
    response = requests.get(url)
    response.raise_for_status()
    with open(destination, 'wb') as f:
        f.write(response.content)

def get_input_path(video_file, video_url, temp_dir):
    """Returns the path to the video file, downloading it if necessary."""
    if video_file is not None:
        return Path(video_file.name)
    elif video_url:
        url_path = urlparse(video_url).path
        file_name = Path(url_path).name
        destination = temp_dir / file_name
        download_file(video_url, destination)
        return destination
    else:
        raise ValueError("No input was provided.")

def get_output_path(input_path, temp_dir):
    """Returns the path to the output file, creating it if necessary."""
    output_path = temp_dir / (Path(input_path).stem + ".m3u8")
    return output_path

def get_aspect_ratio(input_path, aspect_ratio):
    """Returns the aspect ratio of the video, calculating it if necessary."""
    if aspect_ratio is not None:
        return aspect_ratio
    video = VideoFileClip(str(input_path))
    return f"{video.size[0]}:{video.size[1]}"

def upload_to_web3_storage(api_key, path):
    """Uploads a file to web3.storage using the HTTP API."""
    headers = {"Authorization": f"Bearer {api_key}"}
    with open(path, 'rb') as f:
        response = requests.post(
            "https://api.web3.storage/upload",
            headers=headers,
            data=f,
        )
    response.raise_for_status()  # Raises an exception if the request failed
    cid = response.json()["value"]["cid"]
    return f"https://dweb.link/ipfs/{cid}"

def convert_video(video_file, quality, aspect_ratio, video_url, api_key, upload):
    """Converts a video to HLS format, adjusting the quality and aspect ratio as necessary."""
    with tempfile.TemporaryDirectory() as temp_dir:
        temp_dir = Path(temp_dir)
        input_path = get_input_path(video_file, video_url, temp_dir)
        output_path = get_output_path(input_path, temp_dir)
        aspect_ratio = get_aspect_ratio(input_path, aspect_ratio)

        ffmpeg_command = [
            "ffmpeg", "-i", str(input_path), "-c:v", "libx264", "-crf", str(quality),
            "-vf", f"scale=-1:720,setsar={aspect_ratio}", "-hls_time", "6",
            "-hls_playlist_type", "vod", "-f", "hls", str(output_path)
        ]

        try:
            logging.info("Running command: %s", " ".join(ffmpeg_command))
            subprocess.run(ffmpeg_command, check=True, timeout=600)
        except subprocess.CalledProcessError:
            logging.exception("ffmpeg command failed.")
            return "ffmpeg command failed."
        except subprocess.TimeoutExpired:
            logging.exception("ffmpeg command timed out.")
            return "ffmpeg command timed out."
        except FileNotFoundError:
            logging.exception("ffmpeg is not installed.")
            return "ffmpeg is not installed."
        except Exception as e:
            logging.exception("An error occurred.")
            return f"An error occurred: {str(e)}"

        # Copy the output to a new temporary file that won't be deleted when the
        # TemporaryDirectory context manager exits.
        output_copy_path = shutil.copy2(output_path, tempfile.gettempdir())

    if upload:
        return upload_to_web3_storage(api_key, output_copy_path)
    else:
        return output_copy_path

def main():
    video_file = gr.inputs.File(label="Video File", type="file")
    quality = gr.inputs.Dropdown(
        choices=["18", "23", "28", "32"], label="Quality", default="23")
    aspect_ratio = gr.inputs.Dropdown(
        choices=[None, "1:1", "4:3", "3:2", "5:4", "16:9", "21:9", 
                 "1.85:1", "2.35:1", "3:1", "360", "9:16", "16:9", 
                 "2:1", "1:2", "9:1"], 
        label="Aspect Ratio", default=None) 
    video_url = gr.inputs.Textbox(label="Video URL")
    api_key = gr.inputs.Textbox(label="web3.storage API Key")
    upload = gr.inputs.Checkbox(label="Upload to web3.storage", default=False)

    gr.Interface(
        convert_video, 
        inputs=[video_file, quality, aspect_ratio, video_url, api_key, upload],
        outputs='text'
    ).launch()

if __name__ == "__main__":
    main()