You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

functions.ts 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import { IStateful } from '../base/app/types';
  2. import { IJitsiConference } from '../base/conference/reducer';
  3. import { getFakeParticipants } from '../base/participants/functions';
  4. import { toState } from '../base/redux/functions';
  5. import {
  6. ALLOW_ALL_URL_DOMAINS,
  7. PLAYBACK_START,
  8. PLAYBACK_STATUSES,
  9. SHARED_VIDEO,
  10. VIDEO_PLAYER_PARTICIPANT_NAME,
  11. YOUTUBE_PLAYER_PARTICIPANT_NAME,
  12. YOUTUBE_URL_DOMAIN
  13. } from './constants';
  14. /**
  15. * Validates the entered video url.
  16. *
  17. * It returns a boolean to reflect whether the url matches the youtube regex.
  18. *
  19. * @param {string} url - The entered video link.
  20. * @returns {string} The youtube video id if matched.
  21. */
  22. function getYoutubeId(url: string) {
  23. if (!url) {
  24. return null;
  25. }
  26. const p = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|(?:m\.)?youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/;// eslint-disable-line max-len
  27. const result = url.match(p);
  28. return result ? result[1] : null;
  29. }
  30. /**
  31. * Checks if the status is one that is actually sharing the video - playing, pause or start.
  32. *
  33. * @param {string} status - The shared video status.
  34. * @returns {boolean}
  35. */
  36. export function isSharingStatus(status: string) {
  37. return [ PLAYBACK_STATUSES.PLAYING, PLAYBACK_STATUSES.PAUSED, PLAYBACK_START ].includes(status);
  38. }
  39. /**
  40. * Returns true if there is a video being shared in the meeting.
  41. *
  42. * @param {Object | Function} stateful - The Redux state or a function that gets resolved to the Redux state.
  43. * @returns {boolean}
  44. */
  45. export function isVideoPlaying(stateful: IStateful): boolean {
  46. let videoPlaying = false;
  47. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  48. for (const [ id, p ] of getFakeParticipants(stateful)) {
  49. if (p.name === VIDEO_PLAYER_PARTICIPANT_NAME || p.name === YOUTUBE_PLAYER_PARTICIPANT_NAME) {
  50. videoPlaying = true;
  51. break;
  52. }
  53. }
  54. return videoPlaying;
  55. }
  56. /**
  57. * Extracts a Youtube id or URL from the user input.
  58. *
  59. * @param {string} input - The user input.
  60. * @returns {string|undefined}
  61. */
  62. export function extractYoutubeIdOrURL(input: string) {
  63. if (!input) {
  64. return;
  65. }
  66. const trimmedLink = input.trim();
  67. if (!trimmedLink) {
  68. return;
  69. }
  70. const youtubeId = getYoutubeId(trimmedLink);
  71. if (youtubeId) {
  72. return youtubeId;
  73. }
  74. // Check if the URL is valid, native may crash otherwise.
  75. try {
  76. // eslint-disable-next-line no-new
  77. new URL(trimmedLink);
  78. } catch (_) {
  79. return;
  80. }
  81. return trimmedLink;
  82. }
  83. /**
  84. * Returns true if shared video functionality is enabled and false otherwise.
  85. *
  86. * @param {IStateful} stateful - - The redux store or {@code getState} function.
  87. * @returns {boolean}
  88. */
  89. export function isSharedVideoEnabled(stateful: IStateful) {
  90. const state = toState(stateful);
  91. const { disableThirdPartyRequests = false } = state['features/base/config'];
  92. return !disableThirdPartyRequests;
  93. }
  94. /**
  95. * Returns true if the passed url is allowed to be used for shared video or not.
  96. *
  97. * @param {string} url - The URL.
  98. * @param {Array<string>} allowedUrlDomains - The allowed url domains.
  99. * @param {boolean} considerNonURLsAllowedForYoututbe - If true, the invalid URLs will be considered youtube IDs
  100. * and if youtube is allowed the function will return true.
  101. * @returns {boolean}
  102. */
  103. export function isURLAllowedForSharedVideo(url: string,
  104. allowedUrlDomains: Array<string> = [], considerNonURLsAllowedForYoututbe = false) {
  105. if (!url) {
  106. return false;
  107. }
  108. try {
  109. const urlObject = new URL(url);
  110. if ([ 'http:', 'https:' ].includes(urlObject?.protocol?.toLowerCase())) {
  111. return allowedUrlDomains.includes(ALLOW_ALL_URL_DOMAINS) || allowedUrlDomains.includes(urlObject?.hostname);
  112. }
  113. } catch (_e) { // it should be YouTube id.
  114. return considerNonURLsAllowedForYoututbe && allowedUrlDomains.includes(YOUTUBE_URL_DOMAIN);
  115. }
  116. return false;
  117. }
  118. /**
  119. * Sends SHARED_VIDEO command.
  120. *
  121. * @param {string} id - The id of the video.
  122. * @param {string} status - The status of the shared video.
  123. * @param {JitsiConference} conference - The current conference.
  124. * @param {string} localParticipantId - The id of the local participant.
  125. * @param {string} time - The seek position of the video.
  126. * @returns {void}
  127. */
  128. export function sendShareVideoCommand({ id, status, conference, localParticipantId = '', time, muted, volume }: {
  129. conference?: IJitsiConference; id: string; localParticipantId?: string; muted?: boolean;
  130. status: string; time: number; volume?: number;
  131. }) {
  132. conference?.sendCommandOnce(SHARED_VIDEO, {
  133. value: id,
  134. attributes: {
  135. from: localParticipantId,
  136. muted,
  137. state: status,
  138. time,
  139. volume
  140. }
  141. });
  142. }