#!/usr/bin/env ruby # coding: utf-8 require 'open-uri' require 'nokogiri' require 'erb' MONTHS = [ "Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez", ] def fmt_time t if t.is_a? String t else t.strftime "%Y%m%dT%H%M%S" end end class Event attr_accessor :title, :url, :location attr_reader :date, :dtstart, :dtend def date=(s) if s =~ /(\d+)\.\s*(\S{3})\s+(.*)/ day = $1.to_i month = MONTHS.index($2) + 1 year = $3.to_i year_time = $3 if year_time =~ /(\d{4})(.*)/ year = $1.to_i time = $2 else raise "Invalid year: #{year_time.inspect} in #{s.inspect}" end if time =~ /(\d+)[\.:](\d{2})/ @dtstart = Time::local year, month, day, $1.to_i, $2.to_i, 0 @dtend = @dtstart + 3600 elsif time =~ /(\d+)\s+Uhr/ @dtstart = Time::local year, month, day, $1.to_i, 0, 0 @dtend = @dtstart + 3600 else @dtstart = @dtend = "#{year}#{month.to_s.rjust(2, "0")}#{day.to_s.rjust(2, "0")}" end else raise "Invalid date: #{s.inspect}" end end end events = [] url = "https://kunsthausdresden.de/" doc = Nokogiri::HTML URI.open(url) doc.css(".events").each do |content| date = content.css(".meta.date").text.strip location = content.css(".meta.location").text.strip .sub(/^Ort:\s*/, "") .sub(/Ort:.*/, "") title_link = content.css(".article-header h1.title a") href = title_link.attr 'href' next unless href begin ev = Event::new ev.title = title_link.attr 'title' ev.url = URI.join url, href ev.date = date ev.location = location events << ev rescue STDERR.puts "Omitting: #{$!}" STDERR.puts $!.backtrace end end ical = ERB::new <<~EOF BEGIN:VCALENDAR VERSION:2.0 METHOD:PUBLISH X-WR-TIMEZONE;VALUE=TEXT:Europe/Berlin <% events.each do |ev| %> BEGIN:VEVENT SUMMARY:<%= ev.title %> DTSTART:<%= fmt_time ev.dtstart %> DTEND:<%= fmt_time ev.dtend %> UID:<%= ev.url %> URL:<%= ev.url %> LOCATION:<%= ev.location %> END:VEVENT <% end %> END:VCALENDAR EOF puts ical.result