wip
parent
2cccb891bc
commit
242c74b827
143
main.go
143
main.go
|
|
@ -2,12 +2,14 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
_ "modernc.org/sqlite"
|
_ "modernc.org/sqlite"
|
||||||
)
|
)
|
||||||
|
|
@ -21,17 +23,19 @@ func main() {
|
||||||
data := os.Args[1]
|
data := os.Args[1]
|
||||||
fromU := os.Args[2]
|
fromU := os.Args[2]
|
||||||
toU := os.Args[3]
|
toU := os.Args[3]
|
||||||
_ = toU
|
_ = toU
|
||||||
|
|
||||||
workd, err := ioutil.TempDir(os.TempDir(), "jellyfin-user-clone.*")
|
workd, err := ioutil.TempDir(os.TempDir(), "jellyfin-user-clone.*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cp(path.Join(data, jellyDB), path.Join(workd, jellyDB)); err != nil {
|
{
|
||||||
panic(err)
|
if err := cp(path.Join(data, jellyDB), path.Join(workd, jellyDB)); err != nil {
|
||||||
} else if err := cp(path.Join(data, libraryDB), path.Join(workd, libraryDB)); err != nil {
|
panic(err)
|
||||||
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))
|
jellyfinDB, err := sql.Open("sqlite", path.Join(workd, jellyDB))
|
||||||
|
|
@ -40,17 +44,65 @@ func main() {
|
||||||
}
|
}
|
||||||
defer jellyfinDB.Close()
|
defer jellyfinDB.Close()
|
||||||
|
|
||||||
fromUUID, err := SelectOne[string](jellyfinDB, `SELECT Id FROM Users WHERE Username = $1`, fromU)
|
fromUUID, err := SelectOne[string](jellyfinDB, `SELECT Id FROM Users WHERE Username = $1`, fromU)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
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 n, err := SelectOne[int](jellyfinDB, `SELECT COUNT(*) FROM Users WHERE Username = $1`, toU); err != nil {
|
||||||
if err != nil {
|
panic(err)
|
||||||
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 {
|
func cp(from, to string) error {
|
||||||
|
|
@ -70,36 +122,49 @@ func cp(from, to string) error {
|
||||||
return err
|
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) {
|
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...)
|
results, err := Select[T](db, q, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return some, err
|
return some, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(results) != 1 {
|
if len(results) != 1 {
|
||||||
return some, fmt.Errorf("expected 1 result but got %d (%+v)", len(results), results)
|
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) {
|
func Select[T any](db *sql.DB, q string, args ...any) ([]T, error) {
|
||||||
rows, err := db.Query(q, args...)
|
rows, err := db.Query(q, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
results := []T{}
|
results := []T{}
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var some T
|
var some T
|
||||||
if err := rows.Scan(&some); err != nil {
|
if err := rows.Scan(&some); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
results = append(results, some)
|
results = append(results, some)
|
||||||
}
|
}
|
||||||
|
|
||||||
return results, rows.Err()
|
return results, rows.Err()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue