@vkontakte/videoplayer-statistics 1.0.113-dev.9dd0ca0bc.0 → 1.0.113-dev.fc8d8316c.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.113-dev.9dd0ca0bc.0
3
- * Tue, 21 Jul 2026 06:24:51 GMT
2
+ * @vkontakte/videoplayer-statistics v1.0.113-dev.fc8d8316c.0
3
+ * Tue, 21 Jul 2026 11:40:40 GMT
4
4
  * https://st.mycdn.me/static/vkontakte-videoplayer/1-0-113/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:``},_={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 se,getWindow as ce}from"@vkontakte/videoplayer-shared/evergreen";import{Logger as le,detectEmbed 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 T{static vsid;static getVSID(){return T.vsid}static generateVSID(e){return T.vsid=e?fe():de(),T.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}};import{getWindow as me}from"@vkontakte/videoplayer-shared/evergreen";var he=async e=>{let t=me().crypto?.subtle;if(!t)return;let n=new TextEncoder().encode(e),r=await t.digest(`SHA-256`,n);return Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,`0`)).join(``)},E=`1.0.113-dev.9dd0ca0bc.0`;import{ValueSubject as ge,getExponentialDelay as _e,ErrorCategory as D,getWindow as O}from"@vkontakte/videoplayer-shared/evergreen";var ve=/Mobile|mini|Fennec|Android|iP(ad|od|hone)|opera (mini|mobi)/i;class ye{id=`forticom`;params;authToken;sessionKey;authorizePromise;refreshAuthTokenPromise;consequentAuthErrors=0;authorized$=new ge(!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=ve.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=_e(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&&(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 be{id=`uvrest`;authorized$=new ge(!1);params;statToken;authorizePromise;isDestroyed=!1;constructor(e){this.params=e}async authorize(){if(!this.isDestroyed)return 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=this.params.getAuthToken?await this.params.getAuthToken():await this.selfAuthorize();if(this.isDestroyed)return;if(!e){this.params.error$.next({id:`OneStat:UvRestApi:NoToken`,category:D.EXTERNAL_API,message:`No stat token obtained`});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 selfAuthorize(){let e=this.params.timeSynchronisation?.now()??Date.now(),t=this.params.userId===void 0?``:String(this.params.userId),n=this.params.config.apiKey,r=this.params.deviceId,i=await he(`${t}${n}${r}${e}`);if(!i){this.params.error$.next({id:`OneStat:UvRestApi:SignatureUnavailable`,category:D.WTF,message:`crypto.subtle is unavailable for self authorization`});return}return(await this.params.apiTransport.sendJsonRequest(`/uv/stat/token`,{userId:t,applicationId:n,deviceId:r},{"X-Signature-Timestamp":String(e),Signature:i}))?.token}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=ve.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 k,now as A,getWindow as xe}from"@vkontakte/videoplayer-shared/evergreen";class Se{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:k.NETWORK,message:`Unhandled resolve api base url error`,thrown:e}),g.vk_alias}finally{this.isApiBaseUrlFetched=!0}}sendBeacon(e,t,n){if(!xe().Blob||!xe().navigator.sendBeacon)return!1;let r=this._prepareQueryParams({method:e,queryParams:t,sessionKey:n}),i=xe().Blob,a=new i([r.toString()],{type:`application/x-www-form-urlencoded`});try{return xe().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.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: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}})},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=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 Ce,now as we,safeStorage as j,debounceFn as Te}from"@vkontakte/videoplayer-shared/evergreen";var Ee=e=>t=>t.timestamp+e>=we();class De{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=Te(()=>this.safeFlushQueue(a),this.params.config.firstFlushTime,{maxWait:this.params.config.firstFlushTime}),r=j.isPersistent()?this.params.config.flushMaxWait:0,i=Te(()=>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:Ce.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(Ee(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(Ee(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(Ee(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 Oe,Surface as M,VideoFormat as N,VideoQuality as P}from"@vkontakte/videoplayer-core/evergreen";import{assertNever as ke}from"@vkontakte/videoplayer-shared/evergreen";var Ae=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],je=e=>e&&{[Oe.HTTP1]:`http1`,[Oe.HTTP2]:`http2`,[Oe.QUIC]:`http3`}[e],Me=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 ke(e)}},Ne=(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 ke(e)}},Pe=e=>{switch(e){case`slow-2g`:return`poor`;case`2g`:return`poor`;case`3g`:return`good`;case`4g`:return`excellent`}};class Fe{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 Ie}from"@vkontakte/videoplayer-core/evergreen";import{filter as Le,filterChanged as Re,fromEvent as ze,isNullable as Be,map as Ve,merge as F,Observable as He,Subject as Ue,Subscription as We,ValueSubject as Ge}from"@vkontakte/videoplayer-shared/evergreen";var Ke=(e,t)=>new He(n=>{let r=new We,i=F(ze(window,`beforeunload`),e.events.willDestruct$),a=new Ge(void 0),o;r.add(e.info.isLive$.pipe(Re()).subscribe(t=>{o&&(o.unsubscribe(),a.next(void 0)),o=t?e.info.liveTime$.pipe(Ve(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(Le(()=>e.info.playbackState$.getValue()===Ie.PLAYING)),d=e.events.seeked$.pipe(Le(()=>e.info.playbackState$.getValue()===Ie.PLAYING)),f=!1,p=new Ue;r.add(u.subscribe(()=>{f||p.next(),f=!0})),r.add(d.subscribe(()=>f=!1));let m=new Ue,h=new Ue,g=()=>t.watchCoverageExactTime?e.info.isLive$.getValue()?e.getExactLiveTime():e.getExactTime():a.getValue()??0,_=e.info.stallStartTime$.pipe(Re(),Le(e=>e>0)),v=F(s,d,m).pipe(Ve(()=>g())),y=F(l,F(c,p,i,h,_).pipe(Ve(()=>g()))),b,x=e=>{b=e},S=e=>{let t=e;Be(b)||b===t||Be(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 I}from"@vkontakte/videoplayer-core/evergreen";import{debounce as qe,filterChanged as Je,Subject as Ye}from"@vkontakte/videoplayer-shared/evergreen";var Xe=({uiEvents:e,initExternalSubscribers:t,subscribe:n,player:r})=>{let i=new Ye;t(i.pipe(qe(0),Je()));let a=!1,o=!1,s=!1;n(e.inPiP$,e=>{a=e,i.next(e?I.PIP:o?I.FULLSCREEN:s?I.INLINE:void 0)}),n(e.inFullscreen$,e=>{o=e,i.next(e?I.FULLSCREEN:a?I.PIP:s?I.INLINE:void 0)}),r&&n(r.info.surface$,e=>{switch(e){case I.SECOND_SCREEN:case I.INVISIBLE:case I.NONE:case I.INLINE:!o&&!a&&(e===I.INLINE&&(s=!0),i.next(e));break}})},Ze=`_one-stat_deviceId`,Qe=(e,t)=>e&&t?`${e}_${t}`:e??t,$e=()=>{let e=new oe;return{subscription:e,subscribe:(t,n)=>{t&&e.add(t.subscribe(n))}}};class et{apis;logger;config;subscription=new oe;beforeunloadSubscription;timeSynchronisation;debugLogger=new le;oneStatDebugLog=this.debugLogger.createComponentLog(`onestat`);loopCounter=0;disabled=!1;experimental;get vsid$(){return new se(T.getVSID())}isid$=new se(void 0);zenUid$=new se(void 0);statContext;isEmbed;embedParent;uiEvents;player;seekAction$=new se(`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 Fe);let n=new ae;this.experimental={error$:n};let r=ie.get(Ze);this.statContext.deviceId?this.deviceId=this.statContext.deviceId:r?this.deviceId=r:(this.deviceId=y(),ie.set(Ze,this.deviceId)),this.resetViewSession(),t.useIsid&&this.isid$.next(t.isid??fe()),this.zenUid$.next(t.zenUid);let i=new Se({config:this.config,error$:n,timeSynchronisation:this.timeSynchronisation}),a=[];this.config.apiForticom&&a.push(new ye({config:this.config,apiTransport:i,refreshAuthToken:t.refreshAuthToken,mobile:this.statContext.mobile??!1,deviceId:this.deviceId,error$:n,vktvVersion:t.vktvVersion})),this.config.apiUvRest&&a.push(new be({config:this.config,apiTransport:i,error$:n,userId:this.statContext.userId,deviceId:this.deviceId,getAuthToken:t.getUvRestAuthToken,mobile:this.statContext.mobile??!1,vktvVersion:t.vktvVersion,timeSynchronisation:this.timeSynchronisation})),this.apis=a,this.logger=new De({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 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(Ke(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=Ae(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:Me(e)})),n(e.info.currentPlaybackRate$,e=>this.updateContext({rate: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:je(e)}),this.updateContext({connectionType:je(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:Ne(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}=$e();return this.player?(n(e.actionRewind$,()=>{this.player&&(this.resetViewSession(),this.logActionPlay({position:this.player.info.position$.getValue()}))}),n(e.actionSeek$,this.seekAction$),Xe({uiEvents:this.uiEvents,initExternalSubscribers:e=>{n(e,e=>{this.updateContext({mode:Ne(e,this.statContext.isPreviewPlayerView)})})},subscribe:n,player:this.player}),n(e.actionSetSubtitle$,e=>this.updateContext({subtitles:e?.split(`.`)[0]})),n(e.nextMovie$,e=>this.logNextMovie(e)),this.resubscribeBeforeunload(),this.subscription.add(t),t):t}attachToAds(e){let{subscription:t,subscribe:n}=$e();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}=$e();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)},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=ce().navigator.connection;e&&`onchange`in e&&`effectiveType`in e&&this.subscription.add(te(S(e,`change`),ne([`init`])).subscribe(()=>this.updateContext({network:Pe(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:Qe(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 tt={};r(tt,{VERSION:()=>E,ThinOneStat:()=>Mn,ActionSeekType:()=>vt});import{assertNonNullable as nt,detectEmbed as rt,fromEvent as it,Logger as at,merge as ot,combine as L,filter as R,filterChanged as st,once as ct,skip as lt,debounce as ut,safeStorage as dt,getWindow as ft,Subject as pt,Subscription as z,ValueSubject as mt,ErrorCategory as B}from"@vkontakte/videoplayer-shared/evergreen";import{clientChecker as V}from"@vkontakte/videoplayer-core/evergreen";import{fillWithDefault as ht}from"@vkontakte/videoplayer-shared/evergreen";var gt=[`play`,`manifest_request`,`first_byte_manifest`,`first_media_request`,`first_byte_media`,`first_video_frame_decoded`,`ready`,`playback_started`,`watched_n`],_t;(e=>{e.AUTO=`auto`,e.AUTO_POOR=`auto_poor`,e.AUTO_RICH=`auto_rich`})(_t||={});var vt;(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`})(vt||={});var yt=`CIOPGQJGDIHBABABA`,bt={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:``},xt={apiKey:yt,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},St=e=>ht(e,xt);import{ErrorCategory as H,ValueSubject as Ct}from"@vkontakte/videoplayer-shared/evergreen";function wt(e){let t=Error(`HTTP ${e.status}: ${e.statusText}`);return t.status=e.status,t.statusText=e.statusText,t.response=e,t}function Tt(){let e=Error(`Request timeout`);return e.isTimeout=!0,e}function Et(e){let t=Error(e.error_msg);return t.errorData=e,t}function Dt(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 Ot=e=>e.match(/^\d+\.\d+\.\d+/)?.[0]??e,kt=({application:e,platform:t,product:n,...r})=>r;class At{id=`forticom`;authorized$;params;authToken;sessionKey;authorizePromise;refreshAuthTokenPromise;isDestroyed=!1;constructor(e){this.params=e,this.authorized$=new Ct(!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=Dt(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=Dt(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=Dt(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.isDestroyed?void 0:this.executeAuthorize(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&&(e.session_data.auth_token=this.authToken,e.session_data.version=3),e}getClientVersion(){return Ot(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: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(kt)})}}destroy(){this.isDestroyed=!0,this.authorizePromise=void 0,this.refreshAuthTokenPromise=void 0,this.sessionKey=void 0,this.authorized$.next(!1)}}class jt{id=`uvrest`;authorized$;params;statToken;authorizePromise;isDestroyed=!1;constructor(e){this.params=e,this.authorized$=new Ct(!1)}async authorize(e){if(!this.isDestroyed)return 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=this.params.getAuthToken?await this.params.getAuthToken():await this.selfAuthorize();if(this.isDestroyed)return;if(!e){this.params.errors$.next({id:`ThinOneStat:UvRestApi:NoToken`,category:H.EXTERNAL_API,message:`No stat token obtained`});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 selfAuthorize(){let e=this.params.timeSynchronisation?.now()??Date.now(),t=this.params.userId===void 0?``:String(this.params.userId),n=this.params.config.apiKey,r=this.params.deviceId,i=await he(`${t}${n}${r}${e}`);if(!i){this.params.errors$.next({id:`ThinOneStat:UvRestApi:SignatureUnavailable`,category:H.WTF,message:`crypto.subtle is unavailable for self authorization`});return}return(await this.params.apiTransport.sendJsonRequest(`/uv/stat/token`,{userId:t,applicationId:n,deviceId:r},{"X-Signature-Timestamp":String(e),Signature:i}))?.token}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(kt)}}}import{now as U,getWindow as W,getExponentialDelay as Mt,isAbortError as Nt,ErrorCategory as G}from"@vkontakte/videoplayer-shared/evergreen";class Pt{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??bt[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 Tt();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 Tt();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),Nt(e)?Tt():e}}async processResponse(e,t){if(!e.ok){let t=wt(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 Et(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===bt.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}),bt.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:Mt(t,{start:this.retryConfig.baseDelay,max:this.retryConfig.maxDelay,factor:2,random:.2})}}import{ErrorCategory as Ft}from"@vkontakte/videoplayer-shared/evergreen";import{now as It,debounceFn as Lt,getWindow as K,safeStorage as q,ErrorCategory as J}from"@vkontakte/videoplayer-shared/evergreen";var Rt=e=>t=>(t.client_time??It())+e>=It();class zt{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=Lt(()=>this.safeFlush(),this.params.config.flushFirstTime,{maxWait:this.params.config.flushFirstTime});let t=q.isPersistent()?this.params.config.flushMaxWait:0;this.debouncedFlush=Lt(()=>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=q.isPersistent?.()??!1;return e||this.debugLog({message:`Storage not available`}),e}readFromStorage(){if(!this.isStorageAvailable())return{};try{let e=q.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:J.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 q.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:J.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:J.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(Rt(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:J.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:J.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(Rt(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:J.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:J.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:J.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:J.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 Bt{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 zt({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:Ft.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 Vt(){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 Ht{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 Ut}from"@vkontakte/videoplayer-core/evergreen";import{Observable as Wt,Subscription as Gt,ValueSubject as Kt,Subject as qt,fromEvent as Jt,isNullable as Yt,map as Xt,merge as Y,filter as Zt,filterChanged as Qt,getWindow as $t}from"@vkontakte/videoplayer-shared/evergreen";var en=(e,t,n)=>new Wt(r=>{let i=new Gt,a,o=new Kt(void 0),s;i.add(e.info.isLive$.pipe(Qt()).subscribe(t=>{s&&(s.unsubscribe(),o.next(void 0)),a=void 0,s=t?e.info.liveTime$.pipe(Xt(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(Zt(()=>e.info.playbackState$.getValue()===Ut.PLAYING)),p=e.events.seeked$.pipe(Zt(()=>e.info.playbackState$.getValue()===Ut.PLAYING)),m=e.info.isStalled$.pipe(Zt(e=>e)),h=!1,g=new qt;i.add(f.subscribe(()=>{h||g.next(),h=!0})).add(p.subscribe(()=>h=!1));let _=Y(Jt($t(),`beforeunload`),e.events.willDestruct$),v=e=>{a=e},y=e=>{let t=a;if(a=void 0,!(Yt(t)||Yt(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 qt,x=new qt,S=()=>n.exactTime?e.info.isLive$.getValue()?e.getExactLiveTime():e.getExactTime():o.getValue()??0,C=Y(c,p,b).pipe(Xt(()=>S())),ee=Y(d,Y(l,g,_,u,x,m).pipe(Xt(()=>S()))),te=t.started$&&t.ended$?Y(C,t.ended$):C,w=t.started$&&t.ended$?Y(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=$t().setTimeout(t,n.heartbeatInterval);e.push(r)})).add(w.subscribe(()=>{e.forEach(e=>{$t().clearTimeout(e)}),e=[]}))}return i});import{Subscription as tn}from"@vkontakte/videoplayer-core/evergreen";import{Observable as nn,merge as rn}from"@vkontakte/videoplayer-shared/evergreen";var an=(e,t)=>new nn(n=>{let r=new tn;return r.add(rn(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 on}from"@vkontakte/videoplayer-core/evergreen";import{Observable as sn,filter as cn,getWindow as ln}from"@vkontakte/videoplayer-shared/evergreen";var un=(e,{maxTimeWindow:t})=>new sn(n=>{let r=new on,i={maxBytesThreshold:100*1024*1024,minBytesThreshold:100*1024,maxTimeWindow:t,minTimeWindow:2e3},a={bytes:0,startTime:0,lastEmitTime:0,timeoutId:0},o=()=>{a.timeoutId&&=(ln().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=ln().setTimeout(()=>{a.timeoutId=null,l()},t):t>0&&l()}};return r.add(e.info.httpDownloadMetrics$.pipe(cn(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 dn,Subscription as fn,merge as pn}from"@vkontakte/videoplayer-shared/evergreen";var mn=e=>new dn(t=>{let n=new fn,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(pn(p,m).subscribe(l)).add(pn(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 hn,Subscription as gn,merge as _n}from"@vkontakte/videoplayer-shared/evergreen";var vn=(e,t)=>new hn(n=>{let r=new gn,i=0;return r.add(_n(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 yn,isNullable as bn}from"@vkontakte/videoplayer-shared/evergreen";import{HttpConnectionType as xn,Surface as X,VideoFormat as Z,VideoQuality as Q}from"@vkontakte/videoplayer-core/evergreen";var Sn=e=>{if(!bn(e)){if(typeof e==`string`)return e;try{return JSON.stringify(e)}catch{return String(e)}}},Cn=e=>e&&{[xn.HTTP1]:`http1`,[xn.HTTP2]:`http2`,[xn.QUIC]:`http3`}[e],wn=e=>{if(e!==void 0)switch(e){case Z.MPEG:return`MP4`;case Z.DASH:case Z.DASH_LIVE:return`DASH`;case Z.DASH_SEP:return`DASH_SEP`;case Z.DASH_ONDEMAND:return`ONDEMAND_DASH`;case Z.HLS_ONDEMAND:return`ONDEMAND_HLS`;case Z.HLS:case Z.HLS_LIVE:return`HLS`;case Z.HLS_FMP4:return`HLS_FMP4`;case Z.DASH_WEBM:case Z.DASH_LIVE_WEBM:return`WEBM`;case Z.DASH_LIVE_CMAF:return`ONDEMAND_DASH_LIVE`;case Z.HLS_LIVE_CMAF:return`ONDEMAND_HLS_LIVE`;case Z.WEB_RTC_LIVE:return`WEBRTC`;case Z.DASH_WEBM_AV1:return`AV1`;case Z.DASH_STREAMS:return`MULTI_DASH`;default:return yn(e)}},$=e=>{if(e!==void 0)switch(e){case Q.Q_144P:return`144p`;case Q.Q_240P:return`240p`;case Q.Q_360P:return`360p`;case Q.Q_480P:return`480p`;case Q.Q_720P:return`720p`;case Q.Q_1080P:return`1080p`;case Q.Q_1440P:return`1440p`;case Q.Q_2160P:return`2160p`;case Q.INVARIANT:case Q.Q_576P:case Q.Q_4320P:return`UNKNOWN`;default:return yn(e)}},Tn=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}},En=(e,t,n)=>{if(e&&t)switch(e){case Z.MPEG:return n&&t[e]&&t[e][n];default:return t[e]?.url}},Dn=(e,t=!1)=>{if(t)return`minimal`;switch(e){case void 0:case X.NONE:return;case X.INLINE:return`inline`;case X.FULLSCREEN:return`fullscreen`;case X.SECOND_SCREEN:return`chromecast`;case X.PIP:return`pip_external`}},On=e=>{switch(e){case void 0:return;case X.INVISIBLE:return`background`;default:return`foreground`}},kn=`_thin-one-stat_deviceId`,An=`2.2.0`,jn=()=>{let e=new z;return{subscription:e,subscribe:(t,n)=>{t&&e.add(t.subscribe(n))}}};class Mn{apis=[];logger;config;subscription;lifecycleFlushSubscription;timeSynchronisation;statContext;deviceId;targetDuration;debugLogger=new at;thinOneStatDebugLog=this.debugLogger.createComponentLog(`ThinOneStat`);onceEvents=new Set(gt);sentOnceEvents=new Set;eventNumber=1;isStarted;isSeeking;inBufferStarvation;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 mt(`unknown`);vsid$=new mt(void 0);isid$=new mt(void 0);errors$=new pt;getTotalViewTime=()=>0;constructor(e,t){this.statContext=e,this.config=St(t.config??{}),this.subscription=new z,this.config.synchronizeTime&&(this.timeSynchronisation=new Ht),this.subscription.add(this.errors$.subscribe(e=>{this.thinOneStatDebugLog({message:`[${e.category}] ${e.id}: ${e.message}`})}));let n=dt.get(kn);this.statContext.deviceId?this.deviceId=this.statContext.deviceId:n?this.deviceId=n:(this.deviceId=Vt(),dt.set(kn,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 Pt({errors$:this.errors$,config:this.config,timeSynchronisation:this.timeSynchronisation});this.config.apiForticom&&this.apis.push(new At({config:this.config,apiTransport:r,errors$:this.errors$,deviceId:this.deviceId,refreshAuthToken:t.refreshAuthToken})),this.config.apiUvRest&&this.apis.push(new jt({config:this.config,apiTransport:r,errors$:this.errors$,userId:this.statContext.userId,deviceId:this.deviceId,getAuthToken:t.getUvRestAuthToken,timeSynchronisation:this.timeSynchronisation})),this.logger=new Bt({config:this.config,debugLogger:this.debugLogger,apis:this.apis,errors$:this.errors$,userSalt:t.userSalt});let{isEmbed:i,topOrigin:a}=rt();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 z,r=(e,t)=>n.add(e.subscribe(t));r(mn(e),e=>{this.getTotalViewTime=e}),r(e.info.isLive$,e=>this.isLive=e),r(e.info.currentFormat$,e=>{let t=wn(e);t&&(this.lastContentType=t)});let i;r(e.info.hostname$.pipe(R(e=>e!==void 0),st()),e=>{if(i!==void 0&&i!==e){let t={cdn_host:e,connection_type:this.connectionType,connection_reused:this.connectionReused,content_type:this.getCurrentContentType()};this.logFailover(t),this.logTelemetry(this.collectTelemetryData())}this.cdnHostname=i=e}),r(e.info.httpConnectionType$,e=>{this.connectionType=Cn(e)}),r(e.info.httpConnectionReused$,e=>{this.connectionReused=e}),r(en(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:$(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(vn(e,{interval:this.statContext.telemetryInterval??this.config.telemetryInterval,getTotalViewTime:this.getTotalViewTime}),()=>{this.logTelemetry(this.collectTelemetryData())}),r(an(e,{targetDuration:this.targetDuration,getTotalViewTime:this.getTotalViewTime}),e=>{this.logWatchedN(e)}),r(e.events.willReady$,()=>{let t={isid:this.isid$.getValue(),stream_profile:Tn(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:En(t,n,i),playback_quality:$(i)};this.logPreloadStarted(a)}});let a=()=>({playback_url:En(e.info.currentFormat$.getValue(),e.info.availableSources$.getValue(),e.info.currentQuality$.getValue()),cdn_host:this.cdnHostname,connection_type:this.connectionType,connection_reused:this.connectionReused});r(L({manifestRequested$:e.events.manifestRequested$,connectionType:e.info.httpConnectionType$,connectionReused:e.info.httpConnectionReused$}).pipe(ct()),()=>{this.logManifestRequest(a())}),r(L({firstBytesManifest:e.events.firstBytesManifest$,connectionType:e.info.httpConnectionType$,connectionReused:e.info.httpConnectionReused$}).pipe(ct()),()=>{this.logFirstByteManifest(a())}),r(e.events.manifestReceived$,()=>{this.logManifestReceived(a())}),r(e.events.firstBytesRequested$,()=>{this.logFirstMediaRequest(a())}),r(e.events.firstBytes$,()=>{this.logFirstByteMedia(a())}),r(ot(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:$(n),user_quality:r?`auto`:$(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:Dn(o,this.statContext.isPreviewPlayerView),visibility:On(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(ot(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:Sn(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.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:Sn(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:Sn(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(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),st((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:En(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(un(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.isStarted||this.inBufferStarvation||(this.inBufferStarvation=!0,this.logBufferStarvation({buffer_time:this.calcBufferTime(e.info.currentBuffer$.getValue())}),this.logTelemetry(this.collectTelemetryData()))}),r(e.info.currentBuffer$.pipe(R(e=>!!this.calcBufferTime(e)),ct()),e=>{let t=this.calcBufferTime(e);if(this.statContext.preload){let e={buffer_time:t};this.logPreloadEnded(e)}this.logReady({buffer_time:t})});let o;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(o!==r){let i=e.info.isAutoQualityEnabled$.getValue();if(this.userQuality=i?`auto`:$(r),this.downloadQuality=$(r),this.isStarted){let e=t?.codec,r=n?.codec,i={user_quality:this.userQuality,playback_quality:$(o),download_quality:this.downloadQuality,codec_info:this.genCodecInfo(e,r)};this.logQualityChanged(i)}o=r}});let s,c;return r(e.info.surface$,e=>{let t=Dn(e,this.statContext.isPreviewPlayerView);t&&!this.uiEvents&&this.isStarted&&this.logModeChanged({mode:t}),c=On(e),s!==c&&(this.isStarted&&this.logVisibilityChanged({visibility:c}),s=On(e))}),r(L({muted:e.info.muted$,volume:e.info.volume$}).pipe(ut(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),lt(1)),e=>{let t={content_type:wn(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),lt(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),lt(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}=jn();return 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)}}),Xe({uiEvents:this.uiEvents,initExternalSubscribers:e=>{t(e,e=>{this.isStarted&&this.logModeChanged({mode:Dn(e)})})},subscribe:t,player:this.player}),t(e.actionQuality$,e=>{let t=e=>Object.values(_t).includes(e),n=this.player?.info.currentVideoStream$.getValue()?.codec,r=this.player?.info.currentAudioStream$.getValue()?.codec,i={user_quality:t(e)?`auto`:$(e),playback_quality:$(this.player?.info.currentQuality$.getValue()),download_quality:t(e)?$(this.player?.info.currentQuality$?.getValue()):$(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}=jn();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`}),T.generateVSID(this.config.useVsid64),this.vsid$.next(T.getVSID()),this.eventNumber=0,this.sentOnceEvents.clear()}async destroy(){this.thinOneStatDebugLog({message:`Destroying ThinOneStat`}),this.subscription.unsubscribe(),this.lifecycleFlushSubscription?.unsubscribe(),await this.logger.destroy(),this.apis.forEach(e=>e.destroy()),this.sentOnceEvents.clear(),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=wn(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 wn(n)}genCodecInfo(e,t){return e&&t?`${e},${t}`:void 0}getLatencyInfo(){let e=this.player?.info.atLiveEdge$.getValue();return JSON.stringify({client_time:Date.now(),live:e})}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:$(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();nt(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||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:An,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;if(this.onceEvents.has(e)){if(this.sentOnceEvents.has(e))return;this.sentOnceEvents.add(e)}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=ft(),t=()=>{this.logger.flush({wantBeacon:!0,clearStorage:this.config.clearStorageAtUnload}).catch(()=>{})},n=new z;n.add(it(e,`beforeunload`).subscribe(t)),n.add(it(e,`pagehide`).subscribe(t)),n.add(it(e.document,`visibilitychange`).subscribe(e=>{e.target?.visibilityState===`hidden`&&t()})),this.lifecycleFlushSubscription=n}}import{PlaybackState as Nn,Subscription as Pn}from"@vkontakte/videoplayer-core/evergreen";import{Logger as Fn}from"@vkontakte/videoplayer-shared/evergreen";class In{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 Ln=()=>window.Image?new Image:document.createElement(`img`);class Rn{params;position=0;started=!1;isActiveLive;heartbeatPixels=[];heartbeatLastTimeSent={};heartbeatInterval;heartbeatFirstTimeoutId;idleCallbackIds=[];log;stopwatch=new In;subscription=new Pn;constructor(e){this.params=e;let t=new Fn;this.log=t.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===Nn.PLAYING?this.started?this.play():this.start():e===Nn.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(()=>Ln().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,tt as ThinOneStat,c as SeekAction,a as Quality,et as OneStat,Rn 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=[`adv`],a;(e=>{e.PROD=`prod`,e.VK_ALIAS=`vk_alias`,e.VIDEOTEST=`videotest`,e.TEST=`test`,e.OKCDN=`okcdn`,e.AUTO=`auto`})(a||={});var o;(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`})(o||={});var s;(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`})(s||={});var c;(e=>{e.HTTP1=`http1`,e.HTTP2=`http2`,e.HTTP3=`http3`})(c||={});var l;(e=>{e.ADV=`adv`,e.COMMON=`common`})(l||={});var u;(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`})(u||={});var d;(e=>{e.GRAPH_SHOW=`iGraphShow`,e.GRAPH_HIDE=`iGraphHide`,e.NEXT_AREA=`iNextChapterArea`,e.NEXT_BUTTON=`iNextChapterBtn`,e.WATCH_AGAIN=`iWatchAgainBtn`})(d||={});var f={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`},p={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`},m={unknown:`un`,mobile:`m`,lowest:`ls`,low:`l`,medium:`md`,high:`h`,fullhd:`f`,quadhd:`q`,ultrahd:`u`},h={pip:`pi`,fullscreen:`fs`,external:`ex`,prefetch:`pr`,airplay:`ap`,chromecast:`cc`,invisible:`iv`,minimal:`minimal`};import{fillWithDefault as g}from"@vkontakte/videoplayer-shared/evergreen";var _=`CIOPGQJGDIHBABABA`,v={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:``},y={apiEnv:`vk_alias`,apiKey:_,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},b=e=>g(e,y);function ee(){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 x,combine as S,fromEvent as te,isNonNullable as C,isNullable as w,merge as ne,now as T,observableFrom as re,once as ie,safeStorage as ae,Subject as oe,Subscription as se,ValueSubject as E,getWindow as ce}from"@vkontakte/videoplayer-shared/evergreen";import{Logger as le,detectEmbed 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 D{static vsid;static getVSID(){return D.vsid}static generateVSID(e){return D.vsid=e?fe():de(),D.vsid}}var pe=e=>{let{operation:t,custom:n}=e,r=Object.fromEntries(Object.entries(n).map(([e,t])=>{let n=p[e]??e,r=t;return t&&(e===`mode`?r=h[t]??t:e===`quality`&&(r=m[t]??t)),[n,r]}));return{...e,operation:f[t]??t,custom:r}};import{getWindow as me}from"@vkontakte/videoplayer-shared/evergreen";var he=async e=>{let t=me().crypto?.subtle;if(!t)return;let n=new TextEncoder().encode(e),r=await t.digest(`SHA-256`,n);return Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,`0`)).join(``)},O=`1.0.113-dev.fc8d8316c.0`;import{ValueSubject as ge,getExponentialDelay as _e,ErrorCategory as k,getWindow as ve}from"@vkontakte/videoplayer-shared/evergreen";var ye=/Mobile|mini|Fennec|Android|iP(ad|od|hone)|opera (mini|mobi)/i;class be{id=`forticom`;params;authToken;sessionKey;authorizePromise;refreshAuthTokenPromise;consequentAuthErrors=0;authorized$=new ge(!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:k.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:k.EXTERNAL_API,message:`${t} error`,data:n});return}}};return i(e)}destroy(){ve().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:${O}`;if(this.params.config.useVKComIsMobileLogic){let{appVersion:e}=ve().navigator;n=ye.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=_e(this.consequentAuthErrors,this.params.config.backoff);return new Promise(t=>{this.backoffTimeoutId||=ve().setTimeout(()=>{this._authorize().then(t).catch(e=>this.params.error$.next({id:`AuthorizeBackoff`,category:k.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:O.split(`-`)[0],client_type:`SDK_JS`}};return this.authToken&&(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:k.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:k.EXTERNAL_API,message:`authorize error`,data:e}):this.params.error$.next({id:`AuthorizeUnknown`,category:k.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 xe{id=`uvrest`;authorized$=new ge(!1);params;statToken;authorizePromise;isDestroyed=!1;constructor(e){this.params=e}async authorize(){if(!this.isDestroyed)return 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:k.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=this.params.getAuthToken?await this.params.getAuthToken():await this.selfAuthorize();if(this.isDestroyed)return;if(!e){this.params.error$.next({id:`OneStat:UvRestApi:NoToken`,category:k.EXTERNAL_API,message:`No stat token obtained`});return}return this.statToken=e,this.statToken}catch(e){if(this.isDestroyed)return;this.params.error$.next({id:`OneStat:UvRestApi:AuthorizeFailed`,category:k.NETWORK,message:`Failed to get stat token`,thrown:e});return}}async selfAuthorize(){let e=this.params.timeSynchronisation?.now()??Date.now(),t=this.params.userId===void 0?``:String(this.params.userId),n=this.params.config.apiKey,r=this.params.deviceId,i=await he(`${t}${n}${r}${e}`);if(!i){this.params.error$.next({id:`OneStat:UvRestApi:SignatureUnavailable`,category:k.WTF,message:`crypto.subtle is unavailable for self authorization`});return}return(await this.params.apiTransport.sendJsonRequest(`/uv/stat/token`,{userId:t,applicationId:n,deviceId:r},{"X-Signature-Timestamp":String(e),Signature:i}))?.token}async handleLogRequestError(e){let t=e?.status;return t===401?(this.params.error$.next({id:`OneStat:UvRestApi:TokenExpired`,category:k.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:k.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:k.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:k.EXTERNAL_API,message:`Log request failed after token refresh`,thrown:e})}}buildBody(e){let t=`WEB`,n=!1,r=`@vkontakte/videoplayer-statistics:${O}`;if(this.params.config.useVKComIsMobileLogic){let{appVersion:e}=ve().navigator;n=ye.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 Se{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??v[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}),v.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 Ce,now as we,safeStorage as N,debounceFn as Te}from"@vkontakte/videoplayer-shared/evergreen";var Ee=e=>t=>t.timestamp+e>=we();class De{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=Te(()=>this.safeFlushQueue(a),this.params.config.firstFlushTime,{maxWait:this.params.config.firstFlushTime}),r=N.isPersistent()?this.params.config.flushMaxWait:0,i=Te(()=>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:Ce.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(Ee(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(Ee(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(Ee(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 Oe,Surface as P,VideoFormat as F,VideoQuality as I}from"@vkontakte/videoplayer-core/evergreen";import{assertNever as ke}from"@vkontakte/videoplayer-shared/evergreen";var Ae=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],je=e=>e&&{[Oe.HTTP1]:`http1`,[Oe.HTTP2]:`http2`,[Oe.QUIC]:`http3`}[e],Me=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 ke(e)}},Ne=(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 ke(e)}},Pe=e=>{switch(e){case`slow-2g`:return`poor`;case`2g`:return`poor`;case`3g`:return`good`;case`4g`:return`excellent`}};class Fe{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 Ie}from"@vkontakte/videoplayer-core/evergreen";import{filter as Le,filterChanged as Re,fromEvent as ze,isNullable as Be,map as Ve,merge as He,Observable as Ue,Subject as We,Subscription as Ge,ValueSubject as Ke}from"@vkontakte/videoplayer-shared/evergreen";var qe=(e,t)=>new Ue(n=>{let r=new Ge,i=He(ze(window,`beforeunload`),e.events.willDestruct$),a=new Ke(void 0),o;r.add(e.info.isLive$.pipe(Re()).subscribe(t=>{o&&(o.unsubscribe(),a.next(void 0)),o=t?e.info.liveTime$.pipe(Ve(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(Le(()=>e.info.playbackState$.getValue()===Ie.PLAYING)),d=e.events.seeked$.pipe(Le(()=>e.info.playbackState$.getValue()===Ie.PLAYING)),f=!1,p=new We;r.add(u.subscribe(()=>{f||p.next(),f=!0})),r.add(d.subscribe(()=>f=!1));let m=new We,h=new We,g=()=>t.watchCoverageExactTime?e.info.isLive$.getValue()?e.getExactLiveTime():e.getExactTime():a.getValue()??0,_=e.info.stallStartTime$.pipe(Re(),Le(e=>e>0)),v=He(s,d,m).pipe(Ve(()=>g())),y=He(l,He(c,p,i,h,_).pipe(Ve(()=>g()))),b,ee=e=>{b=e},x=e=>{let t=e;Be(b)||b===t||Be(t)||(n.next({from:b,to:t}),b=void 0)},S=()=>{h.next(),m.next()};if(r.add(v.subscribe(ee)),r.add(y.subscribe(x)),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(S,t.forceInterval)})),r.add(y.subscribe(()=>n())),r.add(()=>n())}else{let e=0;r.add(v.subscribe(()=>e=window.setTimeout(S,t.forceInterval))),r.add(y.subscribe(()=>window.clearTimeout(e)))}return r}),Je=new Set(i),Ye=e=>Je.has(e);import{Surface as L}from"@vkontakte/videoplayer-core/evergreen";import{debounce as Xe,filterChanged as Ze,Subject as Qe}from"@vkontakte/videoplayer-shared/evergreen";var $e=({uiEvents:e,initExternalSubscribers:t,subscribe:n,player:r})=>{let i=new Qe;t(i.pipe(Xe(0),Ze()));let a=!1,o=!1,s=!1;n(e.inPiP$,e=>{a=e,i.next(e?L.PIP:o?L.FULLSCREEN:s?L.INLINE:void 0)}),n(e.inFullscreen$,e=>{o=e,i.next(e?L.FULLSCREEN:a?L.PIP:s?L.INLINE:void 0)}),r&&n(r.info.surface$,e=>{switch(e){case L.SECOND_SCREEN:case L.INVISIBLE:case L.NONE:case L.INLINE:!o&&!a&&(e===L.INLINE&&(s=!0),i.next(e));break}})},et=`_one-stat_deviceId`,tt=(e,t)=>e&&t?`${e}_${t}`:e??t,nt=()=>{let e=new se;return{subscription:e,subscribe:(t,n)=>{t&&e.add(t.subscribe(n))}}};class rt{apis;logger;config;subscription=new se;beforeunloadSubscription;timeSynchronisation;debugLogger=new le;oneStatDebugLog=this.debugLogger.createComponentLog(`onestat`);loopCounter=0;disabled=!1;sessionMode=`common`;experimental;get vsid$(){return new E(D.getVSID())}isid$=new E(void 0);zenUid$=new E(void 0);statContext;isEmbed;embedParent;uiEvents;player;seekAction$=new E(`unknown`);deviceId;constructor(e,t){this.statContext=e,this.config=b(t.config??{}),C(t.apiEnv)&&(this.config.apiEnv=t.apiEnv),this.config.synchronizeTime&&(this.timeSynchronisation=new Fe);let n=new oe;this.experimental={error$:n};let r=ae.get(et);this.statContext.deviceId?this.deviceId=this.statContext.deviceId:r?this.deviceId=r:(this.deviceId=ee(),ae.set(et,this.deviceId)),this.resetViewSession(),t.useIsid&&this.isid$.next(t.isid??fe()),this.zenUid$.next(t.zenUid);let i=new Se({config:this.config,error$:n,timeSynchronisation:this.timeSynchronisation}),a=[];this.config.apiForticom&&a.push(new be({config:this.config,apiTransport:i,refreshAuthToken:t.refreshAuthToken,mobile:this.statContext.mobile??!1,deviceId:this.deviceId,error$:n,vktvVersion:t.vktvVersion})),this.config.apiUvRest&&a.push(new xe({config:this.config,apiTransport:i,error$:n,userId:this.statContext.userId,deviceId:this.deviceId,getAuthToken:t.getUvRestAuthToken,mobile:this.statContext.mobile??!1,vktvVersion:t.vktvVersion,timeSynchronisation:this.timeSynchronisation})),this.apis=a,this.logger=new De({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,C(r)&&(r={startedAt:T(),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:T()-r.startedAt,liveAtStall:r.liveAtStall}),r=void 0,s=!0}),n(e.events.seeked$,()=>{!s&&C(r)&&o&&(this.logEmptyBuffer({duration:T()-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(qe(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(T()-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=C(r)?T()-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=T(),this.logFirstBytes({time:e})}),n(e.events.willStart$,()=>a=T()),n(e.info.currentBuffer$,e=>{!o&&e&&e.end-e.start>0&&C(i)&&(this.logPlayerReady({duration:T()-i}),c())}),n(e.events.firstFrame$,()=>{C(i)&&!o&&(this.logPlayerReady({duration:T()-i}),c()),C(a)&&this.logFirstFrame({time:T()-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(S({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=Ae(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:Me(e)})),n(e.info.currentPlaybackRate$,e=>this.updateContext({rate: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:je(e)}),this.updateContext({connectionType:je(e)})}),n(e.info.httpConnectionReused$,e=>{w(this.statContext.firstConnectionReused)&&this.updateContext({firstConnectionReused:e}),this.updateContext({connectionReused:e})}),n(e.info.surface$,e=>{this.uiEvents||this.updateContext({mode:Ne(e,this.statContext.isPreviewPlayerView)})}),n(S({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}=nt();return this.player?(n(e.actionRewind$,()=>{this.player&&(this.resetViewSession(),this.logActionPlay({position:this.player.info.position$.getValue()}))}),n(e.actionSeek$,this.seekAction$),$e({uiEvents:this.uiEvents,initExternalSubscribers:e=>{n(e,e=>{this.updateContext({mode:Ne(e,this.statContext.isPreviewPlayerView)})})},subscribe:n,player:this.player}),n(e.actionSetSubtitle$,e=>this.updateContext({subtitles:e?.split(`.`)[0]})),n(e.nextMovie$,e=>this.logNextMovie(e)),this.resubscribeBeforeunload(),this.subscription.add(t),t):t}attachToAds(e){let{subscription:t,subscribe:n}=nt();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}=nt();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)))}setSessionMode(e){this.sessionMode=e,this.oneStatDebugLog({message:`session mode set to ${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`}),D.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=ce().navigator.connection;e&&`onchange`in e&&`effectiveType`in e&&this.subscription.add(ne(te(e,`change`),re([`init`])).subscribe(()=>this.updateContext({network:Pe(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=te(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.sessionMode===`adv`&&!Ye(e.operation)){this.oneStatDebugLog({message:`operation ${e.operation} skipped: adv mode`});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()??T(),a=this.vsid$.getValue();x(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||w(this.statContext.rate)?void 0:this.statContext.rate.toFixed(2),view_360:this.statContext.is3d?1:void 0,codec_info:tt(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 it={};r(it,{VERSION:()=>O,ThinOneStat:()=>Bn,SessionMode:()=>St,ActionSeekType:()=>Ct});import{assertNonNullable as at,detectEmbed as ot,fromEvent as st,Logger as ct,merge as lt,combine as R,filter as z,filterChanged as ut,once as dt,skip as ft,debounce as pt,safeStorage as mt,getWindow as ht,Subject as gt,Subscription as B,ValueSubject as _t,ErrorCategory as V}from"@vkontakte/videoplayer-shared/evergreen";import{clientChecker as H}from"@vkontakte/videoplayer-core/evergreen";import{fillWithDefault as vt}from"@vkontakte/videoplayer-shared/evergreen";var yt=[`adv_configuration`,`adv_request`,`adv_break_started`,`adv_break_ended`,`adv_error`],bt=[`play`,`manifest_request`,`first_byte_manifest`,`first_media_request`,`first_byte_media`,`first_video_frame_decoded`,`ready`,`playback_started`,`watched_n`],xt;(e=>{e.AUTO=`auto`,e.AUTO_POOR=`auto_poor`,e.AUTO_RICH=`auto_rich`})(xt||={});var St;(e=>{e.ADV=`adv`,e.COMMON=`common`})(St||={});var Ct;(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`})(Ct||={});var wt=`CIOPGQJGDIHBABABA`,Tt={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:``},Et={apiKey:wt,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},Dt=e=>vt(e,Et);import{ErrorCategory as U,ValueSubject as Ot}from"@vkontakte/videoplayer-shared/evergreen";function kt(e){let t=Error(`HTTP ${e.status}: ${e.statusText}`);return t.status=e.status,t.statusText=e.statusText,t.response=e,t}function At(){let e=Error(`Request timeout`);return e.isTimeout=!0,e}function jt(e){let t=Error(e.error_msg);return t.errorData=e,t}function Mt(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 Nt=e=>e.match(/^\d+\.\d+\.\d+/)?.[0]??e,Pt=({application:e,platform:t,product:n,...r})=>r;class Ft{id=`forticom`;authorized$;params;authToken;sessionKey;authorizePromise;refreshAuthTokenPromise;isDestroyed=!1;constructor(e){this.params=e,this.authorized$=new Ot(!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:U.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=Mt(e);return r===void 0?(this.params.errors$.next({id:`ThinOneStat:Api:LogRequestUnknown`,category:U.NETWORK,message:`Unknown ${t} error`,thrown:e,data:{params:n}}),!1):this.isSessionExpiredError(r)?(this.params.errors$.next({id:`ThinOneStat:Api:LogRequestSessionError#${r}`,category:U.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:U.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:U.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:U.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=Mt(e);this.params.errors$.next({id:`ThinOneStat:Api:LogRequestRetryFailed#${t??`unknown`}`,category:U.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:U.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=Mt(t);if(n===401&&this.params.refreshAuthToken){if(this.params.errors$.next({id:`ThinOneStat:Api:AuthorizeAuthLogin`,category:U.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:U.EXTERNAL_API,message:`Authorization failed after ${e} attempts`,data:{error:t,code:n}});return}return this.authToken=await this.refreshAuthToken(),this.isDestroyed?void 0:this.executeAuthorize(e+1)}n?this.params.errors$.next({id:`ThinOneStat:Api:Authorize#${n}`,category:U.EXTERNAL_API,message:`Authorize error`,data:{error:t,code:n}}):this.params.errors$.next({id:`ThinOneStat:Api:AuthorizeUnknown`,category:U.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&&(e.session_data.auth_token=this.authToken,e.session_data.version=3),e}getClientVersion(){return Nt(O)}async refreshAuthToken(){if(this.params.refreshAuthToken)return this.refreshAuthTokenPromise||=this.params.refreshAuthToken().catch(e=>{throw this.params.errors$.next({id:`ThinOneStat:Api:RefreshAuthTokenFailed`,category:U.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(Pt)})}}destroy(){this.isDestroyed=!0,this.authorizePromise=void 0,this.refreshAuthTokenPromise=void 0,this.sessionKey=void 0,this.authorized$.next(!1)}}class It{id=`uvrest`;authorized$;params;statToken;authorizePromise;isDestroyed=!1;constructor(e){this.params=e,this.authorized$=new Ot(!1)}async authorize(e){if(!this.isDestroyed)return 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:U.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=this.params.getAuthToken?await this.params.getAuthToken():await this.selfAuthorize();if(this.isDestroyed)return;if(!e){this.params.errors$.next({id:`ThinOneStat:UvRestApi:NoToken`,category:U.EXTERNAL_API,message:`No stat token obtained`});return}return this.statToken=e,this.statToken}catch(e){if(this.isDestroyed)return;this.params.errors$.next({id:`ThinOneStat:UvRestApi:AuthorizeFailed`,category:U.NETWORK,message:`Failed to get stat token`,thrown:e});return}}async selfAuthorize(){let e=this.params.timeSynchronisation?.now()??Date.now(),t=this.params.userId===void 0?``:String(this.params.userId),n=this.params.config.apiKey,r=this.params.deviceId,i=await he(`${t}${n}${r}${e}`);if(!i){this.params.errors$.next({id:`ThinOneStat:UvRestApi:SignatureUnavailable`,category:U.WTF,message:`crypto.subtle is unavailable for self authorization`});return}return(await this.params.apiTransport.sendJsonRequest(`/uv/stat/token`,{userId:t,applicationId:n,deviceId:r},{"X-Signature-Timestamp":String(e),Signature:i}))?.token}async handleLogRequestError(e){let t=e?.status;return t===401?(this.params.errors$.next({id:`ThinOneStat:UvRestApi:TokenExpired`,category:U.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:U.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:U.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:U.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(Pt)}}}import{now as W,getWindow as G,getExponentialDelay as Lt,isAbortError as Rt,ErrorCategory as K}from"@vkontakte/videoplayer-shared/evergreen";class zt{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??Tt[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(!G().Blob||!G().navigator.sendBeacon)return!1;let r=this.resolvedApiBaseUrl??this.apiBaseUrl,i=this.prepareQueryParams({method:e,queryParams:t,sessionKey:n}),a=G().Blob,o=new a([i.toString()],{type:`application/x-www-form-urlencoded`});try{return G().navigator.sendBeacon(`${r}/fb.do`,o)}catch(n){this.params.errors$.next({id:`ThinOneStat:ApiTransport:sendBeacon`,category:K.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=W(),s=a??o+this.maxTotalRequestTime;if(W()>=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)&&W()<s){let c=this.getRetryDelay(a,i);if(W()+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??W(),c=await this.resolveApiBaseUrl(),l=o===void 0?this.fetchTimeout:o-W();if(l<=0)throw At();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:K.NETWORK,message:`Keepalive request failed`,thrown:t,data:{path:e}})})}catch(t){this.params.errors$.next({id:`ThinOneStat:ApiTransport:sendJsonBeacon`,category:K.NETWORK,message:`Failed to initiate keepalive request`,thrown:t,data:{path:e}})}}async sendJsonRequestWithRetry(e,t,n,r=1,i){let a=W(),o=i??a+this.maxTotalRequestTime;if(W()>=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)&&W()<o){let s=this.getRetryDelay(i,r);if(W()+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??W(),s=a===void 0?this.fetchTimeout:a-W();if(s<=0)throw At();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=G().setTimeout(()=>r.abort(),n);try{let n=await fetch(e,{...t,signal:r.signal});return G().clearTimeout(i),n}catch(e){throw G().clearTimeout(i),Rt(e)?At():e}}async processResponse(e,t){if(!e.ok){let t=kt(e),n=this.parseRetryAfter(e);throw n!==void 0&&(t.retryAfter=n),t}let n=new Date(e.headers.get(`date`)??``).getTime(),r=W()-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 jt(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:K.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=K.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:W()-r,maxAttempts:this.retryConfig.maxAttempts,attempts:a}})}handleJsonFinalError(e,t,n,r){this.params.errors$.next({id:`ThinOneStat:ApiTransport:sendJsonRequest`,category:K.NETWORK,message:n instanceof Error?n.message:`JSON request failed after retries`,thrown:n,data:{path:e,time:W()-t,maxAttempts:this.retryConfig.maxAttempts,attempts:r}})}sleep(e){return new Promise(t=>G().setTimeout(t,e))}resolveApiBaseUrl(){return this.apiEnv===`auto`?(this.resolveApiBaseUrlPromise||=this.fetchApiBaseUrl().then(e=>(e===Tt.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:K.NETWORK,message:`Unhandled resolve api base url error`,thrown:e}),Tt.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:Lt(t,{start:this.retryConfig.baseDelay,max:this.retryConfig.maxDelay,factor:2,random:.2})}}import{ErrorCategory as Bt}from"@vkontakte/videoplayer-shared/evergreen";import{now as Vt,debounceFn as Ht,getWindow as q,safeStorage as Ut,ErrorCategory as J}from"@vkontakte/videoplayer-shared/evergreen";var Wt=e=>t=>(t.client_time??Vt())+e>=Vt();class Gt{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=Ht(()=>this.safeFlush(),this.params.config.flushFirstTime,{maxWait:this.params.config.flushFirstTime});let t=Ut.isPersistent()?this.params.config.flushMaxWait:0;this.debouncedFlush=Ht(()=>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()},q().addEventListener(`online`,this.onlineListener),this.housekeepStorage()}isUrgent=e=>this.urgentEvents.includes(e.event_name);scheduleRetry(){this.retryFlushTimerId!==void 0&&q().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=q().setTimeout(()=>{this.retryFlushTimerId=void 0,this.safeFlush()},n)}cancelRetry(){this.retryFlushTimerId!==void 0&&(q().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=Ut.isPersistent?.()??!1;return e||this.debugLog({message:`Storage not available`}),e}readFromStorage(){if(!this.isStorageAvailable())return{};try{let e=Ut.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:J.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 Ut.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:J.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:J.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(Wt(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:J.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:J.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(Wt(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:J.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:J.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:J.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:J.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&&=(q().removeEventListener(`online`,this.onlineListener),void 0),this.subscription.unsubscribe(),this.firstFlush.cancel(),this.debouncedFlush.cancel(),this.flushPromise=null,this.debugLog({message:`Queue destroyed`})}}class Kt{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 Gt({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:Bt.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=[]}}var qt=new Set(yt),Jt=e=>qt.has(e);function Yt(){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 Xt{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 Zt}from"@vkontakte/videoplayer-core/evergreen";import{Observable as Qt,Subscription as $t,ValueSubject as en,Subject as tn,fromEvent as nn,isNullable as rn,map as an,merge as Y,filter as on,filterChanged as sn,getWindow as cn}from"@vkontakte/videoplayer-shared/evergreen";var ln=(e,t,n)=>new Qt(r=>{let i=new $t,a,o=new en(void 0),s;i.add(e.info.isLive$.pipe(sn()).subscribe(t=>{s&&(s.unsubscribe(),o.next(void 0)),a=void 0,s=t?e.info.liveTime$.pipe(an(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(on(()=>e.info.playbackState$.getValue()===Zt.PLAYING)),p=e.events.seeked$.pipe(on(()=>e.info.playbackState$.getValue()===Zt.PLAYING)),m=e.info.isStalled$.pipe(on(e=>e)),h=!1,g=new tn;i.add(f.subscribe(()=>{h||g.next(),h=!0})).add(p.subscribe(()=>h=!1));let _=Y(nn(cn(),`beforeunload`),e.events.willDestruct$),v=e=>{a=e},y=e=>{let t=a;if(a=void 0,!(rn(t)||rn(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 tn,ee=new tn,x=()=>n.exactTime?e.info.isLive$.getValue()?e.getExactLiveTime():e.getExactTime():o.getValue()??0,S=Y(c,p,b).pipe(an(()=>x())),te=Y(d,Y(l,g,_,u,ee,m).pipe(an(()=>x()))),C=t.started$&&t.ended$?Y(S,t.ended$):S,w=t.started$&&t.ended$?Y(te,t.started$):te;if(i.add(C.subscribe(v)).add(w.subscribe(y)),n.heartbeatInterval&&isFinite(n.heartbeatInterval)){let e=[],t=()=>{ee.next(),b.next()};i.add(C.subscribe(()=>{let r=cn().setTimeout(t,n.heartbeatInterval);e.push(r)})).add(w.subscribe(()=>{e.forEach(e=>{cn().clearTimeout(e)}),e=[]}))}return i});import{Subscription as un}from"@vkontakte/videoplayer-core/evergreen";import{Observable as dn,merge as fn}from"@vkontakte/videoplayer-shared/evergreen";var pn=(e,t)=>new dn(n=>{let r=new un;return r.add(fn(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 mn}from"@vkontakte/videoplayer-core/evergreen";import{Observable as hn,filter as gn,getWindow as _n}from"@vkontakte/videoplayer-shared/evergreen";var vn=(e,{maxTimeWindow:t})=>new hn(n=>{let r=new mn,i={maxBytesThreshold:100*1024*1024,minBytesThreshold:100*1024,maxTimeWindow:t,minTimeWindow:2e3},a={bytes:0,startTime:0,lastEmitTime:0,timeoutId:0},o=()=>{a.timeoutId&&=(_n().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=_n().setTimeout(()=>{a.timeoutId=null,l()},t):t>0&&l()}};return r.add(e.info.httpDownloadMetrics$.pipe(gn(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 yn,Subscription as bn,merge as xn}from"@vkontakte/videoplayer-shared/evergreen";var Sn=e=>new yn(t=>{let n=new bn,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(xn(p,m).subscribe(l)).add(xn(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 Cn,Subscription as wn,merge as Tn}from"@vkontakte/videoplayer-shared/evergreen";var En=(e,t)=>new Cn(n=>{let r=new wn,i=0;return r.add(Tn(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 Dn,isNullable as On}from"@vkontakte/videoplayer-shared/evergreen";import{HttpConnectionType as kn,Surface as X,VideoFormat as Z,VideoQuality as Q}from"@vkontakte/videoplayer-core/evergreen";var An=e=>{if(!On(e)){if(typeof e==`string`)return e;try{return JSON.stringify(e)}catch{return String(e)}}},jn=e=>e&&{[kn.HTTP1]:`http1`,[kn.HTTP2]:`http2`,[kn.QUIC]:`http3`}[e],Mn=e=>{if(e!==void 0)switch(e){case Z.MPEG:return`MP4`;case Z.DASH:case Z.DASH_LIVE:return`DASH`;case Z.DASH_SEP:return`DASH_SEP`;case Z.DASH_ONDEMAND:return`ONDEMAND_DASH`;case Z.HLS_ONDEMAND:return`ONDEMAND_HLS`;case Z.HLS:case Z.HLS_LIVE:return`HLS`;case Z.HLS_FMP4:return`HLS_FMP4`;case Z.DASH_WEBM:case Z.DASH_LIVE_WEBM:return`WEBM`;case Z.DASH_LIVE_CMAF:return`ONDEMAND_DASH_LIVE`;case Z.HLS_LIVE_CMAF:return`ONDEMAND_HLS_LIVE`;case Z.WEB_RTC_LIVE:return`WEBRTC`;case Z.DASH_WEBM_AV1:return`AV1`;case Z.DASH_STREAMS:return`MULTI_DASH`;default:return Dn(e)}},$=e=>{if(e!==void 0)switch(e){case Q.Q_144P:return`144p`;case Q.Q_240P:return`240p`;case Q.Q_360P:return`360p`;case Q.Q_480P:return`480p`;case Q.Q_720P:return`720p`;case Q.Q_1080P:return`1080p`;case Q.Q_1440P:return`1440p`;case Q.Q_2160P:return`2160p`;case Q.INVARIANT:case Q.Q_576P:case Q.Q_4320P:return`UNKNOWN`;default:return Dn(e)}},Nn=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}},Pn=(e,t,n)=>{if(e&&t)switch(e){case Z.MPEG:return n&&t[e]&&t[e][n];default:return t[e]?.url}},Fn=(e,t=!1)=>{if(t)return`minimal`;switch(e){case void 0:case X.NONE:return;case X.INLINE:return`inline`;case X.FULLSCREEN:return`fullscreen`;case X.SECOND_SCREEN:return`chromecast`;case X.PIP:return`pip_external`}},In=e=>{switch(e){case void 0:return;case X.INVISIBLE:return`background`;default:return`foreground`}},Ln=`_thin-one-stat_deviceId`,Rn=`2.2.0`,zn=()=>{let e=new B;return{subscription:e,subscribe:(t,n)=>{t&&e.add(t.subscribe(n))}}};class Bn{apis=[];logger;config;subscription;lifecycleFlushSubscription;timeSynchronisation;statContext;deviceId;targetDuration;debugLogger=new ct;thinOneStatDebugLog=this.debugLogger.createComponentLog(`ThinOneStat`);onceEvents=new Set(bt);sentOnceEvents=new Set;eventNumber=1;sessionMode=`common`;isStarted;isSeeking;inBufferStarvation;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 _t(`unknown`);vsid$=new _t(void 0);isid$=new _t(void 0);errors$=new gt;getTotalViewTime=()=>0;constructor(e,t){this.statContext=e,this.config=Dt(t.config??{}),this.subscription=new B,this.config.synchronizeTime&&(this.timeSynchronisation=new Xt),this.subscription.add(this.errors$.subscribe(e=>{this.thinOneStatDebugLog({message:`[${e.category}] ${e.id}: ${e.message}`})}));let n=mt.get(Ln);this.statContext.deviceId?this.deviceId=this.statContext.deviceId:n?this.deviceId=n:(this.deviceId=Yt(),mt.set(Ln,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 zt({errors$:this.errors$,config:this.config,timeSynchronisation:this.timeSynchronisation});this.config.apiForticom&&this.apis.push(new Ft({config:this.config,apiTransport:r,errors$:this.errors$,deviceId:this.deviceId,refreshAuthToken:t.refreshAuthToken})),this.config.apiUvRest&&this.apis.push(new It({config:this.config,apiTransport:r,errors$:this.errors$,userId:this.statContext.userId,deviceId:this.deviceId,getAuthToken:t.getUvRestAuthToken,timeSynchronisation:this.timeSynchronisation})),this.logger=new Kt({config:this.config,debugLogger:this.debugLogger,apis:this.apis,errors$:this.errors$,userSalt:t.userSalt});let{isEmbed:i,topOrigin:a}=ot();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 B,r=(e,t)=>n.add(e.subscribe(t));r(Sn(e),e=>{this.getTotalViewTime=e}),r(e.info.isLive$,e=>this.isLive=e),r(e.info.currentFormat$,e=>{let t=Mn(e);t&&(this.lastContentType=t)});let i;r(e.info.hostname$.pipe(z(e=>e!==void 0),ut()),e=>{if(i!==void 0&&i!==e){let t={cdn_host:e,connection_type:this.connectionType,connection_reused:this.connectionReused,content_type:this.getCurrentContentType()};this.logFailover(t),this.logTelemetry(this.collectTelemetryData())}this.cdnHostname=i=e}),r(e.info.httpConnectionType$,e=>{this.connectionType=jn(e)}),r(e.info.httpConnectionReused$,e=>{this.connectionReused=e}),r(ln(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:$(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(En(e,{interval:this.statContext.telemetryInterval??this.config.telemetryInterval,getTotalViewTime:this.getTotalViewTime}),()=>{this.logTelemetry(this.collectTelemetryData())}),r(pn(e,{targetDuration:this.targetDuration,getTotalViewTime:this.getTotalViewTime}),e=>{this.logWatchedN(e)}),r(e.events.willReady$,()=>{let t={isid:this.isid$.getValue(),stream_profile:Nn(this.getCurrentContentType()),dpi:Math.round(this.statContext.dpi??96*H.display.pixelRatio),web_layout:this.statContext.isMobile||H.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:Pn(t,n,i),playback_quality:$(i)};this.logPreloadStarted(a)}});let a=()=>({playback_url:Pn(e.info.currentFormat$.getValue(),e.info.availableSources$.getValue(),e.info.currentQuality$.getValue()),cdn_host:this.cdnHostname,connection_type:this.connectionType,connection_reused:this.connectionReused});r(R({manifestRequested$:e.events.manifestRequested$,connectionType:e.info.httpConnectionType$,connectionReused:e.info.httpConnectionReused$}).pipe(dt()),()=>{this.logManifestRequest(a())}),r(R({firstBytesManifest:e.events.firstBytesManifest$,connectionType:e.info.httpConnectionType$,connectionReused:e.info.httpConnectionReused$}).pipe(dt()),()=>{this.logFirstByteManifest(a())}),r(e.events.manifestReceived$,()=>{this.logManifestReceived(a())}),r(e.events.firstBytesRequested$,()=>{this.logFirstMediaRequest(a())}),r(e.events.firstBytes$,()=>{this.logFirstByteMedia(a())}),r(lt(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:$(n),user_quality:r?`auto`:$(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:Fn(o,this.statContext.isPreviewPlayerView),visibility:In(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(lt(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:An(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.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:An(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:An(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),ut((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:Pn(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(vn(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.isStarted||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)),dt()),e=>{let t=this.calcBufferTime(e);if(this.statContext.preload){let e={buffer_time:t};this.logPreloadEnded(e)}this.logReady({buffer_time:t})});let o;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(o!==r){let i=e.info.isAutoQualityEnabled$.getValue();if(this.userQuality=i?`auto`:$(r),this.downloadQuality=$(r),this.isStarted){let e=t?.codec,r=n?.codec,i={user_quality:this.userQuality,playback_quality:$(o),download_quality:this.downloadQuality,codec_info:this.genCodecInfo(e,r)};this.logQualityChanged(i)}o=r}});let s,c;return r(e.info.surface$,e=>{let t=Fn(e,this.statContext.isPreviewPlayerView);t&&!this.uiEvents&&this.isStarted&&this.logModeChanged({mode:t}),c=In(e),s!==c&&(this.isStarted&&this.logVisibilityChanged({visibility:c}),s=In(e))}),r(R({muted:e.info.muted$,volume:e.info.volume$}).pipe(pt(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),ft(1)),e=>{let t={content_type:Mn(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),ft(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),ft(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}=zn();return 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)}}),$e({uiEvents:this.uiEvents,initExternalSubscribers:e=>{t(e,e=>{this.isStarted&&this.logModeChanged({mode:Fn(e)})})},subscribe:t,player:this.player}),t(e.actionQuality$,e=>{let t=e=>Object.values(xt).includes(e),n=this.player?.info.currentVideoStream$.getValue()?.codec,r=this.player?.info.currentAudioStream$.getValue()?.codec,i={user_quality:t(e)?`auto`:$(e),playback_quality:$(this.player?.info.currentQuality$.getValue()),download_quality:t(e)?$(this.player?.info.currentQuality$?.getValue()):$(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}=zn();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}setSessionMode(e){this.sessionMode=e,this.thinOneStatDebugLog({message:`session mode set to ${e}`})}pause(){this.logger.pause(),this.thinOneStatDebugLog({message:`paused`})}resume(){this.logger.resume(),this.thinOneStatDebugLog({message:`resumed`})}getDeviceId(){return this.deviceId}resetViewSession(){this.thinOneStatDebugLog({message:`VSID reset`}),D.generateVSID(this.config.useVsid64),this.vsid$.next(D.getVSID()),this.eventNumber=0,this.sentOnceEvents.clear()}async destroy(){this.thinOneStatDebugLog({message:`Destroying ThinOneStat`}),this.subscription.unsubscribe(),this.lifecycleFlushSubscription?.unsubscribe(),await this.logger.destroy(),this.apis.forEach(e=>e.destroy()),this.sentOnceEvents.clear(),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 V.NETWORK:return`network`;case V.VIDEO_PIPELINE:return`video_pipeline`;case V.EXTERNAL_API:return`external_api`;case V.PARSER:return`parser`;case V.DOM:return`dom`;default:return`wtf`}}mapErrorSeverity(e){return V.FATAL===e?`critical`:`informative`}getCurrentContentType(){let e=Mn(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 Mn(n)}genCodecInfo(e,t){return e&&t?`${e},${t}`:void 0}getLatencyInfo(){let e=this.player?.info.atLiveEdge$.getValue();return JSON.stringify({client_time:Date.now(),live:e})}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:$(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();at(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:${O}`,platform:this.isValidPlatform(this.statContext.platform)?this.statContext.platform:`web:${this.statContext.isMobile||H.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:Rn,browser:this.statContext.browser??H.browser.current,browser_version:this.statContext.browserVersion??String(H.browser.currentVersion),os:this.statContext.os??H.device.os.name,os_version:this.statContext.osVersion??H.device.os.version,device_type:this.statContext.deviceType??(this.statContext.isMobile||H.device.isMobile?`mobile`:`desktop`),device_manufacturer:this.statContext.deviceManufacturer??H.device.details.vendor,device_model:this.statContext.deviceModel??H.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.sessionMode===`adv`&&!Jt(e)||this.config.disabledEvents.includes(e))return;if(this.onceEvents.has(e)){if(this.sentOnceEvents.has(e))return;this.sentOnceEvents.add(e)}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=ht(),t=()=>{this.logger.flush({wantBeacon:!0,clearStorage:this.config.clearStorageAtUnload}).catch(()=>{})},n=new B;n.add(st(e,`beforeunload`).subscribe(t)),n.add(st(e,`pagehide`).subscribe(t)),n.add(st(e.document,`visibilitychange`).subscribe(e=>{e.target?.visibilityState===`hidden`&&t()})),this.lifecycleFlushSubscription=n}}import{PlaybackState as Vn,Subscription as Hn}from"@vkontakte/videoplayer-core/evergreen";import{Logger as Un}from"@vkontakte/videoplayer-shared/evergreen";class Wn{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 Gn=()=>window.Image?new Image:document.createElement(`img`);class Kn{params;position=0;started=!1;isActiveLive;heartbeatPixels=[];heartbeatLastTimeSent={};heartbeatInterval;heartbeatFirstTimeoutId;idleCallbackIds=[];log;stopwatch=new Wn;subscription=new Hn;constructor(e){this.params=e;let t=new Un;this.log=t.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===Vn.PLAYING?this.started?this.play():this.start():e===Vn.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(()=>Gn().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{O as VERSION,it as ThinOneStat,l as SessionMode,u as SeekAction,o as Quality,rt as OneStat,Kn as MediascopePixel,d as InteractiveInterfaceClick,s as ContentType,c as ConnectionType,a as ApiEnv};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vkontakte/videoplayer-statistics",
