strava.js (3414B)
1 import BaseService from './baseService'; 2 import {corsProxyOriginalUrl, urlViaCorsProxy} from '~/lib/CORSProxy'; 3 4 class Strava extends BaseService { 5 urlRe = /^https?:\/\/(?:.+\.)?strava\.com\/activities\/(\d+)/u; 6 7 isOurUrl() { 8 return this.urlRe.test(this.origUrl); 9 } 10 11 requestOptions() { 12 const m = this.urlRe.exec(this.origUrl); 13 const trackId = this.trackId = m[1]; 14 function isResponseSuccess(response) { 15 return [200, 401, 404].includes(response.status); 16 } 17 return [ 18 { 19 url: urlViaCorsProxy(`https://www.strava.com/activities/${trackId}?hl=en-GB`), 20 options: { 21 isResponseSuccess 22 } 23 }, 24 { 25 url: urlViaCorsProxy(`https://www.strava.com/activities/${trackId}/streams?stream_types%5B%5D=latlng`), 26 options: { 27 responseType: 'json', 28 isResponseSuccess 29 } 30 } 31 ]; 32 } 33 34 parseResponse(responses) { 35 const statusMessages = { 36 401: 'Requested Strava activity marked as private', 37 404: 'Requested Strava activity could not be found' 38 }; 39 const [pageResponse, trackResponse] = responses; 40 if (trackResponse.status !== 200) { 41 return [{error: statusMessages[trackResponse.status]}]; 42 } 43 let name = `Strava ${this.trackId}`; 44 const latlngs = trackResponse.responseJSON?.latlng; 45 if (!latlngs || !Array.isArray(latlngs)) { 46 return [{name, error: 'UNSUPPORTED'}]; 47 } 48 const tracks = [latlngs.map((p) => ({lat: p[0], lng: p[1]}))]; 49 let dom; 50 try { 51 dom = (new DOMParser()).parseFromString(pageResponse.response, 'text/html'); 52 } catch (e) { 53 // will use default name 54 } 55 if (dom) { 56 const userName = (dom.querySelector('a.minimal[href*="/athletes/"]')?.textContent ?? '').trim(); 57 const activityTitle = (dom.querySelector('h1.activity-name')?.textContent ?? '').trim(); 58 let date = dom.querySelector('time')?.textContent ?? ''; 59 date = date.split(',')[1] ?? ''; 60 date = date.trim(); 61 if (userName && activityTitle && date) { 62 name = `${userName} - ${activityTitle} ${date}`; 63 } 64 } 65 return [{ 66 name, 67 tracks 68 }]; 69 } 70 } 71 72 class StravaShortUrl extends BaseService { 73 urlRe = /^https:\/\/strava.app.link\/([A-Za-z0-9]+)/u; 74 75 isOurUrl() { 76 return this.urlRe.test(this.origUrl); 77 } 78 79 requestOptions() { 80 return [ 81 { 82 url: urlViaCorsProxy(this.origUrl), 83 options: {isResponseSuccess: (response) => [200, 404].includes(response.status)}, 84 }, 85 ]; 86 } 87 88 parseResponse(responses) { 89 const response = responses[0]; 90 const url = corsProxyOriginalUrl(response.responseURL); 91 if (response.status === 404) { 92 return [{error: 'Requested Strava activity was deleted'}]; 93 } 94 const strava = new Strava(url); 95 if (!strava.isOurUrl()) { 96 return [{error: 'Bad short link for Strava activity or activity is marked as private'}]; 97 } 98 return strava.geoData(); 99 } 100 } 101 102 export {Strava, StravaShortUrl};