mirror of
https://github.com/simon-ding/polaris.git
synced 2026-06-09 19:47:47 +08:00
feat: support generate .plexmatch
This commit is contained in:
@@ -10,6 +10,7 @@ const (
|
|||||||
SettingDownloadDir = "download_dir"
|
SettingDownloadDir = "download_dir"
|
||||||
SettingLogLevel = "log_level"
|
SettingLogLevel = "log_level"
|
||||||
SettingProxy = "proxy"
|
SettingProxy = "proxy"
|
||||||
|
SettingPlexMatchEnabled = "plexmatch_enabled"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import (
|
|||||||
type Storage interface {
|
type Storage interface {
|
||||||
Move(src, dest string) error
|
Move(src, dest string) error
|
||||||
ReadDir(dir string) ([]fs.FileInfo, error)
|
ReadDir(dir string) ([]fs.FileInfo, error)
|
||||||
|
ReadFile(string)([]byte, error)
|
||||||
|
WriteFile(string, []byte) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLocalStorage(dir string) (*LocalStorage, error) {
|
func NewLocalStorage(dir string) (*LocalStorage, error) {
|
||||||
@@ -81,3 +83,12 @@ func (l *LocalStorage) Move(src, destDir string) error {
|
|||||||
func (l *LocalStorage) ReadDir(dir string) ([]fs.FileInfo, error) {
|
func (l *LocalStorage) ReadDir(dir string) ([]fs.FileInfo, error) {
|
||||||
return ioutil.ReadDir(filepath.Join(l.dir, dir))
|
return ioutil.ReadDir(filepath.Join(l.dir, dir))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *LocalStorage) ReadFile(name string) ([]byte, error) {
|
||||||
|
return os.ReadFile(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (l *LocalStorage) WriteFile(name string, data []byte) error {
|
||||||
|
return os.WriteFile(name, data, os.ModePerm)
|
||||||
|
}
|
||||||
@@ -98,3 +98,13 @@ func (w *WebdavStorage) Move(local, remoteDir string) error {
|
|||||||
func (w *WebdavStorage) ReadDir(dir string) ([]fs.FileInfo, error) {
|
func (w *WebdavStorage) ReadDir(dir string) ([]fs.FileInfo, error) {
|
||||||
return w.fs.ReadDir(filepath.Join(w.dir, dir))
|
return w.fs.ReadDir(filepath.Join(w.dir, dir))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (w *WebdavStorage) ReadFile(name string) ([]byte, error) {
|
||||||
|
return w.fs.Read(filepath.Join(w.dir, name))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (w *WebdavStorage) WriteFile(name string, data []byte) error {
|
||||||
|
return w.fs.Write(filepath.Join(w.dir, name), data, os.ModePerm)
|
||||||
|
}
|
||||||
42
server/integration.go
Normal file
42
server/integration.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"polaris/db"
|
||||||
|
"polaris/ent/media"
|
||||||
|
"polaris/log"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Server) createPlexmatchIfNotExists(seriesId int) error {
|
||||||
|
|
||||||
|
if !s.plexmatchEnabled() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
series, err := s.db.GetMedia(seriesId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if series.MediaType != media.MediaTypeTv {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
st, err := s.getStorage(series.StorageID, media.MediaTypeTv)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "get storage")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = st.ReadFile(filepath.Join(series.TargetDir, ".plexmatch"))
|
||||||
|
if err != nil {
|
||||||
|
//create new
|
||||||
|
log.Warnf(".plexmatch file not found, create new one: %s", series.NameEn)
|
||||||
|
st.WriteFile(filepath.Join(series.TargetDir, ".plexmatch"), []byte(fmt.Sprintf("tmdbid=%d\n",series.TmdbID)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) plexmatchEnabled() bool {
|
||||||
|
return s.db.GetSetting(db.SettingPlexMatchEnabled) == "true"
|
||||||
|
}
|
||||||
@@ -71,6 +71,9 @@ func (s *Server) moveCompletedTask(id int) (err1 error) {
|
|||||||
log.Errorf("no season id: %v", r.TargetDir)
|
log.Errorf("no season id: %v", r.TargetDir)
|
||||||
seasonNum = -1
|
seasonNum = -1
|
||||||
}
|
}
|
||||||
|
if err := s.createPlexmatchIfNotExists(r.MediaID); err != nil {
|
||||||
|
log.Errorf("create .plexmatch file error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
s.db.SetHistoryStatus(r.ID, history.StatusFail)
|
s.db.SetHistoryStatus(r.ID, history.StatusFail)
|
||||||
@@ -143,29 +146,12 @@ func (s *Server) checkDownloadedSeriesFiles(m *ent.Media) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
log.Infof("check files in directory: %s", m.TargetDir)
|
log.Infof("check files in directory: %s", m.TargetDir)
|
||||||
st := s.db.GetStorage(m.StorageID)
|
|
||||||
|
|
||||||
var storageImpl storage.Storage
|
var storageImpl, err = s.getStorage(m.StorageID, media.MediaTypeTv)
|
||||||
|
if err != nil {
|
||||||
switch st.Implementation {
|
return err
|
||||||
case storage1.ImplementationLocal:
|
|
||||||
ls := st.ToLocalSetting()
|
|
||||||
targetPath := ls.TvPath
|
|
||||||
storageImpl1, err := storage.NewLocalStorage(targetPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "new local")
|
|
||||||
}
|
|
||||||
storageImpl = storageImpl1
|
|
||||||
|
|
||||||
case storage1.ImplementationWebdav:
|
|
||||||
ws := st.ToWebDavSetting()
|
|
||||||
targetPath := ws.TvPath
|
|
||||||
storageImpl1, err := storage.NewWebdavStorage(ws.URL, ws.User, ws.Password, targetPath, ws.ChangeFileHash == "true")
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "new webdav")
|
|
||||||
}
|
|
||||||
storageImpl = storageImpl1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
files, err := storageImpl.ReadDir(m.TargetDir)
|
files, err := storageImpl.ReadDir(m.TargetDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "read dir %s", m.TargetDir)
|
return errors.Wrapf(err, "read dir %s", m.TargetDir)
|
||||||
|
|||||||
@@ -14,10 +14,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type GeneralSettings struct {
|
type GeneralSettings struct {
|
||||||
TmdbApiKey string `json:"tmdb_api_key"`
|
TmdbApiKey string `json:"tmdb_api_key"`
|
||||||
DownloadDir string `json:"download_dir"`
|
DownloadDir string `json:"download_dir"`
|
||||||
LogLevel string `json:"log_level"`
|
LogLevel string `json:"log_level"`
|
||||||
Proxy string `json:"proxy"`
|
Proxy string `json:"proxy"`
|
||||||
|
EnablePlexmatch bool `json:"enable_plexmatch"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) SetSetting(c *gin.Context) (interface{}, error) {
|
func (s *Server) SetSetting(c *gin.Context) (interface{}, error) {
|
||||||
@@ -45,6 +46,13 @@ func (s *Server) SetSetting(c *gin.Context) (interface{}, error) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plexmatchEnabled := s.db.GetSetting(db.SettingPlexMatchEnabled)
|
||||||
|
if in.EnablePlexmatch && plexmatchEnabled != "true" {
|
||||||
|
s.db.SetSetting(db.SettingPlexMatchEnabled, "true")
|
||||||
|
} else if !in.EnablePlexmatch && plexmatchEnabled != "false" {
|
||||||
|
s.db.SetSetting(db.SettingPlexMatchEnabled, "false")
|
||||||
|
}
|
||||||
|
|
||||||
s.setProxy(in.Proxy)
|
s.setProxy(in.Proxy)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@@ -72,11 +80,13 @@ func (s *Server) GetSetting(c *gin.Context) (interface{}, error) {
|
|||||||
tmdb := s.db.GetSetting(db.SettingTmdbApiKey)
|
tmdb := s.db.GetSetting(db.SettingTmdbApiKey)
|
||||||
downloadDir := s.db.GetSetting(db.SettingDownloadDir)
|
downloadDir := s.db.GetSetting(db.SettingDownloadDir)
|
||||||
logLevel := s.db.GetSetting(db.SettingLogLevel)
|
logLevel := s.db.GetSetting(db.SettingLogLevel)
|
||||||
|
plexmatchEnabled := s.db.GetSetting(db.SettingPlexMatchEnabled)
|
||||||
return &GeneralSettings{
|
return &GeneralSettings{
|
||||||
TmdbApiKey: tmdb,
|
TmdbApiKey: tmdb,
|
||||||
DownloadDir: downloadDir,
|
DownloadDir: downloadDir,
|
||||||
LogLevel: logLevel,
|
LogLevel: logLevel,
|
||||||
Proxy: s.db.GetSetting(db.SettingProxy),
|
Proxy: s.db.GetSetting(db.SettingProxy),
|
||||||
|
EnablePlexmatch: plexmatchEnabled == "true",
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package server
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"polaris/db"
|
"polaris/db"
|
||||||
|
"polaris/ent/media"
|
||||||
|
storage1 "polaris/ent/storage"
|
||||||
"polaris/log"
|
"polaris/log"
|
||||||
"polaris/pkg/storage"
|
"polaris/pkg/storage"
|
||||||
"polaris/pkg/utils"
|
"polaris/pkg/utils"
|
||||||
@@ -106,3 +108,35 @@ func (s *Server) SuggestedMovieFolderName(c *gin.Context) (interface{}, error) {
|
|||||||
log.Infof("tv series of tmdb id %v suggestting name is %v", id, name)
|
log.Infof("tv series of tmdb id %v suggestting name is %v", id, name)
|
||||||
return gin.H{"name": name}, nil
|
return gin.H{"name": name}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (s *Server) getStorage(storageId int, mediaType media.MediaType) (storage.Storage, error) {
|
||||||
|
st := s.db.GetStorage(storageId)
|
||||||
|
switch st.Implementation {
|
||||||
|
case storage1.ImplementationLocal:
|
||||||
|
ls := st.ToLocalSetting()
|
||||||
|
targetPath := ls.TvPath
|
||||||
|
if mediaType == media.MediaTypeMovie {
|
||||||
|
targetPath = ls.MoviePath
|
||||||
|
}
|
||||||
|
storageImpl1, err := storage.NewLocalStorage(targetPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "new local")
|
||||||
|
}
|
||||||
|
return storageImpl1, nil
|
||||||
|
|
||||||
|
case storage1.ImplementationWebdav:
|
||||||
|
ws := st.ToWebDavSetting()
|
||||||
|
targetPath := ws.TvPath
|
||||||
|
if mediaType == media.MediaTypeMovie {
|
||||||
|
targetPath = ws.MoviePath
|
||||||
|
}
|
||||||
|
|
||||||
|
storageImpl1, err := storage.NewWebdavStorage(ws.URL, ws.User, ws.Password, targetPath, ws.ChangeFileHash == "true")
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "new webdav")
|
||||||
|
}
|
||||||
|
return storageImpl1, nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("no storage found")
|
||||||
|
}
|
||||||
|
|||||||
@@ -51,16 +51,22 @@ class GeneralSetting {
|
|||||||
String? downloadDIr;
|
String? downloadDIr;
|
||||||
String? logLevel;
|
String? logLevel;
|
||||||
String? proxy;
|
String? proxy;
|
||||||
|
bool? enablePlexmatch;
|
||||||
|
|
||||||
GeneralSetting(
|
GeneralSetting(
|
||||||
{this.tmdbApiKey, this.downloadDIr, this.logLevel, this.proxy});
|
{this.tmdbApiKey,
|
||||||
|
this.downloadDIr,
|
||||||
|
this.logLevel,
|
||||||
|
this.proxy,
|
||||||
|
this.enablePlexmatch});
|
||||||
|
|
||||||
factory GeneralSetting.fromJson(Map<String, dynamic> json) {
|
factory GeneralSetting.fromJson(Map<String, dynamic> json) {
|
||||||
return GeneralSetting(
|
return GeneralSetting(
|
||||||
tmdbApiKey: json["tmdb_api_key"],
|
tmdbApiKey: json["tmdb_api_key"],
|
||||||
downloadDIr: json["download_dir"],
|
downloadDIr: json["download_dir"],
|
||||||
logLevel: json["log_level"],
|
logLevel: json["log_level"],
|
||||||
proxy: json["proxy"]);
|
proxy: json["proxy"],
|
||||||
|
enablePlexmatch: json["enable_plexmatch"] ?? false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
@@ -69,6 +75,7 @@ class GeneralSetting {
|
|||||||
data['download_dir'] = downloadDIr;
|
data['download_dir'] = downloadDIr;
|
||||||
data["log_level"] = logLevel;
|
data["log_level"] = logLevel;
|
||||||
data["proxy"] = proxy;
|
data["proxy"] = proxy;
|
||||||
|
data["enable_plexmatch"] = enablePlexmatch;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ class _GeneralState extends ConsumerState<GeneralSettings> {
|
|||||||
"download_dir": v.downloadDIr,
|
"download_dir": v.downloadDIr,
|
||||||
"log_level": v.logLevel,
|
"log_level": v.logLevel,
|
||||||
"proxy": v.proxy,
|
"proxy": v.proxy,
|
||||||
|
"enable_plexmatch": v.enablePlexmatch
|
||||||
},
|
},
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@@ -78,6 +79,11 @@ class _GeneralState extends ConsumerState<GeneralSettings> {
|
|||||||
validator: FormBuilderValidators.required(),
|
validator: FormBuilderValidators.required(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 300,
|
||||||
|
child: FormBuilderSwitch(
|
||||||
|
name: "enable_plexmatch", title: const Text("Plex 刮削支持")),
|
||||||
|
),
|
||||||
Center(
|
Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(top: 28.0),
|
padding: const EdgeInsets.only(top: 28.0),
|
||||||
@@ -95,7 +101,10 @@ class _GeneralState extends ConsumerState<GeneralSettings> {
|
|||||||
tmdbApiKey: values["tmdb_api"],
|
tmdbApiKey: values["tmdb_api"],
|
||||||
downloadDIr: values["download_dir"],
|
downloadDIr: values["download_dir"],
|
||||||
logLevel: values["log_level"],
|
logLevel: values["log_level"],
|
||||||
proxy: values["proxy"])).then((v) => showSnakeBar("更新成功"));
|
proxy: values["proxy"],
|
||||||
|
enablePlexmatch:
|
||||||
|
values["enable_plexmatch"]))
|
||||||
|
.then((v) => showSnakeBar("更新成功"));
|
||||||
showLoadingWithFuture(f);
|
showLoadingWithFuture(f);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user