/**
 * Konichiwa~
 * => Part of Content Script
 * This is responsible for the MyAnimeList widgets/components.
 */ declare function require ( arg ) ; import { IMALSearchAnime , IMALUserListAnime , Intent , } from "../common" ; import { cleanAnimeName , loadSettings } from "../utils" ; let animeName = "" ; let animeId = "" ; let animeInUserList = false ; let currentAnime ; let malWatchedEpisodes = 0 ; let autoUpdate = true ; let statusIconTimeout = 0 ; let userList ; enum StatusType { InProgress , Success , Fail } const selectors = { add : "#nac__mal__add" , incrementEp : "#nac__mal__increment-ep" , quickAccess : "#nac__mal__quick-access" , sectionAdd : "#nac__mal__section-add" , sectionUpdate : "#nac__mal__section-update" , statusIcon : "#nac__mal__status-icon" , totalEp : "#nac__mal__total-ep" , update : "#nac__mal__update" , watchedEp : "#nac__mal__watched-ep" , } ; interface ISetupOptions { animeName : string ; } export function setup ( options ) { loadSettings ( "malAutoUpdate" ) . then ( resp => { resp . malAutoUpdate = resp . malAutoUpdate === undefined ? true : resp . malAutoUpdate ; autoUpdate = resp . malAutoUpdate ; animeName = cleanAnimeName ( options . animeName ) ; $ ( "#player" ) . parent ( ) . append ( quickAccess ( ) ) ; initialize ( ) ; } ) ; } function hideLoader ( ) { $ ( selectors . quickAccess ) . find ( ".loader" ) . fadeOut ( 300 ) ; } function showStatusIcon ( statusType = StatusType . InProgress ) { clearTimeout ( statusIconTimeout ) ; let statusIcon = $ ( selectors . statusIcon ) ; switch ( statusType ) { case StatusType . Success : statusIcon . attr ( "src" , chrome . extension . getURL ( "images/check-mark.png" ) ) ; break ; case StatusType . Fail : statusIcon . attr ( "src" , chrome . extension . getURL ( "images/x-mark.png" ) ) ; break ; default : statusIcon . attr ( "src" , chrome . extension . getURL ( "images/tail-spin.svg" ) ) ; break ; } statusIcon . show ( ) ; } function hideStatusIcon ( ) { clearTimeout ( statusIconTimeout ) ; statusIconTimeout = setTimeout ( ( ) => { $ ( selectors . statusIcon ) . fadeOut ( 500 ) ; } , 5000 ) ; } function showSectionAdd ( ) { $ ( selectors . sectionAdd ) . show ( ) ; $ ( selectors . sectionUpdate ) . hide ( ) ; } function showSectionUpdate ( ) { $ ( selectors . sectionAdd ) . hide ( ) ; $ ( selectors . sectionUpdate ) . show ( ) ; } /**
 * Callback function for  epChangeCallbacks . This function helps
 * implement the auto mal sync behaviour.
 *  param newEpId param newEpNum export function epTracker ( newEpId , newEpNum ) { if ( ! isNaN ( Number ( newEpNum ) ) && autoUpdate && animeInUserList && newEpNum > malWatchedEpisodes ) { $ ( selectors . watchedEp ) . val ( newEpNum ) ; malWatchedEpisodes = newEpNum ; $ ( selectors . update ) . click ( ) ; } } /**
 * Checks if the current anime is in users MAL List. If it
 * exists, then the MAL entry is returned which is used for
 * getting information like watched episodes etc. If the
 * current anime does not exist, then null is returned.
 */ function findAnimeInUserList ( ) { for ( let entry of userList ) { if ( currentAnime . id === entry . series_animedb_id ) { return entry ; } } return null ; } /**
 * Searches MAL and returns current anime. It does this by regex
 * matching the items on the returned MAL search list with the
 * anime name that we get from the title.
 */ function getCurrentAnime ( ) { return new Promise ( ( resolve , reject ) => { chrome . runtime . sendMessage ( { animeName , intent : Intent . MAL_Search , } , resp => { if ( resp . success ) { let fixed = animeName . replace ( "(" , "\\(" ) . replace ( ")" , "\\)" ) ; let titleRe = new RegExp ( `^${ fixed }$` , "i" ) ; for ( let entry of ( resp . data as IMALSearchAnime [ ] ) ) { if ( entry . title . match ( titleRe ) ) { return resolve ( entry ) ; } } } reject ( resp . err ) ; } ) ; } ) ; } /**
 * Returns users MAL Anime List.
 */ function getUserList ( ) { return new Promise ( ( resolve , reject ) => { chrome . runtime . sendMessage ( { intent : Intent . MAL_Userlist , } , resp => { if ( resp . success ) { resolve ( resp . data as IMALUserListAnime [ ] ) ; } else { reject ( resp . err ) ; } } ) ; } ) ; } export function initialize ( ) { Promise . all ( [ getCurrentAnime ( ) , getUserList ( ) ] ) . then ( value => { currentAnime = value [ 0 ] ; userList = value [ 1 ] ; animeId = currentAnime . id ; let entry = findAnimeInUserList ( ) ; if ( entry ) { animeInUserList = true ; showSectionUpdate ( ) ; $ ( selectors . totalEp ) . text ( currentAnime . episodes ) ; $ ( selectors . watchedEp ) . val ( entry . my_watched_episodes ) ; malWatchedEpisodes = Number ( entry . my_watched_episodes ) || 0 ; } else { showSectionAdd ( ) ; } hideLoader ( ) ; } ) . catch ( err => { let qa = $ ( selectors . quickAccess ) ; qa . find ( ".loader > img" ) . hide ( ) ; switch ( err ) { case 204 : qa . find ( ".loader > .status" ) . show ( ) . text ( "Anime not found in MAL :(" ) ; break ; case 401 : qa . find ( ".loader > .status" ) . show ( ) . text ( "Invalid MAL credentials" ) ; break ; default : qa . find ( ".loader > .status" ) . show ( ) . text ( "Oops! Something went wrong" ) ; break ; } } ) ; } /**
 * Returns the MyAnimeList quick access widget. This widget
 * allows a user to quickly add/update anime to their MAL.
 */ export function quickAccess ( ) { let template = require ( "html-loader!../../templates/mal_quickAccess.html" ) ; let qa = $ ( template ) ; qa . find ( ".loader > img" ) . attr ( "src" , chrome . extension . getURL ( "images/puff.svg" ) ) ; qa . find ( selectors . statusIcon ) . attr ( "src" , "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" ) ; qa . find ( selectors . statusIcon ) . hide ( ) ; qa . find ( selectors . watchedEp ) . on ( "keydown" , e => { if ( e . keyCode ) { if ( ! ( e . keyCode === 8 || ( e . keyCode >= 48 && e . keyCode <= 57 ) || ( e . keyCode >= 96 && e . keyCode <= 105 ) ) ) { return false ; } } } ) ; qa . find ( selectors . incrementEp ) . on ( "click" , ( ) => { let c = $ ( selectors . watchedEp ) . val ( ) ; $ ( selectors . watchedEp ) . val ( Number ( c ) + 1 ) ; } ) ; qa . find ( selectors . add ) . on ( "click" , ( ) => { showStatusIcon ( ) ; chrome . runtime . sendMessage ( { animeId , intent : Intent . MAL_QuickAdd , } , resp => { if ( resp . success ) { animeInUserList = true ; showStatusIcon ( StatusType . Success ) ; showSectionUpdate ( ) ; $ ( selectors . totalEp ) . text ( currentAnime . episodes ) ; $ ( selectors . watchedEp ) . val ( 1 ) ; } else { showStatusIcon ( StatusType . Fail ) ; } hideStatusIcon ( ) ; } ) ; } ) ; qa . find ( selectors . update ) . on ( "click" , ( ) => { showStatusIcon ( ) ; chrome . runtime . sendMessage ( { animeId , episode : $ ( selectors . watchedEp ) . val ( ) , intent : Intent . MAL_QuickUpdate , } , resp => { if ( resp . success ) { showStatusIcon ( StatusType . Success ) ; } else { showStatusIcon ( StatusType . Fail ) ; } hideStatusIcon ( ) ; } ) ; } ) ; qa . find ( ".loader > .status" ) . hide ( ) ; return qa ; }