mirror of
https://github.com/sbondCo/Watcharr.git
synced 2026-06-23 04:10:07 +00:00
ac8d8769af
Fixing watcharr import from watcharr export not importing users games. Also works if user edits the table in import/process to change the type of something to a game (and multi results works too). Added warning message if user tries importing a watcharr export that has games when `!serverFeatures.games`
310 lines
16 KiB
Go
310 lines
16 KiB
Go
// Watcharr is licensed under the GPLv3 license.
|
||
|
||
package main
|
||
|
||
import (
|
||
"bufio"
|
||
"fmt"
|
||
"log"
|
||
"log/slog"
|
||
"net/http"
|
||
"net/http/httputil"
|
||
"os"
|
||
"os/exec"
|
||
"path"
|
||
"time"
|
||
|
||
_ "embed"
|
||
|
||
"github.com/gin-contrib/cors"
|
||
"github.com/gin-gonic/gin"
|
||
"github.com/gin-gonic/gin/binding"
|
||
"github.com/go-playground/validator/v10"
|
||
"github.com/joho/godotenv"
|
||
"github.com/sbondCo/Watcharr/config"
|
||
"github.com/sbondCo/Watcharr/database"
|
||
"github.com/sbondCo/Watcharr/database/entity"
|
||
"github.com/sbondCo/Watcharr/domain"
|
||
"github.com/sbondCo/Watcharr/feature/activity"
|
||
"github.com/sbondCo/Watcharr/feature/arr"
|
||
"github.com/sbondCo/Watcharr/feature/auth"
|
||
"github.com/sbondCo/Watcharr/feature/content"
|
||
"github.com/sbondCo/Watcharr/feature/discover"
|
||
"github.com/sbondCo/Watcharr/feature/feature"
|
||
"github.com/sbondCo/Watcharr/feature/follow"
|
||
"github.com/sbondCo/Watcharr/feature/game"
|
||
"github.com/sbondCo/Watcharr/feature/imprt"
|
||
"github.com/sbondCo/Watcharr/feature/jellyfin"
|
||
"github.com/sbondCo/Watcharr/feature/job"
|
||
"github.com/sbondCo/Watcharr/feature/plex"
|
||
"github.com/sbondCo/Watcharr/feature/profile"
|
||
"github.com/sbondCo/Watcharr/feature/search"
|
||
"github.com/sbondCo/Watcharr/feature/server"
|
||
"github.com/sbondCo/Watcharr/feature/setup"
|
||
"github.com/sbondCo/Watcharr/feature/tag"
|
||
"github.com/sbondCo/Watcharr/feature/task"
|
||
"github.com/sbondCo/Watcharr/feature/user"
|
||
"github.com/sbondCo/Watcharr/feature/watched"
|
||
"github.com/sbondCo/Watcharr/feature/watched/episode"
|
||
"github.com/sbondCo/Watcharr/feature/watched/season"
|
||
"github.com/sbondCo/Watcharr/logging"
|
||
"github.com/sbondCo/Watcharr/media/tmdb"
|
||
"github.com/sbondCo/Watcharr/router"
|
||
taskl "github.com/sbondCo/Watcharr/task"
|
||
)
|
||
|
||
//go:embed VERSION
|
||
var version string
|
||
|
||
func main() {
|
||
err := godotenv.Load()
|
||
if err != nil {
|
||
// Do not fail if file does not exist
|
||
if !os.IsNotExist(err) {
|
||
log.Fatal("Failed to load vars from .env file:", err)
|
||
}
|
||
}
|
||
|
||
multiw := logging.Setup(path.Join(config.DataPath, "watcharr.log"))
|
||
slog.Info("Watcharr Starting", "version", version)
|
||
fmt.Printf(`
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣀⣀⣀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣴⣶⣿⠿⠛⠛⠛⠻⠿⣿⣿⣿⣿⣿⣶⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣿⣷⣻⠶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⠂⠀⢀⣠⣾⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⢀⣤⣾⣿⣿⣿⣿⣿⣿⡿⣽⣻⣳⢎⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⢡⠂⠄⣢⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⡷⣯⡞⣝⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⠀⠁⡐⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣳⣟⡾⣹⢎⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠂⣼⣿⣿⣿⣿⡿⠿⠛⠋⠉⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠛⠻⠿⣿⣿⣿⣿⣿⡿⣾⣝⣧⢻⡜⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢂⠐⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⠂⢸⣿⡿⠟⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠻⠿⣿⣳⢯⣞⡳⣎⠅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⢈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⠁⠚⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠛⢯⡞⣵⣋⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠱⣍⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⡞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡄⢀⣾⡇⠀⣾⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⠁⣾⣿⡇⢰⣿⣿⠀⠀⣆⠀⠀⠀⠀⢰⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⡀⠀⠀⣼⡏⢰⣿⣿⠇⣾⣿⣿⡆⠀⣿⠀⠀⠀⠀⢸⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠈⡇⠀⠀⠀⠀⠀⠀⠀⠀⠰⠃⠀⠒⠛⠃⠚⠿⣿⢰⣿⣿⣿⡇⣤⣿⣤⣶⣦⣀⢼⣿⣧⠀⢰⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⢠⣶⢰⣿⣿⣿⣧⡹⢓⣾⣾⣿⣿⣿⣧⣿⣿⣿⣿⣋⣁⣀⣀⣀⣁⠘⠃⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣾⡟⢋⠁⡀⠀⠉⠙⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠱⣚⣭⡿⢿⣿⣷⣦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⡄⢠⣆⠀⠀⠀⠀⣿⣏⡀⣾⠀⠀⠀⠀⣰⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⣁⠀⢠⠀⠀⠉⠻⢿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⢠⢇⣾⣿⣷⠀⠀⠀⣿⣿⣿⣞⡓⠥⠬⣒⣷⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢿⠀⠀⠀⠀⠀⣦⠈⢳⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣾⣿⣿⣿⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣮⡢⢄⡀⠤⠾⢧⣦⣼⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡇⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣶⣶⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⣿⢁⣿⣿⠇⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣏⢾⡅⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠆⣼⣿⣿⣦⣾⠀⠀⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣷⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⢀⠰⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⣼⣻⢿⣯⡿⣟⠇⠀⡜⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠌⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⣰⢧⡟⡿⣾⡽⢏⣿⣾⣿⡌⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣛⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⢀⡰⣣⢻⡜⣯⢳⡝⣼⣿⣿⣿⣿⣆⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⢂⠐⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⢠⠎⡵⢣⢧⡹⣜⢣⣿⣿⣿⣿⣿⣿⣿⣷⡌⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠀⠀⠀⢀⠂⠔⡀⢂⠐⡀⢂⠠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠡⢚⠴⣉⠦⡑⢎⢣⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⣙⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⡩⠂⠀⠀⠀⠀⠀⣀⡔⢦⠃⢈⠐⡀⢂⠐⠠⠀⠄⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠁⠎⡰⢡⠙⡌⣸⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠟⠒⠌⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠛⠉⠀⠈⠀⠀⠀⠀⠀⣀⠶⡱⢎⢧⢋⠀⡐⢀⠂⠌⢀⠂⢀⠂⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠁⠢⠑⡨⣟⠿⠟⠟⠋⠋⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠛⠟⠛⠋⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢴⡩⢞⡱⢫⠜⡪⢅⠀⠂⠄⠂⠠⠀⠂⢀⠐⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢢⡙⢦⡙⡔⢣⠈⢀⠂⠈⡀⠐⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠂⠴⢉⠆⡁⠀⡀⠁⢀⠐⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠐⠡⠀⠀⠐⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠂⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||
|
||
██╗ ██╗ █████╗ ████████╗ ██████╗██╗ ██╗ █████╗ ██████╗ ██████╗
|
||
██║ ██║██╔══██╗╚══██╔══╝██╔════╝██║ ██║██╔══██╗██╔══██╗██╔══██╗
|
||
██║ █╗ ██║███████║ ██║ ██║ ███████║███████║██████╔╝██████╔╝
|
||
██║███╗██║██╔══██║ ██║ ██║ ██╔══██║██╔══██║██╔══██╗██╔══██╗
|
||
╚███╔███╔╝██║ ██║ ██║ ╚██████╗██║ ██║██║ ██║██║ ██║██║ ██║
|
||
╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
|
||
|
||
Layer:%s Starting now. Get ready!
|
||
|
||
Thank you for running my (spaghetti) code on your system.`+"\n\n", version)
|
||
|
||
// Ensure data dir exists
|
||
err = ensureDirExists(config.DataPath)
|
||
if err != nil {
|
||
log.Fatal("Failed to create data dir:", err)
|
||
}
|
||
|
||
cfg, err := config.Get()
|
||
if err != nil {
|
||
log.Fatal("Failed to get server config!", err)
|
||
}
|
||
|
||
logging.SetLevel(cfg.DEBUG)
|
||
|
||
// Check if we want to be in DEV or PROD
|
||
isProd := true
|
||
if os.Getenv("MODE") == "DEV" {
|
||
slog.Info("Starting in DEV mode")
|
||
isProd = false
|
||
}
|
||
|
||
db, err := database.New()
|
||
if err != nil {
|
||
log.Fatal("Failed to connect to database:", err)
|
||
}
|
||
|
||
if isProd {
|
||
go runUI()
|
||
gin.SetMode(gin.ReleaseMode)
|
||
}
|
||
gin.DefaultWriter = multiw
|
||
gine := gin.Default()
|
||
|
||
// Register our custom validators
|
||
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
|
||
v.RegisterValidation("validsearchtype", domain.ValidSearchType)
|
||
v.RegisterValidation("validdiscoverfilter", domain.ValidDiscoverFilter)
|
||
}
|
||
|
||
gine.Use(cors.New(cors.Config{
|
||
AllowOrigins: []string{"*"},
|
||
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
||
AllowHeaders: []string{
|
||
"Content-Type",
|
||
"Content-Length",
|
||
"Accept-Encoding",
|
||
"X-CSRF-Token",
|
||
"Authorization",
|
||
"accept",
|
||
"origin",
|
||
"Cache-Control",
|
||
"X-Requested-With",
|
||
},
|
||
ExposeHeaders: []string{
|
||
"Content-Length",
|
||
"watcharr-lastviewedseason-saved",
|
||
},
|
||
AllowCredentials: true,
|
||
MaxAge: 12 * time.Hour,
|
||
}))
|
||
if isProd {
|
||
// Proxy NoRoute requests to UI server
|
||
gine.NoRoute(func(c *gin.Context) {
|
||
director := func(req *http.Request) {
|
||
req.URL.Scheme = "http"
|
||
req.URL.Host = "127.0.0.1:3000"
|
||
}
|
||
proxy := &httputil.ReverseProxy{Director: director}
|
||
proxy.ServeHTTP(c.Writer, c.Request)
|
||
})
|
||
}
|
||
api := gine.Group("/api")
|
||
br := router.NewBaseRouter(db, api, cfg)
|
||
|
||
t := tmdb.NewTMDB(cfg.TMDB_KEY)
|
||
|
||
plexService := plex.NewService(cfg)
|
||
authService := auth.NewService(db, cfg, plexService)
|
||
authTrustedHeaderService := auth.NewTrustedHeaderService(db, cfg, authService)
|
||
contentService := content.NewService(db, t)
|
||
activityService := activity.NewService(db)
|
||
userService := user.NewService(db)
|
||
userManageService := user.NewManageService(db)
|
||
gameService := game.NewService(db, &br.Cfg.TWITCH, activityService)
|
||
watchedService := watched.NewService(db, contentService, gameService, activityService)
|
||
watchedSeasonService := season.NewService(db, activityService)
|
||
watchedEpisodeService := episode.NewService(
|
||
db,
|
||
watchedService,
|
||
watchedSeasonService,
|
||
contentService,
|
||
activityService,
|
||
userService)
|
||
jellyfinService := jellyfin.NewService(cfg)
|
||
jellyfinSyncService := jellyfin.NewSyncService(
|
||
cfg,
|
||
jellyfinService,
|
||
watchedService,
|
||
watchedSeasonService,
|
||
watchedEpisodeService,
|
||
activityService)
|
||
plexSyncService := plex.NewSyncService(
|
||
plexService,
|
||
watchedService,
|
||
watchedSeasonService,
|
||
watchedEpisodeService,
|
||
activityService)
|
||
featureService := feature.NewService(cfg)
|
||
profileService := profile.NewService(db)
|
||
followService := follow.NewService(db)
|
||
tagService := tag.NewService(db, watchedService)
|
||
searchService := search.NewService(db, br.Cfg, contentService, watchedService)
|
||
discoverService := discover.NewService(db, br.Cfg, contentService)
|
||
importService := imprt.NewService(
|
||
db,
|
||
watchedService,
|
||
watchedSeasonService,
|
||
watchedEpisodeService,
|
||
contentService,
|
||
activityService,
|
||
tagService,
|
||
searchService)
|
||
importTraktService := imprt.NewTraktService(importService)
|
||
|
||
auth.NewRouter(br, authService, authTrustedHeaderService).AddRoutes()
|
||
content.NewRouter(br, contentService, watchedService).AddRoutes()
|
||
watched.NewRouter(br, t, watchedService).AddRoutes()
|
||
season.NewRouter(br, watchedSeasonService).AddRoutes()
|
||
episode.NewRouter(br, watchedEpisodeService).AddRoutes()
|
||
activity.NewRouter(br, activityService).AddRoutes()
|
||
profile.NewRouter(br, profileService).AddRoutes()
|
||
jellyfin.NewRouter(br, jellyfinService, jellyfinSyncService).AddRoutes()
|
||
plex.NewRouter(br, plexSyncService).AddRoutes()
|
||
user.NewRouter(br, userService, userManageService).AddRoutes()
|
||
follow.NewRouter(br, followService).AddRoutes()
|
||
imprt.NewRouter(br, importService, importTraktService).AddRoutes()
|
||
server.NewRouter(br, plexService, authTrustedHeaderService, userManageService).AddRoutes()
|
||
feature.NewRouter(br, featureService).AddRoutes()
|
||
arr.NewRouter(br, contentService).AddRoutes()
|
||
job.NewRouter(br).AddRoutes()
|
||
task.NewRouter(br).AddRoutes()
|
||
tag.NewRouter(br, tagService).AddRoutes()
|
||
game.NewRouter(br, gameService, watchedService).AddRoutes()
|
||
search.NewRouter(br, searchService, watchedService).AddRoutes()
|
||
discover.NewRouter(br, discoverService, watchedService).AddRoutes()
|
||
|
||
// Only add setup routes if there are no users found in db.
|
||
var userCount int64
|
||
if uresp := db.Model(&entity.User{}).Count(&userCount); uresp.Error == nil {
|
||
if userCount != 0 {
|
||
slog.Debug("registered users found.. skipped creating setup routes.")
|
||
} else {
|
||
slog.Info("No users found.. creating setup routes.")
|
||
setup.NewRouter(br, authService).AddRoutes()
|
||
}
|
||
} else {
|
||
slog.Error("Failed to check if any users exist.. not registering setup routes",
|
||
"error", uresp.Error)
|
||
}
|
||
|
||
api.Static("/img", path.Join(config.DataPath, "img"))
|
||
|
||
go taskl.SetupTasks(cfg, db)
|
||
|
||
gine.Run("0.0.0.0:3080")
|
||
}
|
||
|
||
// Run UI server
|
||
func runUI() {
|
||
cmd := exec.Command("node", "ui/index.js")
|
||
cmdReader, err := cmd.StdoutPipe()
|
||
if err != nil {
|
||
log.Fatal("UI ERR @ get stdout read pipe: ", err)
|
||
}
|
||
scanner := bufio.NewScanner(cmdReader)
|
||
go func() {
|
||
for scanner.Scan() {
|
||
fmt.Println(scanner.Text())
|
||
}
|
||
}()
|
||
if err := cmd.Start(); err != nil {
|
||
log.Fatal("UI ERR @ command start: ", err)
|
||
}
|
||
if err := cmd.Wait(); err != nil {
|
||
log.Fatal("UI ERR @ command wait: ", err)
|
||
}
|
||
}
|
||
|
||
func ensureDirExists(dir string) error {
|
||
err := os.MkdirAll(dir, 0764)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|