mirror of https://github.com/sualko/cloud_bbb
Merge b1369aa02c into f9456b2830
commit
93a2fd70cc
|
|
@ -9,7 +9,7 @@
|
|||
}
|
||||
],
|
||||
"require": {
|
||||
"littleredbutton/bigbluebutton-api-php": "^4.0"
|
||||
"littleredbutton/bigbluebutton-api-php": "^6.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.5 || ^9.3",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace OCA\BigBlueButton\BigBlueButton;
|
|||
|
||||
use BigBlueButton\BigBlueButton;
|
||||
use BigBlueButton\Core\Record;
|
||||
use BigBlueButton\Enum\Role;
|
||||
use BigBlueButton\Parameters\CreateMeetingParameters;
|
||||
use BigBlueButton\Parameters\DeleteRecordingsParameters;
|
||||
use BigBlueButton\Parameters\GetRecordingsParameters;
|
||||
|
|
@ -62,13 +63,10 @@ class API {
|
|||
* @return string join url
|
||||
*/
|
||||
public function createJoinUrl(Room $room, float $creationTime, string $displayname, bool $isModerator, ?string $uid = null) {
|
||||
$password = $isModerator ? $room->moderatorPassword : $room->attendeePassword;
|
||||
|
||||
$joinMeetingParams = new JoinMeetingParameters($room->uid, $displayname, $password);
|
||||
$joinMeetingParams = new JoinMeetingParameters($room->uid, $displayname, $isModerator ? Role::MODERATOR : Role::VIEWER);
|
||||
|
||||
// ensure that float is not converted to a string in scientific notation
|
||||
$joinMeetingParams->setCreateTime(sprintf("%.0f", $creationTime));
|
||||
$joinMeetingParams->setJoinViaHtml5(true);
|
||||
$joinMeetingParams->setCreateTime(intval(sprintf("%.0f", $creationTime)));
|
||||
$joinMeetingParams->setRedirect(true);
|
||||
|
||||
// set the guest parameter for everyone but moderators to send all users to the waiting room if setting is selected
|
||||
|
|
@ -130,8 +128,6 @@ class API {
|
|||
|
||||
private function buildMeetingParams(Room $room, ?Presentation $presentation = null): CreateMeetingParameters {
|
||||
$createMeetingParams = new CreateMeetingParameters($room->uid, $room->name);
|
||||
$createMeetingParams->setAttendeePW($room->attendeePassword);
|
||||
$createMeetingParams->setModeratorPW($room->moderatorPassword);
|
||||
$createMeetingParams->setRecord($room->record);
|
||||
$createMeetingParams->setAllowStartStopRecording($room->record);
|
||||
$createMeetingParams->setLogoutURL($this->urlGenerator->getBaseUrl());
|
||||
|
|
@ -239,6 +235,16 @@ class API {
|
|||
* @psalm-return array{id: string, meetingId: string, name: string, published: bool, state: string, startTime: string, participants: int, type: string, length: string, url: string, metas: array}
|
||||
*/
|
||||
private function recordToArray(Record $record): array {
|
||||
$formats = [];
|
||||
|
||||
foreach ($record->getPlaybackFormats() as $format) {
|
||||
$formats[] = [
|
||||
'type' => $format->getType(),
|
||||
'length' => $format->getLength(),
|
||||
'url' => $format->getUrl()
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $record->getRecordId(),
|
||||
'meetingId' => $record->getMeetingId(),
|
||||
|
|
@ -247,10 +253,8 @@ class API {
|
|||
'state' => $record->getState(),
|
||||
'startTime' => $record->getStartTime(),
|
||||
'participants' => $record->getParticipantCount(),
|
||||
'type' => $record->getPlaybackType(),
|
||||
'length' => $record->getPlaybackLength(),
|
||||
'url' => $record->getPlaybackUrl(),
|
||||
'metas' => $record->getMetas(),
|
||||
'formats' => $formats,
|
||||
'metas' => $record->getMetas()
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -65,12 +65,16 @@ export type Recording = {
|
|||
state: 'processing' | 'processed' | 'published' | 'unpublished' | 'deleted';
|
||||
startTime: number;
|
||||
participants: number;
|
||||
type: string;
|
||||
length: number;
|
||||
url: string;
|
||||
formats: RecordingFormat[];
|
||||
meta: any;
|
||||
}
|
||||
|
||||
export type RecordingFormat = {
|
||||
type: string
|
||||
length: number
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface ShareWithOption {
|
||||
label: string;
|
||||
value: {
|
||||
|
|
@ -210,12 +214,12 @@ class Api {
|
|||
return response.data;
|
||||
}
|
||||
|
||||
public async storeRecording(recording: Recording, path: string) {
|
||||
public async storeRecording(recording: Recording, format: RecordingFormat, path: string) {
|
||||
const startDate = new Date(recording.startTime);
|
||||
const filename = `${encodeURIComponent(recording.name + ' ' + startDate.toISOString().replace(/:/g, '-').substr(0,19))}.url`;
|
||||
const url = OC.linkToRemote(`dav/files/${OC.currentUser}${path}/${filename}`);
|
||||
|
||||
await axios.put(url, `[InternetShortcut]\nURL=${recording.url}`);
|
||||
await axios.put(url, `[InternetShortcut]\nURL=${format.url}`);
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
import React from 'react';
|
||||
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
||||
import { Recording } from '../Common/Api';
|
||||
import {Recording, RecordingFormat} from '../Common/Api';
|
||||
|
||||
type Props = {
|
||||
recording: Recording;
|
||||
format: RecordingFormat;
|
||||
isAdmin : boolean;
|
||||
deleteRecording: (recording: Recording) => void;
|
||||
storeRecording: (recording: Recording) => void;
|
||||
storeRecording: (recording: Recording, format: RecordingFormat) => void;
|
||||
publishRecording: (recording: Recording, publish: boolean) => void;
|
||||
}
|
||||
|
||||
const RecordingRow = ({recording, isAdmin, deleteRecording, storeRecording, publishRecording}: Props): JSX.Element => {
|
||||
const RecordingRow = ({recording, format, isAdmin, deleteRecording, storeRecording, publishRecording}: Props): JSX.Element => {
|
||||
|
||||
function checkPublished(recording: Recording, onChange: (value: boolean) => void) {
|
||||
return (
|
||||
|
|
@ -28,19 +29,19 @@ const RecordingRow = ({recording, isAdmin, deleteRecording, storeRecording, publ
|
|||
return (
|
||||
<tr key={recording.id}>
|
||||
<td className="start icon-col">
|
||||
<a href={recording.url} className="action-item" target="_blank" rel="noopener noreferrer" title={t('bbb', 'Open recording')}>
|
||||
<a href={format.url} className="action-item" target="_blank" rel="noopener noreferrer" title={t('bbb', 'Open recording')}>
|
||||
<span className="icon icon-external icon-visible"></span>
|
||||
</a>
|
||||
</td>
|
||||
<td className="share icon-col">
|
||||
<CopyToClipboard text={recording.url} options={{format:'text/plain'}}>
|
||||
<CopyToClipboard text={format.url} options={{format:'text/plain'}}>
|
||||
<button className="action-item copy-to-clipboard" title={t('bbb', 'Copy to clipboard')}>
|
||||
<span className="icon icon-clippy icon-visible" ></span>
|
||||
</button>
|
||||
</CopyToClipboard>
|
||||
</td>
|
||||
<td className="icon-col">
|
||||
<button className="action-item" onClick={() => storeRecording(recording)} title={t('bbb', 'Save as file')}>
|
||||
<button className="action-item" onClick={() => storeRecording(recording, format)} title={t('bbb', 'Save as file')}>
|
||||
<span className="icon icon-add-shortcut icon-visible"></span>
|
||||
</button>
|
||||
</td>
|
||||
|
|
@ -48,13 +49,13 @@ const RecordingRow = ({recording, isAdmin, deleteRecording, storeRecording, publ
|
|||
{(new Date(recording.startTime)).toLocaleString()}
|
||||
</td>
|
||||
<td>
|
||||
{recording.length === 0 ? '< 1 min' : (recording.length + ' min')}
|
||||
{format.length === 0 ? '< 1 min' : (format.length + ' min')}
|
||||
</td>
|
||||
<td>
|
||||
{n('bbb', '%n participant', '%n participants', recording.participants)}
|
||||
</td>
|
||||
<td>
|
||||
{recording.type}
|
||||
{format.type}
|
||||
</td>
|
||||
<td>
|
||||
{isAdmin && checkPublished(recording, (checked) => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
||||
import { api, Recording, Room, Restriction, Access, Permission } from '../Common/Api';
|
||||
import {api, Recording, Room, Restriction, Access, Permission, RecordingFormat} from '../Common/Api';
|
||||
import EditRoom from './EditRoom';
|
||||
import RecordingRow from './RecordingRow';
|
||||
import EditableValue from './EditableValue';
|
||||
|
|
@ -98,9 +98,9 @@ const RoomRow = (props: Props): JSX.Element => {
|
|||
}, undefined, 'httpd/unix-directory');
|
||||
}
|
||||
|
||||
function storeRecording(recording: Recording) {
|
||||
function storeRecording(recording: Recording, format: RecordingFormat) {
|
||||
OC.dialogs.filepicker(t('bbb', 'Select target folder'), (path: string) => {
|
||||
api.storeRecording(recording, path).then((filename) => {
|
||||
api.storeRecording(recording, format, path).then((filename) => {
|
||||
OC.dialogs.info(
|
||||
t('bbb', 'URL to presentation was stored in "{path}" as "{filename}".', { path: path + '/', filename }),
|
||||
t('bbb', 'Link stored'),
|
||||
|
|
@ -288,7 +288,7 @@ const RoomRow = (props: Props): JSX.Element => {
|
|||
<td colSpan={11}>
|
||||
<table>
|
||||
<tbody>
|
||||
{recordings?.sort((r1, r2) => r1.startTime - r2.startTime).map(recording => <RecordingRow key={recording.id} isAdmin={adminRoom} recording={recording} deleteRecording={deleteRecording} storeRecording={storeRecording} publishRecording={publishRecording} />)}
|
||||
{recordings?.sort((r1, r2) => r1.startTime - r2.startTime).map(recording => recording.formats.map(format => <RecordingRow key={recording.id} isAdmin={adminRoom} recording={recording} format={format} deleteRecording={deleteRecording} storeRecording={storeRecording} publishRecording={publishRecording} />))}
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
|
|
|
|||
Loading…
Reference in New Issue