defmodule PinchflatWeb.Sources.SourceController do use PinchflatWeb, :controller use Pinchflat.Media.MediaQuery alias Pinchflat.Repo alias Pinchflat.Tasks alias Pinchflat.Sources alias Pinchflat.Sources.Source alias Pinchflat.Media.MediaItem alias Pinchflat.Profiles.MediaProfile alias Pinchflat.Downloading.DownloadingHelpers alias Pinchflat.SlowIndexing.SlowIndexingHelpers alias Pinchflat.Metadata.SourceMetadataStorageWorker def index(conn, _params) do source_query = from s in Source, as: :source, inner_join: mp in assoc(s, :media_profile), preload: [media_profile: mp], order_by: [asc: s.custom_name], select: map(s, ^Source.__schema__(:fields)), select_merge: %{ downloaded_count: subquery( from m in MediaItem, where: m.source_id == parent_as(:source).id, where: ^MediaQuery.downloaded(), select: count(m.id) ), pending_count: subquery( from m in MediaItem, join: s in assoc(m, :source), where: m.source_id == parent_as(:source).id, where: ^MediaQuery.pending(), select: count(m.id) ) } render(conn, :index, sources: Repo.all(source_query)) end def new(conn, _params) do changeset = Sources.change_source(%Source{}) render(conn, :new, changeset: changeset, media_profiles: media_profiles(), layout: get_onboarding_layout() ) end def create(conn, %{"source" => source_params}) do case Sources.create_source(source_params) do {:ok, source} -> redirect_location = if Settings.get!(:onboarding), do: ~p"/?onboarding=1", else: ~p"/sources/#{source}" conn |> put_flash(:info, "Source created successfully.") |> redirect(to: redirect_location) {:error, %Ecto.Changeset{} = changeset} -> render(conn, :new, changeset: changeset, media_profiles: media_profiles(), layout: get_onboarding_layout() ) end end def show(conn, %{"id" => id}) do source = Repo.preload(Sources.get_source!(id), :media_profile) pending_tasks = source |> Tasks.list_tasks_for(nil, [:executing, :available, :scheduled, :retryable]) |> Repo.preload(:job) render(conn, :show, source: source, pending_tasks: pending_tasks) 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} = params) do delete_files = Map.get(params, "delete_files", false) source = Sources.get_source!(id) {:ok, _source} = Sources.delete_source(source, delete_files: delete_files) flash_message = if delete_files do "Source and files deleted successfully." else "Source deleted successfully. Files were not deleted." end conn |> put_flash(:info, flash_message) |> redirect(to: ~p"/sources") end def force_download_pending(conn, %{"source_id" => id}) do wrap_forced_action( conn, id, "Forcing download of pending media items.", &DownloadingHelpers.enqueue_pending_download_tasks/1 ) end def force_redownload(conn, %{"source_id" => id}) do wrap_forced_action( conn, id, "Forcing re-download of downloaded media items.", &DownloadingHelpers.kickoff_redownload_for_existing_media/1 ) end def force_index(conn, %{"source_id" => id}) do wrap_forced_action( conn, id, "Index enqueued.", &SlowIndexingHelpers.kickoff_indexing_task(&1, %{force: true}) ) end def force_metadata_refresh(conn, %{"source_id" => id}) do wrap_forced_action( conn, id, "Metadata refresh enqueued.", &SourceMetadataStorageWorker.kickoff_with_task/1 ) end defp wrap_forced_action(conn, source_id, message, fun) do source = Sources.get_source!(source_id) fun.(source) conn |> put_flash(:info, message) |> redirect(to: ~p"/sources/#{source}") end defp media_profiles do MediaProfile |> order_by(asc: :name) |> Repo.all() end defp get_onboarding_layout do if Settings.get!(:onboarding) do {Layouts, :onboarding} else {Layouts, :app} end end end