Store Revamp / Full database synchronization across windows (#1833)
* History: Refactor history module
* Profiles: Refactor profiles module
* IPC: Move channel ids to their own file and make them constants
* IPC: Replace single sync channel for one channel per sync type
* Everywhere: Replace default profile id magic strings with constant ref
* Profiles: Refactor `activeProfile` property from store
This commit makes it so that `activeProfile`'s getter returns
the entire profile, while the related update function only needs
the profile id (instead of the previously used array index)
to change the currently active profile.
This change was made due to inconsistency regarding the active profile
when creating new profiles.
If a new profile coincidentally landed in the current active profile's
array index after sorting, the app would mistakenly change to it
without any action from the user apart from the profile's creation.
Turning the profile id into the selector instead solves this issue.
* Revert "Store: Implement history synchronization between windows"
This reverts commit 99b61e6178
.
This is necessary for an upcoming improved implementation of the
history synchronization.
* History: Remove unused mutation
* Everywhere: Create abstract database handlers
The project now utilizes abstract handlers to fetch, modify
or otherwise manipulate data from the database.
This facilitates 3 aspects of the app, in addition of
making them future proof:
- Switching database libraries is now trivial
Since most of the app utilizes the abstract handlers, it's incredibly
easily to change to a different DB library.
Hypothetically, all that would need to be done is to simply replace the
the file containing the base handlers, while the rest of the app
would go unchanged.
- Syncing logic between Electron and web is now properly separated
There are now two distinct DB handling APIs: the Electron one and
the web one.
The app doesn't need to manually choose the API, because it's detected
which platform is being utilized on import.
- All Electron windows now share the same database instance
This provides a single source of truth, improving consistency
regarding data manipulation and windows synchronization.
As a sidenote, syncing implementation has been left as is
(web unimplemented; Electron only syncs settings, remaining
datastore syncing will be implemented in the upcoming commits).
* Electron/History: Implement history synchronization
* Profiles: Implement suplementary profile creation logic
* ft-profile-edit: Small fix on profile name missing display
* Electron/Profiles: Implement profile synchronization
* Electron/Playlists: Implement playlist synchronization
This commit is contained in:
parent
3ad9dd2517
commit
daecf944fb
|
@ -0,0 +1,77 @@
|
||||||
|
// IPC Channels
|
||||||
|
const IpcChannels = {
|
||||||
|
ENABLE_PROXY: 'enable-proxy',
|
||||||
|
DISABLE_PROXY: 'disable-proxy',
|
||||||
|
OPEN_EXTERNAL_LINK: 'open-external-link',
|
||||||
|
GET_SYSTEM_LOCALE: 'get-system-locale',
|
||||||
|
GET_USER_DATA_PATH: 'get-user-data-path',
|
||||||
|
GET_USER_DATA_PATH_SYNC: 'get-user-data-path-sync',
|
||||||
|
SHOW_OPEN_DIALOG: 'show-open-dialog',
|
||||||
|
SHOW_SAVE_DIALOG: 'show-save-dialog',
|
||||||
|
STOP_POWER_SAVE_BLOCKER: 'stop-power-save-blocker',
|
||||||
|
START_POWER_SAVE_BLOCKER: 'start-power-save-blocker',
|
||||||
|
CREATE_NEW_WINDOW: 'create-new-window',
|
||||||
|
OPEN_IN_EXTERNAL_PLAYER: 'open-in-external-player',
|
||||||
|
|
||||||
|
DB_SETTINGS: 'db-settings',
|
||||||
|
DB_HISTORY: 'db-history',
|
||||||
|
DB_PROFILES: 'db-profiles',
|
||||||
|
DB_PLAYLISTS: 'db-playlists',
|
||||||
|
|
||||||
|
SYNC_SETTINGS: 'sync-settings',
|
||||||
|
SYNC_HISTORY: 'sync-history',
|
||||||
|
SYNC_PROFILES: 'sync-profiles',
|
||||||
|
SYNC_PLAYLISTS: 'sync-playlists'
|
||||||
|
}
|
||||||
|
|
||||||
|
const DBActions = {
|
||||||
|
GENERAL: {
|
||||||
|
CREATE: 'db-action-create',
|
||||||
|
FIND: 'db-action-find',
|
||||||
|
UPSERT: 'db-action-upsert',
|
||||||
|
DELETE: 'db-action-delete',
|
||||||
|
DELETE_MULTIPLE: 'db-action-delete-multiple',
|
||||||
|
DELETE_ALL: 'db-action-delete-all',
|
||||||
|
PERSIST: 'db-action-persist'
|
||||||
|
},
|
||||||
|
|
||||||
|
HISTORY: {
|
||||||
|
UPDATE_WATCH_PROGRESS: 'db-action-history-update-watch-progress'
|
||||||
|
},
|
||||||
|
|
||||||
|
PLAYLISTS: {
|
||||||
|
UPSERT_VIDEO: 'db-action-playlists-upsert-video-by-playlist-name',
|
||||||
|
UPSERT_VIDEO_IDS: 'db-action-playlists-upsert-video-ids-by-playlist-id',
|
||||||
|
DELETE_VIDEO_ID: 'db-action-playlists-delete-video-by-playlist-name',
|
||||||
|
DELETE_VIDEO_IDS: 'db-action-playlists-delete-video-ids',
|
||||||
|
DELETE_ALL_VIDEOS: 'db-action-playlists-delete-all-videos'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SyncEvents = {
|
||||||
|
GENERAL: {
|
||||||
|
CREATE: 'sync-create',
|
||||||
|
UPSERT: 'sync-upsert',
|
||||||
|
DELETE: 'sync-delete',
|
||||||
|
DELETE_ALL: 'sync-delete-all'
|
||||||
|
},
|
||||||
|
|
||||||
|
HISTORY: {
|
||||||
|
UPDATE_WATCH_PROGRESS: 'sync-history-update-watch-progress'
|
||||||
|
},
|
||||||
|
|
||||||
|
PLAYLISTS: {
|
||||||
|
UPSERT_VIDEO: 'sync-playlists-upsert-video',
|
||||||
|
DELETE_VIDEO: 'sync-playlists-delete-video'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utils
|
||||||
|
const MAIN_PROFILE_ID = 'allChannels'
|
||||||
|
|
||||||
|
export {
|
||||||
|
IpcChannels,
|
||||||
|
DBActions,
|
||||||
|
SyncEvents,
|
||||||
|
MAIN_PROFILE_ID
|
||||||
|
}
|
|
@ -0,0 +1,153 @@
|
||||||
|
import db from '../index'
|
||||||
|
|
||||||
|
class Settings {
|
||||||
|
static find() {
|
||||||
|
return db.settings.find({ _id: { $ne: 'bounds' } })
|
||||||
|
}
|
||||||
|
|
||||||
|
static upsert(_id, value) {
|
||||||
|
return db.settings.update({ _id }, { _id, value }, { upsert: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******************** //
|
||||||
|
// Unique Electron main process handlers
|
||||||
|
static _findAppReadyRelatedSettings() {
|
||||||
|
return db.settings.find({
|
||||||
|
$or: [
|
||||||
|
{ _id: 'disableSmoothScrolling' },
|
||||||
|
{ _id: 'useProxy' },
|
||||||
|
{ _id: 'proxyProtocol' },
|
||||||
|
{ _id: 'proxyHostname' },
|
||||||
|
{ _id: 'proxyPort' }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static _findBounds() {
|
||||||
|
return db.settings.findOne({ _id: 'bounds' })
|
||||||
|
}
|
||||||
|
|
||||||
|
static _updateBounds(value) {
|
||||||
|
return db.settings.update({ _id: 'bounds' }, { _id: 'bounds', value }, { upsert: true })
|
||||||
|
}
|
||||||
|
// ******************** //
|
||||||
|
}
|
||||||
|
|
||||||
|
class History {
|
||||||
|
static find() {
|
||||||
|
return db.history.find({}).sort({ timeWatched: -1 })
|
||||||
|
}
|
||||||
|
|
||||||
|
static upsert(record) {
|
||||||
|
return db.history.update({ videoId: record.videoId }, record, { upsert: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
static updateWatchProgress(videoId, watchProgress) {
|
||||||
|
return db.history.update({ videoId }, { $set: { watchProgress } }, { upsert: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
static delete(videoId) {
|
||||||
|
return db.history.remove({ videoId })
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteAll() {
|
||||||
|
return db.history.remove({}, { multi: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
static persist() {
|
||||||
|
db.history.persistence.compactDatafile()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Profiles {
|
||||||
|
static create(profile) {
|
||||||
|
return db.profiles.insert(profile)
|
||||||
|
}
|
||||||
|
|
||||||
|
static find() {
|
||||||
|
return db.profiles.find({})
|
||||||
|
}
|
||||||
|
|
||||||
|
static upsert(profile) {
|
||||||
|
return db.profiles.update({ _id: profile._id }, profile, { upsert: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
static delete(id) {
|
||||||
|
return db.profiles.remove({ _id: id })
|
||||||
|
}
|
||||||
|
|
||||||
|
static persist() {
|
||||||
|
db.profiles.persistence.compactDatafile()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Playlists {
|
||||||
|
static create(playlists) {
|
||||||
|
return db.playlists.insert(playlists)
|
||||||
|
}
|
||||||
|
|
||||||
|
static find() {
|
||||||
|
return db.playlists.find({})
|
||||||
|
}
|
||||||
|
|
||||||
|
static upsertVideoByPlaylistName(playlistName, videoData) {
|
||||||
|
return db.playlists.update(
|
||||||
|
{ playlistName },
|
||||||
|
{ $push: { videos: videoData } },
|
||||||
|
{ upsert: true }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static upsertVideoIdsByPlaylistId(_id, videoIds) {
|
||||||
|
return db.playlists.update(
|
||||||
|
{ _id },
|
||||||
|
{ $push: { videos: { $each: videoIds } } },
|
||||||
|
{ upsert: true }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static delete(_id) {
|
||||||
|
return db.playlists.remove({ _id, protected: { $ne: true } })
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteVideoIdByPlaylistName(playlistName, videoId) {
|
||||||
|
return db.playlists.update(
|
||||||
|
{ playlistName },
|
||||||
|
{ $pull: { videos: { videoId } } },
|
||||||
|
{ upsert: true }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteVideoIdsByPlaylistName(playlistName, videoIds) {
|
||||||
|
return db.playlists.update(
|
||||||
|
{ playlistName },
|
||||||
|
{ $pull: { videos: { $in: videoIds } } },
|
||||||
|
{ upsert: true }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteAllVideosByPlaylistName(playlistName) {
|
||||||
|
return db.playlists.update(
|
||||||
|
{ playlistName },
|
||||||
|
{ $set: { videos: [] } },
|
||||||
|
{ upsert: true }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteMultiple(ids) {
|
||||||
|
return db.playlists.remove({ _id: { $in: ids }, protected: { $ne: true } })
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteAll() {
|
||||||
|
return db.playlists.remove({ protected: { $ne: true } })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseHandlers = {
|
||||||
|
settings: Settings,
|
||||||
|
history: History,
|
||||||
|
profiles: Profiles,
|
||||||
|
playlists: Playlists
|
||||||
|
}
|
||||||
|
|
||||||
|
export default baseHandlers
|
|
@ -0,0 +1,198 @@
|
||||||
|
import { ipcRenderer } from 'electron'
|
||||||
|
import { IpcChannels, DBActions } from '../../constants'
|
||||||
|
|
||||||
|
class Settings {
|
||||||
|
static find() {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_SETTINGS,
|
||||||
|
{ action: DBActions.GENERAL.FIND }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static upsert(_id, value) {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_SETTINGS,
|
||||||
|
{ action: DBActions.GENERAL.UPSERT, data: { _id, value } }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class History {
|
||||||
|
static find() {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_HISTORY,
|
||||||
|
{ action: DBActions.GENERAL.FIND }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static upsert(record) {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_HISTORY,
|
||||||
|
{ action: DBActions.GENERAL.UPSERT, data: record }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static updateWatchProgress(videoId, watchProgress) {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_HISTORY,
|
||||||
|
{
|
||||||
|
action: DBActions.HISTORY.UPDATE_WATCH_PROGRESS,
|
||||||
|
data: { videoId, watchProgress }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static delete(videoId) {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_HISTORY,
|
||||||
|
{ action: DBActions.GENERAL.DELETE, data: videoId }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteAll() {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_HISTORY,
|
||||||
|
{ action: DBActions.GENERAL.DELETE_ALL }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static persist() {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_HISTORY,
|
||||||
|
{ action: DBActions.GENERAL.PERSIST }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Profiles {
|
||||||
|
static create(profile) {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_PROFILES,
|
||||||
|
{ action: DBActions.GENERAL.CREATE, data: profile }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static find() {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_PROFILES,
|
||||||
|
{ action: DBActions.GENERAL.FIND }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static upsert(profile) {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_PROFILES,
|
||||||
|
{ action: DBActions.GENERAL.UPSERT, data: profile }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static delete(id) {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_PROFILES,
|
||||||
|
{ action: DBActions.GENERAL.DELETE, data: id }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static persist() {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_PROFILES,
|
||||||
|
{ action: DBActions.GENERAL.PERSIST }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Playlists {
|
||||||
|
static create(playlists) {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_PLAYLISTS,
|
||||||
|
{ action: DBActions.GENERAL.CREATE, data: playlists }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static find() {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_PLAYLISTS,
|
||||||
|
{ action: DBActions.GENERAL.FIND }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static upsertVideoByPlaylistName(playlistName, videoData) {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_PLAYLISTS,
|
||||||
|
{
|
||||||
|
action: DBActions.PLAYLISTS.UPSERT_VIDEO,
|
||||||
|
data: { playlistName, videoData }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static upsertVideoIdsByPlaylistId(_id, videoIds) {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_PLAYLISTS,
|
||||||
|
{
|
||||||
|
action: DBActions.PLAYLISTS.UPSERT_VIDEO_IDS,
|
||||||
|
data: { _id, videoIds }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static delete(_id) {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_PLAYLISTS,
|
||||||
|
{ action: DBActions.GENERAL.DELETE, data: _id }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteVideoIdByPlaylistName(playlistName, videoId) {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_PLAYLISTS,
|
||||||
|
{
|
||||||
|
action: DBActions.PLAYLISTS.DELETE_VIDEO_ID,
|
||||||
|
data: { playlistName, videoId }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteVideoIdsByPlaylistName(playlistName, videoIds) {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_PLAYLISTS,
|
||||||
|
{
|
||||||
|
action: DBActions.PLAYLISTS.DELETE_VIDEO_IDS,
|
||||||
|
data: { playlistName, videoIds }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteAllVideosByPlaylistName(playlistName) {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_PLAYLISTS,
|
||||||
|
{
|
||||||
|
action: DBActions.PLAYLISTS.DELETE_ALL_VIDEOS,
|
||||||
|
data: playlistName
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteMultiple(ids) {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_PLAYLISTS,
|
||||||
|
{ action: DBActions.GENERAL.DELETE_MULTIPLE, data: ids }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteAll() {
|
||||||
|
return ipcRenderer.invoke(
|
||||||
|
IpcChannels.DB_PLAYLISTS,
|
||||||
|
{ action: DBActions.GENERAL.DELETE_ALL }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlers = {
|
||||||
|
settings: Settings,
|
||||||
|
history: History,
|
||||||
|
profiles: Profiles,
|
||||||
|
playlists: Playlists
|
||||||
|
}
|
||||||
|
|
||||||
|
export default handlers
|
|
@ -0,0 +1,19 @@
|
||||||
|
let handlers
|
||||||
|
const usingElectron = window?.process?.type === 'renderer'
|
||||||
|
if (usingElectron) {
|
||||||
|
handlers = require('./electron').default
|
||||||
|
} else {
|
||||||
|
handlers = require('./web').default
|
||||||
|
}
|
||||||
|
|
||||||
|
const DBSettingHandlers = handlers.settings
|
||||||
|
const DBHistoryHandlers = handlers.history
|
||||||
|
const DBProfileHandlers = handlers.profiles
|
||||||
|
const DBPlaylistHandlers = handlers.playlists
|
||||||
|
|
||||||
|
export {
|
||||||
|
DBSettingHandlers,
|
||||||
|
DBHistoryHandlers,
|
||||||
|
DBProfileHandlers,
|
||||||
|
DBPlaylistHandlers
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
import baseHandlers from './base'
|
||||||
|
|
||||||
|
// TODO: Syncing
|
||||||
|
// Syncing on the web would involve a different implementation
|
||||||
|
// to the electron one (obviously)
|
||||||
|
// One idea would be to use a watcher-like mechanism on
|
||||||
|
// localStorage or IndexedDB to inform other tabs on the changes
|
||||||
|
// that have occurred in other tabs
|
||||||
|
//
|
||||||
|
// NOTE: NeDB uses `localForage` on the browser
|
||||||
|
// https://www.npmjs.com/package/localforage
|
||||||
|
|
||||||
|
class Settings {
|
||||||
|
static find() {
|
||||||
|
return baseHandlers.settings.find()
|
||||||
|
}
|
||||||
|
|
||||||
|
static upsert(_id, value) {
|
||||||
|
return baseHandlers.settings.upsert(_id, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class History {
|
||||||
|
static find() {
|
||||||
|
return baseHandlers.history.find()
|
||||||
|
}
|
||||||
|
|
||||||
|
static upsert(record) {
|
||||||
|
return baseHandlers.history.upsert(record)
|
||||||
|
}
|
||||||
|
|
||||||
|
static updateWatchProgress(videoId, watchProgress) {
|
||||||
|
return baseHandlers.history.updateWatchProgress(videoId, watchProgress)
|
||||||
|
}
|
||||||
|
|
||||||
|
static delete(videoId) {
|
||||||
|
return baseHandlers.history.delete(videoId)
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteAll() {
|
||||||
|
return baseHandlers.history.deleteAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
static persist() {
|
||||||
|
baseHandlers.history.persist()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Profiles {
|
||||||
|
static create(profile) {
|
||||||
|
return baseHandlers.profiles.create(profile)
|
||||||
|
}
|
||||||
|
|
||||||
|
static find() {
|
||||||
|
return baseHandlers.profiles.find()
|
||||||
|
}
|
||||||
|
|
||||||
|
static upsert(profile) {
|
||||||
|
return baseHandlers.profiles.upsert(profile)
|
||||||
|
}
|
||||||
|
|
||||||
|
static delete(id) {
|
||||||
|
return baseHandlers.profiles.delete(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
static persist() {
|
||||||
|
baseHandlers.profiles.persist()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Playlists {
|
||||||
|
static create(playlists) {
|
||||||
|
return baseHandlers.playlists.create(playlists)
|
||||||
|
}
|
||||||
|
|
||||||
|
static find() {
|
||||||
|
return baseHandlers.playlists.find()
|
||||||
|
}
|
||||||
|
|
||||||
|
static upsertVideoByPlaylistName(playlistName, videoData) {
|
||||||
|
return baseHandlers.playlists.upsertVideoByPlaylistName(playlistName, videoData)
|
||||||
|
}
|
||||||
|
|
||||||
|
static upsertVideoIdsByPlaylistId(_id, videoIds) {
|
||||||
|
return baseHandlers.playlists.upsertVideoIdsByPlaylistId(_id, videoIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
static delete(_id) {
|
||||||
|
return baseHandlers.playlists.delete(_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteVideoIdByPlaylistName(playlistName, videoId) {
|
||||||
|
return baseHandlers.playlists.deleteVideoIdByPlaylistName(playlistName, videoId)
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteVideoIdsByPlaylistName(playlistName, videoIds) {
|
||||||
|
return baseHandlers.playlists.deleteVideoIdsByPlaylistName(playlistName, videoIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteAllVideosByPlaylistName(playlistName) {
|
||||||
|
return baseHandlers.playlists.deleteAllVideosByPlaylistName(playlistName)
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteMultiple(ids) {
|
||||||
|
return baseHandlers.playlists.deleteMultiple(ids)
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteAll() {
|
||||||
|
return baseHandlers.playlists.deleteAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlers = {
|
||||||
|
settings: Settings,
|
||||||
|
history: History,
|
||||||
|
profiles: Profiles,
|
||||||
|
playlists: Playlists
|
||||||
|
}
|
||||||
|
|
||||||
|
export default handlers
|
|
@ -0,0 +1,21 @@
|
||||||
|
import Datastore from 'nedb-promises'
|
||||||
|
|
||||||
|
let dbPath = null
|
||||||
|
|
||||||
|
const isElectronMain = !!process?.versions?.electron
|
||||||
|
if (isElectronMain) {
|
||||||
|
const { app } = require('electron')
|
||||||
|
const { join } = require('path')
|
||||||
|
const userDataPath = app.getPath('userData') // This is based on the user's OS
|
||||||
|
dbPath = (dbName) => join(userDataPath, `${dbName}.db`)
|
||||||
|
} else {
|
||||||
|
dbPath = (dbName) => `${dbName}.db`
|
||||||
|
}
|
||||||
|
|
||||||
|
const db = {}
|
||||||
|
db.settings = Datastore.create({ filename: dbPath('settings'), autoload: true })
|
||||||
|
db.profiles = Datastore.create({ filename: dbPath('profiles'), autoload: true })
|
||||||
|
db.playlists = Datastore.create({ filename: dbPath('playlists'), autoload: true })
|
||||||
|
db.history = Datastore.create({ filename: dbPath('history'), autoload: true })
|
||||||
|
|
||||||
|
export default db
|
|
@ -2,10 +2,12 @@ import {
|
||||||
app, BrowserWindow, dialog, Menu, ipcMain,
|
app, BrowserWindow, dialog, Menu, ipcMain,
|
||||||
powerSaveBlocker, screen, session, shell
|
powerSaveBlocker, screen, session, shell
|
||||||
} from 'electron'
|
} from 'electron'
|
||||||
import Datastore from 'nedb-promises'
|
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import cp from 'child_process'
|
import cp from 'child_process'
|
||||||
|
|
||||||
|
import { IpcChannels, DBActions, SyncEvents } from '../constants'
|
||||||
|
import baseHandlers from '../datastores/handlers/base'
|
||||||
|
|
||||||
if (process.argv.includes('--version')) {
|
if (process.argv.includes('--version')) {
|
||||||
console.log(`v${app.getVersion()}`)
|
console.log(`v${app.getVersion()}`)
|
||||||
app.exit()
|
app.exit()
|
||||||
|
@ -29,13 +31,6 @@ function runApp() {
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
const localDataStorage = app.getPath('userData') // Grabs the userdata directory based on the user's OS
|
|
||||||
|
|
||||||
const settingsDb = Datastore.create({
|
|
||||||
filename: localDataStorage + '/settings.db',
|
|
||||||
autoload: true
|
|
||||||
})
|
|
||||||
|
|
||||||
// disable electron warning
|
// disable electron warning
|
||||||
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true'
|
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true'
|
||||||
const isDev = process.env.NODE_ENV === 'development'
|
const isDev = process.env.NODE_ENV === 'development'
|
||||||
|
@ -93,15 +88,7 @@ function runApp() {
|
||||||
app.on('ready', async (_, __) => {
|
app.on('ready', async (_, __) => {
|
||||||
let docArray
|
let docArray
|
||||||
try {
|
try {
|
||||||
docArray = await settingsDb.find({
|
docArray = await baseHandlers.settings._findAppReadyRelatedSettings()
|
||||||
$or: [
|
|
||||||
{ _id: 'disableSmoothScrolling' },
|
|
||||||
{ _id: 'useProxy' },
|
|
||||||
{ _id: 'proxyProtocol' },
|
|
||||||
{ _id: 'proxyHostname' },
|
|
||||||
{ _id: 'proxyPort' }
|
|
||||||
]
|
|
||||||
})
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
app.exit()
|
app.exit()
|
||||||
|
@ -241,7 +228,7 @@ function runApp() {
|
||||||
height: 800
|
height: 800
|
||||||
})
|
})
|
||||||
|
|
||||||
const boundsDoc = await settingsDb.findOne({ _id: 'bounds' })
|
const boundsDoc = await baseHandlers.settings._findBounds()
|
||||||
if (typeof boundsDoc?.value === 'object') {
|
if (typeof boundsDoc?.value === 'object') {
|
||||||
const { maximized, ...bounds } = boundsDoc.value
|
const { maximized, ...bounds } = boundsDoc.value
|
||||||
const allDisplaysSummaryWidth = screen
|
const allDisplaysSummaryWidth = screen
|
||||||
|
@ -296,11 +283,7 @@ function runApp() {
|
||||||
maximized: newWindow.isMaximized()
|
maximized: newWindow.isMaximized()
|
||||||
}
|
}
|
||||||
|
|
||||||
await settingsDb.update(
|
await baseHandlers.settings._updateBounds(value)
|
||||||
{ _id: 'bounds' },
|
|
||||||
{ _id: 'bounds', value },
|
|
||||||
{ upsert: true }
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
newWindow.once('closed', () => {
|
newWindow.once('closed', () => {
|
||||||
|
@ -354,70 +337,292 @@ function runApp() {
|
||||||
app.quit()
|
app.quit()
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on('enableProxy', (_, url) => {
|
ipcMain.on(IpcChannels.ENABLE_PROXY, (_, url) => {
|
||||||
console.log(url)
|
console.log(url)
|
||||||
session.defaultSession.setProxy({
|
session.defaultSession.setProxy({
|
||||||
proxyRules: url
|
proxyRules: url
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on('disableProxy', () => {
|
ipcMain.on(IpcChannels.DISABLE_PROXY, () => {
|
||||||
session.defaultSession.setProxy({})
|
session.defaultSession.setProxy({})
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on('openExternalLink', (_, url) => {
|
ipcMain.on(IpcChannels.OPEN_EXTERNAL_LINK, (_, url) => {
|
||||||
if (typeof url === 'string') shell.openExternal(url)
|
if (typeof url === 'string') shell.openExternal(url)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('getSystemLocale', () => {
|
ipcMain.handle(IpcChannels.GET_SYSTEM_LOCALE, () => {
|
||||||
return app.getLocale()
|
return app.getLocale()
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('getUserDataPath', () => {
|
ipcMain.handle(IpcChannels.GET_USER_DATA_PATH, () => {
|
||||||
return app.getPath('userData')
|
return app.getPath('userData')
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on('getUserDataPathSync', (event) => {
|
ipcMain.on(IpcChannels.GET_USER_DATA_PATH_SYNC, (event) => {
|
||||||
event.returnValue = app.getPath('userData')
|
event.returnValue = app.getPath('userData')
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('showOpenDialog', async (_, options) => {
|
ipcMain.handle(IpcChannels.SHOW_OPEN_DIALOG, async (_, options) => {
|
||||||
return await dialog.showOpenDialog(options)
|
return await dialog.showOpenDialog(options)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('showSaveDialog', async (_, options) => {
|
ipcMain.handle(IpcChannels.SHOW_SAVE_DIALOG, async (_, options) => {
|
||||||
return await dialog.showSaveDialog(options)
|
return await dialog.showSaveDialog(options)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on('stopPowerSaveBlocker', (_, id) => {
|
ipcMain.on(IpcChannels.STOP_POWER_SAVE_BLOCKER, (_, id) => {
|
||||||
powerSaveBlocker.stop(id)
|
powerSaveBlocker.stop(id)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('startPowerSaveBlocker', (_, type) => {
|
ipcMain.handle(IpcChannels.START_POWER_SAVE_BLOCKER, (_) => {
|
||||||
return powerSaveBlocker.start(type)
|
return powerSaveBlocker.start('prevent-display-sleep')
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on('createNewWindow', () => {
|
ipcMain.on(IpcChannels.CREATE_NEW_WINDOW, () => {
|
||||||
createWindow(false)
|
createWindow(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on('syncWindows', (event, payload) => {
|
ipcMain.on(IpcChannels.OPEN_IN_EXTERNAL_PLAYER, (_, payload) => {
|
||||||
const otherWindows = BrowserWindow.getAllWindows().filter(
|
|
||||||
(window) => {
|
|
||||||
return window.webContents.id !== event.sender.id
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
for (const window of otherWindows) {
|
|
||||||
window.webContents.send('syncWindows', payload)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcMain.on('openInExternalPlayer', (_, payload) => {
|
|
||||||
const child = cp.spawn(payload.executable, payload.args, { detached: true, stdio: 'ignore' })
|
const child = cp.spawn(payload.executable, payload.args, { detached: true, stdio: 'ignore' })
|
||||||
child.unref()
|
child.unref()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ************************************************* //
|
||||||
|
// DB related IPC calls
|
||||||
|
// *********** //
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
ipcMain.handle(IpcChannels.DB_SETTINGS, async (event, { action, data }) => {
|
||||||
|
try {
|
||||||
|
switch (action) {
|
||||||
|
case DBActions.GENERAL.FIND:
|
||||||
|
return await baseHandlers.settings.find()
|
||||||
|
|
||||||
|
case DBActions.GENERAL.UPSERT:
|
||||||
|
await baseHandlers.settings.upsert(data._id, data.value)
|
||||||
|
syncOtherWindows(
|
||||||
|
IpcChannels.SYNC_SETTINGS,
|
||||||
|
event,
|
||||||
|
{ event: SyncEvents.GENERAL.UPSERT, data }
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
|
||||||
|
default:
|
||||||
|
// eslint-disable-next-line no-throw-literal
|
||||||
|
throw 'invalid settings db action'
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if (typeof err === 'string') throw err
|
||||||
|
else throw err.toString()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// *********** //
|
||||||
|
// History
|
||||||
|
ipcMain.handle(IpcChannels.DB_HISTORY, async (event, { action, data }) => {
|
||||||
|
try {
|
||||||
|
switch (action) {
|
||||||
|
case DBActions.GENERAL.FIND:
|
||||||
|
return await baseHandlers.history.find()
|
||||||
|
|
||||||
|
case DBActions.GENERAL.UPSERT:
|
||||||
|
await baseHandlers.history.upsert(data)
|
||||||
|
syncOtherWindows(
|
||||||
|
IpcChannels.SYNC_HISTORY,
|
||||||
|
event,
|
||||||
|
{ event: SyncEvents.GENERAL.UPSERT, data }
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
|
||||||
|
case DBActions.HISTORY.UPDATE_WATCH_PROGRESS:
|
||||||
|
await baseHandlers.history.updateWatchProgress(data.videoId, data.watchProgress)
|
||||||
|
syncOtherWindows(
|
||||||
|
IpcChannels.SYNC_HISTORY,
|
||||||
|
event,
|
||||||
|
{ event: SyncEvents.HISTORY.UPDATE_WATCH_PROGRESS, data }
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
|
||||||
|
case DBActions.GENERAL.DELETE:
|
||||||
|
await baseHandlers.history.delete(data)
|
||||||
|
syncOtherWindows(
|
||||||
|
IpcChannels.SYNC_HISTORY,
|
||||||
|
event,
|
||||||
|
{ event: SyncEvents.GENERAL.DELETE, data }
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
|
||||||
|
case DBActions.GENERAL.DELETE_ALL:
|
||||||
|
await baseHandlers.history.deleteAll()
|
||||||
|
syncOtherWindows(
|
||||||
|
IpcChannels.SYNC_HISTORY,
|
||||||
|
event,
|
||||||
|
{ event: SyncEvents.GENERAL.DELETE_ALL }
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
|
||||||
|
case DBActions.GENERAL.PERSIST:
|
||||||
|
baseHandlers.history.persist()
|
||||||
|
return null
|
||||||
|
|
||||||
|
default:
|
||||||
|
// eslint-disable-next-line no-throw-literal
|
||||||
|
throw 'invalid history db action'
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if (typeof err === 'string') throw err
|
||||||
|
else throw err.toString()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// *********** //
|
||||||
|
// Profiles
|
||||||
|
ipcMain.handle(IpcChannels.DB_PROFILES, async (event, { action, data }) => {
|
||||||
|
try {
|
||||||
|
switch (action) {
|
||||||
|
case DBActions.GENERAL.CREATE: {
|
||||||
|
const newProfile = await baseHandlers.profiles.create(data)
|
||||||
|
syncOtherWindows(
|
||||||
|
IpcChannels.SYNC_PROFILES,
|
||||||
|
event,
|
||||||
|
{ event: SyncEvents.GENERAL.CREATE, data: newProfile }
|
||||||
|
)
|
||||||
|
return newProfile
|
||||||
|
}
|
||||||
|
|
||||||
|
case DBActions.GENERAL.FIND:
|
||||||
|
return await baseHandlers.profiles.find()
|
||||||
|
|
||||||
|
case DBActions.GENERAL.UPSERT:
|
||||||
|
await baseHandlers.profiles.upsert(data)
|
||||||
|
syncOtherWindows(
|
||||||
|
IpcChannels.SYNC_PROFILES,
|
||||||
|
event,
|
||||||
|
{ event: SyncEvents.GENERAL.UPSERT, data }
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
|
||||||
|
case DBActions.GENERAL.DELETE:
|
||||||
|
await baseHandlers.profiles.delete(data)
|
||||||
|
syncOtherWindows(
|
||||||
|
IpcChannels.SYNC_PROFILES,
|
||||||
|
event,
|
||||||
|
{ event: SyncEvents.GENERAL.DELETE, data }
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
|
||||||
|
case DBActions.GENERAL.PERSIST:
|
||||||
|
baseHandlers.profiles.persist()
|
||||||
|
return null
|
||||||
|
|
||||||
|
default:
|
||||||
|
// eslint-disable-next-line no-throw-literal
|
||||||
|
throw 'invalid profile db action'
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if (typeof err === 'string') throw err
|
||||||
|
else throw err.toString()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// *********** //
|
||||||
|
// Playlists
|
||||||
|
// ! NOTE: A lot of these actions are currently not used for anything
|
||||||
|
// As such, only the currently used actions have synchronization implemented
|
||||||
|
// The remaining should have it implemented only when playlists
|
||||||
|
// get fully implemented into the app
|
||||||
|
ipcMain.handle(IpcChannels.DB_PLAYLISTS, async (event, { action, data }) => {
|
||||||
|
try {
|
||||||
|
switch (action) {
|
||||||
|
case DBActions.GENERAL.CREATE:
|
||||||
|
await baseHandlers.playlists.create(data)
|
||||||
|
// TODO: Syncing (implement only when it starts being used)
|
||||||
|
// syncOtherWindows(IpcChannels.SYNC_PLAYLISTS, event, { event: '_', data })
|
||||||
|
return null
|
||||||
|
|
||||||
|
case DBActions.GENERAL.FIND:
|
||||||
|
return await baseHandlers.playlists.find()
|
||||||
|
|
||||||
|
case DBActions.PLAYLISTS.UPSERT_VIDEO:
|
||||||
|
await baseHandlers.playlists.upsertVideoByPlaylistName(data.playlistName, data.videoData)
|
||||||
|
syncOtherWindows(
|
||||||
|
IpcChannels.SYNC_PLAYLISTS,
|
||||||
|
event,
|
||||||
|
{ event: SyncEvents.PLAYLISTS.UPSERT_VIDEO, data }
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
|
||||||
|
case DBActions.PLAYLISTS.UPSERT_VIDEO_IDS:
|
||||||
|
await baseHandlers.playlists.upsertVideoIdsByPlaylistId(data._id, data.videoIds)
|
||||||
|
// TODO: Syncing (implement only when it starts being used)
|
||||||
|
// syncOtherWindows(IpcChannels.SYNC_PLAYLISTS, event, { event: '_', data })
|
||||||
|
return null
|
||||||
|
|
||||||
|
case DBActions.GENERAL.DELETE:
|
||||||
|
await baseHandlers.playlists.delete(data)
|
||||||
|
// TODO: Syncing (implement only when it starts being used)
|
||||||
|
// syncOtherWindows(IpcChannels.SYNC_PLAYLISTS, event, { event: '_', data })
|
||||||
|
return null
|
||||||
|
|
||||||
|
case DBActions.PLAYLISTS.DELETE_VIDEO_ID:
|
||||||
|
await baseHandlers.playlists.deleteVideoIdByPlaylistName(data.playlistName, data.videoId)
|
||||||
|
syncOtherWindows(
|
||||||
|
IpcChannels.SYNC_PLAYLISTS,
|
||||||
|
event,
|
||||||
|
{ event: SyncEvents.PLAYLISTS.DELETE_VIDEO, data }
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
|
||||||
|
case DBActions.PLAYLISTS.DELETE_VIDEO_IDS:
|
||||||
|
await baseHandlers.playlists.deleteVideoIdsByPlaylistName(data.playlistName, data.videoIds)
|
||||||
|
// TODO: Syncing (implement only when it starts being used)
|
||||||
|
// syncOtherWindows(IpcChannels.SYNC_PLAYLISTS, event, { event: '_', data })
|
||||||
|
return null
|
||||||
|
|
||||||
|
case DBActions.PLAYLISTS.DELETE_ALL_VIDEOS:
|
||||||
|
await baseHandlers.playlists.deleteAllVideosByPlaylistName(data)
|
||||||
|
// TODO: Syncing (implement only when it starts being used)
|
||||||
|
// syncOtherWindows(IpcChannels.SYNC_PLAYLISTS, event, { event: '_', data })
|
||||||
|
return null
|
||||||
|
|
||||||
|
case DBActions.GENERAL.DELETE_MULTIPLE:
|
||||||
|
await baseHandlers.playlists.deleteMultiple(data)
|
||||||
|
// TODO: Syncing (implement only when it starts being used)
|
||||||
|
// syncOtherWindows(IpcChannels.SYNC_PLAYLISTS, event, { event: '_', data })
|
||||||
|
return null
|
||||||
|
|
||||||
|
case DBActions.GENERAL.DELETE_ALL:
|
||||||
|
await baseHandlers.playlists.deleteAll()
|
||||||
|
// TODO: Syncing (implement only when it starts being used)
|
||||||
|
// syncOtherWindows(IpcChannels.SYNC_PLAYLISTS, event, { event: '_', data })
|
||||||
|
return null
|
||||||
|
|
||||||
|
default:
|
||||||
|
// eslint-disable-next-line no-throw-literal
|
||||||
|
throw 'invalid playlist db action'
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if (typeof err === 'string') throw err
|
||||||
|
else throw err.toString()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// *********** //
|
||||||
|
|
||||||
|
function syncOtherWindows(channel, event, payload) {
|
||||||
|
const otherWindows = BrowserWindow.getAllWindows().filter((window) => {
|
||||||
|
return window.webContents.id !== event.sender.id
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const window of otherWindows) {
|
||||||
|
window.webContents.send(channel, payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************************************************* //
|
||||||
|
|
||||||
app.once('window-all-closed', () => {
|
app.once('window-all-closed', () => {
|
||||||
// Clear cache and storage if it's the last window
|
// Clear cache and storage if it's the last window
|
||||||
session.defaultSession.clearCache()
|
session.defaultSession.clearCache()
|
||||||
|
|
|
@ -92,9 +92,6 @@ export default Vue.extend({
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
activeProfile: function () {
|
|
||||||
return this.$store.getters.getActiveProfile
|
|
||||||
},
|
|
||||||
defaultProfile: function () {
|
defaultProfile: function () {
|
||||||
return this.$store.getters.getDefaultProfile
|
return this.$store.getters.getDefaultProfile
|
||||||
},
|
},
|
||||||
|
@ -142,7 +139,7 @@ export default Vue.extend({
|
||||||
if (this.usingElectron) {
|
if (this.usingElectron) {
|
||||||
console.log('User is using Electron')
|
console.log('User is using Electron')
|
||||||
ipcRenderer = require('electron').ipcRenderer
|
ipcRenderer = require('electron').ipcRenderer
|
||||||
this.setupListenerToSyncWindows()
|
this.setupListenersToSyncWindows()
|
||||||
this.activateKeyboardShortcuts()
|
this.activateKeyboardShortcuts()
|
||||||
this.openAllLinksExternally()
|
this.openAllLinksExternally()
|
||||||
this.enableOpenUrl()
|
this.enableOpenUrl()
|
||||||
|
@ -468,7 +465,7 @@ export default Vue.extend({
|
||||||
'getExternalPlayerCmdArgumentsData',
|
'getExternalPlayerCmdArgumentsData',
|
||||||
'fetchInvidiousInstances',
|
'fetchInvidiousInstances',
|
||||||
'setRandomCurrentInvidiousInstance',
|
'setRandomCurrentInvidiousInstance',
|
||||||
'setupListenerToSyncWindows'
|
'setupListenersToSyncWindows'
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,6 +5,7 @@ import FtButton from '../ft-button/ft-button.vue'
|
||||||
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
|
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
|
||||||
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
||||||
import FtPrompt from '../ft-prompt/ft-prompt.vue'
|
import FtPrompt from '../ft-prompt/ft-prompt.vue'
|
||||||
|
import { MAIN_PROFILE_ID } from '../../../constants'
|
||||||
|
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import { opmlToJSON } from 'opml-to-json'
|
import { opmlToJSON } from 'opml-to-json'
|
||||||
|
@ -165,7 +166,7 @@ export default Vue.extend({
|
||||||
message: message
|
message: message
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
if (profileObject.name === 'All Channels' || profileObject._id === 'allChannels') {
|
if (profileObject.name === 'All Channels' || profileObject._id === MAIN_PROFILE_ID) {
|
||||||
primaryProfile.subscriptions = primaryProfile.subscriptions.concat(profileObject.subscriptions)
|
primaryProfile.subscriptions = primaryProfile.subscriptions.concat(profileObject.subscriptions)
|
||||||
primaryProfile.subscriptions = primaryProfile.subscriptions.filter((sub, index) => {
|
primaryProfile.subscriptions = primaryProfile.subscriptions.filter((sub, index) => {
|
||||||
const profileIndex = primaryProfile.subscriptions.findIndex((x) => {
|
const profileIndex = primaryProfile.subscriptions.findIndex((x) => {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import FtPrompt from '../../components/ft-prompt/ft-prompt.vue'
|
||||||
import FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'
|
import FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'
|
||||||
import FtInput from '../../components/ft-input/ft-input.vue'
|
import FtInput from '../../components/ft-input/ft-input.vue'
|
||||||
import FtButton from '../../components/ft-button/ft-button.vue'
|
import FtButton from '../../components/ft-button/ft-button.vue'
|
||||||
|
import { MAIN_PROFILE_ID } from '../../../constants'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'FtProfileEdit',
|
name: 'FtProfileEdit',
|
||||||
|
@ -40,6 +41,9 @@ export default Vue.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
isMainProfile: function () {
|
||||||
|
return this.profileId === MAIN_PROFILE_ID
|
||||||
|
},
|
||||||
colorValues: function () {
|
colorValues: function () {
|
||||||
return this.$store.getters.getColorValues
|
return this.$store.getters.getColorValues
|
||||||
},
|
},
|
||||||
|
@ -70,7 +74,7 @@ export default Vue.extend({
|
||||||
this.profileTextColor = await this.calculateColorLuminance(val)
|
this.profileTextColor = await this.calculateColorLuminance(val)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted: async function () {
|
created: function () {
|
||||||
this.profileId = this.$route.params.id
|
this.profileId = this.$route.params.id
|
||||||
this.profileName = this.profile.name
|
this.profileName = this.profile.name
|
||||||
this.profileBgColor = this.profile.bgColor
|
this.profileBgColor = this.profile.bgColor
|
||||||
|
@ -109,9 +113,8 @@ export default Vue.extend({
|
||||||
|
|
||||||
console.log(profile)
|
console.log(profile)
|
||||||
|
|
||||||
this.updateProfile(profile)
|
|
||||||
|
|
||||||
if (this.isNew) {
|
if (this.isNew) {
|
||||||
|
this.createProfile(profile)
|
||||||
this.showToast({
|
this.showToast({
|
||||||
message: this.$t('Profile.Profile has been created')
|
message: this.$t('Profile.Profile has been created')
|
||||||
})
|
})
|
||||||
|
@ -119,6 +122,7 @@ export default Vue.extend({
|
||||||
path: '/settings/profile/'
|
path: '/settings/profile/'
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
this.updateProfile(profile)
|
||||||
this.showToast({
|
this.showToast({
|
||||||
message: this.$t('Profile.Profile has been updated')
|
message: this.$t('Profile.Profile has been updated')
|
||||||
})
|
})
|
||||||
|
@ -134,20 +138,22 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
deleteProfile: function () {
|
deleteProfile: function () {
|
||||||
|
if (this.activeProfile._id === this.profileId) {
|
||||||
|
this.updateActiveProfile(MAIN_PROFILE_ID)
|
||||||
|
}
|
||||||
|
|
||||||
this.removeProfile(this.profileId)
|
this.removeProfile(this.profileId)
|
||||||
|
|
||||||
const message = this.$t('Profile.Removed $ from your profiles').replace('$', this.profileName)
|
const message = this.$t('Profile.Removed $ from your profiles').replace('$', this.profileName)
|
||||||
this.showToast({
|
this.showToast({ message })
|
||||||
message: message
|
|
||||||
})
|
|
||||||
if (this.defaultProfile === this.profileId) {
|
if (this.defaultProfile === this.profileId) {
|
||||||
this.updateDefaultProfile('allChannels')
|
this.updateDefaultProfile(MAIN_PROFILE_ID)
|
||||||
this.showToast({
|
this.showToast({
|
||||||
message: this.$t('Profile.Your default profile has been changed to your primary profile')
|
message: this.$t('Profile.Your default profile has been changed to your primary profile')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (this.profileList[this.activeProfile]._id === this.profileId) {
|
|
||||||
this.updateActiveProfile(0)
|
|
||||||
}
|
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
path: '/settings/profile/'
|
path: '/settings/profile/'
|
||||||
})
|
})
|
||||||
|
@ -155,6 +161,7 @@ export default Vue.extend({
|
||||||
|
|
||||||
...mapActions([
|
...mapActions([
|
||||||
'showToast',
|
'showToast',
|
||||||
|
'createProfile',
|
||||||
'updateProfile',
|
'updateProfile',
|
||||||
'removeProfile',
|
'removeProfile',
|
||||||
'updateDefaultProfile',
|
'updateDefaultProfile',
|
||||||
|
|
|
@ -77,7 +77,7 @@
|
||||||
@click="setDefaultProfile"
|
@click="setDefaultProfile"
|
||||||
/>
|
/>
|
||||||
<ft-button
|
<ft-button
|
||||||
v-if="profileId !== 'allChannels' && !isNew"
|
v-if="!isMainProfile && !isNew"
|
||||||
:label="$t('Profile.Delete Profile')"
|
:label="$t('Profile.Delete Profile')"
|
||||||
text-color="var(--text-with-main-color)"
|
text-color="var(--text-with-main-color)"
|
||||||
background-color="var(--primary-color)"
|
background-color="var(--primary-color)"
|
||||||
|
|
|
@ -67,22 +67,20 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
setActiveProfile: function (profile) {
|
setActiveProfile: function (profile) {
|
||||||
if (this.profileList[this.activeProfile]._id === profile._id) {
|
if (this.activeProfile._id !== profile._id) {
|
||||||
return
|
const targetProfile = this.profileList.find((x) => {
|
||||||
}
|
|
||||||
const index = this.profileList.findIndex((x) => {
|
|
||||||
return x._id === profile._id
|
return x._id === profile._id
|
||||||
})
|
})
|
||||||
|
|
||||||
if (index === -1) {
|
if (targetProfile) {
|
||||||
return
|
this.updateActiveProfile(targetProfile._id)
|
||||||
}
|
|
||||||
this.updateActiveProfile(index)
|
|
||||||
const message = this.$t('Profile.$ is now the active profile').replace('$', profile.name)
|
const message = this.$t('Profile.$ is now the active profile').replace('$', profile.name)
|
||||||
this.showToast({
|
this.showToast({ message })
|
||||||
message: message
|
}
|
||||||
})
|
}
|
||||||
$('#profileList').focusout()
|
|
||||||
|
$('#profileList').trigger('focusout')
|
||||||
},
|
},
|
||||||
|
|
||||||
...mapActions([
|
...mapActions([
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="colorOption"
|
class="colorOption"
|
||||||
:style="{ background: profileList[activeProfile].bgColor, color: profileList[activeProfile].textColor }"
|
:style="{ background: activeProfile.bgColor, color: activeProfile.textColor }"
|
||||||
@click="toggleProfileList"
|
@click="toggleProfileList"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="initial"
|
class="initial"
|
||||||
>
|
>
|
||||||
{{ profileInitials[activeProfile] }}
|
{{ activeProfileInitial }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ft-card
|
<ft-card
|
||||||
|
|
|
@ -13,6 +13,8 @@ import 'videojs-contrib-quality-levels'
|
||||||
import 'videojs-http-source-selector'
|
import 'videojs-http-source-selector'
|
||||||
import { ipcRenderer } from 'electron'
|
import { ipcRenderer } from 'electron'
|
||||||
|
|
||||||
|
import { IpcChannels } from '../../../constants'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'FtVideoPlayer',
|
name: 'FtVideoPlayer',
|
||||||
components: {
|
components: {
|
||||||
|
@ -32,7 +34,7 @@ export default Vue.extend({
|
||||||
|
|
||||||
if (this.usingElectron && this.powerSaveBlocker !== null) {
|
if (this.usingElectron && this.powerSaveBlocker !== null) {
|
||||||
const { ipcRenderer } = require('electron')
|
const { ipcRenderer } = require('electron')
|
||||||
ipcRenderer.send('stopPowerSaveBlocker', this.powerSaveBlocker)
|
ipcRenderer.send(IpcChannels.STOP_POWER_SAVE_BLOCKER, this.powerSaveBlocker)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
@ -288,7 +290,7 @@ export default Vue.extend({
|
||||||
|
|
||||||
if (this.usingElectron && this.powerSaveBlocker !== null) {
|
if (this.usingElectron && this.powerSaveBlocker !== null) {
|
||||||
const { ipcRenderer } = require('electron')
|
const { ipcRenderer } = require('electron')
|
||||||
ipcRenderer.send('stopPowerSaveBlocker', this.powerSaveBlocker)
|
ipcRenderer.send(IpcChannels.STOP_POWER_SAVE_BLOCKER, this.powerSaveBlocker)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -427,14 +429,14 @@ export default Vue.extend({
|
||||||
if (this.usingElectron) {
|
if (this.usingElectron) {
|
||||||
const { ipcRenderer } = require('electron')
|
const { ipcRenderer } = require('electron')
|
||||||
this.powerSaveBlocker =
|
this.powerSaveBlocker =
|
||||||
await ipcRenderer.invoke('startPowerSaveBlocker', 'prevent-display-sleep')
|
await ipcRenderer.invoke(IpcChannels.START_POWER_SAVE_BLOCKER)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.player.on('pause', function () {
|
this.player.on('pause', function () {
|
||||||
if (this.usingElectron && this.powerSaveBlocker !== null) {
|
if (this.usingElectron && this.powerSaveBlocker !== null) {
|
||||||
const { ipcRenderer } = require('electron')
|
const { ipcRenderer } = require('electron')
|
||||||
ipcRenderer.send('stopPowerSaveBlocker', this.powerSaveBlocker)
|
ipcRenderer.send(IpcChannels.STOP_POWER_SAVE_BLOCKER, this.powerSaveBlocker)
|
||||||
this.powerSaveBlocker = null
|
this.powerSaveBlocker = null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,6 +5,7 @@ import FtButton from '../ft-button/ft-button.vue'
|
||||||
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
|
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
|
||||||
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
||||||
import FtPrompt from '../ft-prompt/ft-prompt.vue'
|
import FtPrompt from '../ft-prompt/ft-prompt.vue'
|
||||||
|
import { MAIN_PROFILE_ID } from '../../../constants'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'PrivacySettings',
|
name: 'PrivacySettings',
|
||||||
|
@ -91,13 +92,13 @@ export default Vue.extend({
|
||||||
handleRemoveSubscriptions: function (option) {
|
handleRemoveSubscriptions: function (option) {
|
||||||
this.showRemoveSubscriptionsPrompt = false
|
this.showRemoveSubscriptionsPrompt = false
|
||||||
|
|
||||||
this.updateActiveProfile(0)
|
this.updateActiveProfile(MAIN_PROFILE_ID)
|
||||||
|
|
||||||
if (option === 'yes') {
|
if (option === 'yes') {
|
||||||
this.profileList.forEach((profile) => {
|
this.profileList.forEach((profile) => {
|
||||||
if (profile._id === 'allChannels') {
|
if (profile._id === MAIN_PROFILE_ID) {
|
||||||
const newProfile = {
|
const newProfile = {
|
||||||
_id: 'allChannels',
|
_id: MAIN_PROFILE_ID,
|
||||||
name: profile.name,
|
name: profile.name,
|
||||||
bgColor: profile.bgColor,
|
bgColor: profile.bgColor,
|
||||||
textColor: profile.textColor,
|
textColor: profile.textColor,
|
||||||
|
|
|
@ -14,6 +14,8 @@ import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
||||||
import { ipcRenderer } from 'electron'
|
import { ipcRenderer } from 'electron'
|
||||||
import debounce from 'lodash.debounce'
|
import debounce from 'lodash.debounce'
|
||||||
|
|
||||||
|
import { IpcChannels } from '../../../constants'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'ProxySettings',
|
name: 'ProxySettings',
|
||||||
components: {
|
components: {
|
||||||
|
@ -111,11 +113,11 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
enableProxy: function () {
|
enableProxy: function () {
|
||||||
ipcRenderer.send('enableProxy', this.proxyUrl)
|
ipcRenderer.send(IpcChannels.ENABLE_PROXY, this.proxyUrl)
|
||||||
},
|
},
|
||||||
|
|
||||||
disableProxy: function () {
|
disableProxy: function () {
|
||||||
ipcRenderer.send('disableProxy')
|
ipcRenderer.send(IpcChannels.DISABLE_PROXY)
|
||||||
},
|
},
|
||||||
|
|
||||||
testProxy: function () {
|
testProxy: function () {
|
||||||
|
|
|
@ -25,7 +25,7 @@ export default Vue.extend({
|
||||||
return this.$store.getters.getActiveProfile
|
return this.$store.getters.getActiveProfile
|
||||||
},
|
},
|
||||||
activeSubscriptions: function () {
|
activeSubscriptions: function () {
|
||||||
const profile = JSON.parse(JSON.stringify(this.profileList[this.activeProfile]))
|
const profile = JSON.parse(JSON.stringify(this.activeProfile))
|
||||||
return profile.subscriptions.sort((a, b) => {
|
return profile.subscriptions.sort((a, b) => {
|
||||||
const nameA = a.name.toLowerCase()
|
const nameA = a.name.toLowerCase()
|
||||||
const nameB = b.name.toLowerCase()
|
const nameB = b.name.toLowerCase()
|
||||||
|
|
|
@ -7,6 +7,8 @@ import $ from 'jquery'
|
||||||
import debounce from 'lodash.debounce'
|
import debounce from 'lodash.debounce'
|
||||||
import ytSuggest from 'youtube-suggest'
|
import ytSuggest from 'youtube-suggest'
|
||||||
|
|
||||||
|
import { IpcChannels } from '../../../constants'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'TopNav',
|
name: 'TopNav',
|
||||||
components: {
|
components: {
|
||||||
|
@ -303,7 +305,7 @@ export default Vue.extend({
|
||||||
createNewWindow: function () {
|
createNewWindow: function () {
|
||||||
if (this.usingElectron) {
|
if (this.usingElectron) {
|
||||||
const { ipcRenderer } = require('electron')
|
const { ipcRenderer } = require('electron')
|
||||||
ipcRenderer.send('createNewWindow')
|
ipcRenderer.send(IpcChannels.CREATE_NEW_WINDOW)
|
||||||
} else {
|
} else {
|
||||||
// Web placeholder
|
// Web placeholder
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import FtListDropdown from '../ft-list-dropdown/ft-list-dropdown.vue'
|
||||||
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
||||||
import FtIconButton from '../ft-icon-button/ft-icon-button.vue'
|
import FtIconButton from '../ft-icon-button/ft-icon-button.vue'
|
||||||
import FtShareButton from '../ft-share-button/ft-share-button.vue'
|
import FtShareButton from '../ft-share-button/ft-share-button.vue'
|
||||||
|
import { MAIN_PROFILE_ID } from '../../../constants'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'WatchVideoInfo',
|
name: 'WatchVideoInfo',
|
||||||
|
@ -228,7 +229,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
isSubscribed: function () {
|
isSubscribed: function () {
|
||||||
const subIndex = this.profileList[this.activeProfile].subscriptions.findIndex((channel) => {
|
const subIndex = this.activeProfile.subscriptions.findIndex((channel) => {
|
||||||
return channel.id === this.channelId
|
return channel.id === this.channelId
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -322,7 +323,7 @@ export default Vue.extend({
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentProfile = JSON.parse(JSON.stringify(this.profileList[this.activeProfile]))
|
const currentProfile = JSON.parse(JSON.stringify(this.activeProfile))
|
||||||
const primaryProfile = JSON.parse(JSON.stringify(this.profileList[0]))
|
const primaryProfile = JSON.parse(JSON.stringify(this.profileList[0]))
|
||||||
|
|
||||||
if (this.isSubscribed) {
|
if (this.isSubscribed) {
|
||||||
|
@ -335,13 +336,13 @@ export default Vue.extend({
|
||||||
message: this.$t('Channel.Channel has been removed from your subscriptions')
|
message: this.$t('Channel.Channel has been removed from your subscriptions')
|
||||||
})
|
})
|
||||||
|
|
||||||
if (this.activeProfile === 0) {
|
if (this.activeProfile._id === MAIN_PROFILE_ID) {
|
||||||
// Check if a subscription exists in a different profile.
|
// Check if a subscription exists in a different profile.
|
||||||
// Remove from there as well.
|
// Remove from there as well.
|
||||||
let duplicateSubscriptions = 0
|
let duplicateSubscriptions = 0
|
||||||
|
|
||||||
this.profileList.forEach((profile) => {
|
this.profileList.forEach((profile) => {
|
||||||
if (profile._id === 'allChannels') {
|
if (profile._id === MAIN_PROFILE_ID) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const parsedProfile = JSON.parse(JSON.stringify(profile))
|
const parsedProfile = JSON.parse(JSON.stringify(profile))
|
||||||
|
@ -380,7 +381,7 @@ export default Vue.extend({
|
||||||
message: this.$t('Channel.Added channel to your subscriptions')
|
message: this.$t('Channel.Added channel to your subscriptions')
|
||||||
})
|
})
|
||||||
|
|
||||||
if (this.activeProfile !== 0) {
|
if (this.activeProfile._id !== MAIN_PROFILE_ID) {
|
||||||
const index = primaryProfile.subscriptions.findIndex((channel) => {
|
const index = primaryProfile.subscriptions.findIndex((channel) => {
|
||||||
return channel.id === this.channelId
|
return channel.id === this.channelId
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
import Datastore from 'nedb-promises'
|
|
||||||
|
|
||||||
// Initialize all datastores and export their references
|
|
||||||
// Current dbs:
|
|
||||||
// `settings.db`
|
|
||||||
// `profiles.db`
|
|
||||||
// `playlists.db`
|
|
||||||
// `history.db`
|
|
||||||
|
|
||||||
let buildFileName = null
|
|
||||||
|
|
||||||
// Check if using Electron
|
|
||||||
const usingElectron = window?.process?.type === 'renderer'
|
|
||||||
if (usingElectron) {
|
|
||||||
const { ipcRenderer } = require('electron')
|
|
||||||
const userDataPath = ipcRenderer.sendSync('getUserDataPathSync')
|
|
||||||
buildFileName = (dbName) => userDataPath + '/' + dbName + '.db'
|
|
||||||
} else {
|
|
||||||
buildFileName = (dbName) => dbName + '.db'
|
|
||||||
}
|
|
||||||
|
|
||||||
const settingsDb = Datastore.create({
|
|
||||||
filename: buildFileName('settings'),
|
|
||||||
autoload: true
|
|
||||||
})
|
|
||||||
|
|
||||||
const playlistsDb = Datastore.create({
|
|
||||||
filename: buildFileName('playlists'),
|
|
||||||
autoload: true
|
|
||||||
})
|
|
||||||
|
|
||||||
const profilesDb = Datastore.create({
|
|
||||||
filename: buildFileName('profiles'),
|
|
||||||
autoload: true
|
|
||||||
})
|
|
||||||
|
|
||||||
const historyDb = Datastore.create({
|
|
||||||
filename: buildFileName('history'),
|
|
||||||
autoload: true
|
|
||||||
})
|
|
||||||
|
|
||||||
export {
|
|
||||||
settingsDb,
|
|
||||||
profilesDb,
|
|
||||||
playlistsDb,
|
|
||||||
historyDb
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { historyDb } from '../datastores'
|
import { DBHistoryHandlers } from '../../../datastores/handlers/index'
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
historyCache: []
|
historyCache: []
|
||||||
|
@ -12,80 +12,52 @@ const getters = {
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
async grabHistory({ commit }) {
|
async grabHistory({ commit }) {
|
||||||
const results = await historyDb.find({}).sort({ timeWatched: -1 })
|
try {
|
||||||
|
const results = await DBHistoryHandlers.find()
|
||||||
commit('setHistoryCache', results)
|
commit('setHistoryCache', results)
|
||||||
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async updateHistory({ commit, dispatch, state }, entry) {
|
async updateHistory({ commit }, record) {
|
||||||
await historyDb.update(
|
try {
|
||||||
{ videoId: entry.videoId },
|
await DBHistoryHandlers.upsert(record)
|
||||||
entry,
|
commit('upsertToHistoryCache', record)
|
||||||
{ upsert: true }
|
} catch (errMessage) {
|
||||||
)
|
console.error(errMessage)
|
||||||
|
}
|
||||||
const entryIndex = state.historyCache.findIndex((currentEntry) => {
|
|
||||||
return entry.videoId === currentEntry.videoId
|
|
||||||
})
|
|
||||||
|
|
||||||
entryIndex === -1
|
|
||||||
? commit('insertNewEntryToHistoryCache', entry)
|
|
||||||
: commit('hoistEntryToTopOfHistoryCache', {
|
|
||||||
currentIndex: entryIndex,
|
|
||||||
updatedEntry: entry
|
|
||||||
})
|
|
||||||
|
|
||||||
dispatch('propagateHistory')
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async removeFromHistory({ commit, dispatch }, videoId) {
|
async removeFromHistory({ commit }, videoId) {
|
||||||
await historyDb.remove({ videoId: videoId })
|
try {
|
||||||
|
await DBHistoryHandlers.delete(videoId)
|
||||||
const updatedCache = state.historyCache.filter((entry) => {
|
commit('removeFromHistoryCacheById', videoId)
|
||||||
return entry.videoId !== videoId
|
} catch (errMessage) {
|
||||||
})
|
console.error(errMessage)
|
||||||
|
}
|
||||||
commit('setHistoryCache', updatedCache)
|
|
||||||
|
|
||||||
dispatch('propagateHistory')
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async removeAllHistory({ commit, dispatch }) {
|
async removeAllHistory({ commit }) {
|
||||||
await historyDb.remove({}, { multi: true })
|
try {
|
||||||
|
await DBHistoryHandlers.deleteAll()
|
||||||
commit('setHistoryCache', [])
|
commit('setHistoryCache', [])
|
||||||
dispatch('propagateHistory')
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async updateWatchProgress({ commit, dispatch }, entry) {
|
async updateWatchProgress({ commit }, { videoId, watchProgress }) {
|
||||||
await historyDb.update(
|
try {
|
||||||
{ videoId: entry.videoId },
|
await DBHistoryHandlers.updateWatchProgress(videoId, watchProgress)
|
||||||
{ $set: { watchProgress: entry.watchProgress } },
|
commit('updateRecordWatchProgressInHistoryCache', { videoId, watchProgress })
|
||||||
{ upsert: true }
|
} catch (errMessage) {
|
||||||
)
|
console.error(errMessage)
|
||||||
|
|
||||||
const entryIndex = state.historyCache.findIndex((currentEntry) => {
|
|
||||||
return entry.videoId === currentEntry.videoId
|
|
||||||
})
|
|
||||||
|
|
||||||
commit('updateEntryWatchProgressInHistoryCache', {
|
|
||||||
index: entryIndex,
|
|
||||||
value: entry.watchProgress
|
|
||||||
})
|
|
||||||
|
|
||||||
dispatch('propagateHistory')
|
|
||||||
},
|
|
||||||
|
|
||||||
propagateHistory({ getters: { getUsingElectron: usingElectron } }) {
|
|
||||||
if (usingElectron) {
|
|
||||||
const { ipcRenderer } = require('electron')
|
|
||||||
ipcRenderer.send('syncWindows', {
|
|
||||||
type: 'history',
|
|
||||||
data: state.historyCache
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
compactHistory(_) {
|
compactHistory(_) {
|
||||||
historyDb.persistence.compactDatafile()
|
DBHistoryHandlers.persist()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,17 +66,42 @@ const mutations = {
|
||||||
state.historyCache = historyCache
|
state.historyCache = historyCache
|
||||||
},
|
},
|
||||||
|
|
||||||
insertNewEntryToHistoryCache(state, entry) {
|
|
||||||
state.historyCache.unshift(entry)
|
|
||||||
},
|
|
||||||
|
|
||||||
hoistEntryToTopOfHistoryCache(state, { currentIndex, updatedEntry }) {
|
hoistEntryToTopOfHistoryCache(state, { currentIndex, updatedEntry }) {
|
||||||
state.historyCache.splice(currentIndex, 1)
|
state.historyCache.splice(currentIndex, 1)
|
||||||
state.historyCache.unshift(updatedEntry)
|
state.historyCache.unshift(updatedEntry)
|
||||||
},
|
},
|
||||||
|
|
||||||
updateEntryWatchProgressInHistoryCache(state, { index, value }) {
|
upsertToHistoryCache(state, record) {
|
||||||
state.historyCache[index].watchProgress = value
|
const i = state.historyCache.findIndex((currentRecord) => {
|
||||||
|
return record.videoId === currentRecord.videoId
|
||||||
|
})
|
||||||
|
|
||||||
|
if (i !== -1) {
|
||||||
|
// Already in cache
|
||||||
|
// Must be hoisted to top, remove it and then unshift it
|
||||||
|
state.historyCache.splice(i, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
state.historyCache.unshift(record)
|
||||||
|
},
|
||||||
|
|
||||||
|
updateRecordWatchProgressInHistoryCache(state, { videoId, watchProgress }) {
|
||||||
|
const i = state.historyCache.findIndex((currentRecord) => {
|
||||||
|
return currentRecord.videoId === videoId
|
||||||
|
})
|
||||||
|
|
||||||
|
const targetRecord = Object.assign({}, state.historyCache[i])
|
||||||
|
targetRecord.watchProgress = watchProgress
|
||||||
|
state.historyCache.splice(i, 1, targetRecord)
|
||||||
|
},
|
||||||
|
|
||||||
|
removeFromHistoryCacheById(state, videoId) {
|
||||||
|
for (let i = 0; i < state.historyCache.length; i++) {
|
||||||
|
if (state.historyCache[i].videoId === videoId) {
|
||||||
|
state.historyCache.splice(i, 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { playlistsDb } from '../datastores'
|
import { DBPlaylistHandlers } from '../../../datastores/handlers/index'
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
playlists: [
|
playlists: [
|
||||||
|
@ -25,89 +25,111 @@ const getters = {
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
async addPlaylist({ commit }, payload) {
|
async addPlaylist({ commit }, payload) {
|
||||||
await playlistsDb.insert(payload)
|
try {
|
||||||
|
await DBPlaylistHandlers.create(payload)
|
||||||
commit('addPlaylist', payload)
|
commit('addPlaylist', payload)
|
||||||
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async addPlaylists({ commit }, payload) {
|
async addPlaylists({ commit }, payload) {
|
||||||
await playlistsDb.insert(payload)
|
try {
|
||||||
|
await DBPlaylistHandlers.create(payload)
|
||||||
commit('addPlaylists', payload)
|
commit('addPlaylists', payload)
|
||||||
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async addVideo({ commit }, payload) {
|
async addVideo({ commit }, payload) {
|
||||||
await playlistsDb.update(
|
try {
|
||||||
{ playlistName: payload.playlistName },
|
const { playlistName, videoData } = payload
|
||||||
{ $push: { videos: payload.videoData } },
|
await DBPlaylistHandlers.upsertVideoByPlaylistName(playlistName, videoData)
|
||||||
{ upsert: true }
|
|
||||||
)
|
|
||||||
commit('addVideo', payload)
|
commit('addVideo', payload)
|
||||||
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async addVideos({ commit }, payload) {
|
async addVideos({ commit }, payload) {
|
||||||
await playlistsDb.update(
|
try {
|
||||||
{ _id: payload.playlistId },
|
const { playlistId, videoIds } = payload
|
||||||
{ $push: { videos: { $each: payload.videosIds } } },
|
await DBPlaylistHandlers.upsertVideoIdsByPlaylistId(playlistId, videoIds)
|
||||||
{ upsert: true }
|
|
||||||
)
|
|
||||||
commit('addVideos', payload)
|
commit('addVideos', payload)
|
||||||
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async grabAllPlaylists({ commit, dispatch }) {
|
async grabAllPlaylists({ commit, dispatch, state }) {
|
||||||
const payload = await playlistsDb.find({})
|
try {
|
||||||
|
const payload = await DBPlaylistHandlers.find()
|
||||||
if (payload.length === 0) {
|
if (payload.length === 0) {
|
||||||
commit('setAllPlaylists', state.playlists)
|
commit('setAllPlaylists', state.playlists)
|
||||||
dispatch('addPlaylists', payload)
|
dispatch('addPlaylists', payload)
|
||||||
} else {
|
} else {
|
||||||
commit('setAllPlaylists', payload)
|
commit('setAllPlaylists', payload)
|
||||||
}
|
}
|
||||||
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async removeAllPlaylists({ commit }) {
|
async removeAllPlaylists({ commit }) {
|
||||||
await playlistsDb.remove({ protected: { $ne: true } })
|
try {
|
||||||
|
await DBPlaylistHandlers.deleteAll()
|
||||||
commit('removeAllPlaylists')
|
commit('removeAllPlaylists')
|
||||||
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async removeAllVideos({ commit }, playlistName) {
|
async removeAllVideos({ commit }, playlistName) {
|
||||||
await playlistsDb.update(
|
try {
|
||||||
{ playlistName: playlistName },
|
await DBPlaylistHandlers.deleteAllVideosByPlaylistName(playlistName)
|
||||||
{ $set: { videos: [] } },
|
|
||||||
{ upsert: true }
|
|
||||||
)
|
|
||||||
commit('removeAllVideos', playlistName)
|
commit('removeAllVideos', playlistName)
|
||||||
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async removePlaylist({ commit }, playlistId) {
|
async removePlaylist({ commit }, playlistId) {
|
||||||
await playlistsDb.remove({
|
try {
|
||||||
_id: playlistId,
|
await DBPlaylistHandlers.delete(playlistId)
|
||||||
protected: { $ne: true }
|
|
||||||
})
|
|
||||||
commit('removePlaylist', playlistId)
|
commit('removePlaylist', playlistId)
|
||||||
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async removePlaylists({ commit }, playlistIds) {
|
async removePlaylists({ commit }, playlistIds) {
|
||||||
await playlistsDb.remove({
|
try {
|
||||||
_id: { $in: playlistIds },
|
await DBPlaylistHandlers.deleteMultiple(playlistIds)
|
||||||
protected: { $ne: true }
|
|
||||||
})
|
|
||||||
commit('removePlaylists', playlistIds)
|
commit('removePlaylists', playlistIds)
|
||||||
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async removeVideo({ commit }, payload) {
|
async removeVideo({ commit }, payload) {
|
||||||
await playlistsDb.update(
|
try {
|
||||||
{ playlistName: payload.playlistName },
|
const { playlistName, videoId } = payload
|
||||||
{ $pull: { videos: { videoId: payload.videoId } } },
|
await DBPlaylistHandlers.deleteVideoIdByPlaylistName(playlistName, videoId)
|
||||||
{ upsert: true }
|
|
||||||
)
|
|
||||||
commit('removeVideo', payload)
|
commit('removeVideo', payload)
|
||||||
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async removeVideos({ commit }, payload) {
|
async removeVideos({ commit }, payload) {
|
||||||
await playlistsDb.update(
|
try {
|
||||||
{ _id: payload.playlistName },
|
const { playlistName, videoIds } = payload
|
||||||
{ $pull: { videos: { $in: payload.videoId } } },
|
await DBPlaylistHandlers.deleteVideoIdsByPlaylistName(playlistName, videoIds)
|
||||||
{ upsert: true }
|
|
||||||
)
|
|
||||||
commit('removeVideos', payload)
|
commit('removeVideos', payload)
|
||||||
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import { profilesDb } from '../datastores'
|
import { MAIN_PROFILE_ID } from '../../../constants'
|
||||||
|
import { DBProfileHandlers } from '../../../datastores/handlers/index'
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
profileList: [{
|
profileList: [{
|
||||||
_id: 'allChannels',
|
_id: MAIN_PROFILE_ID,
|
||||||
name: 'All Channels',
|
name: 'All Channels',
|
||||||
bgColor: '#000000',
|
bgColor: '#000000',
|
||||||
textColor: '#FFFFFF',
|
textColor: '#FFFFFF',
|
||||||
subscriptions: []
|
subscriptions: []
|
||||||
}],
|
}],
|
||||||
activeProfile: 0
|
activeProfile: MAIN_PROFILE_ID
|
||||||
}
|
}
|
||||||
|
|
||||||
const getters = {
|
const getters = {
|
||||||
|
@ -16,94 +17,111 @@ const getters = {
|
||||||
return state.profileList
|
return state.profileList
|
||||||
},
|
},
|
||||||
|
|
||||||
getActiveProfile: () => {
|
getActiveProfile: (state) => {
|
||||||
return state.activeProfile
|
const activeProfileId = state.activeProfile
|
||||||
|
return state.profileList.find((profile) => {
|
||||||
|
return profile._id === activeProfileId
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
profileById: (state) => (id) => {
|
||||||
|
const profile = state.profileList.find(p => p._id === id)
|
||||||
|
return profile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function profileSort(a, b) {
|
||||||
|
if (a._id === MAIN_PROFILE_ID) return -1
|
||||||
|
if (b._id === MAIN_PROFILE_ID) return 1
|
||||||
|
if (a.name < b.name) return -1
|
||||||
|
if (a.name > b.name) return 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
async grabAllProfiles({ rootState, dispatch, commit }, defaultName = null) {
|
async grabAllProfiles({ rootState, dispatch, commit }, defaultName = null) {
|
||||||
let profiles = await profilesDb.find({})
|
let profiles
|
||||||
if (profiles.length === 0) {
|
try {
|
||||||
dispatch('createDefaultProfile', defaultName)
|
profiles = await DBProfileHandlers.find()
|
||||||
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// We want the primary profile to always be first
|
|
||||||
// So sort with that then sort alphabetically by profile name
|
|
||||||
profiles = profiles.sort((a, b) => {
|
|
||||||
if (a._id === 'allChannels') {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b._id === 'allChannels') {
|
if (!Array.isArray(profiles)) return
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return b.name - a.name
|
if (profiles.length === 0) {
|
||||||
})
|
// Create a default profile and persist it
|
||||||
|
|
||||||
if (state.profileList.length < profiles.length) {
|
|
||||||
const profileIndex = profiles.findIndex((profile) => {
|
|
||||||
return profile._id === rootState.settings.defaultProfile
|
|
||||||
})
|
|
||||||
|
|
||||||
if (profileIndex !== -1) {
|
|
||||||
commit('setActiveProfile', profileIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
commit('setProfileList', profiles)
|
|
||||||
},
|
|
||||||
|
|
||||||
async grabProfileInfo(_, profileId) {
|
|
||||||
console.log(profileId)
|
|
||||||
return await profilesDb.findOne({ _id: profileId })
|
|
||||||
},
|
|
||||||
|
|
||||||
async createDefaultProfile({ dispatch }, defaultName) {
|
|
||||||
const randomColor = await dispatch('getRandomColor')
|
const randomColor = await dispatch('getRandomColor')
|
||||||
const textColor = await dispatch('calculateColorLuminance', randomColor)
|
const textColor = await dispatch('calculateColorLuminance', randomColor)
|
||||||
const defaultProfile = {
|
const defaultProfile = {
|
||||||
_id: 'allChannels',
|
_id: MAIN_PROFILE_ID,
|
||||||
name: defaultName,
|
name: defaultName,
|
||||||
bgColor: randomColor,
|
bgColor: randomColor,
|
||||||
textColor: textColor,
|
textColor: textColor,
|
||||||
subscriptions: []
|
subscriptions: []
|
||||||
}
|
}
|
||||||
|
|
||||||
await profilesDb.update(
|
try {
|
||||||
{ _id: 'allChannels' },
|
await DBProfileHandlers.create(defaultProfile)
|
||||||
defaultProfile,
|
commit('setProfileList', [defaultProfile])
|
||||||
{ upsert: true }
|
} catch (errMessage) {
|
||||||
)
|
console.error(errMessage)
|
||||||
dispatch('grabAllProfiles')
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// We want the primary profile to always be first
|
||||||
|
// So sort with that then sort alphabetically by profile name
|
||||||
|
profiles = profiles.sort(profileSort)
|
||||||
|
|
||||||
|
if (state.profileList.length < profiles.length) {
|
||||||
|
const profile = profiles.find((profile) => {
|
||||||
|
return profile._id === rootState.settings.defaultProfile
|
||||||
|
})
|
||||||
|
|
||||||
|
if (profile) {
|
||||||
|
commit('setActiveProfile', profile._id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
commit('setProfileList', profiles)
|
||||||
},
|
},
|
||||||
|
|
||||||
async updateProfile({ dispatch }, profile) {
|
async createProfile({ commit }, profile) {
|
||||||
await profilesDb.update(
|
try {
|
||||||
{ _id: profile._id },
|
const newProfile = await DBProfileHandlers.create(profile)
|
||||||
profile,
|
commit('addProfileToList', newProfile)
|
||||||
{ upsert: true }
|
} catch (errMessage) {
|
||||||
)
|
console.error(errMessage)
|
||||||
dispatch('grabAllProfiles')
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async insertProfile({ dispatch }, profile) {
|
async updateProfile({ commit }, profile) {
|
||||||
await profilesDb.insert(profile)
|
try {
|
||||||
dispatch('grabAllProfiles')
|
await DBProfileHandlers.upsert(profile)
|
||||||
|
commit('upsertProfileToList', profile)
|
||||||
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async removeProfile({ dispatch }, profileId) {
|
async removeProfile({ commit }, profileId) {
|
||||||
await profilesDb.remove({ _id: profileId })
|
try {
|
||||||
dispatch('grabAllProfiles')
|
await DBProfileHandlers.delete(profileId)
|
||||||
|
commit('removeProfileFromList', profileId)
|
||||||
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
compactProfiles(_) {
|
compactProfiles(_) {
|
||||||
profilesDb.persistence.compactDatafile()
|
DBProfileHandlers.persist()
|
||||||
},
|
},
|
||||||
|
|
||||||
updateActiveProfile({ commit }, index) {
|
updateActiveProfile({ commit }, id) {
|
||||||
commit('setActiveProfile', index)
|
commit('setActiveProfile', id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,8 +129,36 @@ const mutations = {
|
||||||
setProfileList(state, profileList) {
|
setProfileList(state, profileList) {
|
||||||
state.profileList = profileList
|
state.profileList = profileList
|
||||||
},
|
},
|
||||||
|
|
||||||
setActiveProfile(state, activeProfile) {
|
setActiveProfile(state, activeProfile) {
|
||||||
state.activeProfile = activeProfile
|
state.activeProfile = activeProfile
|
||||||
|
},
|
||||||
|
|
||||||
|
addProfileToList(state, profile) {
|
||||||
|
state.profileList.push(profile)
|
||||||
|
state.profileList.sort(profileSort)
|
||||||
|
},
|
||||||
|
|
||||||
|
upsertProfileToList(state, updatedProfile) {
|
||||||
|
const i = state.profileList.findIndex((p) => {
|
||||||
|
return p._id === updatedProfile._id
|
||||||
|
})
|
||||||
|
|
||||||
|
if (i === -1) {
|
||||||
|
state.profileList.push(updatedProfile)
|
||||||
|
} else {
|
||||||
|
state.profileList.splice(i, 1, updatedProfile)
|
||||||
|
}
|
||||||
|
|
||||||
|
state.profileList.sort(profileSort)
|
||||||
|
},
|
||||||
|
|
||||||
|
removeProfileFromList(state, profileId) {
|
||||||
|
const i = state.profileList.findIndex((profile) => {
|
||||||
|
return profile._id === profileId
|
||||||
|
})
|
||||||
|
|
||||||
|
state.profileList.splice(i, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { settingsDb } from '../datastores'
|
|
||||||
import i18n from '../../i18n/index'
|
import i18n from '../../i18n/index'
|
||||||
|
import { MAIN_PROFILE_ID, IpcChannels, SyncEvents } from '../../../constants'
|
||||||
|
import { DBSettingHandlers } from '../../../datastores/handlers/index'
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Due to the complexity of the settings module in FreeTube, a more
|
* Due to the complexity of the settings module in FreeTube, a more
|
||||||
|
@ -170,7 +171,7 @@ const state = {
|
||||||
defaultCaptionSettings: '{}',
|
defaultCaptionSettings: '{}',
|
||||||
defaultInterval: 5,
|
defaultInterval: 5,
|
||||||
defaultPlayback: 1,
|
defaultPlayback: 1,
|
||||||
defaultProfile: 'allChannels',
|
defaultProfile: MAIN_PROFILE_ID,
|
||||||
defaultQuality: '720',
|
defaultQuality: '720',
|
||||||
defaultSkipInterval: 5,
|
defaultSkipInterval: 5,
|
||||||
defaultTheatreMode: false,
|
defaultTheatreMode: false,
|
||||||
|
@ -312,10 +313,8 @@ Object.assign(customGetters, {
|
||||||
|
|
||||||
const customActions = {
|
const customActions = {
|
||||||
grabUserSettings: async ({ commit, dispatch, getters }) => {
|
grabUserSettings: async ({ commit, dispatch, getters }) => {
|
||||||
const userSettings = await settingsDb.find({
|
try {
|
||||||
_id: { $ne: 'bounds' }
|
const userSettings = await DBSettingHandlers.find()
|
||||||
})
|
|
||||||
|
|
||||||
for (const setting of userSettings) {
|
for (const setting of userSettings) {
|
||||||
const { _id, value } = setting
|
const { _id, value } = setting
|
||||||
if (getters.settingHasSideEffects(_id)) {
|
if (getters.settingHasSideEffects(_id)) {
|
||||||
|
@ -324,17 +323,19 @@ const customActions = {
|
||||||
|
|
||||||
commit(defaultMutationId(_id), value)
|
commit(defaultMutationId(_id), value)
|
||||||
}
|
}
|
||||||
|
} catch (errMessage) {
|
||||||
|
console.error(errMessage)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Should be a root action, but we'll tolerate
|
// Should be a root action, but we'll tolerate
|
||||||
setupListenerToSyncWindows: ({ commit, dispatch, getters }) => {
|
setupListenersToSyncWindows: ({ commit, dispatch, getters }) => {
|
||||||
// Already known to be Electron, no need to check
|
// Already known to be Electron, no need to check
|
||||||
const { ipcRenderer } = require('electron')
|
const { ipcRenderer } = require('electron')
|
||||||
ipcRenderer.on('syncWindows', (_, payload) => {
|
|
||||||
const { type, data } = payload
|
ipcRenderer.on(IpcChannels.SYNC_SETTINGS, (_, { event, data }) => {
|
||||||
switch (type) {
|
switch (event) {
|
||||||
case 'setting':
|
case SyncEvents.GENERAL.UPSERT:
|
||||||
// `data` is a single setting => { _id, value }
|
|
||||||
if (getters.settingHasSideEffects(data._id)) {
|
if (getters.settingHasSideEffects(data._id)) {
|
||||||
dispatch(defaultSideEffectsTriggerId(data._id), data.value)
|
dispatch(defaultSideEffectsTriggerId(data._id), data.value)
|
||||||
}
|
}
|
||||||
|
@ -342,18 +343,65 @@ const customActions = {
|
||||||
commit(defaultMutationId(data._id), data.value)
|
commit(defaultMutationId(data._id), data.value)
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'history':
|
default:
|
||||||
// `data` is the whole history => Array of history entries
|
console.error('settings: invalid sync event received')
|
||||||
commit('setHistoryCache', data)
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcRenderer.on(IpcChannels.SYNC_HISTORY, (_, { event, data }) => {
|
||||||
|
switch (event) {
|
||||||
|
case SyncEvents.GENERAL.UPSERT:
|
||||||
|
commit('upsertToHistoryCache', data)
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'playlist':
|
case SyncEvents.HISTORY.UPDATE_WATCH_PROGRESS:
|
||||||
// TODO: Not implemented
|
commit('updateRecordWatchProgressInHistoryCache', data)
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'profile':
|
case SyncEvents.GENERAL.DELETE:
|
||||||
// TODO: Not implemented
|
commit('removeFromHistoryCacheById', data)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
case SyncEvents.GENERAL.DELETE_ALL:
|
||||||
|
commit('setHistoryCache', [])
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
console.error('history: invalid sync event received')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcRenderer.on(IpcChannels.SYNC_PROFILES, (_, { event, data }) => {
|
||||||
|
switch (event) {
|
||||||
|
case SyncEvents.GENERAL.CREATE:
|
||||||
|
commit('addProfileToList', data)
|
||||||
|
break
|
||||||
|
|
||||||
|
case SyncEvents.GENERAL.UPSERT:
|
||||||
|
commit('upsertProfileToList', data)
|
||||||
|
break
|
||||||
|
|
||||||
|
case SyncEvents.GENERAL.DELETE:
|
||||||
|
commit('removeProfileFromList', data)
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
console.error('profiles: invalid sync event received')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcRenderer.on(IpcChannels.SYNC_PLAYLISTS, (_, { event, data }) => {
|
||||||
|
switch (event) {
|
||||||
|
case SyncEvents.PLAYLISTS.UPSERT_VIDEO:
|
||||||
|
commit('addVideo', data)
|
||||||
|
break
|
||||||
|
|
||||||
|
case SyncEvents.PLAYLISTS.DELETE_VIDEO:
|
||||||
|
commit('removeVideo', data)
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
console.error('playlists: invalid sync event received')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -398,30 +446,16 @@ for (const settingId of Object.keys(state)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
actions[updaterId] = async ({ commit, dispatch, getters }, value) => {
|
actions[updaterId] = async ({ commit, dispatch, getters }, value) => {
|
||||||
await settingsDb.update(
|
try {
|
||||||
{ _id: settingId },
|
await DBSettingHandlers.upsert(settingId, value)
|
||||||
{ _id: settingId, value: value },
|
|
||||||
{ upsert: true }
|
|
||||||
)
|
|
||||||
|
|
||||||
const {
|
if (getters.settingHasSideEffects(settingId)) {
|
||||||
getUsingElectron: usingElectron,
|
|
||||||
settingHasSideEffects
|
|
||||||
} = getters
|
|
||||||
|
|
||||||
if (settingHasSideEffects(settingId)) {
|
|
||||||
dispatch(triggerId, value)
|
dispatch(triggerId, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
commit(mutationId, value)
|
commit(mutationId, value)
|
||||||
|
} catch (errMessage) {
|
||||||
if (usingElectron) {
|
console.error(errMessage)
|
||||||
const { ipcRenderer } = require('electron')
|
|
||||||
|
|
||||||
// Propagate settings to all other existing windows
|
|
||||||
ipcRenderer.send('syncWindows', {
|
|
||||||
type: 'setting',
|
|
||||||
data: { _id: settingId, value: value }
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
import { MAIN_PROFILE_ID } from '../../../constants'
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
allSubscriptionsList: [],
|
allSubscriptionsList: [],
|
||||||
profileSubscriptions: {
|
profileSubscriptions: {
|
||||||
activeProfile: 0,
|
activeProfile: MAIN_PROFILE_ID,
|
||||||
videoList: []
|
videoList: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import IsEqual from 'lodash.isequal'
|
import IsEqual from 'lodash.isequal'
|
||||||
import FtToastEvents from '../../components/ft-toast/ft-toast-events'
|
import FtToastEvents from '../../components/ft-toast/ft-toast-events'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
|
|
||||||
|
import { IpcChannels } from '../../../constants'
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
isSideNavOpen: false,
|
isSideNavOpen: false,
|
||||||
sessionSearchHistory: [],
|
sessionSearchHistory: [],
|
||||||
|
@ -166,7 +169,7 @@ const actions = {
|
||||||
const usingElectron = rootState.settings.usingElectron
|
const usingElectron = rootState.settings.usingElectron
|
||||||
if (usingElectron) {
|
if (usingElectron) {
|
||||||
const ipcRenderer = require('electron').ipcRenderer
|
const ipcRenderer = require('electron').ipcRenderer
|
||||||
ipcRenderer.send('openExternalLink', url)
|
ipcRenderer.send(IpcChannels.OPEN_EXTERNAL_LINK, url)
|
||||||
} else {
|
} else {
|
||||||
// Web placeholder
|
// Web placeholder
|
||||||
}
|
}
|
||||||
|
@ -179,25 +182,25 @@ const actions = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (await invokeIRC(context, 'getSystemLocale', webCbk)) || 'en-US'
|
return (await invokeIRC(context, IpcChannels.GET_SYSTEM_LOCALE, webCbk)) || 'en-US'
|
||||||
},
|
},
|
||||||
|
|
||||||
async showOpenDialog (context, options) {
|
async showOpenDialog (context, options) {
|
||||||
// TODO: implement showOpenDialog web compatible callback
|
// TODO: implement showOpenDialog web compatible callback
|
||||||
const webCbk = () => null
|
const webCbk = () => null
|
||||||
return await invokeIRC(context, 'showOpenDialog', webCbk, options)
|
return await invokeIRC(context, IpcChannels.SHOW_OPEN_DIALOG, webCbk, options)
|
||||||
},
|
},
|
||||||
|
|
||||||
async showSaveDialog (context, options) {
|
async showSaveDialog (context, options) {
|
||||||
// TODO: implement showSaveDialog web compatible callback
|
// TODO: implement showSaveDialog web compatible callback
|
||||||
const webCbk = () => null
|
const webCbk = () => null
|
||||||
return await invokeIRC(context, 'showSaveDialog', webCbk, options)
|
return await invokeIRC(context, IpcChannels.SHOW_SAVE_DIALOG, webCbk, options)
|
||||||
},
|
},
|
||||||
|
|
||||||
async getUserDataPath (context) {
|
async getUserDataPath (context) {
|
||||||
// TODO: implement getUserDataPath web compatible callback
|
// TODO: implement getUserDataPath web compatible callback
|
||||||
const webCbk = () => null
|
const webCbk = () => null
|
||||||
return await invokeIRC(context, 'getUserDataPath', webCbk)
|
return await invokeIRC(context, IpcChannels.GET_USER_DATA_PATH, webCbk)
|
||||||
},
|
},
|
||||||
|
|
||||||
updateShowProgressBar ({ commit }, value) {
|
updateShowProgressBar ({ commit }, value) {
|
||||||
|
@ -853,10 +856,7 @@ const actions = {
|
||||||
console.log(executable, args)
|
console.log(executable, args)
|
||||||
|
|
||||||
const { ipcRenderer } = require('electron')
|
const { ipcRenderer } = require('electron')
|
||||||
ipcRenderer.send('openInExternalPlayer', {
|
ipcRenderer.send(IpcChannels.OPEN_IN_EXTERNAL_PLAYER, { executable, args })
|
||||||
executable,
|
|
||||||
args
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import FtElementList from '../../components/ft-element-list/ft-element-list.vue'
|
||||||
|
|
||||||
import ytch from 'yt-channel-info'
|
import ytch from 'yt-channel-info'
|
||||||
import autolinker from 'autolinker'
|
import autolinker from 'autolinker'
|
||||||
|
import { MAIN_PROFILE_ID } from '../../../constants'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'Search',
|
name: 'Search',
|
||||||
|
@ -90,7 +91,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
isSubscribed: function () {
|
isSubscribed: function () {
|
||||||
const subIndex = this.profileList[this.activeProfile].subscriptions.findIndex((channel) => {
|
const subIndex = this.activeProfile.subscriptions.findIndex((channel) => {
|
||||||
return channel.id === this.id
|
return channel.id === this.id
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -508,7 +509,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
handleSubscription: function () {
|
handleSubscription: function () {
|
||||||
const currentProfile = JSON.parse(JSON.stringify(this.profileList[this.activeProfile]))
|
const currentProfile = JSON.parse(JSON.stringify(this.activeProfile))
|
||||||
const primaryProfile = JSON.parse(JSON.stringify(this.profileList[0]))
|
const primaryProfile = JSON.parse(JSON.stringify(this.profileList[0]))
|
||||||
|
|
||||||
if (this.isSubscribed) {
|
if (this.isSubscribed) {
|
||||||
|
@ -521,13 +522,13 @@ export default Vue.extend({
|
||||||
message: this.$t('Channel.Channel has been removed from your subscriptions')
|
message: this.$t('Channel.Channel has been removed from your subscriptions')
|
||||||
})
|
})
|
||||||
|
|
||||||
if (this.activeProfile === 0) {
|
if (this.activeProfile === MAIN_PROFILE_ID) {
|
||||||
// Check if a subscription exists in a different profile.
|
// Check if a subscription exists in a different profile.
|
||||||
// Remove from there as well.
|
// Remove from there as well.
|
||||||
let duplicateSubscriptions = 0
|
let duplicateSubscriptions = 0
|
||||||
|
|
||||||
this.profileList.forEach((profile) => {
|
this.profileList.forEach((profile) => {
|
||||||
if (profile._id === 'allChannels') {
|
if (profile._id === MAIN_PROFILE_ID) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const parsedProfile = JSON.parse(JSON.stringify(profile))
|
const parsedProfile = JSON.parse(JSON.stringify(profile))
|
||||||
|
@ -566,7 +567,7 @@ export default Vue.extend({
|
||||||
message: this.$t('Channel.Added channel to your subscriptions')
|
message: this.$t('Channel.Added channel to your subscriptions')
|
||||||
})
|
})
|
||||||
|
|
||||||
if (this.activeProfile !== 0) {
|
if (this.activeProfile !== MAIN_PROFILE_ID) {
|
||||||
const index = primaryProfile.subscriptions.findIndex((channel) => {
|
const index = primaryProfile.subscriptions.findIndex((channel) => {
|
||||||
return channel.id === this.id
|
return channel.id === this.id
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import { mapActions } from 'vuex'
|
import { mapActions, mapGetters } from 'vuex'
|
||||||
import FtLoader from '../../components/ft-loader/ft-loader.vue'
|
import FtLoader from '../../components/ft-loader/ft-loader.vue'
|
||||||
import FtProfileEdit from '../../components/ft-profile-edit/ft-profile-edit.vue'
|
import FtProfileEdit from '../../components/ft-profile-edit/ft-profile-edit.vue'
|
||||||
import FtProfileChannelList from '../../components/ft-profile-channel-list/ft-profile-channel-list.vue'
|
import FtProfileChannelList from '../../components/ft-profile-channel-list/ft-profile-channel-list.vue'
|
||||||
import FtProfileFilterChannelsList from '../../components/ft-profile-filter-channels-list/ft-profile-filter-channels-list.vue'
|
import FtProfileFilterChannelsList from '../../components/ft-profile-filter-channels-list/ft-profile-filter-channels-list.vue'
|
||||||
|
import { MAIN_PROFILE_ID } from '../../../constants'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'ProfileEdit',
|
name: 'ProfileEdit',
|
||||||
|
@ -15,25 +16,30 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
isLoading: false,
|
isLoading: true,
|
||||||
isNew: false,
|
isNew: false,
|
||||||
profileId: '',
|
profileId: '',
|
||||||
profile: {}
|
profile: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapGetters([
|
||||||
|
'profileById'
|
||||||
|
]),
|
||||||
|
|
||||||
profileList: function () {
|
profileList: function () {
|
||||||
return this.$store.getters.getProfileList
|
return this.$store.getters.getProfileList
|
||||||
},
|
},
|
||||||
|
|
||||||
isMainProfile: function () {
|
isMainProfile: function () {
|
||||||
return this.profileId === 'allChannels'
|
return this.profileId === MAIN_PROFILE_ID
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
profileList: {
|
profileList: {
|
||||||
handler: function () {
|
handler: function () {
|
||||||
this.grabProfileInfo(this.profileId).then((profile) => {
|
const profile = this.profileById(this.profileId)
|
||||||
if (profile === null) {
|
if (!profile) {
|
||||||
this.showToast({
|
this.showToast({
|
||||||
message: this.$t('Profile.Profile could not be found')
|
message: this.$t('Profile.Profile could not be found')
|
||||||
})
|
})
|
||||||
|
@ -42,13 +48,11 @@ export default Vue.extend({
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.profile = profile
|
this.profile = profile
|
||||||
})
|
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted: async function () {
|
mounted: async function () {
|
||||||
this.isLoading = true
|
|
||||||
const profileType = this.$route.name
|
const profileType = this.$route.name
|
||||||
|
|
||||||
this.deletePromptLabel = `${this.$t('Profile.Are you sure you want to delete this profile?')} ${this.$t('Profile["All subscriptions will also be deleted."]')}`
|
this.deletePromptLabel = `${this.$t('Profile.Are you sure you want to delete this profile?')} ${this.$t('Profile["All subscriptions will also be deleted."]')}`
|
||||||
|
@ -63,13 +67,12 @@ export default Vue.extend({
|
||||||
textColor: textColor,
|
textColor: textColor,
|
||||||
subscriptions: []
|
subscriptions: []
|
||||||
}
|
}
|
||||||
this.isLoading = false
|
|
||||||
} else {
|
} else {
|
||||||
this.isNew = false
|
this.isNew = false
|
||||||
this.profileId = this.$route.params.id
|
this.profileId = this.$route.params.id
|
||||||
|
|
||||||
this.grabProfileInfo(this.profileId).then((profile) => {
|
const profile = this.profileById(this.profileId)
|
||||||
if (profile === null) {
|
if (!profile) {
|
||||||
this.showToast({
|
this.showToast({
|
||||||
message: this.$t('Profile.Profile could not be found')
|
message: this.$t('Profile.Profile could not be found')
|
||||||
})
|
})
|
||||||
|
@ -78,14 +81,13 @@ export default Vue.extend({
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.profile = profile
|
this.profile = profile
|
||||||
this.isLoading = false
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.isLoading = false
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions([
|
...mapActions([
|
||||||
'showToast',
|
'showToast',
|
||||||
'grabProfileInfo',
|
|
||||||
'getRandomColor',
|
'getRandomColor',
|
||||||
'calculateColorLuminance'
|
'calculateColorLuminance'
|
||||||
])
|
])
|
||||||
|
|
|
@ -9,6 +9,7 @@ import FtElementList from '../../components/ft-element-list/ft-element-list.vue'
|
||||||
|
|
||||||
import ytch from 'yt-channel-info'
|
import ytch from 'yt-channel-info'
|
||||||
import Parser from 'rss-parser'
|
import Parser from 'rss-parser'
|
||||||
|
import { MAIN_PROFILE_ID } from '../../../constants'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'Subscriptions',
|
name: 'Subscriptions',
|
||||||
|
@ -81,11 +82,11 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
activeSubscriptionList: function () {
|
activeSubscriptionList: function () {
|
||||||
return this.profileList[this.activeProfile].subscriptions
|
return this.activeProfile.subscriptions
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
activeProfile: async function (val) {
|
activeProfile: async function (_) {
|
||||||
this.getProfileSubscriptions()
|
this.getProfileSubscriptions()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -97,7 +98,7 @@ export default Vue.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.profileSubscriptions.videoList.length !== 0) {
|
if (this.profileSubscriptions.videoList.length !== 0) {
|
||||||
if (this.profileSubscriptions.activeProfile === this.activeProfile) {
|
if (this.profileSubscriptions.activeProfile === this.activeProfile._id) {
|
||||||
const subscriptionList = JSON.parse(JSON.stringify(this.profileSubscriptions))
|
const subscriptionList = JSON.parse(JSON.stringify(this.profileSubscriptions))
|
||||||
if (this.hideWatchedSubs) {
|
if (this.hideWatchedSubs) {
|
||||||
this.videoList = await Promise.all(subscriptionList.videoList.filter((video) => {
|
this.videoList = await Promise.all(subscriptionList.videoList.filter((video) => {
|
||||||
|
@ -172,7 +173,7 @@ export default Vue.extend({
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const profileSubscriptions = {
|
const profileSubscriptions = {
|
||||||
activeProfile: this.activeProfile,
|
activeProfile: this.activeProfile._id,
|
||||||
videoList: videoList
|
videoList: videoList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +192,7 @@ export default Vue.extend({
|
||||||
this.isLoading = false
|
this.isLoading = false
|
||||||
this.updateShowProgressBar(false)
|
this.updateShowProgressBar(false)
|
||||||
|
|
||||||
if (this.activeProfile === 0) {
|
if (this.activeProfile === MAIN_PROFILE_ID) {
|
||||||
this.updateAllSubscriptionsList(profileSubscriptions.videoList)
|
this.updateAllSubscriptionsList(profileSubscriptions.videoList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue