diff --git a/Configuration.cs b/Configuration.cs index 3309128..a1755d6 100644 --- a/Configuration.cs +++ b/Configuration.cs @@ -7,11 +7,12 @@ namespace ttrss_co_client public Uri BaseURI { get; set; } public string Username { get; set; } public string Password { get; set; } - public string CopilotDoneCaption { get; set; } - public IEnumerable feedActions{get;set;} + public string PodcastTitlePrefix { get; set; } + public string OnDoneCopy { get; set; } + public IEnumerable feedActions { get; set; } public class FeedAction { - public string feedurl { get; set; } + public string triggerlabelCaption { get; set; } public string command { get; set; } } } diff --git a/Program.cs b/Program.cs index 67d3da6..1a1f290 100644 --- a/Program.cs +++ b/Program.cs @@ -15,52 +15,89 @@ namespace ttrss_co_client var loggedin = await ttrssClient.IsLoggedIn(); Console.WriteLine($"logged in: {loggedin}"); - var doneLabelCaption = conf.CopilotDoneCaption.ToLower(); - var miscTasks = new List(); var unreadFeeds = await ttrssClient.GetFeeds(cat_id: -3, unread_only: true); foreach (var uf in unreadFeeds) { - var actionForFeed = conf.feedActions.FirstOrDefault(fa => fa.feedurl == uf.feed_url.ToString()); - if (actionForFeed != null) - { + var headlines = await ttrssClient.GetHeadlines(uf.id, view_mode: ttrss.ApiClient.VIEWMODE.Unread); foreach (var hl in headlines) { - var doneLabel = (await ttrssClient.GetLabels(hl.id)).First(l => l.caption?.ToLower() == doneLabelCaption); - if (!doneLabel.@checked) + var labelsWRTFeed = (await ttrssClient.GetLabels(hl.id)); + var actionsForFeed = conf.feedActions.Where(fa => + labelsWRTFeed.Where(l => l.@checked).Select(l => l.caption).Contains(fa.triggerlabelCaption))?.ToList(); + if(actionsForFeed != null && actionsForFeed.Any()) { - var noteString = hl.note; - if (!string.IsNullOrWhiteSpace(noteString)) + foreach(var action in actionsForFeed) { - noteString += $"{hl.note}\n"; + var noteString = hl.note; + if (!string.IsNullOrWhiteSpace(noteString)) + { + noteString += $"{hl.note}\n"; + } + switch (action.command) + { + case "dl": + var stdDLResult = await standardDL(hl.link.ToString()); + miscTasks.Add(ttrssClient.UpdateArticleNote($"{noteString}[{DateTime.Now.ToLongTimeString()}] - {stdDLResult.Item2}", hl.id)); + if (stdDLResult.Item1 == true) + { + miscTasks.Add( + ttrssClient.SetArticleLabel( + labelsWRTFeed.First(l => l.caption == action.triggerlabelCaption).id, + false, + hl.id)); + } + break; + case "podcastify": + var nameLabel = labelsWRTFeed.FirstOrDefault(l => l.caption?.StartsWith(conf.PodcastTitlePrefix) == true); + var podcastName = nameLabel?.caption.Substring(conf.PodcastTitlePrefix.Length) + ?? hl.feed_title; + var podcastifyResult = await podcastify(hl.link.ToString(), podcastName); + miscTasks.Add(ttrssClient.UpdateArticleNote($"{noteString}[{DateTime.Now.ToLongTimeString()}] - {podcastifyResult.Item2}", hl.id)); + if (podcastifyResult.Item1 == true) + { + miscTasks.Add( + ttrssClient.SetArticleLabel( + labelsWRTFeed.First(l => l.caption == action.triggerlabelCaption).id, + false, + hl.id)); + if(nameLabel != null) + { + miscTasks.Add(ttrssClient.SetArticleLabel(nameLabel.id, false, hl.id)); + } + } + break; + default: + noteString += $"[{DateTime.Now.ToLongTimeString()}] - feed configured but action not recognized"; + break; + } + miscTasks.Add(ttrssClient.UpdateArticleNote(noteString, hl.id)); } - switch (actionForFeed.command) - { - case "dl": - var tr = await standardDL(hl.link.ToString()); - miscTasks.Add(ttrssClient.UpdateArticleNote($"[{DateTime.Now.ToLongTimeString()}] - {tr.Item2}", hl.id)); - if (tr.Item1 == true) - { - miscTasks.Add(ttrssClient.SetArticleLabel(doneLabel.id, true, hl.id)); - } - break; - default: - noteString += $"[{DateTime.Now.ToLongTimeString()}] - feed configured but action not recognized"; - miscTasks.Add(ttrssClient.SetArticleLabel(doneLabel.id, true, hl.id)); - break; - } - miscTasks.Add(ttrssClient.UpdateArticleNote(noteString, hl.id)); } } - } } miscTasks.Add(ttrssClient.Logout()); - Console.WriteLine($"awaiting remaining tasks"); + Console.WriteLine($"awaiting remaining download tasks"); Task.WaitAll(miscTasks.ToArray()); - Console.WriteLine($"done"); + Console.WriteLine($"done, moving files from temporary location"); + + var resulted = Directory.GetFiles("tmp", "*.*", SearchOption.AllDirectories); + if(resulted.Count() > 0) + { + foreach(var f in resulted) + { + var moveTarget = Path.Combine(conf.OnDoneCopy, f.Substring("tmp/".Length)); + if(!Path.Exists(Path.GetDirectoryName(moveTarget))) + { + Directory.CreateDirectory(Path.GetDirectoryName(moveTarget)); + } + File.Move(f, moveTarget); + } + } + Console.WriteLine($"done for real"); } static Configuration Configure(string configurationPath = "appsettings.json") { @@ -95,14 +132,9 @@ namespace ttrss_co_client var ytdl = new YoutubeDLSharp.YoutubeDL(); ytdl.YoutubeDLPath = "yt-dlp"; ytdl.FFmpegPath = "ffmpeg"; - ytdl.OutputFolder = "./tmp/"; + ytdl.OutputFolder = "./tmp/recent episodes"; ytdl.OutputFileTemplate = "%(upload_date)s - %(title)s - [%(id)s].mp4"; var sw = new Stopwatch(); - // var data = await ytdl.RunVideoDataFetch(articleLink); - // if (data.Data.ReleaseDate != null && data.Data.ReleaseDate > DateTime.Now) - // { - // return new Tuple(false, $"release date in future? {data.Data.ReleaseDate}"); - // } sw.Start(); var res = await ytdl.RunVideoDownload(articleLink); sw.Stop(); @@ -113,5 +145,34 @@ namespace ttrss_co_client } return new Tuple(res.Success, outputStr); } + private static async Task> podcastify(string articleLink, string podcastName) + { + var ytdl = new YoutubeDLSharp.YoutubeDL(); + ytdl.YoutubeDLPath = "yt-dlp"; + ytdl.FFmpegPath = "ffmpeg"; + ytdl.OutputFolder = $"./tmp/podcasts/{podcastName}"; + ytdl.OutputFileTemplate = "%(upload_date)s - %(title)s - [%(id)s].%(ext)s"; + var sw = new Stopwatch(); + sw.Start(); + var res = await ytdl.RunVideoDownload(articleLink); + sw.Stop(); + var outputStr = $"{(res.Success ? "Success" : "fail")} in {sw.Elapsed}"; + if(res.ErrorOutput != null && res.ErrorOutput.Length > 0) + { + outputStr += "\n" + string.Join('\n', res.ErrorOutput); + } + if(!res.Data.EndsWith(".mp3")) + { + sw.Reset(); + var outputFilename = res.Data.Substring(0, res.Data.LastIndexOf('.')) + ".mp3"; + sw.Start(); + var conversionProc =Process.Start("ffmpeg", $"-y -i \"{res.Data}\" \"{outputFilename}\""); + conversionProc.WaitForExit(); + sw.Stop(); + File.Delete(res.Data); + outputStr += $"\nconverted in {sw.Elapsed}"; + } + return new Tuple(res.Success, outputStr); + } } } \ No newline at end of file diff --git a/sample-appsettings.json b/sample-appsettings.json index 0945a91..06448f2 100644 --- a/sample-appsettings.json +++ b/sample-appsettings.json @@ -2,11 +2,17 @@ "BaseUri": "https://ttrss.example.com/api/", "username": "guy who didn't configure", "password": "sordph1sh", - "feedactions": + "podcastTitlePrefix": "[podcast title] - ", + "onDoneCopy":"./", + "feedActions": [ { - "feedurl":"youtube.com/a_channel", + "triggerlabelCaption":"dl plz", "command":"dl" + }, + { + "triggerlabelCaption":"podcastify plz", + "command":"podcastify" } ] } \ No newline at end of file