update: function to add frames into encoding queue
add: scripts to migrate to V3 schema TODO: fix processEncodingTasks() in `encoding.ts` TODO: write docs for V3 schema
This commit is contained in:
parent
37e0fbfc89
commit
1f9b8ea124
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "openrewind",
|
"name": "openrewind",
|
||||||
"version": "0.4.0",
|
"version": "0.5.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Your second brain, superpowered.",
|
"description": "Your second brain, superpowered.",
|
||||||
"main": "dist/electron/index.js",
|
"main": "dist/electron/index.js",
|
||||||
@ -32,15 +32,16 @@
|
|||||||
"i18next-electron-fs-backend": "^3.0.2",
|
"i18next-electron-fs-backend": "^3.0.2",
|
||||||
"i18next-fs-backend": "^2.6.0",
|
"i18next-fs-backend": "^2.6.0",
|
||||||
"i18next-icu": "^2.3.0",
|
"i18next-icu": "^2.3.0",
|
||||||
|
"image-size": "^1.1.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-i18next": "^15.1.2",
|
"react-i18next": "^15.1.2",
|
||||||
"react-router": "^7.0.1",
|
"react-router": "^7.0.1",
|
||||||
"react-router-dom": "^7.0.1",
|
"react-router-dom": "^7.0.1",
|
||||||
|
"screenshot-desktop": "^1.15.0",
|
||||||
"sqlite3": "^5.1.7",
|
"sqlite3": "^5.1.7",
|
||||||
"sqlstring": "^2.3.3",
|
"sqlstring": "^2.3.3",
|
||||||
"vite-tsconfig-paths": "^5.1.3",
|
"vite-tsconfig-paths": "^5.1.3"
|
||||||
"screenshot-desktop": "^1.15.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@electron/rebuild": "^3.7.1",
|
"@electron/rebuild": "^3.7.1",
|
||||||
|
132
pnpm-lock.yaml
132
pnpm-lock.yaml
@ -16,7 +16,7 @@ importers:
|
|||||||
version: 2.0.3
|
version: 2.0.3
|
||||||
better-sqlite3:
|
better-sqlite3:
|
||||||
specifier: ^11.6.0
|
specifier: ^11.6.0
|
||||||
version: 11.6.0
|
version: 11.7.0
|
||||||
electron-context-menu:
|
electron-context-menu:
|
||||||
specifier: ^4.0.4
|
specifier: ^4.0.4
|
||||||
version: 4.0.4
|
version: 4.0.4
|
||||||
@ -37,13 +37,13 @@ importers:
|
|||||||
version: 5.0.3
|
version: 5.0.3
|
||||||
execa:
|
execa:
|
||||||
specifier: ^9.5.1
|
specifier: ^9.5.1
|
||||||
version: 9.5.1
|
version: 9.5.2
|
||||||
i18next:
|
i18next:
|
||||||
specifier: ^24.0.2
|
specifier: ^24.0.2
|
||||||
version: 24.0.5(typescript@5.6.3)
|
version: 24.0.5(typescript@5.6.3)
|
||||||
i18next-browser-languagedetector:
|
i18next-browser-languagedetector:
|
||||||
specifier: ^8.0.0
|
specifier: ^8.0.0
|
||||||
version: 8.0.0
|
version: 8.0.1
|
||||||
i18next-electron-fs-backend:
|
i18next-electron-fs-backend:
|
||||||
specifier: ^3.0.2
|
specifier: ^3.0.2
|
||||||
version: 3.0.2
|
version: 3.0.2
|
||||||
@ -52,7 +52,10 @@ importers:
|
|||||||
version: 2.6.0
|
version: 2.6.0
|
||||||
i18next-icu:
|
i18next-icu:
|
||||||
specifier: ^2.3.0
|
specifier: ^2.3.0
|
||||||
version: 2.3.0(intl-messageformat@10.7.7)
|
version: 2.3.0(intl-messageformat@10.7.8)
|
||||||
|
image-size:
|
||||||
|
specifier: ^1.1.1
|
||||||
|
version: 1.1.1
|
||||||
react:
|
react:
|
||||||
specifier: ^18.3.1
|
specifier: ^18.3.1
|
||||||
version: 18.3.1
|
version: 18.3.1
|
||||||
@ -131,7 +134,7 @@ importers:
|
|||||||
version: 0.0.3
|
version: 0.0.3
|
||||||
electron-builder:
|
electron-builder:
|
||||||
specifier: ^25.1.8
|
specifier: ^25.1.8
|
||||||
version: 25.1.8(electron-builder-squirrel-windows@25.1.8(dmg-builder@25.1.8))
|
version: 25.1.8(electron-builder-squirrel-windows@25.1.8)
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^9.13.0
|
specifier: ^9.13.0
|
||||||
version: 9.16.0(jiti@1.21.6)
|
version: 9.16.0(jiti@1.21.6)
|
||||||
@ -487,17 +490,17 @@ packages:
|
|||||||
resolution: {integrity: sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==}
|
resolution: {integrity: sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
'@formatjs/ecma402-abstract@2.2.4':
|
'@formatjs/ecma402-abstract@2.2.5':
|
||||||
resolution: {integrity: sha512-lFyiQDVvSbQOpU+WFd//ILolGj4UgA/qXrKeZxdV14uKiAUiPAtX6XAn7WBCRi7Mx6I7EybM9E5yYn4BIpZWYg==}
|
resolution: {integrity: sha512-ep/5vGkyZvMSi6s8nQG8k7vTcKjuXs402fgGIWixj0AWRgKbeaZeLuYc32NIPXexgBjWepMeZGgHLuZXkuD2Gg==}
|
||||||
|
|
||||||
'@formatjs/fast-memoize@2.2.3':
|
'@formatjs/fast-memoize@2.2.4':
|
||||||
resolution: {integrity: sha512-3jeJ+HyOfu8osl3GNSL4vVHUuWFXR03Iz9jjgI7RwjG6ysu/Ymdr0JRCPHfF5yGbTE6JCrd63EpvX1/WybYRbA==}
|
resolution: {integrity: sha512-8SzI0cBADgbLOYsoQW/IqVHljCH964CrOdESFQ07wMkRLP90+MfV7k6gZPiGD88ubqET9igJV5c292rT28B7xQ==}
|
||||||
|
|
||||||
'@formatjs/icu-messageformat-parser@2.9.4':
|
'@formatjs/icu-messageformat-parser@2.9.5':
|
||||||
resolution: {integrity: sha512-Tbvp5a9IWuxUcpWNIW6GlMQYEc4rwNHR259uUFoKWNN1jM9obf9Ul0e+7r7MvFOBNcN+13K7NuKCKqQiAn1QEg==}
|
resolution: {integrity: sha512-mHauC9wuVXtnshAIoAYjlNrh6+OFOT6cC4fpK+AG+DHkVWwIPFVQE28hLQ/KptuvQ8VMfG/zYx6rRjtaeFPkSQ==}
|
||||||
|
|
||||||
'@formatjs/icu-skeleton-parser@1.8.8':
|
'@formatjs/icu-skeleton-parser@1.8.9':
|
||||||
resolution: {integrity: sha512-vHwK3piXwamFcx5YQdCdJxUQ1WdTl6ANclt5xba5zLGDv5Bsur7qz8AD7BevaKxITwpgDeU0u8My3AIibW9ywA==}
|
resolution: {integrity: sha512-1KSSlU7ywsU5E5v7xr6VTlBzLGszMi3GOu7EVINjkfA501GN5OkeNSbd5q6ie1wIknZJGBlqkvXPYYdp3YXjpw==}
|
||||||
|
|
||||||
'@formatjs/intl-localematcher@0.5.8':
|
'@formatjs/intl-localematcher@0.5.8':
|
||||||
resolution: {integrity: sha512-I+WDNWWJFZie+jkfkiK5Mp4hEDyRSEvmyfYadflOno/mmKJKcB17fEpEH0oJu/OWhhCJ8kJBDz2YMd/6cDl7Mg==}
|
resolution: {integrity: sha512-I+WDNWWJFZie+jkfkiK5Mp4hEDyRSEvmyfYadflOno/mmKJKcB17fEpEH0oJu/OWhhCJ8kJBDz2YMd/6cDl7Mg==}
|
||||||
@ -929,8 +932,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
||||||
engines: {node: '>= 6.0.0'}
|
engines: {node: '>= 6.0.0'}
|
||||||
|
|
||||||
agent-base@7.1.2:
|
agent-base@7.1.3:
|
||||||
resolution: {integrity: sha512-JVzqkCNRT+VfqzzgPWDPnwvDheSAUdiMUn3NoLXpDJF5lRqeJqyC9iGsAxIOAW+mzIdq+uP1TvcX6bMtrH0agg==}
|
resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
|
|
||||||
agentkeepalive@4.5.0:
|
agentkeepalive@4.5.0:
|
||||||
@ -1173,8 +1176,8 @@ packages:
|
|||||||
bcrypt-pbkdf@1.0.2:
|
bcrypt-pbkdf@1.0.2:
|
||||||
resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==}
|
resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==}
|
||||||
|
|
||||||
better-sqlite3@11.6.0:
|
better-sqlite3@11.7.0:
|
||||||
resolution: {integrity: sha512-2J6k/eVxcFYY2SsTxsXrj6XylzHWPxveCn4fKPKZFv/Vqn/Cd7lOuX4d7rGQXT5zL+97MkNL3nSbCrIoe3LkgA==}
|
resolution: {integrity: sha512-mXpa5jnIKKHeoGzBrUJrc65cXFKcILGZpU3FXR0pradUEm9MA7UZz02qfEejaMcm9iXrSOCenwwYMJ/tZ1y5Ig==}
|
||||||
|
|
||||||
binary-extensions@2.3.0:
|
binary-extensions@2.3.0:
|
||||||
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
||||||
@ -1407,8 +1410,8 @@ packages:
|
|||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
conf@13.0.1:
|
conf@13.1.0:
|
||||||
resolution: {integrity: sha512-l9Uwc9eOnz39oADzGO2cSBDi7siv8lwO+31ocQ2nOJijnDiW3pxqm9VV10DPYUO28wW83DjABoUqY1nfHRR2hQ==}
|
resolution: {integrity: sha512-Bi6v586cy1CoTFViVO4lGTtx780lfF96fUmS1lSX6wpZf6330NvHUu6fReVuDP1de8Mg0nkZb01c8tAQdz1o3w==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
config-file-ts@0.2.8-rc1:
|
config-file-ts@0.2.8-rc1:
|
||||||
@ -1766,8 +1769,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
execa@9.5.1:
|
execa@9.5.2:
|
||||||
resolution: {integrity: sha512-QY5PPtSonnGwhhHDNI7+3RvY285c7iuJFFB+lU+oEzMY/gEGJ808owqJsrr8Otd1E/x07po1LkUBmdAc5duPAg==}
|
resolution: {integrity: sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==}
|
||||||
engines: {node: ^18.19.0 || >=20.5.0}
|
engines: {node: ^18.19.0 || >=20.5.0}
|
||||||
|
|
||||||
expand-template@2.0.3:
|
expand-template@2.0.3:
|
||||||
@ -2208,8 +2211,8 @@ packages:
|
|||||||
i18next-browser-languagedetector@4.0.1:
|
i18next-browser-languagedetector@4.0.1:
|
||||||
resolution: {integrity: sha512-RxSoX6mB8cab0CTIQ+klCS764vYRj+Jk621cnFVsINvcdlb/cdi3vQFyrPwmnowB7ReUadjHovgZX+RPIzHVQQ==}
|
resolution: {integrity: sha512-RxSoX6mB8cab0CTIQ+klCS764vYRj+Jk621cnFVsINvcdlb/cdi3vQFyrPwmnowB7ReUadjHovgZX+RPIzHVQQ==}
|
||||||
|
|
||||||
i18next-browser-languagedetector@8.0.0:
|
i18next-browser-languagedetector@8.0.1:
|
||||||
resolution: {integrity: sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==}
|
resolution: {integrity: sha512-z9ZuWA7qxbww+cPtdJTgV0O2H9+qlLpQnb37RpnwfsWnUmrO+q92gbVKVtfBL7jRvxfmVMOUKxKGg6VBqO49Pg==}
|
||||||
|
|
||||||
i18next-electron-fs-backend@3.0.2:
|
i18next-electron-fs-backend@3.0.2:
|
||||||
resolution: {integrity: sha512-KRP+4ORx0WG31qHvMNUpI4CytEQFAkFtXnrZ9/NBXH6k/DcKU3IdB573Zl+L+lR4GA6PCKyBX89mqrUhStoItA==}
|
resolution: {integrity: sha512-KRP+4ORx0WG31qHvMNUpI4CytEQFAkFtXnrZ9/NBXH6k/DcKU3IdB573Zl+L+lR4GA6PCKyBX89mqrUhStoItA==}
|
||||||
@ -2252,6 +2255,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
|
|
||||||
|
image-size@1.1.1:
|
||||||
|
resolution: {integrity: sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==}
|
||||||
|
engines: {node: '>=16.x'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
import-fresh@3.3.0:
|
import-fresh@3.3.0:
|
||||||
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
|
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@ -2287,8 +2295,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==}
|
resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==}
|
||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
|
|
||||||
intl-messageformat@10.7.7:
|
intl-messageformat@10.7.8:
|
||||||
resolution: {integrity: sha512-F134jIoeYMro/3I0h08D0Yt4N9o9pjddU/4IIxMMURqbAtI2wu70X8hvG1V48W49zXHXv3RKSF/po+0fDfsGjA==}
|
resolution: {integrity: sha512-XnFFzJnTfdaDqeiF/ZAUjpkoKEM8UKwHijQXuqpLiM42kuJCawytP/rYAMDYNNaWww/PTaI0rIoG4oUjRrRlnA==}
|
||||||
|
|
||||||
ip-address@9.0.5:
|
ip-address@9.0.5:
|
||||||
resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==}
|
resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==}
|
||||||
@ -3167,6 +3175,9 @@ packages:
|
|||||||
queue-tick@1.0.1:
|
queue-tick@1.0.1:
|
||||||
resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==}
|
resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==}
|
||||||
|
|
||||||
|
queue@6.0.2:
|
||||||
|
resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==}
|
||||||
|
|
||||||
quick-lru@5.1.1:
|
quick-lru@5.1.1:
|
||||||
resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
|
resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@ -4382,25 +4393,25 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
levn: 0.4.1
|
levn: 0.4.1
|
||||||
|
|
||||||
'@formatjs/ecma402-abstract@2.2.4':
|
'@formatjs/ecma402-abstract@2.2.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@formatjs/fast-memoize': 2.2.3
|
'@formatjs/fast-memoize': 2.2.4
|
||||||
'@formatjs/intl-localematcher': 0.5.8
|
'@formatjs/intl-localematcher': 0.5.8
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
'@formatjs/fast-memoize@2.2.3':
|
'@formatjs/fast-memoize@2.2.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
'@formatjs/icu-messageformat-parser@2.9.4':
|
'@formatjs/icu-messageformat-parser@2.9.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@formatjs/ecma402-abstract': 2.2.4
|
'@formatjs/ecma402-abstract': 2.2.5
|
||||||
'@formatjs/icu-skeleton-parser': 1.8.8
|
'@formatjs/icu-skeleton-parser': 1.8.9
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
'@formatjs/icu-skeleton-parser@1.8.8':
|
'@formatjs/icu-skeleton-parser@1.8.9':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@formatjs/ecma402-abstract': 2.2.4
|
'@formatjs/ecma402-abstract': 2.2.5
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
'@formatjs/intl-localematcher@0.5.8':
|
'@formatjs/intl-localematcher@0.5.8':
|
||||||
@ -4847,11 +4858,7 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
agent-base@7.1.2:
|
agent-base@7.1.3: {}
|
||||||
dependencies:
|
|
||||||
debug: 4.4.0
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
|
|
||||||
agentkeepalive@4.5.0:
|
agentkeepalive@4.5.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -4927,7 +4934,7 @@ snapshots:
|
|||||||
|
|
||||||
app-builder-bin@5.0.0-alpha.10: {}
|
app-builder-bin@5.0.0-alpha.10: {}
|
||||||
|
|
||||||
app-builder-lib@25.1.8(dmg-builder@25.1.8(electron-builder-squirrel-windows@25.1.8))(electron-builder-squirrel-windows@25.1.8(dmg-builder@25.1.8)):
|
app-builder-lib@25.1.8(dmg-builder@25.1.8)(electron-builder-squirrel-windows@25.1.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@develar/schema-utils': 2.6.5
|
'@develar/schema-utils': 2.6.5
|
||||||
'@electron/notarize': 2.5.0
|
'@electron/notarize': 2.5.0
|
||||||
@ -5119,7 +5126,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
tweetnacl: 0.14.5
|
tweetnacl: 0.14.5
|
||||||
|
|
||||||
better-sqlite3@11.6.0:
|
better-sqlite3@11.7.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
bindings: 1.5.0
|
bindings: 1.5.0
|
||||||
prebuild-install: 7.1.2
|
prebuild-install: 7.1.2
|
||||||
@ -5431,7 +5438,7 @@ snapshots:
|
|||||||
tree-kill: 1.2.2
|
tree-kill: 1.2.2
|
||||||
yargs: 17.7.2
|
yargs: 17.7.2
|
||||||
|
|
||||||
conf@13.0.1:
|
conf@13.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
ajv: 8.17.1
|
ajv: 8.17.1
|
||||||
ajv-formats: 3.0.1(ajv@8.17.1)
|
ajv-formats: 3.0.1(ajv@8.17.1)
|
||||||
@ -5568,7 +5575,7 @@ snapshots:
|
|||||||
|
|
||||||
dmg-builder@25.1.8(electron-builder-squirrel-windows@25.1.8):
|
dmg-builder@25.1.8(electron-builder-squirrel-windows@25.1.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
app-builder-lib: 25.1.8(dmg-builder@25.1.8(electron-builder-squirrel-windows@25.1.8))(electron-builder-squirrel-windows@25.1.8(dmg-builder@25.1.8))
|
app-builder-lib: 25.1.8(dmg-builder@25.1.8)(electron-builder-squirrel-windows@25.1.8)
|
||||||
builder-util: 25.1.7
|
builder-util: 25.1.7
|
||||||
builder-util-runtime: 9.2.10
|
builder-util-runtime: 9.2.10
|
||||||
fs-extra: 10.1.0
|
fs-extra: 10.1.0
|
||||||
@ -5646,7 +5653,7 @@ snapshots:
|
|||||||
|
|
||||||
electron-builder-squirrel-windows@25.1.8(dmg-builder@25.1.8):
|
electron-builder-squirrel-windows@25.1.8(dmg-builder@25.1.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
app-builder-lib: 25.1.8(dmg-builder@25.1.8(electron-builder-squirrel-windows@25.1.8))(electron-builder-squirrel-windows@25.1.8(dmg-builder@25.1.8))
|
app-builder-lib: 25.1.8(dmg-builder@25.1.8)(electron-builder-squirrel-windows@25.1.8)
|
||||||
archiver: 5.3.2
|
archiver: 5.3.2
|
||||||
builder-util: 25.1.7
|
builder-util: 25.1.7
|
||||||
fs-extra: 10.1.0
|
fs-extra: 10.1.0
|
||||||
@ -5655,9 +5662,9 @@ snapshots:
|
|||||||
- dmg-builder
|
- dmg-builder
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
electron-builder@25.1.8(electron-builder-squirrel-windows@25.1.8(dmg-builder@25.1.8)):
|
electron-builder@25.1.8(electron-builder-squirrel-windows@25.1.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
app-builder-lib: 25.1.8(dmg-builder@25.1.8(electron-builder-squirrel-windows@25.1.8))(electron-builder-squirrel-windows@25.1.8(dmg-builder@25.1.8))
|
app-builder-lib: 25.1.8(dmg-builder@25.1.8)(electron-builder-squirrel-windows@25.1.8)
|
||||||
builder-util: 25.1.7
|
builder-util: 25.1.7
|
||||||
builder-util-runtime: 9.2.10
|
builder-util-runtime: 9.2.10
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
@ -5718,7 +5725,7 @@ snapshots:
|
|||||||
|
|
||||||
electron-store@10.0.0:
|
electron-store@10.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
conf: 13.0.1
|
conf: 13.1.0
|
||||||
type-fest: 4.30.0
|
type-fest: 4.30.0
|
||||||
|
|
||||||
electron-to-chromium@1.5.71: {}
|
electron-to-chromium@1.5.71: {}
|
||||||
@ -5878,7 +5885,7 @@ snapshots:
|
|||||||
|
|
||||||
esutils@2.0.3: {}
|
esutils@2.0.3: {}
|
||||||
|
|
||||||
execa@9.5.1:
|
execa@9.5.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sindresorhus/merge-streams': 4.0.0
|
'@sindresorhus/merge-streams': 4.0.0
|
||||||
cross-spawn: 7.0.6
|
cross-spawn: 7.0.6
|
||||||
@ -5933,7 +5940,8 @@ snapshots:
|
|||||||
|
|
||||||
extsprintf@1.3.0: {}
|
extsprintf@1.3.0: {}
|
||||||
|
|
||||||
extsprintf@1.4.1: {}
|
extsprintf@1.4.1:
|
||||||
|
optional: true
|
||||||
|
|
||||||
fancy-log@1.3.3:
|
fancy-log@1.3.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -6404,7 +6412,7 @@ snapshots:
|
|||||||
|
|
||||||
http-proxy-agent@7.0.2:
|
http-proxy-agent@7.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
agent-base: 7.1.2
|
agent-base: 7.1.3
|
||||||
debug: 4.4.0
|
debug: 4.4.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@ -6429,7 +6437,7 @@ snapshots:
|
|||||||
|
|
||||||
https-proxy-agent@7.0.6:
|
https-proxy-agent@7.0.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
agent-base: 7.1.2
|
agent-base: 7.1.3
|
||||||
debug: 4.4.0
|
debug: 4.4.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@ -6444,7 +6452,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.26.0
|
'@babel/runtime': 7.26.0
|
||||||
|
|
||||||
i18next-browser-languagedetector@8.0.0:
|
i18next-browser-languagedetector@8.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.26.0
|
'@babel/runtime': 7.26.0
|
||||||
|
|
||||||
@ -6455,9 +6463,9 @@ snapshots:
|
|||||||
|
|
||||||
i18next-fs-backend@2.6.0: {}
|
i18next-fs-backend@2.6.0: {}
|
||||||
|
|
||||||
i18next-icu@2.3.0(intl-messageformat@10.7.7):
|
i18next-icu@2.3.0(intl-messageformat@10.7.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
intl-messageformat: 10.7.7
|
intl-messageformat: 10.7.8
|
||||||
|
|
||||||
i18next@19.0.2:
|
i18next@19.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -6487,6 +6495,10 @@ snapshots:
|
|||||||
|
|
||||||
ignore@5.3.2: {}
|
ignore@5.3.2: {}
|
||||||
|
|
||||||
|
image-size@1.1.1:
|
||||||
|
dependencies:
|
||||||
|
queue: 6.0.2
|
||||||
|
|
||||||
import-fresh@3.3.0:
|
import-fresh@3.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
parent-module: 1.0.1
|
parent-module: 1.0.1
|
||||||
@ -6513,11 +6525,11 @@ snapshots:
|
|||||||
|
|
||||||
interpret@3.1.1: {}
|
interpret@3.1.1: {}
|
||||||
|
|
||||||
intl-messageformat@10.7.7:
|
intl-messageformat@10.7.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@formatjs/ecma402-abstract': 2.2.4
|
'@formatjs/ecma402-abstract': 2.2.5
|
||||||
'@formatjs/fast-memoize': 2.2.3
|
'@formatjs/fast-memoize': 2.2.4
|
||||||
'@formatjs/icu-messageformat-parser': 2.9.4
|
'@formatjs/icu-messageformat-parser': 2.9.5
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
ip-address@9.0.5:
|
ip-address@9.0.5:
|
||||||
@ -7335,6 +7347,10 @@ snapshots:
|
|||||||
|
|
||||||
queue-tick@1.0.1: {}
|
queue-tick@1.0.1: {}
|
||||||
|
|
||||||
|
queue@6.0.2:
|
||||||
|
dependencies:
|
||||||
|
inherits: 2.0.4
|
||||||
|
|
||||||
quick-lru@5.1.1: {}
|
quick-lru@5.1.1: {}
|
||||||
|
|
||||||
rc@1.2.8:
|
rc@1.2.8:
|
||||||
@ -8104,7 +8120,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
assert-plus: 1.0.0
|
assert-plus: 1.0.0
|
||||||
core-util-is: 1.0.2
|
core-util-is: 1.0.2
|
||||||
extsprintf: 1.4.1
|
extsprintf: 1.3.0
|
||||||
|
|
||||||
verror@1.10.1:
|
verror@1.10.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
118
src/electron/backend/encoding.ts
Normal file
118
src/electron/backend/encoding.ts
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import { Database } from 'better-sqlite3';
|
||||||
|
import { exec } from 'child_process';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path, { join } from "path";
|
||||||
|
import type { EncodingTask, Frame } from "./schema";
|
||||||
|
import sizeOf from "image-size";
|
||||||
|
import { getScreenshotsDir } from "../utils/backend.js";
|
||||||
|
|
||||||
|
const ENCODING_INTERVAL = 10000; // 10 sec
|
||||||
|
const CHECK_TASK_INTERVAL = 5000; // 5 sec
|
||||||
|
const MIN_FRAMES_TO_ENCODE = 300; // At least 10 mins (0.5fps)
|
||||||
|
const CONCURRENCY = 1; // Number of concurrent encoding tasks
|
||||||
|
|
||||||
|
// Detect and insert encoding tasks
|
||||||
|
export function checkFramesForEncoding(db: Database) {
|
||||||
|
const stmt = db.prepare(`
|
||||||
|
SELECT id, imgFilename, createdAt
|
||||||
|
FROM frame
|
||||||
|
WHERE encodeStatus = 0
|
||||||
|
ORDER BY createdAt ASC;
|
||||||
|
`);
|
||||||
|
const frames = stmt.all() as Frame[];
|
||||||
|
|
||||||
|
const buffer: Frame[] = [];
|
||||||
|
|
||||||
|
if (frames.length < MIN_FRAMES_TO_ENCODE) return;
|
||||||
|
|
||||||
|
for (let i = 1; i < frames.length; i++) {
|
||||||
|
const frame = frames[i];
|
||||||
|
const lastFrame = frames[i - 1];
|
||||||
|
const currentFrameSize = sizeOf(join(getScreenshotsDir(), frame.imgFilename));
|
||||||
|
const lastFrameSize = sizeOf(join(getScreenshotsDir(), lastFrame.imgFilename));
|
||||||
|
const twoFramesHaveSameSize =
|
||||||
|
currentFrameSize.width === lastFrameSize.width
|
||||||
|
&& currentFrameSize.height === lastFrameSize.height;
|
||||||
|
const bufferIsBigEnough = buffer.length >= MIN_FRAMES_TO_ENCODE;
|
||||||
|
const chunkConditionSatisfied = !twoFramesHaveSameSize || bufferIsBigEnough;
|
||||||
|
buffer.push(lastFrame);
|
||||||
|
if (chunkConditionSatisfied) {
|
||||||
|
// Create new encoding task
|
||||||
|
const taskStmt = db.prepare(`
|
||||||
|
INSERT INTO encoding_task (status) VALUES (0);
|
||||||
|
`);
|
||||||
|
const taskId = taskStmt.run().lastInsertRowid;
|
||||||
|
|
||||||
|
// Insert frames into encoding_task_data
|
||||||
|
const insertStmt = db.prepare(`
|
||||||
|
INSERT INTO encoding_task_data (encodingTaskID, frame) VALUES (?, ?);
|
||||||
|
`);
|
||||||
|
for (const frame of buffer) {
|
||||||
|
insertStmt.run(taskId, frame.id);
|
||||||
|
db.prepare(`
|
||||||
|
UPDATE frame SET encodeStatus = 1 WHERE id = ?;
|
||||||
|
`).run(frame.id);
|
||||||
|
}
|
||||||
|
console.log(`Created encoding task ${taskId} with ${buffer.length} frames`);
|
||||||
|
buffer.length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Fix this function
|
||||||
|
// Check and process encoding task
|
||||||
|
function processEncodingTasks(db: Database) {
|
||||||
|
const stmt = db.prepare(`
|
||||||
|
SELECT id, status
|
||||||
|
FROM encoding_task
|
||||||
|
WHERE status = 0
|
||||||
|
LIMIT ?
|
||||||
|
`);
|
||||||
|
|
||||||
|
const tasks = stmt.all(CONCURRENCY) as EncodingTask[];
|
||||||
|
|
||||||
|
for (const task of tasks) {
|
||||||
|
const taskId = task.id;
|
||||||
|
|
||||||
|
// Update task status as processing (1)
|
||||||
|
const updateStmt = db.prepare(`
|
||||||
|
UPDATE encoding_task SET status = 1 WHERE id = ?
|
||||||
|
`);
|
||||||
|
updateStmt.run(taskId);
|
||||||
|
|
||||||
|
const framesStmt = db.prepare(`
|
||||||
|
SELECT frame.imgFilename
|
||||||
|
FROM encoding_task_data
|
||||||
|
JOIN frame ON encoding_task_data.frame = frame.id
|
||||||
|
WHERE encoding_task_data.encodingTaskID = ?
|
||||||
|
ORDER BY frame.createAt ASC
|
||||||
|
`);
|
||||||
|
const frames = framesStmt.all(taskId) as Frame[];
|
||||||
|
|
||||||
|
const metaFilePath = path.join(__dirname, `${taskId}_meta.txt`);
|
||||||
|
const metaContent = frames.map(frame => `file '${frame.imgFilename}'`).join('\n');
|
||||||
|
fs.writeFileSync(metaFilePath, metaContent);
|
||||||
|
|
||||||
|
const videoName = `video_${taskId}.mp4`;
|
||||||
|
const ffmpegCommand = `ffmpeg -f concat -safe 0 -i ${metaFilePath} -c:v libx264 -r 30 ${videoName}`;
|
||||||
|
exec(ffmpegCommand, (error, stdout, stderr) => {
|
||||||
|
if (error) {
|
||||||
|
console.error(`FFmpeg error: ${error.message}`);
|
||||||
|
// Set task status to unprocessed (0)
|
||||||
|
const failStmt = db.prepare(`
|
||||||
|
UPDATE encoding_task SET status = 0 WHERE id = ?
|
||||||
|
`);
|
||||||
|
failStmt.run(taskId);
|
||||||
|
} else {
|
||||||
|
console.log(`Video ${videoName} created successfully`);
|
||||||
|
// Update task status to complete (2)
|
||||||
|
const completeStmt = db.prepare(`
|
||||||
|
UPDATE encoding_task SET status = 2 WHERE id = ?
|
||||||
|
`);
|
||||||
|
completeStmt.run(taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.unlinkSync(metaFilePath);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,6 @@ import DB from "better-sqlite3";
|
|||||||
import { __dirname } from "../dirname.js";
|
import { __dirname } from "../dirname.js";
|
||||||
import { getDatabaseDir } from "../utils/backend.js";
|
import { getDatabaseDir } from "../utils/backend.js";
|
||||||
import { migrate } from "./migrate/index.js";
|
import { migrate } from "./migrate/index.js";
|
||||||
import { initSchemaInV2 } from "./migrate/migrateToV2";
|
|
||||||
|
|
||||||
function getLibSimpleExtensionPath() {
|
function getLibSimpleExtensionPath() {
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
@ -28,14 +27,14 @@ function init(db: Database) {
|
|||||||
db.exec(`
|
db.exec(`
|
||||||
CREATE TABLE IF NOT EXISTS frame (
|
CREATE TABLE IF NOT EXISTS frame (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
createAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
createdAt REAL,
|
||||||
imgFilename TEXT,
|
imgFilename TEXT,
|
||||||
segmentID INTEGER NULL,
|
segmentID INTEGER NULL,
|
||||||
videoPath TEXT NULL,
|
videoPath TEXT NULL,
|
||||||
videoFrameIndex INTEGER NULL,
|
videoFrameIndex INTEGER NULL,
|
||||||
collectionID INTEGER NULL,
|
collectionID INTEGER NULL,
|
||||||
encoded BOOLEAN DEFAULT 0,
|
encodeStatus INTEGER DEFAULT 0,
|
||||||
FOREIGN KEY (segmentID) REFERENCES segements (id)
|
FOREIGN KEY (segmentID) REFERENCES segments (id)
|
||||||
);
|
);
|
||||||
`);
|
`);
|
||||||
|
|
||||||
@ -50,10 +49,10 @@ function init(db: Database) {
|
|||||||
`);
|
`);
|
||||||
|
|
||||||
db.exec(`
|
db.exec(`
|
||||||
CREATE TABLE IF NOT EXISTS segements(
|
CREATE TABLE IF NOT EXISTS segments(
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
startAt TIMESTAMP,
|
startedAt REAL,
|
||||||
endAt TIMESTAMP,
|
endedAt REAL,
|
||||||
title TEXT,
|
title TEXT,
|
||||||
appName TEXT,
|
appName TEXT,
|
||||||
appPath TEXT,
|
appPath TEXT,
|
||||||
@ -97,10 +96,49 @@ function init(db: Database) {
|
|||||||
END;
|
END;
|
||||||
`);
|
`);
|
||||||
|
|
||||||
initSchemaInV2(db);
|
db.exec(`
|
||||||
|
CREATE TABLE config (
|
||||||
|
key TEXT PRIMARY KEY,
|
||||||
|
value TEXT
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
|
||||||
|
db.exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS encoding_task (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
createdAt REAL,
|
||||||
|
status INT DEFAULT 0
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
|
||||||
|
db.exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS encoding_task_data (
|
||||||
|
encodingTaskID INTEGER,
|
||||||
|
frame ID INTEGER PRIMARY KEY,
|
||||||
|
FOREIGN KEY (encodingTaskID) REFERENCES encoding_task(id),
|
||||||
|
FOREIGN KEY (frame) REFERENCES frame(id)
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
|
||||||
|
db.exec(`
|
||||||
|
CREATE TRIGGER IF NOT EXISTS delete_encoding_task
|
||||||
|
AFTER UPDATE OF status
|
||||||
|
ON encoding_task
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM encoding_task_data
|
||||||
|
WHERE encodingTaskID = OLD.id AND NEW.status = 2;
|
||||||
|
|
||||||
|
DELETE FROM encoding_task
|
||||||
|
WHERE id = OLD.id AND NEW.status = 2;
|
||||||
|
END;
|
||||||
|
`);
|
||||||
|
|
||||||
|
db.exec(`
|
||||||
|
INSERT INTO config (key, value) VALUES ('version', '3');
|
||||||
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initDatabase() {
|
export async function initDatabase() {
|
||||||
const dbPath = getDatabaseDir();
|
const dbPath = getDatabaseDir();
|
||||||
const db = new DB(dbPath, { verbose: console.log });
|
const db = new DB(dbPath, { verbose: console.log });
|
||||||
const libSimpleExtensionPath = getLibSimpleExtensionPath();
|
const libSimpleExtensionPath = getLibSimpleExtensionPath();
|
||||||
@ -114,5 +152,7 @@ export function initDatabase() {
|
|||||||
migrate(db);
|
migrate(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
db.exec("PRAGMA journal_mode=WAL;");
|
||||||
|
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,16 @@
|
|||||||
import { Database } from "better-sqlite3";
|
import { Database } from "better-sqlite3";
|
||||||
import { migrateToV2 } from "./migrateToV2.js";
|
import { migrateToV2 } from "./migrateToV2.js";
|
||||||
|
import { migrateToV3 } from "./migrateToV3.js";
|
||||||
|
|
||||||
|
const CURRENT_VERSION = 3;
|
||||||
|
|
||||||
|
function migrateTo(version: number, db: Database) {
|
||||||
|
switch (version) {
|
||||||
|
case 2:
|
||||||
|
migrateToV3(db);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function migrate(db: Database) {
|
export function migrate(db: Database) {
|
||||||
const configTableExists =
|
const configTableExists =
|
||||||
@ -8,4 +19,19 @@ export function migrate(db: Database) {
|
|||||||
if (!configTableExists) {
|
if (!configTableExists) {
|
||||||
migrateToV2(db);
|
migrateToV2(db);
|
||||||
}
|
}
|
||||||
|
let databaseVersion = parseInt(
|
||||||
|
(
|
||||||
|
db.prepare(`SELECT value FROM config WHERE key = 'version';`).get() as
|
||||||
|
{ value: any }
|
||||||
|
).value
|
||||||
|
);
|
||||||
|
while (databaseVersion < CURRENT_VERSION) {
|
||||||
|
migrateTo(databaseVersion, db);
|
||||||
|
databaseVersion = parseInt(
|
||||||
|
(
|
||||||
|
db.prepare(`SELECT value FROM config WHERE key = 'version';`).get() as
|
||||||
|
{ value: any }
|
||||||
|
).value
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
@ -11,7 +11,7 @@ interface OldFrame {
|
|||||||
encoded: number;
|
encoded: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initSchemaInV2(db: Database) {
|
function initSchemaInV2(db: Database) {
|
||||||
db.exec(`
|
db.exec(`
|
||||||
CREATE TABLE config (
|
CREATE TABLE config (
|
||||||
key TEXT PRIMARY KEY,
|
key TEXT PRIMARY KEY,
|
||||||
|
191
src/electron/backend/migrate/migrateToV3.ts
Normal file
191
src/electron/backend/migrate/migrateToV3.ts
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
import { Database } from "better-sqlite3";
|
||||||
|
|
||||||
|
function convertTimestampToUnix(timestamp: string): number {
|
||||||
|
const date = new Date(timestamp);
|
||||||
|
const now = new Date();
|
||||||
|
const offsetInMinutes = now.getTimezoneOffset();
|
||||||
|
const offsetInSeconds = offsetInMinutes * 60;
|
||||||
|
return date.getTime() / 1000 - offsetInSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformEncodingTask(db: Database) {
|
||||||
|
const createTableSql = `
|
||||||
|
CREATE TABLE IF NOT EXISTS encoding_task_new (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
status INT DEFAULT 0
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO encoding_task_new (id, createdAt, status)
|
||||||
|
SELECT id, createdAt, status FROM encoding_task;
|
||||||
|
DROP TABLE encoding_task;
|
||||||
|
ALTER TABLE encoding_task_new RENAME TO encoding_task;
|
||||||
|
ALTER TABLE encoding_task ADD COLUMN createdAt_new REAL;
|
||||||
|
`;
|
||||||
|
db.exec(createTableSql);
|
||||||
|
|
||||||
|
const rows = db.prepare(`SELECT id, createdAt FROM encoding_task`).all() as { [x: string]: unknown; id: unknown; }[];
|
||||||
|
const updateStmt = db.prepare(`UPDATE encoding_task SET createdAt_new = ? WHERE id = ?`);
|
||||||
|
rows.forEach((row) => {
|
||||||
|
const unixTimestamp = convertTimestampToUnix(row.createdAt as string);
|
||||||
|
updateStmt.run(unixTimestamp, row.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
db.exec(`
|
||||||
|
ALTER TABLE encoding_task DROP COLUMN createdAt;
|
||||||
|
ALTER TABLE encoding_task RENAME COLUMN createdAt_new TO createdAt;
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformFrame(db: Database) {
|
||||||
|
const createTableSql = `
|
||||||
|
CREATE TABLE frame_new(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
imgFilename TEXT,
|
||||||
|
segmentID INTEGER NULL,
|
||||||
|
videoPath TEXT NULL,
|
||||||
|
videoFrameIndex INTEGER NULL,
|
||||||
|
collectionID INTEGER NULL,
|
||||||
|
encodeStatus INT DEFAULT 0,
|
||||||
|
FOREIGN KEY (segmentID) REFERENCES segments (id)
|
||||||
|
);
|
||||||
|
INSERT INTO frame_new (id, createdAt, imgFilename, segmentID, videoPath, videoFrameIndex, collectionID, encodeStatus)
|
||||||
|
SELECT id, createdAt, imgFilename, segmentID, videoPath, videoFrameIndex, collectionID, encodeStatus FROM frame;
|
||||||
|
DROP TABLE frame;
|
||||||
|
ALTER TABLE frame_new RENAME TO frame;
|
||||||
|
ALTER TABLE frame ADD COLUMN createdAt_new REAL;
|
||||||
|
`
|
||||||
|
db.exec(createTableSql);
|
||||||
|
|
||||||
|
const rows = db.prepare(`SELECT id, createdAt FROM frame`).all() as { [x: string]: unknown; id: unknown; }[];
|
||||||
|
const updateStmt = db.prepare(`UPDATE frame SET createdAt_new = ? WHERE id = ?`);
|
||||||
|
rows.forEach((row) => {
|
||||||
|
const unixTimestamp = convertTimestampToUnix(row.createdAt as string);
|
||||||
|
updateStmt.run(unixTimestamp, row.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
db.exec(`
|
||||||
|
ALTER TABLE frame DROP COLUMN createdAt;
|
||||||
|
ALTER TABLE frame RENAME COLUMN createdAt_new TO createdAt;
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformSegments(db: Database) {
|
||||||
|
db.exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS segments_new(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
startedAt REAL,
|
||||||
|
endedAt REAL,
|
||||||
|
title TEXT,
|
||||||
|
appName TEXT,
|
||||||
|
appPath TEXT,
|
||||||
|
text TEXT,
|
||||||
|
type TEXT,
|
||||||
|
appBundleID TEXT NULL,
|
||||||
|
url TEXT NULL
|
||||||
|
);
|
||||||
|
INSERT INTO segments_new (id, startedAt, endedAt, title, appName, appPath, text, type, appBundleID, url)
|
||||||
|
SELECT id, startedAt, endedAt, title, appName, appPath, text, type, appBundleID, url FROM segments;
|
||||||
|
DROP TABLE segments;
|
||||||
|
ALTER TABLE segments_new RENAME TO segments;
|
||||||
|
ALTER TABLE segments ADD COLUMN startedAt_new REAL;
|
||||||
|
ALTER TABLE segments ADD COLUMN endedAt_new REAL;
|
||||||
|
`);
|
||||||
|
const rows = db.prepare(`SELECT id, startedAt, endedAt FROM segments`).all() as { [x: string]: unknown; id: unknown; }[];
|
||||||
|
const updateStart = db.prepare(`UPDATE segments SET startedAt_new = ? WHERE id = ?`);
|
||||||
|
const updateEnd = db.prepare(`UPDATE segments SET endedAt_new = ? WHERE id = ?`);
|
||||||
|
rows.forEach((row) => {
|
||||||
|
updateStart.run(convertTimestampToUnix(row.startedAt as string), row.id);
|
||||||
|
updateEnd.run(convertTimestampToUnix(row.endedAt as string), row.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
db.exec(`
|
||||||
|
ALTER TABLE segments DROP COLUMN startedAt;
|
||||||
|
ALTER TABLE segments DROP COLUMN endedAt;
|
||||||
|
ALTER TABLE segments RENAME COLUMN startedAt_new TO startedAt;
|
||||||
|
ALTER TABLE segments RENAME COLUMN endedAt_new TO endedAt;
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renameColumn(tableName: string, oldColumnName: string, newColumnName: string, db: Database) {
|
||||||
|
if (db.prepare(`SELECT 1 FROM pragma_table_info(?) WHERE name=?`).get([tableName, oldColumnName])) {
|
||||||
|
db.prepare(`ALTER TABLE ? RENAME COLUMN ? TO ?`).run([tableName, oldColumnName, newColumnName]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function migrateToV3(db: Database) {
|
||||||
|
db.prepare(`ALTER TABLE segements RENAME TO segments`).run();
|
||||||
|
db.exec(`
|
||||||
|
PRAGMA foreign_keys = OFF;
|
||||||
|
CREATE TABLE frame_new(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
createAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
imgFilename TEXT,
|
||||||
|
segmentID INTEGER NULL,
|
||||||
|
videoPath TEXT NULL,
|
||||||
|
videoFrameIndex INTEGER NULL,
|
||||||
|
collectionID INTEGER NULL,
|
||||||
|
encodeStatus INT DEFAULT 0,
|
||||||
|
FOREIGN KEY (segmentID) REFERENCES segments (id)
|
||||||
|
);
|
||||||
|
INSERT INTO frame_new (id, createAt, imgFilename, segmentID, videoPath, videoFrameIndex, collectionID, encodeStatus)
|
||||||
|
SELECT id, createAt, imgFilename, segmentID, videoPath, videoFrameIndex, collectionID, encodeStatus FROM frame;
|
||||||
|
DROP TABLE frame;
|
||||||
|
ALTER TABLE frame_new RENAME TO frame;
|
||||||
|
|
||||||
|
CREATE TABLE encoding_task_data_new (
|
||||||
|
encodingTaskID INTEGER,
|
||||||
|
frame ID INTEGER PRIMARY KEY,
|
||||||
|
FOREIGN KEY (encodingTaskID) REFERENCES encoding_task(id),
|
||||||
|
FOREIGN KEY (frame) REFERENCES frame(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO encoding_task_data SELECT * FROM encoding_task_data_new;
|
||||||
|
DROP TRIGGER delete_encoding_task;
|
||||||
|
DROP TABLE encoding_task_data;
|
||||||
|
|
||||||
|
ALTER TABLE encoding_task_data_new RENAME TO encoding_task_data;
|
||||||
|
|
||||||
|
CREATE TRIGGER IF NOT EXISTS delete_encoding_task
|
||||||
|
AFTER UPDATE OF status
|
||||||
|
ON encoding_task
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM encoding_task_data
|
||||||
|
WHERE encodingTaskID = OLD.id AND NEW.status = 2;
|
||||||
|
|
||||||
|
DELETE FROM encoding_task
|
||||||
|
WHERE id = OLD.id AND NEW.status = 2;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TABLE recognition_data_new (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
frameID INTEGER,
|
||||||
|
data TEXT,
|
||||||
|
text TEXT,
|
||||||
|
FOREIGN KEY (frameID) REFERENCES frame (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO recognition_data SELECT * FROM recognition_data_new;
|
||||||
|
DROP TABLE recognition_data;
|
||||||
|
ALTER TABLE recognition_data_new RENAME TO recognition_data;
|
||||||
|
|
||||||
|
PRAGMA foreign_keys = ON;
|
||||||
|
`);
|
||||||
|
|
||||||
|
renameColumn('encoding_task', 'createAt', 'createdAt', db);
|
||||||
|
renameColumn('frame', 'createAt', 'createdAt', db);
|
||||||
|
renameColumn('segments', 'startAt', 'startedAt', db);
|
||||||
|
renameColumn('segments', 'endAt', 'endedAt', db);
|
||||||
|
if (db.prepare(`SELECT 1 FROM pragma_table_info('frame') WHERE name='encoded'`).get()) {
|
||||||
|
db.prepare(`ALTER TABLE frame DROP COLUMN encoded`).run();
|
||||||
|
}
|
||||||
|
|
||||||
|
transformSegments(db);
|
||||||
|
transformFrame(db);
|
||||||
|
transformEncodingTask(db);
|
||||||
|
|
||||||
|
db.exec(`
|
||||||
|
UPDATE config SET value = '3' WHERE key = 'version';
|
||||||
|
`);
|
||||||
|
}
|
22
src/electron/backend/schema.d.ts
vendored
Normal file
22
src/electron/backend/schema.d.ts
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
export interface Frame {
|
||||||
|
id: number;
|
||||||
|
createdAt: number;
|
||||||
|
imgFilename: string;
|
||||||
|
segmentID: number | null;
|
||||||
|
videoPath: string | null;
|
||||||
|
videoFrameIndex: number | null;
|
||||||
|
collectionID: number | null;
|
||||||
|
encodeStatus: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface EncodingTask {
|
||||||
|
id: number;
|
||||||
|
createdAt: number;
|
||||||
|
status: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EncodingTaskData {
|
||||||
|
encodingTaskID: number;
|
||||||
|
frame: number;
|
||||||
|
}
|
@ -12,8 +12,8 @@ export function startScreenshotLoop(db: Database) {
|
|||||||
const screenshotPath = join(screenshotDir, filename);
|
const screenshotPath = join(screenshotDir, filename);
|
||||||
screenshot({filename: screenshotPath, format: "png"}).then((absolutePath) => {
|
screenshot({filename: screenshotPath, format: "png"}).then((absolutePath) => {
|
||||||
const SQL = SqlString.format(
|
const SQL = SqlString.format(
|
||||||
"INSERT INTO frame (imgFilename) VALUES (?)",
|
"INSERT INTO frame (imgFilename, createdAt) VALUES (?, ?)",
|
||||||
[filename]
|
[filename, new Date().getTime() / 1000]
|
||||||
);
|
);
|
||||||
db.exec(SQL);
|
db.exec(SQL);
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
|
@ -8,6 +8,7 @@ import { Database } from "better-sqlite3";
|
|||||||
import { startScreenshotLoop } from "./backend/screenshot.js";
|
import { startScreenshotLoop } from "./backend/screenshot.js";
|
||||||
import { __dirname } from "./dirname.js";
|
import { __dirname } from "./dirname.js";
|
||||||
import { hideDock } from "./utils/electron.js";
|
import { hideDock } from "./utils/electron.js";
|
||||||
|
import { checkFramesForEncoding } from "./backend/encoding.js";
|
||||||
|
|
||||||
const i18n = initI18n();
|
const i18n = initI18n();
|
||||||
|
|
||||||
@ -73,8 +74,11 @@ app.on("activate", () => {});
|
|||||||
|
|
||||||
app.on("ready", () => {
|
app.on("ready", () => {
|
||||||
createTray();
|
createTray();
|
||||||
dbConnection = initDatabase();
|
initDatabase().then((db) => {
|
||||||
screenshotInterval = startScreenshotLoop(dbConnection);
|
screenshotInterval = startScreenshotLoop(db);
|
||||||
|
setInterval(checkFramesForEncoding, 10000, db);
|
||||||
|
dbConnection = db;
|
||||||
|
});
|
||||||
mainWindow = createMainWindow(port, () => (mainWindow = null));
|
mainWindow = createMainWindow(port, () => (mainWindow = null));
|
||||||
settingsWindow = createSettingsWindow(port, () => (settingsWindow = null));
|
settingsWindow = createSettingsWindow(port, () => (settingsWindow = null));
|
||||||
globalShortcut.register("Escape", () => {
|
globalShortcut.register("Escape", () => {
|
||||||
|
@ -49,3 +49,12 @@ export function getRecordingsDir() {
|
|||||||
const dataDir = createDataDir();
|
const dataDir = createDataDir();
|
||||||
return path.join(dataDir, "recordings");
|
return path.join(dataDir, "recordings");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getEncodingTempDir() {
|
||||||
|
const tempDir = createTempDir();
|
||||||
|
const encodingTempDir = path.join(tempDir, "encoding");
|
||||||
|
if (!fs.existsSync(encodingTempDir)) {
|
||||||
|
fs.mkdirSync(encodingTempDir, { recursive: true });
|
||||||
|
}
|
||||||
|
return encodingTempDir;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user