incyclist-services 1.6.2 → 1.6.4
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/ride/service.d.ts +1 -0
- package/lib/activities/ride/service.js +10 -1
- package/lib/devices/pairing/service.js +1 -1
- package/lib/ride/display/service.js +1 -1
- package/lib/ride/route/RLVDisplayService.d.ts +4 -2
- package/lib/ride/route/RLVDisplayService.js +63 -6
- package/lib/ride/route/RouteDisplayService.js +2 -2
- package/lib/routes/base/utils/route.d.ts +1 -0
- package/lib/routes/base/utils/route.js +10 -1
- package/lib/video/VideoSyncHelper.js +11 -8
- package/lib/workouts/list/service.js +4 -1
- package/package.json +2 -2
|
@@ -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;
|
|
@@ -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');
|
|
@@ -3,7 +3,7 @@ import { Observer } from "../../base/types";
|
|
|
3
3
|
import { LocalizationService } from "../../i18n";
|
|
4
4
|
import { RouteListService } from "../../routes";
|
|
5
5
|
import { Route } from "../../routes/base/model/route";
|
|
6
|
-
import { RouteInfoText } from "../../routes/base/types";
|
|
6
|
+
import { RouteInfoText, RoutePoint } from "../../routes/base/types";
|
|
7
7
|
import { VideoConversion, VideoSyncHelper } from "../../video";
|
|
8
8
|
import { CurrentPosition, CurrentRideDisplayProps, InfotextDisplayProps, OverlayDisplayProps, RLVDisplayProps } from "../base";
|
|
9
9
|
import { RouteDisplayService } from "./RouteDisplayService";
|
|
@@ -45,6 +45,7 @@ export declare class RLVDisplayService extends RouteDisplayService {
|
|
|
45
45
|
getDisplayProperties(props: CurrentRideDisplayProps): RLVDisplayProps;
|
|
46
46
|
protected getInfotextDisplayProps(): InfotextDisplayProps;
|
|
47
47
|
protected checkFinishOptions(position: CurrentPosition): boolean;
|
|
48
|
+
protected preparePointsForMerge(currentPoints: RoutePoint[], nextPoints: RoutePoint[]): void;
|
|
48
49
|
protected onNextVideo(): void;
|
|
49
50
|
protected checkInfotextDisplayProps(time: number): void;
|
|
50
51
|
protected getUIText(input: string): string;
|
|
@@ -76,13 +77,14 @@ export declare class RLVDisplayService extends RouteDisplayService {
|
|
|
76
77
|
start: number;
|
|
77
78
|
end: number;
|
|
78
79
|
}>, video?: VideoState): void;
|
|
80
|
+
protected getCode(error: MediaError): any;
|
|
79
81
|
protected onVideoPlaybackError(error: MediaError, video?: VideoState): void;
|
|
80
82
|
protected onVideoPlayBackUpdate(time: number, rate: number, e: any, video?: VideoState): void;
|
|
81
83
|
protected onVideoEnded(video?: VideoState): void;
|
|
82
84
|
onActivityUpdate(activityPos: ActivityUpdate, data: any): void;
|
|
83
85
|
protected initVideoSource(video: VideoState): VideoConversion;
|
|
84
86
|
protected initMp4VideoSource(video: VideoState): void;
|
|
85
|
-
protected buildVideoError(error: MediaError): string;
|
|
87
|
+
protected buildVideoError(error: MediaError, video?: VideoState): string;
|
|
86
88
|
protected getVideoUrl(video: VideoState): string;
|
|
87
89
|
protected getVideoTime(routeDistance: number, video?: VideoState): number;
|
|
88
90
|
protected initAviVideoSource(video: VideoState): VideoConversion;
|
|
@@ -49,6 +49,7 @@ const types_1 = require("../../base/types");
|
|
|
49
49
|
const i18n_1 = require("../../i18n");
|
|
50
50
|
const utils_1 = require("../../maps/MapArea/utils");
|
|
51
51
|
const routes_1 = require("../../routes");
|
|
52
|
+
const geo_1 = require("../../utils/geo");
|
|
52
53
|
const video_1 = require("../../video");
|
|
53
54
|
const RouteDisplayService_1 = require("./RouteDisplayService");
|
|
54
55
|
let RLVDisplayService = (() => {
|
|
@@ -209,6 +210,22 @@ let RLVDisplayService = (() => {
|
|
|
209
210
|
return false;
|
|
210
211
|
}
|
|
211
212
|
}
|
|
213
|
+
preparePointsForMerge(currentPoints, nextPoints) {
|
|
214
|
+
(0, routes_1.correctDistanceValues)(currentPoints);
|
|
215
|
+
(0, routes_1.correctDistanceValues)(nextPoints);
|
|
216
|
+
nextPoints.forEach(p => {
|
|
217
|
+
delete p.routeDistance;
|
|
218
|
+
delete p.cnt;
|
|
219
|
+
delete p.elevationGain;
|
|
220
|
+
delete p.slope;
|
|
221
|
+
});
|
|
222
|
+
const pLastCurrent = currentPoints[currentPoints.length - 1];
|
|
223
|
+
const pFirstNext = nextPoints[0];
|
|
224
|
+
const distance = (0, geo_1.distanceBetween)(pLastCurrent, pFirstNext);
|
|
225
|
+
const elevationGain = distance < 5 ? 0 : pLastCurrent.slope * distance / 100;
|
|
226
|
+
const elevationDelta = (pLastCurrent.elevation + elevationGain) - pFirstNext.elevation;
|
|
227
|
+
nextPoints.forEach(p => { p.elevation += elevationDelta; });
|
|
228
|
+
}
|
|
212
229
|
onNextVideo() {
|
|
213
230
|
const old = this.currentVideo;
|
|
214
231
|
const next = this.currentVideo.next;
|
|
@@ -225,8 +242,11 @@ let RLVDisplayService = (() => {
|
|
|
225
242
|
setTimeout(() => {
|
|
226
243
|
old.syncHelper.reset();
|
|
227
244
|
}, 2000);
|
|
228
|
-
|
|
229
|
-
|
|
245
|
+
const currentPoints = this.getCurrentRoute().details.points;
|
|
246
|
+
const nextPoints = next.route.details.points;
|
|
247
|
+
this.preparePointsForMerge(currentPoints, nextPoints);
|
|
248
|
+
(0, utils_1.concatPaths)(currentPoints, nextPoints, 'after');
|
|
249
|
+
(0, routes_1.validateRoute)(this.getCurrentRoute(), false);
|
|
230
250
|
this.emit('route-updated', this.getCurrentRoute());
|
|
231
251
|
this.logEvent({ message: 'switching to next video', route: this.getCurrentRoute().details.title,
|
|
232
252
|
segment: this.currentVideo.route.description.title, offset: this.offset, segmentDistance: this.currentVideo.route.description.distance,
|
|
@@ -352,9 +372,12 @@ let RLVDisplayService = (() => {
|
|
|
352
372
|
}
|
|
353
373
|
onVideoLoadError(error, video = this.currentVideo) {
|
|
354
374
|
video.loaded = false;
|
|
355
|
-
video.error = this.buildVideoError(error);
|
|
356
|
-
if (
|
|
357
|
-
this.logEvent({ message: 'could not load
|
|
375
|
+
video.error = this.buildVideoError(error, video);
|
|
376
|
+
if (video.isInitial) {
|
|
377
|
+
this.logEvent({ message: 'could not load video', video: this.getVideoUrl(video), error: error.message, errorCode: this.getCode(error) });
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
this.logEvent({ message: 'could not load next video', video: this.getVideoUrl(video), error: error.message, errorCode: this.getCode(error) });
|
|
358
381
|
const errIdx = this.videos.indexOf(video);
|
|
359
382
|
if (errIdx !== -1) {
|
|
360
383
|
this.videos.splice(errIdx);
|
|
@@ -370,7 +393,27 @@ let RLVDisplayService = (() => {
|
|
|
370
393
|
onVideoWaiting(time, rate, bufferedTime, buffers, video = this.currentVideo) {
|
|
371
394
|
video.syncHelper.onVideoWaiting(time, rate, bufferedTime, buffers);
|
|
372
395
|
}
|
|
396
|
+
getCode(error) {
|
|
397
|
+
const codes = ['MEDIA_ERR_ABORTED', 'MEDIA_ERR_NETWORK', 'MEDIA_ERR_DECODE', 'MEDIA_ERR_SRC_NOT_SUPPORTED'];
|
|
398
|
+
try {
|
|
399
|
+
let codeStr;
|
|
400
|
+
if (error.code !== undefined) {
|
|
401
|
+
codeStr = codes === null || codes === void 0 ? void 0 : codes[error.code - 1];
|
|
402
|
+
if (codeStr) {
|
|
403
|
+
codeStr = `${codeStr} (${error.code})`;
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
codeStr = error.code.toString();
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
return codeStr;
|
|
410
|
+
}
|
|
411
|
+
catch (err) {
|
|
412
|
+
this.logError(err, 'getCode');
|
|
413
|
+
}
|
|
414
|
+
}
|
|
373
415
|
onVideoPlaybackError(error, video = this.currentVideo) {
|
|
416
|
+
this.logEvent({ message: 'video playback error', video: this.getVideoUrl(video), error: error.message, errorCode: this.getCode(error) });
|
|
374
417
|
}
|
|
375
418
|
onVideoPlayBackUpdate(time, rate, e, video = this.currentVideo) {
|
|
376
419
|
video.syncHelper.onVideoPlaybackUpdate(time, rate, e);
|
|
@@ -413,7 +456,21 @@ let RLVDisplayService = (() => {
|
|
|
413
456
|
video.playback = 'native';
|
|
414
457
|
}
|
|
415
458
|
}
|
|
416
|
-
buildVideoError(error) {
|
|
459
|
+
buildVideoError(error, video = this.currentVideo) {
|
|
460
|
+
const src = this.getVideoUrl(video);
|
|
461
|
+
const remote = src === null || src === void 0 ? void 0 : src.startsWith('http');
|
|
462
|
+
switch (error.code) {
|
|
463
|
+
case MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED:
|
|
464
|
+
if (error.message.includes('Format error'))
|
|
465
|
+
return remote ? 'Could not load video' : 'Could not open video file';
|
|
466
|
+
return 'Could not decode video';
|
|
467
|
+
case MediaError.MEDIA_ERR_NETWORK:
|
|
468
|
+
return remote ? 'Could not load video' : 'Could not open video file';
|
|
469
|
+
case MediaError.MEDIA_ERR_ABORTED:
|
|
470
|
+
return 'The playback was canceled';
|
|
471
|
+
case MediaError.MEDIA_ERR_DECODE:
|
|
472
|
+
return 'Could not decode video';
|
|
473
|
+
}
|
|
417
474
|
return error.message;
|
|
418
475
|
}
|
|
419
476
|
getVideoUrl(video) {
|
|
@@ -89,12 +89,12 @@ let RouteDisplayService = (() => {
|
|
|
89
89
|
return;
|
|
90
90
|
}
|
|
91
91
|
try {
|
|
92
|
+
const prevPosition = Object.assign({}, this.position);
|
|
92
93
|
const newPosition = this.updatePosition(activityPos);
|
|
93
94
|
if (!newPosition)
|
|
94
95
|
return;
|
|
95
96
|
const isCompleted = this.checkFinishOptions(newPosition);
|
|
96
97
|
if (!isCompleted) {
|
|
97
|
-
const prevPosition = this.position;
|
|
98
98
|
this.position = Object.assign({}, newPosition);
|
|
99
99
|
const { lat, lng, routeDistance, lap } = newPosition;
|
|
100
100
|
this.onPositionUpdate({ route: this.getOriginalRoute(), position: this.position });
|
|
@@ -275,7 +275,7 @@ let RouteDisplayService = (() => {
|
|
|
275
275
|
const current = this.toLapPoint(this.position);
|
|
276
276
|
props = { routeDistance: activityPos === null || activityPos === void 0 ? void 0 : activityPos.routeDistance, prev: current };
|
|
277
277
|
const next = (0, routes_1.getNextPosition)(this.getCurrentRoute(), props);
|
|
278
|
-
|
|
278
|
+
this.position = this.fromLapPoint(next);
|
|
279
279
|
}
|
|
280
280
|
return this.position;
|
|
281
281
|
}
|
|
@@ -7,6 +7,7 @@ export declare const validateSlopes: (points: Array<RoutePoint>) => void;
|
|
|
7
7
|
export declare const updateSlopes: (points: Array<RoutePoint>, validateOnly?: boolean) => void;
|
|
8
8
|
export declare const getSegments: (route: Route) => Array<RouteSegment>;
|
|
9
9
|
export declare const addDetails: (route: Route, details: RouteApiDetail) => void;
|
|
10
|
+
export declare const correctDistanceValues: (points: RoutePoint[]) => void;
|
|
10
11
|
export declare const validateRoute: (route: Route | RouteApiDetail, reset?: boolean) => void;
|
|
11
12
|
export declare const validateDistance: (points: Array<RoutePoint>) => void;
|
|
12
13
|
export declare const getTotalElevation: (route: RouteApiDetail) => number;
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getNextVideoId = exports.hasNextVideo = exports.createFromJson = exports.getPointAtDistance = exports.getHeading = exports.getPosition = exports.getNextPosition = exports.getRouteHash = exports.getTotalDistance = exports.updateCnt = exports.updateElevationGain = exports.getElevationGainAt = exports.getTotalElevation = exports.validateDistance = exports.validateRoute = exports.addDetails = exports.getSegments = exports.updateSlopes = exports.validateSlopes = exports.checkIsLoop = void 0;
|
|
6
|
+
exports.getNextVideoId = exports.hasNextVideo = exports.createFromJson = exports.getPointAtDistance = exports.getHeading = exports.getPosition = exports.getNextPosition = exports.getRouteHash = exports.getTotalDistance = exports.updateCnt = exports.updateElevationGain = exports.getElevationGainAt = exports.getTotalElevation = exports.validateDistance = exports.validateRoute = exports.correctDistanceValues = exports.addDetails = exports.getSegments = exports.updateSlopes = exports.validateSlopes = exports.checkIsLoop = void 0;
|
|
7
7
|
const utils_1 = require("../../../utils");
|
|
8
8
|
const clone_1 = __importDefault(require("../../../utils/clone"));
|
|
9
9
|
const geo_1 = require("../../../utils/geo");
|
|
@@ -179,6 +179,15 @@ const addVideoDetails = (route, details) => {
|
|
|
179
179
|
route.description.hasGpx = details.points.find(p => p.lat && p.lng) !== undefined;
|
|
180
180
|
route.description.next = (_c = details.video) === null || _c === void 0 ? void 0 : _c.next;
|
|
181
181
|
};
|
|
182
|
+
const correctDistanceValues = (points) => {
|
|
183
|
+
points.forEach((p, idx) => {
|
|
184
|
+
if (idx == 0) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
p.distance = p.routeDistance - points[idx - 1].routeDistance;
|
|
188
|
+
});
|
|
189
|
+
};
|
|
190
|
+
exports.correctDistanceValues = correctDistanceValues;
|
|
182
191
|
const validateRoute = (route, reset = false) => {
|
|
183
192
|
var _a;
|
|
184
193
|
if (!((_a = route === null || route === void 0 ? void 0 : route.points) === null || _a === void 0 ? void 0 : _a.length))
|
|
@@ -207,7 +207,7 @@ class VideoSyncHelper extends service_1.IncyclistService {
|
|
|
207
207
|
this.onUpdate(updates);
|
|
208
208
|
}
|
|
209
209
|
onUpdate(updates = []) {
|
|
210
|
-
var _a, _b, _c;
|
|
210
|
+
var _a, _b, _c, _d;
|
|
211
211
|
if (this.isStopped || this.rlvStatus.timeRequested)
|
|
212
212
|
return;
|
|
213
213
|
try {
|
|
@@ -244,13 +244,16 @@ class VideoSyncHelper extends service_1.IncyclistService {
|
|
|
244
244
|
this.logEvent({ message: 'video debug', videoState: this.rlvStatus, activityState: this.activityStatus });
|
|
245
245
|
}
|
|
246
246
|
};
|
|
247
|
-
if (this.loopMode &&
|
|
248
|
-
|
|
247
|
+
if (this.loopMode && actDistance > totalDistance) {
|
|
248
|
+
actDistance = actDistance % totalDistance;
|
|
249
|
+
rlvDistance = rlvDistance % totalDistance;
|
|
249
250
|
}
|
|
250
|
-
|
|
251
|
-
|
|
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);
|
|
252
256
|
}
|
|
253
|
-
const delta = rlvDistance - actDistance;
|
|
254
257
|
if (Math.abs(delta) > Math.abs(this.maxDelta)) {
|
|
255
258
|
this.maxDelta = delta;
|
|
256
259
|
}
|
|
@@ -278,13 +281,13 @@ class VideoSyncHelper extends service_1.IncyclistService {
|
|
|
278
281
|
return;
|
|
279
282
|
}
|
|
280
283
|
const tTarget = 5;
|
|
281
|
-
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);
|
|
282
285
|
const correction = Math.sign(delta) * Math.min(Math.abs(delta), maxCorrection);
|
|
283
286
|
const rate = (this.activityStatus.speed - correction / tTarget * 3.6) / this.rlvStatus.speed;
|
|
284
287
|
this.updateRate(rate);
|
|
285
288
|
}
|
|
286
289
|
}
|
|
287
|
-
this.cpuTime = ((
|
|
290
|
+
this.cpuTime = ((_d = this.cpuTime) !== null && _d !== void 0 ? _d : 0) + (Date.now() - tsStart);
|
|
288
291
|
}
|
|
289
292
|
catch (err) {
|
|
290
293
|
this.logError(err, 'onUpdate');
|
|
@@ -93,7 +93,10 @@ let WorkoutListService = (() => {
|
|
|
93
93
|
this.getWorkoutCalendar().off('updated', this.onUpdate);
|
|
94
94
|
this.getWorkoutCalendar().reset();
|
|
95
95
|
}
|
|
96
|
-
getSelected() {
|
|
96
|
+
getSelected() {
|
|
97
|
+
const workoutShown = this.getAppState().getState('workoutShown');
|
|
98
|
+
return workoutShown ? this.selectedWorkout : undefined;
|
|
99
|
+
}
|
|
97
100
|
setScreenProps(props) { this.screenProps = props; }
|
|
98
101
|
getScreenProps() { return this.screenProps; }
|
|
99
102
|
open() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "incyclist-services",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.4",
|
|
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",
|