Skip to content

Commit

Permalink
feat: add stream api endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
trueChazza authored Apr 17, 2022
1 parent 33765a2 commit ab75c1d
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 32 deletions.
10 changes: 10 additions & 0 deletions lib/media_server_web/live/watch_episode_live/show.ex
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
defmodule MediaServerWeb.WatchEpisodeLive.Show do
use MediaServerWeb, :live_view

alias MediaServer.Accounts
alias MediaServerWeb.Repositories.Episodes
alias MediaServer.Continues

@impl true
def mount(_params, session, socket) do
{
:ok,
socket
|> assign(:current_user, Accounts.get_user_by_session_token(session["user_token"]))
}
end

@impl true
def handle_params(%{"episode" => episode_id}, _url, socket) do
episode = Episodes.get_episode(episode_id)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<video id="video" phx-hook="episode" poster={MediaServerWeb.Repositories.Episodes.get_background(@episode)} controlsList="nodownload" controls autoplay>
<source src={Routes.stream_episode_path(@socket, :show, @episode["id"])} type="video/mp4">
<source src={Routes.stream_episode_path(@socket, :show, @episode["id"], token: Phoenix.Token.sign(MediaServerWeb.Endpoint, "user auth", @current_user.id))} type="video/mp4">
</video>
1 change: 0 additions & 1 deletion lib/media_server_web/live/watch_movie_live/show.ex
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ defmodule MediaServerWeb.WatchMovieLive.Show do
},
socket
) do

Continues.update_or_create_movie(%{
movie_id: socket.assigns.movie["id"],
title: socket.assigns.movie["title"],
Expand Down
2 changes: 1 addition & 1 deletion lib/media_server_web/live/watch_movie_live/show.html.heex
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<video id="video" phx-hook="movie" poster={MediaServerWeb.Repositories.Movies.get_background(@movie)} controlsList="nodownload" controls autoplay>
<source src={Routes.stream_movie_path(@socket, :show, @movie["id"])} type="video/mp4">
<source src={Routes.stream_movie_path(@socket, :show, @movie["id"], token: Phoenix.Token.sign(MediaServerWeb.Endpoint, "user auth", @current_user.id))} type="video/mp4">
</video>
17 changes: 17 additions & 0 deletions lib/media_server_web/plugs/verify_token.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
defmodule MediaServerWeb.Plugs.VerifyToken do
import Plug.Conn

def init(default), do: default

def call(%Plug.Conn{params: %{"token" => token}} = conn, _default) do
case Phoenix.Token.verify(conn, "user auth", token, max_age: 86400) do
{:ok, _user_id} -> conn
{:error, :invalid} -> conn |> resp(403, "Forbidden") |> halt
{:error, :expired} -> conn |> resp(403, "Forbidden") |> halt
end
end

def call(conn, _default) do
conn |> resp(403, "Forbidden") |> halt
end
end
15 changes: 12 additions & 3 deletions lib/media_server_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,23 @@ defmodule MediaServerWeb.Router do
plug :fetch_current_user
end

pipeline :api do
plug :accepts, ["json"]
plug MediaServerWeb.Plugs.VerifyToken
end

scope "/", MediaServerWeb do
pipe_through [:browser, :require_authenticated_user]

live "/", HomeLive.Index, :index

live "/movies", MoviesLive.Index, :index
live "/movies/:movie", MoviesLive.Show, :show
get "/movies/:movie/stream", StreamMovieController, :show

live "/series", SeriesLive.Index, :index
live "/series/:serie", SeriesLive.Show, :show
live "/series/:serie/seasons/:season", SeasonsLive.Show, :show

get "/episodes/:episode/stream", StreamEpisodeController, :show

live_session :watch, root_layout: {MediaServerWeb.WatchView, "watch.html"} do
live "/movies/:movie/watch", WatchMovieLive.Show, :show
live "/episodes/:episode/watch", WatchEpisodeLive.Show, :show
Expand All @@ -49,6 +51,13 @@ defmodule MediaServerWeb.Router do
post "/login", UserSessionController, :create
end

scope "/api", MediaServerWeb do
pipe_through :api

get "/movies/:movie/stream", StreamMovieController, :show
get "/episodes/:episode/stream", StreamEpisodeController, :show
end

# Enables the Swoosh mailbox preview in development.
#
# Note that preview only shows emails that were sent by the same
Expand Down
30 changes: 10 additions & 20 deletions priv/static/assets/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -1015,10 +1015,6 @@ select {
white-space: nowrap;
}

.rounded-md {
border-radius: 0.375rem;
}

.rounded-full {
border-radius: 9999px;
}
Expand All @@ -1027,18 +1023,22 @@ select {
border-radius: 0.125rem;
}

.rounded-md {
border-radius: 0.375rem;
}

.rounded-none {
border-radius: 0px;
}

.rounded-l-md {
border-top-left-radius: 0.375rem;
border-bottom-left-radius: 0.375rem;
.rounded-l-sm {
border-top-left-radius: 0.125rem;
border-bottom-left-radius: 0.125rem;
}

.rounded-r-md {
border-top-right-radius: 0.375rem;
border-bottom-right-radius: 0.375rem;
.rounded-r-sm {
border-top-right-radius: 0.125rem;
border-bottom-right-radius: 0.125rem;
}

.rounded-t-md {
Expand All @@ -1051,16 +1051,6 @@ select {
border-bottom-left-radius: 0.375rem;
}

.rounded-l-sm {
border-top-left-radius: 0.125rem;
border-bottom-left-radius: 0.125rem;
}

.rounded-r-sm {
border-top-right-radius: 0.125rem;
border-bottom-right-radius: 0.125rem;
}

.border {
border-width: 1px;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,58 @@ defmodule MediaServerWeb.StreamEpisodeControllerTest do

episode = EpisodesFixtures.get_episode(serie["id"])

conn = get(conn, Routes.stream_episode_path(conn, :show, episode["id"]))
token = Phoenix.Token.sign(conn, "user auth", user.id)

conn = get(conn, Routes.stream_episode_path(conn, :show, episode["id"]), token: token)

assert conn.status === 206
assert conn.state === :file
assert Enum.member?(conn.resp_headers, {"content-type", "video/mp4"})
assert Enum.member?(conn.resp_headers, {"content-range", "bytes 0-47552616/47552617"})
end

test "it halts with random token", %{conn: conn, user: user} do
conn =
post(conn, Routes.user_session_path(conn, :create), %{
"user" => %{"email" => user.email, "password" => AccountsFixtures.valid_user_password()}
})

assert get_session(conn, :user_token)
assert redirected_to(conn) == "/"

serie = SeriesFixtures.get_serie()

episode = EpisodesFixtures.get_episode(serie["id"])

Phoenix.Token.sign(conn, "user auth", user.id)

conn = get(conn, Routes.stream_episode_path(conn, :show, episode["id"]), token: "someToken")

assert conn.status === 403
assert conn.halted
end

test "it halts without token", %{conn: conn, user: user} do
conn =
post(conn, Routes.user_session_path(conn, :create), %{
"user" => %{"email" => user.email, "password" => AccountsFixtures.valid_user_password()}
})

assert get_session(conn, :user_token)
assert redirected_to(conn) == "/"

serie = SeriesFixtures.get_serie()

episode = EpisodesFixtures.get_episode(serie["id"])

Phoenix.Token.sign(conn, "user auth", user.id)

conn = get(conn, Routes.stream_episode_path(conn, :show, episode["id"]))

assert conn.status === 403
assert conn.halted
end

test "episode range", %{conn: conn, user: user} do
conn =
post(conn, Routes.user_session_path(conn, :create), %{
Expand All @@ -46,8 +90,10 @@ defmodule MediaServerWeb.StreamEpisodeControllerTest do

episode = EpisodesFixtures.get_episode(serie["id"])

token = Phoenix.Token.sign(conn, "user auth", user.id)

conn = conn |> recycle() |> put_req_header("range", "bytes=124-")
conn = get(conn, Routes.stream_episode_path(conn, :show, episode["id"]))
conn = get(conn, Routes.stream_episode_path(conn, :show, episode["id"]), token: token)

assert conn.status === 206
assert conn.state === :file
Expand All @@ -68,8 +114,10 @@ defmodule MediaServerWeb.StreamEpisodeControllerTest do

episode = EpisodesFixtures.get_episode(serie["id"])

token = Phoenix.Token.sign(conn, "user auth", user.id)

conn = conn |> recycle() |> put_req_header("range", "bytes=0-1")
conn = get(conn, Routes.stream_episode_path(conn, :show, episode["id"]))
conn = get(conn, Routes.stream_episode_path(conn, :show, episode["id"]), token: token)

assert conn.status === 206
assert conn.state === :file
Expand Down
50 changes: 47 additions & 3 deletions test/media_server_web/controllers/stream_movie_controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,54 @@ defmodule MediaServerWeb.StreamMovieControllerTest do

movie = MoviesFixtures.get_movie()

conn = get(conn, Routes.stream_movie_path(conn, :show, movie["id"]))
token = Phoenix.Token.sign(conn, "user auth", user.id)

conn = get(conn, Routes.stream_movie_path(conn, :show, movie["id"]), token: token)

assert conn.status === 206
assert conn.state === :file
assert Enum.member?(conn.resp_headers, {"content-type", "video/mp4"})
assert Enum.member?(conn.resp_headers, {"content-range", "bytes 0-35103579/35103580"})
end

test "it halts with random token", %{conn: conn, user: user} do
conn =
post(conn, Routes.user_session_path(conn, :create), %{
"user" => %{"email" => user.email, "password" => AccountsFixtures.valid_user_password()}
})

assert get_session(conn, :user_token)
assert redirected_to(conn) == "/"

movie = MoviesFixtures.get_movie()

Phoenix.Token.sign(conn, "user auth", user.id)

conn = get(conn, Routes.stream_movie_path(conn, :show, movie["id"]), token: "someToken")

assert conn.status === 403
assert conn.halted
end

test "it halts without token", %{conn: conn, user: user} do
conn =
post(conn, Routes.user_session_path(conn, :create), %{
"user" => %{"email" => user.email, "password" => AccountsFixtures.valid_user_password()}
})

assert get_session(conn, :user_token)
assert redirected_to(conn) == "/"

movie = MoviesFixtures.get_movie()

Phoenix.Token.sign(conn, "user auth", user.id)

conn = get(conn, Routes.stream_movie_path(conn, :show, movie["id"]))

assert conn.status === 403
assert conn.halted
end

test "movie range", %{conn: conn, user: user} do
conn =
post(conn, Routes.user_session_path(conn, :create), %{
Expand All @@ -41,8 +81,10 @@ defmodule MediaServerWeb.StreamMovieControllerTest do

movie = MoviesFixtures.get_movie()

token = Phoenix.Token.sign(conn, "user auth", user.id)

conn = conn |> recycle() |> put_req_header("range", "bytes=124-")
conn = get(conn, Routes.stream_movie_path(conn, :show, movie["id"]))
conn = get(conn, Routes.stream_movie_path(conn, :show, movie["id"]), token: token)

assert conn.status === 206
assert conn.state === :file
Expand All @@ -61,8 +103,10 @@ defmodule MediaServerWeb.StreamMovieControllerTest do

movie = MoviesFixtures.get_movie()

token = Phoenix.Token.sign(conn, "user auth", user.id)

conn = conn |> recycle() |> put_req_header("range", "bytes=0-1")
conn = get(conn, Routes.stream_movie_path(conn, :show, movie["id"]))
conn = get(conn, Routes.stream_movie_path(conn, :show, movie["id"]), token: token)

assert conn.status === 206
assert conn.state === :file
Expand Down

0 comments on commit ab75c1d

Please sign in to comment.