summaryrefslogtreecommitdiffstats
path: root/assets/js/notifications.js
diff options
context:
space:
mode:
authorCaian Benedicto <caianbene@gmail.com>2024-12-13 18:29:28 -0300
committerCaian Benedicto <caianbene@gmail.com>2024-12-13 20:26:52 -0300
commitd7f5cdc2f971af524c496aaeb25226eb9f8236df (patch)
tree1e69d1088ee67407b1058f490cc188cd1dd4e287 /assets/js/notifications.js
parent78773d732672d8985795fb040a39dd7e946c7b7c (diff)
parent98926047586154269bb269d01e3e52e60e044035 (diff)
downloadinvidious-d7f5cdc2f971af524c496aaeb25226eb9f8236df.tar.gz
invidious-d7f5cdc2f971af524c496aaeb25226eb9f8236df.tar.bz2
invidious-d7f5cdc2f971af524c496aaeb25226eb9f8236df.zip
Merge branch 'master' into unix-sockets
Diffstat (limited to 'assets/js/notifications.js')
-rw-r--r--assets/js/notifications.js216
1 files changed, 102 insertions, 114 deletions
diff --git a/assets/js/notifications.js b/assets/js/notifications.js
index 3d1ec1ed..55b7a15c 100644
--- a/assets/js/notifications.js
+++ b/assets/js/notifications.js
@@ -1,46 +1,30 @@
-var notification_data = JSON.parse(document.getElementById('notification_data').innerHTML);
+'use strict';
+var notification_data = JSON.parse(document.getElementById('notification_data').textContent);
-var notifications, delivered;
-
-function get_subscriptions(callback, retries) {
- if (retries == undefined) retries = 5;
-
- if (retries <= 0) {
- return;
- }
-
- var xhr = new XMLHttpRequest();
- xhr.responseType = 'json';
- xhr.timeout = 10000;
- xhr.open('GET', '/api/v1/auth/subscriptions?fields=authorId', true);
-
- xhr.onreadystatechange = function () {
- if (xhr.readyState === 4) {
- if (xhr.status === 200) {
- subscriptions = xhr.response;
- callback(subscriptions);
- }
- }
- }
+/** 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';
- xhr.onerror = function () {
- console.log('Pulling subscriptions failed... ' + retries + '/5');
- setTimeout(function () { get_subscriptions(callback, retries - 1) }, 1000);
- }
-
- xhr.ontimeout = function () {
- console.log('Pulling subscriptions failed... ' + retries + '/5');
- get_subscriptions(callback, retries - 1);
- }
-
- xhr.send();
+var notifications, delivered;
+var notifications_mock = { close: function () { } };
+
+function get_subscriptions() {
+ helpers.xhr('GET', '/api/v1/auth/subscriptions', {
+ retries: 5,
+ entity_name: 'subscriptions'
+ }, {
+ on200: create_notification_stream
+ });
}
function create_notification_stream(subscriptions) {
+ // 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
notifications = new SSE(
- '/api/v1/auth/notifications?fields=videoId,title,author,authorId,publishedText,published,authorThumbnails,liveNow', {
+ '/api/v1/auth/notifications', {
withCredentials: true,
- payload: 'topics=' + subscriptions.map(function (subscription) { return subscription.authorId }).join(','),
+ payload: 'topics=' + subscriptions.map(function (subscription) { return subscription.authorId; }).join(','),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
delivered = [];
@@ -48,96 +32,100 @@ function create_notification_stream(subscriptions) {
var start_time = Math.round(new Date() / 1000);
notifications.onmessage = function (event) {
- if (!event.id) {
- return;
- }
+ if (!event.id) return;
var notification = JSON.parse(event.data);
- console.log('Got notification:', notification);
-
- if (start_time < notification.published && !delivered.includes(notification.videoId)) {
- if (Notification.permission === 'granted') {
- var system_notification =
- new Notification((notification.liveNow ? notification_data.live_now_text : notification_data.upload_text).replace('`x`', notification.author), {
- body: notification.title,
- icon: '/ggpht' + new URL(notification.authorThumbnails[2].url).pathname,
- img: '/ggpht' + new URL(notification.authorThumbnails[4].url).pathname,
- tag: notification.videoId
- });
-
- system_notification.onclick = function (event) {
- window.open('/watch?v=' + event.currentTarget.tag, '_blank');
- }
- }
-
- delivered.push(notification.videoId);
- localStorage.setItem('notification_count', parseInt(localStorage.getItem('notification_count') || '0') + 1);
- var notification_ticker = document.getElementById('notification_ticker');
-
- if (parseInt(localStorage.getItem('notification_count')) > 0) {
- notification_ticker.innerHTML =
- '<span id="notification_count">' + localStorage.getItem('notification_count') + '</span> <i class="icon ion-ios-notifications"></i>';
- } else {
- notification_ticker.innerHTML =
- '<i class="icon ion-ios-notifications-outline"></i>';
- }
+ console.info('Got notification:', notification);
+
+ // 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();
+
+ // permission for notifications handled on settings page. JS handler is in handlers.js
+ 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);
+
+ 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
+ });
+
+ system_notification.onclick = function (e) {
+ open('/watch?v=' + notification.videoId, '_blank');
+ };
}
- }
+ };
- notifications.addEventListener('error', handle_notification_error);
- notifications.stream();
-}
+ notifications.addEventListener('error', function (e) {
+ console.warn('Something went wrong with notifications, trying to reconnect...');
+ notifications = notifications_mock;
+ setTimeout(get_subscriptions, 1000);
+ });
-function handle_notification_error(event) {
- console.log('Something went wrong with notifications, trying to reconnect...');
- notifications = { close: function () { } };
- setTimeout(function () { get_subscriptions(create_notification_stream) }, 1000);
+ notifications.stream();
}
-window.addEventListener('load', function (e) {
- localStorage.setItem('notification_count', document.getElementById('notification_count') ? document.getElementById('notification_count').innerText : '0');
+function update_ticker_count() {
+ var notification_ticker = document.getElementById('notification_ticker');
- if (localStorage.getItem('stream')) {
- localStorage.removeItem('stream');
+ 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>';
} else {
- setTimeout(function () {
- if (!localStorage.getItem('stream')) {
- notifications = { close: function () { } };
- localStorage.setItem('stream', true);
- get_subscriptions(create_notification_stream);
- }
- }, Math.random() * 1000 + 50);
+ notification_ticker.innerHTML =
+ '<i class="icon ion-ios-notifications-outline"></i>';
}
+}
- window.addEventListener('storage', function (e) {
- if (e.key === 'stream' && !e.newValue) {
- if (notifications) {
- localStorage.setItem('stream', true);
- } else {
- setTimeout(function () {
- if (!localStorage.getItem('stream')) {
- notifications = { close: function () { } };
- localStorage.setItem('stream', true);
- get_subscriptions(create_notification_stream);
- }
- }, Math.random() * 1000 + 50);
- }
- } else if (e.key === 'notification_count') {
- var notification_ticker = document.getElementById('notification_ticker');
-
- if (parseInt(e.newValue) > 0) {
- notification_ticker.innerHTML =
- '<span id="notification_count">' + e.newValue + '</span> <i class="icon ion-ios-notifications"></i>';
- } else {
- notification_ticker.innerHTML =
- '<i class="icon ion-ios-notifications-outline"></i>';
- }
+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
+}
+
+
+addEventListener('storage', function (e) {
+ if (e.key === STORAGE_KEY_NOTIF_COUNT)
+ update_ticker_count();
-window.addEventListener('unload', function (e) {
- if (notifications) {
- localStorage.removeItem('stream');
+ // 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();
+ }
}
});
+
+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();
+});
+
+addEventListener('unload', function () {
+ // let chance to other tabs to be a streamer via firing 'storage' event
+ if (notifications) helpers.storage.remove(STORAGE_KEY_STREAM);
+});