mirror of
https://github.com/photoprism/photoprism.git
synced 2025-09-27 05:08:13 +08:00
CLI: Refactor photoprism/dl test suite
Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
@@ -3,16 +3,10 @@ package dl
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -22,74 +16,6 @@ const (
|
||||
subtitlesTestVideoRawURL = "https://www.youtube.com/watch?v=QRS8MkLhQmM"
|
||||
)
|
||||
|
||||
// Todo: Must be fixed, which might require an updated YT-DLP version or different request parameters.
|
||||
func TestParseInfo(t *testing.T) {
|
||||
t.Skip("todo: must be fixed, which might require an updated YT-DLP version or different request parameters")
|
||||
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
|
||||
for _, c := range []struct {
|
||||
url string
|
||||
expectedTitle string
|
||||
}{
|
||||
{"https://soundcloud.com/avalonemerson/avalon-emerson-live-at-printworks-london-march-2017",
|
||||
"Avalon Emerson Live at Printworks London 2017"},
|
||||
{"https://www.infoq.com/presentations/Simple-Made-Easy",
|
||||
"Simple Made Easy - InfoQ"},
|
||||
{testVideoRawURL,
|
||||
"Cinematic Epic Deep Trailer - Background Music for Trailers and Film"},
|
||||
} {
|
||||
t.Run(c.url, func(t *testing.T) {
|
||||
ctx, cancelFn := context.WithCancel(context.Background())
|
||||
ydlResult, err := NewMetadata(ctx, c.url, Options{
|
||||
DownloadThumbnail: true,
|
||||
})
|
||||
if err != nil {
|
||||
cancelFn()
|
||||
t.Errorf("failed to parse: %v", err)
|
||||
return
|
||||
}
|
||||
cancelFn()
|
||||
|
||||
yi := ydlResult.Info
|
||||
results := ydlResult.Formats()
|
||||
|
||||
if yi.Title != c.expectedTitle {
|
||||
t.Errorf("expected title %q got %q", c.expectedTitle, yi.Title)
|
||||
}
|
||||
|
||||
if yi.Thumbnail != "" && len(yi.ThumbnailBytes) == 0 {
|
||||
t.Errorf("expected thumbnail bytes")
|
||||
}
|
||||
|
||||
var dummy map[string]interface{}
|
||||
if err := json.Unmarshal(ydlResult.RawJSON, &dummy); err != nil {
|
||||
t.Errorf("failed to parse RawJSON")
|
||||
}
|
||||
|
||||
if len(results) == 0 {
|
||||
t.Errorf("expected formats")
|
||||
}
|
||||
|
||||
for _, f := range results {
|
||||
if f.FormatID == "" {
|
||||
t.Errorf("expected to have FormatID")
|
||||
}
|
||||
if f.Ext == "" {
|
||||
t.Errorf("expected to have Ext")
|
||||
}
|
||||
if (f.ACodec == "" || f.ACodec == "none") &&
|
||||
(f.VCodec == "" || f.VCodec == "none") &&
|
||||
f.Ext == "" {
|
||||
t.Errorf("expected to have some media: audio %q video %q ext %q", f.ACodec, f.VCodec, f.Ext)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlaylist(t *testing.T) {
|
||||
t.Skip("skipping test because playlist URL is unreliable.")
|
||||
|
||||
@@ -152,7 +78,7 @@ func TestChannel(t *testing.T) {
|
||||
|
||||
func TestUnsupportedURL(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
t.Skip("skipped download test in short mode")
|
||||
}
|
||||
|
||||
_, ydlResultErr := NewMetadata(context.Background(), "https://www.google.com", Options{})
|
||||
@@ -218,107 +144,9 @@ func TestSubtitles(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Todo: Must be fixed, which might require an updated YT-DLP version or different request parameters.
|
||||
func TestDownloadSections(t *testing.T) {
|
||||
t.Skip("todo: must be fixed, which might require an updated YT-DLP version or different request parameters")
|
||||
|
||||
fileName := fs.Abs("./testdata/duration_test_file")
|
||||
duration := 5
|
||||
|
||||
defer func() {
|
||||
_ = os.Remove(fileName)
|
||||
}()
|
||||
|
||||
cmd := exec.Command(FindFFmpegBin(), "-version")
|
||||
_, err := cmd.Output()
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("failed to check ffmpeg installed: %s", err)
|
||||
}
|
||||
|
||||
ydlResult, ydlResultErr := NewMetadata(
|
||||
context.Background(),
|
||||
testVideoRawURL,
|
||||
Options{
|
||||
DownloadSections: fmt.Sprintf("*0:0-0:%d", duration),
|
||||
})
|
||||
|
||||
if ydlResult.Options.DownloadSections != "*0:0-0:5" {
|
||||
t.Errorf("failed to setup --download-sections")
|
||||
}
|
||||
|
||||
if ydlResultErr != nil {
|
||||
t.Errorf("failed to download: %s", ydlResultErr)
|
||||
}
|
||||
|
||||
dr, err := ydlResult.Download(context.Background(), "")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
f, err := os.Create(fileName)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
_, err = io.Copy(f, dr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cmd = exec.Command(FindFFprobeBin(), "-v", "quiet", "-show_entries", "format=duration", fileName)
|
||||
stdout, err := cmd.Output()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var gotDurationString string
|
||||
output := string(stdout)
|
||||
for _, line := range strings.Split(output, "\n") {
|
||||
if strings.Contains(line, "duration") {
|
||||
if d, found := strings.CutPrefix(line, "duration="); found {
|
||||
gotDurationString = d
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gotDuration, err := strconv.ParseFloat(gotDurationString, 32)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
seconds := int(gotDuration)
|
||||
|
||||
if seconds != duration {
|
||||
t.Fatalf("did not get expected duration of %d, but got %d", duration, seconds)
|
||||
}
|
||||
|
||||
_ = dr.Close()
|
||||
}
|
||||
|
||||
func TestErrorNotAPlaylist(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
|
||||
_, ydlResultErr := NewMetadata(context.Background(), testVideoRawURL, Options{
|
||||
Type: TypePlaylist,
|
||||
DownloadThumbnail: false,
|
||||
})
|
||||
if ydlResultErr != ErrNotAPlaylist {
|
||||
t.Errorf("expected is playlist error, got %s", ydlResultErr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorNotASingleEntry(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
t.Skip("skipped download test in short mode")
|
||||
}
|
||||
|
||||
_, ydlResultErr := NewMetadata(context.Background(), playlistRawURL, Options{
|
||||
@@ -331,40 +159,6 @@ func TestErrorNotASingleEntry(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Todo: Must be fixed, which might require an updated YT-DLP version or different request parameters.
|
||||
func TestOptionDownloader(t *testing.T) {
|
||||
t.Skip("todo: must be fixed, which might require an updated YT-DLP version or different request parameters")
|
||||
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
|
||||
ydlResult, ydlResultErr := NewMetadata(
|
||||
context.Background(),
|
||||
testVideoRawURL,
|
||||
Options{
|
||||
Downloader: "ffmpeg",
|
||||
})
|
||||
|
||||
if ydlResultErr != nil {
|
||||
t.Fatalf("failed to download: %s", ydlResultErr)
|
||||
}
|
||||
|
||||
dr, err := ydlResult.Download(context.Background(), ydlResult.Info.Formats[0].FormatID)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
downloadBuf := &bytes.Buffer{}
|
||||
_, err = io.Copy(downloadBuf, dr)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dr.Close()
|
||||
}
|
||||
|
||||
func TestInvalidOptionTypeField(t *testing.T) {
|
||||
_, err := NewMetadata(context.Background(), playlistRawURL, Options{
|
||||
Type: 42,
|
||||
@@ -376,7 +170,7 @@ func TestInvalidOptionTypeField(t *testing.T) {
|
||||
|
||||
func TestDownloadPlaylistEntry(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
t.Skip("skipped download test in short mode")
|
||||
}
|
||||
|
||||
// Download file by specifying the playlist index
|
||||
|
@@ -1,11 +1,16 @@
|
||||
//go:build yt
|
||||
|
||||
package dl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -14,12 +19,200 @@ import (
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
)
|
||||
|
||||
// Todo: Must be fixed, which might require an updated YT-DLP version or different request parameters.
|
||||
func TestDownload(t *testing.T) {
|
||||
t.Skip("todo: must be fixed, which might require an updated YT-DLP version or different request parameters")
|
||||
func TestDownloadSections(t *testing.T) {
|
||||
fileName := fs.Abs("./testdata/duration_test_file")
|
||||
duration := 5
|
||||
|
||||
defer func() {
|
||||
_ = os.Remove(fileName)
|
||||
}()
|
||||
|
||||
cmd := exec.Command(FindFFmpegBin(), "-version")
|
||||
_, err := cmd.Output()
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("failed to check ffmpeg installed: %s", err)
|
||||
}
|
||||
|
||||
ydlResult, ydlResultErr := NewMetadata(
|
||||
context.Background(),
|
||||
testVideoRawURL,
|
||||
Options{
|
||||
DownloadSections: fmt.Sprintf("*0:0-0:%d", duration),
|
||||
})
|
||||
|
||||
if ydlResult.Options.DownloadSections != "*0:0-0:5" {
|
||||
t.Errorf("failed to setup --download-sections")
|
||||
}
|
||||
|
||||
if ydlResultErr != nil {
|
||||
t.Errorf("failed to download: %s", ydlResultErr)
|
||||
}
|
||||
|
||||
dr, err := ydlResult.Download(context.Background(), "")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
f, err := os.Create(fileName)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
_, err = io.Copy(f, dr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cmd = exec.Command(FindFFprobeBin(), "-v", "quiet", "-show_entries", "format=duration", fileName)
|
||||
stdout, err := cmd.Output()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var gotDurationString string
|
||||
output := string(stdout)
|
||||
for _, line := range strings.Split(output, "\n") {
|
||||
if strings.Contains(line, "duration") {
|
||||
if d, found := strings.CutPrefix(line, "duration="); found {
|
||||
gotDurationString = d
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gotDuration, err := strconv.ParseFloat(gotDurationString, 32)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
seconds := int(gotDuration)
|
||||
|
||||
if seconds != duration {
|
||||
t.Fatalf("did not get expected duration of %d, but got %d", duration, seconds)
|
||||
}
|
||||
|
||||
_ = dr.Close()
|
||||
}
|
||||
|
||||
func TestErrorNotAPlaylist(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
t.Skip("skipped download test in short mode")
|
||||
}
|
||||
|
||||
_, ydlResultErr := NewMetadata(context.Background(), testVideoRawURL, Options{
|
||||
Type: TypePlaylist,
|
||||
DownloadThumbnail: false,
|
||||
})
|
||||
if ydlResultErr != ErrNotAPlaylist {
|
||||
t.Errorf("expected is playlist error, got %s", ydlResultErr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOptionDownloader(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipped download test in short mode")
|
||||
}
|
||||
|
||||
ydlResult, ydlResultErr := NewMetadata(
|
||||
context.Background(),
|
||||
testVideoRawURL,
|
||||
Options{
|
||||
Downloader: "ffmpeg",
|
||||
})
|
||||
|
||||
if ydlResultErr != nil {
|
||||
t.Fatalf("failed to download: %s", ydlResultErr)
|
||||
}
|
||||
|
||||
dr, err := ydlResult.Download(context.Background(), ydlResult.Info.Formats[0].FormatID)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
downloadBuf := &bytes.Buffer{}
|
||||
_, err = io.Copy(downloadBuf, dr)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dr.Close()
|
||||
}
|
||||
|
||||
func TestParseInfo(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipped download test in short mode")
|
||||
}
|
||||
|
||||
for _, c := range []struct {
|
||||
url string
|
||||
expectedTitle string
|
||||
}{
|
||||
{"https://soundcloud.com/avalonemerson/avalon-emerson-live-at-printworks-london-march-2017",
|
||||
"Avalon Emerson Live at Printworks London 2017"},
|
||||
{"https://www.infoq.com/presentations/Simple-Made-Easy",
|
||||
"Simple Made Easy - InfoQ"},
|
||||
{testVideoRawURL,
|
||||
"Cinematic Epic Deep Trailer - Background Music for Trailers and Film"},
|
||||
} {
|
||||
t.Run(c.url, func(t *testing.T) {
|
||||
ctx, cancelFn := context.WithCancel(context.Background())
|
||||
ydlResult, err := NewMetadata(ctx, c.url, Options{
|
||||
DownloadThumbnail: true,
|
||||
})
|
||||
if err != nil {
|
||||
cancelFn()
|
||||
t.Errorf("failed to parse: %v", err)
|
||||
return
|
||||
}
|
||||
cancelFn()
|
||||
|
||||
yi := ydlResult.Info
|
||||
results := ydlResult.Formats()
|
||||
|
||||
if yi.Title != c.expectedTitle {
|
||||
t.Errorf("expected title %q got %q", c.expectedTitle, yi.Title)
|
||||
}
|
||||
|
||||
if yi.Thumbnail != "" && len(yi.ThumbnailBytes) == 0 {
|
||||
t.Errorf("expected thumbnail bytes")
|
||||
}
|
||||
|
||||
var dummy map[string]interface{}
|
||||
if err := json.Unmarshal(ydlResult.RawJSON, &dummy); err != nil {
|
||||
t.Errorf("failed to parse RawJSON")
|
||||
}
|
||||
|
||||
if len(results) == 0 {
|
||||
t.Errorf("expected formats")
|
||||
}
|
||||
|
||||
for _, f := range results {
|
||||
if f.FormatID == "" {
|
||||
t.Errorf("expected to have FormatID")
|
||||
}
|
||||
if f.Ext == "" {
|
||||
t.Errorf("expected to have Ext")
|
||||
}
|
||||
if (f.ACodec == "" || f.ACodec == "none") &&
|
||||
(f.VCodec == "" || f.VCodec == "none") &&
|
||||
f.Ext == "" {
|
||||
t.Errorf("expected to have some media: audio %q video %q ext %q", f.ACodec, f.VCodec, f.Ext)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDownload(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipped download test in short mode")
|
||||
}
|
||||
|
||||
// Fetch metadata.
|
||||
@@ -74,10 +267,7 @@ func TestDownload(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Todo: Must be fixed, which might require an updated YT-DLP version or different request parameters.
|
||||
func TestDownloadWithoutInfo(t *testing.T) {
|
||||
t.Skip("todo: must be fixed, which might require an updated YT-DLP version or different request parameters")
|
||||
|
||||
stderrBuf := &bytes.Buffer{}
|
||||
dr, err := Download(context.Background(), testVideoRawURL, Options{
|
||||
StderrFn: func(cmd *exec.Cmd) io.Writer {
|
||||
|
Reference in New Issue
Block a user