Notifier.js 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import { formatMessage, formatTitleWithDefault, openUrl, playSound, topicDisplayName, topicShortUrl } from "./utils";
  2. import prefs from "./Prefs";
  3. import subscriptionManager from "./SubscriptionManager";
  4. import logo from "../img/ntfy.png";
  5. /**
  6. * The notifier is responsible for displaying desktop notifications. Note that not all modern browsers
  7. * support this; most importantly, all iOS browsers do not support window.Notification.
  8. */
  9. class Notifier {
  10. async notify(subscriptionId, notification, onClickFallback) {
  11. if (!this.supported()) {
  12. return;
  13. }
  14. const subscription = await subscriptionManager.get(subscriptionId);
  15. const shouldNotify = await this.shouldNotify(subscription, notification);
  16. if (!shouldNotify) {
  17. return;
  18. }
  19. const shortUrl = topicShortUrl(subscription.baseUrl, subscription.topic);
  20. const displayName = topicDisplayName(subscription);
  21. const message = formatMessage(notification);
  22. const title = formatTitleWithDefault(notification, displayName);
  23. // Show notification
  24. console.log(`[Notifier, ${shortUrl}] Displaying notification ${notification.id}: ${message}`);
  25. const n = new Notification(title, {
  26. body: message,
  27. icon: logo,
  28. });
  29. if (notification.click) {
  30. n.onclick = () => openUrl(notification.click);
  31. } else {
  32. n.onclick = () => onClickFallback(subscription);
  33. }
  34. // Play sound
  35. const sound = await prefs.sound();
  36. if (sound && sound !== "none") {
  37. try {
  38. await playSound(sound);
  39. } catch (e) {
  40. console.log(`[Notifier, ${shortUrl}] Error playing audio`, e);
  41. }
  42. }
  43. }
  44. granted() {
  45. return this.supported() && Notification.permission === "granted";
  46. }
  47. maybeRequestPermission(cb) {
  48. if (!this.supported()) {
  49. cb(false);
  50. return;
  51. }
  52. if (!this.granted()) {
  53. Notification.requestPermission().then((permission) => {
  54. const granted = permission === "granted";
  55. cb(granted);
  56. });
  57. }
  58. }
  59. async shouldNotify(subscription, notification) {
  60. if (subscription.mutedUntil === 1) {
  61. return false;
  62. }
  63. const priority = notification.priority ? notification.priority : 3;
  64. const minPriority = await prefs.minPriority();
  65. if (priority < minPriority) {
  66. return false;
  67. }
  68. return true;
  69. }
  70. supported() {
  71. return this.browserSupported() && this.contextSupported();
  72. }
  73. browserSupported() {
  74. return "Notification" in window;
  75. }
  76. /**
  77. * Returns true if this is a HTTPS site, or served over localhost. Otherwise the Notification API
  78. * is not supported, see https://developer.mozilla.org/en-US/docs/Web/API/notification
  79. */
  80. contextSupported() {
  81. return window.location.protocol === "https:" || window.location.hostname.match("^127.") || window.location.hostname === "localhost";
  82. }
  83. }
  84. const notifier = new Notifier();
  85. export default notifier;