forked from opensource-f2f/open-podcasts
/
track.go
101 lines (87 loc) · 2.64 KB
/
track.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
package advanced_ui
import (
"fmt"
"github.com/faiface/beep"
"github.com/faiface/beep/mp3"
"github.com/faiface/beep/speaker"
"github.com/linuxsuren/http-downloader/pkg/net"
playio "github.com/linuxsuren/open-podcasts/cli/pkg/io"
"github.com/linuxsuren/open-podcasts/cli/pkg/rss"
"github.com/linuxsuren/open-podcasts/cli/pkg/ui"
"github.com/linuxsuren/open-podcasts/cli/pkg/util"
"github.com/spf13/viper"
"io"
"os"
"path"
"time"
)
type TrackAudioPanel struct {
ui.AudioPlayer
audioUID string
}
func NewTrackAudioPanel(episode rss.Episode) (panel *TrackAudioPanel, err error) {
_ = loadConfig()
var buffer io.Reader
if buffer, err = playWithLocalCache(episode.AudioLink); err == nil {
var streamer beep.StreamSeekCloser
var format beep.Format
streamer, format, err = mp3.Decode(playio.SeekerWithoutCloser(buffer))
if err != nil {
return
}
speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/30))
return &TrackAudioPanel{
AudioPlayer: ui.NewAudioPanel(format.SampleRate, streamer, episode.Title),
audioUID: episode.UID,
}, nil
}
return
}
func LoadAudioFile(rssURL string) (audioCacheFile string, err error) {
cacheDir := os.ExpandEnv("$HOME/.config/goplay/cache")
_ = os.MkdirAll(cacheDir, 0751)
audioCacheFile = path.Join(cacheDir, fmt.Sprintf("%s.audio", util.HashCodeAsString(rssURL)))
if _, err = os.Stat(audioCacheFile); err != nil {
err = net.DownloadFileWithMultipleThread(rssURL, audioCacheFile, 4, true)
}
return
}
func saveOrGetCache(rssURL string) (reader io.Reader, err error) {
var audioCacheFile string
if audioCacheFile, err = LoadAudioFile(rssURL); err == nil {
reader, err = os.Open(audioCacheFile)
}
return
}
func playWithLocalCache(trackURL string) (reader io.Reader, err error) {
reader, err = saveOrGetCache(trackURL)
return
}
func loadConfig() (err error) {
viper.SetConfigName("goplay")
viper.SetConfigType("yaml")
viper.AddConfigPath("$HOME/.config")
viper.AddConfigPath(".")
if err = viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// Config file not found; ignore error if desired
err = nil
} else {
err = fmt.Errorf("failed to load config: %s, error: %v", os.ExpandEnv("$HOME/.config/goplay.yaml"), err)
}
}
return
}
// Start starts to play and try to seek the last position
func (t *TrackAudioPanel) Start() error {
t.Play()
if position := viper.GetInt(t.audioUID); position > 0 {
return t.Seek(position)
}
return nil
}
// Stop stops the audio player
func (t *TrackAudioPanel) Stop() {
viper.Set(t.audioUID, t.Position())
_ = viper.WriteConfigAs(os.ExpandEnv("$HOME/.config/goplay.yaml")) // TODO print a warning log
}