More renaming; renamed channel details module

This commit is contained in:
Kieran Eglin 2024-02-02 10:21:12 -08:00
parent d822aaa899
commit 2250695a3e
No known key found for this signature in database
GPG key ID: 193984967FCF432D
9 changed files with 64 additions and 64 deletions

View file

@ -11,4 +11,4 @@ alias Pinchflat.Media
alias Pinchflat.Profiles alias Pinchflat.Profiles
alias Pinchflat.MediaSource alias Pinchflat.MediaSource
alias Pinchflat.MediaClient.{ChannelDetails, VideoDownloader} alias Pinchflat.MediaClient.{SourceDetails, VideoDownloader}

View file

@ -18,7 +18,7 @@ defmodule Pinchflat.Media do
end end
@doc """ @doc """
Returns a list of pending media_items for a given channel, where Returns a list of pending media_items for a given source, where
pending means the `media_filepath` is `nil`. pending means the `media_filepath` is `nil`.
Returns [%MediaItem{}, ...]. Returns [%MediaItem{}, ...].

View file

@ -4,7 +4,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.Channel do
""" """
use Pinchflat.MediaClient.Backends.YtDlp.VideoCollection use Pinchflat.MediaClient.Backends.YtDlp.VideoCollection
alias Pinchflat.MediaClient.ChannelDetails alias Pinchflat.MediaClient.SourceDetails
@doc """ @doc """
Gets a channel's ID and name from its URL. Gets a channel's ID and name from its URL.
@ -13,14 +13,14 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.Channel do
instead we're fetching just the first video (using playlist_end: 1) instead we're fetching just the first video (using playlist_end: 1)
and parsing the channel ID and name from _its_ metadata and parsing the channel ID and name from _its_ metadata
Returns {:ok, %ChannelDetails{}} | {:error, any, ...}. Returns {:ok, %SourceDetails{}} | {:error, any, ...}.
""" """
def get_source_details(channel_url) do def get_source_details(channel_url) do
opts = [:skip_download, playlist_end: 1] opts = [:skip_download, playlist_end: 1]
with {:ok, output} <- backend_runner().run(channel_url, opts, "%(.{channel,channel_id})j"), with {:ok, output} <- backend_runner().run(channel_url, opts, "%(.{channel,channel_id})j"),
{:ok, parsed_json} <- Phoenix.json_library().decode(output) do {:ok, parsed_json} <- Phoenix.json_library().decode(output) do
{:ok, ChannelDetails.new(parsed_json["channel_id"], parsed_json["channel"])} {:ok, SourceDetails.new(parsed_json["channel_id"], parsed_json["channel"])}
else else
err -> err err -> err
end end

View file

@ -1,6 +1,6 @@
defmodule Pinchflat.MediaClient.ChannelDetails do defmodule Pinchflat.MediaClient.SourceDetails do
@moduledoc """ @moduledoc """
This is the integration layer for actually working with channels. This is the integration layer for actually working with sources.
Technically hardcodes the yt-dlp backend for now, but should leave Technically hardcodes the yt-dlp backend for now, but should leave
it open-ish for future expansion (just in case). it open-ish for future expansion (just in case).
@ -16,24 +16,24 @@ defmodule Pinchflat.MediaClient.ChannelDetails do
end end
@doc """ @doc """
Gets a channel's ID and name from its URL, using the given backend. Gets a source's ID and name from its URL, using the given backend.
Returns {:ok, map()} | {:error, any, ...}. Returns {:ok, map()} | {:error, any, ...}.
""" """
def get_source_details(channel_url, backend \\ :yt_dlp) do def get_source_details(source_url, backend \\ :yt_dlp) do
channel_module(backend).get_source_details(channel_url) source_module(backend).get_source_details(source_url)
end end
@doc """ @doc """
Returns a list of video IDs for the given channel URL, using the given backend. Returns a list of video IDs for the given source URL, using the given backend.
Returns {:ok, list(binary())} | {:error, any, ...}. Returns {:ok, list(binary())} | {:error, any, ...}.
""" """
def get_video_ids(channel_url, backend \\ :yt_dlp) do def get_video_ids(source_url, backend \\ :yt_dlp) do
channel_module(backend).get_video_ids(channel_url) source_module(backend).get_video_ids(source_url)
end end
defp channel_module(backend) do defp source_module(backend) do
case backend do case backend do
:yt_dlp -> YtDlpChannel :yt_dlp -> YtDlpChannel
end end

View file

