[Enhancement] Optionally use the YouTube API for improved fast indexing (#282)
* Started adding youtube API for fast indexing * Hooked youtube API into fast indexing * Added youtube_api_key to settings * Added youtube api key to settings UI * Added tests * Refactored the youtube api module * More refactor * Changed editing mode name from basic to standard * [WIP] started on copy changes * Updated copy
This commit is contained in:
@@ -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, "<yt:videoId>test_1</yt:videoId>"} 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, "<yt:videoId>test_1</yt:videoId>"} 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, "<yt:videoId>test_1</yt:videoId>"}
|
||||
end)
|
||||
|
||||
Settings.set(youtube_api_key: nil)
|
||||
|
||||
assert [%MediaItem{}] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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
|
||||
@@ -11,7 +11,13 @@ defmodule Pinchflat.FastIndexing.YoutubeRssTest do
|
||||
{:ok, source: source}
|
||||
end
|
||||
|
||||
describe "get_recent_media_ids_from_rss/1" do
|
||||
describe "enabled?/0" do
|
||||
test "returns true" do
|
||||
assert YoutubeRss.enabled?()
|
||||
end
|
||||
end
|
||||
|
||||
describe "get_recent_media_ids/1" do
|
||||
test "calls the expected URL for channel sources" do
|
||||
source = source_fixture(collection_type: :channel, collection_id: "channel_id")
|
||||
|
||||
@@ -21,7 +27,7 @@ defmodule Pinchflat.FastIndexing.YoutubeRssTest do
|
||||
{:ok, ""}
|
||||
end)
|
||||
|
||||
assert {:ok, _} = YoutubeRss.get_recent_media_ids_from_rss(source)
|
||||
assert {:ok, _} = YoutubeRss.get_recent_media_ids(source)
|
||||
end
|
||||
|
||||
test "calls the expected URL for playlist sources" do
|
||||
@@ -33,13 +39,13 @@ defmodule Pinchflat.FastIndexing.YoutubeRssTest do
|
||||
{:ok, ""}
|
||||
end)
|
||||
|
||||
assert {:ok, _} = YoutubeRss.get_recent_media_ids_from_rss(source)
|
||||
assert {:ok, _} = YoutubeRss.get_recent_media_ids(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)
|
||||
assert {:error, "Failed to fetch RSS feed"} = YoutubeRss.get_recent_media_ids(source)
|
||||
end
|
||||
|
||||
test "returns the media IDs from the RSS feed", %{source: source} do
|
||||
@@ -47,7 +53,7 @@ defmodule Pinchflat.FastIndexing.YoutubeRssTest do
|
||||
{: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)
|
||||
assert {:ok, ["test_1", "test_2"]} = YoutubeRss.get_recent_media_ids(source)
|
||||
end
|
||||
|
||||
test "strips whitespace from media IDs", %{source: source} do
|
||||
@@ -55,7 +61,7 @@ defmodule Pinchflat.FastIndexing.YoutubeRssTest do
|
||||
{: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)
|
||||
assert {:ok, ["test_1", "test_2"]} = YoutubeRss.get_recent_media_ids(source)
|
||||
end
|
||||
|
||||
test "removes empty media IDs", %{source: source} do
|
||||
@@ -63,7 +69,7 @@ defmodule Pinchflat.FastIndexing.YoutubeRssTest do
|
||||
{:ok, "<yt:videoId>test_1</yt:videoId><yt:videoId></yt:videoId>"}
|
||||
end)
|
||||
|
||||
assert {:ok, ["test_1"]} = YoutubeRss.get_recent_media_ids_from_rss(source)
|
||||
assert {:ok, ["test_1"]} = YoutubeRss.get_recent_media_ids(source)
|
||||
end
|
||||
|
||||
test "removes duplicate media IDs", %{source: source} do
|
||||
@@ -71,7 +77,7 @@ defmodule Pinchflat.FastIndexing.YoutubeRssTest do
|
||||
{:ok, "<yt:videoId>test_1</yt:videoId><yt:videoId>test_1</yt:videoId>"}
|
||||
end)
|
||||
|
||||
assert {:ok, ["test_1"]} = YoutubeRss.get_recent_media_ids_from_rss(source)
|
||||
assert {:ok, ["test_1"]} = YoutubeRss.get_recent_media_ids(source)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user