Outbound live stream notifications (#1663)
* First pass at browser, discord, twilio notifications * Commit updated Javascript packages * Remove twilio notification support * Email notifications/smtp support * Fix Firefox notification support, remove chrome checks * WIP more email work * Add support for twitter notifications * Add stream title to discord and twitter notifications * Update notification registration modal * Fix hide/show email section * Commit updated API documentation * Commit updated Javascript packages * Fix post-rebase missing var * Remove unused var * Handle unsubscribe errors for browser push * Standardize email config prop names * Allow overriding go live email template * Some notifications cleanup * Commit updated Javascript packages * Remove email/smtp/mailjet support * Remove more references to email notifications Co-authored-by: Owncast <owncast@owncast.online>
This commit is contained in:
@@ -25,6 +25,8 @@ import FediverseFollowModal, {
|
||||
FediverseFollowButton,
|
||||
} from './components/fediverse-follow-modal.js';
|
||||
|
||||
import { NotifyButton, NotifyModal } from './components/notification.js';
|
||||
import { isPushNotificationSupported } from './notification/registerWeb.js';
|
||||
import {
|
||||
addNewlines,
|
||||
checkUrlPathForDisplay,
|
||||
@@ -59,8 +61,10 @@ import {
|
||||
URL_STATUS,
|
||||
URL_VIEWER_PING,
|
||||
WIDTH_SINGLE_COL,
|
||||
USER_VISIT_COUNT_KEY,
|
||||
} from './utils/constants.js';
|
||||
import { checkIsModerator } from './utils/chat.js';
|
||||
|
||||
import TabBar from './components/tab-bar.js';
|
||||
|
||||
export default class App extends Component {
|
||||
@@ -138,6 +142,8 @@ export default class App extends Component {
|
||||
this.displayFediverseFollowModal =
|
||||
this.displayFediverseFollowModal.bind(this);
|
||||
this.closeFediverseFollowModal = this.closeFediverseFollowModal.bind(this);
|
||||
this.displayNotificationModal = this.displayNotificationModal.bind(this);
|
||||
this.closeNotificationModal = this.closeNotificationModal.bind(this);
|
||||
|
||||
// player events
|
||||
this.handlePlayerReady = this.handlePlayerReady.bind(this);
|
||||
@@ -179,8 +185,22 @@ export default class App extends Component {
|
||||
});
|
||||
this.player.init();
|
||||
|
||||
this.registerServiceWorker();
|
||||
|
||||
// check routing
|
||||
this.getRoute();
|
||||
|
||||
// Increment the visit counter
|
||||
this.incrementVisitCounter();
|
||||
}
|
||||
|
||||
incrementVisitCounter() {
|
||||
let visits = parseInt(getLocalStorage(USER_VISIT_COUNT_KEY));
|
||||
if (isNaN(visits)) {
|
||||
visits = 0;
|
||||
}
|
||||
|
||||
setLocalStorage(USER_VISIT_COUNT_KEY, visits + 1);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
@@ -248,7 +268,8 @@ export default class App extends Component {
|
||||
}
|
||||
|
||||
setConfigData(data = {}) {
|
||||
const { name, summary, chatDisabled, socketHostOverride } = data;
|
||||
const { name, summary, chatDisabled, socketHostOverride, notifications } =
|
||||
data;
|
||||
window.document.title = name;
|
||||
|
||||
this.socketHostOverride = socketHostOverride;
|
||||
@@ -263,6 +284,7 @@ export default class App extends Component {
|
||||
|
||||
this.setState({
|
||||
canChat: !chatDisabled,
|
||||
notifications,
|
||||
configData: {
|
||||
...data,
|
||||
summary: summary && addNewlines(summary),
|
||||
@@ -579,6 +601,23 @@ export default class App extends Component {
|
||||
this.setState({ fediverseModalData: null });
|
||||
}
|
||||
|
||||
displayNotificationModal(data) {
|
||||
this.setState({ notificationModalData: data });
|
||||
}
|
||||
closeNotificationModal() {
|
||||
this.setState({ notificationModalData: null });
|
||||
}
|
||||
|
||||
async registerServiceWorker() {
|
||||
try {
|
||||
const reg = await navigator.serviceWorker.register('/serviceWorker.js', {
|
||||
scope: '/',
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Owncast service worker registration failed!', err);
|
||||
}
|
||||
}
|
||||
|
||||
handleWebsocketMessage(e) {
|
||||
if (e.type === SOCKET_MESSAGE_TYPES.ERROR_USER_DISABLED) {
|
||||
// User has been actively disabled on the backend. Turn off chat for them.
|
||||
@@ -670,6 +709,7 @@ export default class App extends Component {
|
||||
|
||||
render(props, state) {
|
||||
const {
|
||||
accessToken,
|
||||
chatInputEnabled,
|
||||
configData,
|
||||
displayChatPanel,
|
||||
@@ -690,6 +730,8 @@ export default class App extends Component {
|
||||
windowWidth,
|
||||
fediverseModalData,
|
||||
externalActionModalData,
|
||||
notificationModalData,
|
||||
notifications,
|
||||
lastDisconnectTime,
|
||||
section,
|
||||
sectionId,
|
||||
@@ -753,6 +795,14 @@ export default class App extends Component {
|
||||
: html` <${VideoPoster} offlineImage=${logo} active=${streamOnline} /> `;
|
||||
|
||||
// modal buttons
|
||||
const notificationsButton =
|
||||
notifications &&
|
||||
notifications.browser.enabled &&
|
||||
isPushNotificationSupported() &&
|
||||
html`<${NotifyButton}
|
||||
serverName=${name}
|
||||
onClick=${this.displayNotificationModal}
|
||||
/>`;
|
||||
const externalActionButtons = html`<div
|
||||
id="external-actions-container"
|
||||
class="flex flex-row flex-wrap justify-end"
|
||||
@@ -774,6 +824,7 @@ export default class App extends Component {
|
||||
federationInfo=${federation}
|
||||
serverName=${name}
|
||||
/>`}
|
||||
${notificationsButton}
|
||||
</div>`;
|
||||
|
||||
// modal component
|
||||
@@ -800,6 +851,19 @@ export default class App extends Component {
|
||||
/>
|
||||
`;
|
||||
|
||||
const notificationModal =
|
||||
notificationModalData &&
|
||||
html` <${ExternalActionModal}
|
||||
onClose=${this.closeNotificationModal}
|
||||
action=${notificationModalData}
|
||||
useIframe=${false}
|
||||
customContent=${html`<${NotifyModal}
|
||||
notifications=${notifications}
|
||||
streamName=${name}
|
||||
accessToken=${accessToken}
|
||||
/>`}
|
||||
/>`;
|
||||
|
||||
const chat = this.state.websocket
|
||||
? html`
|
||||
<${Chat}
|
||||
@@ -807,7 +871,7 @@ export default class App extends Component {
|
||||
username=${username}
|
||||
chatInputEnabled=${chatInputEnabled && !chatDisabled}
|
||||
instanceTitle=${name}
|
||||
accessToken=${this.state.accessToken}
|
||||
accessToken=${accessToken}
|
||||
inputMaxBytes=${maxSocketPayloadSize - EST_SOCKET_PAYLOAD_BUFFER ||
|
||||
CHAT_MAX_MESSAGE_LENGTH}
|
||||
/>
|
||||
@@ -977,6 +1041,7 @@ export default class App extends Component {
|
||||
</footer>
|
||||
|
||||
${chat} ${externalActionModal} ${fediverseFollowModal}
|
||||
${notificationModal}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user