Started adding youtube API for fast indexing
This commit is contained in:
parent
af86ca1e0e
commit
2fc5e20077
7 changed files with 88 additions and 11 deletions
|
|
@ -12,3 +12,5 @@ services:
|
|||
- ./docker-run.dev.sh
|
||||
stdin_open: true
|
||||
tty: true
|
||||
env_file:
|
||||
- .env
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpers do
|
|||
downloaded_.
|
||||
"""
|
||||
def kickoff_download_tasks_from_youtube_rss_feed(%Source{} = source) do
|
||||
{:ok, media_ids} = YoutubeRss.get_recent_media_ids_from_rss(source)
|
||||
{:ok, media_ids} = YoutubeRss.get_recent_media_ids(source)
|
||||
existing_media_items = list_media_items_by_media_id_for(source, media_ids)
|
||||
new_media_ids = media_ids -- Enum.map(existing_media_items, & &1.media_id)
|
||||
|
||||
|
|
|
|||
66
lib/pinchflat/fast_indexing/youtube_api.ex
Normal file
66
lib/pinchflat/fast_indexing/youtube_api.ex
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
defmodule Pinchflat.FastIndexing.YoutubeApi do
|
||||
@moduledoc """
|
||||
TODO
|
||||
"""
|
||||
|
||||
require Logger
|
||||
|
||||
alias Pinchflat.Sources.Source
|
||||
alias Pinchflat.Utils.FunctionUtils
|
||||
|
||||
# TODO: test
|
||||
# TODO: make this a behaviour
|
||||
def get_recent_media_ids(%Source{} = source) do
|
||||
api_response =
|
||||
source
|
||||
|> determine_playlist_id()
|
||||
|> do_api_request()
|
||||
|
||||
case api_response do
|
||||
{:ok, parsed_json} -> get_media_ids_from_response(parsed_json)
|
||||
{:error, reason} -> {:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
# The UC prefix is for channels which won't work with this API endpoint. Swapping
|
||||
# the prefix to UU will get us the playlist that represents the channel's uploads
|
||||
defp determine_playlist_id(%{collection_id: c_id}) do
|
||||
String.replace_prefix(c_id, "UC", "UU")
|
||||
end
|
||||
|
||||
defp do_api_request(playlist_id) do
|
||||
Logger.debug("Fetching recent media IDs from YouTube API for playlist: #{playlist_id}")
|
||||
|
||||
api_base = "https://youtube.googleapis.com/youtube/v3/playlistItems"
|
||||
request_url = "#{api_base}?part=contentDetails&maxResults=50&playlistId=#{playlist_id}&key=#{api_key()}"
|
||||
|
||||
case http_client().get(request_url, accept: "application/json") do
|
||||
{:ok, response} ->
|
||||
Phoenix.json_library().decode(response)
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
defp get_media_ids_from_response(parsed_json) do
|
||||
parsed_json
|
||||
|> Map.get("items", [])
|
||||
|> Enum.map(fn item ->
|
||||
item
|
||||
|> Map.get("contentDetails", %{})
|
||||
|> Map.get("videoId", nil)
|
||||
end)
|
||||
|> Enum.reject(&is_nil/1)
|
||||
|> FunctionUtils.wrap_ok()
|
||||
end
|
||||
|
||||
# TODO: replace this with a user setting
|
||||
defp api_key do
|
||||
System.get_env("YOUTUBE_API_KEY")
|
||||
end
|
||||
|
||||
defp http_client do
|
||||
Application.get_env(:pinchflat, :http_client, Pinchflat.HTTP.HTTPClient)
|
||||
end
|
||||
end
|
||||
3
lib/pinchflat/fast_indexing/youtube_behaviour.ex
Normal file
3
lib/pinchflat/fast_indexing/youtube_behaviour.ex
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
defmodule Pinchflat.FastIndexing.YoutubeBehaviour do
|
||||
# TODO
|
||||
end
|
||||
|
|
@ -12,7 +12,7 @@ defmodule Pinchflat.FastIndexing.YoutubeRss do
|
|||
|
||||
Returns {:ok, [binary()]} | {:error, binary()}
|
||||
"""
|
||||
def get_recent_media_ids_from_rss(%Source{} = source) do
|
||||
def get_recent_media_ids(%Source{} = source) do
|
||||
Logger.debug("Fetching recent media IDs from YouTube RSS feed for source: #{source.collection_id}")
|
||||
|
||||
case http_client().get(rss_url_for_source(source)) do
|
||||
|
|
|
|||
|
|
@ -21,9 +21,11 @@ defmodule Pinchflat.HTTP.HTTPClient do
|
|||
"""
|
||||
@impl HTTPBehaviour
|
||||
def get(url, headers \\ [], opts \\ []) do
|
||||
headers = parse_headers(headers)
|
||||
|
||||
case :httpc.request(:get, {url, headers}, [], opts) do
|
||||
{:ok, {{_version, 200, _reason_phrase}, _headers, body}} ->
|
||||
{:ok, body}
|
||||
{:ok, to_string(body)}
|
||||
|
||||
{:ok, {{_version, status_code, reason_phrase}, _headers, _body}} ->
|
||||
{:error, "HTTP request failed with status code #{status_code}: #{reason_phrase}"}
|
||||
|
|
@ -32,4 +34,8 @@ defmodule Pinchflat.HTTP.HTTPClient do
|
|||
{:error, "HTTP request failed: #{reason}"}
|
||||
end
|
||||
end
|
||||
|
||||
defp parse_headers(headers) do
|
||||
Enum.map(headers, fn {k, v} -> {to_charlist(k), to_charlist(v)} end)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ defmodule Pinchflat.FastIndexing.YoutubeRssTest do
|
|||
{:ok, source: source}
|
||||
end
|
||||
|
||||
describe "get_recent_media_ids_from_rss/1" do
|
||||
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 +21,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 +33,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 +47,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 +55,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 +63,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 +71,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
|
||||
|
|
|
|||
Loading…
Reference in a new issue