summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Pointner <equinox@helsinki.at>2016-07-14 21:18:15 (GMT)
committerChristian Pointner <equinox@helsinki.at>2016-07-14 21:18:15 (GMT)
commit1a409362450ea903019005bc48145be1da14848d (patch)
tree510b6562da3d0802cd6acaff9f29112356fc675c
parent139e9fae3956443bcdeaa120d7f9349901275e82 (diff)
added support for youtube-dl
-rw-r--r--rhimport/fetcher.go62
-rw-r--r--rhimport/youtubedl_responses.go51
2 files changed, 113 insertions, 0 deletions
diff --git a/rhimport/fetcher.go b/rhimport/fetcher.go
index 469d36b..3933105 100644
--- a/rhimport/fetcher.go
+++ b/rhimport/fetcher.go
@@ -25,6 +25,7 @@
package rhimport
import (
+ "bytes"
"fmt"
"io"
"io/ioutil"
@@ -32,6 +33,7 @@ import (
"net/http"
"net/url"
"os"
+ "os/exec"
"os/user"
"path"
"path/filepath"
@@ -134,9 +136,51 @@ func curlProgressCallback(dltotal, dlnow, ultotal, ulnow float64, userdata inter
return true
}
+func checkYoutubeDL(ctx *Context, res *Result, uri *url.URL) *YoutubeDLInfo {
+ cmd := exec.Command("youtube-dl", "--no-playlist", "-f", "bestaudio/best", "--prefer-free-formats", "-J", ctx.SourceUri)
+ var stderr, stdout bytes.Buffer
+ cmd.Stdout = &stdout
+ cmd.Stderr = &stderr
+
+ done := make(chan *YoutubeDLInfo)
+ go func() {
+ defer func() {
+ done <- nil
+ }()
+ if err := cmd.Run(); err != nil {
+ rhdl.Printf("youtube-dl: %v, stderr: %s", err, strings.TrimSpace(stderr.String()))
+ return
+ }
+ info, err := NewYoutubeDLInfoFromJSON(&stdout)
+ if err != nil {
+ rhdl.Printf("youtube-dl: %v, stderr: %s", err, strings.TrimSpace(stderr.String()))
+ return
+ }
+ rhl.Printf("youtube-dl: extractor: %s -> %s", info.Extractor, info.URL)
+ ctx.SourceUri = info.URL
+ done <- info
+ }()
+
+ select {
+ case info := <-done:
+ return info
+ case <-ctx.Cancel:
+ cmd.Process.Kill()
+ res.ResponseCode = http.StatusNoContent
+ res.ErrorString = "canceled"
+ return nil
+ }
+}
+
func fetchFileCurl(ctx *Context, res *Result, uri *url.URL) (err error) {
rhl.Printf("curl-based fetcher called for '%s'", ctx.SourceUri)
+ info := checkYoutubeDL(ctx, res, uri)
+ if res.ResponseCode == http.StatusNoContent {
+ rhl.Printf("download of '%s' got canceled", ctx.SourceUri)
+ return nil
+ }
+
easy := curl.EasyInit()
if easy == nil {
err = fmt.Errorf("Error initializing libcurl")
@@ -148,10 +192,28 @@ func fetchFileCurl(ctx *Context, res *Result, uri *url.URL) (err error) {
easy.Setopt(curl.OPT_URL, ctx.SourceUri)
easy.Setopt(curl.OPT_USERAGENT, "Radio Helsinki Import")
+ if info != nil && (info.Protocol == "http" || info.Protocol == "https") {
+ if len(info.HTTPHeaders) > 0 {
+ var h []string
+ for key, value := range info.HTTPHeaders {
+ h = append(h, key+": "+value)
+ }
+ easy.Setopt(curl.OPT_HTTPHEADER, h)
+ rhdl.Printf("added HTTP header: %q", h)
+ }
+ }
+
cbdata := &FetcherCurlCBData{ctx: ctx, res: res, remotename: path.Base(uri.Path)}
if cbdata.basepath, err = ioutil.TempDir(ctx.conf.TempDir, "rhimportd-"); err != nil {
return
}
+ if info != nil {
+ if info.Title == "" {
+ cbdata.remotename = info.ID + "." + info.Ext
+ } else {
+ cbdata.remotename = info.Title + "." + info.Ext
+ }
+ }
easy.Setopt(curl.OPT_HEADERFUNCTION, curlHeaderCallback)
easy.Setopt(curl.OPT_HEADERDATA, cbdata)
diff --git a/rhimport/youtubedl_responses.go b/rhimport/youtubedl_responses.go
new file mode 100644
index 0000000..1a8c0ca
--- /dev/null
+++ b/rhimport/youtubedl_responses.go
@@ -0,0 +1,51 @@
+//
+// rhimportd
+//
+// The Radio Helsinki Rivendell Import Daemon
+//
+//
+// Copyright (C) 2015-2016 Christian Pointner <equinox@helsinki.at>
+//
+// This file is part of rhimportd.
+//
+// rhimportd is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// rhimportd is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with rhimportd. If not, see <http://www.gnu.org/licenses/>.
+//
+
+package rhimport
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+)
+
+type YoutubeDLInfo struct {
+ ID string `json:"id"`
+ Title string `json:"title"`
+ URL string `json:"url"`
+ Extractor string `json:"extractor"`
+ Ext string `json:"ext"`
+ Protocol string `json:"protocol"`
+ HTTPHeaders map[string]string `json:"http_headers"`
+}
+
+func NewYoutubeDLInfoFromJSON(data io.Reader) (res *YoutubeDLInfo, err error) {
+ decoder := json.NewDecoder(data)
+ res = &YoutubeDLInfo{}
+ if jsonerr := decoder.Decode(res); jsonerr != nil {
+ err = fmt.Errorf("Error parsing JSON response: %s", jsonerr)
+ return
+ }
+ return
+}