@vkontakte/videoplayer-statistics 1.0.109-dev.eb086bcd9.0 → 1.0.110-dev.0bbcbb01d.0

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/evergreen.esm.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @vkontakte/videoplayer-statistics v1.0.109-dev.eb086bcd9.0
3
- * Mon, 08 Jun 2026 09:08:35 GMT
4
- * https://st.mycdn.me/static/vkontakte-videoplayer/1-0-109/doc/
2
+ * @vkontakte/videoplayer-statistics v1.0.110-dev.0bbcbb01d.0
3
+ * Tue, 16 Jun 2026 11:51:52 GMT
4
+ * https://st.mycdn.me/static/vkontakte-videoplayer/1-0-110/doc/
5
5
  */
6
- var e=Object.defineProperty,t=e=>e;function n(e,n){this[e]=t.bind(null,n)}var r=(t,r)=>{for(var i in r)e(t,i,{get:r[i],enumerable:!0,configurable:!0,set:n.bind(r,i)})},i;(e=>{e.PROD=`prod`,e.VK_ALIAS=`vk_alias`,e.VIDEOTEST=`videotest`,e.TEST=`test`,e.OKCDN=`okcdn`,e.AUTO=`auto`})(i||={});var a;(e=>{e.Q144P=`mobile`,e.Q240P=`lowest`,e.Q360P=`low`,e.Q480P=`medium`,e.Q720P=`high`,e.Q1080P=`fullhd`,e.Q1440P=`quadhd`,e.Q2160P=`ultrahd`,e.UNKNOWN=`unknown`})(a||={});var o;(e=>{e.MP4=`mp4`,e.DASH=`dash`,e.DASH_SEP=`dash_sep`,e.ONDEMAND_DASH=`ondemand_dash`,e.HLS=`hls`,e.HLS_FMP4=`hls_fmp4`,e.ONDEMAND_HLS=`ondemand_hls`,e.WEBM=`webm`,e.AV1=`av1`,e.ONDEMAND_DASH_LIVE=`ondemand_dash_live`,e.ONDEMAND_HLS_LIVE=`ondemand_hls_live`,e.WEBRTC=`webrtc`,e.UNKNOWN=`unknown`,e.RTMP=`rtmp`})(o||={});var s;(e=>{e.HTTP1=`http1`,e.HTTP2=`http2`,e.HTTP3=`http3`})(s||={});var c;(e=>{e.SLIDER=`slider`,e.RICH=`rich`,e.DOUBLE_TAP=`double_tap`,e.TIME_CODE=`time_code`,e.EPISODE=`episode`,e.REWIND=`rewind`,e.LIVE=`live`,e.UNKNOWN=`unknown`})(c||={});var l;(e=>{e.GRAPH_SHOW=`iGraphShow`,e.GRAPH_HIDE=`iGraphHide`,e.NEXT_AREA=`iNextChapterArea`,e.NEXT_BUTTON=`iNextChapterBtn`,e.WATCH_AGAIN=`iWatchAgainBtn`})(l||={});var u={action_play:`ap`,action_play_interactive:`api`,first_bytes:`fb`,player_ready:`pr`,first_frame:`ff`,seek:`sk`,watch_coverage_record:`wr`,watch_coverage_live:`wl`,empty_buffer:`eb`,action_stop:`as`,close_at_empty_buffer:`cb`,content_error:`er`,player_interface_click:`pc`,next_movie:`nm`,track_switch:`ts`,failover:`fo`,quality:`qt`},d={vsid:`si`,isid:`is`,vid:`vi`,place:`pl`,quality:`qt`,cdn_host:`ch`,stat_type:`st`,param:`pm`,vk_app_id:`va`,track_code:`tc`,connection_type:`cnt`,connection_reused:`cr`,cached_data:`cd`,live:`lv`,muted:`mu`,mode:`mo`,subtitles:`sb`,failover:`fo`,download_speed:`ds`,manual_quality:`mq`,ref_domain:`rd`,direct_url:`du`},f={unknown:`un`,mobile:`m`,lowest:`ls`,low:`l`,medium:`md`,high:`h`,fullhd:`f`,quadhd:`q`,ultrahd:`u`},p={pip:`pi`,fullscreen:`fs`,external:`ex`,prefetch:`pr`,airplay:`ap`,chromecast:`cc`,invisible:`iv`,minimal:`minimal`};import{fillWithDefault as m}from"@vkontakte/videoplayer-shared/evergreen";var h=`CIOPGQJGDIHBABABA`,g={prod:`https://api.ok.ru`,vk_alias:`https://api.mycdn.me`,videotest:`https://videotestapi.ok.ru/api`,test:`https://apitest.ok.ru`,okcdn:`https://api.okcdn.ru`,auto:``},ee={apiEnv:`vk_alias`,apiKey:h,apiBaseUrl:null,apiForticom:!0,apiUvRest:!1,requestRetryCount:1,useVsid64:!1,firstFlushTime:5e3,flushDebounceTime:1e4,flushMaxWait:6e4,storageExpiration:2160*60*1e3,watchCoverageInterval:15e3,disabledOperations:[`quality`],disabledCustomFields:[],shorten:!0,maxLoops:100,embedUrlParams:[],useBeacon:!0,synchronizeTime:!0,debugLog:!1,clearStorageAtUnload:!0,useVKComIsMobileLogic:!1,backoff:{start:1e3,factor:1.5,max:300*1e3,random:.1},useKeepalive:!1,watchCoverageTimeoutFix:!0,watchCoverageExactTime:!1},_=e=>m(e,ee);function v(){let e=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`.split(``),t=Array(36),n=0,r,i;for(i=0;i<36;i++)i===8||i===13||i===18||i===23?t[i]=`-`:i===14?t[i]=`4`:(n<=2&&(n=33554432+Math.random()*16777216|0),r=n&15,n>>=4,t[i]=e[i===19?r&3|8:r]);return t.join(``)}import{assertNonNullable as y,combine as b,fromEvent as x,isNonNullable as S,isNullable as te,merge as ne,now as C,observableFrom as re,once as ie,safeStorage as ae,Subject as oe,Subscription as se,ValueSubject as w,getWindow as ce}from"@vkontakte/videoplayer-shared/evergreen";import{Logger as le,detectEmbed as ue,ErrorCategory as de}from"@vkontakte/videoplayer-shared/evergreen";var fe=()=>Math.floor(Math.random()*2**32).toString(36).padStart(13,`0`),pe=()=>Math.floor(Math.random()*2**64).toString(36).padStart(13,`0`);class T{static vsid;static getVSID(){return T.vsid}static generateVSID(e){return T.vsid=e?pe():fe(),T.vsid}}var me=e=>{let{operation:t,custom:n}=e,r=Object.fromEntries(Object.entries(n).map(([e,t])=>{let n=d[e]??e,r=t;return t&&(e===`mode`?r=p[t]??t:e===`quality`&&(r=f[t]??t)),[n,r]}));return{...e,operation:u[t]??t,custom:r}},E=`1.0.109-dev.eb086bcd9.0`;import{ValueSubject as he,getExponentialDelay as ge,ErrorCategory as D,getWindow as O}from"@vkontakte/videoplayer-shared/evergreen";var _e=/Mobile|mini|Fennec|Android|iP(ad|od|hone)|opera (mini|mobi)/i;class ve{id=`forticom`;params;authToken;sessionKey;authorizePromise;refreshAuthTokenPromise;consequentAuthErrors=0;authorized$=new he(!1);backoffTimeoutId;constructor(e){this.params=e}async authorize(e){return this.authToken=e??await this.refreshAuthToken(),this._authorizeWithBackoff()}logBeacon(e){let t=this.createLogParams(e),n=this.sessionKey;n&&(this.params.apiTransport.sendBeacon(`log.externalLog`,t,n)||this.logRequest(e).catch(()=>{}))}async logRequest(e){let t=`log.externalLog`,n=this.createLogParams(e),r=this.sessionKey??await this._authorizeWithBackoff();if(!r)return;let i=async(e,a=this.params.config.requestRetryCount)=>{try{return await this.params.apiTransport.sendRequest(t,n,r)}catch(n){if(!n||!(`error_code`in n)){this.params.error$.next({id:`logRequestUnknown`,category:D.NETWORK,message:`Unknown ${t} error`,thrown:n});return}let r=n?.error_code;switch(r){case 102:case 103:case 104:return this.authorized$.next(!1),this.sessionKey=await this._authorizeWithBackoff(),a>0?i(e,a-1):void 0;case 401:return this.authorized$.next(!1),this.authToken=await this.refreshAuthToken(),this.sessionKey=await this._authorizeWithBackoff(),a>0?i(e,a-1):void 0;default:this.params.error$.next({id:`LogRequest#${r}`,category:D.EXTERNAL_API,message:`${t} error`,data:n});return}}};return i(e)}destroy(){O().clearTimeout(this.backoffTimeoutId),this.backoffTimeoutId=0}async refreshAuthToken(){if(this.params.refreshAuthToken)return this.refreshAuthTokenPromise||=this.params.refreshAuthToken().finally(()=>{this.refreshAuthTokenPromise=void 0}),this.refreshAuthTokenPromise}createLogParams(e){let t=`WEB`,n=!1,r=`@vkontakte/videoplayer-statistics:${E}`;if(this.params.config.useVKComIsMobileLogic){let{appVersion:e}=O().navigator;n=_e.test(e)}else this.params.mobile&&(n=!0);return n&&(t=`M_WEB`),this.params.vktvVersion&&(t=`SMART_TV`,r=this.params.vktvVersion),{collector:`ok.mobile.apps.video`,data:JSON.stringify({application:r,platform:t,items:this.params.config.shorten?e.map(me):e})}}_authorizeWithBackoff(){if(!this.consequentAuthErrors)return this._authorize();let e=ge(this.consequentAuthErrors,this.params.config.backoff);return new Promise(t=>{this.backoffTimeoutId||=O().setTimeout(()=>{this._authorize().then(t).catch(e=>this.params.error$.next({id:`AuthorizeBackoff`,category:D.NETWORK,message:`Otherwise unhandled error in authorization`,thrown:e})).finally(()=>this.backoffTimeoutId=0)},e)})}async _authorize(){if(this.authorizePromise)return this.authorizePromise;this.sessionKey=void 0,this.authorized$.next(!1);let e={session_data:{version:2,device_id:this.params.deviceId,client_version:E.split(`-`)[0],client_type:`SDK_JS`}};return this.authToken!==void 0&&(e.session_data.auth_token=this.authToken,e.session_data.version=3),this.authorizePromise=this.params.apiTransport.sendRequest(`auth.anonymLogin`,e).then(e=>((!e||!e.session_key)&&this.params.error$.next({id:`AuthorizeFailed`,category:D.EXTERNAL_API,message:`No session key`,data:e}),this.sessionKey=e?.session_key??void 0,this.sessionKey)).catch(async e=>{this.sessionKey=void 0;let t=e?.error_code;switch(t){case 401:return this.authToken=await this.refreshAuthToken(),this._authorizeWithBackoff()}t?this.params.error$.next({id:`Authorize#${t}`,category:D.EXTERNAL_API,message:`authorize error`,data:e}):this.params.error$.next({id:`AuthorizeUnknown`,category:D.NETWORK,message:`authorize error`,thrown:e})}).finally(()=>{this.authorizePromise=void 0,this.consequentAuthErrors=this.sessionKey?0:this.consequentAuthErrors+1,this.authorized$.next(this.sessionKey!==void 0)}),this.authorizePromise}}class ye{id=`uvrest`;authorized$=new he(!1);params;statToken;authorizePromise;isDestroyed=!1;constructor(e){this.params=e}async authorize(e){if(!this.isDestroyed)return e?(this.statToken=e,this.authorized$.next(!0),e):this.authorizePromise?this.authorizePromise:(this.authorized$.next(!1),this.authorizePromise=this.executeAuthorize().finally(()=>{this.authorizePromise=void 0,this.isDestroyed||this.authorized$.next(this.statToken!==void 0)}),this.authorizePromise)}async logRequest(e){if(!e.length)return;let t=this.buildBody(e);try{let e=await this.getValidToken();if(!e){this.params.error$.next({id:`OneStat:UvRestApi:LogRequestNoToken`,category:D.NETWORK,message:`No stat token available for log request`});return}await this.params.apiTransport.sendJsonRequest(`/uv/stat/externalLog`,t,{Authorization:`Bearer ${e}`})}catch(e){await this.handleLogRequestError(e)&&await this.retryLogRequestAfterRecovery(t)}}logBeacon(e){if(!e.length)return;let t=this.statToken;if(!t)return;let n=this.buildBody(e);this.params.apiTransport.sendJsonBeacon(`/uv/stat/externalLog`,n,{Authorization:`Bearer ${t}`})}destroy(){this.isDestroyed=!0,this.authorizePromise=void 0,this.statToken=void 0,this.authorized$.next(!1)}async getValidToken(){return this.statToken?this.statToken:this.authorize()}async executeAuthorize(){try{let e=await this.params.getAuthToken();if(this.isDestroyed)return;if(!e){this.params.error$.next({id:`OneStat:UvRestApi:NoToken`,category:D.EXTERNAL_API,message:`getAuthToken returned no token`});return}return this.statToken=e,this.statToken}catch(e){if(this.isDestroyed)return;this.params.error$.next({id:`OneStat:UvRestApi:AuthorizeFailed`,category:D.NETWORK,message:`Failed to get stat token`,thrown:e});return}}async handleLogRequestError(e){let t=e?.status;return t===401?(this.params.error$.next({id:`OneStat:UvRestApi:TokenExpired`,category:D.EXTERNAL_API,message:`Stat token expired (401), refreshing`,thrown:e}),this.authorized$.next(!1),this.statToken=void 0,await this.authorize()!==void 0):(this.params.error$.next({id:`OneStat:UvRestApi:LogRequestFailed#${t??`unknown`}`,category:D.EXTERNAL_API,message:`Log request failed with status ${t}`,thrown:e}),!1)}async retryLogRequestAfterRecovery(e){let t=this.statToken;if(!t){this.params.error$.next({id:`OneStat:UvRestApi:RetryNoToken`,category:D.NETWORK,message:`Cannot retry log request: no token after recovery`});return}try{await this.params.apiTransport.sendJsonRequest(`/uv/stat/externalLog`,e,{Authorization:`Bearer ${t}`})}catch(e){this.params.error$.next({id:`OneStat:UvRestApi:RetryFailed`,category:D.EXTERNAL_API,message:`Log request failed after token refresh`,thrown:e})}}buildBody(e){let t=`WEB`,n=!1,r=`@vkontakte/videoplayer-statistics:${E}`;if(this.params.config.useVKComIsMobileLogic){let{appVersion:e}=O().navigator;n=_e.test(e)}else this.params.mobile&&(n=!0);return n&&(t=`M_WEB`),this.params.vktvVersion&&(t=`SMART_TV`,r=this.params.vktvVersion),[{application:r,platform:t,user_id:this.params.userId,items:this.params.config.shorten?e.map(me):e}]}}import{ErrorCategory as k,now as A,getWindow as be}from"@vkontakte/videoplayer-shared/evergreen";class xe{apiKey;apiBaseUrl;apiEnv;timeSynchronisation;isApiBaseUrlFetched;params;constructor(e){this.params=e,this.apiKey=e.config.apiKey,this.apiEnv=e.config.apiEnv,this.apiBaseUrl=e.config.apiBaseUrl??g[this.apiEnv],this.timeSynchronisation=e.timeSynchronisation,this.isApiBaseUrlFetched=!1}async resolveApiBaseUrl(){if(this.apiEnv!==`auto`||this.isApiBaseUrlFetched)return this.apiBaseUrl;try{let e=atob(`aHR0cHM6Ly9kbnMuZ29vZ2xlL3Jlc29sdmU/bmFtZT12aWRlby5fZW5kcG9pbnQub2sucnUmdHlwZT1UWFQ=`),t=(await(await fetch(e,{method:`GET`,mode:`cors`,cache:`no-cache`})).json())?.Answer[0]?.data;if(!t)throw Error(`Wrong DNS response`);return t}catch(e){return this.params.error$.next({id:`OneStat:ApiTransport:resolveApiBaseUrl`,category:k.NETWORK,message:`Unhandled resolve api base url error`,thrown:e}),g.vk_alias}finally{this.isApiBaseUrlFetched=!0}}sendBeacon(e,t,n){if(!be().Blob||!be().navigator.sendBeacon)return!1;let r=this._prepareQueryParams({method:e,queryParams:t,sessionKey:n}),i=be().Blob,a=new i([r.toString()],{type:`application/x-www-form-urlencoded`});try{return be().navigator.sendBeacon(`${this.apiBaseUrl}/fb.do`,a)}catch(n){this.params.error$.next({id:`OneStat:ApiTransport:sendBeacon`,category:k.NETWORK,message:`Unhandled beacon error`,thrown:n,data:{method:e,params:t}})}return!1}async sendRequest(e,t,n){let r=A(),i=i=>{if(i instanceof TypeError&&[`Failed to fetch`,`NetworkError when attempting to fetch resource.`].includes(i.message)){this.params.error$.next({id:`Network`,category:k.NETWORK,message:`Request failed`,thrown:i});return}this.params.error$.next({id:`OneStat:ApiTransport:sendRequest`,category:k.NETWORK,message:`Unhandled request error`,thrown:i,data:{method:e,params:t,sessionKey:n,time:A()-r}})};this.apiBaseUrl=await this.resolveApiBaseUrl();let a={method:`post`,headers:{"Content-type":`application/x-www-form-urlencoded`},body:this._prepareQueryParams({method:e,queryParams:t,sessionKey:n})};return this.params.config.useKeepalive&&(a.keepalive=!0),fetch(`${this.apiBaseUrl}/fb.do`,a).then(e=>{let t=Number(e.headers.get(`content-length`))===0,n=new Date(e.headers.get(`date`)??``).getTime(),a=A()-r;if(isFinite(n)&&this.timeSynchronisation?.addServerTime(n,a),!t)return e.json().then(e=>Object.prototype.hasOwnProperty.call(e,`error_msg`)?Promise.reject(e):e,i)},i)}sendJsonBeacon(e,t,n){let r=`${this.apiBaseUrl}${e}`;try{fetch(r,{method:`POST`,headers:{"Content-Type":`application/json`,...n},body:JSON.stringify(t),keepalive:!0}).catch(t=>{this.params.error$.next({id:`OneStat:ApiTransport:sendJsonBeacon`,category:k.NETWORK,message:`Keepalive request failed`,thrown:t,data:{path:e}})})}catch(t){this.params.error$.next({id:`OneStat:ApiTransport:sendJsonBeacon`,category:k.NETWORK,message:`Failed to initiate keepalive request`,thrown:t,data:{path:e}})}}async sendJsonRequest(e,t,n){let r=A(),i=t=>{if(t instanceof TypeError&&[`Failed to fetch`,`NetworkError when attempting to fetch resource.`].includes(t.message)){this.params.error$.next({id:`Network`,category:k.NETWORK,message:`JSON request failed`,thrown:t});return}this.params.error$.next({id:`OneStat:ApiTransport:sendJsonRequest`,category:k.NETWORK,message:`Unhandled JSON request error`,thrown:t,data:{path:e,time:A()-r}})};this.apiBaseUrl=await this.resolveApiBaseUrl();let a={method:`POST`,headers:{"Content-Type":`application/json`,...n},body:JSON.stringify(t)};return this.params.config.useKeepalive&&(a.keepalive=!0),fetch(`${this.apiBaseUrl}${e}`,a).then(e=>{let t=Number(e.headers.get(`content-length`))===0,n=new Date(e.headers.get(`date`)??``).getTime(),a=A()-r;if(isFinite(n)&&this.timeSynchronisation?.addServerTime(n,a),!e.ok)return Promise.reject({status:e.status,statusText:e.statusText});if(!t)return e.json().catch(i)},i)}_prepareQueryParams(e){let t=new URLSearchParams({format:`JSON`,method:e.method,application_key:this.apiKey});return e.sessionKey!==void 0&&t.append(`session_key`,e.sessionKey),Object.entries(e.queryParams).forEach(([e,n])=>t.append(e,typeof n==`string`?n:JSON.stringify(n))),t}}import{ErrorCategory as Se,now as Ce,safeStorage as j,debounceFn as we}from"@vkontakte/videoplayer-shared/evergreen";var Te=e=>t=>t.timestamp+e>=Ce();class Ee{params;error$;userSalt;isPaused=!1;loggerDebugLog;queues=[];constructor(e){this.params=e,this.error$=e.error$,this.userSalt=e.userSalt,this.loggerDebugLog=e.debugLogger.createComponentLog(`stat logger`);for(let t of e.apis)this.queues.push(this.createQueueState(t));this.housekeepStorage()}createQueueState(e){let t=`onestat_events_${e.id}`,n=we(()=>this.safeFlushQueue(a),this.params.config.firstFlushTime,{maxWait:this.params.config.firstFlushTime}),r=j.isPersistent()?this.params.config.flushMaxWait:0,i=we(()=>this.safeFlushQueue(a),this.params.config.flushDebounceTime,{maxWait:r}),a={api:e,storageKey:t,unsaltedStorage:[],lastVsid:void 0,firstFlush:n,debouncedFlush:i,subscription:e.authorized$.subscribe(e=>{e&&i()})};return a}isUrgent=e=>{let{operation:t}=e;return[`action_play`,`action_play_interactive`,`watch_coverage_record`,`watch_coverage_live`,`action_stop`,`close_at_empty_buffer`].includes(t)};safeFlushQueue(e){try{this.flushQueue(e)}catch(t){this.error$.next({id:`LoggerError`,category:Se.WTF,message:t?String(t):`Unknown logger error`,thrown:t,data:{storageKey:e.storageKey}})}}readFromStorage(e){let t=j.get(e);try{return t?JSON.parse(t):{}}catch{}return{}}addToStorage(e,t){if(!this.userSalt){e.unsaltedStorage.push(t);return}let n=this.readFromStorage(e.storageKey),r=(n[this.userSalt]??[]).filter(Te(this.params.config.storageExpiration));j.set(e.storageKey,JSON.stringify({...n,[this.userSalt]:[...r,t]}))}getFromStorage(e){return this.userSalt?(this.readFromStorage(e.storageKey)[this.userSalt]??[]).filter(Te(this.params.config.storageExpiration)):e.unsaltedStorage}markStorageSent(e){if(!this.userSalt){e.unsaltedStorage=[];return}let t=this.readFromStorage(e.storageKey);delete t[this.userSalt],j.set(e.storageKey,JSON.stringify(t))}housekeepStorage(){for(let e of this.queues){let t=this.readFromStorage(e.storageKey);for(let[n,r]of Object.entries(t)){let i=r.filter(Te(this.params.config.storageExpiration));i.length?t[n]=i:delete t[n],this.loggerDebugLog({message:`${r.length} retrieved from storage, ${i.length} of them actual (${e.storageKey})`})}j.set(e.storageKey,JSON.stringify(t))}}log(e){for(let t of this.queues)this.addToStorage(t,e),!this.isPaused&&(this.isUrgent(e)?this.flushQueue(t):t.lastVsid===e.custom.vsid?t.debouncedFlush():t.firstFlush(),t.lastVsid=e.custom.vsid)}flush(e={wantBeacon:!1,clearStorage:!0}){for(let t of this.queues)this.flushQueue(t,e)}flushQueue(e,{wantBeacon:t,clearStorage:n}={wantBeacon:!1,clearStorage:!0}){let r=this.getFromStorage(e);r.length!==0&&(e.api.authorized$.getValue()?(t&&this.params.config.useBeacon?(this.loggerDebugLog({message:`Flushing ${r.length} events through beacon (${e.storageKey})`}),e.api.logBeacon(r)):(this.loggerDebugLog({message:`Flushing ${r.length} events (${e.storageKey})`}),e.api.logRequest(r)),n&&this.markStorageSent(e)):e.api.authorize(),e.firstFlush.cancel(),e.debouncedFlush.cancel())}pause(){this.isPaused=!0;for(let e of this.queues)e.debouncedFlush.cancel()}resume(){this.isPaused=!1;for(let e of this.queues)e.debouncedFlush()}destroy(){for(let e of this.queues)e.subscription.unsubscribe(),e.firstFlush.cancel(),e.debouncedFlush.cancel();this.queues=[]}}import{HttpConnectionType as De,Surface as M,VideoFormat as N,VideoQuality as P}from"@vkontakte/videoplayer-core/evergreen";import{assertNever as Oe}from"@vkontakte/videoplayer-shared/evergreen";var ke=e=>e&&{[P.INVARIANT]:`unknown`,[P.Q_144P]:`mobile`,[P.Q_240P]:`lowest`,[P.Q_360P]:`low`,[P.Q_480P]:`medium`,[P.Q_576P]:`unknown`,[P.Q_720P]:`high`,[P.Q_1080P]:`fullhd`,[P.Q_1440P]:`quadhd`,[P.Q_2160P]:`ultrahd`,[P.Q_4320P]:`unknown`}[e],Ae=e=>e&&{[De.HTTP1]:`http1`,[De.HTTP2]:`http2`,[De.QUIC]:`http3`}[e],je=e=>{if(e!==void 0)switch(e){case N.MPEG:return`mp4`;case N.DASH:case N.DASH_LIVE:case N.DASH_STREAMS:return`dash`;case N.DASH_SEP:return`dash_sep`;case N.DASH_ONDEMAND:return`ondemand_dash`;case N.DASH_WEBM:case N.DASH_LIVE_WEBM:return`webm`;case N.DASH_WEBM_AV1:return`av1`;case N.DASH_LIVE_CMAF:return`ondemand_dash_live`;case N.HLS:case N.HLS_LIVE:return`hls`;case N.HLS_FMP4:return`hls_fmp4`;case N.HLS_ONDEMAND:return`ondemand_hls`;case N.HLS_LIVE_CMAF:return`ondemand_hls_live`;case N.WEB_RTC_LIVE:return`webrtc`;default:return Oe(e)}},Me=(e,t)=>{if(t)return`minimal`;switch(e){case void 0:case M.NONE:case M.INLINE:return;case M.FULLSCREEN:return`fullscreen`;case M.SECOND_SCREEN:return`chromecast`;case M.PIP:return`pip`;case M.INVISIBLE:return`invisible`;default:return Oe(e)}},Ne=e=>{switch(e){case`slow-2g`:return`poor`;case`2g`:return`poor`;case`3g`:return`good`;case`4g`:return`excellent`}};class Pe{offset=void 0;constructor(e){this.offset=e}getOffset(){return this.offset??0}setOffset(e){this.offset=e}now(){return Date.now()+(this.offset??0)}date(e=new Date){return e.setTime(e.getTime()+(this.offset??0)),e}addServerTime(e,t){let n=e-Date.now()-t/2;if(Math.abs(n)<1e3){this.offset=0;return}if(this.offset===void 0)this.offset=Math.round(n);else{let e=.2;this.offset=Math.round(e*n+(1-e)*this.offset)}}}import{PlaybackState as Fe}from"@vkontakte/videoplayer-core/evergreen";import{filter as Ie,filterChanged as Le,fromEvent as Re,isNullable as ze,map as Be,merge as F,Observable as Ve,Subject as He,Subscription as Ue,ValueSubject as We}from"@vkontakte/videoplayer-shared/evergreen";var Ge=(e,t)=>new Ve(n=>{let r=new Ue,i=F(Re(window,`beforeunload`),e.events.willDestruct$),a=new We(void 0),o;r.add(e.info.isLive$.pipe(Le()).subscribe(t=>{o&&(o.unsubscribe(),a.next(void 0)),o=t?e.info.liveTime$.pipe(Be(e=>e&&e/1e3)).subscribe(a):e.info.position$.subscribe(a),r.add(o)}));let{playing$:s,paused$:c,looped$:l}=e.events,u=e.events.willSeek$.pipe(Ie(()=>e.info.playbackState$.getValue()===Fe.PLAYING)),d=e.events.seeked$.pipe(Ie(()=>e.info.playbackState$.getValue()===Fe.PLAYING)),f=!1,p=new He;r.add(u.subscribe(()=>{f||p.next(),f=!0})),r.add(d.subscribe(()=>f=!1));let m=new He,h=new He,g=()=>t.watchCoverageExactTime?e.info.isLive$.getValue()?e.getExactLiveTime():e.getExactTime():a.getValue()??0,ee=e.info.stallStartTime$.pipe(Le(),Ie(e=>e>0)),_=F(s,d,m).pipe(Be(()=>g())),v=F(l,F(c,p,i,h,ee).pipe(Be(()=>g()))),y,b=e=>{y=e},x=e=>{let t=e;ze(y)||y===t||ze(t)||(n.next({from:y,to:t}),y=void 0)},S=()=>{h.next(),m.next()};if(r.add(_.subscribe(b)),r.add(v.subscribe(x)),t.forceInterval&&isFinite(t.forceInterval))if(t.watchCoverageTimeoutFix){let e,n=()=>{e!==void 0&&(window.clearTimeout(e),e=void 0)};r.add(_.subscribe(()=>{n(),e=window.setTimeout(S,t.forceInterval)})),r.add(v.subscribe(()=>n())),r.add(()=>n())}else{let e=0;r.add(_.subscribe(()=>e=window.setTimeout(S,t.forceInterval))),r.add(v.subscribe(()=>window.clearTimeout(e)))}return r});import{Surface as I}from"@vkontakte/videoplayer-core/evergreen";import{debounce as Ke,filterChanged as qe,Subject as Je}from"@vkontakte/videoplayer-shared/evergreen";var Ye=(e,t,n)=>{let r=new Je,i=r.pipe(Ke(0),qe()),a=!1,o=!1,s=!1;return t(e.inPiP$,e=>{a=e,r.next(e?I.PIP:o?I.FULLSCREEN:s?I.INLINE:void 0)}),t(e.inFullscreen$,e=>{o=e,r.next(e?I.FULLSCREEN:a?I.PIP:s?I.INLINE:void 0)}),n&&t(n.info.surface$,e=>{switch(e){case I.SECOND_SCREEN:case I.NONE:case I.INLINE:!o&&!a&&(e===I.INLINE&&(s=!0),r.next(e));break}}),{surface$:i}},Xe=`_one-stat_deviceId`,Ze=(e,t)=>e&&t?`${e}_${t}`:e??t,Qe=()=>{let e=new se;return{subscription:e,subscribe:(t,n)=>{t&&e.add(t.subscribe(n))}}};class $e{apis;logger;config;subscription=new se;beforeunloadSubscription;timeSynchronisation;debugLogger=new le;oneStatDebugLog=this.debugLogger.createComponentLog(`onestat`);loopCounter=0;disabled=!1;experimental;get vsid$(){return new w(T.getVSID())}isid$=new w(void 0);zenUid$=new w(void 0);statContext;isEmbed;embedParent;uiEvents;player;seekAction$=new w(`unknown`);deviceId;constructor(e,t){this.statContext=e,this.config=_(t.config??{}),S(t.apiEnv)&&(this.config.apiEnv=t.apiEnv),this.config.synchronizeTime&&(this.timeSynchronisation=new Pe);let n=new oe;this.experimental={error$:n};let r=ae.get(Xe);this.statContext.deviceId?this.deviceId=this.statContext.deviceId:r?this.deviceId=r:(this.deviceId=v(),ae.set(Xe,this.deviceId)),this.resetViewSession(),t.useIsid&&this.isid$.next(t.isid??pe()),this.zenUid$.next(t.zenUid);let i=new xe({config:this.config,error$:n,timeSynchronisation:this.timeSynchronisation}),a=[];this.config.apiForticom&&a.push(new ve({config:this.config,apiTransport:i,refreshAuthToken:t.refreshAuthToken,mobile:this.statContext.mobile??!1,deviceId:this.deviceId,error$:n,vktvVersion:t.vktvVersion})),this.config.apiUvRest&&(t.getUvRestAuthToken?a.push(new ye({config:this.config,apiTransport:i,error$:n,userId:this.statContext.userId,getAuthToken:t.getUvRestAuthToken,mobile:this.statContext.mobile??!1,vktvVersion:t.vktvVersion})):n.next({id:`OneStat:Init:MissingGetUvRestAuthToken`,category:de.WTF,message:`oldStatToUvRest enabled but getUvRestAuthToken callback not provided`})),this.apis=a,this.logger=new Ee({config:this.config,debugLogger:this.debugLogger,apis:this.apis,error$:n,userSalt:t.userSalt});let{isEmbed:o,topOrigin:s}=ue();this.isEmbed=o,this.embedParent=s?new URL(s).hostname:void 0,this.subscribe()}updateContext(e){this.statContext={...this.statContext,...e}}attachTo(e){let t=new se,n=(e,n)=>t.add(e.subscribe(n)),r,i,a,o=!1,s=!1,c=()=>{o||(o=!0,S(r)&&(r={startedAt:C(),liveAtStall:!!this.statContext.liveEdge}))};n(e.events.willStart$,()=>{let t=e.info.position$.getValue();this.logActionPlay({position:t}),this.statContext.projectId&&this.logActionPlayInteractive()}),n(e.events.looped$,()=>{this.resetViewSession(),++this.loopCounter>this.config.maxLoops&&(this.disabled=!0),this.logActionPlay({position:e.info.position$.getValue()})}),n(e.events.willSeek$,()=>{S(r)&&o&&this.logEmptyBuffer({duration:C()-r.startedAt,liveAtStall:r.liveAtStall}),r=void 0,s=!0}),n(e.events.seeked$,()=>{!s&&S(r)&&o&&(this.logEmptyBuffer({duration:C()-r.startedAt,liveAtStall:r.liveAtStall}),r=void 0),s=!1;let t=this.seekAction$.getValue();this.logSeek({action:t===`rich`?`slider`:t,time:e.info.position$.getValue()}),this.seekAction$.next(`unknown`)}),n(e.events.paused$,()=>{this.logPause({position:e.info.position$.getValue()})}),n(e.events.willResume$,()=>{this.logPlay()}),n(e.events.started$,()=>{this.statContext.clip&&this.logWatchCoverageRecord({start:0,end:0})}),n(e.events.playing$,()=>{this.logPlaying()}),n(Ge(e,{forceInterval:this.config.watchCoverageInterval,watchCoverageTimeoutFix:this.config.watchCoverageTimeoutFix,watchCoverageExactTime:this.config.watchCoverageExactTime}),t=>{let n=e.info.isLive$.getValue(),r=e.info.atLiveEdge$.getValue(),i={start:parseFloat(t.from.toFixed(3)),end:parseFloat(t.to.toFixed(3))};if(r){let t=e.info.liveLatency$.getValue()??0,n=e.info.currentBuffer$.getValue()?.end??0,r=e.info.liveBufferTime$.getValue()??0,a=Math.round((t-(n-r))*1e3),o=Math.round(t*1e3);a&&o&&(i.latency=a,i.bufferLatency=o)}n?this.logWatchCoverageLive(i):this.logWatchCoverageRecord(i)}),n(e.info.stallStartTime$,e=>{e>0?r={startedAt:e,liveAtStall:!!this.statContext.liveEdge}:(S(r)&&o&&this.logEmptyBuffer({duration:Math.round(C()-r.startedAt),liveAtStall:r.liveAtStall}),r=void 0)});let l=!1;t.add(e.events.fatalError$.pipe(ie()).subscribe(()=>l=!0)),n(e.events.willStop$,()=>{if(e.info.isBuffering$.getValue()&&o){let e=S(r)?C()-r.startedAt:void 0;this.logCloseAtEmptyBuffer({duration:e??0,liveAtStall:r?.liveAtStall}),r=void 0}else l||this.logActionStop()}),n(e.events.managedError$,({id:e})=>{this.logError({fatal:!1,errorType:e})}),n(e.events.fatalError$,({id:e})=>{this.logError({fatal:!0,errorType:e})}),n(e.events.firstBytes$,e=>{i=C(),this.logFirstBytes({time:e})}),n(e.events.willStart$,()=>a=C()),n(e.info.currentBuffer$,e=>{!o&&e&&e.end-e.start>0&&S(i)&&(this.logPlayerReady({duration:C()-i}),c())}),n(e.events.firstFrame$,()=>{S(i)&&!o&&(this.logPlayerReady({duration:C()-i}),c()),S(a)&&this.logFirstFrame({time:C()-a})});let u;n(e.info.currentVideoStream$,e=>{e&&(this.updateContext({videoCodec:e.codec}),u&&e.id!==u&&this.logTrackSwitch(e),u=e.id)});let d;n(e.info.currentAudioStream$,e=>{e&&(this.updateContext({audioCodec:e.codec}),d&&e.id!==d&&this.logTrackSwitch(e),d=e.id)}),n(e.info.atLiveEdge$,e=>this.updateContext({liveEdge:e})),n(b({muted:e.info.muted$,volume:e.info.volume$}),({muted:e,volume:t})=>this.updateContext({audible:!e&&t>0})),n(e.info.currentQuality$,e=>{let t=ke(e);this.updateContext({quality:t}),t&&this.logQuality(t)}),n(e.info.isAutoQualityEnabled$,e=>this.updateContext({autoQuality:e})),n(e.info.currentFormat$,e=>this.updateContext({contentType:je(e)})),n(e.info.currentPlaybackRate$,e=>this.updateContext({rate:e})),n(e.info.is3DVideo$,e=>this.updateContext({is3d:e}));let f;return n(e.info.hostname$,e=>{let t=f!==void 0&&f!==e;this.updateContext({cdnHostname:e,failover:t}),t&&this.logFailover(e),f=e}),n(e.info.throughputEstimation$,e=>this.updateContext({downloadSpeed:e})),n(e.info.httpConnectionType$,e=>{this.statContext.firstConnectionType||this.updateContext({firstConnectionType:Ae(e)}),this.updateContext({connectionType:Ae(e)})}),n(e.info.httpConnectionReused$,e=>{te(this.statContext.firstConnectionReused)&&this.updateContext({firstConnectionReused:e}),this.updateContext({connectionReused:e})}),n(e.info.surface$,e=>{this.uiEvents||this.updateContext({mode:Me(e,this.statContext.isPreviewPlayerView)})}),n(b({current:e.info.currentTextTrack$,available:e.info.availableTextTracks$}),({current:e,available:t})=>{let n=t.find(({id:t})=>t===e),r=n&&(n.isAuto?`${n.language}_auto`:n.language);this.updateContext({subtitles:r?.split(`.`)[0]})}),this.player=e,this.uiEvents&&this.attachToUi(this.uiEvents),this.resubscribeBeforeunload(),this.subscription.add(t),t}attachToUi(e){this.uiEvents=e;let{subscription:t,subscribe:n}=Qe();if(!this.player)return t;n(e.actionRewind$,()=>{this.player&&(this.resetViewSession(),this.logActionPlay({position:this.player.info.position$.getValue()}))}),n(e.actionSeek$,this.seekAction$);let{surface$:r}=Ye(this.uiEvents,n,this.player);return n(r,e=>{this.updateContext({mode:Me(e,this.statContext.isPreviewPlayerView)})}),n(e.actionSetSubtitle$,e=>this.updateContext({subtitles:e?.split(`.`)[0]})),n(e.nextMovie$,e=>this.logNextMovie(e)),this.resubscribeBeforeunload(),this.subscription.add(t),t}attachToAds(e){let{subscription:t,subscribe:n}=Qe();return n(e.slotRequested$,()=>this.logAdSlotRequest()),n(e.started$,e=>this.logAdStarted(e)),n(e.paused$,()=>this.logAdPaused()),n(e.resumed$,()=>this.logAdResumed()),n(e.ended$,()=>this.logAdEnded()),n(e.skipped$,()=>this.logAdSkipped()),n(e.clicked$,()=>this.logAdClicked()),n(e.error$,e=>this.logError({errorType:e,fatal:!1})),this.resubscribeBeforeunload(),this.subscription.add(t),t}attachToInteractive(e){let{subscription:t,subscribe:n}=Qe();return n(e.click$,e=>this.logInterfaceClick(e)),n(e.nextMovie$,e=>this.logNextMovie(e)),this.resubscribeBeforeunload(),this.subscription.add(t),t}authorize(e){return Promise.all(this.apis.map(t=>t.authorize(e)))}pause(){this.logger.pause(),this.oneStatDebugLog({message:`paused`})}resume(){this.logger.resume(),this.oneStatDebugLog({message:`resumed`})}destroy(){this.logger.flush(),this.subscription.unsubscribe(),this.apis.forEach(e=>e.destroy()),this.logger.destroy()}resetViewSession(){this.oneStatDebugLog({message:`VSID reset`}),T.generateVSID(this.config.useVsid64)}getDeviceId(){return this.deviceId}setFieldBlacklist(){}logInited(){}logReady(e){this.log({operation:`player_ready`,param:String(e.time)})}logStarted(...e){this.logActionPlay(...e)}logPlay(){this.log({operation:`play_toggle`})}logPlaying(){this.log({operation:`playing`})}logPause(e){this.log({operation:`pause`,param:String(Math.round(e.position))})}logSeek(e){this.log({operation:`seek`,param:e.action,time:e.time})}logFirstBytes(e){this.log({operation:`first_bytes`,param:String(e.time)})}logFirstFrame(e){this.log({operation:`first_frame`,param:String(e.time)})}logError(e){this.log({operation:`content_error`,param:`${e.fatal?`fatal`:`recoverable`}_${e.errorType}`})}logWatchCoverageRecord(e){this.log({operation:`watch_coverage_record`,param:`${e.start}-${e.end}`},{in_history:this.statContext.inHistory?1:void 0})}logWatchCoverageLive(e){let t=this.timeSynchronisation?.getOffset()??0,n=e.start+t,r=e.end+t;this.log({operation:`watch_coverage_live`,param:`${n}-${r}`},{in_history:this.statContext.inHistory?1:void 0,latency:e.latency,buffer_latency:e.bufferLatency})}logEmptyBuffer(e){this.log({operation:`empty_buffer`,param:String(e.duration)},S(e.liveAtStall)?{live:e.liveAtStall?1:void 0}:{})}logDownloadSpeed(){}logAdSlotRequest(){this.log({operation:`adv`,param:`slot_request`})}logAdStarted(e){this.log({operation:`adv`,param:e})}logAdPaused(){this.log({operation:`adv`,param:`pause`})}logAdResumed(){this.log({operation:`adv`,param:`resume`})}logAdEnded(){this.log({operation:`adv`,param:`ended`})}logAdSkipped(){this.log({operation:`adv`,param:`skip`})}logAdClicked(){this.log({operation:`adv`,param:`click`})}logInterfaceClick(e){this.log({operation:`player_interface_click`,param:e})}logNextMovie(e){this.log({operation:`next_movie`,param:String(e)})}subscribe(){this.resubscribeBeforeunload();let e=ce().navigator.connection;e&&`onchange`in e&&`effectiveType`in e&&this.subscription.add(ne(x(e,`change`),re([`init`])).subscribe(()=>this.updateContext({network:Ne(e.effectiveType)}))),this.config.debugLog&&this.debugLogger.log$.subscribe(e=>{console.debug(`%c stat `,`background:#fa6470;`,`component: ${e.component}.`,e.message)})}resubscribeBeforeunload(){this.beforeunloadSubscription?.unsubscribe(),this.beforeunloadSubscription=x(window,`beforeunload`).subscribe(()=>this.logger.flush({wantBeacon:!0,clearStorage:this.config.clearStorageAtUnload})),this.subscription.add(this.beforeunloadSubscription)}logPlayerReady(e){this.log({operation:`player_ready`,param:String(Math.round(e.duration))})}logActionPlay(e){this.log({operation:`action_play`,param:String(Math.round(e.position))})}logActionPlayInteractive(){this.statContext.projectId&&this.log({operation:`action_play_interactive`,param:String(this.statContext.movieId)},{vid:this.statContext.projectId})}logFailover(e){this.log({operation:`failover`,param:e})}logCloseAtEmptyBuffer(e){this.log({operation:`close_at_empty_buffer`,param:String(Math.round(e.duration))},S(e.liveAtStall)?{live:e.liveAtStall?1:void 0}:{})}logActionStop(){this.log({operation:`action_stop`})}logTrackSwitch(e){this.log({operation:`track_switch`,param:e.id})}logQuality(e){this.log({operation:`quality`,param:e})}log(e,t={}){if(this.disabled){this.oneStatDebugLog({message:`operation ${e.operation} but statistics is disabled`});return}if(this.config.disabledOperations.includes(e.operation)){this.oneStatDebugLog({message:`operation ${e.operation} but it is disabled`});return}this.oneStatDebugLog({message:`operation ${e.operation} ${e.param}`});let n=this.createLogItem(e,t);this.logger.log(n)}createLogItem({operation:e,param:t,time:n},r={}){let i=this.timeSynchronisation?.now()??C(),a=this.vsid$.getValue();y(a);let o=this.isid$.getValue(),s=e===`empty_buffer`||e===`close_at_empty_buffer`?this.statContext.connectionType:this.statContext.firstConnectionType,c=this.statContext.firstConnectionReused,l,u;if(this.isEmbed||this.statContext.place===`embed`){l=this.embedParent;let e=[...new URLSearchParams(location.search).entries()].filter(([e,t])=>this.config.embedUrlParams.includes(e));u=new URLSearchParams(e).toString()}else if(this.statContext.place===`direct`){let e=this.statContext.refDomain||document.referrer;l=e&&URL.canParse(e)?new URL(e).hostname:e,u=location.href.substring(0,1024)}let d={vsid:a,isid:o,vid:this.statContext.movieId,uid:this.zenUid$.getValue(),ct:this.statContext.contentType,place:this.isEmbed?`embed`:this.statContext.place,quality:this.statContext.quality,cdn_host:this.statContext.cdnHostname,stat_type:this.statContext.autoplay===!0?`auto`:this.statContext.autoplay===!1?``:void 0,param:t,vk_app_id:this.statContext.vkAppId,track_code:this.statContext.trackCode,connection_type:s,connection_reused:c===!0?1:c===!1?0:void 0,cached_data:this.statContext.cached===!0?1:this.statContext.cached===!1?0:void 0,live:this.statContext.liveEdge?1:void 0,muted:this.statContext.audible===!1?1:void 0,mode:this.statContext.mode,subtitles:this.statContext.subtitles,download_speed:this.statContext.downloadSpeed,manual_quality:this.statContext.autoQuality?void 0:1,ref_domain:l,direct_url:u,rate:this.statContext.rate===1||te(this.statContext.rate)?void 0:this.statContext.rate.toFixed(2),view_360:this.statContext.is3d?1:void 0,codec_info:Ze(this.statContext.videoCodec,this.statContext.audioCodec),aid:this.statContext.albumId,vk_playlist_id:this.statContext.vkPlaylistId,...r};for(let e of this.config.disabledCustomFields)delete d[e];return{operation:e,type:1,time:n,network:this.statContext.network,timestamp:i,custom:d}}}var et={};r(et,{VERSION:()=>E,ThinOneStat:()=>En,ActionSeekType:()=>_t});import{assertNonNullable as tt,detectEmbed as nt,fromEvent as rt,Logger as it,merge as at,combine as L,filter as R,filterChanged as ot,once as st,skip as ct,debounce as lt,safeStorage as ut,getWindow as dt,Subject as ft,Subscription as pt,ValueSubject as mt,ErrorCategory as z}from"@vkontakte/videoplayer-shared/evergreen";import{clientChecker as B}from"@vkontakte/videoplayer-core/evergreen";import{fillWithDefault as ht}from"@vkontakte/videoplayer-shared/evergreen";var gt;(e=>{e.AUTO=`auto`,e.AUTO_POOR=`auto_poor`,e.AUTO_RICH=`auto_rich`})(gt||={});var _t;(e=>{e.SLIDER=`slider`,e.RICH=`rich`,e.DOUBLE_TAP=`double_tap`,e.TIME_CODE=`time_code`,e.EPISODE=`episode`,e.REWIND=`rewind`,e.LIVE=`live`,e.UNKNOWN=`unknown`})(_t||={});var vt=`CIOPGQJGDIHBABABA`,yt={prod:`https://api.ok.ru`,vk_alias:`https://api.mycdn.me`,videotest:`https://videotestapi.ok.ru/api`,test:`https://apitest.ok.ru`,okcdn:`https://api.okcdn.ru`,auto:``},bt={apiKey:vt,apiEnv:`okcdn`,apiBaseUrl:null,apiForticom:!0,apiUvRest:!1,requestRetryCount:3,useVsid64:!1,flushFirstTime:5e3,flushDebounceTime:1e4,flushMaxWait:6e4,flushRetryFirstDelay:3e3,flushRetryMaxDelay:18e5,storageExpiration:2160*60*1e3,clearStorageAtUnload:!1,disabledEvents:[],disabledParams:[],synchronizeTime:!0,useBeacon:!1,alwaysSendDesktop:!1,watchCoverageHeartbeatInterval:3e4,watchCoverageExactTime:!1,watchedNDefaultTargetDuration:1e3,telemetryInterval:3e4,downloadBytesMaxTime:3e4},xt=e=>ht(e,bt);import{ErrorCategory as V,ValueSubject as St}from"@vkontakte/videoplayer-shared/evergreen";function Ct(e){let t=Error(`HTTP ${e.status}: ${e.statusText}`);return t.status=e.status,t.statusText=e.statusText,t.response=e,t}function wt(){let e=Error(`Request timeout`);return e.isTimeout=!0,e}function Tt(e){let t=Error(e.error_msg);return t.errorData=e,t}function Et(e){if(!(!e||typeof e!=`object`)){if(`errorData`in e)return e.errorData?.error_code;if(`error_code`in e){let t=e.error_code;return typeof t==`number`?t:void 0}}}class Dt{id=`forticom`;authorized$;params;authToken;sessionKey;authorizePromise;refreshAuthTokenPromise;isDestroyed=!1;constructor(e){this.params=e,this.authorized$=new St(!1)}async authorize(e){return this.authToken=e??await this.refreshAuthToken(),this.doAuthorize()}logBeacon(e){if(!e.length)return;let t=this.createLogParams(e),n=this.sessionKey;n&&(this.params.apiTransport.sendBeacon(`log.logUvStat`,t,n)||this.logRequest(e).catch(()=>{}))}async logRequest(e){if(!e.length)return;let t=`log.logUvStat`,n=this.createLogParams(e),r={};try{let e=await this.getValidSessionKey();if(!e){this.params.errors$.next({id:`ThinOneStat:Api:LogRequestNoSession`,category:V.NETWORK,message:`No session key available for log request`});return}await this.params.apiTransport.sendRequest(t,n,e,r)}catch(e){await this.handleLogRequestError(e,t,n)&&await this.retryLogRequestAfterSessionRecovery(t,n)}}async getValidSessionKey(){return this.sessionKey?this.sessionKey:this.doAuthorize()}async handleLogRequestError(e,t,n){let r=Et(e);return r===void 0?(this.params.errors$.next({id:`ThinOneStat:Api:LogRequestUnknown`,category:V.NETWORK,message:`Unknown ${t} error`,thrown:e,data:{params:n}}),!1):this.isSessionExpiredError(r)?(this.params.errors$.next({id:`ThinOneStat:Api:LogRequestSessionError#${r}`,category:V.EXTERNAL_API,message:`Session error: ${r}`,data:{error:e,code:r}}),this.authorized$.next(!1),this.sessionKey=void 0,await this.doAuthorize()!==void 0):r===401?(this.params.errors$.next({id:`ThinOneStat:Api:LogRequestAuthLogin#${r}`,category:V.EXTERNAL_API,message:`Auth token expired`,data:{error:e,code:r}}),this.authorized$.next(!1),this.authToken=await this.refreshAuthToken(),this.sessionKey=void 0,await this.doAuthorize()!==void 0):(this.params.errors$.next({id:`ThinOneStat:Api:LogRequest#${r}`,category:V.EXTERNAL_API,message:`${t} error`,data:{error:e,code:r,params:n}}),!1)}async retryLogRequestAfterSessionRecovery(e,t){let n=this.sessionKey;if(!n){this.params.errors$.next({id:`ThinOneStat:Api:LogRequestRetryFailed`,category:V.NETWORK,message:`Cannot retry log request: no session key after recovery`});return}try{await this.params.apiTransport.sendRequest(e,t,n)}catch(e){let t=Et(e);this.params.errors$.next({id:`ThinOneStat:Api:LogRequestRetryFailed#${t??`unknown`}`,category:V.EXTERNAL_API,message:`Log request failed after session recovery`,thrown:e,data:{originalError:e,retryCode:t}})}}isSessionExpiredError(e){return!!e&&[102,103,104].includes(e)}async doAuthorize(e=1){if(!this.isDestroyed)return this.authorizePromise?this.authorizePromise:(this.sessionKey=void 0,this.authorized$.next(!1),this.authorizePromise=this.executeAuthorize(e).finally(()=>{this.authorizePromise=void 0,this.isDestroyed||this.authorized$.next(this.sessionKey!==void 0)}),this.authorizePromise)}async executeAuthorize(e){let t=this.buildAuthParams();try{let e=await this.params.apiTransport.sendRequest(`auth.anonymLogin`,t);if(this.isDestroyed)return;if(!e?.session_key){this.params.errors$.next({id:`ThinOneStat:Api:AuthorizeFailed`,category:V.EXTERNAL_API,message:`No session key in response`,data:e});return}return this.sessionKey=e.session_key,this.sessionKey}catch(t){if(this.isDestroyed)return;let n=Et(t);if(n===401&&this.params.refreshAuthToken){if(this.params.errors$.next({id:`ThinOneStat:Api:AuthorizeAuthLogin`,category:V.EXTERNAL_API,message:`Auth token expired during authorization`,data:{error:t,code:n,attempt:e}}),e>=2){this.params.errors$.next({id:`ThinOneStat:Api:AuthorizeMaxAttemptsReached`,category:V.EXTERNAL_API,message:`Authorization failed after ${e} attempts`,data:{error:t,code:n}});return}return this.authToken=await this.refreshAuthToken(),this.doAuthorize(e+1)}n?this.params.errors$.next({id:`ThinOneStat:Api:Authorize#${n}`,category:V.EXTERNAL_API,message:`Authorize error`,data:{error:t,code:n}}):this.params.errors$.next({id:`ThinOneStat:Api:AuthorizeUnknown`,category:V.NETWORK,message:`Authorize error`,thrown:t});return}}buildAuthParams(){let e={session_data:{version:2,device_id:this.params.deviceId,client_version:this.getClientVersion(),client_type:`SDK_JS`}};return this.authToken!==void 0&&(e.session_data.auth_token=this.authToken,e.session_data.version=3),e}getClientVersion(){return E}async refreshAuthToken(){if(this.params.refreshAuthToken)return this.refreshAuthTokenPromise||=this.params.refreshAuthToken().catch(e=>{throw this.params.errors$.next({id:`ThinOneStat:Api:RefreshAuthTokenFailed`,category:V.NETWORK,message:`Failed to refresh auth token`,thrown:e}),e}).finally(()=>{this.refreshAuthTokenPromise=void 0}),this.refreshAuthTokenPromise}createLogParams(e){let t=`@vkontakte/videoplayer-statistics:${this.getClientVersion()}`;return this.params.vktvVersion&&(t=this.params.vktvVersion),{collector:`ok.mobile.apps.video`,uv_stat_data:JSON.stringify({application:t,platform:e[0].platform,product:e[0].product,events:e})}}destroy(){this.isDestroyed=!0,this.authorizePromise=void 0,this.refreshAuthTokenPromise=void 0,this.sessionKey=void 0,this.authorized$.next(!1)}}class Ot{id=`uvrest`;authorized$;params;statToken;authorizePromise;isDestroyed=!1;constructor(e){this.params=e,this.authorized$=new St(!1)}async authorize(e){if(!this.isDestroyed)return e?(this.statToken=e,this.authorized$.next(!0),e):this.authorizePromise?this.authorizePromise:(this.authorized$.next(!1),this.authorizePromise=this.executeAuthorize().finally(()=>{this.authorizePromise=void 0,this.isDestroyed||this.authorized$.next(this.statToken!==void 0)}),this.authorizePromise)}async logRequest(e){if(!e.length)return;let t=this.buildBody(e);try{let e=await this.getValidToken();if(!e){this.params.errors$.next({id:`ThinOneStat:UvRestApi:LogRequestNoToken`,category:V.NETWORK,message:`No stat token available for log request`});return}await this.params.apiTransport.sendJsonRequest(`/uv/stat/logUvStat`,t,{Authorization:`Bearer ${e}`})}catch(e){await this.handleLogRequestError(e)&&await this.retryLogRequestAfterRecovery(t)}}logBeacon(e){if(!e.length)return;let t=this.statToken;if(!t)return;let n=this.buildBody(e);this.params.apiTransport.sendJsonBeacon(`/uv/stat/logUvStat`,n,{Authorization:`Bearer ${t}`})}destroy(){this.isDestroyed=!0,this.authorizePromise=void 0,this.statToken=void 0,this.authorized$.next(!1)}async getValidToken(){return this.statToken?this.statToken:this.authorize()}async executeAuthorize(){try{let e=await this.params.getAuthToken();if(this.isDestroyed)return;if(!e){this.params.errors$.next({id:`ThinOneStat:UvRestApi:NoToken`,category:V.EXTERNAL_API,message:`getAuthToken returned no token`});return}return this.statToken=e,this.statToken}catch(e){if(this.isDestroyed)return;this.params.errors$.next({id:`ThinOneStat:UvRestApi:AuthorizeFailed`,category:V.NETWORK,message:`Failed to get stat token`,thrown:e});return}}async handleLogRequestError(e){let t=e?.status;return t===401?(this.params.errors$.next({id:`ThinOneStat:UvRestApi:TokenExpired`,category:V.EXTERNAL_API,message:`Stat token expired (401), refreshing`,thrown:e}),this.authorized$.next(!1),this.statToken=void 0,await this.authorize()!==void 0):(this.params.errors$.next({id:`ThinOneStat:UvRestApi:LogRequestFailed#${t??`unknown`}`,category:V.EXTERNAL_API,message:`Log request failed with status ${t}`,thrown:e}),!1)}async retryLogRequestAfterRecovery(e){let t=this.statToken;if(!t){this.params.errors$.next({id:`ThinOneStat:UvRestApi:RetryNoToken`,category:V.NETWORK,message:`Cannot retry log request: no token after recovery`});return}try{await this.params.apiTransport.sendJsonRequest(`/uv/stat/logUvStat`,e,{Authorization:`Bearer ${t}`})}catch(e){this.params.errors$.next({id:`ThinOneStat:UvRestApi:RetryFailed`,category:V.EXTERNAL_API,message:`Log request failed after token refresh`,thrown:e})}}buildBody(e){let t=e[0],n=t.application;return this.params.vktvVersion&&(n=this.params.vktvVersion),[{product:t.product,platform:t.platform,application:n,user_id:this.params.userId,events:e}]}}import{now as H,getWindow as U,getExponentialDelay as kt,isAbortError as At,ErrorCategory as W}from"@vkontakte/videoplayer-shared/evergreen";class jt{params;apiKey;apiBaseUrl;apiEnv;resolvedApiBaseUrl=null;resolveApiBaseUrlPromise=null;timeSynchronisation;fetchTimeout=3e4;maxTotalRequestTime=6e4;retryConfig;constructor(e){this.params=e,this.apiKey=e.config.apiKey,this.apiEnv=e.config.apiEnv,this.apiBaseUrl=e.config.apiBaseUrl??yt[this.apiEnv],this.timeSynchronisation=e.timeSynchronisation,this.retryConfig={maxAttempts:e.config.requestRetryCount??3,baseDelay:3e3,maxDelay:3e4,retryableErrors:[`Failed to fetch`,`NetworkError when attempting to fetch resource.`,`Request timeout`,`Network request failed`],retryableStatuses:[408,429,500,502,503,504]}}sendBeacon(e,t,n){if(!U().Blob||!U().navigator.sendBeacon)return!1;let r=this.resolvedApiBaseUrl??this.apiBaseUrl,i=this.prepareQueryParams({method:e,queryParams:t,sessionKey:n}),a=U().Blob,o=new a([i.toString()],{type:`application/x-www-form-urlencoded`});try{return U().navigator.sendBeacon(`${r}/fb.do`,o)}catch(n){this.params.errors$.next({id:`ThinOneStat:ApiTransport:sendBeacon`,category:W.NETWORK,message:`Unhandled beacon error`,thrown:n,data:{method:e,params:t}})}return!1}async sendRequest(e,t,n,r){return this.sendRequestWithRetry(e,t,n,r)}async sendRequestWithRetry(e,t,n,r,i=1,a){let o=H(),s=a??o+this.maxTotalRequestTime;if(H()>=s){let r=Error(`Request deadline exceeded`);throw this.handleFinalError(e,t,n,o,r,i),r}try{return await this.executeRequest(e,t,n,r,o,i,s)}catch(a){if(this.shouldRetry(a,i)&&H()<s){let c=this.getRetryDelay(a,i);if(H()+c>=s)throw this.handleFinalError(e,t,n,o,a,i),a;return this.logRetryAttempt(e,i,a,c),await this.sleep(c),this.sendRequestWithRetry(e,t,n,r,i+1,s)}throw this.handleFinalError(e,t,n,o,a,i),a}}async executeRequest(e,t,n,r,i,a,o){let s=i??H(),c=await this.resolveApiBaseUrl(),l=o===void 0?this.fetchTimeout:o-H();if(l<=0)throw wt();try{let i=await this.fetchWithTimeout(`${c}/fb.do`,{method:`post`,headers:{"Content-type":`application/x-www-form-urlencoded`,...r},body:this.prepareQueryParams({method:e,queryParams:t,sessionKey:n})},Math.min(this.fetchTimeout,l));return await this.processResponse(i,s)}catch(t){throw t instanceof Error&&(t.context={method:e,attempt:a,url:`${c}/fb.do`}),t}}async sendJsonRequest(e,t,n){return this.sendJsonRequestWithRetry(e,t,n)}sendJsonBeacon(e,t,n){let r=`${this.resolvedApiBaseUrl??this.apiBaseUrl}${e}`;try{fetch(r,{method:`POST`,headers:{"Content-Type":`application/json`,...n},body:JSON.stringify(t),keepalive:!0}).catch(t=>{this.params.errors$.next({id:`ThinOneStat:ApiTransport:sendJsonBeacon`,category:W.NETWORK,message:`Keepalive request failed`,thrown:t,data:{path:e}})})}catch(t){this.params.errors$.next({id:`ThinOneStat:ApiTransport:sendJsonBeacon`,category:W.NETWORK,message:`Failed to initiate keepalive request`,thrown:t,data:{path:e}})}}async sendJsonRequestWithRetry(e,t,n,r=1,i){let a=H(),o=i??a+this.maxTotalRequestTime;if(H()>=o){let t=Error(`Request deadline exceeded`);throw this.handleJsonFinalError(e,a,t,r),t}try{return await this.executeJsonRequest(e,t,n,a,r,o)}catch(i){if(this.shouldRetry(i,r)&&H()<o){let s=this.getRetryDelay(i,r);if(H()+s>=o)throw this.handleJsonFinalError(e,a,i,r),i;return this.logRetryAttempt(e,r,i,s),await this.sleep(s),this.sendJsonRequestWithRetry(e,t,n,r+1,o)}throw this.handleJsonFinalError(e,a,i,r),i}}async executeJsonRequest(e,t,n,r,i,a){let o=r??H(),s=await this.resolveApiBaseUrl(),c=a===void 0?this.fetchTimeout:a-H();if(c<=0)throw wt();let l=`${s}${e}`;try{let e=await this.fetchWithTimeout(l,{method:`POST`,headers:{"Content-Type":`application/json`,...n},body:JSON.stringify(t)},Math.min(this.fetchTimeout,c));return await this.processResponse(e,o)}catch(t){throw t instanceof Error&&(t.context={method:e,attempt:i,url:l}),t}}async fetchWithTimeout(e,t,n=this.fetchTimeout){let r=new AbortController,i=U().setTimeout(()=>r.abort(),n);try{let n=await fetch(e,{...t,signal:r.signal});return U().clearTimeout(i),n}catch(e){throw U().clearTimeout(i),At(e)?wt():e}}async processResponse(e,t){if(!e.ok){let t=Ct(e),n=this.parseRetryAfter(e);throw n!==void 0&&(t.retryAfter=n),t}let n=new Date(e.headers.get(`date`)??``).getTime(),r=H()-t;isFinite(n)&&this.timeSynchronisation?.addServerTime(n,r);let i=e.headers.get(`content-length`);if(i!==null&&Number(i)===0)return{};let a=await e.json();if(a&&typeof a==`object`&&`error_msg`in a)throw Tt(a);return a}shouldRetry(e,t){if(t>=this.retryConfig.maxAttempts||!(e instanceof Error))return!1;let n=e;return!!(n.isTimeout||n.status&&this.retryConfig.retryableStatuses.includes(n.status)||this.retryConfig.retryableErrors.includes(e.message)||e.message.includes(`network`)||e.message.includes(`timeout`)||e.message.includes(`connection`))}logRetryAttempt(e,t,n,r){let i=n instanceof Error?n.message:String(n);this.params.errors$.next({id:`ThinOneStat:ApiTransport:retry`,category:W.NETWORK,message:`Retrying request (attempt ${t}/${this.retryConfig.maxAttempts}) after ${Math.round(r)}ms`,thrown:n,data:{method:e,attempt:t,delay:r,errorMessage:i}})}handleFinalError(e,t,n,r,i,a){let o=W.NETWORK;this.params.errors$.next({id:`ThinOneStat:ApiTransport:sendRequest`,category:o,message:i instanceof Error?i.message:`Request failed after retries`,thrown:i,data:{method:e,params:t,sessionKey:n,time:H()-r,maxAttempts:this.retryConfig.maxAttempts,attempts:a}})}handleJsonFinalError(e,t,n,r){this.params.errors$.next({id:`ThinOneStat:ApiTransport:sendJsonRequest`,category:W.NETWORK,message:n instanceof Error?n.message:`JSON request failed after retries`,thrown:n,data:{path:e,time:H()-t,maxAttempts:this.retryConfig.maxAttempts,attempts:r}})}sleep(e){return new Promise(t=>U().setTimeout(t,e))}resolveApiBaseUrl(){return this.apiEnv===`auto`?(this.resolveApiBaseUrlPromise||=this.fetchApiBaseUrl().then(e=>(e===yt.vk_alias&&(this.resolveApiBaseUrlPromise=null),e)),this.resolveApiBaseUrlPromise):Promise.resolve(this.apiBaseUrl)}async fetchApiBaseUrl(){try{let e=atob(`aHR0cHM6Ly9kbnMuZ29vZ2xlL3Jlc29sdmU/bmFtZT12aWRlby5fZW5kcG9pbnQub2sucnUmdHlwZT1UWFQ=`),t=(await(await this.fetchWithTimeout(e,{method:`GET`,mode:`cors`,cache:`no-cache`},5e3)).json())?.Answer[0]?.data;if(!t)throw Error(`Wrong DNS response`);return this.resolvedApiBaseUrl=t,t}catch(e){return this.params.errors$.next({id:`ThinOneStat:ApiTransport:resolveApiBaseUrl`,category:W.NETWORK,message:`Unhandled resolve api base url error`,thrown:e}),yt.vk_alias}}prepareQueryParams(e){let t=new URLSearchParams({format:`JSON`,method:e.method,application_key:this.apiKey});return e.sessionKey!==void 0&&t.append(`session_key`,e.sessionKey),Object.entries(e.queryParams).forEach(([e,n])=>t.append(e,typeof n==`string`?n:JSON.stringify(n))),t}parseRetryAfter(e){let t=e.headers.get(`Retry-After`);if(!t)return;let n=Number(t);if(!isNaN(n)&&n>=0)return n*1e3;let r=new Date(t).getTime();if(!isNaN(r))return Math.max(0,r-Date.now())}getRetryDelay(e,t){let n=e;return n?.retryAfter!==void 0&&n.retryAfter>0?n.retryAfter:kt(t,{start:this.retryConfig.baseDelay,max:this.retryConfig.maxDelay,factor:2,random:.2})}}import{ErrorCategory as Mt}from"@vkontakte/videoplayer-shared/evergreen";import{now as Nt,debounceFn as Pt,getWindow as G,safeStorage as Ft,ErrorCategory as K}from"@vkontakte/videoplayer-shared/evergreen";var It=e=>t=>(t.client_time??Nt())+e>=Nt();class Lt{params;subscription;userSalt;unsaltedStorage=[];lastVsid;isPaused=!1;firstFlush;debouncedFlush;flushRetryCount=0;retryFlushTimerId;debugLog;flushPromise=null;flushSnapshotLength=0;onlineListener;urgentEvents=[`watch_coverage`,`watch_coverage_live`,`watched_n`,`playback_started`];STORAGE_MAX_ATTEMPTS=3;constructor(e){this.params=e,this.userSalt=e.userSalt,this.debugLog=e.debugLogger.createComponentLog(`batch-queue:${e.storageKey}`),this.firstFlush=Pt(()=>this.safeFlush(),this.params.config.flushFirstTime,{maxWait:this.params.config.flushFirstTime});let t=Ft.isPersistent()?this.params.config.flushMaxWait:0;this.debouncedFlush=Pt(()=>this.safeFlush(),this.params.config.flushDebounceTime,{maxWait:t}),this.subscription=this.params.canSend$.subscribe(e=>{e&&(this.debugLog({message:`Can send, triggering flush`}),this.debouncedFlush())}),this.onlineListener=()=>{this.debugLog({message:`Network online, triggering flush`}),this.cancelRetry(),this.safeFlush()},G().addEventListener(`online`,this.onlineListener),this.housekeepStorage()}isUrgent=e=>this.urgentEvents.includes(e.event_name);scheduleRetry(){this.retryFlushTimerId!==void 0&&G().clearTimeout(this.retryFlushTimerId);let e=this.params.config.flushRetryFirstDelay,t=this.params.config.flushRetryMaxDelay,n=Math.min(e*2**this.flushRetryCount,t);this.flushRetryCount++,this.debugLog({message:`Scheduling flush retry #${this.flushRetryCount} in ${n}ms`}),this.retryFlushTimerId=G().setTimeout(()=>{this.retryFlushTimerId=void 0,this.safeFlush()},n)}cancelRetry(){this.retryFlushTimerId!==void 0&&(G().clearTimeout(this.retryFlushTimerId),this.retryFlushTimerId=void 0),this.flushRetryCount=0}safeFlush(){if(this.flushPromise){this.debugLog({message:`Flush already in progress, skipping`});return}this.flushPromise=this.flush().finally(()=>{this.flushPromise=null})}isStorageAvailable(){let e=Ft.isPersistent?.()??!1;return e||this.debugLog({message:`Storage not available`}),e}readFromStorage(){if(!this.isStorageAvailable())return{};try{let e=Ft.get(this.params.storageKey),t=e?JSON.parse(e):{};return this.debugLog({message:`Read ${Object.keys(t).length} users from storage`}),t}catch(e){return this.params.errors$.next({id:`ThinOneStat:BatchQueue:ReadStorageError`,category:K.WTF,message:`Failed to read from storage`,thrown:e,data:{storageKey:this.params.storageKey}}),this.debugLog({message:`Failed to read from storage`}),{}}}writeToStorage(e){if(!this.isStorageAvailable())return!1;try{return Ft.set(this.params.storageKey,JSON.stringify(e)),this.debugLog({message:`Written ${Object.keys(e).length} users to storage`}),!0}catch(e){return this.params.errors$.next({id:`ThinOneStat:BatchQueue:WriteStorageError`,category:K.WTF,message:`Failed to write to storage`,thrown:e,data:{storageKey:this.params.storageKey}}),this.debugLog({message:`Failed to write to storage`}),!1}}addToStorage(e){if(!this.userSalt){this.unsaltedStorage.push(e),this.debugLog({message:`Added item to unsalted storage, total: ${this.unsaltedStorage.length}`});return}for(let t=0;t<this.STORAGE_MAX_ATTEMPTS;t++)try{let t=this.readFromStorage(),n=t[this.userSalt]??[];if(this.debugLog({message:`Adding item to storage for user ${this.userSalt}`}),this.writeToStorage({...t,[this.userSalt]:[...n,e]}))return}catch(n){t===this.STORAGE_MAX_ATTEMPTS-1&&(this.params.errors$.next({id:`ThinOneStat:BatchQueue:AddToStorageFailed`,category:K.WTF,message:`Failed to add item to storage after retries`,thrown:n,data:{item:e,attempt:t,storageKey:this.params.storageKey}}),this.debugLog({message:`Failed to add item to storage after retries`}))}}getFromStorage(){if(!this.userSalt)return this.debugLog({message:`Retrieved ${this.unsaltedStorage.length} items from unsalted storage`}),this.flushSnapshotLength=this.unsaltedStorage.length,this.unsaltedStorage.slice();let e=this.readFromStorage(),t=e[this.userSalt]??[],n=t.filter(It(this.params.config.storageExpiration));if(this.debugLog({message:`Retrieved from storage for user ${this.userSalt}`}),n.length!==t.length){let r=t.length-n.length;this.params.errors$.next({id:`ThinOneStat:BatchQueue:DropExpiredEvents`,category:K.WTF,message:`Dropped ${r} expired events from storage`,data:{droppedCount:r,expiration:this.params.config.storageExpiration,storageKey:this.params.storageKey}}),this.debugLog({message:`Cleaning ${r} expired items from storage`});let i={...e};n.length?i[this.userSalt]=n:delete i[this.userSalt],this.writeToStorage(i)}return this.flushSnapshotLength=n.length,n}markStorageSent(){if(!this.userSalt){let e=this.unsaltedStorage.splice(0,this.flushSnapshotLength);this.debugLog({message:`Cleared unsalted storage, removed ${e.length} items, ${this.unsaltedStorage.length} new items kept`}),this.flushSnapshotLength=0;return}let e=this.flushSnapshotLength;this.flushSnapshotLength=0;for(let t=0;t<this.STORAGE_MAX_ATTEMPTS;t++)try{let t=this.readFromStorage(),n=(t[this.userSalt]??[]).slice(e),r={...t};if(n.length?r[this.userSalt]=n:delete r[this.userSalt],this.writeToStorage(r)){this.debugLog({message:`Marked storage as sent for user ${this.userSalt}, removed ${e} items, ${n.length} kept`});return}}catch(e){t===this.STORAGE_MAX_ATTEMPTS-1&&(this.params.errors$.next({id:`ThinOneStat:BatchQueue:MarkStorageSentFailed`,category:K.WTF,message:`Failed to mark storage as sent after retries`,thrown:e,data:{storageKey:this.params.storageKey}}),this.debugLog({message:`Failed to mark storage as sent after retries`}))}}housekeepStorage(){if(this.isStorageAvailable())try{let e=this.readFromStorage(),t=!1,n=0;for(let[r,i]of Object.entries(e)){let a=i.filter(It(this.params.config.storageExpiration)),o=i.length-a.length;n+=o,a.length?a.length!==i.length&&(e[r]=a,t=!0):(delete e[r],t=!0),this.debugLog({message:`${i.length} retrieved from storage, ${a.length} of them actual for ${r}`})}t?(this.debugLog({message:`Housekeeping completed, removed ${n} expired items total`}),this.writeToStorage(e),n>0&&this.params.errors$.next({id:`ThinOneStat:BatchQueue:DropExpiredEvents`,category:K.WTF,message:`Dropped ${n} expired events during housekeeping`,data:{droppedCount:n,expiration:this.params.config.storageExpiration,storageKey:this.params.storageKey}})):this.debugLog({message:`Housekeeping completed, no changes needed`})}catch(e){this.params.errors$.next({id:`ThinOneStat:BatchQueue:HousekeepStorageError`,category:K.WTF,message:`Failed to housekeep storage`,thrown:e,data:{storageKey:this.params.storageKey}}),this.debugLog({message:`Failed to housekeep storage`})}}log(e){try{if(this.debugLog({message:`Logging item: ${e.event_name}`}),this.addToStorage(e),this.isPaused){this.debugLog({message:`Queue paused, skipping flush`});return}this.isUrgent(e)?(this.debugLog({message:`Urgent item, flushing immediately`}),this.safeFlush()):this.lastVsid===e.vsid?(this.debugLog({message:`Same VSID, scheduling debounced flush`}),this.debouncedFlush()):(this.debugLog({message:`VSID changed, triggering first flush`}),this.firstFlush()),this.lastVsid=e.vsid}catch(t){this.params.errors$.next({id:`ThinOneStat:BatchQueue:LogError`,category:K.WTF,message:`Failed to log item`,thrown:t,data:{item:e,storageKey:this.params.storageKey}}),this.debugLog({message:`Failed to log item`})}}flush(e={wantBeacon:!1,clearStorage:!0}){return this.flushPromise?(this.debugLog({message:`Flush already in progress, waiting`}),this.flushPromise):(this.flushPromise=this.flushInternal(e).finally(()=>{this.flushPromise=null}),this.flushPromise)}async flushInternal({wantBeacon:e,clearStorage:t}){this.debugLog({message:`Starting flush`});let n=this.getFromStorage();if(n.length===0){this.debugLog({message:`No items to flush`});return}let r=this.params.canSend$.getValue();if(this.debugLog({message:`Can send status: ${r}`}),!r){this.debugLog({message:`Cannot send, requesting ready state`}),this.params.requestReady();return}if(e&&this.params.config.useBeacon){this.debugLog({message:`Flushing ${n.length} events through beacon`}),this.params.sendBeacon(n),t&&this.markStorageSent(),this.firstFlush.cancel(),this.debouncedFlush.cancel();return}this.debugLog({message:`Flushing ${n.length} events`});try{await this.params.send(n),this.debugLog({message:`Flush completed successfully`}),this.cancelRetry(),t&&this.markStorageSent(),this.firstFlush.cancel(),this.debouncedFlush.cancel()}catch(e){throw this.params.errors$.next({id:`ThinOneStat:BatchQueue:FlushRequestError`,category:K.NETWORK,message:`Failed to send events, will retry later`,thrown:e,data:{itemsCount:n.length,storageKey:this.params.storageKey}}),this.debugLog({message:`Flush failed, scheduling retry`}),this.scheduleRetry(),e}}pause(){this.debugLog({message:`Queue paused`}),this.isPaused=!0,this.debouncedFlush.cancel(),this.firstFlush.cancel(),this.cancelRetry()}resume(){this.debugLog({message:`Queue resumed`}),this.isPaused=!1,this.debouncedFlush()}async destroy(){this.debugLog({message:`Destroying queue`}),this.flushPromise&&(this.debugLog({message:`Waiting for ongoing flush to complete`}),await this.flushPromise),this.cancelRetry(),this.onlineListener&&=(G().removeEventListener(`online`,this.onlineListener),void 0),this.subscription.unsubscribe(),this.firstFlush.cancel(),this.debouncedFlush.cancel(),this.flushPromise=null,this.debugLog({message:`Queue destroyed`})}}class Rt{params;queues=[];constructor(e){this.params=e;for(let t of e.apis)this.queues.push(this.createQueueForApi(t))}createQueueForApi(e){let t=this.getStorageKeyForApi(e.id);return new Lt({config:this.params.config,storageKey:t,debugLogger:this.params.debugLogger,errors$:this.params.errors$,userSalt:this.params.userSalt,send:t=>e.logRequest(t),sendBeacon:t=>e.logBeacon(t),canSend$:e.authorized$,requestReady:()=>{e.authorize().catch(e=>{this.params.errors$.next({id:`ThinOneStat:Logger:RequestReadyFailed`,category:Mt.NETWORK,message:`Failed to authorize on requestReady`,thrown:e,data:{storageKey:t}})})}})}getStorageKeyForApi(e){return`thinonestat_events_${e}`}log(e){this.queues.forEach(t=>t.log(e))}async flush(e){let t=await Promise.allSettled(this.queues.map(t=>t.flush(e)));if(t.length>0&&t.every(e=>e.status===`rejected`))throw t.find(e=>e.status===`rejected`).reason}pause(){this.queues.forEach(e=>e.pause())}resume(){this.queues.forEach(e=>e.resume())}async destroy(){await Promise.allSettled(this.queues.map(e=>e.destroy())),this.queues=[]}}function zt(){let e=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`.split(``),t=Array(36),n=0,r,i;for(i=0;i<36;i++)i===8||i===13||i===18||i===23?t[i]=`-`:i===14?t[i]=`4`:(n<=2&&(n=33554432+Math.random()*16777216|0),r=n&15,n>>=4,t[i]=e[i===19?r&3|8:r]);return t.join(``)}class Bt{offset=void 0;constructor(e){this.offset=e}getOffset(){return this.offset??0}setOffset(e){this.offset=e}now(){return Date.now()+(this.offset??0)}date(e=new Date){return e.setTime(e.getTime()+(this.offset??0)),e}addServerTime(e,t){let n=e-Date.now()-t/2;if(Math.abs(n)<1e3){this.offset=0;return}if(this.offset===void 0)this.offset=Math.round(n);else{let e=.2;this.offset=Math.round(e*n+(1-e)*this.offset)}}}import{PlaybackState as Vt}from"@vkontakte/videoplayer-core/evergreen";import{Observable as Ht,Subscription as Ut,ValueSubject as Wt,Subject as Gt,fromEvent as Kt,isNullable as qt,map as Jt,merge as q,filter as Yt,filterChanged as Xt,getWindow as Zt}from"@vkontakte/videoplayer-shared/evergreen";var Qt=(e,t,n)=>new Ht(r=>{let i=new Ut,a=new Wt(void 0),o;i.add(e.info.isLive$.pipe(Xt()).subscribe(t=>{o&&(o.unsubscribe(),a.next(void 0)),o=t?e.info.liveTime$.pipe(Jt(e=>e&&e/1e3)).subscribe(a):e.info.position$.subscribe(a),i.add(o)}));let{playing$:s,paused$:c,ended$:l,looped$:u}=e.events,d=e.events.willSeek$.pipe(Yt(()=>e.info.playbackState$.getValue()===Vt.PLAYING)),f=e.events.seeked$.pipe(Yt(()=>e.info.playbackState$.getValue()===Vt.PLAYING)),p=!1,m=new Gt;i.add(d.subscribe(()=>{p||m.next(),p=!0})).add(f.subscribe(()=>p=!1));let h=q(Kt(Zt(),`beforeunload`),e.events.willDestruct$),g,ee=e=>{g=e},_=e=>{let t=e;qt(g)||qt(t)||g===t||(r.next({from:g,to:t}),g=void 0)},v=new Gt,y=new Gt,b=()=>n.exactTime?e.info.isLive$.getValue()?e.getExactLiveTime():e.getExactTime():a.getValue()??0,x=q(s,f,v).pipe(Jt(()=>b())),S=q(u,q(c,m,h,l,y).pipe(Jt(()=>b()))),te=t.started$&&t.ended$?q(x,t.ended$):x,ne=t.started$&&t.ended$?q(S,t.started$):S;if(i.add(te.subscribe(ee)).add(ne.subscribe(_)),n.heartbeatInterval&&isFinite(n.heartbeatInterval)){let e=[],t=()=>{y.next(),v.next()};i.add(te.subscribe(()=>{let r=Zt().setTimeout(t,n.heartbeatInterval);e.push(r)})).add(ne.subscribe(()=>{e.forEach(e=>{Zt().clearTimeout(e)}),e=[]}))}return i});import{Subscription as $t}from"@vkontakte/videoplayer-core/evergreen";import{Observable as en,merge as tn}from"@vkontakte/videoplayer-shared/evergreen";var nn=(e,t)=>new en(n=>{let r=new $t;return r.add(tn(e.info.position$,e.info.liveTime$).subscribe(()=>{let e=t.getTotalViewTime();e>=t.targetDuration&&(n.next({target_duration:t.targetDuration,current_tvt:e}),r.unsubscribe())})),r});import{Subscription as rn}from"@vkontakte/videoplayer-core/evergreen";import{Observable as an,filter as on,getWindow as sn}from"@vkontakte/videoplayer-shared/evergreen";var cn=(e,{maxTimeWindow:t})=>new an(n=>{let r=new rn,i={maxBytesThreshold:100*1024*1024,minBytesThreshold:100*1024,maxTimeWindow:t,minTimeWindow:2e3},a={bytes:0,startTime:0,lastEmitTime:0,timeoutId:0},o=()=>{a.timeoutId&&=(sn().clearTimeout(a.timeoutId),null)},s=()=>{a.bytes=0,a.startTime=0,a.lastEmitTime=0,o()},c=e=>{if(a.bytes<i.minBytesThreshold||e-a.lastEmitTime<i.minTimeWindow&&a.lastEmitTime>0)return!1;let t=(a.startTime>0?e-a.startTime:0)>=i.maxTimeWindow,n=a.bytes>=i.maxBytesThreshold;return t||n},l=(e=!1)=>{let t=Date.now();if(!e&&!c(t))return;o();let r=a.startTime>0?t-a.startTime:Math.max(i.minTimeWindow,1),l=a.bytes/(r/1e3);n.next({download_bytes:Math.round(a.bytes),download_speed:Math.round(l)}),a.lastEmitTime=t,s()},u=()=>{if(o(),a.startTime>0&&a.bytes>=i.minBytesThreshold){let e=Date.now()-a.startTime,t=i.maxTimeWindow-e;t>100?a.timeoutId=sn().setTimeout(()=>{a.timeoutId=null,l()},t):t>0&&l()}};return r.add(e.info.httpDownloadMetrics$.pipe(on(e=>e!==void 0)).subscribe(e=>{let t=Date.now();a.startTime===0&&(a.startTime=t),a.bytes+=e.bytes,c(t)?l():u()})),r.add(()=>{if(o(),a.bytes>0){let e=Date.now(),t=a.startTime>0?e-a.startTime:i.minTimeWindow,r=a.bytes/(t/1e3);n.next({download_bytes:Math.round(a.bytes),download_speed:Math.round(r)})}s()}),r});import{Observable as ln,Subscription as un,merge as dn}from"@vkontakte/videoplayer-shared/evergreen";var fn=e=>new ln(t=>{let n=new un,r=0,i=1,a=0,o=!1,s=!1,c=()=>{if(!o)return;let e=Date.now();a+=(e-r)*i,r=e},l=()=>{(!o||s)&&(r=Date.now(),o=!0,s=!1)},u=()=>{o&&=(c(),!1)},d=()=>{o&&(c(),o=!1,s=!0)},f=e=>{o&&c(),i=e,r=Date.now()},{started$:p,playing$:m,paused$:h,willSeek$:g,ended$:ee,willDestruct$:_}=e.events,{currentPlaybackRate$:v}=e.info;return n.add(g.subscribe(d)).add(dn(p,m).subscribe(l)).add(dn(h,ee,_).subscribe(u)).add(v.subscribe(f)),t.next(()=>{let e=a;return o&&(e+=(Date.now()-r)*i),Math.round(e)}),n});import{Observable as pn,Subscription as mn,merge as hn}from"@vkontakte/videoplayer-shared/evergreen";var gn=(e,t)=>new pn(n=>{let r=new mn,i=0;return r.add(hn(e.info.position$,e.info.liveTime$).subscribe(()=>{let e=t.getTotalViewTime();e>i&&Math.floor(e/t.interval)>Math.floor(i/t.interval)&&(i=e,n.next())})),r});import{assertNever as _n}from"@vkontakte/videoplayer-shared/evergreen";import{HttpConnectionType as vn,Surface as J,VideoFormat as Y,VideoQuality as X}from"@vkontakte/videoplayer-core/evergreen";var yn=e=>e&&{[vn.HTTP1]:`http1`,[vn.HTTP2]:`http2`,[vn.QUIC]:`http3`}[e],Z=e=>{if(e!==void 0)switch(e){case Y.MPEG:return`MP4`;case Y.DASH:case Y.DASH_LIVE:return`DASH`;case Y.DASH_SEP:return`DASH_SEP`;case Y.DASH_ONDEMAND:return`ONDEMAND_DASH`;case Y.HLS_ONDEMAND:return`ONDEMAND_HLS`;case Y.HLS:case Y.HLS_LIVE:return`HLS`;case Y.HLS_FMP4:return`HLS_FMP4`;case Y.DASH_WEBM:case Y.DASH_LIVE_WEBM:return`WEBM`;case Y.DASH_LIVE_CMAF:return`ONDEMAND_DASH_LIVE`;case Y.HLS_LIVE_CMAF:return`ONDEMAND_HLS_LIVE`;case Y.WEB_RTC_LIVE:return`WEBRTC`;case Y.DASH_WEBM_AV1:return`AV1`;case Y.DASH_STREAMS:return`MULTI_DASH`;default:return _n(e)}},Q=e=>{if(e!==void 0)switch(e){case X.Q_144P:return`144p`;case X.Q_240P:return`240p`;case X.Q_360P:return`360p`;case X.Q_480P:return`480p`;case X.Q_720P:return`720p`;case X.Q_1080P:return`1080p`;case X.Q_1440P:return`1440p`;case X.Q_2160P:return`2160p`;case X.INVARIANT:case X.Q_576P:case X.Q_4320P:return`UNKNOWN`;default:return _n(e)}},bn=e=>{if(e!==void 0)switch(e){case`MP4`:case`ONDEMAND_DASH`:case`ONDEMAND_DASH_LIVE`:case`ONDEMAND_HLS`:case`ONDEMAND_HLS_LIVE`:case`MULTI_DASH`:case`WEBM`:case`AV1`:return`vod`;case`DASH`:case`HLS`:case`HLS_FMP4`:case`WEBRTC`:return`live`;default:return}},$=(e,t,n)=>{if(e&&t)switch(e){case Y.MPEG:return n&&t[e]&&t[e][n];default:return t[e]?.url}},xn=(e,t=!1)=>{if(t)return`minimal`;switch(e){case void 0:case J.NONE:return;case J.INLINE:return`inline`;case J.FULLSCREEN:return`fullscreen`;case J.SECOND_SCREEN:return`chromecast`;case J.PIP:return`pip_external`}},Sn=e=>{switch(e){case void 0:return;case J.INVISIBLE:return`background`;default:return`foreground`}},Cn=`_thin-one-stat_deviceId`,wn=`2.2.0`,Tn=()=>{let e=new pt;return{subscription:e,subscribe:(t,n)=>{t&&e.add(t.subscribe(n))}}};class En{apis=[];logger;config;subscription;beforeunloadSubscription;timeSynchronisation;statContext;deviceId;targetDuration;debugLogger=new it;thinOneStatDebugLog=this.debugLogger.createComponentLog(`ThinOneStat`);eventNumber=1;isStarted;wasPaused;isLive;cdnHostname;isEmbed;embedHostname;connectionType;connectionReused;player;playerSize={width:0,height:0};currentSubtitle;userQuality;downloadQuality;downloadSpeed;networkType;uiEvents;playerSubscription;uiSubscription;adsSubscription;seekAction$=new mt(`unknown`);vsid$=new mt(void 0);isid$=new mt(void 0);errors$=new ft;getTotalViewTime=()=>0;constructor(e,t){this.statContext=e,this.config=xt(t.config??{}),this.subscription=new pt,this.config.synchronizeTime&&(this.timeSynchronisation=new Bt),this.subscription.add(this.errors$.subscribe(e=>{this.thinOneStatDebugLog({message:`[${e.category}] ${e.id}: ${e.message}`})}));let n=ut.get(Cn);this.statContext.deviceId?this.deviceId=this.statContext.deviceId:n?this.deviceId=n:(this.deviceId=zt(),ut.set(Cn,this.deviceId)),this.statContext.targetDuration?this.targetDuration=this.statContext.targetDuration:this.targetDuration=this.config.watchedNDefaultTargetDuration,this.resetViewSession(),t.useIsid&&this.isid$.next(t.isid??pe());let r=new jt({errors$:this.errors$,config:this.config,timeSynchronisation:this.timeSynchronisation});this.config.apiForticom&&this.apis.push(new Dt({config:this.config,apiTransport:r,errors$:this.errors$,deviceId:this.deviceId,refreshAuthToken:t.refreshAuthToken})),this.config.apiUvRest&&(t.getUvRestAuthToken?this.apis.push(new Ot({config:this.config,apiTransport:r,errors$:this.errors$,userId:this.statContext.userId,getAuthToken:t.getUvRestAuthToken})):this.errors$.next({id:`ThinOneStat:Init:MissingGetUvRestAuthToken`,category:z.WTF,message:`thinStatToUvRest enabled but getUvRestAuthToken callback not provided`})),this.logger=new Rt({config:this.config,debugLogger:this.debugLogger,apis:this.apis,errors$:this.errors$,userSalt:t.userSalt});let{isEmbed:i,topOrigin:a}=nt();this.isEmbed=i,this.embedHostname=a?new URL(a).hostname:void 0}authorize(e){this.apis.forEach(t=>{t.authorize(e).catch(()=>{})})}updateContext(e){this.statContext={...this.statContext,...e}}attachTo(e,t){this.playerSubscription&&(this.thinOneStatDebugLog({message:`Re-attaching to player, unsubscribing from previous`}),this.playerSubscription.unsubscribe());let n=new pt,r=(e,t)=>n.add(e.subscribe(t));r(fn(e),e=>{this.getTotalViewTime=e}),r(e.info.isLive$,e=>this.isLive=e),r(e.info.hostname$.pipe(R(e=>e!==void 0)),e=>{this.cdnHostname=e});let i;r(L({hostname:e.info.hostname$,connectionType:e.info.httpConnectionType$,connectionReused:e.info.httpConnectionReused$}).pipe(R(({hostname:e})=>e!==void 0),R(({connectionType:e})=>e!==void 0),R(({connectionReused:e})=>e!==void 0)),({hostname:t,connectionType:n,connectionReused:r})=>{if(i!==void 0&&i!==t){let i={cdn_host:t,connection_type:yn(n),connection_reused:r,content_type:Z(e.info.currentFormat$.getValue())};this.logFailover(i),this.logTelemetry(this.collectTelemetryData())}this.cdnHostname=i=t}),r(e.info.httpConnectionType$,e=>{this.connectionType=yn(e)}),r(e.info.httpConnectionReused$,e=>{this.connectionReused=e}),r(Qt(e,t,{heartbeatInterval:this.config.watchCoverageHeartbeatInterval,exactTime:this.config.watchCoverageExactTime}),t=>{let n={watch_interval:`${Math.round(t.from*1e3)}-${Math.round(t.to*1e3)}`,in_history:!!this.statContext.inHistory,content_type:Z(e.info.currentFormat$.getValue()),playback_quality:Q(e.info.currentQuality$.getValue()),recom_info:this.statContext.recomInfo};if(!e.info.isLive$.getValue())this.logWatchCoverage(n);else{let t=e.info.atLiveEdge$.getValue();this.logWatchCoverageLive({...n,live:!!t})}}),r(gn(e,{interval:this.statContext.telemetryInterval??this.config.telemetryInterval,getTotalViewTime:this.getTotalViewTime}),()=>{this.logTelemetry(this.collectTelemetryData())}),r(nn(e,{targetDuration:this.targetDuration,getTotalViewTime:this.getTotalViewTime}),e=>{this.logWatchedN(e)}),r(e.events.willReady$,()=>{let t={isid:this.isid$.getValue(),stream_profile:bn(Z(e.info.currentFormat$.getValue())),dpi:Math.round(this.statContext.dpi??96*B.display.pixelRatio),web_layout:this.statContext.isMobile||B.device.isMobile?`mobile`:`desktop`,preloaded:this.statContext.preload,navigation:this.statContext.navigation,recom_info:this.statContext.recomInfo};if(this.isEmbed&&(t.iframe_host=this.embedHostname??`unknown`),this.logStartSession(t),this.statContext.preload){let t=e.info.currentFormat$.getValue(),n=e.info.availableSources$.getValue(),r=e.info.currentBuffer$.getValue(),i=e.info.currentQuality$.getValue(),a={target_buffer_time:this.calcBufferTime(r),playback_url:$(t,n,i),playback_quality:Q(i)};this.logPreloadStarted(a)}}),r(L({manifestRequested$:e.events.manifestRequested$,connectionType:e.info.httpConnectionType$,connectionReused:e.info.httpConnectionReused$}).pipe(R(({connectionType:e})=>e!==void 0),R(({connectionReused:e})=>e!==void 0),st()),()=>{let t={playback_url:$(e.info.currentFormat$.getValue(),e.info.availableSources$.getValue(),e.info.currentQuality$.getValue()),cdn_host:this.cdnHostname,connection_type:this.connectionType,connection_reused:this.connectionReused};this.logManifestRequest(t)}),r(L({firstBytesManifest:e.events.firstBytesManifest$,connectionType:e.info.httpConnectionType$,connectionReused:e.info.httpConnectionReused$}).pipe(R(({connectionType:e})=>e!==void 0),R(({connectionReused:e})=>e!==void 0),st()),()=>{let t={playback_url:$(e.info.currentFormat$.getValue(),e.info.availableSources$.getValue(),e.info.currentQuality$.getValue()),cdn_host:this.cdnHostname,connection_type:this.connectionType,connection_reused:this.connectionReused};this.logFirstByteManifest(t)}),r(e.events.manifestReceived$,()=>{let t={playback_url:$(e.info.currentFormat$.getValue(),e.info.availableSources$.getValue(),e.info.currentQuality$.getValue()),cdn_host:this.cdnHostname,connection_type:this.connectionType,connection_reused:this.connectionReused};this.logManifestReceived(t)}),r(e.events.firstBytesRequested$,()=>{let t={playback_url:$(e.info.currentFormat$.getValue(),e.info.availableSources$.getValue(),e.info.currentQuality$.getValue()),cdn_host:this.cdnHostname,connection_type:this.connectionType,connection_reused:this.connectionReused};this.logFirstMediaRequest(t)}),r(e.events.firstBytes$,()=>{let t={playback_url:$(e.info.currentFormat$.getValue(),e.info.availableSources$.getValue(),e.info.currentQuality$.getValue()),cdn_host:this.cdnHostname,connection_type:this.connectionType,connection_reused:this.connectionReused};this.logFirstByteMedia(t)}),r(at(e.events.willStart$,e.events.looped$),e=>{e&&this.resetViewSession(),this.isStarted=!0}),r(e.events.started$,()=>{let t=e.info.currentBuffer$.getValue(),n=e.info.currentQuality$.getValue(),r=e.info.isAutoQualityEnabled$.getValue(),i=e.info.muted$.getValue(),a=e.info.volume$.getValue(),o=e.info.surface$.getValue(),s=e.info.availableTextTracks$.getValue(),c=e.info.currentTextTrack$.getValue(),l=e.info.currentAudioStream$.getValue(),u=e.info.currentPlaybackRate$.getValue(),d={playback_quality:Q(n),user_quality:r?`auto`:Q(n),player_width:Math.round(this.statContext.playerSize?.width??this.playerSize.width),player_height:Math.round(this.statContext.playerSize?.height??this.playerSize.height),muted:i,sound_volume:Math.round(a*100),buffer_time:this.calcBufferTime(t),mode:xn(o,this.statContext.isPreviewPlayerView),visibility:Sn(o),subtitles_enabled:c?!!c:this.currentSubtitle?.enabled,auto_subtitles:s.find(({id:e})=>e===c)?.isAuto??this.currentSubtitle?.auto,audio_track_lang:l?.language,playback_rate:u*100,recom_info:this.statContext.recomInfo};this.logPlaybackStarted(d),this.logTelemetry(this.collectTelemetryData())}),r(e.events.willStart$,()=>{this.logPlay()}),r(e.events.playing$,()=>{let t=e.info.currentBuffer$.getValue(),n={buffer_time:this.calcBufferTime(t)};this.logPlaying(n),this.wasPaused&&this.logResume()}),r(e.events.paused$,()=>{this.wasPaused=!0,this.logPause()}),r(e.events.ended$,()=>{this.logContentEndReached()}),r(e.events.willStop$,()=>{this.isStarted=!1,this.logStop()}),r(at(e.events.fetcherRecoverableError$,e.events.fatalError$),()=>{this.statContext.preload&&this.logPreloadError()});let a=e=>{switch(e){case z.NETWORK:return`network`;case z.VIDEO_PIPELINE:return`video_pipeline`;case z.EXTERNAL_API:return`external_api`;case z.PARSER:return`parser`;case z.DOM:return`dom`;default:return`wtf`}},o=e=>z.FATAL===e?`critical`:`informative`;r(e.events.fetcherRecoverableError$,({id:t,category:n,data:r,message:i,httpCode:s,UVBackendErrorCode:c})=>{let l={error_severity:o(n),error_category:a(n),player_error_code:t,player_error_trace:r,http_error_code:s,uv_backend_error_code_subcode:c,error_message:i,content_type:Z(e.info.currentFormat$.getValue())};this.logError(l),o(n)===`critical`&&this.logCannotPlay(),this.logTelemetry(this.collectTelemetryData())}),r(e.events.managedError$,({id:t,category:n,data:r,message:i})=>{let s={error_severity:o(n),error_category:a(n),player_error_code:t,player_error_trace:r,error_message:i,content_type:Z(e.info.currentFormat$.getValue())};this.logError(s),this.logTelemetry(this.collectTelemetryData())}),r(e.events.fatalError$,({id:t,category:n,data:r,message:i})=>{let o={error_severity:`critical`,error_category:a(n),player_error_code:t,player_error_trace:r,error_message:i,content_type:Z(e.info.currentFormat$.getValue())};this.logError(o),this.logCannotPlay(),this.logTelemetry(this.collectTelemetryData())}),r(L({connectionType:e.info.httpConnectionType$,connectionReused:e.info.httpConnectionReused$,connectionMetrics:e.info.httpConnectionMetrics$}).pipe(R(({connectionReused:e})=>e!==void 0),R(({connectionMetrics:e})=>e!==void 0),ot((e,t)=>e.connectionType===t.connectionType)),({connectionMetrics:t})=>{let n=e.info.currentFormat$.getValue(),r=e.info.availableSources$.getValue(),i=e.info.currentQuality$.getValue(),a=e.info.rttEstimation$.getValue();this.networkType=this.statContext.networkType??t?.networkType;let o=t?.dnsResolveTime,s=t?.tcpHandshakeTime,c=t?.tlsHandshakeTime,l={playback_url:$(n,r,i),cdn_host:this.cdnHostname,connection_type:this.connectionType,connection_reused:this.connectionReused,rtt:a?Math.round(a):void 0,network_type:this.networkType,dns_resolve_time:o?Math.round(o):void 0,tcp_handshake_time:s?Math.round(s):void 0,tls_handshake_time:c?Math.round(c):void 0};this.logConnectionEstablished(l)}),r(cn(e,{maxTimeWindow:this.config.downloadBytesMaxTime}),e=>{this.downloadSpeed=e.download_speed,this.logDownloadBytes(e)}),r(e.events.firstFrame$,()=>{this.logFirstVideoFrameDecoded()}),r(e.events.willSeek$,()=>{let e={seek_type:this.seekAction$.getValue()};this.isStarted&&this.logSeeking(e)}),r(e.events.seeked$,()=>{let e={seek_type:this.seekAction$.getValue()};this.isStarted&&this.logSeeked(e),this.seekAction$.next(`unknown`)}),r(e.info.isStalled$,t=>{let n=e.info.currentBuffer$.getValue(),r=this.calcBufferTime(n);t&&r&&r>0&&(this.logBufferStarvation({buffer_time:r}),this.logTelemetry(this.collectTelemetryData()))}),r(e.info.currentBuffer$.pipe(R(e=>!!this.calcBufferTime(e)),st()),e=>{let t=this.calcBufferTime(e);if(this.statContext.preload){let e={buffer_time:t};this.logPreloadEnded(e)}this.logReady({buffer_time:t})});let s;r(L({videoStream:e.info.currentVideoStream$,audioStream:e.info.currentAudioStream$,quality:e.info.currentQuality$}).pipe(R(({videoStream:e,audioStream:t})=>e!==void 0&&t!==void 0),R(({quality:e})=>e!==void 0)),({videoStream:t,audioStream:n,quality:r})=>{if(s!==r){if(this.userQuality=e.info.isAutoQualityEnabled$.getValue()?`auto`:Q(r),this.downloadQuality=Q(r),this.isStarted){let e=t?.codec,r=n?.codec,i={user_quality:this.userQuality,playback_quality:Q(s),download_quality:this.downloadQuality,codec_info:this.genCodecInfo(e,r)};this.logQualityChanged(i)}s=r}});let c,l;return r(e.info.surface$,e=>{let t=xn(e,this.statContext.isPreviewPlayerView);t&&!this.uiEvents&&this.isStarted&&this.logModeChanged({mode:t}),l=Sn(e),c!==l&&(this.isStarted&&this.logVisibilityChanged({visibility:l}),c=Sn(e))}),r(L({muted:e.info.muted$,volume:e.info.volume$}).pipe(lt(300)),({muted:e,volume:t})=>{if(this.isStarted){let n={muted:e,sound_volume:Math.round(t*100)};this.logSoundChanged(n)}}),r(e.info.currentFormat$.pipe(R(e=>e!==void 0),ct(1)),e=>{let t={content_type:Z(e),cdn_host:this.cdnHostname,connection_type:this.connectionType,connection_reused:this.connectionReused};this.logContentTypeChange(t)}),r(e.info.currentAudioStream$.pipe(R(e=>e!==void 0),ct(1)),e=>{let t={audio_track_lang:e.language,codec_info:e.codec};this.logAudioTrackSwitched(t)}),r(e.info.currentVideoStream$.pipe(R(e=>e!==void 0),ct(1)),e=>{let t={hdr:e.hdr,codec_info:e.codec};this.logVideoTrackSwitched(t)}),this.player=e,this.playerSubscription=n,this.resubscribeBeforeunload(),this.subscription.add(n),n}attachToUi(e){this.uiSubscription&&(this.thinOneStatDebugLog({message:`Re-attaching to UI, unsubscribing from previous`}),this.uiSubscription.unsubscribe()),this.uiEvents=e;let{subscribe:t,subscription:n}=Tn();t(e.actionSeek$,this.seekAction$),t(e.playerSize$,({width:e,height:t})=>{e&&t&&(this.playerSize={width:e,height:t},this.isStarted&&this.logViewPortChanged({player_width:Math.round(e),player_height:Math.round(t)}))}),t(e.isLoaderVisible$,e=>{e&&this.isStarted&&this.logShowLoader()}),t(e.actionSubtitlesSwitched$,e=>{if(this.currentSubtitle={...e},this.isStarted){let t={subtitles_enabled:e.enabled,subtitles_track_lang:e.lang,auto_subtitles:e.auto};this.logSubtitlesSwitched(t)}});let{surface$:r}=Ye(this.uiEvents,t,this.player);return t(r,e=>{this.isStarted&&this.logModeChanged({mode:xn(e)})}),t(e.actionQuality$,e=>{let t=e=>Object.values(gt).includes(e),n=this.player?.info.currentVideoStream$.getValue()?.codec,r=this.player?.info.currentAudioStream$.getValue()?.codec,i={user_quality:t(e)?`auto`:Q(e),playback_quality:Q(this.player?.info.currentQuality$.getValue()),download_quality:t(e)?Q(this.player?.info.currentQuality$?.getValue()):Q(e),codec_info:this.genCodecInfo(n,r)};this.logQualityChangeRequested(i)}),this.uiSubscription=n,this.resubscribeBeforeunload(),this.subscription.add(n),n}attachToAds(e){this.adsSubscription&&(this.thinOneStatDebugLog({message:`Re-attaching to ads, unsubscribing from previous`}),this.adsSubscription.unsubscribe());let{subscription:t,subscribe:n}=Tn();return n(e.init$,e=>{let t={slot:e};this.logAdvConfiguration(t)}),n(e.slotRequested$,e=>{let t={adv_section:e};this.logAdvRequest(t)}),n(e.started$,e=>{let t={adv_section:e};this.logAdvBreakStarted(t)}),n(e.ended$,({section:e,ordIds:t})=>{let n={adv_section:e,erids:t.join(`,`)};this.logAdvBreakEnded(n)}),n(e.error$,e=>{let t={error_message:e};this.logAdvError(t)}),this.adsSubscription=t,this.resubscribeBeforeunload(),this.subscription.add(t),t}getDeviceId(){return this.deviceId}resetViewSession(){this.thinOneStatDebugLog({message:`VSID reset`}),T.generateVSID(this.config.useVsid64),this.vsid$.next(T.getVSID()),this.eventNumber=0}async destroy(){this.thinOneStatDebugLog({message:`Destroying ThinOneStat`}),this.subscription.unsubscribe(),await this.logger.destroy(),this.apis.forEach(e=>e.destroy()),this.thinOneStatDebugLog({message:`ThinOneStat destroyed`})}calcBufferTime(e){return e?Math.round((e.end??0)-(e.start??0))*1e3:void 0}genCodecInfo(e,t){return e&&t?`${e},${t}`:void 0}getLatencyInfo(){let e=this.player?.info.atLiveEdge$.getValue(),t={client_time:Date.now(),live:e};return JSON.stringify(t)}collectTelemetryData(){if(!this.player)return{};let e=this.player.info.currentBuffer$.getValue(),t=this.player.experimental.element$.getValue(),n=0,r=0;t&&(n=t.getVideoPlaybackQuality().droppedVideoFrames,r=t.getVideoPlaybackQuality().totalVideoFrames);let i=Z(this.player.info.currentFormat$.getValue()),a=this.player.info.currentVideoStream$.getValue()?.codec,o=this.player.info.currentAudioStream$.getValue()?.codec,s=this.player.info.videoBitrate$.getValue(),c=this.player.info.rttEstimation$.getValue();return{buffer_time:this.calcBufferTime(e),dropped_frames_count:n,rendered_frames_count:r,content_type:i,user_quality:this.userQuality,playback_quality:Q(this.player.info.currentQuality$.getValue()),download_quality:this.downloadQuality,codec_info:this.genCodecInfo(a,o),bandwidth_from_manifest:s?Math.round(s):void 0,cdn_host:this.cdnHostname,download_speed:this.downloadSpeed?Math.round(this.downloadSpeed):void 0,network_type:this.networkType,rtt:c?Math.round(c):void 0,latency:this.getLatencyInfo()}}isValidPlatform(e=``){return[`web:desktop`,`web:mobile`,`smart_tv`].includes(e)}createRequiredParams(e){let t=this.vsid$.getValue();tt(t);let n=this.eventNumber++,r=((this.isLive?this.player?.info.liveTime$.getValue():this.player?.info.position$.getValue())??0)*1e3,i={vsid:t,uv_movie_id:this.statContext.movieId,event_name:e,client_time:Date.now(),application:this.statContext.application??`@vkontakte/videoplayer-statistics:${E}`,platform:this.isValidPlatform(this.statContext.platform)?this.statContext.platform:`web:${this.statContext.isMobile||B.device.isMobile?`mobile`:`desktop`}`,product:this.statContext.product,event_number:n,playback_position:Math.round(r),current_tvt:this.getTotalViewTime(),cdn_host:this.cdnHostname};for(let e of this.config.disabledParams)delete i[e];return i}createRequiredFatParams(){let e={stats_version:wn,browser:this.statContext.browser??B.browser.current,browser_version:this.statContext.browserVersion??String(B.browser.currentVersion),os:this.statContext.os??B.device.os.name,os_version:this.statContext.osVersion??B.device.os.version,device_type:this.statContext.deviceType??(this.statContext.isMobile||B.device.isMobile?`mobile`:`desktop`),device_manufacturer:this.statContext.deviceManufacturer??B.device.details.vendor,device_model:this.statContext.deviceModel??B.device.details.model,navigation:this.statContext.navigation};for(let t of this.config.disabledParams)delete e[t];return e}log(e,t,n=!1){if(this.config.disabledEvents.includes(e))return;let r=this.createRequiredParams(e),i={};n&&(i=this.createRequiredFatParams()),this.logger.log({...r,...i,...t})}logWatchCoverage(e){this.log(`watch_coverage`,e,!0)}logWatchCoverageLive(e){this.log(`watch_coverage_live`,e,!0)}logWatchedN(e){this.log(`watched_n`,e,!0)}logStartSession(e){this.log(`start_session`,e,!0)}logPreloadStarted(e){this.log(`preload_started`,e)}logPreloadEnded(e){this.log(`preload_ended`,e)}logPreloadError(){this.log(`preload_error`)}logPlaybackStarted(e){this.log(`playback_started`,e,!0)}logPlay(){this.log(`play`)}logManifestRequest(e){this.log(`manifest_request`,e)}logFirstByteManifest(e){this.log(`first_byte_manifest`,e)}logFirstMediaRequest(e){this.log(`first_media_request`,e)}logFirstByteMedia(e){this.log(`first_byte_media`,e)}logManifestReceived(e){this.log(`manifest_received`,e)}logConnectionEstablished(e){this.log(`connection_established`,e)}logFirstVideoFrameDecoded(){this.log(`first_video_frame_decoded`)}logReady(e){this.log(`ready`,e)}logPlaying(e){this.log(`playing`,e)}logPause(){this.log(`pause`)}logResume(){this.log(`resume`)}logSeeking(e){this.log(`seeking`,e)}logSeeked(e){this.log(`seeked`,e)}logContentEndReached(){this.log(`content_end_reached`)}logStop(){this.log(`stop`)}logBufferStarvation(e){this.log(`buffer_starvation`,e)}logShowLoader(){this.log(`show_loader`)}logQualityChangeRequested(e){this.log(`quality_change_requested`,e)}logQualityChanged(e){this.log(`quality_changed`,e)}logCdnHostChanged(e){this.log(`cdn_host_changed`,e)}logViewPortChanged(e){this.log(`view_port_changed`,e)}logModeChanged(e){this.log(`mode_changed`,e)}logVisibilityChanged(e){this.log(`visibility_changed`,e)}logAudioTrackSwitched(e){this.log(`audio_track_switched`,e)}logVideoTrackSwitched(e){this.log(`video_track_switched`,e)}logSubtitlesSwitched(e){this.log(`subtitles_switched`,e)}logSoundChanged(e){this.log(`sound_changed`,e)}logFailover(e){this.log(`failover`,e)}logContentTypeChange(e){this.log(`content_type_change`,e)}logError(e){this.log(`error`,e,!0)}logCannotPlay(){this.log(`cannot_play`,{},!0)}logDownloadBytes(e){this.log(`download_bytes`,e)}logTelemetry(e){this.log(`telemetry`,e)}logAdvConfiguration(e){this.log(`adv_configuration`,e)}logAdvRequest(e){this.log(`adv_request`,e)}logAdvBreakStarted(e){this.log(`adv_break_started`,e)}logAdvBreakEnded(e){this.log(`adv_break_ended`,e)}logAdvError(e){this.log(`adv_error`,e)}resubscribeBeforeunload(){this.beforeunloadSubscription?.unsubscribe(),this.beforeunloadSubscription=rt(dt(),`beforeunload`).subscribe(()=>{this.logger.flush({wantBeacon:!0,clearStorage:this.config.clearStorageAtUnload}).catch(()=>{})}),this.subscription.add(this.beforeunloadSubscription)}}import{PlaybackState as Dn,Subscription as On}from"@vkontakte/videoplayer-core/evergreen";import{Logger as kn}from"@vkontakte/videoplayer-shared/evergreen";class An{startTime=null;stopTime=null;accumulatedTime=0;get time(){return Math.floor(this.timeMs/1e3)}get timeMs(){return this.startTime===null?0:(this.stopTime??this.now())-this.startTime-this.accumulatedTime}get isRunning(){return this.startTime!==null&&this.stopTime===null}start(){this.isRunning||(this.stopTime===null?this.startTime=this.now():(this.accumulatedTime+=this.now()-this.stopTime,this.stopTime=null))}stop(){this.isRunning&&(this.stopTime=this.now())}reset(){this.startTime=null,this.stopTime=null,this.accumulatedTime=0}now(){return Date.now()}}var jn=()=>window.Image?new Image:document.createElement(`img`);class Mn{params;position=0;started=!1;isActiveLive;heartbeatPixels=[];heartbeatLastTimeSent={};heartbeatInterval;heartbeatFirstTimeoutId;idleCallbackIds=[];log;stopwatch=new An;subscription=new On;constructor(e){this.params=e,this.log=new kn().createComponentLog(`MediascopePixel`)}attachTo(e){this.subscription.add(e.info.playbackState$.subscribe(e=>this.onPlaybackState(e))).add(e.info.position$.subscribe(e=>this.onPosition(e))).add(e.info.atLiveEdge$.subscribe(e=>this.isActiveLive=e)),this.subscription.add(e.events.willSeek$.subscribe(()=>this.onWillSeek())).add(e.events.seeked$.subscribe(()=>this.onSeeked())).add(e.events.ended$.subscribe(()=>this.onEnded()))}destroy(){this.stopwatch.reset(),this.subscription.unsubscribe(),window.clearTimeout(this.heartbeatFirstTimeoutId),this.idleCallbackIds.forEach(e=>window.cancelIdleCallback(e)),this.send(`stop`)}onPlaybackState(e){e===Dn.PLAYING?this.started?this.play():this.start():e===Dn.PAUSED&&this.pause()}start(){this.started=!0,this.stopwatch.start(),this.send(`start`),this.heartbeatPixels=this.prepareHeartbeatPixels(),this.heartbeatInterval=this.heartbeatPixels[0]?.interval;let e=this.heartbeatPixels[0]?.url,t=this.heartbeatPixels[0]?.delay;if(t!==void 0&&e)try{this.heartbeatFirstTimeoutId=window.setTimeout(()=>{this.sendHeartbeat(e)},t*1e3)}catch(e){this.log({message:e.message})}}play(){this.stopwatch.start(),this.send(`resume`)}pause(){this.stopwatch.stop(),this.send(`pause`)}onPosition(e){if(this.position=e,this.heartbeatInterval&&this.stopwatch.time!==0&&this.stopwatch.time%this.heartbeatInterval===0)for(let[e,{url:t}]of this.heartbeatPixels.entries())this.heartbeatLastTimeSent[e]!==this.stopwatch.time&&(this.heartbeatLastTimeSent[e]=this.stopwatch.time,this.sendHeartbeat(t))}onWillSeek(){this.started&&this.send(`stop`)}onSeeked(){this.started&&this.send(`start`)}onEnded(){this.stopwatch.stop(),this.send(`stop`)}validatePixels(e,t){return e?.filter(e=>e.event===t.event&&t.keys.every(t=>!!e[t]))}getFrameTimestamp(){let e;if(this.isActiveLive){let t=Math.floor(Math.random()*25)+5;e=Date.now()/1e3-t}else e=this.position||0;return Math.floor(e)}getUTC(){return Math.floor(Date.now()/1e3)}prepareUrl(e){return e.replace(`{@fts_fake_sec}`,String(this.getFrameTimestamp())).replace(`{@utc_sec}`,String(this.getUTC())).split(`&`).filter(e=>!/={@[a-zA-Z_]+}/.test(e)).join(`&`)}preparePixels(e){return this.validatePixels(this.params.pixels,{event:e,keys:[`url`]})}prepareHeartbeatPixels(){return this.validatePixels(this.params.pixels,{event:`heartbeat`,keys:[`url`,`interval`]})}call(e){try{this.idleCallbackIds.push(requestIdleCallback(()=>jn().src=this.prepareUrl(e)))}catch(e){this.log({message:e.message})}}send(e){let t=this.preparePixels(e);for(let{url:e}of t)this.call(e)}sendHeartbeat(e){this.call(e)}}export{E as VERSION,et as ThinOneStat,c as SeekAction,a as Quality,$e as OneStat,Mn as MediascopePixel,l as InteractiveInterfaceClick,o as ContentType,s as ConnectionType,i as ApiEnv};
6
+ var e=Object.defineProperty,t=e=>e;function n(e,n){this[e]=t.bind(null,n)}var r=(t,r)=>{for(var i in r)e(t,i,{get:r[i],enumerable:!0,configurable:!0,set:n.bind(r,i)})},i;(e=>{e.PROD=`prod`,e.VK_ALIAS=`vk_alias`,e.VIDEOTEST=`videotest`,e.TEST=`test`,e.OKCDN=`okcdn`,e.AUTO=`auto`})(i||={});var a;(e=>{e.Q144P=`mobile`,e.Q240P=`lowest`,e.Q360P=`low`,e.Q480P=`medium`,e.Q720P=`high`,e.Q1080P=`fullhd`,e.Q1440P=`quadhd`,e.Q2160P=`ultrahd`,e.UNKNOWN=`unknown`})(a||={});var o;(e=>{e.MP4=`mp4`,e.DASH=`dash`,e.DASH_SEP=`dash_sep`,e.ONDEMAND_DASH=`ondemand_dash`,e.HLS=`hls`,e.HLS_FMP4=`hls_fmp4`,e.ONDEMAND_HLS=`ondemand_hls`,e.WEBM=`webm`,e.AV1=`av1`,e.ONDEMAND_DASH_LIVE=`ondemand_dash_live`,e.ONDEMAND_HLS_LIVE=`ondemand_hls_live`,e.WEBRTC=`webrtc`,e.UNKNOWN=`unknown`,e.RTMP=`rtmp`})(o||={});var s;(e=>{e.HTTP1=`http1`,e.HTTP2=`http2`,e.HTTP3=`http3`})(s||={});var c;(e=>{e.SLIDER=`slider`,e.RICH=`rich`,e.DOUBLE_TAP=`double_tap`,e.TIME_CODE=`time_code`,e.EPISODE=`episode`,e.REWIND=`rewind`,e.LIVE=`live`,e.UNKNOWN=`unknown`})(c||={});var l;(e=>{e.GRAPH_SHOW=`iGraphShow`,e.GRAPH_HIDE=`iGraphHide`,e.NEXT_AREA=`iNextChapterArea`,e.NEXT_BUTTON=`iNextChapterBtn`,e.WATCH_AGAIN=`iWatchAgainBtn`})(l||={});var u={action_play:`ap`,action_play_interactive:`api`,first_bytes:`fb`,player_ready:`pr`,first_frame:`ff`,seek:`sk`,watch_coverage_record:`wr`,watch_coverage_live:`wl`,empty_buffer:`eb`,action_stop:`as`,close_at_empty_buffer:`cb`,content_error:`er`,player_interface_click:`pc`,next_movie:`nm`,track_switch:`ts`,failover:`fo`,quality:`qt`},d={vsid:`si`,isid:`is`,vid:`vi`,place:`pl`,quality:`qt`,cdn_host:`ch`,stat_type:`st`,param:`pm`,vk_app_id:`va`,track_code:`tc`,connection_type:`cnt`,connection_reused:`cr`,cached_data:`cd`,live:`lv`,muted:`mu`,mode:`mo`,subtitles:`sb`,failover:`fo`,download_speed:`ds`,manual_quality:`mq`,ref_domain:`rd`,direct_url:`du`},f={unknown:`un`,mobile:`m`,lowest:`ls`,low:`l`,medium:`md`,high:`h`,fullhd:`f`,quadhd:`q`,ultrahd:`u`},p={pip:`pi`,fullscreen:`fs`,external:`ex`,prefetch:`pr`,airplay:`ap`,chromecast:`cc`,invisible:`iv`,minimal:`minimal`};import{fillWithDefault as m}from"@vkontakte/videoplayer-shared/evergreen";var h=`CIOPGQJGDIHBABABA`,g={prod:`https://api.ok.ru`,vk_alias:`https://api.mycdn.me`,videotest:`https://videotestapi.ok.ru/api`,test:`https://apitest.ok.ru`,okcdn:`https://api.okcdn.ru`,auto:``},_={apiEnv:`vk_alias`,apiKey:h,apiBaseUrl:null,apiUvRestBaseUrl:`https://uvapi.okcdn.ru`,apiCollector:`ok.mobile.apps.video`,apiForticom:!0,apiUvRest:!1,requestRetryCount:1,useVsid64:!1,firstFlushTime:5e3,flushDebounceTime:1e4,flushMaxWait:6e4,storageExpiration:2160*60*1e3,watchCoverageInterval:15e3,disabledOperations:[`quality`],disabledCustomFields:[],shorten:!0,maxLoops:100,embedUrlParams:[],useBeacon:!0,synchronizeTime:!0,debugLog:!1,clearStorageAtUnload:!0,useVKComIsMobileLogic:!1,backoff:{start:1e3,factor:1.5,max:300*1e3,random:.1},useKeepalive:!1,watchCoverageTimeoutFix:!0,watchCoverageExactTime:!1},v=e=>m(e,_);function y(){let e=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`.split(``),t=Array(36),n=0,r,i;for(i=0;i<36;i++)i===8||i===13||i===18||i===23?t[i]=`-`:i===14?t[i]=`4`:(n<=2&&(n=33554432+Math.random()*16777216|0),r=n&15,n>>=4,t[i]=e[i===19?r&3|8:r]);return t.join(``)}import{assertNonNullable as b,combine as x,fromEvent as S,isNonNullable as C,isNullable as ee,merge as te,now as w,observableFrom as ne,once as re,safeStorage as ie,Subject as ae,Subscription as oe,ValueSubject as T,getWindow as se}from"@vkontakte/videoplayer-shared/evergreen";import{Logger as ce,detectEmbed as le,ErrorCategory as ue}from"@vkontakte/videoplayer-shared/evergreen";var de=()=>Math.floor(Math.random()*2**32).toString(36).padStart(13,`0`),fe=()=>Math.floor(Math.random()*2**64).toString(36).padStart(13,`0`);class E{static vsid;static getVSID(){return E.vsid}static generateVSID(e){return E.vsid=e?fe():de(),E.vsid}}var pe=e=>{let{operation:t,custom:n}=e,r=Object.fromEntries(Object.entries(n).map(([e,t])=>{let n=d[e]??e,r=t;return t&&(e===`mode`?r=p[t]??t:e===`quality`&&(r=f[t]??t)),[n,r]}));return{...e,operation:u[t]??t,custom:r}},D=`1.0.110-dev.0bbcbb01d.0`;import{ValueSubject as me,getExponentialDelay as he,ErrorCategory as O,getWindow as k}from"@vkontakte/videoplayer-shared/evergreen";var ge=/Mobile|mini|Fennec|Android|iP(ad|od|hone)|opera (mini|mobi)/i;class _e{id=`forticom`;params;authToken;sessionKey;authorizePromise;refreshAuthTokenPromise;consequentAuthErrors=0;authorized$=new me(!1);backoffTimeoutId;constructor(e){this.params=e}async authorize(e){return this.authToken=e??await this.refreshAuthToken(),this._authorizeWithBackoff()}logBeacon(e){let t=this.createLogParams(e),n=this.sessionKey;n&&(this.params.apiTransport.sendBeacon(`log.externalLog`,t,n)||this.logRequest(e).catch(()=>{}))}async logRequest(e){let t=`log.externalLog`,n=this.createLogParams(e),r=this.sessionKey??await this._authorizeWithBackoff();if(!r)return;let i=async(e,a=this.params.config.requestRetryCount)=>{try{return await this.params.apiTransport.sendRequest(t,n,r)}catch(n){if(!n||!(`error_code`in n)){this.params.error$.next({id:`logRequestUnknown`,category:O.NETWORK,message:`Unknown ${t} error`,thrown:n});return}let r=n?.error_code;switch(r){case 102:case 103:case 104:return this.authorized$.next(!1),this.sessionKey=await this._authorizeWithBackoff(),a>0?i(e,a-1):void 0;case 401:return this.authorized$.next(!1),this.authToken=await this.refreshAuthToken(),this.sessionKey=await this._authorizeWithBackoff(),a>0?i(e,a-1):void 0;default:this.params.error$.next({id:`LogRequest#${r}`,category:O.EXTERNAL_API,message:`${t} error`,data:n});return}}};return i(e)}destroy(){k().clearTimeout(this.backoffTimeoutId),this.backoffTimeoutId=0}async refreshAuthToken(){if(this.params.refreshAuthToken)return this.refreshAuthTokenPromise||=this.params.refreshAuthToken().finally(()=>{this.refreshAuthTokenPromise=void 0}),this.refreshAuthTokenPromise}createLogParams(e){let t=`WEB`,n=!1,r=`@vkontakte/videoplayer-statistics:${D}`;if(this.params.config.useVKComIsMobileLogic){let{appVersion:e}=k().navigator;n=ge.test(e)}else this.params.mobile&&(n=!0);return n&&(t=`M_WEB`),this.params.vktvVersion&&(t=`SMART_TV`,r=this.params.vktvVersion),{collector:this.params.config.apiCollector,data:JSON.stringify({application:r,platform:t,items:this.params.config.shorten?e.map(pe):e})}}_authorizeWithBackoff(){if(!this.consequentAuthErrors)return this._authorize();let e=he(this.consequentAuthErrors,this.params.config.backoff);return new Promise(t=>{this.backoffTimeoutId||=k().setTimeout(()=>{this._authorize().then(t).catch(e=>this.params.error$.next({id:`AuthorizeBackoff`,category:O.NETWORK,message:`Otherwise unhandled error in authorization`,thrown:e})).finally(()=>this.backoffTimeoutId=0)},e)})}async _authorize(){if(this.authorizePromise)return this.authorizePromise;this.sessionKey=void 0,this.authorized$.next(!1);let e={session_data:{version:2,device_id:this.params.deviceId,client_version:D.split(`-`)[0],client_type:`SDK_JS`}};return this.authToken!==void 0&&(e.session_data.auth_token=this.authToken,e.session_data.version=3),this.authorizePromise=this.params.apiTransport.sendRequest(`auth.anonymLogin`,e).then(e=>((!e||!e.session_key)&&this.params.error$.next({id:`AuthorizeFailed`,category:O.EXTERNAL_API,message:`No session key`,data:e}),this.sessionKey=e?.session_key??void 0,this.sessionKey)).catch(async e=>{this.sessionKey=void 0;let t=e?.error_code;switch(t){case 401:return this.authToken=await this.refreshAuthToken(),this._authorizeWithBackoff()}t?this.params.error$.next({id:`Authorize#${t}`,category:O.EXTERNAL_API,message:`authorize error`,data:e}):this.params.error$.next({id:`AuthorizeUnknown`,category:O.NETWORK,message:`authorize error`,thrown:e})}).finally(()=>{this.authorizePromise=void 0,this.consequentAuthErrors=this.sessionKey?0:this.consequentAuthErrors+1,this.authorized$.next(this.sessionKey!==void 0)}),this.authorizePromise}}class ve{id=`uvrest`;authorized$=new me(!1);params;statToken;authorizePromise;isDestroyed=!1;constructor(e){this.params=e}async authorize(e){if(!this.isDestroyed)return e?(this.statToken=e,this.authorized$.next(!0),e):this.authorizePromise?this.authorizePromise:(this.authorized$.next(!1),this.authorizePromise=this.executeAuthorize().finally(()=>{this.authorizePromise=void 0,this.isDestroyed||this.authorized$.next(this.statToken!==void 0)}),this.authorizePromise)}async logRequest(e){if(!e.length)return;let t=this.buildBody(e);try{let e=await this.getValidToken();if(!e){this.params.error$.next({id:`OneStat:UvRestApi:LogRequestNoToken`,category:O.NETWORK,message:`No stat token available for log request`});return}await this.params.apiTransport.sendJsonRequest(`/uv/stat/externalLog`,t,{Authorization:`Bearer ${e}`})}catch(e){await this.handleLogRequestError(e)&&await this.retryLogRequestAfterRecovery(t)}}logBeacon(e){if(!e.length)return;let t=this.statToken;if(!t)return;let n=this.buildBody(e);this.params.apiTransport.sendJsonBeacon(`/uv/stat/externalLog`,n,{Authorization:`Bearer ${t}`})}destroy(){this.isDestroyed=!0,this.authorizePromise=void 0,this.statToken=void 0,this.authorized$.next(!1)}async getValidToken(){return this.statToken?this.statToken:this.authorize()}async executeAuthorize(){try{let e=await this.params.getAuthToken();if(this.isDestroyed)return;if(!e){this.params.error$.next({id:`OneStat:UvRestApi:NoToken`,category:O.EXTERNAL_API,message:`getAuthToken returned no token`});return}return this.statToken=e,this.statToken}catch(e){if(this.isDestroyed)return;this.params.error$.next({id:`OneStat:UvRestApi:AuthorizeFailed`,category:O.NETWORK,message:`Failed to get stat token`,thrown:e});return}}async handleLogRequestError(e){let t=e?.status;return t===401?(this.params.error$.next({id:`OneStat:UvRestApi:TokenExpired`,category:O.EXTERNAL_API,message:`Stat token expired (401), refreshing`,thrown:e}),this.authorized$.next(!1),this.statToken=void 0,await this.authorize()!==void 0):(this.params.error$.next({id:`OneStat:UvRestApi:LogRequestFailed#${t??`unknown`}`,category:O.EXTERNAL_API,message:`Log request failed with status ${t}`,thrown:e}),!1)}async retryLogRequestAfterRecovery(e){let t=this.statToken;if(!t){this.params.error$.next({id:`OneStat:UvRestApi:RetryNoToken`,category:O.NETWORK,message:`Cannot retry log request: no token after recovery`});return}try{await this.params.apiTransport.sendJsonRequest(`/uv/stat/externalLog`,e,{Authorization:`Bearer ${t}`})}catch(e){this.params.error$.next({id:`OneStat:UvRestApi:RetryFailed`,category:O.EXTERNAL_API,message:`Log request failed after token refresh`,thrown:e})}}buildBody(e){let t=`WEB`,n=!1,r=`@vkontakte/videoplayer-statistics:${D}`;if(this.params.config.useVKComIsMobileLogic){let{appVersion:e}=k().navigator;n=ge.test(e)}else this.params.mobile&&(n=!0);return n&&(t=`M_WEB`),this.params.vktvVersion&&(t=`SMART_TV`,r=this.params.vktvVersion),[{application:r,platform:t,user_id:this.params.userId,items:this.params.config.shorten?e.map(pe):e}]}}import{ErrorCategory as A,now as j,getWindow as M}from"@vkontakte/videoplayer-shared/evergreen";class ye{apiKey;apiBaseUrl;apiUvRestBaseUrl;apiEnv;timeSynchronisation;isApiBaseUrlFetched;params;constructor(e){this.params=e,this.apiKey=e.config.apiKey,this.apiEnv=e.config.apiEnv,this.apiBaseUrl=e.config.apiBaseUrl??g[this.apiEnv],this.apiUvRestBaseUrl=e.config.apiUvRestBaseUrl,this.timeSynchronisation=e.timeSynchronisation,this.isApiBaseUrlFetched=!1}async resolveApiBaseUrl(){if(this.apiEnv!==`auto`||this.isApiBaseUrlFetched)return this.apiBaseUrl;try{let e=atob(`aHR0cHM6Ly9kbnMuZ29vZ2xlL3Jlc29sdmU/bmFtZT12aWRlby5fZW5kcG9pbnQub2sucnUmdHlwZT1UWFQ=`),t=(await(await fetch(e,{method:`GET`,mode:`cors`,cache:`no-cache`})).json())?.Answer[0]?.data;if(!t)throw Error(`Wrong DNS response`);return t}catch(e){return this.params.error$.next({id:`OneStat:ApiTransport:resolveApiBaseUrl`,category:A.NETWORK,message:`Unhandled resolve api base url error`,thrown:e}),g.vk_alias}finally{this.isApiBaseUrlFetched=!0}}sendBeacon(e,t,n){if(!M().Blob||!M().navigator.sendBeacon)return!1;let r=this._prepareQueryParams({method:e,queryParams:t,sessionKey:n}),i=M().Blob,a=new i([r.toString()],{type:`application/x-www-form-urlencoded`});try{return M().navigator.sendBeacon(`${this.apiBaseUrl}/fb.do`,a)}catch(n){this.params.error$.next({id:`OneStat:ApiTransport:sendBeacon`,category:A.NETWORK,message:`Unhandled beacon error`,thrown:n,data:{method:e,params:t}})}return!1}async sendRequest(e,t,n){let r=j(),i=i=>{if(i instanceof TypeError&&[`Failed to fetch`,`NetworkError when attempting to fetch resource.`].includes(i.message)){this.params.error$.next({id:`Network`,category:A.NETWORK,message:`Request failed`,thrown:i});return}this.params.error$.next({id:`OneStat:ApiTransport:sendRequest`,category:A.NETWORK,message:`Unhandled request error`,thrown:i,data:{method:e,params:t,sessionKey:n,time:j()-r}})};this.apiBaseUrl=await this.resolveApiBaseUrl();let a={method:`post`,headers:{"Content-type":`application/x-www-form-urlencoded`},body:this._prepareQueryParams({method:e,queryParams:t,sessionKey:n})};return this.params.config.useKeepalive&&(a.keepalive=!0),fetch(`${this.apiBaseUrl}/fb.do`,a).then(e=>{let t=Number(e.headers.get(`content-length`))===0,n=new Date(e.headers.get(`date`)??``).getTime(),a=j()-r;if(isFinite(n)&&this.timeSynchronisation?.addServerTime(n,a),!t)return e.json().then(e=>Object.prototype.hasOwnProperty.call(e,`error_msg`)?Promise.reject(e):e,i)},i)}sendJsonBeacon(e,t,n){let r=`${this.apiUvRestBaseUrl}${e}`;try{fetch(r,{method:`POST`,headers:{"Content-Type":`application/json`,...n},body:JSON.stringify(t),keepalive:!0}).catch(t=>{this.params.error$.next({id:`OneStat:ApiTransport:sendJsonBeacon`,category:A.NETWORK,message:`Keepalive request failed`,thrown:t,data:{path:e}})})}catch(t){this.params.error$.next({id:`OneStat:ApiTransport:sendJsonBeacon`,category:A.NETWORK,message:`Failed to initiate keepalive request`,thrown:t,data:{path:e}})}}async sendJsonRequest(e,t,n){let r=j(),i=t=>{if(t instanceof TypeError&&[`Failed to fetch`,`NetworkError when attempting to fetch resource.`].includes(t.message)){this.params.error$.next({id:`Network`,category:A.NETWORK,message:`JSON request failed`,thrown:t});return}this.params.error$.next({id:`OneStat:ApiTransport:sendJsonRequest`,category:A.NETWORK,message:`Unhandled JSON request error`,thrown:t,data:{path:e,time:j()-r}})},a={method:`POST`,headers:{"Content-Type":`application/json`,...n},body:JSON.stringify(t)};return this.params.config.useKeepalive&&(a.keepalive=!0),fetch(`${this.apiUvRestBaseUrl}${e}`,a).then(e=>{let t=Number(e.headers.get(`content-length`))===0,n=new Date(e.headers.get(`date`)??``).getTime(),a=j()-r;if(isFinite(n)&&this.timeSynchronisation?.addServerTime(n,a),!e.ok)return Promise.reject({status:e.status,statusText:e.statusText});if(!t)return e.json().catch(i)},i)}_prepareQueryParams(e){let t=new URLSearchParams({format:`JSON`,method:e.method,application_key:this.apiKey});return e.sessionKey!==void 0&&t.append(`session_key`,e.sessionKey),Object.entries(e.queryParams).forEach(([e,n])=>t.append(e,typeof n==`string`?n:JSON.stringify(n))),t}}import{ErrorCategory as be,now as xe,safeStorage as N,debounceFn as Se}from"@vkontakte/videoplayer-shared/evergreen";var Ce=e=>t=>t.timestamp+e>=xe();class we{params;error$;userSalt;isPaused=!1;loggerDebugLog;queues=[];constructor(e){this.params=e,this.error$=e.error$,this.userSalt=e.userSalt,this.loggerDebugLog=e.debugLogger.createComponentLog(`stat logger`);for(let t of e.apis)this.queues.push(this.createQueueState(t));this.housekeepStorage()}createQueueState(e){let t=`onestat_events_${e.id}`,n=Se(()=>this.safeFlushQueue(a),this.params.config.firstFlushTime,{maxWait:this.params.config.firstFlushTime}),r=N.isPersistent()?this.params.config.flushMaxWait:0,i=Se(()=>this.safeFlushQueue(a),this.params.config.flushDebounceTime,{maxWait:r}),a={api:e,storageKey:t,unsaltedStorage:[],lastVsid:void 0,firstFlush:n,debouncedFlush:i,subscription:e.authorized$.subscribe(e=>{e&&i()})};return a}isUrgent=e=>{let{operation:t}=e;return[`action_play`,`action_play_interactive`,`watch_coverage_record`,`watch_coverage_live`,`action_stop`,`close_at_empty_buffer`].includes(t)};safeFlushQueue(e){try{this.flushQueue(e)}catch(t){this.error$.next({id:`LoggerError`,category:be.WTF,message:t?String(t):`Unknown logger error`,thrown:t,data:{storageKey:e.storageKey}})}}readFromStorage(e){let t=N.get(e);try{return t?JSON.parse(t):{}}catch{}return{}}addToStorage(e,t){if(!this.userSalt){e.unsaltedStorage.push(t);return}let n=this.readFromStorage(e.storageKey),r=(n[this.userSalt]??[]).filter(Ce(this.params.config.storageExpiration));N.set(e.storageKey,JSON.stringify({...n,[this.userSalt]:[...r,t]}))}getFromStorage(e){return this.userSalt?(this.readFromStorage(e.storageKey)[this.userSalt]??[]).filter(Ce(this.params.config.storageExpiration)):e.unsaltedStorage}markStorageSent(e){if(!this.userSalt){e.unsaltedStorage=[];return}let t=this.readFromStorage(e.storageKey);delete t[this.userSalt],N.set(e.storageKey,JSON.stringify(t))}housekeepStorage(){for(let e of this.queues){let t=this.readFromStorage(e.storageKey);for(let[n,r]of Object.entries(t)){let i=r.filter(Ce(this.params.config.storageExpiration));i.length?t[n]=i:delete t[n],this.loggerDebugLog({message:`${r.length} retrieved from storage, ${i.length} of them actual (${e.storageKey})`})}N.set(e.storageKey,JSON.stringify(t))}}log(e){for(let t of this.queues)this.addToStorage(t,e),!this.isPaused&&(this.isUrgent(e)?this.flushQueue(t):t.lastVsid===e.custom.vsid?t.debouncedFlush():t.firstFlush(),t.lastVsid=e.custom.vsid)}flush(e={wantBeacon:!1,clearStorage:!0}){for(let t of this.queues)this.flushQueue(t,e)}flushQueue(e,{wantBeacon:t,clearStorage:n}={wantBeacon:!1,clearStorage:!0}){let r=this.getFromStorage(e);r.length!==0&&(e.api.authorized$.getValue()?(t&&this.params.config.useBeacon?(this.loggerDebugLog({message:`Flushing ${r.length} events through beacon (${e.storageKey})`}),e.api.logBeacon(r)):(this.loggerDebugLog({message:`Flushing ${r.length} events (${e.storageKey})`}),e.api.logRequest(r)),n&&this.markStorageSent(e)):e.api.authorize(),e.firstFlush.cancel(),e.debouncedFlush.cancel())}pause(){this.isPaused=!0;for(let e of this.queues)e.debouncedFlush.cancel()}resume(){this.isPaused=!1;for(let e of this.queues)e.debouncedFlush()}destroy(){for(let e of this.queues)e.subscription.unsubscribe(),e.firstFlush.cancel(),e.debouncedFlush.cancel();this.queues=[]}}import{HttpConnectionType as Te,Surface as P,VideoFormat as F,VideoQuality as I}from"@vkontakte/videoplayer-core/evergreen";import{assertNever as Ee}from"@vkontakte/videoplayer-shared/evergreen";var De=e=>e&&{[I.INVARIANT]:`unknown`,[I.Q_144P]:`mobile`,[I.Q_240P]:`lowest`,[I.Q_360P]:`low`,[I.Q_480P]:`medium`,[I.Q_576P]:`unknown`,[I.Q_720P]:`high`,[I.Q_1080P]:`fullhd`,[I.Q_1440P]:`quadhd`,[I.Q_2160P]:`ultrahd`,[I.Q_4320P]:`unknown`}[e],Oe=e=>e&&{[Te.HTTP1]:`http1`,[Te.HTTP2]:`http2`,[Te.QUIC]:`http3`}[e],ke=e=>{if(e!==void 0)switch(e){case F.MPEG:return`mp4`;case F.DASH:case F.DASH_LIVE:case F.DASH_STREAMS:return`dash`;case F.DASH_SEP:return`dash_sep`;case F.DASH_ONDEMAND:return`ondemand_dash`;case F.DASH_WEBM:case F.DASH_LIVE_WEBM:return`webm`;case F.DASH_WEBM_AV1:return`av1`;case F.DASH_LIVE_CMAF:return`ondemand_dash_live`;case F.HLS:case F.HLS_LIVE:return`hls`;case F.HLS_FMP4:return`hls_fmp4`;case F.HLS_ONDEMAND:return`ondemand_hls`;case F.HLS_LIVE_CMAF:return`ondemand_hls_live`;case F.WEB_RTC_LIVE:return`webrtc`;default:return Ee(e)}},Ae=(e,t)=>{if(t)return`minimal`;switch(e){case void 0:case P.NONE:case P.INLINE:return;case P.FULLSCREEN:return`fullscreen`;case P.SECOND_SCREEN:return`chromecast`;case P.PIP:return`pip`;case P.INVISIBLE:return`invisible`;default:return Ee(e)}},je=e=>{switch(e){case`slow-2g`:return`poor`;case`2g`:return`poor`;case`3g`:return`good`;case`4g`:return`excellent`}};class Me{offset=void 0;constructor(e){this.offset=e}getOffset(){return this.offset??0}setOffset(e){this.offset=e}now(){return Date.now()+(this.offset??0)}date(e=new Date){return e.setTime(e.getTime()+(this.offset??0)),e}addServerTime(e,t){let n=e-Date.now()-t/2;if(Math.abs(n)<1e3){this.offset=0;return}if(this.offset===void 0)this.offset=Math.round(n);else{let e=.2;this.offset=Math.round(e*n+(1-e)*this.offset)}}}import{PlaybackState as Ne}from"@vkontakte/videoplayer-core/evergreen";import{filter as Pe,filterChanged as Fe,fromEvent as Ie,isNullable as Le,map as Re,merge as ze,Observable as Be,Subject as Ve,Subscription as He,ValueSubject as Ue}from"@vkontakte/videoplayer-shared/evergreen";var We=(e,t)=>new Be(n=>{let r=new He,i=ze(Ie(window,`beforeunload`),e.events.willDestruct$),a=new Ue(void 0),o;r.add(e.info.isLive$.pipe(Fe()).subscribe(t=>{o&&(o.unsubscribe(),a.next(void 0)),o=t?e.info.liveTime$.pipe(Re(e=>e&&e/1e3)).subscribe(a):e.info.position$.subscribe(a),r.add(o)}));let{playing$:s,paused$:c,looped$:l}=e.events,u=e.events.willSeek$.pipe(Pe(()=>e.info.playbackState$.getValue()===Ne.PLAYING)),d=e.events.seeked$.pipe(Pe(()=>e.info.playbackState$.getValue()===Ne.PLAYING)),f=!1,p=new Ve;r.add(u.subscribe(()=>{f||p.next(),f=!0})),r.add(d.subscribe(()=>f=!1));let m=new Ve,h=new Ve,g=()=>t.watchCoverageExactTime?e.info.isLive$.getValue()?e.getExactLiveTime():e.getExactTime():a.getValue()??0,_=e.info.stallStartTime$.pipe(Fe(),Pe(e=>e>0)),v=ze(s,d,m).pipe(Re(()=>g())),y=ze(l,ze(c,p,i,h,_).pipe(Re(()=>g()))),b,x=e=>{b=e},S=e=>{let t=e;Le(b)||b===t||Le(t)||(n.next({from:b,to:t}),b=void 0)},C=()=>{h.next(),m.next()};if(r.add(v.subscribe(x)),r.add(y.subscribe(S)),t.forceInterval&&isFinite(t.forceInterval))if(t.watchCoverageTimeoutFix){let e,n=()=>{e!==void 0&&(window.clearTimeout(e),e=void 0)};r.add(v.subscribe(()=>{n(),e=window.setTimeout(C,t.forceInterval)})),r.add(y.subscribe(()=>n())),r.add(()=>n())}else{let e=0;r.add(v.subscribe(()=>e=window.setTimeout(C,t.forceInterval))),r.add(y.subscribe(()=>window.clearTimeout(e)))}return r});import{Surface as L}from"@vkontakte/videoplayer-core/evergreen";import{debounce as Ge,filterChanged as Ke,Subject as qe}from"@vkontakte/videoplayer-shared/evergreen";var Je=(e,t,n)=>{let r=new qe,i=r.pipe(Ge(0),Ke()),a=!1,o=!1,s=!1;return t(e.inPiP$,e=>{a=e,r.next(e?L.PIP:o?L.FULLSCREEN:s?L.INLINE:void 0)}),t(e.inFullscreen$,e=>{o=e,r.next(e?L.FULLSCREEN:a?L.PIP:s?L.INLINE:void 0)}),n&&t(n.info.surface$,e=>{switch(e){case L.SECOND_SCREEN:case L.NONE:case L.INLINE:!o&&!a&&(e===L.INLINE&&(s=!0),r.next(e));break}}),{surface$:i}},Ye=`_one-stat_deviceId`,Xe=(e,t)=>e&&t?`${e}_${t}`:e??t,Ze=()=>{let e=new oe;return{subscription:e,subscribe:(t,n)=>{t&&e.add(t.subscribe(n))}}};class Qe{apis;logger;config;subscription=new oe;beforeunloadSubscription;timeSynchronisation;debugLogger=new ce;oneStatDebugLog=this.debugLogger.createComponentLog(`onestat`);loopCounter=0;disabled=!1;experimental;get vsid$(){return new T(E.getVSID())}isid$=new T(void 0);zenUid$=new T(void 0);statContext;isEmbed;embedParent;uiEvents;player;seekAction$=new T(`unknown`);deviceId;constructor(e,t){this.statContext=e,this.config=v(t.config??{}),C(t.apiEnv)&&(this.config.apiEnv=t.apiEnv),this.config.synchronizeTime&&(this.timeSynchronisation=new Me);let n=new ae;this.experimental={error$:n};let r=ie.get(Ye);this.statContext.deviceId?this.deviceId=this.statContext.deviceId:r?this.deviceId=r:(this.deviceId=y(),ie.set(Ye,this.deviceId)),this.resetViewSession(),t.useIsid&&this.isid$.next(t.isid??fe()),this.zenUid$.next(t.zenUid);let i=new ye({config:this.config,error$:n,timeSynchronisation:this.timeSynchronisation}),a=[];this.config.apiForticom&&a.push(new _e({config:this.config,apiTransport:i,refreshAuthToken:t.refreshAuthToken,mobile:this.statContext.mobile??!1,deviceId:this.deviceId,error$:n,vktvVersion:t.vktvVersion})),this.config.apiUvRest&&(t.getUvRestAuthToken?a.push(new ve({config:this.config,apiTransport:i,error$:n,userId:this.statContext.userId,getAuthToken:t.getUvRestAuthToken,mobile:this.statContext.mobile??!1,vktvVersion:t.vktvVersion})):n.next({id:`OneStat:Init:MissingGetUvRestAuthToken`,category:ue.WTF,message:`oldStatToUvRest enabled but getUvRestAuthToken callback not provided`})),this.apis=a,this.logger=new we({config:this.config,debugLogger:this.debugLogger,apis:this.apis,error$:n,userSalt:t.userSalt});let{isEmbed:o,topOrigin:s}=le();this.isEmbed=o,this.embedParent=s?new URL(s).hostname:void 0,this.subscribe()}updateContext(e){this.statContext={...this.statContext,...e}}attachTo(e){let t=new oe,n=(e,n)=>t.add(e.subscribe(n)),r,i,a,o=!1,s=!1,c=()=>{o||(o=!0,C(r)&&(r={startedAt:w(),liveAtStall:!!this.statContext.liveEdge}))};n(e.events.willStart$,()=>{let t=e.info.position$.getValue();this.logActionPlay({position:t}),this.statContext.projectId&&this.logActionPlayInteractive()}),n(e.events.looped$,()=>{this.resetViewSession(),++this.loopCounter>this.config.maxLoops&&(this.disabled=!0),this.logActionPlay({position:e.info.position$.getValue()})}),n(e.events.willSeek$,()=>{C(r)&&o&&this.logEmptyBuffer({duration:w()-r.startedAt,liveAtStall:r.liveAtStall}),r=void 0,s=!0}),n(e.events.seeked$,()=>{!s&&C(r)&&o&&(this.logEmptyBuffer({duration:w()-r.startedAt,liveAtStall:r.liveAtStall}),r=void 0),s=!1;let t=this.seekAction$.getValue();this.logSeek({action:t===`rich`?`slider`:t,time:e.info.position$.getValue()}),this.seekAction$.next(`unknown`)}),n(e.events.paused$,()=>{this.logPause({position:e.info.position$.getValue()})}),n(e.events.willResume$,()=>{this.logPlay()}),n(e.events.started$,()=>{this.statContext.clip&&this.logWatchCoverageRecord({start:0,end:0})}),n(e.events.playing$,()=>{this.logPlaying()}),n(We(e,{forceInterval:this.config.watchCoverageInterval,watchCoverageTimeoutFix:this.config.watchCoverageTimeoutFix,watchCoverageExactTime:this.config.watchCoverageExactTime}),t=>{let n=e.info.isLive$.getValue(),r=e.info.atLiveEdge$.getValue(),i={start:parseFloat(t.from.toFixed(3)),end:parseFloat(t.to.toFixed(3))};if(r){let t=e.info.liveLatency$.getValue()??0,n=e.info.currentBuffer$.getValue()?.end??0,r=e.info.liveBufferTime$.getValue()??0,a=Math.round((t-(n-r))*1e3),o=Math.round(t*1e3);a&&o&&(i.latency=a,i.bufferLatency=o)}n?this.logWatchCoverageLive(i):this.logWatchCoverageRecord(i)}),n(e.info.stallStartTime$,e=>{e>0?r={startedAt:e,liveAtStall:!!this.statContext.liveEdge}:(C(r)&&o&&this.logEmptyBuffer({duration:Math.round(w()-r.startedAt),liveAtStall:r.liveAtStall}),r=void 0)});let l=!1;t.add(e.events.fatalError$.pipe(re()).subscribe(()=>l=!0)),n(e.events.willStop$,()=>{if(e.info.isBuffering$.getValue()&&o){let e=C(r)?w()-r.startedAt:void 0;this.logCloseAtEmptyBuffer({duration:e??0,liveAtStall:r?.liveAtStall}),r=void 0}else l||this.logActionStop()}),n(e.events.managedError$,({id:e})=>{this.logError({fatal:!1,errorType:e})}),n(e.events.fatalError$,({id:e})=>{this.logError({fatal:!0,errorType:e})}),n(e.events.firstBytes$,e=>{i=w(),this.logFirstBytes({time:e})}),n(e.events.willStart$,()=>a=w()),n(e.info.currentBuffer$,e=>{!o&&e&&e.end-e.start>0&&C(i)&&(this.logPlayerReady({duration:w()-i}),c())}),n(e.events.firstFrame$,()=>{C(i)&&!o&&(this.logPlayerReady({duration:w()-i}),c()),C(a)&&this.logFirstFrame({time:w()-a})});let u;n(e.info.currentVideoStream$,e=>{e&&(this.updateContext({videoCodec:e.codec}),u&&e.id!==u&&this.logTrackSwitch(e),u=e.id)});let d;n(e.info.currentAudioStream$,e=>{e&&(this.updateContext({audioCodec:e.codec}),d&&e.id!==d&&this.logTrackSwitch(e),d=e.id)}),n(e.info.atLiveEdge$,e=>this.updateContext({liveEdge:e})),n(x({muted:e.info.muted$,volume:e.info.volume$}),({muted:e,volume:t})=>this.updateContext({audible:!e&&t>0})),n(e.info.currentQuality$,e=>{let t=De(e);this.updateContext({quality:t}),t&&this.logQuality(t)}),n(e.info.isAutoQualityEnabled$,e=>this.updateContext({autoQuality:e})),n(e.info.currentFormat$,e=>this.updateContext({contentType:ke(e)})),n(e.info.currentPlaybackRate$,e=>this.updateContext({rate:e})),n(e.info.is3DVideo$,e=>this.updateContext({is3d:e}));let f;return n(e.info.hostname$,e=>{let t=f!==void 0&&f!==e;this.updateContext({cdnHostname:e,failover:t}),t&&this.logFailover(e),f=e}),n(e.info.throughputEstimation$,e=>this.updateContext({downloadSpeed:e})),n(e.info.httpConnectionType$,e=>{this.statContext.firstConnectionType||this.updateContext({firstConnectionType:Oe(e)}),this.updateContext({connectionType:Oe(e)})}),n(e.info.httpConnectionReused$,e=>{ee(this.statContext.firstConnectionReused)&&this.updateContext({firstConnectionReused:e}),this.updateContext({connectionReused:e})}),n(e.info.surface$,e=>{this.uiEvents||this.updateContext({mode:Ae(e,this.statContext.isPreviewPlayerView)})}),n(x({current:e.info.currentTextTrack$,available:e.info.availableTextTracks$}),({current:e,available:t})=>{let n=t.find(({id:t})=>t===e),r=n&&(n.isAuto?`${n.language}_auto`:n.language);this.updateContext({subtitles:r?.split(`.`)[0]})}),this.player=e,this.uiEvents&&this.attachToUi(this.uiEvents),this.resubscribeBeforeunload(),this.subscription.add(t),t}attachToUi(e){this.uiEvents=e;let{subscription:t,subscribe:n}=Ze();if(!this.player)return t;n(e.actionRewind$,()=>{this.player&&(this.resetViewSession(),this.logActionPlay({position:this.player.info.position$.getValue()}))}),n(e.actionSeek$,this.seekAction$);let{surface$:r}=Je(this.uiEvents,n,this.player);return n(r,e=>{this.updateContext({mode:Ae(e,this.statContext.isPreviewPlayerView)})}),n(e.actionSetSubtitle$,e=>this.updateContext({subtitles:e?.split(`.`)[0]})),n(e.nextMovie$,e=>this.logNextMovie(e)),this.resubscribeBeforeunload(),this.subscription.add(t),t}attachToAds(e){let{subscription:t,subscribe:n}=Ze();return n(e.slotRequested$,()=>this.logAdSlotRequest()),n(e.started$,e=>this.logAdStarted(e)),n(e.paused$,()=>this.logAdPaused()),n(e.resumed$,()=>this.logAdResumed()),n(e.ended$,()=>this.logAdEnded()),n(e.skipped$,()=>this.logAdSkipped()),n(e.clicked$,()=>this.logAdClicked()),n(e.error$,e=>this.logError({errorType:e,fatal:!1})),this.resubscribeBeforeunload(),this.subscription.add(t),t}attachToInteractive(e){let{subscription:t,subscribe:n}=Ze();return n(e.click$,e=>this.logInterfaceClick(e)),n(e.nextMovie$,e=>this.logNextMovie(e)),this.resubscribeBeforeunload(),this.subscription.add(t),t}authorize(e){return Promise.all(this.apis.map(t=>t.authorize(e)))}pause(){this.logger.pause(),this.oneStatDebugLog({message:`paused`})}resume(){this.logger.resume(),this.oneStatDebugLog({message:`resumed`})}destroy(){this.logger.flush(),this.subscription.unsubscribe(),this.apis.forEach(e=>e.destroy()),this.logger.destroy()}resetViewSession(){this.oneStatDebugLog({message:`VSID reset`}),E.generateVSID(this.config.useVsid64)}getDeviceId(){return this.deviceId}setFieldBlacklist(){}logInited(){}logReady(e){this.log({operation:`player_ready`,param:String(e.time)})}logStarted(...e){this.logActionPlay(...e)}logPlay(){this.log({operation:`play_toggle`})}logPlaying(){this.log({operation:`playing`})}logPause(e){this.log({operation:`pause`,param:String(Math.round(e.position))})}logSeek(e){this.log({operation:`seek`,param:e.action,time:e.time})}logFirstBytes(e){this.log({operation:`first_bytes`,param:String(e.time)})}logFirstFrame(e){this.log({operation:`first_frame`,param:String(e.time)})}logError(e){this.log({operation:`content_error`,param:`${e.fatal?`fatal`:`recoverable`}_${e.errorType}`})}logWatchCoverageRecord(e){this.log({operation:`watch_coverage_record`,param:`${e.start}-${e.end}`},{in_history:this.statContext.inHistory?1:void 0})}logWatchCoverageLive(e){let t=this.timeSynchronisation?.getOffset()??0,n=e.start+t,r=e.end+t;this.log({operation:`watch_coverage_live`,param:`${n}-${r}`},{in_history:this.statContext.inHistory?1:void 0,latency:e.latency,buffer_latency:e.bufferLatency})}logEmptyBuffer(e){this.log({operation:`empty_buffer`,param:String(e.duration)},C(e.liveAtStall)?{live:e.liveAtStall?1:void 0}:{})}logDownloadSpeed(){}logAdSlotRequest(){this.log({operation:`adv`,param:`slot_request`})}logAdStarted(e){this.log({operation:`adv`,param:e})}logAdPaused(){this.log({operation:`adv`,param:`pause`})}logAdResumed(){this.log({operation:`adv`,param:`resume`})}logAdEnded(){this.log({operation:`adv`,param:`ended`})}logAdSkipped(){this.log({operation:`adv`,param:`skip`})}logAdClicked(){this.log({operation:`adv`,param:`click`})}logInterfaceClick(e){this.log({operation:`player_interface_click`,param:e})}logNextMovie(e){this.log({operation:`next_movie`,param:String(e)})}subscribe(){this.resubscribeBeforeunload();let e=se().navigator.connection;e&&`onchange`in e&&`effectiveType`in e&&this.subscription.add(te(S(e,`change`),ne([`init`])).subscribe(()=>this.updateContext({network:je(e.effectiveType)}))),this.config.debugLog&&this.debugLogger.log$.subscribe(e=>{console.debug(`%c stat `,`background:#fa6470;`,`component: ${e.component}.`,e.message)})}resubscribeBeforeunload(){this.beforeunloadSubscription?.unsubscribe(),this.beforeunloadSubscription=S(window,`beforeunload`).subscribe(()=>this.logger.flush({wantBeacon:!0,clearStorage:this.config.clearStorageAtUnload})),this.subscription.add(this.beforeunloadSubscription)}logPlayerReady(e){this.log({operation:`player_ready`,param:String(Math.round(e.duration))})}logActionPlay(e){this.log({operation:`action_play`,param:String(Math.round(e.position))})}logActionPlayInteractive(){this.statContext.projectId&&this.log({operation:`action_play_interactive`,param:String(this.statContext.movieId)},{vid:this.statContext.projectId})}logFailover(e){this.log({operation:`failover`,param:e})}logCloseAtEmptyBuffer(e){this.log({operation:`close_at_empty_buffer`,param:String(Math.round(e.duration))},C(e.liveAtStall)?{live:e.liveAtStall?1:void 0}:{})}logActionStop(){this.log({operation:`action_stop`})}logTrackSwitch(e){this.log({operation:`track_switch`,param:e.id})}logQuality(e){this.log({operation:`quality`,param:e})}log(e,t={}){if(this.disabled){this.oneStatDebugLog({message:`operation ${e.operation} but statistics is disabled`});return}if(this.config.disabledOperations.includes(e.operation)){this.oneStatDebugLog({message:`operation ${e.operation} but it is disabled`});return}this.oneStatDebugLog({message:`operation ${e.operation} ${e.param}`});let n=this.createLogItem(e,t);this.logger.log(n)}createLogItem({operation:e,param:t,time:n},r={}){let i=this.timeSynchronisation?.now()??w(),a=this.vsid$.getValue();b(a);let o=this.isid$.getValue(),s=e===`empty_buffer`||e===`close_at_empty_buffer`?this.statContext.connectionType:this.statContext.firstConnectionType,c=this.statContext.firstConnectionReused,l,u;if(this.isEmbed||this.statContext.place===`embed`){l=this.embedParent;let e=[...new URLSearchParams(location.search).entries()].filter(([e,t])=>this.config.embedUrlParams.includes(e));u=new URLSearchParams(e).toString()}else if(this.statContext.place===`direct`){let e=this.statContext.refDomain||document.referrer;l=e&&URL.canParse(e)?new URL(e).hostname:e,u=location.href.substring(0,1024)}let d={vsid:a,isid:o,vid:this.statContext.movieId,uid:this.zenUid$.getValue(),ct:this.statContext.contentType,place:this.isEmbed?`embed`:this.statContext.place,quality:this.statContext.quality,cdn_host:this.statContext.cdnHostname,stat_type:this.statContext.autoplay===!0?`auto`:this.statContext.autoplay===!1?``:void 0,param:t,vk_app_id:this.statContext.vkAppId,track_code:this.statContext.trackCode,connection_type:s,connection_reused:c===!0?1:c===!1?0:void 0,cached_data:this.statContext.cached===!0?1:this.statContext.cached===!1?0:void 0,live:this.statContext.liveEdge?1:void 0,muted:this.statContext.audible===!1?1:void 0,mode:this.statContext.mode,subtitles:this.statContext.subtitles,download_speed:this.statContext.downloadSpeed,manual_quality:this.statContext.autoQuality?void 0:1,ref_domain:l,direct_url:u,rate:this.statContext.rate===1||ee(this.statContext.rate)?void 0:this.statContext.rate.toFixed(2),view_360:this.statContext.is3d?1:void 0,codec_info:Xe(this.statContext.videoCodec,this.statContext.audioCodec),aid:this.statContext.albumId,vk_playlist_id:this.statContext.vkPlaylistId,...r};for(let e of this.config.disabledCustomFields)delete d[e];return{operation:e,type:1,time:n,network:this.statContext.network,timestamp:i,custom:d}}}var $e={};r($e,{VERSION:()=>D,ThinOneStat:()=>kn,ActionSeekType:()=>gt});import{assertNonNullable as et,detectEmbed as tt,fromEvent as nt,Logger as rt,merge as it,combine as R,filter as z,filterChanged as at,once as ot,skip as st,debounce as ct,safeStorage as lt,getWindow as ut,Subject as dt,Subscription as ft,ValueSubject as pt,ErrorCategory as B}from"@vkontakte/videoplayer-shared/evergreen";import{clientChecker as V}from"@vkontakte/videoplayer-core/evergreen";import{fillWithDefault as mt}from"@vkontakte/videoplayer-shared/evergreen";var ht;(e=>{e.AUTO=`auto`,e.AUTO_POOR=`auto_poor`,e.AUTO_RICH=`auto_rich`})(ht||={});var gt;(e=>{e.SLIDER=`slider`,e.RICH=`rich`,e.DOUBLE_TAP=`double_tap`,e.TIME_CODE=`time_code`,e.EPISODE=`episode`,e.REWIND=`rewind`,e.LIVE=`live`,e.UNKNOWN=`unknown`})(gt||={});var _t=`CIOPGQJGDIHBABABA`,vt={prod:`https://api.ok.ru`,vk_alias:`https://api.mycdn.me`,videotest:`https://videotestapi.ok.ru/api`,test:`https://apitest.ok.ru`,okcdn:`https://api.okcdn.ru`,auto:``},yt={apiKey:_t,apiEnv:`okcdn`,apiBaseUrl:null,apiUvRestBaseUrl:`https://uvapi.okcdn.ru`,apiForticom:!0,apiUvRest:!1,requestRetryCount:3,useVsid64:!1,flushFirstTime:5e3,flushDebounceTime:1e4,flushMaxWait:6e4,flushRetryFirstDelay:3e3,flushRetryMaxDelay:18e5,storageExpiration:2160*60*1e3,clearStorageAtUnload:!1,disabledEvents:[],disabledParams:[],synchronizeTime:!0,useBeacon:!1,alwaysSendDesktop:!1,watchCoverageHeartbeatInterval:3e4,watchCoverageExactTime:!1,watchedNDefaultTargetDuration:1e3,telemetryInterval:3e4,downloadBytesMaxTime:3e4},bt=e=>mt(e,yt);import{ErrorCategory as H,ValueSubject as xt}from"@vkontakte/videoplayer-shared/evergreen";function St(e){let t=Error(`HTTP ${e.status}: ${e.statusText}`);return t.status=e.status,t.statusText=e.statusText,t.response=e,t}function Ct(){let e=Error(`Request timeout`);return e.isTimeout=!0,e}function wt(e){let t=Error(e.error_msg);return t.errorData=e,t}function Tt(e){if(!(!e||typeof e!=`object`)){if(`errorData`in e)return e.errorData?.error_code;if(`error_code`in e){let t=e.error_code;return typeof t==`number`?t:void 0}}}var Et=({application:e,platform:t,product:n,...r})=>r;class Dt{id=`forticom`;authorized$;params;authToken;sessionKey;authorizePromise;refreshAuthTokenPromise;isDestroyed=!1;constructor(e){this.params=e,this.authorized$=new xt(!1)}async authorize(e){return this.authToken=e??await this.refreshAuthToken(),this.doAuthorize()}logBeacon(e){if(!e.length)return;let t=this.createLogParams(e),n=this.sessionKey;n&&(this.params.apiTransport.sendBeacon(`log.logUvStat`,t,n)||this.logRequest(e).catch(()=>{}))}async logRequest(e){if(!e.length)return;let t=`log.logUvStat`,n=this.createLogParams(e),r={};try{let e=await this.getValidSessionKey();if(!e){this.params.errors$.next({id:`ThinOneStat:Api:LogRequestNoSession`,category:H.NETWORK,message:`No session key available for log request`});return}await this.params.apiTransport.sendRequest(t,n,e,r)}catch(e){await this.handleLogRequestError(e,t,n)&&await this.retryLogRequestAfterSessionRecovery(t,n)}}async getValidSessionKey(){return this.sessionKey?this.sessionKey:this.doAuthorize()}async handleLogRequestError(e,t,n){let r=Tt(e);return r===void 0?(this.params.errors$.next({id:`ThinOneStat:Api:LogRequestUnknown`,category:H.NETWORK,message:`Unknown ${t} error`,thrown:e,data:{params:n}}),!1):this.isSessionExpiredError(r)?(this.params.errors$.next({id:`ThinOneStat:Api:LogRequestSessionError#${r}`,category:H.EXTERNAL_API,message:`Session error: ${r}`,data:{error:e,code:r}}),this.authorized$.next(!1),this.sessionKey=void 0,await this.doAuthorize()!==void 0):r===401?(this.params.errors$.next({id:`ThinOneStat:Api:LogRequestAuthLogin#${r}`,category:H.EXTERNAL_API,message:`Auth token expired`,data:{error:e,code:r}}),this.authorized$.next(!1),this.authToken=await this.refreshAuthToken(),this.sessionKey=void 0,await this.doAuthorize()!==void 0):(this.params.errors$.next({id:`ThinOneStat:Api:LogRequest#${r}`,category:H.EXTERNAL_API,message:`${t} error`,data:{error:e,code:r,params:n}}),!1)}async retryLogRequestAfterSessionRecovery(e,t){let n=this.sessionKey;if(!n){this.params.errors$.next({id:`ThinOneStat:Api:LogRequestRetryFailed`,category:H.NETWORK,message:`Cannot retry log request: no session key after recovery`});return}try{await this.params.apiTransport.sendRequest(e,t,n)}catch(e){let t=Tt(e);this.params.errors$.next({id:`ThinOneStat:Api:LogRequestRetryFailed#${t??`unknown`}`,category:H.EXTERNAL_API,message:`Log request failed after session recovery`,thrown:e,data:{originalError:e,retryCode:t}})}}isSessionExpiredError(e){return!!e&&[102,103,104].includes(e)}async doAuthorize(e=1){if(!this.isDestroyed)return this.authorizePromise?this.authorizePromise:(this.sessionKey=void 0,this.authorized$.next(!1),this.authorizePromise=this.executeAuthorize(e).finally(()=>{this.authorizePromise=void 0,this.isDestroyed||this.authorized$.next(this.sessionKey!==void 0)}),this.authorizePromise)}async executeAuthorize(e){let t=this.buildAuthParams();try{let e=await this.params.apiTransport.sendRequest(`auth.anonymLogin`,t);if(this.isDestroyed)return;if(!e?.session_key){this.params.errors$.next({id:`ThinOneStat:Api:AuthorizeFailed`,category:H.EXTERNAL_API,message:`No session key in response`,data:e});return}return this.sessionKey=e.session_key,this.sessionKey}catch(t){if(this.isDestroyed)return;let n=Tt(t);if(n===401&&this.params.refreshAuthToken){if(this.params.errors$.next({id:`ThinOneStat:Api:AuthorizeAuthLogin`,category:H.EXTERNAL_API,message:`Auth token expired during authorization`,data:{error:t,code:n,attempt:e}}),e>=2){this.params.errors$.next({id:`ThinOneStat:Api:AuthorizeMaxAttemptsReached`,category:H.EXTERNAL_API,message:`Authorization failed after ${e} attempts`,data:{error:t,code:n}});return}return this.authToken=await this.refreshAuthToken(),this.doAuthorize(e+1)}n?this.params.errors$.next({id:`ThinOneStat:Api:Authorize#${n}`,category:H.EXTERNAL_API,message:`Authorize error`,data:{error:t,code:n}}):this.params.errors$.next({id:`ThinOneStat:Api:AuthorizeUnknown`,category:H.NETWORK,message:`Authorize error`,thrown:t});return}}buildAuthParams(){let e={session_data:{version:2,device_id:this.params.deviceId,client_version:this.getClientVersion(),client_type:`SDK_JS`}};return this.authToken!==void 0&&(e.session_data.auth_token=this.authToken,e.session_data.version=3),e}getClientVersion(){return D}async refreshAuthToken(){if(this.params.refreshAuthToken)return this.refreshAuthTokenPromise||=this.params.refreshAuthToken().catch(e=>{throw this.params.errors$.next({id:`ThinOneStat:Api:RefreshAuthTokenFailed`,category:H.NETWORK,message:`Failed to refresh auth token`,thrown:e}),e}).finally(()=>{this.refreshAuthTokenPromise=void 0}),this.refreshAuthTokenPromise}createLogParams(e){let t=e[0],n=t.application??`@vkontakte/videoplayer-statistics:${this.getClientVersion()}`;return this.params.vktvVersion&&(n=this.params.vktvVersion),{collector:`ok.mobile.apps.video`,uv_stat_data:JSON.stringify({application:n,platform:t.platform,product:t.product,events:e.map(Et)})}}destroy(){this.isDestroyed=!0,this.authorizePromise=void 0,this.refreshAuthTokenPromise=void 0,this.sessionKey=void 0,this.authorized$.next(!1)}}class Ot{id=`uvrest`;authorized$;params;statToken;authorizePromise;isDestroyed=!1;constructor(e){this.params=e,this.authorized$=new xt(!1)}async authorize(e){if(!this.isDestroyed)return e?(this.statToken=e,this.authorized$.next(!0),e):this.authorizePromise?this.authorizePromise:(this.authorized$.next(!1),this.authorizePromise=this.executeAuthorize().finally(()=>{this.authorizePromise=void 0,this.isDestroyed||this.authorized$.next(this.statToken!==void 0)}),this.authorizePromise)}async logRequest(e){if(!e.length)return;let t=this.buildBody(e);try{let e=await this.getValidToken();if(!e){this.params.errors$.next({id:`ThinOneStat:UvRestApi:LogRequestNoToken`,category:H.NETWORK,message:`No stat token available for log request`});return}await this.params.apiTransport.sendJsonRequest(`/uv/stat/logUvStat`,t,{Authorization:`Bearer ${e}`})}catch(e){await this.handleLogRequestError(e)&&await this.retryLogRequestAfterRecovery(t)}}logBeacon(e){if(!e.length)return;let t=this.statToken;if(!t)return;let n=this.buildBody(e);this.params.apiTransport.sendJsonBeacon(`/uv/stat/logUvStat`,n,{Authorization:`Bearer ${t}`})}destroy(){this.isDestroyed=!0,this.authorizePromise=void 0,this.statToken=void 0,this.authorized$.next(!1)}async getValidToken(){return this.statToken?this.statToken:this.authorize()}async executeAuthorize(){try{let e=await this.params.getAuthToken();if(this.isDestroyed)return;if(!e){this.params.errors$.next({id:`ThinOneStat:UvRestApi:NoToken`,category:H.EXTERNAL_API,message:`getAuthToken returned no token`});return}return this.statToken=e,this.statToken}catch(e){if(this.isDestroyed)return;this.params.errors$.next({id:`ThinOneStat:UvRestApi:AuthorizeFailed`,category:H.NETWORK,message:`Failed to get stat token`,thrown:e});return}}async handleLogRequestError(e){let t=e?.status;return t===401?(this.params.errors$.next({id:`ThinOneStat:UvRestApi:TokenExpired`,category:H.EXTERNAL_API,message:`Stat token expired (401), refreshing`,thrown:e}),this.authorized$.next(!1),this.statToken=void 0,await this.authorize()!==void 0):(this.params.errors$.next({id:`ThinOneStat:UvRestApi:LogRequestFailed#${t??`unknown`}`,category:H.EXTERNAL_API,message:`Log request failed with status ${t}`,thrown:e}),!1)}async retryLogRequestAfterRecovery(e){let t=this.statToken;if(!t){this.params.errors$.next({id:`ThinOneStat:UvRestApi:RetryNoToken`,category:H.NETWORK,message:`Cannot retry log request: no token after recovery`});return}try{await this.params.apiTransport.sendJsonRequest(`/uv/stat/logUvStat`,e,{Authorization:`Bearer ${t}`})}catch(e){this.params.errors$.next({id:`ThinOneStat:UvRestApi:RetryFailed`,category:H.EXTERNAL_API,message:`Log request failed after token refresh`,thrown:e})}}buildBody(e){let t=e[0],n=t.application;return this.params.vktvVersion&&(n=this.params.vktvVersion),[{product:t.product,platform:t.platform,application:n,user_id:this.params.userId,events:e.map(Et)}]}}import{now as U,getWindow as W,getExponentialDelay as kt,isAbortError as At,ErrorCategory as G}from"@vkontakte/videoplayer-shared/evergreen";class jt{params;apiKey;apiBaseUrl;apiUvRestBaseUrl;apiEnv;resolvedApiBaseUrl=null;resolveApiBaseUrlPromise=null;timeSynchronisation;fetchTimeout=3e4;maxTotalRequestTime=6e4;retryConfig;constructor(e){this.params=e,this.apiKey=e.config.apiKey,this.apiEnv=e.config.apiEnv,this.apiBaseUrl=e.config.apiBaseUrl??vt[this.apiEnv],this.apiUvRestBaseUrl=e.config.apiUvRestBaseUrl,this.timeSynchronisation=e.timeSynchronisation,this.retryConfig={maxAttempts:e.config.requestRetryCount??3,baseDelay:3e3,maxDelay:3e4,retryableErrors:[`Failed to fetch`,`NetworkError when attempting to fetch resource.`,`Request timeout`,`Network request failed`],retryableStatuses:[408,429,500,502,503,504]}}sendBeacon(e,t,n){if(!W().Blob||!W().navigator.sendBeacon)return!1;let r=this.resolvedApiBaseUrl??this.apiBaseUrl,i=this.prepareQueryParams({method:e,queryParams:t,sessionKey:n}),a=W().Blob,o=new a([i.toString()],{type:`application/x-www-form-urlencoded`});try{return W().navigator.sendBeacon(`${r}/fb.do`,o)}catch(n){this.params.errors$.next({id:`ThinOneStat:ApiTransport:sendBeacon`,category:G.NETWORK,message:`Unhandled beacon error`,thrown:n,data:{method:e,params:t}})}return!1}async sendRequest(e,t,n,r){return this.sendRequestWithRetry(e,t,n,r)}async sendRequestWithRetry(e,t,n,r,i=1,a){let o=U(),s=a??o+this.maxTotalRequestTime;if(U()>=s){let r=Error(`Request deadline exceeded`);throw this.handleFinalError(e,t,n,o,r,i),r}try{return await this.executeRequest(e,t,n,r,o,i,s)}catch(a){if(this.shouldRetry(a,i)&&U()<s){let c=this.getRetryDelay(a,i);if(U()+c>=s)throw this.handleFinalError(e,t,n,o,a,i),a;return this.logRetryAttempt(e,i,a,c),await this.sleep(c),this.sendRequestWithRetry(e,t,n,r,i+1,s)}throw this.handleFinalError(e,t,n,o,a,i),a}}async executeRequest(e,t,n,r,i,a,o){let s=i??U(),c=await this.resolveApiBaseUrl(),l=o===void 0?this.fetchTimeout:o-U();if(l<=0)throw Ct();try{let i=await this.fetchWithTimeout(`${c}/fb.do`,{method:`post`,headers:{"Content-type":`application/x-www-form-urlencoded`,...r},body:this.prepareQueryParams({method:e,queryParams:t,sessionKey:n})},Math.min(this.fetchTimeout,l));return await this.processResponse(i,s)}catch(t){throw t instanceof Error&&(t.context={method:e,attempt:a,url:`${c}/fb.do`}),t}}async sendJsonRequest(e,t,n){return this.sendJsonRequestWithRetry(e,t,n)}sendJsonBeacon(e,t,n){let r=`${this.apiUvRestBaseUrl}${e}`;try{fetch(r,{method:`POST`,headers:{"Content-Type":`application/json`,...n},body:JSON.stringify(t),keepalive:!0}).catch(t=>{this.params.errors$.next({id:`ThinOneStat:ApiTransport:sendJsonBeacon`,category:G.NETWORK,message:`Keepalive request failed`,thrown:t,data:{path:e}})})}catch(t){this.params.errors$.next({id:`ThinOneStat:ApiTransport:sendJsonBeacon`,category:G.NETWORK,message:`Failed to initiate keepalive request`,thrown:t,data:{path:e}})}}async sendJsonRequestWithRetry(e,t,n,r=1,i){let a=U(),o=i??a+this.maxTotalRequestTime;if(U()>=o){let t=Error(`Request deadline exceeded`);throw this.handleJsonFinalError(e,a,t,r),t}try{return await this.executeJsonRequest(e,t,n,a,r,o)}catch(i){if(this.shouldRetry(i,r)&&U()<o){let s=this.getRetryDelay(i,r);if(U()+s>=o)throw this.handleJsonFinalError(e,a,i,r),i;return this.logRetryAttempt(e,r,i,s),await this.sleep(s),this.sendJsonRequestWithRetry(e,t,n,r+1,o)}throw this.handleJsonFinalError(e,a,i,r),i}}async executeJsonRequest(e,t,n,r,i,a){let o=r??U(),s=a===void 0?this.fetchTimeout:a-U();if(s<=0)throw Ct();let c=`${this.apiUvRestBaseUrl}${e}`;try{let e=await this.fetchWithTimeout(c,{method:`POST`,headers:{"Content-Type":`application/json`,...n},body:JSON.stringify(t)},Math.min(this.fetchTimeout,s));return await this.processResponse(e,o)}catch(t){throw t instanceof Error&&(t.context={method:e,attempt:i,url:c}),t}}async fetchWithTimeout(e,t,n=this.fetchTimeout){let r=new AbortController,i=W().setTimeout(()=>r.abort(),n);try{let n=await fetch(e,{...t,signal:r.signal});return W().clearTimeout(i),n}catch(e){throw W().clearTimeout(i),At(e)?Ct():e}}async processResponse(e,t){if(!e.ok){let t=St(e),n=this.parseRetryAfter(e);throw n!==void 0&&(t.retryAfter=n),t}let n=new Date(e.headers.get(`date`)??``).getTime(),r=U()-t;isFinite(n)&&this.timeSynchronisation?.addServerTime(n,r);let i=e.headers.get(`content-length`);if(i!==null&&Number(i)===0)return{};let a=await e.json();if(a&&typeof a==`object`&&`error_msg`in a)throw wt(a);return a}shouldRetry(e,t){if(t>=this.retryConfig.maxAttempts||!(e instanceof Error))return!1;let n=e;return!!(n.isTimeout||n.status&&this.retryConfig.retryableStatuses.includes(n.status)||this.retryConfig.retryableErrors.includes(e.message)||e.message.includes(`network`)||e.message.includes(`timeout`)||e.message.includes(`connection`))}logRetryAttempt(e,t,n,r){let i=n instanceof Error?n.message:String(n);this.params.errors$.next({id:`ThinOneStat:ApiTransport:retry`,category:G.NETWORK,message:`Retrying request (attempt ${t}/${this.retryConfig.maxAttempts}) after ${Math.round(r)}ms`,thrown:n,data:{method:e,attempt:t,delay:r,errorMessage:i}})}handleFinalError(e,t,n,r,i,a){let o=G.NETWORK;this.params.errors$.next({id:`ThinOneStat:ApiTransport:sendRequest`,category:o,message:i instanceof Error?i.message:`Request failed after retries`,thrown:i,data:{method:e,params:t,sessionKey:n,time:U()-r,maxAttempts:this.retryConfig.maxAttempts,attempts:a}})}handleJsonFinalError(e,t,n,r){this.params.errors$.next({id:`ThinOneStat:ApiTransport:sendJsonRequest`,category:G.NETWORK,message:n instanceof Error?n.message:`JSON request failed after retries`,thrown:n,data:{path:e,time:U()-t,maxAttempts:this.retryConfig.maxAttempts,attempts:r}})}sleep(e){return new Promise(t=>W().setTimeout(t,e))}resolveApiBaseUrl(){return this.apiEnv===`auto`?(this.resolveApiBaseUrlPromise||=this.fetchApiBaseUrl().then(e=>(e===vt.vk_alias&&(this.resolveApiBaseUrlPromise=null),e)),this.resolveApiBaseUrlPromise):Promise.resolve(this.apiBaseUrl)}async fetchApiBaseUrl(){try{let e=atob(`aHR0cHM6Ly9kbnMuZ29vZ2xlL3Jlc29sdmU/bmFtZT12aWRlby5fZW5kcG9pbnQub2sucnUmdHlwZT1UWFQ=`),t=(await(await this.fetchWithTimeout(e,{method:`GET`,mode:`cors`,cache:`no-cache`},5e3)).json())?.Answer[0]?.data;if(!t)throw Error(`Wrong DNS response`);return this.resolvedApiBaseUrl=t,t}catch(e){return this.params.errors$.next({id:`ThinOneStat:ApiTransport:resolveApiBaseUrl`,category:G.NETWORK,message:`Unhandled resolve api base url error`,thrown:e}),vt.vk_alias}}prepareQueryParams(e){let t=new URLSearchParams({format:`JSON`,method:e.method,application_key:this.apiKey});return e.sessionKey!==void 0&&t.append(`session_key`,e.sessionKey),Object.entries(e.queryParams).forEach(([e,n])=>t.append(e,typeof n==`string`?n:JSON.stringify(n))),t}parseRetryAfter(e){let t=e.headers.get(`Retry-After`);if(!t)return;let n=Number(t);if(!isNaN(n)&&n>=0)return n*1e3;let r=new Date(t).getTime();if(!isNaN(r))return Math.max(0,r-Date.now())}getRetryDelay(e,t){let n=e;return n?.retryAfter!==void 0&&n.retryAfter>0?n.retryAfter:kt(t,{start:this.retryConfig.baseDelay,max:this.retryConfig.maxDelay,factor:2,random:.2})}}import{ErrorCategory as Mt}from"@vkontakte/videoplayer-shared/evergreen";import{now as Nt,debounceFn as Pt,getWindow as K,safeStorage as Ft,ErrorCategory as q}from"@vkontakte/videoplayer-shared/evergreen";var It=e=>t=>(t.client_time??Nt())+e>=Nt();class Lt{params;subscription;userSalt;unsaltedStorage=[];lastVsid;isPaused=!1;firstFlush;debouncedFlush;flushRetryCount=0;retryFlushTimerId;debugLog;flushPromise=null;flushSnapshotLength=0;onlineListener;urgentEvents=[`watch_coverage`,`watch_coverage_live`,`watched_n`,`playback_started`];STORAGE_MAX_ATTEMPTS=3;constructor(e){this.params=e,this.userSalt=e.userSalt,this.debugLog=e.debugLogger.createComponentLog(`batch-queue:${e.storageKey}`),this.firstFlush=Pt(()=>this.safeFlush(),this.params.config.flushFirstTime,{maxWait:this.params.config.flushFirstTime});let t=Ft.isPersistent()?this.params.config.flushMaxWait:0;this.debouncedFlush=Pt(()=>this.safeFlush(),this.params.config.flushDebounceTime,{maxWait:t}),this.subscription=this.params.canSend$.subscribe(e=>{e&&(this.debugLog({message:`Can send, triggering flush`}),this.debouncedFlush())}),this.onlineListener=()=>{this.debugLog({message:`Network online, triggering flush`}),this.cancelRetry(),this.safeFlush()},K().addEventListener(`online`,this.onlineListener),this.housekeepStorage()}isUrgent=e=>this.urgentEvents.includes(e.event_name);scheduleRetry(){this.retryFlushTimerId!==void 0&&K().clearTimeout(this.retryFlushTimerId);let e=this.params.config.flushRetryFirstDelay,t=this.params.config.flushRetryMaxDelay,n=Math.min(e*2**this.flushRetryCount,t);this.flushRetryCount++,this.debugLog({message:`Scheduling flush retry #${this.flushRetryCount} in ${n}ms`}),this.retryFlushTimerId=K().setTimeout(()=>{this.retryFlushTimerId=void 0,this.safeFlush()},n)}cancelRetry(){this.retryFlushTimerId!==void 0&&(K().clearTimeout(this.retryFlushTimerId),this.retryFlushTimerId=void 0),this.flushRetryCount=0}safeFlush(){if(this.flushPromise){this.debugLog({message:`Flush already in progress, skipping`});return}this.flushPromise=this.flush().finally(()=>{this.flushPromise=null})}isStorageAvailable(){let e=Ft.isPersistent?.()??!1;return e||this.debugLog({message:`Storage not available`}),e}readFromStorage(){if(!this.isStorageAvailable())return{};try{let e=Ft.get(this.params.storageKey),t=e?JSON.parse(e):{};return this.debugLog({message:`Read ${Object.keys(t).length} users from storage`}),t}catch(e){return this.params.errors$.next({id:`ThinOneStat:BatchQueue:ReadStorageError`,category:q.WTF,message:`Failed to read from storage`,thrown:e,data:{storageKey:this.params.storageKey}}),this.debugLog({message:`Failed to read from storage`}),{}}}writeToStorage(e){if(!this.isStorageAvailable())return!1;try{return Ft.set(this.params.storageKey,JSON.stringify(e)),this.debugLog({message:`Written ${Object.keys(e).length} users to storage`}),!0}catch(e){return this.params.errors$.next({id:`ThinOneStat:BatchQueue:WriteStorageError`,category:q.WTF,message:`Failed to write to storage`,thrown:e,data:{storageKey:this.params.storageKey}}),this.debugLog({message:`Failed to write to storage`}),!1}}addToStorage(e){if(!this.userSalt){this.unsaltedStorage.push(e),this.debugLog({message:`Added item to unsalted storage, total: ${this.unsaltedStorage.length}`});return}for(let t=0;t<this.STORAGE_MAX_ATTEMPTS;t++)try{let t=this.readFromStorage(),n=t[this.userSalt]??[];if(this.debugLog({message:`Adding item to storage for user ${this.userSalt}`}),this.writeToStorage({...t,[this.userSalt]:[...n,e]}))return}catch(n){t===this.STORAGE_MAX_ATTEMPTS-1&&(this.params.errors$.next({id:`ThinOneStat:BatchQueue:AddToStorageFailed`,category:q.WTF,message:`Failed to add item to storage after retries`,thrown:n,data:{item:e,attempt:t,storageKey:this.params.storageKey}}),this.debugLog({message:`Failed to add item to storage after retries`}))}}getFromStorage(){if(!this.userSalt)return this.debugLog({message:`Retrieved ${this.unsaltedStorage.length} items from unsalted storage`}),this.flushSnapshotLength=this.unsaltedStorage.length,this.unsaltedStorage.slice();let e=this.readFromStorage(),t=e[this.userSalt]??[],n=t.filter(It(this.params.config.storageExpiration));if(this.debugLog({message:`Retrieved from storage for user ${this.userSalt}`}),n.length!==t.length){let r=t.length-n.length;this.params.errors$.next({id:`ThinOneStat:BatchQueue:DropExpiredEvents`,category:q.WTF,message:`Dropped ${r} expired events from storage`,data:{droppedCount:r,expiration:this.params.config.storageExpiration,storageKey:this.params.storageKey}}),this.debugLog({message:`Cleaning ${r} expired items from storage`});let i={...e};n.length?i[this.userSalt]=n:delete i[this.userSalt],this.writeToStorage(i)}return this.flushSnapshotLength=n.length,n}markStorageSent(){if(!this.userSalt){let e=this.unsaltedStorage.splice(0,this.flushSnapshotLength);this.debugLog({message:`Cleared unsalted storage, removed ${e.length} items, ${this.unsaltedStorage.length} new items kept`}),this.flushSnapshotLength=0;return}let e=this.flushSnapshotLength;this.flushSnapshotLength=0;for(let t=0;t<this.STORAGE_MAX_ATTEMPTS;t++)try{let t=this.readFromStorage(),n=(t[this.userSalt]??[]).slice(e),r={...t};if(n.length?r[this.userSalt]=n:delete r[this.userSalt],this.writeToStorage(r)){this.debugLog({message:`Marked storage as sent for user ${this.userSalt}, removed ${e} items, ${n.length} kept`});return}}catch(e){t===this.STORAGE_MAX_ATTEMPTS-1&&(this.params.errors$.next({id:`ThinOneStat:BatchQueue:MarkStorageSentFailed`,category:q.WTF,message:`Failed to mark storage as sent after retries`,thrown:e,data:{storageKey:this.params.storageKey}}),this.debugLog({message:`Failed to mark storage as sent after retries`}))}}housekeepStorage(){if(this.isStorageAvailable())try{let e=this.readFromStorage(),t=!1,n=0;for(let[r,i]of Object.entries(e)){let a=i.filter(It(this.params.config.storageExpiration)),o=i.length-a.length;n+=o,a.length?a.length!==i.length&&(e[r]=a,t=!0):(delete e[r],t=!0),this.debugLog({message:`${i.length} retrieved from storage, ${a.length} of them actual for ${r}`})}t?(this.debugLog({message:`Housekeeping completed, removed ${n} expired items total`}),this.writeToStorage(e),n>0&&this.params.errors$.next({id:`ThinOneStat:BatchQueue:DropExpiredEvents`,category:q.WTF,message:`Dropped ${n} expired events during housekeeping`,data:{droppedCount:n,expiration:this.params.config.storageExpiration,storageKey:this.params.storageKey}})):this.debugLog({message:`Housekeeping completed, no changes needed`})}catch(e){this.params.errors$.next({id:`ThinOneStat:BatchQueue:HousekeepStorageError`,category:q.WTF,message:`Failed to housekeep storage`,thrown:e,data:{storageKey:this.params.storageKey}}),this.debugLog({message:`Failed to housekeep storage`})}}log(e){try{if(this.debugLog({message:`Logging item: ${e.event_name}`}),this.addToStorage(e),this.isPaused){this.debugLog({message:`Queue paused, skipping flush`});return}this.isUrgent(e)?(this.debugLog({message:`Urgent item, flushing immediately`}),this.safeFlush()):this.lastVsid===e.vsid?(this.debugLog({message:`Same VSID, scheduling debounced flush`}),this.debouncedFlush()):(this.debugLog({message:`VSID changed, triggering first flush`}),this.firstFlush()),this.lastVsid=e.vsid}catch(t){this.params.errors$.next({id:`ThinOneStat:BatchQueue:LogError`,category:q.WTF,message:`Failed to log item`,thrown:t,data:{item:e,storageKey:this.params.storageKey}}),this.debugLog({message:`Failed to log item`})}}flush(e={wantBeacon:!1,clearStorage:!0}){return this.flushPromise?(this.debugLog({message:`Flush already in progress, waiting`}),this.flushPromise):(this.flushPromise=this.flushInternal(e).finally(()=>{this.flushPromise=null}),this.flushPromise)}async flushInternal({wantBeacon:e,clearStorage:t}){this.debugLog({message:`Starting flush`});let n=this.getFromStorage();if(n.length===0){this.debugLog({message:`No items to flush`});return}let r=this.params.canSend$.getValue();if(this.debugLog({message:`Can send status: ${r}`}),!r){this.debugLog({message:`Cannot send, requesting ready state`}),this.params.requestReady();return}if(e&&this.params.config.useBeacon){this.debugLog({message:`Flushing ${n.length} events through beacon`}),this.params.sendBeacon(n),t&&this.markStorageSent(),this.firstFlush.cancel(),this.debouncedFlush.cancel();return}this.debugLog({message:`Flushing ${n.length} events`});try{await this.params.send(n),this.debugLog({message:`Flush completed successfully`}),this.cancelRetry(),t&&this.markStorageSent(),this.firstFlush.cancel(),this.debouncedFlush.cancel()}catch(e){throw this.params.errors$.next({id:`ThinOneStat:BatchQueue:FlushRequestError`,category:q.NETWORK,message:`Failed to send events, will retry later`,thrown:e,data:{itemsCount:n.length,storageKey:this.params.storageKey}}),this.debugLog({message:`Flush failed, scheduling retry`}),this.scheduleRetry(),e}}pause(){this.debugLog({message:`Queue paused`}),this.isPaused=!0,this.debouncedFlush.cancel(),this.firstFlush.cancel(),this.cancelRetry()}resume(){this.debugLog({message:`Queue resumed`}),this.isPaused=!1,this.debouncedFlush()}async destroy(){this.debugLog({message:`Destroying queue`}),this.flushPromise&&(this.debugLog({message:`Waiting for ongoing flush to complete`}),await this.flushPromise),this.cancelRetry(),this.onlineListener&&=(K().removeEventListener(`online`,this.onlineListener),void 0),this.subscription.unsubscribe(),this.firstFlush.cancel(),this.debouncedFlush.cancel(),this.flushPromise=null,this.debugLog({message:`Queue destroyed`})}}class Rt{params;queues=[];constructor(e){this.params=e;for(let t of e.apis)this.queues.push(this.createQueueForApi(t))}createQueueForApi(e){let t=this.getStorageKeyForApi(e.id);return new Lt({config:this.params.config,storageKey:t,debugLogger:this.params.debugLogger,errors$:this.params.errors$,userSalt:this.params.userSalt,send:t=>e.logRequest(t),sendBeacon:t=>e.logBeacon(t),canSend$:e.authorized$,requestReady:()=>{e.authorize().catch(e=>{this.params.errors$.next({id:`ThinOneStat:Logger:RequestReadyFailed`,category:Mt.NETWORK,message:`Failed to authorize on requestReady`,thrown:e,data:{storageKey:t}})})}})}getStorageKeyForApi(e){return`thinonestat_events_${e}`}log(e){this.queues.forEach(t=>t.log(e))}async flush(e){let t=await Promise.allSettled(this.queues.map(t=>t.flush(e)));if(t.length>0&&t.every(e=>e.status===`rejected`))throw t.find(e=>e.status===`rejected`).reason}pause(){this.queues.forEach(e=>e.pause())}resume(){this.queues.forEach(e=>e.resume())}async destroy(){await Promise.allSettled(this.queues.map(e=>e.destroy())),this.queues=[]}}function zt(){let e=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`.split(``),t=Array(36),n=0,r,i;for(i=0;i<36;i++)i===8||i===13||i===18||i===23?t[i]=`-`:i===14?t[i]=`4`:(n<=2&&(n=33554432+Math.random()*16777216|0),r=n&15,n>>=4,t[i]=e[i===19?r&3|8:r]);return t.join(``)}class Bt{offset=void 0;constructor(e){this.offset=e}getOffset(){return this.offset??0}setOffset(e){this.offset=e}now(){return Date.now()+(this.offset??0)}date(e=new Date){return e.setTime(e.getTime()+(this.offset??0)),e}addServerTime(e,t){let n=e-Date.now()-t/2;if(Math.abs(n)<1e3){this.offset=0;return}if(this.offset===void 0)this.offset=Math.round(n);else{let e=.2;this.offset=Math.round(e*n+(1-e)*this.offset)}}}import{PlaybackState as Vt}from"@vkontakte/videoplayer-core/evergreen";import{Observable as Ht,Subscription as Ut,ValueSubject as Wt,Subject as Gt,fromEvent as Kt,isNullable as qt,map as Jt,merge as J,filter as Yt,filterChanged as Xt,getWindow as Zt}from"@vkontakte/videoplayer-shared/evergreen";var Qt=(e,t,n)=>new Ht(r=>{let i=new Ut,a,o=new Wt(void 0),s;i.add(e.info.isLive$.pipe(Xt()).subscribe(t=>{s&&(s.unsubscribe(),o.next(void 0)),a=void 0,s=t?e.info.liveTime$.pipe(Jt(e=>e&&e/1e3)).subscribe(o):e.info.position$.subscribe(o),i.add(s)}));let{playing$:c,paused$:l,ended$:u,looped$:d}=e.events,f=e.events.willSeek$.pipe(Yt(()=>e.info.playbackState$.getValue()===Vt.PLAYING)),p=e.events.seeked$.pipe(Yt(()=>e.info.playbackState$.getValue()===Vt.PLAYING)),m=e.info.isStalled$.pipe(Yt(e=>e)),h=!1,g=new Gt;i.add(f.subscribe(()=>{h||g.next(),h=!0})).add(p.subscribe(()=>h=!1));let _=J(Kt(Zt(),`beforeunload`),e.events.willDestruct$),v=e=>{a=e},y=e=>{let t=a;if(a=void 0,!(qt(t)||qt(e)||!isFinite(t)||!isFinite(e))){if(Math.round(e*1e3)<=Math.round(t*1e3)){a=e;return}r.next({from:t,to:e})}},b=new Gt,x=new Gt,S=()=>n.exactTime?e.info.isLive$.getValue()?e.getExactLiveTime():e.getExactTime():o.getValue()??0,C=J(c,p,b).pipe(Jt(()=>S())),ee=J(d,J(l,g,_,u,x,m).pipe(Jt(()=>S()))),te=t.started$&&t.ended$?J(C,t.ended$):C,w=t.started$&&t.ended$?J(ee,t.started$):ee;if(i.add(te.subscribe(v)).add(w.subscribe(y)),n.heartbeatInterval&&isFinite(n.heartbeatInterval)){let e=[],t=()=>{x.next(),b.next()};i.add(te.subscribe(()=>{let r=Zt().setTimeout(t,n.heartbeatInterval);e.push(r)})).add(w.subscribe(()=>{e.forEach(e=>{Zt().clearTimeout(e)}),e=[]}))}return i});import{Subscription as $t}from"@vkontakte/videoplayer-core/evergreen";import{Observable as en,merge as tn}from"@vkontakte/videoplayer-shared/evergreen";var nn=(e,t)=>new en(n=>{let r=new $t;return r.add(tn(e.info.position$,e.info.liveTime$).subscribe(()=>{let e=t.getTotalViewTime();e>=t.targetDuration&&(n.next({target_duration:t.targetDuration,current_tvt:e}),r.unsubscribe())})),r});import{Subscription as rn}from"@vkontakte/videoplayer-core/evergreen";import{Observable as an,filter as on,getWindow as sn}from"@vkontakte/videoplayer-shared/evergreen";var cn=(e,{maxTimeWindow:t})=>new an(n=>{let r=new rn,i={maxBytesThreshold:100*1024*1024,minBytesThreshold:100*1024,maxTimeWindow:t,minTimeWindow:2e3},a={bytes:0,startTime:0,lastEmitTime:0,timeoutId:0},o=()=>{a.timeoutId&&=(sn().clearTimeout(a.timeoutId),null)},s=()=>{a.bytes=0,a.startTime=0,a.lastEmitTime=0,o()},c=e=>{if(a.bytes<i.minBytesThreshold||e-a.lastEmitTime<i.minTimeWindow&&a.lastEmitTime>0)return!1;let t=(a.startTime>0?e-a.startTime:0)>=i.maxTimeWindow,n=a.bytes>=i.maxBytesThreshold;return t||n},l=(e=!1)=>{let t=Date.now();if(!e&&!c(t))return;o();let r=a.startTime>0?t-a.startTime:Math.max(i.minTimeWindow,1),l=a.bytes/(r/1e3);n.next({download_bytes:Math.round(a.bytes),download_speed:Math.round(l)}),a.lastEmitTime=t,s()},u=()=>{if(o(),a.startTime>0&&a.bytes>=i.minBytesThreshold){let e=Date.now()-a.startTime,t=i.maxTimeWindow-e;t>100?a.timeoutId=sn().setTimeout(()=>{a.timeoutId=null,l()},t):t>0&&l()}};return r.add(e.info.httpDownloadMetrics$.pipe(on(e=>e!==void 0)).subscribe(e=>{let t=Date.now();a.startTime===0&&(a.startTime=t),a.bytes+=e.bytes,c(t)?l():u()})),r.add(()=>{if(o(),a.bytes>0){let e=Date.now(),t=a.startTime>0?e-a.startTime:i.minTimeWindow,r=a.bytes/(t/1e3);n.next({download_bytes:Math.round(a.bytes),download_speed:Math.round(r)})}s()}),r});import{Observable as ln,Subscription as un,merge as dn}from"@vkontakte/videoplayer-shared/evergreen";var fn=e=>new ln(t=>{let n=new un,r=0,i=1,a=0,o=!1,s=!1,c=()=>{if(!o)return;let e=Date.now();a+=(e-r)*i,r=e},l=()=>{(!o||s)&&(r=Date.now(),o=!0,s=!1)},u=()=>{o&&=(c(),!1)},d=()=>{o&&(c(),o=!1,s=!0)},f=e=>{o&&c(),i=e,r=Date.now()},{started$:p,playing$:m,paused$:h,willSeek$:g,ended$:_,willDestruct$:v}=e.events,{currentPlaybackRate$:y}=e.info;return n.add(g.subscribe(d)).add(dn(p,m).subscribe(l)).add(dn(h,_,v).subscribe(u)).add(y.subscribe(f)),t.next(()=>{let e=a;return o&&(e+=(Date.now()-r)*i),Math.round(e)}),n});import{Observable as pn,Subscription as mn,merge as hn}from"@vkontakte/videoplayer-shared/evergreen";var gn=(e,t)=>new pn(n=>{let r=new mn,i=0;return r.add(hn(e.info.position$,e.info.liveTime$).subscribe(()=>{let e=t.getTotalViewTime();e>i&&Math.floor(e/t.interval)>Math.floor(i/t.interval)&&(i=e,n.next())})),r});import{assertNever as _n,isNullable as vn}from"@vkontakte/videoplayer-shared/evergreen";import{HttpConnectionType as yn,Surface as Y,VideoFormat as X,VideoQuality as Z}from"@vkontakte/videoplayer-core/evergreen";var bn=e=>{if(!vn(e)){if(typeof e==`string`)return e;try{return JSON.stringify(e)}catch{return String(e)}}},xn=e=>e&&{[yn.HTTP1]:`http1`,[yn.HTTP2]:`http2`,[yn.QUIC]:`http3`}[e],Sn=e=>{if(e!==void 0)switch(e){case X.MPEG:return`MP4`;case X.DASH:case X.DASH_LIVE:return`DASH`;case X.DASH_SEP:return`DASH_SEP`;case X.DASH_ONDEMAND:return`ONDEMAND_DASH`;case X.HLS_ONDEMAND:return`ONDEMAND_HLS`;case X.HLS:case X.HLS_LIVE:return`HLS`;case X.HLS_FMP4:return`HLS_FMP4`;case X.DASH_WEBM:case X.DASH_LIVE_WEBM:return`WEBM`;case X.DASH_LIVE_CMAF:return`ONDEMAND_DASH_LIVE`;case X.HLS_LIVE_CMAF:return`ONDEMAND_HLS_LIVE`;case X.WEB_RTC_LIVE:return`WEBRTC`;case X.DASH_WEBM_AV1:return`AV1`;case X.DASH_STREAMS:return`MULTI_DASH`;default:return _n(e)}},Q=e=>{if(e!==void 0)switch(e){case Z.Q_144P:return`144p`;case Z.Q_240P:return`240p`;case Z.Q_360P:return`360p`;case Z.Q_480P:return`480p`;case Z.Q_720P:return`720p`;case Z.Q_1080P:return`1080p`;case Z.Q_1440P:return`1440p`;case Z.Q_2160P:return`2160p`;case Z.INVARIANT:case Z.Q_576P:case Z.Q_4320P:return`UNKNOWN`;default:return _n(e)}},Cn=e=>{if(e!==void 0)switch(e){case`MP4`:case`ONDEMAND_DASH`:case`ONDEMAND_DASH_LIVE`:case`ONDEMAND_HLS`:case`ONDEMAND_HLS_LIVE`:case`MULTI_DASH`:case`WEBM`:case`AV1`:return`vod`;case`DASH`:case`HLS`:case`HLS_FMP4`:case`WEBRTC`:return`live`;default:return}},$=(e,t,n)=>{if(e&&t)switch(e){case X.MPEG:return n&&t[e]&&t[e][n];default:return t[e]?.url}},wn=(e,t=!1)=>{if(t)return`minimal`;switch(e){case void 0:case Y.NONE:return;case Y.INLINE:return`inline`;case Y.FULLSCREEN:return`fullscreen`;case Y.SECOND_SCREEN:return`chromecast`;case Y.PIP:return`pip_external`}},Tn=e=>{switch(e){case void 0:return;case Y.INVISIBLE:return`background`;default:return`foreground`}},En=`_thin-one-stat_deviceId`,Dn=`2.2.0`,On=()=>{let e=new ft;return{subscription:e,subscribe:(t,n)=>{t&&e.add(t.subscribe(n))}}};class kn{apis=[];logger;config;subscription;lifecycleFlushSubscription;timeSynchronisation;statContext;deviceId;targetDuration;debugLogger=new rt;thinOneStatDebugLog=this.debugLogger.createComponentLog(`ThinOneStat`);eventNumber=1;isStarted;isSeeking;inBufferStarvation;firstByteManifestSent;firstMediaRequestSent;firstByteMediaSent;wasPaused;isLive;lastContentType;cdnHostname;isEmbed;embedHostname;connectionType;connectionReused;player;playerSize={width:0,height:0};currentSubtitle;userQuality;downloadQuality;downloadSpeed;networkType;uiEvents;playerSubscription;uiSubscription;adsSubscription;seekAction$=new pt(`unknown`);vsid$=new pt(void 0);isid$=new pt(void 0);errors$=new dt;getTotalViewTime=()=>0;constructor(e,t){this.statContext=e,this.config=bt(t.config??{}),this.subscription=new ft,this.config.synchronizeTime&&(this.timeSynchronisation=new Bt),this.subscription.add(this.errors$.subscribe(e=>{this.thinOneStatDebugLog({message:`[${e.category}] ${e.id}: ${e.message}`})}));let n=lt.get(En);this.statContext.deviceId?this.deviceId=this.statContext.deviceId:n?this.deviceId=n:(this.deviceId=zt(),lt.set(En,this.deviceId)),this.statContext.targetDuration?this.targetDuration=this.statContext.targetDuration:this.targetDuration=this.config.watchedNDefaultTargetDuration,this.resetViewSession(),t.useIsid&&this.isid$.next(t.isid??fe());let r=new jt({errors$:this.errors$,config:this.config,timeSynchronisation:this.timeSynchronisation});this.config.apiForticom&&this.apis.push(new Dt({config:this.config,apiTransport:r,errors$:this.errors$,deviceId:this.deviceId,refreshAuthToken:t.refreshAuthToken})),this.config.apiUvRest&&(t.getUvRestAuthToken?this.apis.push(new Ot({config:this.config,apiTransport:r,errors$:this.errors$,userId:this.statContext.userId,getAuthToken:t.getUvRestAuthToken})):this.errors$.next({id:`ThinOneStat:Init:MissingGetUvRestAuthToken`,category:B.WTF,message:`thinStatToUvRest enabled but getUvRestAuthToken callback not provided`})),this.logger=new Rt({config:this.config,debugLogger:this.debugLogger,apis:this.apis,errors$:this.errors$,userSalt:t.userSalt});let{isEmbed:i,topOrigin:a}=tt();this.isEmbed=i,this.embedHostname=a?new URL(a).hostname:void 0}authorize(e){this.apis.forEach(t=>{t.authorize(e).catch(()=>{})})}reportError(e){let t={error_severity:e.severity,error_category:this.mapErrorCategory(e.category),player_error_code:e.code,player_error_trace:e.trace,error_message:e.message,content_type:this.getCurrentContentType()};this.logError(t),e.severity===`critical`&&this.logCannotPlay(),this.logTelemetry(this.collectTelemetryData())}updateContext(e){this.statContext={...this.statContext,...e}}attachTo(e,t){this.playerSubscription&&(this.thinOneStatDebugLog({message:`Re-attaching to player, unsubscribing from previous`}),this.playerSubscription.unsubscribe());let n=new ft,r=(e,t)=>n.add(e.subscribe(t));r(fn(e),e=>{this.getTotalViewTime=e}),r(e.info.isLive$,e=>this.isLive=e),r(e.info.currentFormat$,e=>{let t=Sn(e);t&&(this.lastContentType=t)}),r(e.info.hostname$.pipe(z(e=>e!==void 0)),e=>{this.cdnHostname=e});let i;r(R({hostname:e.info.hostname$,connectionType:e.info.httpConnectionType$,connectionReused:e.info.httpConnectionReused$}).pipe(z(({hostname:e})=>e!==void 0),z(({connectionType:e})=>e!==void 0),z(({connectionReused:e})=>e!==void 0)),({hostname:e,connectionType:t,connectionReused:n})=>{if(i!==void 0&&i!==e){let r={cdn_host:e,connection_type:xn(t),connection_reused:n,content_type:this.getCurrentContentType()};this.logFailover(r),this.logTelemetry(this.collectTelemetryData())}this.cdnHostname=i=e}),r(e.info.httpConnectionType$,e=>{this.connectionType=xn(e)}),r(e.info.httpConnectionReused$,e=>{this.connectionReused=e}),r(Qt(e,t,{heartbeatInterval:this.config.watchCoverageHeartbeatInterval,exactTime:this.config.watchCoverageExactTime}),t=>{let n={watch_interval:`${Math.round(t.from*1e3)}-${Math.round(t.to*1e3)}`,in_history:!!this.statContext.inHistory,content_type:this.getCurrentContentType(),playback_quality:Q(e.info.currentQuality$.getValue()),recom_info:this.statContext.recomInfo};if(!e.info.isLive$.getValue())this.logWatchCoverage(n);else{let t=e.info.atLiveEdge$.getValue();this.logWatchCoverageLive({...n,live:!!t})}}),r(gn(e,{interval:this.statContext.telemetryInterval??this.config.telemetryInterval,getTotalViewTime:this.getTotalViewTime}),()=>{this.logTelemetry(this.collectTelemetryData())}),r(nn(e,{targetDuration:this.targetDuration,getTotalViewTime:this.getTotalViewTime}),e=>{this.logWatchedN(e)}),r(e.events.willReady$,()=>{let t={isid:this.isid$.getValue(),stream_profile:Cn(this.getCurrentContentType()),dpi:Math.round(this.statContext.dpi??96*V.display.pixelRatio),web_layout:this.statContext.isMobile||V.device.isMobile?`mobile`:`desktop`,preloaded:this.statContext.preload,navigation:this.statContext.navigation,recom_info:this.statContext.recomInfo};if(this.isEmbed&&(t.iframe_host=this.embedHostname??`unknown`),this.logStartSession(t),this.statContext.preload){let t=e.info.currentFormat$.getValue(),n=e.info.availableSources$.getValue(),r=e.info.currentBuffer$.getValue(),i=e.info.currentQuality$.getValue(),a={target_buffer_time:this.calcBufferTime(r),playback_url:$(t,n,i),playback_quality:Q(i)};this.logPreloadStarted(a)}}),r(R({manifestRequested$:e.events.manifestRequested$,connectionType:e.info.httpConnectionType$,connectionReused:e.info.httpConnectionReused$}).pipe(z(({connectionType:e})=>e!==void 0),z(({connectionReused:e})=>e!==void 0),ot()),()=>{let t={playback_url:$(e.info.currentFormat$.getValue(),e.info.availableSources$.getValue(),e.info.currentQuality$.getValue()),cdn_host:this.cdnHostname,connection_type:this.connectionType,connection_reused:this.connectionReused};this.logManifestRequest(t)}),r(R({firstBytesManifest:e.events.firstBytesManifest$,connectionType:e.info.httpConnectionType$,connectionReused:e.info.httpConnectionReused$}).pipe(ot()),()=>{if(this.firstByteManifestSent)return;this.firstByteManifestSent=!0;let t={playback_url:$(e.info.currentFormat$.getValue(),e.info.availableSources$.getValue(),e.info.currentQuality$.getValue()),cdn_host:this.cdnHostname,connection_type:this.connectionType,connection_reused:this.connectionReused};this.logFirstByteManifest(t)}),r(e.events.manifestReceived$,()=>{let t={playback_url:$(e.info.currentFormat$.getValue(),e.info.availableSources$.getValue(),e.info.currentQuality$.getValue()),cdn_host:this.cdnHostname,connection_type:this.connectionType,connection_reused:this.connectionReused};this.logManifestReceived(t)}),r(e.events.firstBytesRequested$,()=>{if(this.firstMediaRequestSent)return;this.firstMediaRequestSent=!0;let t={playback_url:$(e.info.currentFormat$.getValue(),e.info.availableSources$.getValue(),e.info.currentQuality$.getValue()),cdn_host:this.cdnHostname,connection_type:this.connectionType,connection_reused:this.connectionReused};this.logFirstMediaRequest(t)}),r(e.events.firstBytes$,()=>{if(this.firstByteMediaSent)return;this.firstByteMediaSent=!0;let t={playback_url:$(e.info.currentFormat$.getValue(),e.info.availableSources$.getValue(),e.info.currentQuality$.getValue()),cdn_host:this.cdnHostname,connection_type:this.connectionType,connection_reused:this.connectionReused};this.logFirstByteMedia(t)}),r(it(e.events.willStart$,e.events.looped$),e=>{e&&this.resetViewSession(),this.isStarted=!0}),r(e.events.started$,()=>{let t=e.info.currentBuffer$.getValue(),n=e.info.currentQuality$.getValue(),r=e.info.isAutoQualityEnabled$.getValue(),i=e.info.muted$.getValue(),a=e.info.volume$.getValue(),o=e.info.surface$.getValue(),s=e.info.availableTextTracks$.getValue(),c=e.info.currentTextTrack$.getValue(),l=e.info.currentAudioStream$.getValue(),u=e.info.currentPlaybackRate$.getValue(),d={playback_quality:Q(n),user_quality:r?`auto`:Q(n),player_width:Math.round(this.statContext.playerSize?.width??this.playerSize.width),player_height:Math.round(this.statContext.playerSize?.height??this.playerSize.height),muted:i,sound_volume:Math.round(a*100),buffer_time:this.calcBufferTime(t),mode:wn(o,this.statContext.isPreviewPlayerView),visibility:Tn(o),subtitles_enabled:c?!!c:this.currentSubtitle?.enabled,auto_subtitles:s.find(({id:e})=>e===c)?.isAuto??this.currentSubtitle?.auto,audio_track_lang:l?.language,playback_rate:u*100,recom_info:this.statContext.recomInfo};this.logPlaybackStarted(d),this.logTelemetry(this.collectTelemetryData())}),r(e.events.willStart$,()=>{this.logPlay()}),r(e.events.playing$,()=>{let t=e.info.currentBuffer$.getValue(),n={buffer_time:this.calcBufferTime(t)};this.logPlaying(n),this.inBufferStarvation=!1,this.wasPaused&&this.logResume()}),r(e.events.paused$,()=>{this.wasPaused=!0,this.logPause()}),r(e.events.ended$,()=>{this.logContentEndReached()}),r(e.events.willStop$,()=>{this.isStarted=!1,this.isSeeking=!1,this.inBufferStarvation=!1,this.logStop()}),r(it(e.events.fetcherRecoverableError$,e.events.fatalError$),()=>{this.statContext.preload&&this.logPreloadError()}),r(e.events.fetcherRecoverableError$,({id:e,category:t,data:n,message:r,httpCode:i,UVBackendErrorCode:a})=>{let o={error_severity:this.mapErrorSeverity(t),error_category:this.mapErrorCategory(t),player_error_code:e,player_error_trace:bn(n),http_error_code:i,uv_backend_error_code_subcode:a,error_message:r,content_type:this.getCurrentContentType()};this.logError(o),this.mapErrorSeverity(t)===`critical`&&this.logCannotPlay(),this.logTelemetry(this.collectTelemetryData())}),r(e.events.managedError$,({id:e,category:t,data:n,message:r,httpCode:i,UVBackendErrorCode:a})=>{let o={error_severity:this.mapErrorSeverity(t),error_category:this.mapErrorCategory(t),player_error_code:e,player_error_trace:bn(n),http_error_code:i,uv_backend_error_code_subcode:a,error_message:r,content_type:this.getCurrentContentType()};this.logError(o),this.logTelemetry(this.collectTelemetryData())}),r(e.events.fatalError$,({id:e,category:t,data:n,message:r,httpCode:i,UVBackendErrorCode:a})=>{let o={error_severity:`critical`,error_category:this.mapErrorCategory(t),player_error_code:e,player_error_trace:bn(n),http_error_code:i,uv_backend_error_code_subcode:a,error_message:r,content_type:this.getCurrentContentType()};this.logError(o),this.logCannotPlay(),this.logTelemetry(this.collectTelemetryData())}),r(R({connectionType:e.info.httpConnectionType$,connectionReused:e.info.httpConnectionReused$,connectionMetrics:e.info.httpConnectionMetrics$}).pipe(z(({connectionReused:e})=>e!==void 0),z(({connectionMetrics:e})=>e!==void 0),at((e,t)=>e.connectionType===t.connectionType)),({connectionMetrics:t})=>{let n=e.info.currentFormat$.getValue(),r=e.info.availableSources$.getValue(),i=e.info.currentQuality$.getValue(),a=e.info.rttEstimation$.getValue();this.networkType=this.statContext.networkType??t?.networkType;let o=t?.dnsResolveTime,s=t?.tcpHandshakeTime,c=t?.tlsHandshakeTime,l={playback_url:$(n,r,i),cdn_host:this.cdnHostname,connection_type:this.connectionType,connection_reused:this.connectionReused,rtt:a?Math.round(a):void 0,network_type:this.networkType,dns_resolve_time:o?Math.round(o):void 0,tcp_handshake_time:s?Math.round(s):void 0,tls_handshake_time:c?Math.round(c):void 0};this.logConnectionEstablished(l)}),r(cn(e,{maxTimeWindow:this.config.downloadBytesMaxTime}),e=>{this.downloadSpeed=e.download_speed,this.logDownloadBytes(e)}),r(e.events.firstFrame$,()=>{this.logFirstVideoFrameDecoded()}),r(e.events.willSeek$,()=>{this.isSeeking=!0;let e={seek_type:this.seekAction$.getValue()};this.isStarted&&this.logSeeking(e)}),r(e.events.seeked$,()=>{this.isSeeking=!1;let e={seek_type:this.seekAction$.getValue()};this.isStarted&&this.logSeeked(e),this.seekAction$.next(`unknown`)}),r(e.info.stallStartTime$,t=>{if(t<=0){this.inBufferStarvation=!1;return}this.inBufferStarvation||(this.inBufferStarvation=!0,this.logBufferStarvation({buffer_time:this.calcBufferTime(e.info.currentBuffer$.getValue())}),this.logTelemetry(this.collectTelemetryData()))}),r(e.info.currentBuffer$.pipe(z(e=>!!this.calcBufferTime(e)),ot()),e=>{let t=this.calcBufferTime(e);if(this.statContext.preload){let e={buffer_time:t};this.logPreloadEnded(e)}this.logReady({buffer_time:t})});let a;r(R({videoStream:e.info.currentVideoStream$,audioStream:e.info.currentAudioStream$,quality:e.info.currentQuality$}).pipe(z(({videoStream:e,audioStream:t})=>e!==void 0&&t!==void 0),z(({quality:e})=>e!==void 0)),({videoStream:t,audioStream:n,quality:r})=>{if(a!==r){if(this.userQuality=e.info.isAutoQualityEnabled$.getValue()?`auto`:Q(r),this.downloadQuality=Q(r),this.isStarted){let e=t?.codec,r=n?.codec,i={user_quality:this.userQuality,playback_quality:Q(a),download_quality:this.downloadQuality,codec_info:this.genCodecInfo(e,r)};this.logQualityChanged(i)}a=r}});let o,s;return r(e.info.surface$,e=>{let t=wn(e,this.statContext.isPreviewPlayerView);t&&!this.uiEvents&&this.isStarted&&this.logModeChanged({mode:t}),s=Tn(e),o!==s&&(this.isStarted&&this.logVisibilityChanged({visibility:s}),o=Tn(e))}),r(R({muted:e.info.muted$,volume:e.info.volume$}).pipe(ct(300)),({muted:e,volume:t})=>{if(this.isStarted){let n={muted:e,sound_volume:Math.round(t*100)};this.logSoundChanged(n)}}),r(e.info.currentFormat$.pipe(z(e=>e!==void 0),st(1)),e=>{let t={content_type:Sn(e),cdn_host:this.cdnHostname,connection_type:this.connectionType,connection_reused:this.connectionReused};this.logContentTypeChange(t)}),r(e.info.currentAudioStream$.pipe(z(e=>e!==void 0),st(1)),e=>{let t={audio_track_lang:e.language,codec_info:e.codec};this.logAudioTrackSwitched(t)}),r(e.info.currentVideoStream$.pipe(z(e=>e!==void 0),st(1)),e=>{let t={hdr:e.hdr,codec_info:e.codec};this.logVideoTrackSwitched(t)}),this.player=e,this.playerSubscription=n,this.resubscribeLifecycleFlush(),this.subscription.add(n),n}attachToUi(e){this.uiSubscription&&(this.thinOneStatDebugLog({message:`Re-attaching to UI, unsubscribing from previous`}),this.uiSubscription.unsubscribe()),this.uiEvents=e;let{subscribe:t,subscription:n}=On();t(e.actionSeek$,this.seekAction$),t(e.playerSize$,({width:e,height:t})=>{e&&t&&(this.playerSize={width:e,height:t},this.isStarted&&this.logViewPortChanged({player_width:Math.round(e),player_height:Math.round(t)}))}),t(e.isLoaderVisible$,e=>{if(!e){this.inBufferStarvation=!1;return}this.isStarted&&(this.logShowLoader(),!(this.isSeeking||this.inBufferStarvation||!this.player)&&(this.inBufferStarvation=!0,this.logBufferStarvation({buffer_time:this.calcBufferTime(this.player.info.currentBuffer$.getValue())}),this.logTelemetry(this.collectTelemetryData())))}),t(e.actionSubtitlesSwitched$,e=>{if(this.currentSubtitle={...e},this.isStarted){let t={subtitles_enabled:e.enabled,subtitles_track_lang:e.lang,auto_subtitles:e.auto};this.logSubtitlesSwitched(t)}});let{surface$:r}=Je(this.uiEvents,t,this.player);return t(r,e=>{this.isStarted&&this.logModeChanged({mode:wn(e)})}),t(e.actionQuality$,e=>{let t=e=>Object.values(ht).includes(e),n=this.player?.info.currentVideoStream$.getValue()?.codec,r=this.player?.info.currentAudioStream$.getValue()?.codec,i={user_quality:t(e)?`auto`:Q(e),playback_quality:Q(this.player?.info.currentQuality$.getValue()),download_quality:t(e)?Q(this.player?.info.currentQuality$?.getValue()):Q(e),codec_info:this.genCodecInfo(n,r)};this.logQualityChangeRequested(i)}),this.uiSubscription=n,this.resubscribeLifecycleFlush(),this.subscription.add(n),n}attachToAds(e){this.adsSubscription&&(this.thinOneStatDebugLog({message:`Re-attaching to ads, unsubscribing from previous`}),this.adsSubscription.unsubscribe());let{subscription:t,subscribe:n}=On();return n(e.init$,e=>{let t={slot:e};this.logAdvConfiguration(t)}),n(e.slotRequested$,e=>{let t={adv_section:e};this.logAdvRequest(t)}),n(e.started$,e=>{let t={adv_section:e};this.logAdvBreakStarted(t)}),n(e.ended$,({section:e,ordIds:t})=>{let n={adv_section:e,erids:t.join(`,`)};this.logAdvBreakEnded(n)}),n(e.error$,e=>{let t={error_message:e};this.logAdvError(t)}),this.adsSubscription=t,this.resubscribeLifecycleFlush(),this.subscription.add(t),t}getDeviceId(){return this.deviceId}resetViewSession(){this.thinOneStatDebugLog({message:`VSID reset`}),E.generateVSID(this.config.useVsid64),this.vsid$.next(E.getVSID()),this.eventNumber=0,this.firstByteManifestSent=!1,this.firstMediaRequestSent=!1,this.firstByteMediaSent=!1}async destroy(){this.thinOneStatDebugLog({message:`Destroying ThinOneStat`}),this.subscription.unsubscribe(),this.lifecycleFlushSubscription?.unsubscribe(),await this.logger.destroy(),this.apis.forEach(e=>e.destroy()),this.thinOneStatDebugLog({message:`ThinOneStat destroyed`})}calcBufferTime(e){return e?Math.round(((e.end??0)-(e.start??0))*1e3):void 0}mapErrorCategory(e){switch(e){case B.NETWORK:return`network`;case B.VIDEO_PIPELINE:return`video_pipeline`;case B.EXTERNAL_API:return`external_api`;case B.PARSER:return`parser`;case B.DOM:return`dom`;default:return`wtf`}}mapErrorSeverity(e){return B.FATAL===e?`critical`:`informative`}getCurrentContentType(){let e=Sn(this.player?.info.currentFormat$.getValue());if(e)return e;if(this.lastContentType)return this.lastContentType;let t=this.player?.info.availableSources$.getValue();if(!t)return;let n=Object.keys(t)[0];return Sn(n)}genCodecInfo(e,t){return e&&t?`${e},${t}`:void 0}getLatencyInfo(){let e=this.player?.info.atLiveEdge$.getValue(),t={client_time:Date.now(),live:e};return JSON.stringify(t)}collectTelemetryData(){if(!this.player)return{};let e=this.player.info.currentBuffer$.getValue(),t=this.player.experimental.element$.getValue(),n=0,r=0;t&&(n=t.getVideoPlaybackQuality().droppedVideoFrames,r=t.getVideoPlaybackQuality().totalVideoFrames);let i=this.getCurrentContentType(),a=this.player.info.currentVideoStream$.getValue()?.codec,o=this.player.info.currentAudioStream$.getValue()?.codec,s=this.player.info.videoBitrate$.getValue(),c=this.player.info.rttEstimation$.getValue();return{buffer_time:this.calcBufferTime(e),dropped_frames_count:n,rendered_frames_count:r,content_type:i,user_quality:this.userQuality,playback_quality:Q(this.player.info.currentQuality$.getValue()),download_quality:this.downloadQuality,codec_info:this.genCodecInfo(a,o),bandwidth_from_manifest:s?Math.round(s):void 0,cdn_host:this.cdnHostname,download_speed:this.downloadSpeed?Math.round(this.downloadSpeed):void 0,network_type:this.networkType,rtt:c?Math.round(c):void 0,latency:this.getLatencyInfo()}}isValidPlatform(e=``){return[`web:desktop`,`web:mobile`,`smart_tv`].includes(e)}createRequiredParams(e){let t=this.vsid$.getValue();et(t);let n=this.eventNumber++,r=((this.isLive?this.player?.info.liveTime$.getValue():this.player?.info.position$.getValue())??0)*1e3,i={vsid:t,uv_movie_id:this.statContext.movieId,event_name:e,client_time:Date.now(),application:this.statContext.application??`@vkontakte/videoplayer-statistics:${D}`,platform:this.isValidPlatform(this.statContext.platform)?this.statContext.platform:`web:${this.statContext.isMobile||V.device.isMobile?`mobile`:`desktop`}`,product:this.statContext.product,event_number:n,playback_position:Math.round(r),current_tvt:this.getTotalViewTime(),cdn_host:this.cdnHostname};for(let e of this.config.disabledParams)delete i[e];return i}createRequiredFatParams(){let e={stats_version:Dn,browser:this.statContext.browser??V.browser.current,browser_version:this.statContext.browserVersion??String(V.browser.currentVersion),os:this.statContext.os??V.device.os.name,os_version:this.statContext.osVersion??V.device.os.version,device_type:this.statContext.deviceType??(this.statContext.isMobile||V.device.isMobile?`mobile`:`desktop`),device_manufacturer:this.statContext.deviceManufacturer??V.device.details.vendor,device_model:this.statContext.deviceModel??V.device.details.model,navigation:this.statContext.navigation};for(let t of this.config.disabledParams)delete e[t];return e}log(e,t,n=!1){if(this.config.disabledEvents.includes(e))return;let r=this.createRequiredParams(e),i={};n&&(i=this.createRequiredFatParams()),this.logger.log({...r,...i,...t})}logWatchCoverage(e){this.log(`watch_coverage`,e,!0)}logWatchCoverageLive(e){this.log(`watch_coverage_live`,e,!0)}logWatchedN(e){this.log(`watched_n`,e,!0)}logStartSession(e){this.log(`start_session`,e,!0)}logPreloadStarted(e){this.log(`preload_started`,e)}logPreloadEnded(e){this.log(`preload_ended`,e)}logPreloadError(){this.log(`preload_error`)}logPlaybackStarted(e){this.log(`playback_started`,e,!0)}logPlay(){this.log(`play`)}logManifestRequest(e){this.log(`manifest_request`,e)}logFirstByteManifest(e){this.log(`first_byte_manifest`,e)}logFirstMediaRequest(e){this.log(`first_media_request`,e)}logFirstByteMedia(e){this.log(`first_byte_media`,e)}logManifestReceived(e){this.log(`manifest_received`,e)}logConnectionEstablished(e){this.log(`connection_established`,e)}logFirstVideoFrameDecoded(){this.log(`first_video_frame_decoded`)}logReady(e){this.log(`ready`,e)}logPlaying(e){this.log(`playing`,e)}logPause(){this.log(`pause`)}logResume(){this.log(`resume`)}logSeeking(e){this.log(`seeking`,e)}logSeeked(e){this.log(`seeked`,e)}logContentEndReached(){this.log(`content_end_reached`)}logStop(){this.log(`stop`)}logBufferStarvation(e){this.log(`buffer_starvation`,e)}logShowLoader(){this.log(`show_loader`)}logQualityChangeRequested(e){this.log(`quality_change_requested`,e)}logQualityChanged(e){this.log(`quality_changed`,e)}logCdnHostChanged(e){this.log(`cdn_host_changed`,e)}logViewPortChanged(e){this.log(`view_port_changed`,e)}logModeChanged(e){this.log(`mode_changed`,e)}logVisibilityChanged(e){this.log(`visibility_changed`,e)}logAudioTrackSwitched(e){this.log(`audio_track_switched`,e)}logVideoTrackSwitched(e){this.log(`video_track_switched`,e)}logSubtitlesSwitched(e){this.log(`subtitles_switched`,e)}logSoundChanged(e){this.log(`sound_changed`,e)}logFailover(e){this.log(`failover`,e)}logContentTypeChange(e){this.log(`content_type_change`,e)}logError(e){this.log(`error`,e,!0)}logCannotPlay(){this.log(`cannot_play`,{},!0)}logDownloadBytes(e){this.log(`download_bytes`,e)}logTelemetry(e){this.log(`telemetry`,e)}logAdvConfiguration(e){this.log(`adv_configuration`,e)}logAdvRequest(e){this.log(`adv_request`,e)}logAdvBreakStarted(e){this.log(`adv_break_started`,e)}logAdvBreakEnded(e){this.log(`adv_break_ended`,e)}logAdvError(e){this.log(`adv_error`,e)}resubscribeLifecycleFlush(){this.lifecycleFlushSubscription?.unsubscribe();let e=ut(),t=()=>{this.logger.flush({wantBeacon:!0,clearStorage:this.config.clearStorageAtUnload}).catch(()=>{})},n=new ft;n.add(nt(e,`beforeunload`).subscribe(t)),n.add(nt(e,`pagehide`).subscribe(t)),n.add(nt(e.document,`visibilitychange`).subscribe(e=>{e.target?.visibilityState===`hidden`&&t()})),this.lifecycleFlushSubscription=n}}import{PlaybackState as An,Subscription as jn}from"@vkontakte/videoplayer-core/evergreen";import{Logger as Mn}from"@vkontakte/videoplayer-shared/evergreen";class Nn{startTime=null;stopTime=null;accumulatedTime=0;get time(){return Math.floor(this.timeMs/1e3)}get timeMs(){return this.startTime===null?0:(this.stopTime??this.now())-this.startTime-this.accumulatedTime}get isRunning(){return this.startTime!==null&&this.stopTime===null}start(){this.isRunning||(this.stopTime===null?this.startTime=this.now():(this.accumulatedTime+=this.now()-this.stopTime,this.stopTime=null))}stop(){this.isRunning&&(this.stopTime=this.now())}reset(){this.startTime=null,this.stopTime=null,this.accumulatedTime=0}now(){return Date.now()}}var Pn=()=>window.Image?new Image:document.createElement(`img`);class Fn{params;position=0;started=!1;isActiveLive;heartbeatPixels=[];heartbeatLastTimeSent={};heartbeatInterval;heartbeatFirstTimeoutId;idleCallbackIds=[];log;stopwatch=new Nn;subscription=new jn;constructor(e){this.params=e,this.log=new Mn().createComponentLog(`MediascopePixel`)}attachTo(e){this.subscription.add(e.info.playbackState$.subscribe(e=>this.onPlaybackState(e))).add(e.info.position$.subscribe(e=>this.onPosition(e))).add(e.info.atLiveEdge$.subscribe(e=>this.isActiveLive=e)),this.subscription.add(e.events.willSeek$.subscribe(()=>this.onWillSeek())).add(e.events.seeked$.subscribe(()=>this.onSeeked())).add(e.events.ended$.subscribe(()=>this.onEnded()))}destroy(){this.stopwatch.reset(),this.subscription.unsubscribe(),window.clearTimeout(this.heartbeatFirstTimeoutId),this.idleCallbackIds.forEach(e=>window.cancelIdleCallback(e)),this.send(`stop`)}onPlaybackState(e){e===An.PLAYING?this.started?this.play():this.start():e===An.PAUSED&&this.pause()}start(){this.started=!0,this.stopwatch.start(),this.send(`start`),this.heartbeatPixels=this.prepareHeartbeatPixels(),this.heartbeatInterval=this.heartbeatPixels[0]?.interval;let e=this.heartbeatPixels[0]?.url,t=this.heartbeatPixels[0]?.delay;if(t!==void 0&&e)try{this.heartbeatFirstTimeoutId=window.setTimeout(()=>{this.sendHeartbeat(e)},t*1e3)}catch(e){this.log({message:e.message})}}play(){this.stopwatch.start(),this.send(`resume`)}pause(){this.stopwatch.stop(),this.send(`pause`)}onPosition(e){if(this.position=e,this.heartbeatInterval&&this.stopwatch.time!==0&&this.stopwatch.time%this.heartbeatInterval===0)for(let[e,{url:t}]of this.heartbeatPixels.entries())this.heartbeatLastTimeSent[e]!==this.stopwatch.time&&(this.heartbeatLastTimeSent[e]=this.stopwatch.time,this.sendHeartbeat(t))}onWillSeek(){this.started&&this.send(`stop`)}onSeeked(){this.started&&this.send(`start`)}onEnded(){this.stopwatch.stop(),this.send(`stop`)}validatePixels(e,t){return e?.filter(e=>e.event===t.event&&t.keys.every(t=>!!e[t]))}getFrameTimestamp(){let e;if(this.isActiveLive){let t=Math.floor(Math.random()*25)+5;e=Date.now()/1e3-t}else e=this.position||0;return Math.floor(e)}getUTC(){return Math.floor(Date.now()/1e3)}prepareUrl(e){return e.replace(`{@fts_fake_sec}`,String(this.getFrameTimestamp())).replace(`{@utc_sec}`,String(this.getUTC())).split(`&`).filter(e=>!/={@[a-zA-Z_]+}/.test(e)).join(`&`)}preparePixels(e){return this.validatePixels(this.params.pixels,{event:e,keys:[`url`]})}prepareHeartbeatPixels(){return this.validatePixels(this.params.pixels,{event:`heartbeat`,keys:[`url`,`interval`]})}call(e){try{this.idleCallbackIds.push(requestIdleCallback(()=>Pn().src=this.prepareUrl(e)))}catch(e){this.log({message:e.message})}}send(e){let t=this.preparePixels(e);for(let{url:e}of t)this.call(e)}sendHeartbeat(e){this.call(e)}}export{D as VERSION,$e as ThinOneStat,c as SeekAction,a as Quality,Qe as OneStat,Fn as MediascopePixel,l as InteractiveInterfaceClick,o as ContentType,s as ConnectionType,i as ApiEnv};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vkontakte/videoplayer-statistics",
3
- "version": "1.0.109-dev.eb086bcd9.0",
3
+ "version": "1.0.110-dev.0bbcbb01d.0",
4
4
  "author": "vk.com",
5
5
  "description": "Statistics library for vk.com videoplayer",
6
6
  "homepage": "https://vk.com",
@@ -42,7 +42,7 @@
42
42
  "**/*.d.ts"
43
43
  ],
44
44
  "dependencies": {
45
- "@vkontakte/videoplayer-core": "2.0.163-dev.eb086bcd9.0",
46
- "@vkontakte/videoplayer-shared": "1.0.92-dev.eb086bcd9.0"
45
+ "@vkontakte/videoplayer-core": "2.0.164-dev.0bbcbb01d.0",
46
+ "@vkontakte/videoplayer-shared": "1.0.93-dev.0bbcbb01d.0"
47
47
  }
48
48
  }
