@vkontakte/videoplayer-statistics 1.0.34 → 1.0.35-beta.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/es2015.cjs.js +4 -4
- package/es2015.esm.js +4 -4
- package/es2018.cjs.js +4 -4
- package/es2018.esm.js +4 -4
- package/esnext.cjs.js +4 -4
- package/esnext.esm.js +4 -4
- package/evergreen.esm.js +4 -4
- package/index.d.ts +155 -53
- package/package.json +3 -3
package/evergreen.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @vkontakte/videoplayer-statistics v1.0.
|
|
3
|
-
*
|
|
4
|
-
* https://st.mycdn.me/static/vkontakte-videoplayer/1-0-
|
|
2
|
+
* @vkontakte/videoplayer-statistics v1.0.35-beta.0
|
|
3
|
+
* Wed, 24 May 2023 14:18:45 GMT
|
|
4
|
+
* https://st.mycdn.me/static/vkontakte-videoplayer/1-0-35/doc/
|
|
5
5
|
*/
|
|
6
|
-
import{ValueSubject as $,getExponentialDelay as B,ErrorCategory as u,now as A,assertNever as U,Subscription as v,Subject as L,fromEvent as H,isNonNullable as k}from"@vkontakte/videoplayer-shared/esnext.esm.js";import{VideoQuality as c,HttpConnectionType as y,VideoFormat as n,ChromecastState as C}from"@vkontakte/videoplayer-core/esnext.esm.js";import D from"lodash/debounce.js";const w="_one-stat_",m=(()=>{try{const t=Date.now().toString(),e=window.localStorage;e.setItem(t,t);const i=e.getItem(t)===t;return e.removeItem(t),i?e:null}catch{return null}})();function M(t){const e=m?m.getItem(w+t):null;if(e===null)return null;try{return JSON.parse(e)}catch{return null}}function q(t,e){try{m&&m.setItem(w+t,JSON.stringify(e))}catch{}}function K(t){m&&m.removeItem(w+t)}var N={get(t){return M(t)||null},set(t,e){q(t,e)},remove(t){K(t)}};function z(){const t="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(""),e=new Array(36);let i=0,s,o;for(o=0;o<36;o++)o===8||o===13||o===18||o===23?e[o]="-":o===14?e[o]="4":(i<=2&&(i=33554432+Math.random()*16777216|0),s=i&15,i=i>>4,e[o]=t[o===19?s&3|8:s]);return e.join("")}var l;(function(t){t.PROD="prod",t.VK_ALIAS="vk_alias",t.VIDEOTEST="videotest",t.TEST="test",t.AUTO="auto"})(l||(l={}));var h;(function(t){t.Q144P="144",t.Q240P="240",t.Q360P="360",t.Q480P="480",t.Q720P="720",t.Q1080P="1080",t.Q1440P="1440",t.Q2160P="2160",t.Q4320P="4320",t.UNKNOWN="unknown"})(h||(h={}));var P;(function(t){t.CHROMECAST="chromecast",t.APPLE_TV="appletv",t.PIP="pip",t.HEADPHONES="externalHeadphones",t.SCREEN=""})(P||(P={}));var d;(function(t){t.MP4="mp4",t.DASH="dash",t.DASH_SEP="dash_sep",t.ONDEMAND_DASH="ondemand_dash",t.HLS="hls",t.ONDEMAND_HLS="ondemand_hls",t.WEBM="webm",t.RTMP="rtmp",t.UNKNOWN="unknown"})(d||(d={}));var T;(function(t){t.AUTO="auto",t.MANUAL=""})(T||(T={}));var _;(function(t){t.HTTP1="http1",t.HTTP2="http2",t.HTTP3="http3"})(_||(_={}));var E;(function(t){t[t.YES=1]="YES",t[t.NO=0]="NO"})(E||(E={}));const I="1.0.34",Q="evergreen.esm.js",W="CIOPGQJGDIHBABABA",O={[l.PROD]:"https://api.ok.ru",[l.VK_ALIAS]:"https://api.mycdn.me",[l.VIDEOTEST]:"https://videotestapi.ok.ru/api",[l.TEST]:"https://apitest.ok.ru",[l.AUTO]:""},F={start:1e3,factor:1.5,max:5*60*1e3,random:.1};var p;(function(t){t[t.PARAM_SESSION_EXPIRED=102]="PARAM_SESSION_EXPIRED",t[t.PARAM_SESSION_KEY=103]="PARAM_SESSION_KEY",t[t.PARAM_SIGNATURE=104]="PARAM_SIGNATURE",t[t.AUTH_LOGIN=401]="AUTH_LOGIN"})(p||(p={}));class V{params;uuid;authToken;sessionKey;authorizePromise;refreshAuthTokenPromise;consequentAuthErrors=0;authorized$=new $(!1);backoffTimeoutId;constructor(e){this.params=e;const i=N.get("uuid");i?this.uuid=String(i):(this.uuid=z(),N.set("uuid",this.uuid))}async authorize(e){return this.authToken=e??await this.refreshAuthToken(),this._authorizeWithBackoff()}logBeacon(e){const i="log.externalLog",s=this.createLogParams(e),o=this.sessionKey;if(!o)return;this.params.apiTransport.sendBeacon(i,s,o)||this.logRequest(e)}async logRequest(e){const i="log.externalLog",s=this.createLogParams(e),o=this.sessionKey??await this._authorizeWithBackoff();if(!o)return;const a=async(r,g=this.params.requestRetryCount)=>{try{return await this.params.apiTransport.sendRequest(i,s,o)}catch(f){if(!f||!("error_code"in f)){this.params.error$.next({id:"logRequestUnknown",category:u.NETWORK,message:`Unknown ${i} error`,thrown:f});return}const S=f?.error_code;switch(S){case p.PARAM_SESSION_EXPIRED:case p.PARAM_SESSION_KEY:case p.PARAM_SIGNATURE:return this.authorized$.next(!1),this.sessionKey=await this._authorizeWithBackoff(),g>0?a(r,g-1):void 0;case p.AUTH_LOGIN:return this.authorized$.next(!1),this.authToken=await this.refreshAuthToken(),this.sessionKey=await this._authorizeWithBackoff(),g>0?a(r,g-1):void 0;default:{this.params.error$.next({id:`LogRequest#${S}`,category:u.EXTERNAL_API,message:`${i} error`,data:f});return}}}};return a(e)}destroy(){window.clearTimeout(this.backoffTimeoutId),this.backoffTimeoutId=0}async refreshAuthToken(){if(this.params.refreshAuthToken)return this.refreshAuthTokenPromise||(this.refreshAuthTokenPromise=this.params.refreshAuthToken().finally(()=>{this.refreshAuthTokenPromise=void 0})),this.refreshAuthTokenPromise}createLogParams(e){return{collector:"ok.mobile.apps.video",data:JSON.stringify({application:`${Q}:${I}`,platform:"WEB",items:e.map(i=>({...i,time:0,type:1}))})}}_authorizeWithBackoff(){if(!this.consequentAuthErrors)return this._authorize();const e=B(this.consequentAuthErrors,F);return new Promise(i=>{this.backoffTimeoutId||(this.backoffTimeoutId=window.setTimeout(()=>{this._authorize().then(i).catch(s=>this.params.error$.next({id:"AuthorizeBackoff",category:u.NETWORK,message:"Otherwise unhandle errror in authrization",thrown:s})).finally(()=>this.backoffTimeoutId=0)},e))})}async _authorize(){if(this.authorizePromise)return this.authorizePromise;this.sessionKey=void 0,this.authorized$.next(!1);const e="auth.anonymLogin",i={session_data:{version:2,device_id:this.uuid,client_version:I.split("-")[0],client_type:"SDK_JS"}};return this.authToken!==void 0&&(i.session_data.auth_token=this.authToken,i.session_data.version=3),this.authorizePromise=this.params.apiTransport.sendRequest(e,i).then(s=>((!s||!s.session_key)&&this.params.error$.next({id:"AuthorizeFailed",category:u.EXTERNAL_API,message:"No session key",data:s}),this.sessionKey=s?.session_key??void 0,this.sessionKey)).catch(async s=>{this.sessionKey=void 0;const o=s?.error_code;switch(o){case p.AUTH_LOGIN:return this.authToken=await this.refreshAuthToken(),this._authorizeWithBackoff()}o?this.params.error$.next({id:`Authorize#${o}`,category:u.EXTERNAL_API,message:"authorize error",data:s}):this.params.error$.next({id:"AuthorizeUnknown",category:u.NETWORK,message:"authorize error",thrown:s})}).finally(()=>{this.authorizePromise=void 0,this.consequentAuthErrors=this.sessionKey?0:this.consequentAuthErrors+1,this.authorized$.next(this.sessionKey!==void 0)}),this.authorizePromise}}class G{apiKey;apiBaseUrl;apiEnv;timeSynchronisation;isApiBaseUrlFetched;params;constructor(e){this.params=e,this.apiKey=e.apiKey,this.apiEnv=e.apiEnv,this.apiBaseUrl=e.apiBaseUrl,this.timeSynchronisation=e.timeSynchronisation,this.isApiBaseUrlFetched=!1}async resolveApiBaseUrl(){if(this.apiEnv!==l.AUTO||this.isApiBaseUrlFetched)return this.apiBaseUrl;try{const e=atob("aHR0cHM6Ly9kbnMuZ29vZ2xlL3Jlc29sdmU/bmFtZT12aWRlby5fZW5kcG9pbnQub2sucnUmdHlwZT1UWFQ="),o=(await(await fetch(e,{method:"GET",mode:"cors",cache:"no-cache"})).json())?.Answer[0]?.data;if(!o)throw new Error("Wrong DNS response");return o}catch(e){return this.params.error$.next({id:"OneStat:ApiTransport:resolveApiBaseUrl",category:u.NETWORK,message:"Unhandled resolve api base url error",thrown:e}),O[l.VK_ALIAS]}finally{this.isApiBaseUrlFetched=!0}}sendBeacon(e,i,s){if(!window.Blob||!window.navigator.sendBeacon)return!1;const o=this._prepareQueryParams({method:e,queryParams:i,sessionKey:s}),a=new window.Blob([o.toString()],{type:"application/x-www-form-urlencoded"});try{return window.navigator.sendBeacon(`${this.apiBaseUrl}/fb.do`,a)}catch(r){this.params.error$.next({id:"OneStat:ApiTransport:sendBeacon",category:u.NETWORK,message:"Unhandled beacon error",thrown:r,data:{method:e,params:i}})}return!1}async sendRequest(e,i,s){const o=A(),a=r=>{if(r instanceof TypeError&&["Failed to fetch","NetworkError when attempting to fetch resource."].includes(r.message)){this.params.error$.next({id:"Network",category:u.NETWORK,message:"Request failed",thrown:r});return}this.params.error$.next({id:"OneStat:ApiTransport:sendRequest",category:u.NETWORK,message:"Unhandled request error",thrown:r,data:{method:e,params:i,sessionKey:s,time:A()-o}})};return this.apiBaseUrl=await this.resolveApiBaseUrl(),fetch(`${this.apiBaseUrl}/fb.do`,{method:"post",headers:{"Content-type":"application/x-www-form-urlencoded"},body:this._prepareQueryParams({method:e,queryParams:i,sessionKey:s})}).then(r=>{const g=Number(r.headers.get("content-length"))===0,f=new Date(r.headers.get("date")??"").getTime(),S=A()-o;if(isFinite(f)&&this.timeSynchronisation.addServerTime(f,S),!g)return r.json().then(b=>Object.prototype.hasOwnProperty.call(b,"error_msg")?Promise.reject(b):b,a)},a)}_prepareQueryParams(e){const i=new URLSearchParams({format:"JSON",method:e.method,application_key:this.apiKey});return e.sessionKey!==void 0&&i.append("session_key",e.sessionKey),Object.entries(e.queryParams).forEach(([s,o])=>i.append(s,typeof o=="string"?o:JSON.stringify(o))),i}}const x=3e3,j=x*5;class J{api;error$;requestQueue=[];subscription;isPaused=!1;debouncedFlush=D(()=>{try{this.flush()}catch(e){this.error$.next({id:"LoggerError",category:u.WTF,message:String(e)??"Unknown logger error",thrown:e})}},x,{maxWait:j});constructor(e){this.api=e.api,this.error$=e.error$,this.subscription=this.api.authorized$.subscribe(i=>{i&&this.debouncedFlush()})}log(e){this.requestQueue.push(e),this.isPaused||this.debouncedFlush()}flush(e=!1){this.requestQueue.length!==0&&(this.api.authorized$.getValue()?(e?this.api.logBeacon(this.requestQueue):this.api.logRequest(this.requestQueue),this.requestQueue=[]):this.api.authorize(),this.debouncedFlush.cancel())}pause(){this.isPaused=!0,this.debouncedFlush.cancel()}resume(){this.isPaused=!1,this.debouncedFlush()}destroy(){this.subscription.unsubscribe()}}class X{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,i){const s=Date.now(),o=e-s-i/2;if(Math.abs(o)<1e3){this.offset=0;return}this.offset===void 0?this.offset=Math.round(o):this.offset=Math.round(.2*o+(1-.2)*this.offset)}}const R=()=>Math.floor(Math.random()*2**32).toString(36).padStart(8,"0"),Y=t=>t&&{[c.INVARIANT]:h.UNKNOWN,[c.Q_144P]:h.Q144P,[c.Q_240P]:h.Q240P,[c.Q_360P]:h.Q360P,[c.Q_480P]:h.Q480P,[c.Q_720P]:h.Q720P,[c.Q_1080P]:h.Q1080P,[c.Q_1440P]:h.Q1440P,[c.Q_2160P]:h.Q2160P,[c.Q_4320P]:h.Q4320P}[t],Z=t=>t&&{[y.HTTP1]:_.HTTP1,[y.HTTP2]:_.HTTP2,[y.QUIC]:_.HTTP3}[t],ee=t=>{if(t!==void 0)switch(t){case n.MPEG:return d.MP4;case n.DASH:case n.DASH_LIVE:case n.DASH_LIVE_CMAF:return d.DASH;case n.DASH_SEP:return d.DASH_SEP;case n.DASH_ONDEMAND:return d.ONDEMAND_DASH;case n.DASH_WEBM:case n.DASH_LIVE_WEBM:return d.WEBM;case n.HLS:case n.HLS_LIVE:case n.HLS_LIVE_CMAF:return d.HLS;case n.HLS_ONDEMAND:return d.ONDEMAND_HLS;case n.WEB_RTC_LIVE:return d.RTMP;default:return U(t)}};class oe{api;logger;config;subscription=new v;timeSynchronisation=new X;experimental;statContext;vsid=R();fieldBlacklist=[];constructor(e,i){this.statContext=e,this.config={...i.config??{},requestRetryCount:1};const s=new L;this.experimental={error$:s};const o=new G({apiKey:W,apiBaseUrl:O[i.apiEnv],apiEnv:i.apiEnv,error$:s,timeSynchronisation:this.timeSynchronisation});this.api=new V({apiTransport:o,refreshAuthToken:i.refreshAuthToken,requestRetryCount:this.config.requestRetryCount,error$:s}),this.logger=new J({api:this.api,error$:s}),this.subscription.add(H(window,"beforeunload").subscribe(()=>this.logger.flush(!0)))}updateContext(e){this.statContext={...this.statContext,...e}}attachTo(e){let i;return new v().add(e.events.started$.subscribe(()=>{this.logStarted({position:e.info.position$.getValue()})})).add(e.events.looped$.subscribe(()=>{this.resetViewSession(),this.logStarted({position:e.info.position$.getValue()})})).add(e.events.seeked$.subscribe(()=>{this.logSeek()})).add(e.events.willPause$.subscribe(()=>{this.logPause({position:e.info.position$.getValue()})})).add(e.events.willResume$.subscribe(()=>{this.logPlay()})).add(e.events.managedError$.subscribe(({id:s})=>{this.logError({errorType:s})})).add(e.events.fatalError$.subscribe(({id:s})=>{this.logError({errorType:s})})).add(e.events.inited$.subscribe(()=>{this.logInited()})).add(e.events.canplay$.subscribe(s=>{this.logReady({time:s})})).add(e.events.firstBytes$.subscribe(s=>{this.logFirstBytes({time:s})})).add(e.events.firstFrame$.subscribe(s=>{this.logFirstFrame({time:s})})).add(e.events.watchCoverageRecord$.subscribe(s=>{this.logWatchCoverageRecord(s)})).add(e.events.watchCoverageLive$.subscribe(s=>{this.logWatchCoverageLive(s)})).add(e.info.isStalled$.subscribe(s=>{s?i=A():(k(i)&&this.logEmptyBuffer({duration:A()-i}),i=void 0)})).add(e.events.ended$.subscribe(()=>{const s=e.info.throughputEstimation$.getValue();k(s)&&this.logDownloadSpeed({speed:s/8})})).add(e.info.hostname$.subscribe(s=>{this.updateContext({cdnHostname:s})})).add(e.info.httpConnectionType$.subscribe(s=>{this.updateContext({connectionType:Z(s)})})).add(e.info.httpConnectionReused$.subscribe(s=>{this.updateContext({connectionReused:s})})).add(e.info.currentQuality$.subscribe(s=>{this.updateContext({quality:Y(s)})})).add(e.info.currentFormat$.subscribe(s=>{this.updateContext({contentType:ee(s)})})).add(e.info.chromecastState$.subscribe(s=>{this.updateContext({destination:s===C.CONNECTED?P.CHROMECAST:P.SCREEN})}))}authorize(e){return this.api.authorize(e)}pause(){this.logger.pause()}resume(){this.logger.resume()}destroy(){this.logger.flush(),this.subscription.unsubscribe(),this.api.destroy(),this.logger.destroy()}resetViewSession(){this.vsid=R()}setFieldBlacklist(e=[]){this.fieldBlacklist=e}logInited(){this.log({operation:"init"})}logReady(e){this.log({operation:"player_ready",param:String(e.time)})}logStarted(e){this.log({operation:"play",param:String(Math.round(e.position))})}logPlay(){this.log({operation:"play_toggle"})}logPause(e){this.log({operation:"pause",param:String(Math.round(e.position))})}logSeek(){this.log({operation:"seek"})}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:"error",param:e.errorType})}logWatchCoverageRecord(e){this.log({operation:"watch_coverage_record",param:`${e.start}-${e.end}`}),this.logger.flush(!0)}logWatchCoverageLive(e){const i=e.start+this.timeSynchronisation.getOffset(),s=e.end+this.timeSynchronisation.getOffset();this.log({operation:"watch_coverage_live",param:`${i}-${s}`}),this.logger.flush(!0)}logEmptyBuffer(e){this.log({operation:"empty_buffer",param:String(e.duration)})}logDownloadSpeed(e){this.log({operation:"download_speed",param:String(e.speed)})}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"})}log(e){const i=this.createLogItem(e);this.logger.log(i)}createLogItem({operation:e,param:i}){const s=this.timeSynchronisation.now(),o={vsid:this.vsid,vid:this.statContext.movieId,quality:this.statContext.quality,dst:this.statContext.destination,ct:this.statContext.contentType,aid:this.statContext.albumId,place:this.statContext.place,cdn_host:this.statContext.cdnHostname,connection_type:this.statContext.connectionType,connection_reused:this.statContext.connectionReused===!0?E.YES:this.statContext.connectionReused===!1?E.NO:void 0,stat_type:this.statContext.autoplay===!0?T.AUTO:this.statContext.autoplay===!1?T.MANUAL:void 0,vk_playlist_id:this.statContext.vkPlaylistId,vk_app_id:this.statContext.vkAppId,track_code:this.statContext.trackCode};i!==void 0&&(o.param=i);for(const a of this.fieldBlacklist)delete o[a];return{operation:e,timestamp:s,custom:o}}}export{l as ApiEnv,_ as ConnectionType,d as ContentType,oe as OneStat,h as Quality,P as ScreenDestination};
|
|
6
|
+
import{ValueSubject as H,safeStorage as w,getExponentialDelay as J,ErrorCategory as g,now as f,assertNever as X,Observable as Z,Subscription as $,merge as k,fromEvent as B,filterChanged as tt,map as et,filter as M,isNullable as F,Subject as st,once as it,combine as W,observableFrom as ot,isNonNullable as v}from"@vkontakte/videoplayer-shared/esnext.esm.js";import K from"lodash/debounce.js";import{Surface as N,VideoQuality as E,HttpConnectionType as L,VideoFormat as c,PlaybackState as V}from"@vkontakte/videoplayer-core/esnext.esm.js";function nt(){const e="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(""),t=new Array(36);let s=0,i,o;for(o=0;o<36;o++)o===8||o===13||o===18||o===23?t[o]="-":o===14?t[o]="4":(s<=2&&(s=33554432+Math.random()*16777216|0),i=s&15,s=s>>4,t[o]=e[o===19?i&3|8:i]);return t.join("")}var b;(function(e){e.PROD="prod",e.VK_ALIAS="vk_alias",e.VIDEOTEST="videotest",e.TEST="test",e.AUTO="auto"})(b||(b={}));var d;(function(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"})(d||(d={}));var l;(function(e){e.MP4="mp4",e.DASH="dash",e.DASH_SEP="dash_sep",e.ONDEMAND_DASH="ondemand_dash",e.HLS="hls",e.ONDEMAND_HLS="ondemand_hls",e.WEBM="webm",e.ONDEMAND_DASH_LIVE="ondemand_dash_live",e.ONDEMAND_HLS_LIVE="ondemand_hls_live",e.WEBRTC="webrtc",e.UNKNOWN="unknown",e.RTMP="rtmp"})(l||(l={}));var R;(function(e){e.AUTO="auto",e.MANUAL=""})(R||(R={}));var x;(function(e){e.HTTP1="http1",e.HTTP2="http2",e.HTTP3="http3"})(x||(x={}));var _;(function(e){e[e.YES=1]="YES",e[e.NO=0]="NO"})(_||(_={}));var y;(function(e){e.EXCELLENT="excellent",e.GOOD="good",e.POOR="poor"})(y||(y={}));var P;(function(e){e.PIP="pip",e.FULLSCREEN="fullscreen",e.EXTERNAL="external",e.PREFETCH="prefetch"})(P||(P={}));var I;(function(e){e.SLIDER="slider",e.DOUBLE_TAP="double_tap",e.TIME_CODE="time_code",e.EPISODE="episode",e.REWIND="rewind",e.LIVE="live",e.UNKNOWN="unknown"})(I||(I={}));const q="1.0.35-beta.0",rt="CIOPGQJGDIHBABABA",j={[b.PROD]:"https://api.ok.ru",[b.VK_ALIAS]:"https://api.mycdn.me",[b.VIDEOTEST]:"https://videotestapi.ok.ru/api",[b.TEST]:"https://apitest.ok.ru",[b.AUTO]:""},at="_one-stat_",z=`${at}uuid`,ht={start:1e3,factor:1.5,max:5*60*1e3,random:.1};var T;(function(e){e[e.PARAM_SESSION_EXPIRED=102]="PARAM_SESSION_EXPIRED",e[e.PARAM_SESSION_KEY=103]="PARAM_SESSION_KEY",e[e.PARAM_SIGNATURE=104]="PARAM_SIGNATURE",e[e.AUTH_LOGIN=401]="AUTH_LOGIN"})(T||(T={}));class ut{params;uuid;authToken;sessionKey;authorizePromise;refreshAuthTokenPromise;consequentAuthErrors=0;authorized$=new H(!1);backoffTimeoutId;constructor(t){this.params=t;const s=w.get(z);s?this.uuid=String(s):(this.uuid=nt(),w.set(z,this.uuid))}async authorize(t){return this.authToken=t??await this.refreshAuthToken(),this._authorizeWithBackoff()}logBeacon(t){const s="log.externalLog",i=this.createLogParams(t),o=this.sessionKey;if(!o)return;this.params.apiTransport.sendBeacon(s,i,o)||this.logRequest(t)}async logRequest(t){const s="log.externalLog",i=this.createLogParams(t),o=this.sessionKey??await this._authorizeWithBackoff();if(!o)return;const a=async(r,u=this.params.requestRetryCount)=>{try{return await this.params.apiTransport.sendRequest(s,i,o)}catch(h){if(!h||!("error_code"in h)){this.params.error$.next({id:"logRequestUnknown",category:g.NETWORK,message:`Unknown ${s} error`,thrown:h});return}const m=h?.error_code;switch(m){case T.PARAM_SESSION_EXPIRED:case T.PARAM_SESSION_KEY:case T.PARAM_SIGNATURE:return this.authorized$.next(!1),this.sessionKey=await this._authorizeWithBackoff(),u>0?a(r,u-1):void 0;case T.AUTH_LOGIN:return this.authorized$.next(!1),this.authToken=await this.refreshAuthToken(),this.sessionKey=await this._authorizeWithBackoff(),u>0?a(r,u-1):void 0;default:{this.params.error$.next({id:`LogRequest#${m}`,category:g.EXTERNAL_API,message:`${s} error`,data:h});return}}}};return a(t)}destroy(){window.clearTimeout(this.backoffTimeoutId),this.backoffTimeoutId=0}async refreshAuthToken(){if(this.params.refreshAuthToken)return this.refreshAuthTokenPromise||(this.refreshAuthTokenPromise=this.params.refreshAuthToken().finally(()=>{this.refreshAuthTokenPromise=void 0})),this.refreshAuthTokenPromise}createLogParams(t){return{collector:"ok.mobile.apps.video",data:JSON.stringify({application:`@vkontakte/videoplayer-statistics:${q}`,platform:this.params.mobile?"M_WEB":"WEB",items:t})}}_authorizeWithBackoff(){if(!this.consequentAuthErrors)return this._authorize();const t=J(this.consequentAuthErrors,ht);return new Promise(s=>{this.backoffTimeoutId||(this.backoffTimeoutId=window.setTimeout(()=>{this._authorize().then(s).catch(i=>this.params.error$.next({id:"AuthorizeBackoff",category:g.NETWORK,message:"Otherwise unhandled error in authorization",thrown:i})).finally(()=>this.backoffTimeoutId=0)},t))})}async _authorize(){if(this.authorizePromise)return this.authorizePromise;this.sessionKey=void 0,this.authorized$.next(!1);const t="auth.anonymLogin",s={session_data:{version:2,device_id:this.uuid,client_version:q.split("-")[0],client_type:"SDK_JS"}};return this.authToken!==void 0&&(s.session_data.auth_token=this.authToken,s.session_data.version=3),this.authorizePromise=this.params.apiTransport.sendRequest(t,s).then(i=>((!i||!i.session_key)&&this.params.error$.next({id:"AuthorizeFailed",category:g.EXTERNAL_API,message:"No session key",data:i}),this.sessionKey=i?.session_key??void 0,this.sessionKey)).catch(async i=>{this.sessionKey=void 0;const o=i?.error_code;switch(o){case T.AUTH_LOGIN:return this.authToken=await this.refreshAuthToken(),this._authorizeWithBackoff()}o?this.params.error$.next({id:`Authorize#${o}`,category:g.EXTERNAL_API,message:"authorize error",data:i}):this.params.error$.next({id:"AuthorizeUnknown",category:g.NETWORK,message:"authorize error",thrown:i})}).finally(()=>{this.authorizePromise=void 0,this.consequentAuthErrors=this.sessionKey?0:this.consequentAuthErrors+1,this.authorized$.next(this.sessionKey!==void 0)}),this.authorizePromise}}class ct{apiKey;apiBaseUrl;apiEnv;timeSynchronisation;isApiBaseUrlFetched;params;constructor(t){this.params=t,this.apiKey=t.apiKey,this.apiEnv=t.apiEnv,this.apiBaseUrl=t.apiBaseUrl,this.timeSynchronisation=t.timeSynchronisation,this.isApiBaseUrlFetched=!1}async resolveApiBaseUrl(){if(this.apiEnv!==b.AUTO||this.isApiBaseUrlFetched)return this.apiBaseUrl;try{const t=atob("aHR0cHM6Ly9kbnMuZ29vZ2xlL3Jlc29sdmU/bmFtZT12aWRlby5fZW5kcG9pbnQub2sucnUmdHlwZT1UWFQ="),o=(await(await fetch(t,{method:"GET",mode:"cors",cache:"no-cache"})).json())?.Answer[0]?.data;if(!o)throw new Error("Wrong DNS response");return o}catch(t){return this.params.error$.next({id:"OneStat:ApiTransport:resolveApiBaseUrl",category:g.NETWORK,message:"Unhandled resolve api base url error",thrown:t}),j[b.VK_ALIAS]}finally{this.isApiBaseUrlFetched=!0}}sendBeacon(t,s,i){if(!window.Blob||!window.navigator.sendBeacon)return!1;const o=this._prepareQueryParams({method:t,queryParams:s,sessionKey:i}),a=new window.Blob([o.toString()],{type:"application/x-www-form-urlencoded"});try{return window.navigator.sendBeacon(`${this.apiBaseUrl}/fb.do`,a)}catch(r){this.params.error$.next({id:"OneStat:ApiTransport:sendBeacon",category:g.NETWORK,message:"Unhandled beacon error",thrown:r,data:{method:t,params:s}})}return!1}async sendRequest(t,s,i){const o=f(),a=r=>{if(r instanceof TypeError&&["Failed to fetch","NetworkError when attempting to fetch resource."].includes(r.message)){this.params.error$.next({id:"Network",category:g.NETWORK,message:"Request failed",thrown:r});return}this.params.error$.next({id:"OneStat:ApiTransport:sendRequest",category:g.NETWORK,message:"Unhandled request error",thrown:r,data:{method:t,params:s,sessionKey:i,time:f()-o}})};return this.apiBaseUrl=await this.resolveApiBaseUrl(),fetch(`${this.apiBaseUrl}/fb.do`,{method:"post",headers:{"Content-type":"application/x-www-form-urlencoded"},body:this._prepareQueryParams({method:t,queryParams:s,sessionKey:i})}).then(r=>{const u=Number(r.headers.get("content-length"))===0,h=new Date(r.headers.get("date")??"").getTime(),m=f()-o;if(isFinite(h)&&this.timeSynchronisation.addServerTime(h,m),!u)return r.json().then(n=>Object.prototype.hasOwnProperty.call(n,"error_msg")?Promise.reject(n):n,a)},a)}_prepareQueryParams(t){const s=new URLSearchParams({format:"JSON",method:t.method,application_key:this.apiKey});return t.sessionKey!==void 0&&s.append("session_key",t.sessionKey),Object.entries(t.queryParams).forEach(([i,o])=>s.append(i,typeof o=="string"?o:JSON.stringify(o))),s}}const Q=5e3,dt=1e4,lt=6e4,O="onestat_events",ft=36*60*60*1e3,D=e=>e.timestamp+ft>=f();class pt{api;error$;subscription;userSalt;unsaltedStorage=[];lastVsid;isPaused=!1;constructor(t){this.api=t.api,this.error$=t.error$,this.userSalt=t.userSalt,this.subscription=this.api.authorized$.subscribe(s=>{s&&this.debouncedFlush()}),this.housekeepStorage()}isUrgent=t=>{const{operation:s,custom:{param:i}}=t;return["action_stop","close_at_empty_buffer"].includes(s)||s==="watch_coverage_record"&&i==="0-0"};safeFlush(){try{this.flush()}catch(t){this.error$.next({id:"LoggerError",category:g.WTF,message:String(t)??"Unknown logger error",thrown:t})}}firstFlush=K(()=>this.safeFlush(),Q,{maxWait:Q});debouncedFlush=K(()=>this.safeFlush(),dt,{maxWait:lt});readFromStorage(){const t=w.get(O);try{return t?JSON.parse(t):{}}catch{}return{}}addToStorage(t){if(!this.userSalt){this.unsaltedStorage.push(t);return}const s=this.readFromStorage(),o=(s[this.userSalt]??[]).filter(D);w.set(O,JSON.stringify({...s,[this.userSalt]:[...o,t]}))}getFromStorage(){return this.userSalt?(this.readFromStorage()[this.userSalt]??[]).filter(D):this.unsaltedStorage}markStorageSent(){if(!this.userSalt){this.unsaltedStorage=[];return}const t=this.readFromStorage();delete t[this.userSalt],w.set(O,JSON.stringify(t))}housekeepStorage(){const t=this.readFromStorage();for(const[s,i]of Object.entries(t)){const o=i.filter(D);o.length?t[s]=o:delete t[s]}w.set(O,JSON.stringify(t))}log(t){console.log(t.operation,t.custom.param,t),this.addToStorage(t),!this.isPaused&&(this.isUrgent(t)?this.flush():this.lastVsid!==t.custom.vsid?this.firstFlush():this.debouncedFlush(),this.lastVsid=t.custom.vsid)}flush(t=!1){const s=this.getFromStorage();s.length!==0&&(this.api.authorized$.getValue()?(console.log("flush",s.length,"events",s),t?this.api.logBeacon(s):this.api.logRequest(s),this.markStorageSent()):this.api.authorize(),this.firstFlush.cancel(),this.debouncedFlush.cancel())}pause(){this.isPaused=!0,this.debouncedFlush.cancel()}resume(){this.isPaused=!1,this.debouncedFlush()}destroy(){this.subscription.unsubscribe(),this.firstFlush.cancel(),this.debouncedFlush.cancel()}}const gt=()=>{let e,t;try{e=window.self!==window.top}catch(i){i instanceof DOMException&&i.name==="SecurityError"?e=!0:(e=!1,console.error(i))}try{window.location.ancestorOrigins&&(t=window.location.ancestorOrigins[window.location.ancestorOrigins.length-1])}catch(i){console.error(i)}try{!t&&document.referrer&&(t=document.referrer)}catch(i){console.error(i)}const s=t?new URL(t).hostname:void 0;return{isEmbed:e,host:s}},mt=e=>e&&{[E.INVARIANT]:d.UNKNOWN,[E.Q_144P]:d.Q144P,[E.Q_240P]:d.Q240P,[E.Q_360P]:d.Q360P,[E.Q_480P]:d.Q480P,[E.Q_720P]:d.Q720P,[E.Q_1080P]:d.Q1080P,[E.Q_1440P]:d.Q1440P,[E.Q_2160P]:d.Q2160P,[E.Q_4320P]:d.UNKNOWN}[e],G=e=>e&&{[L.HTTP1]:x.HTTP1,[L.HTTP2]:x.HTTP2,[L.QUIC]:x.HTTP3}[e],St=e=>{if(e!==void 0)switch(e){case c.MPEG:return l.MP4;case c.DASH:case c.DASH_LIVE:return l.DASH;case c.DASH_SEP:return l.DASH_SEP;case c.DASH_ONDEMAND:return l.ONDEMAND_DASH;case c.DASH_WEBM:case c.DASH_LIVE_WEBM:return l.WEBM;case c.DASH_LIVE_CMAF:return l.ONDEMAND_DASH_LIVE;case c.HLS:case c.HLS_LIVE:return l.HLS;case c.HLS_ONDEMAND:return l.ONDEMAND_HLS;case c.HLS_LIVE_CMAF:return l.ONDEMAND_HLS_LIVE;case c.WEB_RTC_LIVE:return l.WEBRTC;default:return X(e)}},U=e=>{if(e!==void 0)switch(e){case N.NONE:case N.INLINE:return;case N.FULLSCREEN:return P.FULLSCREEN;case N.SECOND_SCREEN:return P.EXTERNAL;case N.PIP:return P.PIP;default:return X(e)}},Et=e=>{switch(e){case"slow-2g":return y.POOR;case"2g":return y.POOR;case"3g":return y.GOOD;case"4g":return y.EXCELLENT}};class _t{offset=void 0;constructor(t){this.offset=t}getOffset(){return this.offset??0}setOffset(t){this.offset=t}now(){return Date.now()+(this.offset??0)}date(t=new Date){return t.setTime(t.getTime()+(this.offset??0)),t}addServerTime(t,s){const i=Date.now(),o=t-i-s/2;if(Math.abs(o)<1e3){this.offset=0;return}this.offset===void 0?this.offset=Math.round(o):this.offset=Math.round(.2*o+(1-.2)*this.offset)}}const Y=()=>Math.floor(Math.random()*2**32).toString(36).padStart(8,"0"),bt=e=>new Z(t=>{const s=new $,i=k(B(window,"beforeunload"),e.events.willDestruct$),o=new H(void 0);let a;e.info.isLive$.pipe(tt()).subscribe(A=>{a&&(a.unsubscribe(),o.next(void 0)),A?a=e.info.liveTime$.pipe(et(C=>C&&C/1e3)).subscribe(o):a=e.info.position$.subscribe(o),s.add(a)});const{playing$:r,paused$:u}=e.events,h=e.events.willSeek$.pipe(M(()=>e.info.playbackState$.getValue()===V.PLAYING)),m=e.events.seeked$.pipe(M(()=>e.info.playbackState$.getValue()===V.PLAYING)),n=k(r,m),p=k(u,h,i,e.events.looped$);let S;return s.add(n.subscribe(()=>S=o.getValue())),s.add(p.subscribe(()=>{const A=o.getValue();F(S)||S===A||F(A)||(t.next({from:S,to:A}),S=void 0)})),s});class wt{api;logger;config;subscription=new $;timeSynchronisation=new _t;experimental;statContext;vsid=Y();isEmbed;embedParent;uiEvents;player;seekAction$=new H(I.UNKNOWN);constructor(t,s){this.statContext=t,this.config={...s.config??{},requestRetryCount:1};const i=new st;this.experimental={error$:i};const o=new ct({apiKey:rt,apiBaseUrl:j[s.apiEnv],apiEnv:s.apiEnv,error$:i,timeSynchronisation:this.timeSynchronisation});this.api=new ut({apiTransport:o,refreshAuthToken:s.refreshAuthToken,requestRetryCount:this.config.requestRetryCount,mobile:this.statContext.mobile??!1,error$:i}),this.logger=new pt({api:this.api,error$:i,userSalt:s.userSalt});const{isEmbed:a,host:r}=gt();this.isEmbed=a,this.embedParent=r,this.subscribe()}updateContext(t){this.statContext={...this.statContext,...t}}attachTo(t){const s=new $,i=(n,p)=>s.add(n.subscribe(p));i(t.events.willStart$,()=>{this.logActionPlay({position:t.info.position$.getValue()})}),i(t.events.looped$,()=>{this.resetViewSession(),this.logActionPlay({position:t.info.position$.getValue()})}),i(t.events.seeked$,()=>{this.logSeek({action:this.seekAction$.getValue(),time:t.info.position$.getValue()}),this.seekAction$.next(I.UNKNOWN)}),i(t.events.paused$,()=>{this.logPause({position:t.info.position$.getValue()})}),i(t.events.willResume$,()=>{this.logPlay()}),i(t.events.started$,()=>{this.statContext.clip&&this.logWatchCoverageRecord({start:0,end:0})}),i(bt(t),n=>{const p=t.info.isLive$.getValue(),S={start:n.from,end:n.to};p?this.logWatchCoverageLive(S):this.logWatchCoverageRecord(S)});let o;i(t.info.isStalled$,n=>{n?o=f():(v(o)&&this.logEmptyBuffer({duration:f()-o}),o=void 0)});let a=!1;s.add(t.events.fatalError$.pipe(it()).subscribe(()=>a=!0)),i(t.events.willStop$,()=>{if(t.info.isStalled$.getValue()){const p=v(o)?f()-o:void 0;this.logCloseAtEmptyBuffer({duration:p??0}),o=void 0}else a||this.logActionStop()}),i(t.events.managedError$,({id:n})=>{this.logError({fatal:!1,errorType:n})}),i(t.events.fatalError$,({id:n})=>{this.logError({fatal:!0,errorType:n})});let r,u,h=!1;i(t.events.firstBytes$,n=>{r=f(),this.logFirstBytes({time:n})}),i(t.events.willStart$,()=>u=f()),i(t.info.currentBuffer$,n=>{!h&&n&&n.end-n.start>0&&v(r)&&(this.logPlayerReady({duration:f()-r}),h=!0)}),i(t.events.firstFrame$,()=>{v(r)&&!h&&(this.logPlayerReady({duration:f()-r}),h=!0),v(u)&&this.logFirstFrame({time:f()-u})}),i(t.info.atLiveEdge$,n=>this.updateContext({liveEdge:n})),i(W({muted:t.info.muted$,volume:t.info.volume$}),({muted:n,volume:p})=>this.updateContext({audible:!n&&p>0})),i(t.info.currentQuality$,n=>this.updateContext({quality:mt(n)})),i(t.info.isAutoQualityEnabled$,n=>this.updateContext({autoQuality:n})),i(t.info.currentFormat$,n=>this.updateContext({contentType:St(n)}));let m;return i(t.info.hostname$,n=>{this.updateContext({cdnHostname:n,failover:m!==void 0&&m!==n}),m=n}),i(t.info.throughputEstimation$,n=>this.updateContext({downloadSpeed:n})),i(t.info.httpConnectionType$,n=>{this.statContext.firstConnectionType||this.updateContext({firstConnectionType:G(n)}),this.updateContext({connectionType:G(n)})}),i(t.info.httpConnectionReused$,n=>{F(this.statContext.firstConnectionReused)&&this.updateContext({firstConnectionReused:n}),this.updateContext({connectionReused:n})}),i(t.info.surface$,n=>this.updateContext({mode:U(n)})),i(W({current:t.info.currentTextTrack$,available:t.info.availableTextTracks$}),({current:n,available:p})=>{const S=p.find(({id:A})=>A===n);this.updateContext({subtitles:S?.language})}),this.player=t,this.uiEvents&&this.attachToUi(this.uiEvents),this.subscription.add(s),s}attachToUi(t){this.uiEvents=t;const s=new $;return this.player&&(s.add(t.actionRewind$.subscribe(()=>{this.player&&(this.resetViewSession(),this.logActionPlay({position:this.player.info.position$.getValue()}))})),s.add(t.actionSeek$.subscribe(this.seekAction$)),s.add(t.inPiP$.subscribe(i=>{const o=i?P.PIP:U(this.player?.info.surface$.getValue());this.updateContext({mode:o})})),s.add(t.inFullscreen$.subscribe(i=>{const o=i?P.FULLSCREEN:U(this.player?.info.surface$.getValue());this.updateContext({mode:o})})),s.add(t.actionSetSubtitle$.subscribe(i=>{this.updateContext({subtitles:i})})),this.subscription.add(s)),s}attachToAds(t){const s=new $;return s.add(t.slotRequested$.subscribe(()=>this.logAdSlotRequest())).add(t.started$.subscribe(i=>this.logAdStarted(i))).add(t.paused$.subscribe(()=>this.logAdPaused())).add(t.resumed$.subscribe(()=>this.logAdResumed())).add(t.ended$.subscribe(()=>this.logAdEnded())).add(t.skipped$.subscribe(()=>this.logAdSkipped())).add(t.clicked$.subscribe(()=>this.logAdClicked())),this.subscription.add(s),s}authorize(t){return this.api.authorize(t)}pause(){this.logger.pause()}resume(){this.logger.resume()}destroy(){this.logger.flush(),this.subscription.unsubscribe(),this.api.destroy(),this.logger.destroy()}resetViewSession(){this.vsid=Y()}setFieldBlacklist(){}logInited(){}logReady(t){this.log({operation:"player_ready",param:String(t.time)})}logStarted(...t){this.logActionPlay(...t)}logPlay(){this.log({operation:"play_toggle"})}logPause(t){this.log({operation:"pause",param:String(Math.round(t.position))})}logSeek(t){this.log({operation:"seek",param:t.action,time:t.time})}logFirstBytes(t){this.log({operation:"first_bytes",param:String(t.time)})}logFirstFrame(t){this.log({operation:"first_frame",param:String(t.time)})}logError(t){this.log({operation:"content_error",param:`${t.fatal?"fatal":"recoverable"}_${t.errorType}`})}logWatchCoverageRecord(t){this.log({operation:"watch_coverage_record",param:`${t.start}-${t.end}`})}logWatchCoverageLive(t){const s=t.start+this.timeSynchronisation.getOffset(),i=t.end+this.timeSynchronisation.getOffset();this.log({operation:"watch_coverage_live",param:`${s}-${i}`})}logEmptyBuffer(t){this.log({operation:"empty_buffer",param:String(t.duration)})}logDownloadSpeed(){}logAdSlotRequest(){this.log({operation:"adv",param:"slot_request"})}logAdStarted(t){this.log({operation:"adv",param:t})}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"})}subscribe(){this.subscription.add(B(window,"beforeunload").subscribe(()=>this.logger.flush(!0)));const t=window.navigator.connection;t&&"onchange"in t&&"effectiveType"in t&&this.subscription.add(k(B(t,"change"),ot(["init"])).subscribe(()=>this.updateContext({network:Et(t.effectiveType)})))}logPlayerReady(t){this.log({operation:"player_ready",param:String(Math.round(t.duration))})}logActionPlay(t){this.log({operation:"action_play",param:String(Math.round(t.position))})}logCloseAtEmptyBuffer(t){this.log({operation:"close_at_empty_buffer",param:String(Math.round(t.duration))})}logActionStop(){this.log({operation:"action_stop"})}log(t){const s=this.createLogItem(t);this.logger.log(s)}createLogItem({operation:t,param:s,time:i}){const o=this.timeSynchronisation.now(),a=t==="empty_buffer"||t==="close_at_empty_buffer"?this.statContext.connectionType:this.statContext.firstConnectionType,r=this.statContext.firstConnectionReused,u={vsid:this.vsid,vid:this.statContext.movieId,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?R.AUTO:this.statContext.autoplay===!1?R.MANUAL:void 0,param:s,vk_app_id:this.statContext.vkAppId,track_code:this.statContext.trackCode,connection_type:a,connection_reused:r===!0?_.YES:r===!1?_.NO:void 0,cached_data:this.statContext.cached===!0?_.YES:this.statContext.cached===!1?_.NO:void 0,live:this.statContext.liveEdge?_.YES:void 0,muted:this.statContext.audible===!1?_.YES:void 0,mode:this.statContext.mode,subtitles:this.statContext.subtitles,download_speed:this.statContext.downloadSpeed,manual_quality:this.statContext.autoQuality?void 0:_.YES,ref_domain:this.embedParent,aid:this.statContext.albumId,vk_playlist_id:this.statContext.vkPlaylistId};return{operation:t,type:1,time:i,network:this.statContext.network,timestamp:o,custom:u}}}export{b as ApiEnv,x as ConnectionType,l as ContentType,wt as OneStat,d as Quality,I as SeekAction,q as VERSION};
|
package/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ISubscription, IObservable, IError, Seconds, Milliseconds } from '@vkontakte/videoplayer-shared';
|
|
2
1
|
import { IPlayer } from '@vkontakte/videoplayer-core';
|
|
2
|
+
import { Kbps, IObservable, ISubscription, IError, Seconds, Milliseconds, Subscription } from '@vkontakte/videoplayer-shared';
|
|
3
3
|
|
|
4
4
|
declare enum ApiEnv {
|
|
5
5
|
PROD = "prod",
|
|
@@ -9,24 +9,16 @@ declare enum ApiEnv {
|
|
|
9
9
|
AUTO = "auto"
|
|
10
10
|
}
|
|
11
11
|
declare enum Quality {
|
|
12
|
-
Q144P = "
|
|
13
|
-
Q240P = "
|
|
14
|
-
Q360P = "
|
|
15
|
-
Q480P = "
|
|
16
|
-
Q720P = "
|
|
17
|
-
Q1080P = "
|
|
18
|
-
Q1440P = "
|
|
19
|
-
Q2160P = "
|
|
20
|
-
Q4320P = "4320",
|
|
12
|
+
Q144P = "mobile",
|
|
13
|
+
Q240P = "lowest",
|
|
14
|
+
Q360P = "low",
|
|
15
|
+
Q480P = "medium",
|
|
16
|
+
Q720P = "high",
|
|
17
|
+
Q1080P = "fullhd",
|
|
18
|
+
Q1440P = "quadhd",
|
|
19
|
+
Q2160P = "ultrahd",
|
|
21
20
|
UNKNOWN = "unknown"
|
|
22
21
|
}
|
|
23
|
-
declare enum ScreenDestination {
|
|
24
|
-
CHROMECAST = "chromecast",
|
|
25
|
-
APPLE_TV = "appletv",
|
|
26
|
-
PIP = "pip",
|
|
27
|
-
HEADPHONES = "externalHeadphones",
|
|
28
|
-
SCREEN = ""
|
|
29
|
-
}
|
|
30
22
|
declare enum ContentType {
|
|
31
23
|
MP4 = "mp4",
|
|
32
24
|
DASH = "dash",
|
|
@@ -35,8 +27,12 @@ declare enum ContentType {
|
|
|
35
27
|
HLS = "hls",
|
|
36
28
|
ONDEMAND_HLS = "ondemand_hls",
|
|
37
29
|
WEBM = "webm",
|
|
38
|
-
|
|
39
|
-
|
|
30
|
+
ONDEMAND_DASH_LIVE = "ondemand_dash_live",
|
|
31
|
+
ONDEMAND_HLS_LIVE = "ondemand_hls_live",
|
|
32
|
+
WEBRTC = "webrtc",
|
|
33
|
+
UNKNOWN = "unknown",
|
|
34
|
+
/** @deprecated сдк не поддерживает RTMP, не нужно его использовать */
|
|
35
|
+
RTMP = "rtmp"
|
|
40
36
|
}
|
|
41
37
|
declare enum StatType {
|
|
42
38
|
AUTO = "auto",
|
|
@@ -47,37 +43,76 @@ declare enum ConnectionType {
|
|
|
47
43
|
HTTP2 = "http2",
|
|
48
44
|
HTTP3 = "http3"
|
|
49
45
|
}
|
|
50
|
-
declare enum
|
|
46
|
+
declare enum Flag {
|
|
51
47
|
YES = 1,
|
|
52
48
|
NO = 0
|
|
49
|
+
}
|
|
50
|
+
declare enum Network {
|
|
51
|
+
EXCELLENT = "excellent",
|
|
52
|
+
GOOD = "good",
|
|
53
|
+
POOR = "poor"
|
|
54
|
+
}
|
|
55
|
+
declare enum Mode {
|
|
56
|
+
PIP = "pip",
|
|
57
|
+
FULLSCREEN = "fullscreen",
|
|
58
|
+
EXTERNAL = "external",
|
|
59
|
+
PREFETCH = "prefetch"
|
|
60
|
+
}
|
|
61
|
+
declare enum SeekAction {
|
|
62
|
+
SLIDER = "slider",
|
|
63
|
+
DOUBLE_TAP = "double_tap",
|
|
64
|
+
TIME_CODE = "time_code",
|
|
65
|
+
EPISODE = "episode",
|
|
66
|
+
REWIND = "rewind",
|
|
67
|
+
LIVE = "live",
|
|
68
|
+
UNKNOWN = "unknown"
|
|
53
69
|
}
|
|
54
70
|
|
|
55
71
|
interface ILogCustomData {
|
|
56
|
-
/**
|
|
57
|
-
* Id видео
|
|
58
|
-
*/
|
|
59
|
-
vid: number;
|
|
60
72
|
/**
|
|
61
73
|
* Сессия смотрения, уникальна для пользователя, контента, экземпляра плеера и одного просмотра
|
|
62
74
|
* См https://confluence.vk.team/display/VID/Video%20Session%20ID
|
|
63
75
|
*/
|
|
64
|
-
vsid
|
|
65
|
-
|
|
66
|
-
dst?: ScreenDestination;
|
|
76
|
+
vsid: string;
|
|
77
|
+
vid: number;
|
|
67
78
|
ct?: ContentType;
|
|
68
|
-
aid?: string;
|
|
69
79
|
place?: string;
|
|
80
|
+
quality?: Quality;
|
|
70
81
|
cdn_host?: string;
|
|
71
|
-
connection_type?: ConnectionType;
|
|
72
|
-
connection_reused?: ConnectionReused;
|
|
73
82
|
stat_type?: StatType;
|
|
74
|
-
|
|
83
|
+
param?: any;
|
|
75
84
|
vk_app_id?: string;
|
|
76
85
|
track_code?: string;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
86
|
+
connection_type?: ConnectionType;
|
|
87
|
+
connection_reused?: Flag;
|
|
88
|
+
cached_data?: Flag;
|
|
89
|
+
live?: Flag;
|
|
90
|
+
muted?: Flag;
|
|
91
|
+
mode?: Mode;
|
|
92
|
+
subtitles?: string;
|
|
93
|
+
failover?: Flag;
|
|
94
|
+
download_speed?: Kbps;
|
|
95
|
+
manual_quality?: Flag;
|
|
96
|
+
ref_domain?: string;
|
|
97
|
+
vk_playlist_id?: string;
|
|
98
|
+
aid?: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
interface IUIEvents {
|
|
102
|
+
actionRewind$: IObservable<void>;
|
|
103
|
+
actionSeek$: IObservable<SeekAction>;
|
|
104
|
+
inPiP$: IObservable<boolean>;
|
|
105
|
+
inFullscreen$: IObservable<boolean>;
|
|
106
|
+
actionSetSubtitle$: IObservable<string>;
|
|
107
|
+
}
|
|
108
|
+
interface IAdsEvents {
|
|
109
|
+
slotRequested$: IObservable<void>;
|
|
110
|
+
started$: IObservable<string>;
|
|
111
|
+
paused$: IObservable<void>;
|
|
112
|
+
resumed$: IObservable<void>;
|
|
113
|
+
ended$: IObservable<void>;
|
|
114
|
+
skipped$: IObservable<void>;
|
|
115
|
+
clicked$: IObservable<void>;
|
|
81
116
|
}
|
|
82
117
|
|
|
83
118
|
interface IOneStat {
|
|
@@ -93,6 +128,8 @@ interface IOneStat {
|
|
|
93
128
|
*/
|
|
94
129
|
updateContext(context: Partial<IStatContext>): void;
|
|
95
130
|
attachTo(player: IPlayer): ISubscription;
|
|
131
|
+
attachToUi(uiEvents: IUIEvents): ISubscription;
|
|
132
|
+
attachToAds(adsEvents: IAdsEvents): ISubscription;
|
|
96
133
|
/**
|
|
97
134
|
* Ставит отправку событий на паузу. Они будут накапливаться до вызова `resume()`
|
|
98
135
|
*/
|
|
@@ -110,70 +147,107 @@ interface IOneStat {
|
|
|
110
147
|
*/
|
|
111
148
|
resetViewSession(): void;
|
|
112
149
|
/**
|
|
150
|
+
* @deprecated
|
|
113
151
|
* Отключает отправку полей событий
|
|
114
152
|
*/
|
|
115
153
|
setFieldBlacklist(fields: (keyof ILogCustomData)[]): void;
|
|
116
154
|
/**
|
|
117
|
-
*
|
|
155
|
+
* @deprecated
|
|
118
156
|
*/
|
|
119
157
|
logInited(): void;
|
|
120
158
|
/**
|
|
159
|
+
* @deprecated публично нужно использовать attachTo
|
|
121
160
|
* Плеер готов начать воспроизведение
|
|
122
161
|
*/
|
|
123
162
|
logReady(payload: IReadyPayload): void;
|
|
124
163
|
/**
|
|
164
|
+
* @deprecated публично нужно использовать attachTo
|
|
125
165
|
* Первый старт видео. Отправляется 1 раз, когда фактически началось воспроизведение ролика, а также после зацикливания, но не после паузы.
|
|
126
166
|
*
|
|
127
167
|
* В документации API может называться `play`
|
|
128
168
|
*/
|
|
129
169
|
logStarted(payload: IActionPlayPayload): void;
|
|
130
170
|
/**
|
|
171
|
+
* @deprecated публично нужно использовать attachTo
|
|
131
172
|
* Возобновление после паузы
|
|
132
173
|
*
|
|
133
174
|
* В документации API может называться `play_toggle`
|
|
134
175
|
*/
|
|
135
176
|
logPlay(): void;
|
|
136
177
|
/**
|
|
178
|
+
* @deprecated публично нужно использовать attachTo
|
|
137
179
|
* Постановка видео на паузу
|
|
138
180
|
*/
|
|
139
181
|
logPause(payload: IPausePayload): void;
|
|
140
182
|
/**
|
|
183
|
+
* @deprecated публично нужно использовать attachTo
|
|
141
184
|
* перемотка видео
|
|
142
185
|
*/
|
|
143
|
-
logSeek(): void;
|
|
186
|
+
logSeek(payload: ISeekPayload): void;
|
|
144
187
|
/**
|
|
188
|
+
* @deprecated публично нужно использовать attachTo
|
|
145
189
|
* Промежутки видео, которые были просмотрены пользователем.
|
|
146
190
|
* Время указывается в секундах от начала ролика (т.е. является позицией).
|
|
147
191
|
*/
|
|
148
192
|
logWatchCoverageRecord(payload: IWatchCoveragePayload): void;
|
|
149
193
|
/**
|
|
194
|
+
* @deprecated публично нужно использовать attachTo
|
|
150
195
|
* Промежутки видео, которые были просмотрены пользователем.
|
|
151
196
|
* Время указывается в виде UTC timestamp'ов.
|
|
152
197
|
*/
|
|
153
198
|
logWatchCoverageLive(payload: IWatchCoveragePayload): void;
|
|
154
199
|
/**
|
|
200
|
+
* @deprecated публично нужно использовать attachTo
|
|
155
201
|
* Буфер пуст и пользователь видит залипший кадр.
|
|
156
202
|
*/
|
|
157
203
|
logEmptyBuffer(payload: IEmptyBufferPayload): void;
|
|
158
204
|
/**
|
|
205
|
+
* @deprecated публично нужно использовать attachTo
|
|
159
206
|
* Получен первый кусок данных контента от сервера раздачи видео
|
|
160
207
|
*/
|
|
161
208
|
logFirstBytes(payload: IFirstBytesPayload): void;
|
|
162
209
|
/**
|
|
210
|
+
* @deprecated публично нужно использовать attachTo
|
|
163
211
|
* Пользователь увидел первый кадр
|
|
164
212
|
*/
|
|
165
213
|
logFirstFrame(payload: IFirstFramePayload): void;
|
|
214
|
+
/**
|
|
215
|
+
* @deprecated публично нужно использовать attachTo
|
|
216
|
+
* @param payload
|
|
217
|
+
*/
|
|
166
218
|
logDownloadSpeed(payload: IDownloadSpeedPayload): void;
|
|
167
219
|
/**
|
|
168
220
|
* произошла ошибка
|
|
169
221
|
*/
|
|
170
222
|
logError(payload: IErrorPayload): void;
|
|
223
|
+
/**
|
|
224
|
+
* @deprecated публично нужно использовать attachToAds
|
|
225
|
+
*/
|
|
171
226
|
logAdSlotRequest(): void;
|
|
227
|
+
/**
|
|
228
|
+
* @deprecated публично нужно использовать attachToAds
|
|
229
|
+
* @param sectionType
|
|
230
|
+
*/
|
|
172
231
|
logAdStarted(sectionType: string): void;
|
|
232
|
+
/**
|
|
233
|
+
* @deprecated публично нужно использовать attachToAds
|
|
234
|
+
*/
|
|
173
235
|
logAdPaused(): void;
|
|
236
|
+
/**
|
|
237
|
+
* @deprecated публично нужно использовать attachToAds
|
|
238
|
+
*/
|
|
174
239
|
logAdResumed(): void;
|
|
240
|
+
/**
|
|
241
|
+
* @deprecated публично нужно использовать attachToAds
|
|
242
|
+
*/
|
|
175
243
|
logAdEnded(): void;
|
|
244
|
+
/**
|
|
245
|
+
* @deprecated публично нужно использовать attachToAds
|
|
246
|
+
*/
|
|
176
247
|
logAdSkipped(): void;
|
|
248
|
+
/**
|
|
249
|
+
* @deprecated публично нужно использовать attachToAds
|
|
250
|
+
*/
|
|
177
251
|
logAdClicked(): void;
|
|
178
252
|
experimental: {
|
|
179
253
|
error$: IObservable<IError>;
|
|
@@ -191,6 +265,13 @@ interface IPausePayload {
|
|
|
191
265
|
*/
|
|
192
266
|
position: Seconds;
|
|
193
267
|
}
|
|
268
|
+
interface ISeekPayload {
|
|
269
|
+
/**
|
|
270
|
+
* Действие пользователя приведшее к перемотке
|
|
271
|
+
*/
|
|
272
|
+
action: SeekAction;
|
|
273
|
+
time: Seconds;
|
|
274
|
+
}
|
|
194
275
|
interface IReadyPayload {
|
|
195
276
|
/**
|
|
196
277
|
* время в миллисекундах с события inited
|
|
@@ -226,27 +307,34 @@ interface IErrorPayload {
|
|
|
226
307
|
* строка из символов(без пробелов): тип ошибки
|
|
227
308
|
*/
|
|
228
309
|
errorType: string;
|
|
310
|
+
fatal: boolean;
|
|
229
311
|
}
|
|
230
312
|
interface IStatContext {
|
|
231
|
-
|
|
232
|
-
* Ид видео
|
|
233
|
-
*/
|
|
313
|
+
mobile: boolean;
|
|
234
314
|
movieId: number;
|
|
315
|
+
vkAppId?: string;
|
|
316
|
+
clip?: boolean;
|
|
317
|
+
liveEdge?: boolean;
|
|
318
|
+
autoplay: boolean;
|
|
319
|
+
audible?: boolean;
|
|
235
320
|
quality?: Quality;
|
|
236
|
-
|
|
321
|
+
autoQuality?: boolean;
|
|
237
322
|
contentType?: ContentType;
|
|
238
323
|
albumId?: string;
|
|
239
324
|
vkPlaylistId?: string;
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Раздел сайта на котором играет видео: Лента, плеер, личные сообщения, ...
|
|
243
|
-
*/
|
|
325
|
+
trackCode?: string;
|
|
244
326
|
place?: string;
|
|
245
327
|
cdnHostname?: string;
|
|
328
|
+
downloadSpeed?: Kbps;
|
|
246
329
|
connectionType?: ConnectionType;
|
|
247
330
|
connectionReused?: boolean;
|
|
248
|
-
|
|
249
|
-
|
|
331
|
+
firstConnectionType?: ConnectionType;
|
|
332
|
+
firstConnectionReused?: boolean;
|
|
333
|
+
network?: Network;
|
|
334
|
+
cached?: boolean;
|
|
335
|
+
mode?: Mode;
|
|
336
|
+
subtitles?: string;
|
|
337
|
+
failover?: boolean;
|
|
250
338
|
}
|
|
251
339
|
interface IConfig {
|
|
252
340
|
requestRetryCount: number;
|
|
@@ -254,6 +342,7 @@ interface IConfig {
|
|
|
254
342
|
interface IConstructorParams {
|
|
255
343
|
apiEnv: ApiEnv;
|
|
256
344
|
config?: Partial<IConfig>;
|
|
345
|
+
userSalt?: string;
|
|
257
346
|
refreshAuthToken?: () => Promise<string>;
|
|
258
347
|
}
|
|
259
348
|
interface IWatchCoveragePayload {
|
|
@@ -271,29 +360,35 @@ declare class OneStat implements IOneStat {
|
|
|
271
360
|
};
|
|
272
361
|
private statContext;
|
|
273
362
|
private vsid;
|
|
274
|
-
private
|
|
363
|
+
private isEmbed;
|
|
364
|
+
private embedParent;
|
|
365
|
+
private uiEvents;
|
|
366
|
+
private player;
|
|
367
|
+
private seekAction$;
|
|
275
368
|
constructor(statContext: IStatContext, params: IConstructorParams);
|
|
276
369
|
updateContext(newContext: Partial<IStatContext>): void;
|
|
277
370
|
attachTo(player: IPlayer): ISubscription;
|
|
371
|
+
attachToUi(events: IUIEvents): Subscription;
|
|
372
|
+
attachToAds(adsEvents: IAdsEvents): ISubscription;
|
|
278
373
|
authorize(authToken?: string): Promise<unknown>;
|
|
279
374
|
pause(): void;
|
|
280
375
|
resume(): void;
|
|
281
376
|
destroy(): void;
|
|
282
377
|
resetViewSession(): void;
|
|
283
|
-
setFieldBlacklist(
|
|
378
|
+
setFieldBlacklist(): void;
|
|
284
379
|
logInited(): void;
|
|
285
380
|
logReady(payload: IReadyPayload): void;
|
|
286
|
-
logStarted(
|
|
381
|
+
logStarted(...args: Parameters<typeof this$1.logActionPlay>): void;
|
|
287
382
|
logPlay(): void;
|
|
288
383
|
logPause(payload: IPausePayload): void;
|
|
289
|
-
logSeek(): void;
|
|
384
|
+
logSeek(payload: ISeekPayload): void;
|
|
290
385
|
logFirstBytes(payload: IFirstBytesPayload): void;
|
|
291
386
|
logFirstFrame(payload: IFirstFramePayload): void;
|
|
292
387
|
logError(payload: IErrorPayload): void;
|
|
293
388
|
logWatchCoverageRecord(payload: IWatchCoveragePayload): void;
|
|
294
389
|
logWatchCoverageLive(payload: IWatchCoveragePayload): void;
|
|
295
390
|
logEmptyBuffer(payload: IEmptyBufferPayload): void;
|
|
296
|
-
logDownloadSpeed(
|
|
391
|
+
logDownloadSpeed(): void;
|
|
297
392
|
logAdSlotRequest(): void;
|
|
298
393
|
logAdStarted(sectionType: string): void;
|
|
299
394
|
logAdPaused(): void;
|
|
@@ -301,8 +396,15 @@ declare class OneStat implements IOneStat {
|
|
|
301
396
|
logAdEnded(): void;
|
|
302
397
|
logAdSkipped(): void;
|
|
303
398
|
logAdClicked(): void;
|
|
399
|
+
private subscribe;
|
|
400
|
+
private logPlayerReady;
|
|
401
|
+
private logActionPlay;
|
|
402
|
+
private logCloseAtEmptyBuffer;
|
|
403
|
+
private logActionStop;
|
|
304
404
|
private log;
|
|
305
405
|
private createLogItem;
|
|
306
406
|
}
|
|
307
407
|
|
|
308
|
-
|
|
408
|
+
declare const VERSION: string;
|
|
409
|
+
|
|
410
|
+
export { ApiEnv, ConnectionType, ContentType, IAdsEvents, IOneStat, IStatContext, IUIEvents, OneStat, Quality, SeekAction, VERSION };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vkontakte/videoplayer-statistics",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.35-beta.0",
|
|
4
4
|
"author": "vk.com",
|
|
5
5
|
"description": "Statistics library for vk.com videoplayer",
|
|
6
6
|
"homepage": "https://vk.com",
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
"**/*.d.ts"
|
|
50
50
|
],
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@vkontakte/videoplayer-shared": "
|
|
52
|
+
"@vkontakte/videoplayer-shared": "1.0.24-beta.3",
|
|
53
53
|
"lodash": "4.17.21"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"@vkontakte/videoplayer-core": "
|
|
56
|
+
"@vkontakte/videoplayer-core": "2.0.87-beta.3"
|
|
57
57
|
}
|
|
58
58
|
}
|