new command to scrape psn by full content id; useful for delisted games

This commit is contained in:
13xforever
2018-08-17 21:12:01 +05:00
committed by Roberto Anić Banić
parent e479772d4c
commit 8f6eed45dd
3 changed files with 75 additions and 5 deletions

View File

@@ -2,6 +2,7 @@
using System.Threading.Tasks;
using CompatApiClient.Utils;
using CompatBot.EventHandlers;
using CompatBot.ThumbScrapper;
using CompatBot.Utils;
using CompatBot.Utils.ResultFormatters;
using DSharpPlus.CommandsNext;
@@ -16,11 +17,11 @@ namespace CompatBot.Commands
[Group("check")]
[Description("Commands to check for various stuff on PSN")]
public sealed class Check : BaseCommandModuleCustom
public sealed class Check: BaseCommandModuleCustom
{
[Command("updates"), Aliases("update")]
[Description("Checks if specified product has any updates")]
public async Task Updates(CommandContext ctx, [RemainingText, Description("Product ID such as BLUS12345")] string productId)
public async Task Updates(CommandContext ctx, [RemainingText, Description("Product ID such as `BLUS12345`")] string productId)
{
productId = ProductCodeLookup.GetProductIds(productId).FirstOrDefault();
if (string.IsNullOrEmpty(productId))
@@ -31,9 +32,33 @@ namespace CompatBot.Commands
var updateInfo = await Client.GetTitleUpdatesAsync(productId, Config.Cts.Token).ConfigureAwait(false);
var embeds = await updateInfo.AsEmbedAsync(ctx.Client, productId).ConfigureAwait(false);
foreach(var embed in embeds)
foreach (var embed in embeds)
await ctx.RespondAsync(embed: embed).ConfigureAwait(false);
}
[Command("content")]
[Description("Adds PSN content id to the scraping queue")]
public async Task Content(CommandContext ctx, [RemainingText, Description("Content IDs to scrape, such as `UP0006-NPUB30592_00-MONOPOLYPSNNA000`")] string contentIds)
{
if (string.IsNullOrEmpty(contentIds))
{
await ctx.ReactWithAsync(Config.Reactions.Failure, "No IDs were specified").ConfigureAwait(false);
return;
}
var matches = PsnScraper.ContentIdMatcher.Matches(contentIds);
var itemsToCheck = matches.Select(m => m.Groups["content_id"].Value).ToList();
if (itemsToCheck.Count == 0)
{
await ctx.ReactWithAsync(Config.Reactions.Failure, "No IDs were specified").ConfigureAwait(false);
return;
}
foreach (var id in itemsToCheck)
PsnScraper.CheckContentId(id, Config.Cts.Token);
await ctx.ReactWithAsync(Config.Reactions.Success, $"Added {itemsToCheck.Count} ID{StringUtils.GetSuffix(itemsToCheck.Count)} to the scraping queue").ConfigureAwait(false);
}
}
}
}

View File

@@ -16,10 +16,11 @@ namespace CompatBot.ThumbScrapper
internal class PsnScraper
{
private static readonly PsnClient.Client Client = new PsnClient.Client();
public static readonly Regex ContentIdMatcher = new Regex(@"(?<service_id>(?<service_letters>\w\w)(?<service_number>\d{4}))-(?<product_id>(?<product_letters>\w{4})(?<product_number>\d{5}))_(?<part>\d\d)-(?<label>\w{16})", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture);
public static readonly Regex ContentIdMatcher = new Regex(@"(?<content_id>(?<service_id>(?<service_letters>\w\w)(?<service_number>\d{4}))-(?<product_id>(?<product_letters>\w{4})(?<product_number>\d{5}))_(?<part>\d\d)-(?<label>\w{16}))", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture);
private static readonly SemaphoreSlim LockObj = new SemaphoreSlim(1, 1);
private static List<string> PsnStores = new List<string>();
private static DateTime StoreRefreshTimestamp = DateTime.MinValue;
private static readonly SemaphoreSlim QueueLimiter = new SemaphoreSlim(32, 32);
public async Task Run(CancellationToken cancellationToken)
{
@@ -42,6 +43,50 @@ namespace CompatBot.ThumbScrapper
} while (!cancellationToken.IsCancellationRequested);
}
public static async void CheckContentId(string contentId, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(contentId))
return;
var match = ContentIdMatcher.Match(contentId);
if (!match.Success)
return;
if (!QueueLimiter.Wait(0))
return;
try
{
List<string> storesToScrape;
contentId = match.Groups["content_id"].Value;
await LockObj.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
storesToScrape = new List<string>(PsnStores);
}
finally
{
LockObj.Release();
}
foreach (var locale in storesToScrape)
{
var relatedContainer = await Client.ResolveContentAsync(locale, contentId, 1, cancellationToken).ConfigureAwait(false);
if (relatedContainer == null)
continue;
Console.WriteLine($"\tFound {contentId} in {locale} store");
await ProcessIncludedGamesAsync(locale, relatedContainer, cancellationToken, false).ConfigureAwait(false);
return;
}
Console.WriteLine($"\tDidn't find {contentId} in any PSN store");
}
finally
{
QueueLimiter.Release();
}
}
private static async Task RefreshStoresAsync(CancellationToken cancellationToken)
{
try

View File

@@ -59,7 +59,7 @@ namespace CompatBot.Utils
public static async Task ReactWithAsync(this DiscordMessage message, DiscordClient client, DiscordEmoji emoji, string fallbackMessage = null, bool showBoth = false)
{
var canReact = message.Channel.PermissionsFor(client.GetMember(message.Channel.Guild, client.CurrentUser)).HasPermission(Permissions.AddReactions);
var canReact = message.Channel.IsPrivate || message.Channel.PermissionsFor(client.GetMember(message.Channel.Guild, client.CurrentUser)).HasPermission(Permissions.AddReactions);
if (canReact)
await message.CreateReactionAsync(emoji).ConfigureAwait(false);
if ((!canReact || showBoth) && !string.IsNullOrEmpty(fallbackMessage))