1+ import { BountyBoardStatus , BountyStatus , WebhookType } from "~/common/constants" ;
12import { countBounties } from "~/common/helpers" ;
2- import { Bounty } from "~/common/types" ;
3+ import { Bounty , Webhook } from "~/common/types" ;
34
4- import { getBounties , getBountyBoardSettings } from "./twitch" ;
5+ import { applyMigrations } from "./migrations" ;
6+ import { getBounties , getBountyBoardSettings , getLogin } from "./twitch" ;
57
68function getIconUrl ( color : string , size : number ) {
79 return browser . runtime . getURL ( `icon-${ color } -${ size } .png` ) ;
@@ -21,7 +23,7 @@ async function fetchStatus() {
2123 const [ { data } ] = await getBountyBoardSettings ( ) ;
2224
2325 if ( data == null ) {
24- return "NONE" ;
26+ return BountyBoardStatus . None ;
2527 }
2628
2729 const {
@@ -58,10 +60,10 @@ async function fetchBounties() {
5860
5961 get date ( ) {
6062 switch ( node . status ) {
61- case "COMPLETED" :
63+ case BountyStatus . Completed :
6264 return Date . parse ( node . trackingStoppedAt ) ;
6365
64- case "LIVE" :
66+ case BountyStatus . Live :
6567 return Date . parse ( node . expiresAt ) ;
6668 }
6769
@@ -70,7 +72,7 @@ async function fetchBounties() {
7072
7173 get amount ( ) {
7274 switch ( node . status ) {
73- case "COMPLETED" :
75+ case BountyStatus . Completed :
7476 return node . payoutCents / 100 ;
7577 }
7678
@@ -80,27 +82,29 @@ async function fetchBounties() {
8082 campaign : {
8183 id : campaign . id ,
8284 title : campaign . title ,
85+ sponsor : campaign . sponsor ,
86+ displayName : campaign . displayName || campaign . game . displayName ,
8387 boxArtUrl : campaign . boxArtURL || campaign . game . boxArtURL ,
8488 } ,
8589 } ;
8690 } ) ;
8791 } ) ;
8892}
8993
90- async function refreshBounties ( ) {
94+ async function refresh ( ) {
9195 let bounties = new Array < Bounty > ( ) ;
9296 let active = false ;
9397
9498 try {
9599 const status = await fetchStatus ( ) ;
96100
97- if ( status === "ACCEPTED" ) {
101+ if ( status === BountyBoardStatus . Accepted ) {
98102 bounties = await fetchBounties ( ) ;
99103 active = true ;
100104 }
101105 } catch { } // eslint-disable-line no-empty
102106
103- const badgeCount = countBounties ( bounties , "AVAILABLE" ) ;
107+ const badgeCount = countBounties ( bounties , BountyStatus . Available ) ;
104108 const color = active ? "purple" : "gray" ;
105109
106110 browser . storage . session . set ( {
@@ -127,21 +131,122 @@ async function refreshBounties() {
127131 } ) ;
128132}
129133
134+ async function formatTestWebhook ( webhook : Webhook ) {
135+ const login = await getLogin ( ) ;
136+
137+ switch ( webhook . type ) {
138+ case WebhookType . Discord :
139+ return {
140+ username : browser . i18n . getMessage ( "extensionName" ) ,
141+ avatar_url : "https://github.com/Seldszar/Coco/raw/main/public/icon-purple-96.png" ,
142+ content : browser . i18n . getMessage ( "testWebhook_messageContent" , login ) ,
143+ } ;
144+
145+ case WebhookType . Slack :
146+ return {
147+ text : browser . i18n . getMessage ( "testWebhook_messageContent" , login ) ,
148+ } ;
149+ }
150+
151+ throw new RangeError ( "Webhook type not supported" ) ;
152+ }
153+
154+ async function formatBountyWebhook ( webhook : Webhook , bounty : Bounty ) {
155+ const login = await getLogin ( ) ;
156+
157+ switch ( webhook . type ) {
158+ case WebhookType . Discord :
159+ return {
160+ username : browser . i18n . getMessage ( "extensionName" ) ,
161+ avatar_url : "https://github.com/Seldszar/Coco/raw/main/public/icon-purple-96.png" ,
162+ content : browser . i18n . getMessage ( "bountyWebhook_messageContent" , login ) ,
163+ embeds : [
164+ {
165+ title : bounty . campaign . sponsor ,
166+ description : bounty . campaign . title ,
167+ url : "https://dashboard.twitch.tv/bounties" ,
168+ color : "11032055" ,
169+ thumbnail : {
170+ url : bounty . campaign . boxArtUrl ,
171+ } ,
172+ footer : {
173+ text : browser . i18n . getMessage ( "extensionName" ) ,
174+ icon_url : "https://github.com/Seldszar/Coco/raw/main/public/icon-purple-32.png" ,
175+ } ,
176+ } ,
177+ ] ,
178+ } ;
179+
180+ case WebhookType . Slack :
181+ return {
182+ text : browser . i18n . getMessage ( "bountyWebhook_messageContent" , login ) ,
183+ blocks : [
184+ {
185+ type : "actions" ,
186+ elements : [
187+ {
188+ type : "section" ,
189+ text : {
190+ type : "mrkdwn" ,
191+ text : `*<https://dashboard.twitch.tv/bounties|${ bounty . campaign . sponsor } >*\n${ bounty . campaign . title } ` ,
192+ } ,
193+ accessory : {
194+ type : "image" ,
195+ image_url : bounty . campaign . boxArtUrl ,
196+ alt_text : bounty . campaign . title ,
197+ } ,
198+ } ,
199+ {
200+ type : "button" ,
201+ url : "https://dashboard.twitch.tv/bounties" ,
202+ text : {
203+ type : "plain_text" ,
204+ text : browser . i18n . getMessage ( "bountyWebhook_buttonLabel" ) ,
205+ } ,
206+ } ,
207+ ] ,
208+ } ,
209+ ] ,
210+ } ;
211+ }
212+
213+ throw new RangeError ( "Webhook type not supported" ) ;
214+ }
215+
216+ async function executeWebhook ( webhook : Webhook , body : any ) {
217+ return fetch ( webhook . url , {
218+ headers : [ [ "Content-Type" , "application/json" ] ] ,
219+ body : JSON . stringify ( body ) ,
220+ method : "POST" ,
221+ } ) ;
222+ }
223+
224+ async function executeTestWebhook ( webhook : Webhook ) {
225+ return executeWebhook ( webhook , await formatTestWebhook ( webhook ) ) ;
226+ }
227+
228+ async function executeBountyWebhook ( webhook : Webhook , bounty : Bounty ) {
229+ return executeWebhook ( webhook , await formatBountyWebhook ( webhook , bounty ) ) ;
230+ }
231+
130232async function checkAlarm ( ) {
131233 if ( await browser . alarms . get ( ) ) {
132234 return ;
133235 }
134236
135- refreshBounties ( ) ;
237+ refresh ( ) ;
136238}
137239
138240browser . runtime . onMessage . addListener ( async ( message ) => {
139241 switch ( message . type ) {
242+ case "executeTestWebhook" :
243+ return executeTestWebhook ( message . data ) ;
244+
140245 case "openBountyBoard" :
141246 return openBountyBoard ( ) ;
142247
143- case "refreshBounties " :
144- return refreshBounties ( ) ;
248+ case "refresh " :
249+ return refresh ( ) ;
145250 }
146251
147252 throw new RangeError ( "Unknown message type" ) ;
@@ -153,7 +258,8 @@ browser.storage.onChanged.addListener(async (changes) => {
153258 if ( bounties == null ) {
154259 return ;
155260 }
156- const { newValue = [ ] , oldValue } = bounties ;
261+
262+ const { newValue, oldValue } = bounties ;
157263
158264 if ( oldValue == null ) {
159265 return ;
@@ -162,20 +268,21 @@ browser.storage.onChanged.addListener(async (changes) => {
162268 const { settings } = await browser . storage . local . get ( {
163269 settings : {
164270 notifications : false ,
271+ webhooks : [ ] ,
165272 } ,
166273 } ) ;
167274
168- if ( settings . notifications ) {
169- const newBounties = newValue . filter (
170- ( newItem ) =>
171- newItem . status === "AVAILABLE" &&
172- oldValue . every ( ( oldItem ) => newItem . campaign . id !== oldItem . campaign . id ) ,
173- ) ;
174-
175- if ( newBounties . length === 0 ) {
176- return ;
177- }
275+ const newBounties = newValue . filter (
276+ ( newItem : Bounty ) =>
277+ newItem . status === BountyStatus . Available &&
278+ oldValue . every ( ( oldItem : Bounty ) => newItem . campaign . id !== oldItem . campaign . id ) ,
279+ ) ;
178280
281+ if ( newBounties . length === 0 ) {
282+ return ;
283+ }
284+
285+ if ( settings . notifications ) {
179286 newBounties . forEach ( ( bounty : Bounty ) => {
180287 browser . notifications . create ( {
181288 iconUrl : getIconUrl ( "purple" , 96 ) ,
@@ -185,11 +292,19 @@ browser.storage.onChanged.addListener(async (changes) => {
185292 } ) ;
186293 } ) ;
187294 }
295+
296+ settings . webhooks . forEach ( ( webhook : Webhook ) => {
297+ newBounties . forEach ( ( bounty : Bounty ) => executeBountyWebhook ( webhook , bounty ) ) ;
298+ } ) ;
299+ } ) ;
300+
301+ browser . runtime . onInstalled . addListener ( async ( ) => {
302+ await applyMigrations ( ) ;
303+ await refresh ( ) ;
188304} ) ;
189305
190- browser . runtime . onInstalled . addListener ( refreshBounties ) ;
191- browser . runtime . onStartup . addListener ( refreshBounties ) ;
192- browser . alarms . onAlarm . addListener ( refreshBounties ) ;
306+ browser . runtime . onStartup . addListener ( refresh ) ;
307+ browser . alarms . onAlarm . addListener ( refresh ) ;
193308
194309browser . action . onClicked . addListener ( openBountyBoard ) ;
195310browser . notifications . onClicked . addListener ( openBountyBoard ) ;
0 commit comments