@vkontakte/videoplayer-statistics 1.0.34 → 1.0.35-dev.f578f79.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.34
3
- * Mon, 17 Apr 2023 11:31:09 GMT
4
- * https://st.mycdn.me/static/vkontakte-videoplayer/1-0-34/doc/
2
+ * @vkontakte/videoplayer-statistics v1.0.35-dev.f578f79.0
3
+ * Wed, 10 May 2023 11:40:54 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 U,safeStorage as B,getExponentialDelay as Y,ErrorCategory as g,now as p,assertNever as Q,Observable as X,Subscription as N,merge as x,fromEvent as I,filterChanged as j,map as J,filter as H,isNullable as D,Subject as Z,once as ee,combine as M,observableFrom as te,isNonNullable as y}from"@vkontakte/videoplayer-shared/esnext.esm.js";import se from"lodash/debounce.js";import{Surface as $,VideoQuality as A,HttpConnectionType as C,VideoFormat as c,PlaybackState as W}from"@vkontakte/videoplayer-core/esnext.esm.js";function ie(){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 b;(function(t){t.PROD="prod",t.VK_ALIAS="vk_alias",t.VIDEOTEST="videotest",t.TEST="test",t.AUTO="auto"})(b||(b={}));var d;(function(t){t.Q144P="mobile",t.Q240P="lowest",t.Q360P="low",t.Q480P="medium",t.Q720P="high",t.Q1080P="fullhd",t.Q1440P="quadhd",t.Q2160P="ultrahd",t.UNKNOWN="unknown"})(d||(d={}));var l;(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.ONDEMAND_DASH_LIVE="ondemand_dash_live",t.ONDEMAND_HLS_LIVE="ondemand_hls_live",t.WEBRTC="webrtc",t.UNKNOWN="unknown",t.RTMP="rtmp"})(l||(l={}));var k;(function(t){t.AUTO="auto",t.MANUAL=""})(k||(k={}));var v;(function(t){t.HTTP1="http1",t.HTTP2="http2",t.HTTP3="http3"})(v||(v={}));var _;(function(t){t[t.YES=1]="YES",t[t.NO=0]="NO"})(_||(_={}));var T;(function(t){t.EXCELLENT="excellent",t.GOOD="good",t.POOR="poor"})(T||(T={}));var w;(function(t){t.PIP="pip",t.FULLSCREEN="fullscreen",t.EXTERNAL="external",t.PREFETCH="prefetch"})(w||(w={}));var O;(function(t){t.SLIDER="slider",t.DOUBLE_TAP="double_tap",t.TIME_CODE="time_code",t.EPISODE="episode",t.REWIND="rewind",t.LIVE="live",t.UNKNOWN="unknown"})(O||(O={}));const q="1.0.35-dev.f578f79.0",oe="evergreen.esm.js",ne="CIOPGQJGDIHBABABA",z={[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]:""},re="_one-stat_",K=`${re}uuid`,ae={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 ue{params;uuid;authToken;sessionKey;authorizePromise;refreshAuthTokenPromise;consequentAuthErrors=0;authorized$=new U(!1);backoffTimeoutId;constructor(e){this.params=e;const i=B.get(K);i?this.uuid=String(i):(this.uuid=ie(),B.set(K,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,h=this.params.requestRetryCount)=>{try{return await this.params.apiTransport.sendRequest(i,s,o)}catch(u){if(!u||!("error_code"in u)){this.params.error$.next({id:"logRequestUnknown",category:g.NETWORK,message:`Unknown ${i} error`,thrown:u});return}const m=u?.error_code;switch(m){case P.PARAM_SESSION_EXPIRED:case P.PARAM_SESSION_KEY:case P.PARAM_SIGNATURE:return this.authorized$.next(!1),this.sessionKey=await this._authorizeWithBackoff(),h>0?a(r,h-1):void 0;case P.AUTH_LOGIN:return this.authorized$.next(!1),this.authToken=await this.refreshAuthToken(),this.sessionKey=await this._authorizeWithBackoff(),h>0?a(r,h-1):void 0;default:{this.params.error$.next({id:`LogRequest#${m}`,category:g.EXTERNAL_API,message:`${i} error`,data:u});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:`${oe}:${q}`,platform:this.params.mobile?"M_WEB":"WEB",items:e})}}_authorizeWithBackoff(){if(!this.consequentAuthErrors)return this._authorize();const e=Y(this.consequentAuthErrors,ae);return new Promise(i=>{this.backoffTimeoutId||(this.backoffTimeoutId=window.setTimeout(()=>{this._authorize().then(i).catch(s=>this.params.error$.next({id:"AuthorizeBackoff",category:g.NETWORK,message:"Otherwise unhandled error in authorization",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:q.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:g.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:g.EXTERNAL_API,message:"authorize error",data:s}):this.params.error$.next({id:"AuthorizeUnknown",category:g.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 he{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!==b.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:g.NETWORK,message:"Unhandled resolve api base url error",thrown:e}),z[b.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:g.NETWORK,message:"Unhandled beacon error",thrown:r,data:{method:e,params:i}})}return!1}async sendRequest(e,i,s){const o=p(),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:e,params:i,sessionKey:s,time:p()-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 h=Number(r.headers.get("content-length"))===0,u=new Date(r.headers.get("date")??"").getTime(),m=p()-o;if(isFinite(u)&&this.timeSynchronisation.addServerTime(u,m),!h)return r.json().then(n=>Object.prototype.hasOwnProperty.call(n,"error_msg")?Promise.reject(n):n,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 G=3e3,ce=G*5;class de{api;error$;requestQueue=[];subscription;isPaused=!1;debouncedFlush=se(()=>{try{this.flush()}catch(e){this.error$.next({id:"LoggerError",category:g.WTF,message:String(e)??"Unknown logger error",thrown:e})}},G,{maxWait:ce});constructor(e){this.api=e.api,this.error$=e.error$,this.subscription=this.api.authorized$.subscribe(i=>{i&&this.debouncedFlush()})}log(e){console.log(e.operation,e.custom.param,e),this.requestQueue.push(e),this.isPaused||this.debouncedFlush()}flush(e=!1){this.requestQueue.length!==0&&(this.api.authorized$.getValue()?(console.log("Sending",this.requestQueue.length,"events",this.requestQueue),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()}}const le=()=>{let t,e;try{t=window.self!==window.top}catch(s){s instanceof DOMException&&s.name==="SecurityError"?t=!0:(t=!1,console.error(s))}try{window.location.ancestorOrigins&&(e=window.location.ancestorOrigins[window.location.ancestorOrigins.length-1])}catch(s){console.error(s)}try{!e&&document.referrer&&(e=document.referrer)}catch(s){console.error(s)}const i=e?new URL(e).hostname:void 0;return{isEmbed:t,host:i}},fe=t=>t&&{[A.INVARIANT]:d.UNKNOWN,[A.Q_144P]:d.Q144P,[A.Q_240P]:d.Q240P,[A.Q_360P]:d.Q360P,[A.Q_480P]:d.Q480P,[A.Q_720P]:d.Q720P,[A.Q_1080P]:d.Q1080P,[A.Q_1440P]:d.Q1440P,[A.Q_2160P]:d.Q2160P,[A.Q_4320P]:d.UNKNOWN}[t],V=t=>t&&{[C.HTTP1]:v.HTTP1,[C.HTTP2]:v.HTTP2,[C.QUIC]:v.HTTP3}[t],pe=t=>{if(t!==void 0)switch(t){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 Q(t)}},L=t=>{if(t!==void 0)switch(t){case $.NONE:case $.INLINE:return;case $.FULLSCREEN:return w.FULLSCREEN;case $.SECOND_SCREEN:return w.EXTERNAL;case $.PIP:return w.PIP;default:return Q(t)}},ge=t=>{switch(t){case"slow-2g":return T.POOR;case"2g":return T.POOR;case"3g":return T.GOOD;case"4g":return T.EXCELLENT}};class me{offset=void 0;constructor(e){this.offset=e}getOffset(){return this.offset??0}setOffset(e){this.offset=e}now(){return Date.now()+(this.offset??0)}date(e=new Date){return e.setTime(e.getTime()+(this.offset??0)),e}addServerTime(e,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 F=()=>Math.floor(Math.random()*2**32).toString(36).padStart(8,"0"),Ee=t=>new X(e=>{const i=new N,s=x(I(window,"beforeunload"),t.events.willDestruct$),o=new U(void 0);let a;t.info.isLive$.pipe(j()).subscribe(S=>{a&&(a.unsubscribe(),o.next(void 0)),S?a=t.info.liveTime$.pipe(J(R=>R&&R/1e3)).subscribe(o):a=t.info.position$.subscribe(o),i.add(a)});const{playing$:r,paused$:h}=t.events,u=t.events.willSeek$.pipe(H(()=>t.info.playbackState$.getValue()===W.PLAYING)),m=t.events.seeked$.pipe(H(()=>t.info.playbackState$.getValue()===W.PLAYING)),n=x(r,m),f=x(h,u,s,t.events.looped$);let E;return i.add(n.subscribe(()=>E=o.getValue())),i.add(f.subscribe(()=>{const S=o.getValue();D(E)||E===S||D(S)||(e.next({from:E,to:S}),E=void 0)})),i});class Se{api;logger;config;subscription=new N;timeSynchronisation=new me;experimental;statContext;vsid=F();isEmbed;embedParent;uiEvents;player;seekAction$=new U(O.UNKNOWN);constructor(e,i){this.statContext=e,this.config={...i.config??{},requestRetryCount:1};const s=new Z;this.experimental={error$:s};const o=new he({apiKey:ne,apiBaseUrl:z[i.apiEnv],apiEnv:i.apiEnv,error$:s,timeSynchronisation:this.timeSynchronisation});this.api=new ue({apiTransport:o,refreshAuthToken:i.refreshAuthToken,requestRetryCount:this.config.requestRetryCount,mobile:this.statContext.mobile??!1,error$:s}),this.logger=new de({api:this.api,error$:s});const{isEmbed:a,host:r}=le();this.isEmbed=a,this.embedParent=r,this.subscribe()}updateContext(e){this.statContext={...this.statContext,...e}}attachTo(e){const i=new N,s=(n,f)=>i.add(n.subscribe(f));s(e.events.willStart$,()=>{this.logActionPlay({position:e.info.position$.getValue()})}),s(e.events.looped$,()=>{this.resetViewSession(),this.logActionPlay({position:e.info.position$.getValue()})}),s(e.events.seeked$,()=>{this.logSeek({action:this.seekAction$.getValue(),time:e.info.position$.getValue()}),this.seekAction$.next(O.UNKNOWN)}),s(e.events.paused$,()=>{this.logPause({position:e.info.position$.getValue()})}),s(e.events.willResume$,()=>{this.logPlay()}),s(e.events.started$,()=>{this.statContext.clip&&(this.logWatchCoverageRecord({start:0,end:0}),this.logger.flush())}),s(Ee(e),n=>{const f=e.info.isLive$.getValue(),E={start:n.from,end:n.to};f?this.logWatchCoverageLive(E):this.logWatchCoverageRecord(E)});let o;s(e.info.isStalled$,n=>{n?o=p():(y(o)&&this.logEmptyBuffer({duration:p()-o}),o=void 0)});let a=!1;i.add(e.events.fatalError$.pipe(ee()).subscribe(()=>a=!0)),s(e.events.willStop$,()=>{if(e.info.isStalled$.getValue()){const f=y(o)?p()-o:void 0;this.logCloseAtEmptyBuffer({duration:f??0}),o=void 0}else a||this.logActionStop();this.logger.flush()}),s(e.events.managedError$,({id:n})=>{this.logError({fatal:!1,errorType:n})}),s(e.events.fatalError$,({id:n})=>{this.logError({fatal:!0,errorType:n})});let r,h,u=!1;s(e.events.firstBytes$,n=>{r=p(),this.logFirstBytes({time:n})}),s(e.events.willStart$,()=>h=p()),s(e.info.currentBuffer$,n=>{!u&&n&&n.end-n.start>0&&y(r)&&(this.logPlayerReady({duration:p()-r}),u=!0)}),s(e.events.firstFrame$,()=>{y(r)&&!u&&(this.logPlayerReady({duration:p()-r}),u=!0),y(h)&&this.logFirstFrame({time:p()-h})}),s(e.info.atLiveEdge$,n=>this.updateContext({liveEdge:n})),s(M({muted:e.info.muted$,volume:e.info.volume$}),({muted:n,volume:f})=>this.updateContext({audible:!n&&f>0})),s(e.info.currentQuality$,n=>this.updateContext({quality:fe(n)})),s(e.info.isAutoQualityEnabled$,n=>this.updateContext({autoQuality:n})),s(e.info.currentFormat$,n=>this.updateContext({contentType:pe(n)}));let m;return s(e.info.hostname$,n=>{this.updateContext({cdnHostname:n,failover:m!==void 0&&m!==n}),m=n}),s(e.info.throughputEstimation$,n=>this.updateContext({downloadSpeed:n})),s(e.info.httpConnectionType$,n=>{this.statContext.firstConnectionType||this.updateContext({firstConnectionType:V(n)}),this.updateContext({connectionType:V(n)})}),s(e.info.httpConnectionReused$,n=>{D(this.statContext.firstConnectionReused)&&this.updateContext({firstConnectionReused:n}),this.updateContext({connectionReused:n})}),s(e.info.surface$,n=>this.updateContext({mode:L(n)})),s(M({current:e.info.currentTextTrack$,available:e.info.availableTextTracks$}),({current:n,available:f})=>{const E=f.find(({id:S})=>S===n);this.updateContext({subtitles:E?.language})}),this.player=e,this.uiEvents&&this.attachToUi(this.uiEvents),this.subscription.add(i),i}attachToUi(e){this.uiEvents=e;const i=new N;return this.player&&(i.add(e.actionRewind$.subscribe(()=>{this.player&&(this.resetViewSession(),this.logActionPlay({position:this.player.info.position$.getValue()}))})),i.add(e.actionSeek$.subscribe(this.seekAction$)),i.add(e.inPiP$.subscribe(s=>{const o=s?w.PIP:L(this.player?.info.surface$.getValue());this.updateContext({mode:o})})),i.add(e.inFullscreen$.subscribe(s=>{const o=s?w.FULLSCREEN:L(this.player?.info.surface$.getValue());this.updateContext({mode:o})})),this.subscription.add(i)),i}attachToAds(e){const i=new N;return i.add(e.slotRequested$.subscribe(()=>this.logAdSlotRequest())).add(e.started$.subscribe(s=>this.logAdStarted(s))).add(e.paused$.subscribe(()=>this.logAdPaused())).add(e.resumed$.subscribe(()=>this.logAdResumed())).add(e.ended$.subscribe(()=>this.logAdEnded())).add(e.skipped$.subscribe(()=>this.logAdSkipped())).add(e.clicked$.subscribe(()=>this.logAdClicked())),this.subscription.add(i),i}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=F()}setFieldBlacklist(){}logInited(){}logReady(e){this.log({operation:"player_ready",param:String(e.time)})}logStarted(...e){this.logActionPlay(...e)}logPlay(){this.log({operation:"play_toggle"})}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}`})}logWatchCoverageLive(e){const i=e.start+this.timeSynchronisation.getOffset(),s=e.end+this.timeSynchronisation.getOffset();this.log({operation:"watch_coverage_live",param:`${i}-${s}`})}logEmptyBuffer(e){this.log({operation:"empty_buffer",param:String(e.duration)})}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"})}subscribe(){this.subscription.add(I(window,"beforeunload").subscribe(()=>this.logger.flush(!0)));const e=window.navigator.connection;e&&"onchange"in e&&"effectiveType"in e&&this.subscription.add(x(I(e,"change"),te(["init"])).subscribe(()=>this.updateContext({network:ge(e.effectiveType)})))}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))})}logCloseAtEmptyBuffer(e){this.log({operation:"close_at_empty_buffer",param:String(Math.round(e.duration))})}logActionStop(){this.log({operation:"action_stop"})}log(e){const i=this.createLogItem(e);this.logger.log(i)}createLogItem({operation:e,param:i,time:s}){const o=this.timeSynchronisation.now(),a=e==="empty_buffer"||e==="close_at_empty_buffer"?this.statContext.connectionType:this.statContext.firstConnectionType,r=this.statContext.firstConnectionReused,h={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?k.AUTO:this.statContext.autoplay===!1?k.MANUAL:void 0,param:i,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:e,type:1,time:s,network:this.statContext.network,timestamp:o,custom:h}}}export{b as ApiEnv,v as ConnectionType,l as ContentType,Se as OneStat,d as Quality,O as SeekAction};
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 = "144",
13
- Q240P = "240",
14
- Q360P = "360",
15
- Q480P = "480",
16
- Q720P = "720",
17
- Q1080P = "1080",
18
- Q1440P = "1440",
19
- Q2160P = "2160",
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
- RTMP = "rtmp",
39
- UNKNOWN = "unknown"
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,75 @@ declare enum ConnectionType {
47
43
  HTTP2 = "http2",
48
44
  HTTP3 = "http3"
49
45
  }
50
- declare enum ConnectionReused {
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?: string;
65
- quality?: Quality;
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
- vk_playlist_id?: string;
83
+ param?: any;
75
84
  vk_app_id?: string;
76
85
  track_code?: string;
77
- /**
78
- * Параметр события (имеет разный смысл в каждом из событий)
79
- */
80
- param?: any;
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
+ }
107
+ interface IAdsEvents {
108
+ slotRequested$: IObservable<void>;
109
+ started$: IObservable<string>;
110
+ paused$: IObservable<void>;
111
+ resumed$: IObservable<void>;
112
+ ended$: IObservable<void>;
113
+ skipped$: IObservable<void>;
114
+ clicked$: IObservable<void>;
81
115
  }
82
116
 
83
117
  interface IOneStat {
@@ -93,6 +127,8 @@ interface IOneStat {
93
127
  */
94
128
  updateContext(context: Partial<IStatContext>): void;
95
129
  attachTo(player: IPlayer): ISubscription;
130
+ attachToUi(uiEvents: IUIEvents): ISubscription;
131
+ attachToAds(adsEvents: IAdsEvents): ISubscription;
96
132
  /**
97
133
  * Ставит отправку событий на паузу. Они будут накапливаться до вызова `resume()`
98
134
  */
@@ -110,70 +146,107 @@ interface IOneStat {
110
146
  */
111
147
  resetViewSession(): void;
112
148
  /**
149
+ * @deprecated
113
150
  * Отключает отправку полей событий
114
151
  */
115
152
  setFieldBlacklist(fields: (keyof ILogCustomData)[]): void;
116
153
  /**
117
- * Плеер создался и получил ссылку
154
+ * @deprecated
118
155
  */
119
156
  logInited(): void;
120
157
  /**
158
+ * @deprecated публично нужно использовать attachTo
121
159
  * Плеер готов начать воспроизведение
122
160
  */
123
161
  logReady(payload: IReadyPayload): void;
124
162
  /**
163
+ * @deprecated публично нужно использовать attachTo
125
164
  * Первый старт видео. Отправляется 1 раз, когда фактически началось воспроизведение ролика, а также после зацикливания, но не после паузы.
126
165
  *
127
166
  * В документации API может называться `play`
128
167
  */
129
168
  logStarted(payload: IActionPlayPayload): void;
130
169
  /**
170
+ * @deprecated публично нужно использовать attachTo
131
171
  * Возобновление после паузы
132
172
  *
133
173
  * В документации API может называться `play_toggle`
134
174
  */
135
175
  logPlay(): void;
136
176
  /**
177
+ * @deprecated публично нужно использовать attachTo
137
178
  * Постановка видео на паузу
138
179
  */
139
180
  logPause(payload: IPausePayload): void;
140
181
  /**
182
+ * @deprecated публично нужно использовать attachTo
141
183
  * перемотка видео
142
184
  */
143
- logSeek(): void;
185
+ logSeek(payload: ISeekPayload): void;
144
186
  /**
187
+ * @deprecated публично нужно использовать attachTo
145
188
  * Промежутки видео, которые были просмотрены пользователем.
146
189
  * Время указывается в секундах от начала ролика (т.е. является позицией).
147
190
  */
148
191
  logWatchCoverageRecord(payload: IWatchCoveragePayload): void;
149
192
  /**
193
+ * @deprecated публично нужно использовать attachTo
150
194
  * Промежутки видео, которые были просмотрены пользователем.
151
195
  * Время указывается в виде UTC timestamp'ов.
152
196
  */
153
197
  logWatchCoverageLive(payload: IWatchCoveragePayload): void;
154
198
  /**
199
+ * @deprecated публично нужно использовать attachTo
155
200
  * Буфер пуст и пользователь видит залипший кадр.
156
201
  */
157
202
  logEmptyBuffer(payload: IEmptyBufferPayload): void;
158
203
  /**
204
+ * @deprecated публично нужно использовать attachTo
159
205
  * Получен первый кусок данных контента от сервера раздачи видео
160
206
  */
161
207
  logFirstBytes(payload: IFirstBytesPayload): void;
162
208
  /**
209
+ * @deprecated публично нужно использовать attachTo
163
210
  * Пользователь увидел первый кадр
164
211
  */
165
212
  logFirstFrame(payload: IFirstFramePayload): void;
213
+ /**
214
+ * @deprecated публично нужно использовать attachTo
215
+ * @param payload
216
+ */
166
217
  logDownloadSpeed(payload: IDownloadSpeedPayload): void;
167
218
  /**
168
219
  * произошла ошибка
169
220
  */
170
221
  logError(payload: IErrorPayload): void;
222
+ /**
223
+ * @deprecated публично нужно использовать attachToAds
224
+ */
171
225
  logAdSlotRequest(): void;
226
+ /**
227
+ * @deprecated публично нужно использовать attachToAds
228
+ * @param sectionType
229
+ */
172
230
  logAdStarted(sectionType: string): void;
231
+ /**
232
+ * @deprecated публично нужно использовать attachToAds
233
+ */
173
234
  logAdPaused(): void;
235
+ /**
236
+ * @deprecated публично нужно использовать attachToAds
237
+ */
174
238
  logAdResumed(): void;
239
+ /**
240
+ * @deprecated публично нужно использовать attachToAds
241
+ */
175
242
  logAdEnded(): void;
243
+ /**
244
+ * @deprecated публично нужно использовать attachToAds
245
+ */
176
246
  logAdSkipped(): void;
247
+ /**
248
+ * @deprecated публично нужно использовать attachToAds
249
+ */
177
250
  logAdClicked(): void;
178
251
  experimental: {
179
252
  error$: IObservable<IError>;
@@ -191,6 +264,13 @@ interface IPausePayload {
191
264
  */
192
265
  position: Seconds;
193
266
  }
267
+ interface ISeekPayload {
268
+ /**
269
+ * Действие пользователя приведшее к перемотке
270
+ */
271
+ action: SeekAction;
272
+ time: Seconds;
273
+ }
194
274
  interface IReadyPayload {
195
275
  /**
196
276
  * время в миллисекундах с события inited
@@ -226,27 +306,34 @@ interface IErrorPayload {
226
306
  * строка из символов(без пробелов): тип ошибки
227
307
  */
228
308
  errorType: string;
309
+ fatal: boolean;
229
310
  }
230
311
  interface IStatContext {
231
- /**
232
- * Ид видео
233
- */
312
+ mobile: boolean;
234
313
  movieId: number;
314
+ vkAppId?: string;
315
+ clip?: boolean;
316
+ liveEdge?: boolean;
317
+ autoplay: boolean;
318
+ audible?: boolean;
235
319
  quality?: Quality;
236
- destination?: ScreenDestination;
320
+ autoQuality?: boolean;
237
321
  contentType?: ContentType;
238
322
  albumId?: string;
239
323
  vkPlaylistId?: string;
240
- vkAppId?: string;
241
- /**
242
- * Раздел сайта на котором играет видео: Лента, плеер, личные сообщения, ...
243
- */
324
+ trackCode?: string;
244
325
  place?: string;
245
326
  cdnHostname?: string;
327
+ downloadSpeed?: Kbps;
246
328
  connectionType?: ConnectionType;
247
329
  connectionReused?: boolean;
248
- autoplay?: boolean;
249
- trackCode?: string;
330
+ firstConnectionType?: ConnectionType;
331
+ firstConnectionReused?: boolean;
332
+ network?: Network;
333
+ cached?: boolean;
334
+ mode?: Mode;
335
+ subtitles?: string;
336
+ failover?: boolean;
250
337
  }
251
338
  interface IConfig {
252
339
  requestRetryCount: number;
@@ -271,29 +358,35 @@ declare class OneStat implements IOneStat {
271
358
  };
272
359
  private statContext;
273
360
  private vsid;
274
- private fieldBlacklist;
361
+ private isEmbed;
362
+ private embedParent;
363
+ private uiEvents;
364
+ private player;
365
+ private seekAction$;
275
366
  constructor(statContext: IStatContext, params: IConstructorParams);
276
367
  updateContext(newContext: Partial<IStatContext>): void;
277
368
  attachTo(player: IPlayer): ISubscription;
369
+ attachToUi(events: IUIEvents): Subscription;
370
+ attachToAds(adsEvents: IAdsEvents): ISubscription;
278
371
  authorize(authToken?: string): Promise<unknown>;
279
372
  pause(): void;
280
373
  resume(): void;
281
374
  destroy(): void;
282
375
  resetViewSession(): void;
283
- setFieldBlacklist(fields?: (keyof ILogCustomData)[]): void;
376
+ setFieldBlacklist(): void;
284
377
  logInited(): void;
285
378
  logReady(payload: IReadyPayload): void;
286
- logStarted(payload: IActionPlayPayload): void;
379
+ logStarted(...args: Parameters<typeof this$1.logActionPlay>): void;
287
380
  logPlay(): void;
288
381
  logPause(payload: IPausePayload): void;
289
- logSeek(): void;
382
+ logSeek(payload: ISeekPayload): void;
290
383
  logFirstBytes(payload: IFirstBytesPayload): void;
291
384
  logFirstFrame(payload: IFirstFramePayload): void;
292
385
  logError(payload: IErrorPayload): void;
293
386
  logWatchCoverageRecord(payload: IWatchCoveragePayload): void;
294
387
  logWatchCoverageLive(payload: IWatchCoveragePayload): void;
295
388
  logEmptyBuffer(payload: IEmptyBufferPayload): void;
296
- logDownloadSpeed(payload: IDownloadSpeedPayload): void;
389
+ logDownloadSpeed(): void;
297
390
  logAdSlotRequest(): void;
298
391
  logAdStarted(sectionType: string): void;
299
392
  logAdPaused(): void;
@@ -301,8 +394,13 @@ declare class OneStat implements IOneStat {
301
394
  logAdEnded(): void;
302
395
  logAdSkipped(): void;
303
396
  logAdClicked(): void;
397
+ private subscribe;
398
+ private logPlayerReady;
399
+ private logActionPlay;
400
+ private logCloseAtEmptyBuffer;
401
+ private logActionStop;
304
402
  private log;
305
403
  private createLogItem;
306
404
  }
307
405
 
308
- export { ApiEnv, ConnectionType, ContentType, IOneStat, IStatContext, OneStat, Quality, ScreenDestination };
406
+ export { ApiEnv, ConnectionType, ContentType, IAdsEvents, IOneStat, IStatContext, IUIEvents, OneStat, Quality, SeekAction };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vkontakte/videoplayer-statistics",
3
- "version": "1.0.34",
3
+ "version": "1.0.35-dev.f578f79.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": "^1.0.23",
52
+ "@vkontakte/videoplayer-shared": "^1.0.24-dev.fd1a076.0",
53
53
  "lodash": "4.17.21"
54
54
  },
55
55
  "peerDependencies": {
56
- "@vkontakte/videoplayer-core": "^2.0.82"
56
+ "@vkontakte/videoplayer-core": "^2.0.86-dev.f2e1ec4.0"
57
57
  }
58
58
  }