diff --git a/.iex.exs b/.iex.exs index 29c42a6..d23dd0c 100644 --- a/.iex.exs +++ b/.iex.exs @@ -11,4 +11,4 @@ alias Pinchflat.Media alias Pinchflat.Profiles alias Pinchflat.MediaSource -alias Pinchflat.MediaClient.{ChannelDetails, VideoDownloader} +alias Pinchflat.MediaClient.{SourceDetails, VideoDownloader} diff --git a/lib/pinchflat/media.ex b/lib/pinchflat/media.ex index be05cf4..fe864ae 100644 --- a/lib/pinchflat/media.ex +++ b/lib/pinchflat/media.ex @@ -18,7 +18,7 @@ defmodule Pinchflat.Media do end @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`. Returns [%MediaItem{}, ...]. diff --git a/lib/pinchflat/media_client/backends/yt_dlp/channel.ex b/lib/pinchflat/media_client/backends/yt_dlp/channel.ex index 22cb8d6..783979e 100644 --- a/lib/pinchflat/media_client/backends/yt_dlp/channel.ex +++ b/lib/pinchflat/media_client/backends/yt_dlp/channel.ex @@ -4,7 +4,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.Channel do """ use Pinchflat.MediaClient.Backends.YtDlp.VideoCollection - alias Pinchflat.MediaClient.ChannelDetails + alias Pinchflat.MediaClient.SourceDetails @doc """ 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) 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 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, ChannelDetails.new(parsed_json["channel_id"], parsed_json["channel"])} + {:ok, SourceDetails.new(parsed_json["channel_id"], parsed_json["channel"])} else err -> err end diff --git a/lib/pinchflat/media_client/channel_details.ex b/lib/pinchflat/media_client/source_details.ex similarity index 51% rename from lib/pinchflat/media_client/channel_details.ex rename to lib/pinchflat/media_client/source_details.ex index c9909de..e8796c2 100644 --- a/lib/pinchflat/media_client/channel_details.ex +++ b/lib/pinchflat/media_client/source_details.ex @@ -1,6 +1,6 @@ -defmodule Pinchflat.MediaClient.ChannelDetails do +defmodule Pinchflat.MediaClient.SourceDetails do @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 it open-ish for future expansion (just in case). @@ -16,24 +16,24 @@ defmodule Pinchflat.MediaClient.ChannelDetails do end @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, ...}. """ - def get_source_details(channel_url, backend \\ :yt_dlp) do - channel_module(backend).get_source_details(channel_url) + def get_source_details(source_url, backend \\ :yt_dlp) do + source_module(backend).get_source_details(source_url) end @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, ...}. """ - def get_video_ids(channel_url, backend \\ :yt_dlp) do - channel_module(backend).get_video_ids(channel_url) + def get_video_ids(source_url, backend \\ :yt_dlp) do + source_module(backend).get_video_ids(source_url) end - defp channel_module(backend) do + defp source_module(backend) do case backend do :yt_dlp -> YtDlpChannel end diff --git a/lib/pinchflat/media_source.ex b/lib/pinchflat/media_source.ex index 750a932..2391036 100644 --- a/lib/pinchflat/media_source.ex +++ b/lib/pinchflat/media_source.ex @@ -10,25 +10,25 @@ defmodule Pinchflat.MediaSource do alias Pinchflat.Media alias Pinchflat.Tasks.SourceTasks alias Pinchflat.MediaSource.Source - alias Pinchflat.MediaClient.ChannelDetails + alias Pinchflat.MediaClient.SourceDetails @doc """ - Returns the list of channels. Returns [%Source{}, ...] + Returns the list of sources. Returns [%Source{}, ...] """ def list_sources do Repo.all(Source) end @doc """ - Gets a single channel. + Gets a single source. Returns %Source{}. Raises `Ecto.NoResultsError` if the Channel does not exist. """ def get_source!(id), do: Repo.get!(Source, id) @doc """ - Creates a channel. May attempt to pull additional channel details from the - original_url (if provided). Will attempt to start indexing the channel's + Creates a source. May attempt to pull additional source details from the + original_url (if provided). Will attempt to start indexing the source's media if successfully inserted. Returns {:ok, %Source{}} | {:error, %Ecto.Changeset{}} @@ -46,7 +46,7 @@ defmodule Pinchflat.MediaSource do Returns [%MediaItem{}, ...] | [%Ecto.Changeset{}, ...] """ 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 |> Enum.map(fn media_id -> @@ -60,8 +60,8 @@ defmodule Pinchflat.MediaSource do end @doc """ - Updates a channel. May attempt to pull additional channel details from the - original_url (if changed). May attempt to start indexing the channel's + Updates a source. May attempt to pull additional source details from the + original_url (if changed). May attempt to start indexing the source's media if the indexing frequency has been changed. 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{}} """ - def update_source(%Source{} = channel, attrs) do - channel + def update_source(%Source{} = source, attrs) do + source |> change_source_from_url(attrs) |> commit_and_start_indexing() end @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{}} """ - def delete_source(%Source{} = channel) do - Tasks.delete_tasks_for(channel) - Repo.delete(channel) + def delete_source(%Source{} = source) do + Tasks.delete_tasks_for(source) + Repo.delete(source) end @doc """ - Returns an `%Ecto.Changeset{}` for tracking channel changes. + Returns an `%Ecto.Changeset{}` for tracking source changes. """ - def change_source(%Source{} = channel, attrs \\ %{}) do - Source.changeset(channel, attrs) + def change_source(%Source{} = source, attrs \\ %{}) do + Source.changeset(source, attrs) end @doc """ - Returns an `%Ecto.Changeset{}` for tracking channel changes and additionally - fetches channel details from the original_url (if provided). If the channel + Returns an `%Ecto.Changeset{}` for tracking source changes and additionally + fetches source details from the original_url (if provided). If the source 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 is pretty easy to change, but for MVP I'm not concerned. """ - def change_source_from_url(%Source{} = channel, attrs) do - case change_source(channel, attrs) do + def change_source_from_url(%Source{} = source, attrs) do + case change_source(source, attrs) do %Ecto.Changeset{changes: %{original_url: _}} = changeset -> - add_source_details_to_changeset(channel, changeset) + add_source_details_to_changeset(source, changeset) changeset -> changeset 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 - case ChannelDetails.get_source_details(changes.original_url) do - {:ok, %ChannelDetails{} = channel_details} -> + case SourceDetails.get_source_details(changes.original_url) do + {:ok, %SourceDetails{} = source_details} -> change_source( - channel, + source, Map.merge(changes, %{ - name: channel_details.name, - collection_id: channel_details.id + name: source_details.name, + collection_id: source_details.id }) ) @@ -128,7 +128,7 @@ defmodule Pinchflat.MediaSource do Ecto.Changeset.add_error( changeset, :original_url, - "could not fetch channel details from URL", + "could not fetch source details from URL", error: runner_error ) end @@ -136,27 +136,27 @@ defmodule Pinchflat.MediaSource do defp commit_and_start_indexing(changeset) do case Repo.insert_or_update(changeset) do - {:ok, %Source{} = channel} -> - maybe_run_indexing_task(changeset, channel) + {:ok, %Source{} = source} -> + maybe_run_indexing_task(changeset, source) - {:ok, channel} + {:ok, source} err -> err end end - defp maybe_run_indexing_task(changeset, channel) do + defp maybe_run_indexing_task(changeset, source) do case changeset.data do # If the changeset is new (not persisted), attempt indexing no matter what %{__meta__: %{state: :built}} -> - SourceTasks.kickoff_indexing_task(channel) + SourceTasks.kickoff_indexing_task(source) # If the record has been persisted, only attempt indexing if the # indexing frequency has been changed %{__meta__: %{state: :loaded}} -> if Map.has_key?(changeset.changes, :index_frequency_minutes) do - SourceTasks.kickoff_indexing_task(channel) + SourceTasks.kickoff_indexing_task(source) end end end diff --git a/lib/pinchflat/tasks.ex b/lib/pinchflat/tasks.ex index 3bd5231..642864c 100644 --- a/lib/pinchflat/tasks.ex +++ b/lib/pinchflat/tasks.ex @@ -71,7 +71,7 @@ defmodule Pinchflat.Tasks do def create_task(%Oban.Job{} = job, attached_record) do attached_record_attr = 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} end diff --git a/test/pinchflat/media_client/backends/yt_dlp/channel_test.exs b/test/pinchflat/media_client/backends/yt_dlp/channel_test.exs index b8fdbb9..724e6e3 100644 --- a/test/pinchflat/media_client/backends/yt_dlp/channel_test.exs +++ b/test/pinchflat/media_client/backends/yt_dlp/channel_test.exs @@ -2,7 +2,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.ChannelTest do use ExUnit.Case, async: true import Mox - alias Pinchflat.MediaClient.ChannelDetails + alias Pinchflat.MediaClient.SourceDetails alias Pinchflat.MediaClient.Backends.YtDlp.Channel @channel_url "https://www.youtube.com/c/TheUselessTrials" @@ -10,13 +10,13 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.ChannelTest do setup :verify_on_exit! 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 -> {:ok, "{\"channel\": \"TheUselessTrials\", \"channel_id\": \"UCQH2\"}"} end) assert {:ok, res} = Channel.get_source_details(@channel_url) - assert %ChannelDetails{id: "UCQH2", name: "TheUselessTrials"} = res + assert %SourceDetails{id: "UCQH2", name: "TheUselessTrials"} = res end test "it passes the expected args to the backend runner" do diff --git a/test/pinchflat/media_client/channel_details_test.exs b/test/pinchflat/media_client/source_details_test.exs similarity index 67% rename from test/pinchflat/media_client/channel_details_test.exs rename to test/pinchflat/media_client/source_details_test.exs index 7ca3db5..244e65d 100644 --- a/test/pinchflat/media_client/channel_details_test.exs +++ b/test/pinchflat/media_client/source_details_test.exs @@ -1,8 +1,8 @@ -defmodule Pinchflat.MediaClient.ChannelDetailsTest do +defmodule Pinchflat.MediaClient.SourceDetailsTest do use ExUnit.Case, async: true import Mox - alias Pinchflat.MediaClient.ChannelDetails + alias Pinchflat.MediaClient.SourceDetails @channel_url "https://www.youtube.com/c/TheUselessTrials" @@ -10,8 +10,8 @@ defmodule Pinchflat.MediaClient.ChannelDetailsTest do describe "new/2" do test "it returns a struct with the given values" do - assert %ChannelDetails{id: "UCQH2", name: "TheUselessTrials"} = - ChannelDetails.new("UCQH2", "TheUselessTrials") + assert %SourceDetails{id: "UCQH2", name: "TheUselessTrials"} = + SourceDetails.new("UCQH2", "TheUselessTrials") end end @@ -24,7 +24,7 @@ defmodule Pinchflat.MediaClient.ChannelDetailsTest do {:ok, "{\"channel\": \"TheUselessTrials\", \"channel_id\": \"UCQH2\"}"} end) - assert {:ok, _} = ChannelDetails.get_source_details(@channel_url) + assert {:ok, _} = SourceDetails.get_source_details(@channel_url) end 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\"}"} end) - assert {:ok, res} = ChannelDetails.get_source_details(@channel_url) - assert %ChannelDetails{id: "UCQH2", name: "TheUselessTrials"} = res + assert {:ok, res} = SourceDetails.get_source_details(@channel_url) + assert %SourceDetails{id: "UCQH2", name: "TheUselessTrials"} = res end end @@ -46,7 +46,7 @@ defmodule Pinchflat.MediaClient.ChannelDetailsTest do {:ok, ""} end) - assert {:ok, _} = ChannelDetails.get_video_ids(@channel_url) + assert {:ok, _} = SourceDetails.get_video_ids(@channel_url) end test "it returns a list of strings" do @@ -54,7 +54,7 @@ defmodule Pinchflat.MediaClient.ChannelDetailsTest do {:ok, "video1\nvideo2\nvideo3"} 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 diff --git a/test/pinchflat/media_source_test.exs b/test/pinchflat/media_source_test.exs index 40e88b1..e113df5 100644 --- a/test/pinchflat/media_source_test.exs +++ b/test/pinchflat/media_source_test.exs @@ -301,7 +301,7 @@ defmodule Pinchflat.MediaSourceTest do }) 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