Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: transcoding and player datastores and configuration
- Loading branch information
Showing
32 changed files
with
783 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
db/migration/20200310181627_add_transcoding_and_player_tables.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package migration | ||
|
||
import ( | ||
"database/sql" | ||
|
||
"github.com/pressly/goose" | ||
) | ||
|
||
func init() { | ||
goose.AddMigration(Up20200310181627, Down20200310181627) | ||
} | ||
|
||
func Up20200310181627(tx *sql.Tx) error { | ||
_, err := tx.Exec(` | ||
create table transcoding | ||
( | ||
id varchar(255) not null primary key, | ||
name varchar(255) not null, | ||
target_format varchar(255) not null, | ||
command varchar(255) default '' not null, | ||
default_bit_rate int default 192, | ||
unique (name), | ||
unique (target_format) | ||
); | ||
create table player | ||
( | ||
id varchar(255) not null primary key, | ||
name varchar not null, | ||
type varchar, | ||
user_name varchar not null, | ||
client varchar not null, | ||
ip_address varchar, | ||
last_seen timestamp, | ||
transcoding_id varchar, -- todo foreign key | ||
max_bit_rate int default 0, | ||
unique (name) | ||
); | ||
`) | ||
return err | ||
} | ||
|
||
func Down20200310181627(tx *sql.Tx) error { | ||
_, err := tx.Exec(` | ||
drop table transcoding; | ||
drop table player; | ||
`) | ||
return err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package engine | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/deluan/navidrome/log" | ||
"github.com/deluan/navidrome/model" | ||
"github.com/google/uuid" | ||
) | ||
|
||
type Players interface { | ||
Get(ctx context.Context, playerId string) (*model.Player, error) | ||
Register(ctx context.Context, id, client, typ, ip string) (*model.Player, error) | ||
} | ||
|
||
func NewPlayers(ds model.DataStore) Players { | ||
return &players{ds} | ||
} | ||
|
||
type players struct { | ||
ds model.DataStore | ||
} | ||
|
||
func (p *players) Register(ctx context.Context, id, client, typ, ip string) (*model.Player, error) { | ||
var plr *model.Player | ||
var err error | ||
userName := ctx.Value("username").(string) | ||
if id != "" { | ||
plr, err = p.ds.Player(ctx).Get(id) | ||
} | ||
if err != nil || id == "" { | ||
plr, err = p.ds.Player(ctx).FindByName(client, userName) | ||
if err == nil { | ||
log.Trace("Found player by name", "id", plr.ID, "client", client, "userName", userName) | ||
} else { | ||
r, _ := uuid.NewRandom() | ||
plr = &model.Player{ | ||
ID: r.String(), | ||
Name: fmt.Sprintf("%s (%s)", client, userName), | ||
UserName: userName, | ||
Client: client, | ||
} | ||
log.Trace("Create new player", "id", plr.ID, "client", client, "userName", userName) | ||
} | ||
} | ||
plr.LastSeen = time.Now() | ||
plr.Type = typ | ||
plr.IPAddress = ip | ||
err = p.ds.Player(ctx).Put(plr) | ||
return plr, err | ||
} | ||
|
||
func (p *players) Get(ctx context.Context, playerId string) (*model.Player, error) { | ||
return p.ds.Player(ctx).Get(playerId) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package engine | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"github.com/deluan/navidrome/log" | ||
"github.com/deluan/navidrome/model" | ||
"github.com/deluan/navidrome/persistence" | ||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
) | ||
|
||
var _ = Describe("Players", func() { | ||
var players Players | ||
var repo *mockPlayerRepository | ||
ctx := context.WithValue(log.NewContext(nil), "user", model.User{ID: "userid", UserName: "johndoe"}) | ||
ctx = context.WithValue(ctx, "username", "johndoe") | ||
var beforeRegister time.Time | ||
|
||
BeforeEach(func() { | ||
repo = &mockPlayerRepository{} | ||
ds := &persistence.MockDataStore{MockedPlayer: repo} | ||
players = NewPlayers(ds) | ||
beforeRegister = time.Now() | ||
}) | ||
|
||
Describe("Register", func() { | ||
It("creates a new player when no ID is specified", func() { | ||
p, err := players.Register(ctx, "", "client", "chrome", "1.2.3.4") | ||
Expect(err).ToNot(HaveOccurred()) | ||
Expect(p.ID).ToNot(BeEmpty()) | ||
Expect(p.LastSeen).To(BeTemporally(">=", beforeRegister)) | ||
Expect(p.Client).To(Equal("client")) | ||
Expect(p.UserName).To(Equal("johndoe")) | ||
Expect(p.Type).To(Equal("chrome")) | ||
Expect(repo.lastSaved).To(Equal(p)) | ||
}) | ||
|
||
It("creates a new player if it cannot find any matching player", func() { | ||
p, err := players.Register(ctx, "123", "client", "chrome", "1.2.3.4") | ||
Expect(err).ToNot(HaveOccurred()) | ||
Expect(p.ID).ToNot(BeEmpty()) | ||
Expect(p.LastSeen).To(BeTemporally(">=", beforeRegister)) | ||
Expect(repo.lastSaved).To(Equal(p)) | ||
}) | ||
|
||
It("finds players by ID", func() { | ||
plr := &model.Player{ID: "123", Name: "A Player", LastSeen: time.Time{}} | ||
repo.add(plr) | ||
p, err := players.Register(ctx, "123", "client", "chrome", "1.2.3.4") | ||
Expect(err).ToNot(HaveOccurred()) | ||
Expect(p.ID).To(Equal("123")) | ||
Expect(p.LastSeen).To(BeTemporally(">=", beforeRegister)) | ||
Expect(repo.lastSaved).To(Equal(p)) | ||
}) | ||
|
||
It("finds player by client and user names when ID is not found", func() { | ||
plr := &model.Player{ID: "123", Name: "A Player", Client: "client", UserName: "johndoe", LastSeen: time.Time{}} | ||
repo.add(plr) | ||
p, err := players.Register(ctx, "999", "client", "chrome", "1.2.3.4") | ||
Expect(err).ToNot(HaveOccurred()) | ||
Expect(p.ID).To(Equal("123")) | ||
Expect(p.LastSeen).To(BeTemporally(">=", beforeRegister)) | ||
Expect(repo.lastSaved).To(Equal(p)) | ||
}) | ||
|
||
It("finds player by client and user names when not ID is provided", func() { | ||
plr := &model.Player{ID: "123", Name: "A Player", Client: "client", UserName: "johndoe", LastSeen: time.Time{}} | ||
repo.add(plr) | ||
p, err := players.Register(ctx, "", "client", "chrome", "1.2.3.4") | ||
Expect(err).ToNot(HaveOccurred()) | ||
Expect(p.ID).To(Equal("123")) | ||
Expect(p.LastSeen).To(BeTemporally(">=", beforeRegister)) | ||
Expect(repo.lastSaved).To(Equal(p)) | ||
}) | ||
}) | ||
}) | ||
|
||
type mockPlayerRepository struct { | ||
model.PlayerRepository | ||
lastSaved *model.Player | ||
data map[string]model.Player | ||
} | ||
|
||
func (m *mockPlayerRepository) add(p *model.Player) { | ||
if m.data == nil { | ||
m.data = make(map[string]model.Player) | ||
} | ||
m.data[p.ID] = *p | ||
} | ||
|
||
func (m *mockPlayerRepository) Get(id string) (*model.Player, error) { | ||
if p, ok := m.data[id]; ok { | ||
return &p, nil | ||
} | ||
return nil, model.ErrNotFound | ||
} | ||
|
||
func (m *mockPlayerRepository) FindByName(client, userName string) (*model.Player, error) { | ||
for _, p := range m.data { | ||
if p.Client == client && p.UserName == userName { | ||
return &p, nil | ||
} | ||
} | ||
return nil, model.ErrNotFound | ||
} | ||
|
||
func (m *mockPlayerRepository) Put(p *model.Player) error { | ||
m.lastSaved = p | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,4 +18,5 @@ var Set = wire.NewSet( | |
NewMediaStreamer, | ||
transcoder.New, | ||
NewTranscodingCache, | ||
NewPlayers, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package model | ||
|
||
import ( | ||
"time" | ||
) | ||
|
||
type Player struct { | ||
ID string `json:"id" orm:"column(id)"` | ||
Name string `json:"name"` | ||
Type string `json:"type"` | ||
UserName string `json:"userName"` | ||
Client string `json:"client"` | ||
IPAddress string `json:"ipAddress"` | ||
LastSeen time.Time `json:"lastSeen"` | ||
TranscodingId string `json:"transcodingId"` | ||
MaxBitRate int `json:"maxBitRate"` | ||
} | ||
|
||
type Players []Player | ||
|
||
type PlayerRepository interface { | ||
Get(id string) (*Player, error) | ||
FindByName(client, userName string) (*Player, error) | ||
Put(p *Player) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package model | ||
|
||
type Transcoding struct { | ||
ID string `json:"id" orm:"column(id)"` | ||
Name string `json:"name"` | ||
TargetFormat string `json:"targetFormat"` | ||
Command string `json:"command"` | ||
DefaultBitRate int `json:"defaultBitRate"` | ||
} | ||
|
||
type Transcodings []Transcoding | ||
|
||
type TranscodingRepository interface { | ||
Put(*Transcoding) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.