Skip to content

Commit

Permalink
Scene Collections V2: Backup and Sync (stream-labs#202)
Browse files Browse the repository at this point in the history
* WIP scene collection sync

* embarking on a scene collections rewrite

* WIP Scene Collections V2

* working basic functionality v2

* implement recovery

* implement overlay installation in the new system

* tmp working on onboarding

* recopy nodes

* implement login-logout and onboarding step

* add migration code

* carry over fetch scene collection schema thing

* move over to the new system

* notify the server of newly active scene collections

* remove migrator

* fix tests

* clean up API

* small refactor to add state management to a separate class

* update comment

* move over initial state to state service

* update README with new scene collection loading process

* update cache uploader

* remove comment

* update comment
  • Loading branch information
avacreeth authored Jan 26, 2018
1 parent 3062655 commit f7850b9
Show file tree
Hide file tree
Showing 57 changed files with 1,448 additions and 762 deletions.
11 changes: 2 additions & 9 deletions app/components/ExtraSettings.vue.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Vue from 'vue';
import electron from 'electron';
import { Component } from 'vue-property-decorator';
import { OverlaysPersistenceService } from '../services/scenes-collections';
import { CacheUploaderService } from '../services/cache-uploader';
import { Inject } from '../util/injector';
import BoolInput from './shared/forms/BoolInput.vue';
Expand All @@ -13,15 +12,9 @@ import { StreamlabelsService } from '../services/streamlabels';
components: { BoolInput }
})
export default class ExtraSettings extends Vue {

@Inject('OverlaysPersistenceService')
overlaysService: OverlaysPersistenceService;

@Inject()
cacheUploaderService: CacheUploaderService;

@Inject() streamlabelsService: StreamlabelsService;
@Inject() cacheUploaderService: CacheUploaderService;
@Inject() customizationService: CustomizationService;
@Inject() streamlabelsService: StreamlabelsService;

cacheUploading = false;

Expand Down
14 changes: 5 additions & 9 deletions app/components/Login.vue.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import Vue from 'vue';
import { Component } from 'vue-property-decorator';
import { UserService } from '../services/user';
import { OnboardingService } from '../services/onboarding';
import { Inject } from '../util/injector';
import { UserService } from 'services/user';
import { OnboardingService } from 'services/onboarding';
import { Inject } from 'util/injector';

@Component({})
export default class Login extends Vue {

@Inject()
userService: UserService;

@Inject()
onboardingService: OnboardingService;
@Inject() userService: UserService;
@Inject() onboardingService: OnboardingService;

get loggedIn() {
return this.userService.isLoggedIn();
Expand Down
9 changes: 5 additions & 4 deletions app/components/OverlaySettings.vue.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import Vue from 'vue';
import { Component } from 'vue-property-decorator';
import { Inject } from 'util/injector';
import { OverlaysPersistenceService, ScenesCollectionsService } from 'services/scenes-collections';
import { SceneCollectionsService } from 'services/scene-collections';
import { OverlaysPersistenceService } from 'services/scene-collections/overlays';
import electron from 'electron';
import path from 'path';
import { AppService } from 'services/app';
Expand All @@ -10,8 +11,8 @@ import { ScenesService } from 'services/scenes';

@Component({})
export default class OverlaySettings extends Vue {
@Inject() sceneCollectionsService: SceneCollectionsService;
@Inject() overlaysPersistenceService: OverlaysPersistenceService;
@Inject() scenesCollectionsService: ScenesCollectionsService;
@Inject() appService: AppService;
@Inject() widgetsService: WidgetsService;
@Inject() scenesService: ScenesService;
Expand Down Expand Up @@ -47,9 +48,9 @@ export default class OverlaySettings extends Vue {
this.message = '';

const filename = path.parse(chosenPath[0]).name;
const configName = this.scenesCollectionsService.suggestName(filename);
const configName = this.sceneCollectionsService.suggestName(filename);

this.appService.loadOverlay(configName, chosenPath[0]).then(() => {
this.sceneCollectionsService.loadOverlay(chosenPath[0], configName).then(() => {
this.busy = false;
this.message = `Successfully loaded ${filename}.overlay`;
});
Expand Down
11 changes: 6 additions & 5 deletions app/components/SceneSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@

<div class="scene-collections-wrapper">

<DropdownMenu :title="activeConfig">
<DropdownMenu :title="activeCollection.name">
<div class="dropdown-menu__item" @click="addCollection">New</div>
<div class="dropdown-menu__item" @click="duplicateCollection">Duplicate</div>
<div class="dropdown-menu__item" @click="renameCollection">Rename</div>
<div class="dropdown-menu__item" @click="removeCollection">Remove</div>
<div class="dropdown-menu__separator"></div>
<div
v-for="sceneCollection in scenesCollections"
v-for="sceneCollection in sceneCollections"
:key="sceneCollection.id"
class="dropdown-menu__item"
:class="{ active: activeConfig === sceneCollection }"
@click="loadConfig(sceneCollection)"
:class="{ active: activeId === sceneCollection.id }"
@click="loadCollection(sceneCollection.id)"
>
{{ sceneCollection }}
{{ sceneCollection.name }}
</div>
</DropdownMenu>

Expand Down
36 changes: 20 additions & 16 deletions app/components/SceneSelector.vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Selector from './Selector.vue';
import { ScenesService } from '../services/scenes';
import { Menu } from '../util/menus/Menu';
import { ScenesTransitionsService } from '../services/scenes-transitions';
import { ScenesCollectionsService } from '../services/scenes-collections/config';
import { SceneCollectionsService } from '../services/scene-collections';
import { AppService } from '../services/app';
import DropdownMenu from './shared/DropdownMenu.vue';
import HelpTip from './shared/HelpTip.vue';
Expand All @@ -16,7 +16,7 @@ import { EDismissable } from 'services/dismissables';
})
export default class SceneSelector extends Vue {
@Inject() scenesService: ScenesService;
@Inject() scenesCollectionsService: ScenesCollectionsService;
@Inject() sceneCollectionsService: SceneCollectionsService;
@Inject() appService: AppService;
@Inject() scenesTransitionsService: ScenesTransitionsService;

Expand Down Expand Up @@ -58,10 +58,6 @@ export default class SceneSelector extends Vue {
this.scenesTransitionsService.showSceneTransitions();
}

loadConfig(configName: string) {
this.appService.loadConfig(configName);
}

get scenes() {
return this.scenesService.scenes.map(scene => {
return {
Expand All @@ -71,12 +67,16 @@ export default class SceneSelector extends Vue {
});
}

get scenesCollections() {
return this.scenesCollectionsService.state.scenesCollections;
get sceneCollections() {
return this.sceneCollectionsService.collections;
}

get activeId() {
return this.sceneCollectionsService.activeCollection.id;
}

get activeConfig() {
return this.scenesCollectionsService.state.activeCollection;
get activeCollection() {
return this.sceneCollectionsService.activeCollection;
}

get activeSceneId() {
Expand All @@ -87,26 +87,30 @@ export default class SceneSelector extends Vue {
return null;
}

loadCollection(id: string) {
this.sceneCollectionsService.load(id);
}

addCollection() {
this.scenesCollectionsService.showNameConfig();
this.sceneCollectionsService.showNameConfig();
}


duplicateCollection() {
this.scenesCollectionsService.showNameConfig({
scenesCollectionToDuplicate: this.activeConfig
this.sceneCollectionsService.showNameConfig({
sceneCollectionToDuplicate: this.activeCollection.id
});
}


renameCollection() {
this.scenesCollectionsService.showNameConfig({ rename: true });
this.sceneCollectionsService.showNameConfig({ rename: true });
}


removeCollection() {
if (!confirm(`remove ${this.activeConfig} ?`)) return;
this.appService.removeCurrentConfig();
if (!confirm(`remove ${this.activeCollection.name} ?`)) return;
this.sceneCollectionsService.delete();
}

get helpTipDismissable() {
Expand Down
8 changes: 4 additions & 4 deletions app/components/pages/BrowseOverlays.vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ import { Component } from 'vue-property-decorator';
import { UserService } from '../../services/user';
import { Inject } from '../../util/injector';
import { GuestApiService } from 'services/guest-api';
import { IDownloadProgress } from 'services/scenes-collections';
import { AppService } from 'services/app';
import { NavigationService } from 'services/navigation';
import { SceneCollectionsService } from 'services/scene-collections';
import { IDownloadProgress } from 'services/scene-collections/overlays';
import urlLib from 'url';

@Component({})
export default class BrowseOverlays extends Vue {
@Inject() userService: UserService;
@Inject() guestApiService: GuestApiService;
@Inject() appService: AppService;
@Inject() sceneCollectionsService: SceneCollectionsService;
@Inject() navigationService: NavigationService;

$refs: {
Expand All @@ -38,7 +38,7 @@ export default class BrowseOverlays extends Vue {
return;
}

await this.appService.installOverlay(url, name, progressCallback);
await this.sceneCollectionsService.installOverlay(url, name, progressCallback);
this.navigationService.navigate('Studio');
}

Expand Down
4 changes: 3 additions & 1 deletion app/components/pages/Onboarding.vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import OptimizeB from './onboarding_steps/OptimizeB.vue';
import ObsImport from './onboarding_steps/ObsImport.vue';
import OptimizeC from './onboarding_steps/OptimizeC.vue';
import SuccessfullyImported from './onboarding_steps/SuccessfullyImported.vue';
import SceneCollectionsImport from './onboarding_steps/SceneCollectionsImport.vue';
import SelectWidgets from './onboarding_steps/SelectWidgets.vue';
import { OnboardingService } from '../../services/onboarding';
import { Inject } from '../../util/injector';
Expand All @@ -18,7 +19,8 @@ import { Inject } from '../../util/injector';
ObsImport,
OptimizeC,
SuccessfullyImported,
SelectWidgets
SelectWidgets,
SceneCollectionsImport
}
})
export default class Onboarding extends Vue {
Expand Down
4 changes: 3 additions & 1 deletion app/components/pages/onboarding_steps/Connect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
<div class="signup-buttons">
<button
class="button button--twitch"
:disabled="loadingState"
@click="authPlatform('twitch')">
<i class="fa" :class="iconForPlatform('twitch')" /> Twitch
</button>
<button
class="button button--yt"
:disabled="loadingState"
@click="authPlatform('youtube')">
<i class="fa" :class="iconForPlatform('youtube')" /> Youtube
</button>
Expand All @@ -31,4 +33,4 @@
width: 100%;
justify-content: space-between;
}
</style>
</style>
27 changes: 13 additions & 14 deletions app/components/pages/onboarding_steps/Connect.vue.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
import Vue from 'vue';
import { Component } from 'vue-property-decorator';
import { UserService } from '../../../services/user';
import { TPlatform } from '../../../services/platforms';
import { Inject } from '../../../util/injector';
import { OnboardingService } from '../../../services/onboarding';
import { UserService } from 'services/user';
import { TPlatform } from 'services/platforms';
import { Inject } from 'util/injector';
import { OnboardingService } from 'services/onboarding';

@Component({})
export default class Connect extends Vue {
@Inject() userService: UserService;
@Inject() onboardingService: OnboardingService;

@Inject()
userService: UserService;

@Inject()
onboardingService: OnboardingService;

loadingState: Dictionary<boolean> = {};
loadingState = false;

authPlatform(platform: TPlatform) {
Vue.set(this.loadingState, platform, true);
this.loadingState = true;
this.userService.startAuth(
platform,
() => {
this.loadingState[platform] = false;
this.loadingState = false;
},
() => {
this.loadingState = true;
},
() => {
this.onboardingService.next();
Expand All @@ -30,7 +29,7 @@ export default class Connect extends Vue {
}

iconForPlatform(platform: TPlatform) {
if (this.loadingState[platform]) return 'fa-spinner fa-spin';
if (this.loadingState) return 'fa-spinner fa-spin';

return {
twitch: 'fa-twitch',
Expand Down
9 changes: 4 additions & 5 deletions app/components/pages/onboarding_steps/ObsImport.vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { OnboardingService } from '../../../services/onboarding';
import { Multiselect } from 'vue-multiselect';
import { ObsImporterService } from '../../../services/obs-importer';
import { defer } from 'lodash';
import { ScenesCollectionsService } from '../../../services/scenes-collections';
import { SceneCollectionsService } from 'services/scene-collections';

@Component({
components: { Multiselect }
Expand All @@ -19,7 +19,7 @@ export default class ObsImport extends Vue {
obsImporterService: ObsImporterService;

@Inject()
scenesCollectionsService: ScenesCollectionsService;
sceneCollectionsService: SceneCollectionsService;

status = 'initial';

Expand Down Expand Up @@ -49,11 +49,11 @@ export default class ObsImport extends Vue {

get description() {
if (this.status === 'importing') {
return `Importing your scenes and sources`;
return 'Importing your scenes and sources';
}

if (this.status === 'done') {
return `All scenes, sources and settings have been imported.`;
return 'All scenes, sources and settings have been imported.';
}

return 'Import your scenes and your settings from OBS with a simple click, or start fresh.';
Expand All @@ -73,7 +73,6 @@ export default class ObsImport extends Vue {
}

startFresh() {
this.scenesCollectionsService.switchToBlankConfig();
this.onboardingService.skip();
}

Expand Down
42 changes: 42 additions & 0 deletions app/components/pages/onboarding_steps/SceneCollectionsImport.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<template>
<div>
<div class="onboarding-step">
<div class="onboarding-title">Scene Collections Import</div>
<div class="onboarding-desc">The following scene collections have been imported from your Streamlabs account</div>
<ul class="scene-collections-list">
<li v-for="collection in sceneCollections" :key="collection.id">
{{ collection.name }}
</li>
</ul>
<button
class="button button--action button--lg"
@click="next">
Continue
</button>
</div>
</div>
</template>

<script lang="ts" src="./SceneCollectionsImport.vue.ts"></script>

<style lang="less" scoped>
@import '../../../styles/index';
.scene-collections-list {
margin: 0;
padding: 10px;
width: 100%;
height: 200px;
color: white;
list-style: none;
overflow: auto;
border-radius: 3px;
background: @day-secondary;
}
.night-theme {
.scene-collections-list {
background: @night-secondary;
}
}
</style>
Loading

0 comments on commit f7850b9

Please sign in to comment.