2022-04-20 10:38:24 +02:00
'use strict' ;
2022-04-20 12:40:30 +02:00
var notification _data = JSON . parse ( document . getElementById ( 'notification_data' ) . textContent ) ;
2020-03-15 22:46:08 +01:00
2022-05-21 12:35:41 +02:00
/** Boolean meaning 'some tab have stream' */
const STORAGE _KEY _STREAM = 'stream' ;
/** Number of notifications. May be increased or reset */
const STORAGE _KEY _NOTIF _COUNT = 'notification_count' ;
2019-05-05 14:46:01 +02:00
var notifications , delivered ;
2022-05-21 12:35:41 +02:00
var notifications _mock = { close : function ( ) { } } ;
2022-05-06 03:46:59 +02:00
function get _subscriptions ( ) {
2023-11-20 17:43:57 +01:00
helpers . xhr ( 'GET' , '/api/v1/auth/subscriptions' , {
2022-05-06 03:46:59 +02:00
retries : 5 ,
entity _name : 'subscriptions'
} , {
on200 : create _notification _stream
} ) ;
2019-05-05 14:46:01 +02:00
}
function create _notification _stream ( subscriptions ) {
2022-05-06 03:46:59 +02:00
// sse.js can't be replaced to EventSource in place as it lack support of payload and headers
// see https://developer.mozilla.org/en-US/docs/Web/API/EventSource/EventSource
2019-05-05 14:46:01 +02:00
notifications = new SSE (
2023-11-20 17:43:57 +01:00
'/api/v1/auth/notifications' , {
2019-05-05 14:46:01 +02:00
withCredentials : true ,
2022-04-20 11:05:19 +02:00
payload : 'topics=' + subscriptions . map ( function ( subscription ) { return subscription . authorId ; } ) . join ( ',' ) ,
2019-05-05 14:46:01 +02:00
headers : { 'Content-Type' : 'application/x-www-form-urlencoded' }
} ) ;
delivered = [ ] ;
var start _time = Math . round ( new Date ( ) / 1000 ) ;
notifications . onmessage = function ( event ) {
2022-05-06 03:46:59 +02:00
if ( ! event . id ) return ;
2019-05-05 14:46:01 +02:00
var notification = JSON . parse ( event . data ) ;
2022-04-20 15:36:03 +02:00
console . info ( 'Got notification:' , notification ) ;
2019-05-05 14:46:01 +02:00
2022-05-21 12:35:41 +02:00
// Ignore not actual and delivered notifications
if ( start _time > notification . published || delivered . includes ( notification . videoId ) ) return ;
delivered . push ( notification . videoId ) ;
let notification _count = helpers . storage . get ( STORAGE _KEY _NOTIF _COUNT ) || 0 ;
notification _count ++ ;
helpers . storage . set ( STORAGE _KEY _NOTIF _COUNT , notification _count ) ;
update _ticker _count ( ) ;
2022-05-21 18:30:51 +02:00
// permission for notifications handled on settings page. JS handler is in handlers.js
2022-05-21 12:35:41 +02:00
if ( window . Notification && Notification . permission === 'granted' ) {
var notification _text = notification . liveNow ? notification _data . live _now _text : notification _data . upload _text ;
notification _text = notification _text . replace ( '`x`' , notification . author ) ;
2022-06-05 19:54:48 +02:00
2022-05-21 12:35:41 +02:00
var system _notification = new Notification ( notification _text , {
body : notification . title ,
icon : '/ggpht' + new URL ( notification . authorThumbnails [ 2 ] . url ) . pathname ,
img : '/ggpht' + new URL ( notification . authorThumbnails [ 4 ] . url ) . pathname
} ) ;
2022-06-05 19:54:48 +02:00
2022-05-21 12:35:41 +02:00
system _notification . onclick = function ( e ) {
open ( '/watch?v=' + notification . videoId , '_blank' ) ;
2022-05-21 18:30:51 +02:00
} ;
2019-05-05 14:46:01 +02:00
}
2022-04-20 11:05:19 +02:00
} ;
2019-05-05 14:46:01 +02:00
2022-05-21 12:35:41 +02:00
notifications . addEventListener ( 'error' , function ( e ) {
console . warn ( 'Something went wrong with notifications, trying to reconnect...' ) ;
notifications = notifications _mock ;
setTimeout ( get _subscriptions , 1000 ) ;
} ) ;
2019-05-05 14:46:01 +02:00
notifications . stream ( ) ;
}
2022-05-21 12:35:41 +02:00
function update _ticker _count ( ) {
var notification _ticker = document . getElementById ( 'notification_ticker' ) ;
2019-06-17 01:11:34 +02:00
2022-05-21 12:35:41 +02:00
const notification _count = helpers . storage . get ( STORAGE _KEY _STREAM ) ;
if ( notification _count > 0 ) {
notification _ticker . innerHTML =
'<span id="notification_count">' + notification _count + '</span> <i class="icon ion-ios-notifications"></i>' ;
2022-05-06 06:21:19 +02:00
} else {
2022-05-21 12:35:41 +02:00
notification _ticker . innerHTML =
'<i class="icon ion-ios-notifications-outline"></i>' ;
2022-05-06 06:21:19 +02:00
}
2022-05-21 12:35:41 +02:00
}
function start _stream _if _needed ( ) {
// random wait for other tabs set 'stream' flag
setTimeout ( function ( ) {
if ( ! helpers . storage . get ( STORAGE _KEY _STREAM ) ) {
// if no one set 'stream', set it by yourself and start stream
helpers . storage . set ( STORAGE _KEY _STREAM , true ) ;
notifications = notifications _mock ;
get _subscriptions ( ) ;
}
} , Math . random ( ) * 1000 + 50 ) ; // [0.050 .. 1.050) second
}
2019-05-05 14:46:01 +02:00
2019-06-02 00:38:49 +02:00
2022-05-21 12:35:41 +02:00
addEventListener ( 'storage' , function ( e ) {
if ( e . key === STORAGE _KEY _NOTIF _COUNT )
update _ticker _count ( ) ;
// if 'stream' key was removed
if ( e . key === STORAGE _KEY _STREAM && ! helpers . storage . get ( STORAGE _KEY _STREAM ) ) {
if ( notifications ) {
// restore it if we have active stream
helpers . storage . set ( STORAGE _KEY _STREAM , true ) ;
} else {
start _stream _if _needed ( ) ;
2019-06-02 00:38:49 +02:00
}
2022-05-21 12:35:41 +02:00
}
} ) ;
addEventListener ( 'load' , function ( ) {
var notification _count _el = document . getElementById ( 'notification_count' ) ;
var notification _count = notification _count _el ? parseInt ( notification _count _el . textContent ) : 0 ;
helpers . storage . set ( STORAGE _KEY _NOTIF _COUNT , notification _count ) ;
if ( helpers . storage . get ( STORAGE _KEY _STREAM ) )
helpers . storage . remove ( STORAGE _KEY _STREAM ) ;
start _stream _if _needed ( ) ;
2019-05-05 14:46:01 +02:00
} ) ;
2022-05-21 12:35:41 +02:00
addEventListener ( 'unload' , function ( ) {
// let chance to other tabs to be a streamer via firing 'storage' event
if ( notifications ) helpers . storage . remove ( STORAGE _KEY _STREAM ) ;
2019-05-05 14:46:01 +02:00
} ) ;