Last active
September 6, 2021 09:28
-
-
Save hhsprings/07bc04b0443f15018936961aee5c08c4 to your computer and use it in GitHub Desktop.
url list to html calendar
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- 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"] = " " * 5 | |
res = re.sub( | |
r">([^<>]+)<", | |
(r' id="{id}"><a href="#{id_prev}" title="{title_prev}"><</a>' + | |
r'<span title="{title}">{spaces}\1{spaces}</span>' + | |
r'<a href="#{id_next}" title="{title_next}">></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"> </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