3
- "version": "1.0.113-dev.9dd0ca0bc.0",
3
+ "version": "1.0.113-dev.fc8d8316c.0",
4
4
  "author": "vk.ru",
5
5
  "description": "Statistics library for vk.ru videoplayer",
6
6
  "homepage": "https://vk.ru",
@@ -42,7 +42,7 @@
42
42
  "**/*.d.ts"
43
43
  ],
44
44
  "dependencies": {
45
- "@vkontakte/videoplayer-core": "2.0.167-dev.9dd0ca0bc.0",
46
- "@vkontakte/videoplayer-shared": "1.0.96-dev.9dd0ca0bc.0"
45
+ "@vkontakte/videoplayer-core": "2.0.167-dev.fc8d8316c.0",
46
+ "@vkontakte/videoplayer-shared": "1.0.96-dev.fc8d8316c.0"
47
47
  }
48
48
  }
@@ -1,11 +1,11 @@
1
1
  import type { IOptionalConfig } from "./config";
2
+ import { type IPlayer } from "@vkontakte/videoplayer-core";
2
3
  import type { IError, IObservable, ISubscription, IValueObservable, Kbps, Milliseconds, Seconds } from "@vkontakte/videoplayer-shared";
3
4
  import { ValueSubject } from "@vkontakte/videoplayer-shared";
