mirror of
https://github.com/tanrax/RSSingle.git
synced 2025-03-03 03:35:46 +01:00
Compare commits
61 Commits
v1.0.0
...
dependabot
Author | SHA1 | Date | |
---|---|---|---|
63e71bc075 | |||
fe49baf040 | |||
4434603b33 | |||
67c1342ce1 | |||
f8b43a8b79 | |||
a63da96bd1 | |||
9532ff5760 | |||
21610500db | |||
1d8d444d2c | |||
2555616e65 | |||
8cd30e8b9e | |||
5e931082e4 | |||
62d93c43b9 | |||
e17c396fb2 | |||
768ca68241 | |||
34b4ae3e2b | |||
4ab9bc864f | |||
8e5e7646ce | |||
ab3c1b4610 | |||
84b108e154 | |||
e9980668c4 | |||
c1aa3e59d1 | |||
6be4933a9a | |||
cfd6bddafc | |||
4b5c774324 | |||
e03fff3a42 | |||
b7cfae13e1 | |||
57ed8aef3a | |||
b526fc582f | |||
f7a2c2417e | |||
0dfb71de00 | |||
124a57c033 | |||
16e80795cd | |||
4cd87527bd | |||
0a075bbdc9 | |||
62f24bb204 | |||
e8c77f3398 | |||
dd16696103 | |||
846de90642 | |||
e101803091 | |||
c3708e8899 | |||
cf60155018 | |||
82b3ff5cfd | |||
f64d68fb8f | |||
d2813ee689 | |||
9014c78d29 | |||
758733d025 | |||
bbe24f6364 | |||
52ccc2e676 | |||
df52406dfe | |||
3347b233de | |||
1f36dea889 | |||
daf79338b5 | |||
ff30f5807b | |||
1460f92f02 | |||
8f499d4c22 | |||
1a94b51f1a | |||
7a8721f6a1 | |||
d622931090 | |||
6eeda374da | |||
cafef51765 |
5
.dockerignore
Normal file
5
.dockerignore
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/LICENSE
|
||||||
|
/README.md
|
||||||
|
/rssingle.png
|
||||||
|
/Dockerfile
|
||||||
|
/config.yml
|
2
.github/FUNDING.yml
vendored
Normal file
2
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
github: tanrax
|
||||||
|
ko_fi: androsfenollosa
|
19
.github/dependabot.yml
vendored
Normal file
19
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
groups:
|
||||||
|
gh-actions-deps:
|
||||||
|
patterns:
|
||||||
|
- "*"
|
||||||
|
|
||||||
|
- package-ecosystem: "pip"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
groups:
|
||||||
|
python-deps:
|
||||||
|
patterns:
|
||||||
|
- "*"
|
59
.github/workflows/ci.yml
vendored
Normal file
59
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
name: CI workflow for RSSingle
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-check:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
python-version: ["3.8", "3.9", "3.10"]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install flake8
|
||||||
|
pip install -r requirements.txt
|
||||||
|
- name: Lint with flake8
|
||||||
|
run: |
|
||||||
|
# stop the build if there are Python syntax errors or undefined names
|
||||||
|
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
|
||||||
|
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
|
||||||
|
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
|
||||||
|
|
||||||
|
# to be completed once macOS builds fixed
|
||||||
|
create-and-publish-release:
|
||||||
|
needs: build-and-check
|
||||||
|
if: startsWith(github.ref, 'refs/tags/') && success()
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
# `--windowed` is for macOS, and `--onefile` is for other OSes.
|
||||||
|
pyinstaller-type: ['--windowed', '--onefile']
|
||||||
|
runner: ["macos-latest", "windows-latest", "ubuntu-latest"]
|
||||||
|
runs-on: ${{ matrix.runner }}
|
||||||
|
name: Builder for Python all-in-one executables, published on a release.
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Set up Python 3.8
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.8"
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install pyinstaller
|
||||||
|
pip install -r requirements.txt
|
||||||
|
- name: Build RSSingle (Windows, Linux)
|
||||||
|
if: ${{ matrix.runner != 'macos-latest' }}
|
||||||
|
run: pyinstaller --onefile ./rssingle.py
|
||||||
|
- name: Build RSSingle (macOS)
|
||||||
|
if: ${{ matrix.runner == 'macos-latest' }}
|
||||||
|
run: pyinstaller --windowed ./rssingle.py
|
||||||
|
- name: List artifacts for finishing this action
|
||||||
|
run: find ./dist/
|
45
.github/workflows/container.yml
vendored
Normal file
45
.github/workflows/container.yml
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
name: Container image builder for RSS single
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_run:
|
||||||
|
workflows: ["CI workflow for RSSingle"]
|
||||||
|
types: [completed]
|
||||||
|
branches: [master]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push-container-image:
|
||||||
|
name: Build and push container image to Docker Hub and GHCR.io
|
||||||
|
if: ${{ github.event.workflow_run.conclusion == 'success' && github.repository == 'tanrax/RSSingle' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build container image
|
||||||
|
id: build
|
||||||
|
uses: redhat-actions/buildah-build@v2
|
||||||
|
with:
|
||||||
|
image: ${{ github.repository }}
|
||||||
|
tags: latest
|
||||||
|
containerfiles: Dockerfile
|
||||||
|
|
||||||
|
- name: Push container image to Docker Hub
|
||||||
|
uses: redhat-actions/push-to-registry@v2
|
||||||
|
with:
|
||||||
|
image: ${{ steps.build.outputs.image }}
|
||||||
|
tags: ${{ steps.build.outputs.tags }}
|
||||||
|
registry: docker.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.DOCKER_TOKEN }}
|
||||||
|
|
||||||
|
- name: Push container image to GHCR.io
|
||||||
|
uses: redhat-actions/push-to-registry@v2
|
||||||
|
with:
|
||||||
|
image: ${{ steps.build.outputs.image }}
|
||||||
|
tags: ${{ steps.build.outputs.tags }}
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
|
18
Dockerfile
Normal file
18
Dockerfile
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
FROM docker.io/python:3.8-buster AS base
|
||||||
|
|
||||||
|
FROM base AS build
|
||||||
|
|
||||||
|
WORKDIR /work
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN pip3 install pyinstaller
|
||||||
|
|
||||||
|
RUN pip3 install -r /work/requirements.txt
|
||||||
|
RUN pyinstaller --onefile /work/rssingle.py
|
||||||
|
|
||||||
|
FROM docker.io/python:3.8-buster AS app
|
||||||
|
|
||||||
|
COPY --from=build /work/dist/rssingle /rssingle
|
||||||
|
|
||||||
|
ENTRYPOINT ["/rssingle"]
|
19
README.md
19
README.md
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
Generates an RSS file from the list of other feeds (RSS/Atom/JSON). Very handy when you want to centralise the list of your feeds in one place and all your devices feed from the same place.
|
Generates an RSS file from the list of other feeds (RSS/Atom/JSON). Very handy when you want to centralise the list of your feeds in one place and all your devices feed from the same place.
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="rssingle.png" width="200" alt="RRSingle">
|
||||||
|
</p>
|
||||||
|
|
||||||
## Run
|
## Run
|
||||||
|
|
||||||
1. Download the binary.
|
1. Download the binary.
|
||||||
@ -12,9 +16,11 @@ Generates an RSS file from the list of other feeds (RSS/Atom/JSON). Very handy w
|
|||||||
wget https://github.com/tanrax/RSSingle/releases/download/v1.0.0/rssingle
|
wget https://github.com/tanrax/RSSingle/releases/download/v1.0.0/rssingle
|
||||||
```
|
```
|
||||||
|
|
||||||
**MacOS and Windows**
|
**Windows**
|
||||||
|
|
||||||
Coming soon
|
``` shell
|
||||||
|
wget https://github.com/tanrax/RSSingle/releases/download/v1.0.0/rssingle.exe
|
||||||
|
```
|
||||||
|
|
||||||
2. Gives execution permissions.
|
2. Gives execution permissions.
|
||||||
|
|
||||||
@ -29,6 +35,7 @@ title: My RSS Feed
|
|||||||
description: My customised RSS feed with technology news
|
description: My customised RSS feed with technology news
|
||||||
url: https://www.example.com
|
url: https://www.example.com
|
||||||
output: rss.xml
|
output: rss.xml
|
||||||
|
max_entries: 5 # Delete this line to get all
|
||||||
feeds:
|
feeds:
|
||||||
- https://programadorwebvalencia.com/feed/
|
- https://programadorwebvalencia.com/feed/
|
||||||
- https://republicaweb.es/feed/
|
- https://republicaweb.es/feed/
|
||||||
@ -43,13 +50,19 @@ curl -o config.yml https://raw.githubusercontent.com/tanrax/RSSingle/master/conf
|
|||||||
4. Run the binary.
|
4. Run the binary.
|
||||||
|
|
||||||
``` shell
|
``` shell
|
||||||
./rssingle
|
./rssingle
|
||||||
```
|
```
|
||||||
|
|
||||||
A file called `rss.xml` will be created.
|
A file called `rss.xml` will be created.
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
|
Activate Debug messages by console.
|
||||||
|
|
||||||
|
```
|
||||||
|
export SR_LOG_LEVEl=DEBUG
|
||||||
|
```
|
||||||
|
|
||||||
### Compiling
|
### Compiling
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
@ -2,6 +2,10 @@ title: My RSS Feed
|
|||||||
description: My customised RSS feed with technology news
|
description: My customised RSS feed with technology news
|
||||||
url: https://www.example.com
|
url: https://www.example.com
|
||||||
output: rss.xml
|
output: rss.xml
|
||||||
|
max_entries: 2 # Delete this line to get all
|
||||||
feeds:
|
feeds:
|
||||||
- https://programadorwebvalencia.com/feed/
|
- https://programadorwebvalencia.com/feed/
|
||||||
- https://republicaweb.es/feed/
|
- https://republicaweb.es/feed/
|
||||||
|
filter_strings:
|
||||||
|
- unwanted
|
||||||
|
- exclude_this
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
feedgen==0.9.0
|
feedgen==1.0.0
|
||||||
feedparser==6.0.10
|
feedparser==6.0.11
|
||||||
listparser==0.19.0
|
listparser==0.20
|
||||||
lxml==4.9.0
|
lxml==5.2.2
|
||||||
python-dateutil==2.8.2
|
python-dateutil==2.9.0.post0
|
||||||
pyyaml==6.0
|
pyyaml==6.0.1
|
||||||
pyinstaller==5.1
|
pyinstaller==6.9.0
|
@ -1,5 +0,0 @@
|
|||||||
# For stdout to file
|
|
||||||
0 * * * * cd /opt/rss && . ./.env && /opt/rss/singlerss.py > /var/www/html/feeds.xml
|
|
||||||
|
|
||||||
# For file direct.
|
|
||||||
0 * * * * cd /opt/rss && . ./.env && /opt/rss/singlerss.py
|
|
@ -1,26 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Generate combined RSS feed.
|
|
||||||
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=oneshot
|
|
||||||
# Make sure to set user and group
|
|
||||||
# to your setup.
|
|
||||||
User=nginx
|
|
||||||
Group=nobody
|
|
||||||
|
|
||||||
# Make sure to customise these to your
|
|
||||||
# system!
|
|
||||||
WorkingDirectory=/var/www/html/feed.xml
|
|
||||||
# And this.
|
|
||||||
EnvironmentFile=/opt/singlerss/.env
|
|
||||||
# And this.
|
|
||||||
ExecStart=/opt/rss/singlerss.py
|
|
||||||
|
|
||||||
# These don't work on older systemd versions.
|
|
||||||
# In that case, you should configure singlerss
|
|
||||||
# to output to file, as documented in the README,
|
|
||||||
# and comment these directives out.
|
|
||||||
StandardInput=null
|
|
||||||
StandardError=journal
|
|
||||||
StandardOutput=file:$SINGLERSS_FEED_OUT_PATH
|
|
@ -1,8 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Hourly refresh of singlerss
|
|
||||||
|
|
||||||
[Timer]
|
|
||||||
OnCalendar=hourly
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=timers.target
|
|
BIN
rssingle.png
Normal file
BIN
rssingle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
60
rssingle.py
60
rssingle.py
@ -15,14 +15,13 @@ import json
|
|||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
# Varaibles
|
# Variables
|
||||||
|
|
||||||
log = None
|
log = None
|
||||||
CONFIG_PATH = "config.yml"
|
CONFIG_PATH = "config.yml"
|
||||||
LOG_LEVEL = environ.get("SR_LOG_LEVEl", "ERROR")
|
LOG_LEVEL = environ.get("SR_LOG_LEVEl", "ERROR")
|
||||||
fg = None
|
fg = None
|
||||||
FEED_OUT_PATH = None
|
FEED_OUT_PATH = None
|
||||||
FEED_LIST_PATH = None
|
|
||||||
FEEDS = []
|
FEEDS = []
|
||||||
CFG = None
|
CFG = None
|
||||||
|
|
||||||
@ -45,7 +44,7 @@ def setup_logging() -> None:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_url_from_feed(config):
|
def get_url_from_feed(config) -> str:
|
||||||
"""
|
"""
|
||||||
This function returns the URL from a feed.
|
This function returns the URL from a feed.
|
||||||
"""
|
"""
|
||||||
@ -70,9 +69,8 @@ def init_feed() -> None:
|
|||||||
fg.link(href=get_url_from_feed(CONFIG), rel="self")
|
fg.link(href=get_url_from_feed(CONFIG), rel="self")
|
||||||
fg.subtitle(CONFIG["description"])
|
fg.subtitle(CONFIG["description"])
|
||||||
fg.language("en")
|
fg.language("en")
|
||||||
except:
|
except BaseException: # find out what exceptions FeedGenerator can cause as well as KeyError.
|
||||||
log.error("Error initialising the feed!")
|
logging.exception("Error initialising the feed!")
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
log.debug("Feed initialised!")
|
log.debug("Feed initialised!")
|
||||||
|
|
||||||
@ -85,10 +83,20 @@ def parse_rss_feed(url) -> feedparser.FeedParserDict:
|
|||||||
try:
|
try:
|
||||||
# Hopefully this should parse..
|
# Hopefully this should parse..
|
||||||
return feedparser.parse(url)
|
return feedparser.parse(url)
|
||||||
except Exception:
|
except BaseException: # find out what exceptions .parse() call can cause.
|
||||||
log.warning("Failed to parse RSS feed.")
|
log.warning("Failed to parse RSS feed.")
|
||||||
# Now, we could handle gracefully.
|
# Now, we could handle gracefully.
|
||||||
|
|
||||||
|
def filter_feed_entries(entry) -> bool:
|
||||||
|
"""
|
||||||
|
This function filters feed entries based on strings defined in config.yml.
|
||||||
|
"""
|
||||||
|
filter_strings = CONFIG.get("filter_strings", [])
|
||||||
|
for filter_str in filter_strings:
|
||||||
|
if filter_str.lower() in entry.get("title", "").lower() or filter_str.lower() in entry.get("summary", "").lower():
|
||||||
|
log.debug(f"Entry filtered out: {entry['title']}")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
log.debug("Loading feed list into memory..")
|
log.debug("Loading feed list into memory..")
|
||||||
@ -99,30 +107,34 @@ def main():
|
|||||||
rss = parse_rss_feed(feed)
|
rss = parse_rss_feed(feed)
|
||||||
entries = rss.get("entries")
|
entries = rss.get("entries")
|
||||||
log.debug("Iterating over [input] feed entries..")
|
log.debug("Iterating over [input] feed entries..")
|
||||||
for entry in entries:
|
for entry in entries[:CONFIG["max_entries"]] if "max_entries" in CONFIG else entries:
|
||||||
log.debug("New feed entry created.")
|
log.debug("New feed entry created.")
|
||||||
|
|
||||||
|
if not filter_feed_entries(entry):
|
||||||
|
continue # Skip this entry
|
||||||
|
|
||||||
fe = fg.add_entry()
|
fe = fg.add_entry()
|
||||||
|
|
||||||
log.debug("Working on new feed entry..")
|
log.debug("Working on new feed entry..")
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
fe.id(entry["id"])
|
fe.id(entry["id"])
|
||||||
except:
|
except KeyError:
|
||||||
# Deifnitely weird...
|
# Definitely weird...
|
||||||
log.warning("Empty id attribute, defaulting..")
|
log.warning("Empty id attribute, defaulting..")
|
||||||
fe.id("about:blank")
|
fe.id("about:blank")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
fe.title(entry["title"])
|
fe.title(entry["title"])
|
||||||
except:
|
except KeyError:
|
||||||
# OK, this is a definite malformed feed!
|
# OK, this is a definite malformed feed!
|
||||||
log.warning("Empty title attribute, defaulting..")
|
log.warning("Empty title attribute, defaulting..")
|
||||||
fe.title("Unspecified")
|
fe.title("Unspecified")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
fe.link(href=entry["link"])
|
fe.link(href=entry["link"])
|
||||||
except:
|
except KeyError:
|
||||||
# When we have a empty link attribute, this isn't ideal
|
# When we have a empty link attribute, this isn't ideal
|
||||||
# to set a default value.. :/
|
# to set a default value.. :/
|
||||||
log.warning("Empty link attribute, defaulting..")
|
log.warning("Empty link attribute, defaulting..")
|
||||||
@ -136,12 +148,12 @@ def main():
|
|||||||
try:
|
try:
|
||||||
for author in entry["authors"]:
|
for author in entry["authors"]:
|
||||||
fe.author(author)
|
fe.author(author)
|
||||||
except:
|
except KeyError:
|
||||||
log.debug("Oh dear, a malformed feed! Adjusting.")
|
log.debug("Oh dear, a malformed feed! Adjusting.")
|
||||||
# This is a ugly hack to fix broken feed entries with the author attribute!
|
# This is a ugly hack to fix broken feed entries with the author attribute!
|
||||||
author["email"] = author.pop("href")
|
author["email"] = author.pop("href")
|
||||||
fe.author(author)
|
fe.author(author)
|
||||||
except:
|
except KeyError:
|
||||||
# Sometimes we don't have ANY author attributes, so we
|
# Sometimes we don't have ANY author attributes, so we
|
||||||
# have to set a dummy attribute.
|
# have to set a dummy attribute.
|
||||||
log.warning("Empty authors attribute, defaulting..")
|
log.warning("Empty authors attribute, defaulting..")
|
||||||
@ -155,7 +167,7 @@ def main():
|
|||||||
fe.description(entry["description"])
|
fe.description(entry["description"])
|
||||||
fe.summary(entry["description"])
|
fe.summary(entry["description"])
|
||||||
fe.content(entry["description"])
|
fe.content(entry["description"])
|
||||||
except:
|
except KeyError:
|
||||||
# Sometimes feeds don't provide a summary OR description, so we
|
# Sometimes feeds don't provide a summary OR description, so we
|
||||||
# have to set an empty value.
|
# have to set an empty value.
|
||||||
# This is pretty useless for a feed, so hopefully we
|
# This is pretty useless for a feed, so hopefully we
|
||||||
@ -169,11 +181,11 @@ def main():
|
|||||||
try:
|
try:
|
||||||
fe.published(entry["published"])
|
fe.published(entry["published"])
|
||||||
fe.updated(entry["published"])
|
fe.updated(entry["published"])
|
||||||
except:
|
except KeyError:
|
||||||
fe.published("1970-01/01T00:00:00+00:00")
|
fe.published("1970-01/01T00:00:00+00:00")
|
||||||
fe.updated("1970-01/01T00:00:00+00:00")
|
fe.updated("1970-01/01T00:00:00+00:00")
|
||||||
continue
|
continue
|
||||||
except:
|
except Exception:
|
||||||
# Sometimes feeds don't even provide a publish date, so we default to
|
# Sometimes feeds don't even provide a publish date, so we default to
|
||||||
# the start date &time of the Unix epoch.
|
# the start date &time of the Unix epoch.
|
||||||
log.warning("Empty publish attribute, defaulting..")
|
log.warning("Empty publish attribute, defaulting..")
|
||||||
@ -201,20 +213,6 @@ if __name__ == "__main__":
|
|||||||
log.error("This program will NOT run without that set.")
|
log.error("This program will NOT run without that set.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
try:
|
|
||||||
FEED_LIST_PATH = CONFIG["url"]
|
|
||||||
except:
|
|
||||||
log.error("*** Configure variable missing! ***")
|
|
||||||
log.error("`url` variable missing.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
try:
|
|
||||||
FEED_LIST_PATH = CONFIG["feeds"]
|
|
||||||
except:
|
|
||||||
log.error("*** Configure variable missing! ***")
|
|
||||||
log.error("`feeds` variable missing.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
init_feed()
|
init_feed()
|
||||||
|
|
||||||
log.debug("Begin processing feeds...")
|
log.debug("Begin processing feeds...")
|
||||||
|
Reference in New Issue
Block a user