@ -10,25 +10,25 @@ defmodule Pinchflat.MediaSource do
alias Pinchflat.Media alias Pinchflat.Media
alias Pinchflat.Tasks.SourceTasks alias Pinchflat.Tasks.SourceTasks
alias Pinchflat.MediaSource.Source alias Pinchflat.MediaSource.Source
alias Pinchflat.MediaClient.ChannelDetails alias Pinchflat.MediaClient.SourceDetails
@doc """ @doc """
Returns the list of channels. Returns [%Source{}, ...] Returns the list of sources. Returns [%Source{}, ...]
""" """
def list_sources do def list_sources do
Repo.all(Source) Repo.all(Source)
end end
@doc """ @doc """
Gets a single channel. Gets a single source.
Returns %Source{}. Raises `Ecto.NoResultsError` if the Channel does not exist. Returns %Source{}. Raises `Ecto.NoResultsError` if the Channel does not exist.
""" """
def get_source!(id), do: Repo.get!(Source, id) def get_source!(id), do: Repo.get!(Source, id)
@doc """ @doc """
Creates a channel. May attempt to pull additional channel details from the Creates a source. May attempt to pull additional source details from the
original_url (if provided). Will attempt to start indexing the channel's original_url (if provided). Will attempt to start indexing the source's
media if successfully inserted. media if successfully inserted.
Returns {:ok, %Source{}} | {:error, %Ecto.Changeset{}} Returns {:ok, %Source{}} | {:error, %Ecto.Changeset{}}
@ -46,7 +46,7 @@ defmodule Pinchflat.MediaSource do
Returns [%MediaItem{}, ...] | [%Ecto.Changeset{}, ...] Returns [%MediaItem{}, ...] | [%Ecto.Changeset{}, ...]
""" """
def index_media_items(%Source{} = source) do def index_media_items(%Source{} = source) do
{:ok, media_ids} = ChannelDetails.get_video_ids(source.original_url) {:ok, media_ids} = SourceDetails.get_video_ids(source.original_url)
media_ids media_ids
|> Enum.map(fn media_id -> |> Enum.map(fn media_id ->
@ -60,8 +60,8 @@ defmodule Pinchflat.MediaSource do
end end
@doc """ @doc """
Updates a channel. May attempt to pull additional channel details from the Updates a source. May attempt to pull additional source details from the
original_url (if changed). May attempt to start indexing the channel's original_url (if changed). May attempt to start indexing the source's
media if the indexing frequency has been changed. media if the indexing frequency has been changed.
Existing indexing tasks will be cancelled if the indexing frequency has been Existing indexing tasks will be cancelled if the indexing frequency has been
@ -69,58 +69,58 @@ defmodule Pinchflat.MediaSource do
Returns {:ok, %Source{}} | {:error, %Ecto.Changeset{}} Returns {:ok, %Source{}} | {:error, %Ecto.Changeset{}}
""" """
def update_source(%Source{} = channel, attrs) do def update_source(%Source{} = source, attrs) do
channel source
|> change_source_from_url(attrs) |> change_source_from_url(attrs)
|> commit_and_start_indexing() |> commit_and_start_indexing()
end end
@doc """ @doc """
Deletes a channel and it's associated tasks (of any state). Deletes a source and it's associated tasks (of any state).
Returns {:ok, %Source{}} | {:error, %Ecto.Changeset{}} Returns {:ok, %Source{}} | {:error, %Ecto.Changeset{}}
""" """
def delete_source(%Source{} = channel) do def delete_source(%Source{} = source) do
Tasks.delete_tasks_for(channel) Tasks.delete_tasks_for(source)
Repo.delete(channel) Repo.delete(source)
end end
@doc """ @doc """
Returns an `%Ecto.Changeset{}` for tracking channel changes. Returns an `%Ecto.Changeset{}` for tracking source changes.
""" """
def change_source(%Source{} = channel, attrs \\ %{}) do def change_source(%Source{} = source, attrs \\ %{}) do
Source.changeset(channel, attrs) Source.changeset(source, attrs)
end end
@doc """ @doc """
Returns an `%Ecto.Changeset{}` for tracking channel changes and additionally Returns an `%Ecto.Changeset{}` for tracking source changes and additionally
fetches channel details from the original_url (if provided). If the channel fetches source details from the original_url (if provided). If the source
details cannot be fetched, an error is added to the changeset. details cannot be fetched, an error is added to the changeset.
Note that this fetches channel details as long as the `original_url` is present. Note that this fetches source details as long as the `original_url` is present.
This means that it'll go for it even if a changeset is otherwise invalid. This This means that it'll go for it even if a changeset is otherwise invalid. This
is pretty easy to change, but for MVP I'm not concerned. is pretty easy to change, but for MVP I'm not concerned.
""" """
def change_source_from_url(%Source{} = channel, attrs) do def change_source_from_url(%Source{} = source, attrs) do
case change_source(channel, attrs) do case change_source(source, attrs) do
%Ecto.Changeset{changes: %{original_url: _}} = changeset -> %Ecto.Changeset{changes: %{original_url: _}} = changeset ->
add_source_details_to_changeset(channel, changeset) add_source_details_to_changeset(source, changeset)
changeset -> changeset ->
changeset changeset
end end
end end
defp add_source_details_to_changeset(channel, changeset) do defp add_source_details_to_changeset(source, changeset) do
%Ecto.Changeset{changes: changes} = changeset %Ecto.Changeset{changes: changes} = changeset
case ChannelDetails.get_source_details(changes.original_url) do case SourceDetails.get_source_details(changes.original_url) do
{:ok, %ChannelDetails{} = channel_details} -> {:ok, %SourceDetails{} = source_details} ->
change_source( change_source(
channel, source,
Map.merge(changes, %{ Map.merge(changes, %{
name: channel_details.name, name: source_details.name,
collection_id: channel_details.id collection_id: source_details.id
}) })
) )
@ -128,7 +128,7 @@ defmodule Pinchflat.MediaSource do
Ecto.Changeset.add_error( Ecto.Changeset.add_error(
changeset, changeset,
:original_url, :original_url,
"could not fetch channel details from URL", "could not fetch source details from URL",
error: runner_error error: runner_error
) )
end end
@ -136,27 +136,27 @@ defmodule Pinchflat.MediaSource do
defp commit_and_start_indexing(changeset) do defp commit_and_start_indexing(changeset) do
case Repo.insert_or_update(changeset) do case Repo.insert_or_update(changeset) do
{:ok, %Source{} = channel} -> {:ok, %Source{} = source} ->
maybe_run_indexing_task(changeset, channel) maybe_run_indexing_task(changeset, source)
{:ok, channel} {:ok, source}
err -> err ->
err err
end end
end end
defp maybe_run_indexing_task(changeset, channel) do defp maybe_run_indexing_task(changeset, source) do
case changeset.data do case changeset.data do
# If the changeset is new (not persisted), attempt indexing no matter what # If the changeset is new (not persisted), attempt indexing no matter what
%{__meta__: %{state: :built}} -> %{__meta__: %{state: :built}} ->
SourceTasks.kickoff_indexing_task(channel) SourceTasks.kickoff_indexing_task(source)
# If the record has been persisted, only attempt indexing if the # If the record has been persisted, only attempt indexing if the
# indexing frequency has been changed # indexing frequency has been changed
%{__meta__: %{state: :loaded}} -> %{__meta__: %{state: :loaded}} ->
if Map.has_key?(changeset.changes, :index_frequency_minutes) do if Map.has_key?(changeset.changes, :index_frequency_minutes) do
SourceTasks.kickoff_indexing_task(channel) SourceTasks.kickoff_indexing_task(source)
end end
end end
end end

View file

@ -71,7 +71,7 @@ defmodule Pinchflat.Tasks do
def create_task(%Oban.Job{} = job, attached_record) do def create_task(%Oban.Job{} = job, attached_record) do
attached_record_attr = attached_record_attr =
case attached_record do case attached_record do
%Source{} = channel -> %{source_id: channel.id} %Source{} = source -> %{source_id: source.id}
%MediaItem{} = media_item -> %{media_item_id: media_item.id} %MediaItem{} = media_item -> %{media_item_id: media_item.id}
end end

View file

@ -2,7 +2,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.ChannelTest do
use ExUnit.Case, async: true use ExUnit.Case, async: true
import Mox import Mox
alias Pinchflat.MediaClient.ChannelDetails alias Pinchflat.MediaClient.SourceDetails
alias Pinchflat.MediaClient.Backends.YtDlp.Channel alias Pinchflat.MediaClient.Backends.YtDlp.Channel
@channel_url "https://www.youtube.com/c/TheUselessTrials" @channel_url "https://www.youtube.com/c/TheUselessTrials"
@ -10,13 +10,13 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.ChannelTest do
setup :verify_on_exit! setup :verify_on_exit!
describe "get_source_details/1" do describe "get_source_details/1" do
test "it returns a %ChannelDetails{} with data on success" do test "it returns a %SourceDetails{} with data on success" do
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot ->
{:ok, "{\"channel\": \"TheUselessTrials\", \"channel_id\": \"UCQH2\"}"} {:ok, "{\"channel\": \"TheUselessTrials\", \"channel_id\": \"UCQH2\"}"}
end) end)
assert {:ok, res} = Channel.get_source_details(@channel_url) assert {:ok, res} = Channel.get_source_details(@channel_url)
assert %ChannelDetails{id: "UCQH2", name: "TheUselessTrials"} = res assert %SourceDetails{id: "UCQH2", name: "TheUselessTrials"} = res
end end
test "it passes the expected args to the backend runner" do test "it passes the expected args to the backend runner" do

View file

@ -1,8 +1,8 @@
defmodule Pinchflat.MediaClient.ChannelDetailsTest do defmodule Pinchflat.MediaClient.SourceDetailsTest do
use ExUnit.Case, async: true use ExUnit.Case, async: true
import Mox import Mox
alias Pinchflat.MediaClient.ChannelDetails alias Pinchflat.MediaClient.SourceDetails
@channel_url "https://www.youtube.com/c/TheUselessTrials" @channel_url "https://www.youtube.com/c/TheUselessTrials"
@ -10,8 +10,8 @@ defmodule Pinchflat.MediaClient.ChannelDetailsTest do
describe "new/2" do describe "new/2" do
test "it returns a struct with the given values" do test "it returns a struct with the given values" do
assert %ChannelDetails{id: "UCQH2", name: "TheUselessTrials"} = assert %SourceDetails{id: "UCQH2", name: "TheUselessTrials"} =
ChannelDetails.new("UCQH2", "TheUselessTrials") SourceDetails.new("UCQH2", "TheUselessTrials")
end end
end end
@ -24,7 +24,7 @@ defmodule Pinchflat.MediaClient.ChannelDetailsTest do
{:ok, "{\"channel\": \"TheUselessTrials\", \"channel_id\": \"UCQH2\"}"} {:ok, "{\"channel\": \"TheUselessTrials\", \"channel_id\": \"UCQH2\"}"}
end) end)
assert {:ok, _} = ChannelDetails.get_source_details(@channel_url) assert {:ok, _} = SourceDetails.get_source_details(@channel_url)
end end
test "it returns a struct composed of the returned data" do test "it returns a struct composed of the returned data" do
@ -32,8 +32,8 @@ defmodule Pinchflat.MediaClient.ChannelDetailsTest do
{:ok, "{\"channel\": \"TheUselessTrials\", \"channel_id\": \"UCQH2\"}"} {:ok, "{\"channel\": \"TheUselessTrials\", \"channel_id\": \"UCQH2\"}"}
end) end)
assert {:ok, res} = ChannelDetails.get_source_details(@channel_url) assert {:ok, res} = SourceDetails.get_source_details(@channel_url)
assert %ChannelDetails{id: "UCQH2", name: "TheUselessTrials"} = res assert %SourceDetails{id: "UCQH2", name: "TheUselessTrials"} = res
end end
end end
@ -46,7 +46,7 @@ defmodule Pinchflat.MediaClient.ChannelDetailsTest do
{:ok, ""} {:ok, ""}
end) end)
assert {:ok, _} = ChannelDetails.get_video_ids(@channel_url) assert {:ok, _} = SourceDetails.get_video_ids(@channel_url)
end end
test "it returns a list of strings" do test "it returns a list of strings" do
@ -54,7 +54,7 @@ defmodule Pinchflat.MediaClient.ChannelDetailsTest do
{:ok, "video1\nvideo2\nvideo3"} {:ok, "video1\nvideo2\nvideo3"}
end) end)
assert {:ok, ["video1", "video2", "video3"]} = ChannelDetails.get_video_ids(@channel_url) assert {:ok, ["video1", "video2", "video3"]} = SourceDetails.get_video_ids(@channel_url)
end end
end end
end end

View file

@ -301,7 +301,7 @@ defmodule Pinchflat.MediaSourceTest do
}) })
assert %Ecto.Changeset{} = changeset assert %Ecto.Changeset{} = changeset
assert errors_on(changeset).original_url == ["could not fetch channel details from URL"] assert errors_on(changeset).original_url == ["could not fetch source details from URL"]
end end
end end