first commit

This commit is contained in:
Roy Olav Purser 2021-03-23 09:48:02 +01:00
commit f621612340
No known key found for this signature in database
GPG Key ID: 0BA77797F072BC52
2 changed files with 286 additions and 0 deletions

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module git.purser.it/roypur/envconf
go 1.16

283
main.go Normal file
View 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)
}
}