diff --git a/.gitignore b/.gitignore index b0a7be8..5c6c69b 100644 --- a/.gitignore +++ b/.gitignore @@ -135,3 +135,7 @@ data/certbot/conf/* !data/certbot/conf/letsencrypt-recommended-ssl.conf !data/certbot/conf/letsencrypt-dhparams.pem data/certbot/www/* + +# Generator data +data/tiles/config.json +data/tiles/tiles.json diff --git a/docker-compose.override.yml b/docker-compose.override.yml index caa5e90..4d9e3db 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -15,6 +15,10 @@ services: - ./node_modules:/usr/src/backend/node_modules ports: - "1337:1337" + generator: + volumes: + - ./data/tiles/:/usr/src/data/ + - ./src/generator/bin/Release/netcoreapp3.1/publish/:/usr/src/app proxy: volumes: - ./src/proxy/nginx.dev.conf:/etc/nginx/conf.d/nginx.conf diff --git a/docker-compose.yml b/docker-compose.yml index 006daa9..d4cbd1f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,6 +12,10 @@ services: build: context: . dockerfile: src/backend/Dockerfile + generator: + build: + context: src/generator/ + entrypoint: "/bin/sh -c 'trap exit TERM; while :; do dotnet generator.dll /usr/src/data/config.json /usr/src/data/tiles.json; sleep 12h & wait $${!}; done;'" proxy: image: nginx:1.19-alpine ports: diff --git a/src/generator/.vscode/launch.json b/src/generator/.vscode/launch.json new file mode 100644 index 0000000..8a14d6d --- /dev/null +++ b/src/generator/.vscode/launch.json @@ -0,0 +1,27 @@ +{ + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/Debug/netcoreapp3.1/generator.dll", + "args": [], + "cwd": "${workspaceFolder}", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "internalConsole", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickProcess}" + } + ] +} \ No newline at end of file diff --git a/src/generator/.vscode/tasks.json b/src/generator/.vscode/tasks.json new file mode 100644 index 0000000..a585a86 --- /dev/null +++ b/src/generator/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/generator.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/generator.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "${workspaceFolder}/generator.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/src/generator/ApiConfigManager.cs b/src/generator/ApiConfigManager.cs index 174454a..d33a8da 100644 --- a/src/generator/ApiConfigManager.cs +++ b/src/generator/ApiConfigManager.cs @@ -38,18 +38,18 @@ public class LastfmApiConfig [JsonProperty("username")] public string Username { get; set; } - [JsonProperty("albumChartPeriod")] - public LastStatsTimeSpan AlbumChartPeriod { get; set; } = LastStatsTimeSpan.Month; + [JsonProperty("period")] + public LastStatsTimeSpan Period { get; set; } = LastStatsTimeSpan.Month; - [JsonProperty("albumChartCount")] - public int AlbumChartCount { get; set; } + [JsonProperty("count")] + public int Count { get; set; } = 5; } public class ApiConfig { [JsonProperty("github")] public GitHubApiConfig GitHub { get; set; } - + [JsonProperty("lastfm")] public LastfmApiConfig Lastfm { get; set; } diff --git a/src/generator/Dockerfile b/src/generator/Dockerfile new file mode 100644 index 0000000..b5b0828 --- /dev/null +++ b/src/generator/Dockerfile @@ -0,0 +1,13 @@ +FROM mcr.microsoft.com/dotnet/core/sdk:3.1 + +COPY . usr/src/app/ +WORKDIR usr/src/app/ +# https://github.com/NuGet/Home/issues/9020 +RUN dotnet restore --disable-parallel +RUN dotnet publish -c Release + +FROM mcr.microsoft.com/dotnet/core/runtime:3.1 +COPY --from=0 usr/src/app/bin/Release/netcoreapp3.1/publish/ /usr/src/app + +WORKDIR /usr/src/app +ENTRYPOINT ["dotnet", "generator.dll"] diff --git a/src/generator/PageBuilder.cs b/src/generator/PageBuilder.cs deleted file mode 100644 index b91cf2f..0000000 --- a/src/generator/PageBuilder.cs +++ /dev/null @@ -1,237 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using generator.Tiles; -using HeyRed.MarkdownSharp; -using Humanizer; -using Mustache; - -namespace generator -{ - public class PageBuilder - { - private enum SourceType - { - Other = 0, - Html, - Markdown - } - - private readonly string _sourceDir; - private readonly ApiConfig _config; - private readonly string _outDir; - private readonly TemplateManager _templateManager; - - public PageBuilder(string sourceDir, string outDir, ApiConfig config, TemplateManager templateManager) - { - _sourceDir = EnsureTerminatingDirectorySeparator(sourceDir); - _outDir = EnsureTerminatingDirectorySeparator(outDir); - _config = config; - _templateManager = templateManager; - } - - public async Task Build() - { - if (!Directory.Exists(_sourceDir)) - { - Console.WriteLine($"Didn't find any pages in {_sourceDir}."); - return; - } - - if (!Directory.Exists(_outDir)) - { - Console.WriteLine($"Creating directory {_outDir}"); - Directory.CreateDirectory(_outDir); - } - - Console.WriteLine($"Building tiles..."); - var tileRoot = await BuildTileHtml(); - - Console.WriteLine($"Building pages..."); - var sourceFiles = EnumerateSourceFiles(_sourceDir) - .Select(path => - { - SourceType type; - switch (Path.GetExtension(path)) - { - case ".html": - type = SourceType.Html; - break; - case ".md": - case ".mdown": - case ".markdown": - type = SourceType.Markdown; - break; - default: - type = SourceType.Other; - break; - } - - return new {path, type}; - }) - .Where(x => x.type != SourceType.Other) - .ToList(); - - Console.WriteLine($"Found {sourceFiles.Count} files in {_sourceDir}"); - - var markdownParser = new Markdown(); - var formatCompiler = new FormatCompiler {RemoveNewLines = false}; - var markdownGenerator = formatCompiler.Compile(_templateManager.Templates["skeleton"]); - foreach (var sourceFile in sourceFiles) - { - // dir structure should be maintained from source to out, - // need to get the relative path from the source file to the root of all source files. - var sourceToWebrootPath = GetRelativePath(sourceFile.path, _sourceDir); - var sourceFileName = Path.GetFileNameWithoutExtension(sourceFile.path); - var webrootToSourceFileDirPath = GetRelativePath(_sourceDir, Path.GetDirectoryName(sourceFile.path)); - - var outFileName = $"{sourceFileName.ToLowerInvariant()}.html"; - var outFilePath = Path.Combine(_outDir, webrootToSourceFileDirPath, outFileName); - - string pageHtml; - if (sourceFile.type == SourceType.Html) - { - var pageTemplate = File.ReadAllText(sourceFile.path); - var compiler = formatCompiler.Compile(pageTemplate); - var pageData = new - { - title = sourceFileName, - tiles = tileRoot, - webroot = sourceToWebrootPath.NullIfEmpty() ?? ".", - date = "" - }; - pageHtml = compiler.Render(pageData); - } - else if (sourceFile.type == SourceType.Markdown) - { - var pageLines = File.ReadAllLines(sourceFile.path).ToList(); - var pageMeta = PageMeta.Parse(pageLines); - - var articleLines = pageLines.SkipWhile(line => line.StartsWith(PageMeta.MD_META_PREFIX)); - var articleMarkdown = string.Join(Environment.NewLine, articleLines); - var articleHtml = markdownParser.Transform(articleMarkdown); - - var pageData = new - { - title = pageMeta.Title ?? sourceFileName.Humanize("-"), - content = articleHtml, - tiles = tileRoot, - webroot = sourceToWebrootPath.NullIfEmpty() ?? ".", - date = pageMeta.Date?.Humanize() ?? "" - }; - - pageHtml = markdownGenerator.Render(pageData); - } - else - { - throw new Exception($"Source type {sourceFile.type} not supported"); - } - - var outFileDir = Path.GetDirectoryName(outFilePath); - if (!Directory.Exists(outFileDir)) - { - Directory.CreateDirectory(outFileDir); - } - - File.WriteAllText(outFilePath, pageHtml); - - var colour = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Green; - Console.WriteLine($"Built {outFilePath.Replace(outFileDir, "")}"); - Console.ForegroundColor = colour; - } - } - - private async Task BuildTileHtml() - { - var tileBuilderFactory = new TileBuilderFactory(_config); - var tileBuilders = tileBuilderFactory.GetBuilders(); - - var tileTasks = tileBuilders.Select(b => b.GetTileAsync()); - var tiles = await Task.WhenAll(tileTasks); - - const string tileRootStart = "
"; - var tilesHtml = tiles - .Select(tile => tile.RenderHtml(_templateManager)) - .Aggregate(tileRootStart, (a, b) => a + b); - tilesHtml += "
"; - - return tilesHtml; - } - - private static IEnumerable EnumerateSourceFiles(string sourceDir) - { - var files = Directory.EnumerateFiles(sourceDir); - var folders = Directory.EnumerateDirectories(sourceDir); - var subfiles = folders.SelectMany(EnumerateSourceFiles); - - return files.Concat(subfiles); - } - - /// - /// Couldn't be bothered to write my own http://stackoverflow.com/a/34659715/268555 - /// - private static string EnsureTerminatingDirectorySeparator(string path) - { - if (path == null) throw new ArgumentNullException(nameof(path)); - - int length = path.Length; - if (length == 0) - { - return "." + Path.DirectorySeparatorChar; - } - - char lastChar = path[length - 1]; - if (lastChar == Path.DirectorySeparatorChar || lastChar == Path.AltDirectorySeparatorChar) - { - return path; - } - - int lastSep = path.LastIndexOfAny(new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }); - - return lastSep >= 0 - ? path + path[lastSep] - : path + Path.DirectorySeparatorChar; - } - - - private static string GetRelativePath(string from, string to) - { - from = Path.GetFullPath(from); - to = Path.GetFullPath(to); - - var fromFrags = from.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar).ToArray(); - var toFrags = to.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar).ToArray(); - - int commonRootIndex = 0; - for (int i = 0; i < fromFrags.Length; i++) - { - if (toFrags.Length <= i - || fromFrags[i] != toFrags[i]) - { - break; - } - - commonRootIndex++; - } - - var levelDiff = fromFrags.Length - 1 - commonRootIndex; - - var dirUpFragment = ".." + Path.DirectorySeparatorChar; - var sb = new StringBuilder(); - for (int i = 0; i < levelDiff; i++) sb.Append(dirUpFragment); - foreach (var toFrag in toFrags.Skip(commonRootIndex).Where(f => !string.IsNullOrWhiteSpace(f))) - { - sb.Append(toFrag); - sb.Append(Path.DirectorySeparatorChar); - } - - var relativePath = sb.ToString(0, sb.Length > 0 ? sb.Length - 1 : 0); - - return relativePath; - } - } -} \ No newline at end of file diff --git a/src/generator/PageMeta.cs b/src/generator/PageMeta.cs deleted file mode 100644 index 692c673..0000000 --- a/src/generator/PageMeta.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace generator -{ - public class PageMeta - { - public const string MD_META_PREFIX = "--"; - - public string Title { get; set; } - public DateTimeOffset? Date { get; set; } - - public static PageMeta Parse(IEnumerable lines) - { - var meta = new PageMeta(); - foreach (var line in lines.TakeWhile(line => line.StartsWith(MD_META_PREFIX))) - { - var metaType = new string(line.Skip(MD_META_PREFIX.Length).TakeWhile(c => c != ' ').ToArray()); - var content = new string(line.Skip(metaType.Length + 3).ToArray()); - - switch (metaType) - { - case "title": - meta.Title = content; - break; - case "date": - DateTimeOffset articleDate; - if (DateTimeOffset.TryParse(content, out articleDate)) - { - meta.Date = articleDate; - } - break; - } - } - - return meta; - } - } -} \ No newline at end of file diff --git a/src/generator/Program.cs b/src/generator/Program.cs index 6c532f7..ba005a5 100644 --- a/src/generator/Program.cs +++ b/src/generator/Program.cs @@ -1,7 +1,9 @@ using System; using System.IO; using System.Linq; +using System.Net.Http; using System.Threading.Tasks; +using generator.Tiles; using Newtonsoft.Json; namespace generator @@ -25,39 +27,31 @@ public static void Main(string[] args) private static async Task MainAsync(string[] args) { - var configPath = args.Skip(0).Take(1).SingleOrDefault() ?? "../../config.json"; - configPath = Path.GetFullPath(configPath); - - var sourceDir = args.Skip(1).Take(1).SingleOrDefault() ?? "../../pages"; - sourceDir = Path.GetFullPath(sourceDir); - - var outDir = args.Skip(2).Take(1).SingleOrDefault() ?? "../../public"; - outDir = Path.GetFullPath(outDir); + if (args.Length != 2) + { + Console.Error.WriteLine("Usage: generator.exe "); + return; + } - var templateDir = args.Skip(3).Take(1).SingleOrDefault() ?? "../../res/html"; - templateDir = Path.GetFullPath(templateDir); - var templateManager = new TemplateManager(); - templateManager.LoadFromDirectory(templateDir); + var configPath = Path.GetFullPath(args.ElementAtOrDefault(0)); + var apiConfig = GetConfigFromFile(configPath); + var outputPath = Path.GetFullPath(args.ElementAtOrDefault(1)); - var colour = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.DarkCyan; - Console.WriteLine($"Config path: {configPath}"); - Console.WriteLine($"Page path: {sourceDir}"); - Console.WriteLine($"Out path: {outDir}"); - Console.WriteLine($"Template path: {templateDir}"); - Console.ForegroundColor = colour; + Console.WriteLine($"Generating tile json. Config: {configPath}, Out: {outputPath}"); - var apiConfig = GetConfig(configPath); - var pageBuilder = new PageBuilder(sourceDir, outDir, apiConfig, templateManager); + var httpClient = new HttpClient(); - await pageBuilder.Build(); + var tileData = new { + github = await new GithubTileBuilder(apiConfig.GitHub).GetTileAsync(), + lastfm = await new LastfmTileBuilder(apiConfig.Lastfm, httpClient).GetTileAsync(), + twitter = await new TwitterTileBuilder(apiConfig.Twitter, httpClient).GetTileAsync(), + }; -#if DEBUG - Console.ReadLine(); -#endif + await File.WriteAllTextAsync(outputPath, JsonConvert.SerializeObject(tileData)); + Console.WriteLine("...complete"); } - private static ApiConfig GetConfig(string configPath) + private static ApiConfig GetConfigFromFile(string configPath) { var fullConfigPath = Path.GetFullPath(configPath); if (!File.Exists(fullConfigPath)) diff --git a/src/generator/Properties/AssemblyInfo.cs b/src/generator/Properties/AssemblyInfo.cs deleted file mode 100644 index 18ceb72..0000000 --- a/src/generator/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("generator")] -[assembly: AssemblyTrademark("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("4b5e2d8f-274b-4d44-bfb3-5e657769863e")] diff --git a/src/generator/StringExtensions.cs b/src/generator/StringExtensions.cs deleted file mode 100644 index 98a6600..0000000 --- a/src/generator/StringExtensions.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace generator -{ - public static class StringExtensions - { - public static string NullIfEmpty(this string s) => string.IsNullOrEmpty(s) ? null : s; - } -} \ No newline at end of file diff --git a/src/generator/TemplateManager.cs b/src/generator/TemplateManager.cs deleted file mode 100644 index c9980df..0000000 --- a/src/generator/TemplateManager.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace generator -{ - public class TemplateManager - { - public Dictionary Templates { get; private set; } - - public void LoadFromDirectory(string path) - { - var templates = Directory.EnumerateFiles(path) - .Where(p => Path.GetExtension(p) == ".html") - .ToDictionary(Path.GetFileNameWithoutExtension, File.ReadAllText); - - Templates = templates; - } - } -} \ No newline at end of file diff --git a/src/generator/Tiles/GithubTileBuilder.cs b/src/generator/Tiles/GithubTileBuilder.cs index 97e5b87..c850c05 100644 --- a/src/generator/Tiles/GithubTileBuilder.cs +++ b/src/generator/Tiles/GithubTileBuilder.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Newtonsoft.Json; using Octokit; using Octokit.Internal; @@ -49,6 +50,7 @@ private async Task> GetTileData() var events = await _client.Activity.Events.GetAllUserPerformedPublic(_config.Username); var activeRepoIds = events.OrderByDescending(e => e.CreatedAt) .Where(e => e.CreatedAt > DateTimeOffset.UtcNow.AddMonths(-3)) + .Where(e => e.Public) .Where(e => { switch (e.Type) @@ -64,14 +66,25 @@ private async Task> GetTileData() .Select(e => e.Repo.Id) .Distinct(); - var activeRepos = await Task.WhenAll(activeRepoIds.Select(id => _client.Repository.Get(id))); - - var data = activeRepos.Select(repo => new TileContent + var data = new List(); + foreach (var id in activeRepoIds) { - Name = repo.Name, - Body = $"{repo.Description} ({repo.Language})", - Overlay = false - }); + try + { + var repo = await _client.Repository.Get(id); + + data.Add(new TileContent + { + Name = $"{repo.Owner.Login}/{repo.Name}", + Body = $"{repo.Description} ({repo.Language})", + Overlay = false + }); + } + catch (Exception e) + { + Console.Error.WriteLine($"GitHub | Error when getting repo {id}: {e.Message}"); + } + } return data; } diff --git a/src/generator/Tiles/LastfmTileBuilder.cs b/src/generator/Tiles/LastfmTileBuilder.cs index 42c2de5..c72f45e 100644 --- a/src/generator/Tiles/LastfmTileBuilder.cs +++ b/src/generator/Tiles/LastfmTileBuilder.cs @@ -19,15 +19,17 @@ public LastfmTileBuilder(LastfmApiConfig config, HttpClient httpClient) protected override async Task BuildAsync() { - var albums = await _lastfmClient.User.GetTopAlbums(_config.Username, _config.AlbumChartPeriod, 1, _config.AlbumChartCount); + var artists = await _lastfmClient.User.GetTopArtists(_config.Username, _config.Period, 1, _config.Count); - var data = albums.Select(a => new TileContent + var data = artists.Select(a => new TileContent { Name = a.Name, - Image = a.Images.Largest, - Overlay = true + Overlay = true, + Body = String.Join(",", a.Tags.Select(tag => tag.Name.ToLower())), }); + Console.WriteLine(String.Join("\n", artists.SelectMany(x => x.MainImage))); + return new Tile { Title = "Now Playing", diff --git a/src/generator/Tiles/Tile.cs b/src/generator/Tiles/Tile.cs index ff85b23..c11cb7f 100644 --- a/src/generator/Tiles/Tile.cs +++ b/src/generator/Tiles/Tile.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using Mustache; using Newtonsoft.Json; namespace generator.Tiles @@ -34,28 +33,11 @@ public string Size [JsonProperty("data")] public IEnumerable Content { get; set; } - + public Tile() { TemplateName = "tt-01"; Size = "large"; } - - public string RenderHtml(TemplateManager templateManager) - { - var formatter = new FormatCompiler(); - - var rootHtml = templateManager.Templates[TemplateName]; - if (string.IsNullOrEmpty(rootHtml)) - { - return null; - } - - var rootTemplate = formatter.Compile(rootHtml); - - var html = rootTemplate.Render(this); - - return html; - } } } \ No newline at end of file diff --git a/src/generator/Tiles/TileBuilder.cs b/src/generator/Tiles/TileBuilder.cs index cb2236e..70afac0 100644 --- a/src/generator/Tiles/TileBuilder.cs +++ b/src/generator/Tiles/TileBuilder.cs @@ -11,15 +11,7 @@ public async Task GetTileAsync() { if (_cachedTile == null || _cachedTile.BuiltUtc < DateTimeOffset.UtcNow.AddDays(-1)) { - if (_cachedTile == null) - { - await RefreshAsync(); - } - else - { - // TODO this isn't good - RefreshAsync(); - } + await RefreshAsync(); } return _cachedTile; diff --git a/src/generator/Tiles/TileBuilderFactory.cs b/src/generator/Tiles/TileBuilderFactory.cs deleted file mode 100644 index 2afd4af..0000000 --- a/src/generator/Tiles/TileBuilderFactory.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net.Http; - -namespace generator.Tiles -{ - public class TileBuilderFactory - { - private readonly ApiConfig _config; - - public TileBuilderFactory(ApiConfig config) - { - _config = config; - } - - public ICollection GetBuilders() - { - var httpClient = new HttpClient(); - - return new List - { - new LastfmTileBuilder(_config.Lastfm, httpClient), - new GithubTileBuilder(_config.GitHub), - //new StaticTileBuilder("tt-02", "Blog", "blog", "wide", new Uri("http://rikk.it/blog")), - new TwitterTileBuilder(_config.Twitter, httpClient) - }; - } - } -} \ No newline at end of file diff --git a/src/generator/Tiles/TwitterTileBuilder.cs b/src/generator/Tiles/TwitterTileBuilder.cs index 42df094..8a81c73 100644 --- a/src/generator/Tiles/TwitterTileBuilder.cs +++ b/src/generator/Tiles/TwitterTileBuilder.cs @@ -29,7 +29,8 @@ protected override async Task BuildAsync() { {"screen_name", _config.Username}, {"exclude_replies", true.ToString() }, - {"trim_user", true.ToString() } + {"trim_user", true.ToString() }, + {"include_rts", false.ToString()}, }; var tweetsUrl = $"{TWITTER_API_ROOT}/1.1/statuses/user_timeline.json?" + string.Join("&", tweetParams.Select(x => $"{x.Key}={x.Value}")); var message = new HttpRequestMessage(HttpMethod.Get, tweetsUrl) @@ -42,7 +43,7 @@ protected override async Task BuildAsync() var response = await _httpClient.SendAsync(message); var json = await response.Content.ReadAsStringAsync(); var tweetList = JArray.Parse(json); - var tweets = tweetList.Select(jo => + var tweets = tweetList.Take(_config.Count).Select(jo => { var tileData = new TileContent { @@ -121,7 +122,7 @@ private async Task InvalidateAccessTokenAsync(string token) var response = await _httpClient.SendAsync(postMessage); if (!response.IsSuccessStatusCode) { - Console.WriteLine($"Didn't invalidate access token {token}\n{response.ReasonPhrase}"); + Console.Error.WriteLine($"Twitter | Didn't invalidate access token {token}: {response.ReasonPhrase}"); } } } diff --git a/src/generator/generator.csproj b/src/generator/generator.csproj new file mode 100644 index 0000000..a5c3a05 --- /dev/null +++ b/src/generator/generator.csproj @@ -0,0 +1,16 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + + diff --git a/src/generator/generator.xproj b/src/generator/generator.xproj deleted file mode 100644 index a47c831..0000000 --- a/src/generator/generator.xproj +++ /dev/null @@ -1,30 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 4b5e2d8f-274b-4d44-bfb3-5e657769863e - generator - .\obj - .\bin\ - v4.5.2 - - - 2.0 - - - - Tiles\html\skeleton.html - - - Tiles\html\tt-01.html - - - Tiles\html\tt-02.html - - - - \ No newline at end of file diff --git a/src/generator/project.json b/src/generator/project.json deleted file mode 100644 index 14f29a1..0000000 --- a/src/generator/project.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "version": "1.0.0-*", - "buildOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "Humanizer.Core": "2.1.0", - "Inflatable.Lastfm": "1.0.0.294", - "Markdown": "2.2.0", - "Microsoft.NETCore.App": "1.1.0", - "Mustache": "1.0.1", - "Newtonsoft.Json": "9.0.1", - "Octokit": "0.23.1-PullRequest1503" - }, - - "frameworks": { - "netcoreapp1.0": { - "imports": "dnxcore50" - } - }, - "runtimes": { - "win10-x64": {}, - "ubuntu.14.04-x64": {} - } -}