Created
October 17, 2016 15:54
-
-
Save xaiki/72cbd9442e4138c698bfdb990a85db8c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function (App) { | |
'use strict'; | |
var _ = require('underscore'), | |
Datastore = require('nedb'), | |
TTL = 1000 * 60 * 60 * 24; | |
var startupTime = window.performance.now(); | |
console.info('Database path: ' + data_path); | |
process.env.TZ = 'America/New_York'; // set same api tz | |
function promisifyDatastore(datastore) { | |
datastore.insert = Q.denodeify(datastore.insert, datastore); | |
datastore.update = Q.denodeify(datastore.update, datastore); | |
datastore.remove = Q.denodeify(datastore.remove, datastore); | |
} | |
var pluckToHash = function (items, key) { | |
return _.pluck(items, key) | |
.reduce(function (o, v) { | |
o[v] = 1 | |
}, {}); | |
} | |
var extractIds = function (items) { | |
return pluckToHash ('imdb_id') | |
}; | |
var extractMovieIds = function (items) { | |
return pluckToHash ('movie_id') | |
}; | |
// This utilizes the exec function on nedb to turn function calls into promises | |
var promisifyDb = function (obj) { | |
return Q.Promise(function (resolve, reject) { | |
obj.exec(function (error, result) { | |
if (error) { | |
return reject(error); | |
} else { | |
return resolve(result); | |
} | |
}); | |
}); | |
}; | |
var Database = Backbone.Model.extend({ | |
defaults: { | |
id: 'imdb_id', | |
name: null | |
}, | |
initialize: function(attrs) { | |
console.error('this', this, attrs) | |
var name = this.get('name'); | |
console.error (name, 'initialize'); | |
this.db = new Datastore({ | |
filename: path.join(data_path, 'data/'+ name +'.db'), | |
autoload: true | |
}); | |
promisifyDatastore(this.db); | |
}, | |
/* XXX(xaiki): need to use apply */ | |
dbCall: function(fn) { | |
var self = this | |
var args = Array.prototype.slice.call(arguments, 1) | |
var promise = promisifyDb(this.db[fn].apply(args)) | |
promise.then(function (ret) { | |
self.emit(fn, ret) | |
}) | |
return promise | |
}, | |
selectorFromId: function (id) { | |
var selector = {} | |
selector[this.id] = id | |
return selector | |
}, | |
selectorFromData: function (data) { | |
return this.selectorFromId(data[this.id]) | |
}, | |
add: function (data, extra) { | |
var formatedData = this.formatData(data, extra) | |
return this.dbCall('insert', formatedData) | |
}, | |
update: function (data, extra) { | |
var formatedData = this.formatData(data, extra) | |
var selector = this.selectorFromData(formatedData) | |
return this.dbCall('update', selector, formatedData); | |
}, | |
remove: function (id) { | |
var selector = this.selectorFromId(id) | |
return this.dbCall('remove', selector) | |
}, | |
reset: function () { | |
return this.dbCall('remove', {}, {multi: true}) | |
}, | |
write: function (data, extra) { | |
var formatedData = this.formatData(data, extra) | |
var selector = this.selectorFromData(formatedData) | |
var db = this.db | |
return this.find(selector) | |
.then(function (result) { | |
if (result) { | |
// XXX(xaiki): prune id for $set | |
return db.update(selector, { | |
$set: data | |
}, {}); | |
} else { | |
return db.insert(data); | |
} | |
}) | |
}, | |
find: function (id) { | |
if (!id) | |
return this.dbCall('find', {}) | |
var selector = this.selectorFromId(id) | |
return this.dbCall('findOne', selector) | |
}, | |
formatData: function (data, extra) { return data } | |
}) | |
/* this is a database where elements can be 'watched' */ | |
var ContentDatabase = Database.extend({ | |
defaults: { | |
watchedId: null, | |
watchedType: null | |
}, | |
checkWatched: function (data) { | |
this.getWatched(data) | |
.then(function (data) { | |
return (data !== null && data.length > 0); | |
}); | |
}, | |
getWatched: function (data) { | |
var selector = {} | |
if (data) { | |
selector[this.watchedId] = data[this.watchedId] | |
} else { | |
selector['type'] = this.watchedType | |
} | |
return promisifyDb(db.watched.find(selector)) | |
}, | |
markWatched: function (data) { | |
if (data instanceof Array) { | |
return data.map(this.markWatched); | |
} | |
var id = data[this.id] | |
if (!id) { | |
console.error('This shouldn\'t be called'); | |
return Q(); | |
} | |
// XXX(xaiki): this is disgusting | |
App[this.watchedObject][id] = 1; | |
var watchedData = this.formatWatched(data) | |
watchedData['date'] = new Date(); | |
return promisifyDb(db.watched.insert(watchedData)) | |
.then (this.onWatched) | |
}, | |
markNotWatched: function (data) { | |
if (data instanceof Array) { | |
return data.map(this.markNotWatched); | |
} | |
var id = data[this.id] | |
if (!id) { | |
console.error('This shouldn\'t be called'); | |
return Q(); | |
} | |
// XXX(xaiki): this is disgusting | |
delete(App[this.watchedObject][id]) | |
var watchedData = this.formatWatched(data) | |
return promisifyDb(db.watched.remove(watchedData)) | |
.then(this.onUnWatched) | |
}, | |
formatWatched: function(data) {return data}, | |
onWatched: function() {}, | |
onUnWatched: function() {}, | |
}) | |
var MoviesDatabase = ContentDatabase.extend({ | |
defaults: { | |
id: 'imdb_id', | |
name: 'movies', | |
watchedId: 'imdb_id', | |
watchedObject: 'watchedMovies' | |
}, | |
initialize: function (attrs) { | |
ContentDatabase.prototype.initialize.call(this, attrs) | |
App.vent.on('movie:watched', _.bind(this.markWatched, this)); | |
App.vent.on('movie:unwatched', _.bind(this.markNotWatched, this)); | |
this.db.ensureIndex({ | |
fieldName: 'imdb_id', | |
unique: true | |
}); | |
this.db.removeIndex('imdb_id'); | |
this.db.removeIndex('tmdb_id'); | |
}, | |
formatWatched: function (data) { | |
return { | |
movie_id: data.imdb_id.toString(), | |
type: 'movie' | |
} | |
} | |
}) | |
var ShowsDatabase = ContentDatabase.extend({ | |
defaults: { | |
id: 'imdb_id', | |
name: 'shows', | |
watchedId: 'tvdb_id', | |
watchedObject: 'watchedShows', | |
watchedType: 'episode' | |
}, | |
initialize: function (attrs) { | |
ContentDatabase.prototype.initialize.call(this, attrs) | |
// Create unique indexes for the various id's for shows and movies | |
this.db.ensureIndex({ | |
fieldName: 'imdb_id', | |
unique: true | |
}); | |
this.db.ensureIndex({ | |
fieldName: 'tvdb_id', | |
unique: true | |
}); | |
App.vent.on('show:watched', _.bind(this.markWatched, this)); | |
App.vent.on('show:unwatched', _.bind(this.markNotWatched, this)); | |
}, | |
formatWatched: function (data) { | |
return { | |
tvdb_id: data.tvdb_id.toString(), | |
imdb_id: data.imdb_id.toString(), | |
season: data.season.toString(), | |
episode: data.episode.toString(), | |
type: 'episode', | |
date: new Date() | |
} | |
}, | |
onWatched: function (data) { | |
App.vent.trigger('show:watched:' + data.tvdb_id, data); | |
}, | |
onUnWatched: function (data) { | |
App.vent.trigger('show:unwatched:' + data.tvdb_id, data); | |
} | |
}) | |
var SettingsDatabase = Database.extend({ | |
defaults: { | |
id: 'key', | |
name: 'settings' | |
}, | |
initialize: function (attrs) { | |
Database.prototype.initialize.call(this, attrs) | |
// settings key uniqueness | |
this.db.ensureIndex({ | |
fieldName: 'key', | |
unique: true | |
}); | |
} | |
}) | |
var BookmarksDatabase = Database.extend({ | |
defaults: { | |
id: 'imdb_id', | |
name: 'bookmarks' | |
}, | |
initialize: function(attrs) { | |
Database.prototype.initialize.call(this, attrs) | |
this.on('add', function(id) {App.userBookmarks[id] = 1}) | |
this.on('remove', function(id) {delete(App.userBookmarks[id])}) | |
this.db.ensureIndex({ | |
fieldName: 'imdb_id', | |
unique: true | |
}); | |
}, | |
formatData: function (id, type) { | |
return { | |
imdb_id: id, | |
type: type | |
} | |
}, | |
find: function (data) { | |
if (data) | |
return this.findOne(data) | |
return this.findAll() | |
}, | |
findAll: function () { | |
return promisifyDb(db.bookmarks.find({})) | |
.then(function (data) { | |
var bookmarks = []; | |
if (data) { | |
bookmarks = extractIds(data); | |
} | |
return bookmarks; | |
}); | |
}, | |
findOne: function (data) { | |
var page = data.page - 1; | |
var byPage = 50; | |
var offset = page * byPage; | |
var query = {}; | |
if (data.type) { | |
query.type = data.type; | |
} | |
return promisifyDb(db[this.name].find(query).skip(offset).limit(byPage)); | |
} | |
}) | |
App.DatabaseHelpers = { | |
getUserInfo: function () { | |
var bookmarks = BookmarksDatabase.get() | |
.then(function (data) { | |
App.userBookmarks = data; | |
}); | |
var movies = MoviesDatabase.getWatched() | |
.then(function (data) { | |
App.watchedMovies = extractMovieIds(data); | |
}); | |
var episodes = ShowsDatabase.getWatched() | |
.then(function (data) { | |
App.watchedShows = extractIds(data) | |
}); | |
return Q.all([bookmarks, movies, episodes]); | |
}, | |
deleteDatabases: function () { | |
Databases.keys().map(function (name) { | |
fs.unlinkSync(path.join(data_path, 'data/'+name+'.db')); | |
}) | |
return Q.Promise(function (resolve, reject) { | |
var req = indexedDB.deleteDatabase(App.Config.cache.name); | |
req.onsuccess = function () { | |
resolve(); | |
}; | |
req.onerror = function () { | |
resolve(); | |
}; | |
}); | |
}, | |
initialize: function () { | |
// we'll intiatlize our settings and our API SSL Validation | |
// we build our settings array | |
return App.bootstrapPromise | |
.then(App.DatabaseHelpers.getUserInfo) | |
.then(App.Databases.settings.find) | |
.then(function (data) { | |
if (data !== null) { | |
for (var key in data) { | |
Settings[data[key].key] = data[key].value; | |
} | |
} else { | |
win.warn('is it possible to get here'); | |
} | |
// new install? | |
if (Settings.version === false) { | |
window.__isNewInstall = true; | |
} | |
App.vent.trigger('initHttpApi'); | |
/*return AdvSettings.checkApiEndpoints([ | |
Settings.updateEndpoint | |
]);*/ | |
}) | |
.then(function () { | |
// set app language | |
window.setLanguage(Settings.language); | |
// set hardware settings and usefull stuff | |
return AdvSettings.setup(); | |
}) | |
.then(function () { | |
App.Trakt = App.Config.getProviderForType('metadata'); | |
App.TVShowTime = App.Config.getProviderForType('tvst'); | |
App.TVShowTime.restoreToken(); | |
// check update | |
var updater = new App.Updater(); | |
updater.update() | |
.catch(function (err) { | |
win.error('updater.update()', err); | |
}); | |
}) | |
.catch(function (err) { | |
win.error('Error starting up', err); | |
}); | |
} | |
}; | |
var WatchedDatabase = new Database({id: 'key', name: 'watched'}) | |
App.Databases = [ | |
new BookmarksDatabase(), | |
new SettingsDatabase(), | |
new ShowsDatabase(), | |
new MoviesDatabase(), | |
WatchedDatabase | |
].reduce(function (o, v) { | |
o[v.get('name')] = v; | |
return o; | |
}, {}) | |
})(window.App); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment