Skip to content

Commit

Permalink
Merge pull request #416 from midarrlabs/feature/automate-sending-push…
Browse files Browse the repository at this point in the history
…-notifications

Automate sending push notifications
  • Loading branch information
trueChazza authored Oct 15, 2023
2 parents 31a8a0e + 5631950 commit 36e71e8
Show file tree
Hide file tree
Showing 19 changed files with 304 additions and 102 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ env:
SONARR_BASE_URL: http://localhost:8989
SONARR_API_KEY: 1accda4476394bfcaddefe8c4fd77d4a

VAPID_PUBLIC_KEY: BDntLA3k5K1tsrFOXXAuS_9Ey30jxy-R2CAosC2DOQnTs8LpQGxpTEx3AcPXinVYFFpJI6tT_RJC8pHgUsdbhOk
VAPID_PRIVATE_KEY: RVPPDBVNmJtSLoZ28jE1SumpG4HyhhCPfcix3bvxbLw
VAPID_SUBJECT: mailto:admin@email.com

GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

Expand All @@ -40,7 +44,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
otp: [ '25' ]
otp: [ '24' ]
elixir: [ '1.15' ]

services:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ services:
To keep your media in sync, webhook urls are required in your integrations. Midarr accepts a
POST request from your integrations with your unique API Token (found on the Midarr Settings page).

Add your webhook urls to `Radarr / Sonarr -> Settings -> Connect`:
Add these webhook urls to Radarr / Sonarr under `Settings -> Connect -> Webhook`:

