|
#!/usr/local/bin/node |
|
|
|
// <xbar.title>GitHub Notifications</xbar.title> |
|
// <xbar.version>v1.0</xbar.version> |
|
// <xbar.author>Alexey Lebedev</xbar.author> |
|
// <xbar.author.github>alisey</xbar.author.github> |
|
// <xbar.desc>Shows the number of unread GitHub notifications.</xbar.desc> |
|
// <xbar.dependencies>node</xbar.dependencies> |
|
// <xbar.var>string(GITHUB_ACCESS_TOKEN=""): GitHub personal access token with permission to access notifications.</xbar.var> |
|
|
|
const https = require('https'); |
|
|
|
const { GITHUB_ACCESS_TOKEN } = process.env; |
|
|
|
const gitHubLogo36Px = |
|
'iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6' + |
|
'JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAhGVYSWZNTQAqAAAACAAFARIAAwAAAAEA' + |
|
'AQAAARoABQAAAAEAAABKARsABQAAAAEAAABSASgAAwAAAAEAAgAAh2kABAAAAAEAAABaAAAAAAAAAJAA' + |
|
'AAABAAAAkAAAAAEAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAJKADAAQAAAABAAAAJAAAAAA4NgJpAAAA' + |
|
'CXBIWXMAABYlAAAWJQFJUiTwAAABWWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4' + |
|
'bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJE' + |
|
'RiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgog' + |
|
'ICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJo' + |
|
'dHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8' + |
|
'L3RpZmY6T3JpZW50YXRpb24+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+Cjwv' + |
|
'eDp4bXBtZXRhPgoZXuEHAAAEgElEQVRYCb1YP1MbRxTftydsJ2SQRBrGmHCO7Jl0EV06RJcu+BNYfALz' + |
|
'DYyrTKpA5w67TGVcuuLSxZWVLjPBYckgT9LEF3ucYWJpX37vTicvsCtOQpOdgX37/u3j/dn3DlJjroU4' + |
|
'jitWf8OamszcIkU1qJAfWalSbFiR0cxJT9unfxhjMkrJX1SSTy0uNdpKq7vgb5WVyfm4o5i2u7+/fFxG' + |
|
'7kKDFm7cakWR3VWK4jIKR/AYxWrrIsOikIJaHNc+nZv/Vmv1EMYUIQmxl8HXFKn1uWq9FtWrz0/S9MQn' + |
|
'5PWQ5EnE+gkMafqEpoAzfeqv+fLrnEEDY/anEKKL7PYapV0pCRM8838YI9dmUZA7XRtO5ZDkjCL62mWA' + |
|
'C/eI+CERScy/cGljwAl0bKPa/kQeOWlAC1eYrr39+/WzQtcwZIOyRjWdXtSntePjg0SwWThttAWld+XM' + |
|
'eHPwDhkilTIXbxHjLx7mXoJc2ShyJU+H6FBk3eXe8cGg5c/BSLHLKPA76tdTY1IXL4rhrvQsvuCRMMyq' + |
|
'mbhrfu0UuGJfXG5wATu76R69vCnnzKCQd4TBZ5DgJ10Bg8TdbXmj8qTWdC90wSe9ihPzEFc5vHg2yEmq' + |
|
'LTSdM3Hw0l6lZ4RxGuta1uuk33lXS2zRkdLrXjKQxPSgSMgQzzh49NkUVfwgJENWr2tcuhpi6OneoxBt' + |
|
'UnzXHGxD1uslrehLjVEhBoNvJdP0jnsBs33qnocwqRaSmuMhwgVYGfc4XZhCumtSZbXpXnYpbZlBl9Iw' + |
|
'iTAev6ATxEPeBGMKPwWTGOHKoC8uu2cHTiWHvAahR8VnO7EjeCkQPbDpUyC9EbM4/+gjAlf7yOp2gDYx' + |
|
'emmpse7rmZlCpiNNmjoh7Zro3rS9ZDV/H7oPHkp0X9m9EAPw8ayNggpGyHlJ1z9r7Aa9AwnWdg8JrxQ6' + |
|
'8D62lsCB5R03A7zn0PmXC98HoXWOOEDAO51XR7+tVLIzqcdo/xkzK2VeYTZZjG/jQ7D/RJJbwVMRR4cw' + |
|
'PCHmvZ7VP59Uep1R89DM+5n4atRfZSLkDLegY+RC5W0LQ+YhAa5jQBtcLsfMI9Kd/2X9wsELLV8YF7rG' + |
|
'//F3I77VQrGI10utwgnCjLLPF7J7o4Cxi0d2pTsTRXdwTh2ajK6dkDHCd2yykTdxZUbBRGqroA+H/Dfp' + |
|
'X6Zana/DZ18NiPFcdR6j5cGz2Xr1B80aNLRiop/Y0s7bN69/KZT4dnwQroC50OVjyXGsdjC+flcw5Dk0' + |
|
'OFV0f+s961VEspmhiDdR9sU/DNqFUJkdYUiH+RAQkFD9gztd8jBkgpQQ9cneQUhMzkTNWY5eSJXk5/z3' + |
|
'NN4mMcbi6/VsYZwySK6TGciSXftgFPIp4n0ZziXxZf/Y6k3XwPFh7ogxvnnrnEGFUVfIriBldtzLvNXm' + |
|
'MpSBofMd/mCfMSJ+KodcfRI+nDcX40YHJXz/ssZIiNCKNo6P8o9O9y4X9nrIZUB5P8ILehPVJ89CIjT0' + |
|
'v0PZRy3wmAE9gWxbHtvBczBKbHzaOAmNr5p43Bv+A9+MtJjLYYqGAAAAAElFTkSuQmCC'; |
|
|
|
async function httpsRequest(options, data = '') { |
|
return new Promise((resolve, reject) => { |
|
const request = https.request(options, (response) => { |
|
let body = ''; |
|
response.setEncoding('utf8'); |
|
response.on('error', reject); |
|
response.on('data', (chunk) => { |
|
body += chunk; |
|
}); |
|
response.on('end', () => resolve({response, body})); |
|
}); |
|
request.on('error', reject); |
|
request.write(data); |
|
request.end(); |
|
}); |
|
} |
|
|
|
async function gitHubGet(endpoint) { |
|
const {response, body} = await httpsRequest({ |
|
host: 'api.github.com', |
|
path: endpoint, |
|
headers: { |
|
'user-agent': 'xbar', |
|
authorization: `token ${GITHUB_ACCESS_TOKEN}`, |
|
}, |
|
timeout: 5000, |
|
}); |
|
if (response.statusCode === 200 || response.statusCode === 304) { |
|
return JSON.parse(body); |
|
} |
|
throw new Error(`HTTP Status ${response.statusCode}`); |
|
} |
|
|
|
function getNotificationUrl(notification) { |
|
let url = notification.subject.url; |
|
url = url.replace('api.github.com/repos', 'github.com'); |
|
url = url.replace('/pulls/', '/pull/'); |
|
return url; |
|
} |
|
|
|
function isOffTime() { |
|
const date = new Date(); |
|
return date.getDay() === 0 || date.getDay() === 6 || date.getHours() < 6 || date.getHours() >= 19; |
|
} |
|
|
|
async function main() { |
|
if (!GITHUB_ACCESS_TOKEN) { |
|
console.log(`✕ | templateImage=${gitHubLogo36Px}`); |
|
console.log('---'); |
|
console.log(`Configure GitHub access token in plugin settings`); |
|
return; |
|
} |
|
|
|
try { |
|
const notifications = await gitHubGet('/notifications'); |
|
const count = isOffTime() ? 0 : notifications.length; |
|
console.log(`${count || ''} | templateImage=${gitHubLogo36Px}`); |
|
if (notifications.length) { |
|
console.log('---'); |
|
} |
|
for (const notification of notifications) { |
|
const title = notification.subject.title; |
|
const url = getNotificationUrl(notification); |
|
console.log(`☉ ${title} | href=${url} | refresh=true`); |
|
} |
|
console.log('---'); |
|
console.log('Open Notifications on GitHub | href=https://github.com/notifications'); |
|
} catch (error) { |
|
console.log(`✕ | templateImage=${gitHubLogo36Px}`); |
|
console.log('---'); |
|
console.log('Error: ' + error.message); |
|
} |
|
} |
|
|
|
main(); |