123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- using BanTur.Core.Entity;
- using BanTur.Core.Rss;
- using BanTur.Core.Utility;
- using System;
- using System.Linq;
- using System.Threading;
- using System.Threading.Tasks;
- namespace BanTur.Core
- {
- public static class BanTurProgram
- {
- public static readonly string EnvVarDbPath = "BanTurDbPath";
- internal const string CmdDaemon = "daemon";
- internal const string CmdFetch = "fetch";
- internal const string CmdHandleNew = "handlenew";
- internal const string CmdComplete = "complete";
- private static void PrintLine(string line)
- {
- Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss.ff} {line}");
- }
- // Fetch
- // Fetch all feed source, add news
- // HandleNew
- // Get All New Entry,Generate notice executable AND start download
- // Complete <id>
- // Call by download complete executable, Update entry state and Send email, delete notice executable
- private static void Main(string[] args)
- {
- switch (args.FirstOrDefault()?.ToLower())
- {
- case CmdDaemon:
- if (args.Length < 2 || !int.TryParse(args[1], out var intervalMin)) throw new ArgumentException("Missing interval(Min)");
- Daemon(intervalMin);
- break;
- case CmdFetch:
- default:
- Fetch();
- break;
- case CmdHandleNew:
- HandleNew();
- Console.WriteLine("Wait 5 Second, for sending email (if available)...");
- Thread.Sleep(5000);
- break;
- case CmdComplete:
- if (args.Length < 2 || !int.TryParse(args[1], out var id)) throw new ArgumentException("Missing id");
- if (args.Length < 3) throw new ArgumentException("Missing FilePath");
- Complete(id, args[2]);
- break;
- }
- }
- private static void Daemon(int intervalMin)
- {
- PrintLine($"Run Bangumi Turret as Daemon, Interval {intervalMin} min. To exit Press Enter");
- var intervalSeconds = intervalMin * 60;
- var isRunning = true;
- void Loop()
- {
- // ReSharper disable once AccessToModifiedClosure
- while (isRunning)
- {
- Fetch();
- for (int i = 0; i < intervalSeconds; i++)
- {
- // ReSharper disable once AccessToModifiedClosure
- if (false == isRunning) break;
- Console.Write($"Sleeping... {i}/{intervalSeconds}");
- Thread.Sleep(1000);
- //clear line and reset cursor
- var left = Console.CursorLeft;
- Console.CursorLeft = 0;
- Console.Write("".PadLeft(left));
- Console.CursorLeft = 0;
- }
- }
- }
- var task = Task.Run(Loop);
- Console.ReadLine();
- isRunning = false;
- Console.WriteLine("Stopping...");
- task.Wait();
- Console.WriteLine("Bye.");
- }
- private static void Fetch()
- {
- //Call by scheduler
- var sources = DbAccess.GetFeedSources();
- if (sources.Length == 0)
- {
- PrintLine("[Fetch] Nothing to do, Please add source entry into database");
- return;
- }
- PrintLine($"Start Fetch...");
- var totalNewItemCount = 0;
- foreach (var feed in sources)
- {
- try
- {
- var xml = HttpAccess.Get(feed.Url);
- var items = RssParser.Parse(xml);
- var newItemCount = 0;
- foreach (var item in items)
- {
- if (DbAccess.CheckExist(item)) continue;
- item.Status = item.PubDate > feed.CreationTime
- ? BangumiEntryStatus.New
- : BangumiEntryStatus.Skipped;
- DbAccess.AddEntry(item);
- ++newItemCount;
- }
- totalNewItemCount += newItemCount;
- PrintLine(newItemCount > 0
- ? $"「{feed.Name}」New {newItemCount} item."
- : $"「{feed.Name}」Checked.");
- }
- catch (Exception e)
- {
- Console.WriteLine(e);
- }
- }
- PrintLine($"Finish Fetch...");
- if (totalNewItemCount > 0) HandleNew();
- }
- private static void HandleNew()
- {
- //Call by scheduler
- PrintLine("[HandleNew] Loading new entries...");
- var entries = DbAccess.GetNewEntries();
- if (entries.Length == 0)
- {
- PrintLine("[HandleNew] Nothing to do.");
- return;
- }
- PrintLine($"[HandleNew] Get {entries.Length} items to handle");
- foreach (var item in entries)
- {
- PrintLine($"[HandleNew] Starting download 「{item.Title}」");
- //Prep executable for complete notice
- var onBtDownloadComplete = Aria2Helper.CreateNoticeFile(item.Id);
- var logFilePath = Aria2Helper.GetLogFilePath(item.Id);
- //start download with notice executable
- Aria2Helper.StartBitTorrentDownload(item.Magnet, DbAccess.Config.DownloadDirectory, onBtDownloadComplete, logFilePath);
- //set status to downloading
- DbAccess.UpdateStatus(item.Id, BangumiEntryStatus.Downloading);
- //send email tell download started
- if (DbAccess.Config.EnableMail) new MailSender().SendMailAndForget($"Download Start #{item.Id}", $"Id: {item.Id}{Environment.NewLine}Title: {item.Title}");
- }
- PrintLine("[HandleNew] Finished");
- }
- private static void Complete(int id, string filePath)
- {
- //Call by download completed notice executable
- var ce = DbAccess.GetEntry(id);
- if (ce == null) throw new EntryNotFoundException();
- //Update entry state and Send email
- if (DbAccess.UpdateStatus(id, BangumiEntryStatus.DownloadComplete, filePath))
- {
- if (DbAccess.Config.EnableMail) new MailSender().SendMail($"Download Completed #{id}", $"Id: {id}{Environment.NewLine}Title: {ce.Title}{Environment.NewLine}Saved to {filePath}");
- //delete notice executable
- Aria2Helper.DeleteNoticeFile(id);
- }
- }
- private class EntryNotFoundException : Exception { }
- }
- }
|