Compare commits

...

4 Commits

Author SHA1 Message Date
Simon Ding
2683c5dbf2 fix: tv name parse 2024-09-27 21:58:34 +08:00
Simon Ding
b717885270 feat: change status color 2024-09-27 15:19:45 +08:00
Simon Ding
4e457e99b9 fix: context 2024-09-27 15:03:00 +08:00
Simon Ding
ecfe31ea45 fix: tv date not exists and folder name suggestion 2024-09-26 09:45:36 +08:00
7 changed files with 75 additions and 48 deletions

View File

@@ -37,7 +37,7 @@ const (
LanguageCN = "zh-CN"
)
const DefaultNamingFormat = "{{.NameCN}} {{.NameEN}} ({{.Year}})"
const DefaultNamingFormat = "{{.NameCN}} {{.NameEN}} {{if .Year}} ({{.Year}}) {{end}}"
type NamingInfo struct {
NameCN string

View File

@@ -2,6 +2,7 @@ package metadata
import (
"fmt"
"polaris/log"
"polaris/pkg/utils"
"regexp"
"strconv"
@@ -170,7 +171,7 @@ func parseChineseName(name string) *Metadata {
}
//episode number
re1 := regexp.MustCompile(`\[\d{1,2}\]`)
re1 := regexp.MustCompile(`\[\d{1,3}\]`)
episodeMatches1 := re1.FindAllString(name, -1)
if len(episodeMatches1) > 0 { //[11] [1080p]
epNum := strings.TrimRight(strings.TrimLeft(episodeMatches1[0], "["), "]")
@@ -228,12 +229,17 @@ func parseChineseName(name string) *Metadata {
}
meta.Season = n
} else {
seasonRe1 := regexp.MustCompile(`第.{1}季`)
seasonRe1 := regexp.MustCompile(`第.{1,2}季`)
seasonMatches := seasonRe1.FindAllString(name, -1)
if len(seasonMatches) > 0 {
se := []rune(seasonMatches[0])
seNum := se[1]
meta.Season = chinese2Num[string(seNum)]
m1 := []rune(seasonMatches[0])
seNum := m1[1 : len(m1)-1]
n, err := strconv.Atoi(string(seNum))
if err != nil {
log.Warnf("parse season number %v error: %v, try to parse using chinese", seNum, err)
n = chinese2Num[string(seNum)]
}
meta.Season = n
}
}
@@ -245,24 +251,29 @@ func parseChineseName(name string) *Metadata {
}
//tv name
title := name
fields := strings.FieldsFunc(title, func(r rune) bool {
fields := strings.FieldsFunc(name, func(r rune) bool {
return r == '[' || r == ']' || r == '【' || r == '】'
})
title = ""
titleCn := ""
title := ""
for _, p := range fields { //寻找匹配的最长的字符串,最有可能是名字
if len([]rune(p)) > len([]rune(title)) {
if utils.ContainsChineseChar(p) && len([]rune(p)) > len([]rune(titleCn)) { //最长含中文字符串
titleCn = p
}
if len([]rune(p)) > len([]rune(title)) { //最长字符串
title = p
}
}
re := regexp.MustCompile(`[^\p{L}\w\s]`)
title = re.ReplaceAllString(strings.TrimSpace(strings.ToLower(title)), "")
title = re.ReplaceAllString(strings.TrimSpace(strings.ToLower(title)), "") //去除标点符号
titleCn = re.ReplaceAllString(strings.TrimSpace(strings.ToLower(titleCn)), "")
meta.NameCn = title
meta.NameCn = titleCn
cnRe := regexp.MustCompile(`\p{Han}.*\p{Han}`)
cnmatches := cnRe.FindAllString(title, -1)
cnmatches := cnRe.FindAllString(titleCn, -1)
//titleCn中最长的中文字符
if len(cnmatches) > 0 {
for _, t := range cnmatches {
if len([]rune(t)) > len([]rune(meta.NameCn)) {
@@ -271,12 +282,13 @@ func parseChineseName(name string) *Metadata {
}
}
//匹配title中最长拉丁字符串
enRe := regexp.MustCompile(`[[:ascii:]]*`)
enM := enRe.FindAllString(title, -1)
if len(enM) > 0 {
for _, t := range enM {
if len(t) > len(meta.NameEn) {
meta.NameEn = strings.ToLower(t)
meta.NameEn = strings.TrimSpace(strings.ToLower(t))
}
}
}

View File

@@ -137,11 +137,11 @@ func Test_ParseTV13(t *testing.T) {
}
func Test_ParseTV14(t *testing.T) {
s1 := ""
s1 := "[GM-Team][国漫][斗破苍穹 第5季][Fights Break Sphere ][2022][113][HEVC][GB][4K]"
m := ParseTv(s1)
log.Infof("results: %+v", m)
assert.Equal(t, 2, m.Season)
assert.Equal(t, 01, m.Episode)
assert.Equal(t, 5, m.Season)
assert.Equal(t, 113, m.Episode)
assert.Equal(t, false, m.IsSeasonPack)
assert.Equal(t, "720p", m.Resolution)
}
//assert.Equal(t, "720p", m.Resolution)
}

View File

@@ -425,7 +425,9 @@ func (c *Client) SuggestedSeriesFolderName(tmdbId int) (string, error) {
if err != nil {
log.Errorf("get en tv detail error: %v", err)
} else {
info.NameEN = stripExtraCharacters(en.Name)
if en.Name != name { //sometimes en name is in chinese
info.NameEN = stripExtraCharacters(en.Name)
}
}
}
year := strings.Split(d.FirstAirDate, "-")[0]

View File

@@ -34,7 +34,7 @@ func (s *Server) SetSetting(c *gin.Context) (interface{}, error) {
return nil, errors.Wrap(err, "bind json")
}
utils.TrimFields(&in)
log.Infof("set setting input: %+v", in)
if in.TmdbApiKey != "" {
if err := s.db.SetSetting(db.SettingTmdbApiKey, in.TmdbApiKey); err != nil {
@@ -54,18 +54,23 @@ func (s *Server) SetSetting(c *gin.Context) (interface{}, error) {
}
}
if in.TvNamingFormat != "" {
if _, err := template.New("test").Parse(in.TvNamingFormat);err != nil {
if _, err := template.New("test").Parse(in.TvNamingFormat); err != nil {
return nil, errors.Wrap(err, "tv format")
}
s.db.SetSetting(db.SettingTvNamingFormat, in.TvNamingFormat)
} else {
s.db.SetSetting(db.SettingTvNamingFormat, "")
}
if in.MovieNamingFormat != "" {
if _, err := template.New("test").Parse(in.MovieNamingFormat);err != nil {
if _, err := template.New("test").Parse(in.MovieNamingFormat); err != nil {
return nil, errors.Wrap(err, "movie format")
}
s.db.SetSetting(db.SettingMovieNamingFormat, in.MovieNamingFormat)
} else {
s.db.SetSetting(db.SettingMovieNamingFormat, "")
}
plexmatchEnabled := s.db.GetSetting(db.SettingPlexMatchEnabled)

View File

@@ -98,8 +98,8 @@ class MediaCard extends StatelessWidget {
LinearProgressIndicator(
value: 1,
color: item.downloadedNum! >= item.monitoredNum!
? Colors.green
: Colors.blue,
? Colors.teal
: Colors.lightGreen,
),
Text(
item.name!,

View File

@@ -38,7 +38,7 @@ class _DetailCardState extends ConsumerState<DetailCard> {
margin: const EdgeInsets.all(4),
clipBehavior: Clip.hardEdge,
child: Container(
constraints: BoxConstraints(maxHeight: 400),
constraints: const BoxConstraints(maxHeight: 400),
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
@@ -52,7 +52,7 @@ class _DetailCardState extends ConsumerState<DetailCard> {
child: Row(
children: <Widget>[
screenWidth < 600
? SizedBox()
? const SizedBox()
: Flexible(
flex: 2,
child: Padding(
@@ -72,14 +72,14 @@ class _DetailCardState extends ConsumerState<DetailCard> {
children: [
//const Text(""),
Text(
"${widget.details.name} ${widget.details.name != widget.details.originalName ? widget.details.originalName : ''} (${widget.details.airDate!.split("-")[0]})",
"${widget.details.name} ${widget.details.name != widget.details.originalName ? widget.details.originalName : ''} ${widget.details.airDate == null ? "" : (widget.details.airDate!.split("-")[0])}",
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
height: 2.5),
),
const Divider(thickness: 1, height: 1),
Text(
const Text(
"",
style: TextStyle(height: 0.2),
),
@@ -93,14 +93,14 @@ class _DetailCardState extends ConsumerState<DetailCard> {
label: Text(
"${widget.details.storage!.name}: ${widget.details.mediaType == "tv" ? widget.details.storage!.tvPath : widget.details.storage!.moviePath}"
"${widget.details.targetDir}"),
padding: EdgeInsets.all(0),
padding: const EdgeInsets.all(0),
),
Chip(
clipBehavior: Clip.hardEdge,
shape: ContinuousRectangleBorder(
borderRadius: BorderRadius.circular(100.0)),
label: Text("${widget.details.resolution}"),
padding: EdgeInsets.all(0),
padding: const EdgeInsets.all(0),
),
widget.details.limiter != null &&
widget.details.limiter!.sizeMax > 0
@@ -109,13 +109,13 @@ class _DetailCardState extends ConsumerState<DetailCard> {
shape: ContinuousRectangleBorder(
borderRadius:
BorderRadius.circular(100.0)),
padding: EdgeInsets.all(0),
padding: const EdgeInsets.all(0),
label: Text(
"${(widget.details.limiter!.sizeMin).readableFileSize()} - ${(widget.details.limiter!.sizeMax).readableFileSize()}"))
: const SizedBox(),
MenuAnchor(
style:
MenuStyle(alignment: Alignment.bottomRight),
style: const MenuStyle(
alignment: Alignment.bottomRight),
menuChildren: [
ActionChip.elevated(
onPressed: () => launchUrl(url),
@@ -124,10 +124,10 @@ class _DetailCardState extends ConsumerState<DetailCard> {
shape: ContinuousRectangleBorder(
borderRadius:
BorderRadius.circular(100.0)),
padding: EdgeInsets.all(0),
label: Text("TMDB")),
padding: const EdgeInsets.all(0),
label: const Text("TMDB")),
isBlank(widget.details.imdbid)
? SizedBox()
? const SizedBox()
: ActionChip.elevated(
onPressed: () => launchUrl(imdbUrl),
backgroundColor: Colors.indigo[700],
@@ -135,8 +135,8 @@ class _DetailCardState extends ConsumerState<DetailCard> {
shape: ContinuousRectangleBorder(
borderRadius:
BorderRadius.circular(100.0)),
padding: EdgeInsets.all(0),
label: Text("IMDB"),
padding: const EdgeInsets.all(0),
label: const Text("IMDB"),
)
],
builder: (context, controller, child) {
@@ -152,8 +152,8 @@ class _DetailCardState extends ConsumerState<DetailCard> {
shape: ContinuousRectangleBorder(
borderRadius:
BorderRadius.circular(100.0)),
padding: EdgeInsets.all(0),
label: Text("外部链接"));
padding: const EdgeInsets.all(0),
label: const Text("外部链接"));
},
),
],
@@ -170,7 +170,7 @@ class _DetailCardState extends ConsumerState<DetailCard> {
children: [
downloadButton(),
editIcon(),
deleteIcon(),
deleteIcon(context),
],
)
],
@@ -185,14 +185,14 @@ class _DetailCardState extends ConsumerState<DetailCard> {
);
}
Widget deleteIcon() {
Widget deleteIcon(BuildContext oriContext) {
return IconButton(
tooltip: widget.details.mediaType == "tv" ? "删除剧集" : "删除电影",
onPressed: () => showConfirmDialog(),
onPressed: () => showConfirmDialog(oriContext),
icon: const Icon(Icons.delete));
}
Future<void> showConfirmDialog() {
Future<void> showConfirmDialog(BuildContext oriContext) {
return showDialog<void>(
context: context,
barrierDismissible: true,
@@ -210,9 +210,13 @@ class _DetailCardState extends ConsumerState<DetailCard> {
.read(mediaDetailsProvider(widget.details.id.toString())
.notifier)
.delete()
.then((v) => context.go(widget.details.mediaType == "tv"
.then((v) {
if (oriContext.mounted) {
oriContext.go(widget.details.mediaType == "tv"
? WelcomePage.routeTv
: WelcomePage.routeMoivie));
: WelcomePage.routeMoivie);
}
});
Navigator.of(context).pop();
},
child: const Text("确认"))
@@ -292,7 +296,11 @@ class _DetailCardState extends ConsumerState<DetailCard> {
.notifier)
.edit(values["resolution"], values["target_dir"],
values["limiter"])
.then((v) => Navigator.of(context).pop());
.then((v) {
if (context.mounted) {
Navigator.of(context).pop();
}
});
}
},
label: const Text("确认"))