.. Copyright (c) 2008-2022 OpenShot Studios, LLC (http://www.openshotstudios.com). This file is part of OpenShot Video Editor (http://www.openshot.org), an open-source project dedicated to delivering high quality video editing and animation solutions to the world. .. OpenShot Video Editor is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. .. OpenShot Video Editor is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. .. You should have received a copy of the GNU General Public License along with OpenShot Library. If not, see . Demos ===== Below you will find many different examples and demos of OpenShot Cloud API. Sample code is provided in many common programming languages, including Python, C#, and JavaScript. Demo App (simple-editor) ------------------------ Check out our free demo app (`simple-editor `_), built with JavaScript, Node.js, and Vue 3, powered by OpenShot Cloud API. This demo is designed as both a showcase for how OpenShot Cloud API can be used and a jump-start for your own software development projects based on OpenShot Cloud API! The `source code `_ is licensed under the MIT license, and can be used with both open-source and commercial applications. *Create and manage video editing projects:* .. image:: images/simple-editor-main-screen.png :alt: Create and manage video editing projects *Upload files, preview videos, and create clips:* .. image:: images/simple-editor-clips.png :alt: Upload files, preview videos, and create clips Python Example Script --------------------- Here is a simple example client script, using Python 3. It connects, creates a new project, uploads a file, creates a clip, and then exports a new video. It should give you a good sense of how things work in general, regardless of programming language. Learn more about the :ref:`api_endpoints_main_ref`. .. code-block:: python import os import time from requests import get, post from requests.auth import HTTPBasicAuth PATH = os.path.dirname(os.path.realpath(__file__)) CLOUD_URL = 'http://cloud.openshot.org' CLOUD_AUTH = HTTPBasicAuth('demo-cloud', 'demo-password') ########################################################## # Get list of projects end_point = '/projects/' r = get(CLOUD_URL + end_point, auth=CLOUD_AUTH) print(r.json()) ########################################################## # Create new project end_point = '/projects/' project_data = { "name": "API Project", "width": 1920, "height": 1080, "fps_num": 30, "fps_den": 1, "sample_rate": 44100, "channels": 2, "channel_layout": 3, "json": "{}", } r = post(CLOUD_URL + end_point, data=project_data, auth=CLOUD_AUTH) print(r.json()) project_id = r.json().get("id") project_url = r.json().get("url") ########################################################## # Upload file to project end_point = '/projects/%s/files/' % project_id source_path = os.path.join(PATH, "example-video.mp4") source_name = os.path.split(source_path)[1] file_data = { "media": None, "project": project_url, "json": "{}" } r = post(CLOUD_URL + end_point, data=file_data, files={"media": (source_name, open(source_path, "rb"))}, auth=CLOUD_AUTH) file_url = r.json().get("url") print(r.json()) ########################################################## # Create a clip for the previously uploaded file end_point = '/projects/%s/clips/' % project_id clip_data = { "file": file_url, "position": 0.0, "start": 0.0, "end": 30.0, "layer": 1, "project": project_url, "json": "{}" } r = post(CLOUD_URL + end_point, data=clip_data, auth=CLOUD_AUTH) print(r.json()) ########################################################## # Create export for final rendered video end_point = '/projects/%s/exports/' % project_id export_data = { "video_format": "mp4", "video_codec": "libx264", "video_bitrate": 8000000, "audio_codec": "ac3", "audio_bitrate": 1920000, "start_frame": 1, "end_frame": None, "project": project_url, "json": "{}" } r = post(CLOUD_URL + end_point, data=export_data, auth=CLOUD_AUTH) export_url = r.json().get("url") print(r.json()) ########################################################## # Wait for Export to finish (give up after around 40 minutes) export_output_url = None is_exported = False countdown = 500 while not is_exported and countdown > 1: r = get(export_url, auth=CLOUD_AUTH) print(r.json()) is_exported = float(r.json().get("progress", 0.0)) == 100.0 countdown -= 1 time.sleep(5.0) # Get final rendered url r = get(export_url, auth=CLOUD_AUTH) export_output_url = r.json().get("output") print(r.json()) print("Export Successfully Completed: %s!" % export_output_url) Node.js Example Script ---------------------- Here is a simple example client script, using JavaScript and Node.js. It connects, creates a new project, uploads some files, creates some clips, exports a video, and then downloads the new video file. It should give you a good sense of how things work using asynchronous JavaScript. Learn more about the :ref:`api_endpoints_main_ref`. .. code-block:: javascript var request = require('request-promise'); var fs = require('fs'); var Promise = require("promise"); var promisePoller = require('promise-poller').default; var projectId = ''; var projectUrl = ''; var exportId = ''; const projectData = { 'json': '{}', 'name': 'My Project Name' }; const protocol = 'http'; const server = 'cloud.openshot.org'; const auth = { 'user': 'demo-cloud', 'pass': 'demo-password'}; // Create a new project post('/projects/', projectData) .then(function(response){ projectUrl = JSON.parse(response).url; projectId = JSON.parse(response).id; console.log('Successfully created project: ' + projectUrl); // Add a couple clips (to be asynchronously processed) const promiseArray = []; promiseArray.push( createClip({ "path": "media-files/MyVideo.mp4", "position": 0.0, "end": 10.0 })); promiseArray.push( createClip({ "path": "media-files/MyAudio.mp4", "position": 0.0, "end": 10.0 })); promiseArray.push( createClip({ "path": "media-files/Watermark.JPG", "position": 0.0, "end": 10.0, "layer": 2 })); // Wait until all files and clips are uploaded Promise.all(promiseArray).then(function(responseArray){ // Export as a new video exportData = { "export_type": "video", "video_format": "mp4", "video_codec": "libx264", "video_bitrate": 8000000, "audio_codec": "ac3", "audio_bitrate": 1920000, "project": projectUrl, "json": '{}' }; post('/exports/', exportData) .then(function(response){ // Export has been created and will begin processing soon var exportUrl = JSON.parse(response).url; exportId = JSON.parse(response).id; console.log('Successfully created export: ' + exportUrl); // Poll until the export has finished var poller = promisePoller({ taskFn: isExportCompleted, interval: 1000, retries: 60*60*1000, timeout: 2000 }).then(function(exportOutputUrl) { // New exported video is ready for download now console.log('Download ' + exportOutputUrl); request(exportOutputUrl).pipe(fs.createWriteStream('Output-' + projectId + '.mp4')); }); }); }); }); function isExportCompleted() { return new Promise(function (resolve, error) { get('/exports/' + exportId + '/', {}) .then(function(response) { var exportStatus = JSON.parse(response).status; var exportOutputUrl = JSON.parse(response).output; if (exportStatus == 'completed') { console.log('Export completed: ' + JSON.stringify(response)); resolve(exportOutputUrl); } }); }); } function createClip(clip) { // Create new File object (and upload file from filesystem) var fileData = { 'json': '{}', 'project': projectUrl, 'media': fs.createReadStream(clip.path) }; return new Promise(function (resolve) { post('/files/', fileData) .then(function(response) { // File uploaded and object created var fileUrl = JSON.parse(response).url; console.log('Successfully created file: ' + fileUrl); // Now we need to add a clip which references this new File object var clipData = { 'file': fileUrl, 'json': '{}', 'position': clip.position || 0.0, 'start': clip.start || 0.0, 'end': clip.end || JSON.parse(response).json.duration, 'layer': clip.layer || 0, 'project': projectUrl }; return post('/clips/', clipData).then(function(response){ var clipUrl = JSON.parse(response).url; console.log('Successfully created clip: ' + clipUrl); resolve(); }); }); }); } function post(endpoint, data) { // Prepare request object and POST data to OpenShot API const r = request.post(protocol + '://' + auth.user + ':' + auth.pass + '@' + server + endpoint, function (err, response, body) { if (err) { return err; } else { console.log(response.statusCode + ': ' + body); return body; } }); // Append form data to request form-data const form_data = r.form(); for ( var key in data ) { form_data.append(key, data[key]); } return r; } function get(endpoint, data) { // Prepare request object and GET data to OpenShot API return request.get(protocol + '://' + auth.user + ':' + auth.pass + '@' + server + endpoint, function (err, response, body) { if (err) { return err; } else { console.log(response.statusCode + ': ' + body); return body; } }); } C# Example Script --------------------- Here is a simple example client script, using C# (.NET version: 5.0.103). It connects, creates a new project, uploads a file, creates a clips, exports a video, and then prints the new video file link. It should give you a good sense of how things work in C# (This code has been made synchronous on purpose). Learn more about the :ref:`api_endpoints_main_ref`. This also uses 2 NuGet packages: Newtonsoft, MimeMapping .. code-block:: csharp using System; using System.Collections.Generic; using System.Threading; using System.Net.Http; using System.Net.Http.Headers; using System.IO; using Newtonsoft.Json.Linq; using MimeMapping; namespace OpenShot { class Program { static void Main(string[] args) { String MakeGetRequest(string url, HttpClient client) { Console.WriteLine("GET: " + url); var response = client.GetAsync(url).GetAwaiter().GetResult(); Console.WriteLine("Response StatusCode: " + (int)response.StatusCode); if (response.IsSuccessStatusCode){ return response.Content.ReadAsStringAsync().GetAwaiter().GetResult();; }else{ Console.WriteLine("Request Failed with message:" + response.Content.ReadAsStringAsync().GetAwaiter().GetResult()); } return ""; } String MakePostRequest(string url, Dictionary formData, HttpClient client) { var requestContent = new FormUrlEncodedContent(formData); Console.WriteLine("POST: " + url); var response = client.PostAsync(url, requestContent).GetAwaiter().GetResult(); Console.WriteLine("Response StatusCode: " + (int)response.StatusCode); if (response.IsSuccessStatusCode){ return response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); }else{ Console.WriteLine("Request Failed with message:" + response.Content.ReadAsStringAsync().GetAwaiter().GetResult()); } return ""; } String MakePostRequestWithFile(string url, Dictionary formData, HttpClient client, FileInfo fileInfo) { var requestContent = new MultipartFormDataContent(); var fileContent = new StreamContent(fileInfo.OpenRead()); fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { Name = "\"media\"", FileName = "\"" + fileInfo.Name + "\"" }; fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(MimeMapping.MimeUtility.GetMimeMapping(fileInfo.Name)); foreach (KeyValuePair kvp in formData) { requestContent.Add(new StringContent(kvp.Value), kvp.Key); } requestContent.Add(fileContent); Console.WriteLine("POST: " + url); var response = client.PostAsync(url, requestContent).GetAwaiter().GetResult(); Console.WriteLine("Response StatusCode: " + (int)response.StatusCode); if (response.IsSuccessStatusCode){ return response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); }else{ Console.WriteLine("Request Failed with message:" + response.Content.ReadAsStringAsync().GetAwaiter().GetResult()); } return ""; } HttpClient client = new HttpClient(); // Connection info string serverUrl = "http://cloud.openshot.org/"; // Basic Auth String username = "demo-cloud"; String password = "demo-password"; String encoded = System.Convert.ToBase64String( System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes( username + ":" + password)); client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", encoded); //////////////////////////////////////////////////////////////////////////////////////// // Get list of projects Console.WriteLine("\n Get list of projects \n"); String responseGetRequest = MakeGetRequest(serverUrl + "projects/", client); Console.WriteLine(responseGetRequest); //////////////////////////////////////////////////////////////////////////////////////// // Create new project Console.WriteLine("\n Create new project \n"); Dictionary payload = new Dictionary { { "name", "API Project" }, { "width", "1920" }, {"height", "1080"}, {"fps_num", "30"}, {"fps_den", "1"}, {"sample_rate", "44100"}, {"channels", "2"}, {"channel_layout", "3"}, {"json", "{}" } }; String responsePostRequest = MakePostRequest(serverUrl + "projects/", payload, client); Console.WriteLine(responsePostRequest); dynamic jsonObj = JObject.Parse(responsePostRequest); Int32 projectId = jsonObj.id; String projectUrl = jsonObj.url; Console.WriteLine("Project ID: " + projectId); Console.WriteLine("Project URL: "+ projectUrl); //////////////////////////////////////////////////////////////////////////////////////// // Upload file to project Console.WriteLine("\n Upload file to project \n"); payload = new Dictionary { {"media", ""}, {"project", projectUrl}, {"json", "{}" } }; String filePath = "D:\\test-file.mp4"; responsePostRequest = MakePostRequestWithFile( projectUrl + "files/", payload, client, new FileInfo(filePath) ); Console.WriteLine(responsePostRequest); jsonObj = JObject.Parse(responsePostRequest); String fileUrl = jsonObj.url; Console.WriteLine("File URL:" + fileUrl); //////////////////////////////////////////////////////////////////////////////////////// // Create a clip for the previously uploaded file Console.WriteLine("\n Create a clip for the previously uploaded file \n"); payload = new Dictionary { {"file", fileUrl}, {"position", "0.0"}, {"start", "0.0"}, {"end", "2.0"}, {"layer", "1"}, {"project", projectUrl}, {"json", "{}"} }; responsePostRequest = MakePostRequest(projectUrl + "clips/", payload, client); Console.WriteLine(responsePostRequest); //////////////////////////////////////////////////////////////////////////////////////// // Create export for final rendered video Console.WriteLine("\n Create export for final rendered video \n"); payload = new Dictionary { {"video_format", "mp4"}, {"video_codec", "libx264"}, {"video_bitrate", "8000000"}, {"audio_codec", "ac3"}, {"audio_bitrate", "1920000"}, {"start_frame", "1"}, {"end_frame", ""}, {"project", projectUrl}, {"json", "{}"} }; responsePostRequest = MakePostRequest(projectUrl + "exports/", payload, client); Console.WriteLine(responsePostRequest); jsonObj = JObject.Parse(responsePostRequest); String exportUrl = jsonObj.url; Boolean isExported = false; Int16 countdown = 500; while (!isExported && countdown > 1){ String responseExportGetRequest = MakeGetRequest(exportUrl, client); jsonObj = JObject.Parse(responseExportGetRequest); String progress = jsonObj.progress; if (progress != null && progress !=""){ float progressFloat = float.Parse(progress); if (progressFloat == 100.0){ isExported = true; } } countdown -= 1; Thread.Sleep(5000); } responseGetRequest = MakeGetRequest(exportUrl, client); jsonObj = JObject.Parse(responseGetRequest); Console.WriteLine(responseGetRequest); Console.WriteLine("Export Successfully Completed: " + jsonObj.output); } } }