Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add playback progress #377

Merged
merged 12 commits into from
Jul 6, 2023
2 changes: 2 additions & 0 deletions lib/media_server/media_actions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ defmodule MediaServer.MediaActions do
belongs_to :media_type, MediaServer.MediaTypes
belongs_to :action, MediaServer.Actions

has_one :continue, MediaServer.Continues, foreign_key: :media_id, references: :media_id

timestamps()
end

Expand Down
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 @@ -24,7 +24,7 @@
) %>
</div>
<a href="https://github.com/midarrlabs" target="_blank" class="text-sm text-center text-zinc-500">
© 2023 Midarr Labs - v3.2.0-beta.1
© 2023 Midarr Labs - v4.0.0-beta.5
</a>
</div>
</div>
Expand Down
21 changes: 20 additions & 1 deletion lib/media_server_web/controllers/images_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ defmodule MediaServerWeb.ImagesController do
end

def index(conn, %{"movie" => id, "type" => "background"}) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} = MediaServerWeb.Repositories.Movies.get("mediacover/#{ id }/fanart.jpg")

background_file = MediaServer.MoviesIndex.get_movie(id)
|> MediaServer.MoviesIndex.get_background()
|> MediaServer.Helpers.get_image_file()

{:ok, %HTTPoison.Response{status_code: 200, body: body}} = HTTPoison.get("https://image.tmdb.org/t/p/w1280/#{ background_file }")

conn
|> put_resp_header("content-type", "image/image")
Expand Down Expand Up @@ -46,4 +51,18 @@ defmodule MediaServerWeb.ImagesController do
|> send_resp(404, "Not found")
end
end

def index(conn, %{"episode" => id, "type" => "poster"}) do

if MediaServerWeb.Repositories.Episodes.get_episode(id) |> MediaServerWeb.Repositories.Episodes.get_poster() do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} = MediaServerWeb.Repositories.Episodes.get_episode(id) |> MediaServerWeb.Repositories.Episodes.get_poster() |> HTTPoison.get()

conn
|> put_resp_header("content-type", "image/image")
|> send_resp(200, body)
else
conn
|> send_resp(404, "Not found")
end
end
end
18 changes: 9 additions & 9 deletions lib/media_server_web/live/history_live/index.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,30 @@ defmodule MediaServerWeb.HistoryLive.Index do

import Ecto.Query

alias MediaServer.Repo
alias MediaServer.Accounts

@impl true
def mount(_params, session, socket) do
{
:ok,
socket
|> assign(page_title: "History")
|> assign(
:current_user,
Accounts.get_user_by_session_token(session["user_token"])
|> Repo.preload(media_actions: from(MediaServer.MediaActions, order_by: [desc: :updated_at]))
)
|> assign(:current_user, MediaServer.Accounts.get_user_by_session_token(session["user_token"]))
}
end

@impl true
def handle_params(_params, _url, socket) do
query = from continue in MediaServer.Continues, where: continue.user_id == ^socket.assigns.current_user.id
query2 = from media_actions in MediaServer.MediaActions,
order_by: [desc: :updated_at],
limit: 12,
preload: [continue: ^query]

current_user = socket.assigns.current_user |> MediaServer.Repo.preload(media_actions: query2)
{
:noreply,
socket
|> assign(:movie_id, MediaServer.MediaTypes.get_movie_id())
|> assign(:user_media_actions, socket.assigns.current_user.media_actions)
|> assign(:user_media_actions, current_user.media_actions)
}
end
end
209 changes: 98 additions & 111 deletions lib/media_server_web/live/history_live/index.html.heex
Original file line number Diff line number Diff line change
@@ -1,140 +1,127 @@
<div>
<.live_component module={MediaServerWeb.Components.NavComponent} id="nav-component" />

<div class="relative">
<main>
<div class="sm:px-8 mt-16 sm:mt-32">
<div class="mx-auto max-w-7xl lg:px-8">
<div class="relative px-4 sm:px-8 lg:px-12">
<div class="mx-auto max-w-2xl lg:max-w-5xl">
<header class="max-w-2xl">
<h1 class="text-4xl font-bold tracking-tight text-zinc-800 dark:text-zinc-100 sm:text-5xl">
History
</h1>
</header>
<MediaServerWeb.Components.PageSectionAlternativeComponent.render>
<%= for item <- @user_media_actions do %>
<%= if item.media_type_id === @movie_id do %>
<div>
<div class="relative">
<div class="relative overflow-hidden rounded-t-lg">
<img
loading="lazy"
class="h-52 w-full object-cover"
alt=""
src={
Routes.images_path(@socket, :index,
movie: item.media_id,
type: "background"
)
}
/>
</div>

