Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
27da7d5
feat: add context for movie watch statuses
trueChazza Feb 20, 2022
defe977
feat: add video hook
trueChazza Feb 21, 2022
1c4ba36
feat: add updating movie watch status
trueChazza Feb 21, 2022
d966a90
refactor: refactor window ids
trueChazza Feb 21, 2022
6bc6222
feat: add user relation for movie watch statuses
trueChazza Feb 21, 2022
496d1dc
refactor: refactor movie watch statuses
trueChazza Feb 21, 2022
d2cb93f
refactor: improve readability
trueChazza Feb 21, 2022
699eb33
refactor: preload user movie watch statuses
trueChazza Feb 21, 2022
1dc84ed
refactor: refactor movie watch statuses
trueChazza Feb 21, 2022
75d2ebe
refactor: refactor movie watch statuses
trueChazza Feb 22, 2022
16ac05b
feat: add continue watching section to home page
trueChazza Feb 22, 2022
b5f2708
refactor: refactor continue watching section
trueChazza Feb 22, 2022
10480d1
refactor: add status component
trueChazza Feb 22, 2022
4eb7c2f
feat: add statuses page
trueChazza Feb 22, 2022
7c3851e
refactor: refactor minor
trueChazza Feb 22, 2022
82b74b3
feat: add delete continue watching movie
trueChazza Feb 22, 2022
d59847f
test: improve coverage
trueChazza Feb 22, 2022
f74424f
Merge pull request #28 from midarrlabs/feature/add-movie-watch-statuses
trueChazza Feb 22, 2022
6fa58d8
feat: add episode context
trueChazza Feb 23, 2022
120dc93
feat: add episode watch statuses
trueChazza Feb 23, 2022
a5475b1
feat: add episode continue watching
trueChazza Feb 23, 2022
e9d9deb
build: bump app js id
trueChazza Feb 23, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 50 additions & 1 deletion assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,56 @@ channel.join()
})

let liveSocket = new LiveSocket("/live", Socket, {
params: { _csrf_token: csrfToken }
params: { _csrf_token: csrfToken },
hooks: {
video: {
mounted() {
const urlParams = new URLSearchParams(window.location.search)

if (urlParams.has('seconds')) {
this.el.currentTime = urlParams.get('seconds')
}

window.addEventListener("beforeunload", event => {
this.pushEvent("video_destroyed", {
movie_id: window.movie_id,
current_time: Math.floor(this.el.currentTime),
duration: Math.floor(this.el.duration),
user_id: window.userId
})

delete event['returnValue']
})
},
destroyed() {
window.removeEventListener("beforeunload")
}
},
episode: {
mounted() {
const urlParams = new URLSearchParams(window.location.search)

if (urlParams.has('seconds')) {
this.el.currentTime = urlParams.get('seconds')
}

window.addEventListener("beforeunload", event => {
this.pushEvent("episode_destroyed", {
episode_id: window.episode_id,
serie_id: window.serie_id,
current_time: Math.floor(this.el.currentTime),
duration: Math.floor(this.el.duration),
user_id: window.userId
})

delete event['returnValue']
})
},
destroyed() {
window.removeEventListener("beforeunload")
}
}
}
})

liveSocket.connect()
Expand Down
3 changes: 3 additions & 0 deletions lib/media_server/accounts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,10 @@ defmodule MediaServer.Accounts do
"""
def get_user_by_session_token(token) do
{:ok, query} = UserToken.verify_session_token_query(token)

Repo.one(query)
|> Repo.preload(:movie_watch_statuses)
|> Repo.preload(:episode_watch_statuses)
end

@doc """
Expand Down
2 changes: 2 additions & 0 deletions lib/media_server/accounts/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ defmodule MediaServer.Accounts.User do
field :hashed_password, :string, redact: true
field :confirmed_at, :naive_datetime
field :is_admin, :boolean
has_many :movie_watch_statuses, MediaServer.WatchStatuses.Movie
has_many :episode_watch_statuses, MediaServer.WatchStatuses.Episode

timestamps()
end
Expand Down
224 changes: 224 additions & 0 deletions lib/media_server/watch_statuses.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
defmodule MediaServer.WatchStatuses do
@moduledoc """
The WatchStatuses context.
"""

import Ecto.Query, warn: false
alias MediaServer.Repo

alias MediaServer.WatchStatuses.Movie

@doc """
Returns the list of movie_watch_statuses.

## Examples

iex> list_movie_watch_statuses()
[%Movie{}, ...]

"""
def list_movie_watch_statuses do
Repo.all(Movie)
end

@doc """
Gets a single movie.

Raises `Ecto.NoResultsError` if the Movie does not exist.

## Examples

iex> get_movie!(123)
%Movie{}

iex> get_movie!(456)
** (Ecto.NoResultsError)

"""
def get_movie!(id), do: Repo.get!(Movie, id)

@doc """
Creates a movie.

## Examples

iex> create_movie(%{field: value})
{:ok, %Movie{}}

iex> create_movie(%{field: bad_value})
{:error, %Ecto.Changeset{}}

"""
def create_movie(attrs \\ %{}) do
%Movie{}
|> Movie.changeset(attrs)
|> Repo.insert()
end

@doc """
Updates a movie.

## Examples

iex> update_movie(movie, %{field: new_value})
{:ok, %Movie{}}

iex> update_movie(movie, %{field: bad_value})
{:error, %Ecto.Changeset{}}

"""
def update_movie(%Movie{} = movie, attrs) do
movie
|> Movie.changeset(attrs)
|> Repo.update()
end

def update_or_create_movie(attrs) do
movie = Repo.get_by(Movie, [movie_id: attrs.movie_id, user_id: attrs.user_id])

case movie do
nil ->
create_movie(attrs)

_ ->
update_movie(movie, attrs)
end
end

@doc """
Deletes a movie.

## Examples

iex> delete_movie(movie)
{:ok, %Movie{}}

iex> delete_movie(movie)
{:error, %Ecto.Changeset{}}

"""
def delete_movie(%Movie{} = movie) do
Repo.delete(movie)
end

@doc """
Returns an `%Ecto.Changeset{}` for tracking movie changes.

## Examples

iex> change_movie(movie)
%Ecto.Changeset{data: %Movie{}}

"""
def change_movie(%Movie{} = movie, attrs \\ %{}) do
Movie.changeset(movie, attrs)
end

alias MediaServer.WatchStatuses.Episode

@doc """
Returns the list of episode_watch_statuses.

## Examples

iex> list_episode_watch_statuses()
[%Episode{}, ...]

"""
def list_episode_watch_statuses do
Repo.all(Episode)
end

@doc """
Gets a single episode.

Raises `Ecto.NoResultsError` if the Episode does not exist.

## Examples

iex> get_episode!(123)
%Episode{}

iex> get_episode!(456)
** (Ecto.NoResultsError)

"""
def get_episode!(id), do: Repo.get!(Episode, id)

@doc """
Creates a episode.

## Examples

iex> create_episode(%{field: value})
{:ok, %Episode{}}

iex> create_episode(%{field: bad_value})
{:error, %Ecto.Changeset{}}

"""
def create_episode(attrs \\ %{}) do
%Episode{}
|> Episode.changeset(attrs)
|> Repo.insert()
end

@doc """
Updates a episode.

## Examples

iex> update_episode(episode, %{field: new_value})
{:ok, %Episode{}}

iex> update_episode(episode, %{field: bad_value})
{:error, %Ecto.Changeset{}}

"""
def update_episode(%Episode{} = episode, attrs) do
episode
|> Episode.changeset(attrs)
|> Repo.update()
end

def update_or_create_episode(attrs) do
episode = Repo.get_by(Episode, [episode_id: attrs.episode_id, serie_id: attrs.serie_id, user_id: attrs.user_id])

case episode do
nil ->
create_episode(attrs)

_ ->
update_episode(episode, attrs)
end
end

@doc """
Deletes a episode.

## Examples

iex> delete_episode(episode)
{:ok, %Episode{}}

iex> delete_episode(episode)
{:error, %Ecto.Changeset{}}

"""
def delete_episode(%Episode{} = episode) do
Repo.delete(episode)
end

@doc """
Returns an `%Ecto.Changeset{}` for tracking episode changes.

## Examples

iex> change_episode(episode)
%Ecto.Changeset{data: %Episode{}}

"""
def change_episode(%Episode{} = episode, attrs \\ %{}) do
Episode.changeset(episode, attrs)
end
end
23 changes: 23 additions & 0 deletions lib/media_server/watch_statuses/episode.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
defmodule MediaServer.WatchStatuses.Episode do
use Ecto.Schema
import Ecto.Changeset

schema "episode_watch_statuses" do
field :current_time, :integer
field :duration, :integer
field :episode_id, :integer
field :image_url, :string
field :serie_id, :integer
field :title, :string
belongs_to :user, MediaServer.Accounts.User

timestamps()
end

@doc false
def changeset(episode, attrs) do
episode
|> cast(attrs, [:episode_id, :serie_id, :title, :image_url, :current_time, :duration, :user_id])
|> validate_required([:episode_id, :serie_id, :title, :current_time, :duration, :user_id])
end
end
22 changes: 22 additions & 0 deletions lib/media_server/watch_statuses/movie.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defmodule MediaServer.WatchStatuses.Movie do
use Ecto.Schema
import Ecto.Changeset

schema "movie_watch_statuses" do
field :movie_id, :integer
field :title, :string
field :image_url, :string
field :current_time, :integer
field :duration, :integer
belongs_to :user, MediaServer.Accounts.User

timestamps()
end

@doc false
def changeset(movie, attrs) do
movie
|> cast(attrs, [:movie_id, :title, :image_url, :current_time, :duration, :user_id])
|> validate_required([:movie_id, :title, :current_time, :duration, :user_id])
end
end
1 change: 0 additions & 1 deletion lib/media_server_web.ex
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ defmodule MediaServerWeb do

# Import LiveView and .heex helpers (live_render, live_patch, <.form>, etc)
import Phoenix.LiveView.Helpers
import MediaServerWeb.LiveHelpers

# Import basic rendering functionality (render, render_layout, etc)
import Phoenix.View
Expand Down
25 changes: 25 additions & 0 deletions lib/media_server_web/components/status_component.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
defmodule MediaServerWeb.Components.StatusComponent do
use MediaServerWeb, :live_component

alias MediaServer.WatchStatuses

def handle_event("delete", %{"id" => id}, socket) do
WatchStatuses.delete_movie(WatchStatuses.get_movie!(id))

{
:noreply,
socket
|> push_redirect(to: socket.assigns.return_to)
}
end

def handle_event("delete_episode", %{"id" => id}, socket) do
WatchStatuses.delete_episode(WatchStatuses.get_episode!(id))

{
:noreply,
socket
|> push_redirect(to: socket.assigns.return_to)
}
end
end
Loading