-
Notifications
You must be signed in to change notification settings - Fork 17
/
instance.go
103 lines (86 loc) · 2.53 KB
/
instance.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package mpris
import (
"context"
"fmt"
"os"
"github.com/godbus/dbus/v5/introspect"
"github.com/godbus/dbus/v5"
"github.com/godbus/dbus/v5/prop"
"github.com/natsukagami/mpd-mpris/mpd"
"github.com/pkg/errors"
)
// Instance is an instance of mpd-mpris.
// It contains a connection to the MPD server and the DBus connection.
type Instance struct {
mpd *mpd.Client
dbus *dbus.Conn
props *prop.Properties
// interface implementations
root *MediaPlayer2
player *Player
name string
}
// Close ends the connection.
func (ins *Instance) Close() error {
if ins.mpd == nil {
return nil // already closed
}
if err := ins.dbus.Close(); err != nil {
return errors.WithStack(err)
}
if err := ins.mpd.Close(); err != nil {
return err
}
ins.mpd = nil
return nil
}
// Name returns the name of the instance.
func (ins *Instance) Name() string {
return ins.name
}
// NewInstance creates a new instance that takes care of the specified mpd.
func NewInstance(mpd *mpd.Client, opts ...Option) (ins *Instance, err error) {
ins = &Instance{
mpd: mpd,
name: fmt.Sprintf("org.mpris.MediaPlayer2.mpd.instance%d", os.Getpid()),
}
if ins.dbus, err = dbus.SessionBus(); err != nil {
return nil, errors.WithStack(err)
}
// Apply options
for _, opt := range opts {
opt(ins)
}
ins.root = &MediaPlayer2{Instance: ins}
ins.player = &Player{Instance: ins}
ins.player.createStatus()
ins.props = prop.New(ins.dbus, "/org/mpris/MediaPlayer2", map[string]map[string]*prop.Prop{
"org.mpris.MediaPlayer2": ins.root.properties(),
"org.mpris.MediaPlayer2.Player": ins.player.props,
})
return
}
// Start starts the instance. Blocking, so you should fire and forget ;)
func (ins *Instance) Start(ctx context.Context) error {
ins.dbus.Export(ins.root, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2")
ins.dbus.Export(ins.player, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player")
ins.dbus.Export(introspect.NewIntrospectable(ins.IntrospectNode()), "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Introspectable")
reply, err := ins.dbus.RequestName(ins.Name(), dbus.NameFlagReplaceExisting)
if err != nil || reply != dbus.RequestNameReplyPrimaryOwner {
return errors.WithStack(err)
}
// Set up a periodic updaters
go ins.mpd.Keepalive(ctx)
go ins.player.pollSeek(ctx)
// Set up a status updater
for {
if err := ins.mpd.Poll(ctx); errors.Is(err, context.Canceled) {
return nil
} else if err != nil {
return errors.Wrap(err, "cannot poll mpd")
}
if err := ins.player.update(); err != nil {
return err
}
}
}