first commit
This commit is contained in:
commit
f621612340
283
main.go
Normal file
283
main.go
Normal file
@ -0,0 +1,283 @@
|
||||
package main
|
||||
|
||||
import ("regexp"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"path/filepath"
|
||||
"io/fs"
|
||||
"os"
|
||||
"github.com/fsnotify/fsnotify")
|
||||
|
||||
type SeasonInfo struct {
|
||||
Name string
|
||||
Season int
|
||||
IsSeries bool
|
||||
IncludeSeriesName bool
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
apikey string
|
||||
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
|
||||
var moviesMatcher *regexp.Regexp
|
||||
|
||||
func getEnvString(key string)(val string, ok bool) {
|
||||
val, ok = os.LookupEnv(key)
|
||||
if ok {
|
||||
val = strings.TrimSuffix(val, "/")
|
||||
} else {
|
||||
fmt.Printf("Environment variable missing: %s\n", key)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
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