incyclist-services 1.6.1 → 1.6.3
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/lib/activities/list/service.js +30 -10
- package/lib/activities/ride/service.d.ts +1 -0
- package/lib/activities/ride/service.js +10 -1
- package/lib/apps/base/api/strava/api.d.ts +1 -0
- package/lib/apps/base/api/strava/api.js +6 -1
- package/lib/devices/configuration/service.js +1 -1
- package/lib/devices/pairing/service.js +1 -1
- package/lib/ride/display/service.js +13 -7
- package/lib/ride/route/RLVDisplayService.d.ts +4 -1
- package/lib/ride/route/RLVDisplayService.js +51 -5
- package/lib/routes/list/service.d.ts +1 -0
- package/lib/routes/list/service.js +42 -0
- package/lib/video/VideoSyncHelper.js +20 -9
- package/package.json +2 -2
|
@@ -79,7 +79,7 @@ let ActivityListService = (() => {
|
|
|
79
79
|
preload(props) {
|
|
80
80
|
let preloadObserver = this.getPreloadObserver();
|
|
81
81
|
try {
|
|
82
|
-
if (
|
|
82
|
+
if (preloadObserver === undefined || preloadObserver === null) {
|
|
83
83
|
this.logEvent({ message: 'preload activity list' });
|
|
84
84
|
const promise = this.loadActivities();
|
|
85
85
|
preloadObserver = this.observers.preload = new observer_1.PromiseObserver(promise);
|
|
@@ -247,10 +247,17 @@ let ActivityListService = (() => {
|
|
|
247
247
|
if (!activity) {
|
|
248
248
|
return false;
|
|
249
249
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
250
|
+
return new Promise(done => {
|
|
251
|
+
const emitUpdate = (update) => __awaiter(this, void 0, void 0, function* () {
|
|
252
|
+
this.exports = yield this.selected.getExports();
|
|
253
|
+
this.emitSelected('updated');
|
|
254
|
+
if (update.status === 'done')
|
|
255
|
+
done(update.success);
|
|
256
|
+
});
|
|
257
|
+
const observer = new observer_1.Observer();
|
|
258
|
+
observer.on('export', emitUpdate);
|
|
259
|
+
activity.export(format, observer);
|
|
260
|
+
});
|
|
254
261
|
});
|
|
255
262
|
}
|
|
256
263
|
upload(connectedApp) {
|
|
@@ -259,11 +266,24 @@ let ActivityListService = (() => {
|
|
|
259
266
|
if (!activity) {
|
|
260
267
|
return false;
|
|
261
268
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
269
|
+
return new Promise(done => {
|
|
270
|
+
const emitUploadUpdate = (update) => {
|
|
271
|
+
if (connectedApp === update.connectedApp) {
|
|
272
|
+
this.emitSelected('updated');
|
|
273
|
+
if (update.status === 'done') {
|
|
274
|
+
done(update.success);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
const emitExportUpdate = (update) => __awaiter(this, void 0, void 0, function* () {
|
|
279
|
+
this.exports = yield this.selected.getExports();
|
|
280
|
+
this.emitSelected('updated');
|
|
281
|
+
});
|
|
282
|
+
const observer = new observer_1.Observer();
|
|
283
|
+
observer.on('upload', emitUploadUpdate);
|
|
284
|
+
observer.on('export', emitExportUpdate);
|
|
285
|
+
activity.upload(connectedApp, observer);
|
|
286
|
+
});
|
|
267
287
|
});
|
|
268
288
|
}
|
|
269
289
|
openRoute() {
|
|
@@ -225,7 +225,15 @@ let ActivityRideService = (() => {
|
|
|
225
225
|
const display = Math.floor(time / 3) % 2;
|
|
226
226
|
const avgMaxStats = (display === 0) ? this.getAverageValues() : this.getMaximumValues();
|
|
227
227
|
const info = this.buildDashboardInfo(currentValues, avgMaxStats, display);
|
|
228
|
-
|
|
228
|
+
let showLog = true;
|
|
229
|
+
try {
|
|
230
|
+
const infoStr = JSON.stringify(info);
|
|
231
|
+
showLog = infoStr !== this.current.info;
|
|
232
|
+
this.current.info = infoStr;
|
|
233
|
+
}
|
|
234
|
+
catch (_a) { }
|
|
235
|
+
if (showLog)
|
|
236
|
+
this.logEvent({ message: 'Dashboard update', items: info.map(i => { var _a, _b, _c, _d, _e, _f; return `${i.title}:${(_b = (_a = i.data[0]) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : ''}:${(_d = (_c = i.data[1]) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : ''}${((_e = i.data[1]) === null || _e === void 0 ? void 0 : _e.label) ? '(' + ((_f = i.data[1]) === null || _f === void 0 ? void 0 : _f.label) + ')' : ''}`; }).join('|') });
|
|
229
237
|
return info;
|
|
230
238
|
}
|
|
231
239
|
catch (err) {
|
|
@@ -654,6 +662,7 @@ let ActivityRideService = (() => {
|
|
|
654
662
|
}
|
|
655
663
|
this.current.deviceData = Object.assign(Object.assign({}, this.current.deviceData), update);
|
|
656
664
|
if (this.state !== 'active') {
|
|
665
|
+
this.emit('data');
|
|
657
666
|
if (this.state === 'paused' && (data.power > 0 || data.cadence > 0) && this.current.isAutoResume) {
|
|
658
667
|
this.resume('system');
|
|
659
668
|
return;
|
|
@@ -28,6 +28,7 @@ export declare class StravaApi extends AppApiBase {
|
|
|
28
28
|
protected verifyToken(): Promise<void>;
|
|
29
29
|
protected isTokenStillValid(): boolean;
|
|
30
30
|
protected verifyAuthentication(): Promise<void>;
|
|
31
|
+
protected waitForReady(): Promise<void>;
|
|
31
32
|
protected waitForUploadResponse(response: StravaUploadResponse): Promise<StravaUploadResult>;
|
|
32
33
|
protected createUpload(request: StravaUploadRequest): Promise<StravaUploadResponse>;
|
|
33
34
|
protected getUploadById(id: string): Promise<StravaUploadResponse>;
|
|
@@ -125,11 +125,16 @@ class StravaApi extends base_1.AppApiBase {
|
|
|
125
125
|
yield this.verifyToken();
|
|
126
126
|
});
|
|
127
127
|
}
|
|
128
|
+
waitForReady() {
|
|
129
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
130
|
+
yield (0, utils_1.sleep)(1000);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
128
133
|
waitForUploadResponse(response) {
|
|
129
134
|
return __awaiter(this, void 0, void 0, function* () {
|
|
130
135
|
let data = response;
|
|
131
136
|
while (data.status !== 'Your activity is ready.' && !data.error) {
|
|
132
|
-
yield
|
|
137
|
+
yield this.waitForReady();
|
|
133
138
|
data = yield this.getUploadById(data.id_str);
|
|
134
139
|
}
|
|
135
140
|
if (data.error) {
|
|
@@ -391,7 +391,7 @@ let DeviceConfigurationService = (() => {
|
|
|
391
391
|
if (adapter.getSupportedCyclingModes) {
|
|
392
392
|
modes = adapter.getSupportedCyclingModes();
|
|
393
393
|
}
|
|
394
|
-
const options = modes.map(M =>
|
|
394
|
+
const options = modes.map(M => adapter.createMode(M));
|
|
395
395
|
mode = requestedMode || device.mode;
|
|
396
396
|
if (!mode) {
|
|
397
397
|
modeObj = adapter.getDefaultCyclingMode();
|
|
@@ -831,7 +831,7 @@ class DevicePairingService extends service_2.IncyclistService {
|
|
|
831
831
|
}
|
|
832
832
|
checkPairingSuccess() {
|
|
833
833
|
const configReadyToRide = this.configuration.canStartRide();
|
|
834
|
-
if (!configReadyToRide)
|
|
834
|
+
if (!configReadyToRide || this.isScanning())
|
|
835
835
|
return false;
|
|
836
836
|
const control = this.getCapability(incyclist_devices_1.IncyclistCapability.Control);
|
|
837
837
|
const power = this.getCapability(incyclist_devices_1.IncyclistCapability.Power);
|
|
@@ -164,7 +164,7 @@ let RideDisplayService = (() => {
|
|
|
164
164
|
try {
|
|
165
165
|
const props = this.getStartOverlayProps();
|
|
166
166
|
this.logEvent({ message: 'button clicked', overlay: 'start overlay', button: 'Cancel', reason: 'user cancel', state: props, eventSource: 'user' });
|
|
167
|
-
yield this.stopRide();
|
|
167
|
+
yield this.stopRide({ noStateUpdates: true });
|
|
168
168
|
}
|
|
169
169
|
catch (err) {
|
|
170
170
|
this.logError(err, 'cancelStart');
|
|
@@ -173,6 +173,9 @@ let RideDisplayService = (() => {
|
|
|
173
173
|
}
|
|
174
174
|
pause(requester = 'user') {
|
|
175
175
|
var _a, _b;
|
|
176
|
+
if (requester === 'device' && this.isResuming) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
176
179
|
try {
|
|
177
180
|
if (this.state !== 'Active')
|
|
178
181
|
return;
|
|
@@ -198,10 +201,8 @@ let RideDisplayService = (() => {
|
|
|
198
201
|
this.state = 'Active';
|
|
199
202
|
this.getActivityRide().resume();
|
|
200
203
|
this.getWorkoutRide().resume();
|
|
201
|
-
this.
|
|
204
|
+
this.pauseReason = 'device';
|
|
202
205
|
(_b = this.observer) === null || _b === void 0 ? void 0 : _b.emit('state-update', this.state);
|
|
203
|
-
(0, utils_1.waitNextTick)().then(() => this.isResuming = false);
|
|
204
|
-
delete this.pauseReason;
|
|
205
206
|
}
|
|
206
207
|
catch (err) {
|
|
207
208
|
this.logError(err, 'resume');
|
|
@@ -545,10 +546,15 @@ let RideDisplayService = (() => {
|
|
|
545
546
|
const currentValues = this.getActivityRide().getCurrentValues();
|
|
546
547
|
if (!currentValues)
|
|
547
548
|
return;
|
|
548
|
-
if (currentValues.speed === 0) {
|
|
549
|
+
if (currentValues.speed === 0 && !this.isResuming) {
|
|
549
550
|
this.pause('device');
|
|
550
551
|
return;
|
|
551
552
|
}
|
|
553
|
+
if (currentValues.speed > 0 && this.isResuming) {
|
|
554
|
+
this.displayService.resume();
|
|
555
|
+
this.isResuming = false;
|
|
556
|
+
delete this.pauseReason;
|
|
557
|
+
}
|
|
552
558
|
this.getRideModeService().onActivityUpdate(data, currentValues);
|
|
553
559
|
this.observer.emit('data-update', data, currentValues);
|
|
554
560
|
}
|
|
@@ -591,7 +597,6 @@ let RideDisplayService = (() => {
|
|
|
591
597
|
}
|
|
592
598
|
}
|
|
593
599
|
onLapCompleted(oldLap, newLap) {
|
|
594
|
-
console.log('# lap completed', oldLap, newLap);
|
|
595
600
|
}
|
|
596
601
|
onRouteUpdated(route) {
|
|
597
602
|
this.getActivityRide().onRouteUpdate(route.points);
|
|
@@ -891,7 +896,7 @@ let RideDisplayService = (() => {
|
|
|
891
896
|
udid: d.udid,
|
|
892
897
|
isControl: d.isControl,
|
|
893
898
|
capabilities: d.capabilities,
|
|
894
|
-
status:
|
|
899
|
+
status: 'Starting'
|
|
895
900
|
}));
|
|
896
901
|
this.updateStartOverlay();
|
|
897
902
|
}
|
|
@@ -974,6 +979,7 @@ let RideDisplayService = (() => {
|
|
|
974
979
|
const pct = Math.round(completed / total * 100);
|
|
975
980
|
this.logEvent({ message: 'onDeviceStartStatusUpdate', pct });
|
|
976
981
|
startDevice.stateText = `uploading (${pct}%)`;
|
|
982
|
+
this.checkStartStatus();
|
|
977
983
|
}
|
|
978
984
|
onDeviceData(data, udid) {
|
|
979
985
|
this.deviceData = data;
|
|
@@ -35,11 +35,13 @@ export declare class RLVDisplayService extends RouteDisplayService {
|
|
|
35
35
|
protected infotext?: InfotextDisplayProps;
|
|
36
36
|
protected videosInitialized: boolean;
|
|
37
37
|
protected startTime: number;
|
|
38
|
+
protected isVideoPaused: boolean;
|
|
38
39
|
constructor();
|
|
39
40
|
initView(): void;
|
|
40
41
|
getOverlayProps(overlay: any, props: CurrentRideDisplayProps): OverlayDisplayProps;
|
|
41
42
|
protected addVideo(route: Route, isCurrent?: boolean, parent?: VideoState): Promise<void>;
|
|
42
43
|
pause(): void;
|
|
44
|
+
resume(): void;
|
|
43
45
|
getDisplayProperties(props: CurrentRideDisplayProps): RLVDisplayProps;
|
|
44
46
|
protected getInfotextDisplayProps(): InfotextDisplayProps;
|
|
45
47
|
protected checkFinishOptions(position: CurrentPosition): boolean;
|
|
@@ -74,13 +76,14 @@ export declare class RLVDisplayService extends RouteDisplayService {
|
|
|
74
76
|
start: number;
|
|
75
77
|
end: number;
|
|
76
78
|
}>, video?: VideoState): void;
|
|
79
|
+
protected getCode(error: MediaError): any;
|
|
77
80
|
protected onVideoPlaybackError(error: MediaError, video?: VideoState): void;
|
|
78
81
|
protected onVideoPlayBackUpdate(time: number, rate: number, e: any, video?: VideoState): void;
|
|
79
82
|
protected onVideoEnded(video?: VideoState): void;
|
|
80
83
|
onActivityUpdate(activityPos: ActivityUpdate, data: any): void;
|
|
81
84
|
protected initVideoSource(video: VideoState): VideoConversion;
|
|
82
85
|
protected initMp4VideoSource(video: VideoState): void;
|
|
83
|
-
protected buildVideoError(error: MediaError): string;
|
|
86
|
+
protected buildVideoError(error: MediaError, video?: VideoState): string;
|
|
84
87
|
protected getVideoUrl(video: VideoState): string;
|
|
85
88
|
protected getVideoTime(routeDistance: number, video?: VideoState): number;
|
|
86
89
|
protected initAviVideoSource(video: VideoState): VideoConversion;
|
|
@@ -62,6 +62,7 @@ let RLVDisplayService = (() => {
|
|
|
62
62
|
super();
|
|
63
63
|
this.currentVideo = __runInitializers(this, _instanceExtraInitializers);
|
|
64
64
|
this.videosInitialized = false;
|
|
65
|
+
this.isVideoPaused = false;
|
|
65
66
|
this.isInitialized = false;
|
|
66
67
|
}
|
|
67
68
|
initView() {
|
|
@@ -130,6 +131,12 @@ let RLVDisplayService = (() => {
|
|
|
130
131
|
pause() {
|
|
131
132
|
super.pause();
|
|
132
133
|
this.currentVideo.syncHelper.pause();
|
|
134
|
+
this.isVideoPaused = true;
|
|
135
|
+
}
|
|
136
|
+
resume() {
|
|
137
|
+
super.resume();
|
|
138
|
+
this.currentVideo.syncHelper.resume();
|
|
139
|
+
this.isVideoPaused = false;
|
|
133
140
|
}
|
|
134
141
|
getDisplayProperties(props) {
|
|
135
142
|
var _b, _c, _d, _e;
|
|
@@ -345,9 +352,12 @@ let RLVDisplayService = (() => {
|
|
|
345
352
|
}
|
|
346
353
|
onVideoLoadError(error, video = this.currentVideo) {
|
|
347
354
|
video.loaded = false;
|
|
348
|
-
video.error = this.buildVideoError(error);
|
|
349
|
-
if (
|
|
350
|
-
this.logEvent({ message: 'could not load
|
|
355
|
+
video.error = this.buildVideoError(error, video);
|
|
356
|
+
if (video.isInitial) {
|
|
357
|
+
this.logEvent({ message: 'could not load video', video: this.getVideoUrl(video), error: error.message, errorCode: this.getCode(error) });
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
this.logEvent({ message: 'could not load next video', video: this.getVideoUrl(video), error: error.message, errorCode: this.getCode(error) });
|
|
351
361
|
const errIdx = this.videos.indexOf(video);
|
|
352
362
|
if (errIdx !== -1) {
|
|
353
363
|
this.videos.splice(errIdx);
|
|
@@ -363,7 +373,27 @@ let RLVDisplayService = (() => {
|
|
|
363
373
|
onVideoWaiting(time, rate, bufferedTime, buffers, video = this.currentVideo) {
|
|
364
374
|
video.syncHelper.onVideoWaiting(time, rate, bufferedTime, buffers);
|
|
365
375
|
}
|
|
376
|
+
getCode(error) {
|
|
377
|
+
const codes = ['MEDIA_ERR_ABORTED', 'MEDIA_ERR_NETWORK', 'MEDIA_ERR_DECODE', 'MEDIA_ERR_SRC_NOT_SUPPORTED'];
|
|
378
|
+
try {
|
|
379
|
+
let codeStr;
|
|
380
|
+
if (error.code !== undefined) {
|
|
381
|
+
codeStr = codes === null || codes === void 0 ? void 0 : codes[error.code - 1];
|
|
382
|
+
if (codeStr) {
|
|
383
|
+
codeStr = `${codeStr} (${error.code})`;
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
codeStr = error.code.toString();
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return codeStr;
|
|
390
|
+
}
|
|
391
|
+
catch (err) {
|
|
392
|
+
this.logError(err, 'getCode');
|
|
393
|
+
}
|
|
394
|
+
}
|
|
366
395
|
onVideoPlaybackError(error, video = this.currentVideo) {
|
|
396
|
+
this.logEvent({ message: 'video playback error', video: this.getVideoUrl(video), error: error.message, errorCode: this.getCode(error) });
|
|
367
397
|
}
|
|
368
398
|
onVideoPlayBackUpdate(time, rate, e, video = this.currentVideo) {
|
|
369
399
|
video.syncHelper.onVideoPlaybackUpdate(time, rate, e);
|
|
@@ -380,7 +410,9 @@ let RLVDisplayService = (() => {
|
|
|
380
410
|
super.onActivityUpdate(activityPos, data);
|
|
381
411
|
const offset = (_b = this.offset) !== null && _b !== void 0 ? _b : 0;
|
|
382
412
|
const { routeDistance, speed } = activityPos;
|
|
383
|
-
this.
|
|
413
|
+
if (!this.isVideoPaused) {
|
|
414
|
+
this.currentVideo.syncHelper.onActivityUpdate(routeDistance - offset, speed);
|
|
415
|
+
}
|
|
384
416
|
}
|
|
385
417
|
initVideoSource(video) {
|
|
386
418
|
var _b, _c;
|
|
@@ -404,7 +436,21 @@ let RLVDisplayService = (() => {
|
|
|
404
436
|
video.playback = 'native';
|
|
405
437
|
}
|
|
406
438
|
}
|
|
407
|
-
buildVideoError(error) {
|
|
439
|
+
buildVideoError(error, video = this.currentVideo) {
|
|
440
|
+
const src = this.getVideoUrl(video);
|
|
441
|
+
const remote = src === null || src === void 0 ? void 0 : src.startsWith('http');
|
|
442
|
+
switch (error.code) {
|
|
443
|
+
case MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED:
|
|
444
|
+
if (error.message.includes('Format error'))
|
|
445
|
+
return remote ? 'Could not load video' : 'Could not open video file';
|
|
446
|
+
return 'Could not decode video';
|
|
447
|
+
case MediaError.MEDIA_ERR_NETWORK:
|
|
448
|
+
return remote ? 'Could not load video' : 'Could not open video file';
|
|
449
|
+
case MediaError.MEDIA_ERR_ABORTED:
|
|
450
|
+
return 'The playback was canceled';
|
|
451
|
+
case MediaError.MEDIA_ERR_DECODE:
|
|
452
|
+
return 'Could not decode video';
|
|
453
|
+
}
|
|
408
454
|
return error.message;
|
|
409
455
|
}
|
|
410
456
|
getVideoUrl(video) {
|
|
@@ -176,6 +176,7 @@ export declare class RouteListService extends IncyclistService implements IRoute
|
|
|
176
176
|
private selectListForSource;
|
|
177
177
|
private addCustomList;
|
|
178
178
|
createPreview(descr: RouteInfo): Promise<unknown>;
|
|
179
|
+
protected checkExistingPreviewFiles(descr: RouteInfo): Promise<string | undefined>;
|
|
179
180
|
protected doCreatePreview(descr: RouteInfo): Promise<string>;
|
|
180
181
|
protected processPreviewQueue(): PromiseObserver<void>;
|
|
181
182
|
protected findCard(target: Route | string): {
|
|
@@ -993,6 +993,45 @@ let RouteListService = (() => {
|
|
|
993
993
|
});
|
|
994
994
|
});
|
|
995
995
|
}
|
|
996
|
+
checkExistingPreviewFiles(descr) {
|
|
997
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
998
|
+
var _a;
|
|
999
|
+
const videoUrl = descr.videoUrl || descr.downloadUrl;
|
|
1000
|
+
const path = (0, api_1.getBindings)().path;
|
|
1001
|
+
const fs = (0, api_1.getBindings)().fs;
|
|
1002
|
+
let existingPreview;
|
|
1003
|
+
let fileUrl = false;
|
|
1004
|
+
try {
|
|
1005
|
+
let { dir, name } = (_a = path.parse(videoUrl)) !== null && _a !== void 0 ? _a : {};
|
|
1006
|
+
if (!dir.startsWith('htttp')) {
|
|
1007
|
+
if (dir.startsWith('video:')) {
|
|
1008
|
+
dir = dir.replace('video:', 'file:');
|
|
1009
|
+
}
|
|
1010
|
+
if (dir.startsWith('file:///')) {
|
|
1011
|
+
dir = dir.replace('file:///', '');
|
|
1012
|
+
fileUrl = true;
|
|
1013
|
+
}
|
|
1014
|
+
const check = (name) => __awaiter(this, void 0, void 0, function* () {
|
|
1015
|
+
if (existingPreview)
|
|
1016
|
+
return;
|
|
1017
|
+
if (yield fs.existsFile(name))
|
|
1018
|
+
existingPreview = name;
|
|
1019
|
+
});
|
|
1020
|
+
yield check(path.join(dir, 'preview.png'));
|
|
1021
|
+
yield check(path.join(dir, 'preview.jpg'));
|
|
1022
|
+
yield check(path.join(dir, `${name}_preview.png`));
|
|
1023
|
+
yield check(path.join(dir, `${name}_preview.jpg`));
|
|
1024
|
+
if (existingPreview) {
|
|
1025
|
+
this.logEvent({ message: 'found preview', title: descr.title, id: descr.id, video: videoUrl, existingPreview });
|
|
1026
|
+
descr.previewUrl = fileUrl ? `file:///${existingPreview}` : existingPreview;
|
|
1027
|
+
return descr.previewUrl;
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
catch (_b) {
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
996
1035
|
doCreatePreview(descr) {
|
|
997
1036
|
return __awaiter(this, void 0, void 0, function* () {
|
|
998
1037
|
let props;
|
|
@@ -1005,6 +1044,9 @@ let RouteListService = (() => {
|
|
|
1005
1044
|
const fs = (0, api_1.getBindings)().fs;
|
|
1006
1045
|
const outDir = path.join(appInfo.getAppDir(), 'previewImg');
|
|
1007
1046
|
yield fs.ensureDir(outDir);
|
|
1047
|
+
const existing = yield this.checkExistingPreviewFiles(descr);
|
|
1048
|
+
if (existing)
|
|
1049
|
+
return existing;
|
|
1008
1050
|
if (!videoUrl)
|
|
1009
1051
|
return;
|
|
1010
1052
|
if (videoUrl.startsWith('http')) {
|
|
@@ -24,12 +24,16 @@ class VideoSyncHelper extends service_1.IncyclistService {
|
|
|
24
24
|
this.logPlaybackSummary();
|
|
25
25
|
this.isPaused = true;
|
|
26
26
|
this.send('rate-update', 0);
|
|
27
|
+
this.activityStatus.ts = Date.now();
|
|
28
|
+
this.rlvStatus.ts = Date.now();
|
|
27
29
|
}
|
|
28
30
|
resume() {
|
|
29
31
|
if (this.isStopped)
|
|
30
32
|
return;
|
|
31
33
|
this.logEvent({ message: 'video resumed', route: this.route.details.title });
|
|
32
34
|
this.isPaused = false;
|
|
35
|
+
this.activityStatus.ts = Date.now();
|
|
36
|
+
this.rlvStatus.ts = Date.now();
|
|
33
37
|
}
|
|
34
38
|
reset() {
|
|
35
39
|
this.logEvent({ message: 'video reset', route: this.route.details.title });
|
|
@@ -64,7 +68,7 @@ class VideoSyncHelper extends service_1.IncyclistService {
|
|
|
64
68
|
try {
|
|
65
69
|
this.endTime = (_a = this.endTime) !== null && _a !== void 0 ? _a : this.getVideoTimeByPosition((_b = this.route.description) === null || _b === void 0 ? void 0 : _b.distance);
|
|
66
70
|
const endTime = this.endTime;
|
|
67
|
-
if (this.isStopped)
|
|
71
|
+
if (this.isStopped || this.isPaused)
|
|
68
72
|
return;
|
|
69
73
|
if (time > endTime - 0.3 && !this.loopMode && !this.rlvStatus.timeRequested) {
|
|
70
74
|
this.updateRate(0);
|
|
@@ -203,7 +207,7 @@ class VideoSyncHelper extends service_1.IncyclistService {
|
|
|
203
207
|
this.onUpdate(updates);
|
|
204
208
|
}
|
|
205
209
|
onUpdate(updates = []) {
|
|
206
|
-
var _a, _b, _c;
|
|
210
|
+
var _a, _b, _c, _d;
|
|
207
211
|
if (this.isStopped || this.rlvStatus.timeRequested)
|
|
208
212
|
return;
|
|
209
213
|
try {
|
|
@@ -240,13 +244,16 @@ class VideoSyncHelper extends service_1.IncyclistService {
|
|
|
240
244
|
this.logEvent({ message: 'video debug', videoState: this.rlvStatus, activityState: this.activityStatus });
|
|
241
245
|
}
|
|
242
246
|
};
|
|
243
|
-
if (this.loopMode &&
|
|
244
|
-
|
|
247
|
+
if (this.loopMode && actDistance > totalDistance) {
|
|
248
|
+
actDistance = actDistance % totalDistance;
|
|
249
|
+
rlvDistance = rlvDistance % totalDistance;
|
|
245
250
|
}
|
|
246
|
-
|
|
247
|
-
|
|
251
|
+
let delta = rlvDistance - actDistance;
|
|
252
|
+
if (this.loopMode) {
|
|
253
|
+
const deltaActAhead = rlvDistance - (actDistance + totalDistance);
|
|
254
|
+
const deltaRlvAhead = (rlvDistance + totalDistance) - actDistance;
|
|
255
|
+
delta = [delta, deltaActAhead, deltaRlvAhead].reduce((best, cur) => Math.abs(cur) < Math.abs(best) ? cur : best, delta);
|
|
248
256
|
}
|
|
249
|
-
const delta = rlvDistance - actDistance;
|
|
250
257
|
if (Math.abs(delta) > Math.abs(this.maxDelta)) {
|
|
251
258
|
this.maxDelta = delta;
|
|
252
259
|
}
|
|
@@ -274,13 +281,13 @@ class VideoSyncHelper extends service_1.IncyclistService {
|
|
|
274
281
|
return;
|
|
275
282
|
}
|
|
276
283
|
const tTarget = 5;
|
|
277
|
-
const maxCorrection = Math.max(20, this.rlvStatus.time < 100 ? 15 : this.bufferedTime / 2.5 * 15);
|
|
284
|
+
const maxCorrection = Math.max(20, this.rlvStatus.time < 100 ? 15 : ((_c = this.bufferedTime) !== null && _c !== void 0 ? _c : 0) / 2.5 * 15);
|
|
278
285
|
const correction = Math.sign(delta) * Math.min(Math.abs(delta), maxCorrection);
|
|
279
286
|
const rate = (this.activityStatus.speed - correction / tTarget * 3.6) / this.rlvStatus.speed;
|
|
280
287
|
this.updateRate(rate);
|
|
281
288
|
}
|
|
282
289
|
}
|
|
283
|
-
this.cpuTime = ((
|
|
290
|
+
this.cpuTime = ((_d = this.cpuTime) !== null && _d !== void 0 ? _d : 0) + (Date.now() - tsStart);
|
|
284
291
|
}
|
|
285
292
|
catch (err) {
|
|
286
293
|
this.logError(err, 'onUpdate');
|
|
@@ -305,6 +312,10 @@ class VideoSyncHelper extends service_1.IncyclistService {
|
|
|
305
312
|
if (this.isPaused && rate > 0) {
|
|
306
313
|
this.resume();
|
|
307
314
|
}
|
|
315
|
+
else if (this.isPaused && rate === 0) {
|
|
316
|
+
delete this.rlvStatus.rateRequested;
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
308
319
|
this.rlvStatus.rateRequested = rate;
|
|
309
320
|
this.send('rate-update', rate);
|
|
310
321
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "incyclist-services",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.3",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"gd-eventlog": "^0.1.26"
|
|
6
6
|
},
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"axios": "^1.8.2",
|
|
45
|
-
"incyclist-devices": "^2.4.
|
|
45
|
+
"incyclist-devices": "^2.4.9",
|
|
46
46
|
"promise.any": "^2.0.6",
|
|
47
47
|
"semver": "^7.6.3",
|
|
48
48
|
"tcx-builder": "^1.1.1",
|