import { Injectable } from '@angular/core' ; import { Client } from '../../../common/api/client.service' ; import { Session } from '../../../services/session' ; import { BehaviorSubject , Observable } from 'rxjs' ; import * as moment from 'moment' ; export interface YoutubeChannel { id : string ; title : string ; connected : number ; auto_import : boolean ; } export interface YoutubeStatusCounts { queued : number ; transferring : number ; } @ Injectable ( ) export class YoutubeMigrationService { endpoint = 'api/v3/media/youtube-importer/' ; channels : YoutubeChannel [ ] ; initChannels : boolean = false ; connected$ : BehaviorSubject < boolean > = new BehaviorSubject ( false ) ; selectedChannel$ : BehaviorSubject < YoutubeChannel > = new BehaviorSubject ( { id : '' , title : '' , connected : 1 , auto_import : false , } ) ; autoImport$ : BehaviorSubject < boolean > = new BehaviorSubject ( false ) ; statusCounts$ : BehaviorSubject < YoutubeStatusCounts > = new BehaviorSubject ( { queued : 0 , transferring : 0 , } ) ; importingAllVideos$ : BehaviorSubject < boolean > = new BehaviorSubject ( false ) ; videos$ : BehaviorSubject < any [ ] > = new BehaviorSubject ( null ) ; constructor ( private client , protected session ) { } /**
     * Initialize the subscriptions that update vals
     * used in multiple functions within this service
     */ setup ( ) { this . connected$ . next ( this . isConnected ( ) ) ; this . connected$ . subscribe ( connected => { if ( connected ) { this . getChannels ( ) ; } } ) ; this . selectedChannel$ . subscribe ( channel => { this . autoImport$ . next ( channel . auto_import ) ; } ) ; } /**
     * Check if current user has connected a YouTube account
     */ isConnected ( ) { const user = this . session . getLoggedInUser ( ) ; return user . yt_channels && user . yt_channels . length > 0 ; } /**
     * Get array of youtube channels associated with user
     */ getChannels ( ) { this . channels = this . session . getLoggedInUser ( ) . yt_channels ; if ( ( ! this . initChannels || ! this . selectedChannel$ . value . id ) && this . channels . length > 0 ) { this . selectChannel ( this . channels [ 0 ] . id ) ; } this . initChannels = true ; return this . channels ; } param channelId selectChannel ( channelId ) { if ( ! this . connected$ . value ) { return ; } const selectedChannel = this . channels . find ( c => c . id === channelId ) || this . channels [ 0 ] ; this . selectedChannel$ . next ( selectedChannel ) ; return selectedChannel ; } param status param nextPageToken async getVideos ( status = null , nextPageToken = null ) { if ( ! this . connected$ . value ) { return ; } const opts = { status : status , nextPageToken : nextPageToken , channelId : this . selectedChannel$ . value . id , } ; try { const response = < any > ( await this . client . get ( `${ this . endpoint }videos` , opts ) ) ; response . videos = this . formatVideos ( response . videos ) ; this . videos$ . next ( response . videos ) ; return response ; } catch ( e ) { console . error ( 'getAllVideos(): ' , e ) ; return e ; } } param youtubeId async getVideoStatus ( youtubeId ) { if ( ! this . connected$ . value ) { return ; } const opts = { youtubeId : youtubeId , status : null , channelId : this . selectedChannel$ . value . id , } ; try { const response = < any > ( await this . client . get ( `${ this . endpoint }videos` , opts ) ) ; return response . videos [ 0 ] . status ; } catch ( e ) { console . error ( 'getVideoStatus(): ' , e ) ; return e ; } } /**
     * Get count of video statuses (queued, transferred) from selected youtube channel
     */ async getStatusCounts ( ) { if ( ! this . connected$ . value ) { return ; } try { const response = < any > await this . client . get ( `${ this . endpoint }videos/count` , { channelId : this . selectedChannel$ . value . id , } ) ; this . statusCounts$ . next ( response . counts ) ; return response . counts ; } catch ( e ) { console . error ( 'count(): ' , e ) ; return e ; } } param videoId async import ( videoId ) { if ( ! this . connected$ . value ) { return ; } const opts = { channelId : this . selectedChannel$ . value . id , videoId : videoId , } ; try { const response = < any > ( await this . client . post ( `${ this . endpoint }videos/import` , opts ) ) ; if ( videoId === 'all' ) { this . importingAllVideos$ . next ( true ) ; } this . getStatusCounts ( ) ; return response ; } catch ( e ) { throw e ; } } param videoId async cancelImport ( videoId ) { if ( ! this . connected$ . value ) { return ; } try { const response = < any > ( await this . client . delete ( `${ this . endpoint }videos/import?channelId=${ this . selectedChannel$ . value . id }&videoId=${ videoId }` ) ) ; this . getStatusCounts ( ) ; return response ; } catch ( e ) { console . error ( 'cancelImport()' , e ) ; return e ; } } /**
     * Automatically transfer newly-uploaded youtube videos to Minds
     */ async enableAutoImport ( ) { const channels = this . session . getLoggedInUser ( ) . yt_channels ; if ( ! channels ) { return ; } let selectedChannel ; if ( ! this . selectedChannel$ . value . id ) { selectedChannel = channels [ 0 ] ; this . selectChannel ( selectedChannel . id ) ; } else { selectedChannel = this . selectedChannel$ . value ; } try { const response = < any > await this . client . post ( `${ this . endpoint }subscribe` , { channelId : selectedChannel . id , } ) ; this . autoImport$ . next ( true ) ; return response ; } catch ( e ) { console . error ( 'enableAutoImport(): ' , e ) ; return e ; } } /**
     * Disable automatic transfer of newly-uploaded youtube videos to Minds
     */ async disableAutoImport ( ) { const channels = this . session . getLoggedInUser ( ) . yt_channels ; if ( ! channels ) { return ; } let selectedChannel ; if ( ! this . selectedChannel$ . value . id ) { selectedChannel = channels [ 0 ] ; this . selectChannel ( selectedChannel . id ) ; } else { selectedChannel = this . selectedChannel$ . value ; } try { const response = < any > ( await this . client . delete ( `${ this . endpoint }subscribe?channelId=${ this . selectedChannel$ . value . id }` ) ) ; this . autoImport$ . next ( false ) ; return response ; } catch ( e ) { console . error ( 'disableAutoImport(): ' , e ) ; return e ; } } /**
     * Connect youtube account to Minds using google oauth.
     * Need to redirect to response.url, then will be automatically redirected back
     * to previous location after user authorizes
     */ async connectAccount ( youtubeId ) { try { const response = < any > await this . client . post ( `${ this . endpoint }account/connect` , { channelId : youtubeId , } ) ; this . session . getLoggedInUser ( ) . yt_channels = [ response . yt_channel ] ; this . connected$ . next ( response . connected ) ; this . selectedChannel$ . next ( response . yt_channel ) ; return response . connected ; } catch ( e ) { if ( e . errorId ) throw e ; return false ; } } param channelId async disconnectAccount ( ) { if ( this . session . isLoggedIn ( ) ) { try { const response = < any > ( await this . client . delete ( `${ this . endpoint }account?channelId=${ this . selectedChannel$ . value . id }` ) ) ; this . connected$ . next ( false ) ; return response ; } catch ( e ) { console . error ( 'disconnectAccount(): ' , e ) ; return e ; } } console . error ( 'User must be logged in to disconnect youtube account' ) ; } /**
     * Format video response for display template
     */ formatVideos ( videos ) { if ( ! videos ) { return ; } videos . forEach ( v => { v . display = { } ; if ( v . ownerObj ) { v . display . title = v . title ; v . display . thumb = v . thumbnail_src ; v . display . date = this . formatDate ( v . time_created ) ; } else { v . display . title = v . title ; v . display . thumb = v . thumbnail ; v . display . date = this . formatDate ( v . youtubeCreationDate ) ; v . display . duration = this . formatDuration ( v . duration ) ; } v . views = v . views || 0 ; } ) ; return videos ; } /**
     * Format duration for video display template
     */ formatDuration ( duration ) { const durationFormat = duration >= 3600 ? 'H:mm:ss' : 'mm:ss' ; return moment . utc ( moment . duration ( Number ( duration ) , 'seconds' ) . asMilliseconds ( ) ) . format ( durationFormat ) ; } /**
     * Format create date for video display template
     */ formatDate ( date ) { return moment ( date , 'X' ) . format ( 'MMM Do YYYY' ) ; } }