Channel automatic update move

This commit is contained in:
Liam 2024-06-25 21:48:32 -04:00
parent a2368fcbf7
commit 813fb0fd97
4 changed files with 94 additions and 50 deletions

View file

@ -6,49 +6,15 @@ defmodule Philomena.Channels do
import Ecto.Query, warn: false
alias Philomena.Repo
alias Philomena.Channels.AutomaticUpdater
alias Philomena.Channels.Channel
alias Philomena.Channels.PicartoChannel
alias Philomena.Channels.PiczelChannel
alias Philomena.Notifications
@doc """
Updates all the tracked channels for which an update
scheme is known.
Updates all the tracked channels for which an update scheme is known.
"""
def update_tracked_channels! do
now = DateTime.utc_now() |> DateTime.truncate(:second)
picarto_channels = PicartoChannel.live_channels(now)
live_picarto_channels = Map.keys(picarto_channels)
piczel_channels = PiczelChannel.live_channels(now)
live_piczel_channels = Map.keys(piczel_channels)
# Update all channels which are offline to reflect offline status
offline_query =
from c in Channel,
where: c.type == "PicartoChannel" and c.short_name not in ^live_picarto_channels,
or_where: c.type == "PiczelChannel" and c.short_name not in ^live_piczel_channels
Repo.update_all(offline_query, set: [is_live: false, updated_at: now])
# Update all channels which are online to reflect online status using
# changeset functions
online_query =
from c in Channel,
where: c.type == "PicartoChannel" and c.short_name in ^live_picarto_channels,
or_where: c.type == "PiczelChannel" and c.short_name in ^live_picarto_channels
online_query
|> Repo.all()
|> Enum.map(fn
%{type: "PicartoChannel", short_name: name} = channel ->
Channel.update_changeset(channel, Map.get(picarto_channels, name, []))
%{type: "PiczelChannel", short_name: name} = channel ->
Channel.update_changeset(channel, Map.get(piczel_channels, name, []))
end)
|> Enum.map(&Repo.update!/1)
AutomaticUpdater.update_tracked_channels!()
end
@doc """
@ -103,6 +69,24 @@ defmodule Philomena.Channels do
|> Repo.update()
end
@doc """
Updates a channel's state when it goes live.
## Examples
iex> update_channel_state(channel, %{field: new_value})
{:ok, %Channel{}}
iex> update_channel_state(channel, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_channel_state(%Channel{} = channel, attrs) do
channel
|> Channel.update_changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a Channel.

View file

@ -0,0 +1,64 @@
defmodule Philomena.Channels.AutomaticUpdater do
@moduledoc """
Automatic update routine for streams.
Calls APIs for each stream provider to remove channels which are no longer online,
and to restore channels which are currently online.
"""
import Ecto.Query, warn: false
alias Philomena.Repo
alias Philomena.Channels
alias Philomena.Channels.Channel
alias Philomena.Channels.PicartoChannel
alias Philomena.Channels.PiczelChannel
@doc """
Updates all the tracked channels for which an update scheme is known.
"""
def update_tracked_channels! do
now = DateTime.utc_now(:second)
Enum.each(providers(), &update_provider(&1, now))
end
defp providers do
[
{"PicartoChannel", PicartoChannel.live_channels()},
{"PiczelChannel", PiczelChannel.live_channels()}
]
end
defp update_provider({provider_name, live_channels}, now) do
channel_names = Map.keys(live_channels)
provider_name
|> update_offline_query(channel_names, now)
|> Repo.update_all([])
provider_name
|> online_query(channel_names)
|> Repo.all()
|> Enum.each(&update_online_channel(&1, live_channels, now))
end
defp update_offline_query(provider_name, channel_names, now) do
from c in Channel,
where: c.type == ^provider_name and c.short_name not in ^channel_names,
update: [set: [is_live: false, updated_at: ^now]]
end
defp online_query(provider_name, channel_names) do
from c in Channel,
where: c.type == ^provider_name and c.short_name in ^channel_names
end
defp update_online_channel(channel, live_channels, now) do
attrs =
live_channels
|> Map.get(channel.short_name, %{})
|> Map.merge(%{last_live_at: now, last_fetched_at: now})
Channels.update_channel_state(channel, attrs)
end
end

View file

@ -1,30 +1,28 @@
defmodule Philomena.Channels.PicartoChannel do
@api_online "https://api.picarto.tv/api/v1/online?adult=true&gaming=true"
@spec live_channels(DateTime.t()) :: map()
def live_channels(now) do
@spec live_channels() :: map()
def live_channels do
@api_online
|> PhilomenaProxy.Http.get()
|> case do
{:ok, %{body: body, status: 200}} ->
body
|> Jason.decode!()
|> Map.new(&{&1["name"], fetch(&1, now)})
|> Map.new(&{&1["name"], fetch(&1)})
_error ->
%{}
end
end
defp fetch(api, now) do
defp fetch(api) do
%{
title: api["title"],
is_live: true,
nsfw: api["adult"],
viewers: api["viewers"],
thumbnail_url: api["thumbnails"]["web"],
last_fetched_at: now,
last_live_at: now,
description: nil
}
end

View file

@ -1,30 +1,28 @@
defmodule Philomena.Channels.PiczelChannel do
@api_online "https://api.piczel.tv/api/streams"
@spec live_channels(DateTime.t()) :: map()
def live_channels(now) do
@spec live_channels() :: map()
def live_channels do
@api_online
|> PhilomenaProxy.Http.get()
|> case do
{:ok, %{body: body, status: 200}} ->
body
|> Jason.decode!()
|> Map.new(&{&1["slug"], fetch(&1, now)})
|> Map.new(&{&1["slug"], fetch(&1)})
_error ->
%{}
end
end
defp fetch(api, now) do
defp fetch(api) do
%{
title: api["title"],
is_live: api["live"],
nsfw: api["adult"],
viewers: api["viewers"],
thumbnail_url: api["user"]["avatar"]["avatar"]["url"],
last_fetched_at: now,
last_live_at: now
thumbnail_url: api["user"]["avatar"]["avatar"]["url"]
}
end
end