diff --git a/.gitignore b/.gitignore index f228309b..7f5933a1 100644 --- a/.gitignore +++ b/.gitignore @@ -131,5 +131,6 @@ projects/app/electron/app # browser extention /extension/next +extension/*.html /*.crx /*.pem \ No newline at end of file diff --git a/android/app/src/main/java/deep/app/MainActivity.java b/android/app/src/main/java/deep/app/MainActivity.java deleted file mode 100644 index a141d603..00000000 --- a/android/app/src/main/java/deep/app/MainActivity.java +++ /dev/null @@ -1,5 +0,0 @@ -package deep.app; - -import com.getcapacitor.BridgeActivity; - -public class MainActivity extends BridgeActivity {} diff --git a/android/variables.gradle b/android/variables.gradle index 777bd7e8..49cd9e90 100644 --- a/android/variables.gradle +++ b/android/variables.gradle @@ -1,3 +1,19 @@ +ext { + minSdkVersion = 22 + compileSdkVersion = 32 + targetSdkVersion = 32 + androidxActivityVersion = '1.4.0' + androidxAppCompatVersion = '1.4.2' + androidxCoordinatorLayoutVersion = '1.2.0' + androidxCoreVersion = '1.8.0' + androidxFragmentVersion = '1.4.1' + coreSplashScreenVersion = '1.0.0-rc01' + androidxWebkitVersion = '1.4.0' + junitVersion = '4.13.2' + androidxJunitVersion = '1.1.3' + androidxEspressoCoreVersion = '3.4.0' + cordovaAndroidVersion = '10.1.1' +} ext { minSdkVersion = 22 compileSdkVersion = 32 diff --git a/electron/.gitignore b/electron/.gitignore deleted file mode 100644 index c340937a..00000000 --- a/electron/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# NPM renames .gitignore to .npmignore -# In order to prevent that, we remove the initial "." -# And the CLI then renames it -app -node_modules -build -dist -logs diff --git a/electron/assets/512x512.png b/electron/assets/512x512.png deleted file mode 100644 index f194b6e1..00000000 Binary files a/electron/assets/512x512.png and /dev/null differ diff --git a/electron/assets/appIcon.icns b/electron/assets/appIcon.icns deleted file mode 100644 index 69d902c5..00000000 Binary files a/electron/assets/appIcon.icns and /dev/null differ diff --git a/electron/assets/appIcon.ico b/electron/assets/appIcon.ico deleted file mode 100644 index 75c3044c..00000000 Binary files a/electron/assets/appIcon.ico and /dev/null differ diff --git a/electron/assets/appIcon.png b/electron/assets/appIcon.png deleted file mode 100644 index e58dfb9e..00000000 Binary files a/electron/assets/appIcon.png and /dev/null differ diff --git a/electron/assets/appIconBig.png b/electron/assets/appIconBig.png deleted file mode 100644 index 924b04b8..00000000 Binary files a/electron/assets/appIconBig.png and /dev/null differ diff --git a/electron/assets/splash.gif b/electron/assets/splash.gif deleted file mode 100644 index 5ee8351b..00000000 Binary files a/electron/assets/splash.gif and /dev/null differ diff --git a/electron/assets/splash.png b/electron/assets/splash.png deleted file mode 100644 index ce554d18..00000000 Binary files a/electron/assets/splash.png and /dev/null differ diff --git a/electron/live-runner.js b/electron/live-runner.js deleted file mode 100644 index 84c3ea73..00000000 --- a/electron/live-runner.js +++ /dev/null @@ -1,75 +0,0 @@ -/* eslint-disable no-undef */ -/* eslint-disable @typescript-eslint/no-var-requires */ -const cp = require('child_process'); -const chokidar = require('chokidar'); -const electron = require('electron'); - -let child = null; -const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm'; -const reloadWatcher = { - debouncer: null, - ready: false, - watcher: null, - restarting: false, -}; - -///* -function runBuild() { - return new Promise((resolve, _reject) => { - let tempChild = cp.spawn(npmCmd, ['run', 'build']); - tempChild.once('exit', () => { - resolve(); - }); - tempChild.stdout.pipe(process.stdout); - }); -} -//*/ - -async function spawnElectron() { - if (child !== null) { - child.stdin.pause(); - child.kill(); - child = null; - await runBuild(); - } - child = cp.spawn(electron, ['--inspect=5858', './']); - child.on('exit', () => { - if (!reloadWatcher.restarting) { - process.exit(0); - } - }); - child.stdout.pipe(process.stdout); -} - -function setupReloadWatcher() { - reloadWatcher.watcher = chokidar - .watch('./src/**/*', { - ignored: /[/\\]\./, - persistent: true, - }) - .on('ready', () => { - reloadWatcher.ready = true; - }) - .on('all', (_event, _path) => { - if (reloadWatcher.ready) { - clearTimeout(reloadWatcher.debouncer); - reloadWatcher.debouncer = setTimeout(async () => { - console.log('Restarting'); - reloadWatcher.restarting = true; - await spawnElectron(); - reloadWatcher.restarting = false; - reloadWatcher.ready = false; - clearTimeout(reloadWatcher.debouncer); - reloadWatcher.debouncer = null; - reloadWatcher.watcher = null; - setupReloadWatcher(); - }, 500); - } - }); -} - -(async () => { - await runBuild(); - await spawnElectron(); - setupReloadWatcher(); -})(); diff --git a/electron/patch-electron-builder.js b/electron/patch-electron-builder.js deleted file mode 100644 index fed0b787..00000000 --- a/electron/patch-electron-builder.js +++ /dev/null @@ -1,13 +0,0 @@ -const fs = require('fs'); -const delimetr = process.platform === 'win32' ? '\\' : '/'; -const badboy = `node_modules${delimetr}app-builder-lib${delimetr}out${delimetr}fileMatcher.js`; - -try { - console.log('patching electron-builder'); - let code = fs.readFileSync(badboy).toString(); - if (!code) throw new Error('file for patch not found'); - code = code.indexOf(',d.ts') ? code.replace(',d.ts', '') : code.replace('d.ts', ''); - fs.writeFileSync(badboy, code); -} catch(err) { - console.error(err); -} \ No newline at end of file diff --git a/electron/resources/electron-publisher-custom.js b/electron/resources/electron-publisher-custom.js deleted file mode 100644 index 6e0821ef..00000000 --- a/electron/resources/electron-publisher-custom.js +++ /dev/null @@ -1,10 +0,0 @@ -/* eslint-disable no-undef */ -/* eslint-disable @typescript-eslint/no-var-requires */ -const electronPublish = require('electron-publish'); - -class Publisher extends electronPublish.Publisher { - async upload(task) { - console.log('electron-publisher-custom', task.file); - } -} -module.exports = Publisher; diff --git a/electron/src/preload.ts b/electron/src/preload.ts deleted file mode 100644 index c817d3b7..00000000 --- a/electron/src/preload.ts +++ /dev/null @@ -1,4 +0,0 @@ -require('./rt/electron-rt'); -////////////////////////////// -// User Defined Preload scripts below -console.log('User Preload!'); diff --git a/electron/src/rt/electron-plugins.js b/electron/src/rt/electron-plugins.js deleted file mode 100644 index b33b2826..00000000 --- a/electron/src/rt/electron-plugins.js +++ /dev/null @@ -1,4 +0,0 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ - -module.exports = { -} \ No newline at end of file diff --git a/electron/src/rt/electron-rt.ts b/electron/src/rt/electron-rt.ts deleted file mode 100644 index f4c701b0..00000000 --- a/electron/src/rt/electron-rt.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { randomBytes } from 'crypto'; -import { ipcRenderer, contextBridge } from 'electron'; -import { EventEmitter } from 'events'; - -//////////////////////////////////////////////////////// -// eslint-disable-next-line @typescript-eslint/no-var-requires -const plugins = require('./electron-plugins'); - -const randomId = (length = 5) => randomBytes(length).toString('hex'); - -const contextApi: { - [plugin: string]: { [functionName: string]: () => Promise }; -} = {}; - -Object.keys(plugins).forEach((pluginKey) => { - Object.keys(plugins[pluginKey]) - .filter((className) => className !== 'default') - .forEach((classKey) => { - const functionList = Object.getOwnPropertyNames(plugins[pluginKey][classKey].prototype).filter( - (v) => v !== 'constructor' - ); - - if (!contextApi[classKey]) { - contextApi[classKey] = {}; - } - - functionList.forEach((functionName) => { - if (!contextApi[classKey][functionName]) { - contextApi[classKey][functionName] = (...args) => ipcRenderer.invoke(`${classKey}-${functionName}`, ...args); - } - }); - - // Events - if (plugins[pluginKey][classKey].prototype instanceof EventEmitter) { - const listeners: { [key: string]: { type: string; listener: (...args: any[]) => void } } = {}; - const listenersOfTypeExist = (type) => - !!Object.values(listeners).find((listenerObj) => listenerObj.type === type); - - Object.assign(contextApi[classKey], { - addListener(type: string, callback: (...args) => void) { - const id = randomId(); - - // Deduplicate events - if (!listenersOfTypeExist(type)) { - ipcRenderer.send(`event-add-${classKey}`, type); - } - - const eventHandler = (_, ...args) => callback(...args); - - ipcRenderer.addListener(`event-${classKey}-${type}`, eventHandler); - listeners[id] = { type, listener: eventHandler }; - - return id; - }, - removeListener(id: string) { - if (!listeners[id]) { - throw new Error('Invalid id'); - } - - const { type, listener } = listeners[id]; - - ipcRenderer.removeListener(`event-${classKey}-${type}`, listener); - - delete listeners[id]; - - if (!listenersOfTypeExist(type)) { - ipcRenderer.send(`event-remove-${classKey}-${type}`); - } - }, - removeAllListeners(type: string) { - Object.entries(listeners).forEach(([id, listenerObj]) => { - if (listenerObj.type === type) { - ipcRenderer.removeListener(`event-${classKey}-${type}`, listenerObj.listener); - delete listeners[id]; - } - }); - - ipcRenderer.send(`event-remove-${classKey}-${type}`); - }, - }); - } - }); -}); - -contextBridge.exposeInMainWorld('CapacitorCustomPlatform', { - name: 'electron', - plugins: contextApi, -}); -//////////////////////////////////////////////////////// diff --git a/electron/src/setup.ts b/electron/src/setup.ts deleted file mode 100644 index d30b0af6..00000000 --- a/electron/src/setup.ts +++ /dev/null @@ -1,233 +0,0 @@ -import type { CapacitorElectronConfig } from '@capacitor-community/electron'; -import { - CapElectronEventEmitter, - CapacitorSplashScreen, - setupCapacitorElectronPlugins, -} from '@capacitor-community/electron'; -import chokidar from 'chokidar'; -import type { MenuItemConstructorOptions } from 'electron'; -import { app, BrowserWindow, Menu, MenuItem, nativeImage, Tray, session } from 'electron'; -import electronIsDev from 'electron-is-dev'; -import electronServe from 'electron-serve'; -import windowStateKeeper from 'electron-window-state'; -import { join } from 'path'; - -// Define components for a watcher to detect when the webapp is changed so we can reload in Dev mode. -const reloadWatcher = { - debouncer: null, - ready: false, - watcher: null, -}; -export function setupReloadWatcher(electronCapacitorApp: ElectronCapacitorApp): void { - reloadWatcher.watcher = chokidar - .watch(join(app.getAppPath(), 'app'), { - ignored: /[/\\]\./, - persistent: true, - }) - .on('ready', () => { - reloadWatcher.ready = true; - }) - .on('all', (_event, _path) => { - if (reloadWatcher.ready) { - clearTimeout(reloadWatcher.debouncer); - reloadWatcher.debouncer = setTimeout(async () => { - electronCapacitorApp.getMainWindow().webContents.reload(); - reloadWatcher.ready = false; - clearTimeout(reloadWatcher.debouncer); - reloadWatcher.debouncer = null; - reloadWatcher.watcher = null; - setupReloadWatcher(electronCapacitorApp); - }, 1500); - } - }); -} - -// Define our class to manage our app. -export class ElectronCapacitorApp { - private MainWindow: BrowserWindow | null = null; - private SplashScreen: CapacitorSplashScreen | null = null; - private TrayIcon: Tray | null = null; - private CapacitorFileConfig: CapacitorElectronConfig; - private TrayMenuTemplate: (MenuItem | MenuItemConstructorOptions)[] = [ - new MenuItem({ label: 'Quit App', role: 'quit' }), - ]; - private AppMenuBarMenuTemplate: (MenuItem | MenuItemConstructorOptions)[] = [ - { role: process.platform === 'darwin' ? 'appMenu' : 'fileMenu' }, - { role: 'viewMenu' }, - ]; - private mainWindowState; - private loadWebApp; - private customScheme: string; - - constructor( - capacitorFileConfig: CapacitorElectronConfig, - trayMenuTemplate?: (MenuItemConstructorOptions | MenuItem)[], - appMenuBarMenuTemplate?: (MenuItemConstructorOptions | MenuItem)[] - ) { - this.CapacitorFileConfig = capacitorFileConfig; - - this.customScheme = this.CapacitorFileConfig.electron?.customUrlScheme ?? 'capacitor-electron'; - - if (trayMenuTemplate) { - this.TrayMenuTemplate = trayMenuTemplate; - } - - if (appMenuBarMenuTemplate) { - this.AppMenuBarMenuTemplate = appMenuBarMenuTemplate; - } - - // Setup our web app loader, this lets us load apps like react, vue, and angular without changing their build chains. - this.loadWebApp = electronServe({ - directory: join(app.getAppPath(), 'app'), - scheme: this.customScheme, - }); - } - - // Helper function to load in the app. - private async loadMainWindow(thisRef: any) { - await thisRef.loadWebApp(thisRef.MainWindow); - } - - // Expose the mainWindow ref for use outside of the class. - getMainWindow(): BrowserWindow { - return this.MainWindow; - } - - getCustomURLScheme(): string { - return this.customScheme; - } - - async init(): Promise { - const icon = nativeImage.createFromPath( - join(app.getAppPath(), 'assets', process.platform === 'win32' ? 'appIcon.ico' : 'appIcon.png') - ); - this.mainWindowState = windowStateKeeper({ - defaultWidth: 1000, - defaultHeight: 800, - }); - // Setup preload script path and construct our main window. - const preloadPath = join(app.getAppPath(), 'build', 'src', 'preload.js'); - this.MainWindow = new BrowserWindow({ - icon, - show: false, - x: this.mainWindowState.x, - y: this.mainWindowState.y, - width: this.mainWindowState.width, - height: this.mainWindowState.height, - webPreferences: { - nodeIntegration: true, - contextIsolation: true, - // Use preload to inject the electron varriant overrides for capacitor plugins. - // preload: join(app.getAppPath(), "node_modules", "@capacitor-community", "electron", "dist", "runtime", "electron-rt.js"), - preload: preloadPath, - }, - }); - this.mainWindowState.manage(this.MainWindow); - - if (this.CapacitorFileConfig.backgroundColor) { - this.MainWindow.setBackgroundColor(this.CapacitorFileConfig.electron.backgroundColor); - } - - // If we close the main window with the splashscreen enabled we need to destory the ref. - this.MainWindow.on('closed', () => { - if (this.SplashScreen?.getSplashWindow() && !this.SplashScreen.getSplashWindow().isDestroyed()) { - this.SplashScreen.getSplashWindow().close(); - } - }); - - // When the tray icon is enabled, setup the options. - if (this.CapacitorFileConfig.electron?.trayIconAndMenuEnabled) { - this.TrayIcon = new Tray(icon); - this.TrayIcon.on('double-click', () => { - if (this.MainWindow) { - if (this.MainWindow.isVisible()) { - this.MainWindow.hide(); - } else { - this.MainWindow.show(); - this.MainWindow.focus(); - } - } - }); - this.TrayIcon.on('click', () => { - if (this.MainWindow) { - if (this.MainWindow.isVisible()) { - this.MainWindow.hide(); - } else { - this.MainWindow.show(); - this.MainWindow.focus(); - } - } - }); - this.TrayIcon.setToolTip(app.getName()); - this.TrayIcon.setContextMenu(Menu.buildFromTemplate(this.TrayMenuTemplate)); - } - - // Setup the main manu bar at the top of our window. - Menu.setApplicationMenu(Menu.buildFromTemplate(this.AppMenuBarMenuTemplate)); - - // If the splashscreen is enabled, show it first while the main window loads then dwitch it out for the main window, or just load the main window from the start. - if (this.CapacitorFileConfig.electron?.splashScreenEnabled) { - this.SplashScreen = new CapacitorSplashScreen({ - imageFilePath: join( - app.getAppPath(), - 'assets', - this.CapacitorFileConfig.electron?.splashScreenImageName ?? 'splash.png' - ), - windowWidth: 400, - windowHeight: 400, - }); - this.SplashScreen.init(this.loadMainWindow, this); - } else { - this.loadMainWindow(this); - } - - // Security - this.MainWindow.webContents.setWindowOpenHandler((details) => { - if (!details.url.includes(this.customScheme)) { - return { action: 'deny' }; - } else { - return { action: 'allow' }; - } - }); - this.MainWindow.webContents.on('will-navigate', (event, _newURL) => { - if (!this.MainWindow.webContents.getURL().includes(this.customScheme)) { - event.preventDefault(); - } - }); - - // Link electron plugins into the system. - setupCapacitorElectronPlugins(); - - // When the web app is loaded we hide the splashscreen if needed and show the mainwindow. - this.MainWindow.webContents.on('dom-ready', () => { - if (this.CapacitorFileConfig.electron?.splashScreenEnabled) { - this.SplashScreen.getSplashWindow().hide(); - } - if (!this.CapacitorFileConfig.electron?.hideMainWindowOnLaunch) { - this.MainWindow.show(); - } - setTimeout(() => { - if (electronIsDev) { - this.MainWindow.webContents.openDevTools(); - } - CapElectronEventEmitter.emit('CAPELECTRON_DeeplinkListenerInitialized', ''); - }, 400); - }); - } -} - -// Set a CSP up for our application based on the custom scheme -export function setupContentSecurityPolicy(customScheme: string): void { - session.defaultSession.webRequest.onHeadersReceived((details, callback) => { - callback({ - responseHeaders: { - ...details.responseHeaders, - 'Content-Security-Policy': [ - electronIsDev - ? `default-src ${customScheme}://* 'unsafe-inline' devtools://* 'unsafe-eval' data:` - : `default-src ${customScheme}://* 'unsafe-inline' data:`, - ], - }, - }); - }); -} diff --git a/electron/tsconfig.json b/electron/tsconfig.json deleted file mode 100644 index ef90ab39..00000000 --- a/electron/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compileOnSave": true, - "include": ["./src/**/*", "./capacitor.config.ts", "./capacitor.config.js"], - "compilerOptions": { - "outDir": "./build", - "importHelpers": true, - "target": "ES2017", - "module": "CommonJS", - "moduleResolution": "node", - "esModuleInterop": true, - "typeRoots": ["./node_modules/@types"], - "allowJs": true, - "rootDir": "." - } -} diff --git a/extension/manifest.json b/extension/manifest.json deleted file mode 100644 index d162569f..00000000 --- a/extension/manifest.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "Next Chrome", - "description": "Next.js Chrome Extension starter", - "version": "0.0.1", - "manifest_version": 3, - "permissions": ["action"], - "host_permissions": [""], - "action": { - "default_title": "Next.js app", - "default_popup": "index.html" - } -} \ No newline at end of file diff --git a/imports/capacitor-voice-recorder/check-device-support.ts b/imports/capacitor-voice-recorder/check-device-support.ts new file mode 100644 index 00000000..2f19afa1 --- /dev/null +++ b/imports/capacitor-voice-recorder/check-device-support.ts @@ -0,0 +1,46 @@ +import { DeepClient } from "@deep-foundation/deeplinks/imports/client"; +import { VoiceRecorder } from "capacitor-voice-recorder" +import { PACKAGE_NAME } from "./install-package"; + +export default async function checkDeviceSupport(deep: DeepClient, deviceLinkId) { + const containTypeLinkId = await deep.id("@deep-foundation/core", "Contain"); + const deviceSupportTypelinkId = await deep.id(PACKAGE_NAME, "DeviceSupport"); + const audioRecordsLinkId = await deep.id(deviceLinkId, "AudioRecords"); + + const { value: supported } = await VoiceRecorder.canDeviceVoiceRecord(); + + await deep.delete({ + up: { + tree_id: { + _id: ['@deep-foundation/core', 'containTree'], + }, + parent: { + type_id: { + _id: ['@deep-foundation/core', 'Contain'], + }, + from_id: audioRecordsLinkId, + to: { + _or: [ + { + type_id: { + _id: [PACKAGE_NAME, 'DeviceSupport'], + }, + }, + ], + }, + }, + }, + }); + + const { data } = await deep.insert({ + type_id: deviceSupportTypelinkId, + string: { data: { value: supported ? "true" : "false" } }, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: audioRecordsLinkId, + }] + } + }) +} + diff --git a/imports/capacitor-voice-recorder/check-permission.ts b/imports/capacitor-voice-recorder/check-permission.ts new file mode 100644 index 00000000..95952d04 --- /dev/null +++ b/imports/capacitor-voice-recorder/check-permission.ts @@ -0,0 +1,46 @@ +import { DeepClient } from "@deep-foundation/deeplinks/imports/client"; +import { VoiceRecorder } from "capacitor-voice-recorder" +import { PACKAGE_NAME } from "./install-package"; + +export default async function checkAudioRecPermission(deep: DeepClient, deviceLinkId) { + const containTypeLinkId = await deep.id("@deep-foundation/core", "Contain"); + const permissionsTypelinkId = await deep.id(PACKAGE_NAME, "Permissions"); + const audioRecordsLinkId = await deep.id(deviceLinkId, "AudioRecords"); + + const { value: permission } = await VoiceRecorder.hasAudioRecordingPermission(); + + await deep.delete({ + up: { + tree_id: { + _id: ['@deep-foundation/core', 'containTree'], + }, + parent: { + type_id: { + _id: ['@deep-foundation/core', 'Contain'], + }, + from_id: audioRecordsLinkId, + to: { + _or: [ + { + type_id: { + _id: [PACKAGE_NAME, 'Permissions'], + }, + }, + ], + }, + }, + }, + }); + + const { data: [{ id: permissionLinkId }] } = await deep.insert({ + type_id: permissionsTypelinkId, + string: { data: { value: permission ? "true" : "false" } }, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: audioRecordsLinkId, + }] + } + }) +} + diff --git a/imports/capacitor-voice-recorder/get-permission.ts b/imports/capacitor-voice-recorder/get-permission.ts new file mode 100644 index 00000000..1a8bb3ea --- /dev/null +++ b/imports/capacitor-voice-recorder/get-permission.ts @@ -0,0 +1,46 @@ +import { DeepClient } from "@deep-foundation/deeplinks/imports/client"; +import { VoiceRecorder } from "capacitor-voice-recorder" +import { PACKAGE_NAME } from "./install-package"; + +export default async function getAudioRecPermission(deep: DeepClient, deviceLinkId) { + const containTypeLinkId = await deep.id("@deep-foundation/core", "Contain"); + const permissionTypelinkId = await deep.id(PACKAGE_NAME, "Permissions"); + const audioRecordsLinkId = await deep.id(deviceLinkId, "AudioRecords"); + + const { value: permission } = await VoiceRecorder.requestAudioRecordingPermission(); + + await deep.delete({ + up: { + tree_id: { + _id: ['@deep-foundation/core', 'containTree'], + }, + parent: { + type_id: { + _id: ['@deep-foundation/core', 'Contain'], + }, + from_id: audioRecordsLinkId, + to: { + _or: [ + { + type_id: { + _id: [PACKAGE_NAME, 'Permissions'], + }, + }, + ], + }, + }, + }, + }); + + const { data: [{ id: permissionLinkId }] } = await deep.insert({ + type_id: permissionTypelinkId, + string: { data: { value: permission ? "true" : "false" } }, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: audioRecordsLinkId, + }] + } + }) +} + diff --git a/imports/capacitor-voice-recorder/get-recording-status.ts b/imports/capacitor-voice-recorder/get-recording-status.ts new file mode 100644 index 00000000..72c5261d --- /dev/null +++ b/imports/capacitor-voice-recorder/get-recording-status.ts @@ -0,0 +1,7 @@ +import { DeepClient } from "@deep-foundation/deeplinks/imports/client"; +import { VoiceRecorder } from "capacitor-voice-recorder" + +export default async function getRecordingStatus(deep: DeepClient) { + const { status } = await VoiceRecorder.getCurrentStatus(); + return status; +} diff --git a/imports/capacitor-voice-recorder/install-package.ts b/imports/capacitor-voice-recorder/install-package.ts new file mode 100644 index 00000000..0e4cb88d --- /dev/null +++ b/imports/capacitor-voice-recorder/install-package.ts @@ -0,0 +1,198 @@ +import { DeepClient } from "@deep-foundation/deeplinks/imports/client"; +import { generateApolloClient } from '@deep-foundation/hasura/client'; +import { getIsPackageInstalled } from "../get-is-package-installed"; +import * as dotenv from 'dotenv'; +import { getIsLinkExist } from "../get-is-link-exist"; +import { v4 as uuidv4 } from 'uuid'; +dotenv.config(); + + +export const PACKAGE_NAME = "@deep-foundation/capacitor-voice-recorder" + +export default async function installPackage(deviceLinkId?) { + + const apolloClient = generateApolloClient({ + path: process.env.NEXT_PUBLIC_GQL_PATH || '', // <<= HERE PATH TO UPDATE + ssl: !!~process.env.NEXT_PUBLIC_GQL_PATH.indexOf('localhost') + ? false + : true, + // admin token in prealpha deep secret key + // token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLWFsbG93ZWQtcm9sZXMiOlsibGluayJdLCJ4LWhhc3VyYS1kZWZhdWx0LXJvbGUiOiJsaW5rIiwieC1oYXN1cmEtdXNlci1pZCI6IjI2MiJ9LCJpYXQiOjE2NTYxMzYyMTl9.dmyWwtQu9GLdS7ClSLxcXgQiKxmaG-JPDjQVxRXOpxs', + }); + + const unloginedDeep = new DeepClient({ apolloClient }); + const guest = await unloginedDeep.guest(); + const guestDeep = new DeepClient({ deep: unloginedDeep, ...guest }); + const admin = await guestDeep.login({ + linkId: await guestDeep.id('deep', 'admin'), + }); + const deep = new DeepClient({ deep: guestDeep, ...admin }); + + if (!await getIsPackageInstalled({ deep, packageName: PACKAGE_NAME })) { + const typeTypeLinkId = await deep.id('@deep-foundation/core', 'Type'); + const containTypeLinkId = await deep.id('@deep-foundation/core', 'Contain'); + const packageTypeLinkId = await deep.id('@deep-foundation/core', 'Package'); + const joinTypeLinkId = await deep.id('@deep-foundation/core', 'Join'); + const valueTypeLinkId = await deep.id('@deep-foundation/core', 'Value'); + const stringTypeLinkId = await deep.id('@deep-foundation/core', 'String'); + const numberTypeLinkId = await deep.id('@deep-foundation/core', 'Number'); + const objectTypeLinkId = await deep.id('@deep-foundation/core', 'Object'); + const anyTypeLinkId = await deep.id("@deep-foundation/core", "Any"); + const treeTypeLinkId = await deep.id('@deep-foundation/core', 'Tree'); + const treeIncludeNodeTypeLinkId = await deep.id('@deep-foundation/core', 'TreeIncludeNode'); + const treeIncludeUpTypeLinkId = await deep.id('@deep-foundation/core', 'TreeIncludeUp'); + const treeIncludeDownTypeLinkId = await deep.id('@deep-foundation/core', 'TreeIncludeDown'); + const userTypeLinkId = await deep.id('@deep-foundation/core', 'User'); + + + + const { data: [{ id: packageLinkId }] } = await deep.insert({ + type_id: packageTypeLinkId, + string: { data: { value: PACKAGE_NAME } }, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: deep.linkId, + }] + }, + out: { + data: [{ + type_id: joinTypeLinkId, + to_id: await deep.id('deep', 'users', 'packages') + }, { + type_id: joinTypeLinkId, + to_id: await deep.id('deep', 'admin') + }] + }, + }) + + await deep.insert([ + { + type_id: typeTypeLinkId, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: packageLinkId, + string: { data: { value: 'AudioRecords' } }, + }] + }, + out: { + data: [ + { + type_id: typeTypeLinkId, + to_id: anyTypeLinkId, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: packageLinkId, + string: { data: { value: 'Permissions' } }, + }] + } + }, + { + type_id: typeTypeLinkId, + to_id: anyTypeLinkId, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: packageLinkId, + string: { data: { value: 'DeviceSupport' } }, + }] + } + }, + { + type_id: typeTypeLinkId, + to_id: anyTypeLinkId, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: packageLinkId, + string: { data: { value: 'Record' } }, + }] + }, + out: { + data: [ + { + type_id: typeTypeLinkId, + to_id: anyTypeLinkId, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: packageLinkId, + string: { data: { value: 'Duration' } }, + }] + } + }, + { + type_id: typeTypeLinkId, + to_id: anyTypeLinkId, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: packageLinkId, + string: { data: { value: 'StartTime' } }, + }] + } + }, + { + type_id: typeTypeLinkId, + to_id: anyTypeLinkId, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: packageLinkId, + string: { data: { value: 'EndTime' } }, + }] + } + } + ] + } + }, + ] + } + }, + ]); + + const { data: [{ id: deviceDependencyTypeLinkId }] } = await deep.insert({ + type_id: typeTypeLinkId, + from_id: await deep.id("@deep-foundation/device", "Device"), + to_id: await deep.id("@deep-foundation/device", "Device"), + in: { + data: { + type_id: containTypeLinkId, + from_id: packageLinkId, + string: { data: { value: 'DeviceDependency' } }, + }, + } + }); + + const { data: [{ id: soundDependencyTypeLinkId }] } = await deep.insert({ + type_id: typeTypeLinkId, + from_id: await deep.id("@deep-foundation/sound", "Sound"), + to_id: await deep.id("@deep-foundation/sound", "Sound"), + in: { + data: { + type_id: containTypeLinkId, + from_id: packageLinkId, + string: { data: { value: 'SoundDependency' } }, + }, + } + }); + + if (deviceLinkId) { + if (!await getIsLinkExist({ deep, packageName: PACKAGE_NAME, linkName: "AudioRecords" })) { + const { data: [{ id: AudioRecordsLinkId }] } = await deep.insert({ + type_id: await deep.id(PACKAGE_NAME, "AudioRecords"), + in: { + data: { + type_id: containTypeLinkId, + from_id: deviceLinkId, + string: { data: { value: "AudioRecords" } }, + } + } + }) + } + } + console.log("capacitor-voice-recorder package installed"); + } else console.log("capacitor-voice-recorder package already exists"); +} \ No newline at end of file diff --git a/imports/capacitor-voice-recorder/pause-recording.ts b/imports/capacitor-voice-recorder/pause-recording.ts new file mode 100644 index 00000000..a67dfac4 --- /dev/null +++ b/imports/capacitor-voice-recorder/pause-recording.ts @@ -0,0 +1,7 @@ +import { DeepClient } from "@deep-foundation/deeplinks/imports/client"; +import { VoiceRecorder } from "capacitor-voice-recorder" + +export default async function pauseAudioRec(deep: DeepClient) { + const { value: ispaused } = await VoiceRecorder.pauseRecording(); + return ispaused; +} \ No newline at end of file diff --git a/imports/capacitor-voice-recorder/resume-recording.ts b/imports/capacitor-voice-recorder/resume-recording.ts new file mode 100644 index 00000000..3e8f7387 --- /dev/null +++ b/imports/capacitor-voice-recorder/resume-recording.ts @@ -0,0 +1,7 @@ +import { DeepClient } from "@deep-foundation/deeplinks/imports/client"; +import { VoiceRecorder } from "capacitor-voice-recorder" + +export default async function resumeAudioRec(deep: DeepClient) { + const { value: isresumed } = await VoiceRecorder.resumeRecording(); + return isresumed; +} \ No newline at end of file diff --git a/imports/capacitor-voice-recorder/stop-recording.ts b/imports/capacitor-voice-recorder/stop-recording.ts new file mode 100644 index 00000000..198b5fbc --- /dev/null +++ b/imports/capacitor-voice-recorder/stop-recording.ts @@ -0,0 +1,7 @@ +import { DeepClient } from "@deep-foundation/deeplinks/imports/client"; +import { VoiceRecorder } from "capacitor-voice-recorder" + +export default async function stopAudioRec(deep: DeepClient) { + const { value: record } = await VoiceRecorder.stopRecording(); + return record; +} \ No newline at end of file diff --git a/imports/capacitor-voice-recorder/strart-recording.ts b/imports/capacitor-voice-recorder/strart-recording.ts new file mode 100644 index 00000000..fab31948 --- /dev/null +++ b/imports/capacitor-voice-recorder/strart-recording.ts @@ -0,0 +1,7 @@ +import { DeepClient } from "@deep-foundation/deeplinks/imports/client"; +import { VoiceRecorder } from "capacitor-voice-recorder" + +export default async function startAudioRec(deep: DeepClient) { + const { value: isrecording } = await VoiceRecorder.startRecording(); + return isrecording; +} \ No newline at end of file diff --git a/imports/capacitor-voice-recorder/upload-records.ts b/imports/capacitor-voice-recorder/upload-records.ts new file mode 100644 index 00000000..082074cb --- /dev/null +++ b/imports/capacitor-voice-recorder/upload-records.ts @@ -0,0 +1,84 @@ +import { PACKAGE_NAME } from "./install-package"; + +export default async function uploadRecords(deep, deviceLinkId, sounds) { + const containTypeLinkId = await deep.id("@deep-foundation/core", "Contain"); + const audioRecordsLinkId = await deep.id(deviceLinkId, "AudioRecords"); + const soundTypeLinkId = await deep.id("@deep-foundation/sound", "Sound"); + const recordTypeLinkId = await deep.id(PACKAGE_NAME, "Record"); + const durationTypeLinkId = await deep.id(PACKAGE_NAME, "Duration"); + const startTimeTypeLinkId = await deep.id(PACKAGE_NAME, "StartTime"); + const endTimeTypeLinkId = await deep.id(PACKAGE_NAME, "EndTime"); + const mimetypeTypeLinkId = await deep.id("@deep-foundation/sound", "MIME/type"); + const formatTypeLinkId = await deep.id("@deep-foundation/sound", "Format"); + + await deep.insert(sounds.map((sound) => ({ + type_id: recordTypeLinkId, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: audioRecordsLinkId, + }] + }, + out: { + data: [ + { + type_id: containTypeLinkId, + to: { + data: { + type_id: soundTypeLinkId, + string: { data: { value: sound.record["recordDataBase64"] } }, + out: { + data: [ + { + type_id: containTypeLinkId, + to: { + data: { + type_id: mimetypeTypeLinkId, + string: { data: { value: sound.record["mimeType"] } }, + } + } + }, + { + type_id: containTypeLinkId, + to: { + data: { + type_id: formatTypeLinkId, + string: { data: { value: sound.record["mimeType"] === "audio/webm;codecs=opus" ? "webm" : "aac" } }, + } + } + } + ] + } + } + } + }, + { + type_id: containTypeLinkId, + to: { + data: { + type_id: durationTypeLinkId, + number: { data: { value: sound.record["msDuration"] } }, + } + } + }, + { + type_id: containTypeLinkId, + to: { + data: { + type_id: startTimeTypeLinkId, + string: { data: { value: sound.startTime } }, + } + } + }, + { + type_id: containTypeLinkId, + to: { + data: { + type_id: endTimeTypeLinkId, + string: { data: { value: sound.endTime } }, + } + } + }] + } + }))); +} \ No newline at end of file diff --git a/imports/convert-audio/insert-handler.ts b/imports/convert-audio/insert-handler.ts new file mode 100644 index 00000000..51f79289 --- /dev/null +++ b/imports/convert-audio/insert-handler.ts @@ -0,0 +1,140 @@ +import { DeepClient } from "@deep-foundation/deeplinks/imports/client"; +import { CONVERT_AUDIO_PACKAGE_NAME } from "./package-name"; + +export default async function insertConvertHandler(deep: DeepClient) { + const fileTypeLinkId = await deep.id("@deep-foundation/core", "SyncTextFile"); + const containTypeLinkId = await deep.id("@deep-foundation/core", "Contain"); + const supportsId = await deep.id("@deep-foundation/core", "dockerSupportsJs"); + const handlerTypeLinkId = await deep.id("@deep-foundation/core", "Handler"); + const packageId = await deep.id(CONVERT_AUDIO_PACKAGE_NAME); + const handleOperationTypeLinkId = await deep.id("@deep-foundation/core", "HandleInsert"); + const triggerTypeLinkId = await deep.id(CONVERT_AUDIO_PACKAGE_NAME, "Convert"); + + const code = /*javascript*/`async ({ require, deep, data: { newLink } }) => { + const ffmpeg = require('fluent-ffmpeg'); + const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path; + const ffprobePath = require('@ffprobe-installer/ffprobe').path; + ffmpeg.setFfmpegPath(ffmpegPath); + ffmpeg.setFfprobePath(ffprobePath); + + const soundTypelinkId = await deep.id("@deep-foundation/sound", "Sound"); + const formatTypelinkId = await deep.id("@deep-foundation/sound", "Format"); + const mimetypeTypelinkId = await deep.id("@deep-foundation/sound", "MIME/type"); + + const { data } = await deep.select({ + up: { + parent: { + id: newLink.from_id + }, + link: { + type_id: { + _in: + [ + mimetypeTypelinkId, + formatTypelinkId, + soundTypelinkId + ] + } + } + }, + }); + + const soundLink = data.filter((link) => link.type_id === soundTypelinkId);; + const mimetypeLink = data.filter((link) => link.type_id === mimetypeTypelinkId); + const formatLink = data.filter((link) => link.type_id === formatTypelinkId); + + const soundBase64 = soundLink.value.value; + + const soundBase64 = soundLink.value.value; + + function convertBase64ToAudioBuffer(base64String) { + return Buffer.from(base64String, 'base64'); + } + + async function convertWebmOpusToFlac(inputBuffer) { + return new Promise((resolve, reject) => { + const outputBuffer = Buffer.alloc(0); + + ffmpeg() + .input(inputBuffer) + .inputFormat('webm') + .audioCodec('opus') + .outputFormat('flac') + .on('error', (err) => { + reject(err); + }) + .on('data', (chunk) => { + outputBuffer = Buffer.concat([outputBuffer, chunk]); + }) + .on('end', () => { + resolve(outputBuffer); + }) + .run(); + }); + } + + try { + const inputBuffer = convertBase64ToAudioBuffer(soundBase64); + const converted = await convertWebmOpusToFlac(inputBuffer); + + await deep.insert({ + type_id: soundTypelinkId, + object: { data: { value: converted.toString('base64') } }, + in: { + data: { + type_id: await deep.id("@deep-foundation/core", "Contain"), + from_id: newLink.from_id + } + } + }); + } catch (err) { + console.error(\`Error while converting audio: \${err.message}\`); + } + } + ` + + await deep.insert({ + type_id: fileTypeLinkId, + in: { + data: [ + { + type_id: containTypeLinkId, + from_id: packageId, + string: { data: { value: "HandlerCode" } }, + }, + { + from_id: supportsId, + type_id: handlerTypeLinkId, + in: { + data: [ + { + type_id: containTypeLinkId, + from_id: packageId, + string: { data: { value: "AudioConvertHandler" } }, + }, + { + type_id: handleOperationTypeLinkId, + from_id: triggerTypeLinkId, + in: { + data: [ + { + type_id: containTypeLinkId, + from_id: packageId, + string: { data: { value: "HandleAudioConversion" } }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + string: { + data: { + value: code, + }, + }, + }); + console.log("Audio Conversion handler inserted"); +} \ No newline at end of file diff --git a/imports/convert-audio/install-package.ts b/imports/convert-audio/install-package.ts new file mode 100644 index 00000000..4fb2f037 --- /dev/null +++ b/imports/convert-audio/install-package.ts @@ -0,0 +1,123 @@ +import { DeepClient } from "@deep-foundation/deeplinks/imports/client"; +import { generateApolloClient } from '@deep-foundation/hasura/client'; +import { CONVERT_AUDIO_PACKAGE_NAME } from "./package-name"; +import * as dotenv from 'dotenv'; +import insertConvertHandler from "./insert-handler"; +dotenv.config(); + + +export default async function installPackage() { + + const apolloClient = generateApolloClient({ + path: process.env.NEXT_PUBLIC_GQL_PATH || '', // <<= HERE PATH TO UPDATE + ssl: !!~process.env.NEXT_PUBLIC_GQL_PATH.indexOf('localhost') + ? false + : true, + // admin token in prealpha deep secret key + // token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLWFsbG93ZWQtcm9sZXMiOlsibGluayJdLCJ4LWhhc3VyYS1kZWZhdWx0LXJvbGUiOiJsaW5rIiwieC1oYXN1cmEtdXNlci1pZCI6IjI2MiJ9LCJpYXQiOjE2NTYxMzYyMTl9.dmyWwtQu9GLdS7ClSLxcXgQiKxmaG-JPDjQVxRXOpxs', + }); + + const unloginedDeep = new DeepClient({ apolloClient }); + const guest = await unloginedDeep.guest(); + const guestDeep = new DeepClient({ deep: unloginedDeep, ...guest }); + const admin = await guestDeep.login({ + linkId: await guestDeep.id('deep', 'admin'), + }); + const deep = new DeepClient({ deep: guestDeep, ...admin }); + + + const typeTypeLinkId = await deep.id('@deep-foundation/core', 'Type'); + const containTypeLinkId = await deep.id('@deep-foundation/core', 'Contain'); + const packageTypeLinkId = await deep.id('@deep-foundation/core', 'Package'); + const joinTypeLinkId = await deep.id('@deep-foundation/core', 'Join'); + const valueTypeLinkId = await deep.id('@deep-foundation/core', 'Value'); + const stringTypeLinkId = await deep.id('@deep-foundation/core', 'String'); + const numberTypeLinkId = await deep.id('@deep-foundation/core', 'Number'); + const objectTypeLinkId = await deep.id('@deep-foundation/core', 'Object'); + const anyTypeLinkId = await deep.id("@deep-foundation/core", "Any"); + const userTypeLinkId = await deep.id('@deep-foundation/core', 'User'); + + const { data: [{ id: packageLinkId }] } = await deep.insert({ + type_id: packageTypeLinkId, + string: { data: { value: CONVERT_AUDIO_PACKAGE_NAME } }, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: deep.linkId, + }] + }, + out: { + data: [{ + type_id: joinTypeLinkId, + to_id: await deep.id('deep', 'users', 'packages') + }, { + type_id: joinTypeLinkId, + to_id: await deep.id('deep', 'admin') + }] + }, + }) + + const { data: [{ id: pacakgeTypeLinkId }] } = await deep.insert([ + // { + // type_id: typeTypeLinkId, + // in: { + // data: [{ + // type_id: containTypeLinkId, + // from_id: packageLinkId, + // string: { data: { value: "Transcription" } }, + // }], + // }, + // }, + // { + // type_id: typeTypeLinkId, + // in: { + // data: [{ + // type_id: containTypeLinkId, + // from_id: packageLinkId, + // string: { data: { value: "GoogleCloudAuthFile" } }, + // }], + // }, + // out: { + // data: { + // type_id: valueTypeLinkId, + // to_id: objectTypeLinkId, + // in: { + // data: { + // from_id: packageLinkId, + // type_id: containTypeLinkId, + // string: { data: { value: 'Gcloud auth file data' } }, + // } + // } + // } + // } + // }, + { + type_id: typeTypeLinkId, + from_id: anyTypeLinkId, + to_id: anyTypeLinkId, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: packageLinkId, + string: { data: { value: "Convert" } } + }] + } + }]); + + const { data: [{ id: soundDependencyTypeLinkId }] } = await deep.insert({ + type_id: typeTypeLinkId, + from_id: await deep.id("@deep-foundation/sound", "Sound"), + to_id: await deep.id("@deep-foundation/sound", "Sound"), + in: { + data: { + type_id: containTypeLinkId, + from_id: packageLinkId, + string: { data: { value: 'SoundDependency' } }, + }, + } + }); + + await insertConvertHandler(deep); + + console.log("convert-audio package installed"); +} \ No newline at end of file diff --git a/imports/convert-audio/package-name.ts b/imports/convert-audio/package-name.ts new file mode 100644 index 00000000..8e013a45 --- /dev/null +++ b/imports/convert-audio/package-name.ts @@ -0,0 +1 @@ +export const CONVERT_AUDIO_PACKAGE_NAME = "@deep-foundation/convert-audio" \ No newline at end of file diff --git a/imports/get-is-link-exist.ts b/imports/get-is-link-exist.ts new file mode 100644 index 00000000..60745d56 --- /dev/null +++ b/imports/get-is-link-exist.ts @@ -0,0 +1,15 @@ +import { DeepClient } from "@deep-foundation/deeplinks/imports/client"; + +export async function getIsLinkExist({ deep, packageName, linkName }: { deep: DeepClient, packageName: string, linkName: string }): Promise { + + const { data: linkSelectResponse } = await deep.select({ + type_id: { + _id: [packageName, linkName], + }, + }); + + const isLinkExist = linkSelectResponse.length > 0; + return isLinkExist; +} + + diff --git a/imports/google-speech/insert-gcloud-auth-file.ts b/imports/google-speech/insert-gcloud-auth-file.ts new file mode 100644 index 00000000..bdc58229 --- /dev/null +++ b/imports/google-speech/insert-gcloud-auth-file.ts @@ -0,0 +1,22 @@ +import { DeepClient } from "@deep-foundation/deeplinks/imports/client"; +import { PACKAGE_NAME } from './install-package'; + +export default async function insertGcloudAuthFile(deep: DeepClient, credentials) { + const containTypeLinkId = await deep.id("@deep-foundation/core", "Contain"); + const gcloudAuthKeyTypeLink = await deep.id(PACKAGE_NAME, "GoogleCloudAuthFile"); + const userLink = await deep.id('deep', 'admin'); + + const { data: [{ id: gcloudAuthKeyLinkId }] } = await deep.insert({ + type_id: gcloudAuthKeyTypeLink, + object: { data: { value: credentials } }, + in: { + data: [ + { + type_id: containTypeLinkId, + from_id: userLink, + string: { data: { value: "GoogleCloudAuthFile" } }, + } + ] + } + }) +} \ No newline at end of file diff --git a/imports/google-speech/insert-handler.ts b/imports/google-speech/insert-handler.ts new file mode 100644 index 00000000..d81ecea9 --- /dev/null +++ b/imports/google-speech/insert-handler.ts @@ -0,0 +1,141 @@ +import { DeepClient } from "@deep-foundation/deeplinks/imports/client"; + +export default async function insertGoogleSpeechHandler(deep: DeepClient) { + const fileTypeLinkId = await deep.id("@deep-foundation/core", "SyncTextFile"); + const containTypeLinkId = await deep.id("@deep-foundation/core", "Contain"); + const supportsId = await deep.id("@deep-foundation/core", "dockerSupportsJs"); + const handlerTypeLinkId = await deep.id("@deep-foundation/core", "Handler"); + const packageId = await deep.id("@deep-foundation/google-speech"); + const handleOperationTypeLinkId = await deep.id("@deep-foundation/core", "HandleInsert"); + const triggerTypeLinkId = await deep.id("@deep-foundation/google-speech", "Transcribe"); + + const code = /*javascript*/`async ({ require, deep, data: { newLink } }) => { + const speech = require('@google-cloud/speech'); + const fs = require('fs'); + const os = require('os'); + const { v4: uuid } = require('uuid'); + + const soundTypelinkId = await deep.id("@deep-foundation/sound", "Sound"); + const formatTypelinkId = await deep.id("@deep-foundation/sound", "Format"); + const mimetypeTypelinkId = await deep.id("@deep-foundation/sound", "MIME/type"); + + const { data } = await deep.select({ + up: { + parent: { + id: newLink.to_id + }, + link: { + type_id: { + _in: + [ + soundTypelinkId, + formatTypelinkId, + mimetypeTypelinkId + ] + } + } + }, + }); + + const soundLink = data.filter((link) => link.type_id === soundTypelinkId); + const mimetypeLink = data.filter((link) => link.type_id === mimetypeTypelinkId); + const formatLink = data.filter((link) => link.type_id === formatTypelinkId); + + const authFilelinkId = await deep.id("@deep-foundation/google-speech", "GoogleCloudAuthFile"); + const { data: [{ value: { value: authFile } }] } = await deep.select({ type_id: authFilelinkId }); + + const baseTempDirectory = os.tmpdir(); + const randomId = uuid(); + const tempDirectory = [baseTempDirectory, randomId].join('/'); + fs.mkdirSync(tempDirectory); + const keyFilePath = \`\${tempDirectory}/key.json\`; + fs.writeFile(keyFilePath, JSON.stringify(authFile), (error) => { + if (error) throw error; + }) + + try { + process.env["GOOGLE_APPLICATION_CREDENTIALS"] = keyFilePath; + + const client = new speech.SpeechClient(); + + const audio = { + content: soundLink[0].value.value, + }; + + const config = { + encoding: mimetypeLink[0].value.value === 'audio/webm;codecs=opus' ? 'WEBM_OPUS' : 'LINEAR16', + sampleRateHertz: 48000, + languageCode: 'ru-RU', + }; + + const request = { + audio: audio, + config: config, + }; + + const [response] = await client.recognize(request); + const transcription = response.results + .map(result => result.alternatives[0].transcript) + .join('\n'); + + await deep.insert({ + type_id: await deep.id("@deep-foundation/google-speech", "Transcription"), + string: { data: { value: transcription ? transcription : "No voice detected." } }, + in: { + data: { + type_id: await deep.id("@deep-foundation/core", "Contain"), + from_id: newLink.to_id + } + } + }) + } + finally { + fs.rmSync(keyFilePath, { recursive: true, force: true }); + } + }` + + await deep.insert({ + type_id: fileTypeLinkId, + in: { + data: [ + { + type_id: containTypeLinkId, + from_id: packageId, + string: { data: { value: "GcloudSpeechHandlerCode" } }, + }, + { + from_id: supportsId, + type_id: handlerTypeLinkId, + in: { + data: [ + { + type_id: containTypeLinkId, + from_id: packageId, + string: { data: { value: "GcloudSpeechHandler" } }, + }, + { + type_id: handleOperationTypeLinkId, + from_id: triggerTypeLinkId, + in: { + data: [ + { + type_id: containTypeLinkId, + from_id: packageId, + string: { data: { value: "HandleTranscription" } }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + string: { + data: { + value: code, + }, + }, + }); + console.log("Transcription handler inserted"); +} \ No newline at end of file diff --git a/imports/google-speech/install-package.ts b/imports/google-speech/install-package.ts new file mode 100644 index 00000000..4f5072ef --- /dev/null +++ b/imports/google-speech/install-package.ts @@ -0,0 +1,123 @@ +import { DeepClient } from "@deep-foundation/deeplinks/imports/client"; +import { generateApolloClient } from '@deep-foundation/hasura/client'; +import { getIsPackageInstalled } from "../get-is-package-installed"; +import * as dotenv from 'dotenv'; +import insertGoogleSpeechHandler from "./insert-handler"; +dotenv.config(); + +export const PACKAGE_NAME = "@deep-foundation/google-speech"; + +export default async function installPackage() { + + const apolloClient = generateApolloClient({ + path: process.env.NEXT_PUBLIC_GQL_PATH || '', // <<= HERE PATH TO UPDATE + ssl: !!~process.env.NEXT_PUBLIC_GQL_PATH.indexOf('localhost') + ? false + : true, + // admin token in prealpha deep secret key + // token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLWFsbG93ZWQtcm9sZXMiOlsibGluayJdLCJ4LWhhc3VyYS1kZWZhdWx0LXJvbGUiOiJsaW5rIiwieC1oYXN1cmEtdXNlci1pZCI6IjI2MiJ9LCJpYXQiOjE2NTYxMzYyMTl9.dmyWwtQu9GLdS7ClSLxcXgQiKxmaG-JPDjQVxRXOpxs', + }); + + const unloginedDeep = new DeepClient({ apolloClient }); + const guest = await unloginedDeep.guest(); + const guestDeep = new DeepClient({ deep: unloginedDeep, ...guest }); + const admin = await guestDeep.login({ + linkId: await guestDeep.id('deep', 'admin'), + }); + const deep = new DeepClient({ deep: guestDeep, ...admin }); + + if (!await getIsPackageInstalled({ deep, packageName: PACKAGE_NAME })) { + const typeTypeLinkId = await deep.id('@deep-foundation/core', 'Type'); + const containTypeLinkId = await deep.id('@deep-foundation/core', 'Contain'); + const packageTypeLinkId = await deep.id('@deep-foundation/core', 'Package'); + const joinTypeLinkId = await deep.id('@deep-foundation/core', 'Join'); + const valueTypeLinkId = await deep.id('@deep-foundation/core', 'Value'); + const stringTypeLinkId = await deep.id('@deep-foundation/core', 'String'); + const numberTypeLinkId = await deep.id('@deep-foundation/core', 'Number'); + const objectTypeLinkId = await deep.id('@deep-foundation/core', 'Object'); + const anyTypeLinkId = await deep.id("@deep-foundation/core", "Any"); + const userTypeLinkId = await deep.id('@deep-foundation/core', 'User'); + + const { data: [{ id: packageLinkId }] } = await deep.insert({ + type_id: packageTypeLinkId, + string: { data: { value: PACKAGE_NAME } }, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: deep.linkId, + }] + }, + out: { + data: [{ + type_id: joinTypeLinkId, + to_id: await deep.id('deep', 'users', 'packages') + }, { + type_id: joinTypeLinkId, + to_id: await deep.id('deep', 'admin') + }] + }, + }) + + const { data: [{ id: pacakgeTypeLinkId }] } = await deep.insert([{ + type_id: typeTypeLinkId, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: packageLinkId, + string: { data: { value: "Transcription" } }, + }], + }, + }, + { + type_id: typeTypeLinkId, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: packageLinkId, + string: { data: { value: "GoogleCloudAuthFile" } }, + }], + }, + out: { + data: { + type_id: valueTypeLinkId, + to_id: objectTypeLinkId, + in: { + data: { + from_id: packageLinkId, + type_id: containTypeLinkId, + string: { data: { value: 'Gcloud auth file data' } }, + } + } + } + } + }, + { + type_id: typeTypeLinkId, + from_id: userTypeLinkId, + to_id: anyTypeLinkId, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: packageLinkId, + string: { data: { value: "Transcribe" } } + }] + } + }]); + + const { data: [{ id: soundDependencyTypeLinkId }] } = await deep.insert({ + type_id: typeTypeLinkId, + from_id: await deep.id("@deep-foundation/sound", "Sound"), + to_id: await deep.id("@deep-foundation/sound", "Sound"), + in: { + data: { + type_id: containTypeLinkId, + from_id: packageLinkId, + string: { data: { value: 'SoundDependency' } }, + }, + } + }); + + console.log("google-speech package installed"); + } else console.log("google-speech package already exists"); + await insertGoogleSpeechHandler(deep); +} \ No newline at end of file diff --git a/imports/google-speech/transcribe.ts b/imports/google-speech/transcribe.ts new file mode 100644 index 00000000..522056d1 --- /dev/null +++ b/imports/google-speech/transcribe.ts @@ -0,0 +1,17 @@ +export default async function transcribe(deep, soundLinks) { + const transcribeTypeLinkId = await deep.id("@deep-foundation/google-speech", "Transcribe"); + const containTypeLinkId = await deep.id('@deep-foundation/core', 'Contain'); + + const {data} = await deep.insert(soundLinks.map((soundLinkId) => ({ + type_id: transcribeTypeLinkId, + from_id: deep.linkId, + to_id: soundLinkId, + in: { + data: { + type_id: containTypeLinkId, + from_id: deep.linkId, + } + } + }))) + console.log(data); +} \ No newline at end of file diff --git a/imports/key.json b/imports/key.json new file mode 100644 index 00000000..00840380 --- /dev/null +++ b/imports/key.json @@ -0,0 +1,12 @@ +{ + "type": "service_account", + "project_id": "deep-sound-handler", + "private_key_id": "c03fd7ed391b0e82a666f6b88089e3b145c33879", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCljHCNaHpGK/AS\n4iE9+h+eAL93H3HKLchrz3hADZjHwNetquySoh71g3zcXhKqmQWbD6o3pw4+tAsJ\nHfecgjAlxvmZ8wNbycgfnT6u2iM2fCUhwuxy2WYURHAGTqupAkkZIGksLDSBYQqH\nrqx7l142JnaJdqeYm4YjRdNO8X3ROcQcSlJflK4yBozFq2QyNJLHZMpL+1bCY88Q\nhIKEqXWbVT2iWTAtJPwZqdbRyIr/vjnk63fNuEmNy1VFW1Q6hR2wA3WyY2Re5nKG\nxMQuBpJSfrZn5mJlodPkKpPUP4Jtkn9kfT0O5Fk5nxVA5XIa8kjVHEXzVmrQYbrv\n5VEsKF71AgMBAAECggEAGxYueESm9QJNZpmPPNfHApA2w6Pmd2EkUNeCYmCXJd/c\nqjK0QI28KQmZjWjq/vTIoQVgIXj48LN+tsArenUmsZer0U+cthD+6IVO80cHyeto\nG+0LyQLfG+PSvIV0utN/6FeQPcUB1kVtdqPS3un2ZT/H11gNtf+EZBMRrvH+VxQs\nGyNDQeO9tMhrOxeOyYrZg8KBa+1K9yucBKgQUvjOFTL7jSLXq7ODCs1joUNy17ZD\nOK2H40dp+ul5b9BeA58zwDygHhh1DKgfXef0KjhfzuKQG6wXs0DUXvdG/S6QTnX/\nmZ5qP06/FFlaIVppYJIOrdG5eCtyRfitSWhSgcmPJQKBgQDYC03dSS8gS26GWGgV\nlWnyh7XXVtMx2M/i9cx6/zkXp0p1y+aZoU20CumlTXPbGbIGy5JbRSGmeGCszrZo\nTWA75Yj4lkDR0NjkcfpdvdIe3zjsWuo9N6gNJV5zCSjib9O+YZ5BbcHUoChlaLYz\nG7Uzpszp1jB3xg9AyMfpf+1IcwKBgQDEKmcwLwjcjYRsnmyiveOxNWSsR9CsN/1q\np1WS5XTs9Tv3gtTt6WweGoi/dKTOMNeVRR1pxSxYHJ2e2/hFAAwLUjFUoFvj6htO\nShfqxGtQA+RWCrAxg59mD5I8JFDdm/NGbYP0czOaOhnUbSUVDQ0dNJpjflEsqXeF\n9+bOr6So9wKBgDf2NaUsX9itsWN7Yvq0SU1ZefDdvLccwjy4Ds+NbOyDmPYKayFA\ndzA742m+NlR6w3KfKLobnivQ4rngkb9Sy6q4OlKqGQBAaO5D1+aQVO1KRSR0KFjT\nIeTF2UFTDhQZg2+9OZEZLSw2kEA0b32tn7JRcqLfqI5d73WIjMAfMwehAoGAImv+\nZ2oZd/otPpIeJgCEL9harhB8AXxhr5FlZr104w+1Uh1XF9hZ7H5jeJUTRkszyTGz\nk5fRzDRZREL9Mb5sXqAxn9Pzy+6MlBRUVhHZctT8AE0n1chu9A3Pb1ZACmMPMVCO\nUxrT90AywB/W3fbIUlOks8i6nceu/YcerS4NCskCgYBCusqLkGStC9Tw7R1xX+ey\nDkA5sGNfHIV18PQH1l0R1MNf1cXjxkBvt4aVTO5iqcLfr/LCGwYQJn/CXuBkS2Tv\njKOAdmkFVGe1DdMLXDbhHKwduHnqgAkEyWu0Jw+lPHvziTmcJy2t3m9Lcm9srgEu\nKE9c9B+zjkFrG8NTrLAhbQ==\n-----END PRIVATE KEY-----\n", + "client_email": "deep-sound-handler@deep-sound-handler.iam.gserviceaccount.com", + "client_id": "100687498969961716359", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/deep-sound-handler%40deep-sound-handler.iam.gserviceaccount.com" +} diff --git a/imports/sound/install-package.ts b/imports/sound/install-package.ts new file mode 100644 index 00000000..ffdad3d5 --- /dev/null +++ b/imports/sound/install-package.ts @@ -0,0 +1,43 @@ +import { DeepClient } from "@deep-foundation/deeplinks/imports/client"; + +export const PACKAGE_NAME = "@deep-foundation/sound"; +export const PACKAGE_TYPES = + ["Sound", "Encoding", "Format", "Duration", "MIME/type"]; + +export default async function initializePackage(deep: DeepClient, deviceLinkId) { + const packageTypeLinkId = await deep.id('@deep-foundation/core', "Package") + const containTypeLinkId = await deep.id("@deep-foundation/core", "Contain") + const joinTypeLinkId = await deep.id("@deep-foundation/core", "Join") + const typeTypeLinkId = await deep.id("@deep-foundation/core", "Type") + + const { data: [{ id: packageLinkId }] } = await deep.insert({ + type_id: packageTypeLinkId, + string: { data: { value: PACKAGE_NAME } }, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: deep.linkId, + }] + }, + out: { + data: [{ + type_id: joinTypeLinkId, + to_id: await deep.id('deep', 'users', 'packages') + }, { + type_id: joinTypeLinkId, + to_id: await deep.id('deep', 'admin') + }] + }, + }) + const { data: [{ id: pacakgeTypeLinkId }] } = await deep.insert(PACKAGE_TYPES.map((TYPE) => ({ + type_id: typeTypeLinkId, + in: { + data: [{ + type_id: containTypeLinkId, + from_id: packageLinkId, + string: { data: { value: TYPE } } + }] + } + }))) + console.log("sound package installed"); +} \ No newline at end of file diff --git a/next.config.js b/next.config.js index c27135eb..cf3d0c71 100644 --- a/next.config.js +++ b/next.config.js @@ -7,8 +7,6 @@ const withNextEnv = nextEnv(); module.exports = withNextEnv({ distDir: 'app', - strictMode: false, - webpack: (config) => { config.resolve.fallback = { "buffer": require.resolve('buffer/'), @@ -23,6 +21,7 @@ module.exports = withNextEnv({ "https": false, "stream": false, "crypto": false, + "child_process": false, }; return config; diff --git a/package-lock.json b/package-lock.json index b3092c38..2c565556 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2977,9 +2977,9 @@ "integrity": "sha512-z1CjRjtQyBOYL+5Qr9DdYIfrdLBe746jRTYfaYU6MeXkqp7UfYs/jX16lFFVzZ7PGEJvqZNqYUEtb1mvDww4pA==" }, "@google-cloud/speech": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@google-cloud/speech/-/speech-5.2.0.tgz", - "integrity": "sha512-tGofv+6wvDn1AtdBPHi0y0JSOmSl0CqTF90BGIigT/21oea9M7ptNxRe+y/IqZGn7OyfTBnJWBM7NQ0RramdhQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@google-cloud/speech/-/speech-5.3.1.tgz", + "integrity": "sha512-F1aAWDdRSSrHkylF9PTbq6GitQbe0edIpJRU8Nid+wtB5IxMhUdJf4berdj5wbSm9fbgaYqgUq7cXl06nOGwHg==", "requires": { "@google-cloud/common": "^4.0.0", "@types/pumpify": "^1.4.1", @@ -6567,6 +6567,14 @@ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001449.tgz", "integrity": "sha512-CPB+UL9XMT/Av+pJxCKGhdx+yg1hzplvFJQlJ2n68PyQGMz9L/E2zCyLdOL8uasbouTUgnPl+y0tccI/se+BEw==" }, + "capacitor-voice-recorder": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/capacitor-voice-recorder/-/capacitor-voice-recorder-4.0.2.tgz", + "integrity": "sha512-vBiPEE7iIbBGD5hQnhmRSM7IDmNm2vXqCVO6wpQj0yuoUum87Aj8UKePHIanhzVUlrIQUnP+LTdgMo6W5FiuOA==", + "requires": { + "get-blob-duration": "^1.2.0" + } + }, "card-validator": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/card-validator/-/card-validator-8.1.1.tgz", @@ -8016,6 +8024,29 @@ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true }, + "get-blob-duration": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-blob-duration/-/get-blob-duration-1.2.0.tgz", + "integrity": "sha512-2xNJa+oKznR21eC2ThMzw4a1931a3ogA8aHoY92xruZufc/02G7pl/P793GJZytkyI8xMJ2DepEQ7MWvg/tn/Q==", + "requires": { + "@babel/runtime": "7.11.2" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.11.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz", + "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + } + } + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", diff --git a/package.json b/package.json index df4f36d0..d12656f6 100644 --- a/package.json +++ b/package.json @@ -26,42 +26,43 @@ "ios-build": "rm -rf app && rm -rf out && npm run build && npm run export && npx cap sync ios" }, "dependencies": { - "@deep-foundation/deeplinks": "0.0.107", - "@chakra-ui/react": "^2.4.9", - "@capacitor/screen-reader": "^4.1.2", - "@capacitor/push-notifications": "^4.1.2", - "@capacitor/network": "^4.1.0", - "@capacitor/motion": "^4.0.2", - "@capacitor/local-notifications": "^4.1.4", - "@capacitor/ios": "^4.6.2", - "@capacitor/haptics": "^4.1.0", - "@capacitor/dialog": "^4.1.0", - "@capacitor/geolocation": "^4.1.0", - "@capacitor/device": "^4.1.0", + "@capacitor-community/contacts": "^2.0.0", + "@capacitor-community/electron": "^4.1.2", + "@capacitor/action-sheet": "^4.1.0", + "@capacitor/android": "^4.6.1", + "@capacitor/camera": "^4.1.4", + "@capacitor/cli": "^4.0.0", "@capacitor/clipboard": "^4.1.0", "@capacitor/core": "^4.6.2", - "@capacitor/cli": "^4.0.0", - "@capacitor/camera": "^4.1.4", - "@capacitor/android": "^4.6.1", - "@capacitor/action-sheet": "^4.1.0", - "@capacitor-community/electron": "^4.1.2", - "@capacitor-community/contacts": "^2.0.0", + "@capacitor/device": "^4.1.0", + "@capacitor/dialog": "^4.1.0", + "@capacitor/geolocation": "^4.1.0", + "@capacitor/haptics": "^4.1.0", + "@capacitor/ios": "^4.6.2", + "@capacitor/local-notifications": "^4.1.4", + "@capacitor/motion": "^4.0.2", + "@capacitor/network": "^4.1.0", + "@capacitor/push-notifications": "^4.1.2", + "@capacitor/screen-reader": "^4.1.2", + "@chakra-ui/react": "^2.4.9", + "@deep-foundation/deeplinks": "0.0.107", "@emotion/react": "^11.8.2", "@emotion/styled": "^11.8.1", - "firebase": "^9.15.0", - "events": "^3.3.0", - "dotenv-load": "^2.0.1", - "az": "^0.2.3", - "@octokit/rest": "^19.0.5", - "@ionic/pwa-elements": "^3.1.1", + "@google-cloud/speech": "^5.3.1", "@google-cloud/vision": "^3.1.0", - "@google-cloud/speech": "^5.1.1", + "@ionic/pwa-elements": "^3.1.1", + "@octokit/rest": "^19.0.5", "atob": "^2.1.2", + "az": "^0.2.3", + "capacitor-voice-recorder": "^4.0.2", + "dotenv-load": "^2.0.1", + "events": "^3.3.0", + "firebase": "^9.15.0", "framer-motion": "^6.2.8", - "react-dom": "^18.2.0", - "react": "^18.2.0", + "next": "^13.1.5", "next-env": "^1.1.1", - "next": "^13.1.5" + "react": "^18.2.0", + "react-dom": "^18.2.0" }, "devDependencies": { "@types/react": "^18.0.1", diff --git a/pages/capacitor-voice-recorder.tsx b/pages/capacitor-voice-recorder.tsx new file mode 100644 index 00000000..70453343 --- /dev/null +++ b/pages/capacitor-voice-recorder.tsx @@ -0,0 +1,161 @@ +import React, { useState, useEffect, useCallback } from 'react'; +import { useLocalStore } from '@deep-foundation/store/local'; +import { DeepProvider, useDeep } from '@deep-foundation/deeplinks/imports/client'; +import { Provider } from '../imports/provider'; +import { Button, ChakraProvider, Stack, Text } from '@chakra-ui/react'; +import installPackage, { PACKAGE_NAME } from '../imports/capacitor-voice-recorder/install-package'; +import checkDeviceSupport from '../imports/capacitor-voice-recorder/check-device-support'; +import checkAudioRecPermission from '../imports/capacitor-voice-recorder/check-permission'; +import getAudioRecPermission from '../imports/capacitor-voice-recorder/get-permission'; +import getRecordingStatus from '../imports/capacitor-voice-recorder/get-recording-status'; +import startAudioRec from '../imports/capacitor-voice-recorder/strart-recording'; +import stopAudioRec from '../imports/capacitor-voice-recorder/stop-recording'; +import uploadRecords from '../imports/capacitor-voice-recorder/upload-records'; + +export const delay = (time) => new Promise(res => setTimeout(() => res(null), time)); + +function Page() { + const deep = useDeep(); + const [recording, setRecording] = useState(false); + const [sounds, setSounds] = useLocalStore("Sounds", []); + const [records, setRecords] = useState([]); + const [deviceLinkId, setDeviceLinkId] = useLocalStore( + 'deviceLinkId', + undefined + ); + + useEffect(() => { + const useRecords = async () => { + await uploadRecords(deep, deviceLinkId, sounds); + setSounds([]); + } + if (sounds.length > 0) useRecords(); + }, [sounds]) + + useEffect(() => { + let loop = true; + const startRecordingCycle = async (duration) => { + for (; recording && loop;) { + await startAudioRec(deep); + const startTime = new Date().toLocaleDateString(); + await delay(duration); + const record = await stopAudioRec(deep); + const endTime = new Date().toLocaleDateString(); + console.log({ record }); + setSounds([...sounds, { record, startTime, endTime }]); + } + } + if (recording) startRecordingCycle(5000); + return function stopCycle() { loop = false }; + }, [recording]) + + const startRecording = async (duration) => { + await startAudioRec(deep); + const startTime = new Date().toLocaleString(); + await delay(duration); + const record = await stopAudioRec(deep); + const endTime = new Date().toLocaleString(); + console.log({ record }); + setSounds([...sounds, { record, startTime, endTime }]); + } + + const fetchRecords = async () => { + const recordTypelinkId = await deep.id(PACKAGE_NAME, "Record"); + const soundTypelinkId = await deep.id("@deep-foundation/sound", "Sound"); + const mimetypeTypelinkId = await deep.id("@deep-foundation/sound", "MIME/type"); + const { data: recordLinks } = await deep.select({ + type_id: recordTypelinkId + }); + + let records = []; + + for (let recordLink of recordLinks) { + const { data } = await deep.select({ + up: { + parent: { + id: recordLink.id + }, + link: { + type_id: { + _in: + [ + soundTypelinkId, + mimetypeTypelinkId + ] + } + } + }, + }) + const soundLink = data.filter((link) => link.type_id === soundTypelinkId) + const mimetypeLink = data.filter((link) => link.type_id === mimetypeTypelinkId) + records = [...records, { id: soundLink[0].id, sound: soundLink[0].value.value, mimetype: mimetypeLink[0].value.value }] + } + setRecords(records); + } + + const createContainer = async (deep) => { + const containTypeLinkId = await deep.id("@deep-foundation/core", "Contain"); + const audioRecordsTypeLinkId = await deep.id(PACKAGE_NAME, "AudioRecords"); + await deep.insert({ + type_id: audioRecordsTypeLinkId, + in: { + data: { + type_id: containTypeLinkId, + from_id: deviceLinkId, + string: { data: { value: "AudioRecords" } }, + } + } + }) + } + + return + Device link id: {deviceLinkId ?? " "} + + + + + + + + + + + {records?.map((r) => +} + +export default function Index() { + return ( + + + + + + + + ); +} \ No newline at end of file diff --git a/pages/convert-audio.tsx b/pages/convert-audio.tsx new file mode 100644 index 00000000..c9779055 --- /dev/null +++ b/pages/convert-audio.tsx @@ -0,0 +1,74 @@ +import React, { useState, useEffect, useCallback } from 'react'; +import { useLocalStore } from '@deep-foundation/store/local'; +import { DeepProvider, useDeep } from '@deep-foundation/deeplinks/imports/client'; +import { Provider } from '../imports/provider'; +import { Button, ChakraProvider, Stack, Text } from '@chakra-ui/react'; +import installPackage from '../imports/convert-audio/install-package'; + +function Page() { + const deep = useDeep(); + const [sounds, setSounds] = useLocalStore('Sounds', []) + const [deviceLinkId, setDeviceLinkId] = useLocalStore( + 'deviceLinkId', + undefined + ); + + const fetchSounds = async () => { + const soundTypeLinkId = await deep.id("@deep-foundation/sound", "Sound"); + const formatTypeLinkId = await deep.id("@deep-foundation/sound", "Format"); + const mimetypeTypeLinkId = await deep.id("@deep-foundation/sound", "MIME/type"); + const { data: soundLinks } = await deep.select({ + type_id: soundTypeLinkId + }); + + let sounds = []; + + for (let soundLink of soundLinks) { + const { data } = await deep.select({ + up: { + parent: { + id: soundLink.id + }, + link: { + type_id: { + _in: + [ + soundTypeLinkId, + mimetypeTypeLinkId + ] + } + } + }, + }) + + const id = data.filter((link) => link.type_id === soundTypeLinkId)[0].id + const sound = data.filter((link) => link.type_id === soundTypeLinkId)[0].value.value + const format = data.filter((link) => link.type_id === formatTypeLinkId)[0].value.value + const mimetype = data.filter((link) => link.type_id === mimetypeTypeLinkId)[0].value.value + sounds = [...sounds, { id, sound, mimetype }] + } + setSounds(sounds); + } + + return + + + {sounds?.map((r) => +} + +export default function Index() { + return ( + + + + + + + + ); +} \ No newline at end of file diff --git a/pages/google-speech.tsx b/pages/google-speech.tsx new file mode 100644 index 00000000..49cfdc80 --- /dev/null +++ b/pages/google-speech.tsx @@ -0,0 +1,110 @@ +import React, { useState, useEffect, useCallback } from 'react'; +import { useLocalStore } from '@deep-foundation/store/local'; +import { DeepProvider, useDeep } from '@deep-foundation/deeplinks/imports/client'; +import { Provider } from '../imports/provider'; +import { Button, ChakraProvider, Stack, Text, Box, Card, Center, CardBody, Heading } from '@chakra-ui/react'; +import insertGcloudAuthFile from '../imports/google-speech/insert-gcloud-auth-file'; +import installPackage, { PACKAGE_NAME } from '../imports/google-speech/install-package'; +import fs from "fs"; +import transcribe from '../imports/google-speech/transcribe'; + +export const delay = (time) => new Promise(res => setTimeout(() => res(null), time)); + +export async function getStaticProps() { + const credentials = JSON.parse(fs.readFileSync("./imports/key.json", { encoding: "utf-8" })); + console.log(credentials); + return { + props: { + credentials + } + } +} + +function Page({ credentials }) { + const deep = useDeep(); + const [sounds, setSounds] = useLocalStore('Sounds', []) + const [deviceLinkId, setDeviceLinkId] = useLocalStore( + 'deviceLinkId', + undefined + ); + + const loadSounds = async () => { + const soundTypeLinkId = await deep.id("@deep-foundation/sound", "Sound"); + const formatTypeLinkId = await deep.id("@deep-foundation/sound", "Format"); + const mimetypeTypeLinkId = await deep.id("@deep-foundation/sound", "MIME/type"); + const transcriptionTypeLinkId = await deep.id("@deep-foundation/google-speech", "Transcription"); + const { data: soundLinks } = await deep.select({ + type_id: soundTypeLinkId + }); + + let sounds = []; + + for (let soundLink of soundLinks) { + const { data } = await deep.select({ + up: { + parent: { + id: soundLink.id + }, + link: { + type_id: { + _in: + [ + soundTypeLinkId, + formatTypeLinkId, + mimetypeTypeLinkId, + transcriptionTypeLinkId + ] + } + } + }, + }) + + const id = data.filter((link) => link.type_id === soundTypeLinkId)[0].id + const base64 = data.filter((link) => link.type_id === soundTypeLinkId)[0].value.value + const format = data.filter((link) => link.type_id === formatTypeLinkId)[0]?.value.value + const mimetype = data.filter((link) => link.type_id === mimetypeTypeLinkId)[0].value.value + const transcription = data.filter((link) => link.type_id === transcriptionTypeLinkId)[0]?.value.value + sounds = [...sounds, { id, base64, mimetype, format, transcription }] + } + setSounds(sounds); + } + + return + + + + {sounds?.map((s) => + + + + Sound link id: {s.id} + + + + )} + +} + +export default function Index({ credentials }) { + return ( + + + + + + + + ); +} \ No newline at end of file diff --git a/pages/index.tsx b/pages/index.tsx index 1e1d0c70..8e99303e 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -107,6 +107,18 @@ function Page() {
device
+
+ google-speech +
+
+ capacitor-voice-recorder +
+
+ sound +
+
+ convert-audio +
); } diff --git a/pages/sound.tsx b/pages/sound.tsx new file mode 100644 index 00000000..8df7590d --- /dev/null +++ b/pages/sound.tsx @@ -0,0 +1,37 @@ + + +import React, { useState, useEffect, useCallback } from 'react'; +import { useLocalStore } from '@deep-foundation/store/local'; +import { DeepProvider, useDeep } from '@deep-foundation/deeplinks/imports/client'; +import { Provider } from '../imports/provider'; +import { Button, ChakraProvider, Stack, Text } from '@chakra-ui/react'; +import initializePackage, { PACKAGE_NAME } from '../imports/sound/install-package'; + + +function Page() { + const deep = useDeep(); + const [deviceLinkId, setDeviceLinkId] = useLocalStore( + 'deviceLinkId', + undefined + ); + + + + return + + +} + +export default function Index() { + return ( + + + + + + + + ); +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 7ddf5255..a160b879 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,29 +1,23 @@ { "compilerOptions": { - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "sourceMap": true, - "noImplicitAny": false, - "removeComments": true, - "jsx": "preserve", - "module": "commonjs", - "moduleResolution": "node", - "target": "es2015", + "target": "es5", "lib": [ "dom", - "es6", - "es7" + "dom.iterable", + "esnext" ], - "resolveJsonModule": true, - "esModuleInterop": true, - "isolatedModules": true, - "declaration": true, "allowJs": true, "skipLibCheck": true, "strict": false, "forceConsistentCasingInFileNames": true, "noEmit": true, - "incremental": true + "incremental": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve" }, "include": [ "next-env.d.ts", @@ -31,10 +25,6 @@ "**/*.tsx" ], "exclude": [ - "node_modules", - "electron" - ], - "typeRoots": [ - "./node_modules/@types" + "node_modules" ] -} +} \ No newline at end of file