4
- import type { IOneStatPlayerAdapter } from "./playerAdapter";
5
5
  import type { ILogCustomData } from "./types";
6
6
  import type { IAdsEvents, IInteractiveEvents, IUIEvents } from "./uiEvents";
7
- import type { ApiEnv, ConnectionType, ContentType, Mode, Network, Quality } from "./values";
8
- import { SeekAction } from "./values";
7
+ import type { ApiEnv, ConnectionType, ContentType, SurfaceMode, Network, Quality } from "./values";
8
+ import { SeekAction, SessionMode } from "./values";
9
9
  export interface IOneStat {
10
10
  /**
11
11
  * Лучше авторизоваться сразу, чтобы избежать ситуации:
@@ -18,11 +18,15 @@ export interface IOneStat {
18
18
  * Обновляет общие параметры событий
19
19
  */
20
20
  updateContext(context: Partial<IStatContext>): void;
21
- attachTo(player: IOneStatPlayerAdapter): ISubscription;
21
+ attachTo(player: IPlayer): ISubscription;
22
22
  attachToUi(uiEvents: IUIEvents): ISubscription;
23
23
  attachToAds(adsEvents: IAdsEvents): ISubscription;
24
24
  attachToInteractive(interactiveEvents: IInteractiveEvents): ISubscription;
25
25
  /**
26
+ * Устанавливает режим отправки статистики
27
+ */
28
+ setSessionMode(mode: SessionMode): void;
29
+ /**
26
30
  * Ставит отправку событий на паузу. Они будут накапливаться до вызова `resume()`
27
31
  */
28
32
  pause(): void;
@@ -236,7 +240,7 @@ export interface IStatContext {
236
240
  firstConnectionReused?: boolean;
237
241
  network?: Network;
238
242
  cached?: boolean;
239
- mode?: Mode;
243
+ mode?: SurfaceMode;
240
244
  subtitles?: string;
241
245
  failover?: boolean;
242
246
  rate?: number;
@@ -281,6 +285,7 @@ export declare class OneStat implements IOneStat {
281
285
  private oneStatDebugLog;
282
286
  private loopCounter;
283
287
  private disabled;
288
+ private sessionMode;
284
289
  experimental: {
285
290
  error$: IObservable<IError>;
286
291
  };
@@ -296,11 +301,12 @@ export declare class OneStat implements IOneStat {
296
301
  private deviceId;
297
302
  constructor(statContext: IStatContext, params: IConstructorParams);
298
303
  updateContext(newContext: Partial<IStatContext>): void;
299
- attachTo(player: IOneStatPlayerAdapter): ISubscription;
304
+ attachTo(player: IPlayer): ISubscription;
300
305
  attachToUi(events: IUIEvents): ISubscription;
301
306
  attachToAds(adsEvents: IAdsEvents): ISubscription;
302
307
  attachToInteractive(interactiveEvents: IInteractiveEvents): ISubscription;
303
308
  authorize(authToken?: string): Promise<unknown>;
309
+ setSessionMode(mode: SessionMode): void;
304
310
  pause(): void;
305
311
  resume(): void;
306
312
  destroy(): void;
@@ -1,10 +1,9 @@
1
1
  import { OneStat } from "./OneStat";
2
2
  import type { IOneStat, IStatContext, IConstructorParams } from "./OneStat";
3
- import { ApiEnv, ContentType, Quality, ConnectionType, SeekAction, InteractiveInterfaceClick } from "./values";
3
+ import { ApiEnv, ContentType, Quality, ConnectionType, SeekAction, InteractiveInterfaceClick, SessionMode } from "./values";
4
4
  import type { InterfaceClick } from "./values";
5
5
  import type { IUIEvents, IAdsEvents, IInteractiveEvents } from "./uiEvents";
6
- import type { IOneStatPlayerAdapter } from "./playerAdapter";
7
- export { OneStat, ApiEnv, ContentType, Quality, ConnectionType, SeekAction, InteractiveInterfaceClick };
8
- export type { IOneStat, IStatContext, IConstructorParams, IUIEvents, IAdsEvents, IInteractiveEvents, InterfaceClick, IOneStatPlayerAdapter };
6
+ export { OneStat, ApiEnv, ContentType, Quality, ConnectionType, SeekAction, InteractiveInterfaceClick, SessionMode };
7
+ export type { IOneStat, IStatContext, IConstructorParams, IUIEvents, IAdsEvents, IInteractiveEvents, InterfaceClick };
9
8
  export { VERSION } from "../env";
10
9
  export type { IOptionalConfig } from "./config";
@@ -1,5 +1,5 @@
1
1
  import type { Kbps, Milliseconds, Seconds } from "@vkontakte/videoplayer-shared";
2
- import type { ConnectionType, ContentType, Flag, Mode, Network, Operation, Quality, StatType } from "./values";
2
+ import type { ConnectionType, ContentType, Flag, SurfaceMode, Network, Operation, Quality, StatType } from "./values";
3
3
  export interface ILogItem {
4
4
  operation: Operation;
5
5
  type: 1;
@@ -30,7 +30,7 @@ export interface ILogCustomData {
30
30
  cached_data?: Flag;
31
31
  live?: Flag;
32
32
  muted?: Flag;
33
- mode?: Mode;
33
+ mode?: SurfaceMode;
34
34
  subtitles?: string;
35
35
  failover?: Flag;
36
36
  download_speed?: Kbps;
@@ -1,7 +1,7 @@
1
1
  import { HttpConnectionType as CoreConnectionType, Surface, VideoFormat, VideoQuality } from "@vkontakte/videoplayer-core";
2
- import { ConnectionType as StatisticsConnectionType, ContentType, Mode, Network, Quality } from "../values";
2
+ import { ConnectionType as StatisticsConnectionType, ContentType, SurfaceMode, Network, Quality } from "../values";
3
3
  export declare const quality: (coreQuality: VideoQuality | undefined) => Quality | undefined;
4
4
  export declare const connectionType: (coreType: CoreConnectionType | undefined) => StatisticsConnectionType | undefined;
5
5
  export declare const contentType: (format: VideoFormat | undefined) => ContentType | undefined;
6
- export declare const surface: (surface: Surface | undefined, isPreviewPlayerView?: boolean) => Mode | undefined;
6
+ export declare const surface: (surface: Surface | undefined, isPreviewPlayerView?: boolean) => SurfaceMode | undefined;
7
7
  export declare const network: (effectiveType: "slow-2g" | "2g" | "3g" | "4g" | string) => Network | undefined;
@@ -0,0 +1,2 @@
1
+ import type { Operation, AdvOperation } from "../values";
2
+ export declare const isAdvOperation: (operation: Operation) => operation is AdvOperation;