diff --git a/.gitignore b/.gitignore
index cfce883..2fbc35d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,4 +9,6 @@ CustomEncodingJsonExample/bin
CustomEncodingJsonExample/obj
CustomTranscodingParamsTest/bin
CustomTranscodingParamsTest/obj
+CustomEncodingJsonTUSUploadExample/bin
+CustomEncodingJsonTUSUploadExample/obj
ScaleTest
diff --git a/CustomEncodingJsonTUSUploadExample/CustomEncodingJsonTUSUploadExample.csproj b/CustomEncodingJsonTUSUploadExample/CustomEncodingJsonTUSUploadExample.csproj
new file mode 100644
index 0000000..1078ab3
--- /dev/null
+++ b/CustomEncodingJsonTUSUploadExample/CustomEncodingJsonTUSUploadExample.csproj
@@ -0,0 +1,26 @@
+
+
+
+ Exe
+ netcoreapp2.2
+
+
+
+
+
+
+
+
+ Always
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/CustomEncodingJsonTUSUploadExample/Program.cs b/CustomEncodingJsonTUSUploadExample/Program.cs
new file mode 100644
index 0000000..c2313ce
--- /dev/null
+++ b/CustomEncodingJsonTUSUploadExample/Program.cs
@@ -0,0 +1,171 @@
+using Qencode.Api.CSharp.Client;
+using Qencode.Api.CSharp.Client.Classes;
+using Qencode.Api.CSharp.Client.Exceptions;
+using System;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Security.Cryptography;
+using System.Threading;
+using TusDotNetClient;
+
+namespace CustomEncodingJsonTUSUploadExample
+{
+ class Program
+ {
+ /*
+ * This example upload a local file,
+ * transcode it and then,
+ * download the transcoded file
+ */
+
+ static void Main(string[] args)
+ {
+ // You can find your API key under Project settings in your Dashboard on Qencode portal
+ const string apiKey = "YOUR_API_KEY_HERE";
+ const string relative_output_dir = "TranscodedOutput"; // relative output dir
+
+ // This is the full file name of the source video
+ string sourceVideoFullFileName = "E:\\dev\\My\\Sample720.flv";
+ // if an argument is specified, the source video file will be readed from the first argument
+ if (args.Length >= 1 && !string.IsNullOrEmpty(args[0]))
+ sourceVideoFullFileName = args[0];
+
+ try
+ {
+
+ // get access token
+ Console.WriteLine("Requesting access token...");
+ var q = new QencodeApiClient(apiKey);
+ Console.WriteLine("\taccess token: '" + q.AccessToken + "'");
+
+ // create a new task
+ Console.WriteLine("Creating a new task...");
+ var task = q.CreateTask();
+ Console.WriteLine("\tcreated new task with token: '" + task.TaskToken + "' and url for direct video upload (TUS) '" + task.UploadUrl + "'");
+
+ // direct video upload - initiate upload (get endpoint for task)
+ Console.WriteLine("Initiate upload...");
+ var srcFI = new FileInfo(sourceVideoFullFileName);
+ var client = new TusClient();
+ var tusUploadLocationUrl = client.CreateAsync(task.UploadUrl + "/" + task.TaskToken, srcFI.Length).Result;
+ Console.WriteLine("\tobtained TUS upload location: '" + tusUploadLocationUrl + "'");
+
+ // direct video upload - send data
+ var uploadOperation = client.UploadAsync(tusUploadLocationUrl, srcFI);
+ Console.WriteLine("\ttransfer started");
+ uploadOperation.Progressed += (transferred, total) =>
+ {
+ Console.CursorLeft = 0;
+ Console.Write($"Progress: {transferred}/{total}");
+ };
+ Console.WriteLine();
+ Console.WriteLine();
+ uploadOperation.GetAwaiter().GetResult();
+ Console.WriteLine("\tupload done");
+
+ // define a custom task by reading query.json and filling the ##TUS_FILE_UUID## placeholder
+ var tusFileUUID = tusUploadLocationUrl.Substring(tusUploadLocationUrl.LastIndexOf('/') + 1);
+ var customTrascodingJSON = File.ReadAllText("query.json").Replace("##TUS_FILE_UUID##", tusFileUUID);
+ var customTranscodingParams = CustomTranscodingParams.FromJSON(customTrascodingJSON);
+
+ // start a custom task
+ Console.WriteLine("Custom task starting..");
+ Console.WriteLine(customTrascodingJSON);
+
+ // start a custom task - set event handler
+ bool taskCompletedOrError = false;
+ task.TaskCompleted = new RunWorkerCompletedEventHandler(
+ delegate (object o, RunWorkerCompletedEventArgs e)
+ {
+ if (e.Error != null)
+ {
+ taskCompletedOrError = true;
+ Console.WriteLine("Error: ", e.Error.Message);
+ }
+
+ var response = e.Result as TranscodingTaskStatus;
+ if (response.error == 1)
+ {
+ taskCompletedOrError = true;
+ Console.WriteLine("Error: " + response.error_description);
+ }
+ else if (response.status == "completed")
+ {
+ taskCompletedOrError = true;
+ Console.WriteLine("Video urls: ");
+ foreach (var video in response.videos)
+ Console.WriteLine(video.url);
+ }
+ else
+ {
+ Console.WriteLine(response.status);
+ }
+ });
+ // start a custom task - start
+ Console.WriteLine("\tstarting...");
+ var started = task.StartCustom(customTranscodingParams); // starts and poll
+
+ // waiting
+ Console.WriteLine("Waiting..");
+ while (!taskCompletedOrError)
+ Thread.Sleep(1000);
+
+ // get download url
+ if (task.LastStatus == null)
+ throw new InvalidOperationException("Unable to obtain download url");
+ var outputDownloadUrl = new Uri(task.LastStatus.videos.First().url);
+ Console.WriteLine("Output download url: '" + outputDownloadUrl.ToString() + "'");
+ string output_file_name = GetOutputFileName(sourceVideoFullFileName, outputDownloadUrl.Segments.Last());
+ Console.WriteLine("Output file name: '" + output_file_name + "'");
+
+
+ // download
+ Console.WriteLine("Downloading..");
+ HttpFileDownload(outputDownloadUrl, relative_output_dir, output_file_name);
+ Console.WriteLine("\tdownload done");
+ Environment.Exit(0);
+
+ }
+ catch (QencodeApiException e)
+ {
+ Console.WriteLine("Qencode API exception: " + e.Message);
+ Environment.Exit(-1);
+ }
+ catch (QencodeException e)
+ {
+ Console.WriteLine("API call failed: " + e.Message);
+ Environment.Exit(-1);
+ }
+ }
+
+ private static string GetOutputFileName(string inputFullFileName, string outputProposedFileName)
+ {
+ var inputFI = new FileInfo(inputFullFileName);
+ var ouputFI = new FileInfo(outputProposedFileName);
+ return inputFI.Name + ouputFI.Extension;
+ }
+
+ private static void HttpFileDownload(Uri url, string localFolder, string localFileName)
+ {
+ if (!Directory.Exists($"./{localFolder}"))
+ Directory.CreateDirectory($"./{localFolder}");
+
+ var relativeFileName = $"./{localFolder}/{localFileName}";
+
+ if (File.Exists(relativeFileName))
+ {
+ File.Delete(relativeFileName);
+ Console.WriteLine("\toutput file already existing: deleted");
+ }
+
+ using (var wc = new System.Net.WebClient())
+ wc.DownloadFile(url, relativeFileName);
+
+ }
+
+
+ }
+}
diff --git a/CustomEncodingJsonTUSUploadExample/query.json b/CustomEncodingJsonTUSUploadExample/query.json
new file mode 100644
index 0000000..a66a6e5
--- /dev/null
+++ b/CustomEncodingJsonTUSUploadExample/query.json
@@ -0,0 +1,14 @@
+{
+ "query": {
+ "format": [
+ {
+ "output": "mp4",
+ "size": "1280x720",
+ "profile": "main",
+ "bitrate": 3800,
+ "video_codec": "libx264"
+ }
+ ],
+ "source": "tus:##TUS_FILE_UUID##"
+ }
+}
\ No newline at end of file
diff --git a/Qencode.Api.CSharp.Client/Classes/TranscodingTask.cs b/Qencode.Api.CSharp.Client/Classes/TranscodingTask.cs
index 5e03d6d..ce64ace 100644
--- a/Qencode.Api.CSharp.Client/Classes/TranscodingTask.cs
+++ b/Qencode.Api.CSharp.Client/Classes/TranscodingTask.cs
@@ -9,231 +9,243 @@
namespace Qencode.Api.CSharp.Client.Classes
{
- public class TranscodingTask
- {
- private QencodeApiClient api;
-
- private string taskToken;
- ///
- public string TaskToken
- {
- get { return taskToken; }
- }
-
- private string statusUrl;
- ///
- public string StatusUrl
- {
- get { return statusUrl; }
- }
-
- private TranscodingTaskStatus lastStatus;
- ///
- public TranscodingTaskStatus LastStatus
- {
- get { return lastStatus; }
- }
-
- ///
- /// A starting time in seconds in original video to make clip from
- ///
- public double StartTime { get; set; }
-
- ///
- /// Duration from specified start time in original video, seconds
- ///
- public double Duration { get; set; }
-
- ///
- /// Output path variables map (used to set transcoding profile output path placeholder values)s
- ///
- public Dictionary OutputPathVariables { get; }
-
-
- /// Creates new transcoding task
- /// a reference to QencodeApiClient object
- /// transcoding task token
- public TranscodingTask(QencodeApiClient api, string taskToken)
- {
- this.api = api;
- this.taskToken = taskToken;
- this.statusUrl = null;
- OutputPathVariables = new Dictionary();
- }
-
- /// Starts transcoding job using specified transcoding profile list
- /// Array of transcoding profile identifiers
- /// a link to input video or TUS uri
- /// Transfer method identifier
- /// Any string data of 1000 characters max length. E.g. you could pass id of your site user uploading the video or any json object.
- public StartEncodeResponse Start(string[] transcodingProfiles, string uri, string transferMethod = null, string payload = null)
- {
- var profiles = String.Join(",", transcodingProfiles);
- return Start(profiles, uri, transferMethod, payload);
- }
-
- public RunWorkerCompletedEventHandler TaskCompleted;
- public ProgressChangedEventHandler ProgressChanged;
-
- /// Starts transcoding job using specified transcoding profile or list of profiles
- /// One or several transcoding profile identifiers (as comma-separated string)
- /// a link to input video or TUS uri
- /// Transfer method identifier
- /// Any string data of 1000 characters max length. E.g. you could pass id of your site user uploading the video or any json object.
- public StartEncodeResponse Start(string transcodingProfile, string uri, string transferMethod = null, string payload = null)
- {
- var parameters = new Dictionary() {
- { "task_token", taskToken },
- { "uri", uri },
- { "profiles", transcodingProfile }
- };
-
- if (transferMethod != null)
- {
- parameters.Add("transfer_method", transferMethod);
- }
-
- if (payload != null)
- {
- parameters.Add("payload", payload);
- }
-
- var numberFormat = new NumberFormatInfo();
- numberFormat.NumberDecimalSeparator = ".";
- if (StartTime > 0)
- {
- parameters.Add("start_time", StartTime.ToString("0.####", numberFormat));
- }
-
- if (Duration > 0)
- {
- parameters.Add("duration", Duration.ToString("0.####", numberFormat));
- }
-
- if (OutputPathVariables.Count > 0)
- {
- var outputPathVars = JsonConvert.SerializeObject(OutputPathVariables,
- Formatting.None,
- new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
- parameters.Add("output_path_variables", outputPathVars);
- }
-
- var response = api.Request("start_encode", parameters) as StartEncodeResponse;
- this.statusUrl = response.status_url;
- PollStatus();
- return response;
- }
-
- private void PollStatus()
- {
- if (TaskCompleted != null)
- {
- var bw = new BackgroundWorker();
- bw.WorkerReportsProgress = true;
- bw.DoWork += new DoWorkEventHandler(
- delegate (object o, DoWorkEventArgs args)
- {
- BackgroundWorker b = o as BackgroundWorker;
- int percent = 0;
- do
- {
- Thread.Sleep(checkStatusInterval);
- GetStatus();
- int newPercent = Convert.ToInt32(lastStatus.percent);
- if (newPercent > percent)
- {
- percent = newPercent;
- b.ReportProgress(percent, lastStatus);
- }
- } while (lastStatus.status != "completed" && lastStatus.error != 1);
- args.Result = lastStatus;
- });
-
- if (ProgressChanged != null)
- {
- bw.ProgressChanged += ProgressChanged;
- }
-
- bw.RunWorkerCompleted += TaskCompleted;
- bw.RunWorkerAsync();
- }
- }
-
- private int checkStatusInterval = 5000;
- public int CheckStatusInterval
- {
- get { return checkStatusInterval; }
- set
- {
- if (value < 1000)
- {
- value = 1000;
- }
- checkStatusInterval = value;
- }
- }
-
- //TODO: implement startCustom transcoding method
- /**
-
- * Starts transcoding job using custom params
-
- * @param CustomTranscodingParams $task_params
-
- * @param string $payload Any string data of 1000 characters max length. E.g. you could pass id of your site user uploading the video or any json object.
-
- * @return array start_encode API method response
-
- */
-
- public StartEncodeResponse StartCustom(CustomTranscodingParams taskParams, string payload = null)
- {
- var query = new Dictionary() { { "query", taskParams } };
- var query_json = JsonConvert.SerializeObject(query,
- Formatting.None,
- new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore});
-
- var parameters = new Dictionary
- {
- {"task_token", taskToken },
- {"query", query_json }
- };
- if (payload != null)
- {
- parameters.Add("payload", payload);
- }
-
- return _do_request("start_encode2", parameters);
- }
-
- private StartEncodeResponse _do_request(string methodName, Dictionary parameters)
- {
- var response = api.Request(methodName, parameters) as StartEncodeResponse;
- this.statusUrl = response.status_url;
- PollStatus();
- return response;
- }
-
- ///
- /// Gets current task status from qencode service
- ///
- public TranscodingTaskStatus GetStatus()
- {
- var parameters = new Dictionary() {
- { "task_tokens[]", this.taskToken }
- };
-
- //TODO: fallback to /v1/status
-
- var response = api.Request(statusUrl, parameters) as StatusResponse;
- lastStatus = response.statuses[this.taskToken];
- return lastStatus;
- }
- }
+ public class TranscodingTask
+ {
+ private QencodeApiClient api;
+
+ private string taskToken;
+ ///
+ public string TaskToken
+ {
+ get { return taskToken; }
+ }
+
+ private string statusUrl;
+ ///
+ public string StatusUrl
+ {
+ get { return statusUrl; }
+ }
+
+ private string uploadUrl;
+ ///
+ public string UploadUrl
+ {
+ get { return uploadUrl; }
+ }
+
+
+ private TranscodingTaskStatus lastStatus;
+ ///
+ public TranscodingTaskStatus LastStatus
+ {
+ get { return lastStatus; }
+ }
+
+ ///
+ /// A starting time in seconds in original video to make clip from
+ ///
+ public double StartTime { get; set; }
+
+ ///
+ /// Duration from specified start time in original video, seconds
+ ///
+ public double Duration { get; set; }
+
+ ///
+ /// Output path variables map (used to set transcoding profile output path placeholder values)s
+ ///
+ public Dictionary OutputPathVariables { get; }
+
+
+ /// Creates new transcoding task
+ /// a reference to QencodeApiClient object
+ /// transcoding task token
+ /// url for direct video uplload
+ public TranscodingTask(QencodeApiClient api, string taskToken, string uploadUrl = null)
+ {
+ this.api = api;
+ this.taskToken = taskToken;
+ this.statusUrl = null;
+ this.uploadUrl = uploadUrl;
+ OutputPathVariables = new Dictionary();
+ }
+
+ /// Starts transcoding job using specified transcoding profile list
+ /// Array of transcoding profile identifiers
+ /// a link to input video or TUS uri
+ /// Transfer method identifier
+ /// Any string data of 1000 characters max length. E.g. you could pass id of your site user uploading the video or any json object.
+ public StartEncodeResponse Start(string[] transcodingProfiles, string uri, string transferMethod = null, string payload = null)
+ {
+ var profiles = String.Join(",", transcodingProfiles);
+ return Start(profiles, uri, transferMethod, payload);
+ }
+
+ public RunWorkerCompletedEventHandler TaskCompleted;
+ public ProgressChangedEventHandler ProgressChanged;
+
+ /// Starts transcoding job using specified transcoding profile or list of profiles
+ /// One or several transcoding profile identifiers (as comma-separated string)
+ /// a link to input video or TUS uri
+ /// Transfer method identifier
+ /// Any string data of 1000 characters max length. E.g. you could pass id of your site user uploading the video or any json object.
+ public StartEncodeResponse Start(string transcodingProfile, string uri, string transferMethod = null, string payload = null)
+ {
+ var parameters = new Dictionary() {
+ { "task_token", taskToken },
+ { "uri", uri },
+ { "profiles", transcodingProfile }
+ };
+
+ if (transferMethod != null)
+ {
+ parameters.Add("transfer_method", transferMethod);
+ }
+
+ if (payload != null)
+ {
+ parameters.Add("payload", payload);
+ }
+
+ var numberFormat = new NumberFormatInfo();
+ numberFormat.NumberDecimalSeparator = ".";
+ if (StartTime > 0)
+ {
+ parameters.Add("start_time", StartTime.ToString("0.####", numberFormat));
+ }
+
+ if (Duration > 0)
+ {
+ parameters.Add("duration", Duration.ToString("0.####", numberFormat));
+ }
+
+ if (OutputPathVariables.Count > 0)
+ {
+ var outputPathVars = JsonConvert.SerializeObject(OutputPathVariables,
+ Formatting.None,
+ new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
+ parameters.Add("output_path_variables", outputPathVars);
+ }
+
+ var response = api.Request("start_encode", parameters) as StartEncodeResponse;
+ this.statusUrl = response.status_url;
+ PollStatus();
+ return response;
+ }
+
+ private void PollStatus()
+ {
+ if (TaskCompleted != null)
+ {
+ var bw = new BackgroundWorker();
+ bw.WorkerReportsProgress = true;
+ bw.DoWork += new DoWorkEventHandler(
+ delegate (object o, DoWorkEventArgs args)
+ {
+ BackgroundWorker b = o as BackgroundWorker;
+ int percent = 0;
+ do
+ {
+ Thread.Sleep(checkStatusInterval);
+ GetStatus();
+ int newPercent = Convert.ToInt32(lastStatus.percent);
+ if (newPercent > percent)
+ {
+ percent = newPercent;
+ b.ReportProgress(percent, lastStatus);
+ }
+ } while (lastStatus.status != "completed" && lastStatus.error != 1);
+ args.Result = lastStatus;
+ });
+
+ if (ProgressChanged != null)
+ {
+ bw.ProgressChanged += ProgressChanged;
+ }
+
+ bw.RunWorkerCompleted += TaskCompleted;
+ bw.RunWorkerAsync();
+ }
+ }
+
+ private int checkStatusInterval = 5000;
+ public int CheckStatusInterval
+ {
+ get { return checkStatusInterval; }
+ set
+ {
+ if (value < 1000)
+ {
+ value = 1000;
+ }
+ checkStatusInterval = value;
+ }
+ }
+
+ //TODO: implement startCustom transcoding method
+ /**
+
+ * Starts transcoding job using custom params
+
+ * @param CustomTranscodingParams $task_params
+
+ * @param string $payload Any string data of 1000 characters max length. E.g. you could pass id of your site user uploading the video or any json object.
+
+ * @return array start_encode API method response
+
+ */
+
+ public StartEncodeResponse StartCustom(CustomTranscodingParams taskParams, string payload = null)
+ {
+ var query = new Dictionary() { { "query", taskParams } };
+ var query_json = JsonConvert.SerializeObject(query,
+ Formatting.None,
+ new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
+
+ var parameters = new Dictionary
+ {
+ {"task_token", taskToken },
+ {"query", query_json }
+ };
+ if (payload != null)
+ {
+ parameters.Add("payload", payload);
+ }
+
+ return _do_request("start_encode2", parameters);
+ }
+
+ private StartEncodeResponse _do_request(string methodName, Dictionary parameters)
+ {
+ var response = api.Request(methodName, parameters) as StartEncodeResponse;
+ this.statusUrl = response.status_url;
+ PollStatus();
+ return response;
+ }
+
+ ///
+ /// Gets current task status from qencode service
+ ///
+ public TranscodingTaskStatus GetStatus()
+ {
+ var parameters = new Dictionary() {
+ { "task_tokens[]", this.taskToken }
+ };
+
+ //TODO: fallback to /v1/status
+
+ var response = api.Request(statusUrl, parameters) as StatusResponse;
+ lastStatus = response.statuses[this.taskToken];
+ return lastStatus;
+ }
+ }
}
diff --git a/Qencode.Api.CSharp.Client/Classes/UploadTask.cs b/Qencode.Api.CSharp.Client/Classes/UploadTask.cs
new file mode 100644
index 0000000..d893604
--- /dev/null
+++ b/Qencode.Api.CSharp.Client/Classes/UploadTask.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Qencode.Api.CSharp.Client.Classes
+{
+ ///
+ /// This class describe a TUS upload task
+ ///
+ public class UploadTask
+ {
+
+ private QencodeApiClient api;
+
+ private string taskToken;
+ ///
+ public string TaskToken
+ {
+ get { return taskToken; }
+ }
+
+ ///
+ /// Output path variables map (used to set transcoding profile output path placeholder values)s
+ ///
+ public Dictionary OutputPathVariables { get; }
+
+ public UploadTask(QencodeApiClient api, string taskToken, string upload_location, string file_fullName, long file_size, string file_sha1)
+ {
+ this.api = api;
+ this.taskToken = taskToken;
+ this.upload_location = upload_location;
+ this.file_fullName = file_fullName;
+ this.file_size = file_size;
+ this.file_sha1 = file_sha1;
+ OutputPathVariables = new Dictionary();
+ }
+
+ public int error { get; set; }
+ ///
+ /// Upload url location for specified file.
+ ///
+ ///
+ /// Location: https://storage.qencode.com/v1/upload_file/6c6a9b0a7d23cc9555d460269aa9ed56/fa6ca4b8f06f42daa5b0da04cc461dcb
+ /// (where fa6ca4b8f06f42daa5b0da04cc461dcb is file_uuid)
+ ///
+ public string upload_location { get; private set; }
+ public string file_fullName { get; private set; }
+ public long file_size { get; private set; }
+ public string file_sha1 { get; private set; }
+ ///
+ /// Error description
+ ///
+ public string error_description { get; set; }
+
+ public string payload;
+ }
+}
diff --git a/Qencode.Api.CSharp.Client/QencodeApiClient.cs b/Qencode.Api.CSharp.Client/QencodeApiClient.cs
index 04f5a31..4b0261c 100644
--- a/Qencode.Api.CSharp.Client/QencodeApiClient.cs
+++ b/Qencode.Api.CSharp.Client/QencodeApiClient.cs
@@ -217,7 +217,7 @@ public TranscodingTask CreateTask()
{ "token", accessToken }
}) as CreateTaskResponse;
- return new TranscodingTask(this, response.task_token);
+ return new TranscodingTask(this, response.task_token, response.upload_url);
}
}
}
diff --git a/Qencode.Api.CSharp.Client/Responses/CreateTaskResponse.cs b/Qencode.Api.CSharp.Client/Responses/CreateTaskResponse.cs
index 4b4e385..93731b7 100644
--- a/Qencode.Api.CSharp.Client/Responses/CreateTaskResponse.cs
+++ b/Qencode.Api.CSharp.Client/Responses/CreateTaskResponse.cs
@@ -9,8 +9,7 @@ public class CreateTaskResponse : QencodeApiResponse
public string task_token { get; set; }
///
- /// Url for direct video upload using tus.io protocol
- /// (currently not supported with this library)
+ /// Url for direct video upload using tus.io protocol
///
public string upload_url { get; set; }
}
diff --git a/Qencode.Api.CSharp.Client/Responses/CreateUploadTaskResponse.cs b/Qencode.Api.CSharp.Client/Responses/CreateUploadTaskResponse.cs
new file mode 100644
index 0000000..4e95394
--- /dev/null
+++ b/Qencode.Api.CSharp.Client/Responses/CreateUploadTaskResponse.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Qencode.Api.CSharp.Client.Responses
+{
+ public class CreateUploadTaskResponse : QencodeApiResponse
+ {
+ ///
+ /// Upload location for this direct video upload
+ ///
+ ///
+ /// Location: https://storage.qencode.com/v1/upload_file/6c6a9b0a7d23cc9555d460269aa9ed56/fa6ca4b8f06f42daa5b0da04cc461dcb
+ ///
+ public string Location { get; set; }
+ }
+}
diff --git a/Qencode.Api.CSharp.sln b/Qencode.Api.CSharp.sln
index 7f4fe42..93dfc7d 100644
--- a/Qencode.Api.CSharp.sln
+++ b/Qencode.Api.CSharp.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27130.2027
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29806.167
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Qencode.Api.CSharp.Client", "Qencode.Api.CSharp.Client\Qencode.Api.CSharp.Client.csproj", "{D961400F-9432-4078-A664-FFF8134FE133}"
EndProject
@@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProfileEncodingExample", "P
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CustomEncodingJsonExample", "CustomEncodingJsonExample\CustomEncodingJsonExample.csproj", "{15CA760D-18F6-4C77-9E10-28FC35B80996}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomEncodingJsonTUSUploadExample", "CustomEncodingJsonTUSUploadExample\CustomEncodingJsonTUSUploadExample.csproj", "{8B2299C9-6239-4AF5-83A9-AF1150D5BE67}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -33,6 +35,10 @@ Global
{15CA760D-18F6-4C77-9E10-28FC35B80996}.Debug|Any CPU.Build.0 = Debug|Any CPU
{15CA760D-18F6-4C77-9E10-28FC35B80996}.Release|Any CPU.ActiveCfg = Release|Any CPU
{15CA760D-18F6-4C77-9E10-28FC35B80996}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8B2299C9-6239-4AF5-83A9-AF1150D5BE67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8B2299C9-6239-4AF5-83A9-AF1150D5BE67}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8B2299C9-6239-4AF5-83A9-AF1150D5BE67}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8B2299C9-6239-4AF5-83A9-AF1150D5BE67}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE