diff --git a/lib/pinchflat/fast_indexing/fast_indexing_helpers.ex b/lib/pinchflat/fast_indexing/fast_indexing_helpers.ex
index bad6af3..02fc00f 100644
--- a/lib/pinchflat/fast_indexing/fast_indexing_helpers.ex
+++ b/lib/pinchflat/fast_indexing/fast_indexing_helpers.ex
@@ -51,7 +51,6 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpers do
# If possible, use the YouTube API to fetch media IDs. If that fails, fall back to the RSS feed.
# If the YouTube API isn't set up, just use the RSS feed.
defp get_recent_media_ids(source) do
- # TODO: test
with true <- YoutubeApi.enabled?(),
{:ok, media_ids} <- YoutubeApi.get_recent_media_ids(source) do
{:ok, media_ids}
diff --git a/lib/pinchflat/fast_indexing/youtube_api.ex b/lib/pinchflat/fast_indexing/youtube_api.ex
index b41450e..03796f1 100644
--- a/lib/pinchflat/fast_indexing/youtube_api.ex
+++ b/lib/pinchflat/fast_indexing/youtube_api.ex
@@ -5,6 +5,7 @@ defmodule Pinchflat.FastIndexing.YoutubeApi do
require Logger
+ alias Pinchflat.Settings
alias Pinchflat.Sources.Source
alias Pinchflat.Utils.FunctionUtils
alias Pinchflat.FastIndexing.YoutubeBehaviour
@@ -12,16 +13,14 @@ defmodule Pinchflat.FastIndexing.YoutubeApi do
@behaviour YoutubeBehaviour
@doc """
- Determines if the YouTube API is enabled for fast indexing
+ Determines if the YouTube API is enabled for fast indexing by checking
+ if the user has an API key set
Returns boolean()
"""
- # TODO: test
- # TODO: update this to use a user setting
@impl YoutubeBehaviour
- def enabled?(), do: true
+ def enabled?(), do: is_binary(api_key())
- # TODO: test
@doc """
Fetches the recent media IDs from the YouTube API for a given source.
@@ -75,9 +74,8 @@ defmodule Pinchflat.FastIndexing.YoutubeApi do
|> FunctionUtils.wrap_ok()
end
- # TODO: replace this with a user setting
defp api_key do
- System.get_env("YOUTUBE_API_KEY")
+ Settings.get!(:youtube_api_key)
end
defp http_client do
diff --git a/lib/pinchflat/sources/source.ex b/lib/pinchflat/sources/source.ex
index 02af5bd..30b653f 100644
--- a/lib/pinchflat/sources/source.ex
+++ b/lib/pinchflat/sources/source.ex
@@ -128,7 +128,7 @@ defmodule Pinchflat.Sources.Source do
@doc false
def fast_index_frequency do
# minutes
- 15
+ 10
end
@doc false
diff --git a/test/pinchflat/fast_indexing/fast_indexing_helpers_test.exs b/test/pinchflat/fast_indexing/fast_indexing_helpers_test.exs
index 94d12aa..46f4226 100644
--- a/test/pinchflat/fast_indexing/fast_indexing_helpers_test.exs
+++ b/test/pinchflat/fast_indexing/fast_indexing_helpers_test.exs
@@ -6,19 +6,20 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do
import Pinchflat.ProfilesFixtures
alias Pinchflat.Tasks
+ alias Pinchflat.Settings
alias Pinchflat.Media.MediaItem
alias Pinchflat.Downloading.MediaDownloadWorker
alias Pinchflat.FastIndexing.FastIndexingHelpers
+ setup do
+ stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot ->
+ {:ok, media_attributes_return_fixture()}
+ end)
+
+ {:ok, [source: source_fixture()]}
+ end
+
describe "kickoff_download_tasks_from_youtube_rss_feed/1" do
- setup do
- stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot ->
- {:ok, media_attributes_return_fixture()}
- end)
-
- {:ok, [source: source_fixture()]}
- end
-
test "enqueues a new worker for each new media_id in the source's RSS feed", %{source: source} do
expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1"} end)
@@ -107,4 +108,49 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do
assert [] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
end
end
+
+ describe "kickoff_download_tasks_from_youtube_rss_feed/1 when testing backends" do
+ test "uses the YouTube API if it is enabled", %{source: source} do
+ expect(HTTPClientMock, :get, fn url, _headers ->
+ assert url =~ "https://youtube.googleapis.com/youtube/v3/playlistItems"
+
+ {:ok, "{}"}
+ end)
+
+ Settings.set(youtube_api_key: "test_key")
+
+ assert [] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
+ end
+
+ test "the YouTube API creates records as expected", %{source: source} do
+ expect(HTTPClientMock, :get, fn _url, _headers ->
+ {:ok, ~s({ "items": [ {"contentDetails": {"videoId": "test_1"}} ] })}
+ end)
+
+ Settings.set(youtube_api_key: "test_key")
+
+ assert [%MediaItem{}] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
+ end
+
+ test "RSS is used as a backup if the API fails", %{source: source} do
+ expect(HTTPClientMock, :get, fn _url, _headers -> {:error, ""} end)
+ expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1"} end)
+
+ Settings.set(youtube_api_key: "test_key")
+
+ assert [%MediaItem{}] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
+ end
+
+ test "RSS is used if the API is not enabled", %{source: source} do
+ expect(HTTPClientMock, :get, fn url ->
+ assert url =~ "https://www.youtube.com/feeds/videos.xml"
+
+ {:ok, "test_1"}
+ end)
+
+ Settings.set(youtube_api_key: nil)
+
+ assert [%MediaItem{}] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
+ end
+ end
end
diff --git a/test/pinchflat/fast_indexing/youtube_api_test.exs b/test/pinchflat/fast_indexing/youtube_api_test.exs
new file mode 100644
index 0000000..cc310d6
--- /dev/null
+++ b/test/pinchflat/fast_indexing/youtube_api_test.exs
@@ -0,0 +1,85 @@
+defmodule Pinchflat.FastIndexing.YoutubeApiTest do
+ use Pinchflat.DataCase
+
+ import Pinchflat.SourcesFixtures
+
+ alias Pinchflat.Settings
+ alias Pinchflat.FastIndexing.YoutubeApi
+
+ describe "enabled?/0" do
+ test "returns true if the user has set a YouTube API key" do
+ Settings.set(youtube_api_key: "test_key")
+
+ assert YoutubeApi.enabled?()
+ end
+
+ test "returns false if the user has not set an API key" do
+ Settings.set(youtube_api_key: nil)
+
+ refute YoutubeApi.enabled?()
+ end
+ end
+
+ describe "get_recent_media_ids/1" do
+ setup do
+ source = source_fixture()
+ Settings.set(youtube_api_key: "test_key")
+
+ {:ok, source: source}
+ end
+
+ test "calls the expected URL", %{source: source} do
+ expect(HTTPClientMock, :get, fn url, headers ->
+ api_base = "https://youtube.googleapis.com/youtube/v3/playlistItems"
+ request_url = "#{api_base}?part=contentDetails&maxResults=50&playlistId=#{source.collection_id}&key=test_key"
+
+ assert url == request_url
+ assert headers == [accept: "application/json"]
+
+ {:ok, "{}"}
+ end)
+
+ assert {:ok, _} = YoutubeApi.get_recent_media_ids(source)
+ end
+
+ test "replaces channel IDs with playlist IDs if needed" do
+ source = source_fixture(collection_id: "UC_ABC123")
+
+ expect(HTTPClientMock, :get, fn url, _headers ->
+ assert url =~ "playlistId=UU_ABC123&"
+
+ {:ok, "{}"}
+ end)
+
+ assert {:ok, _} = YoutubeApi.get_recent_media_ids(source)
+ end
+
+ test "returns an empty list if no media is returned", %{source: source} do
+ expect(HTTPClientMock, :get, fn _url, _headers -> {:ok, "{}"} end)
+
+ assert {:ok, []} = YoutubeApi.get_recent_media_ids(source)
+ end
+
+ test "returns media IDs if present", %{source: source} do
+ expect(HTTPClientMock, :get, fn _url, _headers ->
+ {:ok,
+ """
+ {
+ "items": [
+ {"contentDetails": {"videoId": "test_1"}},
+ {"contentDetails": {"videoId": "test_2"}}
+ ]
+ }
+ """}
+ end)
+
+ assert {:ok, ["test_1", "test_2"]} = YoutubeApi.get_recent_media_ids(source)
+ end
+
+ test "returns an error if the HTTP request fails", %{source: source} do
+ expect(HTTPClientMock, :get, fn _url, _headers -> {:error, "error"} end)
+
+ assert {:error, "error"} = YoutubeApi.get_recent_media_ids(source)
+ end
+ end
+end