Files
BiliDown/internal/util/db.go
T
yw1573 eb662a8b66 feat: add FFmpeg status check and shutdown button
- FFmpeg check no longer blocks server startup
- Add /api/checkFFmpeg endpoint to query FFmpeg availability
- Add /api/shutdown endpoint to gracefully stop the server
- Add FFmpeg status indicator in web header
- Add shutdown button in web interface
- Move static files output to cmd/bilidown/static for embedding
- Update .gitignore to exclude cmd/bilidown/static

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 15:27:55 +08:00

133 lines
2.7 KiB
Go

package util
import (
"database/sql"
"errors"
"fmt"
"log"
"strings"
"sync"
)
func CreateLog(db *sql.DB, content string) error {
SqliteLock.Lock()
_, err := db.Exec(`INSERT INTO "log" ("content") VALUES (?)`, content)
SqliteLock.Unlock()
return err
}
func GetFields(db *sql.DB, names ...string) (map[string]string, error) {
if len(names) == 0 {
return nil, nil
}
placeholders := make([]string, len(names))
for i := 0; i < len(names); i++ {
placeholders[i] = "?"
}
query := fmt.Sprintf(`SELECT "name", "value" FROM "field" WHERE "name" IN (%s)`, strings.Join(placeholders, ","))
values := make([]interface{}, len(names))
for i := 0; i < len(names); i++ {
values[i] = names[i]
}
SqliteLock.Lock()
row, err := db.Query(query, values...)
SqliteLock.Unlock()
if err != nil {
return nil, err
}
defer row.Close()
var name, value string
fields := make(map[string]string)
for row.Next() {
if err := row.Scan(&name, &value); err != nil {
return nil, err
}
fields[name] = value
}
return fields, nil
}
func SaveFields(db *sql.DB, data [][2]string) error {
if len(data) == 0 {
return nil
}
tx, err := db.Begin()
if err != nil {
return err
}
defer func() {
if err != nil {
tx.Rollback()
} else {
tx.Commit()
}
}()
stmt, err := tx.Prepare(`INSERT OR REPLACE INTO "field" ("name", "value") VALUES (?, ?)`)
if err != nil {
return err
}
defer stmt.Close()
for _, d := range data {
SqliteLock.Lock()
_, err = stmt.Exec(d[0], d[1])
SqliteLock.Unlock()
if err != nil {
return err
}
}
return nil
}
// GetCurrentFolder 获取数据库中的下载保存路径,如果不存在则将默认路径保存到数据库
func GetCurrentFolder(db *sql.DB) (string, error) {
var folder string
SqliteLock.Lock()
err := db.QueryRow(`SELECT "value" FROM "field" WHERE "name" = 'download_folder'`).Scan(&folder)
SqliteLock.Unlock()
if err != nil && err == sql.ErrNoRows {
folder, err = GetDefaultDownloadFolder()
if err != nil {
return "", err
}
err = SaveDownloadFolder(db, folder)
if err != nil {
return "", err
}
return folder, nil
}
return folder, err
}
// SaveDownloadFolder 保存下载路径(不自动创建目录)
func SaveDownloadFolder(db *sql.DB, downloadFolder string) error {
SqliteLock.Lock()
_, err := db.Exec(`INSERT OR REPLACE INTO "field" ("name", "value") VALUES ('download_folder', ?)`, downloadFolder)
SqliteLock.Unlock()
return err
}
var SqliteLock sync.Mutex
func MustGetDB(path ...string) *sql.DB {
pathStr := ""
if len(path) == 0 {
pathStr = "./data.db"
} else if len(path) > 1 {
log.Fatalln(errors.New("len(path) <= 1"))
} else {
pathStr = path[0]
}
db, err := sql.Open("sqlite", pathStr)
if err != nil {
log.Fatalln("sql.Open:", err)
}
return db
}