<div class="absolute inset-x-0 top-0 flex h-full items-end justify-end overflow-hidden pb-2 pr-2">
<div
aria-hidden="true"
class="absolute inset-x-0 bottom-0 h-36 bg-gradient-to-t from-black opacity-50"
>
</div>
<p class="relative text-sm font-semibold text-white bg-black text-center rounded-lg">
<span class="p-2">
<%= MediaServer.MoviesIndex.get_movie(item.media_id)["movieFile"]["mediaInfo"][
"runTime"
] %>
</span>
</p>
</div>
</div>
</div>
</div>
</main>

<MediaServerWeb.Components.PageSectionAlternativeComponent.render>
<%= if item.continue do %>
<div class="absolute flex w-full bg-slate-200 h-1 overflow-hidden rounded-b-lg">
<div
class="bg-red-500 h-1"
style={"width: #{ MediaServerWeb.Helpers.percentage_complete_from_seconds(item.continue.current_time, item.continue.duration) }%"}
>
</div>
</div>
<% end %>
</div>

<%= for item <- @user_media_actions do %>
<%= if item.media_type_id !== @movie_id do %>
<article class="aspect-auto w-full flex-none overflow-hidden rounded-sm">
<div class="relative w-full">
<%= if MediaServerWeb.Repositories.Episodes.get_screenshot(MediaServerWeb.Repositories.Episodes.get_episode(item.media_id)) do %>
<div class="relative flex mt-4 space-x-2">
<div>
<h3 class="text-sm font-medium text-zinc-100">
<%= MediaServer.MoviesIndex.get_movie_title(item.media_id) %>
</h3>
<p class="mt-1 text-sm text-zinc-400">
<%= MediaServer.MoviesIndex.get_movie(item.media_id)["year"] %> • <%= MediaServer.MoviesIndex.get_movie(
item.media_id
)["certification"] %>
</p>
</div>
</div>
</div>
<% else %>
<%= if MediaServerWeb.Repositories.Episodes.get_episode(item.media_id) do %>
<div>
<div class="relative">
<div class="relative overflow-hidden rounded-t-lg">
<img
loading="lazy"
class="h-52 w-full object-cover"
alt=""
src={
Routes.images_path(@socket, :index,
episode: item.media_id,
type: "screenshot"
)
}
alt=""
class="w-full rounded-sm bg-gray-100 object-cover lg:aspect-[3/2]"
loading="lazy"
/>
<% else %>
<div class="w-full rounded-sm bg-zinc-800/90 object-cover aspect-[3/2]"></div>
<% end %>
</div>
<div class="max-w-xl">
<div class="mt-8 flex items-center gap-x-4 text-xs justify-between">
<time class="text-sm text-zinc-400 text-zinc-500">
<%= Calendar.strftime(
DateTime.from_naive!(item.updated_at, "Etc/UTC"),
"%B %-d, %Y"
) %>
</time>
</div>

<div class="flex rounded-full px-3 mr-1 text-sm font-medium shadow-lg shadow-zinc-800/5 ring-1 ring-zinc-900/5 backdrop-blur bg-zinc-800/90 text-zinc-200 ring-white/10">
<%= live_redirect id: "play-#{ item.media_id }", to: Routes.watch_index_path(@socket, :index, episode: item.media_id), class: "flex items-center text-sm py-2 transition hover:text-red-400" do %>
<svg
aria-hidden="true"
viewBox="0 0 10 10"
fill="none"
class="h-2.5 w-2.5 fill-current"
>
<path d="M8.25 4.567a.5.5 0 0 1 0 .866l-7.5 4.33A.5.5 0 0 1 0 9.33V.67A.5.5 0 0 1 .75.237l7.5 4.33Z">
</path>
</svg>
<span class="ml-3">Watch</span>
<% end %>
<div class="absolute inset-x-0 top-0 flex h-full items-end justify-end overflow-hidden pb-2 pr-2">
<div
aria-hidden="true"
class="absolute inset-x-0 bottom-0 h-36 bg-gradient-to-t from-black opacity-50"
>
</div>
</div>
<div class="group relative">
<h3 class="mt-3 text-base font-semibold tracking-tight text-zinc-100">
<%= MediaServerWeb.Repositories.Episodes.get_episode(item.media_id)[
"episodeNumber"
] %>: <%= MediaServerWeb.Repositories.Episodes.get_episode(item.media_id)[
"title"
] %>
</h3>
<p class="mt-5 text-sm text-zinc-400">
<%= MediaServerWeb.Repositories.Episodes.get_episode(item.media_id)["overview"] %>
<p class="relative text-sm font-semibold text-white bg-black text-center rounded-lg">
<span class="p-2">
<%= MediaServerWeb.Repositories.Episodes.get_episode(item.media_id)[
"episodeFile"
]["mediaInfo"]["runTime"] %>
</span>
</p>
</div>
</div>
</article>
<% else %>
<article class="aspect-auto w-full flex-none overflow-hidden rounded-sm">
<div class="relative w-full">
<%= if MediaServer.MoviesIndex.get_background(MediaServer.MoviesIndex.get_movie(item.media_id)) do %>
<img
src={
Routes.images_path(@socket, :index,
movie: item.media_id,
type: "background"
)
}
alt=""
class="w-full rounded-sm bg-gray-100 object-cover lg:aspect-[3/2]"
loading="lazy"
/>
<% else %>
<div class="w-full rounded-sm bg-zinc-800/90 object-cover aspect-[3/2]"></div>

