@christianriedl/media 1.0.269 → 1.0.271
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/iMedia.d.ts +0 -2
- package/dist/iMedia.js.map +1 -1
- package/package.json +2 -2
- package/src/components/PhotoMetaData.vue +150 -137
- package/src/views/DocumentsPage.vue +1 -1
- package/src/views/PhotoAlbumPage.vue +290 -286
package/dist/iMedia.d.ts
CHANGED
package/dist/iMedia.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iMedia.js","sourceRoot":"","sources":["../src/iMedia.ts"],"names":[],"mappings":"AAGA,MAAM,CAAN,IAAY,UASX;AATD,WAAY,UAAU;IAClB,6CAAS,CAAA;IACT,6CAAS,CAAA;IACT,iDAAW,CAAA;IACX,4CAAS,CAAA;IACT,0DAAgB,CAAA;IAChB,iDAAa,CAAA;IACb,6CAAW,CAAA;IACX,mDAAc,CAAA;AAClB,CAAC,EATW,UAAU,KAAV,UAAU,QASrB;AACD,MAAM,CAAN,IAAY,eAeX;AAfD,WAAY,eAAe;IACvB,qDAAiB,CAAA;IACjB,gEAAoB,CAAA;IACpB,gEAAoB,CAAA;IACpB,gEAAoB,CAAA;IACpB,gEAAoB,CAAA;IACpB,kEAAoB,CAAA;IACpB,gEAAoB,CAAA;IACpB,gEAAoB,CAAA;IACpB,gEAAoB,CAAA;IACpB,kEAAoB,CAAA;IACpB,4DAAoB,CAAA;IACpB,4DAAoB,CAAA;IACpB,4DAAoB,CAAA;IACpB,8DAAoB,CAAA;AACxB,CAAC,EAfW,eAAe,KAAf,eAAe,QAe1B;
|
|
1
|
+
{"version":3,"file":"iMedia.js","sourceRoot":"","sources":["../src/iMedia.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@christianriedl/media",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.271",
|
|
4
4
|
"description": "RIC media interfaces",
|
|
5
5
|
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"author": "Christian Riedl",
|
|
19
19
|
"license": "ISC",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@christianriedl/utils": "^1.0.
|
|
21
|
+
"@christianriedl/utils": "^1.0.141",
|
|
22
22
|
"@christianriedl/rest": "^1.0.84",
|
|
23
23
|
"@christianriedl/epg": "^1.0.43"
|
|
24
24
|
},
|
|
@@ -1,165 +1,178 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref, computed, inject } from 'vue';
|
|
2
|
+
import { ref, computed, inject, watch } from 'vue';
|
|
3
3
|
import { Dictionary, Helper } from '@christianriedl/utils';
|
|
4
4
|
import { IPictureFile, EOrientation, EPictureFlags, getMediaBinSymbol } from '@christianriedl/media';
|
|
5
5
|
|
|
6
|
-
const props = defineProps<{
|
|
6
|
+
const props = defineProps<{ file: IPictureFile, all: boolean, splitxmp: boolean }>();
|
|
7
7
|
|
|
8
8
|
interface ITree {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
id: number;
|
|
10
|
+
title: string;
|
|
11
|
+
children?: ITree[];
|
|
12
|
+
data?: Dictionary<any>[];
|
|
13
13
|
}
|
|
14
14
|
const tree = ref<ITree[]>([]);
|
|
15
15
|
const properties = ref<Dictionary<any>>({});
|
|
16
16
|
const propertiesVisible = ref(false);
|
|
17
17
|
const getMediaService = inject(getMediaBinSymbol)!;
|
|
18
18
|
const mediaService = getMediaService();
|
|
19
|
-
const treeColumns = props.splitxmp ? 3 : 2;
|
|
19
|
+
const treeColumns = computed(() => props.splitxmp ? 3 : 2);
|
|
20
|
+
let metadata: Dictionary<any>;
|
|
21
|
+
let allMetaData: Dictionary<any>;
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
watch(() => props.all, async () => await fetchMetaData(), { immediate: true });
|
|
24
|
+
watch(() => props.splitxmp, () => buildTree());
|
|
25
|
+
|
|
26
|
+
async function fetchMetaData() {
|
|
27
|
+
if (props.all) {
|
|
28
|
+
if (!allMetaData) {
|
|
29
|
+
allMetaData = await mediaService.getExifInfo(props.file.dlnaParentId, props.file.dlnaid, props.all, props.splitxmp);
|
|
30
|
+
}
|
|
31
|
+
buildTree();
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
if (!metadata) {
|
|
35
|
+
const data = await mediaService.getExifInfo(props.file.dlnaParentId, props.file.dlnaid, props.all, props.splitxmp);
|
|
36
|
+
setMetaData(data, props.file);
|
|
37
|
+
}
|
|
38
|
+
properties.value = metadata;
|
|
39
|
+
}
|
|
26
40
|
}
|
|
27
41
|
|
|
28
42
|
function setMetaData(exif: Dictionary<any>, file: IPictureFile) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
metadata['Dimension'] = `${file.width}x${file.height} o:${EOrientation[file.orientation]}`;
|
|
98
|
-
metadata['Thumbnail'] = `${file.thumbWidth}x${file.thumbHeight}`;
|
|
99
|
-
metadata['Flags'] = `${EPictureFlags[file.flags]}`;
|
|
100
|
-
metadata['Mb'] = (file.size / 1000000).toString() + " Mb";
|
|
101
|
-
if (file.eventIdx >= 0)
|
|
102
|
-
metadata['Ereignis'] = mediaService.getListEntry("Picture.Event", file.eventIdx);
|
|
103
|
-
else
|
|
104
|
-
delete metadata['Ereignis'];
|
|
105
|
-
if (file.locationIdx >= 0)
|
|
106
|
-
metadata['Ort'] = mediaService.getListEntry("Picture.Location", file.locationIdx);
|
|
107
|
-
else
|
|
108
|
-
delete metadata['Ort'];
|
|
109
|
-
if (file.personIdxs && file.personIdxs.length > 0) {
|
|
110
|
-
let persons = "";
|
|
111
|
-
for (let i = 0; i < file.personIdxs.length; i++) {
|
|
112
|
-
persons = persons + mediaService.getListEntry("Picture.Person", file.personIdxs[i]) + " ";
|
|
113
|
-
}
|
|
114
|
-
metadata['Personen'] = persons;
|
|
115
|
-
}
|
|
116
|
-
else
|
|
117
|
-
delete metadata['Personen'];
|
|
43
|
+
const folder = mediaService.getFolder(file.dlnaParentId);
|
|
44
|
+
metadata = {};
|
|
45
|
+
metadata['Album'] = folder.name;
|
|
46
|
+
metadata['Name'] = file.name;
|
|
47
|
+
let fileName: string = folder.url + file.url;
|
|
48
|
+
const idx = fileName.lastIndexOf('/');
|
|
49
|
+
if (idx > 0)
|
|
50
|
+
fileName = fileName.substring(idx + 1);
|
|
51
|
+
metadata['File'] = fileName;
|
|
52
|
+
if (exif) {
|
|
53
|
+
if (exif.Model)
|
|
54
|
+
metadata['Kamera'] = exif.Model;
|
|
55
|
+
else
|
|
56
|
+
delete metadata['Kamera'];
|
|
57
|
+
if (exif.LensModel)
|
|
58
|
+
metadata['Objectiv'] = exif.LensModel;
|
|
59
|
+
else
|
|
60
|
+
delete metadata['Objectiv'];
|
|
61
|
+
if (exif.Artist)
|
|
62
|
+
metadata['Von'] = exif.Artist as string;
|
|
63
|
+
else
|
|
64
|
+
delete metadata['Von'];
|
|
65
|
+
if (exif.ExposureTime)
|
|
66
|
+
metadata['Belichtung'] = '1/' + Helper.round(1.0 / exif.ExposureTime, 0);
|
|
67
|
+
else
|
|
68
|
+
delete metadata['Belichtung'];
|
|
69
|
+
if (exif.FNumber)
|
|
70
|
+
metadata['Blende'] = exif.FNumber.toString();
|
|
71
|
+
else
|
|
72
|
+
delete metadata['Blende'];
|
|
73
|
+
if (exif.DateTimeOriginal)
|
|
74
|
+
metadata['Zeit'] = exif.DateTimeOriginal;
|
|
75
|
+
else
|
|
76
|
+
metadata['Zeit'] = file.date.toLocaleString();
|
|
77
|
+
if (exif.Country) {
|
|
78
|
+
if (exif.State)
|
|
79
|
+
metadata['Land'] = exif.Country + ' - ' + exif.State;
|
|
80
|
+
else
|
|
81
|
+
metadata['Land'] = exif.Country;
|
|
82
|
+
}
|
|
83
|
+
else
|
|
84
|
+
delete metadata['Land'];
|
|
85
|
+
if (exif.City)
|
|
86
|
+
metadata['Stadt'] = exif.City;
|
|
87
|
+
else
|
|
88
|
+
delete metadata['Stadt'];
|
|
89
|
+
if (exif.Location)
|
|
90
|
+
metadata['Strasse'] = exif.Location;
|
|
91
|
+
else
|
|
92
|
+
delete metadata['Strasse'];
|
|
93
|
+
if (exif.Copyright)
|
|
94
|
+
metadata['Copyright'] = exif.Copyright;
|
|
95
|
+
else
|
|
96
|
+
delete metadata['Copyright'];
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
delete metadata['Kamera'];
|
|
100
|
+
delete metadata['Objectiv'];
|
|
101
|
+
delete metadata['Von'];
|
|
102
|
+
delete metadata['Belichtung'];
|
|
103
|
+
delete metadata['Blende'];
|
|
104
|
+
delete metadata['Land'];
|
|
105
|
+
delete metadata['Stadt'];
|
|
106
|
+
delete metadata['Strasse'];
|
|
107
|
+
delete metadata['Copyright'];
|
|
108
|
+
metadata['Zeit'] = file.date.toLocaleString();
|
|
109
|
+
}
|
|
118
110
|
|
|
119
|
-
|
|
111
|
+
metadata['Dimension'] = `${file.width}x${file.height} o:${EOrientation[file.orientation]}`;
|
|
112
|
+
metadata['Thumbnail'] = `${file.thumbWidth}x${file.thumbHeight}`;
|
|
113
|
+
metadata['Flags'] = `${EPictureFlags[file.flags]}`;
|
|
114
|
+
metadata['Mb'] = (file.size / 1000000).toString() + " Mb";
|
|
115
|
+
if (file.eventIdx >= 0)
|
|
116
|
+
metadata['Ereignis'] = mediaService.getListEntry("Picture.Event", file.eventIdx);
|
|
117
|
+
else
|
|
118
|
+
delete metadata['Ereignis'];
|
|
119
|
+
if (file.locationIdx >= 0)
|
|
120
|
+
metadata['Ort'] = mediaService.getListEntry("Picture.Location", file.locationIdx);
|
|
121
|
+
else
|
|
122
|
+
delete metadata['Ort'];
|
|
123
|
+
if (file.personIdxs && file.personIdxs.length > 0) {
|
|
124
|
+
let persons = "";
|
|
125
|
+
for (let i = 0; i < file.personIdxs.length; i++) {
|
|
126
|
+
persons = persons + mediaService.getListEntry("Picture.Person", file.personIdxs[i]) + " ";
|
|
127
|
+
}
|
|
128
|
+
metadata['Personen'] = persons;
|
|
129
|
+
}
|
|
130
|
+
else
|
|
131
|
+
delete metadata['Personen'];
|
|
120
132
|
}
|
|
121
133
|
|
|
122
134
|
function buildTree() {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
135
|
+
let id = 1;
|
|
136
|
+
tree.value.splice(0, tree.value.length);
|
|
137
|
+
for (var key in allMetaData) {
|
|
138
|
+
const subTree: ITree = { id: id++, title: key };
|
|
139
|
+
if (props.splitxmp && key == 'XMP') {
|
|
140
|
+
const xmpDict: Dictionary<any> = allMetaData[key];
|
|
141
|
+
subTree.children = [];
|
|
142
|
+
for (var xmpkey in xmpDict) {
|
|
143
|
+
const xmpTree: ITree = { id: id++, title: xmpkey };
|
|
144
|
+
subTree.children.push(xmpTree);
|
|
145
|
+
xmpTree.data = xmpDict[xmpkey];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
subTree.data = allMetaData[key];
|
|
150
|
+
}
|
|
151
|
+
tree.value.splice(tree.value.length, 0, subTree);
|
|
152
|
+
}
|
|
140
153
|
}
|
|
141
154
|
|
|
142
155
|
function getTree(id: number, trees: ITree[]): ITree | undefined {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
156
|
+
let tree: ITree | undefined = undefined;
|
|
157
|
+
for (let i = 0; i < trees.length; i++) {
|
|
158
|
+
if (trees[i].id == id)
|
|
159
|
+
tree = trees[i];
|
|
160
|
+
else if (trees[i].children)
|
|
161
|
+
tree = getTree(id, trees[i].children!);
|
|
162
|
+
if (tree)
|
|
163
|
+
return tree;
|
|
164
|
+
}
|
|
152
165
|
}
|
|
153
166
|
function onSelectTree(sel: any) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
167
|
+
const tr = getTree(sel as number, tree.value);
|
|
168
|
+
if (tr && tr.data) {
|
|
169
|
+
properties.value = tr.data;
|
|
170
|
+
propertiesVisible.value = true;
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
properties.value = {};
|
|
174
|
+
propertiesVisible.value = false;
|
|
175
|
+
}
|
|
163
176
|
}
|
|
164
177
|
</script>
|
|
165
178
|
<template>
|
|
@@ -151,7 +151,7 @@
|
|
|
151
151
|
for (const key in aiService.vectorStore) {
|
|
152
152
|
const store = aiService.vectorStore[key];
|
|
153
153
|
for (const id in store.files) {
|
|
154
|
-
if (store.files[id] == file) {
|
|
154
|
+
if (store.files[id]!.filename == file) {
|
|
155
155
|
return { fileId: id, vectorStore: key };
|
|
156
156
|
}
|
|
157
157
|
}
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
import type { ComponentPublicInstance } from 'vue';
|
|
4
4
|
import { useRouter, useRoute } from 'vue-router';
|
|
5
5
|
import { IAppState, IAppConfig, EDevice, EDirection, Dictionary, appStateSymbol, appConfigSymbol } from '@christianriedl/utils';
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import {
|
|
7
|
+
EMediaType, EPictureFlags, IPictureFile, IMediaFolder, IMediaService, IMediaAppConfig, EPictureQuality,
|
|
8
|
+
MediaHelper, getMediaBinSymbol
|
|
9
|
+
} from '@christianriedl/media';
|
|
8
10
|
|
|
9
11
|
import PhotoMetaData from '../components/PhotoMetaData.vue';
|
|
10
12
|
import PhotoMap from '../components/PhotoMap.vue';
|
|
@@ -15,7 +17,7 @@
|
|
|
15
17
|
const appConfig = inject(appConfigSymbol)!;
|
|
16
18
|
const mediaAppConfig = appConfig as unknown as IMediaAppConfig;
|
|
17
19
|
const getMediaService = inject(getMediaBinSymbol)!;
|
|
18
|
-
const mediaService = getMediaService()
|
|
20
|
+
const mediaService = getMediaService();
|
|
19
21
|
const heightStyle = computed<StyleValue>(() => { return { height: appState.bodyHeight.value + 'px', overflowY: 'hidden' } });
|
|
20
22
|
const isMobile = appState.isMobile;
|
|
21
23
|
const headerText = ref("");
|
|
@@ -32,8 +34,9 @@
|
|
|
32
34
|
const hasCoordinates = ref(false);
|
|
33
35
|
const carousel = ref<ComponentPublicInstance | null>(null);
|
|
34
36
|
const itemName = ref("");
|
|
37
|
+
const showAllMetaData = ref(false);
|
|
38
|
+
const splitXmlMetaData = ref(false);
|
|
35
39
|
const zoom = 14;
|
|
36
|
-
let metadata: Dictionary<any>;
|
|
37
40
|
let album: IMediaFolder;
|
|
38
41
|
let origUrl = "";
|
|
39
42
|
let location: string;
|
|
@@ -46,317 +49,316 @@
|
|
|
46
49
|
const showName = ref(false);
|
|
47
50
|
|
|
48
51
|
watch([appState.bodyHeight, appState.pageWidth], () => {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
width.value = appState.pageWidth.value;
|
|
53
|
+
height.value = appState.bodyHeight.value;
|
|
54
|
+
landscape.value = width.value > height.value;
|
|
52
55
|
}, { immediate: true });
|
|
53
56
|
|
|
54
57
|
async function start(): Promise<boolean> {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
window.document.addEventListener('keydown', onKey);
|
|
59
|
+
appState.navigate.value = onNavigate;
|
|
60
|
+
if (carousel.value)
|
|
61
|
+
appState.fullScreenElement.value = carousel.value.$el as HTMLElement;
|
|
59
62
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
63
|
+
//if (mediaAppConfig.useMediaBin) {
|
|
64
|
+
const rc = await mediaService.initialize(EMediaType.Picture);
|
|
65
|
+
if (!rc)
|
|
66
|
+
return false;
|
|
67
|
+
//else {
|
|
68
|
+
// if (!mediaService.medialists["Picture.Event"])
|
|
69
|
+
// await (mediaService as MediaService).getLists(EMediaType.Picture);
|
|
70
|
+
//}
|
|
71
|
+
let list: IPictureFile[] = [];
|
|
72
|
+
if (route.query!.id) {
|
|
73
|
+
// by id usafe
|
|
74
|
+
const folderId = decodeURIComponent(route.query!.id!.toString());
|
|
75
|
+
let folder = mediaService.getFolder(folderId);
|
|
76
|
+
if (!folder) {
|
|
77
|
+
const split = folderId.split(/[.|]/);
|
|
78
|
+
await mediaService.getPhotosByCriteria(split[1], split[2]);
|
|
79
|
+
folder = mediaService.getFolder(folderId);
|
|
80
|
+
if (!folder)
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
album = await mediaService.getPhotos(folder);
|
|
84
|
+
list = album.files as IPictureFile[];
|
|
85
|
+
}
|
|
86
|
+
else if (route.query!.title) {
|
|
87
|
+
const title = decodeURIComponent(route.query!.title!.toString());
|
|
88
|
+
list = await MediaHelper.searchPictures(mediaService, title, route.query!.pers!.toString() === "true", route.query!.loc!.toString() === "true", mediaService.photoSelection.rating, mediaAppConfig.pictureSearchLimit);
|
|
89
|
+
}
|
|
90
|
+
if (list && list.length > 0) {
|
|
91
|
+
items.splice(0, items.length, ...list);
|
|
92
|
+
if (route.query.start) {
|
|
93
|
+
const start = route.query.start.toString();
|
|
94
|
+
const idx = items.findIndex((item) => item.dlnaid == start);
|
|
95
|
+
if (idx >= 0) {
|
|
96
|
+
index.value = idx;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
onUpdate();
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
nextTick(() => router.back());
|
|
103
|
+
}
|
|
104
|
+
return true;
|
|
102
105
|
}
|
|
103
106
|
onMounted(async () => {
|
|
104
|
-
|
|
107
|
+
await start();
|
|
105
108
|
});
|
|
106
109
|
onUnmounted(() => {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
110
|
+
appState.fullScreenElement.value = null;
|
|
111
|
+
window.document.removeEventListener('keydown', onKey);
|
|
112
|
+
appState.navigate.value = onNavigate;
|
|
113
|
+
if (keepBlobs && mediaAppConfig.useImagePreload) {
|
|
114
|
+
for (let i = 0; i < items.length; i++) {
|
|
115
|
+
const item = items[i];
|
|
116
|
+
if (item.blob && item.blob.startsWith('blob')) {
|
|
117
|
+
window.URL.revokeObjectURL(item.blob);
|
|
118
|
+
item.blob = undefined;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
119
122
|
});
|
|
120
123
|
function onNavigate(direction: EDirection): void {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
124
|
+
if (direction === EDirection.Left)
|
|
125
|
+
onKeyClick("ArrowLeft")
|
|
126
|
+
if (direction === EDirection.Right)
|
|
127
|
+
onKeyClick("ArrowRight")
|
|
125
128
|
}
|
|
126
129
|
|
|
127
130
|
function getQuality(pictureQuality: EPictureQuality) {
|
|
128
|
-
|
|
131
|
+
return pictureQuality % 1000;
|
|
129
132
|
}
|
|
130
133
|
function getFactor(pictureQuality: EPictureQuality) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
134
|
+
let factor = Math.floor(pictureQuality / 1000);
|
|
135
|
+
if (factor > 1 && appState.pixelRatio > 1)
|
|
136
|
+
factor = appState.pixelRatio;
|
|
137
|
+
return factor;
|
|
135
138
|
}
|
|
136
139
|
|
|
137
140
|
function getUrl(item: IPictureFile) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
141
|
+
const pictureQuality = mediaAppConfig.pictureQuality;
|
|
142
|
+
const quality = getQuality(pictureQuality);
|
|
143
|
+
const factor = getFactor(pictureQuality);
|
|
144
|
+
const albumUrl = album ? album.url : mediaService.getFolder(item.dlnaParentId).url;
|
|
145
|
+
if (landscape.value) {
|
|
146
|
+
let h = height.value * factor;
|
|
147
|
+
if (item.height <= h)
|
|
148
|
+
h = 0;
|
|
149
|
+
return mediaService.getPhotoUrl(albumUrl, item.url, `${0}x${h}x${item.orientation}x${quality}`);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
let w = width.value * factor;
|
|
153
|
+
if (item.width <= w)
|
|
154
|
+
w = 0;
|
|
155
|
+
return mediaService.getPhotoUrl(albumUrl, item.url, `${w}x${0}x${item.orientation}x${quality}`);
|
|
156
|
+
}
|
|
154
157
|
}
|
|
155
158
|
function getHeight(item: IPictureFile) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
159
|
+
const pictureQuality = mediaAppConfig.pictureQuality;
|
|
160
|
+
const factor = getFactor(pictureQuality);
|
|
161
|
+
if (pictureQuality == EPictureQuality.Full || factor > 1) {
|
|
162
|
+
if (landscape.value)
|
|
163
|
+
return height.value;
|
|
164
|
+
}
|
|
165
|
+
return undefined;
|
|
163
166
|
}
|
|
164
167
|
function getWidth(item: IPictureFile) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
168
|
+
const pictureQuality = mediaAppConfig.pictureQuality;
|
|
169
|
+
const factor = getFactor(pictureQuality);
|
|
170
|
+
if (pictureQuality == EPictureQuality.Full || factor > 1) {
|
|
171
|
+
if (!landscape.value)
|
|
172
|
+
return width.value;
|
|
173
|
+
}
|
|
174
|
+
return undefined;
|
|
172
175
|
}
|
|
173
176
|
function onShowMap(ev: Event) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
+
const current = items[index.value];
|
|
178
|
+
location = `${current.latitude! / 1000000}|${current.longitude! / 1000000}`;
|
|
179
|
+
showMap.value = true;
|
|
177
180
|
}
|
|
178
181
|
function onClick() {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
182
|
+
if (isMobile) {
|
|
183
|
+
if (mouseTimer >= 0) { // 2. click
|
|
184
|
+
window.clearTimeout(mouseTimer);
|
|
185
|
+
onKeyClick("KeyF");
|
|
186
|
+
mouseTimer = -1;
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
mouseTimer = window.setTimeout(() => {
|
|
190
|
+
mouseTimer = -1;
|
|
191
|
+
showKeys.value = true;
|
|
192
|
+
}, 500);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
const msecDiff = new Date().getTime() - mouseDownTime;
|
|
197
|
+
if (msecDiff < 500) {
|
|
198
|
+
if (appState.device != EDevice.Windows && appState.device != EDevice.Mac) {
|
|
199
|
+
showKeys.value = true;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
else
|
|
203
|
+
onKeyClick("KeyF");
|
|
204
|
+
mouseDownTime = 0;
|
|
205
|
+
}
|
|
203
206
|
}
|
|
204
207
|
function onMouseDown() {
|
|
205
|
-
|
|
208
|
+
mouseDownTime = new Date().getTime();
|
|
206
209
|
}
|
|
207
210
|
async function onKey(ev: KeyboardEvent) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
211
|
+
switch (ev.code) {
|
|
212
|
+
case "Escape":
|
|
213
|
+
if (appState.fullScreen.value) {
|
|
214
|
+
await appState.exitFullScreen();
|
|
215
|
+
showInfo.value = false;
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (showInfo.value) {
|
|
219
|
+
showInfo.value = false;
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (showKeys.value) {
|
|
223
|
+
showKeys.value = false;
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
router.back();
|
|
227
|
+
break;
|
|
228
|
+
case "ArrowLeft":
|
|
229
|
+
if (index.value > 0)
|
|
230
|
+
index.value--;
|
|
231
|
+
onUpdate();
|
|
232
|
+
break;
|
|
233
|
+
case "ArrowRight":
|
|
234
|
+
if (index.value < items.length - 1)
|
|
235
|
+
index.value++;
|
|
236
|
+
onUpdate();
|
|
237
|
+
break;
|
|
238
|
+
case "KeyI": // Info
|
|
239
|
+
if (showInfo.value) {
|
|
240
|
+
showInfo.value = false;
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
const item = items[index.value];
|
|
244
|
+
const folder = album ? album : mediaService.getFolder(item.dlnaParentId);
|
|
245
|
+
origUrl = mediaService.getPhotoUrl(folder.url, item.url, '0x0x0');
|
|
246
|
+
hasCoordinates.value = !!(item.flags & EPictureFlags.Has_Gps);
|
|
247
|
+
headerText.value = "Metadaten - " + item.name;
|
|
248
|
+
showInfo.value = true;
|
|
249
|
+
}
|
|
250
|
+
break;
|
|
251
|
+
case "KeyC": // Continue
|
|
252
|
+
cycle.value = true;
|
|
253
|
+
break;
|
|
254
|
+
case "KeyF": // Fullscreen
|
|
255
|
+
showInfo.value = false;
|
|
256
|
+
if (appState.fullScreen.value) {
|
|
257
|
+
await appState.exitFullScreen();
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
if (carousel.value) {
|
|
261
|
+
await appState.setFullScreen();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
break;
|
|
265
|
+
case "KeyP":
|
|
266
|
+
case "Digit0":
|
|
267
|
+
cycle.value = false;
|
|
268
|
+
break;
|
|
269
|
+
case "Digit1":
|
|
270
|
+
cycle.value = true; interval.value = 1000;
|
|
271
|
+
break;
|
|
272
|
+
case "Digit2":
|
|
273
|
+
cycle.value = true; interval.value = 2000;
|
|
274
|
+
break;
|
|
275
|
+
case "Digit3":
|
|
276
|
+
cycle.value = true; interval.value = 3000;
|
|
277
|
+
break;
|
|
278
|
+
case "Digit4":
|
|
279
|
+
cycle.value = true; interval.value = 4000;
|
|
280
|
+
break;
|
|
281
|
+
case "Digit5":
|
|
282
|
+
cycle.value = true; interval.value = 5000;
|
|
283
|
+
break;
|
|
284
|
+
case "Digit6":
|
|
285
|
+
cycle.value = true; interval.value = 6000;
|
|
286
|
+
break;
|
|
287
|
+
case "Digit7":
|
|
288
|
+
cycle.value = true; interval.value = 7000;
|
|
289
|
+
break;
|
|
290
|
+
case "Digit8":
|
|
291
|
+
cycle.value = true; interval.value = 8000;
|
|
292
|
+
break;
|
|
293
|
+
case "Digit9":
|
|
294
|
+
cycle.value = true; interval.value = 9000;
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
295
297
|
}
|
|
296
298
|
function onKeyClick(code: string) {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
299
|
+
showKeys.value = false;
|
|
300
|
+
if (code != 'close') {
|
|
301
|
+
const keyEvent = new KeyboardEvent("key", { "code": code, "bubbles": true, "cancelable": false });
|
|
302
|
+
onKey(keyEvent);
|
|
303
|
+
}
|
|
302
304
|
}
|
|
303
305
|
function onDownload() {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
306
|
+
const anchor = document.createElement("a");
|
|
307
|
+
anchor.href = origUrl;
|
|
308
|
+
anchor.download = items[index.value].url;
|
|
309
|
+
document.body.appendChild(anchor);
|
|
310
|
+
anchor.click();
|
|
311
|
+
document.body.removeChild(anchor);
|
|
312
|
+
showInfo.value = false;
|
|
311
313
|
}
|
|
312
314
|
function clearName() { // also called by VImg::loadstart
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
315
|
+
showName.value = false;
|
|
316
|
+
itemName.value = "";
|
|
317
|
+
if (nameTimer >= 0) {
|
|
318
|
+
window.clearTimeout(nameTimer);
|
|
319
|
+
nameTimer = -1;
|
|
320
|
+
}
|
|
319
321
|
}
|
|
320
322
|
function onUpdate() { // Carousel updated
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
323
|
+
showInfo.value = false;
|
|
324
|
+
clearName();
|
|
325
|
+
const item = items[index.value];
|
|
326
|
+
if (mediaAppConfig.useImagePreload) {
|
|
327
|
+
if (index.value != nextIndex && !item.blob) {
|
|
328
|
+
createBlob(item);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
item.blob = getUrl(item);
|
|
333
|
+
}
|
|
334
|
+
nameTimer = window.setTimeout(() => { onLoad(item); }, 200);
|
|
333
335
|
}
|
|
334
336
|
function onLoad(item: IPictureFile) { // img loaded or cached
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
337
|
+
if (mediaAppConfig.useImagePreload) {
|
|
338
|
+
if (item.blob && item.blob.startsWith("blob")) {
|
|
339
|
+
if (!keepBlobs)
|
|
340
|
+
window.URL.revokeObjectURL(item.blob);
|
|
341
|
+
const next = index.value + 1;
|
|
342
|
+
if (next < items.length && next > nextIndex) {
|
|
343
|
+
nextIndex = next;
|
|
344
|
+
createBlob(items[nextIndex]);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
clearName();
|
|
349
|
+
if (item.title) {
|
|
350
|
+
showName.value = true;
|
|
351
|
+
itemName.value = item.title;
|
|
352
|
+
nameTimer = window.setTimeout(() => { clearName(); }, mediaAppConfig.nameDurationMS);
|
|
353
|
+
}
|
|
352
354
|
}
|
|
353
|
-
function createBlob
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
355
|
+
function createBlob(item: IPictureFile) {
|
|
356
|
+
item.blob = appConfig.urlPrefix + "img/Wait.png";
|
|
357
|
+
const url = getUrl(item).substr(mediaUrlLength); // trim mediaserver url
|
|
358
|
+
mediaService.getImage(url)
|
|
359
|
+
.then((blob) => {
|
|
360
|
+
item.blob = window.URL.createObjectURL(blob);
|
|
361
|
+
});
|
|
360
362
|
|
|
361
363
|
}
|
|
362
364
|
</script>
|
|
@@ -375,19 +377,21 @@
|
|
|
375
377
|
<v-card v-if="showInfo" >
|
|
376
378
|
<v-card-title class="headline">{{headerText}}</v-card-title>
|
|
377
379
|
<v-card-text>
|
|
378
|
-
<photo-meta-data :file="items[index]" :
|
|
380
|
+
<photo-meta-data :file="items[index]" :all="showAllMetaData" :splitxmp="splitXmlMetaData"></photo-meta-data>
|
|
379
381
|
</v-card-text>
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
382
|
+
<v-card-actions>
|
|
383
|
+
<v-btn @click="showInfo = false">
|
|
384
|
+
<v-icon size="large" icon="$back" />
|
|
385
|
+
</v-btn>
|
|
386
|
+
<v-btn @click="showAllMetaData = !showAllMetaData">{{showAllMetaData ? "SHOW IMPORTANT" : "SHOW ALL"}}</v-btn>
|
|
387
|
+
<v-btn v-if="showAllMetaData" @click="splitXmlMetaData = !splitXmlMetaData">{{splitXmlMetaData ? "NO SPLIT" : "SPLIT"}}</v-btn>
|
|
388
|
+
<v-btn v-if="hasCoordinates" @click="onShowMap">
|
|
389
|
+
<v-icon size="large" icon="$gps" />
|
|
390
|
+
</v-btn>
|
|
391
|
+
<v-btn @click="onDownload">
|
|
392
|
+
<v-icon size="large" icon="$download" />
|
|
393
|
+
</v-btn>
|
|
394
|
+
</v-card-actions>
|
|
391
395
|
</v-card>
|
|
392
396
|
</v-dialog>
|
|
393
397
|
<v-dialog v-model="showKeys" :fullscreen="isMobile" width="50%" >
|