Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: OBS as source of truth for hotkeys #1054

Merged
merged 3 commits into from
Dec 15, 2018
Merged

WIP: OBS as source of truth for hotkeys #1054

merged 3 commits into from
Dec 15, 2018

Conversation

blackxored
Copy link
Contributor

Initial support for using OBS as the source of truth for hotkeys.

app/services/hotkeys.ts Outdated Show resolved Hide resolved
@blackxored blackxored force-pushed the refactor/hotkeys branch 3 times, most recently from 01c7b61 to 54a2f8e Compare November 29, 2018 20:23
@AppVeyorBot
Copy link

❌ build failed

@AppVeyorBot
Copy link

❌ build failed

1 similar comment
@AppVeyorBot
Copy link

❌ build failed

@blackxored blackxored force-pushed the refactor/hotkeys branch 2 times, most recently from 53c7fcd to 4f43d1d Compare December 12, 2018 21:59
@AppVeyorBot
Copy link

❌ build failed

1 similar comment
@AppVeyorBot
Copy link

❌ build failed

@@ -476,6 +476,7 @@ export class SceneCollectionsService extends Service

await this.loadDataIntoApplicationState(data);
} catch (e) {
console.error('Error while loading collection, restoring backup', e);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


HOTKEY_ACTIONS.GENERAL.forEach(action => {
Object.values(GENERAL_ACTIONS).forEach(action => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK this is the only place you're using the *_ACTIONS objects so i'm kind of wondering why you refactored them into objects? if you only use them to turn back into arrays it just seems like it's adding in an extra step, but i might be missing something here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will peel them off, one by one. Easier to have them separate to differentiate logic (such as general being run first and not having to duplicate-check), does that make sense?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i understand breaking them up into chunks, but the data transformation from array into object -> array is where i'm lost

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need these indexed for getActionFromName and normalization, in the future, this could be a way to improve performance in lookups as well.

Object.keys(hotkeySet.sources).forEach(sourceId => hotkeys.push(...hotkeySet.sources[sourceId]));
Object.keys(hotkeySet.sources).forEach(sourceId =>
hotkeys.push(...hotkeySet.sources[sourceId]),
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are these all automatic linter changes? i feel like we should change the config because we use single line ifs and anonymous functions all the time

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For style issues, I believe we should focus our effort on #1129. I believe it'd be wasteful to change something back to just change it again (or not) in the other branch. This might've been before we merged #1043, so I apologize if it was a result of my editor and switching branches.


const getActionFromName = (actionName: string) => {
return ACTIONS[actionName] || ACTIONS[getMigrationMapping(actionName)];
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure why this and the above are using manual returns

Copy link
Contributor Author

@blackxored blackxored Dec 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed getActionFromName. I believe getMigrationMapping should stay this way due to a somewhat complex expression and the fact we're using an object.

}
};

const normalizeActionName = (actionName: string) => actionName.split('.')[0];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i feel like utility functions should be defined above the class, we already have several examples of that in this file. open to putting them after but either way i think it should be consistent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree 100% with this, however I've mixed feelings about it. There wasn't an easy choice, as I believe the most important thing for us looking at this file would be
Types -> Consts -> Class -> Utils
Unfortunately, the functions you see above Class are there because of no-use-before-define. The rest is supporting and I believe should stay out of the way at the end. Unless we really want them in our way before we get to read the class, that is.

ISceneCreateOptions,
IScenesServiceApi
Scene,
SceneItem,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure why these imports change order? it just seems like dirtying the diff for no actual reason

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd be great if we started sorting imports, it's recommended by pretty much everyone. Relevant rule: https://eslint.org/docs/rules/sort-imports.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes of this file have to be excluded from this PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you mean? We need the scene dedup that's in here.

height: 250
}
height: 250,
},
});
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it doesn't look like anything was actually changed in this file apart from style changes? i think we should keep those in separate PRs to reduce diff size and cognitive load when reviewing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've added scene dedup and typed a few functions. While I see your point about having style diffs here, these kinds of style changes wouldn't be an issue anymore, shortly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea that was more a future consideration than something to change for this PR

isActive: () => getTransitionsService().state.studioMode
isActive: () => {
const streamingService = getStreamingService();
return !streamingService.isStreaming;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't see a reason why you replaced one line expression to the 2 lines

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please paste the line? I'm not entirely sure what you're referring to in this particular case.

interface IHotkeysServiceState {
hotkeys: IHotkey[]; // only bound hotkeys are stored
}

type OBSHotkey = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually use T prefix for types

type TOBSHotkey

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only to disambiguate, no?

upHandler?(): void;
}

type HotkeyGroup = {
[x: string]: IHotkeyAction;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is x? I assume it must be actionName here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is conventional indexer syntax in TS, do you think having actionName would really increase readability?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed

ISceneCreateOptions,
IScenesServiceApi
Scene,
SceneItem,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes of this file have to be excluded from this PR


type THotkeyType = 'GENERAL' | 'SCENE' | 'SCENE_ITEM' | 'SOURCE';
const isAudio = (sourceId: string) => {
const source = getSourcesService().getSource(sourceId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really possible to get source = null in this function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, in my testing

@AppVeyorBot
Copy link

❌ build failed

return this.state.displayOrder.map(id => {
return this.getScene(id);
});
return uniqBy(this.state.displayOrder.map(id => this.getScene(id)), x => x.id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's looks like a bug symptom fix. Can you please describe this bug in the TODO comment before this line and add a task to Asana with steps how to reproduce this issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added it closer to where the bug happens.

@@ -1,4 +1,6 @@
import Vue from 'vue';
import { uniqBy } from 'lodash';
import { Subject } from 'rxjs';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which one exactly? Both uniqBy and Subject are used.

@AppVeyorBot
Copy link

❌ build failed

* support display capture hotkeys.
* fix issues with duplicate scenes.
* support sending keyup events to OBS backend.
* log error when scene collection fails to load.

Now we can process `SHOW_SCENE_ITEM` and `HIDE_SCENE_ITEM` without
getting duplicate scenes in `SceneSelector`, coming from the service.
An uniqueness check was added to the getter for scenes that checks
based on scene ID.

If we fail to load an scene collection, the behavior appears to be
trying to restore from backup. This causes the loading of application
state to be invoked a second time, with unexpected side-effects like
duplicate scenes. This commit addresses the visibility part by
displaying an error message for developers as opposed to swallowing the
error entirely. Prior to this, we addressed the second part of one of
those visible effects by adding uniqueness checks in the scenes API.

* Fortifies checking for a source's type in case it cannot be found in
the service (it has happened).
* Fix action names for `TOGGLE_MUTE` and `TOGGLE_UNMUTE`.
* Track added hotkeys on a set for the time being, ensuring we don't
add duplicates coming from OBS that we're already handling.
* Add explicit check for whether the returned item belongs to a scene
hotkey.

Please notice that currently identifying which kind of hotkey we got
from the backend is factorial as we don't seem to have a better way to
get this info from the backend. The number of hotkeys affected by this
is minimal (the main reason we're sticking to the former loops for now)
but could still be significant. I have not, however, profiled this.
@avacreeth avacreeth merged commit bced379 into staging Dec 15, 2018
@avacreeth avacreeth deleted the refactor/hotkeys branch December 15, 2018 01:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants