Merge branch '45' to solve bug #45 about sending multiple times the same message to Mastodon
This commit is contained in:
commit
64f33ecfac
5 changed files with 127 additions and 0 deletions
|
@ -52,8 +52,14 @@ class CliParse:
|
||||||
help='tweet all RSS items, regardless of cache')
|
help='tweet all RSS items, regardless of cache')
|
||||||
parser.add_argument('-l', '--limit', dest='limit', default=10, type=int,
|
parser.add_argument('-l', '--limit', dest='limit', default=10, type=int,
|
||||||
help='tweet only LIMIT items (default: %(default)s)')
|
help='tweet only LIMIT items (default: %(default)s)')
|
||||||
|
parser.add_argument('-t', '--lock-timeout', dest='locktimeout', default=3600, type=int,
|
||||||
|
help='lock timeout in seconds after which feed2toot can removes the lock itself')
|
||||||
parser.add_argument('--cachefile', dest='cachefile',
|
parser.add_argument('--cachefile', dest='cachefile',
|
||||||
help='location of the cache file (default: %(default)s)')
|
help='location of the cache file (default: %(default)s)')
|
||||||
|
parser.add_argument('--lockfile', dest='lockfile',
|
||||||
|
default=os.path.join(os.getenv('XDG_CONFIG_HOME', '~/.config'),
|
||||||
|
'feed2toot.lock'),
|
||||||
|
help='location of the lock file (default: %(default)s)')
|
||||||
parser.add_argument('-n', '--dry-run', dest='dryrun',
|
parser.add_argument('-n', '--dry-run', dest='dryrun',
|
||||||
action='store_true', default=False,
|
action='store_true', default=False,
|
||||||
help='Do not actually post tweets')
|
help='Do not actually post tweets')
|
||||||
|
|
|
@ -31,6 +31,7 @@ import feedparser
|
||||||
from feed2toot.confparsers.cache import parsecache
|
from feed2toot.confparsers.cache import parsecache
|
||||||
from feed2toot.confparsers.hashtaglist import parsehashtaglist
|
from feed2toot.confparsers.hashtaglist import parsehashtaglist
|
||||||
from feed2toot.confparsers.feedparser import parsefeedparser
|
from feed2toot.confparsers.feedparser import parsefeedparser
|
||||||
|
from feed2toot.confparsers.lock import parselock
|
||||||
from feed2toot.confparsers.media import parsemedia
|
from feed2toot.confparsers.media import parsemedia
|
||||||
from feed2toot.confparsers.plugins import parseplugins
|
from feed2toot.confparsers.plugins import parseplugins
|
||||||
from feed2toot.confparsers.rss.pattern import parsepattern
|
from feed2toot.confparsers.rss.pattern import parsepattern
|
||||||
|
@ -69,6 +70,10 @@ class ConfParse:
|
||||||
# pattern and patter_case_sensitive format option
|
# pattern and patter_case_sensitive format option
|
||||||
#################################################
|
#################################################
|
||||||
options['patterns'], options['patternscasesensitive'] = parsepattern(config)
|
options['patterns'], options['patternscasesensitive'] = parsepattern(config)
|
||||||
|
#################################################
|
||||||
|
# lock file options
|
||||||
|
#################################################
|
||||||
|
options['lockfile'], options['locktimeout'] = parselock(self.clioptions.lockfile, self.clioptions.locktimeout, config)
|
||||||
###############################
|
###############################
|
||||||
# addtags option, default: True
|
# addtags option, default: True
|
||||||
###############################
|
###############################
|
||||||
|
|
48
feed2toot/confparsers/lock.py
Normal file
48
feed2toot/confparsers/lock.py
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
# -*- coding: 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/
|
||||||
|
|
||||||
|
# Get values of the lock section
|
||||||
|
'''Get values of the lock section'''
|
||||||
|
|
||||||
|
# standard library imports
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def parselock(lockfile, locktimeout, config):
|
||||||
|
'''Parse configuration values and get values of the hashtaglist section'''
|
||||||
|
lockfile = lockfile
|
||||||
|
locktimeout = locktimeout
|
||||||
|
section = 'lock'
|
||||||
|
##################
|
||||||
|
# lockfile option
|
||||||
|
##################
|
||||||
|
confoption = 'lock_file'
|
||||||
|
if config.has_section(section):
|
||||||
|
lockfile = config.get(section, confoption)
|
||||||
|
lockfile = os.path.expanduser(lockfile)
|
||||||
|
lockfileparent = os.path.dirname(lockfile)
|
||||||
|
if lockfileparent and not os.path.exists(lockfileparent):
|
||||||
|
sys.exit('The parent directory of the cache file does not exist: {lockfileparent}'.format(lockfileparent=lockfileparent))
|
||||||
|
######################
|
||||||
|
# lock_timeout option
|
||||||
|
######################
|
||||||
|
if config.has_section(section):
|
||||||
|
confoption = 'lock_timeout'
|
||||||
|
if config.has_option(section, confoption):
|
||||||
|
try:
|
||||||
|
locktimeout = int(config.get(section, confoption))
|
||||||
|
except ValueError as err:
|
||||||
|
sys.exit('Error in configuration with the {confoption} parameter in [{section}]: {err}'.format(confoption=confoption, section=section, err=err))
|
||||||
|
return lockfile, locktimeout
|
63
feed2toot/lock.py
Normal file
63
feed2toot/lock.py
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
# 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/>
|
||||||
|
|
||||||
|
'''Manage a lock file'''
|
||||||
|
|
||||||
|
# standard libraires imports
|
||||||
|
import datetime
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class LockFile:
|
||||||
|
'''LockFile object'''
|
||||||
|
def __init__(self, lockfile, locktimeout):
|
||||||
|
'''check the lockfile and the locktimeout'''
|
||||||
|
self.lockfile = lockfile
|
||||||
|
ltimeout = datetime.timedelta(seconds=locktimeout)
|
||||||
|
self.lfdateformat = '%Y-%m-%d_%H-%M-%S'
|
||||||
|
# if a lock file exists
|
||||||
|
if os.path.exists(self.lockfile):
|
||||||
|
if os.path.isfile(self.lockfile):
|
||||||
|
with open(self.lockfile, 'r') as lf:
|
||||||
|
lfcontent = lf.read().rstrip()
|
||||||
|
# lfcontent should be a datetime
|
||||||
|
logging.debug('Check if lock file is older than timeout ({timeout} secs)'.format(timeout=locktimeout))
|
||||||
|
locktime = datetime.datetime.strptime(lfcontent, self.lfdateformat)
|
||||||
|
if locktime < (datetime.datetime.now() - ltimeout):
|
||||||
|
# remove the lock file
|
||||||
|
logging.debug('Found an expired lock file')
|
||||||
|
self.release()
|
||||||
|
self.create_lock()
|
||||||
|
else:
|
||||||
|
# quit because another feed2toot process is running
|
||||||
|
logging.debug('Found a valid lock file. Exiting immediately.')
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
# no lock file. Creating one
|
||||||
|
self.create_lock()
|
||||||
|
|
||||||
|
def create_lock(self):
|
||||||
|
'''Create a lock file'''
|
||||||
|
with open(self.lockfile, 'w') as lf:
|
||||||
|
currentdatestring = datetime.datetime.now().strftime(self.lfdateformat)
|
||||||
|
lf.write(currentdatestring)
|
||||||
|
logging.debug('lockfile {lockfile} created.'.format(lockfile=self.lockfile))
|
||||||
|
|
||||||
|
def release(self):
|
||||||
|
'''Release the lockfile'''
|
||||||
|
os.remove(self.lockfile)
|
||||||
|
logging.debug('Removed lock file.')
|
|
@ -32,6 +32,7 @@ from feed2toot.filterentry import FilterEntry
|
||||||
from feed2toot.removeduplicates import RemoveDuplicates
|
from feed2toot.removeduplicates import RemoveDuplicates
|
||||||
from feed2toot.tootpost import TootPost
|
from feed2toot.tootpost import TootPost
|
||||||
from feed2toot.feedcache import FeedCache
|
from feed2toot.feedcache import FeedCache
|
||||||
|
from feed2toot.lock import LockFile
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
class Main:
|
class Main:
|
||||||
|
@ -71,6 +72,8 @@ class Main:
|
||||||
tweetformat = conf[2]
|
tweetformat = conf[2]
|
||||||
feeds = conf[3]
|
feeds = conf[3]
|
||||||
plugins = conf[4]
|
plugins = conf[4]
|
||||||
|
# check the logfile and logtimeout
|
||||||
|
lockfile = LockFile(options['lockfile'], options['locktimeout'])
|
||||||
# create link to the persistent list
|
# create link to the persistent list
|
||||||
cache = FeedCache(options)
|
cache = FeedCache(options)
|
||||||
if 'hashtaglist' in options and options['hashtaglist']:
|
if 'hashtaglist' in options and options['hashtaglist']:
|
||||||
|
@ -221,3 +224,5 @@ class Main:
|
||||||
print(err)
|
print(err)
|
||||||
# do not forget to close cache (shelf object)
|
# do not forget to close cache (shelf object)
|
||||||
cache.close()
|
cache.close()
|
||||||
|
# release the lock file
|
||||||
|
lockfile.release()
|
||||||
|
|
Loading…
Reference in a new issue