diff --git a/db/db.go b/db/db.go index 5e7d29a..a355656 100644 --- a/db/db.go +++ b/db/db.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "os" + "path/filepath" "polaris/ent" "polaris/ent/downloadclients" "polaris/ent/episode" @@ -14,6 +15,8 @@ import ( "polaris/ent/settings" "polaris/ent/storage" "polaris/log" + "polaris/pkg/utils" + "strings" "time" "entgo.io/ent/dialect" @@ -86,6 +89,16 @@ func (c *Client) AddWatchlist(storageId int, nameCn, nameEn string, detail *tmdb storageId = r.ID } } + st := c.GetStorage(storageId) + + targetDir := fmt.Sprintf("%s %s (%v)", nameCn, nameEn, strings.Split(detail.FirstAirDate, "-")[0]) + if !utils.IsChineseChar(nameCn) { + log.Warnf("name cn is not chinese name: %v", nameCn) + targetDir = fmt.Sprintf("%s (%v)", nameEn, strings.Split(detail.FirstAirDate, "-")[0]) + } + + + targetDir = filepath.Join(st.GetPath(), targetDir) r, err := c.ent.Series.Create(). SetTmdbID(int(detail.ID)). @@ -97,6 +110,7 @@ func (c *Client) AddWatchlist(storageId int, nameCn, nameEn string, detail *tmdb SetPosterPath(detail.PosterPath). SetAirDate(detail.FirstAirDate). SetResolution(res.String()). + SetTargetDir(targetDir). AddEpisodeIDs(episodes...). Save(context.TODO()) return r, err @@ -311,7 +325,12 @@ func (s *Storage) ToWebDavSetting() WebdavSetting { var webdavSetting WebdavSetting json.Unmarshal([]byte(s.Settings), &webdavSetting) return webdavSetting +} +func (s *Storage) GetPath() string { + var m map[string]string + json.Unmarshal([]byte(s.Settings), &m) + return m["path"] } func (c *Client) GetStorage(id int) *Storage { @@ -387,3 +406,12 @@ func (c *Client) GetDownloadDir() string { } return r.Value } + +func (c *Client) UpdateEpisodeFile(seriesID int, seasonNum, episodeNum int, file string) error { + ep, err := c.ent.Episode.Query().Where(episode.SeriesID(seriesID)).Where(episode.EpisodeNumber(episodeNum)). + Where(episode.SeasonNumber(seasonNum)).First(context.TODO()) + if err != nil { + return errors.Wrap(err, "finding episode") + } + return ep.Update().SetFileInStorage(file).Exec(context.TODO()) +} diff --git a/pkg/storage/local.go b/pkg/storage/local.go index aa784f5..820aef3 100644 --- a/pkg/storage/local.go +++ b/pkg/storage/local.go @@ -3,6 +3,7 @@ package storage import ( "io" "io/fs" + "io/ioutil" "os" "path/filepath" @@ -62,3 +63,8 @@ func (l *LocalStorage) Move(src, dest string) error { return os.RemoveAll(src) } + + +func (l *LocalStorage) ReadDir(dir string) ([]fs.FileInfo, error) { + return ioutil.ReadDir(dir) +} \ No newline at end of file diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 9ea87a9..fbb890c 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -1,6 +1,7 @@ package utils import ( + "regexp" "unicode" "golang.org/x/crypto/bcrypt" @@ -25,4 +26,14 @@ func HashPassword(password string) (string, error) { func VerifyPassword(password, hash string) bool { err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) return err == nil -} \ No newline at end of file +} + +func IsChineseChar(str string) bool { + + for _, r := range str { + if unicode.Is(unicode.Han, r) || (regexp.MustCompile("[\u3002\uff1b\uff0c\uff1a\u201c\u201d\uff08\uff09\u3001\uff1f\u300a\u300b]").MatchString(string(r))) { + return true + } + } + return false +} diff --git a/server/resources.go b/server/resources.go index 86c2c6f..d981f98 100644 --- a/server/resources.go +++ b/server/resources.go @@ -112,13 +112,7 @@ func (s *Server) searchAndDownload(seriesId, seasonNum, episodeNum int) (*string } torrent.Start() - var name = series.NameEn - if name == "" { - name = series.OriginalName - } - var year = strings.Split(series.AirDate, "-")[0] - - dir := fmt.Sprintf("%s (%s)/Season %02d", name, year, ep.SeasonNumber) + dir := fmt.Sprintf("%s/Season %02d", series.TargetDir, ep.SeasonNumber) history, err :=s.db.SaveHistoryRecord(ent.History{ SeriesID: ep.SeriesID, diff --git a/server/scheduler.go b/server/scheduler.go index 3cedc88..900212a 100644 --- a/server/scheduler.go +++ b/server/scheduler.go @@ -2,16 +2,21 @@ package server import ( "path/filepath" + "polaris/ent" + storage1 "polaris/ent/storage" "polaris/log" "polaris/pkg" "polaris/pkg/storage" - storage1 "polaris/ent/storage" + "regexp" + "strconv" + "strings" "github.com/pkg/errors" ) func (s *Server) scheduler() { s.mustAddCron("@every 1m", s.checkTasks) + s.mustAddCron("@every 10m", s.checkAllFiles) s.cron.Start() } @@ -85,7 +90,75 @@ func (s *Server) updateSeriesEpisodes(seriesId int) { } -func (s *Server) checkFileExists() {} +func (s *Server) checkAllFiles() { + var tvs = s.db.GetWatchlist() + for _, se := range tvs { + if err := s.checkFileExists(se); err != nil { + log.Errorf("check files for %s error: %v", se.NameCn, err) + } + } +} + +func (s *Server) checkFileExists(series *ent.Series) error{ + log.Infof("check files in directory: %s", series.TargetDir) + st := s.db.GetStorage(series.StorageID) + var storageImpl storage.Storage + + switch st.Implementation { + case storage1.ImplementationLocal: + ls := st.ToLocalSetting() + storageImpl1, err := storage.NewLocalStorage(ls.Path) + if err != nil { + return errors.Wrap(err, "new local") + } + storageImpl = storageImpl1 + + case storage1.ImplementationWebdav: + ws := st.ToWebDavSetting() + storageImpl1, err := storage.NewWebdavStorage(ws.Path, ws.User, ws.Password) + if err != nil { + return errors.Wrap(err, "new webdav") + } + storageImpl = storageImpl1 + } + files, err := storageImpl.ReadDir(series.TargetDir) + if err != nil { + return errors.Wrapf(err, "read dir %s", series.TargetDir) + } + numRe := regexp.MustCompile("[0-9]+") + epRe := regexp.MustCompile("E[0-9]+") + for _, in := range files { + if !in.IsDir() {//season dir, ignore file + continue + } + nums := numRe.FindAllString(in.Name(), -1) + if len(nums) == 0 { + continue + } + seasonNum := nums[0] + seasonNum1, _ := strconv.Atoi(seasonNum) + dir := filepath.Join(series.TargetDir, in.Name()) + epFiles, err := storageImpl.ReadDir(dir) + if err != nil { + log.Errorf("read dir %s error: %v", dir, err) + continue + } + for _, ep := range epFiles { + match := epRe.FindAllString(ep.Name(), -1) + if len(match) == 0 { + continue + } + epNum := strings.TrimPrefix(match[0], "E") + epNum1, _ := strconv.Atoi(epNum) + err := s.db.UpdateEpisodeFile(series.ID, seasonNum1, epNum1, filepath.Join(in.Name(), ep.Name())) + if err != nil { + log.Error("update episode: %v", err) + } + } + } + return nil + +} type Task struct { Processing bool