<%= if item.continue do %>
<div class="absolute flex w-full bg-slate-200 h-1 overflow-hidden rounded-b-lg">
<div
class="bg-red-500 h-1"
style={"width: #{ MediaServerWeb.Helpers.percentage_complete_from_seconds(item.continue.current_time, item.continue.duration) }%"}
>
</div>
</div>
<% end %>
</div>
<div class="max-w-xl">
<div class="mt-8 flex items-center gap-x-4 text-xs justify-between">
<time class="text-sm text-zinc-400 text-zinc-500">
<%= Calendar.strftime(
DateTime.from_naive!(item.updated_at, "Etc/UTC"),
"%B %-d, %Y"
) %>
</time>

<div class="flex rounded-full px-3 mr-1 text-sm font-medium shadow-lg shadow-zinc-800/5 ring-1 ring-zinc-900/5 backdrop-blur bg-zinc-800/90 text-zinc-200 ring-white/10">
<%= live_redirect id: "play-#{ item.media_id }", to: Routes.watch_index_path(@socket, :index, movie: item.media_id), class: "flex items-center text-sm py-2 transition hover:text-red-400" do %>
<svg
aria-hidden="true"
viewBox="0 0 10 10"
fill="none"
class="h-2.5 w-2.5 fill-current"
>
<path d="M8.25 4.567a.5.5 0 0 1 0 .866l-7.5 4.33A.5.5 0 0 1 0 9.33V.67A.5.5 0 0 1 .75.237l7.5 4.33Z">
</path>
</svg>
<span class="ml-3">Watch</span>
<% end %>
</div>
</div>
<div class="group relative">
<h3 class="mt-3 text-base font-semibold tracking-tight text-zinc-100">
<%= MediaServer.MoviesIndex.get_movie_title(item.media_id) %>
<div class="relative flex mt-4 space-x-2">
<div>
<h3 class="text-sm font-medium text-zinc-100">
<%= MediaServerWeb.Repositories.Episodes.get_episode(item.media_id)["series"][
"title"
] %>
</h3>
<p class="mt-5 text-sm text-zinc-400">
<%= MediaServer.MoviesIndex.get_movie(item.media_id)["overview"] %>
<p class="mt-1 text-sm text-zinc-400">
<%= MediaServerWeb.Repositories.Episodes.get_episode(item.media_id)["series"][
"year"
] %>
</p>
</div>
</div>
</article>
</div>
<% end %>
<% end %>
</MediaServerWeb.Components.PageSectionAlternativeComponent.render>
<% end %>
</MediaServerWeb.Components.PageSectionAlternativeComponent.render>

<.live_component module={MediaServerWeb.Components.FooterComponent} id="footer-component" />
</div>
<.live_component module={MediaServerWeb.Components.FooterComponent} id="footer-component" />
</div>
11 changes: 8 additions & 3 deletions lib/media_server_web/repositories/episodes.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,22 @@ defmodule MediaServerWeb.Repositories.Episodes do
|> Enum.at(0))["url"]
end

def handle_screenshot(nil) do
def handle_image(nil) do
nil
end

def handle_screenshot(screenshot) do
def handle_image(screenshot) do
screenshot["url"]
end

def get_screenshot(episode) do
Enum.find(episode["images"], nil, fn x -> x["coverType"] === "screenshot" end)
|> handle_screenshot()
|> handle_image()
end

def get_poster(episode) do
Enum.find(episode["series"]["images"], nil, fn x -> x["coverType"] === "poster" end)
|> handle_image()
end

def get_subtitle_path_for(id) do
Expand Down
2 changes: 1 addition & 1 deletion lib/media_server_web/repositories/series.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ defmodule MediaServerWeb.Repositories.Series do
end

def handle_response(_) do
[]
nil
end

def get_all() do
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule MediaServer.MixProject do
def project do
[
app: :media_server,
version: "3.2.0",
version: "4.0.0",
elixir: "~> 1.14",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: Mix.compilers(),
Expand Down