#### Radarr example
```
Expand Down
6 changes: 4 additions & 2 deletions lib/media_server/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ defmodule MediaServer.Application do
# {MediaServer.Worker, arg}
MediaServerWeb.Presence,
{DynamicSupervisor, name: MediaServer.DynamicSupervisor},
MediaServer.UserActions,
MediaServer.MoviesIndex,
MediaServer.SeriesIndex
MediaServer.SeriesIndex,
MediaServer.MovieActions,
MediaServer.SeriesActions,
MediaServer.UserActions
]

# See https://hexdocs.pm/elixir/Supervisor.html
Expand Down
22 changes: 21 additions & 1 deletion lib/media_server/media_actions.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
defmodule MediaServer.MediaActions do
use Ecto.Schema
import Ecto.Changeset
import Ecto.Query

alias MediaServer.Repo

Expand Down Expand Up @@ -59,6 +60,25 @@ defmodule MediaServer.MediaActions do

def delete(attrs) do
Repo.get_by(__MODULE__, attrs)
|> Repo.delete
|> Repo.delete()
end

def movie(id) do
from this in __MODULE__,
where: this.media_type_id == ^MediaServer.MediaTypes.get_movie_id() and this.media_id == ^id
end

def series(id) do
from this in __MODULE__,
where:
this.media_type_id == ^MediaServer.MediaTypes.get_series_id() and this.media_id == ^id
end

def followers(query) do
MediaServer.Repo.all(
from this in query,
where: this.action_id == ^MediaServer.Actions.get_followed_id(),
preload: [user: [:push_subscriptions]]
)
end
end
4 changes: 4 additions & 0 deletions lib/media_server/media_types.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ defmodule MediaServer.MediaTypes do
Repo.get_by!(__MODULE__, type: "movie").id
end

def get_series_id() do
Repo.get_by!(__MODULE__, type: "series").id
end

def get_episode_id() do
Repo.get_by!(__MODULE__, type: "episode").id
end
Expand Down
34 changes: 34 additions & 0 deletions lib/media_server/movie_actions.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
defmodule MediaServer.MovieActions do
use Task

def start_link(arg) do
Task.start_link(__MODULE__, :run, [arg])
end

def run(_arg) do
Phoenix.PubSub.subscribe(MediaServer.PubSub, "movie")
end

def handle_info({:added, %{"movie" => %{"id" => id, "title" => title}}}) do
MediaServer.MoviesIndex.reset()

followers = MediaServer.MediaActions.movie(id) |> MediaServer.MediaActions.followers()

Enum.each(followers, fn media_action ->
Enum.each(media_action.user.push_subscriptions, fn push_subscription ->
WebPushElixir.send_notification(
push_subscription.push_subscription,
"#{title} is now available"
)
end)
end)
end

def handle_info({:deleted}) do
MediaServer.MoviesIndex.reset()
end

def handle_info({:deleted_file}) do
MediaServer.MoviesIndex.reset()
end
end
2 changes: 1 addition & 1 deletion lib/media_server/push_subscriptions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ defmodule MediaServer.PushSubscriptions do

def delete(attrs) do
Repo.get_by(__MODULE__, attrs)
|> Repo.delete
|> Repo.delete()
end
end
36 changes: 36 additions & 0 deletions lib/media_server/series_actions.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
defmodule MediaServer.SeriesActions do
use Task

require Logger

def start_link(arg) do
Task.start_link(__MODULE__, :run, [arg])
end

def run(_arg) do
Phoenix.PubSub.subscribe(MediaServer.PubSub, "series")
end

def handle_info({:added, %{"series" => %{"id" => id, "title" => title}}}) do
MediaServer.SeriesIndex.reset()

followers = MediaServer.MediaActions.series(id) |> MediaServer.MediaActions.followers()

Enum.each(followers, fn media_action ->
Enum.each(media_action.user.push_subscriptions, fn push_subscription ->
WebPushElixir.send_notification(
push_subscription.push_subscription,
"#{title} is now available"
)
end)
end)
end

def handle_info({:deleted}) do
MediaServer.SeriesIndex.reset()
end

def handle_info({:deleted_episode_file}) do
MediaServer.SeriesIndex.reset()
end
end
20 changes: 12 additions & 8 deletions lib/media_server/user_actions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ defmodule MediaServer.UserActions do
end

def handle_info({:followed, params}, state) do

media_type_id = MediaServer.MediaTypes.get_type_id(params["media_type"])

MediaServer.MediaActions.create(%{
Expand All @@ -34,13 +33,14 @@ defmodule MediaServer.UserActions do
media_type_id: media_type_id
})

Logger.info("user_id:#{ params["user_id"] }:followed:media_type_id:#{ media_type_id }:media_id:#{ params["media_id"] }")
Logger.info(
"user_id:#{params["user_id"]}:followed:media_type_id:#{media_type_id}:media_id:#{params["media_id"]}"
)

{:noreply, state}
end

def handle_info({:unfollowed, params}, state) do

media_type_id = MediaServer.MediaTypes.get_type_id(params["media_type"])

MediaServer.MediaActions.delete(%{
Expand All @@ -50,31 +50,35 @@ defmodule MediaServer.UserActions do
media_type_id: media_type_id
})

Logger.info("user_id:#{ params["user_id"] }:unfollowed:media_type_id:#{ media_type_id }:media_id:#{ params["media_id"] }")
Logger.info(
"user_id:#{params["user_id"]}:unfollowed:media_type_id:#{media_type_id}:media_id:#{params["media_id"]}"
)

{:noreply, state}
end

def handle_info({:granted_push_notifications, params}, state) do

MediaServer.PushSubscriptions.create(%{
user_id: params["user_id"],
push_subscription: params["push_subscription"]
})

Logger.info("user_id:#{ params["user_id"] }:granted_push_notifications:media_type_id:#{ params["media_type_id"] }:media_id:#{ params["media_id"] }")
Logger.info(
"user_id:#{params["user_id"]}:granted_push_notifications:media_type_id:#{params["media_type_id"]}:media_id:#{params["media_id"]}"
)

{:noreply, state}
end

def handle_info({:denied_push_notifications, params}, state) do

MediaServer.PushSubscriptions.create(%{
user_id: params["user_id"],
push_subscription: params["message"]
})

Logger.info("user_id:#{ params["user_id"] }:denied_push_notifications:media_type_id:#{ params["media_type_id"] }:media_id:#{ params["media_id"] }")
Logger.info(
"user_id:#{params["user_id"]}:denied_push_notifications:media_type_id:#{params["media_type_id"]}:media_id:#{params["media_id"]}"
)

{:noreply, state}
end
Expand Down
15 changes: 10 additions & 5 deletions lib/media_server_web/components/follow_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@ defmodule MediaServerWeb.Components.FollowComponent do
@impl true
def preload(list_of_assigns) do
media_id = Enum.find(list_of_assigns, fn assign -> Map.get(assign, :media_id) end).media_id
media_type = Enum.find(list_of_assigns, fn assign -> Map.get(assign, :media_type) end).media_type

media_type =
Enum.find(list_of_assigns, fn assign -> Map.get(assign, :media_type) end).media_type

user_id = Enum.find(list_of_assigns, fn assign -> Map.get(assign, :user_id) end).user_id

media_type_id = MediaServer.MediaTypes.get_type_id(media_type)

query =
from media_actions in MediaServer.MediaActions,
where:
media_actions.media_type_id == ^media_type_id and
media_actions.user_id == ^user_id and media_actions.media_id == ^media_id and media_actions.action_id == ^MediaServer.Actions.get_followed_id
where:
media_actions.media_type_id == ^media_type_id and
media_actions.user_id == ^user_id and media_actions.media_id == ^media_id and
media_actions.action_id == ^MediaServer.Actions.get_followed_id()

result = MediaServer.Repo.all(query)

Expand All @@ -30,7 +34,8 @@ defmodule MediaServerWeb.Components.FollowComponent do
state: "Following",
event: "unfollow"
}
end |> Map.merge(%{
end
|> Map.merge(%{
media_id: assign.media_id,
media_type: assign.media_type,
user_id: assign.user_id,
Expand Down
2 changes: 1 addition & 1 deletion lib/media_server_web/components/follow_component.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@
class="inline-flex items-center gap-2 justify-center rounded-lg py-2 px-3 text-sm outline-offset-2 transition active:transition-none bg-zinc-800 font-semibold text-zinc-100 hover:bg-zinc-700 active:bg-zinc-800"
>
<%= @state %>
</button>
</button>
2 changes: 1 addition & 1 deletion lib/media_server_web/components/footer_component.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<div class="flex text-xs text-zinc-600 dark:text-zinc-400">
<p>Copyright © 2023 Midarr Labs</p>
<p class="ml-4 pl-4 border-l border-white/10">
v4.2.0-beta.1
v4.2.0-beta.2
</p>
</div>
<div class="flex gap-4">
Expand Down
16 changes: 8 additions & 8 deletions lib/media_server_web/controllers/webhooks_controller.ex
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
defmodule MediaServerWeb.WebhooksController do
use MediaServerWeb, :controller

def create(conn, %{"id" => "movie", "eventType" => "Download"}) do
MediaServer.MoviesIndex.reset()
def create(conn, %{"id" => "movie", "eventType" => "Download"} = params) do
Phoenix.PubSub.broadcast(MediaServer.PubSub, "movie", {:added, params})

conn
|> send_resp(201, "Ok")
end

def create(conn, %{"id" => "movie", "eventType" => "MovieDelete"}) do
MediaServer.MoviesIndex.reset()
Phoenix.PubSub.broadcast(MediaServer.PubSub, "movie", {:deleted})

conn
|> send_resp(201, "Ok")
end

def create(conn, %{"id" => "movie", "eventType" => "MovieFileDelete"}) do
MediaServer.MoviesIndex.reset()
Phoenix.PubSub.broadcast(MediaServer.PubSub, "movie", {:deleted_file})

conn
|> send_resp(201, "Ok")
end

def create(conn, %{"id" => "series", "eventType" => "Download"}) do
MediaServer.SeriesIndex.reset()
def create(conn, %{"id" => "series", "eventType" => "Download"} = params) do
Phoenix.PubSub.broadcast(MediaServer.PubSub, "series", {:added, params})

conn
|> send_resp(201, "Ok")
end

def create(conn, %{"id" => "series", "eventType" => "SeriesDelete"}) do
MediaServer.SeriesIndex.reset()
Phoenix.PubSub.broadcast(MediaServer.PubSub, "series", {:deleted})

conn
|> send_resp(201, "Ok")
end

def create(conn, %{"id" => "series", "eventType" => "EpisodeFileDelete"}) do
MediaServer.SeriesIndex.reset()
Phoenix.PubSub.broadcast(MediaServer.PubSub, "series", {:deleted_episode_file})

conn
|> send_resp(201, "Ok")
Expand Down
22 changes: 11 additions & 11 deletions lib/media_server_web/live/movies_live/show.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@
</div>
<div class="flex gap-x-4 items-center">
<%= if @movie["hasFile"] do %>
<.link
id={"play-#{ @movie["id"] }"}
navigate={"/watch?movie=#{@movie["id"]}#{ if !is_nil(@continue) do "&timestamp=#{@continue.current_time}" end }"}
class="group relative flex h-16 w-16 flex-shrink-0 items-center justify-center rounded-full bg-zinc-800 hover:bg-zinc-700 focus:outline-none focus:ring focus:ring-slate-700 focus:ring-offset-4"
>
<svg viewBox="0 0 36 36" class="h-8 w-8 fill-white group-active:fill-white/80">
<path d="M33.75 16.701C34.75 17.2783 34.75 18.7217 33.75 19.299L11.25 32.2894C10.25 32.8668 9 32.1451 9 30.9904L9 5.00962C9 3.85491 10.25 3.13323 11.25 3.71058L33.75 16.701Z">
</path>
</svg>
</.link>
<.link
id={"play-#{ @movie["id"] }"}
navigate={"/watch?movie=#{@movie["id"]}#{ if !is_nil(@continue) do "&timestamp=#{@continue.current_time}" end }"}
class="group relative flex h-16 w-16 flex-shrink-0 items-center justify-center rounded-full bg-zinc-800 hover:bg-zinc-700 focus:outline-none focus:ring focus:ring-slate-700 focus:ring-offset-4"
>
<svg viewBox="0 0 36 36" class="h-8 w-8 fill-white group-active:fill-white/80">
<path d="M33.75 16.701C34.75 17.2783 34.75 18.7217 33.75 19.299L11.25 32.2894C10.25 32.8668 9 32.1451 9 30.9904L9 5.00962C9 3.85491 10.25 3.13323 11.25 3.71058L33.75 16.701Z">
</path>
</svg>
</.link>
<% end %>

<.live_component
Expand All @@ -39,7 +39,7 @@
media_type="movie"
user_id={@current_user.id}
return_to={~p"/movies/#{@movie["id"]}"}
/>
/>
</div>
</header>

Expand Down
2 changes: 1 addition & 1 deletion lib/media_server_web/live/series_live/show.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
media_type="series"
user_id={@current_user.id}
return_to={~p"/series/#{@serie["id"]}"}
/>
/>
</div>
</header>

Expand Down
Loading

0 comments on commit 36e71e8

Please sign in to comment.