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);
            }
        }
        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();
        }
Beispiel #3
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);
		}
Beispiel #4
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);
			}
		}
Beispiel #5
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();
				}
			}
		}
Beispiel #6
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();
			}
		}
Beispiel #7
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();
			}
		}
        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 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();
        }
        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;
        }
        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();
                    }
                }
            }
        }
        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;
                }
            }
        }
		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 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;
			}
		}
        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;
        }
        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
                    });
                }
            }
        }