@@ -15,6 +15,7 @@ export interface IApiTransport {
15
15
  export default class ApiTransport implements IApiTransport {
16
16
  private apiKey;
17
17
  private apiBaseUrl;
18
+ private apiUvRestBaseUrl;
18
19
  private apiEnv;
19
20
  private timeSynchronisation?;
20
21
  private isApiBaseUrlFetched;
@@ -6,6 +6,8 @@ export interface IConfig {
6
6
  apiEnv: ApiEnv;
7
7
  apiKey: string;
8
8
  apiBaseUrl: string | null;
9
+ apiUvRestBaseUrl: string;
10
+ apiCollector: string;
9
11
  apiForticom: boolean;
10
12
  apiUvRest: boolean;
11
13
  requestRetryCount: number;
@@ -4,3 +4,5 @@ import { ApiEnv } from "./values";
4
4
  */
5
5
  export declare const API_KEY: string;
6
6
  export declare const API_BASE_URLS: Record<ApiEnv, string>;
7
+ export declare const UV_REST_BASE_URL: string;
8
+ export declare const API_COLLECTOR: string;
@@ -16,6 +16,7 @@ export declare class ApiTransport implements IApiTransport {
16
16
  private params;
17
17
  private apiKey;
18
18
  private apiBaseUrl;
19
+ private apiUvRestBaseUrl;
19
20
  private apiEnv;
20
21
  private resolvedApiBaseUrl;
21
22
  private resolveApiBaseUrlPromise;
@@ -1,4 +1,5 @@
1
1
  import type { IError, IObservable, ISubject, ISubscription, IValueObservable, IValueSubject, Milliseconds } from "@vkontakte/videoplayer-shared";
2
+ import { ErrorCategory } from "@vkontakte/videoplayer-shared";
2
3
  import type { IPlayer } from "@vkontakte/videoplayer-core";
3
4
  import type { IOptionalConfig } from "./config";
4
5
  import type { Mode, Quality, Visibility, ConnectionType, ContentType } from "./values";
@@ -16,6 +17,10 @@ export interface IThinOneStat {
16
17
  */
17
18
  authorize(authToken?: string): void;
18
19
  /**
20
+ * Сообщить об ошибке, возникшей вне core и UI
21
+ */
22
+ reportError(payload: IReportErrorPayload): void;
23
+ /**
19
24
  * Обновляет общие параметры событий
20
25
  */
21
26
  updateContext(context: Partial<IStatContext>): void;
@@ -249,6 +254,13 @@ export interface IErrorPayload {
249
254
  error_message?: string;
250
255
  content_type?: ContentType;
251
256
  }
257
+ export interface IReportErrorPayload {
258
+ severity: NonNullable<IErrorPayload["error_severity"]>;
259
+ category: ErrorCategory;
260
+ code: string;
261
+ message?: string;
262
+ trace?: string;
263
+ }
252
264
  export interface IDownloadBytesPayload {
253
265
  download_bytes?: number;
254
266
  download_speed?: number;
@@ -296,7 +308,7 @@ export declare class ThinOneStat implements IThinOneStat {
296
308
  private logger;
297
309
  private config;
298
310
  private subscription;
299
- private beforeunloadSubscription?;
311
+ private lifecycleFlushSubscription?;
300
312
  private timeSynchronisation?;
301
313
  private statContext;
302
314
  private deviceId;
@@ -305,8 +317,14 @@ export declare class ThinOneStat implements IThinOneStat {
305
317
  private thinOneStatDebugLog;
306
318
  private eventNumber;
307
319
  private isStarted?;
320
+ private isSeeking?;
321
+ private inBufferStarvation?;
322
+ private firstByteManifestSent?;
323
+ private firstMediaRequestSent?;
324
+ private firstByteMediaSent?;
308
325
  private wasPaused?;
309
326
  private isLive?;
327
+ private lastContentType?;
310
328
  private cdnHostname?;
311
329
  private isEmbed;
312
330
  private embedHostname?;
@@ -330,6 +348,7 @@ export declare class ThinOneStat implements IThinOneStat {
330
348
  getTotalViewTime: () => Milliseconds;
331
349
  constructor(statContext: IStatContext, params: IConstructorParams);
332
350
  authorize(authToken?: string): void;
351
+ reportError(payload: IReportErrorPayload): void;
333
352
  updateContext(newContext: Partial<IStatContext>): void;
334
353
  attachTo(player: IPlayer, adsEvents: IAdsEvents): ISubscription;
335
354
  attachToUi(events: IUIEvents): ISubscription;
@@ -338,6 +357,9 @@ export declare class ThinOneStat implements IThinOneStat {
338
357
  resetViewSession(): void;
339
358
  destroy(): Promise<void>;
340
359
  private calcBufferTime;
360
+ private mapErrorCategory;
361
+ private mapErrorSeverity;
362
+ private getCurrentContentType;
341
363
  private genCodecInfo;
342
364
  private getLatencyInfo;
343
365
  private collectTelemetryData;
@@ -392,5 +414,5 @@ export declare class ThinOneStat implements IThinOneStat {
392
414
  private logAdvBreakStarted;
393
415
  private logAdvBreakEnded;
394
416
  private logAdvError;
395
- private resubscribeBeforeunload;
417
+ private resubscribeLifecycleFlush;
396
418
  }
@@ -6,6 +6,7 @@ export interface IConfig {
6
6
  apiKey: string;
7
7
  apiEnv: ApiEnv;
8
8
  apiBaseUrl: string | null;
9
+ apiUvRestBaseUrl: string;
9
10
  apiForticom: boolean;
10
11
  apiUvRest: boolean;
11
12
  requestRetryCount: number;