comments are back
This commit is contained in:
parent
18521317d3
commit
ba81e496c1
1 changed files with 152 additions and 57 deletions
209
nasg.py
209
nasg.py
|
@ -15,7 +15,6 @@ import hashlib
|
||||||
import math
|
import math
|
||||||
import asyncio
|
import asyncio
|
||||||
import csv
|
import csv
|
||||||
import operator
|
|
||||||
import getpass
|
import getpass
|
||||||
|
|
||||||
import magic
|
import magic
|
||||||
|
@ -36,8 +35,6 @@ from webmentiontools.send import WebmentionSend
|
||||||
from bleach import clean
|
from bleach import clean
|
||||||
from emoji import UNICODE_EMOJI
|
from emoji import UNICODE_EMOJI
|
||||||
|
|
||||||
from pprint import pprint
|
|
||||||
|
|
||||||
def splitpath(path):
|
def splitpath(path):
|
||||||
parts = []
|
parts = []
|
||||||
(path, tail) = os.path.split(path)
|
(path, tail) = os.path.split(path)
|
||||||
|
@ -336,6 +333,9 @@ class Comment(object):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reacji(self):
|
def reacji(self):
|
||||||
|
if hasattr(self, '_reacji'):
|
||||||
|
return self._reacji
|
||||||
|
|
||||||
t = self.meta.get('type', 'webmention')
|
t = self.meta.get('type', 'webmention')
|
||||||
typemap = {
|
typemap = {
|
||||||
'like-of': '👍',
|
'like-of': '👍',
|
||||||
|
@ -343,35 +343,62 @@ class Comment(object):
|
||||||
'favorite': '★',
|
'favorite': '★',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self._reacji = ''
|
||||||
|
|
||||||
if t in typemap.keys():
|
if t in typemap.keys():
|
||||||
return typemap[t]
|
self._reacji = typemap[t]
|
||||||
|
else:
|
||||||
|
maybe = clean(self.content).strip()
|
||||||
|
if maybe in UNICODE_EMOJI:
|
||||||
|
self._reacji = maybe
|
||||||
|
|
||||||
maybe = clean(self.content).strip()
|
return self._reacji
|
||||||
if maybe in UNICODE_EMOJI:
|
|
||||||
return maybe
|
|
||||||
|
|
||||||
return ''
|
@property
|
||||||
|
def h(self):
|
||||||
|
if hasattr(self, '_h'):
|
||||||
|
return self._h
|
||||||
|
record = {
|
||||||
|
'mtime': self.mtime,
|
||||||
|
'source': self.source,
|
||||||
|
'target': self.target
|
||||||
|
}
|
||||||
|
h = json.dumps(record, sort_keys=True)
|
||||||
|
self._h = hashlib.sha1(h.encode('utf-8')).hexdigest()
|
||||||
|
return self._h
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def html(self):
|
def html(self):
|
||||||
return shared.Pandoc().convert(self.content)
|
if hasattr(self, '_html'):
|
||||||
|
return self._html
|
||||||
|
|
||||||
|
self._html = shared.Pandoc().convert(self.content)
|
||||||
|
return self._html
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def tmplvars(self):
|
def tmplvars(self):
|
||||||
return {
|
if hasattr(self, '_tmplvars'):
|
||||||
|
return self._tmplvars
|
||||||
|
|
||||||
|
self._tmplvars = {
|
||||||
'published': self.published.datetime,
|
'published': self.published.datetime,
|
||||||
'author': dict(self.meta.get('author', {})),
|
'author': dict(self.meta.get('author', {})),
|
||||||
'content': self.content,
|
'content': self.content,
|
||||||
'html': self.html,
|
'html': self.html,
|
||||||
'source': self.meta.get('source', ''),
|
'source': self.source,
|
||||||
'target': self.meta.get('target', ''),
|
'target': self.target,
|
||||||
'type': self.meta.get('type', 'webmention'),
|
'type': self.meta.get('type', 'webmention'),
|
||||||
'reacji': self.reacji
|
'reacji': self.reacji,
|
||||||
|
'id': self.h
|
||||||
}
|
}
|
||||||
|
return self._tmplvars
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def published(self):
|
def published(self):
|
||||||
return arrow.get(self.meta.get('date', self.mtime))
|
if hasattr(self, '_published'):
|
||||||
|
return self._published
|
||||||
|
self._published = arrow.get(self.meta.get('date', self.mtime))
|
||||||
|
return self._published
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pubtime(self):
|
def pubtime(self):
|
||||||
|
@ -379,17 +406,23 @@ class Comment(object):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def source(self):
|
def source(self):
|
||||||
s = self.meta.get('source')
|
if hasattr(self, '_source'):
|
||||||
for d in shared.config.get('site', 'domains').split(' '):
|
return self._source
|
||||||
|
s = self.meta.get('source', '')
|
||||||
|
domains = shared.config.get('site', 'domains').split(' ')
|
||||||
|
self._source = s
|
||||||
|
for d in domains:
|
||||||
if d in s:
|
if d in s:
|
||||||
return ''
|
self._source = ''
|
||||||
return s
|
return self._source
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target(self):
|
def target(self):
|
||||||
|
if hasattr(self, '_target'):
|
||||||
|
return self._target
|
||||||
t = self.meta.get('target', shared.config.get('site', 'url'))
|
t = self.meta.get('target', shared.config.get('site', 'url'))
|
||||||
t = '{p.path}'.format(p=urllib.parse.urlparse(t)).strip('/')
|
self._target = '{p.path}'.format(p=urllib.parse.urlparse(t)).strip('/')
|
||||||
return t
|
return self._target
|
||||||
|
|
||||||
|
|
||||||
class Comments(object):
|
class Comments(object):
|
||||||
|
@ -552,47 +585,57 @@ class WebImage(object):
|
||||||
@property
|
@property
|
||||||
def rssenclosure(self):
|
def rssenclosure(self):
|
||||||
""" Returns the largest available image for RSS to add as attachment """
|
""" Returns the largest available image for RSS to add as attachment """
|
||||||
|
if hasattr(self, '_rssenclosure'):
|
||||||
|
return self._rssenclosure
|
||||||
|
|
||||||
target = self.sizes[-1][1]
|
target = self.sizes[-1][1]
|
||||||
return {
|
self._rssenclosure = {
|
||||||
'mime': magic.Magic(mime=True).from_file(target['fpath']),
|
'mime': magic.Magic(mime=True).from_file(target['fpath']),
|
||||||
'url': target['url'],
|
'url': target['url'],
|
||||||
'bytes': os.path.getsize(target['fpath'])
|
'bytes': os.path.getsize(target['fpath'])
|
||||||
}
|
}
|
||||||
|
return self._rssenclosure
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_photo(self):
|
def is_photo(self):
|
||||||
""" Match image meta against config artist regex to see if the file is
|
if hasattr(self, '_is_photo'):
|
||||||
a photo or just a regular image """
|
return self._is_photo
|
||||||
pattern = shared.config.get('photo', 'regex', fallback=None)
|
|
||||||
if not pattern or not isinstance(pattern, str):
|
self._is_photo = False
|
||||||
return False
|
#if not pattern or not isinstance(pattern, str):
|
||||||
pattern = re.compile(pattern)
|
# return False
|
||||||
|
pattern = re.compile(shared.config.get('photo', 'regex'))
|
||||||
|
|
||||||
cpr = self.meta.get('Copyright', '')
|
cpr = self.meta.get('Copyright', '')
|
||||||
art = self.meta.get('Artist', '')
|
art = self.meta.get('Artist', '')
|
||||||
if not cpr and not art:
|
if not cpr and not art:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if pattern.search(cpr) \
|
if cpr and art:
|
||||||
or pattern.search(art):
|
if pattern.search(cpr) or pattern.search(art):
|
||||||
return True
|
self._is_photo = True
|
||||||
|
|
||||||
return False
|
return self._is_photo
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_downsizeable(self):
|
def is_downsizeable(self):
|
||||||
|
if hasattr(self, '_is_downsizeable'):
|
||||||
|
return self._is_downsizeable
|
||||||
|
|
||||||
|
self._is_downsizeable = False
|
||||||
""" Check if the image is large enough and jpeg or png in order to
|
""" Check if the image is large enough and jpeg or png in order to
|
||||||
downsize it """
|
downsize it """
|
||||||
fb = self.sizes[-1][0]
|
fb = self.sizes[-1][0]
|
||||||
ftype = self.meta.get('FileType', None)
|
ftype = self.meta.get('FileType', None)
|
||||||
if not ftype:
|
if not ftype:
|
||||||
return False
|
return self._is_downsizeable
|
||||||
if ftype.lower() == 'jpeg' or ftype.lower() == 'png':
|
if ftype.lower() == 'jpeg' or ftype.lower() == 'png':
|
||||||
width = int(self.meta.get('ImageWidth', 0))
|
width = int(self.meta.get('ImageWidth', 0))
|
||||||
height = int(self.meta.get('ImageHeight', 0))
|
height = int(self.meta.get('ImageHeight', 0))
|
||||||
if width > fb or height > fb:
|
if width > fb or height > fb:
|
||||||
return True
|
self._is_downsizeable = True
|
||||||
return False
|
|
||||||
|
return self._is_downsizeable
|
||||||
|
|
||||||
def _copy(self):
|
def _copy(self):
|
||||||
target = os.path.join(
|
target = os.path.join(
|
||||||
|
@ -723,7 +766,10 @@ class Taxonomy(BaseIter):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pages(self):
|
def pages(self):
|
||||||
return math.ceil(len(self.data) / shared.config.getint('common', 'pagination'))
|
if hasattr(self, '_pages'):
|
||||||
|
return self._pages
|
||||||
|
self._pages = math.ceil(len(self.data) / shared.config.getint('common', 'pagination'))
|
||||||
|
return self._pages
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "taxonomy %s with %d items" % (self.taxonomy, len(self.data))
|
return "taxonomy %s with %d items" % (self.taxonomy, len(self.data))
|
||||||
|
@ -845,6 +891,39 @@ class Taxonomy(BaseIter):
|
||||||
html.write(r)
|
html.write(r)
|
||||||
os.utime(target, (self.mtime, self.mtime))
|
os.utime(target, (self.mtime, self.mtime))
|
||||||
|
|
||||||
|
# ---
|
||||||
|
# this is a joke
|
||||||
|
# see http://indieweb.org/YAMLFeed
|
||||||
|
# don't do YAMLFeeds.
|
||||||
|
if 1 == page:
|
||||||
|
yml = {
|
||||||
|
'site': {
|
||||||
|
'author': renderer.sitevars['author'],
|
||||||
|
'url': renderer.sitevars['url'],
|
||||||
|
'title': renderer.sitevars['title'],
|
||||||
|
},
|
||||||
|
'items': [],
|
||||||
|
}
|
||||||
|
|
||||||
|
for p in posttmpls:
|
||||||
|
yml['items'].append({
|
||||||
|
'title': p['title'],
|
||||||
|
'url': "%s/%s/" % ( renderer.sitevars['url'], p['slug']),
|
||||||
|
'content': p['content'],
|
||||||
|
'summary': p['summary'],
|
||||||
|
'published': p['published'],
|
||||||
|
'updated': p['updated'],
|
||||||
|
})
|
||||||
|
|
||||||
|
target = os.path.join(self.feedp, 'index.yml')
|
||||||
|
logging.info("rendering YAML feed to %s", target)
|
||||||
|
fm = frontmatter.loads('')
|
||||||
|
fm.metadata = yml
|
||||||
|
with open(target, "wt") as html:
|
||||||
|
html.write(frontmatter.dumps(fm))
|
||||||
|
os.utime(target, (self.mtime, self.mtime))
|
||||||
|
# ---
|
||||||
|
|
||||||
class Content(BaseIter):
|
class Content(BaseIter):
|
||||||
def __init__(self, images, comments, extensions=['md']):
|
def __init__(self, images, comments, extensions=['md']):
|
||||||
super(Content, self).__init__()
|
super(Content, self).__init__()
|
||||||
|
@ -983,18 +1062,6 @@ class Singular(object):
|
||||||
self.photo
|
self.photo
|
||||||
)
|
)
|
||||||
|
|
||||||
#@property
|
|
||||||
#def isrepost(self):
|
|
||||||
#isrepost = False
|
|
||||||
|
|
||||||
#if len(self.reactions.keys()):
|
|
||||||
#isrepost = list(self.reactions.keys())[0]
|
|
||||||
|
|
||||||
#if isrepost:
|
|
||||||
#if len(self.reactions[isrepost]) == 1:
|
|
||||||
#linkto = self.reactions[isrepost][0]
|
|
||||||
|
|
||||||
|
|
||||||
def __filter_images(self):
|
def __filter_images(self):
|
||||||
linkto = False
|
linkto = False
|
||||||
isrepost = None
|
isrepost = None
|
||||||
|
@ -1072,6 +1139,8 @@ class Singular(object):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reactions(self):
|
def reactions(self):
|
||||||
|
if hasattr(self, '_reactions'):
|
||||||
|
return self._reactions
|
||||||
# getting rid of '-' to avoid css trouble and similar
|
# getting rid of '-' to avoid css trouble and similar
|
||||||
convert = {
|
convert = {
|
||||||
'bookmark-of': 'bookmark',
|
'bookmark-of': 'bookmark',
|
||||||
|
@ -1088,10 +1157,14 @@ class Singular(object):
|
||||||
x = [x]
|
x = [x]
|
||||||
reactions[v] = x
|
reactions[v] = x
|
||||||
|
|
||||||
return reactions
|
self._reactions = reactions
|
||||||
|
return self._reactions
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def urls(self):
|
def urls(self):
|
||||||
|
if hasattr(self, '_urls'):
|
||||||
|
return self._urls
|
||||||
|
|
||||||
urls = shared.URLREGEX.findall(self.content)
|
urls = shared.URLREGEX.findall(self.content)
|
||||||
|
|
||||||
for reactionurls in self.reactions.values():
|
for reactionurls in self.reactions.values():
|
||||||
|
@ -1106,10 +1179,14 @@ class Singular(object):
|
||||||
continue
|
continue
|
||||||
r.append(link)
|
r.append(link)
|
||||||
|
|
||||||
return r
|
self._urls = r
|
||||||
|
return self._urls
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lang(self):
|
def lang(self):
|
||||||
|
if hasattr(self, '_lang'):
|
||||||
|
return self._lang
|
||||||
|
|
||||||
lang = 'en'
|
lang = 'en'
|
||||||
try:
|
try:
|
||||||
lang = langdetect.detect("\n".join([
|
lang = langdetect.detect("\n".join([
|
||||||
|
@ -1118,7 +1195,8 @@ class Singular(object):
|
||||||
]))
|
]))
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
return lang
|
self._lang = lang
|
||||||
|
return self._lang
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def tags(self):
|
def tags(self):
|
||||||
|
@ -1182,11 +1260,16 @@ class Singular(object):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def title(self):
|
def title(self):
|
||||||
|
if hasattr(self, '_title'):
|
||||||
|
return self._title
|
||||||
|
|
||||||
|
self._title = ''
|
||||||
for maybe in ['title', 'bookmark-of', 'in-reply-to', 'repost-of']:
|
for maybe in ['title', 'bookmark-of', 'in-reply-to', 'repost-of']:
|
||||||
maybe = self.meta.get(maybe, False)
|
maybe = self.meta.get(maybe, False)
|
||||||
if maybe:
|
if maybe:
|
||||||
return maybe
|
self._title = maybe
|
||||||
return ''
|
break
|
||||||
|
return self._title
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def url(self):
|
def url(self):
|
||||||
|
@ -1240,6 +1323,9 @@ class Singular(object):
|
||||||
if not self.isphoto:
|
if not self.isphoto:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
if hasattr(self, '_exif'):
|
||||||
|
return self._exif
|
||||||
|
|
||||||
exif = {}
|
exif = {}
|
||||||
mapping = {
|
mapping = {
|
||||||
'camera': [
|
'camera': [
|
||||||
|
@ -1286,7 +1372,8 @@ class Singular(object):
|
||||||
exif[ekey] = maybe
|
exif[ekey] = maybe
|
||||||
break
|
break
|
||||||
|
|
||||||
return exif
|
self._exif = exif
|
||||||
|
return self._exif
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def rssenclosure(self):
|
def rssenclosure(self):
|
||||||
|
@ -1343,10 +1430,18 @@ class Singular(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
async def render(self, renderer):
|
async def render(self, renderer):
|
||||||
|
# this is only when I want salmentions and I want to include all of the comments as well
|
||||||
|
# otherwise it affects both webmentions sending and search indexing
|
||||||
|
#if len(self.comments):
|
||||||
|
#lctime = self.comments[0].mtime
|
||||||
|
#if lctime > self.mtime:
|
||||||
|
#self.mtime = lctime
|
||||||
|
|
||||||
|
mtime = self.mtime
|
||||||
if len(self.comments):
|
if len(self.comments):
|
||||||
lctime = self.comments[0].mtime
|
lctime = self.comments[0].mtime
|
||||||
if lctime > self.mtime:
|
if lctime > self.mtime:
|
||||||
self.mtime = lctime
|
mtime = lctime
|
||||||
|
|
||||||
logging.info("rendering and saving %s", self.fname)
|
logging.info("rendering and saving %s", self.fname)
|
||||||
targetdir = os.path.abspath(os.path.join(
|
targetdir = os.path.abspath(os.path.join(
|
||||||
|
@ -1357,8 +1452,8 @@ class Singular(object):
|
||||||
|
|
||||||
if not shared.config.getboolean('params', 'force') and os.path.isfile(target):
|
if not shared.config.getboolean('params', 'force') and os.path.isfile(target):
|
||||||
ttime = int(os.path.getmtime(target))
|
ttime = int(os.path.getmtime(target))
|
||||||
logging.debug('ttime is %d mtime is %d', ttime, self.mtime)
|
logging.debug('ttime is %d mtime is %d', ttime, mtime)
|
||||||
if ttime == self.mtime:
|
if ttime == mtime:
|
||||||
logging.debug('%s exists and up-to-date (lastmod: %d)', target, ttime)
|
logging.debug('%s exists and up-to-date (lastmod: %d)', target, ttime)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -1375,7 +1470,7 @@ class Singular(object):
|
||||||
logging.debug('writing %s', target)
|
logging.debug('writing %s', target)
|
||||||
html.write(r)
|
html.write(r)
|
||||||
html.close()
|
html.close()
|
||||||
os.utime(target, (self.mtime, self.mtime))
|
os.utime(target, (mtime, mtime))
|
||||||
|
|
||||||
|
|
||||||
async def ping(self, pinger):
|
async def ping(self, pinger):
|
||||||
|
|
Loading…
Reference in a new issue