{"version":3,"file":"6845.e702eeccff39072a.js","mappings":"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","names":["PAGE","ClipsService","_ClipsService","constructor","store","sentryService","clipsApi","youtubeService","analyticsService","this","getPoster","clip","res","poster","DEFAULT_POSTER","youtube_id","getThumbnail","url","createClipFromFilestack","filestackResult","projectId","userId","_this","_asyncToGenerator","uploadTags","lastModifiedDate","duration","environment","production","console","log","warn","Error","newVideo","filename","type","mimetype","size","Date","toISOString","loading","originalFile","lastModified","convertVideoFileToClip","source","src","filestackConfig","storeTo","path","orig","key","name","file","id","Utils","removeFileExt","filmingDate","getDateTimeString","createClip","then","newClip","subClipsUpdated","dispatch","mystackActions","toFixed","seconds","durationInSeconds","clipUpload","error","DEBUG_LOGS","hlsMeta","HLS_META_TRANSCODE","Clip","clipActions","catch","err","Array","isArray","errors","length","errorType","info","message","params","sub","subscribeClipsUpdated","subscribe","next","updates","JSON","parse","hlsSrc","sources","Object","keys","isHlsComplete","unsubscribe","captureError","errorMessage","complete","getPosterTimeFromPoster","sNum","substring","lastIndexOf","parsed","parseInt","updatePosterToPosterTime","posterTime","newPoster","slice","startIndex","endIndex","handleSubClips","i0","i1","i2","i3","i4","i5","factory","ɵfac","providedIn","ClipEditPage_ng_template_7_span_7_Template","ctx_r1","returnUrl","defaultReturnUrl","selectedSegment","clip$","ClipEditPage","_ClipEditPage","clipsService","route","router","location","title","segmentNames","ClipperSegments","Settings","onDestroy$","Subject","ngOnInit","queryParams","pipe","takeUntil","_b","_a","getCurrentNavigation","extras","state","snapshot","paramMap","get","clipId","getClip","urlSegment","toUpperCase","Poster","Split","Trim","ENABLE_FEATURE_TRIM_CLIPS","onSelectSegment","event","createUrlTree","toLowerCase","toString","replaceState","ngOnDestroy","selectors","standalone","features","decls","vars","consts","template","rf","ctx","$event","_r1","ClipEditPage_ng_container_6_Template","ClipEditPage_ng_template_7_Template","ClipEditPage_ng_template_9_Template","tmp_2_0","hasClipId_r4","noClipId_r3","IonHeader","TopNavbarComponent","ClipperSegmentBarComponent","IonContent","NgIf","RouterLink","ClipperComponent","AsyncPipe","TranslatePipe"],"ignoreList":[],"sourceRoot":"webpack:///","sources":["./src/app/clips/shared/services/clips.service.ts","./src/app/pages/clip-edit/clip-edit.page.html","./src/app/pages/clip-edit/clip-edit.page.ts"],"sourcesContent":["/** @format */\n\nimport { Injectable } from '@angular/core';\nimport { Store } from '@ngrx/store';\nimport { State } from '@store/reducers';\nimport * as clipActions from '@store/actions/clips.actions';\nimport * as mystackActions from '@store/actions/mystack.actions';\nimport { ClipsApiService } from '@app/core/api/clips-api.service';\nimport { AnalyticsService } from '@app/core/services/analytics/analytics.service';\nimport { SentryService } from '@app/core/services/sentry.service';\nimport { YoutubeService } from '@app/core/services/youtube.service';\nimport { Utils } from '@app/shared/utils';\nimport { ClipVideoFile, Clip } from '@app/shared/models/clip.model';\nimport { convertVideoFileToClip, isHlsComplete } from '@app/shared/models/clip.model';\nimport { HLS_META_TRANSCODE, DEFAULT_POSTER } from '@app/shared/models/clip.model';\nimport { environment, filestackConfig } from 'src/environments/environment';\n\nconst DEBUG_LOGS = false;\nconst PAGE = '[ClipsService]';\n\n@Injectable({\n  providedIn: 'root',\n})\nexport class ClipsService {\n  constructor(\n    private store: Store<State>,\n    private sentryService: SentryService,\n    private clipsApi: ClipsApiService,\n    private youtubeService: YoutubeService,\n    private analyticsService: AnalyticsService\n  ) {}\n\n  getPoster(clip: Clip, res: string = 'default') {\n    let poster = DEFAULT_POSTER;\n    if (clip) {\n      if (clip.poster) {\n        poster = clip.poster;\n      } else if (clip.youtube_id) {\n        poster = this.youtubeService.getThumbnail(clip.youtube_id, res).url;\n      }\n    }\n    return poster;\n  }\n\n  /**\n   * Create a new Clip from the FileStack Upload\n   */\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  async createClipFromFilestack(filestackResult: any, projectId: string, userId: string) {\n    DEBUG_LOGS && console.log(`createClipFromFilestack filestackResult =`, filestackResult);\n    const {\n      uploadTags: {\n        lastModifiedDate = null, // = (new Date()).toISOString(),\n        // filesize = filestackResult.size, // don't use the stringified from uploadTags\n        duration = 0,\n      } = {},\n    } = filestackResult;\n    // MVP-1169 file selected metadata\n    !environment.production &&\n      console.log(`get size & updatedDate from filestackResult:`, { lastModifiedDate, duration, filestackResult });\n\n    if (!filestackResult || !projectId) {\n      console.warn(`${PAGE} createClipFromFilestack missing required params`, { filestackResult, projectId });\n      throw new Error('Missing required parameters - unable to create clip.');\n    }\n\n    const newVideo: ClipVideoFile = {\n      filename: filestackResult.filename,\n      type: filestackResult.mimetype,\n      size: filestackResult.size,\n      lastModifiedDate: new Date().toISOString(),\n      loading: true,\n    };\n\n    // get additional metadata if it exists.\n    if (lastModifiedDate) {\n      newVideo.lastModifiedDate = lastModifiedDate;\n    } else if (filestackResult.originalFile) {\n      if (\n        filestackResult.originalFile.lastModifiedDate &&\n        typeof filestackResult.originalFile.lastModifiedDate.toISOString === 'function'\n      ) {\n        newVideo.lastModifiedDate = filestackResult.originalFile.lastModifiedDate.toISOString();\n      } else if (filestackResult.originalFile.lastModified) {\n        newVideo.lastModifiedDate = new Date(filestackResult.originalFile.lastModified).toISOString();\n      }\n    }\n\n    // create our clip...\n    const clip = convertVideoFileToClip(newVideo);\n    clip.source = clip.source || {};\n    // it is important that this startsWith(filestackConfig.storeTo.path) in the clipApi logic\n    clip.source.src = filestackConfig.storeTo.clip.path + newVideo.filename;\n    clip.source.orig = filestackResult.key;\n    clip.source.filename = newVideo.filename;\n    clip.source.type = newVideo.type;\n    clip.source.loading = newVideo.loading;\n    clip.source.lastModifiedDate = newVideo.lastModifiedDate;\n\n    if (filestackResult.originalFile && filestackResult.originalFile.name) {\n      clip.source.file = filestackResult.originalFile;\n    }\n    // this must match for api to do its magic...\n    clip.id = Utils.removeFileExt(newVideo.filename);\n    clip.projectId = projectId;\n\n    if (typeof clip.filmingDate !== 'string') {\n      clip.filmingDate = Utils.getDateTimeString(clip.filmingDate);\n    }\n\n    DEBUG_LOGS && console.log(`${PAGE} createClipFromFilestack -> createClip:`, clip);\n\n    // kick off the createClip flow, subscribe to updates, add to mystack\n    // as soon as we return, the Capture Page will nav to the Stack Editor\n    return this.createClip(clip).then((newClip) => {\n      DEBUG_LOGS &&\n        console.log(`${PAGE} createClipFromFilestack -> now watch updates & addToStack (createClip result:`, newClip);\n      // watch changes and push to store\n      this.subClipsUpdated(newClip.projectId, newClip.id, userId);\n      // add the clip to the Editor\n      this.store.dispatch(mystackActions.addClip({ clip: newClip }));\n\n      try {\n        // analytics\n        const size =\n          newVideo && newVideo.size && typeof newVideo.size.toFixed === 'function' ? newVideo.size.toFixed(0) : false;\n        const seconds =\n          clip.source && clip.source.durationInSeconds && typeof clip.source.durationInSeconds.toFixed === 'function'\n            ? clip.source.durationInSeconds.toFixed(3)\n            : false;\n        this.analyticsService.clipUpload({\n          projectId: newClip.projectId,\n          id: newClip.id,\n          userId: newClip.userId,\n          ...(seconds && { seconds }),\n          ...(size && { size }),\n        });\n      } catch (error) {\n        console.warn(`Analytics error:`, error);\n      }\n    });\n  }\n\n  /**\n   * upload clip and add to store\n   * @param clip\n   * 1. Create the clip in DB\n   * 2.\n   */\n  createClip(clip: Clip): Promise<Clip> {\n    DEBUG_LOGS && console.log(`${PAGE} createClip`, clip);\n\n    // add the new HLS transcoding instruction\n    clip.hlsMeta = {\n      ...(clip.hlsMeta || {}),\n      ...HLS_META_TRANSCODE,\n    };\n\n    return this.clipsApi\n      .createClip(clip)\n      .then((res) => {\n        DEBUG_LOGS && console.log(`${PAGE} createClip res:`, res);\n        // add the clip to the Store\n        const newClip = new Clip(res);\n        this.store.dispatch(clipActions.addClip({ clip: newClip }));\n        return newClip;\n      })\n      .catch((err) => {\n        if (\n          err &&\n          Array.isArray(err.errors) &&\n          err.errors.length > 0 &&\n          err.errors[0] &&\n          err.errors[0].errorType &&\n          err.errors[0].errorType === 'DynamoDB:ConditionalCheckFailedException'\n        ) {\n          console.info(`${PAGE} createClip already Exists:`, err);\n          return new Clip(clip);\n        }\n        console.error(`${PAGE} createClip err:`, err);\n        if (err && Array.isArray(err.errors) && err.errors.length > 0 && err.errors[0].message) {\n          throw err.errors[0].message;\n        }\n        throw err;\n      });\n  }\n\n  /**\n   * clipUpdate GraphQL Subscription\n   */\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  subClipsUpdated(projectId: string, id = '', userId = '') {\n    const params: { projectId: string; id?: string } = {\n      projectId,\n    };\n    if (id) {\n      params.id = id;\n    }\n    // not currently using userId on this GQL subscription in the API\n    // if (userId) {  params.userId = userId; }\n\n    // keeping the sub variable local so there can be multiple open subs\n    const sub = this.clipsApi.subscribeClipsUpdated(params).subscribe({\n      next: (res) => {\n        // todo: convert to handleSubClips(res) when this not needed by editor\n        DEBUG_LOGS && console.log(`${PAGE} clipsUpdatedSubscription next:`, res);\n        if (!res || !res.id || !res.projectId) {\n          throw new Error('Missing clip id in subscription?');\n        }\n        const updates: Partial<Clip> = {};\n        let hlsMeta;\n        if (res.hlsMeta) {\n          try {\n            hlsMeta = typeof res.hlsMeta === 'string' ? JSON.parse(res.hlsMeta) : res.hlsMeta;\n            updates.hlsMeta = hlsMeta;\n          } catch (error) {\n            console.log(`Caught error during JSON.parse(res.hlsMeta):`, {\n              hlsMeta: res.hlsMeta,\n              error: error.message || error,\n            });\n          }\n        }\n        if (res.hlsSrc) {\n          updates.hlsSrc = res.hlsSrc;\n        }\n        if (Array.isArray(res.sources) && res.sources.length > 0) {\n          updates.sources = res.sources;\n        }\n        if (res.poster) {\n          updates.poster = res.poster;\n        }\n        if (res.duration) {\n          updates.duration = res.duration;\n        }\n\n        if (Object.keys(updates).length > 0) {\n          // take the updates and flow to store...\n          this.store.dispatch(\n            clipActions.updateClipTranscoding({\n              projectId: res.projectId,\n              id: res.id,\n              updates,\n            })\n          );\n          DEBUG_LOGS &&\n            console.log(`${PAGE} clipsUpdatedSubscription updateClipTranscoding:`, {\n              projectId: res.projectId,\n              id: res.id,\n              updates,\n            });\n        }\n\n        if (isHlsComplete(new Clip(updates))) {\n          // when complete, this.unsubClipsUpdated()\n          sub.unsubscribe();\n        }\n      },\n      error: (err) => {\n        console.warn(`${PAGE} clipsUpdatedSubscription ERROR:`, err);\n        this.sentryService.captureError(err);\n\n        if (projectId && id) {\n          this.store.dispatch(\n            clipActions.updateClipTranscoding({\n              projectId,\n              id,\n              updates: {\n                hlsMeta: {\n                  errorMessage: err.message || err.errorMessage || err,\n                },\n              },\n            })\n          );\n        }\n        sub.unsubscribe();\n      },\n      complete: () => {\n        DEBUG_LOGS && console.log(`${PAGE} clipsUpdatedSubscription => Complete`);\n      },\n    });\n  }\n  //end GraphQL Subscription\n\n  /**\n   * Take the poster string and return poster time from the transcoded name\n   * example poster path:\n   * https://videos.filmstacker.com/public/filmstacker-dev/jd_-_jd-note_202203021348/jd_-_jd-note_202203021348_thumb.0000000.jpg\n   */\n  getPosterTimeFromPoster(clip: Clip) {\n    if (clip && clip.poster) {\n      const sNum = clip.poster.substring(clip.poster.lastIndexOf('_thumb.'), clip.poster.lastIndexOf('.'));\n      // there shouldn't be any dashes anymore\n      // const sTime = sNum.replace(/-/g, '').replace(/0/gi, '');\n      try {\n        const parsed = parseInt(sNum, 10);\n        return parsed > 0 ? parsed : 0;\n      } catch (error) {\n        return 0;\n      }\n    }\n    return 0;\n  }\n\n  /**\n   * Update the poster image to match the new posterTime\n   *\n   * @todo verify it exists in s3\n   * potential ref: https://stackoverflow.com/questions/9815762/detect-when-an-image-fails-to-load-in-javascript\n   *\n   * example poster path:\n   * https://videos.filmstacker.com/public/filmstacker-dev/jd_-_jd-note_202203021348/jd_-_jd-note_202203021348_thumb.0000000.jpg\n   */\n  updatePosterToPosterTime(clip: Clip, posterTime: number) {\n    if (clip && clip.poster) {\n      let newPoster = clip.poster;\n      const sNum = ('0000000' + posterTime).slice(-7);\n      const startIndex = newPoster.lastIndexOf('_thumb.') + '_thumb.'.length;\n      const endIndex = newPoster.lastIndexOf('.');\n      newPoster = newPoster.slice(0, startIndex) + sNum + newPoster.slice(endIndex);\n      console.log(`${PAGE} change clip.poster (TODO: verify it exists in s3) posterTime: ${posterTime} to:`, {\n        sNum,\n        newPoster,\n      });\n      return newPoster;\n    } else {\n      console.warn(`${PAGE} missing clip.poster - unable to change`, clip);\n      return null;\n    }\n  }\n\n  /**\n   * @deprecated unused - use subClipsUpdated\n   * Do what we need with the clip we just received\n   */\n  private handleSubClips(res) {\n    DEBUG_LOGS && console.log(`${PAGE} handleSubClips next:`, res);\n    if (!res || !res.id || !res.projectId) {\n      throw new Error('Missing clip id in subscription?');\n    }\n    // if any values exist not null, add them as changes?\n    const updates: Partial<Clip> = {};\n    let hlsMeta;\n    if (res.hlsMeta) {\n      try {\n        hlsMeta = typeof res.hlsMeta === 'string' ? JSON.parse(res.hlsMeta) : res.hlsMeta;\n        updates.hlsMeta = hlsMeta;\n      } catch (error) {\n        console.log(`Caught error during JSON.parse(res.hlsMeta):`, {\n          hlsMeta: res.hlsMeta,\n          error: error.message || error,\n        });\n      }\n    }\n    if (res.hlsSrc) {\n      updates.hlsSrc = res.hlsSrc;\n    }\n    if (Array.isArray(res.sources) && res.sources.length > 0) {\n      updates.sources = res.sources;\n    }\n    if (res.poster) {\n      updates.poster = res.poster;\n    }\n    if (res.duration) {\n      updates.duration = res.duration;\n    }\n\n    // take the updates and flow to store...\n    // this.store.dispatch(clipActions.updateClipTranscoding({\n    //   projectId: res.projectId,\n    //   id: res.id,\n    //   updates,\n    // }));\n  }\n}\n","<ion-header>\n  <app-top-navbar \n    [title]=\"((clip$ | async)?.title) ? title + ': ' + (clip$ | async).title : title\" \n    [backButtonReturnUrl]=\"returnUrl\">\n    <app-clipper-segment-bar\n      [selectedSegment]=\"selectedSegment\"\n      (onSelectSegment)=\"onSelectSegment($event)\"\n    ></app-clipper-segment-bar>\n    \n  </app-top-navbar>\n</ion-header>\n\n<ion-content>\n\n  <ng-container *ngIf=\"clipId && projectId; then hasClipId else noClipId\"></ng-container>\n  \n  <ng-template #noClipId>\n    <div class=\"ion-text-center ion-padding\">\n      <div class=\"ion-margin-vertical ion-padding-vertical\">{{ 'ERRORS.NO_CLIP_ID' | translate }}</div>\n\n      <ion-button [routerLink]=\"returnUrl ? returnUrl : defaultReturnUrl\">\n        {{ 'COMMON.BACK' | translate }} <span *ngIf=\"!returnUrl\">&nbsp;{{ 'COMMON.TO_STUDIO' | translate }}</span>\n      </ion-button>\n    </div>\n  </ng-template>\n  \n  <ng-template #hasClipId>\n    \n    <app-clipper\n      [selectedSegment]=\"selectedSegment\"\n      [clip]=\"clip$ | async\"\n      [returnUrl]=\"returnUrl\"\n    ></app-clipper>\n    \n  </ng-template>\n\n</ion-content>\n\n\n","/** @format */\n\nimport { Component, OnDestroy, OnInit } from '@angular/core';\nimport { Location, NgIf, AsyncPipe } from '@angular/common';\nimport { Router, ActivatedRoute, RouterLink } from '@angular/router';\nimport { IonHeader, IonContent } from '@ionic/angular/standalone';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { Observable, Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { ENABLE_FEATURE_TRIM_CLIPS } from '@app/app.config';\nimport { ClipsCoreService } from '@app/core/services/clips.service';\nimport { Clip } from '@app/shared/models/clip.model';\nimport { ClipperComponent, ClipperSegments } from '@app/modules/clipper/clipper.component';\nimport { ClipperSegmentBarComponent } from '@app/modules/clipper/clipper-segment-bar/clipper-segment-bar.component';\nimport { TopNavbarComponent } from '@app/shared/components/top-navbar/top-navbar.component';\n\nconst PAGE = '[ClipEdit]';\n\n@Component({\n  selector: 'app-clip-edit',\n  templateUrl: './clip-edit.page.html',\n  styleUrls: ['./clip-edit.page.scss'],\n  standalone: true,\n  imports: [\n    IonHeader,\n    TopNavbarComponent,\n    ClipperSegmentBarComponent,\n    IonContent,\n    NgIf,\n    RouterLink,\n    ClipperComponent,\n    AsyncPipe,\n    TranslatePipe,\n  ],\n})\nexport class ClipEditPage implements OnInit, OnDestroy {\n  clipId: string;\n  projectId: string;\n  title = 'Edit Clip';\n  clip$: Observable<Clip>;\n  returnUrl: string;\n  defaultReturnUrl = '/stack/studio';\n\n  public segmentNames = ClipperSegments;\n  public selectedSegment: ClipperSegments = ClipperSegments.Settings;\n  private onDestroy$ = new Subject<void>();\n\n  constructor(\n    private clipsService: ClipsCoreService,\n    private route: ActivatedRoute,\n    private router: Router,\n    private location: Location\n  ) {}\n\n  ngOnInit() {\n    this.route.queryParams.pipe(takeUntil(this.onDestroy$)).subscribe((params) => {\n      if (params?.returnUrl) {\n        console.log(`${PAGE} queryParams returnUrl:`, params.returnUrl);\n        this.returnUrl = params.returnUrl; //JSON.parse(params.returnUrl);\n      } else if (this.router.getCurrentNavigation()?.extras?.state) {\n        this.returnUrl = this.router.getCurrentNavigation().extras.state.returnUrl || this.defaultReturnUrl;\n        console.log(`${PAGE} navState:`, { returnUrl: this.returnUrl });\n      }\n    });\n    this.projectId = this.route.snapshot.paramMap.get('projectId');\n    this.clipId = this.route.snapshot.paramMap.get('id');\n\n    if (this.projectId && this.clipId) {\n      // get the clip\n      this.clip$ = this.clipsService.getClip(this.projectId, this.clipId);\n\n      // check for a segment in url\n      const urlSegment = this.route.snapshot.paramMap.get('segment');\n      if (urlSegment) {\n        switch (urlSegment.toUpperCase()) {\n          case ClipperSegments.Poster:\n            this.selectedSegment = ClipperSegments.Poster;\n            break;\n          case ClipperSegments.Split:\n            this.selectedSegment = ClipperSegments.Split;\n            break;\n          case ClipperSegments.Trim:\n            if (ENABLE_FEATURE_TRIM_CLIPS) {\n              this.selectedSegment = ClipperSegments.Trim;\n              break;\n            }\n          // eslint-disable-next-line no-fallthrough\n          case ClipperSegments.Settings:\n          default:\n            this.selectedSegment = ClipperSegments.Settings;\n        }\n      }\n    }\n  }\n\n  onSelectSegment(event) {\n    console.log(`onSelectSegment`, { returnUrl: this.router.url });\n    if (event) {\n      this.selectedSegment = event;\n\n      if (this.clipId && this.projectId) {\n        // update Url so it's linkable\n        const url = this.router\n          .createUrlTree(['/stack/clip/', this.projectId, this.clipId, (event as string).toLowerCase()])\n          .toString();\n        this.location.replaceState(url, '', {\n          state: {\n            returnUrl: this.router.url,\n          },\n        });\n      }\n    } else {\n      console.warn(`${PAGE} segmentChanged NO value?:`, event);\n    }\n  }\n\n  ngOnDestroy() {\n    this.onDestroy$.next();\n    this.onDestroy$.complete();\n  }\n}\n"],"x_google_ignoreList":[]}