/// <summary> /// Check the storage configuration /// </summary> /// <param name="storageContainer">reference to Blob Storage Container</param> /// <returns></returns> private static async Task CheckStorageConfiguration(CloudBlobContainer storageContainer, ILogger log) { if (!await storageContainer.ExistsAsync()) { if (await storageContainer.CreateIfNotExistsAsync()) { log.LogInformation($"creating container {Constants.BLOBPATHCONTAINER}"); await storageContainer.SetPermissionsAsync(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Off }); } } string blobName = Constants.BLOBPATHIMAGESPLAYED.Replace(Constants.BLOBPATHCONTAINER + "/", ""); var blob = storageContainer.GetBlockBlobReference(blobName); if (!await blob.ExistsAsync()) { log.LogInformation($"creating blob {Constants.BLOBPATHIMAGESPLAYED}"); blob.Properties.ContentType = Constants.BLOBCONTENTTYPEIMAGESPLAYED; var imagesPlayedStorage = new ImagesPlayedStorage { ImagesPlayed = new List <ImagePlayed>() }; string blobContent = JsonConvert.SerializeObject(imagesPlayedStorage); await blob.UploadTextAsync(blobContent); } }
/// <summary> /// merge list returned with images already played /// </summary> /// <param name="imageList">list of images returned from service</param> /// <param name="imagesPlayedStorage">storage of images already played</param> /// <returns>merged list</returns> private static ImagesPlayedStorage MergeImagesPlayed(JArray imageList, ImagesPlayedStorage imagesPlayedStorage) { var imagesPlayedStorageResult = new ImagesPlayedStorage { ImagesPlayed = new List <ImagePlayed>() }; foreach (var imageToken in imageList) { JObject imageObject = (JObject)imageToken; if (imageObject["name"] != null && imageObject["@microsoft.graph.downloadUrl"] != null && imageObject["file"] != null && imageObject["photo"] != null) { try { var imageName = imageObject["name"].Value <string>(); var imagePath = imageObject["@microsoft.graph.downloadUrl"].Value <string>(); var imageFile = (JObject)imageObject["file"]; if (imageObject["photo"].HasValues) { var imagePhotoData = (JObject)imageObject["photo"]; var imageCreated = imagePhotoData["takenDateTime"].Value <DateTime>(); var imageMimeType = imageFile["mimeType"].Value <string>(); if (imageMimeType.CompareTo("image/jpeg") == 0) { var imagePlayed = imagesPlayedStorage.ImagesPlayed.FirstOrDefault(i => i.ImageName == imageName); if (imagePlayed == null) { imagePlayed = new ImagePlayed() { ImageName = imageName, ImageUrl = imagePath, Count = 0, Created = imageCreated }; } else { imagePlayed.ImageUrl = imagePath; imagePlayed.Created = imageCreated; } imagesPlayedStorageResult.ImagesPlayed.Add(imagePlayed); } } } catch (Exception ex) { throw new ApplicationException($"Exception on processing image {imageToken.ToString()}"); } } } return(imagesPlayedStorageResult); }
/// <summary> /// Determine URL of next random image to by played /// </summary> /// <param name="imagesPlayedStorage">set of available images</param> /// <returns>URL of image to be played and updated image storage</returns> private static (string, DateTime, ImagesPlayedStorage) GetRandomImageUrl(ImagesPlayedStorage imagesPlayedStorage) { // take image only from top x % int upperBound = (imagesPlayedStorage.ImagesPlayed.Count * Constants.IMAGES_SELECTION_POOL_TOP_X_PERCENT) / 100; if (upperBound > imagesPlayedStorage.ImagesPlayed.Count) { upperBound = imagesPlayedStorage.ImagesPlayed.Count; } var randomImageIndex = RandomBetween(0, upperBound - 1); imagesPlayedStorage.ImagesPlayed[randomImageIndex].Count++; imagesPlayedStorage.ImagesPlayed[randomImageIndex].LastPlayed = DateTime.UtcNow; return(imagesPlayedStorage.ImagesPlayed[randomImageIndex].ImageUrl, imagesPlayedStorage.ImagesPlayed[randomImageIndex].Created, imagesPlayedStorage); }
/// <summary> /// plateau handling: cut down image played counter when all images have been played x times, /// so that new images do not need to be played so often /// before these plateau with the existing / old images /// </summary> /// <param name="imagesPlayedStorage">sorted (by counter) set of available images</param> /// <returns>balanced list</returns> private static ImagesPlayedStorage PlateauImages(ImagesPlayedStorage imagesPlayedStorage) { if (imagesPlayedStorage.ImagesPlayed.Count > 0) { // when in the sorted set of images the first image reaches the plateau, assume // all other images on that plateau if (imagesPlayedStorage.ImagesPlayed[0].Count > Constants.IMAGES_PLAYED_PLATEAU) { foreach (var ip in imagesPlayedStorage.ImagesPlayed) { ip.Count -= Constants.IMAGES_PLAYED_PLATEAU; } } } return(imagesPlayedStorage); }
/// <summary> /// Determine the next image to be played /// - download set of available images from OneDrive /// - merge with the storage of images already played /// - balance images played /// - get next random image from top x % of available images /// </summary> /// <param name="msaToken">OneDrive access token</param> /// <param name="imagesPlayedStorage">storage of images already played</param> /// <returns>stream with image content and updated storage of images already played</returns> private static async Task <(Stream, DateTime, ImagesPlayedStorage)> GetNextBlobImage(TokenEntity msaToken, ImagesPlayedStorage imagesPlayedStorage) { Stream imageResult = null; ImagesPlayedStorage imagesPlayedStorageReturned = null; DateTime imageCreatedResult = DateTime.MinValue; using (var client = new HttpClient()) { var imageListRequest = new HttpRequestMessage(HttpMethod.Get, string.Format(Constants.ONEDRIVEPATH, Util.GetEnvironmentVariable("ONEDRIVE_FOLDER"))); imageListRequest.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(msaToken.TokenType, msaToken.AccessToken); var imageListResponse = await client.SendAsync(imageListRequest); if (imageListResponse.IsSuccessStatusCode) { var imageListPayload = await imageListResponse.Content.ReadAsStringAsync(); var imageList = (JArray)JObject.Parse(imageListPayload)["value"]; // merge list returned with images already played var imagesPlayedStorageMerged = MergeImagesPlayed(imageList, imagesPlayedStorage); // sort ascending by count of played imagesPlayedStorageMerged.ImagesPlayed = imagesPlayedStorageMerged.ImagesPlayed.OrderBy(i => i.Count).ThenBy(i => i.LastPlayed).ToList(); // balance image played counters var imagesPlayedStorageBalanced = PlateauImages(imagesPlayedStorageMerged); // get random image var(imagePath, imageCreated, imagesPlayedStorageUpdated) = GetRandomImageUrl(imagesPlayedStorageBalanced); imageResult = GetImageContent(imagePath); imageCreatedResult = imageCreated; imagesPlayedStorageReturned = imagesPlayedStorageUpdated; } } return(imageResult, imageCreatedResult, imagesPlayedStorageReturned); }