Rename media sources (#25)
* Renamed MediaSource to Sources * Renamed MediaItem controller namespace
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
defmodule PinchflatWeb.Sources.SourceController do
|
||||
use PinchflatWeb, :controller
|
||||
|
||||
alias Pinchflat.Repo
|
||||
alias Pinchflat.Media
|
||||
alias Pinchflat.Profiles
|
||||
alias Pinchflat.Sources
|
||||
alias Pinchflat.Sources.Source
|
||||
|
||||
def index(conn, _params) do
|
||||
sources = Repo.preload(Sources.list_sources(), :media_profile)
|
||||
|
||||
render(conn, :index, sources: sources)
|
||||
end
|
||||
|
||||
def new(conn, _params) do
|
||||
changeset = Sources.change_source(%Source{})
|
||||
|
||||
if get_session(conn, :onboarding) do
|
||||
render(conn, :new,
|
||||
changeset: changeset,
|
||||
media_profiles: media_profiles(),
|
||||
layout: {Layouts, :onboarding}
|
||||
)
|
||||
else
|
||||
render(conn, :new, changeset: changeset, media_profiles: media_profiles())
|
||||
end
|
||||
end
|
||||
|
||||
def create(conn, %{"source" => source_params}) do
|
||||
case Sources.create_source(source_params) do
|
||||
{:ok, source} ->
|
||||
redirect_location =
|
||||
if get_session(conn, :onboarding), do: ~p"/?onboarding=1", else: ~p"/sources/#{source}"
|
||||
|
||||
conn
|
||||
|> put_flash(:info, "Source created successfully.")
|
||||
|> redirect(to: redirect_location)
|
||||
|
||||
{:error, %Ecto.Changeset{} = changeset} ->
|
||||
if get_session(conn, :onboarding) do
|
||||
render(conn, :new,
|
||||
changeset: changeset,
|
||||
media_profiles: media_profiles(),
|
||||
layout: {Layouts, :onboarding}
|
||||
)
|
||||
else
|
||||
render(conn, :new, changeset: changeset, media_profiles: media_profiles())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def show(conn, %{"id" => id}) do
|
||||
source =
|
||||
id
|
||||
|> Sources.get_source!()
|
||||
|> Repo.preload(:media_profile)
|
||||
|
||||
pending_media = Media.list_pending_media_items_for(source)
|
||||
downloaded_media = Media.list_downloaded_media_items_for(source)
|
||||
|
||||
render(conn, :show, source: source, pending_media: pending_media, downloaded_media: downloaded_media)
|
||||
end
|
||||
|
||||
def edit(conn, %{"id" => id}) do
|
||||
source = Sources.get_source!(id)
|
||||
changeset = Sources.change_source(source)
|
||||
|
||||
render(conn, :edit, source: source, changeset: changeset, media_profiles: media_profiles())
|
||||
end
|
||||
|
||||
def update(conn, %{"id" => id, "source" => source_params}) do
|
||||
source = Sources.get_source!(id)
|
||||
|
||||
case Sources.update_source(source, source_params) do
|
||||
{:ok, source} ->
|
||||
conn
|
||||
|> put_flash(:info, "Source updated successfully.")
|
||||
|> redirect(to: ~p"/sources/#{source}")
|
||||
|
||||
{:error, %Ecto.Changeset{} = changeset} ->
|
||||
render(conn, :edit,
|
||||
source: source,
|
||||
changeset: changeset,
|
||||
media_profiles: media_profiles()
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def delete(conn, %{"id" => id}) do
|
||||
source = Sources.get_source!(id)
|
||||
{:ok, _source} = Sources.delete_source(source)
|
||||
|
||||
conn
|
||||
|> put_flash(:info, "Source deleted successfully.")
|
||||
|> redirect(to: ~p"/sources")
|
||||
end
|
||||
|
||||
defp media_profiles do
|
||||
Profiles.list_media_profiles()
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
defmodule PinchflatWeb.Sources.SourceHTML do
|
||||
use PinchflatWeb, :html
|
||||
|
||||
embed_templates "source_html/*"
|
||||
|
||||
@doc """
|
||||
Renders a source form.
|
||||
"""
|
||||
attr :changeset, Ecto.Changeset, required: true
|
||||
attr :action, :string, required: true
|
||||
attr :media_profiles, :list, required: true
|
||||
|
||||
def source_form(assigns)
|
||||
|
||||
def friendly_index_frequencies do
|
||||
[
|
||||
{"Never", -1},
|
||||
{"1 Hour", 60},
|
||||
{"3 Hours", 3 * 60},
|
||||
{"6 Hours", 6 * 60},
|
||||
{"12 Hours", 12 * 60},
|
||||
{"Daily (recommended)", 24 * 60},
|
||||
{"Weekly", 7 * 24 * 60},
|
||||
{"Monthly", 30 * 24 * 60}
|
||||
]
|
||||
end
|
||||
|
||||
def friendly_collection_types do
|
||||
[
|
||||
{"Channel", "channel"},
|
||||
{"Playlist", "playlist"}
|
||||
]
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,14 @@
|
||||
<div class="mb-6 flex gap-3 flex-row items-center">
|
||||
<.link navigate={~p"/sources"}>
|
||||
<.icon name="hero-arrow-left" class="w-10 h-10 hover:dark:text-white" />
|
||||
</.link>
|
||||
<h2 class="text-title-md2 font-bold text-black dark:text-white ml-4">Edit Source</h2>
|
||||
</div>
|
||||
|
||||
<div class="rounded-sm border border-stroke bg-white px-5 pb-2.5 pt-6 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5 xl:pb-1">
|
||||
<div class="max-w-full overflow-x-auto">
|
||||
<div class="flex flex-col gap-10">
|
||||
<.source_form changeset={@changeset} media_profiles={@media_profiles} action={~p"/sources/#{@source}"} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,42 @@
|
||||
<div class="mb-6 flex gap-3 flex-row items-center justify-between">
|
||||
<h2 class="text-title-md2 font-bold text-black dark:text-white">All Sources</h2>
|
||||
<nav>
|
||||
<.link navigate={~p"/sources/new"}>
|
||||
<.button color="bg-primary" rounding="rounded-full">
|
||||
<span class="font-bold mx-2">+</span> New Source
|
||||
</.button>
|
||||
</.link>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark">
|
||||
<div class="max-w-full overflow-x-auto">
|
||||
<div class="flex flex-col gap-10">
|
||||
<.table rows={@sources} table_class="text-black dark:text-white">
|
||||
<:col :let={source} label="Name">
|
||||
<%= source.friendly_name || source.collection_name %>
|
||||
</:col>
|
||||
<:col :let={source} label="Type"><%= source.collection_type %></:col>
|
||||
<:col :let={source} label="Should Download?">
|
||||
<.icon name={if source.download_media, do: "hero-check", else: "hero-x-mark"} />
|
||||
</:col>
|
||||
<:col :let={source} label="Media Profile">
|
||||
<.link
|
||||
navigate={~p"/media_profiles/#{source.media_profile_id}"}
|
||||
class="hover:text-secondary duration-200 ease-in-out"
|
||||
>
|
||||
<%= source.media_profile.name %>
|
||||
</.link>
|
||||
</:col>
|
||||
<:col :let={source} label="" class="flex place-content-evenly">
|
||||
<.link navigate={~p"/sources/#{source.id}"} class="hover:text-secondary duration-200 ease-in-out mx-0.5">
|
||||
<.icon name="hero-eye" />
|
||||
</.link>
|
||||
<.link navigate={~p"/sources/#{source.id}/edit"} class="hover:text-secondary duration-200 ease-in-out mx-0.5">
|
||||
<.icon name="hero-pencil-square" />
|
||||
</.link>
|
||||
</:col>
|
||||
</.table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
<div class="mb-6 flex gap-3 flex-row items-center">
|
||||
<.link :if={!Plug.Conn.get_session(@conn, :onboarding)} navigate={~p"/sources"}>
|
||||
<.icon name="hero-arrow-left" class="w-10 h-10 hover:dark:text-white" />
|
||||
</.link>
|
||||
<h2 class="text-title-md2 font-bold text-black dark:text-white ml-4">New Source</h2>
|
||||
</div>
|
||||
|
||||
<div class="rounded-sm border border-stroke bg-white px-5 pb-2.5 pt-6 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5 xl:pb-1">
|
||||
<div class="max-w-full overflow-x-auto">
|
||||
<div class="flex flex-col gap-10">
|
||||
<.source_form changeset={@changeset} media_profiles={@media_profiles} action={~p"/sources"} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,76 @@
|
||||
<div class="mb-6 flex gap-3 flex-row items-center justify-between">
|
||||
<div class="flex gap-3 items-center">
|
||||
<.link navigate={~p"/sources"}>
|
||||
<.icon name="hero-arrow-left" class="w-10 h-10 hover:dark:text-white" />
|
||||
</.link>
|
||||
<h2 class="text-title-md2 font-bold text-black dark:text-white ml-4">
|
||||
Source #<%= @source.id %>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<.link navigate={~p"/sources/#{@source}/edit"}>
|
||||
<.button color="bg-primary" rounding="rounded-full">
|
||||
<.icon name="hero-pencil-square" class="mr-2" /> Edit Source
|
||||
</.button>
|
||||
</.link>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="rounded-sm border border-stroke bg-white px-5 py-5 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5">
|
||||
<div class="max-w-full overflow-x-auto">
|
||||
<div class="flex flex-col gap-10 dark:text-white">
|
||||
<h3 class="mt-14 font-bold text-xl">Relationships</h3>
|
||||
<.list>
|
||||
<:item title="media_profile">
|
||||
<.link
|
||||
navigate={~p"/media_profiles/#{@source.media_profile_id}"}
|
||||
class="hover:text-secondary duration-200 ease-in-out"
|
||||
>
|
||||
<%= @source.media_profile.name %>
|
||||
</.link>
|
||||
</:item>
|
||||
</.list>
|
||||
|
||||
<h3 class="font-bold text-xl">Attributes</h3>
|
||||
<.list_items_from_map map={Map.from_struct(@source)} />
|
||||
|
||||
<h3 class="font-bold text-xl">Downloaded Media</h3>
|
||||
<%= if match?([_|_], @downloaded_media) do %>
|
||||
<.table rows={@downloaded_media} table_class="text-black dark:text-white">
|
||||
<:col :let={media_item} label="Title">
|
||||
<%= StringUtils.truncate(media_item.title, 50) %>
|
||||
</:col>
|
||||
<:col :let={media_item} label="" class="flex place-content-evenly">
|
||||
<.link
|
||||
navigate={~p"/sources/#{@source.id}/media/#{media_item.id}"}
|
||||
class="hover:text-secondary duration-200 ease-in-out mx-0.5"
|
||||
>
|
||||
<.icon name="hero-eye" />
|
||||
</.link>
|
||||
</:col>
|
||||
</.table>
|
||||
<% else %>
|
||||
<p class="text-black dark:text-white">Nothing Here!</p>
|
||||
<% end %>
|
||||
|
||||
<h3 class="font-bold text-xl">Pending Media</h3>
|
||||
<%= if match?([_|_], @pending_media) do %>
|
||||
<.table rows={@pending_media} table_class="text-black dark:text-white">
|
||||
<:col :let={media_item} label="Title">
|
||||
<%= StringUtils.truncate(media_item.title, 50) %>
|
||||
</:col>
|
||||
<:col :let={media_item} label="" class="flex place-content-evenly">
|
||||
<.link
|
||||
navigate={~p"/sources/#{@source.id}/media/#{media_item.id}"}
|
||||
class="hover:text-secondary duration-200 ease-in-out mx-0.5"
|
||||
>
|
||||
<.icon name="hero-eye" />
|
||||
</.link>
|
||||
</:col>
|
||||
</.table>
|
||||
<% else %>
|
||||
<p class="text-black dark:text-white">Nothing Here!</p>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,37 @@
|
||||
<.simple_form :let={f} for={@changeset} action={@action}>
|
||||
<.error :if={@changeset.action}>
|
||||
Oops, something went wrong! Please check the errors below.
|
||||
</.error>
|
||||
|
||||
<.input field={f[:friendly_name]} type="text" label="Custom Name" />
|
||||
|
||||
<.input field={f[:original_url]} type="text" label="Source URL" help="URL of a channel or playlist (required)" />
|
||||
|
||||
<.input
|
||||
field={f[:media_profile_id]}
|
||||
options={Enum.map(@media_profiles, &{&1.name, &1.id})}
|
||||
type="select"
|
||||
label="Media Profile"
|
||||
/>
|
||||
|
||||
<.input field={f[:collection_type]} options={friendly_collection_types()} type="select" label="Source Type" />
|
||||
|
||||
<.input
|
||||
field={f[:index_frequency_minutes]}
|
||||
options={friendly_index_frequencies()}
|
||||
type="select"
|
||||
label="Index Frequency"
|
||||
help="The time between one index of this source finishing and the next one starting"
|
||||
/>
|
||||
|
||||
<.input
|
||||
field={f[:download_media]}
|
||||
type="toggle"
|
||||
label="Download Media?"
|
||||
help="Unchecking still indexes media but it won't be downloaded until you enable this option"
|
||||
/>
|
||||
|
||||
<:actions>
|
||||
<.button class="mt-15 mb-5 sm:mb-7.5">Save Source</.button>
|
||||
</:actions>
|
||||
</.simple_form>
|
||||
Reference in New Issue
Block a user