You've already forked algora-tv
							
							
				mirror of
				https://github.com/algora-io/tv.git
				synced 2025-10-30 23:07:56 +02:00 
			
		
		
		
	enable admins to edit transcripts (#8)
This commit is contained in:
		| @@ -326,4 +326,18 @@ defmodule Algora.Library do | ||||
|   def change_subtitle(%Subtitle{} = subtitle, attrs \\ %{}) do | ||||
|     Subtitle.changeset(subtitle, attrs) | ||||
|   end | ||||
|  | ||||
|   def save_subtitles(data) do | ||||
|     {:ok, subs} = Jason.decode(data) | ||||
|  | ||||
|     Enum.each(subs, fn sub -> | ||||
|       %Subtitle{id: sub["id"]} | ||||
|       |> Subtitle.changeset(%{ | ||||
|         start: sub["start"], | ||||
|         end: sub["end"], | ||||
|         body: sub["body"] | ||||
|       }) | ||||
|       |> Repo.update!() | ||||
|     end) | ||||
|   end | ||||
| end | ||||
|   | ||||
| @@ -697,6 +697,7 @@ defmodule AlgoraWeb.CoreComponents do | ||||
|   attr :name, :any | ||||
|   attr :label, :string, default: nil | ||||
|   attr :value, :any | ||||
|   attr :class, :string, default: nil | ||||
|  | ||||
|   attr :type, :string, | ||||
|     default: "text", | ||||
| @@ -775,11 +776,12 @@ defmodule AlgoraWeb.CoreComponents do | ||||
|         id={@id || @name} | ||||
|         name={@name} | ||||
|         class={[ | ||||
|           "mt-2 block min-h-[6rem] w-full rounded-lg border-gray-600 py-[7px] px-[11px]", | ||||
|           "bg-gray-950 mt-2 block min-h-[6rem] w-full rounded-lg border-gray-600 py-[7px] px-[11px]", | ||||
|           "text-gray-50 focus:border-gray-500 focus:outline-none focus:ring-4 focus:ring-gray-100/5 sm:text-sm sm:leading-6", | ||||
|           "phx-no-feedback:border-gray-600 phx-no-feedback:focus:border-gray-500 phx-no-feedback:focus:ring-gray-100/5", | ||||
|           "border-gray-600 focus:border-gray-500 focus:ring-gray-100/5", | ||||
|           @errors != [] && "border-red-500 focus:border-red-500 focus:ring-red-500/10" | ||||
|           @errors != [] && "border-red-500 focus:border-red-500 focus:ring-red-500/10", | ||||
|           @class | ||||
|         ]} | ||||
|         {@rest} | ||||
|       ><%= Phoenix.HTML.Form.normalize_value("textarea", @value) %></textarea> | ||||
|   | ||||
| @@ -40,19 +40,71 @@ defmodule AlgoraWeb.SidePanelLive do | ||||
|             id={"side-panel-content-#{tab}"} | ||||
|             class={["side-panel-content", i != 0 && "hidden"]} | ||||
|           > | ||||
|             <div | ||||
|               :if={tab == :transcript} | ||||
|               id="transcript-subtitles" | ||||
|               class="text-sm break-words flex-1 overflow-y-auto h-[calc(100vh-11rem)]" | ||||
|             > | ||||
|               <div :for={subtitle <- @subtitles} id={"subtitle-#{subtitle.id}"}> | ||||
|                 <span class="font-semibold text-indigo-400"> | ||||
|                   <%= Library.to_hhmmss(subtitle.start) %> | ||||
|                 </span> | ||||
|                 <span class="font-medium text-gray-100"> | ||||
|                   <%= subtitle.body %> | ||||
|                 </span> | ||||
|             <div :if={tab == :transcript}> | ||||
|               <div | ||||
|                 id="show-transcript" | ||||
|                 phx-click={ | ||||
|                   JS.hide(to: "#show-transcript") | ||||
|                   |> JS.show(to: "#edit-transcript") | ||||
|                 } | ||||
|               > | ||||
|                 <div class={ | ||||
|                   [ | ||||
|                     "overflow-y-auto text-sm break-words flex-1", | ||||
|                     # HACK: | ||||
|                     if(@current_user.handle == "zaf", | ||||
|                       do: "h-[calc(100vh-11rem)]", | ||||
|                       else: "h-[calc(100vh-8.75rem)]" | ||||
|                     ) | ||||
|                   ] | ||||
|                 }> | ||||
|                   <div :for={subtitle <- @subtitles} id={"subtitle-#{subtitle.id}"}> | ||||
|                     <span class="font-semibold text-indigo-400"> | ||||
|                       <%= Library.to_hhmmss(subtitle.start) %> | ||||
|                     </span> | ||||
|                     <span class="font-medium text-gray-100"> | ||||
|                       <%= subtitle.body %> | ||||
|                     </span> | ||||
|                   </div> | ||||
|                 </div> | ||||
|  | ||||
|                 <button | ||||
|                   :if={@current_user.handle == "zaf"} | ||||
|                   class="mt-2 w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-purple-600 hover:bg-purple-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-400" | ||||
|                 > | ||||
|                   Edit | ||||
|                 </button> | ||||
|               </div> | ||||
|               <.simple_form | ||||
|                 :if={@current_user.handle == "zaf"} | ||||
|                 id="edit-transcript" | ||||
|                 for={@form} | ||||
|                 phx-submit="save" | ||||
|                 class="hidden h-full" | ||||
|               > | ||||
|                 <.input | ||||
|                   field={@form[:subtitles]} | ||||
|                   type="textarea" | ||||
|                   label="Edit transcript" | ||||
|                   class="font-mono h-[calc(100vh-14.75rem)]" | ||||
|                 /> | ||||
|                 <div class="grid grid-cols-2 gap-4"> | ||||
|                   <button | ||||
|                     name="save" | ||||
|                     value="naive" | ||||
|                     class="w-full flex justify-center z-10 py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-purple-600 hover:bg-purple-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-400" | ||||
|                   > | ||||
|                     Save naive | ||||
|                   </button> | ||||
|                   <button | ||||
|                     name="save" | ||||
|                     value="fast" | ||||
|                     class="w-full flex justify-center z-10 py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-purple-600 hover:bg-purple-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-400" | ||||
|                   > | ||||
|                     Save fast | ||||
|                   </button> | ||||
|                 </div> | ||||
|               </.simple_form> | ||||
|             </div> | ||||
|  | ||||
|             <div :if={tab == :chat}> | ||||
| @@ -96,15 +148,48 @@ defmodule AlgoraWeb.SidePanelLive do | ||||
|   end | ||||
|  | ||||
|   def handle_event("show", %{"video_id" => video_id}, socket) do | ||||
|     subtitles = Library.list_subtitles(%Library.Video{id: video_id}) | ||||
|  | ||||
|     data = %{} | ||||
|  | ||||
|     {:ok, encoded_subtitles} = | ||||
|       subtitles | ||||
|       |> Enum.map(&%{id: &1.id, start: &1.start, end: &1.end, body: &1.body}) | ||||
|       |> Jason.encode(pretty: true) | ||||
|  | ||||
|     types = %{subtitles: :string} | ||||
|     params = %{subtitles: encoded_subtitles} | ||||
|  | ||||
|     changeset = | ||||
|       {data, types} | ||||
|       |> Ecto.Changeset.cast(params, Map.keys(types)) | ||||
|  | ||||
|     video = Library.get_video!(video_id) | ||||
|  | ||||
|     socket = | ||||
|       socket | ||||
|       |> assign(subtitles: Library.list_subtitles(%Library.Video{id: video_id})) | ||||
|       |> assign(messages: Chat.list_messages(%Library.Video{id: video_id})) | ||||
|       |> assign(video: video) | ||||
|       |> assign(subtitles: subtitles) | ||||
|       |> assign(messages: Chat.list_messages(video)) | ||||
|       |> assign_form(changeset) | ||||
|       |> push_event("join_chat", %{id: video_id}) | ||||
|  | ||||
|     {:noreply, socket} | ||||
|   end | ||||
|  | ||||
|   def handle_event("save", %{"data" => %{"subtitles" => subtitles}, "save" => save_type}, socket) do | ||||
|     save(save_type, subtitles) | ||||
|     {:noreply, socket} | ||||
|   end | ||||
|  | ||||
|   defp save("naive", subtitles) do | ||||
|     Library.save_subtitles(subtitles) | ||||
|   end | ||||
|  | ||||
|   defp save("fast", subtitles) do | ||||
|     Fly.Postgres.rpc_and_wait(Library, :save_subtitles, [subtitles]) | ||||
|   end | ||||
|  | ||||
|   defp set_active_content(js \\ %JS{}, to) do | ||||
|     js | ||||
|     |> JS.hide(to: ".side-panel-content") | ||||
| @@ -126,4 +211,8 @@ defmodule AlgoraWeb.SidePanelLive do | ||||
|   defp append_if(list, cond, extra) do | ||||
|     if cond, do: list ++ [extra], else: list | ||||
|   end | ||||
|  | ||||
|   defp assign_form(socket, %Ecto.Changeset{} = changeset) do | ||||
|     assign(socket, :form, to_form(changeset, as: :data)) | ||||
|   end | ||||
| end | ||||
|   | ||||
		Reference in New Issue
	
	Block a user