Refactored video importers
This commit is contained in:
parent
5100a10863
commit
88b96784ab
7 changed files with 121 additions and 25 deletions
38
app/app.go
38
app/app.go
|
@ -20,8 +20,8 @@ import (
|
||||||
"github.com/gorilla/handlers"
|
"github.com/gorilla/handlers"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/renstrom/shortuuid"
|
"github.com/renstrom/shortuuid"
|
||||||
"github.com/rylio/ytdl"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/wybiral/tube/importers"
|
||||||
"github.com/wybiral/tube/media"
|
"github.com/wybiral/tube/media"
|
||||||
"github.com/wybiral/tube/utils"
|
"github.com/wybiral/tube/utils"
|
||||||
)
|
)
|
||||||
|
@ -339,7 +339,15 @@ func (a *App) importHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
collection := keys[0]
|
collection := keys[0]
|
||||||
|
|
||||||
vid, err := ytdl.GetVideoInfo(url)
|
videoImporter, err := importers.NewImporter(url)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("error creating video importer for %s: %w", url, err)
|
||||||
|
log.Error(err)
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
videoInfo, err := videoImporter.GetVideoInfo(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("error retriving video info for %s: %w", url, err)
|
err := fmt.Errorf("error retriving video info for %s: %w", url, err)
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
@ -359,8 +367,7 @@ func (a *App) importHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
defer os.Remove(uf.Name())
|
defer os.Remove(uf.Name())
|
||||||
|
|
||||||
err = vid.Download(vid.Formats[0], uf)
|
if err := utils.Download(videoInfo.VideoURL, uf.Name()); err != nil {
|
||||||
if err != nil {
|
|
||||||
err := fmt.Errorf("error downloading video %s: %w", url, err)
|
err := fmt.Errorf("error downloading video %s: %w", url, err)
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
@ -385,29 +392,12 @@ func (a *App) importHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
thumbFn1 := fmt.Sprintf("%s.jpg", strings.TrimSuffix(tf.Name(), filepath.Ext(tf.Name())))
|
thumbFn1 := fmt.Sprintf("%s.jpg", strings.TrimSuffix(tf.Name(), filepath.Ext(tf.Name())))
|
||||||
thumbFn2 := fmt.Sprintf("%s.jpg", strings.TrimSuffix(vf, filepath.Ext(vf)))
|
thumbFn2 := fmt.Sprintf("%s.jpg", strings.TrimSuffix(vf, filepath.Ext(vf)))
|
||||||
|
|
||||||
thumbURL := vid.GetThumbnailURL(ytdl.ThumbnailQualityHigh)
|
if err := utils.Download(videoInfo.ThumbnailURL, thumbFn1); err != nil {
|
||||||
res, err := http.Get(thumbURL.String())
|
|
||||||
if err != nil {
|
|
||||||
err := fmt.Errorf("error downloading thumbnail: %w", err)
|
err := fmt.Errorf("error downloading thumbnail: %w", err)
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
thumbData, err := ioutil.ReadAll(res.Body)
|
|
||||||
res.Body.Close()
|
|
||||||
if err != nil {
|
|
||||||
err := fmt.Errorf("error reading thumbnail data: %w", err)
|
|
||||||
log.Error(err)
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ioutil.WriteFile(thumbFn1, thumbData, 0644); err != nil {
|
|
||||||
err := fmt.Errorf("error writing thumbnail data: %w", err)
|
|
||||||
log.Error(err)
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Use a proper Job Queue and make this async
|
// TODO: Use a proper Job Queue and make this async
|
||||||
if err := utils.RunCmd(
|
if err := utils.RunCmd(
|
||||||
|
@ -419,8 +409,8 @@ func (a *App) importHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
"-acodec", "aac",
|
"-acodec", "aac",
|
||||||
"-strict", "-2",
|
"-strict", "-2",
|
||||||
"-loglevel", "quiet",
|
"-loglevel", "quiet",
|
||||||
"-metadata", fmt.Sprintf("title=%s", vid.Title),
|
"-metadata", fmt.Sprintf("title=%s", videoInfo.Title),
|
||||||
"-metadata", fmt.Sprintf("comment=%s", vid.Description),
|
"-metadata", fmt.Sprintf("comment=%s", videoInfo.Description),
|
||||||
tf.Name(),
|
tf.Name(),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
err := fmt.Errorf("error transcoding video: %w", err)
|
err := fmt.Errorf("error transcoding video: %w", err)
|
||||||
|
|
3
go.mod
3
go.mod
|
@ -20,7 +20,8 @@ require (
|
||||||
github.com/mutschler/mt v0.0.0-20200120124658-d48aed259ff6 // indirect
|
github.com/mutschler/mt v0.0.0-20200120124658-d48aed259ff6 // indirect
|
||||||
github.com/prologic/bitcask v0.3.5
|
github.com/prologic/bitcask v0.3.5
|
||||||
github.com/renstrom/shortuuid v3.0.0+incompatible
|
github.com/renstrom/shortuuid v3.0.0+incompatible
|
||||||
github.com/rylio/ytdl v0.6.2
|
github.com/rs/zerolog v1.18.0 // indirect
|
||||||
|
github.com/rylio/ytdl v0.6.3-0.20200220142242-f3a87da86fb8
|
||||||
github.com/sirupsen/logrus v1.4.2
|
github.com/sirupsen/logrus v1.4.2
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/spf13/viper v1.6.2 // indirect
|
github.com/spf13/viper v1.6.2 // indirect
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -153,10 +153,14 @@ github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
|
||||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||||
github.com/rs/zerolog v1.16.0 h1:AaELmZdcJHT8m6oZ5py4213cdFK8XGXkB3dFdAQ+P7Q=
|
github.com/rs/zerolog v1.16.0 h1:AaELmZdcJHT8m6oZ5py4213cdFK8XGXkB3dFdAQ+P7Q=
|
||||||
github.com/rs/zerolog v1.16.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I=
|
github.com/rs/zerolog v1.16.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I=
|
||||||
|
github.com/rs/zerolog v1.18.0 h1:CbAm3kP2Tptby1i9sYy2MGRg0uxIN9cyDb59Ys7W8z8=
|
||||||
|
github.com/rs/zerolog v1.18.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I=
|
||||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/rylio/ytdl v0.6.2 h1:ZYzaoUqAniH/yb7yscdWlVoecVRcvpFDgS15NyDTZQA=
|
github.com/rylio/ytdl v0.6.2 h1:ZYzaoUqAniH/yb7yscdWlVoecVRcvpFDgS15NyDTZQA=
|
||||||
github.com/rylio/ytdl v0.6.2/go.mod h1:F0WX8szfQ00mhmfla+0xVJp483SBV4VO/ByUaNioNSM=
|
github.com/rylio/ytdl v0.6.2/go.mod h1:F0WX8szfQ00mhmfla+0xVJp483SBV4VO/ByUaNioNSM=
|
||||||
|
github.com/rylio/ytdl v0.6.3-0.20200220142242-f3a87da86fb8 h1:Kxmg/DHYGAALeJ4npCxZWTE+IxORgWkJGkXbUiduArU=
|
||||||
|
github.com/rylio/ytdl v0.6.3-0.20200220142242-f3a87da86fb8/go.mod h1:F0WX8szfQ00mhmfla+0xVJp483SBV4VO/ByUaNioNSM=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
|
33
importers/importer.go
Normal file
33
importers/importer.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package importers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrUnsupportedVideoURL = errors.New("error: unsupported video url")
|
||||||
|
)
|
||||||
|
|
||||||
|
type VideoInfo struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
|
||||||
|
VideoURL string `json:"video_url"`
|
||||||
|
ThumbnailURL string `json:"thumbnail_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Importer interface {
|
||||||
|
GetVideoInfo(url string) (VideoInfo, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewImporter(url string) (Importer, error) {
|
||||||
|
if strings.Contains(url, "youtube.com") || strings.HasPrefix(url, "youtube:") {
|
||||||
|
return &YoutubeImporter{}, nil
|
||||||
|
} else if strings.Contains(url, "youtube.com") || strings.HasPrefix(url, "youtube:") {
|
||||||
|
return &VimeoImporter{}, nil
|
||||||
|
} else {
|
||||||
|
return nil, ErrUnsupportedVideoURL
|
||||||
|
}
|
||||||
|
}
|
10
importers/vimeo_importer.go
Normal file
10
importers/vimeo_importer.go
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package importers
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type VimeoImporter struct{}
|
||||||
|
|
||||||
|
func (i *VimeoImporter) GetVideoInfo(url string) (videoInfo VideoInfo, err error) {
|
||||||
|
err = fmt.Errorf("Not Implemented")
|
||||||
|
return
|
||||||
|
}
|
37
importers/youtube_importer.go
Normal file
37
importers/youtube_importer.go
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package importers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/rylio/ytdl"
|
||||||
|
)
|
||||||
|
|
||||||
|
type YoutubeImporter struct{}
|
||||||
|
|
||||||
|
func (i *YoutubeImporter) GetVideoInfo(url string) (videoInfo VideoInfo, err error) {
|
||||||
|
if strings.HasPrefix(url, "youtube:") {
|
||||||
|
url = strings.TrimPrefix(url, "youtube:")
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := ytdl.GetVideoInfo(url)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("error retriving youtube video info: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
videoURL, err := ytdl.DefaultClient.GetDownloadURL(info, info.Formats[0])
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("error retriving youtube video url: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
videoInfo.VideoURL = videoURL.String()
|
||||||
|
|
||||||
|
videoInfo.ThumbnailURL = info.GetThumbnailURL(ytdl.ThumbnailQualityHigh).String()
|
||||||
|
|
||||||
|
videoInfo.ID = info.ID
|
||||||
|
videoInfo.Title = info.Title
|
||||||
|
videoInfo.Description = info.Description
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -3,11 +3,32 @@ package utils
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func Download(url, filename string) error {
|
||||||
|
res, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(filename, data, 0644); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// FileExists ...
|
// FileExists ...
|
||||||
func FileExists(name string) bool {
|
func FileExists(name string) bool {
|
||||||
if _, err := os.Stat(name); err != nil {
|
if _, err := os.Stat(name); err != nil {
|
||||||
|
|
Loading…
Reference in a new issue