public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { { log.Info($"Webhook was triggered!"); // Init variables string pathUrl = ""; string jsonFaceRedaction = ""; dynamic jpgFaces = new JArray() as dynamic; dynamic objFaceDetection = new JObject(); dynamic objFaceDetectionOffset = new JObject(); dynamic pngThumbnails = new JArray() as dynamic; string prefixpng = ""; string jsonMotionDetection = ""; dynamic objMotionDetection = new JObject(); dynamic objMotionDetectionOffset = new JObject(); string jsonOcr = ""; dynamic objOcr = new JObject(); dynamic objOcrOffset = new JObject(); string jsonAnnotation = ""; dynamic objAnnotation = new JObject(); dynamic objAnnotationOffset = new JObject(); string jsonModeration = ""; dynamic objModeration = new JObject(); dynamic objModerationOffset = new JObject(); string copyToContainer = ""; string prefixjpg = ""; string targetContainerUri = ""; TimeSpan timeOffset = new TimeSpan(0); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); var attachedstoragecred = KeyHelper.ReturnStorageCredentials(); log.Info(jsonContent); MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); // Offset value ? if (data.timeOffset != null) // let's store the offset { timeOffset = TimeSpan.Parse((string)data.timeOffset); } // // FACE REDACTION // if (data.faceRedaction != null && data.faceRedaction.assetId != null) { List <CloudBlob> listJPGCopies = new List <CloudBlob>(); // Get the asset string assetid = data.faceRedaction.assetId; var outputAsset = _context.Assets.Where(a => a.Id == assetid).FirstOrDefault(); if (outputAsset == null) { log.Info($"Asset not found {assetid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } var jsonFile = outputAsset.AssetFiles.Where(a => a.Name.ToUpper().EndsWith(".JSON")).FirstOrDefault(); var jpgFiles = outputAsset.AssetFiles.Where(a => a.Name.ToUpper().EndsWith(".JPG")); Uri publishurl = MediaServicesHelper.GetValidOnDemandPath(_context, outputAsset); if (publishurl != null) { pathUrl = publishurl.ToString(); } else { log.Info($"Asset not published"); } // Let's copy the JPG faces if (data.faceRedaction.copyToContainer != null) { copyToContainer = data.faceRedaction.copyToContainer + DateTime.UtcNow.ToString("yyyyMMdd"); // let's copy JPG to a container prefixjpg = outputAsset.Uri.Segments[1] + "-"; log.Info($"prefixjpg {prefixjpg}"); string storname = amsCredentials.StorageAccountName; string storkey = amsCredentials.StorageAccountKey; if (outputAsset.StorageAccountName != amsCredentials.StorageAccountName) { if (attachedstoragecred.ContainsKey(outputAsset.StorageAccountName)) // asset is using another storage than default but we have the key { storname = outputAsset.StorageAccountName; storkey = attachedstoragecred[storname]; } else // we don't have the key for that storage { log.Info($"Face redaction Asset is in {outputAsset.StorageAccountName} and key is not provided in MediaServicesAttachedStorageCredentials application settings"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Storage key is missing" })); } } var sourceContainer = CopyBlobHelpers.GetCloudBlobContainer(storname, storkey, outputAsset.Uri.Segments[1]); CloudBlobContainer targetContainer; if (data.faceRedaction.copyToContainerAccountName != null) { // copy to a specific storage account targetContainer = CopyBlobHelpers.GetCloudBlobContainer((string)data.faceRedaction.copyToContainerAccountName, (string)data.faceRedaction.copyToContainerAccountKey, copyToContainer); } else { // copy to ams storage account targetContainer = CopyBlobHelpers.GetCloudBlobContainer(amsCredentials.StorageAccountName, amsCredentials.StorageAccountKey, copyToContainer); } listJPGCopies = await CopyBlobHelpers.CopyFilesAsync(sourceContainer, targetContainer, prefixjpg, "jpg", log); targetContainerUri = targetContainer.Uri.ToString(); } foreach (IAssetFile file in jpgFiles) { string index = file.Name.Substring(file.Name.Length - 10, 6); int index_i = 0; if (int.TryParse(index, out index_i)) { dynamic entry = new JObject(); entry.id = index_i; entry.fileId = file.Id; entry.fileName = file.Name; if (copyToContainer != "") { entry.url = targetContainerUri + "/" + prefixjpg + file.Name; } else if (!string.IsNullOrEmpty(pathUrl)) { entry.url = pathUrl + file.Name; } jpgFaces.Add(entry); } } if (jsonFile != null) { jsonFaceRedaction = MediaServicesHelper.ReturnContent(jsonFile); objFaceDetection = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonFaceRedaction); objFaceDetectionOffset = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonFaceRedaction); if (timeOffset.Ticks != 0) // Let's add the offset { foreach (var frag in objFaceDetectionOffset.fragments) { frag.start = ((long)(frag.start)) + (long)((((double)timeOffset.Ticks / (double)TimeSpan.TicksPerSecond) * (double)objFaceDetectionOffset.timescale)); } } } if (jsonFaceRedaction != "" && data.faceRedaction.deleteAsset != null && ((bool)data.faceRedaction.deleteAsset)) // If asset deletion was asked { // let's wait for the copy to finish before deleting the asset.. if (listJPGCopies.Count > 0) { log.Info("JPG Copy with asset deletion was asked. Checking copy status..."); bool continueLoop = true; while (continueLoop) { listJPGCopies = listJPGCopies.Where(r => r.CopyState.Status == CopyStatus.Pending).ToList(); if (listJPGCopies.Count == 0) { continueLoop = false; } else { log.Info("JPG Copy not finished. Waiting 3s..."); Task.Delay(TimeSpan.FromSeconds(3d)).Wait(); listJPGCopies.ForEach(r => r.FetchAttributes()); } } } outputAsset.Delete(); } } // // MES Thumbnails // if (data.mesThumbnails != null && data.mesThumbnails.assetId != null) { List <CloudBlob> listPNGCopies = new List <CloudBlob>(); // Get the asset string assetid = data.mesThumbnails.assetId; var outputAsset = _context.Assets.Where(a => a.Id == assetid).FirstOrDefault(); if (outputAsset == null) { log.Info($"Asset not found {assetid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } var pngFiles = outputAsset.AssetFiles.Where(a => a.Name.ToUpper().EndsWith(".PNG")); Uri publishurl = MediaServicesHelper.GetValidOnDemandPath(_context, outputAsset); if (publishurl != null) { pathUrl = publishurl.ToString(); } else { log.Info($"Asset not published"); } // Let's copy the PNG Thumbnails if (data.mesThumbnails.copyToContainer != null) { copyToContainer = data.mesThumbnails.copyToContainer + DateTime.UtcNow.ToString("yyyyMMdd"); // let's copy PNG to a container prefixpng = outputAsset.Uri.Segments[1] + "-"; log.Info($"prefixpng {prefixpng}"); string storname = amsCredentials.StorageAccountName; string storkey = amsCredentials.StorageAccountKey; if (outputAsset.StorageAccountName != amsCredentials.StorageAccountName) { if (attachedstoragecred.ContainsKey(outputAsset.StorageAccountName)) // asset is using another storage than default but we have the key { storname = outputAsset.StorageAccountName; storkey = attachedstoragecred[storname]; } else // we don't have the key for that storage { log.Info($"MES Thumbnails Asset is in {outputAsset.StorageAccountName} and key is not provided in MediaServicesAttachedStorageCredentials application settings"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Storage key is missing" })); } } var sourceContainer = CopyBlobHelpers.GetCloudBlobContainer(storname, storkey, outputAsset.Uri.Segments[1]); CloudBlobContainer targetContainer; if (data.mesThumbnails.copyToContainerAccountName != null) { // copy to a specific storage account targetContainer = CopyBlobHelpers.GetCloudBlobContainer((string)data.mesThumbnails.copyToContainerAccountName, (string)data.mesThumbnails.copyToContainerAccountKey, copyToContainer); } else { // copy to ams storage account targetContainer = CopyBlobHelpers.GetCloudBlobContainer(amsCredentials.StorageAccountName, amsCredentials.StorageAccountKey, copyToContainer); } listPNGCopies = await CopyBlobHelpers.CopyFilesAsync(sourceContainer, targetContainer, prefixpng, "png", log); targetContainerUri = targetContainer.Uri.ToString(); } foreach (IAssetFile file in pngFiles) { string index = file.Name.Substring(file.Name.Length - 10, 6); int index_i = 0; if (int.TryParse(index, out index_i)) { dynamic entry = new JObject(); entry.id = index_i; entry.fileId = file.Id; entry.fileName = file.Name; if (copyToContainer != "") { entry.url = targetContainerUri + "/" + prefixpng + file.Name; } else if (!string.IsNullOrEmpty(pathUrl)) { entry.url = pathUrl + file.Name; } pngThumbnails.Add(entry); } } if (data.mesThumbnails.deleteAsset != null && ((bool)data.mesThumbnails.deleteAsset)) { // If asset deletion was asked // let's wait for the copy to finish before deleting the asset.. if (listPNGCopies.Count > 0) { log.Info("PNG Copy with asset deletion was asked. Checking copy status..."); bool continueLoop = true; while (continueLoop) { listPNGCopies = listPNGCopies.Where(r => r.CopyState.Status == CopyStatus.Pending).ToList(); if (listPNGCopies.Count == 0) { continueLoop = false; } else { log.Info("PNG Copy not finished. Waiting 3s..."); Task.Delay(TimeSpan.FromSeconds(3d)).Wait(); listPNGCopies.ForEach(r => r.FetchAttributes()); } } } outputAsset.Delete(); } } // // MOTION DETECTION // if (data.motionDetection != null && data.motionDetection.assetId != null) { // Get the asset string assetid = data.motionDetection.assetId; var outputAsset = _context.Assets.Where(a => a.Id == assetid).FirstOrDefault(); if (outputAsset == null) { log.Info($"Asset not found {assetid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } var jsonFile = outputAsset.AssetFiles.Where(a => a.Name.ToUpper().EndsWith(".JSON")).FirstOrDefault(); if (jsonFile != null) { jsonMotionDetection = MediaServicesHelper.ReturnContent(jsonFile); objMotionDetection = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonMotionDetection); objMotionDetectionOffset = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonMotionDetection); if (timeOffset.Ticks != 0) // Let's add the offset { foreach (var frag in objMotionDetectionOffset.fragments) { frag.start = ((long)(frag.start)) + (long)((((double)timeOffset.Ticks / (double)TimeSpan.TicksPerSecond) * (double)objMotionDetectionOffset.timescale)); } } } if (jsonMotionDetection != "" && data.motionDetection.deleteAsset != null && ((bool)data.motionDetection.deleteAsset)) // If asset deletion was asked { outputAsset.Delete(); } } // // OCR // if (data.ocr != null && data.ocr.assetId != null) { // Get the asset string assetid = data.ocr.assetId; var outputAsset = _context.Assets.Where(a => a.Id == assetid).FirstOrDefault(); if (outputAsset == null) { log.Info($"Asset not found {assetid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } var jsonFile = outputAsset.AssetFiles.Where(a => a.Name.ToUpper().EndsWith(".JSON")).FirstOrDefault(); if (jsonFile != null) { jsonOcr = MediaServicesHelper.ReturnContent(jsonFile); objOcr = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonOcr); objOcrOffset = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonOcr); if (timeOffset.Ticks != 0) // Let's add the offset { foreach (var frag in objOcrOffset.fragments) { frag.start = ((long)(frag.start)) + (long)((((double)timeOffset.Ticks / (double)TimeSpan.TicksPerSecond) * (double)objOcrOffset.timescale)); } } } if (jsonOcr != "" && data.ocr.deleteAsset != null && ((bool)data.ocr.deleteAsset)) // If asset deletion was asked { outputAsset.Delete(); } } // // Video Annotator // if (data.videoAnnotation != null && data.videoAnnotation.assetId != null) { // Get the asset string assetid = data.videoAnnotation.assetId; var outputAsset = _context.Assets.Where(a => a.Id == assetid).FirstOrDefault(); if (outputAsset == null) { log.Info($"Asset not found {assetid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } var jsonFile = outputAsset.AssetFiles.Where(a => a.Name.ToUpper().EndsWith(".JSON")).FirstOrDefault(); log.Info($"JSON file = {jsonFile}"); if (jsonFile != null) { jsonAnnotation = MediaServicesHelper.ReturnContent(jsonFile); objAnnotation = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonAnnotation); objAnnotationOffset = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonAnnotation); if (timeOffset.Ticks != 0) // Let's add the offset { foreach (var frag in objAnnotationOffset.fragments) { frag.start = ((long)(frag.start)) + (long)((((double)timeOffset.Ticks / (double)TimeSpan.TicksPerSecond) * (double)objAnnotationOffset.timescale)); } } } if (jsonAnnotation != "" && data.videoAnnotation.deleteAsset != null && ((bool)data.videoAnnotation.deleteAsset)) // If asset deletion was asked { outputAsset.Delete(); } } // // Content Moderation // if (data.contentModeration != null && data.contentModeration.assetId != null) { // Get the asset string assetid = data.contentModeration.assetId; var outputAsset = _context.Assets.Where(a => a.Id == assetid).FirstOrDefault(); if (outputAsset == null) { log.Info($"Asset not found {assetid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } var jsonFile = outputAsset.AssetFiles.Where(a => a.Name.ToUpper().EndsWith(".JSON")).FirstOrDefault(); log.Info($"JSON file = {jsonFile}"); if (jsonFile != null) { jsonModeration = MediaServicesHelper.ReturnContent(jsonFile); objModeration = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonModeration); objModerationOffset = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonModeration); if (timeOffset.Ticks != 0) // Let's add the offset { foreach (var frag in objModerationOffset.fragments) { frag.start = ((long)(frag.start)) + (long)((((double)timeOffset.Ticks / (double)TimeSpan.TicksPerSecond) * (double)objModerationOffset.timescale)); if (frag.events != null) { for (int i = 0; i < frag.events.Count; i++) { frag.events[i][0].timestamp = ((long)(frag.events[i][0].timestamp)) + (long)((((double)timeOffset.Ticks / (double)TimeSpan.TicksPerSecond) * (double)objModerationOffset.timescale)); } } } } } if (jsonModeration != "" && data.contentModeration.deleteAsset != null && ((bool)data.contentModeration.deleteAsset)) // If asset deletion was asked { outputAsset.Delete(); } } } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } log.Info($""); return(req.CreateResponse(HttpStatusCode.OK, new { faceRedaction = new { json = Newtonsoft.Json.JsonConvert.SerializeObject(objFaceDetection), jsonOffset = Newtonsoft.Json.JsonConvert.SerializeObject(objFaceDetectionOffset), jpgFaces = Newtonsoft.Json.JsonConvert.SerializeObject(jpgFaces) }, mesThumbnail = new { pngThumbnails = Newtonsoft.Json.JsonConvert.SerializeObject(pngThumbnails) }, motionDetection = new { json = Newtonsoft.Json.JsonConvert.SerializeObject(objMotionDetection), jsonOffset = Newtonsoft.Json.JsonConvert.SerializeObject(objMotionDetectionOffset) }, ocr = new { json = Newtonsoft.Json.JsonConvert.SerializeObject(objOcr), jsonOffset = Newtonsoft.Json.JsonConvert.SerializeObject(objOcrOffset) }, videoAnnotation = new { json = Newtonsoft.Json.JsonConvert.SerializeObject(objAnnotation), jsonOffset = Newtonsoft.Json.JsonConvert.SerializeObject(objAnnotationOffset) }, contentModeration = new { json = Newtonsoft.Json.JsonConvert.SerializeObject(objModeration), jsonOffset = Newtonsoft.Json.JsonConvert.SerializeObject(objModerationOffset) } })); } }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { { log.Info($"Webhook was triggered!"); // Init variables string vttUrl = ""; string pathUrl = ""; string ttmlUrl = ""; string vttContent = ""; string ttmlContent = ""; string ttmlContentTimeCorrected = ""; string vttContentTimeCorrected = ""; string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info(jsonContent); if (data.assetId == null) { // for test // data.assetId = "nb:cid:UUID:d9496372-32f5-430d-a4c6-d21ec3e01525"; return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass asset ID in the input object (AssetId)" })); } MediaServicesCredentials amsCredentials = new MediaServicesCredentials(); log.Info($"Using Azure Media Service Rest API Endpoint : {amsCredentials.AmsRestApiEndpoint}"); try { AzureAdTokenCredentials tokenCredentials = new AzureAdTokenCredentials(amsCredentials.AmsAadTenantDomain, new AzureAdClientSymmetricKey(amsCredentials.AmsClientId, amsCredentials.AmsClientSecret), AzureEnvironments.AzureCloudEnvironment); AzureAdTokenProvider tokenProvider = new AzureAdTokenProvider(tokenCredentials); _context = new CloudMediaContext(amsCredentials.AmsRestApiEndpoint, tokenProvider); // Get the asset string assetid = data.assetId; var outputAsset = _context.Assets.Where(a => a.Id == assetid).FirstOrDefault(); if (outputAsset == null) { log.Info($"Asset not found {assetid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset not found" })); } var vttSubtitle = outputAsset.AssetFiles.Where(a => a.Name.ToUpper().EndsWith(".VTT")).FirstOrDefault(); var ttmlSubtitle = outputAsset.AssetFiles.Where(a => a.Name.ToUpper().EndsWith(".TTML")).FirstOrDefault(); Uri publishurl = MediaServicesHelper.GetValidOnDemandPath(_context, outputAsset); if (publishurl != null) { pathUrl = publishurl.ToString(); } else { log.Info($"Asset not published"); } if (vttSubtitle != null) { if (publishurl != null) { vttUrl = pathUrl + vttSubtitle.Name; log.Info($"vtt url : {vttUrl}"); } vttContent = MediaServicesHelper.ReturnContent(vttSubtitle); if (data.timeOffset != null) // let's update the ttml with new timecode { var tsoffset = TimeSpan.Parse((string)data.timeOffset); string arrow = " --> "; StringBuilder sb = new StringBuilder(); string[] delim = { Environment.NewLine, "\n" }; // "\n" added in case you manually appended a newline string[] vttlines = vttContent.Split(delim, StringSplitOptions.None); foreach (string vttline in vttlines) { string line = vttline; if (vttline.Contains(arrow)) { TimeSpan begin = TimeSpan.Parse(vttline.Substring(0, vttline.IndexOf(arrow))); TimeSpan end = TimeSpan.Parse(vttline.Substring(vttline.IndexOf(arrow) + 5)); line = (begin + tsoffset).ToString(@"d\.hh\:mm\:ss\.fff") + arrow + (end + tsoffset).ToString(@"d\.hh\:mm\:ss\.fff"); } sb.AppendLine(line); } vttContentTimeCorrected = sb.ToString(); } } if (ttmlSubtitle != null) { if (publishurl != null) { ttmlUrl = pathUrl + vttSubtitle.Name; log.Info($"ttml url : {ttmlUrl}"); } ttmlContent = MediaServicesHelper.ReturnContent(ttmlSubtitle); if (data.timeOffset != null) // let's update the vtt with new timecode { var tsoffset = TimeSpan.Parse((string)data.timeOffset); log.Info("tsoffset : " + tsoffset.ToString(@"d\.hh\:mm\:ss\.fff")); XNamespace xmlns = "http://www.w3.org/ns/ttml"; XDocument docXML = XDocument.Parse(ttmlContent); var tt = docXML.Element(xmlns + "tt"); var subtitles = docXML.Element(xmlns + "tt").Element(xmlns + "body").Element(xmlns + "div").Elements(xmlns + "p"); foreach (var sub in subtitles) { var begin = TimeSpan.Parse((string)sub.Attribute("begin")); var end = TimeSpan.Parse((string)sub.Attribute("end")); sub.SetAttributeValue("end", (end + tsoffset).ToString(@"d\.hh\:mm\:ss\.fff")); sub.SetAttributeValue("begin", (begin + tsoffset).ToString(@"d\.hh\:mm\:ss\.fff")); } ttmlContentTimeCorrected = docXML.Declaration.ToString() + Environment.NewLine + docXML.ToString(); } } if (ttmlContent != "" && vttContent != "" && data.deleteAsset != null && ((bool)data.deleteAsset)) // If asset deletion was asked { outputAsset.Delete(); } } catch (Exception ex) { string message = ex.Message + ((ex.InnerException != null) ? Environment.NewLine + MediaServicesHelper.GetErrorMessage(ex) : ""); log.Info($"ERROR: Exception {message}"); return(req.CreateResponse(HttpStatusCode.InternalServerError, new { error = message })); } log.Info($""); return(req.CreateResponse(HttpStatusCode.OK, new { vttUrl = vttUrl, ttmlUrl = ttmlUrl, pathUrl = pathUrl, ttmlDocument = ttmlContent, ttmlDocumentWithOffset = ttmlContentTimeCorrected, vttDocument = vttContent, vttDocumentWithOffset = vttContentTimeCorrected })); } }