From 242c74b827c77f9a5b799d7cdac83900653cc6c2 Mon Sep 17 00:00:00 2001 From: bel Date: Tue, 3 Jun 2025 23:38:12 -0600 Subject: [PATCH] wip --- main.go | 143 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 104 insertions(+), 39 deletions(-) diff --git a/main.go b/main.go index 8ad7a27..edaeb8e 100644 --- a/main.go +++ b/main.go @@ -2,12 +2,14 @@ package main import ( "database/sql" - "fmt" - "log" + "fmt" "io" "io/ioutil" + "log" "os" "path" + "slices" + "strings" _ "modernc.org/sqlite" ) @@ -21,17 +23,19 @@ func main() { data := os.Args[1] fromU := os.Args[2] toU := os.Args[3] - _ = toU + _ = toU workd, err := ioutil.TempDir(os.TempDir(), "jellyfin-user-clone.*") if err != nil { panic(err) } - if err := cp(path.Join(data, jellyDB), path.Join(workd, jellyDB)); err != nil { - panic(err) - } else if err := cp(path.Join(data, libraryDB), path.Join(workd, libraryDB)); err != nil { - panic(err) + { + if err := cp(path.Join(data, jellyDB), path.Join(workd, jellyDB)); err != nil { + panic(err) + } else if err := cp(path.Join(data, libraryDB), path.Join(workd, libraryDB)); err != nil { + panic(err) + } } jellyfinDB, err := sql.Open("sqlite", path.Join(workd, jellyDB)) @@ -40,17 +44,65 @@ func main() { } defer jellyfinDB.Close() - fromUUID, err := SelectOne[string](jellyfinDB, `SELECT Id FROM Users WHERE Username = $1`, fromU) - if err != nil { - panic(err) - } + fromUUID, err := SelectOne[string](jellyfinDB, `SELECT Id FROM Users WHERE Username = $1`, fromU) + if err != nil { + panic(err) + } + fromID, err := SelectOne[int](jellyfinDB, `SELECT InternalId FROM Users WHERE Id = $1`, fromUUID) + if err != nil { + panic(err) + } + log.Println(fromU, fromUUID, fromID) - fromID, err := SelectOne[int](jellyfinDB, `SELECT InternalId FROM Users WHERE Id = $1`, fromUUID) - if err != nil { - panic(err) - } + if n, err := SelectOne[int](jellyfinDB, `SELECT COUNT(*) FROM Users WHERE Username = $1`, toU); err != nil { + panic(err) + } else if n == 1 { + } else if err := Exec(jellyfinDB, `INSERT INTO Users () SELECT * FROM Users WHERE Id = $1`, fromUUID); err != nil { + panic(err) + } - log.Println(fromU, fromUUID, fromID) + panic("not impl get toU, toUUID") + + tables, err := Tables(jellyfinDB) + if err != nil { + panic(err) + } + + for _, table := range tables { + columns, err := Columns(jellyfinDB, table) + if err != nil { + panic(err) + } + log.Println(table, columns) + + userColumns := slices.DeleteFunc(slices.Clone(columns), func(s string) bool { + return !slices.Contains([]string{ + "user", + "userid", + }, strings.ToLower(s)) + }) + if len(userColumns) == 0 { + continue + } + + for _, column := range userColumns { + if n, err := SelectOne[int](jellyfinDB, fmt.Sprintf(`SELECT COUNT(*) FROM %q WHERE %q = $1`, table, column), fromID); err != nil { + panic(err) + } else if n > 0 { + notThisColumn := strings.Join(slices.DeleteFunc(slices.Clone(columns), func(s string) bool { return s == column }), ", ") + if err := Exec(jellyfinDB, fmt.Sprintf(`INSERT INTO %q (%q, %s) SELECT $2, %s FROM %q WHERE %q = $1`, table, column, notThisColumn, notThisColumn, table, column), fromID, toID); err != nil { + panic(err) + } + } else if n, err := SelectOne[int](jellyfinDB, fmt.Sprintf(`SELECT COUNT(*) FROM %q WHERE %q = $1`, table, column), fromUUID); err != nil { + panic(err) + } else if n > 0 { + panic("not impl: col is uuid") + } + } + + log.Println(table, userColumns) + panic("not impl") + } } func cp(from, to string) error { @@ -70,36 +122,49 @@ func cp(from, to string) error { return err } +func Tables(db *sql.DB) ([]string, error) { + return Select[string](jellyfinDB, `SELECT name FROM sqlite_schema WHERE type = 'table' AND name NOT LIKE 'sqlite_%'`) +} + +func Columns(db *sql.DB, table string) ([]string, error) { + return Select[string](jellyfinDB, `SELECT name FROM PRAGMA_TABLE_INFO($1)`, table) +} + +func Exec(db *sql.DB, q string, args ...any) error { + _, err := db.Exec(q, args...) + return err +} + func SelectOne[T any](db *sql.DB, q string, args ...any) (T, error) { - var some T + var some T - results, err := Select[T](db, q, args...) - if err != nil { - return some, err - } + results, err := Select[T](db, q, args...) + if err != nil { + return some, err + } - if len(results) != 1 { - return some, fmt.Errorf("expected 1 result but got %d (%+v)", len(results), results) - } + if len(results) != 1 { + return some, fmt.Errorf("expected 1 result but got %d (%+v)", len(results), results) + } - return results[0], nil + return results[0], nil } func Select[T any](db *sql.DB, q string, args ...any) ([]T, error) { - rows, err := db.Query(q, args...) - if err != nil { - return nil, err - } - defer rows.Close() + rows, err := db.Query(q, args...) + if err != nil { + return nil, err + } + defer rows.Close() - results := []T{} - for rows.Next() { - var some T - if err := rows.Scan(&some); err != nil { - return nil, err - } - results = append(results, some) - } + results := []T{} + for rows.Next() { + var some T + if err := rows.Scan(&some); err != nil { + return nil, err + } + results = append(results, some) + } - return results, rows.Err() + return results, rows.Err() }