Compare commits
13 commits
Author | SHA1 | Date | |
---|---|---|---|
Simon Bruder | 327235c451 | ||
Simon Bruder | d63397b1ed | ||
Simon Bruder | 1da5439358 | ||
Simon Bruder | 58c9465add | ||
dff929ddc9 | |||
138c1008eb | |||
2f6bda5018 | |||
a1c5399223 | |||
e1e3a334cd | |||
51db9c3061 | |||
9222608962 | |||
466e9189c6 | |||
786ab8c3d6 |
1
.dockerignore
Normal file
1
.dockerignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Dockerfile
|
13
.drone.yml
Normal file
13
.drone.yml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
kind: pipeline
|
||||||
|
name: default
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: docker
|
||||||
|
image: plugins/docker
|
||||||
|
settings:
|
||||||
|
registry: r.sbruder.de
|
||||||
|
username:
|
||||||
|
from_secret: docker_username
|
||||||
|
password:
|
||||||
|
from_secret: docker_password
|
||||||
|
repo: r.sbruder.de/mumbledj
|
17
CHANGELOG.md
17
CHANGELOG.md
|
@ -1,6 +1,23 @@
|
||||||
MumbleDJ Changelog
|
MumbleDJ Changelog
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
### November 5, 2016 -- `v3.2.1`
|
||||||
|
* Fixed YouTube video offsets. Now YouTube URLs with `?t=<timestamp>` at the end will start the audio playback at the appropriate position.
|
||||||
|
|
||||||
|
### November 5, 2016 -- `v3.2.0`
|
||||||
|
* Fixed a Go panic that would occur when a YouTube playlist contained a private video.
|
||||||
|
* Added back immediate skipping for tracks/playlists that are skipped by the submitter. This was a feature that was present in the last major version of MumbleDJ but was forgotten when rewriting the bot (sorry!).
|
||||||
|
|
||||||
|
### August 22, 2016 -- `v3.1.4`
|
||||||
|
* Fixed a SoundCloud API response parsing issue that would result in empty IDs for tracks.
|
||||||
|
* Fixed the startup check for SoundCloud API.
|
||||||
|
|
||||||
|
### August 21, 2016 -- `v3.1.3`
|
||||||
|
* Fixed a deadlock that would occur during the transition from the first to second track in a queue.
|
||||||
|
|
||||||
|
### August 14, 2016 -- `v3.1.2`
|
||||||
|
* Fixed an index out of range crash in the queue skipping function.
|
||||||
|
|
||||||
### July 11, 2016 -- `v3.1.1`
|
### July 11, 2016 -- `v3.1.1`
|
||||||
* Updated vendored dependencies to hopefully address the following issue: https://github.com/matthieugrieger/mumbledj/issues/169.
|
* Updated vendored dependencies to hopefully address the following issue: https://github.com/matthieugrieger/mumbledj/issues/169.
|
||||||
|
|
||||||
|
|
44
Dockerfile
44
Dockerfile
|
@ -1,19 +1,39 @@
|
||||||
FROM alpine:3.3
|
FROM golang:alpine as builder
|
||||||
|
|
||||||
ENV GOPATH=/
|
RUN apk add --no-cache \
|
||||||
|
build-base \
|
||||||
|
opus-dev
|
||||||
|
|
||||||
RUN apk add --update ca-certificates go ffmpeg make build-base opus-dev python aria2
|
COPY . /go/src/github.com/matthieugrieger/mumbledj
|
||||||
RUN apk upgrade
|
WORKDIR /go/src/github.com/matthieugrieger/mumbledj
|
||||||
|
|
||||||
RUN wget https://yt-dl.org/downloads/latest/youtube-dl -O /bin/youtube-dl && chmod a+x /bin/youtube-dl
|
RUN go get -v \
|
||||||
|
&& go build -v -ldflags="-s -w"
|
||||||
|
|
||||||
COPY . /src/github.com/matthieugrieger/mumbledj
|
FROM alpine
|
||||||
COPY config.yaml /root/.config/mumbledj/config.yaml
|
|
||||||
|
|
||||||
WORKDIR /src/github.com/matthieugrieger/mumbledj
|
RUN adduser -D mumbledj
|
||||||
|
|
||||||
RUN make
|
RUN apk add --no-cache \
|
||||||
RUN make install
|
aria2 \
|
||||||
RUN apk del go make build-base && rm -rf /var/cache/apk/*
|
libressl \
|
||||||
|
python2
|
||||||
|
|
||||||
ENTRYPOINT ["/usr/local/bin/mumbledj"]
|
RUN wget -O /usr/bin/youtube-dl https://yt-dl.org/downloads/latest/youtube-dl \
|
||||||
|
&& chmod +x /usr/bin/youtube-dl
|
||||||
|
|
||||||
|
RUN wget https://johnvansickle.com/ffmpeg/builds/ffmpeg-git-amd64-static.tar.xz \
|
||||||
|
&& tar xvf ffmpeg-git-amd64-static.tar.xz '*/ffmpeg' || true \
|
||||||
|
&& mv ffmpeg-git-*-amd64-static/ffmpeg /usr/bin/ffmpeg \
|
||||||
|
&& rm -rf ffmpeg-git-* \
|
||||||
|
&& apk add --no-cache upx \
|
||||||
|
&& upx /usr/bin/ffmpeg \
|
||||||
|
&& apk del upx
|
||||||
|
|
||||||
|
COPY --from=builder /go/src/github.com/matthieugrieger/mumbledj/mumbledj /usr/bin/mumbledj
|
||||||
|
|
||||||
|
COPY config.yaml /home/mumbledj/.config/mumbledj/config.yaml
|
||||||
|
|
||||||
|
USER mumbledj
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/bin/mumbledj"]
|
||||||
|
|
10
README.md
10
README.md
|
@ -3,6 +3,8 @@
|
||||||
<p align="center"><b>A Mumble bot that plays audio fetched from various media websites.</b></p>
|
<p align="center"><b>A Mumble bot that plays audio fetched from various media websites.</b></p>
|
||||||
<p align="center"><a href="https://travis-ci.org/matthieugrieger/mumbledj"><img src="https://travis-ci.org/matthieugrieger/mumbledj.svg?branch=master"/></a> <a href="https://raw.githubusercontent.com/matthieugrieger/mumbledj/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg"/></a> <a href="https://github.com/matthieugrieger/mumbledj/releases"><img src="https://img.shields.io/github/release/matthieugrieger/mumbledj.svg"/></a> <a href="https://goreportcard.com/report/github.com/matthieugrieger/mumbledj"><img src="https://goreportcard.com/badge/github.com/matthieugrieger/mumbledj"/></a> <a href="https://codecov.io/gh/matthieugrieger/mumbledj"><img src="https://img.shields.io/codecov/c/github/matthieugrieger/mumbledj.svg"/></a> <a href="https://gitter.im/matthieugrieger/mumbledj"><img src="https://img.shields.io/gitter/room/matthieugrieger/mumbledj.svg" /></a></p>
|
<p align="center"><a href="https://travis-ci.org/matthieugrieger/mumbledj"><img src="https://travis-ci.org/matthieugrieger/mumbledj.svg?branch=master"/></a> <a href="https://raw.githubusercontent.com/matthieugrieger/mumbledj/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg"/></a> <a href="https://github.com/matthieugrieger/mumbledj/releases"><img src="https://img.shields.io/github/release/matthieugrieger/mumbledj.svg"/></a> <a href="https://goreportcard.com/report/github.com/matthieugrieger/mumbledj"><img src="https://goreportcard.com/badge/github.com/matthieugrieger/mumbledj"/></a> <a href="https://codecov.io/gh/matthieugrieger/mumbledj"><img src="https://img.shields.io/codecov/c/github/matthieugrieger/mumbledj.svg"/></a> <a href="https://gitter.im/matthieugrieger/mumbledj"><img src="https://img.shields.io/gitter/room/matthieugrieger/mumbledj.svg" /></a></p>
|
||||||
|
|
||||||
|
<p align="center"><b>Unfortunately, this project is no longer maintained. Don't expect any responses on bug reports, feature requests, etc. Forks are welcome!</b></p>
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
* [Features](#features)
|
* [Features](#features)
|
||||||
|
@ -106,14 +108,14 @@ sudo make install
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
|
|
||||||
You can also use [docker](https://www.docker.com) to run mumbledj.
|
You can also use [Docker](https://www.docker.com) to run MumbleDJ.
|
||||||
|
|
||||||
First you need to clone the MumbleDJ repository to your machine:
|
First you need to clone the MumbleDJ repository to your machine:
|
||||||
```
|
```
|
||||||
git clone https://github.com/matthieugrieger/mumbledj.git
|
git clone https://github.com/matthieugrieger/mumbledj.git
|
||||||
```
|
```
|
||||||
|
|
||||||
Assuming you have [docker installed](https://www.docker.com/products/docker), you will have to build the image:
|
Assuming you have [Docker installed](https://www.docker.com/products/docker), you will have to build the image:
|
||||||
```
|
```
|
||||||
docker build -t mumbledj .
|
docker build -t mumbledj .
|
||||||
```
|
```
|
||||||
|
@ -123,12 +125,12 @@ And then you can run it, passing the configuration through the command line:
|
||||||
docker run --rm --name=mumbledj mumbledj --server=SERVER --api_keys.youtube=YOUR_YOUTUBE_API_KEY --api_keys.soundcloud=YOUR_SOUNDCLOUD_API_KEY
|
docker run --rm --name=mumbledj mumbledj --server=SERVER --api_keys.youtube=YOUR_YOUTUBE_API_KEY --api_keys.soundcloud=YOUR_SOUNDCLOUD_API_KEY
|
||||||
```
|
```
|
||||||
|
|
||||||
In order to run the process as a deamon and restart it automatically on reboot you can use:
|
In order to run the process as a daemon and restart it automatically on reboot you can use:
|
||||||
```
|
```
|
||||||
docker run -d --restart=unless-stopped --name=mumbledj mumbledj --server=SERVER --api_keys.youtube=YOUR_YOUTUBE_API_KEY --api_keys.soundcloud=YOUR_SOUNDCLOUD_API_KEY
|
docker run -d --restart=unless-stopped --name=mumbledj mumbledj --server=SERVER --api_keys.youtube=YOUR_YOUTUBE_API_KEY --api_keys.soundcloud=YOUR_SOUNDCLOUD_API_KEY
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also install docker on a [raspberry pi](https://www.raspberrypi.org/) for instance with [hypriot](http://blog.hypriot.com/getting-started-with-docker-on-your-arm-device/) or with [archlinux](https://archlinuxarm.org/packages/arm/docker). You just need to build the arm image:
|
You can also install Docker on a [Raspberry Pi](https://www.raspberrypi.org/) for instance with [hypriot](http://blog.hypriot.com/getting-started-with-docker-on-your-arm-device/) or with [archlinux](https://archlinuxarm.org/packages/arm/docker). You just need to build the ARM image:
|
||||||
```
|
```
|
||||||
docker build -f raspberry.Dockerfile -t mumbledj .
|
docker build -f raspberry.Dockerfile -t mumbledj .
|
||||||
```
|
```
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -196,6 +196,7 @@ func SetDefaultConfig() {
|
||||||
viper.SetDefault("commands.skip.description", "Places a vote to skip the current track.")
|
viper.SetDefault("commands.skip.description", "Places a vote to skip the current track.")
|
||||||
viper.SetDefault("commands.skip.messages.already_voted_error", "You have already voted to skip this track.")
|
viper.SetDefault("commands.skip.messages.already_voted_error", "You have already voted to skip this track.")
|
||||||
viper.SetDefault("commands.skip.messages.voted", "<b>%s</b> has voted to skip the current track.")
|
viper.SetDefault("commands.skip.messages.voted", "<b>%s</b> has voted to skip the current track.")
|
||||||
|
viper.SetDefault("commands.skip.messages.submitter_voted", "<b>%s</b>, the submitter of this track, has voted to skip. Skipping immediately.")
|
||||||
|
|
||||||
viper.SetDefault("commands.skipplaylist.aliases", []string{"skipplaylist", "sp"})
|
viper.SetDefault("commands.skipplaylist.aliases", []string{"skipplaylist", "sp"})
|
||||||
viper.SetDefault("commands.skipplaylist.is_admin", false)
|
viper.SetDefault("commands.skipplaylist.is_admin", false)
|
||||||
|
@ -203,6 +204,7 @@ func SetDefaultConfig() {
|
||||||
viper.SetDefault("commands.skipplaylist.messages.no_playlist_error", "The current track is not part of a playlist.")
|
viper.SetDefault("commands.skipplaylist.messages.no_playlist_error", "The current track is not part of a playlist.")
|
||||||
viper.SetDefault("commands.skipplaylist.messages.already_voted_error", "You have already voted to skip this playlist.")
|
viper.SetDefault("commands.skipplaylist.messages.already_voted_error", "You have already voted to skip this playlist.")
|
||||||
viper.SetDefault("commands.skipplaylist.messages.voted", "<b>%s</b> has voted to skip the current playlist.")
|
viper.SetDefault("commands.skipplaylist.messages.voted", "<b>%s</b> has voted to skip the current playlist.")
|
||||||
|
viper.SetDefault("commands.skipplaylist.messages.submitter_voted", "<b>%s</b>, the submitter of this playlist, has voted to skip. Skipping immediately.")
|
||||||
|
|
||||||
viper.SetDefault("commands.toggleshuffle.aliases", []string{"toggleshuffle", "toggleshuf", "togshuf", "tsh"})
|
viper.SetDefault("commands.toggleshuffle.aliases", []string{"toggleshuffle", "toggleshuf", "togshuf", "tsh"})
|
||||||
viper.SetDefault("commands.toggleshuffle.is_admin", true)
|
viper.SetDefault("commands.toggleshuffle.is_admin", true)
|
||||||
|
|
|
@ -199,7 +199,7 @@ func (q *Queue) Skip() {
|
||||||
|
|
||||||
q.mutex.Lock()
|
q.mutex.Lock()
|
||||||
// If caching is disabled, delete the track from disk.
|
// If caching is disabled, delete the track from disk.
|
||||||
if !viper.GetBool("cache.enabled") {
|
if len(q.Queue) != 0 && !viper.GetBool("cache.enabled") {
|
||||||
DJ.YouTubeDL.Delete(q.Queue[0])
|
DJ.YouTubeDL.Delete(q.Queue[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,11 @@ func (c *SkipCommand) Execute(user *gumble.User, args ...string) (string, bool,
|
||||||
if DJ.Queue.Length() == 0 {
|
if DJ.Queue.Length() == 0 {
|
||||||
return "", true, errors.New(viper.GetString("commands.common_messages.no_tracks_error"))
|
return "", true, errors.New(viper.GetString("commands.common_messages.no_tracks_error"))
|
||||||
}
|
}
|
||||||
|
if DJ.Queue.GetTrack(0).GetSubmitter() == user.Name {
|
||||||
|
// The user who submitted the track is skipping, this means we skip this track immediately.
|
||||||
|
DJ.Queue.StopCurrent()
|
||||||
|
return fmt.Sprintf(viper.GetString("commands.skip.messages.submitter_voted"), user.Name), false, nil
|
||||||
|
}
|
||||||
if err := DJ.Skips.AddTrackSkip(user); err != nil {
|
if err := DJ.Skips.AddTrackSkip(user); err != nil {
|
||||||
return "", true, errors.New(viper.GetString("commands.skip.messages.already_voted_error"))
|
return "", true, errors.New(viper.GetString("commands.skip.messages.already_voted_error"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,10 @@ func (c *SkipPlaylistCommand) Execute(user *gumble.User, args ...string) (string
|
||||||
if playlist := currentTrack.GetPlaylist(); playlist == nil {
|
if playlist := currentTrack.GetPlaylist(); playlist == nil {
|
||||||
return "", true, errors.New(viper.GetString("commands.skipplaylist.messages.no_playlist_error"))
|
return "", true, errors.New(viper.GetString("commands.skipplaylist.messages.no_playlist_error"))
|
||||||
}
|
}
|
||||||
|
if currentTrack.GetPlaylist().GetSubmitter() == user.Name {
|
||||||
|
DJ.Queue.SkipPlaylist()
|
||||||
|
return fmt.Sprintf(viper.GetString("commands.skipplaylist.messages.submitter_voted"), user.Name), false, nil
|
||||||
|
}
|
||||||
if err := DJ.Skips.AddPlaylistSkip(user); err != nil {
|
if err := DJ.Skips.AddPlaylistSkip(user); err != nil {
|
||||||
return "", true, errors.New(viper.GetString("commands.skipplaylist.messages.already_voted_error"))
|
return "", true, errors.New(viper.GetString("commands.skipplaylist.messages.already_voted_error"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -374,6 +374,7 @@ commands:
|
||||||
messages:
|
messages:
|
||||||
already_voted_error: "You have already voted to skip this track."
|
already_voted_error: "You have already voted to skip this track."
|
||||||
voted: "<b>%s</b> has voted to skip the current track."
|
voted: "<b>%s</b> has voted to skip the current track."
|
||||||
|
submitter_voted: "<b>%s</b>, the submitter of this track, has voted to skip. Skipping immediately."
|
||||||
|
|
||||||
skipplaylist:
|
skipplaylist:
|
||||||
aliases:
|
aliases:
|
||||||
|
@ -385,6 +386,7 @@ commands:
|
||||||
no_playlist_error: "The current track is not part of a playlist."
|
no_playlist_error: "The current track is not part of a playlist."
|
||||||
already_voted_error: "You have already voted to skip this playlist."
|
already_voted_error: "You have already voted to skip this playlist."
|
||||||
voted: "<b>%s</b> has voted to skip the current playlist."
|
voted: "<b>%s</b> has voted to skip the current playlist."
|
||||||
|
submitter_voted: "<b>%s</b>, the submitter of this playlist, has voted to skip. Skipping immediately."
|
||||||
|
|
||||||
toggleshuffle:
|
toggleshuffle:
|
||||||
aliases:
|
aliases:
|
||||||
|
|
2
main.go
2
main.go
|
@ -32,7 +32,7 @@ func init() {
|
||||||
services.DJ = DJ
|
services.DJ = DJ
|
||||||
bot.DJ = DJ
|
bot.DJ = DJ
|
||||||
|
|
||||||
DJ.Version = "v3.1.1"
|
DJ.Version = "v3.2.1"
|
||||||
|
|
||||||
logrus.SetLevel(logrus.WarnLevel)
|
logrus.SetLevel(logrus.WarnLevel)
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ func (sc *SoundCloud) CheckAPIKey() error {
|
||||||
if viper.GetString("api_keys.soundcloud") == "" {
|
if viper.GetString("api_keys.soundcloud") == "" {
|
||||||
return errors.New("No SoundCloud API key has been provided")
|
return errors.New("No SoundCloud API key has been provided")
|
||||||
}
|
}
|
||||||
url := "http://api.soundcloud.com/tracks/vjflzpbkmerb?client_id=%s"
|
url := "http://api.soundcloud.com/tracks/13158665?client_id=%s"
|
||||||
response, err := http.Get(fmt.Sprintf(url, viper.GetString("api_keys.soundcloud")))
|
response, err := http.Get(fmt.Sprintf(url, viper.GetString("api_keys.soundcloud")))
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -162,7 +162,8 @@ func (sc *SoundCloud) GetTracks(url string, submitter *gumble.User) ([]interface
|
||||||
|
|
||||||
func (sc *SoundCloud) getTrack(obj *jason.Object, offset time.Duration, submitter *gumble.User) (bot.Track, error) {
|
func (sc *SoundCloud) getTrack(obj *jason.Object, offset time.Duration, submitter *gumble.User) (bot.Track, error) {
|
||||||
title, _ := obj.GetString("title")
|
title, _ := obj.GetString("title")
|
||||||
id, _ := obj.GetString("id")
|
idInt, _ := obj.GetInt64("id")
|
||||||
|
id := strconv.FormatInt(idInt, 10)
|
||||||
url, _ := obj.GetString("permalink_url")
|
url, _ := obj.GetString("permalink_url")
|
||||||
author, _ := obj.GetString("user", "username")
|
author, _ := obj.GetString("user", "username")
|
||||||
authorURL, _ := obj.GetString("user", "permalink_url")
|
authorURL, _ := obj.GetString("user", "permalink_url")
|
||||||
|
|
|
@ -13,6 +13,8 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ChannelMeter/iso8601duration"
|
"github.com/ChannelMeter/iso8601duration"
|
||||||
"github.com/antonholmquist/jason"
|
"github.com/antonholmquist/jason"
|
||||||
|
@ -98,9 +100,12 @@ func (yt *YouTube) GetTracks(url string, submitter *gumble.User) ([]interfaces.T
|
||||||
tracks []interfaces.Track
|
tracks []interfaces.Track
|
||||||
)
|
)
|
||||||
|
|
||||||
|
dummyOffset, _ := time.ParseDuration("0s")
|
||||||
|
urlSplit := strings.Split(url, "?t=")
|
||||||
|
|
||||||
playlistURL = "https://www.googleapis.com/youtube/v3/playlists?part=snippet&id=%s&key=%s"
|
playlistURL = "https://www.googleapis.com/youtube/v3/playlists?part=snippet&id=%s&key=%s"
|
||||||
playlistItemsURL = "https://www.googleapis.com/youtube/v3/playlistItems?part=snippet,contentDetails&playlistId=%s&maxResults=%d&key=%s&pageToken=%s"
|
playlistItemsURL = "https://www.googleapis.com/youtube/v3/playlistItems?part=snippet,contentDetails&playlistId=%s&maxResults=%d&key=%s&pageToken=%s"
|
||||||
id, err = yt.getID(url)
|
id, err = yt.getID(urlSplit[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -161,7 +166,7 @@ func (yt *YouTube) GetTracks(url string, submitter *gumble.User) ([]interfaces.T
|
||||||
|
|
||||||
// Unfortunately we have to execute another API call for each video as the YouTube API does not
|
// Unfortunately we have to execute another API call for each video as the YouTube API does not
|
||||||
// return video durations from the playlistItems endpoint...
|
// return video durations from the playlistItems endpoint...
|
||||||
newTrack, _ := yt.getTrack(videoID, submitter)
|
newTrack, _ := yt.getTrack(videoID, submitter, dummyOffset)
|
||||||
newTrack.Playlist = playlist
|
newTrack.Playlist = playlist
|
||||||
tracks = append(tracks, newTrack)
|
tracks = append(tracks, newTrack)
|
||||||
|
|
||||||
|
@ -182,7 +187,13 @@ func (yt *YouTube) GetTracks(url string, submitter *gumble.User) ([]interfaces.T
|
||||||
return tracks, nil
|
return tracks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
track, err = yt.getTrack(id, submitter)
|
// Submitter added a track!
|
||||||
|
offset := dummyOffset
|
||||||
|
if len(urlSplit) == 2 {
|
||||||
|
offset, _ = time.ParseDuration(urlSplit[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
track, err = yt.getTrack(id, submitter, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -190,7 +201,7 @@ func (yt *YouTube) GetTracks(url string, submitter *gumble.User) ([]interfaces.T
|
||||||
return tracks, nil
|
return tracks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (yt *YouTube) getTrack(id string, submitter *gumble.User) (bot.Track, error) {
|
func (yt *YouTube) getTrack(id string, submitter *gumble.User, offset time.Duration) (bot.Track, error) {
|
||||||
var (
|
var (
|
||||||
resp *http.Response
|
resp *http.Response
|
||||||
err error
|
err error
|
||||||
|
@ -209,6 +220,9 @@ func (yt *YouTube) getTrack(id string, submitter *gumble.User) (bot.Track, error
|
||||||
return bot.Track{}, err
|
return bot.Track{}, err
|
||||||
}
|
}
|
||||||
items, _ := v.GetObjectArray("items")
|
items, _ := v.GetObjectArray("items")
|
||||||
|
if len(items) == 0 {
|
||||||
|
return bot.Track{}, errors.New("This YouTube video is private")
|
||||||
|
}
|
||||||
item := items[0]
|
item := items[0]
|
||||||
title, _ := item.GetString("snippet", "title")
|
title, _ := item.GetString("snippet", "title")
|
||||||
thumbnail, _ := item.GetString("snippet", "thumbnails", "high", "url")
|
thumbnail, _ := item.GetString("snippet", "thumbnails", "high", "url")
|
||||||
|
@ -227,6 +241,7 @@ func (yt *YouTube) getTrack(id string, submitter *gumble.User) (bot.Track, error
|
||||||
Filename: id + ".track",
|
Filename: id + ".track",
|
||||||
ThumbnailURL: thumbnail,
|
ThumbnailURL: thumbnail,
|
||||||
Duration: duration,
|
Duration: duration,
|
||||||
|
PlaybackOffset: offset,
|
||||||
Playlist: nil,
|
Playlist: nil,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue