From 80a8577f962f563e31d45fbbbaac28d28ca6cbf9 Mon Sep 17 00:00:00 2001 From: Bel LaPointe <153096461+breel-render@users.noreply.github.com> Date: Wed, 4 Jun 2025 10:35:44 -0600 Subject: [PATCH] o that is kinda runnin --- main.go | 60 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/main.go b/main.go index 7c1dd11..0b133db 100644 --- a/main.go +++ b/main.go @@ -25,7 +25,6 @@ func main() { data := os.Args[1] fromU := os.Args[2] toU := os.Args[3] - _ = toU workd, err := ioutil.TempDir(os.TempDir(), "jellyfin-user-clone.*") if err != nil { @@ -46,6 +45,12 @@ func main() { } defer jellyfinDB.Close() + libraryDB, err := sql.Open("sqlite", path.Join(workd, libDB)) + if err != nil { + log.Fatalf("%v", err) + } + defer libraryDB.Close() + fromUUID, err := SelectOne[string](jellyfinDB, `SELECT Id FROM Users WHERE Username = $1`, fromU) if err != nil { log.Fatalf("%v", err) @@ -58,13 +63,21 @@ func main() { if n, err := SelectOne[int](jellyfinDB, `SELECT COUNT(*) FROM Users WHERE Username = $1`, toU); err != nil { log.Fatalf("%v", err) - } else if n == 1 { - } else if err := CloneForColumn(jellyfinDB, `Users`, `Username`, fromU, toU, `InternalId`); err != nil { // TODO how is InternalId maintained? Chance? - log.Fatalf("%v", err) - } else if n, err := SelectOne[int](jellyfinDB, `SELECT COUNT(*) FROM Users WHERE Username = $1`, toU); err != nil { - log.Fatalf("%v", err) } else if n != 1 { - log.Fatalf("still no username=%q after insert", toU) + nextID, err := SelectOne[int](libraryDB, `SELECT COALESCE(MAX(userId), 0)+1 FROM UserDatas`) + if err != nil { + log.Fatalf("failed to get max userid ever: %v", err) + } + + if err := CloneForColumn(jellyfinDB, `Users`, `Username`, fromU, toU, map[string]any{`InternalId`: nextID}); err != nil { + log.Fatalf("%v", err) + } + + if n, err := SelectOne[int](jellyfinDB, `SELECT COUNT(*) FROM Users WHERE Username = $1 AND InternalId = $2`, toU, nextID); err != nil { + log.Fatalf("%v", err) + } else if n != 1 { + log.Fatalf("still no username=%q after insert", toU) + } } toUUID, err := SelectOne[string](jellyfinDB, `SELECT Id FROM Users WHERE Username = $1`, toU) @@ -77,12 +90,6 @@ func main() { } log.Println(toU, toUUID, toID) - libraryDB, err := sql.Open("sqlite", path.Join(workd, libDB)) - if err != nil { - log.Fatalf("%v", err) - } - defer libraryDB.Close() - for _, db := range []*sql.DB{jellyfinDB, libraryDB} { tables, err := Tables(db) if err != nil { @@ -111,13 +118,13 @@ func main() { if n, err := SelectOne[int](db, fmt.Sprintf(`SELECT COUNT(*) FROM %q WHERE %q = $1`, table, column), fromID); err != nil { log.Fatalf("%v", err) } else if n > 0 { - if err := CloneForColumn(db, table, column, fromID, toID); err != nil { + if err := CloneForColumn(db, table, column, fromID, toID, nil); err != nil { log.Fatalf("%v", err) } } else if n, err := SelectOne[int](db, fmt.Sprintf(`SELECT COUNT(*) FROM %q WHERE %q = $1`, table, column), fromUUID); err != nil { log.Fatalf("%v", err) } else if n > 0 { - if err := CloneForColumn(db, table, column, fromUUID, toUUID); err != nil { + if err := CloneForColumn(db, table, column, fromUUID, toUUID, nil); err != nil { log.Fatalf("%v", err) } } @@ -126,7 +133,7 @@ func main() { } } -func CloneForColumn[T any](db *sql.DB, table, column string, from, to T, extraUniques ...string) error { +func CloneForColumn[T any](db *sql.DB, table, column string, from, to T, fixed map[string]any) error { columns, err := Columns(db, table) if err != nil { return err @@ -143,8 +150,14 @@ func CloneForColumn[T any](db *sql.DB, table, column string, from, to T, extraUn log.Printf("unique text columns %+v, unique int columns %+v", uniqueTextColumns, uniqueIntColumns) + extraUniques := []string{} + for k := range fixed { + extraUniques = append(extraUniques, k) + } omit := append(append(extraUniques, uniqueIntColumns...), uniqueTextColumns...) - notTheseColumns := slices.DeleteFunc(slices.Clone(columns), func(s string) bool { return s == column || slices.Contains(omit, s) }) + notTheseColumns := slices.DeleteFunc(slices.Clone(columns), func(s string) bool { + return s == column || slices.Contains(omit, s) || slices.Contains(extraUniques, s) + }) for i := range notTheseColumns { notTheseColumns[i] = fmt.Sprintf("%q", notTheseColumns[i]) } @@ -153,7 +166,9 @@ func CloneForColumn[T any](db *sql.DB, table, column string, from, to T, extraUn if err != nil { return err } - uuidGenColumns := slices.DeleteFunc(notNullTextColumns, func(s string) bool { return s == column || !slices.Contains(omit, s) }) + uuidGenColumns := slices.DeleteFunc(notNullTextColumns, func(s string) bool { + return s == column || !slices.Contains(omit, s) || slices.Contains(extraUniques, s) + }) for i := range uuidGenColumns { uuidGenColumns[i] = fmt.Sprintf("%q", uuidGenColumns[i]) } @@ -162,7 +177,9 @@ func CloneForColumn[T any](db *sql.DB, table, column string, from, to T, extraUn if err != nil { return err } - incrGenColumns := slices.DeleteFunc(notNullIntColumns, func(s string) bool { return !slices.Contains(omit, s) }) + incrGenColumns := slices.DeleteFunc(notNullIntColumns, func(s string) bool { + return s == column || !slices.Contains(omit, s) || slices.Contains(extraUniques, s) + }) for i := range incrGenColumns { incrGenColumns[i] = fmt.Sprintf("%q", incrGenColumns[i]) } @@ -180,11 +197,14 @@ func CloneForColumn[T any](db *sql.DB, table, column string, from, to T, extraUn for _, arg := range args { values = append(values, *(arg.(*any))) } + for _, k := range extraUniques { + values = append(values, fixed[k]) + } values = append(values, to) q := fmt.Sprintf( `INSERT INTO %q (%s, %q) VALUES (%s %s)`, - table, strings.Join(append(incrGenColumns, append(uuidGenColumns, notTheseColumns...)...), ", "), column, + table, strings.Join(append(append(incrGenColumns, append(uuidGenColumns, notTheseColumns...)...), extraUniques...), ", "), column, selectMaxes, strings.Join(slices.Repeat([]string{"?"}, len(values)), ", "), )