133 lines
5.7 KiB
Python
133 lines
5.7 KiB
Python
#!/usr/bin/env python3
|
|
# vim:ts=4:sw=4:ft=python:fileencoding=utf-8
|
|
# Copyright © 2015-2019 Carl Chenet <carl.chenet@ohmytux.com>
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
|
|
"""Checks an RSS feed and posts new entries to Mastodon."""
|
|
|
|
# standard libraires imports
|
|
import codecs
|
|
import importlib
|
|
import logging
|
|
import logging.handlers
|
|
import sys
|
|
import re
|
|
|
|
# external liraries imports
|
|
from bs4 import BeautifulSoup
|
|
|
|
# app libraries imports
|
|
from feed2toot.addtags import AddTags
|
|
from feed2toot.cliparse import CliParse
|
|
from feed2toot.confparse import ConfParse
|
|
from feed2toot.feedcache import FeedCache
|
|
from feed2toot.filterentry import FilterEntry
|
|
from feed2toot.hashtags import build_hashtags
|
|
from feed2toot.hashtags import extract_hashtags_from_list
|
|
from feed2toot.lock import LockFile
|
|
from feed2toot.message import build_message
|
|
from feed2toot.message import send_message_dry_run
|
|
from feed2toot.message import send_message
|
|
from feed2toot.plugins import activate_plugins
|
|
from feed2toot.removeduplicates import RemoveDuplicates
|
|
from feed2toot.rss import populate_rss
|
|
from feed2toot.sortentries import sort_entries
|
|
from feed2toot.tootpost import TootPost
|
|
|
|
class Main:
|
|
'''Main class of Feed2toot'''
|
|
|
|
def __init__(self):
|
|
self.main()
|
|
|
|
def setup_logging(self, options):
|
|
if options.syslog:
|
|
sl = logging.handlers.SysLogHandler(address='/dev/log')
|
|
sl.setFormatter(logging.Formatter('feed2toot[%(process)d]: %(message)s'))
|
|
# convert syslog argument to a numeric value
|
|
loglevel = getattr(logging, options.syslog.upper(), None)
|
|
if not isinstance(loglevel, int):
|
|
raise ValueError('Invalid log level: %s' % loglevel)
|
|
sl.setLevel(loglevel)
|
|
logging.getLogger('').addHandler(sl)
|
|
logging.debug('configured syslog level %s' % loglevel)
|
|
logging.getLogger('').setLevel(logging.DEBUG)
|
|
sh = logging.StreamHandler()
|
|
sh.setLevel(options.log_level.upper())
|
|
logging.getLogger('').addHandler(sh)
|
|
logging.debug('configured stdout level %s' % sh.level)
|
|
|
|
def main(self):
|
|
'''The main function'''
|
|
clip = CliParse()
|
|
clioptions = clip.options
|
|
self.setup_logging(clioptions)
|
|
# iterating over the different configuration files
|
|
cfgp = ConfParse(clioptions)
|
|
confs = cfgp.confvalues
|
|
for conf in confs:
|
|
options = conf[0]
|
|
config = conf[1]
|
|
tweetformat = conf[2]
|
|
feeds = conf[3]
|
|
plugins = conf[4]
|
|
# check the logfile and logtimeout
|
|
lockfile = LockFile(options['lockfile'], options['locktimeout'])
|
|
# create link to the persistent list
|
|
cache = FeedCache(options)
|
|
severalwordshashtags = extract_hashtags_from_list(options)
|
|
# reverse feed entries because most recent one should be sent as the last one in Mastodon
|
|
for feed in feeds:
|
|
# store the patterns by rss
|
|
if 'patterns' in feed:
|
|
patterns = feed['patterns']
|
|
entries = feed['feed']['entries'][0:clioptions.limit]
|
|
entries.reverse()
|
|
# --rss-sections option: print rss sections and exit
|
|
if clioptions.rsssections:
|
|
if entries:
|
|
print('The following sections are available in this RSS feed: {}'.format([j for j in entries[0]]))
|
|
else:
|
|
print('Could not parse the section of the rss feed')
|
|
# release the lock file
|
|
lockfile.release()
|
|
sys.exit(0)
|
|
# sort entries and check if they were not previously sent
|
|
totweet = sort_entries(clioptions.all, cache, entries)
|
|
for entry in totweet:
|
|
# populate rss with new entry to send
|
|
rss = populate_rss(entry)
|
|
rss = build_hashtags(entry, rss, options, severalwordshashtags)
|
|
# parse tweetfomat to elements
|
|
elements = re.findall(r"\{(.*?)\}",tweetformat)
|
|
# strip : from elements to allow string formating, eg. {title:.20}
|
|
for i,s in enumerate(elements):
|
|
if s.find(':'):
|
|
elements[i] = s.split(':')[0]
|
|
fe = FilterEntry(elements, entry, options, feed['patterns'], feed['rssobject'], feed['feedname'])
|
|
entrytosend = fe.finalentry
|
|
if entrytosend:
|
|
finaltweet = build_message(entrytosend, tweetformat, rss)
|
|
if clioptions.dryrun:
|
|
send_message_dry_run(config, entrytosend, finaltweet)
|
|
else:
|
|
send_message(config, clioptions, options, entrytosend, finaltweet, cache, rss)
|
|
# plugins
|
|
if plugins and entrytosend:
|
|
activate_plugins(plugins, finaltweet)
|
|
# do not forget to close cache (shelf object)
|
|
cache.close()
|
|
# release the lock file
|
|
lockfile.release()
|