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

feat: set default preview when stream can't be found anymore #181

Merged
merged 14 commits into from
May 30, 2023
9 changes: 5 additions & 4 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"recommendations": [
"Vue.volar",
"Vue.vscode-typescript-vue-plugin"
]
"recommendations": [
"vue.volar",
"vue.vscode-typescript-vue-plugin",
"esbenp.prettier-vscode"
]
}
31 changes: 20 additions & 11 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.tsc.autoDetect": "off",
"json.schemas": [
{
"fileMatch": [
"/*electron-builder.json5",
"/*electron-builder.json"
],
"url": "https://json.schemastore.org/electron-builder"
}
]
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.tsc.autoDetect": "off",
"json.schemas": [
{
"fileMatch": [
"/*electron-builder.json5",
"/*electron-builder.json"
],
"url": "https://json.schemastore.org/electron-builder"
}
],
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.formatOnPaste": false,
"editor.inlineSuggest.enabled": true,
"eslint.enable": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.validate": ["javascript", "typescript"]
}
35 changes: 11 additions & 24 deletions electron/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const indexHtml = join(process.env.DIST, 'index.html');

async function createWindow() {
// Determine the icon file based on the current platform
let iconFile;
let iconFile: string;
switch (process.platform) {
case 'win32':
iconFile = 'icon.ico';
Expand All @@ -56,6 +56,7 @@ async function createWindow() {
default:
iconFile = 'icon.png';
}

win = new BrowserWindow({
title: 'Vigad',
icon: join(process.env.PUBLIC, iconFile),
Expand Down Expand Up @@ -85,14 +86,6 @@ async function createWindow() {
win.loadFile(indexHtml);
}

// Test actively push message to the Electron-Renderer
win.webContents.on('did-finish-load', () => {
win?.webContents.send(
'main-process-message',
new Date().toLocaleString()
);
});

// Make all links open with the browser, not with the application
win.webContents.setWindowOpenHandler(({ url }) => {
if (url.startsWith('https:')) shell.openExternal(url);
Expand All @@ -103,15 +96,6 @@ async function createWindow() {

// Get all screens/windows from the main process to the renderer process
ipcMain.handle('get-screens', getScreen);
ipcMain.handle('minimize-screen', () => {
win.minimize();
});
ipcMain.handle('full-screen', () => {
win.isMaximized() ? win.restore() : win.maximize();
});
ipcMain.handle('close-application', () => {
win.close();
});
}

// This method will be called when Electron has finished
Expand Down Expand Up @@ -161,13 +145,16 @@ ipcMain.handle('open-win', (_, arg) => {
}
});

async function getScreen(event, title) {
// In the main process.
async function getScreen() {
const { desktopCapturer } = require('electron');

const allSources = await desktopCapturer.getSources({
types: ['window', 'screen'],
});
try {
const allSources = await desktopCapturer.getSources({
types: ['window', 'screen'],
});

return allSources;
return allSources;
} catch (error) {
throw new Error('Failed to capture sources: ' + error.message);
}
}
46 changes: 12 additions & 34 deletions electron/preload/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,41 +95,19 @@ setTimeout(removeLoading, 4999);

// ! Working with informations from the main process and the renderer process
const { contextBridge, ipcRenderer } = require('electron');
const remote = require('@electron/remote/main');

contextBridge.exposeInMainWorld('electronAPI', {
getMedia: () => ipcRenderer.invoke('get-screens'),
minimizeScreen: () => ipcRenderer.invoke('minimize-screen'),
fullScreen: () => ipcRenderer.invoke('full-screen'),
closeApplication: () => ipcRenderer.invoke('close-application'),
});

ipcRenderer.on('SET_SOURCE', async (event, sourceId) => {
try {
const stream = await navigator.mediaDevices.getUserMedia({
audio: false,
video: {
mandatory: {
chromeMediaSource: 'desktop',
chromeMediaSourceId: sourceId,
minWidth: 1280,
maxWidth: 3840,
minHeight: 720,
maxHeight: 2160,
},
},
getMedia: () => {
return new Promise((resolve, reject) => {
ipcRenderer
.invoke('get-screens')
.then((media) => {
resolve(media);
})
.catch((error) => {
reject(error);
});
});
handleStream(stream);
} catch (e) {
handleError(e);
}
},
});

function handleStream(stream) {
const video = document.querySelector('video');
video.srcObject = stream;
video.onloadedmetadata = (e) => video.play();
}

function handleError(e) {
console.log(e);
}
23 changes: 8 additions & 15 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,30 +37,23 @@
</template>

<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { onMounted } from 'vue';
import { useRouter } from 'vue-router';
import MainVideoStream from '@/components/MainVideoStream/MainVideoStream.vue';
import Navigation from '@/components/Navigation/Navigation.vue';
import NotificantionProvider from '@/components/Notifications/NotificationProvider/NotificationProvider.vue';
import { NotificationAnchorPosition } from '@/components/Notifications/NotificationAnchorPosition';

// Handle System Bar Functions for later
async function minimizeScreen() {
await (window as any).electronAPI.minimizeScreen();
}

async function fullScreen() {
await (window as any).electronAPI.fullScreen();
}

async function closeApplication() {
await (window as any).electronAPI.closeApplication();
}
import useStreamHandler from '@/composables/useStreamHandler/useStreamHandler';

// Force the application to navigate to the default route
const router = useRouter();

onMounted(() => {
// Get the default preview video stream function
const { setDefaultPreviewVideoStream } = useStreamHandler();

onMounted(async () => {
// set the default preview video stream
await setDefaultPreviewVideoStream();
// navigate to the default route
router.push('/');
});
Expand Down
53 changes: 30 additions & 23 deletions src/components/MainVideoStream/MainVideoStream.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div class="video-stream">
<v-responsive id="stream" ref="stream" class="capture-area-selection">
<video preload="none" id="mainVideo" class="video" autoplay></video>
<video preload="none" class="video" autoplay ref="videoRef"></video>
<VueDragResize
v-if="isRerendering"
v-for="captureArea in captureAreas"
Expand Down Expand Up @@ -37,23 +37,42 @@
</template>

<script setup lang="ts">
import { ref, onMounted, watch } from 'vue';
import { ref, watch } from 'vue';
import { useElementSize } from '@vueuse/core';
import { Vigad } from '@/proc/Vigad';
// @ts-ignore
import VueDragResize from 'vue3-drag-resize';
import { isRerendering } from '@/composables/useForceRerender/useForceRerender';
import { Rectangle } from './Rectangle';
import useStreamHandler from '@/composables/useStreamHandler/useStreamHandler';
import useNotificationSystem from '@/composables/useNotificationSystem/useNotificationSystem';
// @ts-ignore
import VueDragResize from 'vue3-drag-resize';

/**
* Get singelton instance reference to vigad
* Get reference to the video element that is used to preview the video stream of the main screen
*/
const vigad = ref(Vigad.getInstance());
const { currentSelectedSource } = useStreamHandler();
const videoRef = ref<any>(null);

/**
* Get singelton instance reference to streamHandler
* Set Video Sources Preview to the main screen (the one that is selected)
*/
watch(currentSelectedSource, (newSource) => {
try {
if (newSource && videoRef.value) {
videoRef.value.srcObject = newSource;
}
} catch (error) {
useNotificationSystem().createErrorNotification({
title: 'An error occured while setting the preview video stream',
message: 'Please restart the application and try again.',
});
}
});

/**
* Get singelton instance reference to vigad
*/
const streamHandler = vigad.value.getStreamHandlerInstance();
const vigad = ref(Vigad.getInstance());

/**
* Get reference to all the capture areas that are currently active
Expand All @@ -74,14 +93,6 @@ watch(hParent, (newValue) => {
vigad.value.setPreviewHeight(newValue);
});

/**
* fetches everything and sets the main video stream to the main screen
*/
async function setDefaultVideoStream() {
// set the default video stream to the main screen
await streamHandler.setDefaultVideoStream();
}

/**
* fetches everything and sets the main video stream to the main screen
*/
Expand All @@ -101,29 +112,25 @@ function changeSize(newRect: Rectangle, item: any) {
item.top = newRect.top;
item.left = newRect.left;
}

/**
* On Mount of this component set the default video stream
*/
onMounted(() => {
setDefaultVideoStream();
});
</script>

<style lang="scss" scoped>
.video-stream {
width: inherit;
height: inherit;
align-self: center;

.capture-area-selection {
margin: 0 auto;
width: fit-content;

.video {
width: 100%;
max-height: calc(100vh - 56px - 16px - 16px);
}
}
}

.draggable-capture-area {
text-align: center;
background-color: rgba($color: #03dac6, $alpha: 0.15);
Expand Down
1 change: 1 addition & 0 deletions src/components/ViewComponent/ViewComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const props = defineProps<{
display: flex;
justify-content: space-between;
}

.scrollable {
max-height: calc(100vh - 56px - 16px - 16px - 68px - 16px);
overflow: auto;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,20 +93,17 @@ const afterConstraint = vigad.value
.getRegexGroups()[0]
.getConstraintRegex()[1];


/**
* Gives a notficiation after deletion of capture area
* @param captureAreaId
*/
function deleteCaptureAreaNotification(id: number): void{
* Gives a notficiation after deletion of capture area
* @param captureAreaId
*/
function deleteCaptureAreaNotification(id: number): void {
useNotificationSystem().createWarningNotification({
title: 'Capture Area Deleted',
message: 'The Capture Area ' + id + ' got deleted'
title: 'Capture Area Deleted',
message: 'The Capture Area ' + id + ' got deleted',
});
vigad.value.deleteCaptureArea(id);

}

</script>

<style lang="scss" scoped>
Expand Down
Loading