Compare commits

...

952 Commits

Author SHA1 Message Date
Jonas Letzbor 4ddcf2c143
Add remote transcoding support 2024-03-01 23:27:03 +01:00
Nextcloud bot 3944499365
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-02-27 02:19:05 +00:00
Nextcloud bot 55ba434019
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-02-25 02:20:32 +00:00
Nextcloud bot c7751b87e1
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-02-21 02:17:16 +00:00
Nextcloud bot c475ac7196
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-02-17 02:26:52 +00:00
Nextcloud bot 8899fdcb34
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-02-16 02:19:07 +00:00
Nextcloud bot f402aac015
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-02-14 02:18:53 +00:00
Nextcloud bot 9769afae38
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-02-11 02:19:42 +00:00
Nextcloud bot 55094b7865
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-02-04 02:21:21 +00:00
Nextcloud bot 1266b7e559
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-02-03 02:18:34 +00:00
Nextcloud bot a5a072e836
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-02-01 02:19:50 +00:00
Nextcloud bot 6d785e30fc
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-01-25 02:17:26 +00:00
Nextcloud bot b044cc2cba
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-01-21 02:36:50 +00:00
Varun Patil 70b5b83968 Merge branch 'master' of https://github.com/pulsejet/memories 2024-01-20 10:44:05 -08:00
Varun Patil d909eb198f places: fix fileId type (fix #1008)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-20 10:44:04 -08:00
Nextcloud bot 28469f19c3
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-01-20 02:22:37 +00:00
Varun Patil ecc05f5d2b timeline: improve RAW stacking (#1006)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-19 09:39:38 -08:00
Varun Patil 4bb1f94f35 timeline: handle stacking Pixel 8 Pro RAW stack (fix #1006)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-19 09:33:22 -08:00
Varun Patil 198eb620a0 Merge branch 'master' of https://github.com/pulsejet/memories 2024-01-19 09:23:10 -08:00
Varun Patil e6760c7452 lp: fix support for Ultra HDR motion photos
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-19 09:23:08 -08:00
Nextcloud bot a98b5ceb5d
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-01-15 02:14:56 +00:00
Nextcloud bot 1e43553eed
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-01-14 02:18:15 +00:00
Varun Patil 6c9fd552e4 dialog: prevent closing underlying modal
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-10 17:09:53 -08:00
Varun Patil 213a3d3778 edit-meta: refactor datecheck
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-10 16:32:02 -08:00
Varun Patil 37881b36b4 face-edit: fix back button (fix #994)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-10 15:53:07 -08:00
Varun Patil 032397384b v6.2.2 2024-01-10 15:43:01 -08:00
Varun Patil 3addbaeb72 edit-meta: add null check
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-10 15:42:38 -08:00
Varun Patil ea540e1434 edit-meta: remove undef orientation
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-10 15:41:38 -08:00
Varun Patil 3ab5c21970 v6.2.1 2024-01-10 15:24:48 -08:00
Varun Patil 9150e13fa9 dav: fix bug in pipeline
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-10 15:23:35 -08:00
Varun Patil 921345523e edit-meta: skip undefined EXIF
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-10 14:59:20 -08:00
Varun Patil b94275030f v6.2.0 2024-01-09 20:05:06 -08:00
Varun Patil 1c68967454 Update changelog
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-09 20:04:38 -08:00
Varun Patil 0604ee1d14 days: use basename as tie-breaker (#985)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-09 19:55:12 -08:00
Nextcloud bot a071cdbc13
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-01-08 02:19:54 +00:00
Nextcloud bot 321f387d3f
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-01-07 02:21:57 +00:00
Varun Patil ca90d0c8d7 docs: add another collation solution (#951)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-05 09:10:06 -08:00
Varun Patil a8a3efd21c config: copy missing from default (fix #971)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-05 09:02:29 -08:00
Varun Patil a8aa090be1 takeout: bump migrator version
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-05 08:19:30 -08:00
Varun Patil a1ee15d288 takeout: include tz (fix #977)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-05 08:18:35 -08:00
Varun Patil 4aaf6c32a2 places-setup: make transaction size configurable (fix #943)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-05 07:59:22 -08:00
Varun Patil 0e42e55333 chore: bump max to 28 (fix #961)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2024-01-05 07:50:02 -08:00
Varun Patil 021b297f0c
Merge pull request #979 from fz72/master
Create metadata for F-Droid repository
2024-01-05 07:44:31 -08:00
Nextcloud bot 79ab5cabc2
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-01-05 02:22:21 +00:00
Nextcloud bot 4d8174d5e5
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-01-04 02:20:00 +00:00
Nextcloud bot 301ad38a2a
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-01-02 02:15:37 +00:00
Nextcloud bot 23ac929048
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-01-01 02:17:55 +00:00
Nextcloud bot 23e1696383
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-31 02:18:35 +00:00
fz72 e6b3b68b99
Rename metadata/en-US/images/screenshot.jpg to metadata/en-US/images/phoneScreenshots/screenshot.jpg 2023-12-30 15:41:51 +00:00
fz72 5d213bdc3b
Add files via upload 2023-12-30 15:41:12 +00:00
fz72 69adef214e
Rename metadata/en-US/icon.png to metadata/en-US/images/icon.png 2023-12-30 15:38:57 +00:00
fz72 c4d727070e
Add files via upload 2023-12-30 15:38:10 +00:00
fz72 f1405b5011
Create full_description.txt 2023-12-30 15:36:08 +00:00
fz72 301e34e0f0
Create short_description.txt 2023-12-30 15:34:25 +00:00
fz72 80565b737a
Create title.txt 2023-12-30 15:33:40 +00:00
fz72 b48ec4337b
add Metadata for F-Droid 2023-12-30 15:32:09 +00:00
Nextcloud bot 44d934d980
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-30 02:25:26 +00:00
Nextcloud bot cd289cf054
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-29 02:16:14 +00:00
Nextcloud bot a856a9d03f
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-28 02:17:54 +00:00
Nextcloud bot a63cedf228
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-27 02:17:04 +00:00
Nextcloud bot 10e481f393
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-26 02:18:25 +00:00
Nextcloud bot c8689351e7
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-25 02:18:51 +00:00
Nextcloud bot a56d3ec1bf
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-24 02:25:00 +00:00
Nextcloud bot c84697d6bb
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-23 02:20:29 +00:00
Nextcloud bot f5627da488
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-20 02:13:57 +00:00
Nextcloud bot 3d147ff29e
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-19 02:15:09 +00:00
Nextcloud bot 7e6ef7a5a9
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-16 02:14:50 +00:00
Nextcloud bot 261d89a501
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-15 02:14:23 +00:00
Nextcloud bot ebd57fe0e6
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-13 02:16:39 +00:00
Nextcloud bot 40fc8299d3
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-12 02:14:59 +00:00
Nextcloud bot 8617c5e32f
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-11 02:20:03 +00:00
Varun Patil ed8e1e4517 Merge branch 'master' of https://github.com/pulsejet/memories 2023-12-09 22:58:10 -08:00
Varun Patil 62a62b453b ios: fix inset padding (fix #957)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-12-09 22:58:06 -08:00
Varun Patil 3165beaacb viewer: fix download of lp video
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-12-09 21:30:07 -08:00
Nextcloud bot 903c96749b
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-08 02:14:57 +00:00
Varun Patil 7b603cd095 ci: always run both static analysis steps 2023-12-02 21:58:28 -08:00
Varun Patil c1a556f235 face: fix back button on merge (fix #949)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-12-02 21:12:24 -08:00
Varun Patil ee0a52d305 Merge branch 'master' of https://github.com/pulsejet/memories 2023-12-02 21:08:59 -08:00
Varun Patil 6b9d5a4566 cluster: fix cursor
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-12-02 21:08:56 -08:00
Nextcloud bot 5bf02246d2
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-03 02:19:21 +00:00
Varun Patil c2958f8127 Merge branch 'master' of https://github.com/pulsejet/memories 2023-12-02 11:27:11 -08:00
Varun Patil ac9ce852bb places: add explicit convert to utf-8 2023-12-02 11:27:08 -08:00
Nextcloud bot db45091379
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-12-01 02:15:04 +00:00
Varun Patil b30786ca0c chore: deps
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-29 12:14:30 -08:00
Varun Patil ec95c4720e face-top: make rename util
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-28 20:42:47 -08:00
Varun Patil 5f138698e0 album: fix route after name edit
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-28 20:25:50 -08:00
Varun Patil 75d82bf2d2 Bump node version
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-27 16:10:07 -08:00
Varun Patil 8c0f3dc8a2 sel: allow both directions for multi-select (fix #893)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-26 20:24:59 -08:00
Varun Patil e69cee9dd4 frame: prevent infinite lp spinner
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-26 19:14:58 -08:00
Varun Patil 2e70655c31 sel: always select clicked photo
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-26 19:10:37 -08:00
Varun Patil 366c6dc5e2 sel: refactor backtracking
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-26 18:51:59 -08:00
Varun Patil 0250b27bdf docs: imporve docstring
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-26 18:18:38 -08:00
Varun Patil 312c98bd70 Merge branch 'master' of https://github.com/pulsejet/memories 2023-11-26 18:12:36 -08:00
Varun Patil 1ea70750bf face: adjust top matter rename size
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-26 18:12:31 -08:00
Nextcloud bot 1c8fed779d
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-26 02:21:09 +00:00
Varun Patil 40bcc0e09a v6.1.5 2023-11-25 13:20:11 -08:00
Varun Patil 764505b039 sw: restore origin check
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-25 13:19:29 -08:00
Varun Patil 81c8fc3049 v6.1.4
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-25 12:42:02 -08:00
Varun Patil 7c94a4efcc sw: fix static path
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-25 12:41:22 -08:00
Varun Patil a4ae2c800f v6.1.3 2023-11-25 12:11:43 -08:00
Varun Patil 37b932196f sw: exclude maps
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-25 12:10:59 -08:00
Varun Patil 012d6981de v6.1.2
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-25 12:03:48 -08:00
Varun Patil bcca24c5c6 Merge branch 'master' of https://github.com/pulsejet/memories 2023-11-25 11:54:42 -08:00
Varun Patil ab24efbeda other: fix error message
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-25 11:54:31 -08:00
Varun Patil 7b4ad788aa sw: improve strategy
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-25 11:53:34 -08:00
Varun Patil 1971c5e3ce app: re-enable sw on localhost
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-25 11:13:25 -08:00
Varun Patil 14702f7669 sw: await update call
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-25 11:02:50 -08:00
Varun Patil eaba80a73b other: do not block sw
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-25 10:57:03 -08:00
Nextcloud bot 7d093893a3
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-25 02:29:13 +00:00
Varun Patil 5c4a1342e4 docs: add play link at bottom
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-24 17:10:06 -08:00
Varun Patil 13721398da docs: add discourse link
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-24 17:07:59 -08:00
Varun Patil 657dae8bac docs: link back to github
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-24 17:02:05 -08:00
Varun Patil 07965536c2 docs: add edit link
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-24 16:59:48 -08:00
Varun Patil c832862610 docs: add site url
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-24 16:56:50 -08:00
Varun Patil 60573a4026 docs: update GH release link for android
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-24 16:55:00 -08:00
Varun Patil 72aea77927 v6.1.1
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-24 16:32:06 -08:00
Varun Patil 04ac501477 deps: prevent weird transitive dep usage
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-24 16:22:54 -08:00
Varun Patil ff912a6bee tw: do not attempt to index zero-byte files (close #933)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-24 15:06:16 -08:00
Varun Patil eb784ef8ab occ: improve index output
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-24 14:50:15 -08:00
Varun Patil e5e35ce357 refactor: non-null filters
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-24 14:16:50 -08:00
Varun Patil 07a20fb454 refactor: truthy filter
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-24 14:06:38 -08:00
Varun Patil f2f6899d53 dav: improve de-duplication for extend
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-24 14:01:17 -08:00
Varun Patil 9bc77aeb89 dav: use pipeline for extendWithStack
Related #903

Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-24 13:56:00 -08:00
Varun Patil 294feef80b exif: write in-place
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-24 13:18:47 -08:00
Varun Patil 75f7c969de sw: exclude licenses from precache
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-24 09:32:18 -08:00
Varun Patil 98740af645 Merge branch 'master' of https://github.com/pulsejet/memories 2023-11-24 08:58:25 -08:00
Varun Patil 427d8ce920 deps: bump vue
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-24 08:57:23 -08:00
Nextcloud bot ea7689aefa
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-24 02:49:43 +00:00
Nextcloud bot 12054519d1
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-23 02:23:51 +00:00
Varun Patil f148b45fc6 timeline: stack RAW with additional file extension (fix #927)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-22 12:39:36 -08:00
Varun Patil e55f0d6343 timeline: refactor RAW stacking logic
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-22 12:39:08 -08:00
Varun Patil fec834855e frame: reorder raw icon
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-22 12:37:49 -08:00
Varun Patil e3223f3a3f timeline: prevent swipe on scroller (fix #937)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-22 12:02:47 -08:00
Varun Patil 915ee8487d Merge branch 'master' of https://github.com/pulsejet/memories 2023-11-22 11:51:03 -08:00
Varun Patil deb0e5ce16 lp: switch to new tag for 12.70
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-22 11:51:01 -08:00
Nextcloud bot 5f0bc4d363
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-22 02:23:23 +00:00
Varun Patil 9653f01636 cluster: fix outline offset
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-21 13:08:20 -08:00
Varun Patil c96a0e3ed9 bin-ext: bump exiftool
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-21 12:46:00 -08:00
Varun Patil 2bc4837d6f video: improve fallback logic
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-21 11:34:04 -08:00
Varun Patil b9a4be7d20 scroller: give focus back to recycler after interaction
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-21 10:20:25 -08:00
Varun Patil 3fe9fdc363 cluster: allow tab navigation
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-21 10:16:46 -08:00
Varun Patil 7af24512d9 Merge branch 'master' of https://github.com/pulsejet/memories 2023-11-21 10:10:55 -08:00
Varun Patil 9cf852b780 timeline: focus on init (fix #932)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-21 10:10:53 -08:00
Nextcloud bot 2d088fc8aa
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-21 02:24:50 +00:00
Varun Patil 35d9df6f9c go-vod/0.2.4
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-20 11:36:29 -08:00
Varun Patil c334c4645d go-vod: update Dockerfile to use jellyfin
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-20 11:35:45 -08:00
Varun Patil 9eed70f848
Merge pull request #929 from szaimen/master
improve aio docs - put the community container first
2023-11-20 11:32:29 -08:00
Simon L 4fa0e236fb put the community container first
Signed-off-by: Simon L <szaimen@e.mail.de>
2023-11-20 14:12:24 +01:00
Nextcloud bot 7bfb3d64b6
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-20 02:24:05 +00:00
Nextcloud bot d885e172cd
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-19 02:27:51 +00:00
Varun Patil 05101ed704 video: change default NVENC scaler to CUDA (#582)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-18 11:28:39 -08:00
Varun Patil a1e6e725a0 Merge branch 'master' of https://github.com/pulsejet/memories 2023-11-18 08:59:00 -08:00
Varun Patil 2a3507d5fd share: copy even if can't share (fix #925)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-18 08:56:07 -08:00
Varun Patil 4005a21b2d docs: add cuda scaler to hw
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-17 23:57:30 -08:00
Nextcloud bot 855db3d8c9
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-18 02:32:27 +00:00
Varun Patil 417fdfb862 Merge branch 'master' of https://github.com/pulsejet/memories 2023-11-17 10:20:52 -08:00
Varun Patil f38f5e15da index: add verbose logging
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-17 10:20:49 -08:00
Nextcloud bot f547d3edf4
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-17 02:26:20 +00:00
Varun Patil 208939464b docs: fix typo
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-16 15:59:57 -08:00
Varun Patil 2cc31aa567 docs: document AIO community container
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-16 15:57:02 -08:00
Varun Patil 5bcec8a9f6 docs: remove v6 warning
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-16 15:45:47 -08:00
Varun Patil 47ac14ed6d Merge branch 'master' of https://github.com/pulsejet/memories 2023-11-16 08:29:36 -08:00
Varun Patil f8d0a8a0d3 metadata: hide hidden albums
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-16 08:29:34 -08:00
Nextcloud bot 697e29e2ef
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-16 02:52:34 +00:00
Varun Patil 60e080ee64 timeline: fix runaway loader values
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-15 14:11:30 -08:00
Varun Patil eb2263d3ea v6.1.0 2023-11-15 12:31:36 -08:00
Varun Patil 23296931fa Merge branch 'master' of https://github.com/pulsejet/memories 2023-11-15 12:30:43 -08:00
Varun Patil 15aa9fdfd8 readme: add link to releases
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-15 12:30:40 -08:00
Varun Patil 389f98bd60 android/1.6 2023-11-15 12:15:00 -08:00
Varun Patil f2ededa6f4 android: bump min server 2023-11-15 12:14:33 -08:00
Varun Patil b4a5faeb92 ci: skip docs on module change
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-15 12:12:00 -08:00
Varun Patil 0b0301e21e android/1.5 2023-11-15 12:07:41 -08:00
Varun Patil 26417f6d9e bin-ext: bump go-vod
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-15 10:28:12 -08:00
Varun Patil 65a46ab679 Merge branch 'master' of https://github.com/pulsejet/memories 2023-11-15 10:26:33 -08:00
Varun Patil d38e2376a5 go-vod/0.2.3
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-15 10:25:59 -08:00
Varun Patil 4a0f9ba183 go-vod: check for root (fix #916)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-15 10:25:23 -08:00
Nextcloud bot 6cd52690e8
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-15 02:29:02 +00:00
Varun Patil 29415b49cf edit-meta: fix GPS ref
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-14 09:23:13 -08:00
Varun Patil 509f797ffb edit-meta: missing key
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-14 09:00:25 -08:00
Varun Patil 379184247f image: fix preview race after edit
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-14 01:31:45 -08:00
Varun Patil 7eb232c10f other: disable service worker in debug mode
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-14 01:10:29 -08:00
Varun Patil 623cbe5d79 album: fix OG title
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-14 01:09:59 -08:00
Varun Patil c7ea8ec7bf share: disable link for locals
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-14 01:02:32 -08:00
Varun Patil 33571bf661 albums: fix link-only titles
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-14 01:01:01 -08:00
Varun Patil 27f8608d69 albums: hide hidden from list
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-14 00:52:07 -08:00
Varun Patil 016991d40e docs: update changelog
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-14 00:41:12 -08:00
Varun Patil 0273ae8537 feat: allow multi-share with sel manager (close #472)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-14 00:40:04 -08:00
Varun Patil f0e1b00096 refactor: image info filling
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-13 23:14:52 -08:00
Varun Patil e396359011 node-share: awits
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-13 23:08:15 -08:00
Varun Patil 14a890796e nx: implement multi-share (fix #901)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-13 22:39:12 -08:00
Varun Patil fe74b9f089 Merge branch 'master' of https://github.com/pulsejet/memories 2023-11-13 22:37:22 -08:00
Varun Patil 680322d916 nx: support multi-share API 2023-11-13 22:37:19 -08:00
Varun Patil 29458546b0 node-share: await clipboard writes
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-13 14:15:50 -08:00
Varun Patil fa644b1b70 Merge branch 'master' of https://github.com/pulsejet/memories 2023-11-13 11:16:37 -08:00
Varun Patil 89ffdc56a8 node-share: copy on native
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-13 11:16:28 -08:00
Nextcloud bot 98429bfdbb
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-11 02:20:43 +00:00
Varun Patil 18c567bc0e refactor: deprecation fixes
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-09 23:56:00 -08:00
Varun Patil d58c492fac folder: redact hash on route change
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-09 23:51:58 -08:00
Varun Patil 857bcb8773 folder: redact hash on route change
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-09 23:47:09 -08:00
Varun Patil 803628c7a2 Merge branch 'master' of https://github.com/pulsejet/memories 2023-11-09 23:43:41 -08:00
Varun Patil c496e0e05a edit-meta: use AllDates for set
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-09 23:43:39 -08:00
Varun Patil 6c42d0b8a4 takeout: fix video dates (fix #910)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-09 23:43:16 -08:00
Nextcloud bot 0e06de2a11
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-10 02:17:26 +00:00
Nextcloud bot 1309c1e217
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-07 02:31:10 +00:00
Nextcloud bot 43ef0510e4
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-06 02:26:22 +00:00
Nextcloud bot e9fd3a528d
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-04 02:25:11 +00:00
Nextcloud bot 6287cdd816
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-03 02:21:50 +00:00
Varun Patil 183de24e62 nx: fix visibility of cursor on video
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-02 13:00:47 -07:00
Varun Patil 7b3119c133 Merge branch 'master' of https://github.com/pulsejet/memories 2023-11-02 13:00:17 -07:00
Varun Patil 2c9cdacdfa android: hide status bars on landscape 2023-11-02 13:00:10 -07:00
Varun Patil 90003614b7 timeline: revert loading icon move
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-02 12:12:30 -07:00
Varun Patil a7e7f80745 edit-orientation: add some warnings
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 22:12:39 -07:00
Varun Patil e64d1e8536 Merge branch 'master' of https://github.com/pulsejet/memories 2023-11-01 19:29:44 -07:00
Varun Patil dc4e2ed9f8 refactor(viewer): actions to array
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 19:29:16 -07:00
Nextcloud bot 501ba618e4
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-02 02:23:39 +00:00
Varun Patil 60d390517d edit-meta: minor CSS fix
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 19:22:36 -07:00
Varun Patil 8eee97c619 viewer: fix edit meta call
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 18:50:13 -07:00
Varun Patil dc43ecfea7 refactor: remove log statement
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 18:50:00 -07:00
Varun Patil 8c16eecc11 edit-meta: add rotate
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 18:45:24 -07:00
Varun Patil 75237ba505 fix(swipe): z-index on mobile
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 15:13:45 -07:00
Varun Patil 9e7b3a32f6 fix(swipe): animation delay
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 15:03:18 -07:00
Varun Patil 133d167f1a fix(nx): detection on server
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 14:44:38 -07:00
Varun Patil 59ec7119ea timeline: move loading to swipe
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 14:25:50 -07:00
Varun Patil 910cb4ada0 feat(timeline): swipe to refresh (close #547)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 13:19:48 -07:00
Varun Patil b1edd24dd9 docs: update changelog
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 10:36:44 -07:00
Varun Patil e1dcdb5cab docs: add go-vod badge
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 10:33:44 -07:00
Varun Patil f4d16215f1 ci: exclude android changes
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 10:32:50 -07:00
Varun Patil 3908c6b471 Add 'android/' from commit 'c3e1cb338b8124ed3af6c3ae51ae3927a0086f22'
git-subtree-dir: android
git-subtree-mainline: e95a7e022c
git-subtree-split: c3e1cb338b
2023-11-01 10:29:25 -07:00
Varun Patil e95a7e022c docs: update readme with tag info
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 10:24:20 -07:00
Varun Patil db34e65cb8 docs: update readme
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 10:21:40 -07:00
Varun Patil 6d2ef1cf97 chore: update paths
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 10:14:24 -07:00
Varun Patil 12137fe2a7 go-vod/0.2.2
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 10:08:28 -07:00
Varun Patil 7c905e378f fix(go-vod): output binary name in CI 2023-11-01 10:07:32 -07:00
Varun Patil 8fc4f1058e go-vod/0.2.1 2023-11-01 09:56:06 -07:00
Varun Patil 7acedae06c ci: update go-vod Docker workflow
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 09:52:48 -07:00
Varun Patil 44ad47f5a0 chore: bump go-vod version
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-11-01 09:50:55 -07:00
Varun Patil 6ea28fa775 ci: update workflows 2023-11-01 09:43:27 -07:00
Varun Patil 4df1ce40f3 Add 'go-vod/' from commit 'a37c11daf8c4aa207186c4ef030d8a35f251d433'
git-subtree-dir: go-vod
git-subtree-mainline: a41998f0f0
git-subtree-split: a37c11daf8
2023-11-01 09:32:27 -07:00
Varun Patil a37c11daf8 refactor: rename package to transcoder 2023-11-01 01:03:28 -07:00
Varun Patil 2f8019cb5a Rename workflows (again) 2023-11-01 00:45:33 -07:00
Varun Patil ddc265b019 Rename workflows 2023-11-01 00:43:06 -07:00
Varun Patil 11c519c654 Fix typo in pipeline 2023-11-01 00:41:15 -07:00
Varun Patil bb3c44acbc ci: combine workflows 2023-11-01 00:36:52 -07:00
Varun Patil a40b1576bb Cross compile for ARM 2023-11-01 00:15:28 -07:00
Varun Patil c3e1cb338b android: prevent reload on rotate 2023-10-31 23:09:25 -07:00
Varun Patil a41998f0f0 sel: fix scrolling up on nx
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 23:03:18 -07:00
Varun Patil 90ccddd47e nx: fix listener
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 22:49:17 -07:00
Varun Patil 7946abbae4 docs: update changelog
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 22:28:51 -07:00
Varun Patil 973cd86c1d video: allow switch to direct on Safari (fix #650)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 22:22:21 -07:00
Varun Patil 44c3ed1b86 ximg: minor refactor
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 21:46:21 -07:00
Varun Patil e2d4a53c66 Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-31 21:32:12 -07:00
Varun Patil 7f58cf51c0 image: refactor params
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 21:29:43 -07:00
Nextcloud bot 364d0639b1
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-11-01 02:28:08 +00:00
Varun Patil e3186c1759 sel: add move frame to resetTouchParams
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 19:12:38 -07:00
Varun Patil c5c72dabd8 sel: perf optimizations
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 19:10:28 -07:00
Varun Patil 5a4fc07eca photo: revert touch action
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 18:23:16 -07:00
Varun Patil e706d0fbdd app: disable swipe nav
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 17:31:36 -07:00
Varun Patil 3dbaaaf543 sidebar: refactor client init
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 16:59:36 -07:00
Varun Patil 55dea017f7 sidebar: fix client injection
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 13:29:38 -07:00
Varun Patil d181772f01 docs: add general FOSS sponsors
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 13:15:02 -07:00
Varun Patil 3374508920 video: fix lp playback on Safari
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 13:04:02 -07:00
Varun Patil 7020d0ddac fragment: fix initial navigation
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 10:37:42 -07:00
Varun Patil 0e1c4cfa44 Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-31 10:19:32 -07:00
Varun Patil 101b2bbe0d edit-date: construction and validation (fix #671)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 10:19:30 -07:00
Varun Patil e5e9a08ba8 edit-date: add type input
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 10:07:04 -07:00
Varun Patil 2d75709ab7 css: hide number input arrows
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-31 10:06:51 -07:00
Nextcloud bot 59c7e05283
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-31 02:26:53 +00:00
Varun Patil 8514120fff Merge branch 'Shawn8901-patch-1' 2023-10-30 18:18:30 -07:00
Varun Patil 2241ad4b4d docs: rearrange troubleshooting
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 18:18:15 -07:00
Varun Patil 040c02889d Merge branch 'patch-1' of https://github.com/Shawn8901/memories into Shawn8901-patch-1 2023-10-30 18:14:00 -07:00
Varun Patil 9f474e3d43 worker: switch to library
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 18:00:50 -07:00
Varun Patil e1c89f9cb0 worker: fix async typing
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 16:50:49 -07:00
Varun Patil 8df9c3034d worker: improve typing
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 16:40:51 -07:00
Varun Patil d2116fd213 refactor: move worker to services
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 15:50:58 -07:00
Varun Patil 93c0d2860b ximg: reduce gc frequency
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 15:36:03 -07:00
Varun Patil 50bae02241 refactor: move dom load events to utils
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 15:31:05 -07:00
Varun Patil 505ccae762 refactor(sidebar): shorten syntax
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 15:21:09 -07:00
Shawn8901 b3fa58937c docs: Add nixos section to get automatic indexer running
When installing nextcloud (and possibly memories also) via nixos modules system, there is some nixos specific extra setup needed, otherwise the automatic indexer is not working. This is kind of a downstream issue, as for FHS distros its common to having perl available at `/usr/bin/perl` (and thus at PATH) but for nixos there is extra work needed.
2023-10-30 23:05:01 +01:00
Varun Patil 1744374329 docs: update changelog for RAW stacking
close #537
close #152
close #419

Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 12:52:16 -07:00
Varun Patil 3be478b8ce edit-meta: fail fast for forbidden mimes
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 12:50:11 -07:00
Varun Patil 32e910561d modal: handle premature close calls
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 12:49:52 -07:00
Varun Patil bf6127493e edit-meta: warn user for stack edit
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 12:39:51 -07:00
Varun Patil 5e4b963379 archive: add lock to folder creation
Close #122
Close #681

Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 12:30:04 -07:00
Varun Patil 782b2c9243 dav: extend archive with stack
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 11:43:50 -07:00
Varun Patil ef44965dee dav: refactor archive to use photo list
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 11:39:15 -07:00
Varun Patil 2c81503484 dav: extend with stack with lp
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 11:32:30 -07:00
Varun Patil f49b93c561 viewer: add stackraw download
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 11:24:23 -07:00
Varun Patil 4b4e4f2c09 dav: add requested with header
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 10:58:48 -07:00
Varun Patil 79c7b02204 docs: fix missing tag in changelog
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 02:38:53 -07:00
Varun Patil 73583da7cb photo: debounce live photo only once
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 02:36:19 -07:00
Varun Patil 5ccba14519 viewer: animate lp icon
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 02:33:46 -07:00
Varun Patil c6f5ed5b05 frame: animate live photo icon (close #898)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 02:12:56 -07:00
Varun Patil 543646624a photo: add delay to live playback
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 01:26:06 -07:00
Varun Patil 1e5a5d3b4f video: catch play throws
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 01:21:06 -07:00
Varun Patil 37783d831d chore: remove dead dependency
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 01:08:43 -07:00
Varun Patil ba473e6314 build: prune admin bundle
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 01:01:27 -07:00
Varun Patil 664bbae0ca mnav: use exact-path
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-30 00:06:44 -07:00
Varun Patil 71d1bba1d5 face: replace router after merge
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 23:46:46 -07:00
Varun Patil 3e40a3e5d2 editor: add missing null checks
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 22:14:06 -07:00
Varun Patil f0c7cf7542 sidebar: do not invalidate for going to same file
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 22:13:44 -07:00
Varun Patil af00252ed4 viewer: prevent useless itemData calls after destroy
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 22:01:38 -07:00
Varun Patil a69be6dd16 deps: update webdav
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 22:00:25 -07:00
Varun Patil 955918dd0a Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-29 20:08:44 -07:00
Varun Patil 6d97ccc1c0 chore: bump deps
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 19:50:07 -07:00
Nextcloud bot 7ef2f46a67
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-30 02:23:24 +00:00
Varun Patil a2b9419988 refactor: config types
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 19:21:19 -07:00
Varun Patil 647f98f3d6 build: change some tsconfig
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 19:21:13 -07:00
Varun Patil 6ba986acfe build: turn on skipLibCheck
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 18:32:00 -07:00
Varun Patil e04fc9e091 timeline: allow disabling RAW stack
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 18:12:14 -07:00
Varun Patil 317874ea44 refactor: make DaysFilterType const
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 18:00:02 -07:00
Varun Patil dbfc23b1ab refactor: typings
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 17:59:53 -07:00
Varun Patil ff00424e3e refactor: turn on verbatimModuleSyntax
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 17:54:53 -07:00
Varun Patil d94841ad6b build: turn on alwaysStrict
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 17:38:54 -07:00
Varun Patil 4de74e0af1 refactor: change types import strategy
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 17:30:11 -07:00
Varun Patil c1ebdb9e34 docs: add transifex link to readme
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 14:14:55 -07:00
Varun Patil a9aef4eab6 refactor: add aliases for imports
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 14:10:56 -07:00
Varun Patil e2e9fa9d42 build: add context to webpack
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 13:15:29 -07:00
Varun Patil 9d75451f32 l10n: add type safety
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 13:14:28 -07:00
Varun Patil 79d8a8675c metadata: reset state when invalidated
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 12:18:13 -07:00
Varun Patil 42f32350d9 metadata: revert quick learning
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 12:17:00 -07:00
Varun Patil 54059b4216 viewer: invalidate metadata during fast changes
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 12:14:42 -07:00
Varun Patil 198fe97b4b viewer: reduce sidebar debounce time
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 11:58:43 -07:00
Varun Patil 9251bba6fc metadata: use loaded image info
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 11:56:06 -07:00
Varun Patil 9e001730c2 refactor(viewer): sidebar debouncing
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 11:51:20 -07:00
Varun Patil a8d940acd0 days: fix reverse on preloads (fix #895)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 11:19:12 -07:00
Varun Patil a305ddc4ad folder: preserve query during navigation
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-29 11:03:20 -07:00
Varun Patil b2e179ff43 fix(frame): invalid video tag
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-28 18:49:47 -07:00
Varun Patil 31ad4a9fa1 frame: mark raw and stack
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-28 18:48:56 -07:00
Varun Patil 757b02fc84 frame: refactor photo CSS
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-28 18:17:00 -07:00
Varun Patil ba12616c0e timeline: reverse priority on stack
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-28 18:00:40 -07:00
Varun Patil 4aed2946bf timeline: hide RAW
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-28 17:56:44 -07:00
Varun Patil 994fea1b9a refactor(viewer): better syntax
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-28 13:39:41 -07:00
Varun Patil 1b378334f5 refactor: remove return from small lambdas
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-28 13:32:44 -07:00
Varun Patil f7de4fe492 viewer: remove useless bang
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-28 13:16:28 -07:00
Varun Patil cc7586af62 timeline: set adjust flag first
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-28 13:07:24 -07:00
Varun Patil 20d53cf291 viewer: implement globalCount change (close #892)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-28 13:02:18 -07:00
Varun Patil 0774c857cf Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-28 03:44:40 -07:00
Varun Patil 35c30831e1 viewer: do not iterate rows
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-28 02:32:33 -07:00
Varun Patil 3637965618 viewer: directly use timeline state
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-28 02:00:58 -07:00
Varun Patil 10ebef22d3 timeline: use map for preloads
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-28 01:38:22 -07:00
Varun Patil a151d9cbd4 refactor: use Map for heads
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-28 01:31:04 -07:00
Varun Patil 18b8a5404f viewer: refactor preloading
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-28 01:09:28 -07:00
Varun Patil e13e9cb37b timeline: make fetchDay once explicitly
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-28 00:51:09 -07:00
Varun Patil be621309aa
Merge pull request #888 from SuperSandro2000/patch-1
Make error about tool version mismatch clearer
2023-10-27 21:49:14 -07:00
Nextcloud bot f25b9af795
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-28 02:25:10 +00:00
Varun Patil eec6e0a492 patch-external: fail CI build
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-27 03:33:10 -07:00
Varun Patil c2076e2535 v6.0.1
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-27 03:06:48 -07:00
Varun Patil 04dadb454c deps: bump go-vod
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-27 03:02:31 -07:00
Varun Patil 2ad35bfe13 videojs: fix startup exception
https://github.com/videojs/http-streaming/pull/1439
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-27 03:02:07 -07:00
Varun Patil e2e6dafee4 0.1.25 2023-10-27 03:00:51 -07:00
Varun Patil e4b8f21b1a patch(plyr): make sure wrapper is inserted
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-27 02:21:26 -07:00
Varun Patil 7283066721 plyr: stop wrapping
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-27 01:46:19 -07:00
Varun Patil ee8693ce0b Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-26 23:32:53 -07:00
Varun Patil 0fad53b3e0 video: keep time in src switches
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-26 23:32:50 -07:00
Varun Patil 61b217d08c stream: omit profile 2023-10-26 23:18:41 -07:00
Varun Patil 3513b543b3 Reduce ref bitrate 2023-10-26 21:56:31 -07:00
Varun Patil c743d14e5d Remove 360p 2023-10-26 21:56:22 -07:00
Nextcloud bot 061e029c69
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-27 02:24:21 +00:00
Sandro 91c83eda71
Make error about tool version mismatch clearer 2023-10-27 01:00:13 +02:00
Nextcloud bot 622dce1a74
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-26 02:25:18 +00:00
Varun Patil 10bc4362ba add dev dockerfile 2023-10-25 14:35:03 -07:00
Varun Patil 1f7602c8c6 fragment: prevent redundant navigation
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-25 14:32:23 -07:00
Varun Patil e4e13459aa v6.0.0
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-25 13:28:58 -07:00
Varun Patil d42a7cfd59 Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-25 10:27:20 -07:00
Varun Patil f5c95f2f60 photo: remove dead lp elements
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-25 10:24:28 -07:00
Varun Patil e9370b6a71 frame: disable touch actions
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-25 10:16:14 -07:00
Nextcloud bot 405fa0d7fe
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-25 02:41:46 +00:00
Varun Patil 134b7cc354 bin-ext: bump go-vod
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 19:35:55 -07:00
Varun Patil c6e9cca896 0.1.24 2023-10-24 19:35:26 -07:00
Varun Patil 0c22323818 video: retry quality change for init
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 19:34:21 -07:00
Varun Patil 35db581c26 video: reduce some useless timers
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 19:13:34 -07:00
Varun Patil 9f4c223dff psvideo: skip for nx
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 19:12:00 -07:00
Varun Patil 791937215d stream: escape printed command 2023-10-24 19:10:20 -07:00
Varun Patil 0223d5f6ef stream: add genpts fflags 2023-10-24 19:06:55 -07:00
Varun Patil a14afa6af0 bin-ext: bump go-vod
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 18:46:30 -07:00
Varun Patil 029d3bf1cb manager: improve bitrate scaling 2023-10-24 18:45:40 -07:00
Varun Patil 346e2e9bff video: bump go-vod
Also disable some videojs option

Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 18:08:08 -07:00
Varun Patil a8ad3e95c6 manager: prevent duplicate max stream 2023-10-24 18:02:15 -07:00
Varun Patil 826388d390 v6.0.0-rc.3 2023-10-24 17:20:35 -07:00
Varun Patil feaa6e55af vod: make QF configurable
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 17:19:43 -07:00
Varun Patil 2438a2946d stream: make QF configurable 2023-10-24 17:17:49 -07:00
Varun Patil 3106108f04 video: catch quality change errors
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 16:51:29 -07:00
Varun Patil 6d1fa55a0f video: turn on some videojs compensation
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 16:26:09 -07:00
Varun Patil 5353b54904 chore: update deps
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 16:16:58 -07:00
Varun Patil e6d288d6d8 fix(mobile): disable hover actions in CSS
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 14:58:30 -07:00
Varun Patil c097bd4193 v6.0.0-rc.2
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 13:05:21 -07:00
Varun Patil f44ac76c58 fragment: remove non-contextual fragments on start
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 13:03:01 -07:00
Varun Patil cf3b782cec fragment: fix wait time
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 12:48:56 -07:00
Varun Patil c6358ff644 cluster-view: prevent route change refresh
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 12:29:16 -07:00
Varun Patil 8588a7d190 dialog: add fragment
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 12:26:12 -07:00
Varun Patil 0a7914d9b9 face: fix move modal
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 12:08:08 -07:00
Varun Patil 5881f7fb09 cluster: fix type of element
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 12:07:28 -07:00
Varun Patil 6f6eb1c3ae editor: put back fragment on cancel
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 11:43:30 -07:00
Varun Patil fc53e020cf settings: add fragment
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 11:33:55 -07:00
Varun Patil f7abbce9de editor: add fragment
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 11:20:32 -07:00
Varun Patil a30012a7da sidebar: add fragment for mobile
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 11:15:18 -07:00
Varun Patil cfe63c328e refactor: NodeShareModal
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 11:05:12 -07:00
Varun Patil 1bc251012c topmatter: hide folder breadcrumbs on single file
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 11:00:32 -07:00
Varun Patil 926e57f896 modal: fix sharing modal
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 10:55:48 -07:00
Varun Patil 79ae924a00 fix: move to folder stuck
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 02:59:34 -07:00
Varun Patil e81e65cf7f refactor(fragment): add hook directly
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 02:40:40 -07:00
Varun Patil 9db97aed3d modal: use fragment
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 02:28:30 -07:00
Varun Patil 937feff286 sel: add fragment (fix #861)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 01:07:00 -07:00
Varun Patil 8eefae4247 refactor: viewer
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 00:47:37 -07:00
Varun Patil a0f40dfcae fragment: fix logic
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-24 00:43:25 -07:00
Varun Patil 3cd2402c4e Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-23 22:12:50 -07:00
Varun Patil 557e87ca3c refactor(fragment): support multiple frags
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-23 22:12:48 -07:00
Varun Patil 182caed840 refactor(modal): reduce watchers
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-23 19:41:24 -07:00
Nextcloud bot 6da5f6c3a7
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-24 02:26:24 +00:00
Varun Patil 1439160b50 frame: remove dead code in Folder
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-23 18:57:24 -07:00
Varun Patil 4f51e866c4 refactor: album delete watch
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-23 18:51:44 -07:00
Varun Patil 25e2c42830 psalm: set target PHP version to 8.0
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-23 18:39:43 -07:00
Varun Patil 2904aa6aa4 exif: suppress Perl language warning
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-22 14:49:41 -07:00
Varun Patil 35cdc1daeb Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-22 14:45:24 -07:00
Varun Patil 7cdced22c0 tw: prevent re-index on aborted force
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-22 14:45:18 -07:00
Varun Patil 46366d6715 psalm: refactor suppressions
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-22 14:13:33 -07:00
Varun Patil 07b0e7070e psalm: refactor suppressions
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-22 14:01:05 -07:00
Varun Patil c9e87c4cf6 refactor: forcePermissions typing
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-22 13:48:30 -07:00
Varun Patil b3f8387a95 refactor: move gisType to SystemConfig
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-22 13:37:50 -07:00
Varun Patil d5fcf19814 docs: fix config defaults
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-22 13:19:23 -07:00
Varun Patil e38da200db refactor: move SystemConfig to file
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-22 12:58:33 -07:00
Varun Patil 8b2df7c2a5 refactor: move ExifFields to class
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-22 12:40:25 -07:00
Varun Patil cd2743764d tw: remove leading slash from lock key
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-22 12:35:56 -07:00
Varun Patil 4d19451471 tw: don't clean up tables in transaction
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-22 12:32:05 -07:00
Varun Patil f8f9ce7b4a tw: minor refactor
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-22 12:29:52 -07:00
Varun Patil a0d78504b9 tw: fix lp return status
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-22 12:25:00 -07:00
Varun Patil f22b75c04d Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-22 12:16:30 -07:00
Varun Patil d3503d5e47 lp: renew query
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-22 12:14:02 -07:00
Varun Patil d8f327141f exif: add null check for MIMEType
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-22 12:09:00 -07:00
Varun Patil 1ad0559436 log: add context
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-22 12:07:22 -07:00
Varun Patil 4be31f19d5 refactor: reduce array_key_exists
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-22 11:56:29 -07:00
Nextcloud bot 67b96f969a
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-22 02:29:52 +00:00
Varun Patil e04bb0a7b6 admin: improve video panels
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-21 12:16:19 -07:00
Varun Patil bdf39678ed admin: hide VA-API status if external
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-21 12:09:41 -07:00
Varun Patil 19a4db3ee5 bin-ext: bump go-vod
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-21 11:48:09 -07:00
Varun Patil 27d332eff5 0.1.20 2023-10-21 11:46:08 -07:00
Varun Patil 4e2b1ddb18 handler: fix exit 2023-10-21 11:45:30 -07:00
Varun Patil ea9e620de3 refactor: create package 2023-10-21 11:36:22 -07:00
Varun Patil 48ed209d59 refactor: move around handler 2023-10-21 11:27:25 -07:00
Varun Patil 4a89dd16c7 docs: minor updates to hw
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-20 21:46:04 -07:00
Varun Patil 7a7cf46a72 docs: mention NEXTCLOUD_ALLOW_INSECURE
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-20 20:57:02 -07:00
Varun Patil 9f50cae0b1 run: more opts 2023-10-20 20:47:09 -07:00
Varun Patil 9c3fca950c ci: add latest tag 2023-10-20 20:28:16 -07:00
Varun Patil 12caf9c03f Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-20 20:19:15 -07:00
Varun Patil 56f4956852 v6.0.0-rc.1
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-20 20:18:40 -07:00
Nextcloud bot 1443f9e7a4
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-21 02:22:56 +00:00
Varun Patil ad59ceffad bin-ext: bump go-vod
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-20 16:11:40 -07:00
Varun Patil 432b7a4791 0.1.19 2023-10-20 16:02:15 -07:00
Varun Patil b1fb3d2e94 Merge branch 'szaimen-master' 2023-10-20 16:01:18 -07:00
Varun Patil 07fff59353 ci: update image name 2023-10-20 16:01:14 -07:00
Varun Patil 7e36063bf5 Merge branch 'master' of https://github.com/szaimen/go-vod into szaimen-master 2023-10-20 16:00:49 -07:00
Varun Patil d4bdc7bd81 Remove NVIDIA Dockerfile 2023-10-20 15:17:55 -07:00
Varun Patil 36832c731c build: don't remove lists 2023-10-20 15:12:58 -07:00
Varun Patil edbcaaa064 dockerfile: swith to inheriting build 2023-10-20 15:02:59 -07:00
Varun Patil 899098bc51 run: improve logging 2023-10-20 14:54:01 -07:00
Varun Patil d98d0b9522 run: add missing params to curl 2023-10-20 14:53:06 -07:00
Varun Patil 5319743c2d admin: remove govod_want
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-20 14:49:19 -07:00
Varun Patil c9317e9e37 video: add support for go-vod run
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-20 14:28:08 -07:00
Varun Patil d678fda96e main: print version to stdout 2023-10-20 14:24:49 -07:00
Varun Patil ad79aa5827 Add run script 2023-10-20 14:14:28 -07:00
Varun Patil d388b6f233 Add version monitor 2023-10-20 14:12:09 -07:00
Varun Patil b5e324b394 video: fix caching
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-20 13:33:06 -07:00
Varun Patil f655a0051c ci: fix bin-ext step
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-20 12:47:14 -07:00
Varun Patil e406b74806 refactor: move pkill to binext
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-20 12:42:22 -07:00
Varun Patil fd851b5e34 refactor: rename exiftool-bin to bin-ext
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-20 12:35:44 -07:00
Varun Patil eb1e224bfa refactor: generalize sw route
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-20 12:21:41 -07:00
Varun Patil 05b8534c47 docs: full PHP version in changelog
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-20 11:29:56 -07:00
Varun Patil ca756732d8 ci: restrict workflow paths
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-20 11:27:00 -07:00
Varun Patil 1287a8e601 docs: update readme apps section
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 23:31:22 -07:00
Varun Patil 0f33ca1aa2 viewer: fix title changes
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 23:14:08 -07:00
Varun Patil d048b7b3bf dtm: check share type
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 23:02:26 -07:00
Varun Patil d1f15240b7 refactor: folder dtm
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 22:55:18 -07:00
Varun Patil b641d08651 Merge branch 'Cl00e9ment-structured-shared-folder' 2023-10-19 22:48:13 -07:00
Varun Patil 0d155f1315 docs: update changelog
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 22:41:56 -07:00
Varun Patil 6f344b863f folder: hide list on recursive
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 22:38:46 -07:00
Varun Patil 3575c0b166 folder-share: tweaks
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 22:32:34 -07:00
Varun Patil 3d8ad4d668 Merge branch 'structured-shared-folder' of https://github.com/Cl00e9ment/memories into Cl00e9ment-structured-shared-folder
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 21:29:33 -07:00
Nextcloud bot adee570195
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-20 02:25:31 +00:00
Varun Patil 090a89602a build: move types to tsconfig
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 19:22:32 -07:00
Varun Patil 66a864560c Revert "build: revert to JS webpack config"
This reverts commit b66d88434e.
2023-10-19 19:21:09 -07:00
Varun Patil b66d88434e build: revert to JS webpack config
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 19:14:10 -07:00
Varun Patil caf0ff3487 Revert "build: fix attempt"
This reverts commit 552e7dc426.
2023-10-19 19:12:07 -07:00
Varun Patil 552e7dc426 build: fix attempt
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 19:08:39 -07:00
Varun Patil 1a05220aa3 folders: sanitize the path
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 18:51:54 -07:00
Varun Patil bbdcecc29e psalm: disable cache
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 18:48:04 -07:00
Varun Patil f69765a42a fs: improve sanitization
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 18:47:58 -07:00
Varun Patil 73cc86c4a1 scroller: hide container when not scrolling
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 14:22:48 -07:00
Varun Patil 993e43a46d refactor: top-left util class
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 14:21:44 -07:00
Varun Patil e96b10da46 scroller: reduce repaints
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 14:13:53 -07:00
Varun Patil 2a333911ef scrolling: minor improvements
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 14:09:02 -07:00
Clément Saccoccio 5d884a564c fix: check that share is a folder before trying to acces sub-folders 2023-10-19 22:50:35 +03:00
Clément Saccoccio c85a611651 share: show directory structure 2023-10-19 22:12:26 +03:00
Varun Patil 8d54a90fc1 build: capitalization in tsconfig
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 12:03:19 -07:00
Varun Patil c57b9ede34 build: remove worker types from global
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 12:00:08 -07:00
Varun Patil 545088de1c bootstrap: simplify video clientId
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 11:57:26 -07:00
Varun Patil 77d91f81e8 build: service-worker to TS
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 11:52:36 -07:00
Simon L 11bca6cc53 Create docker-build.yml
Signed-off-by: Simon L <szaimen@e.mail.de>
2023-10-19 20:50:45 +02:00
Varun Patil bcd1764779 webpack: config to ts
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 11:42:16 -07:00
Varun Patil 03d86e79dc readme: link to shepherd.dev
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-19 00:34:33 -07:00
Varun Patil 85a8f32da1 Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-18 23:15:15 -07:00
Varun Patil d631bb7d83 Merge branch 'meichthys-patch-3' 2023-10-18 23:15:05 -07:00
Varun Patil 1b1400babc docs: hw transcoding update
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-18 23:14:42 -07:00
Varun Patil 25fee175d8 Merge branch 'patch-3' of https://github.com/meichthys/memories into meichthys-patch-3 2023-10-18 23:02:07 -07:00
Nextcloud bot f0ed6976f7
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-19 02:23:46 +00:00
Varun Patil 1ab738c4af dav: remove usage of path
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-18 14:21:51 -07:00
Varun Patil 7e90fc8c40 Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-18 12:55:15 -07:00
Varun Patil 2c35f20eec webpack: fix source maps
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-18 12:55:12 -07:00
Varun Patil 1bf9022756 webpack: increase workbox cache size
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-18 12:39:01 -07:00
Varun Patil 27b252ce9c build: remove babel
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-18 12:21:16 -07:00
Nextcloud bot 892d0d037a
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-18 02:50:53 +00:00
MeIchthys 8cb09cf9e8
Clarify need for updated ffmpeg version
Also add bare-metal helpful links/notes for VM/Container use cases.
2023-10-17 16:06:43 -04:00
Varun Patil 52e82620ab
Merge pull request #877 from Cl00e9ment/recommended-extensions
docs: added recommended extensions to VSCode config
2023-10-17 12:13:36 -07:00
Clément Saccoccio 4e05baf3eb docs: added recommended extensions to VSCode config 2023-10-17 22:12:26 +03:00
Clément Saccoccio 8c35e488bb docs: added recommended extensions to VSCode config 2023-10-17 22:04:17 +03:00
Varun Patil 770f1e92da docs: disable issues 2023-10-17 11:43:51 -07:00
Varun Patil a235c7a2fb docs: general improvements
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-17 08:43:24 -07:00
Varun Patil b43fec0d3f docs: bump Nextcloud requirement
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-17 08:03:13 -07:00
Varun Patil 85adc58cdb docs: link back
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-17 08:02:21 -07:00
Varun Patil 7ac32e60e0 docs: update faq with forums link
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-17 07:58:44 -07:00
Varun Patil 96776de2ff docs: add basic troubleshooting for transcoding
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-17 07:56:25 -07:00
Varun Patil 4400307fe5 docs: general updates
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-16 22:46:47 -07:00
Varun Patil 65b1de8296 docs: update hw transcoding
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-16 21:22:59 -07:00
Varun Patil dc146d0f7a Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-16 21:12:30 -07:00
Varun Patil 2ea45cd1c8 sidebar: compat for Nextcloud 28
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-16 21:04:18 -07:00
Nextcloud bot b2c5b45a07
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-17 02:28:34 +00:00
Varun Patil 728efeaa6a share: disable links for albums
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-16 18:48:17 -07:00
Varun Patil afaebe6106 nx: support header logo change (fix #871)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-16 14:22:35 -07:00
Varun Patil cae270e931 docs: update go-vod clone
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-16 12:56:10 -07:00
Varun Patil 181c0423ff admin: show go-vod clone tag
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-16 12:54:29 -07:00
Varun Patil 75881b33d0 refactor: improve route typing
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-16 12:44:59 -07:00
Varun Patil c7f7d98d4f refactor: add a comment
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-16 11:38:57 -07:00
Varun Patil 9116e2b889 refactor: drop dead 24 code
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-16 11:36:28 -07:00
Varun Patil b2277382b2 refactor: minor typing fixes
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-16 11:36:13 -07:00
Varun Patil 0741eeb113 refactor: revert constants rename
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-16 11:23:01 -07:00
Varun Patil 2c18198c37 refactot: remove GlobalMixin
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-16 11:15:07 -07:00
Varun Patil 449e36e9a1 refactor: move route checkers out of global mixin
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-16 11:08:23 -07:00
Varun Patil a33631a8ae Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-16 09:55:54 -07:00
Varun Patil 395d0506b9 refactor: convert refs to prop
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-16 09:55:52 -07:00
Nextcloud bot 4c78da59f7
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-16 02:24:08 +00:00
Varun Patil 6931f01bfa ci: minor fixes
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 17:42:00 -07:00
Varun Patil 577ec47a81 ci: combine PHP jobs
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 17:39:35 -07:00
Varun Patil b5d89db6b9 ci: fix job description
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 17:33:19 -07:00
Varun Patil ab0a123bdb ci: combine UI linting jobs
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 17:31:01 -07:00
Varun Patil fe55caead2 ci: add vue-tsc workflow
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 17:21:37 -07:00
Varun Patil 8d13f0be98 refactor: add strict typing to refs
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 17:19:35 -07:00
Varun Patil 2144ba0d64 tooling: switch to Volar
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 15:23:57 -07:00
Varun Patil 74b6d9c5f2 refactor: add typing to emits
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 15:09:43 -07:00
Varun Patil 080bf1358d admin: show expected go-vod version
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 14:28:18 -07:00
Varun Patil 5e10d60123 docs: reordering in readme
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 14:13:18 -07:00
Varun Patil 5df95b2ed8 docs: update hw go-vod version
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 14:13:11 -07:00
Varun Patil ab19f66954 utils: warn user if picked folder has trailing/leading whitespace
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 13:56:31 -07:00
Varun Patil 0c3f09e52a psalm: bump level back to 3
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 13:46:20 -07:00
Varun Patil 33561f9ab4 cluster: add missing return type
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 13:26:18 -07:00
Varun Patil 1565638405 lint: modernize old migrations
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 13:23:57 -07:00
Varun Patil 15be33d94b ci: bump psalm level
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 13:18:48 -07:00
Varun Patil 49848bbd16 pslam: fix more issues
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 13:16:57 -07:00
Varun Patil bd2101e7bb refactor: PHP 8 syntax migration
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-15 12:46:35 -07:00
Varun Patil 73624ce5f2 Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-14 19:48:11 -07:00
Varun Patil eccc125991 webpack: add bundle analyzer
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 19:43:21 -07:00
Varun Patil c1b2984e22 refactor: webpack config js
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 19:39:29 -07:00
Varun Patil eee5abf210 refactor: improve typing
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 19:34:30 -07:00
Nextcloud bot 6867547660
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-15 02:23:02 +00:00
Varun Patil 465c5f2597 php-cs: add more rules
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 19:20:21 -07:00
Varun Patil 03c55a8d67 php-cs: add trailing commas
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 18:59:00 -07:00
Varun Patil fb32a94e2e refactor: move to PHP 8 syntax for constructors
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 18:51:17 -07:00
Varun Patil 6965d0214f deps: bump nc and php requirements
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 18:18:21 -07:00
Varun Patil 6a58a10c86 psalm: remove more dead code
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 18:15:01 -07:00
Varun Patil f992d19932 refactor: remove dead code
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 17:54:29 -07:00
Varun Patil 1752396bf8 days: refactor for better typing
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 17:46:54 -07:00
Varun Patil cb12398893 tq: fix string quoting for debug
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 17:31:19 -07:00
Varun Patil 27e9b093bf timeline: enable aggregation for month view
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 17:20:21 -07:00
Varun Patil 7b7ecab8e2 tq: refactor month days API
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 17:01:56 -07:00
Varun Patil 2d5b687350 days: improve monthView query
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 16:35:06 -07:00
Varun Patil 568e10d999 psalm: fix caching
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 16:10:50 -07:00
Varun Patil fe6205aea6 lin: bump psalm level
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 16:06:25 -07:00
Varun Patil eace12df0f days: remove wildcard API
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 16:03:59 -07:00
Varun Patil b29ff26a18 days: make preload more efficient
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 15:37:05 -07:00
Varun Patil c8c6f1f8a1 tags: remove some filters
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 14:35:47 -07:00
Varun Patil d73d96ed27 cI: rename jobs
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 13:15:42 -07:00
Varun Patil 376fa24c4d Merge branch 'ci-pretty' 2023-10-14 13:13:53 -07:00
Varun Patil 1bc5f58f91 chore: update prettier
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 13:12:47 -07:00
Varun Patil ba4c055fea psalm: use separate langserver config
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 12:56:31 -07:00
Varun Patil 351515ea18 ci: add prettier workflow
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 12:50:28 -07:00
Varun Patil 03d1f37a29 days: shorten function
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 12:44:26 -07:00
Varun Patil e255c957f7 tools: various updates
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 12:40:58 -07:00
Varun Patil d8c6266e53 refactor: tools to composer.json
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 03:01:08 -07:00
Varun Patil fb56eb8ce2 docs: update readme badges
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 02:49:43 -07:00
Varun Patil 516f8ab01c ci: refactor workflows
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 02:45:33 -07:00
Varun Patil d07e386029 psalm: update workflow
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 02:39:22 -07:00
Varun Patil f9c76d0b70 psalm: fix excludes
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 02:34:30 -07:00
Varun Patil 1bb40fd532 psalm: ignore externals
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 02:26:30 -07:00
Varun Patil c982c35078 ci: psalm workflow 2023-10-14 02:17:35 -07:00
Varun Patil 3fddf35415 refactor: fix psalm info things
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 02:07:18 -07:00
Varun Patil 71ef41f763 refactor: add psalm
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-14 01:25:50 -07:00
Varun Patil ba959d2c43 refactor: rename timelineQuery
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-13 23:51:12 -07:00
Varun Patil d71295ff1f v1.4 2023-10-13 23:43:43 -07:00
Varun Patil 2f5e732258 Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-13 23:27:08 -07:00
Varun Patil bbacd7ad36 nativex: update API
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-13 23:27:06 -07:00
Varun Patil 69c2e482bc Add self-signed trust for webview 2023-10-13 23:24:53 -07:00
Varun Patil b0c5927d9b Add box for self-signed 2023-10-13 23:12:46 -07:00
Varun Patil 49f97e2895 Move login call to native 2023-10-13 22:06:55 -07:00
Nextcloud bot 6580f5287f
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-14 02:24:38 +00:00
Varun Patil 6baf1bc3f7 cmd: colorize places-setup output
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-13 19:05:55 -07:00
Varun Patil 99dfbef88d cmd: improve index logging
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-13 19:03:13 -07:00
Varun Patil 8fb257fa3c nxsetup: fix back button after setup (close #855)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-13 18:45:35 -07:00
Varun Patil 25d81987b9 tq: exclude hidden mounts
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-13 17:43:01 -07:00
Varun Patil 5ce8696efb tq: fix debug quoting
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-13 16:59:14 -07:00
Varun Patil 0c2de94ee3 fs: fix recursion in folder previews
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-13 16:18:37 -07:00
Varun Patil 8414dbcda7 folder-top: prevent UI glitch when switching to timeline view
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-13 15:38:33 -07:00
Varun Patil 12da305022 fs: fix recursive folders
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-13 15:28:06 -07:00
Varun Patil 6d7c623e46 tq: refactor in root function
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-13 15:10:59 -07:00
Varun Patil 8e79b769ed refactor: fix vue typing
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-13 12:48:26 -07:00
Varun Patil 044d94f3b9 perf: freeze constants
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-13 12:22:25 -07:00
Varun Patil d6e108831e refactor: move globals declaration
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-13 12:22:15 -07:00
Varun Patil 43d3668119 refactor: init state to utils
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-13 12:09:26 -07:00
Varun Patil d0501a1bba refactor: move globals to namespace
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-13 10:32:07 -07:00
Varun Patil e8f5414668 ci: fix test
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-13 09:17:00 -07:00
Varun Patil 313ba6c3c2 refactor(large): disallow implicit any
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-11 22:56:53 -07:00
Varun Patil bcd16a9cb0 chore: update webpack-vue-config
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-11 20:54:06 -07:00
Varun Patil 2d1a0d1542 chore: update deps
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-11 20:30:26 -07:00
Varun Patil 4443f3e8cf Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-11 19:58:07 -07:00
Varun Patil 0c682b7cc3 dialog: restore cancel button (fix #864)
We autofocus the confirm button with MutationObserver

Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-11 19:58:02 -07:00
Nextcloud bot ac3fee401c
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-12 02:21:03 +00:00
Varun Patil 49f8c1e824 Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-10 04:58:55 -07:00
Varun Patil 08e75fb790 places-setup: fix output
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-10 04:56:56 -07:00
Varun Patil 7b647dc5c5 places-setup: improve transactions
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-10 04:48:20 -07:00
Nextcloud bot b6e4d2be36
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-10 02:56:26 +00:00
Varun Patil db93202b08 v5.5.3
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-07 10:43:21 -07:00
Varun Patil 1ca9aac7d6 tw: fix buid access (fix #849)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-07 10:40:38 -07:00
Varun Patil dbfd56e727 Bump up version 2023-10-07 09:34:50 -07:00
Varun Patil 2252100d29 v5.5.2 2023-10-07 09:22:08 -07:00
Varun Patil 72a76d7d30 nx: fix setup continue color
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-07 09:21:28 -07:00
Varun Patil 4ec42b7e0e Remove opening login toast 2023-10-07 09:13:20 -07:00
Varun Patil 2478dc71fd Check server status code on account 2023-10-07 09:12:54 -07:00
Varun Patil b4cd0f3dcb Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-07 08:57:01 -07:00
Varun Patil 4130dcd6fb index: document that --clear is now destructive
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-07 08:56:50 -07:00
Varun Patil 094a57e644 lp: fix mtime type
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-07 08:51:53 -07:00
Varun Patil 6be0cef3cd migrations: make them idempotent
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-07 08:45:35 -07:00
Varun Patil 255ef832ac migration: fix when exif is null (fix #848)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-07 08:18:21 -07:00
Nextcloud bot 4728478b0e
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-07 03:44:03 +00:00
Varun Patil 61294a7dc3 nx: replace route in setup
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-06 16:33:21 -07:00
Varun Patil 82f82cfe5f repair: remove redundant idx, improve output
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-06 15:42:47 -07:00
Varun Patil 9f25571704 migration: move filecache index to repair
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-06 15:29:16 -07:00
Varun Patil 278b2458b3 v5.5.1 2023-10-06 15:20:54 -07:00
Varun Patil 9a9783bea1 migration: fix index addition check
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-06 15:17:04 -07:00
Varun Patil 12bd8823e7 migration: add missing column checks (fix #845)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-06 15:14:16 -07:00
Varun Patil 14941a6c43 readme: add google play badge
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-06 11:02:14 -07:00
Varun Patil 3c28d93bc6 v5.5.0 2023-10-06 10:44:00 -07:00
Varun Patil 20c92e26e1 Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-06 09:57:56 -07:00
Varun Patil 57a161b7ed album: fix OG metadata in public link (fix #844)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-06 09:57:51 -07:00
Varun Patil b9dabc1e14 refactor: minor readjustment in util
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-06 09:55:39 -07:00
Nextcloud bot d4de8243bb
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-06 02:23:27 +00:00
Varun Patil e56828f3e8 lint: fix php
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-04 23:52:11 -07:00
Varun Patil fedb029b3f Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-04 23:51:56 -07:00
Varun Patil 20d049f160 lp: support Samsung HEIC
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-04 23:51:52 -07:00
Varun Patil 1360f411ca exif: trim db fields
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-04 23:33:59 -07:00
Nextcloud bot 64dacfb93f
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-05 02:37:39 +00:00
Varun Patil cb1d0d1ab2 docs: update changelog
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-04 17:16:31 -07:00
Varun Patil 686b399363 exif: only extract unknowns for lp
This is extremely slow for big MKV files, for example

Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-04 16:44:03 -07:00
Varun Patil f07a376c37 v5.5.0-rc.2
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-04 15:50:42 -07:00
Varun Patil 810ee107c9 nx: fix db update event
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-04 15:49:17 -07:00
Varun Patil 8b1121fc62 Fix db update events 2023-10-04 15:49:01 -07:00
Varun Patil d2c12316d3 rename variables 2023-10-04 15:35:38 -07:00
Varun Patil ce78d81d77 exif: fix buid definition
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-04 15:34:15 -07:00
Varun Patil 55631f53b6 docs: update changelog
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-04 15:14:17 -07:00
Varun Patil 96ff22325f nx: implement buid
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-04 15:09:43 -07:00
Varun Patil 55e5c05d54 Implement BUID 2023-10-04 14:59:47 -07:00
Varun Patil 8a90e8e01d nx: remove useless size
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-04 12:54:24 -07:00
Varun Patil 4016d48007 nx: bump min version
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-04 12:47:19 -07:00
Varun Patil c04cc12e88 Bump version 2023-10-04 12:47:08 -07:00
Varun Patil fbc5825ba7 nx: do not stringify numbers
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-04 12:45:35 -07:00
Varun Patil 0705924227 Pass numbers in JS interface 2023-10-04 12:45:05 -07:00
Varun Patil d22d7603ed nx: remove wrong fallback
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-04 12:35:59 -07:00
Varun Patil 4928eef556 remove log message 2023-10-04 12:15:38 -07:00
Varun Patil 864a240d0b nx: debounce fresh insertion
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-04 12:15:15 -07:00
Varun Patil 728c8e46ed Add threadpool for some ops 2023-10-04 11:46:58 -07:00
Varun Patil f7b9940181 Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-04 10:09:59 -07:00
Varun Patil aab9b6f0f7 docs: update privacy
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-04 10:09:56 -07:00
Nextcloud bot e0879ce335
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-04 02:23:13 +00:00
Varun Patil 8f820de237 cluster: add touch sound
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-03 19:20:26 -07:00
Varun Patil 62bbe2470a albums: fix deletion message
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-03 19:12:17 -07:00
Varun Patil 07b4d0dbc4 enable cache 2023-10-03 11:54:39 -07:00
Varun Patil 222db00efa Fix theming 2023-10-03 11:52:15 -07:00
Varun Patil 6d3fa7d27b nxsetup: fix overflow
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-03 11:28:59 -07:00
Varun Patil cba4bfc823 no need to specify http in url 2023-10-03 11:22:45 -07:00
Varun Patil 0152baa016 docs: update changelog
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-03 11:17:08 -07:00
Varun Patil 992a5a57a9 docs: update changelog
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-03 11:12:20 -07:00
Varun Patil 1a4d01f387 Take down req 2023-10-03 11:11:04 -07:00
Varun Patil df76e70202 v5.5.0-rc.1 2023-10-03 11:10:22 -07:00
Varun Patil 9a61e24cee Bump minimum version and check 2023-10-03 11:07:25 -07:00
Varun Patil 3e272236a5 lint: fix php
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-03 11:03:15 -07:00
Varun Patil 8f88c0f96e Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-03 11:01:43 -07:00
Varun Patil d9791d921c binext: allow directory change (fix #821)
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-03 11:01:36 -07:00
Varun Patil f414c224c7
Merge pull request #840 from ASDFGamer/show-place-count
Show number of pictures per place
2023-10-03 10:45:18 -07:00
Varun Patil fd13ebd44d Merge branch 'master' of https://github.com/pulsejet/memories 2023-10-03 10:44:38 -07:00
Varun Patil dfa4ab6695 Merge branch 'pulsejet/nn' 2023-10-03 10:44:14 -07:00
Varun Patil eb5f998505 Encrypt token (fix #10) 2023-10-03 10:43:21 -07:00
Varun Patil cba3e1faeb timeline: prevent unnecessary promises
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-03 10:10:30 -07:00
Varun Patil 5ab50fe85d New marking API 2023-10-03 10:07:01 -07:00
Varun Patil b04586ba34 nx: new marking API
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-03 10:06:40 -07:00
Varun Patil 5f6897b5c9 timeline: fix destructive cache reads
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-03 09:31:03 -07:00
Varun Patil d4765fef1a Fix ordering of query responses 2023-10-03 09:06:07 -07:00
Varun Patil e4ca88462d nx: add day cache
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-03 09:05:45 -07:00
Varun Patil 01d3e66108 nx: improve sorting algorithm
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-03 08:41:56 -07:00
Nextcloud bot 8f0cb9fd31
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-03 02:22:40 +00:00
Varun Patil ae6a2adbc4 ncx: use serverid API
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-02 18:43:11 -07:00
Varun Patil 500fe57e49 add serverid api 2023-10-02 18:32:40 -07:00
Varun Patil 3435ab35c9 app: refactor
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-02 18:00:49 -07:00
Varun Patil 1cb428b489 nx: use hidden API
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-02 17:54:56 -07:00
Varun Patil 51b096c194 api: add hidden day option
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-02 17:22:05 -07:00
Varun Patil 5820c53857 tq: mark hidden files
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-02 17:09:10 -07:00
Varun Patil 58760b1c53 nx: only fetch day for haslocal
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-02 16:27:53 -07:00
Varun Patil a87bc2e14b migration: show progress on epoch migration
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-02 15:42:41 -07:00
Varun Patil 96f0468c3a docs: note large migrations
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-02 13:50:04 -07:00
Varun Patil 63b5c00fc8 Remove useless space
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-02 13:34:47 -07:00
Varun Patil 33d99ee310 nxsetup: more improvements
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-02 13:33:26 -07:00
Varun Patil e3bea8b35b Show sync progress 2023-10-02 13:33:13 -07:00
Varun Patil aa867f1a49 nxsetup: fix nx theme
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-02 10:18:28 -07:00
Varun Patil 5d4fd8b07e Show toast on login 2023-10-02 10:17:27 -07:00
Varun Patil 582035df16 Refactor 2023-10-02 10:09:40 -07:00
Varun Patil b4eb9c1fc1 page: nxsetup is not public
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-02 10:09:23 -07:00
Varun Patil fd1671625a nx: move setup to this
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-02 10:03:58 -07:00
Varun Patil 53f8d248b7 Refactor 2023-10-02 09:36:23 -07:00
Varun Patil bb4d204228 Refactor 2023-10-01 20:36:27 -07:00
Varun Patil 9a85fa22ce Add HTTP service 2023-10-01 20:26:50 -07:00
Varun Patil 882a03312f Refactor 2023-10-01 20:19:24 -07:00
Varun Patil 44da3fc059 Refactor 2023-10-01 19:42:37 -07:00
Varun Patil a0c7408086 Refactor 2023-10-01 19:41:26 -07:00
Varun Patil 99dcd129ab Refactor 2023-10-01 19:38:39 -07:00
Varun Patil 6d83c026b1 Refactor 2023-10-01 19:38:19 -07:00
Varun Patil 2f065e6d12 Refactor 2023-10-01 19:37:35 -07:00
Varun Patil 0eee69bacb Refactor 2023-10-01 19:26:11 -07:00
Nextcloud bot d80be442fd
Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-10-02 02:22:45 +00:00
Varun Patil a612b02dfa Refactor 2023-10-01 19:17:05 -07:00
Varun Patil 4e90123814 Refactor 2023-10-01 19:14:43 -07:00
Varun Patil 73ff1b883f Fix iteration 2023-10-01 19:11:44 -07:00
Varun Patil 19e5fa29dc Reorder stuff 2023-10-01 19:04:41 -07:00
Varun Patil a930eab8d2 refactor: split nativex
Signed-off-by: Varun Patil <radialapps@gmail.com>
2023-10-01 19:04:01 -07:00
Varun Patil 3f85f76d2e Remove dead code 2023-10-01 18:43:38 -07:00
Christoph Wildhagen d7c55aa5a9
Update source of count value 2023-10-01 13:07:05 +02:00
Christoph Wildhagen f5f844e978
Merge branch 'pulsejet:master' into show-place-count 2023-10-01 13:05:51 +02:00
Varun Patil 0796b58b87 Switch share local to AUID 2023-09-30 15:01:35 -07:00
Varun Patil 12d5f137da Switch full load to AUID 2023-09-30 14:47:56 -07:00
Varun Patil f5daa0e557 Adapt to new nx api 2023-09-30 14:15:29 -07:00
Varun Patil 54bfe16c28 Oops 2023-09-30 14:09:38 -07:00
Varun Patil 9f466511eb Add dry delete API 2023-09-30 13:39:11 -07:00
Varun Patil 8976b53284 Upgrade gradle 2023-09-30 12:33:12 -07:00
Varun Patil 7a8c23d4e9 Allow multi resolution full videos 2023-09-30 11:34:18 -07:00
Christoph Wildhagen 06266a27e3 Show number of pictures per place
This shows the number of pictures per place.
This function was previously disabled, if the parameter 'mark'
wasn't set to 0. I found no reason why this was the case.

Signed-off-by: Christoph Wildhagen <git@christoph-wildhagen.de>
2023-09-30 00:58:50 +02:00
Varun Patil ebb9b5373b Bump up version 2023-09-29 10:25:17 -07:00
Varun Patil a7968c9279 stream: add UseGopSize 2023-09-29 10:25:00 -07:00
Varun Patil ec9900e166 refactor: use log for log 2023-09-29 10:24:41 -07:00
Varun Patil c933613d1e Fix sidecar metadata in max.mov 2023-09-29 10:00:22 -07:00
Varun Patil 33714bb36a 0.1.13 2023-08-30 20:06:11 -07:00
Varun Patil 8d46582c11 stream: use passtrough only for scale_cuda 2023-08-30 20:05:13 -07:00
Varun Patil 58ac632839 stream: add split_by_time HLS flag 2023-08-30 19:59:03 -07:00
Varun Patil 814af27881 Bump up version 2023-08-24 22:14:40 -07:00
Varun Patil eb5ce7fedd manager: use container duration 2023-08-24 22:12:35 -07:00
Varun Patil 6b1ccee34c main: remove dead code 2023-08-21 16:08:12 -07:00
Varun Patil ca60375703 reformat manifest 2023-08-21 12:42:38 -07:00
Varun Patil 84086024bd Optimization 2023-08-21 12:41:26 -07:00
Varun Patil 4e89b101b2 Reformat code 2023-08-21 12:38:55 -07:00
Varun Patil 3fb209a994 room: add indices 2023-08-21 12:36:39 -07:00
Varun Patil 6dfe308268 Switch to room 2023-08-21 12:32:52 -07:00
Varun Patil ec8c125b0e account : catch all exceptions 2023-08-21 09:59:22 -07:00
Varun Patil 6f7e68ad17 More refactor 2023-08-21 03:39:16 -07:00
Varun Patil bd5113e6b1 nx: rearrange structure 2023-08-21 03:30:43 -07:00
Varun Patil 23b0f4b102 fields: refactor more 2023-08-21 03:12:41 -07:00
Varun Patil 56a1ec6cf6 Refactor Db calls 2023-08-21 02:42:44 -07:00
Varun Patil 4df353c7d2 Deletion with AUIDs 2023-08-21 00:23:38 -07:00
Varun Patil d9e1c2a95d Implement AUID 2023-08-20 23:08:34 -07:00
Varun Patil 290d8c6bed Store AUID in DB 2023-08-20 21:30:15 -07:00
Varun Patil 831f07a021 Fix perms 2023-08-20 13:55:06 -07:00
Varun Patil 6756d73ffb main: fix color parsing 2023-08-20 13:28:45 -07:00
Varun Patil df534ae500 Bump up version 2023-08-05 11:24:20 -07:00
Varun Patil f347b996d2 manager: fix size calculation 2023-08-05 11:24:07 -07:00
Varun Patil 478d62930d stream: fix odd numbers in size 2023-08-03 21:08:29 -07:00
Varun Patil 7a67cf56e2 Make transpose optional and configurable
Close #15
Close #16
Close #17
2023-08-03 13:06:31 -07:00
Varun Patil f2d1a66a2a Disable transpose for CUDA 2023-07-21 20:21:39 -07:00
Varun Patil ff9c27a74e Fix invalid rotation with CPU 2023-07-21 19:02:31 -07:00
Varun Patil 92413eaa29 build: remove step is not necessary 2023-06-04 11:25:55 -07:00
Varun Patil 272a15245c
Merge pull request #14 from lastlink/patch-1
get dockerfile working on windows
2023-06-03 09:03:06 -07:00
lastlink 3b0e91b1df
get dockerfile working on windows 2023-05-31 11:59:28 -04:00
Varun Patil 4d0020a593 0.1.7 2023-05-27 23:43:09 -07:00
Varun Patil 0e09eb1d76 Another attempt at fixiing autorotation 2023-05-27 23:42:58 -07:00
Varun Patil 1bbc7e5066 update logo 2023-05-26 02:05:29 -07:00
Varun Patil 1e933a0776 Clean up manifest 2023-05-23 20:10:21 -07:00
Varun Patil 7bc13f924f fix wv destruction 2023-05-23 20:09:17 -07:00
Varun Patil 23c784f2cd webview: match host 2023-05-23 20:03:11 -07:00
Varun Patil e5745d0c05 video: support direct playback 2023-05-23 19:57:01 -07:00
Varun Patil 0dedd2acb8 Bump up version 2023-05-22 22:42:52 -07:00
Varun Patil 79aecab377 Watch local changes 2023-05-22 19:16:04 -07:00
Varun Patil 76f3a270c3 destroy webview on activity 2023-05-22 18:07:06 -07:00
Varun Patil 056a640fd0 manifest: turn on hw explicitly 2023-05-21 23:29:48 -07:00
Varun Patil 926afdd7b7 manifest: disable backup 2023-05-21 23:29:18 -07:00
Varun Patil 4f660eaaab Change default status color 2023-05-21 23:26:46 -07:00
Varun Patil d35f5b4583 Add current logo 2023-05-21 23:23:08 -07:00
Varun Patil 8341458f80 welcome: more to sync 2023-05-21 21:45:42 -07:00
Varun Patil 21d803bb04 Add local folder to welcome 2023-05-21 21:41:59 -07:00
Varun Patil 39d137a81c Add local folder config 2023-05-21 20:31:30 -07:00
Varun Patil 5355dc5b38 db: reset sync time on version change 2023-05-21 19:26:04 -07:00
Varun Patil d7678fd218 Docs 2023-05-21 12:18:05 -07:00
Varun Patil 94b8fc82d6 Add sync page 2023-05-18 19:50:19 -07:00
Varun Patil 9464a54481 Improve landing page 2023-05-18 19:10:33 -07:00
Varun Patil 7d7a19eb07 Rename variables 2023-05-18 16:34:56 -07:00
Varun Patil 8aba3e7e81 Add nx for logout 2023-05-18 00:00:44 -07:00
Varun Patil e1b58ae6fb Request permission 2023-05-17 23:38:36 -07:00
Varun Patil a4d250168f Fix user agent 2023-05-17 23:17:29 -07:00
Varun Patil 9c83922943 Check min version of Memories 2023-05-17 22:56:42 -07:00
Varun Patil 3626001c4d Check token revocation 2023-05-17 22:41:32 -07:00
Varun Patil 98d7638473 Update UA 2023-05-16 23:34:14 -07:00
Varun Patil 8cade4d100
Merge pull request #12 from Markvis/nvidia-hw-accel
add nvidia Dockfile
2023-05-16 17:46:27 -07:00
Varun Patil 6e10692962 Add login flow 2023-05-16 03:17:45 -07:00
Varun Patil 56308aa8aa nx: add login flow basics 2023-05-16 01:07:00 -07:00
Varun Patil 0a47baf16e Add API call to welcome 2023-05-16 00:25:34 -07:00
Varun Patil 14bbea4c9f Add welcome page 2023-05-15 21:07:36 -07:00
Varun Patil c08d87777a Add delta sync 2023-05-15 20:09:56 -07:00
Varun Patil 2e67ab5cda Minor refactofr 2023-05-15 09:41:05 -07:00
Varun Patil 9488a2bc7d UX improvements 2023-05-14 22:16:11 -07:00
Varun Patil e8c59d7648 Optimizations 2023-05-14 21:56:41 -07:00
Varun Patil 3fb17c0450 exoplayer: button fixes 2023-05-14 19:58:45 -07:00
Varun Patil c4ad66567f Do not rotate MOV 2023-05-14 19:38:13 -07:00
Varun Patil 15784416eb UX improvements 2023-05-14 19:04:46 -07:00
Varun Patil 3ad8606d8d Remove log 2023-05-14 18:39:30 -07:00
Varun Patil 52cef01dca manager: read rotation from side data 2023-05-14 18:38:50 -07:00
Varun Patil dd637f9b1f Rotate videos 2023-05-14 18:10:17 -07:00
Varun Patil a2765eef60 Add touch sound api 2023-05-14 17:26:39 -07:00
Varun Patil 4205a65b87 Multiple fixes 2023-05-14 16:25:48 -07:00
Varun Patil d7b550e85a Add HLS playback 2023-05-14 13:57:32 -07:00
Varun Patil 403e4404a7 Add local video playback 2023-05-14 13:32:25 -07:00
Varun Patil ce3ee760d0 Remove nativeX static refs on exit 2023-05-13 17:56:11 -07:00
Varun Patil 7f0a75eae2 refactor 2023-05-13 17:50:40 -07:00
Varun Patil 18817f2642 refactor 2023-05-13 17:46:02 -07:00
Varun Patil c7d2d78619 Fix video deletion 2023-05-13 17:16:39 -07:00
Varun Patil 39f2af8dc3 Convert to kotlin 2023-05-12 01:16:30 -07:00
Varun Patil 94e47a194c Convert some files to kotlin 2023-05-11 23:40:19 -07:00
Varun Patil 5386d72456 dl: allow sharing local video 2023-05-11 21:19:26 -07:00
Varun Patil b0b0b74754 Show local videos in timeline 2023-05-11 21:16:43 -07:00
Varun Patil bc5490ecdb Add local sharing 2023-05-10 20:25:53 -07:00
Varun Patil fb3045d6c9 Remove unused var 2023-05-10 20:04:45 -07:00
Varun Patil 884e70e5e6 Add share API 2023-05-10 20:02:30 -07:00
Varun Patil fb911669e6 tq: delete from table on deletion 2023-05-10 13:25:02 -07:00
Varun Patil 414f6cf5ed Update del API for list 2023-05-10 13:20:31 -07:00
Varun Patil 22ed3b3cb0 Add single delete API 2023-05-10 12:47:26 -07:00
Varun Patil 93ee281eee tq: add fake etag 2023-05-08 21:33:38 -07:00
Varun Patil e8baff4273 dl: filename 2023-05-08 20:30:23 -07:00
Varun Patil 6f11b5eeba add untested download code 2023-05-08 20:02:33 -07:00
Varun Patil a6cf5ad190 info: add EXIF 2023-05-08 15:01:24 -07:00
Varun Patil 5149ef94d4 Add basic image info API 2023-05-08 14:07:12 -07:00
Varun Patil 4aaacdda0d Remove async promise 2023-05-08 13:25:44 -07:00
Varun Patil b23b1d81f6 revert whitespace change 2023-05-08 12:07:14 -07:00
Varun Patil c10f3c1296 Disable cache 2023-05-08 12:06:46 -07:00
Varun Patil 942a1eee2e Add theme color API 2023-05-07 21:07:02 -07:00
Varun Patil 01d4bd8489 Add days API 2023-05-07 20:02:37 -07:00
Varun Patil 93350812a3 tq: remove stale images 2023-05-07 19:08:41 -07:00
Varun Patil cd131797cc Update tq 2023-05-07 18:57:29 -07:00
Varun Patil 535daadc51 Add dayId to DB 2023-05-07 18:26:11 -07:00
Varun Patil af97d312bd Add SQLite DB service 2023-05-07 14:18:25 -07:00
Varun Patil ddd8bb7af6 Add NativeX class 2023-05-07 13:06:12 -07:00
Varun Patil 37415f7dd5 refactor 2023-05-07 13:02:04 -07:00
root c2a7be9480 add nvidia Dockfile 2023-05-05 12:12:47 -07:00
Varun Patil c9a9e4379b Initial Commit 2023-05-03 20:10:02 -07:00
Varun Patil d9d903bb4f Merge branch 'master' of https://github.com/pulsejet/go-vod 2023-04-17 00:36:54 -07:00
Varun Patil df7122fe07 Disable ENCODER_COPY 2023-04-17 00:36:36 -07:00
Varun Patil e685d114bf Update build files 2023-04-12 13:20:57 -07:00
Varun Patil 23be0f6d17 Bump up to 0.1.0 2023-04-10 17:00:27 -07:00
Varun Patil 5548498453 Add config POST 2023-04-10 16:44:39 -07:00
Varun Patil 8748f4a6e0 manager: avoid pointless streams 2023-04-03 19:37:10 -07:00
Varun Patil a2a8fda91e Use copy for H264 2023-04-03 18:55:26 -07:00
Varun Patil b1aba2284f refactor: consts 2023-04-03 18:44:11 -07:00
Varun Patil c9198e0218 x264: remove level 2023-03-29 15:57:23 -07:00
Varun Patil 2684f705f9 output: choose zero streams 2023-03-29 15:54:53 -07:00
Varun Patil 1c9d46130e Don't set audio bitrate 2023-03-29 15:50:01 -07:00
Varun Patil 38384b0d6d Revamp scaler + add nv12 to vaapi 2023-03-17 16:40:31 -07:00
Varun Patil b4ad9d91be Switch to main profile 2023-03-17 16:07:33 -07:00
Varun Patil cbad0bb175 Trap exit code for ffmpeg 2023-03-17 14:44:59 -07:00
Varun Patil 5cb165d15f stream: don't die on stdout error 2023-03-17 14:31:03 -07:00
Varun Patil 7dde1e145c Add temp post support 2023-03-17 14:06:54 -07:00
Varun Patil 7f2dc535e4 Add dockerfile 2023-03-17 10:41:09 -07:00
Varun Patil 9ea4f3ad2d Reduce lookBehind to 3 (fix #5) 2023-03-15 10:21:44 -07:00
Varun Patil 5a6d0f8d0c Revert "Update circle config"
This reverts commit dbc2e516ea.
2023-03-14 12:12:16 -07:00
Varun Patil dbc2e516ea Update circle config 2023-03-14 12:10:50 -07:00
Varun Patil 42c971ed64 Remove comment 2023-03-14 12:06:44 -07:00
Varun Patil bfbe46fa98
Merge pull request #7 from remz1337/master
Drop the hwaccel_output_format argument to fix issue #6
2023-03-14 11:52:56 -07:00
Rémi Bédard-Couture 6710930109 Drop the hwaccel_output_format argument to fix issue #6 2023-03-14 14:27:44 -04:00
Varun Patil 95cfe3fd57 Make NVENC more configurable 2023-03-09 13:02:57 -08:00
Varun Patil a38fed1983 vaapi: make lowpower configurable 2023-03-09 12:39:43 -08:00
Varun Patil f41680455c Switch to config file 2023-03-09 11:57:15 -08:00
Varun Patil 35b4b3a8b2 buildvcs=false 2023-02-24 00:35:24 -08:00
Varun Patil 563d14248c go 1.20 2023-02-24 00:29:50 -08:00
Varun Patil 3c2a405133 Return conflict when coder changed 2023-02-24 00:26:10 -08:00
Varun Patil d003a271bf Allow setting bind port 2023-01-31 19:45:09 -08:00
Varun Patil ab49efa89b Don't run ffmpeg for h264 full video 2022-12-03 07:24:24 -08:00
Varun Patil 34b96aa1aa Preserve query strings 2022-12-02 22:06:03 -08:00
Varun Patil 758812c699 Make sure max is at end 2022-12-01 13:05:19 -08:00
Varun Patil c57fb1ca56 Change mp4 to mov 2022-11-29 14:16:27 -08:00
Varun Patil a203bc8f26 Whitespace fixes 2022-11-29 13:55:00 -08:00
Varun Patil 64767d7a78
Merge pull request #3 from MB-Finski/patch-1
Add support for NVIDIA GPU accelerated transcoding
2022-11-29 13:52:08 -08:00
Varun Patil 1729a04527 Copy full video if h264 2022-11-29 13:12:35 -08:00
MB-Finski a7b7fa5360
Add "format" back into NVENC transcode profile 2022-11-29 23:03:35 +02:00
Varun Patil 2c92130c40 Support serving full video 2022-11-29 13:00:36 -08:00
MB-Finski 0dd14fabe2
Optimizations for NVENC transcode profile
Permormance and quality related optimizations for NVENC. Also contains a bugfix where transcoding with "max"-profile would fail due to a bug in the NVENC itself.
2022-11-29 20:33:26 +02:00
MB-Finski 9972fc23c6
Add support for NVIDIA GPU accelerated transcoding
Add a transcoding profile for ffmpeg suitable for using with NVENC.
2022-11-25 13:59:33 +02:00
Varun Patil 56767bc56d Add format to max stream 2022-11-22 09:58:41 -08:00
Varun Patil c90483f61a Remove -map 0 2022-11-22 01:57:29 -08:00
Varun Patil d0f1433f64 Increase timeout to 10s 2022-11-21 16:22:28 -08:00
Varun Patil 8f26483140 Add map 0 to ffmpeg 2022-11-21 16:22:16 -08:00
Varun Patil afdda3038b Fix 10bit decoding 2022-11-21 16:22:02 -08:00
Varun Patil 630178e6cb Reduce buffer goal 2022-11-21 02:23:35 -08:00
Varun Patil 88685d0d69 Reduce idle times 2022-11-21 02:22:38 -08:00
Varun Patil 513e9410ca Force only one audio track 2022-11-16 07:10:21 -08:00
Varun Patil 1469f9eb9d Read paths from env variables 2022-11-15 02:09:33 -08:00
Varun Patil 3bfdc85603 Add global_quality 2022-11-14 01:25:42 -08:00
Varun Patil 7f26d300e3 Adjust crf 2022-11-14 00:57:03 -08:00
Varun Patil e40f53c18b Fix keyframe alignment 2022-11-13 22:08:14 -08:00
Varun Patil e20888f244 revert copy encoding 2022-11-13 19:34:12 -08:00
Varun Patil 10a4e469ba Revert to maxrate for bitrate
https://github.com/pulsejet/memories/issues/190
2022-11-13 02:41:12 -08:00
Varun Patil 8fc89b853c More tuning 2022-11-12 10:51:31 -08:00
Varun Patil af6c0eb190 Use copy if we can 2022-11-12 09:50:16 -08:00
Varun Patil a42fcd6978 Remove stray print statement 2022-11-12 08:27:14 -08:00
Varun Patil bf2f137d89 Tune with framerate 2022-11-12 04:35:05 -08:00
Varun Patil 3408e48db9 More tuning 2022-11-12 03:05:30 -08:00
Varun Patil 2c4575171f stream: double header write 2022-11-12 02:41:42 -08:00
Varun Patil 22e6715b2a More tuning 2022-11-12 02:39:56 -08:00
Varun Patil 5b5a5afe78 Adjust bitrates 2022-11-12 02:09:09 -08:00
Varun Patil ae1c4ae682 Return timeout in waitForChunk 2022-11-11 18:18:16 -08:00
Varun Patil 7764a70471 Increase idle time 2022-11-10 21:49:46 -08:00
Varun Patil e993d738ee Add link to go-transcode 2022-11-10 21:31:47 -08:00
Varun Patil 88d34fdf49 Add link to go-transcode 2022-11-10 21:30:54 -08:00
Varun Patil 2cdc5d5131 Adjustment for VAAPI 2022-11-10 21:29:38 -08:00
Varun Patil 689aa6eae4 Add link to memories 2022-11-10 21:23:20 -08:00
Varun Patil a9cf287618 Adjust timers 2022-11-10 21:20:23 -08:00
Varun Patil 00b9e98f17 Add test arg 2022-11-10 21:03:55 -08:00
Varun Patil f9f43ebb42 Add workflows 2022-11-10 20:26:21 -08:00
Varun Patil 66b2dca145 Add cmd 2022-11-10 20:22:07 -08:00
Varun Patil 7fbcabe2e2 Prep for release 2022-11-10 20:20:45 -08:00
Varun Patil fb9a83de56 Minor fixes 2022-11-10 20:14:38 -08:00
Varun Patil 0e87287035 Tempdir cleanup 2022-11-10 19:40:53 -08:00
Varun Patil 62646cfc81 Add multi-file support 2022-11-10 19:23:28 -08:00
Varun Patil d466a1b7b8 Pruning 2022-11-10 18:49:55 -08:00
Varun Patil a094c37fb5 log improv 2022-11-10 18:20:47 -08:00
Varun Patil 1141c358b8 refactor to config 2022-11-10 18:01:33 -08:00
Varun Patil 6591b3c39c Add max stream 2022-11-10 17:56:38 -08:00
Varun Patil 75d2768fe6 Tuning 2022-11-10 09:39:09 -08:00
Varun Patil 91c6a43fc1 Fix goal 2022-11-10 07:59:31 -08:00
Varun Patil c2fd1659ce Add goal 2022-11-10 07:46:35 -08:00
Varun Patil 31bab910d2 Ugh 2022-11-10 07:34:07 -08:00
Varun Patil 339b7f1e9e First stream 2022-11-10 06:54:32 -08:00
Varun Patil 81607447bd Update 2022-11-10 04:45:10 -08:00
Varun Patil 34e4b9f3d5 ffprobe 2022-11-10 04:27:29 -08:00
Varun Patil d75dd80672 Add stream 2022-11-10 04:09:35 -08:00
Varun Patil 8b36733e36 Initial commit 2022-11-10 03:24:33 -08:00
566 changed files with 27392 additions and 11730 deletions

View File

@ -3,6 +3,10 @@ on:
push:
branches:
- master
paths:
- 'docs/**'
- 'CHANGELOG.md'
- 'mkdocs.yml'
permissions:
contents: write
@ -11,14 +15,20 @@ jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: 3.x
- uses: actions/cache@v2
with:
key: ${{ github.ref }}
path: .cache
- run: cp CHANGELOG.md docs/changelog.md
- run: pip install mkdocs-material pillow cairosvg
- run: mkdocs gh-deploy --force
- name: Build documentation
run: |
cp CHANGELOG.md docs/changelog.md
sed -n '/DEFAULTS = \[/,/];/p' lib/Settings/SystemConfig.php | sed 's/^ //' > docs/system-config.php
pip install mkdocs-material pillow cairosvg
mkdocs gh-deploy --force

View File

@ -5,6 +5,12 @@ on:
branches:
- master
- pulsejet/*
paths-ignore:
- 'docs/**'
- 'go-vod/**'
- 'android/**'
- 'mkdocs.yml'
- '**.md'
env:
APP_NAME: memories
@ -17,10 +23,10 @@ jobs:
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 18.x
node-version: 20.x
- name: Checkout the app
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Build vue app
run: |
@ -56,21 +62,21 @@ jobs:
steps:
- name: Checkout server
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: true
repository: nextcloud/server
ref: ${{ matrix.server-versions }}
- name: Checkout the app
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
path: apps/${{ env.APP_NAME }}
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 18.x
node-version: 20.x
- uses: actions/download-artifact@v2
with:
@ -129,21 +135,21 @@ jobs:
steps:
- name: Checkout server
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: true
repository: nextcloud/server
ref: ${{ matrix.server-versions }}
- name: Checkout the app
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
path: apps/${{ env.APP_NAME }}
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 18.x
node-version: 20.x
- uses: actions/download-artifact@v2
with:
@ -188,21 +194,21 @@ jobs:
steps:
- name: Checkout server
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: true
repository: nextcloud/server
ref: ${{ matrix.server-versions }}
- name: Checkout the app
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
path: apps/${{ env.APP_NAME }}
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 18.x
node-version: 20.x
- uses: actions/download-artifact@v2
with:

70
.github/workflows/go-vod.yml vendored 100644
View File

@ -0,0 +1,70 @@
name: go-vod
on:
push:
tags:
- "go-vod/*"
jobs:
binary:
name: Binary
runs-on: ubuntu-latest
container:
image: golang:1.20-bullseye
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build
working-directory: go-vod
run: |
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -buildvcs=false -ldflags="-s -w" -o go-vod-amd64
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -buildvcs=false -ldflags="-s -w" -o go-vod-aarch64
- name: Upload to releases
uses: svenstaro/upload-release-action@v2
id: attach_to_release
with:
file: go-vod/go-vod-*
file_glob: true
tag: ${{ github.ref }}
overwrite: true
make_latest: false
docker:
runs-on: ubuntu-latest
name: Docker
steps:
- name: Check out the repo
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Get image label
id: image_label
run: echo "label=${GITHUB_REF#refs/tags/go-vod/}" >> $GITHUB_OUTPUT
- name: Build container image
uses: docker/build-push-action@v5
with:
push: true
platforms: linux/amd64,linux/arm64
context: './go-vod/'
no-cache: true
file: './go-vod/Dockerfile'
tags: radialapps/go-vod:${{ steps.image_label.outputs.label }} , radialapps/go-vod:latest
provenance: false

View File

@ -1,16 +0,0 @@
---
name: Lint
on:
- push
- pull_request
jobs:
php-cs-fixer:
name: PHP-CS-Fixer
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: PHP-CS-Fixer
uses: docker://oskarstark/php-cs-fixer-ga
with:
args: --dry-run --diff lib

View File

@ -9,17 +9,18 @@ env:
jobs:
publish:
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 18.x
node-version: 20.x
- name: Build
run: |

View File

@ -0,0 +1,75 @@
---
name: static analysis
on:
push:
paths-ignore:
- 'docs/**'
- 'go-vod/**'
- 'android/**'
- 'mkdocs.yml'
- '**.md'
pull_request:
paths-ignore:
- 'docs/**'
- 'go-vod/**'
- 'android/**'
- 'mkdocs.yml'
- '**.md'
jobs:
php-lint:
name: PHP Lint
runs-on: ubuntu-latest
steps:
- name: Checkout server
uses: actions/checkout@v4
with:
submodules: true
repository: nextcloud/server
ref: stable27
- name: Checkout the app
uses: actions/checkout@v4
with:
path: apps/memories
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@v2
with:
php-version: 8.1
tools: phpunit
extensions: mbstring, iconv, fileinfo, intl
coverage: none
- name: Install dependencies
working-directory: apps/memories
run: |
make install-tools
- name: Run PHP-CS-Fixer
if: ${{ ! cancelled() }}
working-directory: apps/memories
run: |
vendor/bin/php-cs-fixer fix --dry-run --diff
- name: Run Psalm
if: ${{ ! cancelled() }}
working-directory: apps/memories
run: |
vendor/bin/psalm --no-cache --shepherd --stats --threads=max lib
vue-lint:
name: Vue Lint
runs-on: ubuntu-latest
steps:
- name: Checkout the app
uses: actions/checkout@v4
- name: Install dependencies
run: npm ci
- name: Run vue-tsc
run: npx vue-tsc --noEmit --skipLibCheck
- name: Run Prettier
run: npx prettier src --check

4
.gitignore vendored
View File

@ -4,6 +4,7 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
js/
*.tsbuildinfo
# Editor directories and files
.idea
@ -26,5 +27,4 @@ memories.tar.gz
/playwright/.cache/
.cache/
exiftool-bin/
tools/
bin-ext/

View File

@ -15,44 +15,29 @@ declare(strict_types=1);
$finder = PhpCsFixer\Finder::create()
->ignoreDotFiles(false)
->ignoreVCSIgnored(true)
->exclude('tests/Fixtures')
->in(__DIR__)
->append([
__DIR__.'/dev-tools/doc.php',
// __DIR__.'/php-cs-fixer', disabled, as we want to be able to run bootstrap file even on lower PHP version, to show nice message
])
->in(__DIR__.'/lib')
;
$config = new PhpCsFixer\Config();
$config
->setUsingCache(true)
->setRiskyAllowed(true)
->setRules([
'@PHP71Migration' => false,
'@PHP71Migration:risky' => false,
'@PHPUnit75Migration:risky' => true,
'@PhpCsFixer' => true,
'@PhpCsFixer:risky' => true,
'general_phpdoc_annotation_remove' => ['annotations' => ['expectedDeprecation']], // one should use PHPUnit built-in method instead
'modernize_strpos' => false, // needs PHP 8+ or polyfill
'phpdoc_to_comment' => ['ignored_tags' => ['psalm-suppress', 'template-implements', 'var']],
'trailing_comma_in_multiline' => ['elements' => ['arrays', 'parameters', 'arguments']],
'modernize_strpos' => true,
'no_alias_functions' => true,
'array_syntax' => ['syntax' => 'short'],
'ternary_to_elvis_operator' => true,
'ternary_to_null_coalescing' => true,
'return_assignment' => true,
'declare_strict_types' => true,
'strict_param' => true,
])
->setFinder($finder)
;
// special handling of fabbot.io service if it's using too old PHP CS Fixer version
if (false !== getenv('FABBOT_IO')) {
try {
PhpCsFixer\FixerFactory::create()
->registerBuiltInFixers()
->registerCustomFixers($config->getCustomFixers())
->useRuleSet(new PhpCsFixer\RuleSet($config->getRules()))
;
} catch (PhpCsFixer\ConfigurationException\InvalidConfigurationException $e) {
$config->setRules([]);
} catch (UnexpectedValueException $e) {
$config->setRules([]);
} catch (InvalidArgumentException $e) {
$config->setRules([]);
}
}
return $config;
return $config;

10
.vscode/extensions.json vendored 100644
View File

@ -0,0 +1,10 @@
{
"recommendations": [
"bmewburn.vscode-intelephense-client",
"muuvmuuv.vscode-just-php-cs-fixer",
"getpsalm.psalm-vscode-plugin",
"esbenp.prettier-vscode",
"Vue.volar",
"Vue.vscode-typescript-vue-plugin"
]
}

24
.vscode/settings.json vendored
View File

@ -1,5 +1,4 @@
{
"intelephense.environment.phpVersion": "7.4.0",
"intelephense.stubs": [
"apache",
"bcmath",
@ -75,11 +74,22 @@
"zlib",
"imagick"
],
"intelephense.environment.phpVersion": "8.0.0",
"intelephense.environment.documentRoot": "${workspaceFolder}/../../",
"php-cs-fixer.allow-risky": true,
"psalm.disableAutoComplete": true,
"[php]": {
"editor.formatOnSave": false
"editor.defaultFormatter": "muuvmuuv.vscode-just-php-cs-fixer"
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[markdown]": {
"files.trimTrailingWhitespace": false
"files.trimTrailingWhitespace": false,
"editor.formatOnSave": false,
},
"search.exclude": {
"**/l10n": true,
@ -87,6 +97,8 @@
"**/patches": true
},
"git.alwaysSignOff": true,
"intelephense.environment.documentRoot": "/var/www/html",
"editor.formatOnSave": true
}
"editor.formatOnSave": true,
"psalm.configPaths": [
"psalm-ls.xml"
],
}

View File

@ -2,9 +2,60 @@
All notable changes to this project will be documented in this file.
## [Unreleased]
## [v6.2.2] - 2024-01-10
- Hotfix for a bug in request pipelining.
## [v6.2.0] - 2024-01-09
- Nextcloud 28 compatibility
- Various bug fixes
## [v6.1.5] - 2023-11-25
- Hotfix in service worker caching strategy.
## [v6.1.1] - 2023-11-24
- This is an off-cycle hotfix release for some bugs in v6.1.0 ([see](https://github.com/pulsejet/memories/milestone/19?closed=1)).
- **Breaking**: The CUDA scaler is now the default for NVENC. You may need to reconfigure your transcoder. (see [#582](https://github.com/pulsejet/memories/issues/582))
- This release also cuts down a lot of weirdness and improves the usage of dependencies significantly.
## [v6.1.0] - 2023-11-15
- **Feature**: RAW files are now hidden (stacked) when another file with the same basename exists ([#537](https://github.com/pulsejet/memories/issues/537), [#152](https://github.com/pulsejet/memories/issues/152), [#419](https://github.com/pulsejet/memories/issues/419))
- **Feature**: Multiple files can be now selected and shared from the timeline ([#472](https://github.com/pulsejet/memories/issues/472), [#901](https://github.com/pulsejet/memories/issues/901))
- **Feature**: Bulk rotating of images. You can now rotate images losslessly by editing the rotation EXIF metadata. ([#856](https://github.com/pulsejet/memories/issues/856))
- **Feature**: Icon animation when playing live photos ([#898](https://github.com/pulsejet/memories/issues/898))
- **Feature**: Swipe to refresh on timeline ([#547](https://github.com/pulsejet/memories/issues/547))
- **Bugfix**: Allow switching video to direct on Safari ([#650](https://github.com/pulsejet/memories/issues/650))
- Many other [bug fixes](https://github.com/pulsejet/memories/milestone/18?closed=1)
- Android app is now open source ([see](https://github.com/pulsejet/memories/tree/master/android))
## [v6.0.1] - 2023-10-27
- Bug fixes in video streaming.
## [v6.0.0] - 2023-10-25
- This release focuses on improvements in code quality, maintainability and [documentation](https://memories.gallery/install/).
- New CI/CD [jobs](https://github.com/pulsejet/memories/actions/workflows/static-analysis.yaml) for type checking with [Psalm](https://psalm.dev/) and [vue-tsc](https://www.npmjs.com/package/vue-tsc)
- Vue templates are now checked and largely type-safe
- The backend now has native type coverage with PHP 8 type hints. This unearthed multiple bugs that are now fixed.
- [Developing](https://github.com/pulsejet/memories/#-development-setup) is now easier for new contributors
- **Breaking**: Nextcloud 26+ and PHP 8.0 are now required.
- **Breaking**: The directory containing the `exiftool` and `go-vod` binaries was renamed from `exiftool-bin` to `bin-ext`
- **Feature**: External transcoders are much easier to set up now. See [docs](https://memories.gallery/hw-transcoding) for details.
- **Feature**: Folders view in shares ([#880](https://github.com/pulsejet/memories/pull/880))
- **Feature**: Improved back button navigation on mobile ([#861](https://github.com/pulsejet/memories/issues/861)).
- **Feature**: The transcoding quality factor can now be configured from the admin panel.
## [v5.5.0] - 2023-10-06
- **Important**: This update runs some slow database migrations. It is recommended to upgrade using the CLI (`occ upgrade`) instead of the web interface.
- **Important**: This version corrects some errors in indexing and indexes some new EXIF fields. It is recommended to run `occ memories:index -f` after upgrading.
- **Breaking**: Files in hidden folders are now hidden in the timeline ([#825](https://github.com/pulsejet/memories/issues/825))
- **Feature**: An Android app is now available with early access (https://play.google.com/store/apps/details?id=gallery.memories). Memories v5.5+ is required.
- **Feature**: Support showing full file path in sidebar ([#173](https://github.com/pulsejet/memories/issues/173))
- **Feature**: View file in folder on clicking name in sidebar
- **Feature**: User can leave albums that are shared with them
@ -12,6 +63,8 @@ All notable changes to this project will be documented in this file.
- **Feature**: Shared videos will now be transcoded to be smaller in size
- **Feature**: Confirmation box on deletion ([#798](https://github.com/pulsejet/memories/issues/798))
- **Feature**: Prompt on editing metadata if date will be lost
- **Feature**: Allow changing binary temp directory ([#821](https://github.com/pulsejet/memories/issues/821))
- **Feature**: Support for Samsung HEIC Motion Photos on newer devices
- **Fix**: Support for transcoding MKV files.
## [v5.4.1] - 2023-08-20

View File

@ -1,17 +1,19 @@
all: dev-setup lint build-js-production test
# Dev env management
dev-setup: clean clean-dev npm-init exiftool php-cs-fixer
dev-setup: clean clean-dev npm-init bin-ext install-tools
exiftool:
sh scripts/get-exiftool.sh
bin-ext:
sh scripts/get-bin-ext.sh
php-cs-fixer:
mkdir -p tools/php-cs-fixer
composer require --dev --working-dir=tools/php-cs-fixer friendsofphp/php-cs-fixer
install-tools:
composer install
php-lint:
tools/php-cs-fixer/vendor/bin/php-cs-fixer fix lib
vendor/bin/php-cs-fixer fix
psalm:
vendor/bin/psalm --no-cache
npm-init:
npm ci
@ -19,7 +21,7 @@ npm-init:
npm-update:
npm update
.PHONY: dev-setup exiftool php-cs-fixer php-lint npm-init npm-update
.PHONY: dev-setup bin-ext install-tools php-lint psalm npm-init npm-update
# Building
build-js:
@ -29,8 +31,7 @@ build-js-production:
rm -f js/* && npm run build
patch-external:
patch -p1 -N < patches/scroller-perf.patch || true
patch -p1 -N < patches/scroller-sticky.patch || true
bash scripts/patch-external.sh
watch-js:
npm run watch

View File

@ -8,10 +8,14 @@
[![Nextcloud Store](https://img.shields.io/badge/nextcloud_store-blue?style=for-the-badge)](https://apps.nextcloud.com/apps/memories)
![GitHub](https://img.shields.io/github/license/pulsejet/memories)
[![e2e](https://github.com/pulsejet/memories/actions/workflows/e2e.yaml/badge.svg)](https://github.com/pulsejet/memories/actions/workflows/e2e.yaml)
[![GitHub issues](https://img.shields.io/github/issues/pulsejet/memories)](https://github.com/pulsejet/memories/issues)
[![GitHub Sponsor](https://img.shields.io/github/sponsors/pulsejet?logo=GitHub)](https://github.com/sponsors/pulsejet)
[![e2e](https://github.com/pulsejet/memories/actions/workflows/e2e.yaml/badge.svg)](https://github.com/pulsejet/memories/actions/workflows/e2e.yaml)
[![static analysis](https://github.com/pulsejet/memories/actions/workflows/static-analysis.yaml/badge.svg)](https://github.com/pulsejet/memories/actions/workflows/static-analysis.yaml)
[![Shepherd](https://shepherd.dev/github/pulsejet/memories/coverage.svg)](https://shepherd.dev/github/pulsejet/memories)
[![go-vod](https://github.com/pulsejet/memories/actions/workflows/go-vod.yml/badge.svg)](https://github.com/pulsejet/memories/actions/workflows/go-vod.yml)
Memories is a _batteries-included_ photo management solution for Nextcloud with advanced features
## 🎁 Features
@ -36,19 +40,45 @@ Memories is a _batteries-included_ photo management solution for Nextcloud with
1. Run `php occ memories:index` to generate metadata indices for existing photos.
1. Open the 📷 Memories app in Nextcloud and set the directory containing your photos.
## 📱 Mobile Apps
- An Android client for Memories is available in early access on [Google Play](https://play.google.com/store/apps/details?id=gallery.memories) or [GitHub Releases](https://github.com/pulsejet/memories/releases?q=android).
- For automatic uploads, you can use the official Nextcloud mobile apps.
- Android: [Google Play](https://play.google.com/store/apps/details?id=com.nextcloud.client), [F-Droid](https://f-droid.org/en/packages/com.nextcloud.client/)
- iOS: [App Store](https://apps.apple.com/us/app/nextcloud/id1125420102).
## 🏗 Development Setup
1. ☁ Clone this into your `custom_apps` folder of your Nextcloud.
1. ☁ Clone this monorepo into the `custom_apps` folder of your Nextcloud.
1. 📥 Install [Composer](https://getcomposer.org/) and [Node.js 18](https://nodejs.org)
1. 👩‍💻 In a terminal, run the command `make dev-setup` to install the dependencies.
1. 🏗 To build/watch the UI, run `make watch-js`. Lint-fix PHP with `make php-lint`.
1. 🏗 To build/watch the UI, run `make watch-js`.
1. ✅ Enable the app through the app management of your Nextcloud.
1. ⚒️ (Strongly recommended) use VS Code and install Vetur and Prettier.
1. ⚒️ (Strongly recommended) use VS Code for development and install these extensions (`Ctrl+Shift+P` > `Show Recommended Extensions`).
- [PHP Intelephense](https://marketplace.visualstudio.com/items?itemName=bmewburn.vscode-intelephense-client): For PHP intellisense and static analysis
- [PHP-CS-Fixer](https://marketplace.visualstudio.com/items?itemName=muuvmuuv.vscode-just-php-cs-fixer): For PHP formatting (alternatively, `make php-cs-fixer`)
- [Psalm](https://marketplace.visualstudio.com/items?itemName=getpsalm.psalm-vscode-plugin): For PHP static analysis (alternatively, `make psalm`)
- [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode): For autoformatting Vue and Typescript
- [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar): For Vue intellisense and static analysis
- [Volar Typescript](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin): For Vue Typescript support
This monorepo is organized into the following packages:
- [lib](lib): Backend and database migrations (PHP).
- [src](src): Frontend for all platforms (Vue)
- [go-vod](go-vod): On-demand video transcoder (Go)
- [android](android): Android implemention of NativeX (Kotlin)
- [l10n](l10n): Translations (Transifex)
Releases are organized with these tags:
- `v*`: overall releases (e.g. `v1.0.0` or `v1.0.0-beta.1`)
- `go-vod/*`: transcoder releases (e.g. `go-vod/1.0.0`)
- `android/*`: Android releases (e.g. `android/1.0.0`)
## 🤝 Support the project
1. **🌟 Star this repository**: This is the easiest way to support Memories and costs nothing.
1. **🪲 Report bugs**: Report any bugs you find on the issue tracker.
1. **📖 Translate**: Help translate Memories into your language on [Transifex](https://www.transifex.com/nextcloud/nextcloud/memories/).
1. **📝 Contribute**: Read and file or comment on an issue and ask for guidance.
1. **🪙 Sponsorship**: You can support the project financially at [GitHub Sponsors](https://github.com/sponsors/pulsejet).
@ -66,4 +96,10 @@ For the full changelog, see [CHANGELOG.md](CHANGELOG.md).
## 🙏 Special Thanks
Nextcloud team. A lot of this work is based on [Photos](https://github.com/nextcloud/photos).
To the great folks building Nextcloud, PHP, Vue and all the other dependencies that make this project possible.
Thanks to [GitHub](https://github.com), [CircleCI](https://circleci.com/) and [BrowserStack](https://www.browserstack.com) for sponsorship for Open Source projects for CI / testing on different devices.
## 📄 License
Memories is licensed under the [AGPLv3](COPYING). Subpackages such as [go-vod](go-vod) are licensed under their respective licenses. See the directory of the subpackage for more information.

16
android/.gitignore vendored 100644
View File

@ -0,0 +1,16 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
app/release

3
android/.idea/.gitignore vendored 100644
View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

View File

@ -0,0 +1 @@
Memories

View File

@ -0,0 +1,123 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</codeStyleSettings>
</code_scheme>
</component>

View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
</component>
</project>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<targetSelectedWithDropDown>
<Target>
<type value="QUICK_BOOT_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="C:\Users\varun\.android\avd\Pixel_6_API_33_2.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2023-05-16T08:14:59.213052500Z" />
</component>
</project>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="jbr-17" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.0" />
</component>
</project>

View File

@ -0,0 +1,14 @@
<project version="4">
<component name="EntryPointsManager">
<list size="1">
<item index="0" class="java.lang.String" itemvalue="android.webkit.JavascriptInterface" />
</list>
</component>
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

202
android/LICENSE 100644
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,5 @@
# Memories Android Wrapper
Android implementation of the NativeX interface.
Note that all code under this tree is licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0.html), unlike Memories itself, which is licensed under the AGPLv3 license.

1
android/app/.gitignore vendored 100644
View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,57 @@
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'com.google.devtools.ksp' version '1.9.0-1.0.13'
}
android {
namespace 'gallery.memories'
compileSdk 33
defaultConfig {
applicationId "gallery.memories"
minSdk 27
targetSdk 33
versionCode 6
versionName "1.6"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
buildFeatures {
viewBinding true
}
}
dependencies {
def media_version = "1.1.1"
def room_version = "2.5.2"
implementation 'androidx.core:core-ktx:1.10.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.6.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.6.0'
implementation 'androidx.exifinterface:exifinterface:1.3.6'
implementation "androidx.media3:media3-exoplayer:$media_version"
implementation "androidx.media3:media3-ui:$media_version"
implementation "androidx.media3:media3-exoplayer-hls:$media_version"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
ksp "androidx.room:room-compiler:$room_version"
implementation "com.squareup.okhttp3:okhttp:4.10.0"
implementation "io.github.g00fy2:versioncompare:1.5.0"
}

21
android/app/proguard-rules.pro vendored 100644
View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER" />
<application
android:allowBackup="false"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:hardwareAccelerated="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.Memories"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.Memories.NoActionBar"
android:configChanges="orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".service.DownloadBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
</intent-filter>
</receiver>
</application>
</manifest>

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="47.276897mm" height="12.685879mm" viewBox="0 0 47.276898 12.685879" version="1.1" id="svg5"
sodipodi:docname="memories-title (1).svg" inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview14"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="1.2378992"
inkscape:cx="85.225033"
inkscape:cy="88.456314"
inkscape:window-width="1920"
inkscape:window-height="991"
inkscape:window-x="1911"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg5" />
<defs
id="defs2" />
<g
id="layer1"
transform="translate(-57.784684,-63.463599)"
style="stroke:none;stroke-opacity:1;fill:white;fill-opacity:1">
<g
aria-label="Memories"
id="text1574"
style="font-size:14.1111px;line-height:1.25;font-family:monospace;-inkscape-font-specification:monospace;stroke-width:0.264583;stroke:none;stroke-opacity:1;fill:white;fill-opacity:1">
<path
d="m 67.718898,66.850263 c 0,2.328331 -1.467554,4.797774 -1.467554,7.224883 0,1.41111 0.860777,2.074332 1.622776,2.074332 2.031999,0 3.400776,-4.600219 3.781775,-5.870218 0.07056,-0.211667 -0.02822,-0.282222 -0.268111,-0.282222 -0.197555,0 -0.225777,0.05644 -0.296333,0.239889 -0.634999,1.523999 -2.003776,4.938885 -2.850442,4.938885 -0.211666,0 -0.592666,-0.197556 -0.592666,-1.001888 0,-2.356554 1.439332,-4.23333 1.439332,-7.027328 0,-0.719666 -0.141111,-1.79211 -1.142999,-1.79211 -1.326444,0 -2.906887,1.989665 -3.58422,3.443108 0.225778,-0.917221 0.719667,-2.652886 0.719667,-3.711219 0,-0.973666 -0.409222,-1.622776 -1.030111,-1.622776 -1.693332,0 -3.739441,5.26344 -4.388552,6.646328 0.296333,-1.185333 1.298221,-4.684885 1.298221,-5.602107 0,-0.493888 -0.268111,-0.931333 -0.578555,-0.931333 -0.437444,0 -0.917221,0.917222 -1.312332,2.539998 -0.239889,0.945444 -0.649111,3.005665 -0.917222,4.656664 -0.225777,1.396998 -0.366888,2.046109 -0.366888,2.666997 0,0.381 0.183444,0.437445 0.437444,0.437445 0.310444,0 0.536222,-0.08467 0.747888,-0.282222 0.578555,-0.550333 0.620889,-1.622777 0.917222,-2.483554 0.592666,-1.707443 3.062108,-6.180662 3.612441,-6.180662 0.127,0 0.127,0.239889 0.127,0.282222 0,1.636888 -1.241777,4.628441 -1.241777,6.632217 0,0 0,0.409222 0.352778,0.409222 0.155222,0 0.352777,-0.07055 0.522111,-0.197555 0.338666,-0.254 0.409222,-0.592667 0.606777,-1.086555 0.818444,-2.116665 2.82222,-4.571997 3.59833,-4.571997 0.268111,0 0.254,0.239889 0.254,0.451556 z"
style="font-family:'Lofty Goals';-inkscape-font-specification:'Lofty Goals';stroke:none;stroke-opacity:1;fill:white;fill-opacity:1"
id="path7728" />
<path
d="m 71.980438,73.016813 c 1.396999,0 3.033887,-1.693332 3.033887,-2.808109 0,-0.04233 0,-0.07055 -0.01411,-0.112888 -0.07056,-0.08467 -0.155222,-0.141111 -0.268111,-0.141111 -0.366889,0.578555 -1.53811,2.257776 -2.31422,2.257776 -0.437445,0 -0.620889,-0.550333 -0.620889,-0.917222 v -0.07055 c 0.987777,-0.05644 1.91911,-1.298222 1.91911,-2.243665 0,-0.550333 -0.296333,-0.860777 -0.860777,-0.860777 -1.523999,0 -2.314221,1.93322 -2.314221,3.217331 0,0.705555 0.578555,1.67922 1.439332,1.67922 z m 1.030111,-3.880552 c 0,0.395111 -0.719666,1.495777 -1.15711,1.523999 0.02822,-0.381 0.52211,-1.834443 1.001888,-1.834443 0.155222,0 0.155222,0.211666 0.155222,0.310444 z"
style="font-family:'Lofty Goals';-inkscape-font-specification:'Lofty Goals';stroke:none;stroke-opacity:1;fill:white;fill-opacity:1"
id="path7730" />
<path
d="m 75.804523,67.301818 c -1.128888,0 -1.467555,3.838219 -1.467555,4.727218 0,0.352778 0.02822,0.987777 0.508,0.987777 0.790222,0 1.213555,-0.733777 1.425221,-1.396998 0.169333,-0.550333 1.086555,-3.612442 1.552221,-3.668887 0.127,0.197556 0.127,0.635 0.127,0.874889 0,0.888999 -0.08467,1.763887 -0.08467,2.652887 0,0.324555 -0.01411,1.015999 0.465666,1.015999 0.705555,0 1.890887,-3.824108 2.511776,-3.922886 0.07055,0.183444 0.08467,0.366888 0.08467,0.550333 0,1.058332 -0.296333,2.074332 -0.296333,3.132664 0,0.465666 0.05644,1.368777 0.705555,1.368777 0.606777,0 2.610554,-2.892776 2.69522,-3.527775 -0.05644,-0.08467 -0.169333,-0.141111 -0.268111,-0.141111 -0.197555,0 -1.665109,2.342442 -2.046109,2.398887 -0.04233,-0.02822 -0.05644,-0.08467 -0.05644,-0.112889 0,-0.381 0.155223,-0.818444 0.239889,-1.199444 0.169333,-0.761999 0.338667,-1.552221 0.338667,-2.342442 0,-0.508 -0.254,-1.255888 -0.874889,-1.255888 -1.100665,0 -2.017887,1.947332 -2.427109,2.793998 0.01411,-0.578555 0.112889,-1.157111 0.112889,-1.749777 0,-0.564444 -0.05644,-1.66511 -0.846666,-1.66511 -1.171221,0 -2.158998,2.920998 -2.539998,3.83822 0.08467,-0.931333 0.508,-1.820332 0.508,-2.765776 0,-0.282222 0.01411,-0.592666 -0.366889,-0.592666 z"
style="font-family:'Lofty Goals';-inkscape-font-specification:'Lofty Goals';stroke:none;stroke-opacity:1;fill:white;fill-opacity:1"
id="path7732" />
<path
d="m 84.652174,74.046924 c 1.058333,0 1.975554,-1.086555 2.384776,-2.412998 0.860777,-0.09878 2.04611,-0.959555 2.04611,-1.495777 0,-0.127 -0.07056,-0.254 -0.169334,-0.282222 -0.437444,0.352777 -1.199443,0.776111 -1.679221,0.90311 0.02822,-0.183444 0.02822,-0.366888 0.02822,-0.550333 0,-1.396998 -0.747889,-2.652886 -1.594555,-2.652886 -0.691444,0 -1.467554,0.832555 -1.467554,1.566332 0,0.02822 0,0.07055 0,0.09878 -0.691444,0.564444 -1.086555,1.495777 -1.086555,2.539999 0,1.326443 0.649111,2.285998 1.53811,2.285998 z m 1.749777,-3.443109 c -0.606778,-0.338666 -1.284111,-1.044221 -1.284111,-1.467554 0,-0.254 0.268111,-0.550333 0.522111,-0.550333 0.409222,0 0.776111,0.804333 0.776111,1.693332 0,0.112889 0,0.211667 -0.01411,0.324555 z m -0.155223,0.917222 c -0.239888,0.90311 -0.691443,1.679221 -1.227665,1.679221 -0.381,0 -0.733777,-0.620889 -0.733777,-1.298221 0,-0.536222 0.225777,-1.213555 0.465666,-1.523999 0.395111,0.493888 0.959555,0.931332 1.495776,1.142999 z"
style="font-family:'Lofty Goals';-inkscape-font-specification:'Lofty Goals';stroke:none;stroke-opacity:1;fill:white;fill-opacity:1"
id="path7734" />
<path
d="m 89.986155,74.752479 c 1.001888,0 3.570108,-3.697108 3.640664,-4.656663 0.01411,-0.155222 -0.155222,-0.141111 -0.268111,-0.141111 -0.254,0.395111 -2.300109,3.485441 -2.737553,3.485441 -0.09878,0 -0.08467,-0.141111 -0.08467,-0.211666 0.07056,-0.790222 0.705555,-1.594554 0.776111,-2.427109 0.08467,-0.874889 -0.606778,-0.889 -1.312333,-1.128888 0.338667,-0.310445 0.649111,-0.917222 0.691444,-1.354666 0.04233,-0.522111 -0.268111,-1.326443 -0.874888,-1.326443 -1.001888,0 -1.368777,1.015999 -1.439332,1.834443 -0.112889,1.41111 0.931332,1.509887 1.961443,1.834443 -0.01411,0.239888 -0.352778,0.945443 -0.465667,1.227665 -0.225777,0.606778 -0.451555,1.241777 -0.507999,1.876777 -0.04233,0.507999 0.01411,0.987777 0.620888,0.987777 z m -0.155222,-6.349995 c -0.02822,0.282222 -0.169333,0.931332 -0.381,1.128888 -0.211666,-0.112889 -0.239888,-0.479778 -0.225777,-0.705555 0.02822,-0.183445 0.112889,-0.959555 0.395111,-0.959555 0.197555,0 0.225777,0.395111 0.211666,0.536222 z"
style="font-family:'Lofty Goals';-inkscape-font-specification:'Lofty Goals';stroke:none;stroke-opacity:1;fill:white;fill-opacity:1"
id="path7736" />
<path
d="m 94.473479,67.555818 c 0.479778,0 0.719666,-0.550333 0.719666,-0.959555 0,-0.282222 -0.09878,-0.649111 -0.451555,-0.649111 -0.578555,0 -0.804332,0.508 -0.804332,0.945444 0,0.296333 0.211666,0.663222 0.536221,0.663222 z m -0.550333,5.64444 c 0.860778,0 2.568221,-2.328332 2.568221,-3.033887 0,-0.127 -0.02822,-0.211666 -0.169334,-0.211666 -0.52211,0 -1.636887,2.257776 -2.031998,2.257776 -0.211666,0 -0.225778,-0.324556 -0.225778,-0.465667 0,-1.721554 0.677333,-2.356553 0.677333,-2.977442 0,-0.366888 -0.211666,-0.451555 -0.550333,-0.451555 -0.733777,0 -1.213554,1.834443 -1.213554,3.033887 0,0.592666 0.141111,1.848554 0.945443,1.848554 z"
style="font-family:'Lofty Goals';-inkscape-font-specification:'Lofty Goals';stroke:none;stroke-opacity:1;fill:white;fill-opacity:1"
id="path7738" />
<path
d="m 97.098125,73.016813 c 1.396999,0 3.033885,-1.693332 3.033885,-2.808109 0,-0.04233 0,-0.07055 -0.0141,-0.112888 -0.0706,-0.08467 -0.155222,-0.141111 -0.268111,-0.141111 -0.366888,0.578555 -1.53811,2.257776 -2.31422,2.257776 -0.437444,0 -0.620889,-0.550333 -0.620889,-0.917222 v -0.07055 c 0.987777,-0.05644 1.91911,-1.298222 1.91911,-2.243665 0,-0.550333 -0.296333,-0.860777 -0.860777,-0.860777 -1.523999,0 -2.31422,1.93322 -2.31422,3.217331 0,0.705555 0.578555,1.67922 1.439332,1.67922 z m 1.03011,-3.880552 c 0,0.395111 -0.719666,1.495777 -1.15711,1.523999 0.02822,-0.381 0.522111,-1.834443 1.001888,-1.834443 0.155222,0 0.155222,0.211666 0.155222,0.310444 z"
style="font-family:'Lofty Goals';-inkscape-font-specification:'Lofty Goals';stroke:none;stroke-opacity:1;fill:white;fill-opacity:1"
id="path7740" />
<path
d="m 101.00688,72.043148 c -0.95956,0.733777 -1.693333,1.580443 -1.693333,2.328331 0,0.832555 0.634999,1.439332 1.453443,1.439332 1.27,0 2.65289,-1.213554 2.65289,-2.356553 0,-0.776111 -0.31045,-1.298222 -0.73378,-1.693332 0.94544,-0.578556 1.905,-1.100666 2.37066,-1.523999 0.0282,-0.141111 -0.0705,-0.296333 -0.21166,-0.268111 -0.52211,0.127 -1.651,0.634999 -2.75167,1.326443 -0.67733,-0.465666 -1.35466,-0.77611 -1.35466,-1.382888 0,-0.592666 0.60678,-1.707443 1.28411,-1.707443 0.32455,0 0.55033,0.197556 0.55033,0.592666 0,0.324556 -0.16933,0.620889 -0.16933,0.945444 0,0.183444 0.11289,0.324555 0.29633,0.324555 0.508,0 0.80433,-0.64911 0.80433,-1.072443 0,-0.973666 -0.52211,-1.495777 -1.49577,-1.495777 -1.43934,0 -2.441224,1.185333 -2.441224,2.582332 0,1.086554 0.719664,1.566332 1.439334,1.961443 z m -0.69145,2.116665 c 0,-0.578556 0.59267,-1.171222 1.36878,-1.735666 0.42333,0.268111 0.74789,0.578555 0.74789,1.100666 0,0.522111 -0.74789,1.326443 -1.397,1.326443 -0.42333,0 -0.71967,-0.324555 -0.71967,-0.691443 z"
style="font-family:'Lofty Goals';-inkscape-font-specification:'Lofty Goals';stroke:none;stroke-opacity:1;fill:white;fill-opacity:1"
id="path7742" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,107 @@
:root {
--theme-color: #2b94f0;
--fg-color: white;
}
body {
margin: 0;
padding: 0;
background-color: var(--theme-color);
color: var(--fg-color);
overflow: hidden;
font-family: sans-serif;
}
* {
user-select: none;
-webkit-user-select: none;
-webkit-touch-callout: none;
-webkit-tap-highlight-color: transparent;
}
.container {
width: 90vw;
max-width: 800px;
margin: 40px auto;
text-align: center;
}
.animatable {
transition: opacity 0.7s ease-in-out, transform 0.7s ease-in-out;
}
.invisible {
transform: translateY(10px);
opacity: 0;
}
p,
div.p {
color: white;
margin-bottom: 30px;
line-height: 1.5em;
}
.logo {
color: var(--fg-color);
margin-bottom: 30px;
width: 60vw;
max-width: 400px;
}
input.m-input {
width: 80vw;
max-width: 800px;
padding: 10px 12px;
font-size: 16px;
border: 1px solid #ccc;
border-radius: 10px;
background-color: #f9f9f9;
color: #333;
outline: none;
transition: border-color 0.3s ease-in-out;
}
input.m-input:focus {
border-color: #0096ff;
box-shadow: 0 0 4px var(--theme-color);
}
.m-button {
display: inline-block;
padding: 10px 20px;
font-size: 16px;
font-weight: bold;
color: var(--theme-color);
background-color: var(--fg-color);
border: none;
border-radius: 20px;
cursor: pointer;
text-decoration: none;
transition: background-color 0.3s ease-in-out;
}
.m-button:disabled {
background-color: #eee;
color: #aaa;
cursor: not-allowed;
}
.m-button.link {
background-color: unset;
color: var(--fg-color);
}
.login-button {
margin: 10px;
margin-top: 12px;
}
div.trust {
margin-top: 10px;
}
input[type="checkbox"] {
width: 1.5em;
height: 1.5em;
vertical-align: -3px;
}

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Memories</title>
<link rel="stylesheet" href="styles.css" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<div id="main" class="container">
<img src="memories.svg" alt="Memories Logo" class="logo" />
<p id="waiting">
Waiting for login to complete <br />
Keep this page open in the background
</p>
</div>
</body>
</html>

View File

@ -0,0 +1,136 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Memories</title>
<link rel="stylesheet" href="styles.css" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<div id="main" class="container animatable invisible">
<img src="memories.svg" alt="Memories Logo" class="logo" />
<p>
Start organizing and sharing your precious moments. Enter the address of
your Nextcloud server to begin.
</p>
<input
type="url"
id="server-url"
class="m-input"
placeholder="nextcloud.example.com"
/>
<div class="trust">
<label for="trust-all">
<input
type="checkbox"
id="trust-all"
class="m-checkbox"
/>
Disable certificate verification (unsafe)
</label>
</div>
<button class="m-button login-button" id="login">
Continue to Login
</button>
<br />
<a class="m-button link" href="https://memories.gallery/install/">
I don't have a server
</a>
</div>
<script>
const urlBox = document.getElementById("server-url");
const loginButton = document.getElementById("login");
function validateUrl(url) {
try {
url = new URL(url);
const protoOk = url.protocol === "http:" || url.protocol === "https:";
const hostOk = url.hostname.length > 0;
return protoOk && hostOk;
} catch (e) {
return false;
}
}
function getUrl() {
const url = urlBox.value.toLowerCase();
if (!url.startsWith("http://") && !url.startsWith("https://")) {
return "https://" + url;
}
return url;
}
function updateLoginEnabled() {
loginButton.disabled = !validateUrl(getUrl());
}
function getMemoriesUrl() {
const url = new URL(getUrl());
// Add trailing slash to the path if it's not there already
if (!url.pathname.endsWith("/")) {
url.pathname += "/";
}
// Add index.php to the path if it's not there already
if (!url.pathname.includes("index.php")) {
url.pathname += "index.php/";
}
// Add path to memories
url.pathname += "apps/memories/";
return url;
}
// Update login button enabled state when the URL changes
urlBox.addEventListener("input", updateLoginEnabled);
updateLoginEnabled();
// Login button click handler
loginButton.addEventListener("click", async () => {
try {
urlBox.disabled = true;
loginButton.disabled = true;
// Abort request after 5 seconds
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
// Login signal
const encUrl = encodeURIComponent(encodeURIComponent(getMemoriesUrl().toString()));
// Trust all certificates
const trustAll = document.getElementById("trust-all").checked ? "1" : "0";
await fetch(`http://127.0.0.1/api/login/${encUrl}?trustAll=${trustAll}`, {
method: "GET",
signal: controller.signal,
});
// API is fine, redirect to login page
clearTimeout(timeoutId);
} catch (e) {
// unreachable?
} finally {
urlBox.disabled = false;
loginButton.disabled = false;
}
});
// Set action bar color
const themeColor = getComputedStyle(
document.documentElement
).getPropertyValue("--theme-color");
globalThis.nativex?.setThemeColor(themeColor, true);
// Make container visible
document.getElementById("main").classList.remove("invisible");
</script>
</body>
</html>

View File

@ -0,0 +1,442 @@
package gallery.memories
import android.annotation.SuppressLint
import android.content.Intent
import android.content.res.Configuration
import android.graphics.Color
import android.net.Uri
import android.net.http.SslError
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.KeyEvent
import android.view.View
import android.view.WindowInsets
import android.view.WindowInsetsController
import android.view.WindowManager
import android.webkit.CookieManager
import android.webkit.SslErrorHandler
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Lifecycle
import androidx.media3.common.MediaItem
import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import androidx.media3.datasource.DefaultDataSource
import androidx.media3.datasource.DefaultHttpDataSource
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.hls.HlsMediaSource
import androidx.media3.exoplayer.source.ProgressiveMediaSource
import gallery.memories.databinding.ActivityMainBinding
import java.util.concurrent.Executors
@UnstableApi
class MainActivity : AppCompatActivity() {
companion object {
val TAG = MainActivity::class.java.simpleName
}
val binding by lazy(LazyThreadSafetyMode.NONE) {
ActivityMainBinding.inflate(layoutInflater)
}
val threadPool = Executors.newFixedThreadPool(4)
private lateinit var nativex: NativeX
private var player: ExoPlayer? = null
private var playerUris: Array<Uri>? = null
private var playerUid: Long? = null
private var playWhenReady = true
private var mediaItemIndex = 0
private var playbackPosition = 0L
private var mNeedRefresh = false
private val memoriesRegex = Regex("/apps/memories/.*$")
private var host: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
// Restore last known look
restoreTheme()
// Initialize services
nativex = NativeX(this)
// Sync if permission is available
nativex.doMediaSync(false)
// Load JavaScript
initializeWebView()
// Destroy video after 1 seconds (workaround for video not showing on first load)
binding.videoView.postDelayed({
binding.videoView.alpha = 1.0f
binding.videoView.visibility = View.GONE
}, 1000)
}
override fun onDestroy() {
super.onDestroy()
binding.webview.removeAllViews();
binding.coordinator.removeAllViews()
binding.webview.destroy();
nativex.destroy()
}
override fun onConfigurationChanged(config: Configuration) {
super.onConfigurationChanged(config)
// Hide the status bar in landscape
setFullscreen(config.orientation == Configuration.ORIENTATION_LANDSCAPE)
}
public override fun onResume() {
super.onResume()
if (playerUris != null && player == null) {
initializePlayer(playerUris!!, playerUid!!)
}
if (mNeedRefresh) {
refreshTimeline(true)
}
}
public override fun onPause() {
super.onPause()
}
public override fun onStop() {
super.onStop()
releasePlayer()
}
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
when (keyCode) {
KeyEvent.KEYCODE_BACK -> {
if (binding.webview.canGoBack()) {
binding.webview.goBack()
} else {
finish()
}
return true
}
}
}
return super.onKeyDown(keyCode, event)
}
@SuppressLint("SetJavaScriptEnabled", "ClickableViewAccessibility")
private fun initializeWebView() {
// Intercept local APIs
binding.webview.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(
view: WebView,
request: WebResourceRequest
): Boolean {
val pathMatches = request.url.path?.matches(memoriesRegex) == true
val hostMatches = request.url.host.equals(host)
if (pathMatches && hostMatches) {
return false
}
// Open external links in browser
Intent(Intent.ACTION_VIEW, request.url).apply { startActivity(this) }
return true
}
override fun shouldInterceptRequest(
view: WebView,
request: WebResourceRequest
): WebResourceResponse? {
return if (request.url.host == "127.0.0.1") {
nativex.handleRequest(request)
} else null
}
override fun onReceivedSslError(
view: WebView?,
handler: SslErrorHandler?,
error: SslError?
) {
if (nativex.http.isTrustingAllCertificates) {
handler?.proceed()
} else {
nativex.toast("Failed to load due to SSL error: ${error?.primaryError}", true)
super.onReceivedSslError(view, handler, error)
}
}
}
// Pass through touch events
binding.webview.setOnTouchListener { _, event ->
if (player != null) {
binding.videoView.dispatchTouchEvent(event)
}
false
}
val userAgent =
getString(R.string.ua_app_prefix) + BuildConfig.VERSION_NAME + " " + getString(R.string.ua_chrome)
val webSettings = binding.webview.settings
webSettings.javaScriptEnabled = true
webSettings.javaScriptCanOpenWindowsAutomatically = true
webSettings.allowContentAccess = true
webSettings.domStorageEnabled = true
webSettings.databaseEnabled = true
webSettings.userAgentString = userAgent
webSettings.setSupportZoom(false)
webSettings.builtInZoomControls = false
webSettings.displayZoomControls = false
binding.webview.addJavascriptInterface(nativex, "nativex")
binding.webview.setLayerType(View.LAYER_TYPE_HARDWARE, null)
binding.webview.setBackgroundColor(Color.TRANSPARENT)
// binding.webview.clearCache(true)
// WebView.setWebContentsDebuggingEnabled(true);
// Welcome page or actual app
nativex.account.refreshCredentials()
val isApp = loadDefaultUrl()
// Start version check if loaded account
if (isApp) {
// Do not use the threadPool here since this might block indefinitely
Thread { nativex.account.checkCredentialsAndVersion() }.start()
}
}
fun loadDefaultUrl(): Boolean {
// Load app interface if authenticated
host = nativex.http.loadWebView(binding.webview)
if (host != null) return true
// Load welcome page
binding.webview.loadUrl("file:///android_asset/welcome.html");
return false
}
fun initializePlayer(uris: Array<Uri>, uid: Long) {
if (player != null) {
if (playerUid == uid) return
player?.release()
player = null
}
// Prevent re-creating
playerUris = uris
playerUid = uid
// Build exoplayer
player = ExoPlayer.Builder(this)
.build()
.also { exoPlayer ->
// Bind to player view
binding.videoView.player = exoPlayer
binding.videoView.visibility = View.VISIBLE
binding.videoView.setShowNextButton(false)
binding.videoView.setShowPreviousButton(false)
for (uri in uris) {
// Create media item from URI
val mediaItem = MediaItem.fromUri(uri)
// Check if remote or local URI
if (uri.toString().contains("http")) {
// Add cookies from webview to data source
val cookies = CookieManager.getInstance().getCookie(uri.toString())
val httpDataSourceFactory =
DefaultHttpDataSource.Factory()
.setDefaultRequestProperties(mapOf("cookie" to cookies))
.setAllowCrossProtocolRedirects(true)
val dataSourceFactory =
DefaultDataSource.Factory(this, httpDataSourceFactory)
// Check if HLS source from URI (contains .m3u8 anywhere)
exoPlayer.addMediaSource(
if (uri.toString().contains(".m3u8")) {
HlsMediaSource.Factory(dataSourceFactory)
.createMediaSource(mediaItem)
} else {
ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(mediaItem)
}
)
} else {
exoPlayer.setMediaItems(listOf(mediaItem), mediaItemIndex, playbackPosition)
}
}
// Catch errors and fall back to other sources
exoPlayer.addListener(object : Player.Listener {
override fun onPlayerError(error: PlaybackException) {
exoPlayer.seekToNext()
exoPlayer.playWhenReady = true
exoPlayer.play()
}
})
// Start the player
exoPlayer.playWhenReady = playWhenReady
exoPlayer.prepare()
}
}
fun destroyPlayer(uid: Long) {
if (playerUid == uid) {
releasePlayer()
// Reset vars
playWhenReady = true
mediaItemIndex = 0
playbackPosition = 0L
playerUris = null
playerUid = null
}
}
private fun releasePlayer() {
player?.let { exoPlayer ->
playbackPosition = exoPlayer.currentPosition
mediaItemIndex = exoPlayer.currentMediaItemIndex
playWhenReady = exoPlayer.playWhenReady
exoPlayer.release()
}
player = null
binding.videoView.visibility = View.GONE
}
/**
* Make the app fullscreen.
*/
private fun setFullscreen(value: Boolean) {
if (value) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
window.attributes.layoutInDisplayCutoutMode =
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
window.insetsController?.apply {
hide(WindowInsets.Type.statusBars())
systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
} else {
@Suppress("Deprecation")
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_FULLSCREEN
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_IMMERSIVE
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
window.attributes.layoutInDisplayCutoutMode =
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
window.insetsController?.apply {
show(WindowInsets.Type.statusBars())
}
} else {
@Suppress("Deprecation")
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
}
}
}
/**
* Store a given theme for restoreTheme.
*/
fun storeTheme(color: String?, isDark: Boolean) {
if (color == null) return
getSharedPreferences(getString(R.string.preferences_key), 0).edit()
.putString(getString(R.string.preferences_theme_color), color)
.putBoolean(getString(R.string.preferences_theme_dark), isDark)
.apply()
}
/**
* Restore the last known theme color.
*/
fun restoreTheme() {
val preferences = getSharedPreferences(getString(R.string.preferences_key), 0)
val color = preferences.getString(getString(R.string.preferences_theme_color), null)
val isDark = preferences.getBoolean(getString(R.string.preferences_theme_dark), false)
applyTheme(color, isDark)
}
/**
* Apply a color theme.
*/
fun applyTheme(color: String?, isDark: Boolean) {
if (color == null) return
// Set system bars
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val appearance =
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS or WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
window.insetsController?.setSystemBarsAppearance(
if (isDark) 0 else appearance,
appearance
)
} else {
window.decorView.systemUiVisibility =
if (isDark) 0 else View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
}
// Set colors
try {
val parsed = Color.parseColor(color.trim())
window.navigationBarColor = parsed
window.statusBarColor = parsed
} catch (e: Exception) {
Log.w(TAG, "Invalid color: $color")
return
}
}
/**
* Do a soft refresh on the open timeline
*/
fun refreshTimeline(force: Boolean = false) {
runOnUiThread {
// Check webview is loaded
if (binding.webview.url == null) return@runOnUiThread
// Schedule for resume if not active
if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED) || force) {
mNeedRefresh = false
busEmit("nativex:db:updated")
busEmit("memories:timeline:soft-refresh")
} else {
mNeedRefresh = true
}
}
}
/**
* Emit an event to the nextcloud event bus
*/
fun busEmit(event: String, data: String = "null") {
runOnUiThread {
if (binding.webview.url == null) return@runOnUiThread
binding.webview.evaluateJavascript(
"window._nc_event_bus?.emit('$event', $data)",
null
)
}
}
}

View File

@ -0,0 +1,311 @@
package gallery.memories
import android.net.Uri
import android.util.Log
import android.view.SoundEffectConstants
import android.webkit.JavascriptInterface
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.widget.Toast
import androidx.media3.common.util.UnstableApi
import gallery.memories.service.AccountService
import gallery.memories.service.DownloadService
import gallery.memories.service.HttpService
import gallery.memories.service.ImageService
import gallery.memories.service.PermissionsService
import gallery.memories.service.TimelineQuery
import org.json.JSONArray
import java.io.ByteArrayInputStream
import java.net.URLDecoder
@UnstableApi
class NativeX(private val mCtx: MainActivity) {
val TAG = NativeX::class.java.simpleName
private var themeStored = false
val query = TimelineQuery(mCtx)
val image = ImageService(mCtx, query)
val http = HttpService()
val account = AccountService(mCtx, http)
val permissions = PermissionsService(mCtx).register()
init {
dlService = DownloadService(mCtx, query)
}
companion object {
var dlService: DownloadService? = null
}
fun destroy() {
dlService = null
query.destroy()
}
object API {
val LOGIN = Regex("^/api/login/.+$")
val DAYS = Regex("^/api/days$")
val DAY = Regex("^/api/days/\\d+$")
val IMAGE_INFO = Regex("^/api/image/info/\\d+$")
val IMAGE_DELETE = Regex("^/api/image/delete/[0-9a-f]+(,[0-9a-f]+)*$")
val IMAGE_PREVIEW = Regex("^/image/preview/\\d+$")
val IMAGE_FULL = Regex("^/image/full/[0-9a-f]+$")
val SHARE_URL = Regex("^/api/share/url/.+$")
val SHARE_BLOB = Regex("^/api/share/blobs$")
val CONFIG_ALLOW_MEDIA = Regex("^/api/config/allow_media/\\d+$")
}
@JavascriptInterface
fun isNative(): Boolean {
return true
}
@JavascriptInterface
fun setThemeColor(color: String?, isDark: Boolean) {
// Save for getting it back on next start
if (!themeStored && http.isLoggedIn()) {
themeStored = true
mCtx.storeTheme(color, isDark);
}
// Apply the theme
mCtx.runOnUiThread {
mCtx.applyTheme(color, isDark)
}
}
@JavascriptInterface
fun playTouchSound() {
mCtx.runOnUiThread {
mCtx.binding.webview.playSoundEffect(SoundEffectConstants.CLICK)
}
}
@JavascriptInterface
fun toast(message: String, long: Boolean = false) {
mCtx.runOnUiThread {
val duration = if (long) Toast.LENGTH_LONG else Toast.LENGTH_SHORT
Toast.makeText(mCtx, message, duration).show()
}
}
@JavascriptInterface
fun logout() {
account.loggedOut()
}
@JavascriptInterface
fun reload() {
mCtx.runOnUiThread {
mCtx.loadDefaultUrl()
}
}
@JavascriptInterface
fun downloadFromUrl(url: String?, filename: String?) {
if (url == null || filename == null) return;
dlService!!.queue(url, filename)
}
@JavascriptInterface
fun setShareBlobs(objects: String?) {
if (objects == null) return;
dlService!!.setShareBlobs(JSONArray(objects))
}
@JavascriptInterface
fun playVideo(auid: String, fileid: Long, urlsArray: String) {
mCtx.threadPool.submit {
// Get URI of remote videos
val urls = JSONArray(urlsArray)
val list = Array(urls.length()) {
Uri.parse(urls.getString(it))
}
// Get URI of local video
val videos = query.getSystemImagesByAUIDs(arrayListOf(auid))
// Play with exoplayer
mCtx.runOnUiThread {
if (!videos.isEmpty()) {
mCtx.initializePlayer(arrayOf(videos[0].uri), fileid)
} else {
mCtx.initializePlayer(list, fileid)
}
}
}
}
@JavascriptInterface
fun destroyVideo(fileid: Long) {
mCtx.runOnUiThread {
mCtx.destroyPlayer(fileid)
}
}
@JavascriptInterface
fun configSetLocalFolders(json: String?) {
if (json == null) return;
query.localFolders = JSONArray(json)
}
@JavascriptInterface
fun configGetLocalFolders(): String {
return query.localFolders.toString()
}
@JavascriptInterface
fun configHasMediaPermission(): Boolean {
return permissions.hasAllowMedia() && permissions.hasMediaPermission()
}
@JavascriptInterface
fun getSyncStatus(): Int {
return query.syncStatus
}
@JavascriptInterface
fun setHasRemote(auids: String, buids: String, value: Boolean) {
Log.v(TAG, "setHasRemote: auids=$auids, buids=$buids, value=$value")
mCtx.threadPool.submit {
val auidArray = JSONArray(auids)
val buidArray = JSONArray(buids)
query.setHasRemote(
List(auidArray.length()) { auidArray.getString(it) },
List(buidArray.length()) { buidArray.getString(it) },
value
)
}
}
fun handleRequest(request: WebResourceRequest): WebResourceResponse {
val path = request.url.path ?: return makeErrorResponse()
val response = try {
when (request.method) {
"GET" -> {
routerGet(request)
}
"OPTIONS" -> {
WebResourceResponse(
"text/plain",
"UTF-8",
ByteArrayInputStream("".toByteArray())
)
}
else -> {
throw Exception("Method Not Allowed")
}
}
} catch (e: Exception) {
Log.w(TAG, "handleRequest: " + e.message)
makeErrorResponse()
}
// Allow CORS from all origins
response.responseHeaders = mutableMapOf(
"Access-Control-Allow-Origin" to "*",
"Access-Control-Allow-Headers" to "*"
)
// Cache image responses for 7 days
if (path.matches(API.IMAGE_PREVIEW) || path.matches(API.IMAGE_FULL)) {
response.responseHeaders["Cache-Control"] = "max-age=604800"
}
return response
}
@Throws(Exception::class)
private fun routerGet(request: WebResourceRequest): WebResourceResponse {
val path = request.url.path ?: return makeErrorResponse()
val parts = path.split("/").toTypedArray()
return if (path.matches(API.LOGIN)) {
makeResponse(
account.login(
URLDecoder.decode(parts[3], "UTF-8"),
request.url.getBooleanQueryParameter("trustAll", false)
)
)
} else if (path.matches(API.DAYS)) {
makeResponse(query.getDays())
} else if (path.matches(API.DAY)) {
makeResponse(query.getDay(parts[3].toLong()))
} else if (path.matches(API.IMAGE_INFO)) {
makeResponse(query.getImageInfo(parts[4].toLong()))
} else if (path.matches(API.IMAGE_DELETE)) {
makeResponse(
query.delete(
parseIds(parts[4]),
request.url.getBooleanQueryParameter("dry", false)
)
)
} else if (path.matches(API.IMAGE_PREVIEW)) {
makeResponse(image.getPreview(parts[3].toLong()), "image/jpeg")
} else if (path.matches(API.IMAGE_FULL)) {
makeResponse(image.getFull(parts[3]), "image/jpeg")
} else if (path.matches(API.SHARE_URL)) {
makeResponse(dlService!!.shareUrl(URLDecoder.decode(parts[4], "UTF-8")))
} else if (path.matches(API.SHARE_BLOB)) {
makeResponse(dlService!!.shareBlobs())
} else if (path.matches(API.CONFIG_ALLOW_MEDIA)) {
permissions.setAllowMedia(true)
if (permissions.requestMediaPermissionSync()) {
doMediaSync(true) // separate thread
}
makeResponse("done")
} else {
throw Exception("Path did not match any known API route: $path")
}
}
private fun makeResponse(bytes: ByteArray?, mimeType: String?): WebResourceResponse {
return if (bytes != null) {
WebResourceResponse(mimeType, "UTF-8", ByteArrayInputStream(bytes))
} else makeErrorResponse()
}
private fun makeResponse(json: Any): WebResourceResponse {
return makeResponse(json.toString().toByteArray(), "application/json")
}
private fun makeErrorResponse(): WebResourceResponse {
val response = WebResourceResponse(
"application/json",
"UTF-8",
ByteArrayInputStream("{}".toByteArray())
)
response.setStatusCodeAndReasonPhrase(500, "Internal Server Error")
return response
}
private fun parseIds(ids: String): List<String> {
return ids.trim().split(",")
}
fun doMediaSync(forceFull: Boolean) {
if (permissions.hasAllowMedia()) {
// Full sync if this is the first time permission was granted
val fullSync = forceFull || !permissions.hasMediaPermission()
mCtx.threadPool.submit {
// Block for media permission
if (!permissions.requestMediaPermissionSync()) return@submit
// Full sync requested
if (fullSync) query.syncFullDb()
// Run delta sync and register hooks
query.initialize()
}
}
}
}

View File

@ -0,0 +1,49 @@
package gallery.memories.dao
import android.content.Context
import androidx.room.Database
import androidx.room.Room.databaseBuilder
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import gallery.memories.R
import gallery.memories.mapper.Photo
@Database(entities = [Photo::class], version = 34)
abstract class AppDatabase : RoomDatabase() {
abstract fun photoDao(): PhotoDao
companion object {
private val DATABASE_NAME = "memories_room"
@Volatile
private var INSTANCE: AppDatabase? = null
fun get(context: Context): AppDatabase {
if (INSTANCE == null) {
synchronized(AppDatabase::class.java) {
val ctx = context.applicationContext
if (INSTANCE == null) {
INSTANCE = databaseBuilder(ctx, AppDatabase::class.java, DATABASE_NAME)
.fallbackToDestructiveMigration()
.addCallback(callbacks(ctx))
.build()
}
}
}
return INSTANCE!!
}
private fun callbacks(ctx: Context): Callback {
return object : Callback() {
override fun onDestructiveMigration(db: SupportSQLiteDatabase) {
super.onDestructiveMigration(db)
// retrigger synchronization whenever database is destructed
ctx.getSharedPreferences(ctx.getString(R.string.preferences_key), 0).edit()
.remove(ctx.getString(R.string.preferences_last_sync_time))
.apply()
}
}
}
}
}

View File

@ -0,0 +1,47 @@
package gallery.memories.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import gallery.memories.mapper.Bucket
import gallery.memories.mapper.Day
import gallery.memories.mapper.Photo
@Dao
interface PhotoDao {
@Query("SELECT 1")
fun ping(): Int
@Query("SELECT dayid, COUNT(local_id) AS count FROM photos WHERE bucket_id IN (:bucketIds) AND has_remote = 0 GROUP BY dayid ORDER BY dayid DESC")
fun getDays(bucketIds: List<String>): List<Day>
@Query("SELECT * FROM photos WHERE dayid=:dayId AND bucket_id IN (:buckets) AND has_remote = 0 ORDER BY date_taken DESC")
fun getPhotosByDay(dayId: Long, buckets: List<String>): List<Photo>
@Query("DELETE FROM photos WHERE local_id IN (:fileIds)")
fun deleteFileIds(fileIds: List<Long>)
@Query("SELECT * FROM photos WHERE local_id IN (:fileIds)")
fun getPhotosByFileIds(fileIds: List<Long>): List<Photo>
@Query("SELECT * FROM photos WHERE auid IN (:auids)")
fun getPhotosByAUIDs(auids: List<String>): List<Photo>
@Query("UPDATE photos SET flag=1")
fun flagAll()
@Query("UPDATE photos SET flag=0 WHERE local_id=:fileId")
fun unflag(fileId: Long)
@Query("DELETE FROM photos WHERE flag=1")
fun deleteFlagged()
@Insert
fun insert(vararg photos: Photo)
@Query("SELECT bucket_id, bucket_name FROM photos GROUP BY bucket_id")
fun getBuckets(): List<Bucket>
@Query("UPDATE photos SET has_remote=:v WHERE auid IN (:auids) OR buid IN (:buids)")
fun setHasRemote(auids: List<String>, buids: List<String>, v: Boolean)
}

View File

@ -0,0 +1,8 @@
package gallery.memories.mapper
import androidx.room.ColumnInfo
data class Bucket(
@ColumnInfo(name = "bucket_id") val id: String,
@ColumnInfo(name = "bucket_name") val name: String,
)

View File

@ -0,0 +1,8 @@
package gallery.memories.mapper
import androidx.room.ColumnInfo
data class Day(
@ColumnInfo(name = "dayid") val dayId: Long,
@ColumnInfo(name = "count") val count: Long
)

View File

@ -0,0 +1,59 @@
package gallery.memories.mapper
import androidx.exifinterface.media.ExifInterface
class Fields {
object Day {
const val DAYID = Photo.DAYID
const val COUNT = "count"
}
object Photo {
const val FILEID = "fileid"
const val BASENAME = "basename"
const val MIMETYPE = "mimetype"
const val HEIGHT = "h"
const val WIDTH = "w"
const val SIZE = "size"
const val ETAG = "etag"
const val DATETAKEN = "datetaken"
const val EPOCH = "epoch"
const val AUID = "auid"
const val BUID = "buid"
const val DAYID = "dayid"
const val ISVIDEO = "isvideo"
const val VIDEO_DURATION = "video_duration"
const val EXIF = "exif"
const val PERMISSIONS = "permissions"
}
object Perm {
const val DELETE = "D"
}
object EXIF {
val MAP = mapOf(
ExifInterface.TAG_APERTURE_VALUE to "Aperture",
ExifInterface.TAG_FOCAL_LENGTH to "FocalLength",
ExifInterface.TAG_F_NUMBER to "FNumber",
ExifInterface.TAG_SHUTTER_SPEED_VALUE to "ShutterSpeed",
ExifInterface.TAG_EXPOSURE_TIME to "ExposureTime",
ExifInterface.TAG_ISO_SPEED to "ISO",
ExifInterface.TAG_DATETIME_ORIGINAL to "DateTimeOriginal",
ExifInterface.TAG_OFFSET_TIME_ORIGINAL to "OffsetTimeOriginal",
ExifInterface.TAG_GPS_LATITUDE to "GPSLatitude",
ExifInterface.TAG_GPS_LONGITUDE to "GPSLongitude",
ExifInterface.TAG_GPS_ALTITUDE to "GPSAltitude",
ExifInterface.TAG_MAKE to "Make",
ExifInterface.TAG_MODEL to "Model",
ExifInterface.TAG_ORIENTATION to "Orientation",
ExifInterface.TAG_IMAGE_DESCRIPTION to "Description"
)
}
object Bucket {
const val ID = "id"
const val NAME = "name"
const val ENABLED = "enabled"
}
}

View File

@ -0,0 +1,32 @@
package gallery.memories.mapper
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
@Entity(
tableName = "photos", indices = [
Index(value = ["local_id"]),
Index(value = ["auid"]),
Index(value = ["buid"]),
Index(value = ["dayid"]),
Index(value = ["flag"]),
Index(value = ["bucket_id"]),
Index(value = ["bucket_id", "dayid", "has_remote"])
]
)
data class Photo(
@PrimaryKey(autoGenerate = true) val id: Int? = null,
@ColumnInfo(name = "local_id") val localId: Long,
@ColumnInfo(name = "auid") val auid: String,
@ColumnInfo(name = "buid") val buid: String,
@ColumnInfo(name = "mtime") val mtime: Long,
@ColumnInfo(name = "date_taken") val dateTaken: Long,
@ColumnInfo(name = "dayid") val dayId: Long,
@ColumnInfo(name = "basename") val baseName: String,
@ColumnInfo(name = "bucket_id") val bucketId: Long,
@ColumnInfo(name = "bucket_name") val bucketName: String,
@ColumnInfo(name = "has_remote") val hasRemote: Boolean,
@ColumnInfo(name = "flag") val flag: Int
)

View File

@ -0,0 +1,12 @@
package gallery.memories.mapper
import org.json.JSONObject
class Response {
companion object {
val OK
get(): JSONObject {
return JSONObject().put("message", "ok")
}
}
}

View File

@ -0,0 +1,262 @@
package gallery.memories.mapper
import android.content.ContentUris
import android.content.Context
import android.icu.text.SimpleDateFormat
import android.icu.util.TimeZone
import android.net.Uri
import android.provider.MediaStore
import android.util.Log
import androidx.exifinterface.media.ExifInterface
import org.json.JSONObject
import java.io.IOException
import java.math.BigInteger
import java.security.MessageDigest
class SystemImage {
var fileId = 0L
var baseName = ""
var mimeType = ""
var dateTaken = 0L
var height = 0L
var width = 0L
var size = 0L
var mtime = 0L
var dataPath = ""
var bucketId = 0L
var bucketName = ""
var isVideo = false
var videoDuration = 0L
val uri: Uri
get() {
return ContentUris.withAppendedId(mCollection, fileId)
}
private var mCollection: Uri = IMAGE_URI
companion object {
val TAG = SystemImage::class.java.simpleName
val IMAGE_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val VIDEO_URI = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
/**
* Iterate over all images/videos in the given collection
* @param ctx Context - application context
* @param collection Uri - either IMAGE_URI or VIDEO_URI
* @param selection String? - selection string
* @param selectionArgs Array<String>? - selection arguments
* @param sortOrder String? - sort order
* @return Sequence<SystemImage>
*/
fun cursor(
ctx: Context,
collection: Uri,
selection: String?,
selectionArgs: Array<String>?,
sortOrder: String?
) = sequence {
// Base fields common for videos and images
val projection = arrayListOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.MIME_TYPE,
MediaStore.Images.Media.HEIGHT,
MediaStore.Images.Media.WIDTH,
MediaStore.Images.Media.SIZE,
MediaStore.Images.Media.ORIENTATION,
MediaStore.Images.Media.DATE_TAKEN,
MediaStore.Images.Media.DATE_MODIFIED,
MediaStore.Images.Media.DATA,
MediaStore.Images.Media.BUCKET_ID,
MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
)
// Add video-specific fields
if (collection == VIDEO_URI) {
projection.add(MediaStore.Video.Media.DURATION)
}
// Get column indices
val idColumn = projection.indexOf(MediaStore.Images.Media._ID)
val nameColumn = projection.indexOf(MediaStore.Images.Media.DISPLAY_NAME)
val mimeColumn = projection.indexOf(MediaStore.Images.Media.MIME_TYPE)
val heightColumn = projection.indexOf(MediaStore.Images.Media.HEIGHT)
val widthColumn = projection.indexOf(MediaStore.Images.Media.WIDTH)
val sizeColumn = projection.indexOf(MediaStore.Images.Media.SIZE)
val orientationColumn = projection.indexOf(MediaStore.Images.Media.ORIENTATION)
val dateTakenColumn = projection.indexOf(MediaStore.Images.Media.DATE_TAKEN)
val dateModifiedColumn = projection.indexOf(MediaStore.Images.Media.DATE_MODIFIED)
val dataColumn = projection.indexOf(MediaStore.Images.Media.DATA)
val bucketIdColumn = projection.indexOf(MediaStore.Images.Media.BUCKET_ID)
val bucketNameColumn = projection.indexOf(MediaStore.Images.Media.BUCKET_DISPLAY_NAME)
// Query content resolver
ctx.contentResolver.query(
collection,
projection.toTypedArray(),
selection,
selectionArgs,
sortOrder
).use { cursor ->
while (cursor!!.moveToNext()) {
val image = SystemImage()
// Common fields
image.fileId = cursor.getLong(idColumn)
image.baseName = cursor.getString(nameColumn)
image.mimeType = cursor.getString(mimeColumn)
image.height = cursor.getLong(heightColumn)
image.width = cursor.getLong(widthColumn)
image.size = cursor.getLong(sizeColumn)
image.dateTaken = cursor.getLong(dateTakenColumn)
image.mtime = cursor.getLong(dateModifiedColumn)
image.dataPath = cursor.getString(dataColumn)
image.bucketId = cursor.getLong(bucketIdColumn)
image.bucketName = cursor.getString(bucketNameColumn)
image.mCollection = collection
// Swap width/height if orientation is 90 or 270
val orientation = cursor.getInt(orientationColumn)
if (orientation == 90 || orientation == 270) {
image.width = image.height.also { image.height = image.width }
}
// Video specific fields
image.isVideo = collection == VIDEO_URI
if (image.isVideo) {
val durationColumn = projection.indexOf(MediaStore.Video.Media.DURATION)
image.videoDuration = cursor.getLong(durationColumn)
}
// Add to main list
yield(image)
}
}
}
/**
* Get image or video by a list of IDs
* @param ctx Context - application context
* @param ids List<Long> - list of IDs
* @return List<SystemImage>
*/
fun getByIds(ctx: Context, ids: List<Long>): List<SystemImage> {
val selection = MediaStore.Images.Media._ID + " IN (" + ids.joinToString(",") + ")"
val images = cursor(ctx, IMAGE_URI, selection, null, null).toList()
if (images.size == ids.size) return images
return images + cursor(ctx, VIDEO_URI, selection, null, null).toList()
}
}
/**
* JSON representation of the SystemImage.
* This corresponds to IPhoto on the frontend.
*/
val json
get(): JSONObject {
val obj = JSONObject()
.put(Fields.Photo.FILEID, fileId)
.put(Fields.Photo.BASENAME, baseName)
.put(Fields.Photo.MIMETYPE, mimeType)
.put(Fields.Photo.HEIGHT, height)
.put(Fields.Photo.WIDTH, width)
.put(Fields.Photo.SIZE, size)
.put(Fields.Photo.ETAG, mtime.toString())
.put(Fields.Photo.EPOCH, epoch)
if (isVideo) {
obj.put(Fields.Photo.ISVIDEO, 1)
.put(Fields.Photo.VIDEO_DURATION, videoDuration / 1000)
}
return obj
}
/** The epoch timestamp of the image. */
val epoch
get(): Long {
return dateTaken / 1000
}
val exifInterface
get() : ExifInterface? {
if (isVideo) return null
try {
return ExifInterface(dataPath)
} catch (e: Exception) {
Log.w(TAG, "Failed to read EXIF data: " + e.message)
return null
}
}
/** The UTC dateTaken timestamp of the image. */
fun utcDate(exif: ExifInterface?): Long {
// Get EXIF date using ExifInterface if image
if (exif != null) {
try {
val exifDate = exif.getAttribute(ExifInterface.TAG_DATETIME)
?: throw IOException()
val sdf = SimpleDateFormat("yyyy:MM:dd HH:mm:ss")
sdf.timeZone = TimeZone.GMT_ZONE
sdf.parse(exifDate).let {
return it.time / 1000
}
} catch (e: Exception) {
Log.w(TAG, "Failed to read EXIF datetime: " + e.message)
}
}
// No way to get the actual local date, so just assume current timezone
return (dateTaken + TimeZone.getDefault().getOffset(dateTaken).toLong()) / 1000
}
fun auid(): String {
return md5("$epoch$size")
}
fun buid(exif: ExifInterface?): String {
var sfx = "size=$size"
if (exif != null) {
try {
val iuid = exif.getAttribute(ExifInterface.TAG_IMAGE_UNIQUE_ID)
?: throw IOException()
sfx = "iuid=$iuid"
} catch (e: Exception) {
Log.w(TAG, "Failed to read EXIF unique ID ($baseName): " + e.message)
}
}
return md5("$baseName$sfx");
}
/**
* The database Photo object corresponding to the SystemImage.
* This should ONLY be used for insertion into the database.
*/
val photo
get(): Photo {
val exif = exifInterface
val dateCache = utcDate(exif)
return Photo(
localId = fileId,
auid = auid(),
buid = buid(exif),
mtime = mtime,
dateTaken = dateCache,
dayId = dateCache / 86400,
baseName = baseName,
bucketId = bucketId,
bucketName = bucketName,
flag = 0,
hasRemote = false
)
}
private fun md5(input: String): String {
val md = MessageDigest.getInstance("MD5")
return BigInteger(1, md.digest(input.toByteArray())).toString(16).padStart(32, '0')
}
}

View File

@ -0,0 +1,224 @@
package gallery.memories.service
import SecureStorage
import android.content.Intent
import android.net.Uri
import android.util.Log
import android.widget.Toast
import androidx.media3.common.util.UnstableApi
import gallery.memories.MainActivity
import gallery.memories.R
import io.github.g00fy2.versioncompare.Version
@UnstableApi
class AccountService(private val mCtx: MainActivity, private val mHttp: HttpService) {
companion object {
val TAG = AccountService::class.java.simpleName
}
private val store = SecureStorage(mCtx)
/**
* Make the first request to log in
* @param url The URL of the Nextcloud server
* @param trustAll Whether to trust all certificates
*/
fun login(url: String, trustAll: Boolean) {
try {
mHttp.build(url, trustAll)
val res = mHttp.getApiDescription()
if (res.code != 200) {
throw Exception("${url}api/describe (status ${res.code})")
}
val body = mHttp.bodyJson(res) ?: throw Exception("Failed to parse API description")
val baseUrl = body.getString("baseUrl")
val loginFlowUrl = body.getString("loginFlowUrl")
loginFlow(baseUrl, loginFlowUrl)
} catch (e: Exception) {
toast("Error: ${e.message}")
throw Exception("Failed to connect to server: ${e.message}")
}
}
/**
* Login to a server
* @param baseUrl The base URL of the server
* @param loginFlowUrl The login flow URL
* @throws Exception If the login flow failed
*/
fun loginFlow(baseUrl: String, loginFlowUrl: String) {
val res = mHttp.postLoginFlow(loginFlowUrl)
// Check if 200 was received
if (res.code != 200) {
throw Exception("Login flow returned a ${res.code} status code. Check your reverse proxy configuration and overwriteprotocol is correct.")
}
// Get body as JSON
val body = mHttp.bodyJson(res) ?: throw Exception("Failed to parse login flow response")
// Parse response body as JSON
val pollObj = body.getJSONObject("poll")
val pollToken = pollObj.getString("token")
val pollUrl = pollObj.getString("endpoint")
val loginUrl = body.getString("login")
// Open login page in browser
mCtx.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(loginUrl)))
// Start polling in background
Thread { pollLogin(pollUrl, pollToken, baseUrl) }.start()
}
/**
* Poll the login flow URL until we get a login token
* @param pollUrl The login flow URL
* @param pollToken The login token
* @param baseUrl The base URL of the server
*/
private fun pollLogin(pollUrl: String, pollToken: String, baseUrl: String) {
mCtx.binding.webview.post {
mCtx.binding.webview.loadUrl("file:///android_asset/waiting.html")
}
var pollCount = 0
while (pollCount < 10 * 60) {
pollCount += 3
// Sleep for 3s
Thread.sleep(3000)
try {
val response = mHttp.getPollLogin(pollUrl, pollToken)
val body = mHttp.bodyJson(response) ?: throw Exception("Failed to parse login flow response")
Log.v(TAG, "pollLogin: Got status code ${response.code}")
// Check status code
if (response.code != 200) {
throw Exception("Failed to poll login flow")
}
val loginName = body.getString("loginName")
val appPassword = body.getString("appPassword")
toast("Logged in, waiting for next page ...")
mCtx.runOnUiThread {
// Save login info (also updates header)
storeCredentials(baseUrl, loginName, appPassword)
// Go to next screen
mHttp.loadWebView(mCtx.binding.webview, "nxsetup")
}
return
} catch (e: Exception) {
continue
}
}
}
/**
* Check if the credentials are valid and the server version is supported
* Makes a toast to the user if something is wrong
*/
fun checkCredentialsAndVersion() {
if (!mHttp.isLoggedIn()) return
try {
val response = mHttp.getApiDescription()
val body = mHttp.bodyJson(response)
// Check status code
if (response.code == 401) {
return loggedOut()
}
// Could not connect to memories
if (response.code == 404) {
return toast(mCtx.getString(R.string.err_no_ver))
}
// Check body
if (body == null || response.code != 200) {
toast(mCtx.getString(R.string.err_no_describe))
return
}
// Get body values
val uid = body.get("uid")
val version = body.getString("version")
// Check UID exists
if (uid.equals(null)) {
return loggedOut()
}
// Check minimum version
if (Version(version) < Version(mCtx.getString(R.string.min_server_version))) {
return toast(mCtx.getString(R.string.err_no_ver))
}
} catch (e: Exception) {
Log.w(TAG, "checkCredentialsAndVersion: ", e)
return
}
}
/**
* Handle a logout. Delete the stored credentials and go back to the login screen.
*/
fun loggedOut() {
toast(mCtx.getString(R.string.err_logged_out))
deleteCredentials()
mCtx.runOnUiThread {
mCtx.loadDefaultUrl()
}
}
/**
* Store the credentials
* @param url The URL to store
* @param user The username to store
* @param password The password to store
*/
fun storeCredentials(url: String, user: String, password: String) {
store.saveCredentials(Credential(
url = url,
trustAll = mHttp.isTrustingAllCertificates,
username = user,
token = password,
))
refreshCredentials()
}
/**
* Delete the stored credentials
*/
fun deleteCredentials() {
store.deleteCredentials()
mHttp.setAuthHeader(null)
mHttp.build(null, false)
}
/**
* Refresh the authorization header
*/
fun refreshCredentials() {
val cred = store.getCredentials() ?: return
mHttp.build(cred.url, cred.trustAll)
mHttp.setAuthHeader(Pair(cred.username, cred.token))
}
/**
* Show a toast on the UI thread
* @param message The message to show
*/
private fun toast(message: String) {
mCtx.runOnUiThread {
Toast.makeText(mCtx, message, Toast.LENGTH_LONG).show()
}
}
}

View File

@ -0,0 +1,33 @@
package gallery.memories.service
import android.content.Context
import gallery.memories.R
class ConfigService(private val mCtx: Context) {
companion object {
private var mEnabledBuckets: List<String>? = null
}
/**
* Get the list of enabled local folders
* @return The list of enabled local folders
*/
var enabledBucketIds: List<String>
get() {
if (mEnabledBuckets != null) return mEnabledBuckets!!
mEnabledBuckets = mCtx.getSharedPreferences(mCtx.getString(R.string.preferences_key), 0)
.getStringSet(mCtx.getString(R.string.preferences_enabled_local_folders), null)
?.toList()
?: listOf()
return mEnabledBuckets!!
}
set(value) {
mEnabledBuckets = value
mCtx.getSharedPreferences(mCtx.getString(R.string.preferences_key), 0).edit()
.putStringSet(
mCtx.getString(R.string.preferences_enabled_local_folders),
value.toSet()
)
.apply()
}
}

View File

@ -0,0 +1,8 @@
package gallery.memories.service
data class Credential(
var url: String,
var trustAll: Boolean,
var username: String,
var token: String,
)

View File

@ -0,0 +1,16 @@
package gallery.memories.service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.media3.common.util.UnstableApi
import gallery.memories.NativeX
@UnstableApi class DownloadBroadcastReceiver : BroadcastReceiver() {
/**
* Callback when download is complete
*/
override fun onReceive(context: Context, intent: Intent) {
NativeX.dlService?.runDownloadCallback(intent)
}
}

View File

@ -0,0 +1,161 @@
package gallery.memories.service
import android.app.DownloadManager
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Environment
import android.webkit.CookieManager
import androidx.appcompat.app.AppCompatActivity
import androidx.collection.ArrayMap
import androidx.media3.common.util.UnstableApi
import org.json.JSONArray
import java.util.concurrent.CountDownLatch
@UnstableApi class DownloadService(private val mActivity: AppCompatActivity, private val query: TimelineQuery) {
private val mDownloads: MutableMap<Long, () -> Unit> = ArrayMap()
private var mShareBlobs: JSONArray? = null
/**
* Callback when download is complete
* @param intent The intent that triggered the callback
*/
fun runDownloadCallback(intent: Intent) {
if (mActivity.isDestroyed) return
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE == intent.action) {
val id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0)
synchronized(mDownloads) {
mDownloads[id]?.let {
it()
mDownloads.remove(id)
return
}
}
}
}
/**
* Queue a download
* @param url The URL to download
* @param filename The filename to save the download as
* @return The download ID
*/
fun queue(url: String, filename: String): Long {
val uri = Uri.parse(url)
val manager = mActivity.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val request = DownloadManager.Request(uri)
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)
// Copy all cookies from the webview to the download request
val cookies = CookieManager.getInstance().getCookie(url)
request.addRequestHeader("cookie", cookies)
if (filename != "") {
// Save the file to external storage
request.setDestinationInExternalPublicDir(
Environment.DIRECTORY_DOWNLOADS,
"memories/$filename"
)
}
// Start the download
return manager.enqueue(request)
}
/**
* Share a URL as a string
* @param url The URL to share
* @return True if the URL was shared
*/
fun shareUrl(url: String): Boolean {
val intent = Intent(Intent.ACTION_SEND)
intent.type = "text/plain"
intent.putExtra(Intent.EXTRA_TEXT, url)
mActivity.startActivity(Intent.createChooser(intent, null))
return true
}
/**
* Share the blobs from URLs already set by setShareBlobs
* @return True if the URL was shared
*/
@Throws(Exception::class)
fun shareBlobs(): Boolean {
if (mShareBlobs == null) throw Exception("No blobs to share")
// All URIs to share including remote and local files
val uris = ArrayList<Uri>()
val dlIds = ArrayList<Long>()
// Process all objects to share
for (i in 0 until mShareBlobs!!.length()) {
val obj = mShareBlobs!!.getJSONObject(i)
// If AUID is found, then look for local file
val auid = obj.getString("auid")
if (auid != "") {
val sysImgs = query.getSystemImagesByAUIDs(listOf(auid))
if (sysImgs.isNotEmpty()) {
uris.add(sysImgs[0].uri)
continue
}
}
// Queue a download for remote files
dlIds.add(queue(obj.getString("href"), ""))
}
// Wait for all downloads to complete
val latch = CountDownLatch(dlIds.size)
synchronized(mDownloads) {
for (dlId in dlIds) {
mDownloads.put(dlId, fun() { latch.countDown() })
}
}
latch.await()
// Get the URI of the downloaded file
for (id in dlIds) {
val sUri = getDownloadedFileURI(id) ?: throw Exception("Failed to download file")
uris.add(Uri.parse(sUri))
}
// Create sharing intent
val intent = Intent(Intent.ACTION_SEND_MULTIPLE)
intent.type = "*/*"
intent.putExtra(Intent.EXTRA_STREAM, uris)
mActivity.startActivity(Intent.createChooser(intent, null))
// Reset the blobs
mShareBlobs = null
return true
}
/**
* Set the blobs to share
* @param objects The blobs to share
*/
fun setShareBlobs(objects: JSONArray) {
mShareBlobs = objects
}
/**
* Get the URI of a downloaded file from download ID
* @param downloadId The download ID
* @return The URI of the downloaded file
*/
private fun getDownloadedFileURI(downloadId: Long): String? {
val downloadManager =
mActivity.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val query = DownloadManager.Query()
query.setFilterById(downloadId)
val cursor = downloadManager.query(query)
if (cursor.moveToFirst()) {
val columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)
return cursor.getString(columnIndex)
}
cursor.close()
return null
}
}

View File

@ -0,0 +1,194 @@
package gallery.memories.service
import android.net.Uri
import android.util.Base64
import android.webkit.WebView
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import org.json.JSONArray
import org.json.JSONObject
import java.security.SecureRandom
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
class HttpService {
companion object {
val TAG = HttpService::class.java.simpleName
}
private var client = OkHttpClient()
private var authHeader: String? = null
private var mBaseUrl: String? = null
private var mTrustAll = false
/**
* Check if all certificates are trusted
*/
val isTrustingAllCertificates: Boolean
get() = mTrustAll
/**
* Check if the HTTP service is logged in
*/
fun isLoggedIn(): Boolean {
return authHeader != null
}
/**
* Build the HTTP client
* @param url The URL to use
* @param trustAll Whether to trust all certificates
*/
fun build(url: String?, trustAll: Boolean) {
mBaseUrl = url
mTrustAll = trustAll
client = if (trustAll) {
val trustAllCerts = arrayOf<TrustManager>(
object : X509TrustManager {
@Throws(CertificateException::class)
override fun checkClientTrusted(
chain: Array<X509Certificate>,
authType: String
) {
}
@Throws(CertificateException::class)
override fun checkServerTrusted(
chain: Array<X509Certificate>,
authType: String
) {
}
override fun getAcceptedIssuers(): Array<X509Certificate> {
return arrayOf()
}
}
)
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, SecureRandom())
OkHttpClient.Builder()
.sslSocketFactory(sslContext.socketFactory, trustAllCerts[0] as X509TrustManager)
.hostnameVerifier({ hostname, session -> true })
.build()
} else {
OkHttpClient()
}
}
/**
* Set the authorization header
* @param credentials The credentials to use
*/
fun setAuthHeader(credentials: Pair<String, String>?) {
if (credentials != null) {
val auth = "${credentials.first}:${credentials.second}"
authHeader = "Basic ${Base64.encodeToString(auth.toByteArray(), Base64.NO_WRAP)}"
return
}
authHeader = null
}
/**
* Load a webview at the default page
* @param webView The webview to load
* @param subpath The subpath to load
* @return Host URL if authenticated, null otherwise
*/
fun loadWebView(webView: WebView, subpath: String? = null): String? {
// Load app interface if authenticated
if (authHeader != null && mBaseUrl != null) {
var url = mBaseUrl
if (subpath != null) url += subpath
// Get host name
val host = Uri.parse(url).host
// Clear webview history
webView.clearHistory()
// Set authorization header
webView.loadUrl(url!!, mapOf("Authorization" to authHeader))
return host
}
return null
}
/** Get body as JSON Object */
@Throws(Exception::class)
fun bodyJson(response: Response): JSONObject? {
return getBody(response)?.let { JSONObject(it) }
}
/** Get body as JSON array */
@Throws(Exception::class)
fun bodyJsonArray(response: Response): JSONArray? {
return getBody(response)?.let { JSONArray(it) }
}
/** Get a string from the response body */
@Throws(Exception::class)
fun getBody(response: Response): String? {
val body = response.body?.string()
response.body?.close()
return body
}
/** Get the API description request */
@Throws(Exception::class)
fun getApiDescription(): Response {
return runRequest(buildGet("api/describe"))
}
/** Make login flow request */
@Throws(Exception::class)
fun postLoginFlow(loginFlowUrl: String): Response {
return runRequest(
Request.Builder()
.url(loginFlowUrl)
.header("User-Agent", "Memories")
.post("".toRequestBody("application/json".toMediaTypeOrNull()))
.build()
)
}
/** Make login polling request */
@Throws(Exception::class)
fun getPollLogin(pollUrl: String, pollToken: String): Response {
return runRequest(
Request.Builder()
.url(pollUrl)
.post("token=$pollToken".toRequestBody("application/x-www-form-urlencoded".toMediaTypeOrNull()))
.build()
)
}
/** Run a request and get a JSON object */
@Throws(Exception::class)
private fun runRequest(request: Request): Response {
return client.newCall(request).execute()
}
/** Build a GET request */
private fun buildGet(path: String, auth: Boolean = true): Request {
val builder = Request.Builder()
.url(mBaseUrl + path)
.header("User-Agent", "Memories")
.get()
if (auth)
builder.header("Authorization", authHeader ?: "")
return builder.build()
}
}

View File

@ -0,0 +1,70 @@
package gallery.memories.service
import android.content.ContentUris
import android.content.Context
import android.graphics.Bitmap
import android.graphics.ImageDecoder
import android.os.Build
import android.provider.MediaStore
import androidx.media3.common.util.UnstableApi
import java.io.ByteArrayOutputStream
@UnstableApi class ImageService(private val mCtx: Context, private val query: TimelineQuery) {
/**
* Get a preview image for a given image ID
* @param id The image ID
* @return The preview image as a JPEG byte array
*/
@Throws(Exception::class)
fun getPreview(id: Long): ByteArray {
val bitmap =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
mCtx.contentResolver.loadThumbnail(
ContentUris.withAppendedId(
MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL),
id
),
android.util.Size(2048, 2048),
null
)
} else {
MediaStore.Images.Thumbnails.getThumbnail(
mCtx.contentResolver, id, MediaStore.Images.Thumbnails.FULL_SCREEN_KIND, null
)
?: MediaStore.Video.Thumbnails.getThumbnail(
mCtx.contentResolver, id, MediaStore.Video.Thumbnails.FULL_SCREEN_KIND, null
)
?: throw Exception("Thumbnail not found")
}
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, stream)
return stream.toByteArray()
}
/**
* Get a full image for a given image ID
* @param id The image ID
* @return The full image as a JPEG byte array
*/
@Throws(Exception::class)
fun getFull(auid: String): ByteArray {
val sysImgs = query.getSystemImagesByAUIDs(listOf(auid))
if (sysImgs.isEmpty()) {
throw Exception("Image not found")
}
val uri = sysImgs[0].uri
val bitmap =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
ImageDecoder.decodeBitmap(ImageDecoder.createSource(mCtx.contentResolver, uri))
} else {
MediaStore.Images.Media.getBitmap(mCtx.contentResolver, uri)
?: throw Exception("Image not found")
}
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, stream)
return stream.toByteArray()
}
}

View File

@ -0,0 +1,80 @@
package gallery.memories.service
import android.os.Build
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.media3.common.util.UnstableApi
import gallery.memories.MainActivity
import gallery.memories.R
import java.util.concurrent.CountDownLatch
@UnstableApi class PermissionsService(private val activity: MainActivity) {
var isGranted: Boolean = false
var latch: CountDownLatch? = null
lateinit var requestPermissionLauncher: ActivityResultLauncher<Array<String>>
fun register(): PermissionsService {
requestPermissionLauncher = activity.registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
// we need all of these
isGranted = permissions.all { it.value }
// Persist that we have it now
setHasMediaPermission(isGranted)
// Release latch
latch?.countDown()
}
return this
}
/**
* Requests media permission and blocks until it is granted
*/
fun requestMediaPermissionSync(): Boolean {
if (isGranted) return true
// Wait for response
latch = CountDownLatch(1)
// Request media read permission
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requestPermissionLauncher.launch(
arrayOf(
android.Manifest.permission.READ_MEDIA_IMAGES,
android.Manifest.permission.READ_MEDIA_VIDEO,
)
)
} else {
requestPermissionLauncher.launch(arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE))
}
latch?.await()
return isGranted
}
fun hasMediaPermission(): Boolean {
return activity.getSharedPreferences(activity.getString(R.string.preferences_key), 0)
.getBoolean(activity.getString(R.string.preferences_has_media_permission), false)
}
private fun setHasMediaPermission(v: Boolean) {
activity.getSharedPreferences(activity.getString(R.string.preferences_key), 0).edit()
.putBoolean(activity.getString(R.string.preferences_has_media_permission), v)
.apply()
}
fun hasAllowMedia(): Boolean {
return activity.getSharedPreferences(activity.getString(R.string.preferences_key), 0)
.getBoolean(activity.getString(R.string.preferences_allow_media), false)
}
fun setAllowMedia(v: Boolean) {
activity.getSharedPreferences(activity.getString(R.string.preferences_key), 0).edit()
.putBoolean(activity.getString(R.string.preferences_allow_media), v)
.apply()
}
}

View File

@ -0,0 +1,95 @@
import android.content.Context
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import android.security.keystore.KeyProperties.KEY_ALGORITHM_AES
import android.security.keystore.KeyProperties.PURPOSE_DECRYPT
import android.security.keystore.KeyProperties.PURPOSE_ENCRYPT
import android.util.Base64
import gallery.memories.service.Credential
import java.security.KeyStore
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.IvParameterSpec
class SecureStorage(private val context: Context) {
private val keyStore = KeyStore.getInstance("AndroidKeyStore")
private val keyAlias = "MemoriesKey"
init {
keyStore.load(null)
if (!keyStore.containsAlias(keyAlias)) {
generateNewKey()
}
}
fun saveCredentials(cred: Credential) {
val cipher = getCipher()
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey())
val encryptedToken = cipher.doFinal(cred.token.toByteArray())
context.getSharedPreferences("credentials", Context.MODE_PRIVATE).edit()
.putString("url", cred.url)
.putBoolean("trustAll", cred.trustAll)
.putString("username", cred.username)
.putString("encryptedToken", Base64.encodeToString(encryptedToken, Base64.DEFAULT))
.putString("iv", Base64.encodeToString(cipher.iv, Base64.DEFAULT))
.apply()
}
fun getCredentials(): Credential? {
val sharedPreferences = context.getSharedPreferences("credentials", Context.MODE_PRIVATE)
val url = sharedPreferences.getString("url", null)
val trustAll = sharedPreferences.getBoolean("trustAll", false)
val username = sharedPreferences.getString("username", null)
val encryptedToken = sharedPreferences.getString("encryptedToken", null)
val ivStr = sharedPreferences.getString("iv", null)
if (url != null && username != null && encryptedToken != null && ivStr != null) {
val cipher = getCipher()
val iv = Base64.decode(ivStr, Base64.DEFAULT)
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(), IvParameterSpec(iv))
val token = String(cipher.doFinal(Base64.decode(encryptedToken, Base64.DEFAULT)))
return Credential(url, trustAll, username, token)
}
return null
}
fun deleteCredentials() {
context.getSharedPreferences("credentials", Context.MODE_PRIVATE).edit()
.remove("url")
.remove("trustAll")
.remove("encryptedUsername")
.remove("encryptedToken")
.remove("iv")
.apply()
}
private fun generateNewKey() {
val keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM_AES, "AndroidKeyStore")
val keyGenSpec = KeyGenParameterSpec.Builder(
keyAlias,
PURPOSE_ENCRYPT or PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.setUserAuthenticationRequired(false) // Change this if needed
.build()
keyGenerator.init(keyGenSpec)
keyGenerator.generateKey()
}
private fun getCipher(): Cipher {
val transformation =
"$KEY_ALGORITHM_AES/${KeyProperties.BLOCK_MODE_CBC}/${KeyProperties.ENCRYPTION_PADDING_PKCS7}"
return Cipher.getInstance(transformation)
}
private fun getSecretKey(): SecretKey {
return keyStore.getKey(keyAlias, null) as SecretKey
}
}

View File

@ -0,0 +1,461 @@
package gallery.memories.service
import android.annotation.SuppressLint
import android.app.Activity
import android.database.ContentObserver
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.util.Log
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.IntentSenderRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.exifinterface.media.ExifInterface
import androidx.media3.common.util.UnstableApi
import gallery.memories.MainActivity
import gallery.memories.R
import gallery.memories.dao.AppDatabase
import gallery.memories.mapper.Fields
import gallery.memories.mapper.Response
import gallery.memories.mapper.SystemImage
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.io.IOException
import java.time.Instant
import java.util.concurrent.CountDownLatch
@UnstableApi
class TimelineQuery(private val mCtx: MainActivity) {
private val TAG = TimelineQuery::class.java.simpleName
private val mConfigService = ConfigService(mCtx)
// Database
private val mDb = AppDatabase.get(mCtx)
private val mPhotoDao = mDb.photoDao()
// Photo deletion events
var deleting = false
var deleteIntentLauncher: ActivityResultLauncher<IntentSenderRequest>
var deleteCallback: ((ActivityResult?) -> Unit)? = null
// Observers
var imageObserver: ContentObserver? = null
var videoObserver: ContentObserver? = null
var refreshPending: Boolean = false
// Status of synchronization process
// -1 = not started
// >0 = number of files updated
var syncStatus = -1
init {
// Register intent launcher for callback
deleteIntentLauncher =
mCtx.registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result: ActivityResult? ->
synchronized(this) {
deleteCallback?.let { it(result) }
}
}
}
/**
* Initialize content observers for system store.
* Runs the first sync pass.
*/
fun initialize() {
mPhotoDao.ping()
if (syncDeltaDb() > 0) {
mCtx.refreshTimeline()
}
registerHooks()
}
/**
* Destroy content observers for system store.
*/
fun destroy() {
if (imageObserver != null)
mCtx.contentResolver.unregisterContentObserver(imageObserver!!)
if (videoObserver != null)
mCtx.contentResolver.unregisterContentObserver(videoObserver!!)
}
/**
* Register content observers for system store.
*/
fun registerHooks() {
imageObserver = registerContentObserver(SystemImage.IMAGE_URI)
videoObserver = registerContentObserver(SystemImage.VIDEO_URI)
}
/**
* Register content observer for system store.
* @param uri Content URI
* @return Content observer
*/
private fun registerContentObserver(uri: Uri): ContentObserver {
val observer = object : ContentObserver(null) {
override fun onChange(selfChange: Boolean) {
super.onChange(selfChange)
// Debounce refreshes
synchronized(this@TimelineQuery) {
if (refreshPending) return
refreshPending = true
}
// Refresh after 750ms
Thread {
Thread.sleep(750)
synchronized(this@TimelineQuery) {
refreshPending = false
}
// Check if anything to update
if (syncDeltaDb() == 0 || mCtx.isDestroyed || mCtx.isFinishing) return@Thread
mCtx.refreshTimeline()
}.start()
}
}
mCtx.contentResolver.registerContentObserver(uri, true, observer)
return observer
}
/**
* Get system images by AUIDs
* @param auids List of AUIDs
* @return List of SystemImage
*/
fun getSystemImagesByAUIDs(auids: List<String>): List<SystemImage> {
val photos = mPhotoDao.getPhotosByAUIDs(auids)
if (photos.isEmpty()) return listOf()
return SystemImage.getByIds(mCtx, photos.map { it.localId })
}
/**
* Get the days response for local files.
* @return JSON response
*/
@Throws(JSONException::class)
fun getDays(): JSONArray {
return mPhotoDao.getDays(mConfigService.enabledBucketIds).map {
JSONObject()
.put(Fields.Day.DAYID, it.dayId)
.put(Fields.Day.COUNT, it.count)
}.let { JSONArray(it) }
}
/**
* Get the day response for local files.
* @param dayId Day ID
* @return JSON response
*/
@Throws(JSONException::class)
fun getDay(dayId: Long): JSONArray {
// Get the photos for the day from DB
val photos = mPhotoDao.getPhotosByDay(dayId, mConfigService.enabledBucketIds)
.map { it.localId to it }.toMap()
if (photos.isEmpty()) return JSONArray()
val fileIds = photos.keys.toMutableList()
// Get latest metadata from system table
val response = SystemImage.getByIds(mCtx, fileIds).map { image ->
// Mark file exists
fileIds.remove(image.fileId)
// Add missing fields to JSON
val json = image.json
photos[image.fileId]?.let { photo ->
json.put(Fields.Photo.AUID, photo.auid)
.put(Fields.Photo.BUID, photo.buid)
.put(Fields.Photo.DAYID, dayId)
}
json
}.let { JSONArray(it) }
// Remove files that were not found
mPhotoDao.deleteFileIds(fileIds)
return response
}
/**
* Get the image EXIF info response for local files.
* @param id File ID
* @return JSON response
*/
@Throws(Exception::class)
fun getImageInfo(id: Long): JSONObject {
val photos = mPhotoDao.getPhotosByFileIds(listOf(id))
if (photos.isEmpty()) throw Exception("File not found in database")
// Get image from system table
val images = SystemImage.getByIds(mCtx, listOf(id))
if (images.isEmpty()) throw Exception("File not found in system")
// Get the photo and image
val photo = photos[0]
val image = images[0];
// Augment image JSON with database info
val obj = image.json
.put(Fields.Photo.DAYID, photo.dayId)
.put(Fields.Photo.DATETAKEN, photo.dateTaken)
.put(Fields.Photo.PERMISSIONS, Fields.Perm.DELETE)
try {
val exif = ExifInterface(image.dataPath)
obj.put(Fields.Photo.EXIF, JSONObject().apply {
Fields.EXIF.MAP.forEach { (key, field) ->
put(field, exif.getAttribute(key))
}
})
} catch (e: IOException) {
Log.w(TAG, "Error reading EXIF data for $id")
}
return obj
}
/**
* Delete images from local database and system store.
* @param auids List of AUIDs
* @param dry Dry run (returns whether confirmation will be needed)
* @return JSON response
*/
@Throws(Exception::class)
fun delete(auids: List<String>, dry: Boolean): JSONObject {
synchronized(this) {
if (deleting) throw Exception("Already deleting another set of images")
deleting = true
}
val response = Response.OK
try {
// Get list of file IDs
val sysImgs = getSystemImagesByAUIDs(auids)
// Let the UI know how many files we are deleting
response.put("count", sysImgs.size)
// Let the UI know if we are going to ask for confirmation
response.put("confirms", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
// Exit if dry or nothing to do
if (dry || sysImgs.isEmpty()) return response
// List of URIs
val uris = sysImgs.map { it.uri }
if (uris.isEmpty()) return Response.OK
// Delete file with media store
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val intent = MediaStore.createTrashRequest(mCtx.contentResolver, uris, true)
deleteIntentLauncher.launch(
IntentSenderRequest.Builder(intent.intentSender).build()
)
// Wait for response
val latch = CountDownLatch(1)
var res: ActivityResult? = null
deleteCallback = fun(result: ActivityResult?) {
res = result
latch.countDown()
}
latch.await()
deleteCallback = null;
// Throw if canceled or failed
if (res == null || res!!.resultCode != Activity.RESULT_OK) {
throw Exception("Delete canceled or failed")
}
} else {
for (uri in uris) {
mCtx.contentResolver.delete(uri, null, null)
}
}
// Delete from database
mPhotoDao.deleteFileIds(sysImgs.map { it.fileId })
// Clear UI cache
mCtx.busEmit("nativex:db:updated")
} finally {
synchronized(this) { deleting = false }
}
return response
}
/**
* Sync local database with system store.
* @param startTime Only sync files modified after this time
* @return Number of updated files
*/
private fun syncDb(startTime: Long): Int {
// Date modified is in seconds, not millis
val syncTime = Instant.now().toEpochMilli() / 1000;
// SystemImage query
var selection: String? = null
var selectionArgs: Array<String>? = null
// Query everything modified after startTime
if (startTime != 0L) {
selection = MediaStore.Images.Media.DATE_MODIFIED + " > ?"
selectionArgs = arrayOf(startTime.toString())
}
// Count number of updates
var updates = 0
try {
// Iterate all images from system store
for (image in SystemImage.cursor(
mCtx,
SystemImage.IMAGE_URI,
selection,
selectionArgs,
null
)) {
insertItemDb(image)
updates++
syncStatus = updates
}
// Iterate all videos from system store
for (video in SystemImage.cursor(
mCtx,
SystemImage.VIDEO_URI,
selection,
selectionArgs,
null
)) {
insertItemDb(video)
updates++
syncStatus = updates
}
// Store last sync time
mCtx.getSharedPreferences(mCtx.getString(R.string.preferences_key), 0).edit()
.putLong(mCtx.getString(R.string.preferences_last_sync_time), syncTime)
.apply()
} catch (e: Exception) {
Log.e(TAG, "Error syncing database", e)
}
// Reset sync status
synchronized(this) {
syncStatus = -1
}
// Number of updated files
return updates
}
/**
* Sync local database with system store.
* @return Number of updated files
*/
fun syncDeltaDb(): Int {
// Exit if already running
synchronized(this) {
if (syncStatus != -1) return 0
syncStatus = 0
}
// Get last sync time
val syncTime = mCtx.getSharedPreferences(mCtx.getString(R.string.preferences_key), 0)
.getLong(mCtx.getString(R.string.preferences_last_sync_time), 0L)
return syncDb(syncTime)
}
/**
* Sync local database with system store.
* Runs a full synchronization pass, flagging all files for removal.
* @return Number of updated files
*/
fun syncFullDb() {
// Exit if already running
synchronized(this) {
if (syncStatus != -1) return
syncStatus = 0
}
// Flag all images for removal
mPhotoDao.flagAll()
// Sync all files, marking them in the process
syncDb(0L)
// Clean up stale files
mPhotoDao.deleteFlagged()
}
/**
* Insert item into local database.
* @param image SystemImage
*/
@SuppressLint("SimpleDateFormat")
private fun insertItemDb(image: SystemImage) {
val fileId = image.fileId
val baseName = image.baseName
// Check if file with local_id and mtime already exists
val l = mPhotoDao.getPhotosByFileIds(listOf(fileId))
if (!l.isEmpty() && l[0].mtime == image.mtime) {
// File already exists, remove flag
mPhotoDao.unflag(fileId)
Log.v(TAG, "File already exists: $fileId / $baseName")
return
}
// Convert to photo
val photo = image.photo
// Delete file with same local_id and insert new one
mPhotoDao.deleteFileIds(listOf(fileId))
mPhotoDao.insert(photo)
Log.v(TAG, "Inserted file to local DB: $photo")
}
/**
* Set has_remote for list of AUIDs
* @param auids List of AUIDs
* @param value Value to set
*/
fun setHasRemote(auids: List<String>, buids: List<String>, value: Boolean) {
mPhotoDao.setHasRemote(auids, buids, value)
}
/**
* Active local folders response.
* This is in timeline query because it calls the database service.
*/
var localFolders: JSONArray
get() {
return mPhotoDao.getBuckets().map {
JSONObject()
.put(Fields.Bucket.ID, it.id)
.put(Fields.Bucket.NAME, it.name)
.put(Fields.Bucket.ENABLED, mConfigService.enabledBucketIds.contains(it.id))
}.let { JSONArray(it) }
}
set(value) {
val enabled = mutableListOf<String>()
for (i in 0 until value.length()) {
val obj = value.getJSONObject(i)
if (obj.getBoolean(Fields.Bucket.ENABLED)) {
enabled.add(obj.getString(Fields.Bucket.ID))
}
}
mConfigService.enabledBucketIds = enabled
}
}

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/coordinator"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.media3.ui.PlayerView
android:id="@+id/video_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:alpha="0.0"
app:show_buffering="always"
/>
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:soundEffectsEnabled="true"
/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 857 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -0,0 +1,3 @@
<resources>
<dimen name="fab_margin">48dp</dimen>
</resources>

View File

@ -0,0 +1,16 @@
<resources>
<!-- Base application theme. -->
<style name="Theme.Memories" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/theme</item>
<item name="colorPrimaryVariant">@color/theme</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@ -0,0 +1,3 @@
<resources>
<dimen name="fab_margin">200dp</dimen>
</resources>

View File

@ -0,0 +1,3 @@
<resources>
<dimen name="fab_margin">48dp</dimen>
</resources>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="theme">#2b94f0</color>
</resources>

View File

@ -0,0 +1,3 @@
<resources>
<dimen name="fab_margin">16dp</dimen>
</resources>

View File

@ -0,0 +1,20 @@
<resources>
<string name="app_name">Memories</string>
<string name="min_server_version">6.1.0</string>
<string name="preferences_key">memories</string>
<string name="preferences_theme_color">themeColor</string>
<string name="preferences_theme_dark">themeDark</string>
<string name="preferences_last_sync_time">lastDbSyncTime</string>
<string name="preferences_has_media_permission">hasMediaPermission</string>
<string name="preferences_allow_media">allowMedia</string>
<string name="preferences_enabled_local_folders">enabledLocalFolders</string>
<!-- https://www.whatismybrowser.com/guides/the-latest-user-agent/chrome -->
<string name="ua_chrome">"Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.76 Mobile Safari/537.36"</string>
<string name="ua_app_prefix">MemoriesNative/</string>
<string name="err_no_ver">Your server does not have the minimum required version of Memories</string>
<string name="err_logged_out">Logged out from server</string>
<string name="err_no_describe">Failed to connect to server. Reset app data if this persists.</string>
</resources>

View File

@ -0,0 +1,25 @@
<resources>
<!-- Base application theme. -->
<style name="Theme.Memories" parent="Theme.MaterialComponents.Light.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/theme</item>
<item name="colorPrimaryVariant">@color/theme</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
<style name="Theme.Memories.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="Theme.Memories.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="Theme.Memories.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
</resources>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older that API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample data extraction rules file; uncomment and customize as necessary.
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
for details.
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
</cloud-backup>
<!--
<device-transfer>
<include .../>
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>

View File

@ -0,0 +1,12 @@
buildscript {
ext.kotlin_version = '1.9.0'
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
plugins {
id 'com.android.application' version '8.1.2' apply false
id 'com.android.library' version '8.1.2' apply false
id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false
}

View File

@ -0,0 +1,23 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
android.defaults.buildfeatures.buildconfig=true
android.nonFinalResIds=false

Binary file not shown.

View File

@ -0,0 +1,6 @@
#Tue May 02 23:46:18 PDT 2023
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

185
android/gradlew vendored 100644
View File

@ -0,0 +1,185 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

89
android/gradlew.bat vendored 100644
View File

@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -0,0 +1,16 @@
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "Memories"
include ':app'

View File

@ -29,7 +29,7 @@ Memories is a *batteries-included* photo management solution for Nextcloud with
1. Run `php occ memories:index` to generate metadata indices for existing photos.
1. Open the 📷 Memories app in Nextcloud and set the directory containing your photos.
]]></description>
<version>5.4.1</version>
<version>6.2.2</version>
<licence>agpl</licence>
<author mail="radialapps@gmail.com">Varun Patil</author>
<namespace>Memories</namespace>
@ -39,7 +39,7 @@ Memories is a *batteries-included* photo management solution for Nextcloud with
<repository>https://github.com/pulsejet/memories</repository>
<screenshot>https://raw.githubusercontent.com/pulsejet/memories/master/appinfo/screenshot.jpg</screenshot>
<dependencies>
<nextcloud min-version="25" max-version="27"/>
<nextcloud min-version="26" max-version="28"/>
</dependencies>
<commands>
<command>OCA\Memories\Command\Index</command>

View File

@ -1,10 +1,12 @@
<?php
declare(strict_types=1);
function getWildcard($param)
{
return [
'requirements' => [$param => '.*'],
'defaults' => [$param => '']
'defaults' => [$param => ''],
];
}
@ -23,6 +25,7 @@ return [
['name' => 'Page#thisday', 'url' => '/thisday', 'verb' => 'GET'],
['name' => 'Page#map', 'url' => '/map', 'verb' => 'GET'],
['name' => 'Page#explore', 'url' => '/explore', 'verb' => 'GET'],
['name' => 'Page#nxsetup', 'url' => '/nxsetup', 'verb' => 'GET'],
// Routes with params
w(['name' => 'Page#folder', 'url' => '/folders/{path}', 'verb' => 'GET'], 'path'),
@ -33,7 +36,6 @@ return [
w(['name' => 'Page#tags', 'url' => '/tags/{name}', 'verb' => 'GET'], 'name'),
// Public folder share
['name' => 'Public#showShare', 'url' => '/s/{token}', 'verb' => 'GET'],
[
'name' => 'Public#showAuthenticate',
'url' => '/s/{token}/authenticate/{redirect}',
@ -44,6 +46,7 @@ return [
'url' => '/s/{token}/authenticate/{redirect}',
'verb' => 'POST',
],
w(['name' => 'Public#showShare', 'url' => '/s/{token}/{path}', 'verb' => 'GET'], 'path'),
// Public album share
['name' => 'PublicAlbum#showShare', 'url' => '/a/{token}', 'verb' => 'GET'],
@ -51,8 +54,8 @@ return [
// API Routes
['name' => 'Days#days', 'url' => '/api/days', 'verb' => 'GET'],
['name' => 'Days#day', 'url' => '/api/days/{id}', 'verb' => 'GET'],
['name' => 'Days#dayPost', 'url' => '/api/days', 'verb' => 'POST'],
['name' => 'Days#day', 'url' => '/api/days', 'verb' => 'POST'],
['name' => 'Days#dayGet', 'url' => '/api/days/{id}', 'verb' => 'GET'],
['name' => 'Folders#sub', 'url' => '/api/folders/sub', 'verb' => 'GET'],
['name' => 'Clusters#list', 'url' => '/api/clusters/{backend}', 'verb' => 'GET'],
@ -95,7 +98,7 @@ return [
['name' => 'Admin#setSystemConfig', 'url' => '/api/system-config/{key}', 'verb' => 'PUT'],
['name' => 'Admin#placesSetup', 'url' => '/api/occ/places-setup', 'verb' => 'POST'],
// Service worker
['name' => 'Other#serviceWorker', 'url' => '/service-worker.js', 'verb' => 'GET'],
]
// Service worker and assets
['name' => 'Other#static', 'url' => '/static/{name}', 'verb' => 'GET'],
],
];

View File

@ -1,15 +0,0 @@
module.exports = {
plugins: [
'@babel/plugin-syntax-dynamic-import',
],
presets: [
[
'@babel/preset-env',
{
"targets": "> 5%, not dead",
useBuiltIns: false,
modules: 'auto',
},
],
],
}

View File

@ -1,6 +1,6 @@
{
"name": "Memories",
"description": "p",
"name": "radialapps/memories",
"description": "Fast and advanced photo management for Nextcloud",
"type": "project",
"license": "AGPL",
"authors": [
@ -8,8 +8,8 @@
"name": "Varun Patil"
}
],
"require": {},
"require-dev": {
"phpunit/phpunit": "^5.4"
"friendsofphp/php-cs-fixer": "^3.35",
"vimeo/psalm": "^5.15"
}
}

2804
composer.lock generated 100644

File diff suppressed because it is too large Load Diff

3
docs/.gitignore vendored
View File

@ -1 +1,2 @@
changelog.md
changelog.md
system-config.php

View File

@ -4,7 +4,7 @@ description: Steps to configure Memories for the best experience and performance
# Configuration
!!! danger "Use the admin interface"
!!! success "Use the admin interface"
Starting with v5.0.0, you can fully configure memories using the admin panel. With an admin account in Nextcloud, go to `Settings -> Memories`.
Using the admin interface for configuration is **strongly recommended** in most cases.
@ -18,11 +18,7 @@ occ memories:places-setup # set up reverse geocoding, will force re-indexing
occ memories:index # index existing photo files (can run in parallel, refer to admin panel)
```
!!! warning "OCCWeb"
The OCCWeb app is deprecated, and will not work with Memories. You must use the `occ` command line.
!!! tip "Cron"
!!! question "Cron"
You **DO NOT** need to set up a cron job or run `occ memories:index` periodically, since this is handled internally.
Any subsequently uploaded files will be indexed automatically with hooks. In case you upload files externally and run
@ -39,32 +35,30 @@ occ memories:index # index existing photo files (can run in parallel,
If you are using Nextcloud AIO, see [this documentation](https://github.com/nextcloud/all-in-one#how-to-run-occ-commands).
## Storage support
## Recommended Apps
The app can work with external storage for photos. Just set the mountpoint as the timeline directory.
For the best experience and performance, the following apps are recommended.
- If you add any photos from outside Nextcloud, you must run the scan and index commands.
- Indexing may be slow, since all files must be downloaded from the storage.
- [Preview Generator](https://github.com/nextcloud/previewgenerator) - For pre-generating image previews (**required** for performance)
- [Recognize](https://github.com/nextcloud/recognize) - The official Nextcloud app for AI tagging of images and people.
- [Photos](https://github.com/nextcloud/photos) - The official Nextcloud Photos app, required for albums support.
- [Face Recognition](https://github.com/matiasdelellis/facerecognition) - An alternative face recognition app, which offers more fine-tuning. Alpha stage integration.
## Storage Support
Memories works out-of-the-box with most Nextcloud setups, including with external storage.
- If you upload any photos from outside of Nextcloud, you may need to run the `occ files:scan` and `occ memories:index` commands.
- With external storage, indexing may be slow since all files must be downloaded.
!!! warning "Transcoding with external storage"
Video transcoding requires the entire file to be available locally for ffmpeg. To prevent downloading the
entire for every playback, transcoding is disabled for external storage.
## Image/Video support
To get support for all file types including HEIC, TIFF and RAW, refer to [this page](./file-types.md).
To enable support for high resolution images, you need to update Nextcloud's `config.php` to include
```php
'preview_max_memory' => 4096,
'preview_max_filesize_image' => 256,
```
## Transcoding
Memories bundles a [transcoding server](https://github.com/pulsejet/go-vod) with HLS capabilites for adaptive streaming. You need to configure transcoding to be able to play any videos. HLS enables the browser to download the video as small chunks and in resolutions adaptive to the connection speed. As a result, this is usually expected to have a major boost in video experience and performance.
Memories bundles a [transcoding server](https://github.com/pulsejet/memories/tree/master/go-vod) with HLS capabilites for adaptive streaming. You need to configure transcoding to be able to play any videos. HLS enables the browser to download the video as small chunks and in resolutions adaptive to the connection speed. As a result, this is usually expected to have a major boost in video experience and performance.
You can configure transcoding from the admin panel. Make sure to test all settings carefully on different kinds of videos.
@ -76,28 +70,29 @@ Read the following considerations carefully regarding transcoding:
1. If transcoding fails, the video player will fall back to the original video stream. Check the output of `/tmp/go-vod/<instanceid>.log`
1. For better performance, you may configure the transcoder to use hardware acceleration. See [this page](./hw-transcoding.md).
## Reverse geocoding
!!! tip "Hardware Acceleration"
Memories supports reverse geocoding to find the location of photos. To set up geocoding you need to download the planet boundary dataset and store it in the database. This works only on MySQL/MariaDB/Postgres (no SQLite support). To set up, go to the admin panel. Note that all your files will be re-indexed after downloading the planet database.
Memories supports hardware acceleration for transcoding using VA-API and NVENC.
If you have compatible hardware, using acceleration can significantly improve performance.
See the instructions on [this page](./hw-transcoding.md) for more information.
## Recommended apps
## Reverse Geocoding
- [Preview Generator](https://github.com/rullzer/previewgenerator) - For pre-generating image previews (**required** for best performance)
- [Recognize](https://github.com/nextcloud/recognize) - The official Nextcloud app for AI tagging of images and people.
- [Photos](https://github.com/nextcloud/photos) - The official Nextcloud Photos app, required for albums support.
- [Face Recognition](https://github.com/matiasdelellis/facerecognition) - An alternative face recognition app, which offers more fine-tuning. Alpha stage integration.
Reverse geocoding to find the location of photos. To set up geocoding you need to download the planet boundary dataset and store it in the database. This works only on MySQL / MariaDB / Postgres (no SQLite support). To set up reverse geocoding, go to the Memories admin panel.
## Preview storage
!!! info "World map of photos"
Reverse geocoding and the map of photos are **two separate features** and do not depend on each other.
## Preview Storage
By default, previews upto `4096px` size are generated by Nextcloud. Each of the largest previews might be a few megabytes in size. This may not be ideal if you have limited storage space, since the preview size may become larger than the originals (especially if you use efficient image formats like HEIC). In this case, you can limit previews to a smaller size like `2048px`.
Note that Memories will, by default, load the full image upon zooming in. If you are okay with this, you may use a even smaller size like `1024px` to save more space as well as faster preview generation time. Non-JPEG files will be converted on the server when loading in full-res, which may lead to some server load.
Note that Memories will, by default, load the full image upon zooming in. If you are okay with this, you may use a even smaller size like `1024px` to save more space as well as faster preview generation time. Non-JPEG files will be converted on the server when loading in full-res, which may lead to some server load. These options are also configurable through the admin panel.
On Nextcloud AIO, these options are set to the recommended values by default.
```php
'preview_max_x' => 2048,
'preview_max_y' => 2048,
```bash
occ config:system:set preview_max_x --value="2048"
occ config:system:set preview_max_y --value="2048"
```
You can also set the preview JPEG quality to 80 to save more space.
@ -113,9 +108,26 @@ rm -rf <nextcloud-data-dir>/appdata_*/preview
occ files:scan-app-data
```
## Header Logo
Nextcloud supports customizing the logo for your instance. To properly theme the logo to match the user's theme, the logo you use in `Admninistration => Theming` must follow the following criteria:
- It must be an SVG file.
- The `viewBox` attribute on the `<svg>` element must be set appropriately.
- All paths that correspond to white areas must have the `fill` attribute set to `currentColor`. These areas will then automatically be colored according to the user's theme.
- Since Nextcloud doesn't support `currentColor`, you must set the default value for the color (e.g. `white`) as an inline style on the `<svg>` element (`<svg style="color:white">`).
A sample SVG that follows these criteria is shown below (from [here](https://github.com/pulsejet/memories/blob/master/src/assets/nextcloud.svg)):
```xml
--8<-- "src/assets/nextcloud.svg"
```
Note that you may skip these steps and also use a PNG file, but the logo will not be colored according to the user's theme. This can be especially troublesome since Nextcloud mostly shows the logo on a dark background while Memories uses both light and dark backgrounds.
## Migration
Memories directly uses EXIF metadata from files, so migration should be generally easy. The file structure of your photos is preserved as-is.
Memories directly uses EXIF metadata from files, so migration to and from other apps should be generally easy. The file structure of your photos is preserved as-is.
If you are migrating from Nextcloud Photos, you don't need to do anything. Your albums and tags will be carried to Memories as-is.
@ -127,7 +139,6 @@ occ memories:migrate-google-takeout
## Other notes
- For optimal performance, enable HTTP/2 on your reverse proxy (nginx/apache)
- Make sure your server timezone is configured correctly. If a photo does not contain an EXIF date, the server time is used.
- Perform additional server tuning for Nextcloud. See [the docs](https://docs.nextcloud.com/server/latest/admin_manual/installation/server_tuning.html).
- The archive feature moves photos to a separate folder called `.archive` at the root of your timeline. You can, for example, mount this folder to a cold storage.
- Perform additional server tuning for Nextcloud. See [performance](/troubleshooting/#performance) section of troubleshooting.
- The archive feature moves photos to a separate folder called `.archive` at the root of your timeline or the current storage. You can, for example, mount this folder to a cold storage.

Some files were not shown because too many files have changed in this diff Show More