Skip to content

Commit

Permalink
Merge pull request #312 from philomena-dev/channel-extraction
Browse files Browse the repository at this point in the history
Channel automatic update move
  • Loading branch information
liamwhite authored Jul 1, 2024
2 parents 153ea65 + 813fb0f commit d799c9d
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 50 deletions.
58 changes: 21 additions & 37 deletions lib/philomena/channels.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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 """
Expand Down Expand Up @@ -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.
Expand Down
64 changes: 64 additions & 0 deletions lib/philomena/channels/automatic_updater.ex
Original file line number Diff line number Diff line change
@@ -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
10 changes: 4 additions & 6 deletions lib/philomena/channels/picarto_channel.ex
Original file line number Diff line number Diff line change
@@ -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
Expand Down
12 changes: 5 additions & 7 deletions lib/philomena/channels/piczel_channel.ex
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit d799c9d

Please sign in to comment.