Skip to content

Instantly share code, notes, and snippets.

@blackjid
Last active May 8, 2018 13:52
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save blackjid/1efd7332c3cf59d3c3f9 to your computer and use it in GitHub Desktop.
Save blackjid/1efd7332c3cf59d3c3f9 to your computer and use it in GitHub Desktop.
Worldcup Brazil 2014 Google Calendar Matches widget for Dashing

Description

A Dashing widget for displaying next Brazil 2014 World Cup matches from calendar event on Google Calendar

It was designed to be used against this calendar worldcupbrazilcalendar

screen shot

Made by platanus in Chile

Dependencies

Add it to dashing's gemfile:

gem 'google-api-client'
gem 'activesupport'

and run bundle install.

Usage

To use this widget, you'll first need to set up a Google API project.

  1. Create and download a new private key for Google API access.

    1. Go to https://code.google.com/apis/console
    2. Click 'Create Project' and accept TOS's
    3. Enable 'Calendar API' service and accept TOS's
    4. Under 'APIs & auth.' click 'Credentials' in the left-hand nav menu
    5. Pick the OAuth option by clicking 'Create new Client ID'
    6. Select 'Service Account' and click 'Create Client ID'. Download of your Private key is about to start. Save it securely.
    7. Note the password for your new private key ('notasecret')
    8. Next to the OAuth tab you will find the details for the service account you just created. Copy it's email address which will look something like this: 210987654321@developer.gserviceaccount.com - you'll need it in environmental variables later.
  2. Subscribe to matches calendar

    1. Go to www.worldcupbrazilcalendar.com and subscribe the matches calender to your google account.
    2. Go to the other calendar settings in google calendar, and the click in the WorldCup 2014 calendar.
    3. Find the callendar id, it should be something like cdadfstm90rcfdsfsdfsadegi2jgf@import.calendar.google.com
  3. Setup your widget

    1. You can install the widget with dashing install 1efd7332c3cf59d3c3f9, or manually add each file in the corresponding location

    2. Setup your environmental variables

      GOOGLE_SERVICE_ACCOUNT_EMAIL # Email of service account
      GOOGLE_SERVICE_PK_FILE # File containing your private key
      GOOGLE_SERVICE_KEY_SECRET # Password to unlock private key 'notasecret'
      WORLDCUP_CALENDAR # Calendar ID.
      WORLDCUP_MY_TEAM # The team you want to follow, refer to the worldcup.rb job to know how to spell it
    3. Add the widget HTML to your dashboard

      <li data-row="1" data-col="4" data-sizex="1" data-sizey="2">
        <div data-id="worldcup"
             data-view="Worldcup"
             data-title="Brazil 2014"
             data-my-team-title="Chile Matches"
             style="background-color:#357A3E;"></div>
        <img class="icon-background" src="/assets/brazil-back.png" />
      </li>

Notes

To set your PK12 certificate in heroku you can follow this guide http://ar.zu.my/how-to-store-private-key-files-in-heroku/

