Removed Channel yt-dlp module, instead throwing things in the VideoCollection module
This commit is contained in:
parent
2250695a3e
commit
6a31d333ad
5 changed files with 80 additions and 107 deletions
|
|
@ -1,32 +0,0 @@
|
|||
defmodule Pinchflat.MediaClient.Backends.YtDlp.Channel do
|
||||
@moduledoc """
|
||||
Contains utilities for working with a channel's videos
|
||||
"""
|
||||
|
||||
use Pinchflat.MediaClient.Backends.YtDlp.VideoCollection
|
||||
alias Pinchflat.MediaClient.SourceDetails
|
||||
|
||||
@doc """
|
||||
Gets a channel's ID and name from its URL.
|
||||
|
||||
yt-dlp does not _really_ have channel-specific functions, so
|
||||
instead we're fetching just the first video (using playlist_end: 1)
|
||||
and parsing the channel ID and name from _its_ metadata
|
||||
|
||||
Returns {:ok, %SourceDetails{}} | {:error, any, ...}.
|
||||
"""
|
||||
def get_source_details(channel_url) do
|
||||
opts = [:skip_download, playlist_end: 1]
|
||||
|
||||
with {:ok, output} <- backend_runner().run(channel_url, opts, "%(.{channel,channel_id})j"),
|
||||
{:ok, parsed_json} <- Phoenix.json_library().decode(output) do
|
||||
{:ok, SourceDetails.new(parsed_json["channel_id"], parsed_json["channel"])}
|
||||
else
|
||||
err -> err
|
||||
end
|
||||
end
|
||||
|
||||
defp backend_runner do
|
||||
Application.get_env(:pinchflat, :yt_dlp_runner)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,28 +1,47 @@
|
|||
defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollection do
|
||||
@moduledoc """
|
||||
Contains utilities for working with collections of videos (ie: channels, playlists).
|
||||
|
||||
Meant to be included in other modules but can be used on its own. Channels and playlists
|
||||
will have many of their own methods, but also share a lot of methods. This module is for
|
||||
those shared methods.
|
||||
Contains utilities for working with collections of
|
||||
videos (aka: a source [ie: channels, playlists]).
|
||||
"""
|
||||
|
||||
defmacro __using__(_) do
|
||||
quote do
|
||||
@doc """
|
||||
Returns a list of strings representing the video ids in the collection.
|
||||
alias Pinchflat.MediaClient.SourceDetails
|
||||
|
||||
Returns {:ok, [binary()]} | {:error, any, ...}.
|
||||
"""
|
||||
def get_video_ids(url, command_opts \\ []) do
|
||||
runner = Application.get_env(:pinchflat, :yt_dlp_runner)
|
||||
opts = command_opts ++ [:simulate, :skip_download]
|
||||
@doc """
|
||||
Returns a list of strings representing the video ids in the collection.
|
||||
|
||||
case runner.run(url, opts, "%(id)s") do
|
||||
{:ok, output} -> {:ok, String.split(output, "\n", trim: true)}
|
||||
res -> res
|
||||
end
|
||||
end
|
||||
Returns {:ok, [binary()]} | {:error, any, ...}.
|
||||
"""
|
||||
def get_video_ids(url, command_opts \\ []) do
|
||||
runner = Application.get_env(:pinchflat, :yt_dlp_runner)
|
||||
opts = command_opts ++ [:simulate, :skip_download]
|
||||
|
||||
case runner.run(url, opts, "%(id)s") do
|
||||
{:ok, output} -> {:ok, String.split(output, "\n", trim: true)}
|
||||
res -> res
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a source's ID and name from its URL.
|
||||
|
||||
yt-dlp does not _really_ have source-specific functions, so
|
||||
instead we're fetching just the first video (using playlist_end: 1)
|
||||
and parsing the source ID and name from _its_ metadata
|
||||
|
||||
Returns {:ok, %SourceDetails{}} | {:error, any, ...}.
|
||||
"""
|
||||
def get_source_details(source_url) do
|
||||
opts = [:skip_download, playlist_end: 1]
|
||||
|
||||
with {:ok, output} <- backend_runner().run(source_url, opts, "%(.{channel,channel_id})j"),
|
||||
{:ok, parsed_json} <- Phoenix.json_library().decode(output) do
|
||||
{:ok, SourceDetails.new(parsed_json["channel_id"], parsed_json["channel"])}
|
||||
else
|
||||
err -> err
|
||||
end
|
||||
end
|
||||
|
||||
defp backend_runner do
|
||||
Application.get_env(:pinchflat, :yt_dlp_runner)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ defmodule Pinchflat.MediaClient.SourceDetails do
|
|||
@enforce_keys [:id, :name]
|
||||
defstruct [:id, :name]
|
||||
|
||||
alias Pinchflat.MediaClient.Backends.YtDlp.Channel, as: YtDlpChannel
|
||||
alias Pinchflat.MediaClient.Backends.YtDlp.VideoCollection, as: YtDlpSource
|
||||
|
||||
@doc false
|
||||
def new(id, name) do
|
||||
|
|
@ -35,7 +35,7 @@ defmodule Pinchflat.MediaClient.SourceDetails do
|
|||
|
||||
defp source_module(backend) do
|
||||
case backend do
|
||||
:yt_dlp -> YtDlpChannel
|
||||
:yt_dlp -> YtDlpSource
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
defmodule Pinchflat.MediaClient.Backends.YtDlp.ChannelTest do
|
||||
use ExUnit.Case, async: true
|
||||
import Mox
|
||||
|
||||
alias Pinchflat.MediaClient.SourceDetails
|
||||
alias Pinchflat.MediaClient.Backends.YtDlp.Channel
|
||||
|
||||
@channel_url "https://www.youtube.com/c/TheUselessTrials"
|
||||
|
||||
setup :verify_on_exit!
|
||||
|
||||
describe "get_source_details/1" do
|
||||
test "it returns a %SourceDetails{} with data on success" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot ->
|
||||
{:ok, "{\"channel\": \"TheUselessTrials\", \"channel_id\": \"UCQH2\"}"}
|
||||
end)
|
||||
|
||||
assert {:ok, res} = Channel.get_source_details(@channel_url)
|
||||
assert %SourceDetails{id: "UCQH2", name: "TheUselessTrials"} = res
|
||||
end
|
||||
|
||||
test "it passes the expected args to the backend runner" do
|
||||
expect(YtDlpRunnerMock, :run, fn @channel_url, opts, ot ->
|
||||
assert opts == [:skip_download, playlist_end: 1]
|
||||
assert ot == "%(.{channel,channel_id})j"
|
||||
|
||||
{:ok, "{}"}
|
||||
end)
|
||||
|
||||
assert {:ok, _} = Channel.get_source_details(@channel_url)
|
||||
end
|
||||
|
||||
test "it returns an error if the runner returns an error" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:error, "Big issue", 1} end)
|
||||
|
||||
assert {:error, "Big issue", 1} = Channel.get_source_details(@channel_url)
|
||||
end
|
||||
|
||||
test "it returns an error if the output is not JSON" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "Not JSON"} end)
|
||||
|
||||
assert {:error, %Jason.DecodeError{}} = Channel.get_source_details(@channel_url)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -2,13 +2,10 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollectionTest do
|
|||
use ExUnit.Case, async: true
|
||||
import Mox
|
||||
|
||||
alias Pinchflat.MediaClient.SourceDetails
|
||||
alias Pinchflat.MediaClient.Backends.YtDlp.VideoCollection
|
||||
|
||||
@channel_url "https://www.youtube.com/@TheUselessTrials"
|
||||
|
||||
defmodule VideoCollectionUser do
|
||||
use VideoCollection
|
||||
end
|
||||
@channel_url "https://www.youtube.com/c/TheUselessTrials"
|
||||
|
||||
setup :verify_on_exit!
|
||||
|
||||
|
|
@ -16,7 +13,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollectionTest do
|
|||
test "returns a list of video ids with no blank elements" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "id1\nid2\n\nid3\n"} end)
|
||||
|
||||
assert {:ok, ["id1", "id2", "id3"]} = VideoCollectionUser.get_video_ids(@channel_url)
|
||||
assert {:ok, ["id1", "id2", "id3"]} = VideoCollection.get_video_ids(@channel_url)
|
||||
end
|
||||
|
||||
test "it passes the expected default args" do
|
||||
|
|
@ -27,7 +24,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollectionTest do
|
|||
{:ok, ""}
|
||||
end)
|
||||
|
||||
assert {:ok, _} = VideoCollectionUser.get_video_ids(@channel_url)
|
||||
assert {:ok, _} = VideoCollection.get_video_ids(@channel_url)
|
||||
end
|
||||
|
||||
test "it passes the expected custom args" do
|
||||
|
|
@ -37,13 +34,47 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollectionTest do
|
|||
{:ok, ""}
|
||||
end)
|
||||
|
||||
assert {:ok, _} = VideoCollectionUser.get_video_ids(@channel_url, [:custom_arg])
|
||||
assert {:ok, _} = VideoCollection.get_video_ids(@channel_url, [:custom_arg])
|
||||
end
|
||||
|
||||
test "returns the error straight through when the command fails" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:error, "Big issue", 1} end)
|
||||
|
||||
assert {:error, "Big issue", 1} = VideoCollectionUser.get_video_ids(@channel_url)
|
||||
assert {:error, "Big issue", 1} = VideoCollection.get_video_ids(@channel_url)
|
||||
end
|
||||
end
|
||||
|
||||
describe "get_source_details/1" do
|
||||
test "it returns a %SourceDetails{} with data on success" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot ->
|
||||
{:ok, "{\"channel\": \"TheUselessTrials\", \"channel_id\": \"UCQH2\"}"}
|
||||
end)
|
||||
|
||||
assert {:ok, res} = VideoCollection.get_source_details(@channel_url)
|
||||
assert %SourceDetails{id: "UCQH2", name: "TheUselessTrials"} = res
|
||||
end
|
||||
|
||||
test "it passes the expected args to the backend runner" do
|
||||
expect(YtDlpRunnerMock, :run, fn @channel_url, opts, ot ->
|
||||
assert opts == [:skip_download, playlist_end: 1]
|
||||
assert ot == "%(.{channel,channel_id})j"
|
||||
|
||||
{:ok, "{}"}
|
||||
end)
|
||||
|
||||
assert {:ok, _} = VideoCollection.get_source_details(@channel_url)
|
||||
end
|
||||
|
||||
test "it returns an error if the runner returns an error" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:error, "Big issue", 1} end)
|
||||
|
||||
assert {:error, "Big issue", 1} = VideoCollection.get_source_details(@channel_url)
|
||||
end
|
||||
|
||||
test "it returns an error if the output is not JSON" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "Not JSON"} end)
|
||||
|
||||
assert {:error, %Jason.DecodeError{}} = VideoCollection.get_source_details(@channel_url)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue