├── assets ├── .eslintignore ├── .prettierrc.json ├── js │ ├── types │ │ ├── emoji-mart │ │ │ └── index.d.ts │ │ ├── react-swm-icon-pack │ │ │ └── index.d.ts │ │ └── types.ts │ ├── components │ │ ├── event │ │ │ ├── MobileLeftSidebar.tsx │ │ │ ├── animations │ │ │ │ └── ConfettiAnimation.tsx │ │ │ ├── ShareButton.tsx │ │ │ ├── MobileBottomPanel.tsx │ │ │ ├── MobileRightSidebar.tsx │ │ │ ├── ModePanel.tsx │ │ │ ├── RtcPlayer.tsx │ │ │ ├── MobileHlsBar.tsx │ │ │ ├── HlsControlBar.tsx │ │ │ ├── NamePopup.tsx │ │ │ └── ShareList.tsx │ │ ├── helpers │ │ │ ├── svg │ │ │ │ ├── FacebookIcon.tsx │ │ │ │ ├── MessengerIcon.tsx │ │ │ │ └── TwitterIcon.tsx │ │ │ ├── GenericButton.tsx │ │ │ ├── MenuPopover.tsx │ │ │ └── GoogleButton.tsx │ │ ├── dashboard │ │ │ ├── UserField.tsx │ │ │ ├── SearchAndCreatePanel.tsx │ │ │ ├── MobileHeader.tsx │ │ │ ├── SideDashboardPanel.tsx │ │ │ ├── WelcomePanel.tsx │ │ │ ├── EventField.tsx │ │ │ ├── MembraneLogo.tsx │ │ │ └── EventsArea.tsx │ │ └── Router.tsx │ ├── utils │ │ ├── collectionUtils.ts │ │ ├── useToggle.tsx │ │ ├── useAutoHideMobileBottomBar.tsx │ │ ├── ScreenTypeContext.ts │ │ ├── StreamStartContext.tsx │ │ ├── reactUtils.ts │ │ ├── hlsLatancy.ts │ │ ├── modePanelUtils.ts │ │ ├── const.ts │ │ ├── googleAuthUtils.ts │ │ ├── chatUtils.ts │ │ ├── useRecordingChatMessages.ts │ │ ├── useHls.ts │ │ ├── dashboardUtils.ts │ │ └── headerUtils.ts │ ├── app.tsx │ ├── services │ │ ├── jwtApi.ts │ │ └── index.tsx │ └── pages │ │ └── Dashboard.tsx ├── css │ ├── recording │ │ └── recording.css │ ├── dashboard │ │ ├── dashboard.css │ │ ├── userfield.css │ │ ├── searchandcreatepanel.css │ │ ├── welcomepanel.css │ │ ├── modalform.css │ │ ├── sidedashboardpanel.css │ │ └── eventform.css │ ├── event │ │ ├── event.css │ │ ├── namepopup.css │ │ ├── streamarea.css │ │ ├── mobilebottompanel.css │ │ ├── modepanel.css │ │ ├── presenterarea.css │ │ ├── animation.css │ │ ├── mobilesidebars.css │ │ ├── hlscontrolbar.css │ │ ├── shareButton.css │ │ ├── hlsplayer.css │ │ ├── rtcplayer.css │ │ ├── participants.css │ │ ├── controlpanel.css │ │ └── header.css │ ├── toast.css │ └── main.css ├── tsconfig.json ├── helpers │ └── timer.html ├── .eslintrc.json └── package.json ├── lib ├── membrane_live_web │ ├── templates │ │ ├── page │ │ │ └── index.html.heex │ │ └── layout │ │ │ ├── app.html.heex │ │ │ ├── live.html.heex │ │ │ └── root.html.heex │ ├── views │ │ ├── page_view.ex │ │ ├── layout_view.ex │ │ ├── login_view.ex │ │ ├── error_view.ex │ │ ├── chat_view.ex │ │ ├── user_view.ex │ │ ├── changeset_view.ex │ │ ├── error_helpers.ex │ │ ├── recordings_view.ex │ │ └── webinar_view.ex │ ├── controllers │ │ ├── page_controller.ex │ │ ├── user_info_controller.ex │ │ ├── chat_controller.ex │ │ ├── fallback_controller.ex │ │ ├── login_controller.ex │ │ ├── recordings_controller.ex │ │ ├── user_controller.ex │ │ └── webinar_controller.ex │ ├── channels │ │ ├── event_presence.ex │ │ └── event_socket.ex │ ├── gettext.ex │ ├── endpoint.ex │ ├── helpers │ │ ├── token_error_info.ex │ │ ├── controller_callback_helper.ex │ │ └── ets_helper.ex │ ├── plugs │ │ └── auth.ex │ └── router.ex ├── membrane_live │ ├── mailer.ex │ ├── repo.ex │ ├── helpers.ex │ ├── tokens │ │ ├── google_token.ex │ │ └── custom_tokens.ex │ ├── accounts │ │ └── user.ex │ ├── application.ex │ ├── webinars │ │ └── webinar.ex │ ├── chats │ │ └── chat.ex │ ├── accounts.ex │ └── tokens.ex ├── membrane_live.ex └── membrane_live_web.ex ├── priv ├── repo │ └── migrations │ │ ├── .formatter.exs │ │ ├── 20220824133830_add_constraints.exs │ │ ├── 20230323112706_add_is_private_field_to_webinars.exs │ │ ├── 20221013194113_add_is_finished_field_to_webinars.exs │ │ ├── 20220822133355_add_moderator_to_webinar.exs │ │ ├── 20220804123329_create_users.exs │ │ ├── 20220718102030_create_webinars.exs │ │ └── 20221115140746_add_chats_table.exs ├── static │ ├── favicon.ico │ ├── robots.txt │ └── icons │ │ ├── heart-regular.svg │ │ ├── share-nodes-regular.svg │ │ ├── comments-regular.svg │ │ └── gifts-regular.svg └── gettext │ └── errors.pot ├── .formatter.exs ├── config ├── prod.exs ├── dev.exs ├── test.exs ├── config.exs └── runtime.exs ├── test ├── membrane_live_web │ └── views │ │ ├── error_view_test.exs │ │ ├── layout_view_test.exs │ │ └── page_view_test.exs ├── test_helper.exs ├── support │ ├── fixtures │ │ ├── webinars_fixtures.ex │ │ └── accounts_fixtures.ex │ ├── channel_case.ex │ ├── conn_case.ex │ ├── token │ │ └── google_token_mock.ex │ └── data_case.ex └── membrane_live │ ├── accounts_test.exs │ └── event_service_test.exs ├── docker-entrypoint.sh ├── .editorconfig ├── .env.sample ├── make_release.sh ├── scripts └── key-gen.sh ├── .circleci └── config.yml ├── docker-compose.yml ├── README.md ├── .github └── workflows │ ├── staging_build_and_deploy.yml │ ├── sandbox_build_and_deploy.template │ └── tag_build_and_deploy.yml ├── Dockerfile └── docker-compose-test.yml /assets/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /assets/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120 3 | } 4 | -------------------------------------------------------------------------------- /lib/membrane_live_web/templates/page/index.html.heex: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /assets/js/types/emoji-mart/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "@emoji-mart/react"; 2 | -------------------------------------------------------------------------------- /lib/membrane_live_web/templates/layout/app.html.heex: -------------------------------------------------------------------------------- 1 | <%= @inner_content %> 2 | -------------------------------------------------------------------------------- /lib/membrane_live_web/templates/layout/live.html.heex: -------------------------------------------------------------------------------- 1 | <%= @inner_content %> -------------------------------------------------------------------------------- /priv/repo/migrations/.formatter.exs: -------------------------------------------------------------------------------- 1 | [ 2 | import_deps: [:ecto_sql], 3 | inputs: ["*.exs"] 4 | ] 5 | -------------------------------------------------------------------------------- /priv/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/membraneframework-labs/membrane_live/HEAD/priv/static/favicon.ico -------------------------------------------------------------------------------- /lib/membrane_live_web/views/page_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MembraneLiveWeb.PageView do 2 | use MembraneLiveWeb, :view 3 | end 4 | -------------------------------------------------------------------------------- /.formatter.exs: -------------------------------------------------------------------------------- 1 | [ 2 | inputs: [ 3 | "{lib,test,config}/**/*.{ex,exs}", 4 | ".formatter.exs", 5 | "*.exs" 6 | ] 7 | ] 8 | -------------------------------------------------------------------------------- /config/prod.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | 3 | config :logger, level: :info 4 | 5 | config :membrane_live, MembraneLiveWeb.Endpoint, server: true 6 | -------------------------------------------------------------------------------- /lib/membrane_live/mailer.ex: -------------------------------------------------------------------------------- 1 | defmodule MembraneLive.Mailer do 2 | @moduledoc false 3 | 4 | use Swoosh.Mailer, otp_app: :membrane_live 5 | end 6 | -------------------------------------------------------------------------------- /test/membrane_live_web/views/error_view_test.exs: -------------------------------------------------------------------------------- 1 | defmodule MembraneLiveWeb.ErrorViewTest do 2 | use MembraneLiveWeb.ConnCase, async: true 3 | end 4 | -------------------------------------------------------------------------------- /test/membrane_live_web/views/layout_view_test.exs: -------------------------------------------------------------------------------- 1 | defmodule MembraneLiveWeb.LayoutViewTest do 2 | use MembraneLiveWeb.ConnCase, async: true 3 | end 4 | -------------------------------------------------------------------------------- /test/membrane_live_web/views/page_view_test.exs: -------------------------------------------------------------------------------- 1 | defmodule MembraneLiveWeb.PageViewTest do 2 | use MembraneLiveWeb.ConnCase, async: true 3 | end 4 | -------------------------------------------------------------------------------- /docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Docker entrypoint script. 3 | 4 | bin/membrane_live eval "MembraneLive.Release.create_and_migrate" 5 | 6 | exec "$@" 7 | -------------------------------------------------------------------------------- /lib/membrane_live/repo.ex: -------------------------------------------------------------------------------- 1 | defmodule MembraneLive.Repo do 2 | use Ecto.Repo, 3 | otp_app: :membrane_live, 4 | adapter: Ecto.Adapters.Postgres 5 | end 6 | -------------------------------------------------------------------------------- /test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start(capture_log: true) 2 | Ecto.Adapters.SQL.Sandbox.mode(MembraneLive.Repo, :manual) 3 | Application.ensure_all_started(:bypass) 4 | -------------------------------------------------------------------------------- /lib/membrane_live_web/views/layout_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MembraneLiveWeb.LayoutView do 2 | use MembraneLiveWeb, :view 3 | 4 | @compile {:no_warn_undefined, {Routes, :live_dashboard_path, 2}} 5 | end 6 | -------------------------------------------------------------------------------- /priv/repo/migrations/20220824133830_add_constraints.exs: -------------------------------------------------------------------------------- 1 | defmodule MembraneLive.Repo.Migrations.AddConstraints do 2 | use Ecto.Migration 3 | 4 | def change do 5 | create unique_index(:users, :email) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /priv/static/robots.txt: -------------------------------------------------------------------------------- 1 | # See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | max_line_length = 100 10 | tab_width = 2 11 | trim_trailing_whitespace = true 12 | -------------------------------------------------------------------------------- /lib/membrane_live_web/controllers/page_controller.ex: -------------------------------------------------------------------------------- 1 | defmodule MembraneLiveWeb.PageController do 2 | use MembraneLiveWeb, :controller 3 | 4 | @spec index(Plug.Conn.t(), any) :: Plug.Conn.t() 5 | def index(conn, _params) do 6 | render(conn, "index.html") 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/membrane_live_web/views/login_view.ex: -------------------------------------------------------------------------------- 1 | defmodule MembraneLiveWeb.LoginView do 2 | use MembraneLiveWeb, :view 3 | 4 | def render("token.json", %{auth_token: auth_token, refresh_token: ref_token}) do 5 | %{authToken: auth_token, refreshToken: ref_token} 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /priv/repo/migrations/20230323112706_add_is_private_field_to_webinars.exs: -------------------------------------------------------------------------------- 1 | defmodule MembraneLive.Repo.Migrations.AddIsPrivateFieldToWebinars do 2 | use Ecto.Migration 3 | 4 | def change do 5 | alter table(:webinars) do 6 | add(:is_private, :boolean, default: false) 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /priv/repo/migrations/20221013194113_add_is_finished_field_to_webinars.exs: -------------------------------------------------------------------------------- 1 | defmodule MembraneLive.Repo.Migrations.AddIsFinishedFieldToWebinars do 2 | use Ecto.Migration 3 | 4 | def change do 5 | alter table(:webinars) do 6 | add(:is_finished, :boolean, default: false) 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /assets/js/components/event/MobileLeftSidebar.tsx: -------------------------------------------------------------------------------- 1 | export const MobileLeftSidebar = () => { 2 | return ( 3 |Membrane
22 | {isAuthenticated ? ( 23 | 26 | ) : ( 27 |Membrane
31 |Hi{name ? ` ${name.split(" ")[0]}` : ""}!
33 |What event would you like to join today?
34 | > 35 | )} 36 | {currentEvents == "Recorded events" && ( 37 | <> 38 |Recorded events
39 |
40 | Here you will find past events that have been recorded
41 |
42 | Enjoy your watch!
43 |
{webinarInfo.presenters.join(", ")}
33 | clearSessionStorageName()}> 34 | {webinarInfo.title} 35 | 36 |{webinarInfo.description}
37 |Upcoming events
49 |No upcoming events! Create one with the button above!
} 51 |Past events
53 |No past events!
}Recorded events
59 |No available recorded events
} 61 |Share ({eventTitle})
70 |