class Dashing.Worldcup extends Dashing.Widget
ready: ->
@refresh()
onData: (data) ->
@refresh(data)
refresh: (data) ->
nextTitle = if @get('next_matches').length > 1 then "Next Matches" else "Next Match"
@set('next-title', nextTitle)
# Set a global next match formatted time
nextMatch = @get('next_matches')[0]
@set('next-match-time', @formatDate(nextMatch.start, nextMatch.end))
# Set the formatted time for each of my team matches
match.start.formatted = @formatDate(match.start, match.end) for match in @get('my_team_matches')
#
true
formatDate: (startDate, endDate) ->
nowMoment = moment()
startMoment = moment(new Date startDate.dateTime)
endMoment = moment(new Date endDate.dateTime)
if nowMoment > startMoment and nowMoment < endMoment
"LIVE"
else if nowMoment > endMoment
"FINISHED"
else
moment(new Date startDate.dateTime).fromNow()
<h1 class="title">
<span data-bind="title"></span>
</h1>
<h4>
<span data-bind="next-title"></span>
</h4>
<div class="next-time">
<span class="team-name" data-bind="next-match-time"></span>
</div>
<table>
<tbody>
<tr class="match" data-foreach-match="next_matches" >
<td class="left-team team-col">
<span class="team-name" data-bind="match.teams[0].code" ></span>
<img data-bind-src="match.teams[0].flag_large" />
</td>
<td class="vs-col">
<span> vs </span>
</td>
<td class="right-team team-col">
<img data-bind-src="match.teams[1].flag_large" />
<span class="team-name" data-bind="match.teams[1].code" ></span>
</td>
</tr>
</tbody>
</table>
<div data-renderif="my_team_matches.length">
<h5 class="my-team-header" data-bind="myTeamTitle"></h5>
<table>
<tbody>
<tr class="match" data-foreach-match="my_team_matches" >
<td class="flag-col">
<img data-bind-src="match.my_team_opponent.flag_mid" />
</td>
<td class="name-col col-base">
<span class="team-name" data-bind="match.my_team_opponent.code" ></span>
</td>
<td class="col-base">
<span class="team-name" data-bind="match.start.formatted"></span>
</td>
</tr>
</tbody>
</table>
</div>
<p class="updated-at" data-bind="updatedAtMessage"></p>
# encoding: UTF-8
require 'google/api_client'
require 'date'
require 'time'
require 'active_support'
require 'active_support/all'
# require 'pry'
# Update these to match your own apps credentials
service_account_email = ENV['GOOGLE_SERVICE_ACCOUNT_EMAIL'] # Email of service account
key_file = ENV['GOOGLE_SERVICE_PK_FILE'] # File containing your private key
key_secret = ENV['GOOGLE_SERVICE_KEY_SECRET'] # Password to unlock private key
calendarID = ENV['WORLDCUP_CALENDAR'] # Calendar ID.
myTeam = ENV['WORLDCUP_MY_TEAM']
# Get the Google API client
client = Google::APIClient.new(:application_name => 'Platanus Dashboard',
:application_version => '0.0.1')
# Load your credentials for the service account
if not key_file.nil? and File.exists? key_file
key = Google::APIClient::KeyUtils.load_from_pkcs12(key_file, key_secret)
else
key = OpenSSL::PKey::RSA.new ENV['GOOGLE_SERVICE_PK'], key_secret
end
client.authorization = Signet::OAuth2::Client.new(
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
:audience => 'https://accounts.google.com/o/oauth2/token',
:scope => 'https://www.googleapis.com/auth/calendar.readonly',
:issuer => service_account_email,
:signing_key => key)
flags = {
"Brazil" => 'bra',
"Croatia" => 'cro',
"Mexico" => 'mex',
"Cameroon" => 'cmr',
"Spain" => 'esp',
"Netherlands" => 'ned',
"Chile" => 'chi',
"Australia" => 'aus',
"Colombia" => 'col',
"Greece" => 'gre',
"Ivory Coast" => 'civ',
"Japan" => 'jpn',
"Uruguay" => 'uru',
"Costa Rica" => 'crc',
"England" => 'eng',
"Italy" => 'ita',
"Switzerland" => 'sui',
"Ecuador" => 'ecu',
"France" => 'fra',
"Honduras" => 'hon',
"Argentina" => 'arg',
"Bosnia and Herzegovina" => 'bih',
"Iran" => 'irn',
"Nigeria" => 'nig',
"Germany" => 'ger',
"Portugal" => 'por',
"Ghana" => 'gha',
"USA" => 'usa',
"Belgium" => 'bel',
"Algeria" => 'alg',
"Russia" => 'rus',
"South Korea" => 'kor'
}
# Start the scheduler
SCHEDULER.every '60s', :first_in => 4 do |job|
# Request a token for our service account
client.authorization.fetch_access_token!
# Get the calendar API
calendar = client.discovered_api('calendar','v3')
# Start and end dates
startDate = (DateTime.now - 20.minutes).rfc3339 #+ 32.days
endDate = Date.parse("2014-07-15").rfc3339
# Get the events
events = client.execute(:api_method => calendar.events.list,
:parameters => {
:calendarId => calendarID,
:timeMin => startDate,
:timeMax => endDate,
:orderBy => 'startTime',
:singleEvents => true
}
)
# The worldcup matches
matches = events.data.items;
matches = matches.each do |match|
match[:teams] = match.summary.match(/(.*) v (.*)/i)[1,2].map do |team|
next if not flags[team]
{
flag_small: "http://img.fifa.com/images/flags/2/#{flags[team]}.png",
flag_mid: "http://img.fifa.com/images/flags/3/#{flags[team]}.png",
flag_large: "http://img.fifa.com/images/flags/4/#{flags[team]}.png",
name: team,
code: flags[team].upcase
}
end
end
# Set the event if there is one found
if events.data.items.count > 0
# Next Match
nextMatch = matches.first
nextMatches = matches.select {|match| match.start.dateTime == nextMatch.start.dateTime}
# My team matches
myTeamMatches = matches.select do |match|
if match.summary.match(/#{myTeam}/i)
match[:my_team_opponent] = match[:teams].find{|team| not team[:name].match(/#{myTeam}/i) }
true
else
false
end
end
end
# Update the dashboard
send_event('worldcup', {
next_matches: nextMatches,
my_team_matches: myTeamMatches
})
end
.widget-worldcup {
.team-name{
font-size: 14px;
}
.team-col{
vertical-align:top;
line-height:16px;
width: 43%;
padding: 4px 0;
}
.vs-col{
text-align:center;
vertical-align:center;
width: 14%;
}
.col-base{
text-align: left;
}
.flag-col{
width: 25%;
text-align: right;
padding-right: 5px;
}
.name-col{
width: 14%;
}
.left-team{
text-align:right;
}
.right-team{
text-align:left;
}
.next-time{
margin-top:-10px;
}
.my-team-header{
margin-top: 10px;
}
}
@topka
Copy link

topka commented Jun 26, 2014

Any insight if the worldcupbrazilcalendar will update their calendar? The widget just stopped working because there are no country names in the events.
Any alternatives?

@loicteixeira
Copy link

Quick Fix:

  • Subscribe to this calendar instead
  • Update the WORLDCUP_CALENDAR environment variable accordingly.
  • Update line 99 to 108 of worldcup.rb with the following code:
match[:teams] = match.summary.match(/(?:.+: )?(.*) vs (.*)/i) do |team_regex|
  team_regex[1,2].map do |team|
    next if not flags[team]
    {
      flag_small: "http://img.fifa.com/images/flags/2/#{flags[team]}.png",
      flag_mid: "http://img.fifa.com/images/flags/3/#{flags[team]}.png",
      flag_large: "http://img.fifa.com/images/flags/4/#{flags[team]}.png",
      name: team,
      code: flags[team].upcase
    }
  end
end

Notes:

  • As before, it relies on the fact that the owner of the calendar will keep updating it (by replacing "Winner of..." by the team name).
  • At the moment, the playoffs and the final won't show. I tried to make the regex a bit forgiving but because I don't know what the final string will be (whether it will follow other event titles pattern or not), it may need to be updated later.

@topka
Copy link

topka commented Jun 27, 2014

Thanks Loic!
This worked. Appreciate the quick workaround!

@loicteixeira
Copy link

Um.. The owner of the calendar (live) update the title of the event with score information which means the second team does not display properly during the match. Replace the regexp with this one /(?:.+: )?(\w+(?: \w+)*) vs (\w+(?: \w+)*)/i

@blackjid
Copy link
Author

Well, the WorldCup is over!, Germany won, totally deserved...
We'll be updating the widget for Russia 2018. Maybe is a good idea to spin over this widget with something more generic. Champion League, local leagues, etc... maybe one day

@jelofsson
Copy link

jelofsson commented May 8, 2018

@blackjid any update planned for Russia 2018?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment