From 4ccfaad15fb487834cfb8dd6cad321efeaf83e55 Mon Sep 17 00:00:00 2001 From: Gervasio Marchand Date: Sat, 17 Dec 2022 17:27:04 -0800 Subject: [PATCH] Make it possible to scrape followed tags from the instance (#6) --- src/Config.cs | 16 +++++++++++++--- src/GetMoarFediverse.csproj | 4 ++++ src/MastodonConnectionHelper.cs | 23 +++++++++++++++++++++++ src/Program.cs | 23 +++++++++++++++++------ 4 files changed, 57 insertions(+), 9 deletions(-) create mode 100644 src/MastodonConnectionHelper.cs diff --git a/src/Config.cs b/src/Config.cs index 4ac1dcb..c499880 100644 --- a/src/Config.cs +++ b/src/Config.cs @@ -10,15 +10,18 @@ public class Config public string ImportedPath { get; } public string FakeRelayUrl { get; } public string FakeRelayApiKey { get; } + public string? MastodonPostgresConnectionString { get; } public ImmutableArray Tags { get; } public ImmutableArray Sites { get; } - private Config(string importedPath, string fakeRelayUrl, string fakeRelayApiKey, ImmutableArray tags, ImmutableArray sites) + private Config(string importedPath, string fakeRelayUrl, string fakeRelayApiKey, string? mastodonPostgresConnectionString, + ImmutableArray tags, ImmutableArray sites) { ImportedPath = importedPath; FakeRelayUrl = fakeRelayUrl; FakeRelayApiKey = fakeRelayApiKey; + MastodonPostgresConnectionString = mastodonPostgresConnectionString; Tags = tags; Sites = sites; } @@ -30,20 +33,27 @@ public class Config return; } - var data = JsonSerializer.Deserialize(File.ReadAllText(path), JsonContext.Default.ConfigData); + var data = JsonSerializer.Deserialize(File.ReadAllText(path), JsonContext.Default.ConfigData); var importedPath = Path.Join(Path.GetDirectoryName(path), "imported.txt"); var apiKey = string.IsNullOrEmpty(data.FakeRelayApiKey) ? Environment.GetEnvironmentVariable("FAKERELAY_APIKEY") : data.FakeRelayApiKey; - Instance = new Config(importedPath, data.FakeRelayUrl, apiKey, data.Tags.ToImmutableArray(), data.ImmutableSites); + if (apiKey == null) + { + throw new Exception("The api key is missing"); + } + + Instance = new Config(importedPath, data.FakeRelayUrl, apiKey, data.MastodonPostgresConnectionString, + data.Tags.ToImmutableArray(), data.ImmutableSites); } public class ConfigData { public string FakeRelayUrl { get; set; } public string? FakeRelayApiKey { get; set; } + public string? MastodonPostgresConnectionString { get; set; } public string[] Tags { get; set; } public InternalSiteData[]? Sites { get; set; } diff --git a/src/GetMoarFediverse.csproj b/src/GetMoarFediverse.csproj index 40c60dd..3221ac5 100644 --- a/src/GetMoarFediverse.csproj +++ b/src/GetMoarFediverse.csproj @@ -7,4 +7,8 @@ enable + + + + diff --git a/src/MastodonConnectionHelper.cs b/src/MastodonConnectionHelper.cs new file mode 100644 index 0000000..2eab0e8 --- /dev/null +++ b/src/MastodonConnectionHelper.cs @@ -0,0 +1,23 @@ +using Npgsql; + +namespace GetMoarFediverse; + +public static class MastodonConnectionHelper +{ + public static async Task> GetFollowedTagsAsync() + { + var res = new List(); + + await using var conn = new NpgsqlConnection(Config.Instance.MastodonPostgresConnectionString); + await conn.OpenAsync(); + + await using (var cmd = new NpgsqlCommand("SELECT DISTINCT tags.name FROM tag_follows JOIN tags ON tag_id = tags.id ORDER BY tags.name ASC;", conn)) + await using (var reader = await cmd.ExecuteReaderAsync()) + { + while (await reader.ReadAsync()) + res.Add(reader.GetString(0)); + } + + return res; + } +} diff --git a/src/Program.cs b/src/Program.cs index 6325b72..a8057da 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -26,11 +26,22 @@ var importedList = File.ReadAllLines(importedPath).ToList(); var imported = importedList.ToHashSet(); var statusesToLoadBag = new ConcurrentBag(); -var sitesTags = Config.Instance.Sites - .SelectMany(s => Config.Instance.Tags.Select(tag => (s.Host, tag))) - .Concat(Config.Instance.Sites.SelectMany(s => s.SiteSpecificTags.Select(tag => (s.Host, tag)))) - .OrderBy(t => t.tag) - .ToList(); +List<(string host, string tag)> sitesTags; +if (string.IsNullOrEmpty(Config.Instance.MastodonPostgresConnectionString)) +{ + sitesTags = Config.Instance.Sites + .SelectMany(s => Config.Instance.Tags.Select(tag => (s.Host, tag))) + .Concat(Config.Instance.Sites.SelectMany(s => s.SiteSpecificTags.Select(tag => (s.Host, tag)))) + .OrderBy(t => t.tag) + .ToList(); +} +else +{ + var tags = await MastodonConnectionHelper.GetFollowedTagsAsync(); + sitesTags = Config.Instance.Sites + .SelectMany(s => tags.Select(t => (s.Host, t))) + .ToList(); +} ParallelOptions parallelOptions = new() { @@ -54,7 +65,7 @@ await Parallel.ForEachAsync(sitesTags, parallelOptions, async (st, _) => } var json = await response.Content.ReadAsStringAsync(); - var data = JsonSerializer.Deserialize(json, CamelCaseJsonContext.Default.TagResponse); + var data = JsonSerializer.Deserialize(json, CamelCaseJsonContext.Default.TagResponse); foreach (var statusLink in data.OrderedItems.Where(i=>!imported.Contains(i))) {