Skip to content

Instantly share code, notes, and snippets.

@hhsprings
Last active September 6, 2021 09:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hhsprings/07bc04b0443f15018936961aee5c08c4 to your computer and use it in GitHub Desktop.
Save hhsprings/07bc04b0443f15018936961aee5c08c4 to your computer and use it in GitHub Desktop.
url list to html calendar
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from __future__ import print_function
import io
import sys
import re
import os
import datetime
from collections import namedtuple
import locale as _locale
import calendar
from calendar import LocaleHTMLCalendar
if hasattr("", "decode"):
_encode = lambda s: s.encode(sys.getfilesystemencoding())
_decode = lambda s: s.decode(sys.getfilesystemencoding())
else:
_encode = lambda s: s
_decode = lambda s: s
class HRefCollectionLocaleHTMLCalendar(LocaleHTMLCalendar):
def __init__(
self,
urls,
firstweekday=0,
locale=None):
try:
super().__init__(firstweekday, locale)
except TypeError:
super(HRefCollectionLocaleHTMLCalendar, self).__init__(
firstweekday, locale) # python 2.x?
self.cssclass_noday = "noday"
#
_keys = ['href', 'title', 'hovertext']
Anchor = namedtuple('Anchor', _keys) #, defaults=[""] * len(_keys))
self._urls = {}
for dts in urls.keys():
self._urls[dts] = []
for oval in urls[dts]:
if len(oval) == 2:
nval = Anchor(*(oval + [""]))
else:
nval = Anchor(*oval)
self._urls[dts].append(nval)
def formatmonthname(self, theyear, themonth, withyear=True):
"""
Return a month name as a table row.
"""
# '<tr><th colspan="7" class="{cssclass_month_head}">{month}</th></tr>'
res = super(HRefCollectionLocaleHTMLCalendar, self).formatmonthname(
theyear, themonth, withyear=withyear)
da = dict(m=themonth, y=theyear)
_IDFMT = 'y{y}m{m}'
_TFMT = '{m}, {y}'
da["id"] = _IDFMT.format(**da)
#
tm = datetime.date(int(theyear), int(themonth), 1)
pm = (tm - datetime.timedelta(weeks=1))
nm = (tm + datetime.timedelta(weeks=5))
da["id_prev"] = _IDFMT.format(y=pm.year, m=pm.month)
da["id_next"] = _IDFMT.format(y=nm.year, m=nm.month)
da["title"] = _TFMT.format(**da)
da["title_prev"] = _TFMT.format(y=pm.year, m=pm.month)
da["title_next"] = _TFMT.format(y=nm.year, m=nm.month)
da["spaces"] = "&nbsp;" * 5
res = re.sub(
r">([^<>]+)<",
(r' id="{id}"><a href="#{id_prev}" title="{title_prev}">&lt;</a>' +
r'<span title="{title}">{spaces}\1{spaces}</span>' +
r'<a href="#{id_next}" title="{title_next}">&gt;</a><').format(**da), res)
return res
def formatmonth(self, theyear, themonth, withyear=True):
"""
Return a formatted month as a table.
"""
self._theyear = theyear
self._themonth = themonth
return super(HRefCollectionLocaleHTMLCalendar, self).formatmonth(
theyear, themonth, withyear)
def formatday(self, day, weekday):
"""
Return a day as a table cell.
"""
if day == 0:
# day outside month
return '<td class="%s">&nbsp;</td>' % self.cssclass_noday
else:
ds = '{day}'.format(day=day)
ymd = "%d-%02d-%02d" % (self._theyear, self._themonth, day)
_class = self.cssclasses[weekday]
if ymd in self._urls:
ds += "<ul>"
for a in self._urls[ymd]:
if a.href:
cur = '<a href="{href}" title="{hovertext}" target=_blank>{title}</a>'.format(
**a._asdict())
else:
cur = '<span title="{hovertext}">{title}</span>'.format(
**a._asdict())
ds += "<li>{}</li>".format(cur)
ds += "</ul>"
else:
_class += " empty"
return '<td class="{_class}">{ds}</td>'.format(
_class=_class, ds=ds)
def formatyearpage(
self, years, width=3, css='calendar.css',
encoding=None, titlefmt="Calendar for {years}"):
"""
Return formatted years as a complete HTML page.
"""
if encoding is None:
encoding = sys.getdefaultencoding()
if not isinstance(years, (list, tuple,)):
years = [years]
v = []
a = v.append
a('<?xml version="1.0" encoding="%s"?>\n' % encoding)
a('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ' +
'"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n')
a('<html>\n')
a('<head>\n')
a('<meta http-equiv="Content-Type" content="text/html; charset=%s" />\n' % encoding)
if css is not None:
a('<link rel="stylesheet" type="text/css" href="%s" />\n' % css)
title = titlefmt.format(years=", ".join(map(repr, years)))
a('<title>' + title + '</title>\n')
a('</head>\n')
a('<body>\n')
a('<h1>' + title + '</h1>\n')
for theyear in years:
a(self.formatyear(theyear, width))
a('</body>\n')
a('</html>\n')
return ''.join(v).encode(encoding, "xmlcharrefreplace")
if __name__ == '__main__':
# urls_def_json example:
# ---------------------------------------------------
# {
# "2021-03-27": [
# [
# "https://www.youtube.com/watch?v=zqtDch-5whg",
# "【AnimeJapan 2021】 KADOKAWAブースステージ(DAY1)"
# ]
# ],
# "2021-03-28": [
# [
# "https://www.youtube.com/watch?v=cKa2A_-hCUI",
# "【AnimeJapan 2021】 KADOKAWAブースステージ(DAY2)"
# ]
# ]
# }
# ---------------------------------------------------
#
# calendar.css example:
# ---------------------------------------------------
# table, th, td {
# border: 1px solid black;
# }
# .noday {
# background-color: #f3f3f3;
# }
# .mon, .tue, .wed, .thu, .fri, .sat, .sun {
# width: 20em;
# text-align: center;
# }
# .sun {
# background-color: #fff0f0;
# }
# .sat {
# background-color: #f0f0ff;
# }
# td ul li {
# text-align: left;
# }
# .year {
# font-size: 2em;
# }
# ---------------------------------------------------
import argparse
import json
ap = argparse.ArgumentParser()
ap.add_argument("year", help="for multiple years, specify list as json format like: '[2020, 2021]'")
ap.add_argument("urls_def_json")
ap.add_argument("outhtmlname", default="result_calendar.html")
ap.add_argument("--css_url", default="calendar.css")
ap.add_argument("--titlefmt", default="Calendar for {years}")
args = ap.parse_args()
urls = json.load(io.open(args.urls_def_json, encoding="utf-8"))
years = json.loads(args.year)
if not isinstance(years, (list,)):
years = [years]
locale = os.environ.get("LC_TIME", _locale.setlocale(_locale.LC_TIME, ""))
cal = HRefCollectionLocaleHTMLCalendar(urls, 6, locale.split(".")[0])
with io.open(args.outhtmlname, "w", encoding="utf-8") as fo:
fo.write((cal.formatyearpage(
years, css=args.css_url, width=1,
titlefmt=_decode(args.titlefmt))).decode("utf-8"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment