module Footballdata

todo/fix:

use a more generic name?
  might also works for euro or worldcup - check?

Constants

MODS
Mods

e.g. Cardiff City FC | Cardiff › Wales - Cardiff City Stadium, Leckwith Road Cardiff CF11 8AZ AS Monaco FC | Monaco › Monaco - Avenue des Castellans Monaco 98000

STAGE_TO_ROUND
STAGE_TO_STAGE

Public Class Methods

convert( league:, season: ) click to toggle source
# File lib/football-sources/apis/convert.rb, line 6
def self.convert( league:, season: )

  ### note/fix: cl (champions league for now is a "special" case)
  if league.downcase == 'cl'
    convert_cl( league: league,
                season: season )
    return
  end



  season = Season( season )   ## cast (ensure) season class (NOT string, integer, etc.)

  data           = Webcache.read_json( Metal.competition_matches_url( LEAGUES[league.downcase], season.start_year ))
  data_teams     = Webcache.read_json( Metal.competition_teams_url(   LEAGUES[league.downcase], season.start_year ))


  ## build a (reverse) team lookup by name
  puts "#{data_teams['teams'].size} teams"

  teams_by_name = data_teams['teams'].reduce( {} ) do |h,rec|
     h[ rec['name'] ] = rec
     h
  end

  pp teams_by_name.keys



mods = MODS[ league.downcase ] || {}


recs = []

teams = Hash.new( 0 )

stat  =  Stat.new

matches = data[ 'matches']
matches.each do |m|
  stat.update( m )

  team1 = m['homeTeam']['name']
  team2 = m['awayTeam']['name']

  score = m['score']



  if m['stage'] == 'REGULAR_SEASON'
    teams[ team1 ] += 1
    teams[ team2 ] += 1

    ### mods - rename club names
    unless mods.nil? || mods.empty?
      team1 = mods[ team1 ]      if mods[ team1 ]
      team2 = mods[ team2 ]      if mods[ team2 ]
    end


    ## e.g. "utcDate": "2020-05-09T00:00:00Z",
    date_str = m['utcDate']
    date = DateTime.strptime( date_str, '%Y-%m-%dT%H:%M:%SZ' )


    comments = ''
    ft       = ''
    ht       = ''

    case m['status']
    when 'SCHEDULED', 'IN_PLAY'
      ft = ''
      ht = ''
    when 'FINISHED'
      ## todo/fix: assert duration == "REGULAR"
      ft = "#{score['fullTime']['homeTeam']}-#{score['fullTime']['awayTeam']}"
      ht = "#{score['halfTime']['homeTeam']}-#{score['halfTime']['awayTeam']}"
    when 'AWARDED'
      ## todo/fix: assert duration == "REGULAR"
      ft = "#{score['fullTime']['homeTeam']}-#{score['fullTime']['awayTeam']}"
      ft << ' (*)'
      ht = ''
      comments = 'awarded'
    when 'CANCELLED'
      ft = '(*)'
      ht = ''
      comments  = 'canceled'   ## us eng ? -> canceled, british eng. cancelled ?
    when 'POSTPONED'
      ft = '(*)'
      ht = ''
      comments = 'postponed'
    else
      puts "!! ERROR: unsupported match status >#{m['status']}< - sorry:"
      pp m
      exit 1
    end


    ## todo/fix: assert matchday is a number e.g. 1,2,3, etc.!!!
    recs << [m['matchday'],
             date.to_date.strftime( '%Y-%m-%d' ),
             team1,
             ft,
             ht,
             team2,
             comments
            ]


    print '%2s' % m['matchday']
    print ' - '
    print '%-24s' % team1
    print '  '
    print ft
    print ' '
    print "(#{ht})"    unless ht.empty?
    print '  '
    print '%-24s' % team2
    print '  '
    print comments
    print ' | '
    ## print date.to_date  ## strip time
    print date.to_date.strftime( '%a %b %-d %Y' )
    print ' -- '
    print date
    print "\n"
  else
    puts "-- skipping #{m['stage']}"
  end
end # each match



## note: get season from first match
##   assert - all other matches include the same season
## e.g.
# "season": {
#  "id": 154,
#  "startDate": "2018-08-03",
#  "endDate": "2019-05-05",
#  "currentMatchday": 46
# }

start_date = Date.strptime( matches[0]['season']['startDate'], '%Y-%m-%d' )
end_date   = Date.strptime( matches[0]['season']['endDate'],   '%Y-%m-%d' )

dates = "#{start_date.strftime('%b %-d')} - #{end_date.strftime('%b %-d')}"

buf = ''
buf << "#{season.key} (#{dates}) - "
buf << "#{teams.keys.size} clubs, "
buf << "#{stat[:regular_season][:matches]} matches, "
buf << "#{stat[:regular_season][:goals]} goals"
buf << "\n"

puts buf



   ## note: warn if stage is greater one and not regular season!!
   File.open( './errors.txt' , 'a:utf-8' ) do |f|
     if stat[:all][:stage].keys != ['REGULAR_SEASON']
      f.write "!! WARN - league: #{league}, season: #{season.key} includes non-regular stage(s):\n"
      f.write "   #{stat[:all][:stage].keys.inspect}\n"
     end
   end


   File.open( './logs.txt', 'a:utf-8' ) do |f|
     f.write "\n================================\n"
     f.write "====  #{league}  =============\n"
     f.write buf
     f.write "  match status: #{stat[:regular_season][:status].inspect}\n"
     f.write "  match duration: #{stat[:regular_season][:duration].inspect}\n"

     f.write "#{teams.keys.size} teams:\n"
     teams.each do |name, count|
        rec = teams_by_name[ name ]
        f.write "  #{count}x  #{name}"
        if rec
          f.write " | #{rec['shortName']} "   if name != rec['shortName']
          f.write " › #{rec['area']['name']}"
          f.write "  - #{rec['address']}"
        else
          puts "!! ERROR - no team record found in teams.json for >#{name}<"
          exit 1
        end
        f.write "\n"
     end
   end




# recs = recs.sort { |l,r| l[1] <=> r[1] }
## reformat date / beautify e.g. Sat Aug 7 1993
recs.each { |rec| rec[1] = Date.strptime( rec[1], '%Y-%m-%d' ).strftime( '%a %b %-d %Y' ) }

headers = [
  'Matchday',
  'Date',
  'Team 1',
  'FT',
  'HT',
  'Team 2',
  'Comments'
]

## note: change season_key from 2019/20 to 2019-20  (for path/directory!!!!)
Cache::CsvMatchWriter.write( "#{config.convert.out_dir}/#{season.to_path}/#{league.downcase}.csv",
                             recs,
                             headers: headers )


teams.each do |name, count|
  rec = teams_by_name[ name ]
  print "  #{count}x  "
  print name
  if rec
    print " | #{rec['shortName']} "   if name != rec['shortName']
    print " › #{rec['area']['name']}"
    print "  - #{rec['address']}"
  else
    puts "!! ERROR  - no team record found in teams.json for #{name}"
    exit 1
  end
  print "\n"
end

pp stat
end
convert_cl( league:, season: ) click to toggle source
# File lib/football-sources/apis/convert_cl.rb, line 39
def self.convert_cl( league:, season: )
  season = Season( season )   ## cast (ensure) season class (NOT string, integer, etc.)

  data           = Webcache.read_json( Metal.competition_matches_url( LEAGUES[league.downcase], season.start_year ))
  data_teams     = Webcache.read_json( Metal.competition_teams_url(   LEAGUES[league.downcase], season.start_year ))


  ## build a (reverse) team lookup by name
  puts "#{data_teams['teams'].size} teams"

  teams_by_name = data_teams['teams'].reduce( {} ) do |h,rec|
     h[ rec['name'] ] = rec
     h
  end

  pp teams_by_name.keys



mods = MODS[ league.downcase ] || {}


recs = []

teams = Hash.new( 0 )
stat = Stat.new

matches = data[ 'matches' ]
matches.each do |m|
  stat.update( m )

  team1 = m['homeTeam']['name']
  team2 = m['awayTeam']['name']


  score = m['score']



  if m['stage'] == 'GROUP_STAGE'
    stage = 'Group'
    round = "Matchday #{m['matchday']}"
    if m['group'] =~ /Group ([A-Z])/
      group = $1
    else
      puts "!! ERROR - no group name found for group >#{m['group']}<"
      exit 1
    end
  else
    stage = STAGE_TO_STAGE[ m['stage'] ]
    if stage.nil?
      puts "!! ERROR - no stage mapping found for stage >#{m['stage']}<"
      exit 1
    end
    round = STAGE_TO_ROUND[ m['stage'] ]
    if round.nil?
      puts "!! ERROR - no round mapping found for stage >#{m['stage']}<"
      exit 1
    end
    group = ''
  end


    teams[ team1 ] += 1
    teams[ team2 ] += 1

    ### mods - rename club names
    unless mods.nil? || mods.empty?
      team1 = mods[ team1 ]      if mods[ team1 ]
      team2 = mods[ team2 ]      if mods[ team2 ]
    end


    ## e.g. "utcDate": "2020-05-09T00:00:00Z",
    date_str = m['utcDate']
    date = DateTime.strptime( date_str, '%Y-%m-%dT%H:%M:%SZ' )


    comments = ''
    ft       = ''
    ht       = ''
    et       = ''
    pen      = ''

    case m['status']
    when 'SCHEDULED', 'IN_PLAY'
      ft  = ''
      ht  = ''
      et  = ''
      pen = ''
    when 'AWARDED'
      ## todo/fix: assert duration == "REGULAR"
      ft = "#{score['fullTime']['homeTeam']}-#{score['fullTime']['awayTeam']}"
      ft << ' (*)'
      ht = ''
      comments = 'awarded'
    when 'FINISHED'
      ## note: if extraTime present
      ## than fullTime is extraTime score!!
      ##   AND   fullTime - extraTime is fullTime score!!
      ## double check in other season too??
      ##   - checked in cl 2018/19

      if score['extraTime']['homeTeam'] && score['extraTime']['awayTeam']
        et = "#{score['fullTime']['homeTeam']}-#{score['fullTime']['awayTeam']}"
        ft = "#{score['fullTime']['homeTeam']-score['extraTime']['homeTeam']}-#{score['fullTime']['awayTeam']-score['extraTime']['awayTeam']}"
      else
        ft  = "#{score['fullTime']['homeTeam']}-#{score['fullTime']['awayTeam']}"
      end

      ht  = "#{score['halfTime']['homeTeam']}-#{score['halfTime']['awayTeam']}"

      pen = if score['penalties']['homeTeam'] && score['penalties']['awayTeam']
              "#{score['penalties']['homeTeam']}-#{score['penalties']['awayTeam']}"
            else
              ''
            end
    else
      puts "!! ERROR: unsupported match status >#{m['status']}< - sorry:"
      pp m
      exit 1
    end


    recs << [stage,
             round,
             group,
             date.to_date.strftime( '%Y-%m-%d' ),
             team1,
             ft,
             ht,
             team2,
             et,
             pen,
             comments
            ]


    print '%2s' % m['matchday']
    print ' - '
    print '%-24s' % team1
    print '  '
    print ft
    print ' '
    print "(#{ht})"    unless ht.empty?
    print '  '
    print '%-24s' % team2
    print '  '
    print comments
    print ' | '
    ## print date.to_date  ## strip time
    print date.to_date.strftime( '%a %b %-d %Y' )
    print ' -- '
    print date
    print "\n"

end # each match


## note: get season from first match
##   assert - all other matches include the same season
## e.g.
# "season": {
#  "id": 154,
#  "startDate": "2018-08-03",
#  "endDate": "2019-05-05",
#  "currentMatchday": 46
# }

start_date = Date.strptime( matches[0]['season']['startDate'], '%Y-%m-%d' )
end_date   = Date.strptime( matches[0]['season']['endDate'],   '%Y-%m-%d' )

dates = "#{start_date.strftime('%b %-d')} - #{end_date.strftime('%b %-d')}"

buf = ''
buf << "#{season.key} (#{dates}) - "
buf << "#{teams.keys.size} clubs, "
buf << "#{stat[:all][:matches]} matches, "
buf << "#{stat[:all][:goals]} goals"
buf << "\n"

puts buf



# recs = recs.sort { |l,r| l[1] <=> r[1] }
## reformat date / beautify e.g. Sat Aug 7 1993
recs.each { |rec| rec[3] = Date.strptime( rec[3], '%Y-%m-%d' ).strftime( '%a %b %-d %Y' ) }

headers = [
  'Stage',
  'Round',
  'Group',
  'Date',
  'Team 1',
  'FT',
  'HT',
  'Team 2',
  'ET',
  'P',
  'Comments'
]

## note: change season_key from 2019/20 to 2019-20  (for path/directory!!!!)
Cache::CsvMatchWriter.write( "#{config.convert.out_dir}/#{season.to_path}/#{league.downcase}.csv",
                             recs,
                             headers: headers )


teams.each do |name, count|
  rec = teams_by_name[ name ]
  print "  #{count}x  "
  print name
  if rec
    print " | #{rec['shortName']} "   if name != rec['shortName']
    print " › #{rec['area']['name']}"
    print "  - #{rec['address']}"
  else
    print "!! ERROR - no team record found in teams.json for #{name}"
    exit 1
  end
  print "\n"
end

pp stat
end