Skip to content

Commit

Permalink
Removed Channel yt-dlp module, instead throwing things in the VideoCo…
Browse files Browse the repository at this point in the history
…llection module
  • Loading branch information
kieraneglin committed Feb 2, 2024
1 parent 2250695 commit 6a31d33
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 108 deletions.
32 changes: 0 additions & 32 deletions lib/pinchflat/media_client/backends/yt_dlp/channel.ex

This file was deleted.

59 changes: 39 additions & 20 deletions lib/pinchflat/media_client/backends/yt_dlp/video_collection.ex
Original file line number Diff line number Diff line change
@@ -1,28 +1,47 @@
defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollection do
@moduledoc """
Contains utilities for working with collections of videos (ie: channels, playlists).
Contains utilities for working with collections of
videos (aka: a source [ie: channels, playlists]).
"""

alias Pinchflat.MediaClient.SourceDetails

@doc """
Returns a list of strings representing the video ids in the collection.
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.
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.
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]

defmacro __using__(_) do
quote do
@doc """
Returns a list of strings representing the video ids in the collection.
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
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
4 changes: 2 additions & 2 deletions lib/pinchflat/media_client/source_details.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
45 changes: 0 additions & 45 deletions test/pinchflat/media_client/backends/yt_dlp/channel_test.exs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,18 @@ 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!

describe "get_video_ids/2" 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
Expand All @@ -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
Expand All @@ -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

0 comments on commit 6a31d33

Please sign in to comment.