mirror of
https://git.sr.ht/~joren/streamrip-go
synced 2026-06-17 15:05:39 +02:00
initial Go port of streamrip
This commit is contained in:
89
internal/store/sqlite.go
Normal file
89
internal/store/sqlite.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"sync"
|
||||
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
type SQLite struct {
|
||||
db *sql.DB
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func NewSQLite(path string) (*SQLite, error) {
|
||||
db, err := sql.Open("sqlite", path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := &SQLite{db: db}
|
||||
if err = s.init(); err != nil {
|
||||
_ = db.Close()
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *SQLite) init() error {
|
||||
queries := []string{
|
||||
`CREATE TABLE IF NOT EXISTS downloads (id TEXT PRIMARY KEY)`,
|
||||
`CREATE TABLE IF NOT EXISTS failed_downloads (
|
||||
source TEXT NOT NULL,
|
||||
media_type TEXT NOT NULL,
|
||||
id TEXT NOT NULL,
|
||||
PRIMARY KEY (source, media_type, id)
|
||||
)`,
|
||||
}
|
||||
|
||||
for _, q := range queries {
|
||||
if _, err := s.db.Exec(q); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SQLite) IsDownloaded(ctx context.Context, id string) (bool, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
var count int
|
||||
err := s.db.QueryRowContext(ctx, `SELECT COUNT(1) FROM downloads WHERE id = ?`, id).Scan(&count)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
func (s *SQLite) MarkDownloaded(ctx context.Context, id string) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
_, err := s.db.ExecContext(ctx, `INSERT OR IGNORE INTO downloads(id) VALUES (?)`, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *SQLite) MarkFailed(ctx context.Context, source, mediaType, id string) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
_, err := s.db.ExecContext(
|
||||
ctx,
|
||||
`INSERT OR IGNORE INTO failed_downloads(source, media_type, id) VALUES (?, ?, ?)`,
|
||||
source,
|
||||
mediaType,
|
||||
id,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *SQLite) Close() error {
|
||||
if s.db == nil {
|
||||
return nil
|
||||
}
|
||||
return s.db.Close()
|
||||
}
|
||||
42
internal/store/sqlite_test.go
Normal file
42
internal/store/sqlite_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSQLiteStore(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
path := filepath.Join(t.TempDir(), "test.db")
|
||||
|
||||
s, err := NewSQLite(path)
|
||||
if err != nil {
|
||||
t.Fatalf("NewSQLite() error = %v", err)
|
||||
}
|
||||
defer func() { _ = s.Close() }()
|
||||
|
||||
ok, err := s.IsDownloaded(ctx, "a")
|
||||
if err != nil {
|
||||
t.Fatalf("IsDownloaded() error = %v", err)
|
||||
}
|
||||
if ok {
|
||||
t.Fatalf("expected not downloaded")
|
||||
}
|
||||
|
||||
if err = s.MarkDownloaded(ctx, "a"); err != nil {
|
||||
t.Fatalf("MarkDownloaded() error = %v", err)
|
||||
}
|
||||
|
||||
ok, err = s.IsDownloaded(ctx, "a")
|
||||
if err != nil {
|
||||
t.Fatalf("IsDownloaded() error = %v", err)
|
||||
}
|
||||
if !ok {
|
||||
t.Fatalf("expected downloaded")
|
||||
}
|
||||
|
||||
if err = s.MarkFailed(ctx, "qobuz", "track", "1"); err != nil {
|
||||
t.Fatalf("MarkFailed() error = %v", err)
|
||||
}
|
||||
}
|
||||
32
internal/store/store.go
Normal file
32
internal/store/store.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package store
|
||||
|
||||
import "context"
|
||||
|
||||
type Database interface {
|
||||
IsDownloaded(ctx context.Context, id string) (bool, error)
|
||||
MarkDownloaded(ctx context.Context, id string) error
|
||||
MarkFailed(ctx context.Context, source, mediaType, id string) error
|
||||
Close() error
|
||||
}
|
||||
|
||||
type Dummy struct{}
|
||||
|
||||
func NewDummy() *Dummy {
|
||||
return &Dummy{}
|
||||
}
|
||||
|
||||
func (d *Dummy) IsDownloaded(context.Context, string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (d *Dummy) MarkDownloaded(context.Context, string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Dummy) MarkFailed(context.Context, string, string, string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Dummy) Close() error {
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user