mirror of
https://github.com/simon-ding/polaris.git
synced 2026-06-26 10:45:21 +08:00
feat: add ability to change folder naming convention
This commit is contained in:
11
db/const.go
11
db/const.go
@@ -15,6 +15,8 @@ const (
|
|||||||
SettingAllowQiangban = "filter_qiangban"
|
SettingAllowQiangban = "filter_qiangban"
|
||||||
SettingEnableTmdbAdultContent = "tmdb_adult_content"
|
SettingEnableTmdbAdultContent = "tmdb_adult_content"
|
||||||
SetttingSizeLimiter = "size_limiter"
|
SetttingSizeLimiter = "size_limiter"
|
||||||
|
SettingTvNamingFormat = "tv_naming_format"
|
||||||
|
SettingMovieNamingFormat = "movie_naming_format"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -35,6 +37,15 @@ const (
|
|||||||
LanguageCN = "zh-CN"
|
LanguageCN = "zh-CN"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const DefaultNamingFormat = "{{.NameCN}} {{.NameEN}} ({{.Year}})"
|
||||||
|
|
||||||
|
type NamingInfo struct {
|
||||||
|
NameCN string
|
||||||
|
NameEN string
|
||||||
|
Year string
|
||||||
|
TmdbID int
|
||||||
|
}
|
||||||
|
|
||||||
type ResolutionType string
|
type ResolutionType string
|
||||||
|
|
||||||
const JwtSerectKey = "jwt_secrect_key"
|
const JwtSerectKey = "jwt_secrect_key"
|
||||||
|
|||||||
16
db/db.go
16
db/db.go
@@ -628,3 +628,19 @@ func (c *Client) SetSizeLimiter(limiter *SizeLimiter) error {
|
|||||||
}
|
}
|
||||||
return c.SetSetting(SetttingSizeLimiter, string(data))
|
return c.SetSetting(SetttingSizeLimiter, string(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetTvNamingFormat() string {
|
||||||
|
s := c.GetSetting(SettingTvNamingFormat)
|
||||||
|
if s == "" {
|
||||||
|
return DefaultNamingFormat
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetMovingNamingFormat() string {
|
||||||
|
s := c.GetSetting(SettingMovieNamingFormat)
|
||||||
|
if s == "" {
|
||||||
|
return DefaultNamingFormat
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -366,27 +368,35 @@ func (c *Client) SuggestedMovieFolderName(tmdbId int) (string, error) {
|
|||||||
return javid, nil
|
return javid, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
info := db.NamingInfo{TmdbID: tmdbId}
|
||||||
//if name is already in english, no need to query again
|
if utils.IsASCII(name) {
|
||||||
if !utils.IsASCII(name) && c.language == db.LanguageCN {
|
info.NameEN = stripExtraCharacters(name)
|
||||||
|
} else {
|
||||||
|
info.NameCN = stripExtraCharacters(name)
|
||||||
en, err := c.MustTMDB().GetMovieDetails(tmdbId, db.LanguageEN)
|
en, err := c.MustTMDB().GetMovieDetails(tmdbId, db.LanguageEN)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("get en movie detail error: %v", err)
|
log.Errorf("get en tv detail error: %v", err)
|
||||||
} else {
|
} else {
|
||||||
name = fmt.Sprintf("%s %s", name, en.Title)
|
info.NameEN = stripExtraCharacters(en.Title)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//remove extra characters
|
|
||||||
re := regexp.MustCompile(`[^\p{L}\w\s]`)
|
|
||||||
name = re.ReplaceAllString(name, " ")
|
|
||||||
name = strings.Join(strings.Fields(name), " ")
|
|
||||||
year := strings.Split(d1.ReleaseDate, "-")[0]
|
year := strings.Split(d1.ReleaseDate, "-")[0]
|
||||||
if year != "" {
|
info.Year = year
|
||||||
name = fmt.Sprintf("%s (%s)", name, year)
|
movieNamingFormat := c.db.GetMovingNamingFormat()
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("tv series of tmdb id %v suggestting name is %v", tmdbId, name)
|
tmpl, err := template.New("test").Parse(movieNamingFormat)
|
||||||
return name, nil
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "naming format")
|
||||||
|
}
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
err = tmpl.Execute(buff, info)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "tmpl exec")
|
||||||
|
}
|
||||||
|
res := strings.TrimSpace(buff.String())
|
||||||
|
|
||||||
|
log.Infof("tv series of tmdb id %v suggestting name is %v", tmdbId, res)
|
||||||
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) SuggestedSeriesFolderName(tmdbId int) (string, error) {
|
func (c *Client) SuggestedSeriesFolderName(tmdbId int) (string, error) {
|
||||||
@@ -398,24 +408,40 @@ func (c *Client) SuggestedSeriesFolderName(tmdbId int) (string, error) {
|
|||||||
|
|
||||||
name := d.Name
|
name := d.Name
|
||||||
|
|
||||||
//if name is already in english, no need to query again
|
info := db.NamingInfo{TmdbID: tmdbId}
|
||||||
if !utils.IsASCII(name) && c.language == db.LanguageCN {
|
if utils.IsASCII(name) {
|
||||||
|
info.NameEN = stripExtraCharacters(name)
|
||||||
|
} else {
|
||||||
|
info.NameCN = stripExtraCharacters(name)
|
||||||
en, err := c.MustTMDB().GetTvDetails(tmdbId, db.LanguageEN)
|
en, err := c.MustTMDB().GetTvDetails(tmdbId, db.LanguageEN)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("get en tv detail error: %v", err)
|
log.Errorf("get en tv detail error: %v", err)
|
||||||
} else {
|
} else {
|
||||||
name = fmt.Sprintf("%s %s", name, en.Name)
|
info.NameEN = stripExtraCharacters(en.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//remove extra characters
|
|
||||||
re := regexp.MustCompile(`[^\p{L}\w\s]`)
|
|
||||||
name = re.ReplaceAllString(name, " ")
|
|
||||||
name = strings.Join(strings.Fields(name), " ")
|
|
||||||
year := strings.Split(d.FirstAirDate, "-")[0]
|
year := strings.Split(d.FirstAirDate, "-")[0]
|
||||||
if year != "" {
|
info.Year = year
|
||||||
name = fmt.Sprintf("%s (%s)", name, year)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("tv series of tmdb id %v suggestting name is %v", tmdbId, name)
|
tvNamingFormat := c.db.GetTvNamingFormat()
|
||||||
return name, nil
|
|
||||||
|
tmpl, err := template.New("test").Parse(tvNamingFormat)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "naming format")
|
||||||
|
}
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
err = tmpl.Execute(buff, info)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "tmpl exec")
|
||||||
|
}
|
||||||
|
res := strings.TrimSpace(buff.String())
|
||||||
|
|
||||||
|
log.Infof("tv series of tmdb id %v suggestting name is %v", tmdbId, res)
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func stripExtraCharacters(s string) string {
|
||||||
|
re := regexp.MustCompile(`[^\p{L}\w\s]`)
|
||||||
|
s = re.ReplaceAllString(s, " ")
|
||||||
|
return strings.Join(strings.Fields(s), " ")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ type GeneralSettings struct {
|
|||||||
EnableNfo bool `json:"enable_nfo"`
|
EnableNfo bool `json:"enable_nfo"`
|
||||||
AllowQiangban bool `json:"allow_qiangban"`
|
AllowQiangban bool `json:"allow_qiangban"`
|
||||||
EnableAdultContent bool `json:"enable_adult_content"`
|
EnableAdultContent bool `json:"enable_adult_content"`
|
||||||
|
TvNamingFormat string `json:"tv_naming_format"`
|
||||||
|
MovieNamingFormat string `json:"movie_naming_format"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) SetSetting(c *gin.Context) (interface{}, error) {
|
func (s *Server) SetSetting(c *gin.Context) (interface{}, error) {
|
||||||
@@ -46,7 +48,12 @@ func (s *Server) SetSetting(c *gin.Context) (interface{}, error) {
|
|||||||
if err := s.db.SetSetting(db.SettingLogLevel, in.LogLevel); err != nil {
|
if err := s.db.SetSetting(db.SettingLogLevel, in.LogLevel); err != nil {
|
||||||
return nil, errors.Wrap(err, "save log level")
|
return nil, errors.Wrap(err, "save log level")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if in.TvNamingFormat != "" {
|
||||||
|
s.db.SetSetting(db.SettingTvNamingFormat, in.TvNamingFormat)
|
||||||
|
}
|
||||||
|
if in.MovieNamingFormat != "" {
|
||||||
|
s.db.SetSetting(db.SettingMovieNamingFormat, in.MovieNamingFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
plexmatchEnabled := s.db.GetSetting(db.SettingPlexMatchEnabled)
|
plexmatchEnabled := s.db.GetSetting(db.SettingPlexMatchEnabled)
|
||||||
@@ -74,7 +81,6 @@ func (s *Server) SetSetting(c *gin.Context) (interface{}, error) {
|
|||||||
} else {
|
} else {
|
||||||
s.db.SetSetting(db.SettingEnableTmdbAdultContent, "false")
|
s.db.SetSetting(db.SettingEnableTmdbAdultContent, "false")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +92,8 @@ func (s *Server) GetSetting(c *gin.Context) (interface{}, error) {
|
|||||||
allowQiangban := s.db.GetSetting(db.SettingAllowQiangban)
|
allowQiangban := s.db.GetSetting(db.SettingAllowQiangban)
|
||||||
enableNfo := s.db.GetSetting(db.SettingNfoSupportEnabled)
|
enableNfo := s.db.GetSetting(db.SettingNfoSupportEnabled)
|
||||||
enableAdult := s.db.GetSetting(db.SettingEnableTmdbAdultContent)
|
enableAdult := s.db.GetSetting(db.SettingEnableTmdbAdultContent)
|
||||||
|
tvFormat := s.db.GetTvNamingFormat()
|
||||||
|
movieFormat := s.db.GetMovingNamingFormat()
|
||||||
return &GeneralSettings{
|
return &GeneralSettings{
|
||||||
TmdbApiKey: tmdb,
|
TmdbApiKey: tmdb,
|
||||||
DownloadDir: downloadDir,
|
DownloadDir: downloadDir,
|
||||||
@@ -95,6 +103,8 @@ func (s *Server) GetSetting(c *gin.Context) (interface{}, error) {
|
|||||||
AllowQiangban: allowQiangban == "true",
|
AllowQiangban: allowQiangban == "true",
|
||||||
EnableNfo: enableNfo == "true",
|
EnableNfo: enableNfo == "true",
|
||||||
EnableAdultContent: enableAdult == "true",
|
EnableAdultContent: enableAdult == "true",
|
||||||
|
TvNamingFormat: tvFormat,
|
||||||
|
MovieNamingFormat: movieFormat,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ class _ActivityPageState extends ConsumerState<ActivityPage>
|
|||||||
trailing: selectedTab == 0
|
trailing: selectedTab == 0
|
||||||
? IconButton(
|
? IconButton(
|
||||||
tooltip: "删除任务",
|
tooltip: "删除任务",
|
||||||
onPressed: () => onDelete()(ac.id!),
|
onPressed: () => onDelete()(ac.id!.toString()),
|
||||||
icon: const Icon(Icons.delete))
|
icon: const Icon(Icons.delete))
|
||||||
: const Text("-"),
|
: const Text("-"),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ class Activity {
|
|||||||
required this.size,
|
required this.size,
|
||||||
required this.seedRatio});
|
required this.seedRatio});
|
||||||
|
|
||||||
final String? id;
|
final int? id;
|
||||||
final int? mediaId;
|
final int? mediaId;
|
||||||
final int? episodeId;
|
final int? episodeId;
|
||||||
final String? sourceTitle;
|
final String? sourceTitle;
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ class GeneralSetting {
|
|||||||
bool? allowQiangban;
|
bool? allowQiangban;
|
||||||
bool? enableNfo;
|
bool? enableNfo;
|
||||||
bool? enableAdult;
|
bool? enableAdult;
|
||||||
|
String? tvNamingFormat;
|
||||||
|
String? movieNamingFormat;
|
||||||
|
|
||||||
GeneralSetting(
|
GeneralSetting(
|
||||||
{this.tmdbApiKey,
|
{this.tmdbApiKey,
|
||||||
@@ -68,6 +70,8 @@ class GeneralSetting {
|
|||||||
this.enablePlexmatch,
|
this.enablePlexmatch,
|
||||||
this.enableNfo,
|
this.enableNfo,
|
||||||
this.allowQiangban,
|
this.allowQiangban,
|
||||||
|
this.tvNamingFormat,
|
||||||
|
this.movieNamingFormat,
|
||||||
this.enableAdult});
|
this.enableAdult});
|
||||||
|
|
||||||
factory GeneralSetting.fromJson(Map<String, dynamic> json) {
|
factory GeneralSetting.fromJson(Map<String, dynamic> json) {
|
||||||
@@ -79,6 +83,8 @@ class GeneralSetting {
|
|||||||
enableAdult: json["enable_adult_content"] ?? false,
|
enableAdult: json["enable_adult_content"] ?? false,
|
||||||
allowQiangban: json["allow_qiangban"] ?? false,
|
allowQiangban: json["allow_qiangban"] ?? false,
|
||||||
enableNfo: json["enable_nfo"] ?? false,
|
enableNfo: json["enable_nfo"] ?? false,
|
||||||
|
tvNamingFormat: json["tv_naming_format"],
|
||||||
|
movieNamingFormat: json["movie_naming_format"],
|
||||||
enablePlexmatch: json["enable_plexmatch"] ?? false);
|
enablePlexmatch: json["enable_plexmatch"] ?? false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,6 +98,8 @@ class GeneralSetting {
|
|||||||
data["allow_qiangban"] = allowQiangban;
|
data["allow_qiangban"] = allowQiangban;
|
||||||
data["enable_nfo"] = enableNfo;
|
data["enable_nfo"] = enableNfo;
|
||||||
data["enable_adult_content"] = enableAdult;
|
data["enable_adult_content"] = enableAdult;
|
||||||
|
data["tv_naming_format"] = tvNamingFormat;
|
||||||
|
data["movie_naming_format"] = movieNamingFormat;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ class _GeneralState extends ConsumerState<GeneralSettings> {
|
|||||||
"allow_qiangban": v.allowQiangban,
|
"allow_qiangban": v.allowQiangban,
|
||||||
"enable_nfo": v.enableNfo,
|
"enable_nfo": v.enableNfo,
|
||||||
"enable_adult": v.enableAdult,
|
"enable_adult": v.enableAdult,
|
||||||
|
"tv_naming_format": v.tvNamingFormat,
|
||||||
|
"movie_naming_format": v.movieNamingFormat,
|
||||||
},
|
},
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@@ -66,6 +68,22 @@ class _GeneralState extends ConsumerState<GeneralSettings> {
|
|||||||
hintText: "http://10.0.0.1:1080",
|
hintText: "http://10.0.0.1:1080",
|
||||||
helperText: "后台联网代理地址,留空表示不启用代理"),
|
helperText: "后台联网代理地址,留空表示不启用代理"),
|
||||||
),
|
),
|
||||||
|
FormBuilderTextField(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
icon: Icon(Icons.folder),
|
||||||
|
labelText: "电视剧路径命名规则",
|
||||||
|
helperText:
|
||||||
|
"go template语法,可用的变量为:.NameCN, .NameEN, .Year, .TmdbID"),
|
||||||
|
name: "tv_naming_format",
|
||||||
|
),
|
||||||
|
FormBuilderTextField(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
icon: Icon(Icons.folder),
|
||||||
|
labelText: "电影路径命名规则",
|
||||||
|
helperText:
|
||||||
|
"go template语法,可用的变量为:.NameCN, .NameEN, .Year, .TmdbID"),
|
||||||
|
name: "movie_naming_format",
|
||||||
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 300,
|
width: 300,
|
||||||
child: FormBuilderDropdown(
|
child: FormBuilderDropdown(
|
||||||
@@ -137,6 +155,9 @@ class _GeneralState extends ConsumerState<GeneralSettings> {
|
|||||||
allowQiangban: values["allow_qiangban"],
|
allowQiangban: values["allow_qiangban"],
|
||||||
enableAdult: values["enable_adult"],
|
enableAdult: values["enable_adult"],
|
||||||
enableNfo: values["enable_nfo"],
|
enableNfo: values["enable_nfo"],
|
||||||
|
tvNamingFormat: values["tv_naming_format"],
|
||||||
|
movieNamingFormat:
|
||||||
|
values["movie_naming_format"],
|
||||||
enablePlexmatch:
|
enablePlexmatch:
|
||||||
values["enable_plexmatch"]))
|
values["enable_plexmatch"]))
|
||||||
.then((v) => showSnakeBar("更新成功"));
|
.then((v) => showSnakeBar("更新成功"));
|
||||||
|
|||||||
Reference in New Issue
Block a user