Skip to content

Instantly share code, notes, and snippets.

@migrs
Last active June 25, 2019 09:05
Show Gist options
  • Save migrs/710a42062456a47bff1c59e40423a8b8 to your computer and use it in GitHub Desktop.
Save migrs/710a42062456a47bff1c59e40423a8b8 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
# <bitbar.title>GitHub Notifications</bitbar.title>
# <bitbar.version>v1.0.0</bitbar.version>
# <bitbar.author>mig</bitbar.author>
# <bitbar.author.github>migrs</bitbar.author.github>
# <bitbar.desc></bitbar.desc>
# <bitbar.image></bitbar.image>
# <bitbar.dependencies>ruby</bitbar.dependencies>
# <bitbar.abouturl>https://github.com/migrs</bitbar.abouturl>
require 'net/http'
require 'uri'
require 'zlib'
require 'base64'
require 'json'
require 'date'
begin
require 'dotenv'
Dotenv.load __dir__ + '/.env'
rescue LoadError
end
TOKEN = ENV['GITHUB_TOKEN'] || 'PUT-YOUR-GITHUB-TOKEN'
# icon = `curl -s https://github.com/favicon.ico | base64 -w 0`
# icon = Base64.strict_encode64 Zlib::Deflate.deflate icon, Zlib::BEST_COMPRESSION
if RUBY_PLATFORM =~ /linux/
icon = 'eNrtWEtb6joU/UEMytH6CYM7SNr0ART6oEiYaQ+0PBQv3GPBX3/3TuVVaWlRPBMyqIYkKyv7nRBCKCEmYfAlhMF/ZE4dQhohdBWCXwp/SRN/ZLIG/XkyU4yTzfhH00iZRpnLbnmXrWxNDeUOC3dDalyzYdTVWgzG26/F8BxfayBet8ZWln/v4G/T1Jywp7kjSXP9vrSCHWQ/n98S9+/+QS5GRJxETp9aG/eru35Pk2oCH+b7i/gYv6kYpyF3W0TuqLPYVmOJ4nnN1PnbFPaza3t8Bb6vUc/+kLzDVGKrjiRht4LshlXQWksioanUQabqZA8Uf2So1dZiD+9QHl4V8B8CjTo9KQa8EfBbGfeqU3U78SkFVNtsMkd5vezheyxqPoJ8ujf78oF+Ny5uKij/Lj1cfxNZXc3mCX+QbU3MNEm5ZiLfVcJX4GH/NumDvjqMnNOQj5ycN8GD/m207d8JfTslzg+6NgS/cHve2wj8o2nu9AeY6nsJULQfRg70D3gd8EU5pT++WySU1kwhWeKbbC3m760XeBt/0prOxj+82EH7RGiFgn21b6npae0Q1ne58CfcynDEUcX8RJ5gCV7KqYmK9rCK0vZcqI/xR98dLd0s3G9cAk/Mz8ZLyV+VYf9OP/EPOL9t4vnXSd/qsrsAvbpCru2n2nwbRdin/OZ/604Qz5pxPDQi2S2x6klfLYOG4kzV8MKSoPzB8Ky+thp7aN81lz9oUhuMlrCi6/VO9UGLRu9axPnMjQND+UYRggwaJAD8MUH8Ck354xoSHikmJDF/P34gHpxXN01ImqWTyid9AV6/SrPjR3O9XNBiVHF+/Xj8Af3UzUc9mg9L56uIP7UQr8J3eKi/VgjyjaowPhgAvm7c9Xo9Xy1q35oU58fLCnCOlm/F8OZwtiquf97hxVynUeOrpoR4lSLxvcJRvr9zoKbgm4bQt3uwnr84H/rzCEf7ChDvjoB/zZ7Rn+nJfAH+Q80S+Q3tgQk+mf5pstR6JuzVgL0aaP+dZRof+L52TslThwLXoWXzMfI5Zu/xNPHHzfzJH+g/uq6Inxhf7Mzz1zwMAkq+P43L1Au7+JDEx0N5NpzD/WUZ5fV4zB7kSJwX+L9qKG92yv8Vc2yGKP/firYKBkOh32UxvquATxP7emmsg7aI56fqJcHPfLfeLe2r/oVBlCCeIeRTO8F3Df2FivLsnbR3EZ8uk//8nq6TAvvPMD8Opm6uPPn6TZLgTnXRfK23gly++oAB30njxHmCSxdZmE/cE/61FvUDyzlPAL7AL01V5P+j9cVWXpMQx+vZ+l//YP2KfIaZ8dX2k3osa7wt/xxT9C9rnqX/fg3ttT3NtI+6fWF/OrRXLmfqdzJA/37LsWeRT50Lk1TAVml+vNJbaK/j3ol4enNxeYK8uJvv/zOsP/wgv16wnYHuTkeXsc8l1EIW+tPiRLw0RP0u8inL59u7TKrCesvLzz/9mrdcNGO+tedZjr2CTAdWfBGq4n6SL89x/6A++6iX68fjL9T/4a8j9gX1Q8h15d/s+i+JH1jvPsMdfMjS/kkhv6xZdvwBPubnSxvyV7Lylf6QyB8fdSji35gYj1+29aKE9jbCeoLje5duId7IFfqj23zzH44/KQf6HPhRpjyV/PvzxDxWr/wCPL2J97/JsnR9fKR/j/GnifF+0j6a7xM+ufnCFO/3k8l38Dmnr3csYY+F308U+S/whf0iHrTC8vkY5JtlD9/bF/XdUf855/1HyYkPZ/Ori/uxmX1/Pq9t41kSf9nZfPE9Tm8Exe3xCy3JbyIfb+oHUe9AfbZ539ur18b7+XsBa/Xrs/K1Xdu1Xdtfb//8D4zMcxE='
icon = Zlib::Inflate.inflate Base64.decode64(icon)
else
icon = nil
end
def li text = '---', args = {}
args = args.dup
fold = args.delete(:fold) ? '--' : ''
args_set = (alt = args.delete(:alt)) ? [args, args.merge(alt).merge(alternate: true)] : [args]
args_set.each do |_|
puts fold + _.delete(:prepend).to_s + (_.delete(:text) || text).to_s + _.delete(:append).to_s +
(_.empty? ? '' : ' | ' + _.select {|k,v|!v.nil?}.map {|k,v| "#{k}=#{v}"}.join(' '))
end
end
def github_api path, params = {}
headers = { 'Authorization' => "token #{TOKEN}", 'Accept' => 'application/json' }
uri = URI "https://api.github.com/#{path}"
uri.query = URI.encode_www_form params unless params.empty?
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) {|_|_.get uri.request_uri, headers}
raise "error #{res.code} #{res.message}" if res.code != '200'
JSON.parse res.body, symbolize_names: true
end
def icon type
image = 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAYAAAAmlE46AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEwAACxMBAJqcGAAAA'
case type
when 'PullRequest'
image += 'TJJREFUKJG9krFOAlEQRe/MLpqHnd/ATyBWsLWF+hcLPYXibvwCE/gLC2MNVrD7AbbGnpjYboBlro2QXWATabzVy5x338ydPKBC4awTVTEA8Huz9i1FI5gZBINh6+0lnHUiEXkAUGmWMGm/c7Fues4pLU9IPv+aAABm9i2qT6Pm+BECbuoqpnZWW4lmmRLG3ZdV9VyAOEyD+1JdVO4yqX+ua7UPofRHrUlEMgaA4cVYALkEACF6e/N2k4DdJCh1Ky7nENftyVACo9akcjElox3I9yfjsdoaVfFPHbtpcG2GOUy/wjS42r0QTjs3ZpibYV7kPmkxVuuGOKfIl1MAr0WjqMRcrBqec8oCVwDwnNOFnwugezkJ4+ZnFbkPeANanpwsAQr7+2m8Qab1FKcAeYgfqR/3P4pMOYR15QAAAABJRU5ErkJggg=='
when 'RepositoryInvitation'
image += 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAAKCAYAAACE2W/HAAAAAXNSR0IArs4c6QAAAM1JREFUKBWVkD0OQUEUhcdv/ASJn55SyxLoVBJq8tZjBRQsgkZiAQoqOiQ2oFc935nMvLxEXsRJPufOufe+kTHGmBeEf3Jg3i4t8IwOP6QZzeoi+3PFt1BRkKAq+Q4uEKbdUA+/wxm6LoubshPcoO8b9lp3GOMPGPomPoInqOcV/VUfyKfwhsChegJxfS3O6R5hALpFqFY2A69osUyygT3UQOpAWwVSpt4aShAt6lWXkIUk5WiswL5qiqIODdBz6+ZirM67cwFvulwfaH0AC7M1lHL62U4AAAAASUVORK5CYII=';
when 'Issue'
image += 'ZxJREFUKJGdkjFoU2EUhb97k9jNRzEFoWvJVHXoZCqIaQaH7JaUbtpi2zc4ORWJYKGTYJLBroFaiGPo0hBwyAOhU51Cd8EOOid53uugL4SnkOK3/dx7OPccfvhPZPqxHZUWc0gIUjFs6c/CJdDBtN580P36lzCM1jZ+mr9HuFKkJfgXABO9i/mmqOTd7VlztXcyEYbR2oabtFx5kx+Oa7VHn+LpS7bOV3K5UfBaTF+6WLW52juR7ai0mDEGovq2WezuJ8t7UdkBGsXu5KqdfvlQhOeeGRc0h4QIV/nhuDarkIVgft+xHxJnQwWpKNJKn/cvasvtkcCxuFTUsKWkiOsgrhcoBb2uIE1W4NKRO8DH6cF0KSnLewYDBTqGb26dr+Sm53tR2ZNmE8LTx3O4V9XpKKZ1FV24MZyf2aoH8YE5garXBWC3X1oX12NXO8zfvPWqttwepZ08iA9wXqDypFE8a09y7PZL64geCXx37IO4XiSZcK/+dso8bRTP2pD65DufH96WOBuKSwWlAGD4QJ2Oqtff3e99mxVnJr8AXSGi02ni0+YAAAAASUVORK5CYII='
when 'Commit'
image += 'HhJREFUKJHl0LEKwkAQBNCH3yIaf05S+VUqmh8ykFoUYn8WbnEc8a7XgYVlmNkdhv/EDgNmvHDFtmXq8ETCiFvsD2xqxksI9xnXB3cqxamYceHgVOpWC6JUi/QNQxj7jDsEd6wZ83KmLOId69bXzqekOeas0eiv4g3q4SY7NY1R2gAAAABJRU5ErkJggg=='
when 'Release'
image += 'JdJREFUKJGl0DsKwkAUBdDTRgvFHbgmNyLY+QWzKxM/kK2kSKc70MIIQ0ziqBceA/dxinn8mSkKVMGUmH+CBWaNboQjdn2wqt97Pa8kNd5+C0O86YNdSZC34RLjCJxhHZYLXDCIxKuwTHGOwBNcm2WKUw9OcMCybZl6XjHpQOs30cB5gKNQiDPPP0WjV/a4aVwxNsNfUGce7P8k4XgVPSYAAAAASUVORK5CYII='
end
end
def li_issues title, params, q
issues = github_api "search/issues?q=#{q.map {|k,v|"#{k}:#{v}"}.join('+')}"
return unless issues[:total_count] > 0
li "#{title} (#{issues[:total_count]})", params
issues[:items].each do |_|
updated_at = DateTime.parse(_[:updated_at]).new_offset(Rational(9, 24)).strftime('%Y-%m-%d %H:%M')
author = "by #{_[:user][:login]}"
li "#{_[:title]} #{author}", href: _[:html_url], image: icon('PullRequest'),
fold: true, alt: { prepend: "#{updated_at} | " }
end
end
begin
now = Time.now
notifications = github_api 'notifications'
user = github_api 'user'
li '●', color: (notifications.empty? ? '#7d7d7d' : '#4078C0'), image: icon, imageWidth: 18
li
li "Last updated: #{now.strftime('%Y-%m-%d %H:%M')}", color: '#aaaa99', refresh: true
li_issues 'Pull requests', { color: "#58BE89" }, author: user[:login], type: 'pr', state: 'open'
li_issues 'Awaiting reviews', { color: "#ee8888" }, :'review-requested' => user[:login], type: 'pr', state: 'open'
li
if notifications.empty?
li 'No Notifications', href: 'https://github.com/notifications', color: '#66aaff'
else
li "Notifications (#{notifications.count})", href: 'https://github.com/notifications', color: '#66aaff'
end
notifications.group_by { |_|_[:repository][:id] }.each do |_, notifications|
repo = notifications.first[:repository]
li repo[:full_name], color: '#888888', href: repo[:html_url]
notifications.group_by {|_|_[:reason]}.each do |_, notifications|
li "➠ #{_.capitalize.sub(/_/, ' ')}", color: '#33BFDB'
notifications.each do |_|
updated_at = DateTime.parse(_[:updated_at]).new_offset(Rational(9, 24)).strftime('%m-%d %H:%M')
li _[:subject][:title], image: icon(_[:subject][:type]),
href: _[:subject][:url].sub(/(pull|commit)s/, '\1').gsub(%r{api\.|api/v3/|repos/}, ''), refresh: true,
alt: { prepend: "#{updated_at} | " }
end
end
end
rescue
li '!', color: '#ECB935', image: icon, imageWidth: 18
li
li "Exception: #{$!}", refresh: true
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment