From 2aec4b9fabd3afd4191bad61de5c58eff7a8be37 Mon Sep 17 00:00:00 2001 From: Carlos Santos <4a.santos@gmail.com> Date: Mon, 24 Oct 2022 17:08:32 +0200 Subject: [PATCH] openvidu-components: Added captions --- openvidu-components-angular/package.json | 2 +- .../captions/captions.component.css | 205 ++- .../captions/captions.component.html | 58 +- .../captions/captions.component.spec.ts | 12 +- .../components/captions/captions.component.ts | 1574 ++--------------- .../components/layout/layout.component.css | 4 +- .../components/layout/layout.component.html | 4 +- .../lib/components/layout/layout.component.ts | 18 +- .../settings-panel.component.html | 12 +- .../settings-panel.component.ts | 10 +- .../components/session/session.component.ts | 51 +- .../captions.component.css} | 0 .../captions.component.html} | 13 +- .../captions/captions.component.spec.ts | 24 + .../settings/captions/captions.component.ts | 47 + .../subtitles/subtitles.component.spec.ts | 25 - .../settings/subtitles/subtitles.component.ts | 44 - .../components/toolbar/toolbar.component.html | 12 +- .../components/toolbar/toolbar.component.ts | 24 +- .../videoconference.component.css | 2 +- .../videoconference.component.ts | 12 +- .../directives/api/api.directive.module.ts | 27 +- .../lib/directives/api/internals.directive.ts | 2 +- .../lib/directives/api/toolbar.directive.ts | 9 +- .../api/videoconference.directive.ts | 70 +- .../openvidu-angular/src/lib/lang/cn.json | 6 +- .../openvidu-angular/src/lib/lang/de.json | 6 +- .../openvidu-angular/src/lib/lang/en.json | 6 +- .../openvidu-angular/src/lib/lang/es.json | 6 +- .../openvidu-angular/src/lib/lang/fr.json | 6 +- .../openvidu-angular/src/lib/lang/hi.json | 6 +- .../openvidu-angular/src/lib/lang/it.json | 6 +- .../openvidu-angular/src/lib/lang/ja.json | 6 +- .../openvidu-angular/src/lib/lang/nl.json | 6 +- .../openvidu-angular/src/lib/lang/pt.json | 6 +- .../src/lib/models/caption.model.ts | 10 + .../src/lib/models/panel.model.ts | 2 +- .../src/lib/models/storage.model.ts | 5 +- .../src/lib/openvidu-angular.module.ts | 76 +- .../services/caption/caption.service.spec.ts | 16 + .../lib/services/caption/caption.service.ts | 47 + .../config/openvidu-angular.config.service.ts | 6 +- .../lib/services/document/document.service.ts | 12 +- .../src/lib/services/layout/layout.service.ts | 29 +- .../lib/services/storage/storage.service.ts | 10 +- .../services/translate/translate.service.ts | 8 +- 46 files changed, 751 insertions(+), 1791 deletions(-) rename openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/{subtitles/subtitles.component.css => captions/captions.component.css} (100%) rename openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/{subtitles/subtitles.component.html => captions/captions.component.html} (60%) create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/captions/captions.component.spec.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/captions/captions.component.ts delete mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/subtitles/subtitles.component.spec.ts delete mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/subtitles/subtitles.component.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/models/caption.model.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/services/caption/caption.service.spec.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/services/caption/caption.service.ts diff --git a/openvidu-components-angular/package.json b/openvidu-components-angular/package.json index 5aa3748ba..264eb9b92 100644 --- a/openvidu-components-angular/package.json +++ b/openvidu-components-angular/package.json @@ -11,7 +11,7 @@ "@angular/platform-browser-dynamic": "13.3.9", "@angular/router": "13.3.9", "autolinker": "3.14.3", - "lorem-ipsum": "^2.0.8", + "openvidu-browser": "file:openvidu-browser-2.23.0.tgz", "openvidu-browser": "2.23.0", "rxjs": "7.5.6", "tslib": "2.3.1", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.css b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.css index 70db1dc45..6e302e3b8 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.css +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.css @@ -1,78 +1,193 @@ -.subtitles-container { +.captions-container { /* padding: 5px; */ display: flex; - height: var(--ov-captions-height, 200px); + height: var(--ov-captions-height, 230px); margin: 0px 10px; } -.subtitles-offset { - height: var(--ov-captions-height, 200px); +.captions-offset { + height: var(--ov-captions-height, 230px); width: 15%; text-align: center; } -.subtitles-main-container { - flex-grow: 1; - align-self: center; - margin-left: 15px; - max-height: var(--ov-captions-height, 200px); - width: 70%; - overflow: hidden; +.captions-offset-xl { + width: 25% !important; } -/* .subtitles-offset + .subtitles-offset { - margin-left: 2%; -} */ -#subtitle-settings-btn { +.captions-center-container { + flex-grow: 1; + align-self: center; + /* margin-left: 15px; */ + max-height: var(--ov-captions-height, 230px); + width: 70%; + overflow: hidden; + + height: var(--ov-captions-height, 230px); + padding: 0px 10vw 0px; +} + + +/* +* Screen XL +*/ +.captions-center-container.screen-xl { + padding: 0px 14vw; +} + +.captions-center-container.screen-xl .caption-event>span { + font-size: 22px; +} + +.captions-center-container.screen-xl #speaker { + font-size: 16px; +} + +/* captions div*/ +.captions-center-container.screen-xl.events-one .caption-event { + max-height: 140px; +} + +.captions-center-container.screen-xl.events-two .caption-event { + max-height: 69px; +} + +.captions-center-container.screen-xl.events-three .caption-event { + max-height: 35px; +} + + +/* +* Screen MD +*/ +.captions-center-container.screen-md .caption-event>span { + font-size: 20px; +} + +.captions-center-container.screen-md #speaker { + font-size: 14px; +} + +/* captions div*/ +.captions-center-container.screen-md.events-one .caption-event { + max-height: 140px; +} + +.captions-center-container.screen-md.events-two .caption-event { + max-height: 69px; +} + +.captions-center-container.screen-md.events-three .caption-event { + max-height: 35px; +} + +/* +* Screen SM +*/ + +.captions-center-container.screen-sm { + padding: 0px 2vw; +} +.captions-center-container.screen-sm .caption-event>span { + font-size: 20px; +} + +.captions-center-container.screen-sm #speaker { + font-size: 12px; +} + +/* captions div*/ + +.captions-center-container.screen-sm.events-one .caption-event { + max-height: 127px; +} + +.captions-center-container.screen-sm.events-two .caption-event { + max-height: 64px; +} + +.captions-center-container.screen-sm.events-three .caption-event { + max-height: 33px; +} + +/* +* Screen XS +*/ + +.captions-center-container.screen-xs { + padding: 0px 2vw 0px; +} + +.captions-center-container.screen-xs .caption-event>span { + font-size: 20px; +} +.captions-center-container.screen-xs #speaker { + font-size: 12px; +} + +/* captions div*/ +.captions-center-container.screen-xs.events-one .caption-event { + max-height: 130px; +} + +.captions-center-container.screen-xs.events-two .caption-event { + max-height: 69px; +} + +.captions-center-container.screen-xs.events-three .caption-event { + max-height: 35px; +} + +.captions-center-container .going-to-disappear{ + max-height: 30px !important; +} + + + +#caption-settings-btn { color: var(--ov-text-color); background-color: var(--ov-secondary-color); } -#subtitle-settings-icon { +#caption-settings-icon { font-size: 15px; height: 15px; width: 15px; padding-right: 5px; } -#author { - margin-bottom: 3px; +#speaker { + margin-bottom: 2px; font-weight: bold; + /* padding: 5px; */ + margin-left: -5px; + width: fit-content; } -#subtitle-text, -#author { +.captions-center-container .element { + margin: 8px 0px; +} + +.caption-event { + /* background-color: beige; */ + overflow: auto; + pointer-events: none; +} + + +.caption-text, +#speaker { color: var(--ov-text-color); - font-family: "Roboto",arial,sans-serif + font-family: 'Roboto', arial, sans-serif; } -.subtitles-main-container .element { - margin: 5px; -} -#subtitle-text { +.caption-text { background-color: var(--ov-logo-background-color); padding: 4.5px; line-height: 1.6; word-break: break-word; } -.big-text { - font-size: 22px; -} -.medium-text { - font-size: 20px; -} -.small-text { - font-size: 18px; -} -.extra-small-text { - font-size: 16px; -} -.big-author { - font-size: 16px; -} -.medium-author { - font-size: 14px; -} -.small-author { - font-size: 12px; + +::-webkit-scrollbar { + display: none; } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.html index dc0ec828b..b550a5232 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.html +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.html @@ -1,36 +1,40 @@ -
-
-
-
-
-

- {{ item.author }} ({{item.text.length}}) +

+
+

+ {{ caption.nickname }}

- - {{ item.text }} + {{ caption.text }} +
-
-
+
diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.spec.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.spec.ts index 4c6d1353d..b73851b69 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.spec.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.spec.ts @@ -1,20 +1,20 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { SubtitlesComponent } from './subtitles.component'; +import { CaptionsComponent } from './captions.component'; -describe('SubtitlesComponent', () => { - let component: SubtitlesComponent; - let fixture: ComponentFixture; +describe('CaptionsComponent', () => { + let component: CaptionsComponent; + let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ SubtitlesComponent ] + declarations: [ CaptionsComponent ] }) .compileComponents(); }); beforeEach(() => { - fixture = TestBed.createComponent(SubtitlesComponent); + fixture = TestBed.createComponent(CaptionsComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.ts index c938f2db7..e5888420f 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.ts @@ -4,18 +4,18 @@ import { Component, ElementRef, OnInit, - QueryList, - ViewChild, - ViewChildren + QueryList, ViewChildren } from '@angular/core'; -import { BehaviorSubject, Observable, Subscription } from 'rxjs'; -import { PanelSettingsOptions, PanelType } from '../../models/panel.model'; +import { Subscription } from 'rxjs'; import { PanelEvent, PanelService } from '../../services/panel/panel.service'; -import { DocumentService } from '../../services/document/document.service'; -import { MediaChange } from '@angular/flex-layout'; -//TODO: Remove when speech to text is integrated -// import { LoremIpsum } from 'lorem-ipsum'; +import { animate, style, transition, trigger } from '@angular/animations'; +import { Session, SpeechToTextEvent } from 'openvidu-browser'; +import { CaptionModel } from '../../models/caption.model'; +import { PanelSettingsOptions, PanelType } from '../../models/panel.model'; +import { CaptionService } from '../../services/caption/caption.service'; +import { OpenViduService } from '../../services/openvidu/openvidu.service'; +import { ParticipantService } from '../../services/participant/participant.service'; /** * @internal @@ -24,1349 +24,54 @@ import { MediaChange } from '@angular/flex-layout'; selector: 'ov-captions', templateUrl: './captions.component.html', styleUrls: ['./captions.component.css'], + animations: [ + trigger('captionAnimation', [ + transition(':enter', [style({ opacity: 0 }), animate('50ms ease-in', style({ opacity: 1 }))]) + // transition(':leave', [style({ opacity: 1 }), animate('10ms ease-out', style({ opacity: 0 }))]) + ]) + ], changeDetection: ChangeDetectionStrategy.OnPush }) export class CaptionsComponent implements OnInit { - @ViewChild('textContainer') textContainer: ElementRef; + scrollContainer: QueryList; + + @ViewChildren('captionEventElement') + set captionEventRef(captionEventsRef: QueryList) { + setTimeout(() => { + if (captionEventsRef) { + this.scrollContainer = captionEventsRef; + } + }, 0); + } - @ViewChildren('captionElement') captionElementsRef: QueryList; - /** - * @ignore - */ - subtitleText: string; - /** - * @ignore - */ - screenSize: string; - /** - * @ignore - */ settingsPanelOpened: boolean; + + captionEvents: CaptionModel[] = []; + + session: Session; + + private deleteTimeout: NodeJS.Timeout; + + private DELETE_TIMEOUT = 5 * 1000; + private MAX_EVENTS_LIMIT = 3; + private captionLanguageSubscription: Subscription; + private captionLangSelected: { name: string; ISO: string }; private screenSizeSub: Subscription; private panelTogglingSubscription: Subscription; - interval: NodeJS.Timer; - fakeEvent: Observable<{ connectionId: string; partial: string; text?: string }>; - - captionElements: { connectionId: string; author: string; text: string }[] = []; - - //TODO: Remove when speech to text is integrated - private sample = [ - { connectionId: '1', partial: 'frente' }, - { connectionId: '1', partial: 'friends' }, - { connectionId: '1', partial: 'friends' }, - { connectionId: '1', partial: 'friends estilizado' }, - { connectionId: '1', partial: 'friends estilizado' }, - { connectionId: '1', partial: 'friends estilizado' }, - { connectionId: '1', partial: 'friends estilizado' }, - { connectionId: '1', partial: 'friends estilizado efe' }, - { connectionId: '1', partial: 'friends estilizado efe' }, - { connectionId: '1', partial: 'friends estilizado efe erre' }, - { connectionId: '1', partial: 'friends estilizado efe erre' }, - { connectionId: '1', partial: 'friends estilizado efe erre' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y he' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y he' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y he' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y he' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en de' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en de' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en de' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en de' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida como' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida como' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida como' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa' }, - { connectionId: '1', partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa' }, - { - connectionId: '1', - partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como' - }, - { - connectionId: '1', - partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como' - }, - { - connectionId: '1', - partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como' - }, - { - connectionId: '1', - partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como' - }, - { - connectionId: '1', - partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como' - }, - { - connectionId: '1', - partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como' - }, - { - connectionId: '1', - partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como' - }, - { - connectionId: '1', - partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como' - }, - { - connectionId: '1', - partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas' - }, - { - connectionId: '1', - partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas' - }, - { - connectionId: '1', - partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas' - }, - { - connectionId: '1', - partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas' - }, - { - connectionId: '1', - partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas' - }, - { - connectionId: '1', - partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas' - }, - { - connectionId: '1', - partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas' - }, - { - connectionId: '1', - partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas' - }, - { - connectionId: '1', - partial: 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense crear productos' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense crear productos' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense crear productos' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por mayor' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por mayor' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por mayor' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por mark' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por mark' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y la' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y la' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y la' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y la' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y la' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y lápiz' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y lápiz' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y lápiz cree' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y lápiz cree' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y lápiz cree' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y lápiz cree' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y lápiz cree' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y lápiz creen se' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y lápiz creen se' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y lápiz creen se' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y lápiz creen se' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y lápiz creen se' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y lápiz creen se' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y lápiz creen se' - }, - { - connectionId: '1', - partial: - 'friends estilizado efe el rey y en ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense creado y producida por marta kaufman y lápiz creen se' - }, - { - connectionId: '1', - text: 'friends estilizado efe erre y ene de ese también conocida en hispanoamérica como amigos y en españa como colegas durante la temporada uno es una serie de televisión estadounidense y producida por marta kaufman y la creen se emitió' - }, - { connectionId: '2', partial: 'la' }, - { connectionId: '2', partial: 'primera vez en' }, - { connectionId: '2', partial: 'primera vez en' }, - { connectionId: '2', partial: 'a veces vendidos' }, - { connectionId: '2', partial: 'a veces vendidos' }, - { connectionId: '2', partial: 'a veces vendidos' }, - { connectionId: '2', partial: 'a veces vendidos' }, - { connectionId: '2', partial: 'a veces vendidos' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la academia' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la academia' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la academia' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena de' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena de' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en eventos' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en eventos' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena de veces y' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena de veces y' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena de veces y' }, - { - connectionId: '2', - partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena de veces y términos y' - }, - { - connectionId: '2', - partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena de veces y términos y' - }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de' }, - { connectionId: '2', partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de' }, - { - connectionId: '2', - partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil' - }, - { - connectionId: '2', - partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil' - }, - { - connectionId: '2', - partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil' - }, - { - connectionId: '2', - partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil' - }, - { - connectionId: '2', - partial: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatrocientos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatrocientos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatrocientos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro las' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro las' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que recibieron' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que recibieron' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que recibieron' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que recibieron matarnos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que recibieron matarnos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york sucede en' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york sucede en' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto unos como' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto unos como' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto unos como' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la actualidad y' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la actualidad y' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la actualidad y' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el mundo' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el mundo' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el mundo' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el mundo' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el mundo' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el mundo' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el mundo' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el mundo' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el mundo' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el mundo considerable' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el mundo considerable' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el mundo considerable' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el mundo considerable' - }, - { - connectionId: '2', - partial: - 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena en términos de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que residen en oaxaca nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el mundo considerable' - }, - { - connectionId: '2', - text: 'a veces vendidos de septiembre de mil novecientos noventa y cuatro por la cadena de veces y terminó en seis de mayo de dos mil cuatro la serie trata sobre la vida de un grupo de amigos que en baja tan nueva york suceden tanto buenos como malos momentos pero con una crítica cómica los hechos más trascendentales de la autoridad inmediatamente después del éxito de su país el programa comenzó su difusión por todo el mundo considerable resultados' - } - ]; - - captionsHeight = 0; - - constructor(private documentService: DocumentService, private panelService: PanelService, private cd: ChangeDetectorRef) {} + constructor( + private panelService: PanelService, + private openviduService: OpenViduService, + private participantService: ParticipantService, + private captionService: CaptionService, + private cd: ChangeDetectorRef + ) {} ngOnInit(): void { - this.subscribeToScreenSize(); + this.captionLangSelected = this.captionService.getLangSelected(); + this.session = this.openviduService.getWebcamSession(); + + this.subscribeToCaptionLanguage(); this.subscribeToPanelToggling(); this.subscribeToTranscription(); } @@ -1374,147 +79,106 @@ export class CaptionsComponent implements OnInit { ngOnDestroy() { if (this.screenSizeSub) this.screenSizeSub.unsubscribe(); if (this.panelTogglingSubscription) this.panelTogglingSubscription.unsubscribe(); - //TODO: Unsubscribe to openvidu-browser subtitle event - clearInterval(this.interval); + this.session.off('speechToTextMessage'); + this.captionEvents = []; } onSettingsCliked() { - this.panelService.togglePanel(PanelType.SETTINGS, PanelSettingsOptions.SUBTITLES); + this.panelService.togglePanel(PanelType.SETTINGS, PanelSettingsOptions.CAPTIONS); } private subscribeToTranscription() { - //TODO: Subscribe to openvidu-browser subtitle event - this.startFakeEventWithSample(); - this.fakeEvent.subscribe((event) => { - const text = !!event.text ? event.text : event.partial; - this.updateCaption(event.connectionId, text); + this.session.on('speechToTextMessage', (event: SpeechToTextEvent) => { + const { connectionId, data } = event.connection; + const nickname: string = this.participantService.getNicknameFromConnectionData(data); + const color = this.participantService.getRemoteParticipantByConnectionId(connectionId)?.colorProfile || ''; + + const caption: CaptionModel = { + connectionId, + nickname, + color, + text: event.text, + type: event.reason + }; + this.updateCaption(caption); this.cd.markForCheck(); - this.scrollToBottom(); }); } - private updateCaption(connectionId: string, text: string) { - //TODO: Remove when speech to text is integrated - const nicknames = new Map(); - nicknames.set('1', 'Pepe'); - nicknames.set('2', 'Mario'); - nicknames.set('3', 'Luis'); - nicknames.set('4', 'Juan'); - nicknames.set('5', 'INTERUPCION'); - // TODO End delete + private updateCaption(caption: CaptionModel): void { + let captionEventsCopy = [...this.captionEvents]; + let eventsNumber = captionEventsCopy.length; - let newCaptionElements = [...this.captionElements]; - const newItem = { connectionId, author: nicknames.get(connectionId), text }; + if (eventsNumber === this.MAX_EVENTS_LIMIT) { + captionEventsCopy.shift(); + eventsNumber--; + } - if (newCaptionElements?.length > 0) { - let lastItem = newCaptionElements[newCaptionElements.length - 1]; - if (lastItem.connectionId === connectionId) { - //Last author and new author are the same. Updating the caption - lastItem.text = text; - } else { - // const lastIntervention = newCaptionElements.find((item) => item.connectionId === connectionId); - // if (!!lastIntervention) { - // // The author is in the captionElements array - // // adding only the new words after its intervention. - // const splittedText = newItem.text.split(lastIntervention?.text)[1]; - // newItem.text = !!splittedText ? splittedText : newItem.text; - // } - newCaptionElements.push(newItem); - } + if (eventsNumber === 0) { + captionEventsCopy.push(caption); } else { - newCaptionElements.push(newItem); - } + const lastCaption: CaptionModel = captionEventsCopy.slice(-1)[0]; + const sameAuthorAsAbove: boolean = lastCaption.connectionId === caption.connectionId; + const allEventsAreSameSpeaker = captionEventsCopy.every((e) => e.connectionId === caption.connectionId); - this.adjustCaptionsToContainer(newCaptionElements); - } - private adjustCaptionsToContainer(newCaptionElements: { connectionId: string; author: string; text: string }[]) { - this.captionsHeight = 0; - // TODO: the height is being calculated for old data - // it should be calculated with the new caption elements - this.captionElementsRef?.forEach((item: ElementRef) => { - this.captionsHeight += item.nativeElement.offsetHeight; - }); - - - if (newCaptionElements?.length > 3) { - // Maximum elements exceeded. Delete first element. - newCaptionElements.shift(); - } else if (this.captionsHeight > 240) { - if (newCaptionElements?.length === 3) { - // Maximum height exceeded. Delete first element. - newCaptionElements.shift(); - } else if (newCaptionElements?.length === 2 || newCaptionElements?.length === 1) { - newCaptionElements[0].text = newCaptionElements[0].text.slice(100); - if (newCaptionElements[0].text.length < 100) { - newCaptionElements.shift(); + if (sameAuthorAsAbove) { + if (lastCaption.type === 'recognized') { + if (eventsNumber === 2 && allEventsAreSameSpeaker) { + captionEventsCopy.shift(); + clearInterval(this.deleteTimeout); + } + captionEventsCopy.push(caption); + this.deleteEventAfterDelay(this.DELETE_TIMEOUT); + } else { + lastCaption.text = caption.text; + lastCaption.type = caption.type; } + } else { + // TODO: Test when STT is able to work with multiple streams + if (eventsNumber === 2) { + captionEventsCopy.shift(); + clearInterval(this.deleteTimeout); + } + captionEventsCopy.push(caption); + this.deleteEventAfterDelay(this.DELETE_TIMEOUT); } } - this.captionElements = [...newCaptionElements]; + this.captionEvents = [...captionEventsCopy]; + this.scrollToBottom(); } - //TODO: Remove when speech to text is integrated - private startFakeEventWithSample() { - let index = 0; - let event = <{ connectionId: string; partial: string; text?: string }>this.sample[index]; - const fakeEventBS = >new BehaviorSubject(event); - this.fakeEvent = fakeEventBS.asObservable(); + private deleteEventAfterDelay(timeout: number) { + this.deleteTimeout = setTimeout(() => { + this.captionEvents.shift(); + this.cd.markForCheck(); + }, timeout); + } - const eventLoop = () => { - return setInterval(() => { - event = <{ connectionId: string; partial: string; text?: string }>this.sample[index]; - index++; - - fakeEventBS.next(event); - if (!this.sample[index]) { - clearInterval(this.interval); - index = 0; - } - }, 180); - }; - - this.interval = eventLoop(); - - //TODO: Simulating an speech event - //TODO: Remove when speech to text is integrated - // setInterval(() => { - // clearInterval(this.interval); - // const lorem = new LoremIpsum(); - // let times = 5; - // let partial = 'BLA BLA BLA '; - // const interval2 = setInterval(() => { - // fakeEventBS.next({ connectionId: '5', partial }); - // partial += lorem.generateWords(2); - // if (times <= 0) { - // fakeEventBS.next({ connectionId: '5', partial, text: partial }); - // clearInterval(interval2); - // this.interval = eventLoop(); - // } - // times--; - // }, 400); - // }, 6000); + private subscribeToCaptionLanguage() { + this.captionLanguageSubscription = this.captionService.captionLangObs.subscribe((lang) => { + this.captionLangSelected = lang; + this.cd.markForCheck(); + }); } private subscribeToPanelToggling() { this.panelTogglingSubscription = this.panelService.panelOpenedObs.subscribe((ev: PanelEvent) => { this.settingsPanelOpened = ev.opened; - this.cd.markForCheck(); - }); - } - - private subscribeToScreenSize() { - this.screenSizeSub = this.documentService.screenSizeObs.subscribe((change: MediaChange[]) => { - this.screenSize = change[0].mqAlias; - console.log(this.screenSize); - this.cd.markForCheck(); + setTimeout(() => this.cd.markForCheck(), 300); }); } private scrollToBottom(): void { - // setTimeout(() => { - try { - this.textContainer.nativeElement.scrollTop = this.textContainer.nativeElement.scrollHeight; - } catch (err) {} - // }, 20); + setTimeout(() => { + try { + this.scrollContainer.forEach((el: ElementRef) => { + el.nativeElement.scroll({ + top: this.scrollContainer.first.nativeElement.scrollHeight, + left: 0 + // behavior: 'smooth' + }); + }); + } catch (err) {} + }, 20); } } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/layout/layout.component.css b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/layout/layout.component.css index f72894454..2b7f25b16 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/layout/layout.component.css +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/layout/layout.component.css @@ -5,8 +5,8 @@ .container { height: 100%; } -.withSubtitles { - height: calc(100% - var(--ov-captions-height, 200px)) !important; +.withCaptions { + height: calc(100% - var(--ov-captions-height, 250px)) !important; } .layout { diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/layout/layout.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/layout/layout.component.html index d666ebac3..0ba437768 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/layout/layout.component.html +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/layout/layout.component.html @@ -1,4 +1,4 @@ -
+
@@ -14,5 +14,5 @@
- +
diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/layout/layout.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/layout/layout.component.ts index d93b71aed..a6c957249 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/layout/layout.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/layout/layout.component.ts @@ -11,10 +11,10 @@ import { ViewContainerRef } from '@angular/core'; import { Subscription } from 'rxjs'; -import { ParticipantService } from '../../services/participant/participant.service'; +import { StreamDirective } from '../../directives/template/openvidu-angular.directive'; import { ParticipantAbstractModel } from '../../models/participant.model'; import { LayoutService } from '../../services/layout/layout.service'; -import { StreamDirective } from '../../directives/template/openvidu-angular.directive'; +import { ParticipantService } from '../../services/participant/participant.service'; /** * @@ -82,11 +82,11 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit { /** * @ignore */ - subtitlesEnabled = true; + captionsEnabled = true; private localParticipantSubs: Subscription; private remoteParticipantsSubs: Subscription; - private subtitlesSubs: Subscription; + private captionsSubs: Subscription; /** * @ignore @@ -95,7 +95,7 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit { ngOnInit(): void { this.subscribeToParticipants(); - this.subscribeToSubtitles(); + this.subscribeToCaptions(); } ngAfterViewInit() { @@ -107,13 +107,13 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit { this.remoteParticipants = []; if (this.localParticipantSubs) this.localParticipantSubs.unsubscribe(); if (this.remoteParticipantsSubs) this.remoteParticipantsSubs.unsubscribe(); - if (this.subtitlesSubs) this.subtitlesSubs.unsubscribe(); + if (this.captionsSubs) this.captionsSubs.unsubscribe(); this.layoutService.clear(); } - private subscribeToSubtitles() { - this.subtitlesSubs = this.layoutService.subtitlesTogglingObs.subscribe((value: boolean) => { - this.subtitlesEnabled = value; + private subscribeToCaptions() { + this.captionsSubs = this.layoutService.captionsTogglingObs.subscribe((value: boolean) => { + this.captionsEnabled = value; this.cd.markForCheck(); this.layoutService.update(); }); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.html index 591f48043..93bf0b7ae 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.html +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.html @@ -22,14 +22,14 @@
{{ 'PANEL.SETTINGS.AUDIO' | translate }}
closed_caption -
{{ 'PANEL.SETTINGS.SUBTITLE' | translate }}
+
{{ 'PANEL.SETTINGS.CAPTIONS' | translate }}
@@ -47,7 +47,7 @@
- + diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.ts index ea666aaed..24536ef0c 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.ts @@ -15,8 +15,8 @@ import { PanelEvent, PanelService } from '../../../services/panel/panel.service' export class SettingsPanelComponent implements OnInit { settingsOptions: typeof PanelSettingsOptions = PanelSettingsOptions; selectedOption: PanelSettingsOptions = PanelSettingsOptions.GENERAL; - showSubtitles: boolean = true; - private subtitlesSubs: Subscription; + showCaptions: boolean = true; + private captionsSubs: Subscription; panelSubscription: Subscription; constructor(private panelService: PanelService, private libService: OpenViduAngularConfigService) {} ngOnInit() { @@ -25,7 +25,7 @@ export class SettingsPanelComponent implements OnInit { } ngOnDestroy() { - if (this.subtitlesSubs) this.subtitlesSubs.unsubscribe(); + if (this.captionsSubs) this.captionsSubs.unsubscribe(); } close() { @@ -36,8 +36,8 @@ export class SettingsPanelComponent implements OnInit { } private subscribeToDirectives() { - this.subtitlesSubs = this.libService.subtitlesButtonObs.subscribe((value: boolean) => { - this.showSubtitles = value; + this.captionsSubs = this.libService.captionsButtonObs.subscribe((value: boolean) => { + this.showCaptions = value; }); } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.ts index f2d85b7ac..832241377 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.ts @@ -1,5 +1,7 @@ import { - ChangeDetectionStrategy, ChangeDetectorRef, Component, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, ContentChild, ElementRef, EventEmitter, @@ -12,8 +14,12 @@ import { } from '@angular/core'; import { ConnectionEvent, - RecordingEvent, Session, SessionDisconnectedEvent, StreamEvent, - StreamPropertyChangedEvent, Subscriber + RecordingEvent, + Session, + SessionDisconnectedEvent, + StreamEvent, + StreamPropertyChangedEvent, + Subscriber } from 'openvidu-browser'; import { ILogger } from '../../models/logger.model'; @@ -26,6 +32,7 @@ import { SidenavMode } from '../../models/layout.model'; import { PanelType } from '../../models/panel.model'; import { Signal } from '../../models/signal.model'; import { ActionService } from '../../services/action/action.service'; +import { CaptionService } from '../../services/caption/caption.service'; import { ChatService } from '../../services/chat/chat.service'; import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service'; import { LayoutService } from '../../services/layout/layout.service'; @@ -46,11 +53,7 @@ import { TranslateService } from '../../services/translate/translate.service'; selector: 'ov-session', templateUrl: './session.component.html', styleUrls: ['./session.component.css'], - animations: [ - trigger('sessionAnimation', [ - transition(':enter', [style({ opacity: 0 }), animate('400ms', style({ opacity: 1 }))]), - ]) - ], + animations: [trigger('sessionAnimation', [transition(':enter', [style({ opacity: 0 }), animate('400ms', style({ opacity: 1 }))])])], changeDetection: ChangeDetectionStrategy.OnPush }) export class SessionComponent implements OnInit { @@ -77,6 +80,7 @@ export class SessionComponent implements OnInit { protected layoutWidthSubscription: Subscription; protected updateLayoutInterval: NodeJS.Timer; + private captionLanguageSubscription: Subscription; protected log: ILogger; @@ -92,6 +96,7 @@ export class SessionComponent implements OnInit { protected panelService: PanelService, private recordingService: RecordingService, private translateService: TranslateService, + private captionService: CaptionService, private platformService: PlatformService, private cd: ChangeDetectorRef ) { @@ -153,6 +158,7 @@ export class SessionComponent implements OnInit { } this.session = this.openviduService.getWebcamSession(); this.sessionScreen = this.openviduService.getScreenSession(); + this.subscribeToCaptionLanguage(); this.subscribeToConnectionCreatedAndDestroyed(); this.subscribeToStreamCreated(); this.subscribeToStreamDestroyed(); @@ -284,7 +290,7 @@ export class SessionComponent implements OnInit { } private subscribeToStreamCreated() { - this.session.on('streamCreated', (event: StreamEvent) => { + this.session.on('streamCreated', async (event: StreamEvent) => { const connectionId = event.stream?.connection?.connectionId; const data = event.stream?.connection?.data; @@ -293,14 +299,39 @@ export class SessionComponent implements OnInit { const subscriber: Subscriber = this.session.subscribe(event.stream, undefined); this.participantService.addRemoteConnection(connectionId, data, subscriber); // this.oVSessionService.sendNicknameSignal(event.stream.connection); + try { + await this.session.subscribeToSpeechToText(event.stream, this.captionService.getLangSelected().ISO); + } catch (error) { + this.log.e('Error subscribing from STT: ', error); + } } }); } private subscribeToStreamDestroyed() { - this.session.on('streamDestroyed', (event: StreamEvent) => { + this.session.on('streamDestroyed', async (event: StreamEvent) => { const connectionId = event.stream.connection.connectionId; this.participantService.removeConnectionByConnectionId(connectionId); + try { + await this.session.unsubscribeFromSpeechToText(event.stream); + } catch (error) { + this.log.e('Error unsubscribing from STT: ', error); + } + }); + } + + private subscribeToCaptionLanguage() { + this.captionLanguageSubscription = this.captionService.captionLangObs.subscribe(async (lang) => { + // Unsubscribe all streams from speech to text and re-subscribe with new language + this.log.d('Re-subscribe from STT because of language changed to ', lang.ISO); + for (const participant of this.participantService.getRemoteParticipants()) { + try { + await this.session.unsubscribeFromSpeechToText(participant.getCameraConnection().streamManager.stream); + await this.session.subscribeToSpeechToText(participant.getCameraConnection().streamManager.stream, lang.ISO); + } catch (error) { + this.log.e('Error re-subscribing to STT: ', error); + } + } }); } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/subtitles/subtitles.component.css b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/captions/captions.component.css similarity index 100% rename from openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/subtitles/subtitles.component.css rename to openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/captions/captions.component.css diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/subtitles/subtitles.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/captions/captions.component.html similarity index 60% rename from openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/subtitles/subtitles.component.html rename to openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/captions/captions.component.html index e246b6abd..b2af9884c 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/subtitles/subtitles.component.html +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/captions/captions.component.html @@ -1,21 +1,18 @@ -
{{ 'PANEL.SETTINGS.SUBTITLE' | translate }}
- +
{{ 'PANEL.SETTINGS.CAPTIONS' | translate }}
+
{{ 'PANEL.SETTINGS.LANGUAGE' | translate }}:
-
- - - diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/captions/captions.component.spec.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/captions/captions.component.spec.ts new file mode 100644 index 000000000..827a80133 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/captions/captions.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CaptionsSettingComponent } from './captions.component'; + +describe('CaptionsSettingComponent', () => { + let component: CaptionsSettingComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [CaptionsSettingComponent] + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(CaptionsSettingComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/captions/captions.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/captions/captions.component.ts new file mode 100644 index 000000000..0f77c2fcf --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/captions/captions.component.ts @@ -0,0 +1,47 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subscription } from 'rxjs'; +import { CaptionService } from '../../../services/caption/caption.service'; +import { LayoutService } from '../../../services/layout/layout.service'; + +/** + * @internal + */ +@Component({ + selector: 'ov-captions-settings', + templateUrl: './captions.component.html', + styleUrls: ['./captions.component.css'] +}) +export class CaptionsSettingComponent implements OnInit, OnDestroy { + captionsEnabled: boolean; + languagesAvailable: { name: string; ISO: string }[] = []; + captionsSubscription: Subscription; + langSelected: string; + + constructor(private layoutService: LayoutService, private captionService: CaptionService) {} + + ngOnInit(): void { + this.subscribeToCaptions(); + this.langSelected = this.captionService.getLangSelected().name; + this.languagesAvailable = this.captionService.getCaptionLanguages(); + } + + ngOnDestroy() { + if (this.captionsSubscription) this.captionsSubscription.unsubscribe(); + } + + onLangSelected(lang: { name: string; ISO: string }) { + this.langSelected = lang.name; + this.captionService.setLanguage(lang.ISO); + } + + toggleCaptions() { + this.layoutService.toggleCaptions(); + } + + private subscribeToCaptions() { + this.captionsSubscription = this.layoutService.captionsTogglingObs.subscribe((value: boolean) => { + this.captionsEnabled = value; + // this.cd.markForCheck(); + }); + } +} diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/subtitles/subtitles.component.spec.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/subtitles/subtitles.component.spec.ts deleted file mode 100644 index 4c6d1353d..000000000 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/subtitles/subtitles.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { SubtitlesComponent } from './subtitles.component'; - -describe('SubtitlesComponent', () => { - let component: SubtitlesComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ SubtitlesComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(SubtitlesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/subtitles/subtitles.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/subtitles/subtitles.component.ts deleted file mode 100644 index 715b2800f..000000000 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/subtitles/subtitles.component.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { Subscription } from 'rxjs'; -import { LayoutService } from '../../../services/layout/layout.service'; - - -/** - * @internal - */ -@Component({ - selector: 'ov-subtitles-settings', - templateUrl: './subtitles.component.html', - styleUrls: ['./subtitles.component.css'] -}) -export class SubtitlesSettingComponent implements OnInit, OnDestroy { - subtitlesEnabled: boolean; - languagesAvailable = []; - subtitlesSubs: Subscription; - langSelected: string = 'English'; - - constructor(private layoutService: LayoutService) {} - - ngOnInit(): void { - this.subscribeToSubtitles(); - } - - ngOnDestroy() { - if (this.subtitlesSubs) this.subtitlesSubs.unsubscribe(); - } - - onLangSelected(lang: string) { - this.langSelected = lang; - } - - toggleSubtitles() { - this.layoutService.toggleSubtitles(); - } - - private subscribeToSubtitles() { - this.subtitlesSubs = this.layoutService.subtitlesTogglingObs.subscribe((value: boolean) => { - this.subtitlesEnabled = value; - // this.cd.markForCheck(); - }); - } -} diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.html index 98737a6bd..0c7e5f1ab 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.html +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.html @@ -103,17 +103,17 @@ {{ 'TOOLBAR.BACKGROUND' | translate }} - + diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.ts index c37cddf6f..66f702a68 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.ts @@ -308,12 +308,12 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { /** * @ignore */ - showSubtitlesButton: boolean = true; + showCaptionsButton: boolean = true; /** * @ignore */ - subtitlesEnabled: boolean; + captionsEnabled: boolean; /** * @ignore @@ -362,7 +362,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { private displaySessionNameSub: Subscription; private screenSizeSub: Subscription; private settingsButtonSub: Subscription; - private subtitlesSubs: Subscription; + private captionsSubs: Subscription; private currentWindowHeight = window.innerHeight; /** @@ -425,7 +425,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { this.subscribeToChatMessages(); this.subscribeToRecordingStatus(); this.subscribeToScreenSize(); - this.subscribeToSubtitlesToggling(); + this.subscribeToCaptionsToggling(); } ngAfterViewInit() { @@ -453,7 +453,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { if (this.recordingSubscription) this.recordingSubscription.unsubscribe(); if (this.screenSizeSub) this.screenSizeSub.unsubscribe(); if (this.settingsButtonSub) this.settingsButtonSub.unsubscribe(); - if (this.subtitlesSubs) this.subtitlesSubs.unsubscribe(); + if (this.captionsSubs) this.captionsSubs.unsubscribe(); } /** @@ -547,8 +547,8 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { /** * @ignore */ - toggleSubtitles() { - this.layoutService.toggleSubtitles(); + toggleCaptions() { + this.layoutService.toggleCaptions(); } /** @@ -697,8 +697,8 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { this.showSessionName = value; this.cd.markForCheck(); }); - this.subtitlesSubs = this.libService.subtitlesButtonObs.subscribe((value: boolean) => { - this.showSubtitlesButton = value; + this.captionsSubs = this.libService.captionsButtonObs.subscribe((value: boolean) => { + this.showCaptionsButton = value; this.cd.markForCheck(); }); } @@ -710,9 +710,9 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { }); } - private subscribeToSubtitlesToggling() { - this.subtitlesSubs = this.layoutService.subtitlesTogglingObs.subscribe((value: boolean) => { - this.subtitlesEnabled = value; + private subscribeToCaptionsToggling() { + this.captionsSubs = this.layoutService.captionsTogglingObs.subscribe((value: boolean) => { + this.captionsEnabled = value; this.cd.markForCheck(); }); } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.css b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.css index bb53cbdc6..92035d1ea 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.css +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.css @@ -27,5 +27,5 @@ /* Private css variables */ #call-container { - --ov-captions-height: 250px; + --ov-captions-height: 230px; } \ No newline at end of file diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.ts index 81c502280..c0e61891f 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.ts @@ -56,12 +56,14 @@ import { TranslateService } from '../../services/translate/translate.service'; * | :----------------------------: | :-------: | :---------------------------------------------: | * | **minimal** | `boolean` | {@link MinimalDirective} | * | **lang** | `string` | {@link LangDirective} | + * | **captionsLang** | `string` | {@link CaptionsLangDirective} | * | **prejoin** | `boolean` | {@link PrejoinDirective} | * | **participantName** | `string` | {@link ParticipantNameDirective} | * | **videoMuted** | `boolean` | {@link VideoMutedDirective} | * | **audioMuted** | `boolean` | {@link AudioMutedDirective} | * | **toolbarScreenshareButton** | `boolean` | {@link ToolbarScreenshareButtonDirective} | * | **toolbarFullscreenButton** | `boolean` | {@link ToolbarFullscreenButtonDirective} | + * | **toolbarCaptionsButton** | `boolean` | {@link ToolbarCaptionsButtonDirective} | * | **toolbarBackgroundEffectsButton** | `boolean` | {@link ToolbarBackgroundEffectsButtonDirective} | * | **toolbarLeaveButton** | `boolean` | {@link ToolbarLeaveButtonDirective} | * | **toolbarChatPanelButton** | `boolean` | {@link ToolbarChatPanelButtonDirective} | @@ -457,8 +459,8 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni const publisher = await this.openviduService.initDefaultPublisher(); if (publisher) { - publisher.once('accessDenied', (e: any) => { - this.handlePublisherError(e); + publisher.once('accessDenied', async (e: any) => { + await this.handlePublisherError(e); resolve(); }); publisher.once('accessAllowed', async () => { @@ -662,20 +664,20 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni this.onSessionCreated.emit(session); } - private handlePublisherError(e: any): Promise { + private async handlePublisherError(e: any): Promise { let message: string = ''; console.log('ERROR!', e); if (e.name === OpenViduErrorName.DEVICE_ALREADY_IN_USE) { this.log.w('Video device already in use. Disabling video device...'); // Allow access to the room with only mic if camera device is already in use this.deviceSrv.disableVideoDevices(); - return this.initwebcamPublisher(); + return await this.initwebcamPublisher(); } if (e.name === OpenViduErrorName.DEVICE_ACCESS_DENIED) { message = this.translateService.translate('ERRORS.MEDIA_ACCESS'); this.deviceSrv.disableVideoDevices(); this.deviceSrv.disableAudioDevices(); - return this.initwebcamPublisher(); + return await this.initwebcamPublisher(); } else if (e.name === OpenViduErrorName.NO_INPUT_SOURCE_SET) { message = this.translateService.translate('ERRORS.DEVICE_NOT_FOUND'); } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/api.directive.module.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/api.directive.module.ts index 1e0e3dafc..55d7370f6 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/api.directive.module.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/api.directive.module.ts @@ -5,37 +5,39 @@ import { LogoDirective } from './internals.directive'; import { ParticipantPanelItemMuteButtonDirective } from './participant-panel-item.directive'; import { RecordingActivityRecordingErrorDirective, RecordingActivityRecordingsListDirective } from './recording-activity.directive'; import { - StreamDisplayParticipantNameDirective, StreamDisplayAudioDetectionDirective, + StreamDisplayParticipantNameDirective, StreamSettingsButtonDirective } from './stream.directive'; import { - ToolbarScreenshareButtonDirective, + ToolbarActivitiesPanelButtonDirective, + ToolbarBackgroundEffectsButtonDirective, + ToolbarCaptionsButtonDirective, + ToolbarChatPanelButtonDirective, + ToolbarDisplayLogoDirective, + ToolbarDisplaySessionNameDirective, ToolbarFullscreenButtonDirective, ToolbarLeaveButtonDirective, ToolbarParticipantsPanelButtonDirective, - ToolbarChatPanelButtonDirective, - ToolbarDisplaySessionNameDirective, - ToolbarDisplayLogoDirective, - ToolbarActivitiesPanelButtonDirective, - ToolbarBackgroundEffectsButtonDirective, ToolbarRecordingButtonDirective, - ToolbarSettingsButtonDirective, - ToolbarCaptionsButtonDirective + ToolbarScreenshareButtonDirective, + ToolbarSettingsButtonDirective } from './toolbar.directive'; import { AudioMutedDirective, + CaptionsLangDirective, + LangDirective, MinimalDirective, - PrejoinDirective, - VideoMutedDirective, ParticipantNameDirective, - LangDirective + PrejoinDirective, + VideoMutedDirective } from './videoconference.directive'; @NgModule({ declarations: [ MinimalDirective, LangDirective, + CaptionsLangDirective, PrejoinDirective, VideoMutedDirective, AudioMutedDirective, @@ -66,6 +68,7 @@ import { exports: [ MinimalDirective, LangDirective, + CaptionsLangDirective, PrejoinDirective, VideoMutedDirective, AudioMutedDirective, diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/internals.directive.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/internals.directive.ts index 18156714e..b5253103e 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/internals.directive.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/internals.directive.ts @@ -6,7 +6,7 @@ import { Directive, ElementRef, HostListener, Input } from '@angular/core'; * Load default OpenVidu logo if custom one is not exist * @internal */ - @Directive({ +@Directive({ selector: 'img[ovLogo]' }) export class LogoDirective { diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/toolbar.directive.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/toolbar.directive.ts index de5ce0f88..98abaaa75 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/toolbar.directive.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/toolbar.directive.ts @@ -1,4 +1,4 @@ -import { AfterViewInit, Directive, ElementRef, HostListener, Input, OnDestroy } from '@angular/core'; +import { AfterViewInit, Directive, ElementRef, Input, OnDestroy } from '@angular/core'; import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service'; /** @@ -256,9 +256,6 @@ export class ToolbarBackgroundEffectsButtonDirective implements AfterViewInit, O * And it also can be used in the {@link ToolbarComponent}. * @example * - * - * TODO: Make it public when speech to text is integrated - * @internal */ @Directive({ selector: 'ov-videoconference[toolbarCaptionsButton], ov-toolbar[captionsButton]' @@ -298,8 +295,8 @@ export class ToolbarCaptionsButtonDirective implements AfterViewInit, OnDestroy } private update(value: boolean) { - if (this.libService.subtitlesButton.getValue() !== value) { - this.libService.subtitlesButton.next(value); + if (this.libService.captionsButton.getValue() !== value) { + this.libService.captionsButton.next(value); } } } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/videoconference.directive.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/videoconference.directive.ts index a905bea08..55036d09c 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/videoconference.directive.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/videoconference.directive.ts @@ -1,7 +1,9 @@ -import { Directive, Input, ElementRef, OnDestroy, OnInit } from '@angular/core'; +import { Directive, ElementRef, Input, OnDestroy, OnInit } from '@angular/core'; +import { CaptionService } from '../../services/caption/caption.service'; import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service'; import { TranslateService } from '../../services/translate/translate.service'; + /** * The **minimal** directive applies a minimal UI hiding all controls except for cam and mic. * @@ -53,7 +55,7 @@ export class MinimalDirective implements OnDestroy { } /** - * The **lang** directive allows et the UI language to a default language. + * The **lang** directive allows set the UI language to a default language. * * It is only available for {@link VideoconferenceComponent}. * @@ -113,6 +115,70 @@ export class LangDirective implements OnDestroy { } } +/** + * The **captions-lang** directive allows specify the language of room's members + * + * It is only available for {@link VideoconferenceComponent}. + * + * It must be a valid [BCP-47](https://tools.ietf.org/html/bcp47) language tag like "en-US" or "es-ES". + * + * + * **Default:** English `en-US` + * + * **Available:** + * + * * English: `en-US` + * * Spanish: `es-ES` + * * German: `de-DE` + * * French: `fr-FR` + * * Chinese: `zh-CN` + * * Hindi: `hi-IN` + * * Italian: `it-IT` + * * Japanese: `jp-JP` + * * Portuguese: `pt-PT` + * + * @example + * + */ + @Directive({ + selector: 'ov-videoconference[captionsLang]' +}) +export class CaptionsLangDirective implements OnDestroy { + /** + * @ignore + */ + @Input() set captionsLang(value: string) { + this.update(value); + } + + /** + * @ignore + */ + constructor(public elementRef: ElementRef, private captionService: CaptionService) {} + + /** + * @ignore + */ + ngOnDestroy(): void { + this.clear(); + } + + /** + * @ignore + */ + clear() { + this.update('en-US'); + } + + /** + * @ignore + */ + update(value: string) { + this.captionService.setLanguage(value); + } +} + + /** * The **participantName** directive sets the participant name. It can be useful for aplications which doesn't need the prejoin page. * diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/cn.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/cn.json index 5c2f6bf41..af3c82c36 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/cn.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/cn.json @@ -34,8 +34,8 @@ "MORE_OPTIONS":"更多选项", "FULLSCREEN":"全屏", "EXIT_FULLSCREEN": "退出全屏", - "ENABLE_SUBTITLES": "启用字幕", - "DISABLE_SUBTITLES": "禁用字幕", + "ENABLE_CAPTIONS": "启用字幕", + "DISABLE_CAPTIONS": "禁用字幕", "BACKGROUND":"背景效果", "START_RECORDING": "开始录音", "STOP_RECORDING": "停止录制", @@ -73,7 +73,7 @@ "VIDEO": "视频", "AUDIO": "声音的", "LANGUAGE": "语", - "SUBTITLE": "字幕" + "CAPTIONS": "字幕" }, "BACKGROUND": { "TITLE": "背景效果", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/de.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/de.json index a23474678..cf03eb57a 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/de.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/de.json @@ -34,8 +34,8 @@ "MORE_OPTIONS": "Weitere Optionen", "FULLSCREEN": "Vollbild", "EXIT_FULLSCREEN": "Vollbildmodus beenden", - "ENABLE_SUBTITLES": "Untertitel aktivieren", - "DISABLE_SUBTITLES": "Untertitel deaktivieren", + "ENABLE_CAPTIONS": "Untertitel aktivieren", + "DISABLE_CAPTIONS": "Untertitel deaktivieren", "BACKGROUND": "Hintergrund-Effekte", "START_RECORDING": "Aufzeichnung starten", "STOP_RECORDING": "Aufzeichnung stoppen", @@ -73,7 +73,7 @@ "VIDEO": "Video", "AUDIO": "Audio", "LANGUAGE": "Sprache", - "SUBTITLE": "Untertitel" + "CAPTIONS": "Untertitel" }, "BACKGROUND": { "TITLE": "Hintergrund-Effekte", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/en.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/en.json index 37b9bf19a..ecf0df816 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/en.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/en.json @@ -35,8 +35,8 @@ "MORE_OPTIONS": "More options", "FULLSCREEN": "Fullscreen", "EXIT_FULLSCREEN": "Exit fullscreen", - "ENABLE_SUBTITLES": "Enable subtitles", - "DISABLE_SUBTITLES": "Disable subtitles", + "ENABLE_CAPTIONS": "Enable captions", + "DISABLE_CAPTIONS": "Disable captions", "BACKGROUND": "Background effects", "START_RECORDING": "Start recording", "STOP_RECORDING": "Stop recording", @@ -74,7 +74,7 @@ "VIDEO": "Video", "AUDIO": "Audio", "LANGUAGE": "Language", - "SUBTITLE": "Subtitles" + "CAPTIONS": "Captions" }, "BACKGROUND": { "TITLE": "Background effects", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/es.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/es.json index 890835878..2b6d9123c 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/es.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/es.json @@ -34,8 +34,8 @@ "MORE_OPTIONS": "Más opciones", "EXIT_FULLSCREEN": "Quitar pantalla completa", "FULLSCREEN": "Pantalla completa", - "ENABLE_SUBTITLES": "Activar subtítulos", - "DISABLE_SUBTITLES": "Desactivar subtítulos", + "ENABLE_CAPTIONS": "Activar subtítulos", + "DISABLE_CAPTIONS": "Desactivar subtítulos", "BACKGROUND": "Efectos de fondo", "START_RECORDING": "Iniciar grabación", "STOP_RECORDING": "Detener grabación", @@ -73,7 +73,7 @@ "VIDEO": "Video", "AUDIO": "Audio", "LANGUAGE": "Idioma", - "SUBTITLE": "Subtítulos" + "CAPTIONS": "Subtítulos" }, "BACKGROUND": { "TITLE": "Efectos de fondo", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/fr.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/fr.json index 13e17cd14..b2f88fb93 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/fr.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/fr.json @@ -34,8 +34,8 @@ "MORE_OPTIONS": "Plus d'options", "FULLSCREEN": "Plein écran", "EXIT_FULLSCREEN": "Quitter le plein écran", - "ENABLE_SUBTITLES": "Activer les sous-titres", - "DISABLE_SUBTITLES": "Désactiver les sous-titres", + "ENABLE_CAPTIONS": "Activer les sous-titres", + "DISABLE_CAPTIONS": "Désactiver les sous-titres", "BACKGROUND": "Effets de fond", "START_RECORDING": "démarrer l'enregistrement", "STOP_RECORDING": "Arrêter l'enregistrement", @@ -73,7 +73,7 @@ "VIDEO": "Vidéo", "AUDIO": "l'audio", "LANGUAGE": "Langue", - "SUBTITLE": "Les sous-titres" + "CAPTIONS": "Les sous-titres" }, "BACKGROUND": { "TITLE": "Effets de fond", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/hi.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/hi.json index 9b9ad590f..a59d0d7d1 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/hi.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/hi.json @@ -34,8 +34,8 @@ "MORE_OPTIONS": "अधिक विकल्प", "FULLSCREEN": "पूर्ण स्क्रीन", "EXIT_FULLSCREEN": "पूर्ण स्क्रीन से बाहर निकलें", - "ENABLE_SUBTITLES": "उपशीर्षक सक्षम करें", - "DISABLE_SUBTITLES": "उपशीर्षक अक्षम करें", + "ENABLE_CAPTIONS": "उपशीर्षक सक्षम करें", + "DISABLE_CAPTIONS": "उपशीर्षक अक्षम करें", "BACKGROUND": "पृष्ठभूमि प्रभाव", "START_RECORDING": "रिकॉर्डिंग प्रारंभ करें", "STOP_RECORDING": "रिकॉर्डिंग रोकें", @@ -73,7 +73,7 @@ "VIDEO": "वीडियो", "AUDIO": "ऑडियो", "LANGUAGE": "भाषा", - "SUBTITLE": "उपशीर्षक" + "CAPTIONS": "उपशीर्षक" }, "BACKGROUND": { "TITLE": "पृष्ठभूमि प्रभाव", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/it.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/it.json index a12c423b9..bbc757135 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/it.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/it.json @@ -34,8 +34,8 @@ "MORE_OPTIONS": "Altre opzioni", "FULLSCREEN": "Schermo intero", "EXIT_FULLSCREEN": "Esci dallo schermo intero", - "ENABLE_SUBTITLES": "Abilita i sottotitoli", - "DISABLE_SUBTITLES": "Disabilita i sottotitoli", + "ENABLE_CAPTIONS": "Abilita i sottotitoli", + "DISABLE_CAPTIONS": "Disabilita i sottotitoli", "BACKGROUND": "Effetti di sfondo", "START_RECORDING": "Avvia registrazione", "STOP_RECORDING": "Interrompi registrazione", @@ -73,7 +73,7 @@ "VIDEO": "video", "AUDIO": "Audio", "LANGUAGE":"Lingua", - "SUBTITLE": "Sottotitoli" + "CAPTIONS": "Sottotitoli" }, "BACKGROUND": { "TITLE": "Effetti di sfondo", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/ja.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/ja.json index 1dbe11c39..64fa201f0 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/ja.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/ja.json @@ -34,8 +34,8 @@ "MORE_OPTIONS": "その他のオプション", "FULLSCREEN": "フルスクリーン", "EXIT_FULLSCREEN": "フルスクリーンを終了する", - "ENABLE_SUBTITLES": "字幕を有効にする", - "DISABLE_SUBTITLES": "字幕を無効にする", + "ENABLE_CAPTIONS": "字幕を有効にする", + "DISABLE_CAPTIONS": "字幕を無効にする", "BACKGROUND": "背景効果", "START_RECORDING": "録画開始", "STOP_RECORDING": "録画の停止", @@ -73,7 +73,7 @@ "VIDEO": "ビデオ", "AUDIO": "オーディオ", "LANGUAGE":"言語", - "SUBTITLE": "字幕" + "CAPTIONS": "字幕" }, "BACKGROUND": { "TITLE": "背景効果", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/nl.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/nl.json index 18ad397e8..1008ea89f 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/nl.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/nl.json @@ -34,8 +34,8 @@ "MORE_OPTIONS": "Meer opties", "FULLSCREEN": "Volledig scherm", "EXIT_FULLSCREEN": "Volledig scherm verlaten", - "ENABLE_SUBTITLES": "Ondertiteling inschakelen", - "DISABLE_SUBTITLES": "Ondertiteling uitschakelen", + "ENABLE_CAPTIONS": "Ondertiteling inschakelen", + "DISABLE_CAPTIONS": "Ondertiteling uitschakelen", "BACKGROUND": "Achtergrondeffecten", "START_RECORDING": "Start opname", "STOP_RECORDING": "Stop opname", @@ -73,7 +73,7 @@ "VIDEO": "Video", "AUDIO": "Audio", "LANGUAGE":"Taal", - "SUBTITLE": "Ondertitels" + "CAPTIONS": "Ondertitels" }, "BACKGROUND": { "TITLE": "Achtergrondeffecten", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/pt.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/pt.json index eac46ac1f..ba8c69e06 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/pt.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/pt.json @@ -34,8 +34,8 @@ "MORE_OPTIONS": "Mais opções", "FULLSCREEN": "Tela cheia", "EXIT_FULLSCREEN": "Sair da tela cheia", - "ENABLE_SUBTITLES": "Ativar legendas", - "DISABLE_SUBTITLES": "Desativar legendas", + "ENABLE_CAPTIONS": "Ativar legendas", + "DISABLE_CAPTIONS": "Desativar legendas", "BACKGROUND": "Efeitos de fundo", "START_RECORDING": "Iniciar_gravação", "STOP_RECORDING": "Parar de gravar", @@ -73,7 +73,7 @@ "VIDEO": "Vídeo", "AUDIO": "Áudio", "LANGUAGE":"Linguagem", - "SUBTITLE": "Legendas" + "CAPTIONS": "Legendas" }, "BACKGROUND": { "TITLE": "Efeitos de fundo", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/models/caption.model.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/models/caption.model.ts new file mode 100644 index 000000000..64d9a7234 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/models/caption.model.ts @@ -0,0 +1,10 @@ + +export interface CaptionModel { + + connectionId: string; + nickname: string; + color: string; + type: 'recognizing' | 'recognized'; + text: string; +} + diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/models/panel.model.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/models/panel.model.ts index 2382ce05c..9082c65cf 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/models/panel.model.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/models/panel.model.ts @@ -11,5 +11,5 @@ export enum PanelSettingsOptions { GENERAL = 'general', AUDIO = 'audio', VIDEO = 'video', - SUBTITLES = 'subtitles' + CAPTIONS = 'captions' } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/models/storage.model.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/models/storage.model.ts index 706439a45..199e7556c 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/models/storage.model.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/models/storage.model.ts @@ -7,5 +7,6 @@ export enum Storage { AUDIO_DEVICE = 'openviduCallAudioDevice', AUDIO_MUTED = 'openviduCallAudioMuted', VIDEO_MUTED = 'openviduCallVideoMuted', - LANG = "openviduCallLang" -} \ No newline at end of file + LANG = 'openviduCallLang', + CAPTION_LANG = 'openviduCallCaptionLang' +} diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/openvidu-angular.module.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/openvidu-angular.module.ts index 6e81bbed9..ad4431c6d 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/openvidu-angular.module.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/openvidu-angular.module.ts @@ -1,66 +1,66 @@ +import { OverlayContainer } from '@angular/cdk/overlay'; +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; +import { ModuleWithProviders, NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; -import { CommonModule } from '@angular/common'; -import { ModuleWithProviders, NgModule } from '@angular/core'; -import { HttpClientModule } from '@angular/common/http'; -import { OverlayContainer } from '@angular/cdk/overlay'; -import { ToolbarComponent } from './components/toolbar/toolbar.component'; -import { VideoComponent } from './components/video/video.component'; -import { ChatPanelComponent } from './components/panel/chat-panel/chat-panel.component'; -import { SessionComponent } from './components/session/session.component'; -import { LayoutComponent } from './components/layout/layout.component'; -import { StreamComponent } from './components/stream/stream.component'; +import { DeleteDialogComponent } from './components/dialogs/delete-recording.component'; import { DialogTemplateComponent } from './components/dialogs/dialog.component'; import { RecordingDialogComponent } from './components/dialogs/recording-dialog.component'; -import { DeleteDialogComponent } from './components/dialogs/delete-recording.component'; +import { LayoutComponent } from './components/layout/layout.component'; +import { ChatPanelComponent } from './components/panel/chat-panel/chat-panel.component'; +import { SessionComponent } from './components/session/session.component'; +import { StreamComponent } from './components/stream/stream.component'; +import { ToolbarComponent } from './components/toolbar/toolbar.component'; +import { VideoComponent } from './components/video/video.component'; import { LinkifyPipe } from './pipes/linkify.pipe'; -import { TranslatePipe } from './pipes/translate.pipe'; -import { StreamTypesEnabledPipe, ParticipantStreamsPipe } from './pipes/participant.pipe'; +import { ParticipantStreamsPipe, StreamTypesEnabledPipe } from './pipes/participant.pipe'; import { DurationFromSecondsPipe, SearchByStringPropertyPipe, ThumbnailFromUrlPipe } from './pipes/recording.pipe'; +import { TranslatePipe } from './pipes/translate.pipe'; -import { OpenViduAngularConfig } from './config/openvidu-angular.config'; import { CdkOverlayContainer } from './config/custom-cdk-overlay'; -import { DeviceService } from './services/device/device.service'; -import { LoggerService } from './services/logger/logger.service'; -import { PlatformService } from './services/platform/platform.service'; -import { StorageService } from './services/storage/storage.service'; -import { TokenService } from './services/token/token.service'; -import { OpenViduAngularConfigService } from './services/config/openvidu-angular.config.service'; -import { OpenViduService } from './services/openvidu/openvidu.service'; +import { OpenViduAngularConfig } from './config/openvidu-angular.config'; import { ActionService } from './services/action/action.service'; import { ChatService } from './services/chat/chat.service'; +import { OpenViduAngularConfigService } from './services/config/openvidu-angular.config.service'; +import { DeviceService } from './services/device/device.service'; import { DocumentService } from './services/document/document.service'; import { LayoutService } from './services/layout/layout.service'; +import { LoggerService } from './services/logger/logger.service'; +import { OpenViduService } from './services/openvidu/openvidu.service'; import { PanelService } from './services/panel/panel.service'; import { ParticipantService } from './services/participant/participant.service'; +import { PlatformService } from './services/platform/platform.service'; import { RecordingService } from './services/recording/recording.service'; +import { StorageService } from './services/storage/storage.service'; +import { TokenService } from './services/token/token.service'; +import { AudioWaveComponent } from './components/audio-wave/audio-wave.component'; +import { PanelComponent } from './components/panel/panel.component'; import { ParticipantPanelItemComponent } from './components/panel/participants-panel/participant-panel-item/participant-panel-item.component'; import { ParticipantsPanelComponent } from './components/panel/participants-panel/participants-panel/participants-panel.component'; -import { VideoconferenceComponent } from './components/videoconference/videoconference.component'; -import { PanelComponent } from './components/panel/panel.component'; -import { AudioWaveComponent } from './components/audio-wave/audio-wave.component'; import { PreJoinComponent } from './components/pre-join/pre-join.component'; +import { VideoconferenceComponent } from './components/videoconference/videoconference.component'; -import { AvatarProfileComponent } from './components/avatar-profile/avatar-profile.component'; -import { OpenViduAngularDirectiveModule } from './directives/template/openvidu-angular.directive.module'; -import { ApiDirectiveModule } from './directives/api/api.directive.module'; -import { BackgroundEffectsPanelComponent } from './components/panel/background-effects-panel/background-effects-panel.component'; -import { SettingsPanelComponent } from './components/panel/settings-panel/settings-panel.component'; -import { ActivitiesPanelComponent } from './components/panel/activities-panel/activities-panel.component'; -import { RecordingActivityComponent } from './components/panel/activities-panel/recording-activity-panel/recording-activity.component'; import { AdminDashboardComponent } from './admin/dashboard/dashboard.component'; import { AdminLoginComponent } from './admin/login/login.component'; -import { AppMaterialModule } from './openvidu-angular.material.module'; -import { VideoDevicesComponent } from './components/settings/video-devices/video-devices.component'; -import { AudioDevicesComponent } from './components/settings/audio-devices/audio-devices.component'; -import { NicknameInputComponent } from './components/settings/nickname-input/nickname-input.component'; -import { LangSelectorComponent } from './components/settings/lang-selector/lang-selector.component'; -import { SubtitlesSettingComponent } from './components/settings/subtitles/subtitles.component'; +import { AvatarProfileComponent } from './components/avatar-profile/avatar-profile.component'; import { CaptionsComponent } from './components/captions/captions.component'; +import { ActivitiesPanelComponent } from './components/panel/activities-panel/activities-panel.component'; +import { RecordingActivityComponent } from './components/panel/activities-panel/recording-activity-panel/recording-activity.component'; +import { BackgroundEffectsPanelComponent } from './components/panel/background-effects-panel/background-effects-panel.component'; +import { SettingsPanelComponent } from './components/panel/settings-panel/settings-panel.component'; +import { AudioDevicesComponent } from './components/settings/audio-devices/audio-devices.component'; +import { CaptionsSettingComponent } from './components/settings/captions/captions.component'; +import { LangSelectorComponent } from './components/settings/lang-selector/lang-selector.component'; +import { NicknameInputComponent } from './components/settings/nickname-input/nickname-input.component'; +import { VideoDevicesComponent } from './components/settings/video-devices/video-devices.component'; import { CustomBreakPointsProvider, CustomLayoutExtensionDirective } from './config/custom-flexlayout-breakpoints'; +import { ApiDirectiveModule } from './directives/api/api.directive.module'; +import { OpenViduAngularDirectiveModule } from './directives/template/openvidu-angular.directive.module'; +import { AppMaterialModule } from './openvidu-angular.material.module'; const publicComponents = [ AdminDashboardComponent, @@ -92,7 +92,7 @@ const privateComponents = [ NicknameInputComponent, LangSelectorComponent, RecordingActivityComponent, - SubtitlesSettingComponent + CaptionsSettingComponent ]; @NgModule({ diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/caption/caption.service.spec.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/caption/caption.service.spec.ts new file mode 100644 index 000000000..9b3302643 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/caption/caption.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { CaptionService } from './caption.service'; + +describe('CaptionService', () => { + let service: CaptionService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(CaptionService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/caption/caption.service.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/caption/caption.service.ts new file mode 100644 index 000000000..7a6a25942 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/caption/caption.service.ts @@ -0,0 +1,47 @@ +import { Injectable } from '@angular/core'; +import { Observable, Subject } from 'rxjs'; +import { StorageService } from '../storage/storage.service'; + +/** + * @internal + */ +@Injectable({ + providedIn: 'root' +}) +export class CaptionService { + private langTitles = [ + { name: 'English', ISO: 'en-US' }, + { name: 'Español', ISO: 'es-ES' }, + { name: 'Deutsch', ISO: 'de-DE' }, + { name: 'Français', ISO: 'fr-FR' }, + { name: '中国', ISO: 'zh-CN' }, + { name: 'हिन्दी', ISO: 'hi-IN' }, + { name: 'Italiano', ISO: 'it-IT' }, + { name: 'やまと', ISO: 'jp-JP' }, + { name: 'Português', ISO: 'pt-PT' } + ]; + captionLangSelected: { name: string; ISO: string }; + captionLangObs: Observable<{ name: string; ISO: string }>; + private _captionLangObs: Subject<{ name: string; ISO: string }> = new Subject(); + + + constructor(private storageService: StorageService) { + this.captionLangObs = this._captionLangObs.asObservable(); + } + + setLanguage(lang: string) { + if (this.langTitles.some((l) => l.ISO === lang)) { + this.captionLangSelected = this.langTitles.find((l) => l.ISO === lang); + this._captionLangObs.next(this.captionLangSelected); + this.storageService.setCaptionLang(lang); + } + } + + getLangSelected(): { name: string; ISO: string } { + return this.captionLangSelected || this.langTitles[0]; + } + + getCaptionLanguages(): { name: string; ISO: string }[] { + return this.langTitles; + } +} diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/config/openvidu-angular.config.service.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/config/openvidu-angular.config.service.ts index 8b7b50b0d..0801e7be7 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/config/openvidu-angular.config.service.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/config/openvidu-angular.config.service.ts @@ -28,8 +28,8 @@ export class OpenViduAngularConfigService { fullscreenButton = >new BehaviorSubject(true); fullscreenButtonObs: Observable; - subtitlesButton = >new BehaviorSubject(true); - subtitlesButtonObs: Observable; + captionsButton = >new BehaviorSubject(true); + captionsButtonObs: Observable; toolbarSettingsButton = >new BehaviorSubject(true); toolbarSettingsButtonObs: Observable; @@ -95,7 +95,7 @@ export class OpenViduAngularConfigService { this.displayLogoObs = this.displayLogo.asObservable(); this.recordingButtonObs = this.recordingButton.asObservable(); this.toolbarSettingsButtonObs = this.toolbarSettingsButton.asObservable(); - this.subtitlesButtonObs = this.subtitlesButton.asObservable(); + this.captionsButtonObs = this.captionsButton.asObservable(); //Stream observables this.displayParticipantNameObs = this.displayParticipantName.asObservable(); this.displayAudioDetectionObs = this.displayAudioDetection.asObservable(); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/document/document.service.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/document/document.service.ts index 2f89f8d45..10484fd20 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/document/document.service.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/document/document.service.ts @@ -13,17 +13,7 @@ export class DocumentService { screenSizeObs: Observable; constructor(private media: MediaObserver) { - this.screenSizeObs= this.media.asObservable(); - } - - getHTMLElementByClassName(element: HTMLElement, className: string): HTMLElement { - while (!!element && element !== document.body) { - if (element.className.includes(className)) { - return element; - } - element = element.parentElement; - } - return null; + this.screenSizeObs = this.media.asObservable(); } toggleFullscreen(elementId: string) { diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/layout/layout.service.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/layout/layout.service.ts index e45444020..c4e460b87 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/layout/layout.service.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/layout/layout.service.ts @@ -1,7 +1,6 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; import { LayoutAlignment, LayoutClass, OpenViduLayout, OpenViduLayoutOptions } from '../../models/layout.model'; -import { DocumentService } from '../document/document.service'; /** * @internal @@ -10,26 +9,24 @@ import { DocumentService } from '../document/document.service'; providedIn: 'root' }) export class LayoutService { - layoutContainer: HTMLElement | null = null; layoutWidthObs: Observable; - subtitlesTogglingObs: Observable; + captionsTogglingObs: Observable; private layoutWidth: BehaviorSubject = new BehaviorSubject(0); private openviduLayout: OpenViduLayout; private openviduLayoutOptions: OpenViduLayoutOptions; - private subtitlesToggling: BehaviorSubject = new BehaviorSubject(false); + private captionsToggling: BehaviorSubject = new BehaviorSubject(false); - - constructor(private documentService: DocumentService) { + constructor() { this.layoutWidthObs = this.layoutWidth.asObservable(); - this.subtitlesTogglingObs = this.subtitlesToggling.asObservable(); + this.captionsTogglingObs = this.captionsToggling.asObservable(); } initialize(container: HTMLElement) { this.layoutContainer = container; this.openviduLayout = new OpenViduLayout(); this.openviduLayoutOptions = this.getOptions(); - if(this.layoutContainer){ + if (this.layoutContainer) { this.openviduLayout.initLayoutContainer(this.layoutContainer, this.openviduLayoutOptions); } this.sendLayoutWidthEvent(); @@ -66,8 +63,8 @@ export class LayoutService { return options; } - toggleSubtitles() { - this.subtitlesToggling.next(!this.subtitlesToggling.getValue()); + toggleCaptions() { + this.captionsToggling.next(!this.captionsToggling.getValue()); } update(timeout: number = null) { @@ -93,7 +90,7 @@ export class LayoutService { } private sendLayoutWidthEvent() { - const sidenavLayoutElement = this.documentService.getHTMLElementByClassName( + const sidenavLayoutElement = this.getHTMLElementByClassName( this.openviduLayout?.getLayoutContainer(), LayoutClass.SIDENAV_CONTAINER ); @@ -101,4 +98,14 @@ export class LayoutService { this.layoutWidth.next(sidenavLayoutElement.clientWidth); } } + + private getHTMLElementByClassName(element: HTMLElement | null, className: string): HTMLElement | null { + while (!!element && element !== document.body) { + if (element.className.includes(className)) { + return element; + } + element = element.parentElement; + } + return null; + } } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/storage/storage.service.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/storage/storage.service.ts index 3ed8762cd..3e58b8c63 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/storage/storage.service.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/storage/storage.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { ILogger } from '../../models/logger.model'; -import { LoggerService } from '../logger/logger.service'; import { Storage } from '../../models/storage.model'; +import { LoggerService } from '../logger/logger.service'; /** * @internal @@ -62,6 +62,14 @@ export class StorageService { return this.get(Storage.LANG); } + setCaptionLang(lang: string){ + this.set(Storage.CAPTION_LANG, lang); + } + + getCaptionsLang(): string { + return this.get(Storage.CAPTION_LANG); + } + private set(key: string, item: any) { const value = JSON.stringify({ item: item }); // this.log.d('Storing on localStorage "' + key + '" with value "' + value + '"'); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/translate/translate.service.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/translate/translate.service.ts index e5d0a221b..cf593edcd 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/translate/translate.service.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/translate/translate.service.ts @@ -1,12 +1,12 @@ import { Injectable } from '@angular/core'; +import * as cn from '../../lang/cn.json'; +import * as de from '../../lang/de.json'; import * as en from '../../lang/en.json'; import * as es from '../../lang/es.json'; -import * as de from '../../lang/de.json'; import * as fr from '../../lang/fr.json'; -import * as cn from '../../lang/cn.json'; import * as hi from '../../lang/hi.json'; -import * as ja from '../../lang/ja.json'; import * as it from '../../lang/it.json'; +import * as ja from '../../lang/ja.json'; import * as nl from '../../lang/nl.json'; import * as pt from '../../lang/pt.json'; import { StorageService } from '../storage/storage.service'; @@ -36,7 +36,7 @@ export class TranslateService { constructor(private storageService: StorageService) { const iso = this.storageService.getLang() || 'en'; - this.langSelected = this.langTitles.find((lang) => lang.ISO === iso); + this.langSelected = this.langTitles.find((lang) => lang.ISO === iso) || this.langTitles[0]; this.currentLang = this.availableLanguages[this.langSelected.ISO]; }