import * as Defs from 'definitions' ; import { SettingsAction } from './actions.d' ; import { Artist , Album , Tracker , trackerURI , mapTrackerToParams , Library } from 'compactd-models' ; import { getDatabase } from 'app/database' ; import PouchDB from 'pouchdb' ; import { Intent } from '@blueprintjs/core' ; import Toaster from 'app/toaster' ; import Socket from 'app/socket' ; import Session from 'app/session' ; const initialState = { opened : false , scanning : false , trackers : [ ] , libraries : [ ] } ; const TOGGLE_SETTINGS_PAGE = 'cassette/settings/TOGGLE_SETTINGS_PAGE' ; const RESOLVE_TRACKERS = 'cassette/settings/RESOLVE_TRACKERS' ; const RESOLVE_LIBRARIES = 'cassette/settings/RESOLVE_LIBRARIES' ; const SET_SCANNING = 'cassette/settings/SET_SCANNING' ; export function reducer ( state = initialState , action ) { switch ( action . type ) { case SET_SCANNING : return Object . assign ( { } , state , { scanning : action . scanning } ) ; case TOGGLE_SETTINGS_PAGE : return Object . assign ( { } , state , { opened : ! state . opened } ) ; case RESOLVE_TRACKERS : return Object . assign ( { } , state , { trackers : action . trackers } ) ; case RESOLVE_LIBRARIES : return Object . assign ( { } , state , { libraries : action . libraries } ) ; } return state ; } function toggleSettingsPage ( state ? ) { return { type : TOGGLE_SETTINGS_PAGE } ; } function removeTracker ( id ) { return async function ( dispatch , getState ) { try { const Tracker = await getDatabase < Tracker > ( 'trackers' ) ; const doc = await Tracker . get ( id ) ; await Tracker . remove ( doc . _id , doc . _rev ) ; loadTrackers ( ) ( dispatch , getState ) ; } catch ( err ) { Toaster . error ( err ) ; } } ; } function loadTrackers ( ) { return async function ( dispatch , getState ) { try { const Tracker = await getDatabase < Tracker > ( 'trackers' ) ; const trackers = await Tracker . allDocs ( { include_docs : true } ) ; dispatch ( { type : RESOLVE_TRACKERS , trackers : trackers . rows . filter ( ( el ) => el . key !== '_design/validator' ) . map ( ( el ) => el . doc ) } ) ; } catch ( err ) { Toaster . error ( err ) ; } } ; } function loadLibraries ( ) { return async function ( dispatch , getState ) { try { const Library = await getDatabase < Library > ( 'libraries' ) ; const libraries = await Library . allDocs ( { include_docs : true } ) ; dispatch ( { type : RESOLVE_LIBRARIES , libraries : libraries . rows . filter ( ( el ) => el . key !== '_design/validator' ) . map ( ( el ) => el . doc ) } ) ; } catch ( err ) { Toaster . error ( err ) ; } } ; } function editTracker ( id , props ) { return async function ( dispatch , getState ) { try { const Tracker = await getDatabase < Tracker > ( 'trackers' ) ; const old = await Tracker . get ( id , { revs : false , attachments : false , revs_info : false } ) ; const doc = Object . assign ( { } , old , props ) ; if ( old . name !== props . name && props . name ) { doc . _id = trackerURI ( { name : doc . name , type : doc . type } ) ; await Tracker . remove ( id , doc . _rev ) ; } await Tracker . put ( { _id : doc . _id , type : doc . type , name : doc . name , host : doc . host , username : doc . username , boost : doc . boost , ... props , ... ( doc . _id !== id ? { } : { _rev : doc . _rev } ) } ) ; return loadTrackers ( ) ( dispatch , getState ) ; } catch ( err ) { Toaster . error ( err ) ; } } ; } function editTrackerPassword ( id , password ) { return async function ( dispatch , getState ) { try { const { type , name } = trackerURI ( id ) ; const res = await fetch ( `/api/cascade/trackers/${ type }/${ name }/password` , { method : 'post' , body : JSON . stringify ( { password } ) , headers : Session . headers ( { 'content-type' : 'application/json' } ) } ) ; const data = await res . json ( ) ; if ( ! res . ok ) return Toaster . error ( data . error ) ; if ( data . ok ) { Toaster . show ( { icon : 'tick' , message : 'Password succesfully updated' , intent : 'SUCCESS' } ) ; return loadTrackers ( ) ( dispatch , getState ) ; } } catch ( err ) { Toaster . error ( err ) ; } } ; } function addTracker ( name , type , username , host = 'redacted.ch' ) { return async function ( dispatch , getState ) { try { const props = { name , type , username , host } ; const id = trackerURI ( mapTrackerToParams ( props ) ) + `-${ Math . floor ( Math . random ( ) * 2e8 ) . toString ( 36 ) }` ; const Tracker = await getDatabase < Tracker > ( 'trackers' ) ; const tracker = await Tracker . put ( { ... props , _id : id } ) ; return loadTrackers ( ) ( dispatch , getState ) ; } catch ( err ) { Toaster . error ( err ) ; } } ; } function scan ( id , full = false ) { return async ( dispatch ) => { dispatch ( { type : SET_SCANNING , scanning : true } ) ; const res = await fetch ( `/api/scans` , { method : 'POST' , body : JSON . stringify ( { libraryId : id , full } ) , headers : Session . headers ( { 'content-type' : 'application/json' , } ) } ) ; if ( res . status !== 201 ) { return Toaster . error ( 'An error happened while trying to start scan. Check logs for more details' ) ; } const data = await res . json ( ) ; const { finish , open_folder , error } = data . events ; const toast = Toaster . show ( { icon : 'search' , message : 'Scanning your music' , intent : 'PRIMARY' , timeout : 999999999 } ) ; Socket . listen ( finish , ( ) => { Toaster . update ( toast , { message : 'Scan sucessfully finished' , intent : Intent . SUCCESS } ) ; dispatch ( { type : SET_SCANNING , scanning : false , timeout : 2000 } ) ; } ) ; Socket . listen ( open_folder , ( evt ) => { Toaster . update ( toast , { message : `Scanning folder ${ evt . folder }` } ) ; } ) ; Socket . listen ( error , ( evt ) => { dispatch ( { type : SET_SCANNING , scanning : false } ) ; Toaster . update ( toast , { message : 'Scan failed, please check logs for more details' , intent : Intent . DANGER } ) ; } ) ; } ; } export const actions = { toggleSettingsPage , loadTrackers , editTracker , editTrackerPassword , addTracker , loadLibraries , scan , removeTracker } ;