Ejemplo n.º 1
0
func (d *Downloader) downloadMissingMovies(wl *polochon.Wishlist, log *logrus.Entry) {
	log = log.WithField("function", "download_movies")

	for _, wantedMovie := range wl.Movies {
		ok, err := d.library.HasMovie(wantedMovie.ImdbID)
		if err != nil {
			log.Error(err)
			continue
		}

		if ok {
			log.Debugf("movie %q already in the video store", wantedMovie.ImdbID)
			continue
		}

		m := polochon.NewMovie(d.config.Movie)
		m.ImdbID = wantedMovie.ImdbID
		log = log.WithField("imdb_id", m.ImdbID)

		if err := m.GetDetails(log); err != nil {
			errors.LogErrors(log, err)
			if errors.IsFatal(err) {
				continue
			}
		}

		log = log.WithField("title", m.Title)

		if err := m.GetTorrents(log); err != nil && err != polochon.ErrMovieTorrentNotFound {
			errors.LogErrors(log, err)
			if errors.IsFatal(err) {
				continue
			}
		}

		// Keep the torrent URL
		var torrentURL string
	quality_loop:
		for _, q := range wantedMovie.Qualities {
			for _, t := range m.Torrents {
				if t.Quality == q {
					torrentURL = t.URL
					break quality_loop
				}
			}
		}

		if torrentURL == "" {
			log.Debug("no torrent found")
			continue
		}

		if err := d.config.Downloader.Client.Download(torrentURL, log); err != nil {
			log.Error(err)
			continue
		}
	}
}
Ejemplo n.º 2
0
// Start statrs a sub app in its own goroutine
func (a *App) subAppStart(app subapp.App, log *logrus.Entry) {
	log.Debugf("starting sub app %q", app.Name())
	a.wg.Add(1)
	go func() {
		defer a.wg.Done()

		if err := app.Run(log); err != nil {
			// Check the error type, if it comes from a panic recovery
			// reload the app
			switch e := err.(type) {
			case *errors.Error:
				errors.LogErrors(log.WithField("app", app.Name()), e)

				// Notify the safeguard of the error
				a.safeguard.Event()

				// Write to the reload channel in a goroutine to prevent deadlocks
				go func() {
					a.reload <- app
				}()
			// Only log the error
			default:
				log.Error(err)
				go a.Stop(log)
			}
		}
	}()
	log.Debugf("sub app %q started", app.Name())
}
Ejemplo n.º 3
0
func (d *Downloader) downloadMissingShows(wl *polochon.Wishlist, log *logrus.Entry) {
	log = log.WithField("function", "download_shows")

	for _, wishedShow := range wl.Shows {
		s := polochon.NewShow(d.config.Show)
		s.ImdbID = wishedShow.ImdbID
		log = log.WithField("imdb_id", s.ImdbID)

		if err := s.GetDetails(log); err != nil {
			errors.LogErrors(log, err)
			if errors.IsFatal(err) {
				continue
			}
		}

		calendar, err := s.GetCalendar(log)
		if err != nil {
			errors.LogErrors(log, err)
			if errors.IsFatal(err) {
				continue
			}
		}

		for _, calEpisode := range calendar.Episodes {
			// Check if the episode should be downloaded
			if calEpisode.IsOlder(wishedShow) {
				continue
			}

			// Check if the episode has already been downloaded
			ok, err := d.library.HasShowEpisode(wishedShow.ImdbID, calEpisode.Season, calEpisode.Episode)
			if err != nil {
				log.Error(err)
				continue
			}

			if ok {
				continue
			}

			// Setup the episode
			e := polochon.NewShowEpisode(d.config.Show)
			e.ShowImdbID = wishedShow.ImdbID
			e.ShowTitle = s.Title
			e.Season = calEpisode.Season
			e.Episode = calEpisode.Episode
			log = log.WithFields(logrus.Fields{
				"show_imdb_id": e.ShowImdbID,
				"show_title":   e.ShowTitle,
				"season":       e.Season,
				"episode":      e.Episode,
			})

			if err := e.GetTorrents(log); err != nil && err != polochon.ErrShowEpisodeTorrentNotFound {
				errors.LogErrors(log, err)
				if errors.IsFatal(err) {
					continue
				}
			}

			// Keep the torrent URL
			var torrentURL string

		quality_loop:
			for _, q := range wishedShow.Qualities {
				for _, t := range e.Torrents {
					if t.Quality == q {
						torrentURL = t.URL
						break quality_loop
					}
				}
			}

			if torrentURL == "" {
				log.Debug("no torrent found")
				continue
			}

			if err := d.config.Downloader.Client.Download(torrentURL, log); err != nil {
				log.Error(err)
				continue
			}
		}
	}
}
Ejemplo n.º 4
0
// OrganizeFile stores the videos in the video library
func (o *Organizer) organizeFile(filePath string, log *logrus.Entry) error {
	log = log.WithField("file_path", filePath)
	log.Debug("organize file")

	// Create a file
	file := polochon.NewFileWithConfig(filePath, o.config.File)

	// Check if file really exists
	if !file.Exists() {
		log.Warning("the file has been removed")
		return nil
	}

	// Check if file is a video
	if !file.IsVideo() {
		log.Debug("the file is not a video")
		return nil
	}

	// Check if file is ignored
	if file.IsIgnored() {
		log.Debug("the file is ignored")
		return nil
	}

	// Check if file is symlink
	if file.IsSymlink() {
		log.Debug("the file is a symlink")
		return nil
	}

	// Check if file is ignored
	if file.IsExcluded() {
		log.Debug("the file is excluded")
		return file.Ignore()
	}

	// Guess the video inforamtion
	video, err := file.Guess(o.config.Movie, o.config.Show, log)
	if err != nil {
		errors.LogErrors(log, err)
		return file.Ignore()
	}

	// Get video details
	if err := video.GetDetails(log); err != nil {
		errors.LogErrors(log, err)
		if errors.IsFatal(err) {
			return file.Ignore()
		}
	}

	// Store the video
	if err := o.library.Add(video, log); err != nil {
		errors.LogErrors(log, err)
		return file.Ignore()
	}

	// Get subtitle
	if err := video.GetSubtitle(log); err != nil {
		errors.LogErrors(log, err)
	}

	// Notify
	o.Notify(video, log)

	return nil
}
Ejemplo n.º 5
0
func (l *Library) addShow(ep *polochon.ShowEpisode, log *logrus.Entry) error {
	dir := l.getShowDir(ep)
	nfoPath := l.showNFOPath(dir)
	if exists(nfoPath) {
		return nil
	}

	s := ep.Show
	if s == nil {
		s = polochon.NewShowFromEpisode(ep)
		if err := s.GetDetails(log); err != nil {
			errors.LogErrors(log, err)
			if errors.IsFatal(err) {
				return err
			}
		}
	}

	// Create show dir if necessary
	if !exists(dir) {
		if err := os.Mkdir(dir, os.ModePerm); err != nil {
			return err
		}
	}

	// Write NFO into the file
	if err := writeNFOFile(nfoPath, s); err != nil {
		return err
	}

	// Download show images
	if s.Fanart == "" || s.Banner == "" || s.Poster == "" {
		return ErrMissingShowImageURL
	}

	// Download images
	for _, img := range []struct {
		url  string
		name string
	}{
		{
			url:  s.Fanart,
			name: "fanart.jpg",
		},
		{
			url:  s.Poster,
			name: "poster.jpg",
		},
		{
			url:  s.Banner,
			name: "banner.jpg",
		},
	} {
		savePath := filepath.Join(dir, img.name)
		if err := download(img.url, savePath); err != nil {
			return err
		}
	}

	return nil
}
Ejemplo n.º 6
0
// Run launches the app
func (a *App) Run() {
	// Hangle os signals
	osSig := make(chan os.Signal, 1)
	signal.Notify(osSig, syscall.SIGINT, syscall.SIGKILL, syscall.SIGHUP)

	log := logrus.NewEntry(a.logger)
	log.Info("starting the app")

	// Panic loop safeguard
	go func() {
		if err := a.safeguard.Run(log); err != nil {
			errors.LogErrors(log, err)
			go a.Stop(log)
		}
	}()

	// Start all the apps
	a.startSubApps(log)

	// Handle graceful shutdown
	var forceShutdown bool

	// Main loop
	for {
		select {
		case <-a.done:
			log.Info("all done, exiting")
			return
		case subApp := <-a.reload:
			log.Infof("reloading sub app %q", subApp.Name())
			a.wg.Add(1)
			go func() {
				defer a.wg.Done()
				subApp.BlockingStop(log)
				a.subAppStart(subApp, log)
			}()
		case sig := <-osSig:
			log.WithField("os_event", sig).Info("got an os event")
			switch sig {
			case syscall.SIGINT, syscall.SIGKILL:
				if forceShutdown {
					log.Warn("forced shutdown")
					os.Exit(1)
				}
				log.Info("graceful shutdown")

				// stop the app
				go a.Stop(log)

				// Next time it won't be so gentle
				forceShutdown = true

			case syscall.SIGHUP:
				log.Info("reloading app")

				a.stopApps(log)

				if err := a.init(); err != nil {
					log.Fatal(err)
				}

				a.startSubApps(log)

				log.Info("app reloaded")
			}
		}
	}
}