test
This commit is contained in:
parent
f621612340
commit
a29d084b24
295
main.go
295
main.go
@ -1,283 +1,32 @@
|
|||||||
package main
|
package envconf
|
||||||
|
|
||||||
import ("regexp"
|
import ("fmt"
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"os")
|
||||||
"path/filepath"
|
|
||||||
"io/fs"
|
|
||||||
"os"
|
|
||||||
"github.com/fsnotify/fsnotify")
|
|
||||||
|
|
||||||
type SeasonInfo struct {
|
const TypeNone = (1 << 1)
|
||||||
Name string
|
const TypeInt = (1 << 2)
|
||||||
Season int
|
const TypeDuration = (1 << 3)
|
||||||
IsSeries bool
|
const TypeString = (1 << 4)
|
||||||
IncludeSeriesName bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
apikey string
|
env map[string]map[string]int
|
||||||
ignore string // Ignore files with this file extension (case insensitive)
|
|
||||||
size int64 // Minimum file size for files to be moved
|
|
||||||
src string
|
|
||||||
dst string
|
|
||||||
req int64 // Number of requests per second to API
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var seriesMatcher []*regexp.Regexp
|
func NewConfig()(*Config) {
|
||||||
var moviesMatcher *regexp.Regexp
|
config := new(Config)
|
||||||
|
config.env = make(map[string]string)
|
||||||
func getEnvString(key string)(val string, ok bool) {
|
for _,v := range os.Environ() {
|
||||||
val, ok = os.LookupEnv(key)
|
splitted := strings.SplitN(v, "=", 2)
|
||||||
if ok {
|
if len(splitted) == 2 {
|
||||||
val = strings.TrimSuffix(val, "/")
|
key := strings.ToLower(splitted[0])
|
||||||
} else {
|
strval := splitted[1]
|
||||||
fmt.Printf("Environment variable missing: %s\n", key)
|
val := make(map[string]int)
|
||||||
|
val[strval] = TypeNone
|
||||||
|
env[key] = val
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
fmt.Println(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEnvBool(key string)(val bool, ok bool) {
|
|
||||||
var str string
|
|
||||||
var err error
|
|
||||||
str, ok = getEnvString(key)
|
|
||||||
if ok {
|
|
||||||
val, err = strconv.ParseBool(str)
|
|
||||||
if err != nil {
|
|
||||||
ok = false
|
|
||||||
fmt.Printf("Failed to parse environment variable as bool: %s\n", key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
func getEnvInt(key string)(val int64, ok bool) {
|
|
||||||
var str string
|
|
||||||
var err error
|
|
||||||
str, ok = getEnvString(key)
|
|
||||||
if ok {
|
|
||||||
upper := strings.ToUpper(str)
|
|
||||||
mod := int64(1)
|
|
||||||
if strings.HasSuffix(upper, "K") {
|
|
||||||
mod = 1024
|
|
||||||
upper = strings.TrimSuffix(upper, "K")
|
|
||||||
} else if strings.HasSuffix(upper, "M") {
|
|
||||||
mod = 1024 * 1024
|
|
||||||
upper = strings.TrimSuffix(upper, "M")
|
|
||||||
} else if strings.HasSuffix(upper, "G") {
|
|
||||||
mod = 1024 * 1024 * 1024
|
|
||||||
upper = strings.TrimSuffix(upper, "G")
|
|
||||||
}
|
|
||||||
var tmp int64
|
|
||||||
tmp, err = strconv.ParseInt(upper, 10, 64)
|
|
||||||
if err == nil {
|
|
||||||
val = tmp * mod
|
|
||||||
} else {
|
|
||||||
ok = false
|
|
||||||
fmt.Printf("Failed to parse environment variable as int: %s\n", key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
compileRegex()
|
|
||||||
|
|
||||||
anyfail := false
|
|
||||||
var ok bool
|
|
||||||
var config Config
|
|
||||||
var info SeasonInfo
|
|
||||||
|
|
||||||
config.apikey, ok = getEnvString("THEMOVIEDB_API_KEY")
|
|
||||||
anyfail = !ok || anyfail
|
|
||||||
config.src, ok = getEnvString("SOURCE_FOLDER")
|
|
||||||
anyfail = !ok || anyfail
|
|
||||||
config.dst, ok = getEnvString("DESTINATION_FOLDER")
|
|
||||||
anyfail = !ok || anyfail
|
|
||||||
config.ignore, ok = getEnvString("IGNORE_FILE_EXTENSION")
|
|
||||||
anyfail = !ok || anyfail
|
|
||||||
config.req, ok = getEnvInt("REQUESTS_PER_SECOND")
|
|
||||||
anyfail = !ok || anyfail
|
|
||||||
config.size, ok = getEnvInt("MINIMUM_FILE_SIZE")
|
|
||||||
anyfail = !ok || anyfail
|
|
||||||
info.IncludeSeriesName, ok = getEnvBool("INCLUDE_SERIES_IN_FILENAME")
|
|
||||||
anyfail = !ok || anyfail
|
|
||||||
|
|
||||||
if anyfail {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setupRequest(time.Duration(int64(time.Second) / int64(config.req)))
|
|
||||||
watch(config, info)
|
|
||||||
}
|
|
||||||
|
|
||||||
func watch(config Config, info SeasonInfo) {
|
|
||||||
watcher, err := fsnotify.NewWatcher()
|
|
||||||
if err != nil {
|
|
||||||
printerr(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer watcher.Close()
|
|
||||||
|
|
||||||
walkDirFunc := func(path string, dir fs.DirEntry, err error) (nerr error) {
|
|
||||||
if err != nil {
|
|
||||||
printerr(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if dir.IsDir() {
|
|
||||||
return watcher.Add(path)
|
|
||||||
} else {
|
|
||||||
go move(path, config, info)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
filepath.WalkDir(config.src, walkDirFunc)
|
|
||||||
|
|
||||||
for {
|
|
||||||
event, ok := <-watcher.Events
|
|
||||||
if ok {
|
|
||||||
if event.Op & fsnotify.Create == fsnotify.Create {
|
|
||||||
finfo, err := os.Stat(event.Name)
|
|
||||||
if err != nil {
|
|
||||||
printerr(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if finfo.IsDir() {
|
|
||||||
watcher.Add(event.Name)
|
|
||||||
} else {
|
|
||||||
go move(event.Name, config, info)
|
|
||||||
}
|
|
||||||
} else if event.Op & fsnotify.Remove == fsnotify.Remove {
|
|
||||||
watcher.Remove(event.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func compileRegex() {
|
|
||||||
seriesMatcherString := [...]string {
|
|
||||||
"(?:\\[.*\\])?(.*)(?:[Ss])([0-9]{2})(?:[Ee])([0-9]{2})(?:.*)\\.(.+)",
|
|
||||||
"(?:\\[.*\\])?(.*)(?:[Ss])([0-9]{2})(?:[Ee])([0-9])(?:.*)\\.(.+)",
|
|
||||||
"(?:\\[.*\\])?(.*)(?:[Ss])([0-9])(?:[Ee])([0-9]{2})(?:.*)\\.(.+)",
|
|
||||||
"(?:\\[.*\\])?(.*)(?:[Ss])([0-9])(?:[Ee])([0-9])(?:.*)\\.(.+)",
|
|
||||||
"(?:\\[.*\\])?(.*)([0-9]{2})(?:[Xx])([0-9]{2})(?:.*)\\.(.+)",
|
|
||||||
"(?:\\[.*\\])?(.*)([0-9]{2})(?:[Xx])([0-9])(?:.*)\\.(.+)",
|
|
||||||
"(?:\\[.*\\])?(.*)([0-9])(?:[Xx])([0-9]{2})(?:.*)\\.(.+)",
|
|
||||||
"(?:\\[.*\\])?(.*)([0-9])(?:[Xx])([0-9])(?:.*)\\.(.+)",
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
SERIES S01E01
|
|
||||||
SERIES S01E1
|
|
||||||
SERIES S1E01
|
|
||||||
SERIES S1E1
|
|
||||||
SERIES 01X01
|
|
||||||
SERIES 01X1
|
|
||||||
SERIES 1X01
|
|
||||||
SERIES 1X1
|
|
||||||
*/
|
|
||||||
|
|
||||||
seriesMatcher = make([]*regexp.Regexp, len(seriesMatcherString))
|
|
||||||
|
|
||||||
for k,v := range seriesMatcherString {
|
|
||||||
seriesMatcher[k] = regexp.MustCompile(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
moviesMatcher = regexp.MustCompile("(?:\\[.*\\])?(.+)(?:\\(?)((?:18|19|20)(?:[0-9]{2}))(?:\\)?)(?:.*)?\\.(.+)")
|
|
||||||
}
|
|
||||||
|
|
||||||
func move(name string, config Config, info SeasonInfo) {
|
|
||||||
fmt.Printf(`------ lookup file: "%s" ------%s`, name, "\n")
|
|
||||||
config.src = name
|
|
||||||
finfo, err := os.Lstat(config.src)
|
|
||||||
if err != nil {
|
|
||||||
printerr(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
lname := strings.ToLower(config.src)
|
|
||||||
suffix := "." + strings.ToLower(config.ignore)
|
|
||||||
if strings.HasSuffix(lname, suffix) {
|
|
||||||
fmt.Printf(`------ file ignored: "%s" ------%s`, config.src, "\n")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if finfo.Mode().IsRegular() {
|
|
||||||
config.src = strings.TrimSuffix(strings.TrimSuffix(config.src, finfo.Name()), "/")
|
|
||||||
if finfo.Size() > config.size {
|
|
||||||
rename(finfo.Name(), config, info)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func rename(filename string, config Config, info SeasonInfo){
|
|
||||||
var episode int64
|
|
||||||
var extension string
|
|
||||||
|
|
||||||
find := func(re *regexp.Regexp)(bool){
|
|
||||||
res := re.FindStringSubmatch(filename)
|
|
||||||
tf := func(r rune) bool {
|
|
||||||
return r < '0'
|
|
||||||
}
|
|
||||||
for k,v := range res {
|
|
||||||
splitted := strings.Split(v, "(")
|
|
||||||
if len(splitted) > 1 {
|
|
||||||
res[k] = strings.TrimFunc(splitted[0], tf)
|
|
||||||
} else {
|
|
||||||
res[k] = strings.TrimFunc(v, tf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(res) == 5{
|
|
||||||
for _,v := range res{
|
|
||||||
fmt.Println(v)
|
|
||||||
}
|
|
||||||
fmt.Println("")
|
|
||||||
info.Name = res[1]
|
|
||||||
|
|
||||||
season,_ := strconv.ParseInt(res[2], 10, 64)
|
|
||||||
episode,_ = strconv.ParseInt(res[3], 10, 64)
|
|
||||||
info.Season = int(season)
|
|
||||||
extension = res[4]
|
|
||||||
info.IsSeries = true
|
|
||||||
return true
|
|
||||||
}else{
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _,v := range seriesMatcher {
|
|
||||||
if find(v) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if info.IsSeries {
|
|
||||||
newFilename, success := themoviedb(info.Name, info.Season, int(episode), extension, config.apikey, info.IncludeSeriesName, 0)
|
|
||||||
if success {
|
|
||||||
linkFile(config.src + "/" + filename, config.dst + "/" + newFilename)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res := moviesMatcher.FindStringSubmatch(filename)
|
|
||||||
if len(res) == 4{
|
|
||||||
for _,v := range res{
|
|
||||||
fmt.Println(v)
|
|
||||||
}
|
|
||||||
fmt.Println("")
|
|
||||||
|
|
||||||
year,_ := strconv.ParseInt(res[2], 10, 64)
|
|
||||||
|
|
||||||
if (year < 1800) || (year > 2100){
|
|
||||||
year = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
newFilename, success := themoviedb(res[1], info.Season, int(episode), res[3], config.apikey, info.IncludeSeriesName, int(year))
|
|
||||||
if success {
|
|
||||||
linkFile(config.src + "/" + filename, config.dst + "/" + newFilename)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func printerr(err error){
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user