Added module for working with youtube RSS feed
This commit is contained in:
parent
de18b67480
commit
4b63a39883
5 changed files with 125 additions and 4 deletions
12
.iex.exs
12
.iex.exs
|
|
@ -1,10 +1,10 @@
|
|||
alias Pinchflat.Repo
|
||||
|
||||
alias Pinchflat.Tasks.Task
|
||||
alias Pinchflat.Sources.Source
|
||||
alias Pinchflat.Media.MediaItem
|
||||
alias Pinchflat.Tasks.SourceTasks
|
||||
alias Pinchflat.Media.MediaMetadata
|
||||
alias Pinchflat.Sources.Source
|
||||
alias Pinchflat.Profiles.MediaProfile
|
||||
|
||||
alias Pinchflat.Tasks
|
||||
|
|
@ -13,7 +13,11 @@ alias Pinchflat.Profiles
|
|||
alias Pinchflat.Sources
|
||||
alias Pinchflat.Settings
|
||||
|
||||
alias Pinchflat.MediaClient.{SourceDetails, MediaDownloader}
|
||||
alias Pinchflat.MediaClient.MediaDownloader
|
||||
alias Pinchflat.YtDlp.Backend.Media, as: YtDlpMedia
|
||||
alias Pinchflat.YtDlp.Backend.MediaCollection, as: YtDlpCollection
|
||||
|
||||
alias Pinchflat.Api.YoutubeRss
|
||||
alias Pinchflat.Metadata.MetadataFileHelpers
|
||||
|
||||
alias Pinchflat.Utils.FilesystemUtils.FileFollowerServer
|
||||
|
|
@ -38,7 +42,7 @@ defmodule IexHelpers do
|
|||
:channel -> channel_url()
|
||||
end
|
||||
|
||||
SourceDetails.get_source_details(source)
|
||||
YtDlpCollection.get_source_details(source)
|
||||
end
|
||||
|
||||
def ids(type) do
|
||||
|
|
@ -48,7 +52,7 @@ defmodule IexHelpers do
|
|||
:channel -> channel_url()
|
||||
end
|
||||
|
||||
SourceDetails.get_media_attributes_for_collection(source)
|
||||
YtDlpCollection.get_media_attributes_for_collection(source)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
44
lib/pinchflat/api/youtube_rss.ex
Normal file
44
lib/pinchflat/api/youtube_rss.ex
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
defmodule Pinchflat.Api.YoutubeRss do
|
||||
@moduledoc """
|
||||
Methods for interacting with YouTube RSS feeds
|
||||
"""
|
||||
|
||||
alias Pinchflat.Sources.Source
|
||||
|
||||
@doc """
|
||||
Fetches the recent media IDs from a YouTube RSS feed for a given source.
|
||||
|
||||
Returns {:ok, [binary()]} | {:error, binary()}
|
||||
"""
|
||||
def get_recent_media_ids_from_rss(%Source{} = source) do
|
||||
case http_client().get(rss_url_for_source(source)) do
|
||||
{:ok, response} ->
|
||||
response = to_string(response)
|
||||
media_id_regex = ~r/<yt:videoId>(.*?)<\/yt:videoId>/
|
||||
|
||||
# Don't get on me about using regex to search XML.
|
||||
# The content is known, well-formed, and simple.
|
||||
media_ids =
|
||||
media_id_regex
|
||||
|> Regex.scan(response)
|
||||
|> Enum.map(fn [_, id] -> String.trim(id) end)
|
||||
|> Enum.filter(&(String.length(&1) > 0))
|
||||
|
||||
{:ok, media_ids}
|
||||
|
||||
{:error, _reason} ->
|
||||
{:error, "Failed to fetch RSS feed"}
|
||||
end
|
||||
end
|
||||
|
||||
defp rss_url_for_source(source) do
|
||||
case source.collection_type do
|
||||
:channel -> "https://www.youtube.com/feeds/videos.xml?channel_id=#{source.collection_id}"
|
||||
:playlist -> "https://www.youtube.com/feeds/videos.xml?playlist_id=#{source.collection_id}"
|
||||
end
|
||||
end
|
||||
|
||||
defp http_client do
|
||||
Application.get_env(:pinchflat, :http_client, Pinchflat.HTTP.HTTPClient)
|
||||
end
|
||||
end
|
||||
|
|
@ -4,5 +4,7 @@ defmodule Pinchflat.HTTP.HTTPBehaviour do
|
|||
so I can use Mox to create an HTTP mock
|
||||
"""
|
||||
|
||||
@callback get(String.t()) :: {:ok, String.t()} | {:error, String.t()}
|
||||
@callback get(String.t(), Keyword.t()) :: {:ok, String.t()} | {:error, String.t()}
|
||||
@callback get(String.t(), Keyword.t(), Keyword.t()) :: {:ok, String.t()} | {:error, String.t()}
|
||||
end
|
||||
|
|
|
|||
71
test/pinchflat/api/youtube_rss_test.exs
Normal file
71
test/pinchflat/api/youtube_rss_test.exs
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
defmodule Pinchflat.Api.YoutubeRssTest do
|
||||
use Pinchflat.DataCase
|
||||
import Mox
|
||||
import Pinchflat.SourcesFixtures
|
||||
|
||||
alias Pinchflat.Api.YoutubeRss
|
||||
|
||||
setup :verify_on_exit!
|
||||
|
||||
setup do
|
||||
source = source_fixture()
|
||||
|
||||
{:ok, source: source}
|
||||
end
|
||||
|
||||
describe "get_recent_media_ids_from_rss/1" do
|
||||
test "calls the expected URL for channel sources" do
|
||||
source = source_fixture(collection_type: :channel, collection_id: "channel_id")
|
||||
|
||||
expect(HTTPClientMock, :get, fn url ->
|
||||
assert url =~ "https://www.youtube.com/feeds/videos.xml?channel_id=#{source.collection_id}"
|
||||
|
||||
{:ok, ""}
|
||||
end)
|
||||
|
||||
assert {:ok, _} = YoutubeRss.get_recent_media_ids_from_rss(source)
|
||||
end
|
||||
|
||||
test "calls the expected URL for playlist sources" do
|
||||
source = source_fixture(collection_type: :playlist, collection_id: "playlist_id")
|
||||
|
||||
expect(HTTPClientMock, :get, fn url ->
|
||||
assert url =~ "https://www.youtube.com/feeds/videos.xml?playlist_id=#{source.collection_id}"
|
||||
|
||||
{:ok, ""}
|
||||
end)
|
||||
|
||||
assert {:ok, _} = YoutubeRss.get_recent_media_ids_from_rss(source)
|
||||
end
|
||||
|
||||
test "returns an error if the HTTP request fails", %{source: source} do
|
||||
expect(HTTPClientMock, :get, fn _url -> {:error, ""} end)
|
||||
|
||||
assert {:error, "Failed to fetch RSS feed"} = YoutubeRss.get_recent_media_ids_from_rss(source)
|
||||
end
|
||||
|
||||
test "returns the media IDs from the RSS feed", %{source: source} do
|
||||
expect(HTTPClientMock, :get, fn _url ->
|
||||
{:ok, "<yt:videoId>test_1</yt:videoId><yt:videoId>test_2</yt:videoId>"}
|
||||
end)
|
||||
|
||||
assert {:ok, ["test_1", "test_2"]} = YoutubeRss.get_recent_media_ids_from_rss(source)
|
||||
end
|
||||
|
||||
test "strips whitespace from media IDs", %{source: source} do
|
||||
expect(HTTPClientMock, :get, fn _url ->
|
||||
{:ok, "<yt:videoId> test_1 </yt:videoId><yt:videoId> test_2 </yt:videoId>"}
|
||||
end)
|
||||
|
||||
assert {:ok, ["test_1", "test_2"]} = YoutubeRss.get_recent_media_ids_from_rss(source)
|
||||
end
|
||||
|
||||
test "removes empty media IDs", %{source: source} do
|
||||
expect(HTTPClientMock, :get, fn _url ->
|
||||
{:ok, "<yt:videoId>test_1</yt:videoId><yt:videoId></yt:videoId>"}
|
||||
end)
|
||||
|
||||
assert {:ok, ["test_1"]} = YoutubeRss.get_recent_media_ids_from_rss(source)
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue