PageSourceSearch

https://tver.jp/streaksplayer/short/streaksplayer-vr.js

js tver.jp collected 2026-09-24 08:33:17 UTC 10,942 bytes, 405 lines download raw bytes

1// Beaconの間隔(秒で指定)
2var BEACON_INTERVAL = 60;
3// Beaconイベントの名前
4var BEACON_EVENT_NAME = 'loop';
5// play/pauseイベントをトラッキングする場合true
6var TRACK_PLAY_PAUSE_EVENT = false;
7// startイベントをトラッキングする場合true
8var TRACK_START_EVENT = true;
9// endedイベントをトラッキングする場合true
10var TRACK_ENDED_EVENT = true;
11// ad_fieldsから抽出する対象のパラメータのキー
12var AD_FIELDS_KEYS = ['a', 'c', 't', 'pf', 'site', 'player', 'pc', 'luid'];
13// VRに投げるパラメータのデフォルト値
14var DEFAULT_TRACKING_PARAMS= {vr_tagid1: 1043, vr_tagid2: 0001, vr_opt1: 'movie', vr_opt6: 1022};
15// VRのエンドポイントのデフォルト値(プラグイン初期時のパラメータとして渡せる)
16//■本番
17//https://log7.interactive-circle.jp/data7/{乱数}.gif
18//テスト
19//https://log7stg.interactive-circle.jp/data7/{乱数}.gif
20var DEFAULT_ENDPOINT = 'https://log7stg.interactive-circle.jp/data7/';
21
22// クエリパラメータを組み上げる関数
23var buildQueryString = function(params) {
24  var value;
25  var type;
26  var i;
27  var max;
28  var encode = window.encodeURIComponent;
29  var query = '';
30
31  for (var key in params) {
32    value = params[key];
33    type = typeof (value) === 'object' && value instanceof Array ? 'array' : typeof (value);
34    switch (type) {
35    case 'undefined':
36      /* キーのみ */
37      query += key;
38      query += '=';
39      break;
40    case 'array':
41      /* 配列 */
42      for (i = 0, max = value.length; i < max; i++) {
43        query += key + '[]';
44        query += '=';
45        query += encode(value[i]);
46        query += '&';
47      }
48      query = query.substr(0, query.length - 1);
49      break;
50    case 'object':
51      /* ハッシュ */
52      for (i in value) {
53        query += key + '[' + i + ']';
54        query += '=';
55        query += encode(value[i]);
56        query += '&';
57      }
58      query = query.substr(0, query.length - 1);
59      break;
60    default:
61      query += key;
62      query += '=';
63      query += key === 'url' ? encodeUrl(value) : encode(value);
64      break;
65    }
66    query += '&';
67  }
68  query = query.substr(0, query.length - 1);
69  return query;
70};
71
72var encodeUrl = function(url) {
73  const encodedUrl = encodeURIComponent(url);
74  /**
75   * urlの場合、スラッシュだけデコードするようにする
76   * @see https://precas.backlog.jp/view/TVER_OVP_SW-560
77   */
78  return encodedUrl.replace(/%2F/g, '/');
79}
80
81// VR向けのトラッキングプラグイン
82window.streaksplayer.registerPlugin('vodVrTracking', function(options) {
83
84  const randomNum = Math.floor(Math.random() * 1e12);
85
86  var beaconTimerId;
87  var endpoint = options.params.endpoint ? `${options.params.endpoint}${randomNum}.gif` : `${DEFAULT_ENDPOINT}${randomNum}.gif`;
88  var player = this;
89  var vrParams = Object.assign({}, DEFAULT_TRACKING_PARAMS, options.params || {});
90  var lastBeaconTime2 = 0;
91  var playing = false;
92  var started = false;
93  var ios_started = false;
94  var firstPlayed = false;
95  var ended = false;
96  var is_ios = false; //
97  var zeroFlag = true;
98  var adFields = {};
99  var media = {};
100  var speed = 1;
101  var lastPC = null;
102  var isSeeking = false
103  var duration = 0;
104
105  var ua = window.navigator.userAgent;
106  var vr_opt9 = Math.floor(Math.random() * 1e12);
107  var vr_opt10 = 0;
108  if (ua.indexOf('iPhone') != -1 || ua.indexOf('iPad') != -1 || ua.indexOf('iPod') != -1) {
109    is_ios = true;
110  }
111   var track = function(eventType, eventTime) {
112    if (!eventType) {
113      eventType = BEACON_EVENT_NAME;
114    }
115
116    var now = (new Date()).getTime()
117
118    if (eventType === 'start') {
119      if (started) {
120        return;
121      }
122      started = true;
123      if (!TRACK_START_EVENT) {
124        return;
125      }
126      if (is_ios) {
127        return;
128      }
129    } else if (eventType === 'ios_start') {
130      eventType = 'start';
131      if (ios_started) {
132        return;
133      }
134      ios_started = true;
135    } else if (eventType === 'play') {
136      if (playing) {
137        return;
138      }
139      playing = true;
140      if (!TRACK_PLAY_PAUSE_EVENT) {
141        return;
142      }
143    } else if (eventType === 'pause') {
144      if (!playing) {
145        return;
146      }
147      playing = false;
148      if (!TRACK_PLAY_PAUSE_EVENT) {
149        return;
150      }
151    } else if (eventType === 'ended') {
152      playing = false;
153      if (!TRACK_ENDED_EVENT) {
154        return;
155      }
156    } else if (eventType === BEACON_EVENT_NAME) {
157      if (!playing) {
158        return;
159      }
160    }
161
162
163    if (!eventTime) {
164      eventTime = now;
165    }
166    var params = Object.assign({}, vrParams);
167    if (eventType === BEACON_EVENT_NAME || eventType === 'start') {
168      if (player.inAdBreak() || player.isWaitingForAdBreak()) {
169        params.u4 = 1;
170      }
171    }
172    firstPlayed = true;
173
174    AD_FIELDS_KEYS.forEach(function(key) {
175      if (typeof adFields[key] === 'string' && adFields[key].length > 0) {
176        params[key] = adFields[key];
177      }
178    });
179
180    // vr_tagid2
181    if (ua.indexOf('iPhone') != -1 || ua.indexOf('iPad') != -1 || ua.indexOf('iPod') != -1) {
182      // ios
183      params.vr_tagid2 = '0005';
184    } else if (ua.indexOf('Android') != -1) {
185      // android
186      params.vr_tagid2 = '0006';
187    } else {
188      // pc
189      params.vr_tagid2 = '0001';
190    }
191
192    // url
193    params.url = window.location.href;
194
195    // ref
196    params.ref = document.referrer;
197
198    // vr_opt2 mediaのIDを指定するならmedia.id、参照IDを指定するならmedia.refId
199    // パラメータから渡します
200
201    //+++ vr_opt3 再生時刻
202    const vrOpt3 = () => {
203      const currentTime = Math.floor(player.currentTime())
204      if (currentTime === 0) {
205        /**
206         * 0秒時点までシークした際にもログを送信するが、その際は0として送信する
207         * @see https://tver-inc.slack.com/archives/C016ESETKPC/p1738312083235949?thread_ts=1738033550.752209&cid=C016ESETKPC
208         */
209        return isSeeking ? 0 : 1
210      }
211
212      return currentTime
213    }
214    params.vr_opt3 = vrOpt3()
215
216    //+++ vr_opt4 動画尺
217    // パラメータから渡します
218
219    //+++ vr_opt6 局識別子
220    // パラメータから渡します
221
222    // vr_opt7
223    params.vr_opt7 = eventType;
224
225    // vr_opt9
226    params.vr_opt9 = vr_opt9;
227
228    //+++ vr_opt10 連番
229    params.vr_opt10 = ++vr_opt10;
230
231    //+++ vr_opt11 mediaのIDを指定するならmedia.id、参照IDを指定するならmedia.refId
232    // パラメータから渡します
233
234    //+++ vr_opt18
235    params.vr_opt18 = speed;
236
237    //+++ vt_opt19 TVerIDが発行するデバイス単位でユニークなID(非UUID形式、VR連携用の1st party ID)
238    // パラメータから渡します
239
240    //+++ vr_opt21 調査パートナーへの提供オプトアウト
241    // パラメータから渡します
242
243    //+++ vr_opt22 コンテンツ提供パートナーへのデータ提供オプトアウト
244    // パラメータから渡します
245
246    // id1 未指定
247    // params.id1 = window.vr_session_id;
248
249    // 将来的な拡張性を考えてパラメータを外部から組み上げられるようにする
250    if (typeof options.buildParams === 'function') {
251      _params = options.buildParams(player, params) || params;
252    } else {
253      _params = params;
254    }
255
256    var uri = endpoint + ((endpoint.indexOf('?') < 0) ? '?' : '&') + buildQueryString(_params);
257    var image = new Image();
258    image.addEventListener("load", function() {
259      if (options.debug) {
260        console.log('VR track OK : ' + uri, new Date());
261      }
262      if (eventType === 'pause' || eventType === "ended") {
263        return;
264      }
265    }, false);
266    image.src = uri;
267  };
268
269  var trackPlay = function() {
270    if (player.isWaitingForAdBreak()) {
271      return;
272    }
273    if (!started) {
274      track('start');
275    }
276    track('play');
277  };
278  var trackPause = function() {
279    track('pause');
280  };
281  var trackEnded = function() {
282    track('ended');
283  };
284  this.on('dispose', function() {
285    lastPC = null;
286    started = false;
287    ios_started = false;
288    firstPlayed = false;
289    if (playing) {
290      trackPause();
291    }
292  });
293  this.on('programchange', function() {
294    // イベントを取得できる時はイベントの情報をトラッキングする
295    var currentProgram = player.currentProgram();
296    // 同時配信のトラッキング中はイベント情報を投げる
297    if (currentProgram && currentProgram.refId) {
298      if (lastPC == currentProgram.refId) {
299        return;
300      }
301    }
302    if (started) {
303      started = false;
304      ios_started = false;
305      track('start');
306    }
307  });
308  this.on('loadstart', function() {
309    lastPC = null;
310    started = false;
311    ios_started = false;
312    firstPlayed = false;
313    if (playing) {
314      trackPause();
315    }
316  });
317  this.on('mediachange', function() {
318    lastPC = null;
319    started = false;
320    ios_started = false;
321    firstPlayed = false;
322    if (playing) {
323      trackPause();
324    }
325    media = (this.getMedia() || {});
326    lastPDT = NaN;
327    adFields = media.adFields || {};
328    duration = this.duration();
329  });
330  this.on('srcchange', function() {
331    lastPC = null;
332    started = false;
333    ios_started = false;
334    firstPlayed = false;
335    if (playing) {
336      trackPause();
337    }
338    media = (this.getMedia() || {});
339    lastPDT = NaN;
340    adFields = media.adFields || {};
341    duration = this.duration();
342  });
343  this.on('ratechange', function() {
344    var newSpeed = this.playbackRate();
345    if (newSpeed > 0) {
346      speed = newSpeed;
347    }
348  });
349  this.on('firstplay', function() {
350    media = (this.getMedia() || {});
351    firstPlayed = true;
352    lastPDT = NaN;
353    adFields = media.adFields || {};
354    duration = this.duration();
355
356    if (!this.isInAdMode()) {
357      trackPlay();
358    }
359  });
360  this.on('playing', function() {
361    trackPlay();
362  });
363  this.on('adbreakend', function() {
364    // if (is_ios && started && playing && !ios_started) {
365    //   track('ios_start');
366    // }
367  })
368  this.on('timeupdate', function() {
369    const duration = Math.floor(player.duration());
370    const currentTime = Math.floor(player.currentTime());
371    const vodEnded = currentTime === duration;
372    if (!this.paused()) {
373      trackPlay();
374    }
375    if (currentTime == 0 && !zeroFlag && playing) {
376      track();
377      zeroFlag = true
378    }
379    if (currentTime > 0 && zeroFlag) {
380      zeroFlag = false
381    }
382    if (currentTime % BEACON_INTERVAL == 0 && currentTime > 0 && currentTime != lastBeaconTime2) {
383      lastBeaconTime2 = currentTime;
384      track();
385    }
386    if (vodEnded && !ended) {
387      ended = true;
388      trackEnded();
389    } else if (!vodEnded && ended) {
390      ended = false
391    }
392  });
393  this.on('pause', function() {
394    trackPause();
395  });
396  this.on('ended', function() {
397  });
398  this.on("seeking", function() {
399    isSeeking = true
400  })
401  this.on('seeked', function() {
402    lastBeaconTime2 = 0;
403    isSeeking = false
404  });
405});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.