Skip to content

Commit

Permalink
Merge pull request #26 from mlsof21/prevent-other-tabs
Browse files Browse the repository at this point in the history
Prevent other tabs
  • Loading branch information
mlsof21 committed Oct 4, 2022
2 parents 4a15c50 + 19b8119 commit eb7480e
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 111 deletions.
111 changes: 58 additions & 53 deletions CHANGELOG.md
@@ -1,53 +1,58 @@
### 1.2.0 - 2022-09-24 - Always Listening

- Added a toggle-able `Always Listening` mode
- Each command must be prefixed with an activation phrase (defaulted to `okay ghost`)
- Added fix for `maxPower` command (didn't work in normal DIM, only in beta)
- Added fix for search already being populated when performing a command.

### 1.1.3 - 2022-09-20 - Perk fix

- Fixed perk matching

### 1.1.2 - 2022-09-19 - Options page links

- Added an `onInstalled` event for the extension. It'll direct users to the options page.
- Link to the options page from the `?`

### 1.1.1 - 2022-09-16 - Better performance

- Use a `waitForElement/waitForSearchToUpdate` function instead of arbitrarily sleeping in code
- Results in at least a 300% improvement in action duration

### 1.1.0 - 2022-09-13 - The One with Custom Commands

- Quite a few changes in this one
- Reworked how the extension waits for the search to update visible (not dimmed) items
- Really reworked how all UI interactions are performed
- Added the ability to customize the command words for particular actions
- Visit the options page (click the extension icon) to set these
- Added a `store` command for storing items in the vault
- Added an `equip` command for directly equipping an item on your current character (when possible)
- This works like how `transfer` previously did, and `transfer` has been updated to only transfer, not equip
- (from above) `Transfer` now only transfers instead of equipping
- Added mic icon on page with a link to the website
- When listening, there will be text next to the icon that updates as the user speaks their command
- Added link to the [Voice DIM website](https://www.voicedim.com) via the `?` icon.
- Fixed `Start Farming mode` command if a user has at least 10 loadouts saved

### 1.0.1 - 2022-08-23 - Corrected Shortcut

- Defaulted the shortcut correctly (set to `Ctrl+Shift+0`)

### 1.0.0 - 2022-08-19 - Initial Release

- See [Reddit post](https://www.reddit.com/r/DestinyTheGame/comments/wseigx/interact_with_dim_using_your_voice/) about the available commands with more info
- Commands are available to:
- Transfer a weapon by name
- Transfer a weapon with particular perks
- Transfer a weapon by attribute (energy type, slot, ammo type, etc)
- Collect from the postmaster
- Start/Stop farming mode
- Equip loadouts by name
- Equip max power
- Use global shortcut to activate listening
### 1.2.1 - 2022-10-03 - Only in Inventory

- Added fix for loading DIM on another tab. Previously required reloading the page on the inventory tab. Now Voice DIM will load no matter what page is started on
- Added fix for a user having the item popup sidebar being collapsed.

### 1.2.0 - 2022-09-24 - Always Listening

- Added a toggle-able `Always Listening` mode
- Each command must be prefixed with an activation phrase (defaulted to `okay ghost`)
- Added fix for `maxPower` command (didn't work in normal DIM, only in beta)
- Added fix for search already being populated when performing a command.

### 1.1.3 - 2022-09-20 - Perk fix

- Fixed perk matching

### 1.1.2 - 2022-09-19 - Options page links

- Added an `onInstalled` event for the extension. It'll direct users to the options page.
- Link to the options page from the `?`

### 1.1.1 - 2022-09-16 - Better performance

- Use a `waitForElement/waitForSearchToUpdate` function instead of arbitrarily sleeping in code
- Results in at least a 300% improvement in action duration

### 1.1.0 - 2022-09-13 - The One with Custom Commands

- Quite a few changes in this one
- Reworked how the extension waits for the search to update visible (not dimmed) items
- Really reworked how all UI interactions are performed
- Added the ability to customize the command words for particular actions
- Visit the options page (click the extension icon) to set these
- Added a `store` command for storing items in the vault
- Added an `equip` command for directly equipping an item on your current character (when possible)
- This works like how `transfer` previously did, and `transfer` has been updated to only transfer, not equip
- (from above) `Transfer` now only transfers instead of equipping
- Added mic icon on page with a link to the website
- When listening, there will be text next to the icon that updates as the user speaks their command
- Added link to the [Voice DIM website](https://www.voicedim.com) via the `?` icon.
- Fixed `Start Farming mode` command if a user has at least 10 loadouts saved

### 1.0.1 - 2022-08-23 - Corrected Shortcut

- Defaulted the shortcut correctly (set to `Ctrl+Shift+0`)

### 1.0.0 - 2022-08-19 - Initial Release

- See [Reddit post](https://www.reddit.com/r/DestinyTheGame/comments/wseigx/interact_with_dim_using_your_voice/) about the available commands with more info
- Commands are available to:
- Transfer a weapon by name
- Transfer a weapon with particular perks
- Transfer a weapon by attribute (energy type, slot, ammo type, etc)
- Collect from the postmaster
- Start/Stop farming mode
- Equip loadouts by name
- Equip max power
- Use global shortcut to activate listening
7 changes: 4 additions & 3 deletions package.json
@@ -1,13 +1,14 @@
{
"name": "voice-dim",
"version": "1.2.0",
"version": "1.2.1",
"description": "Perform common DIM actions by using speech recognition.",
"main": "dist/chrome/js/voice-dim.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"zip": "npm run build && python scripts/build.py",
"build": "rimraf dist/ && webpack --env mode=production --config webpack.config.js",
"watch": "webpack --env mode=development --config webpack.config.js --progress --watch"
"watch": "webpack --env mode=development --config webpack.config.js --progress --watch",
"update-version": "python scripts/update_version.py"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -45,4 +46,4 @@
"webpack-cli": "^4.10.0",
"webpack-visualizer-plugin2": "^1.0.0"
}
}
}
4 changes: 2 additions & 2 deletions public/manifest.chrome.json
@@ -1,14 +1,14 @@
{
"name": "Voice DIM",
"description": "Control DIM with your voice.",
"version": "1.2.0",
"version": "1.2.1",
"manifest_version": 3,
"background": {
"service_worker": "js/background.js"
},
"content_scripts": [
{
"matches": ["https://*.destinyitemmanager.com/*inventory"],
"matches": ["https://*.destinyitemmanager.com/*"],
"js": ["js/voiceDim.js"],
"css": ["css/voiceDim.css"]
}
Expand Down
2 changes: 1 addition & 1 deletion public/manifest.firefox.json
@@ -1,7 +1,7 @@
{
"name": "Voice DIM",
"description": "Control DIM with your voice.",
"version": "1.2.0",
"version": "1.2.1",
"manifest_version": 2,
"background": {
"scripts": ["js/background.js"]
Expand Down
38 changes: 32 additions & 6 deletions scripts/update_version.py
@@ -1,3 +1,4 @@
from datetime import datetime
import getopt
import json
import os
Expand Down Expand Up @@ -37,31 +38,54 @@ def get_next_version(current_version: str, part_to_update: str):
return f"{major_version}.{minor_version}.{bugfix_version}"


def write_new_version(file_path, new_version):
def write_new_version(file_path: str, new_version: str, dry_run: bool = False):
with open(file_path, 'r') as f:
data = json.load(f)

data['version'] = f"{new_version}"

if dry_run:
return

with open(file_path, 'w') as f:
json.dump(data, f, indent=4)
json.dump(data, f, indent=2)


def write_changelog_update(file_path: str, new_version: str, dry_run: bool = False):
with open(file_path, 'r') as f:
data = f.read()

if data.find(new_version) < 0:
now = datetime.now()
date = now.strftime('%Y-%m-%d')

data = f"### {new_version} - {date} - <title>\n\n- <insert changes>\n\n{data}"
print(data)

if dry_run:
return

with open(file_path, 'w') as f:
f.write(data)


def main():
argument_list = sys.argv[1:]
options = 'p:'
long_options = "part="
options = 'dp:'
long_options = ["dry-run", "part="]
# Parsing argument
arguments, values = getopt.getopt(argument_list, options, long_options)
part = 'bugfix'
dry_run = False
# checking each argument
for current_arg, current_value in arguments:

if current_arg in ("-p", "--part"):
if current_value in ('major', 'minor', 'bugfix'):
part = current_value
else:
print("No part provided. Updating the bugfix version by default")
if current_arg in ('-d', '--dry-run'):
dry_run = True

git_root = get_git_root(os.getcwd())
files = [git_root + '/public/manifest.chrome.json', git_root +
Expand All @@ -86,7 +110,9 @@ def main():
print(next_version)

for file in files:
write_new_version(file, next_version)
write_new_version(file, next_version, dry_run)

write_changelog_update(git_root+"/CHANGELOG.md", next_version, dry_run)


if __name__ == "__main__":
Expand Down
36 changes: 27 additions & 9 deletions src/ts/background.ts
Expand Up @@ -2,18 +2,36 @@ import { infoLog } from './common';

chrome.commands.onCommand.addListener((command: any) => {
infoLog('voice dim', `Command "${command}" triggered`);
sendDimTabMessage({ dimShortcutPressed: true });
});

chrome.tabs.query({}, (tabs: any[]) => {
const dimTabs = tabs.filter((tab: { url: string }) => tab.url?.match(/destinyitemmanager\.com.*inventory/));

if (dimTabs && dimTabs[0]?.id)
chrome.tabs.sendMessage(dimTabs[0].id, { dimShortcutPressed: true }, (response: any) => {
infoLog('voice dim', { response });
});
});
chrome.tabs.onUpdated.addListener(async function (tabId, changeInfo, tab) {
const dimTabId = await getDimTabId();
if (dimTabId && tabId === dimTabId) {
if (changeInfo.url && !changeInfo.url.includes('inventory')) {
sendDimTabMessage('not on inventory page');
} else if (changeInfo.url && changeInfo.url.includes('inventory')) {
sendDimTabMessage('on inventory page');
}
}
});

chrome.runtime.onMessage.addListener((data: any) => {
async function getDimTabId(): Promise<number | undefined | null> {
const dimTabs = await chrome.tabs.query({ url: 'https://*.destinyitemmanager.com/*' });
return dimTabs && dimTabs.length >= 1 ? dimTabs[0]?.id : null;
}
async function sendDimTabMessage(message: any) {
const dimTabId = await getDimTabId();
if (dimTabId) {
infoLog('message', 'sending', message);

chrome.tabs.sendMessage(dimTabId, message, (response: any) => {
infoLog('voice dim', { response });
});
}
}

chrome.runtime.onMessage.addListener((data: any, sender: chrome.runtime.MessageSender) => {
infoLog('voice dim', { data });
if (data === 'showOptions') {
openOptionsPage();
Expand Down
19 changes: 9 additions & 10 deletions src/ts/common.ts
@@ -1,12 +1,11 @@
export interface Action {
func: () => void;
timeout: number;
}

export function infoLog(tag: string, message: unknown, ...args: unknown[]) {
console.log(`[${tag}]`, message, ...args);
}

export function debugLog(tag: string, message: unknown, ...args: unknown[]) {
console.debug(`[${tag}]`, message, ...args);
}

export const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

export const debounce = <F extends (...args: Parameters<F>) => ReturnType<F>>(func: F, waitFor: number = 300) => {
Expand Down Expand Up @@ -54,16 +53,16 @@ export async function waitForElementToDisplay(
checkFrequencyInMs: number = 50,
timeoutInMs: number = 2000
): Promise<Element | null> {
return new Promise((resolve) => {
return new Promise((resolve, reject) => {
var startTimeInMs = Date.now();
(function loopSearch() {
if (document.querySelector(selector) != null) {
return resolve(document.querySelector(selector));
} else {
setTimeout(function () {
if (timeoutInMs && Date.now() - startTimeInMs > timeoutInMs) {
infoLog('voice dim', "couldn't find", selector);
return;
debugLog('voice dim', "couldn't find", selector);
return reject();
}
loopSearch();
}, checkFrequencyInMs);
Expand Down Expand Up @@ -93,13 +92,13 @@ export const DEFAULT_ALWAYS_LISTENING: AlwaysListening = {
activationPhrase: 'okay ghost',
};

export function store(key: string, value: any) {
export function store<T>(key: string, value: T) {
chrome.storage.local.set({ [key]: value }, () => {
infoLog('voice dim', 'Stored', key, value);
});
}

export function retrieve(key: string, defaultValue: any): Promise<any> {
export function retrieve<T>(key: string, defaultValue: T): Promise<T> {
return new Promise((resolve, reject) => {
chrome.storage.local.get([key], function (result) {
if (chrome.runtime.lastError) {
Expand Down
12 changes: 9 additions & 3 deletions src/ts/options.ts
Expand Up @@ -13,7 +13,7 @@ function onCommandChange() {
Object.keys(DEFAULT_COMMANDS).forEach((command) => {
commands[command] = getTextValueById(command);
});
store('commands', commands);
store<Record<string, string[]>>('commands', commands);

updateSaveText(true, 'Saved!');
setTimeout(() => updateSaveText(false), 3000);
Expand Down Expand Up @@ -46,7 +46,10 @@ function onActivationPhraseChange() {
updateSaveText(true, 'Saved!');
setTimeout(() => updateSaveText(false), 3000);

store('alwaysListening', { active: listeningToggle.checked, activationPhrase: activationPhrase.value });
store<AlwaysListening>('alwaysListening', {
active: listeningToggle.checked,
activationPhrase: activationPhrase.value,
});
sendListenOptionsMessage();
}

Expand All @@ -56,7 +59,10 @@ function onAlwaysListeningChange(listeningOptions: AlwaysListening) {
updateSaveText(true, 'Saved!');
setTimeout(() => updateSaveText(false), 3000);

store('alwaysListening', { active: listeningOptions.active, activationPhrase: listeningOptions.activationPhrase });
store<AlwaysListening>('alwaysListening', {
active: listeningOptions.active,
activationPhrase: listeningOptions.activationPhrase,
});
sendListenOptionsMessage();
}

Expand Down

0 comments on commit eb7480e

Please sign in to comment.