node build fixed
This commit is contained in:
1
seanime-2.9.10/internal/mediaplayers/vlc/README.md
Normal file
1
seanime-2.9.10/internal/mediaplayers/vlc/README.md
Normal file
@@ -0,0 +1 @@
|
||||
Source code from [CedArtic/go-vlc-ctrl](https://github.com/CedArctic/go-vlc-ctrl), updated and modified for the purpose of this project.
|
||||
41
seanime-2.9.10/internal/mediaplayers/vlc/art.go
Normal file
41
seanime-2.9.10/internal/mediaplayers/vlc/art.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package vlc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Art fetches cover art based on a playlist item's ID. If no ID is provided, Art returns the current item's cover art.
|
||||
// Cover art is returned in the form of a byte array.
|
||||
func (vlc *VLC) Art(itemID ...int) (byteArr []byte, err error) {
|
||||
|
||||
// Check variadic arguments
|
||||
if len(itemID) > 1 {
|
||||
err = errors.New("please provide only up to one ID")
|
||||
return
|
||||
}
|
||||
|
||||
// Build request URL
|
||||
urlSegment := "/art"
|
||||
if len(itemID) == 1 {
|
||||
urlSegment = urlSegment + "?item=" + strconv.Itoa(itemID[0])
|
||||
}
|
||||
|
||||
// Make request
|
||||
var response string
|
||||
response, err = vlc.RequestMaker(urlSegment)
|
||||
|
||||
// Error Handling
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if response == "Error" {
|
||||
err = errors.New("no cover art available for item")
|
||||
return
|
||||
}
|
||||
|
||||
// Convert response to byte array
|
||||
byteArr = []byte(response)
|
||||
|
||||
return
|
||||
}
|
||||
39
seanime-2.9.10/internal/mediaplayers/vlc/browse.go
Normal file
39
seanime-2.9.10/internal/mediaplayers/vlc/browse.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package vlc
|
||||
|
||||
import "github.com/goccy/go-json"
|
||||
|
||||
// File struct represents a single item in the browsed directory. Can be a file or a dir
|
||||
type File struct {
|
||||
Type string `json:"type"` // file or dir
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
AccessTime uint `json:"access_time"`
|
||||
UID uint `json:"uid"`
|
||||
CreationTime uint `json:"creation_time"`
|
||||
GID uint `json:"gid"`
|
||||
ModificationTime uint `json:"modification_time"`
|
||||
Mode uint `json:"mode"`
|
||||
URI string `json:"uri"`
|
||||
Size uint `json:"size"`
|
||||
}
|
||||
|
||||
// ParseBrowse parses Browse() responses to []File
|
||||
func ParseBrowse(browseResponse string) (files []File, err error) {
|
||||
var temp struct {
|
||||
Files []File `json:"element"`
|
||||
}
|
||||
err = json.Unmarshal([]byte(browseResponse), &temp)
|
||||
files = temp.Files
|
||||
return
|
||||
}
|
||||
|
||||
// Browse returns a File array with the items of the provided directory URI
|
||||
func (vlc *VLC) Browse(uri string) (files []File, err error) {
|
||||
var response string
|
||||
response, err = vlc.RequestMaker("/requests/browse.json?uri=" + uri)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
files, err = ParseBrowse(response)
|
||||
return
|
||||
}
|
||||
39
seanime-2.9.10/internal/mediaplayers/vlc/playlist.go
Normal file
39
seanime-2.9.10/internal/mediaplayers/vlc/playlist.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package vlc
|
||||
|
||||
import "github.com/goccy/go-json"
|
||||
|
||||
// Node structure (node or leaf type) is the basic element of VLC's playlist tree representation.
|
||||
// Leafs are playlist items. Nodes are playlists or folders inside playlists.
|
||||
type Node struct {
|
||||
Ro string `json:"ro"`
|
||||
Type string `json:"type"` // node or leaf
|
||||
Name string `json:"name"`
|
||||
ID string `json:"id"`
|
||||
Duration int `json:"duration,omitempty"`
|
||||
URI string `json:"uri,omitempty"`
|
||||
Current string `json:"current,omitempty"`
|
||||
Children []Node `json:"children,omitempty"`
|
||||
}
|
||||
|
||||
// ParsePlaylist parses Playlist() responses to Node
|
||||
func ParsePlaylist(playlistResponse string) (playlist Node, err error) {
|
||||
err = json.Unmarshal([]byte(playlistResponse), &playlist)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Playlist returns a Node object that is the root node of VLC's Playlist tree
|
||||
// Playlist tree structure: Level 0 - Root Node (Type="node"), Level 1 - Playlists (Type="node"),
|
||||
// Level 2+: Playlist Items (Type="leaf") or Folder (Type="node")
|
||||
func (vlc *VLC) Playlist() (playlist Node, err error) {
|
||||
// Make response and check for errors
|
||||
response, err := vlc.RequestMaker("/requests/playlist.json")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Parse to node
|
||||
playlist, err = ParsePlaylist(response)
|
||||
return
|
||||
}
|
||||
66
seanime-2.9.10/internal/mediaplayers/vlc/start.go
Normal file
66
seanime-2.9.10/internal/mediaplayers/vlc/start.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package vlc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"seanime/internal/util"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (vlc *VLC) getExecutableName() string {
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
return "vlc.exe"
|
||||
case "linux":
|
||||
return "vlc"
|
||||
case "darwin":
|
||||
return "vlc"
|
||||
default:
|
||||
return "vlc"
|
||||
}
|
||||
}
|
||||
|
||||
func (vlc *VLC) GetExecutablePath() string {
|
||||
|
||||
if len(vlc.Path) > 0 {
|
||||
return vlc.Path
|
||||
}
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
return "C:\\Program Files\\VideoLAN\\VLC\\vlc.exe"
|
||||
case "linux":
|
||||
return "/usr/bin/vlc" // Default path for VLC on most Linux distributions
|
||||
case "darwin":
|
||||
return "/Applications/VLC.app/Contents/MacOS/VLC" // Default path for VLC on macOS
|
||||
default:
|
||||
return "C:\\Program Files\\VideoLAN\\VLC\\vlc.exe"
|
||||
}
|
||||
}
|
||||
|
||||
func (vlc *VLC) Start() error {
|
||||
|
||||
// If the path is empty, do not check if VLC is running
|
||||
if vlc.Path == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if VLC is already running
|
||||
name := vlc.getExecutableName()
|
||||
if util.ProgramIsRunning(name) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start VLC
|
||||
exe := vlc.GetExecutablePath()
|
||||
cmd := util.NewCmd(exe)
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
vlc.Logger.Error().Err(err).Msg("vlc: Error starting VLC")
|
||||
return fmt.Errorf("error starting VLC: %w", err)
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
return nil
|
||||
}
|
||||
390
seanime-2.9.10/internal/mediaplayers/vlc/status.go
Normal file
390
seanime-2.9.10/internal/mediaplayers/vlc/status.go
Normal file
@@ -0,0 +1,390 @@
|
||||
package vlc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/goccy/go-json"
|
||||
)
|
||||
|
||||
// Status contains information related to the VLC instance status. Use parseStatus to parse the response from a
|
||||
// status.go function.
|
||||
type Status struct {
|
||||
// TODO: The Status structure is still a work in progress
|
||||
Fullscreen bool `json:"fullscreen"`
|
||||
Stats Stats `json:"stats"`
|
||||
AspectRatio string `json:"aspectratio"`
|
||||
AudioDelay float64 `json:"audiodelay"`
|
||||
APIVersion uint `json:"apiversion"`
|
||||
CurrentPlID uint `json:"currentplid"`
|
||||
Time uint `json:"time"`
|
||||
Volume uint `json:"volume"`
|
||||
Length uint `json:"length"`
|
||||
Random bool `json:"random"`
|
||||
AudioFilters map[string]string `json:"audiofilters"`
|
||||
Rate float64 `json:"rate"`
|
||||
VideoEffects VideoEffects `json:"videoeffects"`
|
||||
State string `json:"state"`
|
||||
Loop bool `json:"loop"`
|
||||
Version string `json:"version"`
|
||||
Position float64 `json:"position"`
|
||||
Information Information `json:"information"`
|
||||
Repeat bool `json:"repeat"`
|
||||
SubtitleDelay float64 `json:"subtitledelay"`
|
||||
Equalizer []Equalizer `json:"equalizer"`
|
||||
}
|
||||
|
||||
// Stats contains certain statistics of a VLC instance. A Stats variable is included in Status
|
||||
type Stats struct {
|
||||
InputBitRate float64 `json:"inputbitrate"`
|
||||
SentBytes uint `json:"sentbytes"`
|
||||
LosABuffers uint `json:"lostabuffers"`
|
||||
AveragedEMuxBitrate float64 `json:"averagedemuxbitrate"`
|
||||
ReadPackets uint `json:"readpackets"`
|
||||
DemuxReadPackets uint `json:"demuxreadpackets"`
|
||||
LostPictures uint `json:"lostpictures"`
|
||||
DisplayedPictures uint `json:"displayedpictures"`
|
||||
SentPackets uint `json:"sentpackets"`
|
||||
DemuxReadBytes uint `json:"demuxreadbytes"`
|
||||
DemuxBitRate float64 `json:"demuxbitrate"`
|
||||
PlayedABuffers uint `json:"playedabuffers"`
|
||||
DemuxDiscontinuity uint `json:"demuxdiscontinuity"`
|
||||
DecodeAudio uint `json:"decodedaudio"`
|
||||
SendBitRate float64 `json:"sendbitrate"`
|
||||
ReadBytes uint `json:"readbytes"`
|
||||
AverageInputBitRate float64 `json:"averageinputbitrate"`
|
||||
DemuxCorrupted uint `json:"demuxcorrupted"`
|
||||
DecodedVideo uint `json:"decodedvideo"`
|
||||
}
|
||||
|
||||
// VideoEffects contains the current video effects configuration. A VideoEffects variable is included in Status
|
||||
type VideoEffects struct {
|
||||
Hue int `json:"hue"`
|
||||
Saturation int `json:"saturation"`
|
||||
Contrast int `json:"contrast"`
|
||||
Brightness int `json:"brightness"`
|
||||
Gamma int `json:"gamma"`
|
||||
}
|
||||
|
||||
// Information contains information related to the item currently being played. It is also part of Status
|
||||
type Information struct {
|
||||
Chapter int `json:"chapter"`
|
||||
// TODO: Chapters definition might need to be changed
|
||||
Chapters []interface{} `json:"chapters"`
|
||||
Title int `json:"title"`
|
||||
// TODO: Category definition might need to be updated/modified
|
||||
Category map[string]struct {
|
||||
Filename string `json:"filename"`
|
||||
Codec string `json:"Codec"`
|
||||
Channels string `json:"Channels"`
|
||||
BitsPerSample string `json:"Bits_per_sample"`
|
||||
Type string `json:"Type"`
|
||||
SampleRate string `json:"Sample_rate"`
|
||||
} `json:"category"`
|
||||
Titles []interface{} `json:"titles"`
|
||||
}
|
||||
|
||||
// Equalizer contains information related to the equalizer configuration. An Equalizer variable is included in Status
|
||||
type Equalizer struct {
|
||||
Presets map[string]string `json:"presets"`
|
||||
Bands map[string]string `json:"bands"`
|
||||
Preamp int `json:"preamp"`
|
||||
}
|
||||
|
||||
// parseStatus parses GetStatus() responses to Status struct.
|
||||
func parseStatus(statusResponse string) (status *Status, err error) {
|
||||
err = json.Unmarshal([]byte(statusResponse), &status)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return status, nil
|
||||
}
|
||||
|
||||
// GetStatus returns a Status object containing information of the instances' status
|
||||
func (vlc *VLC) GetStatus() (status *Status, err error) {
|
||||
// Make request
|
||||
var response string
|
||||
response, err = vlc.RequestMaker("/requests/status.json")
|
||||
// Error handling
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Parse response to Status
|
||||
status, err = parseStatus(response)
|
||||
return
|
||||
}
|
||||
|
||||
// Play playlist item with given id. If id is omitted, play last active item
|
||||
func (vlc *VLC) Play(itemID ...int) (err error) {
|
||||
// Check variadic arguments and form urlSegment
|
||||
if len(itemID) > 1 {
|
||||
err = errors.New("please provide only up to one ID")
|
||||
return
|
||||
}
|
||||
urlSegment := "/requests/status.json?command=pl_play"
|
||||
if len(itemID) == 1 {
|
||||
urlSegment = urlSegment + "&id=" + strconv.Itoa(itemID[0])
|
||||
}
|
||||
_, err = vlc.RequestMaker(urlSegment)
|
||||
return
|
||||
}
|
||||
|
||||
// Pause toggles pause: If current state was 'stop', play item with given id, if no id specified, play current item.
|
||||
// If no current item, play the first item in the playlist.
|
||||
func (vlc *VLC) Pause(itemID ...int) (err error) {
|
||||
// Check variadic arguments and form urlSegment
|
||||
if len(itemID) > 1 {
|
||||
err = errors.New("please provide only up to one ID")
|
||||
return
|
||||
}
|
||||
urlSegment := "/requests/status.json?command=pl_pause"
|
||||
if len(itemID) == 1 {
|
||||
urlSegment = urlSegment + "&id=" + strconv.Itoa(itemID[0])
|
||||
}
|
||||
_, err = vlc.RequestMaker(urlSegment)
|
||||
return
|
||||
}
|
||||
|
||||
// Stop stops playback
|
||||
func (vlc *VLC) Stop() (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=pl_stop")
|
||||
return
|
||||
}
|
||||
|
||||
// Next skips to the next playlist item
|
||||
func (vlc *VLC) Next() (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=pl_next")
|
||||
return
|
||||
}
|
||||
|
||||
// Previous goes back to the previous playlist item
|
||||
func (vlc *VLC) Previous() (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=pl_previous")
|
||||
return
|
||||
}
|
||||
|
||||
// EmptyPlaylist empties the playlist
|
||||
func (vlc *VLC) EmptyPlaylist() (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=pl_empty")
|
||||
return
|
||||
}
|
||||
|
||||
// ToggleLoop toggles Random Playback
|
||||
func (vlc *VLC) ToggleLoop() (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=pl_random")
|
||||
return
|
||||
}
|
||||
|
||||
// ToggleRepeat toggles Playback Looping
|
||||
func (vlc *VLC) ToggleRepeat() (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=pl_loop")
|
||||
return
|
||||
}
|
||||
|
||||
// ToggleRandom toggles Repeat
|
||||
func (vlc *VLC) ToggleRandom() (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=pl_repeat")
|
||||
return
|
||||
}
|
||||
|
||||
// ToggleFullscreen toggles Fullscreen mode
|
||||
func (vlc *VLC) ToggleFullscreen() (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=fullscreen")
|
||||
return
|
||||
}
|
||||
|
||||
func escapeInput(input string) string {
|
||||
if strings.HasPrefix(input, "http") {
|
||||
return url.QueryEscape(input)
|
||||
} else {
|
||||
input = filepath.FromSlash(input)
|
||||
return strings.ReplaceAll(url.QueryEscape(input), "+", "%20")
|
||||
}
|
||||
}
|
||||
|
||||
// AddAndPlay adds a URI to the playlist and starts playback.
|
||||
// The option field is optional and can have the values: noaudio, novideo
|
||||
func (vlc *VLC) AddAndPlay(uri string, option ...string) error {
|
||||
// Check variadic arguments and form urlSegment
|
||||
if len(option) > 1 {
|
||||
return errors.New("please provide only one option")
|
||||
}
|
||||
urlSegment := "/requests/status.json?command=in_play&input=" + escapeInput(uri)
|
||||
if len(option) == 1 {
|
||||
if (option[0] != "noaudio") && (option[0] != "novideo") {
|
||||
return errors.New("invalid option")
|
||||
}
|
||||
urlSegment = urlSegment + "&option=" + option[0]
|
||||
}
|
||||
_, err := vlc.RequestMaker(urlSegment)
|
||||
return err
|
||||
}
|
||||
|
||||
// Add adds a URI to the playlist
|
||||
func (vlc *VLC) Add(uri string) (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=in_enqueue&input=" + escapeInput(uri))
|
||||
return
|
||||
}
|
||||
|
||||
// AddSubtitle adds a subtitle from URI to currently playing file
|
||||
func (vlc *VLC) AddSubtitle(uri string) (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=addsubtitle&val=" + escapeInput(uri))
|
||||
return
|
||||
}
|
||||
|
||||
// Resume resumes playback if paused, else does nothing
|
||||
func (vlc *VLC) Resume() (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=pl_forceresume")
|
||||
return
|
||||
}
|
||||
|
||||
// ForcePause pauses playback, does nothing if already paused
|
||||
func (vlc *VLC) ForcePause() (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=pl_forcepause")
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes an item with given id from playlist
|
||||
func (vlc *VLC) Delete(id int) (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=pl_delete&id=" + strconv.Itoa(id))
|
||||
return
|
||||
}
|
||||
|
||||
// AudioDelay sets Audio Delay in seconds
|
||||
func (vlc *VLC) AudioDelay(delay float64) (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=audiodelay&val=" + strconv.FormatFloat(delay, 'f', -1, 64))
|
||||
return
|
||||
}
|
||||
|
||||
// SubDelay sets Subtitle Delay in seconds
|
||||
func (vlc *VLC) SubDelay(delay float64) (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=subdelay&val=" + strconv.FormatFloat(delay, 'f', -1, 64))
|
||||
return
|
||||
}
|
||||
|
||||
// PlaybackRate sets Playback Rate. Must be > 0
|
||||
func (vlc *VLC) PlaybackRate(rate float64) (err error) {
|
||||
if rate <= 0 {
|
||||
err = errors.New("rate must be greater than 0")
|
||||
return
|
||||
}
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=rate&val=" + strconv.FormatFloat(rate, 'f', -1, 64))
|
||||
return
|
||||
}
|
||||
|
||||
// AspectRatio sets aspect ratio. Must be one of the following values. Any other value will reset aspect ratio to default.
|
||||
// Valid aspect ratio values: 1:1 , 4:3 , 5:4 , 16:9 , 16:10 , 221:100 , 235:100 , 239:100
|
||||
func (vlc *VLC) AspectRatio(ratio string) (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=aspectratio&val=" + ratio)
|
||||
return
|
||||
}
|
||||
|
||||
// Sort sorts playlist using sort mode <val> and order <id>.
|
||||
// If id=0 then items will be sorted in normal order, if id=1 they will be sorted in reverse order.
|
||||
// A non exhaustive list of sort modes: 0 Id, 1 Name, 3 Author, 5 Random, 7 Track number.
|
||||
func (vlc *VLC) Sort(id int, val int) (err error) {
|
||||
if (id != 0) && (id != 1) {
|
||||
err = errors.New("sorting order must be 0 or 1")
|
||||
return
|
||||
}
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=pl_sort&id=" + strconv.Itoa(id) + "&val=" + strconv.Itoa(val))
|
||||
return
|
||||
}
|
||||
|
||||
// ToggleSD toggle-enables service discovery module <val>.
|
||||
// Typical values are: sap shoutcast, podcast, hal
|
||||
func (vlc *VLC) ToggleSD(val string) (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=pl_sd&val=" + val)
|
||||
return
|
||||
}
|
||||
|
||||
// Volume sets Volume level <val> (can be absolute integer, or +/- relative value).
|
||||
// Percentage isn't working at the moment. Allowed values are of the form: +<int>, -<int>, <int> or <int>%
|
||||
func (vlc *VLC) Volume(val string) (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=volume&val=" + val)
|
||||
return
|
||||
}
|
||||
|
||||
// Seek seeks to <val>
|
||||
//
|
||||
// Allowed values are of the form:
|
||||
// [+ or -][<int><H or h>:][<int><M or m or '>:][<int><nothing or S or s or ">]
|
||||
// or [+ or -]<int>%
|
||||
// (value between [ ] are optional, value between < > are mandatory)
|
||||
// examples:
|
||||
// 1000 -> seek to the 1000th second
|
||||
// +1H:2M -> seek 1 hour and 2 minutes forward
|
||||
// -10% -> seek 10% back
|
||||
func (vlc *VLC) Seek(val string) (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=seek&val=" + val)
|
||||
return
|
||||
}
|
||||
|
||||
// Preamp sets the preamp gain value, must be >=-20 and <=20
|
||||
func (vlc *VLC) Preamp(gain int) (err error) {
|
||||
if (gain < -20) || (gain > 20) {
|
||||
err = errors.New("preamp must be between -20 and 20")
|
||||
return
|
||||
}
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=preamp&val=" + strconv.Itoa(gain))
|
||||
return
|
||||
}
|
||||
|
||||
// SetEQ sets the gain for a specific Equalizer band
|
||||
func (vlc *VLC) SetEQ(band int, gain int) (err error) {
|
||||
if (gain < -20) || (gain > 20) {
|
||||
err = errors.New("gain must be between -20 and 20")
|
||||
return
|
||||
}
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=equalizer&band=" + strconv.Itoa(band) + "&val=" + strconv.Itoa(gain))
|
||||
return
|
||||
}
|
||||
|
||||
// ToggleEQ toggles the EQ (true to enable, false to disable)
|
||||
func (vlc *VLC) ToggleEQ(enable bool) (err error) {
|
||||
enableStr := "0"
|
||||
if enable == true {
|
||||
enableStr = "1"
|
||||
}
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=enableeq&val=" + enableStr)
|
||||
return
|
||||
}
|
||||
|
||||
// SetEQPreset sets the equalizer preset as per the id specified
|
||||
func (vlc *VLC) SetEQPreset(id int) (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=setpreset&id=" + strconv.Itoa(id))
|
||||
return
|
||||
}
|
||||
|
||||
// SelectTitle selects the title using the title number
|
||||
func (vlc *VLC) SelectTitle(id int) (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=title&val=" + strconv.Itoa(id))
|
||||
return
|
||||
}
|
||||
|
||||
// SelectChapter selects the chapter using the chapter number
|
||||
func (vlc *VLC) SelectChapter(id int) (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=chapter&val=" + strconv.Itoa(id))
|
||||
return
|
||||
}
|
||||
|
||||
// SelectAudioTrack selects the audio track (use the number from the stream)
|
||||
func (vlc *VLC) SelectAudioTrack(id int) (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=audio_track&val=" + strconv.Itoa(id))
|
||||
return
|
||||
}
|
||||
|
||||
// SelectVideoTrack selects the video track (use the number from the stream)
|
||||
func (vlc *VLC) SelectVideoTrack(id int) (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=video_track&val=" + strconv.Itoa(id))
|
||||
return
|
||||
}
|
||||
|
||||
// SelectSubtitleTrack selects the subtitle track (use the number from the stream)
|
||||
func (vlc *VLC) SelectSubtitleTrack(id int) (err error) {
|
||||
_, err = vlc.RequestMaker("/requests/status.json?command=subtitle_track&val=" + strconv.Itoa(id))
|
||||
return
|
||||
}
|
||||
66
seanime-2.9.10/internal/mediaplayers/vlc/vlc.go
Normal file
66
seanime-2.9.10/internal/mediaplayers/vlc/vlc.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package vlc
|
||||
|
||||
// https://github.com/CedArctic/go-vlc-ctrl/tree/master
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/rs/zerolog"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// VLC struct represents an http interface enabled VLC instance. Build using NewVLC()
|
||||
type VLC struct {
|
||||
Host string
|
||||
Port int
|
||||
Password string
|
||||
Path string
|
||||
Logger *zerolog.Logger
|
||||
}
|
||||
|
||||
func (vlc *VLC) url() string {
|
||||
return fmt.Sprintf("http://%s:%s", vlc.Host, strconv.Itoa(vlc.Port))
|
||||
}
|
||||
|
||||
// RequestMaker make requests to VLC using a urlSegment provided by other functions
|
||||
func (vlc *VLC) RequestMaker(urlSegment string) (response string, err error) {
|
||||
|
||||
// Form a GET Request
|
||||
client := &http.Client{}
|
||||
request, reqErr := http.NewRequest("GET", vlc.url()+urlSegment, nil)
|
||||
if reqErr != nil {
|
||||
err = fmt.Errorf("http request error: %s\n", reqErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Make a GET request
|
||||
request.SetBasicAuth("", vlc.Password)
|
||||
reqResponse, resErr := client.Do(request)
|
||||
if resErr != nil {
|
||||
err = fmt.Errorf("http response error: %s\n", resErr)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
reqResponse.Body.Close()
|
||||
}()
|
||||
|
||||
// Check HTTP status code and errors
|
||||
statusCode := reqResponse.StatusCode
|
||||
if !((statusCode >= 200) && (statusCode <= 299)) {
|
||||
err = fmt.Errorf("http error code: %d\n", statusCode)
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Get byte response and http status code
|
||||
byteArr, readErr := io.ReadAll(reqResponse.Body)
|
||||
if readErr != nil {
|
||||
err = fmt.Errorf("error reading response: %s\n", readErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write response
|
||||
response = string(byteArr)
|
||||
|
||||
return
|
||||
}
|
||||
87
seanime-2.9.10/internal/mediaplayers/vlc/vlc_test.go
Normal file
87
seanime-2.9.10/internal/mediaplayers/vlc/vlc_test.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package vlc
|
||||
|
||||
import (
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"seanime/internal/test_utils"
|
||||
"seanime/internal/util"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestVLC_Play(t *testing.T) {
|
||||
test_utils.InitTestProvider(t, test_utils.MediaPlayer())
|
||||
|
||||
vlc := &VLC{
|
||||
Host: test_utils.ConfigData.Provider.VlcHost,
|
||||
Port: test_utils.ConfigData.Provider.VlcPort,
|
||||
Password: test_utils.ConfigData.Provider.VlcPassword,
|
||||
Path: test_utils.ConfigData.Provider.VlcPath,
|
||||
Logger: util.NewLogger(),
|
||||
}
|
||||
|
||||
err := vlc.Start()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = vlc.AddAndPlay("E:\\Anime\\[Judas] Golden Kamuy (Seasons 1-2) [BD 1080p][HEVC x265 10bit][Eng-Subs]\\[Judas] Golden Kamuy - S2\\[Judas] Golden Kamuy S2 - 16.mkv")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
time.Sleep(400 * time.Millisecond)
|
||||
|
||||
vlc.ForcePause()
|
||||
|
||||
time.Sleep(400 * time.Millisecond)
|
||||
|
||||
status, err := vlc.GetStatus()
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "paused", status.State)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestVLC_Seek(t *testing.T) {
|
||||
test_utils.InitTestProvider(t, test_utils.MediaPlayer())
|
||||
|
||||
vlc := &VLC{
|
||||
Host: test_utils.ConfigData.Provider.VlcHost,
|
||||
Port: test_utils.ConfigData.Provider.VlcPort,
|
||||
Password: test_utils.ConfigData.Provider.VlcPassword,
|
||||
Path: test_utils.ConfigData.Provider.VlcPath,
|
||||
Logger: util.NewLogger(),
|
||||
}
|
||||
|
||||
err := vlc.Start()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = vlc.AddAndPlay("E:\\ANIME\\[SubsPlease] Bocchi the Rock! (01-12) (1080p) [Batch]\\[SubsPlease] Bocchi the Rock! - 01v2 (1080p) [ABDDAE16].mkv")
|
||||
|
||||
time.Sleep(400 * time.Millisecond)
|
||||
|
||||
vlc.ForcePause()
|
||||
|
||||
time.Sleep(400 * time.Millisecond)
|
||||
|
||||
vlc.Seek("100")
|
||||
|
||||
time.Sleep(400 * time.Millisecond)
|
||||
|
||||
status, err := vlc.GetStatus()
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "paused", status.State)
|
||||
|
||||
spew.Dump(status)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
21
seanime-2.9.10/internal/mediaplayers/vlc/vlm.go
Normal file
21
seanime-2.9.10/internal/mediaplayers/vlc/vlm.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package vlc
|
||||
|
||||
import "net/url"
|
||||
|
||||
// Vlm returns the full list of VLM elements
|
||||
func (vlc *VLC) Vlm() (response string, err error) {
|
||||
response, err = vlc.RequestMaker("/requests/vlm.xml")
|
||||
return
|
||||
}
|
||||
|
||||
// VlmCmd executes a VLM Command and returns the response. Command is internally URL percent-encoded
|
||||
func (vlc *VLC) VlmCmd(cmd string) (response string, err error) {
|
||||
response, err = vlc.RequestMaker("/requests/vlm_cmd.xml?command=" + url.QueryEscape(cmd))
|
||||
return
|
||||
}
|
||||
|
||||
// VlmCmdErr returns the last VLM Error
|
||||
func (vlc *VLC) VlmCmdErr() (response string, err error) {
|
||||
response, err = vlc.RequestMaker("/requests/vlm_cmd.xml")
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user