async void LoadAsync() { var key = logCombo.SelectedItem as string; if(key == "Any") key = null; var level = (LogLevel)levelCombo.SelectedItem; var from = fromDatePicker.SelectedDate; var until = untilDatePicker.SelectedDate; var entries = await Task.Factory.StartNew(() => { using(var db = new EpisodeTrackerDBContext()) { var log = db.Log.Where(l => !EpisodeID.HasValue || l.EpisodeID == EpisodeID) .OrderByDescending(l => l.Date) .Include(l => l.Episode) .Include(l => l.Episode.Series); if(key != null) log = log.Where(l => l.Key == key); var i = Array.FindIndex(Levels, l => l == level); var levels = Levels.Skip(i); log = log.Where(l => levels.Contains(l.Level)); if(from.HasValue) log = log.Where(l => l.Date >= from); if(until.HasValue) { until = until.Value.AddDays(1).AddMilliseconds(-1); log = log.Where(l => l.Date <= until); } return log.ToList(); } }); logGrid.ItemsSource = entries; }
protected override void Write(LogEventInfo info) { try { using(var db = new EpisodeTrackerDBContext()) { var level = GetLevel(info); object episodeID; info.Properties.TryGetValue(EpisodeID, out episodeID); var message = String.Format(info.Message, info.Parameters); var entry = new LogEntry { Key = info.LoggerName, Date = info.TimeStamp, Level = level, Message = message, EpisodeID = episodeID as int? }; db.Log.Add(entry); db.SaveChanges(); } } catch(Exception e) { NLog.Common.InternalLogger.Error("Could not save log info to database: " + e); } }
protected override void OnActivated(EventArgs e) { base.OnActivated(e); if(episodeInfo == null) { using(var db = new EpisodeTrackerDBContext()) { var title = db.Series.SingleOrDefault(s => s.ID == SeriesID).Name; Title = title; } ShowEpisodesAsync(); } }
void Check() { var searcher = new EpisodeFileSearcher(); // Only checks the first library (downloads) for now var results = Core.Models.Settings.Default.Libraries.Take(1).AsParallel() .Select(p => { try { return searcher.Search(p); } catch(Exception e) { Logger.Error("Error searching for episode files: " + e.ToString()); return null; } }) .Where(r => r != null) .ToList(); var groups = results .SelectMany(r => r) .GroupBy(r => r.Match.Name, StringComparer.OrdinalIgnoreCase) .Select(g => new { SeriesName = g.Key, Results = g.ToList() }) .OrderBy(g => g.SeriesName); var para = groups .AsParallel() .WithDegreeOfParallelism(5); para.ForAll(info => { using(var db = new EpisodeTrackerDBContext()) { var seriesName = info.SeriesName; if(db.SeriesIgnore.Any(s => s.Name == seriesName)) { return; } var series = db.Series.SingleOrDefault(s => s.Name == seriesName || s.Aliases.Any(a => a.Name == seriesName)); if(series == null) return; var episodes = series.Episodes.ToList(); foreach(var r in info.Results) { var eps = episodes.WhereTVMatch(r.Match); eps.ToList().ForEach(ep => ep.FileName = r.FileName); } db.SaveChanges(); } }); }
void Save_Click(object sender, RoutedEventArgs e) { using(var db = new EpisodeTrackerDBContext()) { var series = db.Series.Single(s => s.ID == SeriesID); series.DownloadMinSeeds = String.IsNullOrEmpty(minSeedsTxt.Text) ? default(int?) : int.Parse(minSeedsTxt.Text); series.DownloadMinMB = String.IsNullOrEmpty(minMBTxt.Text) ? default(int?) : int.Parse(minMBTxt.Text); series.DownloadMaxMB = String.IsNullOrEmpty(maxMBTxt.Text) ? default(int?) : int.Parse(maxMBTxt.Text); series.DownloadUseAbsoluteEpisode = useAbsoluteEpisodeChk.IsChecked.GetValueOrDefault(); series.DownloadHD = downloadHDCombo.SelectedIndex == 0 ? default(bool?) : downloadHDCombo.SelectedIndex == 1 ? true : false; series.DownloadAutomatically = enableAutoDownloadChk.IsChecked.GetValueOrDefault(); series.DownloadFromSeason = String.IsNullOrEmpty(downloadFromSeason.Text) ? default(int?) : int.Parse(downloadFromSeason.Text); series.DownloadFromEpisode = String.IsNullOrEmpty(downloadFromEpisode.Text) ? default(int?) : int.Parse(downloadFromEpisode.Text); db.SaveChanges(); } this.Close(); }
protected override void OnActivated(EventArgs e) { base.OnActivated(e); if(formSet) return; formSet = true; Series series; using(var db = new EpisodeTrackerDBContext()) { series = db.Series.Single(s => s.ID == SeriesID); } if(series.DownloadMinSeeds.HasValue) minSeedsTxt.Text = series.DownloadMinSeeds.ToString(); if(series.DownloadMinMB.HasValue) minMBTxt.Text = series.DownloadMinMB.ToString(); if(series.DownloadMaxMB.HasValue) maxMBTxt.Text = series.DownloadMaxMB.ToString(); useAbsoluteEpisodeChk.IsChecked = series.DownloadUseAbsoluteEpisode; if(series.DownloadHD.HasValue) downloadHDCombo.SelectedIndex = series.DownloadHD.Value ? 1 : 2; enableAutoDownloadChk.IsChecked = series.DownloadAutomatically; if(series.DownloadFromSeason.HasValue) downloadFromSeason.Text = series.DownloadFromSeason.Value.ToString(); if(series.DownloadFromEpisode.HasValue) downloadFromEpisode.Text = series.DownloadFromEpisode.Value.ToString(); }
protected override void OnActivated(EventArgs e) { base.OnActivated(e); if(init) return; using(var db = new EpisodeTrackerDBContext()) { logCombo.ItemsSource = new [] { "Any" }.Union(db.Log.Select(l => l.Key).Distinct().OrderBy(k => k)).ToList(); logCombo.SelectedIndex = 0; } levelCombo.ItemsSource = Levels; levelCombo.SelectedItem = LogLevel.Debug; fromDatePicker.SelectedDate = DateTime.Now.AddDays(-7); fromDatePicker.DisplayDateEnd = DateTime.Now; untilDatePicker.DisplayDateEnd = DateTime.Now; LoadAsync(); init = true; }
List<EpisodeInfo> GetEpisodes() { using(var db = new EpisodeTrackerDBContext()) { var episodes = db.Episodes .Where(ep => ep.SeriesID == SeriesID && ep.Season != 0) .Select(ep => new { Episode = ep, Tracked = ep.Tracked .OrderByDescending(t => t.Updated) .OrderByDescending(t => t.Watched) .FirstOrDefault() }) .ToList(); return episodes .Select(ep => new EpisodeInfo { Episode = ep.Episode, Tracked = ep.Tracked, TrackedTime = ep.Tracked != null && ep.Tracked.TrackedFile != null ? TimeSpan.FromSeconds(ep.Tracked.TrackedFile.TrackedSeconds) : default(TimeSpan?), BannerPath = GetBannerPath(ep.Episode) }) .ToList(); } }
async void PerformWatch(Episode episode) { if(episode == null) { MessageBox.Show("Nothing to watch"); } if(episode.FileName == null || !File.Exists(episode.FileName)) { // Try and find var status = new StatusModal { Text = "Searching for episode file...", SubText = "Parsing files: 0", ShowSubText = true }; status.SetValue(Grid.RowProperty, 1); grid.Children.Add(status); var searcher = new EpisodeFileSearcher(); var totalFound = 0; searcher.FilesFound += (o, ea) => { this.Dispatcher.BeginInvoke(new Action(() => { Interlocked.Add(ref totalFound, ea.Results); status.SubText = "Parsing files: " + totalFound; })); }; var results = await Task.Factory.StartNew(() => { return Core.Models.Settings.Default.Libraries.AsParallel() .Select(path => { try { return searcher.Search(path); } catch(Exception e) { Logger.Error("Problem searching for episode file: " + episode + "-->" + e); return new List<EpisodeFileSearchResult>(); } }); }); var groups = results .SelectMany(r => r) .GroupBy(r => r.Match.Name, StringComparer.OrdinalIgnoreCase) .Select(g => new { SeriesName = g.Key, Results = g.ToList() }) .OrderBy(g => g.SeriesName); var total = groups.Count(); HashSet<string> aliases; Series series; using(var db = new EpisodeTrackerDBContext()) { series = db.Series.Single(s => s.ID == episode.SeriesID); aliases = new HashSet<string>(series.Aliases.Select(a => a.Name), StringComparer.OrdinalIgnoreCase); if(!aliases.Contains(series.Name)) aliases.Add(series.Name); } status.Text = "Checking results..."; status.SubText = String.Format("{0} / {1} series", 0, total); status.ShowProgress = true; var completed = 0; EpisodeFileSearchResult result = null; await Task.Factory.StartNew(() => { var para = groups .AsParallel() .WithDegreeOfParallelism(5); para.ForAll(info => { try { using(var db = new EpisodeTrackerDBContext()) { var seriesName = info.SeriesName; if(db.SeriesIgnore.Any(s => s.Name == seriesName)) { return; } if(!aliases.Contains(seriesName)) return; var ep = episode; var r = info.Results.FirstOrDefault(f => Episode.EqualsMatchExpression(f.Match).Compile()(ep)); if(r != null) result = r; } } finally { Interlocked.Increment(ref completed); this.Dispatcher.BeginInvoke(new Action(() => { status.SubText = String.Format("{0} / {1} series", completed, total); status.UpdateProgress(completed, total); })); } }); }); grid.Children.Remove(status); if(result != null) { using(var db = new EpisodeTrackerDBContext()) { var episodeDB = db.Episodes.Single(ep => ep.ID == episode.ID); episodeDB.FileName = result.FileName; episode.FileName = result.FileName; db.SaveChanges(); } } else { MessageBox.Show("Could not find file"); return; } } try { Process.Start(episode.FileName); } catch(Exception ex) { MessageBox.Show("Problem opening file: " + ex.Message); Logger.Error("Error opening filename: " + episode.FileName + " - " + ex); } }
private void Delete_Click(object sender, RoutedEventArgs e) { if(MessageBox.Show("Are you sure you want to delete these episodes?", "Confirm", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) { var selected = dataGrid.SelectedItems.Cast<EpisodeInfo>(); var selectedIDs = selected.Select(s => s.Episode.ID); using(var db = new EpisodeTrackerDBContext()) { var eps = db.Episodes.Where(ep => selectedIDs.Contains(ep.ID)); foreach(var ep in eps) { db.Episodes.Remove(ep); episodeInfo.Remove(selected.Single(s => s.Episode.ID == ep.ID)); var image = @"resources\series\" + ep.SeriesID + @"\" + ep.ID + ".jpg"; if(File.Exists(image)) { File.Delete(image); } } db.SaveChanges(); } } }
private void Unwatched_Click(object sender, RoutedEventArgs e) { var selected = dataGrid.SelectedItems.Cast<EpisodeInfo>(); var selectedIDs = selected.Select(s => s.Episode.ID); using(var db = new EpisodeTrackerDBContext()) { foreach(var info in selected) { var tracked = db.TrackedEpisodes.Where(te => te.EpisodeID == info.Episode.ID && te.Watched); if(!tracked.Any()) continue; foreach(var te in tracked) db.TrackedEpisodes.Remove(te); info.Tracked = null; } db.SaveChanges(); } }
private void Watched_Click(object sender, RoutedEventArgs e) { var selected = dataGrid.SelectedItems.Cast<EpisodeInfo>(); var selectedIDs = selected.Select(s => s.Episode.ID); using(var db = new EpisodeTrackerDBContext()) { foreach(var info in selected) { if(info.Tracked != null && info.Tracked.Watched) continue; info.Tracked = new TrackedEpisode { EpisodeID = info.Episode.ID, Added = DateTime.Now, Updated = DateTime.Now, Watched = true }; db.TrackedEpisodes.Add(info.Tracked); } db.SaveChanges(); } }
void FindSeries(SeriesFileInfo info) { Series series; info.State = SeriesFileInfoState.None; info.TVDBID = null; info.SeriesID = null; using(var db = new EpisodeTrackerDBContext()) { var seriesName = info.SuggestedName ?? info.SeriesName; if(db.SeriesIgnore.Any(s => s.Name == seriesName)) { info.State = SeriesFileInfoState.Ignored; info.Status = "Ignored"; return; } series = db.Series.SingleOrDefault(s => s.Name == seriesName || s.Aliases.Any(a => a.Name == seriesName)); if(series == null || !series.TVDBID.HasValue) { info.Status = "Searching for series on TVDB..."; TVDBSearchResult tvdbResult; try { tvdbResult = TVDBSeriesSearcher.Search(seriesName); } catch(Exception e) { info.Status = "Error searching TVDB for series: " + e.Message; info.State = SeriesFileInfoState.Error; Logger.Error("Error searching for series: " + seriesName + " - " + e); return; } if(tvdbResult == null) { info.Status = "Series does not exist on TVDB"; info.State = SeriesFileInfoState.NotFound; return; } if(series == null) { series = db.Series.SingleOrDefault(s => s.Name == tvdbResult.Name || s.Aliases.Any(a => a.Name == tvdbResult.Name)); if(series != null) info.SeriesID = series.ID; } info.SuggestedName = tvdbResult.Name; info.TVDBID = tvdbResult.ID; } else { info.SuggestedName = series.Name; info.TVDBID = series.TVDBID; info.SeriesID = series.ID; // Confirmed series, check if there's any new files var episodes = series.Episodes.ToList(); List<EpisodeFileSearchResult> newFiles = new List<EpisodeFileSearchResult>(); foreach(var f in info.Results) { var eps = episodes.WhereTVMatch(f.Match); if(eps.Any(ep => ep.FileName != f.FileName)) { newFiles.Add(f); } } info.Results = newFiles; if(!newFiles.Any()) { info.State = SeriesFileInfoState.Ignored; return; } } info.Status = "Found series info: " + info.TVDBID; info.State = SeriesFileInfoState.Found; } }
void CheckUnmonitoredFile(string fileName) { Logger.Debug("File is not monitored: " + fileName); var mon = new MonitoredFile { FileName = fileName, Start = DateTime.Now }; using(var info = new MediaInfo(fileName)) { mon.Length = info.Length; } var name = Path.GetFileName(fileName); var match = new TvMatcher().Match(name); if(match != null) { Logger.Debug("Found episode info: " + match.ToString()); mon.TvMatch = match; // Try and look it up // TODO: movies Series series; using(var db = new EpisodeTrackerDBContext()) { series = db.Series.SingleOrDefault(s => s.Name == match.Name || s.Aliases.Any(a => a.Name == match.Name)); int? tvdbid = null; if(series == null) { var results = new TVDBRequest().Search(match.Name); var first = results.FirstOrDefault(); if(first != null) { Logger.Debug("Found TVDB result: " + first.Name); series = db.Series.SingleOrDefault(s => s.TVDBID == first.ID || s.Name == first.Name || s.Aliases.Any(a => a.Name == first.Name)); tvdbid = first.ID; } }else { tvdbid = series.TVDBID; } if(tvdbid.HasValue) { if(series == null || series.Updated <= DateTime.Now.AddDays(-7)) { var syncer = new TVDBSeriesSyncer { TVDBID = tvdbid.Value, Name = match.Name, DownloadBannersAsync = true }; syncer.Sync(); } // Pull out series again as it might have been updated series = db.Series .Include(s => s.Episodes) .Single(s => s.TVDBID == tvdbid.Value); mon.Series = series; if(match.Season.HasValue) { var eps = series.Episodes.Where(ep => ep.Season == match.Season.Value); if(match.ToEpisode.HasValue) { mon.Episodes = eps.Where(ep => ep.Number >= match.Episode && ep.Number <= match.ToEpisode.Value); } else { mon.Episodes = eps.Where(ep => ep.Number == match.Episode); } } else { mon.Episodes = series.Episodes.Where(ep => ep.AbsoluteNumber == match.Episode); } if(mon.Episodes != null) { Logger.Debug("Found TVDB episodes: " + String.Join(" + ", mon.Episodes.Select(e => e.Name))); } } } } monitored.Add(mon); }
private void Sync(SyncInfo syncInfo) { if(syncInfo.Complete) return; var tvdbSeries = new TVDBRequest().Series(TVDBID, true); Series series = null; using(var db = new EpisodeTrackerDBContext()) { var seriesQuery = db.Series .Include(s => s.Episodes) .Include(s => s.Aliases); series = seriesQuery.SingleOrDefault(s => s.TVDBID == tvdbSeries.ID); if(series == null) { series = seriesQuery .SingleOrDefault(s => s.Name == tvdbSeries.Name || s.Name == Name || s.Aliases.Any(a => a.Name == Name) ); } if(series == null) { series = new Series { Added = DateTime.Now }; db.Series.Add(series); } series.TVDBID = tvdbSeries.ID; series.Name = tvdbSeries.Name; series.AirsDay = tvdbSeries.AirsDay; series.AirsTime = tvdbSeries.AirsTime; series.Status = tvdbSeries.Status; series.Overview = tvdbSeries.Overview; series.LengthMinutes = tvdbSeries.LengthMinutes; series.Rating = tvdbSeries.Rating; if(Name != null && !Name.Equals(series.Name, StringComparison.OrdinalIgnoreCase) && !db.SeriesAliases.Any(a => a.Name == Name)) { series.Aliases.Add(new SeriesAlias { Name = Name }); } series.Genres.Clear(); GenresSync(series, tvdbSeries.Genres); series.Updated = DateTime.Now; foreach(var ep in tvdbSeries.Episodes) { SyncEpisode(ep, series); } db.SaveChanges(); } if(DownloadBanners || DownloadBannersAsync) { // Do this after saving so we can use the ID var syncBanners = SyncBannersAsync(series, tvdbSeries); if(!DownloadBannersAsync) syncBanners.Wait(); } lock(syncing) { syncing.Remove(TVDBID); } syncInfo.Complete = true; }
private EpisodeTorrentSearcherResult GetResult(Episode episode, IEnumerable<EpisodeTorrentSearcherResult> results) { lock(DownloadedLock) { using(var db = new EpisodeTrackerDBContext()) { var exclude = results.Where(r => db.EpisodeDownloadLog.Any(edl => edl.URL == r.DownloadURL.OriginalString)).ToArray(); if(exclude.Any()) { Logger.Build() .Message("Excluding: {0}\n{1}", exclude.Count(), String.Join(", \n", exclude.Select(e => DisplayResult(e)))) .Episode(episode.ID) .Debug(); } results = results.Except(exclude); foreach(var r in results) { var torrent = Download(episode, r); if(torrent == null) continue; LogDownload(db, episode, r); if(!torrent.Files.Any(f => IgnoreExtensions.Any(ext => f.Path.EndsWith(ext, StringComparison.OrdinalIgnoreCase)))) { Logger.Build() .Episode(episode.ID) .Message("Using result: " + DisplayResult(r)) .Debug(); return r; } } Logger.Build() .Episode(episode.ID) .Message("All results excluded") .Debug(); return null; } } }
void SyncFiles(SeriesFileInfo info) { Series series; info.State = SeriesFileInfoState.None; using(var db = new EpisodeTrackerDBContext()) { series = db.Series.SingleOrDefault(s => s.ID == info.SeriesID || s.TVDBID == info.TVDBID); if(series == null || series.Updated <= DateTime.Now.AddDays(-7)) { info.Status = "Syncing TVDB series..."; try { var syncer = new TVDBSeriesSyncer { Name = info.SeriesName, TVDBID = info.TVDBID.Value, DownloadBanners = true }; syncer.BannerDownloaded += (o, e) => info.Status = String.Format("Banners downloaded: {0}/{1}", e.Complete, e.Total); syncer.Sync(); } catch(Exception e) { info.Status = "Error syncing with TVDB: " + e.Message; info.State = SeriesFileInfoState.Error; Logger.Error("Error syncing with TVDB: " + info.TVDBID + " - " + e); return; } series = db.Series.SingleOrDefault(s => s.TVDBID == info.TVDBID); info.Status = "Synced"; } else if(!series.Name.Equals(info.SeriesName, StringComparison.OrdinalIgnoreCase)) { // Save alias if(!db.Series.Any(s => s.Name == info.SeriesName) && !db.SeriesAliases.Any(a => a.Name == info.SeriesName)) { db.SeriesAliases.Add(new SeriesAlias { SeriesID = series.ID, Name = info.SeriesName }); } } info.Status = "Updating episodes with file names..."; var episodes = series.Episodes.ToList(); foreach(var f in info.Results) { var eps = episodes.Where(ep => f.Match.Season.HasValue && ep.Season == f.Match.Season && ( ep.Number == f.Match.Episode || f.Match.ToEpisode.HasValue && ep.Number >= f.Match.Episode && ep.Number <= f.Match.ToEpisode ) ); eps.ToList().ForEach(ep => ep.FileName = f.FileName); } try { db.SaveChanges(); } catch(Exception e) { info.Status = "Could not update episodes: " + e.Message; info.State = SeriesFileInfoState.Error; Logger.Error("Error update episodes with file names: " + e.Message); return; } info.Status = "Synced"; info.State = SeriesFileInfoState.Synced; } }
void GenresSync(Series series, string[] genres) { lock(genreLock) { var dbGenres = new List<Genre>(); using(var db = new EpisodeTrackerDBContext()) { foreach(var tvdbGenre in genres) { var genre = db.Genres.SingleOrDefault(g => g.Name == tvdbGenre); if(genre == null) { genre = new Genre { Name = tvdbGenre }; db.Genres.Add(genre); } dbGenres.Add(genre); } db.SaveChanges(); } foreach(var genre in dbGenres) { series.Genres.Add(new SeriesGenre { GenreID = genre.ID }); } } }
private void Ignore_Click(object sender, RoutedEventArgs e) { var selected = dataGrid.SelectedItems .Cast<object>() .Where(o => o is SeriesFileInfo) .Cast<SeriesFileInfo>() .ToList(); using(var db = new EpisodeTrackerDBContext()) { foreach(var info in selected) { if(!db.SeriesIgnore.Any(i => i.Name == info.SeriesName)) { db.SeriesIgnore.Add(new SeriesIgnore { Name = info.SeriesName }); info.Status = "Added to ignore list"; info.State = SeriesFileInfoState.Ignored; } } db.SaveChanges(); } }
void CheckMissing(IEnumerable<string> files) { for(var i = 0; i < monitored.Count; i++) { var mon = monitored[i]; if(!files.Contains(mon.FileName)) { Logger.Debug("Monitored file is no longer open: " + mon.FileName); //Logger.Debug("Process output: " + processOutput); // Double check - sometimes the file seems to be released from the process // Might need to delay this a tiny bit if(GetMediaFiles().Any(f => f.Equals(mon.FileName, StringComparison.OrdinalIgnoreCase))) { CheckMonitoredFile(mon); return; } // Not open anymore if(mon.Tracking) { TrackedFile tracked; bool watched = false; using(var db = new EpisodeTrackerDBContext()) { tracked = GetTrackedFile(db, mon); if(tracked.TrackedSeconds >= (mon.Length.TotalSeconds * .66)) { Logger.Debug("Monitored file has probably been watched: " + mon.FileName); watched = true; foreach(var ep in tracked.Episodes) { ep.Watched = true; ep.Updated = DateTime.Now; } db.SaveChanges(); } } Logger.Info("Finished tracking: " + mon.FileName); if(FileRemoved != null) { FileRemoved(this, new MonitoredFileEventArgs { Filename = mon.FileName, FriendlyName = mon.FriendlyName, Watched = watched }); } } monitored.RemoveAt(i); i--; continue; } } }
TrackedFile NewTrackedFile(EpisodeTrackerDBContext db, MonitoredFile mon) { var tracked = new TrackedFile { FileName = mon.FileName, Start = DateTime.Now, Stop = DateTime.Now, LengthSeconds = mon.Length.TotalSeconds }; db.TrackedFile.Add(tracked); if(mon.TvMatch != null) { var seriesQuery = db.Series.Include(s => s.Episodes); Series series = null; if(mon.Series != null) { series = db.Series.SingleOrDefault(s => s.ID == mon.Series.ID); } else { // Series is only null when no TVDB match was found series = seriesQuery.SingleOrDefault(s => s.Name == mon.TvMatch.Name); } if(series == null) { series = new Series { Name = mon.TvMatch.Name, Added = DateTime.Now }; db.Series.Add(series); } IEnumerable<Episode> episodes = null; if(mon.Episodes != null) { var ids = mon.Episodes.Select(e => e.ID); episodes = series.Episodes .Where(ep => ids.Contains(ep.ID)); foreach(var ep in episodes) { tracked.Episodes.Add(new TrackedEpisode { Episode = ep, Added = DateTime.Now, Updated = DateTime.Now }); } } else { // Check for loose reference episodes = series.Episodes .Where(ep => ep.Season == mon.TvMatch.Season && ( !mon.TvMatch.ToEpisode.HasValue && ep.Number == mon.TvMatch.Episode || mon.TvMatch.ToEpisode.HasValue && ep.Number >= mon.TvMatch.Episode && ep.Number <= mon.TvMatch.ToEpisode.Value ) ); for(var i = mon.TvMatch.Episode; i < (mon.TvMatch.ToEpisode ?? mon.TvMatch.Episode); i++) { var episode = series.Episodes.SingleOrDefault(ep => ep.Season == mon.TvMatch.Season && ep.Number == i); if(episode == null) { episode = new Episode { Season = mon.TvMatch.Season ?? 0, Number = i, Added = DateTime.Now }; series.Episodes.Add(episode); } episode.Updated = DateTime.Now; tracked.Episodes.Add(new TrackedEpisode { Episode = episode, Added = DateTime.Now, Updated = DateTime.Now }); } series.Updated = DateTime.Now; } mon.Series = series; mon.Episodes = tracked.Episodes.Select(te => te.Episode); } db.SaveChanges(); return tracked; }
TrackedFile GetTrackedFile(EpisodeTrackerDBContext db, MonitoredFile mon) { TrackedFile file = null; if(mon.TrackedFileID.HasValue) return db.TrackedFile.Single(f => f.ID == mon.TrackedFileID.Value); if(file == null) { file = db.TrackedFile.SingleOrDefault(f => f.FileName == mon.FileName); } if(file == null && mon.Episodes != null) { var episodeIDs = mon.Episodes.Select(e => e.ID); file = db.TrackedFile .FirstOrDefault(f => f.Episodes.Any() && f.Episodes.All(te => episodeIDs.Contains(te.Episode.ID))); } if(file == null && mon.TvMatch != null) { file = db.TrackedFile .FirstOrDefault(f => f.Episodes.Any() && f.Episodes.All(te => te.Episode.Series.Name == mon.TvMatch.Name && te.Episode.Season == mon.TvMatch.Season && ( !mon.TvMatch.ToEpisode.HasValue && te.Episode.Number == mon.TvMatch.Episode || mon.TvMatch.ToEpisode.HasValue && te.Episode.Number >= mon.TvMatch.Episode && te.Episode.Number <= mon.TvMatch.ToEpisode.Value ) ) ); } if(file != null) mon.TrackedFileID = file.ID; return file; }
async void Download_Click(object sender, RoutedEventArgs e) { var selected = dataGrid.SelectedItems.Cast<EpisodeInfo>().Select(i => i.Episode.ID); IEnumerable<Episode> episodes; using(var db = new EpisodeTrackerDBContext()) { episodes = db.Episodes .Where(ep => selected.Contains(ep.ID)) .Include(ep => ep.Series) .ToList(); } var downloadingModel = new StatusModal(); grid.Children.Add(downloadingModel); downloadingModel.Text = "Searching..."; downloadingModel.SubText = "0/" + episodes.Count(); downloadingModel.ShowProgress = true; downloadingModel.ShowSubText = true; var complete = 0; var results = new List<Tuple<Episode, EpisodeTorrentSearcherResult>>(); await Task.Factory.StartNew(() => { episodes.AsParallel() .ForAll(ep => { var downloader = new EpisodeDownloader(ep); var result = downloader.Download(); if(result != null) { RunTorrentHelper.Run(result); lock(results) results.Add(Tuple.Create<Episode, EpisodeTorrentSearcherResult>(ep, result)); } Interlocked.Increment(ref complete); this.Dispatcher.BeginInvoke(new Action(() => { downloadingModel.UpdateProgress(complete, episodes.Count()); downloadingModel.SubText = String.Format("{0}/{1}", complete, episodes.Count()); if(result != null) { var win = App.Current.MainWindow as MainWindow; win.Taskbar.ShowCustomBalloon(new NotificationBalloon { HeaderText = "Episode Tracker", BodyText = "Found new download: " + result.Title }, PopupAnimation.Slide, 5000); } })); }); }); grid.Children.Remove(downloadingModel); MessageBox.Show(String.Format("Found {0} new download(s) out of {1}", results.Count(r => r.Item2 != null), results.Count())); }
async void SetIgnoreDownload(IEnumerable<EpisodeInfo> selected, bool ignore) { var saveDialog = new StatusModal { Text = "Saving..." }; grid.Children.Add(saveDialog); await Task.Factory.StartNew(() => { using(var db = new EpisodeTrackerDBContext()) { var ids = selected.Select(s => s.Episode.ID); var episodes = db.Episodes.Where(ep => ids.Contains(ep.ID)); foreach(var ep in episodes) { ep.IgnoreDownload = true; } db.SaveChanges(); } }); grid.Children.Remove(saveDialog); }
void LogDownload(EpisodeTrackerDBContext db, Episode episode, EpisodeTorrentSearcherResult result) { var ids = db.Episodes.Where(ep => ep.SeriesID == episode.SeriesID) .WhereTVMatch(result.Match) .Select(ep => ep.ID) .ToArray(); Logger.Build() .Episode(episode.ID) .Message("Logging download for episode IDs: " + String.Join(", ", ids)) .Debug(); foreach(var id in ids) { db.EpisodeDownloadLog.Add(new EpisodeDownloadLog { EpisodeID = id, Date = DateTime.Now, URL = result.DownloadURL.OriginalString }); } db.SaveChanges(); }
void Check() { Logger.Debug("Checking"); IEnumerable<Episode> episodes; using(var db = new EpisodeTrackerDBContext()) { episodes = db.Episodes.Where(ep => ep.Series.DownloadAutomatically && !ep.IgnoreDownload && ep.Season != 0 && ep.FileName == null && ep.Aired <= DateTime.Now && !ep.DownloadLog.Any() && ( !ep.Series.DownloadFromSeason.HasValue || ep.Season >= ep.Series.DownloadFromSeason && ep.Number >= ep.Series.DownloadFromEpisode ) ) .Include(ep => ep.Series) .ToList(); } Logger.Debug("Found episodes which need to be downloaded: " + episodes.Count()); Download(episodes); Logger.Debug("Finished checking"); }
void CheckMonitoredFile(MonitoredFile mon) { Logger.Trace("File is monitored"); if(!mon.Watched) { using(var db = new EpisodeTrackerDBContext()) { Logger.Trace("Seconds since started monitoring: " + DateTime.Now.Subtract(mon.Start).TotalSeconds); // check if it's been monitored for a while before doing anything with file if(mon.Start <= DateTime.Now.AddMinutes(-.0)) { var tracked = GetTrackedFile(db, mon); if(!mon.Tracking) { Logger.Debug("Begin tracking file: " + mon.FileName); if(tracked == null) { Logger.Debug("Recording file/episode as tracked"); tracked = NewTrackedFile(db, mon); } else { Logger.Debug("This file has been tracked before"); mon.PreviousTrackedSeconds = tracked.TrackedSeconds; } mon.Tracking = true; Logger.Info("Tracking file: " + mon.FileName); if(FileAdded != null) { FileAdded(this, new MonitoredFileEventArgs { Filename = mon.FileName, FriendlyName = mon.FriendlyName }); } } tracked.TrackedSeconds = (int)DateTime.Now.Subtract(mon.Start).TotalSeconds + mon.PreviousTrackedSeconds; tracked.Stop = DateTime.Now; foreach(var te in tracked.Episodes) te.Updated = DateTime.Now; db.SaveChanges(); } } } }