//[NadekoCommand, Usage, Description, Aliases] //public async Task MCPing([Remainder] string query2 = null) //{ // var query = query2; // if (string.IsNullOrWhiteSpace(query)) // return; // await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); // using (var http = new HttpClient()) // { // http.DefaultRequestHeaders.Clear(); // var ip = query.Split(':')[0]; // var port = query.Split(':')[1]; // var res = await http.GetStringAsync($"https://api.minetools.eu/ping/{Uri.EscapeUriString(ip)}/{Uri.EscapeUriString(port)}").ConfigureAwait(false); // try // { // var items = JObject.Parse(res); // var sb = new StringBuilder(); // var ping = (int)Math.Ceiling(double.Parse(items["latency"].ToString())); // sb.AppendLine($"`Server:` {query}"); // sb.AppendLine($"`Version:` {items["version"]["name"]} / Protocol {items["version"]["protocol"]}"); // sb.AppendLine($"`Description:` {items["description"]}"); // sb.AppendLine($"`Online Players:` {items["players"]["online"]}/{items["players"]["max"]}"); // sb.Append($"`Latency:` {ping}"); // await Context.Channel.SendMessageAsync(sb.ToString()); // } // catch // { // await Context.Channel.SendErrorAsync($"Failed finding `{query}`.").ConfigureAwait(false); // } // } //} //[NadekoCommand, Usage, Description, Aliases] //public async Task MCQ([Remainder] string query = null) //{ // var arg = query; // if (string.IsNullOrWhiteSpace(arg)) // { // await Context.Channel.SendErrorAsync("Please enter `ip:port`.").ConfigureAwait(false); // return; // } // await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); // using (var http = new HttpClient()) // { // http.DefaultRequestHeaders.Clear(); // try // { // var ip = arg.Split(':')[0]; // var port = arg.Split(':')[1]; // var res = await http.GetStringAsync($"https://api.minetools.eu/query/{Uri.EscapeUriString(ip)}/{Uri.EscapeUriString(port)}").ConfigureAwait(false); // var items = JObject.Parse(res); // var sb = new StringBuilder(); // sb.AppendLine($"`Server:` {arg} 〘Status: {items["status"]}〙"); // sb.AppendLine("`Player List (First 5):`"); // foreach (var item in items["Playerlist"].Take(5)) // { // sb.AppendLine($"〔:rosette: {item}〕"); // } // sb.AppendLine($"`Online Players:` {items["Players"]} / {items["MaxPlayers"]}"); // sb.AppendLine($"`Plugins:` {items["Plugins"]}"); // sb.Append($"`Version:` {items["Version"]}"); // await Context.Channel.SendMessageAsync(sb.ToString()); // } // catch // { // await Context.Channel.SendErrorAsync($"Failed finding server `{arg}`.").ConfigureAwait(false); // } // } //} public async Task InternalDapiCommand(IUserMessage umsg, string tag, DapiSearchType type) { var channel = umsg.Channel; tag = tag?.Trim() ?? ""; var imgObj = await _service.DapiSearch(tag, type, Context.Guild?.Id).ConfigureAwait(false); if (imgObj == null) { await channel.SendErrorAsync(umsg.Author.Mention + " " + GetText("no_results")); } else { await channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithDescription($"{umsg.Author.Mention} [{tag ?? "url"}]({imgObj.FileUrl})") .WithImageUrl(imgObj.FileUrl) .WithFooter(efb => efb.WithText(type.ToString()))).ConfigureAwait(false); } }
public static async Task InternalDapiCommand(IUserMessage umsg, string tag, DapiSearchType type) { var channel = umsg.Channel; tag = tag?.Trim() ?? ""; var url = await InternalDapiSearch(tag, type).ConfigureAwait(false); if (url == null) { await channel.SendErrorAsync(umsg.Author.Mention + " No results."); } else { await channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithDescription(umsg.Author.Mention + " " + tag) .WithImageUrl(url) .WithFooter(efb => efb.WithText(type.ToString()))).ConfigureAwait(false); } }
public async Task InternalDapiCommand(string tag, DapiSearchType type, bool forceExplicit) { ImageCacherObject imgObj; try { imgObj = await _service.DapiSearch(tag, type, Context.Guild?.Id, forceExplicit).ConfigureAwait(false); } catch (TagBlacklistedException) { await ReplyErrorLocalized("blacklisted_tag").ConfigureAwait(false); return; } if (imgObj == null) { await ReplyErrorLocalized("not_found").ConfigureAwait(false); } else { var embed = new EmbedBuilder().WithOkColor() .WithTitle(type.ToString()) .WithDescription($"{Context.User} [{tag ?? "url"}]({imgObj}) ") .WithFooter(efb => efb.WithText("Image Tags: " + string.Join(",", imgObj.Tags))); if (Uri.IsWellFormedUriString(imgObj.FileUrl, UriKind.Absolute)) { embed.WithImageUrl(imgObj.FileUrl); } else { _log.Error($"Image link from {type} is not a proper Url: {imgObj.FileUrl}"); } await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } }
public Task <ImageCacherObject> DapiSearch(string tag, DapiSearchType type, ulong?guild, bool isExplicit = false) { if (guild.HasValue) { var blacklistedTags = GetBlacklistedTags(guild.Value); if (blacklistedTags .Any(x => tag.ToLowerInvariant().Contains(x))) { throw new TagBlacklistedException(); } var cacher = _imageCacher.GetOrAdd(guild.Value, (key) => new SearchImageCacher()); return(cacher.GetImage(tag, isExplicit, type, blacklistedTags)); } else { var cacher = _imageCacher.GetOrAdd(guild ?? 0, (key) => new SearchImageCacher()); return(cacher.GetImage(tag, isExplicit, type)); } }
public async Task <ImageCacherObject> GetImage(string[] tags, bool forceExplicit, DapiSearchType type, HashSet <string> blacklistedTags = null) { tags = tags.Select(tag => tag?.ToLowerInvariant()).ToArray(); blacklistedTags = blacklistedTags ?? new HashSet <string>(); blacklistedTags.AddRange(defaultTagBlacklist); blacklistedTags = blacklistedTags.Select(t => t.ToLowerInvariant()).ToHashSet(); if (tags.Any(x => blacklistedTags.Contains(x))) { return(null); } if (type == DapiSearchType.E621) { tags = tags.Select(tag => tag?.Replace("yuri", "female/female", StringComparison.InvariantCulture)) .ToArray(); } var _lock = GetLock(type); await _lock.WaitAsync().ConfigureAwait(false); try { ImageCacherObject[] imgs; if (tags.Any()) { imgs = _cache.Where(x => x.Tags.IsSupersetOf(tags) && x.SearchType == type && (!forceExplicit || x.Rating == "e")).ToArray(); } else { imgs = _cache.Where(x => x.SearchType == type).ToArray(); } imgs = imgs.Where(x => x.Tags.All(t => !blacklistedTags.Contains(t.ToLowerInvariant()))).ToArray(); ImageCacherObject img; if (imgs.Length == 0) { img = null; } else { img = imgs[_rng.Next(imgs.Length)]; } if (img != null) { _cache.Remove(img); return(img); } else { var images = await DownloadImages(tags, forceExplicit, type).ConfigureAwait(false); images = images .Where(x => x.Tags.All(t => !blacklistedTags.Contains(t.ToLowerInvariant()))) .ToArray(); if (images.Length == 0) { return(null); } var toReturn = images[_rng.Next(images.Length)]; #if !GLOBAL_NADEKO foreach (var dledImg in images) { if (dledImg != toReturn) { _cache.Add(dledImg); } } #endif return(toReturn); } } finally { _lock.Release(); } }
public async Task <ImageCacherObject[]> DownloadImages(string[] tags, bool isExplicit, DapiSearchType type) { var tag = "rating%3Aexplicit+"; tag += string.Join('+', tags.Select(x => x.Replace(" ", "_", StringComparison.InvariantCulture).ToLowerInvariant())); if (isExplicit) { tag = "rating%3Aexplicit+" + tag; } var website = ""; switch (type) { case DapiSearchType.Safebooru: website = $"https://safebooru.org/index.php?page=dapi&s=post&q=index&limit=1000&tags={tag}"; break; case DapiSearchType.E621: website = $"https://e621.net/post/index.json?limit=1000&tags={tag}"; break; case DapiSearchType.Danbooru: website = $"http://danbooru.donmai.us/posts.json?limit=100&tags={tag}"; break; case DapiSearchType.Gelbooru: website = $"http://gelbooru.com/index.php?page=dapi&s=post&q=index&limit=100&tags={tag}"; break; case DapiSearchType.Rule34: website = $"https://rule34.xxx/index.php?page=dapi&s=post&q=index&limit=100&tags={tag}"; break; case DapiSearchType.Konachan: website = $"https://konachan.com/post.json?s=post&q=index&limit=100&tags={tag}"; break; case DapiSearchType.Yandere: website = $"https://yande.re/post.json?limit=100&tags={tag}"; break; case DapiSearchType.Derpibooru: website = $"https://derpibooru.org/search.json?q={tag?.Replace('+', ',')}&perpage=49"; break; } try { if (type == DapiSearchType.Konachan || type == DapiSearchType.Yandere || type == DapiSearchType.E621 || type == DapiSearchType.Danbooru) { using (var http = _httpFactory.CreateClient().AddFakeHeaders()) { var data = await http.GetStringAsync(website).ConfigureAwait(false); return(JsonConvert.DeserializeObject <DapiImageObject[]>(data) .Where(x => x.FileUrl != null) .Select(x => new ImageCacherObject(x, type)) .ToArray()); } } if (type == DapiSearchType.Derpibooru) { using (var http = _httpFactory.CreateClient().AddFakeHeaders()) { var data = await http.GetStringAsync(website).ConfigureAwait(false); return(JsonConvert.DeserializeObject <DerpiContainer>(data) .Search .Where(x => !string.IsNullOrWhiteSpace(x.Image)) .Select(x => new ImageCacherObject("https:" + x.Image, type, x.Tags, x.Score)) .ToArray()); } } return((await LoadXmlAsync(website, type).ConfigureAwait(false)).ToArray()); } catch (Exception ex) { _log.Warn(ex.Message); return(Array.Empty <ImageCacherObject>()); } }
private SemaphoreSlim GetLock(DapiSearchType type) { return(_locks.GetOrAdd(type, _ => new SemaphoreSlim(1, 1))); }
public async Task <ImageCacherObject[]> DownloadImagesAsync(string[] tags, bool isExplicit, DapiSearchType type) { isExplicit = type == DapiSearchType.Safebooru ? false : isExplicit; var tag = ""; tag += string.Join('+', tags.Select(x => x.Replace(" ", "_", StringComparison.InvariantCulture).ToLowerInvariant())); if (isExplicit) { tag = "rating%3Aexplicit+" + tag; } var website = ""; switch (type) { case DapiSearchType.Safebooru: website = $"https://safebooru.org/index.php?page=dapi&s=post&q=index&limit=1000&tags={tag}&json=1"; break; case DapiSearchType.E621: website = $"https://e621.net/posts.json?limit=200&tags={tag}"; break; case DapiSearchType.Danbooru: website = $"http://danbooru.donmai.us/posts.json?limit=100&tags={tag}"; break; case DapiSearchType.Gelbooru: website = $"http://gelbooru.com/index.php?page=dapi&s=post&q=index&limit=100&tags={tag}"; break; case DapiSearchType.Rule34: website = $"https://rule34.xxx/index.php?page=dapi&s=post&q=index&limit=100&tags={tag}"; break; case DapiSearchType.Konachan: website = $"https://konachan.com/post.json?s=post&q=index&limit=100&tags={tag}"; break; case DapiSearchType.Yandere: website = $"https://yande.re/post.json?limit=100&tags={tag}"; break; case DapiSearchType.Derpibooru: tag = string.IsNullOrWhiteSpace(tag) ? "safe" : tag; website = $"https://www.derpibooru.org/api/v1/json/search/images?q={tag?.Replace('+', ',')}&per_page=49"; break; case DapiSearchType.Sankaku: website = $"https://capi-v2.sankakucomplex.com/posts?tags={tag}&limit=50"; break; } try { using (var _http = _httpFactory.CreateClient()) { _http.AddFakeHeaders(); if (type == DapiSearchType.Konachan || type == DapiSearchType.Yandere || type == DapiSearchType.Danbooru) { var data = await _http.GetStringAsync(website).ConfigureAwait(false); return(JsonConvert.DeserializeObject <DapiImageObject[]>(data) .Where(x => x.FileUrl != null) .Select(x => new ImageCacherObject(x, type)) .ToArray()); } if (type == DapiSearchType.Sankaku) { var data = await _http.GetStringAsync(website).ConfigureAwait(false); return(JsonConvert.DeserializeObject <SankakuImageObject[]>(data) .Where(x => !string.IsNullOrWhiteSpace(x.FileUrl) && x.FileType.StartsWith("image")) .Select(x => new ImageCacherObject( x.FileUrl, DapiSearchType.Sankaku, x.Tags.Select(x => x.Name).JoinWith(','), x.Score)) .ToArray()); } if (type == DapiSearchType.E621) { var data = await _http.GetStringAsync(website).ConfigureAwait(false); return(JsonConvert.DeserializeAnonymousType(data, new { posts = new List <E621Object>() }) .posts .Where(x => !string.IsNullOrWhiteSpace(x.File?.Url)) .Select(x => new ImageCacherObject(x.File.Url, type, string.Join(' ', x.Tags.General), x.Score.Total)) .ToArray()); } if (type == DapiSearchType.Derpibooru) { var data = await _http.GetStringAsync(website).ConfigureAwait(false); return(JsonConvert.DeserializeObject <DerpiContainer>(data) .Images .Where(x => !string.IsNullOrWhiteSpace(x.ViewUrl)) .Select(x => new ImageCacherObject(x.ViewUrl, type, string.Join("\n", x.Tags), x.Score)) .ToArray()); } if (type == DapiSearchType.Safebooru) { var data = await _http.GetStringAsync(website).ConfigureAwait(false); return(JsonConvert.DeserializeObject <SafebooruElement[]>(data) .Select(x => new ImageCacherObject(x.FileUrl, type, x.Tags, x.Rating)) .ToArray()); } return((await LoadXmlAsync(website, type).ConfigureAwait(false)).ToArray()); } } catch (Exception ex) { Log.Warning(ex, "Error downloading an image: {Message}", ex.Message); return(Array.Empty <ImageCacherObject>()); } }
public async Task <ImageCacherObject[]> DownloadImages(string tag, bool isExplicit, DapiSearchType type) { tag = tag?.Replace(" ", "_").ToLowerInvariant(); if (isExplicit) { tag = "rating%3Aexplicit+" + tag; } var website = ""; switch (type) { case DapiSearchType.Safebooru: website = $"https://safebooru.org/index.php?page=dapi&s=post&q=index&limit=1000&tags={tag}"; break; case DapiSearchType.E621: website = $"https://e621.net/post/index.json?limit=1000&tags={tag}"; break; case DapiSearchType.Danbooru: website = $"http://danbooru.donmai.us/posts.json?limit=100&tags={tag}"; break; case DapiSearchType.Gelbooru: website = $"http://gelbooru.com/index.php?page=dapi&s=post&q=index&limit=100&tags={tag}"; break; case DapiSearchType.Rule34: website = $"https://rule34.xxx/index.php?page=dapi&s=post&q=index&limit=100&tags={tag}"; break; case DapiSearchType.Konachan: website = $"https://konachan.com/post.json?s=post&q=index&limit=100&tags={tag}"; break; case DapiSearchType.Yandere: website = $"https://yande.re/post.json?limit=100&tags={tag}"; break; case DapiSearchType.Derpibooru: website = $"https://derpibooru.org/search.json?q={tag?.Replace('+', ',')}&perpage=49"; break; } if (type == DapiSearchType.Konachan || type == DapiSearchType.Yandere || type == DapiSearchType.E621 || type == DapiSearchType.Danbooru) { var data = await _http.GetStringAsync(website).ConfigureAwait(false); return(JsonConvert.DeserializeObject <DapiImageObject[]>(data) .Where(x => x.File_Url != null) .Select(x => new ImageCacherObject(x, type)) .ToArray()); } if (type == DapiSearchType.Derpibooru) { var data = await _http.GetStringAsync(website).ConfigureAwait(false); return(JsonConvert.DeserializeObject <DerpiContainer>(data) .Search .Where(x => !string.IsNullOrWhiteSpace(x.Image)) .Select(x => new ImageCacherObject("https:" + x.Image, type, x.Tags, x.Score)) .ToArray()); } return((await LoadXmlAsync(website, type)).ToArray()); }
public async Task <ImageCacherObject> GetImage(string tag, bool forceExplicit, DapiSearchType type, HashSet <string> blacklistedTags = null) { tag = tag?.ToLowerInvariant(); blacklistedTags = blacklistedTags ?? new HashSet <string>(); if (type == DapiSearchType.E621) { tag = tag?.Replace("yuri", "female/female", StringComparison.InvariantCulture); } var _lock = GetLock(type); await _lock.WaitAsync().ConfigureAwait(false); try { ImageCacherObject[] imgs; if (!string.IsNullOrWhiteSpace(tag)) { imgs = _cache.Where(x => x.Tags.IsSupersetOf(tag.Split('+')) && x.SearchType == type && (!forceExplicit || x.Rating == "e")).ToArray(); } else { tag = null; imgs = _cache.Where(x => x.SearchType == type).ToArray(); } imgs = imgs.Where(x => x.Tags.All(t => !blacklistedTags.Contains(t))).ToArray(); ImageCacherObject img; if (imgs.Length == 0) { img = null; } else { img = imgs[_rng.Next(imgs.Length)]; } _log.Warn("Blacklisted Tags: " + (blacklistedTags == null ? "null" : string.Join(",", blacklistedTags))); if (img != null) { _cache.Remove(img); _log.Warn("IMG Tags: " + (img.Tags == null ? "null" : string.Join(",", img.Tags))); return(img); } else { var images = await DownloadImages(tag, forceExplicit, type).ConfigureAwait(false); images = images .Where(x => x.Tags.All(t => !blacklistedTags.Contains(t))) .ToArray(); if (images.Length == 0) { return(null); } var toReturn = images[_rng.Next(images.Length)]; #if !GLOBAL_NADEKO foreach (var dledImg in images) { if (dledImg != toReturn) { _cache.Add(dledImg); } } #endif if (toReturn != null) { _log.Warn("ToReturn Tags: " + (toReturn.Tags == null ? "null" : string.Join(",", toReturn.Tags))); } return(toReturn); } } finally { _lock.Release(); } }
private bool IsValidTag(string tag) => tag.All(x => x != '+' && x != '?' && x != '/'); // tags mustn't contain + or ? or / private async Task <UrlReply> GetNsfwImageAsync(ulong guildId, string[] tags, bool forceExplicit, DapiSearchType dapi) { if (!tags.All(x => IsValidTag(x))) { return(new UrlReply { Error = "One or more tags are invalid.", Url = "" }); } Log.Information("Getting {V} image for Guild: {GuildId}...", dapi.ToString(), guildId); try { _blacklistedTags.TryGetValue(guildId, out var blTags); var result = await _cache.GetImage(tags, forceExplicit, dapi, blTags); if (result is null) { return(new UrlReply { Error = "Image not found.", Url = "" }); } var reply = new UrlReply { Error = "", Url = result.FileUrl, Rating = result.Rating, Provider = result.SearchType.ToString() }; reply.Tags.AddRange(result.Tags); return(reply); } catch (Exception ex) { Log.Error(ex, "Failed getting {Dapi} image: {Message}", dapi, ex.Message); return(new UrlReply { Error = ex.Message, Url = "" }); } }
private Task <UrlReply> GetNsfwImageAsync(TagRequest request, ServerCallContext context, DapiSearchType dapi) { string[] tags = new string[request.Tags.Count]; request.Tags.CopyTo(tags, 0); return(GetNsfwImageAsync(request.GuildId, tags, request.ForceExplicit, dapi)); }
public async Task <ImageCacherObject> GetImage(string[] tags, bool forceExplicit, DapiSearchType type, HashSet <string> blacklistedTags = null) { tags = tags.Select(tag => tag?.ToLowerInvariant()).ToArray(); blacklistedTags = blacklistedTags ?? new HashSet <string>(); foreach (var item in defaultTagBlacklist) { blacklistedTags.Add(item); } blacklistedTags = blacklistedTags.Select(t => t.ToLowerInvariant()).ToHashSet(); if (tags.Any(x => blacklistedTags.Contains(x))) { // todo localize blacklisted_tag (already exists) throw new Exception("One of the specified tags is blacklisted"); } if (type == DapiSearchType.E621) { tags = tags.Select(tag => tag?.Replace("yuri", "female/female", StringComparison.InvariantCulture)) .ToArray(); } await _lock.WaitAsync().ConfigureAwait(false); try { ImageCacherObject[] imgs; if (tags.Any()) { imgs = _cache.Where(x => x.Tags.IsSupersetOf(tags) && x.SearchType == type && (!forceExplicit || x.Rating == "e")).ToArray(); } else { imgs = _cache.Where(x => x.SearchType == type).ToArray(); } imgs = imgs.Where(x => x.Tags.All(t => !blacklistedTags.Contains(t.ToLowerInvariant()))).ToArray(); ImageCacherObject img; if (imgs.Length == 0) { img = null; } else { img = imgs[_rng.Next(imgs.Length)]; } if (img != null) { _cache.Remove(img); return(img); } else { var images = await DownloadImagesAsync(tags, forceExplicit, type).ConfigureAwait(false); images = images .Where(x => x.Tags.All(t => !blacklistedTags.Contains(t.ToLowerInvariant()))) .ToArray(); if (images.Length == 0) { return(null); } var toReturn = images[_rng.Next(images.Length)]; foreach (var dledImg in images) { if (dledImg != toReturn) { _cache.Add(dledImg); } } return(toReturn); } } finally { _lock.Release(); } }
public async Task <ImageCacherObject[]> DownloadImages(string tag, bool isExplicit, DapiSearchType type) { _log.Info($"Loading extra images from {type}"); tag = tag?.Replace(" ", "_").ToLowerInvariant(); if (isExplicit) { tag = "rating%3Aexplicit+" + tag; } var website = ""; switch (type) { case DapiSearchType.Safebooru: website = $"https://safebooru.org/index.php?page=dapi&s=post&q=index&limit=1000&tags={tag}"; break; case DapiSearchType.E621: website = $"https://e621.net/post/index.json?limit=1000&tags={tag}"; break; case DapiSearchType.Danbooru: website = $"http://danbooru.donmai.us/posts.json?limit=100&tags={tag}"; break; case DapiSearchType.Gelbooru: website = $"http://gelbooru.com/index.php?page=dapi&s=post&q=index&limit=100&tags={tag}"; break; case DapiSearchType.Rule34: website = $"https://rule34.xxx/index.php?page=dapi&s=post&q=index&limit=100&tags={tag}"; break; case DapiSearchType.Konachan: website = $"https://konachan.com/post.json?s=post&q=index&limit=100&tags={tag}"; break; case DapiSearchType.Yandere: website = $"https://yande.re/post.json?limit=100&tags={tag}"; break; } using (var http = new HttpClient()) { http.AddFakeHeaders(); if (type == DapiSearchType.Konachan || type == DapiSearchType.Yandere || type == DapiSearchType.E621 || type == DapiSearchType.Danbooru) { var data = await http.GetStringAsync(website).ConfigureAwait(false); return(JsonConvert.DeserializeObject <DapiImageObject[]>(data) .Where(x => x.File_Url != null) .Select(x => new ImageCacherObject(x, type)) .ToArray()); } return((await LoadXmlAsync(website, type)).ToArray()); } }
public async Task <ImageCacherObject> GetImage(string tag, bool forceExplicit, DapiSearchType type) { tag = tag?.ToLowerInvariant(); if (type == DapiSearchType.E621) { tag = tag?.Replace("yuri", "female/female"); } var _lock = GetLock(type); await _lock.WaitAsync(); try { ImageCacherObject[] imgs; if (!string.IsNullOrWhiteSpace(tag)) { imgs = _cache.Where(x => x.Tags.IsSupersetOf(tag.Split('+')) && x.SearchType == type && (!forceExplicit || x.Rating == "e")).ToArray(); } else { tag = null; imgs = _cache.Where(x => x.SearchType == type).ToArray(); } ImageCacherObject img; if (imgs.Length == 0) { img = null; } else { img = imgs[_rng.Next(imgs.Length)]; } if (img != null) { _cache.Remove(img); return(img); } else { var images = await DownloadImages(tag, forceExplicit, type).ConfigureAwait(false); if (images.Length == 0) { return(null); } var toReturn = images[_rng.Next(images.Length)]; foreach (var dledImg in images) { if (dledImg != toReturn) { _cache.Add(dledImg); } } return(toReturn); } } finally { _lock.Release(); } }