예제 #1
0
		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;
		}
예제 #2
0
        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);
            }
        }
예제 #3
0
		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();
        }
예제 #7
0
		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;
		}
예제 #8
0
		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();
			}
		}
예제 #9
0
		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);
			}
		}
예제 #10
0
		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();
				}
			}
		}
예제 #11
0
		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();
			}
		}
예제 #12
0
		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();
			}
		}
예제 #13
0
		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);
        }
예제 #15
0
        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;
        }
예제 #16
0
        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;
                }
            }
        }
예제 #17
0
		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;
			}
		}
예제 #18
0
        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
                    });
                }
            }
        }
예제 #19
0
		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;
        }
예제 #23
0
		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()));
		}
예제 #24
0
		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);
		}
예제 #25
0
        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();
                    }
                }
            }
        }