diff --git a/datasets/boards/boat.csv b/datasets/boards/boat.csv
new file mode 100644
index 0000000..c088e1e
--- /dev/null
+++ b/datasets/boards/boat.csv
@@ -0,0 +1 @@
+name, url, language, country
diff --git a/datasets/boards/rent.csv b/datasets/boards/rent.csv
new file mode 100644
index 0000000..c088e1e
--- /dev/null
+++ b/datasets/boards/rent.csv
@@ -0,0 +1 @@
+name, url, language, country
diff --git a/datasets/boards/vacancy.csv b/datasets/boards/vacancy.csv
new file mode 100644
index 0000000..c088e1e
--- /dev/null
+++ b/datasets/boards/vacancy.csv
@@ -0,0 +1 @@
+name, url, language, country
diff --git a/datasets/boards/vehicles.csv b/datasets/boards/vehicles.csv
new file mode 100644
index 0000000..c088e1e
--- /dev/null
+++ b/datasets/boards/vehicles.csv
@@ -0,0 +1 @@
+name, url, language, country
diff --git a/datasets/catalogues/book.csv b/datasets/catalogues/book.csv
new file mode 100644
index 0000000..e69db23
--- /dev/null
+++ b/datasets/catalogues/book.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+New Online Books, https://onlinebooks.library.upenn.edu/newrss.xml, en-US, USA
diff --git a/datasets/catalogues/music.csv b/datasets/catalogues/music.csv
new file mode 100644
index 0000000..5358bb4
--- /dev/null
+++ b/datasets/catalogues/music.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+MetaBrainz Blog, https://blog.metabrainz.org/feed/, en-US, Worldwide
diff --git a/datasets/catalogues/software.csv b/datasets/catalogues/software.csv
new file mode 100644
index 0000000..a8768af
--- /dev/null
+++ b/datasets/catalogues/software.csv
@@ -0,0 +1,17 @@
+name, url, language, country
+Arch Linux: Recent package updates, https://archlinux.org/feeds/packages/, en-US, Worldwide
+Arch Linux: AUR Newest Packages, https://aur.archlinux.org/rss/, en-US, Worldwide
+PyPI recent updates, https://pypi.org/rss/updates.xml, en-US, Worldwide
+ctan-ann, https://www.ctan.org/ctan-ann/atom.xml, en-US, Worldwide
+Recent CPAN uploads - MetaCPAN, https://metacpan.org/recent.rss, en-US, Worldwide
+Announcements published via Launchpad, http://feeds.launchpad.net/announcements.atom, en-US, Worldwide
+store.kde.org - Latest Products, https://store.kde.org/content.rdf, en-US, Worldwide
+Parabola GNU/Linux-libre: Recent package updates, https://www.parabola.nu/feeds/packages/, en-US, Worldwide
+SlackBuilds.org ChangeLog, https://slackbuilds.org/rss/ChangeLog.rss, en-US, Worldwide
+OpenDesktop.org - Latest Products, https://www.opendesktop.org/content.rdf, en-US, Worldwide
+Flathub – recently updated applications, https://flathub.org/api/v2/feed/recently-updated, en-US, Worldwide
+https://flathub.org/api/v2/feed/new, Flathub – recently added applications, en-US, Worldwide
+Latest extensions in GNOME Shell Extensions, https://extensions.gnome.org/rss/, en-US, Worldwide
+DistroWatch.com: News, https://distrowatch.com/news/dw.xml, en-US, Worldwide
+GreasyFork: Recently Updates Userscripts, https://greasyfork.org/en/scripts.atom?sort=updated, en-US, Worldwide
+xfce-look.org - Latest Products, https://www.xfce-look.org/content.rdf, en-US, Worldwide
diff --git a/datasets/downloads/leaked_data.csv b/datasets/downloads/leaked_data.csv
new file mode 100644
index 0000000..9923709
--- /dev/null
+++ b/datasets/downloads/leaked_data.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+Leaked Documents - Postman, http://tracker2.postman.i2p/?view=RSS&mapset=69219, en-US, Worldwide
diff --git a/datasets/events/club.csv b/datasets/events/club.csv
new file mode 100644
index 0000000..9f4cc95
--- /dev/null
+++ b/datasets/events/club.csv
@@ -0,0 +1,3 @@
+name, url, language, country
+DNA Lounge, https://cdn.dnalounge.com/calendar/dnalounge.rss, en-US, USA
+DNA Lounge, https://www.dnalounge.com/calendar/dnalounge.rss, en-US, USA
diff --git a/datasets/forums/coding.csv b/datasets/forums/coding.csv
new file mode 100644
index 0000000..cbc7ce8
--- /dev/null
+++ b/datasets/forums/coding.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+SQLite, https://sqlite.org/forum/timeline.rss, en-US, Worldwide
diff --git a/datasets/forums/hacking.csv b/datasets/forums/hacking.csv
new file mode 100644
index 0000000..74c48ae
--- /dev/null
+++ b/datasets/forums/hacking.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+Leak Zone - Leaking & Cracking Forum - All Forums, https://leakzone.net/syndication.php?type=atom1.0, en-US, Worldwide
diff --git a/datasets/governments/ireland.csv b/datasets/governments/ireland.csv
new file mode 100644
index 0000000..6929039
--- /dev/null
+++ b/datasets/governments/ireland.csv
@@ -0,0 +1,36 @@
+name, url, language, country
+Agri-Food and Biosciences Institute (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/agri-food-and-biosciences-institute.atom, en-UK, United Kingdom
+Arts Council of Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/arts-council-of-northern-ireland.atom, en-UK, United Kingdom
+Boundary Commission for Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/boundary-commission-for-northern-ireland.atom, en-UK, United Kingdom
+Department for Communities (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-for-communities-northern-ireland.atom, en-UK, United Kingdom
+Department for Infrastructure (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-for-infrastructure-northern-ireland.atom, en-UK, United Kingdom
+Department for the Economy (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-for-the-economy-northern-ireland.atom, en-UK, United Kingdom
+"Department of Agriculture, Environment and Rural Affairs (Northern Ireland) - Activity on GOV.UK", https://www.gov.uk/government/organisations/department-of-agriculture-environment-and-rural-affairs-northern-ireland.atom, en-UK, United Kingdom
+Department of Education (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-of-education.atom, en-UK, United Kingdom
+Department of Finance (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-of-finance-northern-ireland.atom, en-UK, United Kingdom
+Department of Health (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-of-health-northern-ireland.atom, en-UK, United Kingdom
+Department of Justice (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-of-justice-northern-ireland.atom, en-UK, United Kingdom
+HSC Business Services Organisation (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/hsc-business-services-organisation-northern-ireland.atom, en-UK, United Kingdom
+Invest Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/invest-northern-ireland.atom, en-UK, United Kingdom
+Labour Relations Agency (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/labour-relations-agency.atom, en-UK, United Kingdom
+Legal Services Agency (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/legal-services-agency-northern-ireland.atom, en-UK, United Kingdom
+Livestock and Meat Commission for Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/livestock-and-meat-commission-for-northern-ireland.atom, en-UK, United Kingdom
+Northern Ireland Cancer Registry - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-cancer-registry.atom, en-UK, United Kingdom
+"Northern Ireland Council for the Curriculum, Examinations and Assessment - Activity on GOV.UK", https://www.gov.uk/government/organisations/northern-ireland-council-for-the-curriculum-examinations-and-assessment.atom, en-UK, United Kingdom
+Northern Ireland Courts and Tribunals Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-court-service.atom, en-UK, United Kingdom
+Northern Ireland Executive - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-executive.atom, en-UK, United Kingdom
+Northern Ireland Housing Executive - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-housing-executive.atom, en-UK, United Kingdom
+Northern Ireland Human Rights Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-human-rights-commission.atom, en-UK, United Kingdom
+Northern Ireland Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-office.atom, en-UK, United Kingdom
+Northern Ireland Policing Board - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-policing-board.atom, en-UK, United Kingdom
+Northern Ireland Prison Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-prison-service.atom, en-UK, United Kingdom
+Northern Ireland Statistics and Research Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-statistics-and-research-agency.atom, en-UK, United Kingdom
+Office of the Police Ombudsman for Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-of-the-police-ombudsman-for-northern-ireland.atom, en-UK, United Kingdom
+Parades Commission for Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/parades-commission-for-northern-ireland.atom, en-UK, United Kingdom
+Police Service of Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/police-service-of-northern-ireland.atom, en-UK, United Kingdom
+Probation Board for Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/probation-board-for-northern-ireland.atom, en-UK, United Kingdom
+Public Health Agency (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/public-health-agency-northern-ireland.atom, en-UK, United Kingdom
+Public Prosecution Service for Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/public-prosecution-service-for-northern-ireland.atom, en-UK, United Kingdom
+Sport Northern Ireland (Sports Council for Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/sports-council-for-northern-ireland.atom, en-UK, United Kingdom
+The Executive Office (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-executive-office-northern-ireland.atom, en-UK, United Kingdom
+Youth Justice Agency of Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/youth-justice-agency-of-northern-ireland.atom, en-UK, United Kingdom
diff --git a/datasets/governments/luxemburg.csv b/datasets/governments/luxemburg.csv
new file mode 100644
index 0000000..96f7706
--- /dev/null
+++ b/datasets/governments/luxemburg.csv
@@ -0,0 +1,4 @@
+name, url, language, country
+Gouvernement - All of the news, https://gouvernement.lu/en/actualites/toutes_actualites.rss, en-UK, Luxemburg
+Gouvernement - Alle Nachrichten, https://gouvernement.lu/de/actualites/toutes_actualites.rss, de-DE, Luxemburg
+Gouvernement - Toutes les actualités, https://gouvernement.lu/fr/actualites/toutes_actualites.rss, fr-FR, Luxemburg
diff --git a/datasets/governments/united_Kingdom.csv b/datasets/governments/united_Kingdom.csv
new file mode 100644
index 0000000..44863e2
--- /dev/null
+++ b/datasets/governments/united_Kingdom.csv
@@ -0,0 +1,619 @@
+name, url, language, country
+Academy for Social Justice - Activity on GOV.UK, https://www.gov.uk/government/organisations/academy-for-social-justice.atom, en-UK, United Kingdom
+Accelerated Capability Environment - Activity on GOV.UK, https://www.gov.uk/government/organisations/accelerated-capability-environment.atom, en-UK, United Kingdom
+Active Travel England - Activity on GOV.UK, https://www.gov.uk/government/organisations/active-travel-england.atom, en-UK, United Kingdom
+Administration of Radioactive Substances Advisory Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/administration-of-radioactive-substances-advisory-committee.atom, en-UK, United Kingdom
+Advanced Research and Invention Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/advanced-research-and-invention-agency.atom, en-UK, United Kingdom
+Advisory Committee on Animal Feedingstuffs - Activity on GOV.UK, https://www.gov.uk/government/organisations/advisory-committee-on-animal-feedingstuffs.atom, en-UK, United Kingdom
+Advisory Committee on Business Appointments - Activity on GOV.UK, https://www.gov.uk/government/organisations/advisory-committee-on-business-appointments.atom, en-UK, United Kingdom
+Advisory Committee on Clinical Impact Awards - Activity on GOV.UK, https://www.gov.uk/government/organisations/advisory-committee-on-clinical-impact-awards.atom, en-UK, United Kingdom
+Advisory Committee on Conscientious Objectors - Activity on GOV.UK, https://www.gov.uk/government/organisations/advisory-committee-on-conscientious-objectors.atom, en-UK, United Kingdom
+Advisory Committee on Novel Foods and Processes - Activity on GOV.UK, https://www.gov.uk/government/organisations/advisory-committee-on-novel-foods-and-processes.atom, en-UK, United Kingdom
+Advisory Committee on Releases to the Environment - Activity on GOV.UK, https://www.gov.uk/government/organisations/advisory-committee-on-releases-to-the-environment.atom, en-UK, United Kingdom
+Advisory Committee on the Microbiological Safety of Food - Activity on GOV.UK, https://www.gov.uk/government/organisations/advisory-committee-on-the-microbiological-safety-of-food.atom, en-UK, United Kingdom
+Advisory Committees on Justices of the Peace - Activity on GOV.UK, https://www.gov.uk/government/organisations/advisory-committees-on-justices-of-the-peace.atom, en-UK, United Kingdom
+"Advisory, Conciliation and Arbitration Service - Activity on GOV.UK", https://www.gov.uk/government/organisations/acas.atom, en-UK, United Kingdom
+Advisory Council on the Misuse of Drugs - Activity on GOV.UK, https://www.gov.uk/government/organisations/advisory-council-on-the-misuse-of-drugs.atom, en-UK, United Kingdom
+Advisory Group on Military and Emergency Response Medicine - Activity on GOV.UK, https://www.gov.uk/government/organisations/advisory-group-on-military-medicine.atom, en-UK, United Kingdom
+Agriculture and Horticulture Development Board - Activity on GOV.UK, https://www.gov.uk/government/organisations/agriculture-and-horticulture-development-board.atom, en-UK, United Kingdom
+Agri-Food and Biosciences Institute (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/agri-food-and-biosciences-institute.atom, en-UK, United Kingdom
+Air Accidents Investigation Branch - Activity on GOV.UK, https://www.gov.uk/government/organisations/air-accidents-investigation-branch.atom, en-UK, United Kingdom
+Animal and Plant Health Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/animal-and-plant-health-agency.atom, en-UK, United Kingdom
+Animals in Science Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/animals-in-science-committee.atom, en-UK, United Kingdom
+Architects Registration Board - Activity on GOV.UK, https://www.gov.uk/government/organisations/architects-registration-board.atom, en-UK, United Kingdom
+Armed Forces Covenant Fund Trust - Activity on GOV.UK, https://www.gov.uk/government/organisations/armed-forces-covenant-fund-trust.atom, en-UK, United Kingdom
+Armed Forces' Pay Review Body - Activity on GOV.UK, https://www.gov.uk/government/organisations/armed-forces-pay-review-body.atom, en-UK, United Kingdom
+Arts and Humanities Research Council - Activity on GOV.UK, https://www.gov.uk/government/organisations/arts-and-humanities-research-council.atom, en-UK, United Kingdom
+Arts Council England - Activity on GOV.UK, https://www.gov.uk/government/organisations/arts-council-england.atom, en-UK, United Kingdom
+Arts Council of Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/arts-council-of-northern-ireland.atom, en-UK, United Kingdom
+Arts Council of Wales - Activity on GOV.UK, https://www.gov.uk/government/organisations/arts-council-of-wales.atom, en-UK, United Kingdom
+Atomic Weapons Establishment - Activity on GOV.UK, https://www.gov.uk/government/organisations/atomic-weapons-establishment.atom, en-UK, United Kingdom
+Attorney General's Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/attorney-generals-office.atom, en-UK, United Kingdom
+Bank of England - Activity on GOV.UK, https://www.gov.uk/government/organisations/bank-of-england.atom, en-UK, United Kingdom
+BBC - Activity on GOV.UK, https://www.gov.uk/government/organisations/bbc.atom, en-UK, United Kingdom
+BBC World Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/bbc-world-service.atom, en-UK, United Kingdom
+Biometrics and Forensics Ethics Group - Activity on GOV.UK, https://www.gov.uk/government/organisations/biometrics-and-forensics-ethics-group.atom, en-UK, United Kingdom
+Biometrics and Surveillance Camera Commissioner - Activity on GOV.UK, https://www.gov.uk/government/organisations/biometrics-and-surveillance-camera-commissioner.atom, en-UK, United Kingdom
+Biotechnology and Biological Sciences Research Council - Activity on GOV.UK, https://www.gov.uk/government/organisations/biotechnology-biological-sciences-research-council.atom, en-UK, United Kingdom
+Board of Trustees of the Royal Botanic Gardens Kew - Activity on GOV.UK, https://www.gov.uk/government/organisations/board-of-trustees-of-the-royal-botanic-gardens-kew.atom, en-UK, United Kingdom
+Bona Vacantia - Activity on GOV.UK, https://www.gov.uk/government/organisations/bona-vacantia.atom, en-UK, United Kingdom
+Border Force - Activity on GOV.UK, https://www.gov.uk/government/organisations/border-force.atom, en-UK, United Kingdom
+Boundary Commission for England - Activity on GOV.UK, https://www.gov.uk/government/organisations/boundary-commission-for-england.atom, en-UK, United Kingdom
+Boundary Commission for Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/boundary-commission-for-northern-ireland.atom, en-UK, United Kingdom
+Boundary Commission for Scotland - Activity on GOV.UK, https://www.gov.uk/government/organisations/boundary-commission-for-scotland.atom, en-UK, United Kingdom
+Boundary Commission for Wales - Activity on GOV.UK, https://www.gov.uk/government/organisations/boundary-commission-for-wales.atom, en-UK, United Kingdom
+British Business Bank - Activity on GOV.UK, https://www.gov.uk/government/organisations/british-business-bank.atom, en-UK, United Kingdom
+British Cattle Movement Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/british-cattle-movement-service.atom, en-UK, United Kingdom
+British Council - Activity on GOV.UK, https://www.gov.uk/government/organisations/british-council.atom, en-UK, United Kingdom
+British Film Institute - Activity on GOV.UK, https://www.gov.uk/government/organisations/british-film-institute.atom, en-UK, United Kingdom
+British Hallmarking Council - Activity on GOV.UK, https://www.gov.uk/government/organisations/british-hallmarking-council.atom, en-UK, United Kingdom
+British Library - Activity on GOV.UK, https://www.gov.uk/government/organisations/british-library.atom, en-UK, United Kingdom
+British Museum - Activity on GOV.UK, https://www.gov.uk/government/organisations/british-museum.atom, en-UK, United Kingdom
+British Pharmacopoeia Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/british-pharmacopoeia.atom, en-UK, United Kingdom
+British Technology Investments Ltd - Activity on GOV.UK, https://www.gov.uk/government/organisations/british-technology-investments-ltd.atom, en-UK, United Kingdom
+British Transport Police Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/british-transport-police-authority.atom, en-UK, United Kingdom
+British Wool - Activity on GOV.UK, https://www.gov.uk/government/organisations/british-wool.atom, en-UK, United Kingdom
+Broads Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/broads-authority.atom, en-UK, United Kingdom
+Building Digital UK - Activity on GOV.UK, https://www.gov.uk/government/organisations/building-digital-uk.atom, en-UK, United Kingdom
+Cabinet Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/cabinet-office.atom, en-UK, United Kingdom
+Cabinet Office Board - Activity on GOV.UK, https://www.gov.uk/government/organisations/cabinet-office-board.atom, en-UK, United Kingdom
+Cafcass - Activity on GOV.UK, https://www.gov.uk/government/organisations/children-and-family-court-advisory-and-support-service.atom, en-UK, United Kingdom
+Careers Wales - Activity on GOV.UK, https://www.gov.uk/government/organisations/careers-wales.atom, en-UK, United Kingdom
+Care Quality Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/care-quality-commission.atom, en-UK, United Kingdom
+Central Advisory Committee on Compensation - Activity on GOV.UK, https://www.gov.uk/government/organisations/central-advisory-committee-on-compensation.atom, en-UK, United Kingdom
+Central Arbitration Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/central-arbitration-committee.atom, en-UK, United Kingdom
+Central Digital and Data Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/central-digital-and-data-office.atom, en-UK, United Kingdom
+Centre for Connected and Autonomous Vehicles - Activity on GOV.UK, https://www.gov.uk/government/organisations/centre-for-connected-and-autonomous-vehicles.atom, en-UK, United Kingdom
+Centre for Data Ethics and Innovation - Activity on GOV.UK, https://www.gov.uk/government/organisations/centre-for-data-ethics-and-innovation.atom, en-UK, United Kingdom
+"Centre for Environment, Fisheries and Aquaculture Science - Activity on GOV.UK", https://www.gov.uk/government/organisations/centre-for-environment-fisheries-and-aquaculture-science.atom, en-UK, United Kingdom
+Certification Officer - Activity on GOV.UK, https://www.gov.uk/government/organisations/certification-officer.atom, en-UK, United Kingdom
+Channel 4 - Activity on GOV.UK, https://www.gov.uk/government/organisations/channel-4.atom, en-UK, United Kingdom
+Chevening Scholarship Programme - Activity on GOV.UK, https://www.gov.uk/government/organisations/chevening-foundation.atom, en-UK, United Kingdom
+Child Safeguarding Practice Review Panel - Activity on GOV.UK, https://www.gov.uk/government/organisations/child-safeguarding-practice-review-panel.atom, en-UK, United Kingdom
+Churches Conservation Trust - Activity on GOV.UK, https://www.gov.uk/government/organisations/churches-conservation-trust.atom, en-UK, United Kingdom
+Civil Aviation Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-aviation-authority.atom, en-UK, United Kingdom
+Civil Justice Council - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-justice-council.atom, en-UK, United Kingdom
+Civil Nuclear Constabulary - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-nuclear-constabulary.atom, en-UK, United Kingdom
+Civil Nuclear Police Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-nuclear-police-authority.atom, en-UK, United Kingdom
+Civil Procedure Rule Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-procedure-rules-committee.atom, en-UK, United Kingdom
+Civil Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service.atom, en-UK, United Kingdom
+Civil Service Board - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-board.atom, en-UK, United Kingdom
+Civil Service Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-commission.atom, en-UK, United Kingdom
+Civil Service Fast Stream - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-fast-stream.atom, en-UK, United Kingdom
+Civil Service Group - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-group.atom, en-UK, United Kingdom
+Civil Service HR - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-hr.atom, en-UK, United Kingdom
+Coal Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-coal-authority.atom, en-UK, United Kingdom
+College of Policing - Activity on GOV.UK, https://www.gov.uk/government/organisations/college-of-policing.atom, en-UK, United Kingdom
+Commissioner for Public Appointments - Activity on GOV.UK, https://www.gov.uk/government/organisations/commissioner-for-public-appointments.atom, en-UK, United Kingdom
+Commission for Countering Extremism - Activity on GOV.UK, https://www.gov.uk/government/organisations/commission-for-countering-extremism.atom, en-UK, United Kingdom
+Commission on Human Medicines - Activity on GOV.UK, https://www.gov.uk/government/organisations/commission-on-human-medicines.atom, en-UK, United Kingdom
+Committee on Climate Change - Activity on GOV.UK, https://www.gov.uk/government/organisations/committee-on-climate-change.atom, en-UK, United Kingdom
+Committee on Fuel Poverty - Activity on GOV.UK, https://www.gov.uk/government/organisations/committee-on-fuel-poverty.atom, en-UK, United Kingdom
+"Committee on Mutagenicity of Chemicals in Food, Consumer Products and the Environment - Activity on GOV.UK", https://www.gov.uk/government/organisations/committee-on-mutagenicity-of-chemicals-in-food-consumer-products-and-the-environment.atom, en-UK, United Kingdom
+Committee on Radioactive Waste Management - Activity on GOV.UK, https://www.gov.uk/government/organisations/committee-on-radioactive-waste-management.atom, en-UK, United Kingdom
+Committee on Standards in Public Life - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-committee-on-standards-in-public-life.atom, en-UK, United Kingdom
+"Committee on Toxicity of Chemicals in Food, Consumer Products and the Environment - Activity on GOV.UK", https://www.gov.uk/government/organisations/committee-on-toxicity-of-chemicals-in-food-consumer-products-and-the-environment.atom, en-UK, United Kingdom
+Commonwealth Scholarship Commission in the UK - Activity on GOV.UK, https://www.gov.uk/government/organisations/commonwealth-scholarship-commission-in-the-uk.atom, en-UK, United Kingdom
+Companies House - Activity on GOV.UK, https://www.gov.uk/government/organisations/companies-house.atom, en-UK, United Kingdom
+Companies House - Activity on GOV.UK, https://www.gov.uk/government/organisations/companies-house.atom, en-UK, United Kingdom
+Company Names Tribunal - Activity on GOV.UK, https://www.gov.uk/government/organisations/company-names-tribunal.atom, en-UK, United Kingdom
+Competition and Markets Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/competition-and-markets-authority.atom, en-UK, United Kingdom
+Competition Appeal Tribunal - Activity on GOV.UK, https://www.gov.uk/government/organisations/competition-appeal-tribunal.atom, en-UK, United Kingdom
+Competition Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/competition-service.atom, en-UK, United Kingdom
+"Conflict, Stability and Security Fund - Activity on GOV.UK", https://www.gov.uk/government/organisations/conflict-stability-and-security-fund.atom, en-UK, United Kingdom
+Construction Industry Training Board - Activity on GOV.UK, https://www.gov.uk/government/organisations/construction-industry-training-board.atom, en-UK, United Kingdom
+Consumer Council for Water - Activity on GOV.UK, https://www.gov.uk/government/organisations/consumer-council-for-water.atom, en-UK, United Kingdom
+Copyright Tribunal - Activity on GOV.UK, https://www.gov.uk/government/organisations/copyright-tribunal.atom, en-UK, United Kingdom
+Corporate Officers of the House of Commons - Activity on GOV.UK, https://www.gov.uk/government/organisations/corporate-officers-of-the-house-of-commons.atom, en-UK, United Kingdom
+Corporate Officers of the House of Lords - Activity on GOV.UK, https://www.gov.uk/government/organisations/corporate-officers-of-the-house-of-lords.atom, en-UK, United Kingdom
+Council for Science and Technology - Activity on GOV.UK, https://www.gov.uk/government/organisations/council-for-science-and-technology.atom, en-UK, United Kingdom
+Covent Garden Market Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/covent-garden-market-authority.atom, en-UK, United Kingdom
+Criminal Cases Review Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/criminal-cases-review-commission.atom, en-UK, United Kingdom
+Criminal Injuries Compensation Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/criminal-injuries-compensation-authority.atom, en-UK, United Kingdom
+Criminal Procedure Rule Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/criminal-procedure-rule-committee.atom, en-UK, United Kingdom
+Crossrail International - Activity on GOV.UK, https://www.gov.uk/government/organisations/crossrail-international.atom, en-UK, United Kingdom
+Crown Commercial Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/crown-commercial-service.atom, en-UK, United Kingdom
+Crown Prosecution Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/crown-prosecution-service.atom, en-UK, United Kingdom
+Dartmoor National Park Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/dartmoor-national-park-authority.atom, en-UK, United Kingdom
+Defence Academy of the United Kingdom - Activity on GOV.UK, https://www.gov.uk/government/organisations/defence-academy.atom, en-UK, United Kingdom
+Defence and Security Accelerator - Activity on GOV.UK, https://www.gov.uk/government/organisations/defence-and-security-accelerator.atom, en-UK, United Kingdom
+Defence and Security Media Advisory Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/defence-and-security-media-advisory-committee.atom, en-UK, United Kingdom
+Defence Equipment and Support - Activity on GOV.UK, https://www.gov.uk/government/organisations/defence-equipment-and-support.atom, en-UK, United Kingdom
+Defence Infrastructure Organisation - Activity on GOV.UK, https://www.gov.uk/government/organisations/defence-infrastructure-organisation.atom, en-UK, United Kingdom
+Defence Nuclear Organisation - Activity on GOV.UK, https://www.gov.uk/government/organisations/defence-nuclear-organisation.atom, en-UK, United Kingdom
+Defence Nuclear Safety Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/defence-nuclear-safety-committee.atom, en-UK, United Kingdom
+Defence Safety Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/defence-safety-authority.atom, en-UK, United Kingdom
+Defence Science and Technology Laboratory - Activity on GOV.UK, https://www.gov.uk/government/organisations/defence-science-and-technology-laboratory.atom, en-UK, United Kingdom
+Defence Sixth Form College - Activity on GOV.UK, https://www.gov.uk/government/organisations/defence-sixth-form-college.atom, en-UK, United Kingdom
+Defra's Science Advisory Council - Activity on GOV.UK, https://www.gov.uk/government/organisations/science-advisory-council.atom, en-UK, United Kingdom
+Department for Business & Trade - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-for-business-and-trade.atom, en-UK, United Kingdom
+Department for Communities (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-for-communities-northern-ireland.atom, en-UK, United Kingdom
+"Department for Culture, Media & Sport - Activity on GOV.UK", https://www.gov.uk/government/organisations/department-for-culture-media-and-sport.atom, en-UK, United Kingdom
+Department for Education - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-for-education.atom, en-UK, United Kingdom
+Department for Energy Security & Net Zero - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-for-energy-security-and-net-zero.atom, en-UK, United Kingdom
+Department for Environment Food & Rural Affairs - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-for-environment-food-rural-affairs.atom, en-UK, United Kingdom
+Department for Infrastructure (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-for-infrastructure-northern-ireland.atom, en-UK, United Kingdom
+"Department for Levelling Up, Housing & Communities - Activity on GOV.UK", https://www.gov.uk/government/organisations/department-for-levelling-up-housing-and-communities.atom, en-UK, United Kingdom
+"Department for Science, Innovation & Technology - Activity on GOV.UK", https://www.gov.uk/government/organisations/department-for-science-innovation-and-technology.atom, en-UK, United Kingdom
+Department for the Economy (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-for-the-economy-northern-ireland.atom, en-UK, United Kingdom
+Department for Transport - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-for-transport.atom, en-UK, United Kingdom
+Department for Work & Pensions - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-for-work-pensions.atom, en-UK, United Kingdom
+"Department of Agriculture, Environment and Rural Affairs (Northern Ireland) - Activity on GOV.UK", https://www.gov.uk/government/organisations/department-of-agriculture-environment-and-rural-affairs-northern-ireland.atom, en-UK, United Kingdom
+Department of Education (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-of-education.atom, en-UK, United Kingdom
+Department of Finance (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-of-finance-northern-ireland.atom, en-UK, United Kingdom
+Department of Health (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-of-health-northern-ireland.atom, en-UK, United Kingdom
+Department of Health & Social Care - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-of-health-and-social-care.atom, en-UK, United Kingdom
+Department of Justice (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/department-of-justice-northern-ireland.atom, en-UK, United Kingdom
+Departments - Activity on GOV.UK, https://www.gov.uk/government/organisations.atom, en-UK, United Kingdom
+DfT OLR Holdings Limited - Activity on GOV.UK, https://www.gov.uk/government/organisations/dft-olr-holdings-limited.atom, en-UK, United Kingdom
+Directly Operated Railways Limited - Activity on GOV.UK, https://www.gov.uk/government/organisations/directly-operated-railways-limited.atom, en-UK, United Kingdom
+Disability Unit - Activity on GOV.UK, https://www.gov.uk/government/organisations/disability-unit.atom, en-UK, United Kingdom
+Disabled People’s Employment Corporation (GB) Ltd - Activity on GOV.UK, https://www.gov.uk/government/organisations/disabled-peoples-employment-corporation.atom, en-UK, United Kingdom
+Disabled Persons Transport Advisory Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/disabled-persons-transport-advisory-committee.atom, en-UK, United Kingdom
+Disclosure and Barring Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/disclosure-and-barring-service.atom, en-UK, United Kingdom
+District Valuer Services (DVS) - Activity on GOV.UK, https://www.gov.uk/government/organisations/district-valuer-services-dvs.atom, en-UK, United Kingdom
+Driver and Vehicle Licensing Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/driver-and-vehicle-licensing-agency.atom, en-UK, United Kingdom
+Driver and Vehicle Standards Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/driver-and-vehicle-standards-agency.atom, en-UK, United Kingdom
+East West Railway Company Limited - Activity on GOV.UK, https://www.gov.uk/government/organisations/east-west-railway-company.atom, en-UK, United Kingdom
+Ebbsfleet Development Corporation - Activity on GOV.UK, https://www.gov.uk/government/organisations/ebbsfleet-development-corporation.atom, en-UK, United Kingdom
+Economic and Social Research Council - Activity on GOV.UK, https://www.gov.uk/government/organisations/economic-and-social-research-council.atom, en-UK, United Kingdom
+Education and Skills Funding Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/education-and-skills-funding-agency.atom, en-UK, United Kingdom
+Electricity Settlements Company - Activity on GOV.UK, https://www.gov.uk/government/organisations/electricity-settlements-company.atom, en-UK, United Kingdom
+Employment Agency Standards Inspectorate - Activity on GOV.UK, https://www.gov.uk/government/organisations/employment-agency-standards-inspectorate.atom, en-UK, United Kingdom
+Engineering and Physical Sciences Research Council - Activity on GOV.UK, https://www.gov.uk/government/organisations/engineering-and-physical-sciences-research-council.atom, en-UK, United Kingdom
+Engineering Construction Industry Training Board - Activity on GOV.UK, https://www.gov.uk/government/organisations/engineering-construction-industry-training-board.atom, en-UK, United Kingdom
+English Institute of Sport - Activity on GOV.UK, https://www.gov.uk/government/organisations/english-institute-of-sport.atom, en-UK, United Kingdom
+Environment Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/environment-agency.atom, en-UK, United Kingdom
+Equality and Human Rights Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/equality-and-human-rights-commission.atom, en-UK, United Kingdom
+Equality Hub - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-equality-hub.atom, en-UK, United Kingdom
+Estyn - Activity on GOV.UK, https://www.gov.uk/government/organisations/estyn.atom, en-UK, United Kingdom
+Evaluation Task Force - Activity on GOV.UK, https://www.gov.uk/government/organisations/evaluation-task-force.atom, en-UK, United Kingdom
+Exmoor National Park Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/exmoor-national-park-authority.atom, en-UK, United Kingdom
+Export Control Joint Unit - Activity on GOV.UK, https://www.gov.uk/government/organisations/export-control-joint-unit.atom, en-UK, United Kingdom
+Export Guarantees Advisory Council - Activity on GOV.UK, https://www.gov.uk/government/organisations/export-guarantees-advisory-council.atom, en-UK, United Kingdom
+Family Justice Council - Activity on GOV.UK, https://www.gov.uk/government/organisations/family-justice-council.atom, en-UK, United Kingdom
+Family Procedure Rule Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/family-procedure-rule-committee.atom, en-UK, United Kingdom
+FCDO Services - Activity on GOV.UK, https://www.gov.uk/government/organisations/fcdo-services.atom, en-UK, United Kingdom
+FCDO Services - Activity on GOV.UK, https://www.gov.uk/government/organisations/fcdo-services.atom, en-UK, United Kingdom
+Financial Conduct Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/financial-conduct-authority.atom, en-UK, United Kingdom
+Financial Reporting Council - Activity on GOV.UK, https://www.gov.uk/government/organisations/financial-reporting-council.atom, en-UK, United Kingdom
+Fire Service College - Activity on GOV.UK, https://www.gov.uk/government/organisations/fire-service-college.atom, en-UK, United Kingdom
+Fleet Air Arm Museum - Activity on GOV.UK, https://www.gov.uk/government/organisations/fleet-air-arm-museum.atom, en-UK, United Kingdom
+Flood and Coastal Erosion Risk Management Research and Development Programme - Activity on GOV.UK, https://www.gov.uk/government/organisations/flood-and-coastal-erosion-risk-management-research-and-development-programme.atom, en-UK, United Kingdom
+Flood Forecasting Centre - Activity on GOV.UK, https://www.gov.uk/government/organisations/flood-forecasting-centre.atom, en-UK, United Kingdom
+Flood Re - Activity on GOV.UK, https://www.gov.uk/government/organisations/flood-re.atom, en-UK, United Kingdom
+Food Standards Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/food-standards-agency.atom, en-UK, United Kingdom
+"Foreign, Commonwealth & Development Office - Activity on GOV.UK", https://www.gov.uk/government/organisations/foreign-commonwealth-development-office.atom, en-UK, United Kingdom
+Forensic Science Regulator - Activity on GOV.UK, https://www.gov.uk/government/organisations/forensic-science-regulator.atom, en-UK, United Kingdom
+Forest Research - Activity on GOV.UK, https://www.gov.uk/government/organisations/forest-research.atom, en-UK, United Kingdom
+Forestry Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/forestry-commission.atom, en-UK, United Kingdom
+Forestry England - Activity on GOV.UK, https://www.gov.uk/government/organisations/forest-enterprise-england.atom, en-UK, United Kingdom
+Further Education Commissioner - Activity on GOV.UK, https://www.gov.uk/government/organisations/further-education-commissioner.atom, en-UK, United Kingdom
+Gambling Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/gambling-commission.atom, en-UK, United Kingdom
+Gangmasters and Labour Abuse Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/gangmasters-and-labour-abuse-authority.atom, en-UK, United Kingdom
+Geospatial Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/geospatial-commission.atom, en-UK, United Kingdom
+Government Actuary's Department - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-actuarys-department.atom, en-UK, United Kingdom
+Government Analysis Function - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-analysis-function.atom, en-UK, United Kingdom
+Government Chemist - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-chemist.atom, en-UK, United Kingdom
+Government Commercial Function - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-commercial-function.atom, en-UK, United Kingdom
+Government Communication Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-government-communication-service.atom, en-UK, United Kingdom
+Government Communications Headquarters - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-communications-headquarters.atom, en-UK, United Kingdom
+Government Corporate Finance Profession - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-corporate-finance-profession-cfp.atom, en-UK, United Kingdom
+Government Data Quality Hub - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-data-quality-hub.atom, en-UK, United Kingdom
+Government Digital Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-digital-service.atom, en-UK, United Kingdom
+Government Economic Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-government-economic-service.atom, en-UK, United Kingdom
+Government Equalities Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-equalities-office.atom, en-UK, United Kingdom
+Government Estates Management - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-estates-management.atom, en-UK, United Kingdom
+Government Finance Function - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-finance-function.atom, en-UK, United Kingdom
+Government Geography Profession - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-geography-profession.atom, en-UK, United Kingdom
+Government Internal Audit Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-internal-audit-agency.atom, en-UK, United Kingdom
+Government Knowledge & Information Management Profession - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-government-knowledge-information-management-profession.atom, en-UK, United Kingdom
+Government Legal Department - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-legal-department.atom, en-UK, United Kingdom
+Government Legal Profession - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-government-legal-profession.atom, en-UK, United Kingdom
+Government Occupational Psychology Profession - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-government-occupational-psychology-profession.atom, en-UK, United Kingdom
+Government Office for Science - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-office-for-science.atom, en-UK, United Kingdom
+Government Office for Technology Transfer - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-office-for-technology-transfer.atom, en-UK, United Kingdom
+Government Operational Research Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-government-operational-research-service.atom, en-UK, United Kingdom
+Government Partnerships International - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-partnerships-international.atom, en-UK, United Kingdom
+Government People Group - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-people-group.atom, en-UK, United Kingdom
+Government Planning Inspectors - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-government-planning-inspectors.atom, en-UK, United Kingdom
+Government Planning Profession - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-the-government-planning-profession.atom, en-UK, United Kingdom
+Government Property Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-property-agency.atom, en-UK, United Kingdom
+Government Property Function - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-property-function.atom, en-UK, United Kingdom
+Government Recruitment Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-recruitment-service.atom, en-UK, United Kingdom
+Government Science & Engineering Profession - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-government-science-engineering.atom, en-UK, United Kingdom
+Government Security Profession - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-security-profession.atom, en-UK, United Kingdom
+Government Skills and Curriculum Unit - Activity on GOV.UK, https://www.gov.uk/government/organisations/government-skills-and-curriculum-unit.atom, en-UK, United Kingdom
+Government Social Research Profession - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-government-social-research-profession.atom, en-UK, United Kingdom
+Government Statistical Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-government-statistical-service.atom, en-UK, United Kingdom
+Government Tax Profession - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-government-tax-profession.atom, en-UK, United Kingdom
+Government Veterinary Services - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-government-veterinary-services.atom, en-UK, United Kingdom
+Gov Facility Services Limited - Activity on GOV.UK, https://www.gov.uk/government/organisations/gov-facility-services-limited.atom, en-UK, United Kingdom
+Great Britain-China Centre - Activity on GOV.UK, https://www.gov.uk/government/organisations/great-britain-china-centre.atom, en-UK, United Kingdom
+Great British Nuclear - Activity on GOV.UK, https://www.gov.uk/government/organisations/great-british-nuclear.atom, en-UK, United Kingdom
+Groceries Code Adjudicator - Activity on GOV.UK, https://www.gov.uk/government/organisations/groceries-code-adjudicator.atom, en-UK, United Kingdom
+Health and Safety Executive - Activity on GOV.UK, https://www.gov.uk/government/organisations/health-and-safety-executive.atom, en-UK, United Kingdom
+Health Education England - Activity on GOV.UK, https://www.gov.uk/government/organisations/health-education-england.atom, en-UK, United Kingdom
+Health Research Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/health-research-authority.atom, en-UK, United Kingdom
+Higher Education Statistics Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/higher-education-statistical-agency.atom, en-UK, United Kingdom
+High Speed Two (HS2) Limited - Activity on GOV.UK, https://www.gov.uk/government/organisations/high-speed-two-limited.atom, en-UK, United Kingdom
+Historic England - Activity on GOV.UK, https://www.gov.uk/government/organisations/historic-england.atom, en-UK, United Kingdom
+Historic Royal Palaces - Activity on GOV.UK, https://www.gov.uk/government/organisations/historic-royal-palaces.atom, en-UK, United Kingdom
+HM Courts & Tribunals Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/hm-courts-and-tribunals-service.atom, en-UK, United Kingdom
+HM Crown Prosecution Service Inspectorate - Activity on GOV.UK, https://www.gov.uk/government/organisations/hm-crown-prosecution-service-inspectorate.atom, en-UK, United Kingdom
+HM Government Communications Centre - Activity on GOV.UK, https://www.gov.uk/government/organisations/hm-government-communications-centre.atom, en-UK, United Kingdom
+HM Inspectorate of Constabulary and Fire & Rescue Services - Activity on GOV.UK, https://www.gov.uk/government/organisations/hm-inspectorate-of-constabulary-and-fire-rescue-services.atom, en-UK, United Kingdom
+HM Inspectorate of Prisons - Activity on GOV.UK, https://www.gov.uk/government/organisations/hm-inspectorate-of-prisons.atom, en-UK, United Kingdom
+HM Inspectorate of Probation - Activity on GOV.UK, https://www.gov.uk/government/organisations/hm-inspectorate-of-probation.atom, en-UK, United Kingdom
+HM Land Registry - Activity on GOV.UK, https://www.gov.uk/government/organisations/land-registry.atom, en-UK, United Kingdom
+HM Nautical Almanac Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/hm-nautical-almanac-office.atom, en-UK, United Kingdom
+HM Passport Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/hm-passport-office.atom, en-UK, United Kingdom
+HM Prison and Probation Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/hm-prison-and-probation-service.atom, en-UK, United Kingdom
+HM Prison Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/hm-prison-service.atom, en-UK, United Kingdom
+HM Revenue & Customs - Activity on GOV.UK, https://www.gov.uk/government/organisations/hm-revenue-customs.atom, en-UK, United Kingdom
+HM Treasury - Activity on GOV.UK, https://www.gov.uk/government/organisations/hm-treasury.atom, en-UK, United Kingdom
+Home Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/home-office.atom, en-UK, United Kingdom
+Homes England - Activity on GOV.UK, https://www.gov.uk/government/organisations/homes-england.atom, en-UK, United Kingdom
+Horniman Public Museum and Public Park Trust - Activity on GOV.UK, https://www.gov.uk/government/organisations/horniman-museum.atom, en-UK, United Kingdom
+Horserace Betting Levy Board - Activity on GOV.UK, https://www.gov.uk/government/organisations/horserace-betting-levy-board.atom, en-UK, United Kingdom
+House of Lords Appointments Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/house-of-lords-appointments-commission.atom, en-UK, United Kingdom
+Housing Ombudsman - Activity on GOV.UK, https://www.gov.uk/government/organisations/housing-ombudsman.atom, en-UK, United Kingdom
+HSC Business Services Organisation (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/hsc-business-services-organisation-northern-ireland.atom, en-UK, United Kingdom
+Human Fertilisation and Embryology Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/human-fertilisation-and-embryology-authority.atom, en-UK, United Kingdom
+Human Tissue Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/human-tissue-authority.atom, en-UK, United Kingdom
+Immigration Enforcement - Activity on GOV.UK, https://www.gov.uk/government/organisations/immigration-enforcement.atom, en-UK, United Kingdom
+Imperial War Museum - Activity on GOV.UK, https://www.gov.uk/government/organisations/imperial-war-museum.atom, en-UK, United Kingdom
+Incubator for Automation and Innovation - Activity on GOV.UK, https://www.gov.uk/government/organisations/incubator-for-automation-and-innovation.atom, en-UK, United Kingdom
+Independent Adviser on Ministers' Interests - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-adviser-on-ministers-interests.atom, en-UK, United Kingdom
+Independent Advisory Panel on Deaths in Custody - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-advisory-panel-on-deaths-in-custody.atom, en-UK, United Kingdom
+Independent Agricultural Appeals Panel - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-agricultural-appeals-panel.atom, en-UK, United Kingdom
+Independent Anti-slavery Commissioner - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-anti-slavery-commissioner.atom, en-UK, United Kingdom
+Independent Case Examiner - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-case-examiner.atom, en-UK, United Kingdom
+Independent Chief Inspector of Borders and Immigration - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-chief-inspector-of-borders-and-immigration.atom, en-UK, United Kingdom
+Independent Chief Inspector of Borders and Immigration - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-chief-inspector-of-borders-and-immigration.atom, en-UK, United Kingdom
+Independent Commission for Aid Impact - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-commission-for-aid-impact.atom, en-UK, United Kingdom
+Independent Commission on Freedom of Information - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-commission-on-freedom-of-information.atom, en-UK, United Kingdom
+Independent Complaints Reviewer - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-complaints-reviewer.atom, en-UK, United Kingdom
+Independent Dormant Assets Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/dormant-assets-commission.atom, en-UK, United Kingdom
+Independent Family Returns Panel - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-family-returns-panel.atom, en-UK, United Kingdom
+Independent Medical Expert Group - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-medical-expert-group.atom, en-UK, United Kingdom
+Independent Monitoring Authority for the Citizens’ Rights Agreements - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-monitoring-authority-for-the-citizens-rights-agreements.atom, en-UK, United Kingdom
+Independent Monitoring Boards - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-monitoring-boards-of-prisons-immigration-removal-centres-and-short-term-holding-rooms.atom, en-UK, United Kingdom
+Independent Office for Police Conduct - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-office-for-police-conduct.atom, en-UK, United Kingdom
+Independent Parliamentary Standards Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-parliamentary-standards-authority.atom, en-UK, United Kingdom
+Independent Reconfiguration Panel - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-reconfiguration-panel.atom, en-UK, United Kingdom
+Independent Reviewer of Terrorism Legislation - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-reviewer-of-terrorism-legislation.atom, en-UK, United Kingdom
+Independent Review Mechanism - Activity on GOV.UK, https://www.gov.uk/government/organisations/independent-review-mechanism.atom, en-UK, United Kingdom
+Industrial Development Advisory Board - Activity on GOV.UK, https://www.gov.uk/government/organisations/industrial-development-advisory-board.atom, en-UK, United Kingdom
+Industrial Injuries Advisory Council - Activity on GOV.UK, https://www.gov.uk/government/organisations/industrial-injuries-advisory-council.atom, en-UK, United Kingdom
+Information Commissioner's Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/information-commissioner-s-office.atom, en-UK, United Kingdom
+Infrastructure and Projects Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/infrastructure-and-projects-authority.atom, en-UK, United Kingdom
+Innovate UK - Activity on GOV.UK, https://www.gov.uk/government/organisations/innovate-uk.atom, en-UK, United Kingdom
+Insolvency Rules Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/insolvency-rules-committee.atom, en-UK, United Kingdom
+Institute for Apprenticeships and Technical Education - Activity on GOV.UK, https://www.gov.uk/government/organisations/institute-for-apprenticeships-and-technical-education.atom, en-UK, United Kingdom
+Intellectual Property Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/intellectual-property-office.atom, en-UK, United Kingdom
+Intelligence Analysis - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-intelligence-analysis-profession.atom, en-UK, United Kingdom
+Internal Audit Profession - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-internal-audit-profession.atom, en-UK, United Kingdom
+Investigatory Powers Commissioner's Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/investigatory-powers-commissioners-office.atom, en-UK, United Kingdom
+Investigatory Powers Tribunal - Activity on GOV.UK, https://www.gov.uk/government/organisations/investigatory-powers-tribunal.atom, en-UK, United Kingdom
+Invest Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/invest-northern-ireland.atom, en-UK, United Kingdom
+Iraq Inquiry - Activity on GOV.UK, https://www.gov.uk/government/organisations/iraq-inquiry.atom, en-UK, United Kingdom
+jHub Defence Innovation - Activity on GOV.UK, https://www.gov.uk/government/organisations/jhub-defence-innovation.atom, en-UK, United Kingdom
+Joint Nature Conservation Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/joint-nature-conservation-committee.atom, en-UK, United Kingdom
+Judicial Appointments and Conduct Ombudsman - Activity on GOV.UK, https://www.gov.uk/government/organisations/judicial-appointments-and-conduct-ombudsman.atom, en-UK, United Kingdom
+Judicial Appointments Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/judicial-appointments-commission.atom, en-UK, United Kingdom
+Judicial Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/judicial-office.atom, en-UK, United Kingdom
+King's Harbour Master - Activity on GOV.UK, https://www.gov.uk/government/organisations/kings-harbour-master.atom, en-UK, United Kingdom
+Labour Relations Agency (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/labour-relations-agency.atom, en-UK, United Kingdom
+Lake District National Park Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/lake-district-national-park-authority.atom, en-UK, United Kingdom
+Lammy Review - Activity on GOV.UK, https://www.gov.uk/government/organisations/lammy-review.atom, en-UK, United Kingdom
+Land Registration Rule Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/land-registration-rule-committee.atom, en-UK, United Kingdom
+Law Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/law-commission.atom, en-UK, United Kingdom
+Leadership College for Government - Activity on GOV.UK, https://www.gov.uk/government/organisations/leadership-college-for-government.atom, en-UK, United Kingdom
+Leasehold Advisory Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/leasehold-advisory-service.atom, en-UK, United Kingdom
+Legal Aid Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/legal-aid-agency.atom, en-UK, United Kingdom
+Legal Services Agency (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/legal-services-agency-northern-ireland.atom, en-UK, United Kingdom
+Legal Services Board - Activity on GOV.UK, https://www.gov.uk/government/organisations/legal-services-board.atom, en-UK, United Kingdom
+LGBT Veterans Independent Review - Activity on GOV.UK, https://www.gov.uk/government/organisations/lgbt-veterans-independent-review.atom, en-UK, United Kingdom
+Life Sciences Organisation - Activity on GOV.UK, https://www.gov.uk/government/organisations/life-sciences-organisation.atom, en-UK, United Kingdom
+Livestock and Meat Commission for Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/livestock-and-meat-commission-for-northern-ireland.atom, en-UK, United Kingdom
+Local Government and Social Care Ombudsman - Activity on GOV.UK, https://www.gov.uk/government/organisations/local-government-ombudsman.atom, en-UK, United Kingdom
+LocatED - Activity on GOV.UK, https://www.gov.uk/government/organisations/located.atom, en-UK, United Kingdom
+London and Continental Railways Limited - Activity on GOV.UK, https://www.gov.uk/government/organisations/london-and-continental-railways-ltd.atom, en-UK, United Kingdom
+Low Carbon Contracts Company - Activity on GOV.UK, https://www.gov.uk/government/organisations/low-carbon-contracts-company.atom, en-UK, United Kingdom
+Low Pay Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/low-pay-commission.atom, en-UK, United Kingdom
+Marine Accident Investigation Branch - Activity on GOV.UK, https://www.gov.uk/government/organisations/marine-accident-investigation-branch.atom, en-UK, United Kingdom
+Marine Management Organisation - Activity on GOV.UK, https://www.gov.uk/government/organisations/marine-management-organisation.atom, en-UK, United Kingdom
+Maritime and Coastguard Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/maritime-and-coastguard-agency.atom, en-UK, United Kingdom
+Marshall Aid Commemoration Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/marshall-aid-commemoration-commission.atom, en-UK, United Kingdom
+Medical Profession - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-medical-profession.atom, en-UK, United Kingdom
+Medical Research Council - Activity on GOV.UK, https://www.gov.uk/government/organisations/medical-research-council.atom, en-UK, United Kingdom
+Medicines and Healthcare products Regulatory Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/medicines-and-healthcare-products-regulatory-agency.atom, en-UK, United Kingdom
+Met Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/met-office.atom, en-UK, United Kingdom
+Migration Advisory Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/migration-advisory-committee.atom, en-UK, United Kingdom
+Military Aviation Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/military-aviation-authority.atom, en-UK, United Kingdom
+Military Engineering Experimental Establishment - Activity on GOV.UK, https://www.gov.uk/government/organisations/military-engineering-experimental-establishment.atom, en-UK, United Kingdom
+Ministry of Defence - Activity on GOV.UK, https://www.gov.uk/government/organisations/ministry-of-defence.atom, en-UK, United Kingdom
+Ministry of Justice - Activity on GOV.UK, https://www.gov.uk/government/organisations/ministry-of-justice.atom, en-UK, United Kingdom
+Modernisation and Reform - Activity on GOV.UK, https://www.gov.uk/government/organisations/modernisation-and-reform.atom, en-UK, United Kingdom
+Money and Pensions Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/single-financial-guidance-body.atom, en-UK, United Kingdom
+Museum of the Home - Activity on GOV.UK, https://www.gov.uk/government/organisations/geffrye-museum.atom, en-UK, United Kingdom
+National Army Museum - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-army-museum.atom, en-UK, United Kingdom
+National Citizen Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-citizen-service.atom, en-UK, United Kingdom
+National Counter Terrorism Security Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-counter-terrorism-security-office.atom, en-UK, United Kingdom
+National Crime Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-crime-agency.atom, en-UK, United Kingdom
+National Crime Agency Remuneration Review Body - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-crime-agency-remuneration-review-body.atom, en-UK, United Kingdom
+National Crime Agency Remuneration Review Body - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-crime-agency-remuneration-review-body.atom, en-UK, United Kingdom
+National Cyber Force - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-cyber-force.atom, en-UK, United Kingdom
+National Cyber Security Centre - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-cyber-security-centre.atom, en-UK, United Kingdom
+National Data Guardian - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-data-guardian.atom, en-UK, United Kingdom
+National Employment Savings Trust (NEST) Corporation - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-employment-savings-trust.atom, en-UK, United Kingdom
+National Forest Company - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-forest-company.atom, en-UK, United Kingdom
+National Gallery - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-gallery.atom, en-UK, United Kingdom
+National Heritage Memorial Fund - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-heritage-memorial-fund.atom, en-UK, United Kingdom
+National Highways - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-highways.atom, en-UK, United Kingdom
+National Infrastructure Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-infrastructure-commission.atom, en-UK, United Kingdom
+National Institute for Health and Care Excellence - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-institute-for-clinical-excellence.atom, en-UK, United Kingdom
+National Lottery Heritage Fund - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-lottery-heritage-fund.atom, en-UK, United Kingdom
+National Museum of the Royal Navy - Activity on GOV.UK, https://www.gov.uk/government/organisations/royal-naval-museum.atom, en-UK, United Kingdom
+National Museums Liverpool - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-museums-liverpool.atom, en-UK, United Kingdom
+National Nuclear Laboratory - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-nuclear-laboratory.atom, en-UK, United Kingdom
+National Physical Laboratory - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-physical-laboratory.atom, en-UK, United Kingdom
+National Portrait Gallery - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-portrait-gallery.atom, en-UK, United Kingdom
+National Protective Security Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-protective-security-authority.atom, en-UK, United Kingdom
+National security and intelligence - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-security.atom, en-UK, United Kingdom
+National Security Technology and Innovation Exchange - Activity on GOV.UK, https://www.gov.uk/government/organisations/national-security-technology-and-innovation-exchange.atom, en-UK, United Kingdom
+Natural England - Activity on GOV.UK, https://www.gov.uk/government/organisations/natural-england.atom, en-UK, United Kingdom
+Natural Environment Research Council - Activity on GOV.UK, https://www.gov.uk/government/organisations/natural-environment-research-council.atom, en-UK, United Kingdom
+Natural History Museum - Activity on GOV.UK, https://www.gov.uk/government/organisations/natural-history-museum.atom, en-UK, United Kingdom
+Natural Resources Wales - Activity on GOV.UK, https://www.gov.uk/government/organisations/natural-resources-wales.atom, en-UK, United Kingdom
+Network Rail - Activity on GOV.UK, https://www.gov.uk/government/organisations/network-rail.atom, en-UK, United Kingdom
+New Forest National Park Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/new-forest-national-park-authority.atom, en-UK, United Kingdom
+NHS Blood and Transplant - Activity on GOV.UK, https://www.gov.uk/government/organisations/nhs-blood-and-transplant.atom, en-UK, United Kingdom
+NHS Business Services Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/nhs-business-services-authority.atom, en-UK, United Kingdom
+NHS Counter Fraud Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/nhs-counter-fraud-authority.atom, en-UK, United Kingdom
+NHS Digital - Activity on GOV.UK, https://www.gov.uk/government/organisations/nhs-digital.atom, en-UK, United Kingdom
+NHS England - Activity on GOV.UK, https://www.gov.uk/government/organisations/nhs-england.atom, en-UK, United Kingdom
+NHS Pay Review Body - Activity on GOV.UK, https://www.gov.uk/government/organisations/nhs-pay-review-body.atom, en-UK, United Kingdom
+NHS Resolution - Activity on GOV.UK, https://www.gov.uk/government/organisations/nhs-resolution.atom, en-UK, United Kingdom
+NHS Wales Informatics Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/nhs-wales-informatics-service.atom, en-UK, United Kingdom
+Northern Ireland Cancer Registry - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-cancer-registry.atom, en-UK, United Kingdom
+"Northern Ireland Council for the Curriculum, Examinations and Assessment - Activity on GOV.UK", https://www.gov.uk/government/organisations/northern-ireland-council-for-the-curriculum-examinations-and-assessment.atom, en-UK, United Kingdom
+Northern Ireland Courts and Tribunals Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-court-service.atom, en-UK, United Kingdom
+Northern Ireland Executive - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-executive.atom, en-UK, United Kingdom
+Northern Ireland Housing Executive - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-housing-executive.atom, en-UK, United Kingdom
+Northern Ireland Human Rights Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-human-rights-commission.atom, en-UK, United Kingdom
+Northern Ireland Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-office.atom, en-UK, United Kingdom
+Northern Ireland Policing Board - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-policing-board.atom, en-UK, United Kingdom
+Northern Ireland Prison Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-prison-service.atom, en-UK, United Kingdom
+Northern Ireland Statistics and Research Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-ireland-statistics-and-research-agency.atom, en-UK, United Kingdom
+Northern Lighthouse Board - Activity on GOV.UK, https://www.gov.uk/government/organisations/northern-lighthouse-board.atom, en-UK, United Kingdom
+North Sea Transition Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/north-sea-transition-authority.atom, en-UK, United Kingdom
+Northumberland National Park Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/northumberland-national-park-authority.atom, en-UK, United Kingdom
+North York Moors National Park Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/north-york-moors-national-park.atom, en-UK, United Kingdom
+NS&I - Activity on GOV.UK, https://www.gov.uk/government/organisations/ns-i.atom, en-UK, United Kingdom
+Nuclear Decommissioning Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/nuclear-decommissioning-authority.atom, en-UK, United Kingdom
+Nuclear Liabilities Financing Assurance Board - Activity on GOV.UK, https://www.gov.uk/government/organisations/nuclear-liabilities-financing-assurance-board.atom, en-UK, United Kingdom
+Nuclear Research Advisory Council - Activity on GOV.UK, https://www.gov.uk/government/organisations/nuclear-research-advisory-council.atom, en-UK, United Kingdom
+Nuclear Restoration Services - Activity on GOV.UK, https://www.gov.uk/government/organisations/nuclear-restoration-services.atom, en-UK, United Kingdom
+Nuclear Waste Services - Activity on GOV.UK, https://www.gov.uk/government/organisations/nuclear-waste-services.atom, en-UK, United Kingdom
+Oak National Academy - Activity on GOV.UK, https://www.gov.uk/government/organisations/oak-national-academy.atom, en-UK, United Kingdom
+Ofcom - Activity on GOV.UK, https://www.gov.uk/government/organisations/ofcom.atom, en-UK, United Kingdom
+Office for Artificial Intelligence - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-for-artificial-intelligence.atom, en-UK, United Kingdom
+Office for Budget Responsibility - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-for-budget-responsibility.atom, en-UK, United Kingdom
+Office for Communications Data Authorisations - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-for-communications-data-authorisations.atom, en-UK, United Kingdom
+Office for Environmental Protection - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-for-environmental-protection.atom, en-UK, United Kingdom
+Office for Health Improvement and Disparities - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-for-health-improvement-and-disparities.atom, en-UK, United Kingdom
+Office for Investment - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-for-investment.atom, en-UK, United Kingdom
+Office for Life Sciences - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-for-life-sciences.atom, en-UK, United Kingdom
+Office for Local Government - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-for-local-government.atom, en-UK, United Kingdom
+Office for National Statistics - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-for-national-statistics.atom, en-UK, United Kingdom
+Office for Nuclear Regulation - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-for-nuclear-regulation.atom, en-UK, United Kingdom
+Office for Place - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-for-place.atom, en-UK, United Kingdom
+Office for Product Safety and Standards - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-for-product-safety-and-standards.atom, en-UK, United Kingdom
+Office for Students - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-for-students.atom, en-UK, United Kingdom
+Office for the Independent Examiner of Complaints - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-for-the-independent-examiner-of-complaints.atom, en-UK, United Kingdom
+Office for the Internal Market - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-for-the-internal-market.atom, en-UK, United Kingdom
+Office for Veterans' Affairs - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-for-veterans-affairs.atom, en-UK, United Kingdom
+Office for Zero Emission Vehicles - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-for-zero-emission-vehicles.atom, en-UK, United Kingdom
+Office of Financial Sanctions Implementation - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-of-financial-sanctions-implementation.atom, en-UK, United Kingdom
+Office of Manpower Economics - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-of-manpower-economics.atom, en-UK, United Kingdom
+Office of Rail and Road - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-of-rail-and-road.atom, en-UK, United Kingdom
+Office of the Advocate General for Scotland - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-of-the-advocate-general-for-scotland.atom, en-UK, United Kingdom
+Office of the Children's Commissioner - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-of-the-children-s-commissioner.atom, en-UK, United Kingdom
+Office of the Immigration Services Commissioner - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-of-the-immigration-services-commissioner.atom, en-UK, United Kingdom
+Office of the Leader of the House of Commons - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-office-of-the-leader-of-the-house-of-commons.atom, en-UK, United Kingdom
+Office of the Leader of the House of Lords - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-of-the-leader-of-the-house-of-lords.atom, en-UK, United Kingdom
+Office of the Parliamentary Counsel - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-of-the-parliamentary-counsel.atom, en-UK, United Kingdom
+Office of the Police Ombudsman for Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-of-the-police-ombudsman-for-northern-ireland.atom, en-UK, United Kingdom
+Office of the Public Guardian - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-of-the-public-guardian.atom, en-UK, United Kingdom
+Office of the Registrar of Consultant Lobbyists - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-of-the-registrar-of-consultant-lobbyists.atom, en-UK, United Kingdom
+Office of the Regulator of Community Interest Companies - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-of-the-regulator-of-community-interest-companies.atom, en-UK, United Kingdom
+Office of the Schools Adjudicator - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-of-the-schools-adjudicator.atom, en-UK, United Kingdom
+Office of the Secretary of State for Scotland - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-of-the-secretary-of-state-for-scotland.atom, en-UK, United Kingdom
+Office of the Secretary of State for Wales - Activity on GOV.UK, https://www.gov.uk/government/organisations/office-of-the-secretary-of-state-for-wales.atom, en-UK, United Kingdom
+Official Solicitor and Public Trustee - Activity on GOV.UK, https://www.gov.uk/government/organisations/official-solicitor-and-public-trustee.atom, en-UK, United Kingdom
+Offshore Petroleum Regulator for Environment and Decommissioning - Activity on GOV.UK, https://www.gov.uk/government/organisations/offshore-petroleum-regulator-for-environment-and-decommissioning.atom, en-UK, United Kingdom
+Ofgem - Activity on GOV.UK, https://www.gov.uk/government/organisations/ofgem.atom, en-UK, United Kingdom
+Ofqual - Activity on GOV.UK, https://www.gov.uk/government/organisations/ofqual.atom, en-UK, United Kingdom
+Ofsted - Activity on GOV.UK, https://www.gov.uk/government/organisations/ofsted.atom, en-UK, United Kingdom
+Open Innovation Team - Activity on GOV.UK, https://www.gov.uk/government/organisations/open-innovation-team.atom, en-UK, United Kingdom
+Open Public Services - Activity on GOV.UK, https://www.gov.uk/government/organisations/open-public-services.atom, en-UK, United Kingdom
+Operational Delivery Profession - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-operational-delivery-profession.atom, en-UK, United Kingdom
+Ordnance Survey - Activity on GOV.UK, https://www.gov.uk/government/organisations/ordnance-survey.atom, en-UK, United Kingdom
+Parades Commission for Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/parades-commission-for-northern-ireland.atom, en-UK, United Kingdom
+Parole Board - Activity on GOV.UK, https://www.gov.uk/government/organisations/parole-board.atom, en-UK, United Kingdom
+Payment Systems Regulator - Activity on GOV.UK, https://www.gov.uk/government/organisations/payment-systems-regulator.atom, en-UK, United Kingdom
+Peak District National Park Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/peak-district-national-park.atom, en-UK, United Kingdom
+"Pension, Compensation and Welfare Support for Armed Forces and Veterans - Activity on GOV.UK", https://www.gov.uk/government/organisations/pension-compensation-and-welfare-support-for-armed-forces-and-veterans.atom, en-UK, United Kingdom
+Pension Protection Fund - Activity on GOV.UK, https://www.gov.uk/government/organisations/pension-protection-fund.atom, en-UK, United Kingdom
+Phone-paid Services Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/phone-paid-services-authority.atom, en-UK, United Kingdom
+Planning Inspectorate - Activity on GOV.UK, https://www.gov.uk/government/organisations/planning-inspectorate.atom, en-UK, United Kingdom
+Plant Varieties and Seeds Tribunal - Activity on GOV.UK, https://www.gov.uk/government/organisations/plant-varieties-and-seeds-tribunal.atom, en-UK, United Kingdom
+Police Advisory Board for England and Wales - Activity on GOV.UK, https://www.gov.uk/government/organisations/police-advisory-board-for-england-and-wales.atom, en-UK, United Kingdom
+Police Discipline Appeals Tribunal - Activity on GOV.UK, https://www.gov.uk/government/organisations/police-discipline-appeals-tribunal.atom, en-UK, United Kingdom
+Police Remuneration Review Body - Activity on GOV.UK, https://www.gov.uk/government/organisations/police-remuneration-review-body.atom, en-UK, United Kingdom
+Police Service of Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/police-service-of-northern-ireland.atom, en-UK, United Kingdom
+Policy Profession - Activity on GOV.UK, https://www.gov.uk/government/organisations/civil-service-policy-profession.atom, en-UK, United Kingdom
+Porton Biopharma Limited - Activity on GOV.UK, https://www.gov.uk/government/organisations/porton-biopharma-limited.atom, en-UK, United Kingdom
+Post Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/post-office.atom, en-UK, United Kingdom
+Preventing Sexual Violence in Conflict Initiative - Activity on GOV.UK, https://www.gov.uk/government/organisations/preventing-sexual-violence-in-conflict-initiative.atom, en-UK, United Kingdom
+"Prime Minister's Office, 10 Downing Street - Activity on GOV.UK", https://www.gov.uk/government/organisations/prime-ministers-office-10-downing-street.atom, en-UK, United Kingdom
+Prisons and Probation Ombudsman - Activity on GOV.UK, https://www.gov.uk/government/organisations/prisons-and-probation-ombudsman.atom, en-UK, United Kingdom
+Prison Service Pay Review Body - Activity on GOV.UK, https://www.gov.uk/government/organisations/prison-services-pay-review-body.atom, en-UK, United Kingdom
+Privy Council Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/privy-council-office.atom, en-UK, United Kingdom
+Probation Board for Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/probation-board-for-northern-ireland.atom, en-UK, United Kingdom
+Probation Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/probation-service.atom, en-UK, United Kingdom
+Professional Standards Authority for Health and Social Care - Activity on GOV.UK, https://www.gov.uk/government/organisations/professional-standards-authority-for-health-and-social-care.atom, en-UK, United Kingdom
+Project Delivery Function - Activity on GOV.UK, https://www.gov.uk/government/organisations/project-delivery-function.atom, en-UK, United Kingdom
+Public Health Agency (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/public-health-agency-northern-ireland.atom, en-UK, United Kingdom
+Public Health Wales - Activity on GOV.UK, https://www.gov.uk/government/organisations/public-health-wales.atom, en-UK, United Kingdom
+Public Prosecution Service for Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/public-prosecution-service-for-northern-ireland.atom, en-UK, United Kingdom
+Public Sector Fraud Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/public-sector-fraud-authority.atom, en-UK, United Kingdom
+Public Services Ombudsman for Wales - Activity on GOV.UK, https://www.gov.uk/government/organisations/public-services-ombudsman-for-wales.atom, en-UK, United Kingdom
+Pubs Code Adjudicator - Activity on GOV.UK, https://www.gov.uk/government/organisations/pubs-code-adjudicator.atom, en-UK, United Kingdom
+Queen Elizabeth II Conference Centre - Activity on GOV.UK, https://www.gov.uk/government/organisations/queen-elizabeth-ii-conference-centre.atom, en-UK, United Kingdom
+Race Disparity Unit - Activity on GOV.UK, https://www.gov.uk/government/organisations/race-disparity-unit.atom, en-UK, United Kingdom
+Rail Accident Investigation Branch - Activity on GOV.UK, https://www.gov.uk/government/organisations/rail-accident-investigation-branch.atom, en-UK, United Kingdom
+Rail Safety and Standards Board - Activity on GOV.UK, https://www.gov.uk/government/organisations/rail-safety-and-standards-board.atom, en-UK, United Kingdom
+Reclaim Fund Ltd - Activity on GOV.UK, https://www.gov.uk/government/organisations/reclaim-fund-ltd.atom, en-UK, United Kingdom
+Regional Department for Education (DfE) Directors - Activity on GOV.UK, https://www.gov.uk/government/organisations/regional-department-for-education-dfe-directors.atom, en-UK, United Kingdom
+Regulator of Social Housing - Activity on GOV.UK, https://www.gov.uk/government/organisations/regulator-of-social-housing.atom, en-UK, United Kingdom
+Regulatory Policy Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/regulatory-policy-committee.atom, en-UK, United Kingdom
+Remploy Pension Scheme Trustees Ltd - Activity on GOV.UK, https://www.gov.uk/government/organisations/remploy-pension-scheme-trustees-ltd.atom, en-UK, United Kingdom
+Remploy Pension Scheme Trustees Ltd - Activity on GOV.UK, https://www.gov.uk/government/organisations/remploy-pension-scheme-trustees-ltd.atom, en-UK, United Kingdom
+Research Collaboration Advice Team - Activity on GOV.UK, https://www.gov.uk/government/organisations/research-collaboration-advice-team.atom, en-UK, United Kingdom
+Reserve Forces' and Cadets' Associations (RFCA) - Activity on GOV.UK, https://www.gov.uk/government/organisations/reserve-forces-and-cadets-associations.atom, en-UK, United Kingdom
+Review Body on Doctors' and Dentists' Remuneration - Activity on GOV.UK, https://www.gov.uk/government/organisations/review-body-on-doctors-and-dentists-remuneration.atom, en-UK, United Kingdom
+Royal Air Force Museum - Activity on GOV.UK, https://www.gov.uk/government/organisations/royal-air-force-museum.atom, en-UK, United Kingdom
+Royal Armouries Museum - Activity on GOV.UK, https://www.gov.uk/government/organisations/royal-armouries-museum.atom, en-UK, United Kingdom
+Royal Marines Museum - Activity on GOV.UK, https://www.gov.uk/government/organisations/royal-marines-museum.atom, en-UK, United Kingdom
+Royal Mint - Activity on GOV.UK, https://www.gov.uk/government/organisations/royal-mint.atom, en-UK, United Kingdom
+Royal Mint Advisory Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/royal-mint-advisory-committee.atom, en-UK, United Kingdom
+Royal Museums Greenwich - Activity on GOV.UK, https://www.gov.uk/government/organisations/royal-museums-greenwich.atom, en-UK, United Kingdom
+Royal Navy Submarine Museum - Activity on GOV.UK, https://www.gov.uk/government/organisations/royal-navy-submarine-museum.atom, en-UK, United Kingdom
+Royal Parks - Activity on GOV.UK, https://www.gov.uk/government/organisations/royal-parks.atom, en-UK, United Kingdom
+Rural Development Programme for England Network - Activity on GOV.UK, https://www.gov.uk/government/organisations/rural-development-programme-for-england-network.atom, en-UK, United Kingdom
+Rural Payments Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/rural-payments-agency.atom, en-UK, United Kingdom
+S4C - Activity on GOV.UK, https://www.gov.uk/government/organisations/s4c.atom, en-UK, United Kingdom
+Salix Finance Ltd - Activity on GOV.UK, https://www.gov.uk/government/organisations/salix-finance-ltd.atom, en-UK, United Kingdom
+School Teachers' Review Body - Activity on GOV.UK, https://www.gov.uk/government/organisations/school-teachers-review-body.atom, en-UK, United Kingdom
+Science Advisory Committees - Activity on GOV.UK, https://www.gov.uk/government/organisations/science-advisory-committees.atom, en-UK, United Kingdom
+Science and Technology Facilities Council - Activity on GOV.UK, https://www.gov.uk/government/organisations/science-and-technology-facilities-council.atom, en-UK, United Kingdom
+Science Museum Group - Activity on GOV.UK, https://www.gov.uk/government/organisations/science-museum-group.atom, en-UK, United Kingdom
+Scientific Advisory Committee on the Medical Implications of Less-Lethal Weapons - Activity on GOV.UK, https://www.gov.uk/government/organisations/science-advisory-committee-on-the-medical-implications-of-less-lethal-weapons.atom, en-UK, United Kingdom
+Scientific Advisory Group for Emergencies - Activity on GOV.UK, https://www.gov.uk/government/organisations/scientific-advisory-group-for-emergencies.atom, en-UK, United Kingdom
+Seafish - Activity on GOV.UK, https://www.gov.uk/government/organisations/seafish.atom, en-UK, United Kingdom
+Secret Intelligence Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/secret-intelligence-service.atom, en-UK, United Kingdom
+Security Industry Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/security-industry-authority.atom, en-UK, United Kingdom
+Security Vetting Appeals Panel - Activity on GOV.UK, https://www.gov.uk/government/organisations/security-vetting-appeals-panel.atom, en-UK, United Kingdom
+Sellafield Ltd - Activity on GOV.UK, https://www.gov.uk/government/organisations/sellafield-ltd.atom, en-UK, United Kingdom
+Senior Salaries Review Body - Activity on GOV.UK, https://www.gov.uk/government/organisations/review-body-on-senior-salaries.atom, en-UK, United Kingdom
+Senior Salaries Review Body - Activity on GOV.UK, https://www.gov.uk/government/organisations/review-body-on-senior-salaries.atom, en-UK, United Kingdom
+Sentencing Council for England and Wales - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-sentencing-council-for-england-and-wales.atom, en-UK, United Kingdom
+Serious Fraud Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/serious-fraud-office.atom, en-UK, United Kingdom
+Service Complaints Ombudsman - Activity on GOV.UK, https://www.gov.uk/government/organisations/service-complaints-ombudsman.atom, en-UK, United Kingdom
+Service Complaints Ombudsman - Activity on GOV.UK, https://www.gov.uk/government/organisations/service-complaints-ombudsman.atom, en-UK, United Kingdom
+Service Prosecuting Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/service-prosecuting-authority.atom, en-UK, United Kingdom
+Sheffield Forgemasters International Ltd - Activity on GOV.UK, https://www.gov.uk/government/organisations/sheffield-forgemasters-international-ltd.atom, en-UK, United Kingdom
+Single Source Regulations Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/single-source-regulations-office.atom, en-UK, United Kingdom
+Sir John Soane's Museum - Activity on GOV.UK, https://www.gov.uk/government/organisations/sir-john-soane-s-museum.atom, en-UK, United Kingdom
+Small Business Commissioner - Activity on GOV.UK, https://www.gov.uk/government/organisations/small-business-commissioner.atom, en-UK, United Kingdom
+Social Mobility Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/social-mobility-commission.atom, en-UK, United Kingdom
+Social Science Research Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/social-science-research-committee.atom, en-UK, United Kingdom
+Social Security Advisory Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/social-security-advisory-committee.atom, en-UK, United Kingdom
+Social Work England - Activity on GOV.UK, https://www.gov.uk/government/organisations/social-work-england.atom, en-UK, United Kingdom
+South Downs National Park Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/south-downs-national-park-authority.atom, en-UK, United Kingdom
+Sport England - Activity on GOV.UK, https://www.gov.uk/government/organisations/sport-england.atom, en-UK, United Kingdom
+Sport Northern Ireland (Sports Council for Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/sports-council-for-northern-ireland.atom, en-UK, United Kingdom
+Sports Council for Wales - Activity on GOV.UK, https://www.gov.uk/government/organisations/sports-council-for-wales.atom, en-UK, United Kingdom
+Sports Grounds Safety Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/sports-grounds-safety-authority.atom, en-UK, United Kingdom
+Standards and Testing Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/standards-and-testing-agency.atom, en-UK, United Kingdom
+Strategic Command - Activity on GOV.UK, https://www.gov.uk/government/organisations/strategic-command.atom, en-UK, United Kingdom
+Student Loans Company - Activity on GOV.UK, https://www.gov.uk/government/organisations/student-loans-company.atom, en-UK, United Kingdom
+Submarine Delivery Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/submarine-delivery-agency.atom, en-UK, United Kingdom
+Subsidy Advice Unit - Activity on GOV.UK, https://www.gov.uk/government/organisations/subsidy-advice-unit.atom, en-UK, United Kingdom
+Supreme Court of the United Kingdom - Activity on GOV.UK, https://www.gov.uk/government/organisations/supreme-court-of-the-united-kingdom.atom, en-UK, United Kingdom
+Tate - Activity on GOV.UK, https://www.gov.uk/government/organisations/tate.atom, en-UK, United Kingdom
+Teaching Regulation Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/teaching-regulation-agency.atom, en-UK, United Kingdom
+Technical Advisory Board - Activity on GOV.UK, https://www.gov.uk/government/organisations/technical-advisory-board.atom, en-UK, United Kingdom
+The Adjudicator’s Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-adjudicator-s-office.atom, en-UK, United Kingdom
+The Advisory Council on National Records and Archives - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-advisory-council-on-national-records-and-archives.atom, en-UK, United Kingdom
+The Charity Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/charity-commission.atom, en-UK, United Kingdom
+The Crown Estate - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-crown-estate.atom, en-UK, United Kingdom
+The Electoral Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-electoral-commission.atom, en-UK, United Kingdom
+The Executive Office (Northern Ireland) - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-executive-office-northern-ireland.atom, en-UK, United Kingdom
+The Insolvency Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/insolvency-service.atom, en-UK, United Kingdom
+The Legal Ombudsman - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-legal-ombudsman.atom, en-UK, United Kingdom
+The National Archives - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-national-archives.atom, en-UK, United Kingdom
+The National Archives - Blog, http://blog.nationalarchives.gov.uk/feed/, en-UK, United Kingdom
+The National Archives - News Archives, https://www.nationalarchives.gov.uk/rss/news.xml, en-UK, United Kingdom
+The National Archives - Podcast Series, https://www.nationalarchives.gov.uk/rss/podcasts.xml, en-UK, United Kingdom
+The National Archives - PSI updates, https://www.nationalarchives.gov.uk/rss/psi-updates.xml, en-UK, United Kingdom
+The National Lottery Community Fund - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-national-lottery-community-fund.atom, en-UK, United Kingdom
+The Oil and Pipelines Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/oil-and-pipelines-agency.atom, en-UK, United Kingdom
+The Parliamentary and Health Service Ombudsman - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-parliamentary-and-health-service-ombudsman.atom, en-UK, United Kingdom
+The Pension Protection Fund Ombudsman - Activity on GOV.UK, https://www.gov.uk/government/organisations/pension-protection-fund-ombudsman.atom, en-UK, United Kingdom
+The Pensions Ombudsman - Activity on GOV.UK, https://www.gov.uk/government/organisations/pensions-ombudsman.atom, en-UK, United Kingdom
+The Pensions Regulator - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-pensions-regulator.atom, en-UK, United Kingdom
+The Reviewing Committee on the Export of Works of Art and Objects of Cultural Interest - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-reviewing-committee-on-the-export-of-works-of-art-and-objects-of-cultural-interest.atom, en-UK, United Kingdom
+The Scottish Government - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-scottish-government.atom, en-UK, United Kingdom
+The Security Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-security-service-mi5.atom, en-UK, United Kingdom
+The Theatres Trust - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-theatres-trust.atom, en-UK, United Kingdom
+The Water Services Regulation Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-water-services-regulation-authority.atom, en-UK, United Kingdom
+The Water Services Regulation Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/the-water-services-regulation-authority.atom, en-UK, United Kingdom
+Trade and Agriculture Commission - Activity on GOV.UK, https://www.gov.uk/government/organisations/trade-and-agriculture-commission.atom, en-UK, United Kingdom
+Trade Remedies Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/trade-remedies-authority.atom, en-UK, United Kingdom
+Traffic Commissioners for Great Britain - Activity on GOV.UK, https://www.gov.uk/government/organisations/traffic-commissioners.atom, en-UK, United Kingdom
+Transport Focus - Activity on GOV.UK, https://www.gov.uk/government/organisations/transport-focus.atom, en-UK, United Kingdom
+Treasure Valuation Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/treasure-valuation-committee.atom, en-UK, United Kingdom
+Tribunal Procedure Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/tribunal-procedure-committee.atom, en-UK, United Kingdom
+Trinity House - Activity on GOV.UK, https://www.gov.uk/government/organisations/trinity-house.atom, en-UK, United Kingdom
+UK Anti-Doping - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-anti-doping.atom, en-UK, United Kingdom
+UK Asset Resolution Limited - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-asset-resolution-limited.atom, en-UK, United Kingdom
+UK Atomic Energy Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-atomic-energy-authority.atom, en-UK, United Kingdom
+UK Commission on Covid Commemoration - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-commission-on-covid-commemoration.atom, en-UK, United Kingdom
+UK Council for Internet Safety - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-council-for-internet-safety.atom, en-UK, United Kingdom
+UK Debt Management Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-debt-management-office.atom, en-UK, United Kingdom
+UK Defence and Security Exports - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-defence-and-security-exports.atom, en-UK, United Kingdom
+UK Export Finance - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-export-finance.atom, en-UK, United Kingdom
+UK Government Investments - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-government-investments.atom, en-UK, United Kingdom
+UK Health Security Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-health-security-agency.atom, en-UK, United Kingdom
+UK Holocaust Memorial Foundation - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-holocaust-memorial-foundation.atom, en-UK, United Kingdom
+UK Hydrographic Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-hydrographic-office.atom, en-UK, United Kingdom
+UK Infrastructure Bank - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-infrastructure-bank.atom, en-UK, United Kingdom
+UK National Authority for Counter-Eavesdropping - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-national-authority-for-counter-eavesdropping.atom, en-UK, United Kingdom
+UK National Contact Point - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-national-contact-point.atom, en-UK, United Kingdom
+UK National Screening Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-national-screening-committee.atom, en-UK, United Kingdom
+UK Research and Innovation - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-research-and-innovation.atom, en-UK, United Kingdom
+UK Shared Business Services Ltd - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-shared-business-services-ltd.atom, en-UK, United Kingdom
+UK Space Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-space-agency.atom, en-UK, United Kingdom
+UK Sport - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-sport.atom, en-UK, United Kingdom
+UK Statistics Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-statistics-authority.atom, en-UK, United Kingdom
+UK Visas and Immigration - Activity on GOV.UK, https://www.gov.uk/government/organisations/uk-visas-and-immigration.atom, en-UK, United Kingdom
+United Kingdom Reserve Forces Association - Activity on GOV.UK, https://www.gov.uk/government/organisations/united-kingdom-reserve-forces-association.atom, en-UK, United Kingdom
+United Kingdom Security Vetting - Activity on GOV.UK, https://www.gov.uk/government/organisations/united-kingdom-security-vetting.atom, en-UK, United Kingdom
+Valuation Office Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/valuation-office-agency.atom, en-UK, United Kingdom
+Valuation Tribunal for England - Activity on GOV.UK, https://www.gov.uk/government/organisations/valuation-tribunal-for-england.atom, en-UK, United Kingdom
+Valuation Tribunal for England - Activity on GOV.UK, https://www.gov.uk/government/organisations/valuation-tribunal-for-england.atom, en-UK, United Kingdom
+Valuation Tribunal Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/valuation-tribunal-service-for-england-valuation-tribunal-service.atom, en-UK, United Kingdom
+Vehicle Certification Agency - Activity on GOV.UK, https://www.gov.uk/government/organisations/vehicle-certification-agency.atom, en-UK, United Kingdom
+Veterans Advisory and Pensions Committees - Activity on GOV.UK, https://www.gov.uk/government/organisations/veterans-advisory-and-pensions-committees-x13.atom, en-UK, United Kingdom
+Veterans UK - Activity on GOV.UK, https://www.gov.uk/government/organisations/veterans-uk.atom, en-UK, United Kingdom
+Veterinary Medicines Directorate - Activity on GOV.UK, https://www.gov.uk/government/organisations/veterinary-medicines-directorate.atom, en-UK, United Kingdom
+Veterinary Products Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/veterinary-products-committee.atom, en-UK, United Kingdom
+Victims' Commissioner - Activity on GOV.UK, https://www.gov.uk/government/organisations/victims-commissioner.atom, en-UK, United Kingdom
+Victoria and Albert Museum - Activity on GOV.UK, https://www.gov.uk/government/organisations/victoria-and-albert-museum.atom, en-UK, United Kingdom
+VisitBritain - Activity on GOV.UK, https://www.gov.uk/government/organisations/visitbritain.atom, en-UK, United Kingdom
+VisitEngland - Activity on GOV.UK, https://www.gov.uk/government/organisations/visitengland.atom, en-UK, United Kingdom
+Wales Audit Office - Activity on GOV.UK, https://www.gov.uk/government/organisations/wales-audit-office.atom, en-UK, United Kingdom
+Wallace Collection - Activity on GOV.UK, https://www.gov.uk/government/organisations/wallace-collection.atom, en-UK, United Kingdom
+Welsh Government - Activity on GOV.UK, https://www.gov.uk/government/organisations/welsh-government.atom, en-UK, United Kingdom
+Welsh Language Commissioner - Activity on GOV.UK, https://www.gov.uk/government/organisations/welsh-language-commissioner.atom, en-UK, United Kingdom
+Westminster Foundation for Democracy - Activity on GOV.UK, https://www.gov.uk/government/organisations/westminster-foundation-for-democracy.atom, en-UK, United Kingdom
+Wilton Park - Activity on GOV.UK, https://www.gov.uk/government/organisations/wilton-park.atom, en-UK, United Kingdom
+Windrush Commemoration Committee - Activity on GOV.UK, https://www.gov.uk/government/organisations/windrush-commemoration-committee.atom, en-UK, United Kingdom
+Yorkshire Dales National Park Authority - Activity on GOV.UK, https://www.gov.uk/government/organisations/yorkshire-dales-national-park-authority.atom, en-UK, United Kingdom
+Youth Custody Service - Activity on GOV.UK, https://www.gov.uk/government/organisations/youth-custody-service.atom, en-UK, United Kingdom
+Youth Justice Agency of Northern Ireland - Activity on GOV.UK, https://www.gov.uk/government/organisations/youth-justice-agency-of-northern-ireland.atom, en-UK, United Kingdom
+Youth Justice Board for England and Wales - Activity on GOV.UK, https://www.gov.uk/government/organisations/youth-justice-board-for-england-and-wales.atom, en-UK, United Kingdom
diff --git a/datasets/legislatures/iceland.csv b/datasets/legislatures/iceland.csv
new file mode 100644
index 0000000..4037fa6
--- /dev/null
+++ b/datasets/legislatures/iceland.csv
@@ -0,0 +1,3 @@
+name, url, language, country
+Alþingi - Alþingi, https://www.althingi.is/rss.xml, is-IS, Iceland
+Alþingi - Jafnlaunavottun, https://www.althingi.is/um-althingi/skrifstofa-althingis/jafnlaunavottun/rss.xml, Icelandic, Iceland
diff --git a/datasets/legislatures/idaho.csv b/datasets/legislatures/idaho.csv
new file mode 100644
index 0000000..2a8e935
--- /dev/null
+++ b/datasets/legislatures/idaho.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+Idaho State Legislature, https://legislature.idaho.gov/feed/, en-US, USA
diff --git a/datasets/legislatures/ireland.csv b/datasets/legislatures/ireland.csv
new file mode 100644
index 0000000..f39cddc
--- /dev/null
+++ b/datasets/legislatures/ireland.csv
@@ -0,0 +1,6 @@
+name, url, language, country
+Houses of the Oireachtas - Dail Schedule, https://www.oireachtas.ie/en/rss/dail-schedule.xml, en-IE, Ireland
+Houses of the Oireachtas - Seanad Schedule, https://www.oireachtas.ie/en/rss/seanad-schedule.xml, en-IE, Ireland
+Houses of the Oireachtas - Committee Schedule, https://www.oireachtas.ie/en/rss/committee-schedule.xml, en-IE, Ireland
+Houses of the Oireachtas - Press Releases, https://www.oireachtas.ie/en/rss/press-releases.xml, en-IE, Ireland
+
diff --git a/datasets/news/.csv b/datasets/news/.csv
new file mode 100644
index 0000000..c088e1e
--- /dev/null
+++ b/datasets/news/.csv
@@ -0,0 +1 @@
+name, url, language, country
diff --git a/datasets/news/5g.csv b/datasets/news/5g.csv
new file mode 100644
index 0000000..c088e1e
--- /dev/null
+++ b/datasets/news/5g.csv
@@ -0,0 +1 @@
+name, url, language, country
diff --git a/datasets/news/art.csv b/datasets/news/art.csv
new file mode 100644
index 0000000..0f66e92
--- /dev/null
+++ b/datasets/news/art.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+The Public Domain Review, https://publicdomainreview.org/rss.xml, en-US, USA
diff --git a/datasets/news/australia.csv b/datasets/news/australia.csv
new file mode 100644
index 0000000..80c1371
--- /dev/null
+++ b/datasets/news/australia.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+Mail Online - Australia Home, https://www.dailymail.co.uk/auhome/index.rss, en-US, Australia
diff --git a/datasets/news/business.csv b/datasets/news/business.csv
new file mode 100644
index 0000000..9b5e4f8
--- /dev/null
+++ b/datasets/news/business.csv
@@ -0,0 +1,13 @@
+name, url, language, country
+ynet - צרכנות, https://www.ynet.co.il/Integration/StoryRss5363.xml, he-IL, Israel
+ynet - כלכלה, https://www.ynet.co.il/Integration/StoryRss6.xml, he-IL, Israel
+דה מרקר - שוק ההון, https://www.themarker.com/srv/tm-markets, he-IL, Israel
+דה מרקר - וול סטריט, https://www.themarker.com/srv/tm-wallstreet, he-IL, Israel
+דה מרקר - נדלן, https://www.themarker.com/srv/tm-real-estate, he-IL, Israel
+דה מרקר - היי-טק, https://www.themarker.com/srv/tm-technation, he-IL, Israel
+דה מרקר - עסקים קטנים ובינוניים, https://www.themarker.com/srv/tm-small-business, he-IL, Israel
+דה מרקר - צרכנות, https://www.themarker.com/srv/tm-consumer, he-IL, Israel
+דה מרקר - כותרות דף הבית, https://www.themarker.com/srv/tm-all-articles, he-IL, Israel
+דה מרקר - כותרות היום, https://www.themarker.com/srv/tm-news, he-IL, Israel
+דה מרקר - פרשנויות היום, https://www.themarker.com/srv/tm-opinions, he-IL, Israel
+Mail Online - Money, https://www.dailymail.co.uk/money/index.rss, en-US, UK
diff --git a/datasets/news/christianity.csv b/datasets/news/christianity.csv
new file mode 100644
index 0000000..35070b3
--- /dev/null
+++ b/datasets/news/christianity.csv
@@ -0,0 +1,4 @@
+name, url, language, country
+Evangelical Endtimemachine, https://www.evangelicalendtimemachine.com/feed/, ce-PH ja-JP nl-NL , Worldwide
+Orthodox Christianity, https://orthochristian.com/xml/rss.xml, en-US, USA
+Legio Christi, https://legiochristi.com/rss/, en-US, USA
diff --git a/datasets/news/computing.csv b/datasets/news/computing.csv
new file mode 100644
index 0000000..a73a1fd
--- /dev/null
+++ b/datasets/news/computing.csv
@@ -0,0 +1,6 @@
+name, url, language, country
+computers are bad, https://computer.rip/rss.xml, en-US, Worldwide
+Jacob McCormick, https://mccor.xyz/rss.xml, en-US, USA
+ju_hnny5, https://blog.jbriault.fr/rss/, fr-FR, France
+Lazy Reading | The Cyber Vanguard, https://cyber.dabamos.de/blog/feed.rss, en-US, USA
+XXIIVV, https://wiki.xxiivv.com/links/rss.xml, en-US, Canada
diff --git a/datasets/news/culture.csv b/datasets/news/culture.csv
new file mode 100644
index 0000000..3585d9f
--- /dev/null
+++ b/datasets/news/culture.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+The Organic Prepper, https://www.theorganicprepper.com/feed/, en-US, USA
diff --git a/datasets/news/cybersecurity.csv b/datasets/news/cybersecurity.csv
new file mode 100644
index 0000000..c088e1e
--- /dev/null
+++ b/datasets/news/cybersecurity.csv
@@ -0,0 +1 @@
+name, url, language, country
diff --git a/datasets/news/entertainment.csv b/datasets/news/entertainment.csv
new file mode 100644
index 0000000..d97f309
--- /dev/null
+++ b/datasets/news/entertainment.csv
@@ -0,0 +1,3 @@
+name, url, language, country
+Mail Online - TV & showbiz, https://www.dailymail.co.uk/tvshowbiz/index.rss, en-US, USA
+Mail Online, https://www.dailymail.co.uk/news/index.rss, en-US, USA
diff --git a/datasets/news/fiction.csv b/datasets/news/fiction.csv
new file mode 100644
index 0000000..7d57186
--- /dev/null
+++ b/datasets/news/fiction.csv
@@ -0,0 +1,10 @@
+name, url, language, country
+ynet - מדע, https://www.ynet.co.il/Integration/StoryRss2142.xml, he-IL, Israel
+Stories by Williams, https://storiesbywilliams.com/feed/, en-US, USA
+SciTechDaily, https://scitechdaily.com/feed/, en-US, USA
+ScienceDaily, https://www.sciencedaily.com/rss/all.xml, en-US, USA
+ScienceAlert, https://www.sciencealert.com/feed, en-US, USA
+NASA Image of the Day, https://www.nasa.gov/feeds/iotd-feed, en-US, USA
+Futurism, https://futurism.com/feed, en-US, USA
+Nature, https://www.nature.com/nature.rss, en-US, USA
+Mail Online - Science & tech, https://www.dailymail.co.uk/sciencetech/index.rss, en-US, UK
diff --git a/datasets/news/gaming.csv b/datasets/news/gaming.csv
new file mode 100644
index 0000000..c088e1e
--- /dev/null
+++ b/datasets/news/gaming.csv
@@ -0,0 +1 @@
+name, url, language, country
diff --git a/datasets/news/general.csv b/datasets/news/general.csv
new file mode 100644
index 0000000..be1fecc
--- /dev/null
+++ b/datasets/news/general.csv
@@ -0,0 +1,8 @@
+name, url, language, country
+mainichi, https://mainichi.jp/rss/etc/english_latest.rss, en-US, Japan
+LewRockwell, http://www.lewrockwell.com/feed/, en-US, USA
+Campaign for Liberty, https://campaignforliberty.org/feed/, en-US, USA
+National Vanguard, https://nationalvanguard.org/feed/, en-US, USA
+Vanguard News Network, http://www.vanguardnewsnetwork.com/feed/, en-US, USA
+Courageous Discourse™ with Dr. Peter McCullough & John Leake, https://petermcculloughmd.substack.com/feed, en-US, USA
+DER SPIEGEL - International, https://www.spiegel.de/international/index.rss, en-US, Germany
diff --git a/datasets/news/government.csv b/datasets/news/government.csv
new file mode 100644
index 0000000..4c9f850
--- /dev/null
+++ b/datasets/news/government.csv
@@ -0,0 +1,4 @@
+name, url, language, country
+The Corbett Report, https://www.corbettreport.com/feed/, en-US, Japan
+ZeroGov, https://zerogov.com/feed/, en-US, USA
+The Organic Prepper, https://www.theorganicprepper.com/feed/, en-US, USA
diff --git a/datasets/news/israel.csv b/datasets/news/israel.csv
new file mode 100644
index 0000000..54a9eb8
--- /dev/null
+++ b/datasets/news/israel.csv
@@ -0,0 +1,7 @@
+name, url, language, country
+בחדרי חרדים, https://www.bhol.co.il/rss/index.xml, he-IL, Israel
+ynet - מבזקים, https://www.ynet.co.il/Integration/StoryRss1854.xml, he-IL, Israel
+ynet - חדשות, https://www.ynet.co.il/Integration/StoryRss2.xml, he-IL, Israel
+ynet - News, https://www.ynet.co.il/3rdparty/mobile/rss/ynetnews/3082/, en-IL, Israel
+העין השביעית, https://www.the7eye.org.il/feed, he-IL, Israel
+
diff --git a/datasets/news/judaism.csv b/datasets/news/judaism.csv
new file mode 100644
index 0000000..aebd7e4
--- /dev/null
+++ b/datasets/news/judaism.csv
@@ -0,0 +1,5 @@
+name, url, language, country
+בחדרי חרדים, https://www.bhol.co.il/rss/index.xml, he-IL, Israel
+ynet - יהדות, https://www.ynet.co.il/Integration/StoryRss4403.xml, he-IL, Israel
+ynet - Jewish, https://www.ynet.co.il/3rdparty/mobile/rss/ynetnews/3443/, en-IL, Israel
+
diff --git a/datasets/news/lifestyle.csv b/datasets/news/lifestyle.csv
new file mode 100644
index 0000000..3e96a3b
--- /dev/null
+++ b/datasets/news/lifestyle.csv
@@ -0,0 +1,4 @@
+name, url, language, country
+Jacob McCormick, https://mccor.xyz/rss.xml, en-US, USA
+The Organic Prepper, https://www.theorganicprepper.com/feed/, en-US, USA
+XXIIVV, https://wiki.xxiivv.com/links/rss.xml, en-US, Canada
diff --git a/datasets/news/linux.csv b/datasets/news/linux.csv
new file mode 100644
index 0000000..d443772
--- /dev/null
+++ b/datasets/news/linux.csv
@@ -0,0 +1,3 @@
+name, url, language, country
+Linux Professional Institute (LPI), https://www.lpi.org/feed/, en-US, Canada
+LinuxConfig, https://linuxconfig.org/feed, en-US, Worldwide
diff --git a/datasets/news/middle_east.csv b/datasets/news/middle_east.csv
new file mode 100644
index 0000000..d65c693
--- /dev/null
+++ b/datasets/news/middle_east.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+MintPress News, https://www.mintpressnews.com/feed/, en-US, USA
diff --git a/datasets/news/opinions.csv b/datasets/news/opinions.csv
new file mode 100644
index 0000000..f6ceda9
--- /dev/null
+++ b/datasets/news/opinions.csv
@@ -0,0 +1,5 @@
+name, url, language, country
+National Vanguard, https://nationalvanguard.org/feed/, en-US, USA
+Vanguard News Network, http://www.vanguardnewsnetwork.com/feed/, en-US, USA
+דה מרקר - פרשנויות היום, https://www.themarker.com/srv/tm-opinions, he-IL, Israel
+
diff --git a/datasets/news/privacy.csv b/datasets/news/privacy.csv
new file mode 100644
index 0000000..c088e1e
--- /dev/null
+++ b/datasets/news/privacy.csv
@@ -0,0 +1 @@
+name, url, language, country
diff --git a/datasets/news/propaganda.csv b/datasets/news/propaganda.csv
new file mode 100644
index 0000000..9d14b6d
--- /dev/null
+++ b/datasets/news/propaganda.csv
@@ -0,0 +1,3 @@
+name, url, language, country
+העין השביעית, https://www.the7eye.org.il/feed, he-IL, Israel
+Fakeologist, https://fakeologist.com/feed/, en-US, Canada
diff --git a/datasets/news/relationship.csv b/datasets/news/relationship.csv
new file mode 100644
index 0000000..24abb1b
--- /dev/null
+++ b/datasets/news/relationship.csv
@@ -0,0 +1,4 @@
+name, url, language, country
+Knowledge For Men, https://www.knowledgeformen.com/feed/, en-US, USA
+ynet - יחסים, https://www.ynet.co.il/Integration/StoryRss3925.xml, he-IL, Israel
+
diff --git a/datasets/news/sailing.csv b/datasets/news/sailing.csv
new file mode 100644
index 0000000..048a173
--- /dev/null
+++ b/datasets/news/sailing.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+XXIIVV, https://wiki.xxiivv.com/links/rss.xml, en-US, Canada
diff --git a/datasets/news/science.csv b/datasets/news/science.csv
new file mode 100644
index 0000000..c088e1e
--- /dev/null
+++ b/datasets/news/science.csv
@@ -0,0 +1 @@
+name, url, language, country
diff --git a/datasets/news/security.csv b/datasets/news/security.csv
new file mode 100644
index 0000000..3585d9f
--- /dev/null
+++ b/datasets/news/security.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+The Organic Prepper, https://www.theorganicprepper.com/feed/, en-US, USA
diff --git a/datasets/news/sorority.csv b/datasets/news/sorority.csv
new file mode 100644
index 0000000..f59eb25
--- /dev/null
+++ b/datasets/news/sorority.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+Alpha Delta Pi, https://www.alphadeltapi.org/feed/, en-US, USA
diff --git a/datasets/news/sports.csv b/datasets/news/sports.csv
new file mode 100644
index 0000000..c088e1e
--- /dev/null
+++ b/datasets/news/sports.csv
@@ -0,0 +1 @@
+name, url, language, country
diff --git a/datasets/news/survival.csv b/datasets/news/survival.csv
new file mode 100644
index 0000000..3585d9f
--- /dev/null
+++ b/datasets/news/survival.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+The Organic Prepper, https://www.theorganicprepper.com/feed/, en-US, USA
diff --git a/datasets/news/technology.csv b/datasets/news/technology.csv
new file mode 100644
index 0000000..e9efbcd
--- /dev/null
+++ b/datasets/news/technology.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+Developpez, https://www.developpez.com/index/atom, fr-FR, France
diff --git a/datasets/news/telecom.csv b/datasets/news/telecom.csv
new file mode 100644
index 0000000..4590b03
--- /dev/null
+++ b/datasets/news/telecom.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+The XMPP Blog on XMPP, https://xmpp.org/feeds/all.atom.xml, en-US, Worldwide
diff --git a/datasets/news/war.csv b/datasets/news/war.csv
new file mode 100644
index 0000000..c088e1e
--- /dev/null
+++ b/datasets/news/war.csv
@@ -0,0 +1 @@
+name, url, language, country
diff --git a/datasets/news/xmpp.csv b/datasets/news/xmpp.csv
new file mode 100644
index 0000000..4590b03
--- /dev/null
+++ b/datasets/news/xmpp.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+The XMPP Blog on XMPP, https://xmpp.org/feeds/all.atom.xml, en-US, Worldwide
diff --git a/datasets/organizations/united_states.csv b/datasets/organizations/united_states.csv
new file mode 100644
index 0000000..4fbf11a
--- /dev/null
+++ b/datasets/organizations/united_states.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+National Alliance, https://www.natall.com/feed/, en-US, USA
diff --git a/datasets/podcasts/code.csv b/datasets/podcasts/code.csv
new file mode 100644
index 0000000..bab220a
--- /dev/null
+++ b/datasets/podcasts/code.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+Talk Python To Me, https://talkpython.fm/episodes/rss, en-US, USA
diff --git a/datasets/podcasts/culture.csv b/datasets/podcasts/culture.csv
new file mode 100644
index 0000000..620925d
--- /dev/null
+++ b/datasets/podcasts/culture.csv
@@ -0,0 +1,4 @@
+name, url, language, country
+American Dissident Voices, https://nationalvanguard.org/category/american-dissident-voices/feed/, en-US, USA
+Radio 3Fourteen, https://redice.tv/rss/radio-3fourteen, en-US, USA
+The National Archives - Podcast Series, https://www.nationalarchives.gov.uk/rss/podcasts.xml, en-UK, United Kingdom
diff --git a/datasets/podcasts/government.csv b/datasets/podcasts/government.csv
new file mode 100644
index 0000000..cba91bb
--- /dev/null
+++ b/datasets/podcasts/government.csv
@@ -0,0 +1,4 @@
+name, url, language, country
+American Dissident Voices, https://nationalvanguard.org/category/american-dissident-voices/feed/, en-US, USA
+The Corbett Report, https://www.corbettreport.com/feed/, en-US, Japan
+Radio 3Fourteen, https://redice.tv/rss/radio-3fourteen, en-US, USA
diff --git a/datasets/podcasts/technology.csv b/datasets/podcasts/technology.csv
new file mode 100644
index 0000000..ab1440a
--- /dev/null
+++ b/datasets/podcasts/technology.csv
@@ -0,0 +1,3 @@
+name, url, language, country
+The Corbett Report, https://www.corbettreport.com/feed/, en-US, Japan
+postmarketOS, https://cast.postmarketos.org/feed.rss, en-US, Germany
diff --git a/datasets/projects/chemistry.csv b/datasets/projects/chemistry.csv
new file mode 100644
index 0000000..0160f4b
--- /dev/null
+++ b/datasets/projects/chemistry.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+Open Chemistry, https://www.openchemistry.org/feed/, en-US, USA
diff --git a/datasets/projects/compiler.csv b/datasets/projects/compiler.csv
new file mode 100644
index 0000000..6295c4a
--- /dev/null
+++ b/datasets/projects/compiler.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+PyPy, https://www.pypy.org/rss.xml, en-US, Worldwide
diff --git a/datasets/projects/internet.csv b/datasets/projects/internet.csv
new file mode 100644
index 0000000..0846c83
--- /dev/null
+++ b/datasets/projects/internet.csv
@@ -0,0 +1,3 @@
+name, url, language, country
+DownThemAll!, https://www.downthemall.org/feed, en-US, Worldwide
+Falkon - KDE web browser, https://www.falkon.org/atom.xml, en-US, Czech
diff --git a/datasets/projects/multimedia.csv b/datasets/projects/multimedia.csv
new file mode 100644
index 0000000..7dbaacc
--- /dev/null
+++ b/datasets/projects/multimedia.csv
@@ -0,0 +1,3 @@
+name, url, language, country
+mosu's Matroska stuff, https://www.bunkus.org/blog/feed/, en-US, Worldwide
+
diff --git a/datasets/projects/visualization.csv b/datasets/projects/visualization.csv
new file mode 100644
index 0000000..ac0c989
--- /dev/null
+++ b/datasets/projects/visualization.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+VTK - The Visualization Toolkit, https://vtk.org/feed/, en-US, USA
diff --git a/datasets/videos/lifestyle.csv b/datasets/videos/lifestyle.csv
new file mode 100644
index 0000000..14e79f3
--- /dev/null
+++ b/datasets/videos/lifestyle.csv
@@ -0,0 +1,3 @@
+name, url, language, country
+denshi.live, https://denshi.live/feeds/videos.xml, en-US, USA
+Luke's Videos, https://videos.lukesmith.xyz/feeds/videos.xml, en-US, USA
diff --git a/datasets/videos/propaganda.csv b/datasets/videos/propaganda.csv
new file mode 100644
index 0000000..efe96af
--- /dev/null
+++ b/datasets/videos/propaganda.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+Fakeotube by Epic Cash, https://fakeotube.com/feed/, en-US, Canada
diff --git a/datasets/videos/technology.csv b/datasets/videos/technology.csv
new file mode 100644
index 0000000..2cf65f7
--- /dev/null
+++ b/datasets/videos/technology.csv
@@ -0,0 +1,4 @@
+name, url, language, country
+denshi.live, https://denshi.live/feeds/videos.xml, en-US, USA
+Luke's Videos, https://videos.lukesmith.xyz/feeds/videos.xml, en-US, USA
+Films By Kris, https://filmsbykris.com/rss.xml, en-US, USA
diff --git a/datasets/wiki/encyclopedia.csv b/datasets/wiki/encyclopedia.csv
new file mode 100644
index 0000000..1bdc68d
--- /dev/null
+++ b/datasets/wiki/encyclopedia.csv
@@ -0,0 +1,3 @@
+name, url, language, country
+Metapedia - Recent changes [en], https://en.metapedia.org/m/index.php?title=Special:RecentChanges&feed=atom, en-US, Worldwide
+Metapedia - Letzte Änderungen [de], https://de.metapedia.org/m/index.php?title=Spezial:Letzte_%C3%84nderungen&feed=atom, de, Worldwide
diff --git a/datasets/wiki/health.csv b/datasets/wiki/health.csv
new file mode 100644
index 0000000..8f35912
--- /dev/null
+++ b/datasets/wiki/health.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+Physiopedia - Recent changes [en], https://www.physio-pedia.com/index.php?title=Special:RecentChanges&feed=atom, en-US, United Kingdom
diff --git a/datasets/wiki/linux.csv b/datasets/wiki/linux.csv
new file mode 100644
index 0000000..c3295c0
--- /dev/null
+++ b/datasets/wiki/linux.csv
@@ -0,0 +1,6 @@
+name, url, language, country
+postmarketOS - Recent changes [en], https://wiki.postmarketos.org/index.php?title=Special:RecentChanges&feed=atom, en-US, Worldwide
+ArchWiki - Recent changes [en], https://wiki.archlinux.org/index.php?title=Special:RecentChanges&feed=atom, en-US, Worldwide
+linux-sunxi.org - Recent changes [en], https://linux-sunxi.org/index.php?title=Special:RecentChanges&feed=atom, en-US, Worldwide
+OpenWrt Wiki, https://openwrt.org/feed.php, en-US, Worldwide
+PINE64 - Recent changes - Recent changes [en], https://wiki.pine64.org/index.php?title=Special:RecentChanges&feed=atom, en-US, Worldwide
diff --git a/datasets/wiki/multimedia.csv b/datasets/wiki/multimedia.csv
new file mode 100644
index 0000000..8ee5b37
--- /dev/null
+++ b/datasets/wiki/multimedia.csv
@@ -0,0 +1,2 @@
+name, url, language, country
+MusicBrainz Wiki - Recent changes [en], https://wiki.musicbrainz.org/index.php?title=Special:RecentChanges&feed=atom, en-US, Worldwide
diff --git a/slixfeed/__main__.py b/slixfeed/__main__.py
index 0fb8831..ee9c5af 100644
--- a/slixfeed/__main__.py
+++ b/slixfeed/__main__.py
@@ -1,13 +1,42 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
-# TODO
-#
-# 0) sql prepared statements
-# 1) Autodetect feed:
-# if page is not feed (or HTML) and contains
-# 2) OPML import/export
-# 3) 2022-12-30 reduce async to (maybe) prevent inner lock. async on task: commands, downloader, updater
+"""
+
+FIXME
+
+1) Check feed duplication on runtime.
+ When feed is valid and is not yet in the database it is
+ posible to send a batch which would result in duplication.
+ Consequently, it might result in database lock error upon
+ feed removal attempt
+
+TODO
+
+1) SQL prepared statements
+
+2) Machine Learning for scrapping Title, Link, Summary and Timstamp
+
+3) Support MUC
+
+4) Support categories
+
+5) Default prepackaged list of feeds
+
+6) XMPP commands
+
+7) Bot as transport
+
+8) OMEMO
+
+9) Logging
+
+10) Default feeds (e.g. Blacklisted News, TBOT etc.)
+
+11) Download and upload/send article (xHTML, xHTMLZ, Markdown, MHTML, TXT)
+ Use Readability
+
+"""
# vars and their meanings:
# jid = Jabber ID (XMPP)
diff --git a/slixfeed/confighandler.py b/slixfeed/confighandler.py
index ba2fbaf..638893a 100644
--- a/slixfeed/confighandler.py
+++ b/slixfeed/confighandler.py
@@ -1,6 +1,15 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
+"""
+
+TODO
+
+1) Use file settings.csv and pathnames.txt instead:
+ See get_value_default and get_default_list
+
+"""
+
import os
import sys
@@ -8,16 +17,21 @@ def get_default_dbdir():
"""
Determine the directory path where dbfile will be stored.
- If $XDG_DATA_HOME is defined, use it
- else if $HOME exists, use it
- else if the platform is Windows, use %APPDATA%
- else use the current directory.
+ * If $XDG_DATA_HOME is defined, use it;
+ * else if $HOME exists, use it;
+ * else if the platform is Windows, use %APPDATA%;
+ * else use the current directory.
- :return: Path to database file.
+ Returns
+ -------
+ str
+ Path to database file.
Note
----
- This code was taken from the buku project.
+ This function was taken from project buku.
+
+ See https://github.com/jarun/buku
* Arun Prakash Jana (jarun)
* Dmitry Marakasov (AMDmi3)
@@ -41,12 +55,15 @@ def get_default_confdir():
"""
Determine the directory path where configuration will be stored.
- If $XDG_CONFIG_HOME is defined, use it
- else if $HOME exists, use it
- else if the platform is Windows, use %APPDATA%
- else use the current directory.
+ * If $XDG_CONFIG_HOME is defined, use it;
+ * else if $HOME exists, use it;
+ * else if the platform is Windows, use %APPDATA%;
+ * else use the current directory.
- :return: Path to configueation directory.
+ Returns
+ -------
+ str
+ Path to configueation directory.
"""
# config_home = xdg.BaseDirectory.xdg_config_home
config_home = os.environ.get('XDG_CONFIG_HOME')
@@ -67,24 +84,69 @@ async def get_value_default(key):
"""
Get settings default value.
- :param key: "enabled", "interval", "quantum".
- :return: Integer.
+ Parameters
+ ----------
+ key : str
+ Key: enabled, filter-allow, filter-deny,
+ interval, quantum, random.
+
+ Returns
+ -------
+ result : int or str
+ Value.
"""
- if key == "enabled":
- result = 1
- elif key == "quantum":
- result = 4
- elif key == "interval":
- result = 30
+ match key:
+ case "enabled":
+ result = 1
+ case "filter-allow":
+ result = "hitler,sadam,saddam"
+ case "filter-deny":
+ result = "crim,dead,death,disaster,holocaust,murder,war"
+ case "interval":
+ result = 30
+ case "quantum":
+ result = 4
+ case "random":
+ result = 0
return result
+def get_list():
+ """
+ Get dictionary file.
+
+ Returns
+ -------
+ paths : list
+ Dictionary of pathnames.
+ """
+ paths = []
+ cfg_dir = get_default_confdir()
+ if not os.path.isdir(cfg_dir):
+ os.mkdir(cfg_dir)
+ cfg_file = os.path.join(cfg_dir, r"url_paths.txt")
+ if not os.path.isfile(cfg_file):
+ # confighandler.generate_dictionary()
+ list = get_default_list()
+ file = open(cfg_file, "w")
+ file.writelines("\n".join(list))
+ file.close()
+ file = open(cfg_file, "r")
+ lines = file.readlines()
+ for line in lines:
+ paths.extend([line.strip()])
+ return paths
+
+
# async def generate_dictionary():
def get_default_list():
"""
Generate a dictionary file.
- :return: List.
+ Returns
+ -------
+ paths : list
+ Dictionary of pathnames.
"""
paths = [
".atom",
@@ -139,6 +201,8 @@ def get_default_list():
# "/rss.json",
"/rss.php",
"/rss.xml",
+ "/syndication.php?type=atom1.0", #mybb
+ "/syndication.php?type=rss2.0",
"/timeline.rss",
"/videos.atom",
# "/videos.json",
diff --git a/slixfeed/datahandler.py b/slixfeed/datahandler.py
index b0ad499..0e763da 100644
--- a/slixfeed/datahandler.py
+++ b/slixfeed/datahandler.py
@@ -1,29 +1,75 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
-import feedparser
import aiohttp
import asyncio
+import feedparser
import os
+
import sqlitehandler
import confighandler
+import datetimehandler
+import filterhandler
-from http.client import IncompleteRead
from asyncio.exceptions import IncompleteReadError
+from http.client import IncompleteRead
from urllib import error
from bs4 import BeautifulSoup
# from xml.etree.ElementTree import ElementTree, ParseError
-from urllib.parse import urlparse
+from urllib.parse import urljoin
+from urllib.parse import urlsplit
+from urllib.parse import urlunsplit
from lxml import html
-async def download_updates(db_file):
+
+# NOTE Perhaps this needs to be executed
+# just once per program execution
+async def initdb(jid, callback, message=None):
+ """
+ Callback function to instantiate action on database.
+
+ Parameters
+ ----------
+ jid : str
+ Jabber ID.
+ callback : ?
+ Function name.
+ message : str, optional
+ Optional kwarg when a message is a part or
+ required argument. The default is None.
+
+ Returns
+ -------
+ object
+ Coroutine object.
+ """
+ db_dir = confighandler.get_default_dbdir()
+ if not os.path.isdir(db_dir):
+ os.mkdir(db_dir)
+ db_file = os.path.join(db_dir, r"{}.db".format(jid))
+ sqlitehandler.create_tables(db_file)
+ # await sqlitehandler.set_default_values(db_file)
+ if message:
+ return await callback(db_file, message)
+ else:
+ return await callback(db_file)
+
+
+async def download_updates(db_file, url=None):
"""
Check feeds for new entries.
- :param db_file: Database filename.
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ url : str, optional
+ URL. The default is None.
"""
- urls = await sqlitehandler.get_subscriptions(db_file)
-
+ if url:
+ urls = [url] # Valid [url] and [url,] and (url,)
+ else:
+ urls = await sqlitehandler.get_feeds_url(db_file)
for url in urls:
# print(os.path.basename(db_file), url[0])
source = url[0]
@@ -34,31 +80,42 @@ async def download_updates(db_file):
# urls.next()
# next(urls)
continue
-
- await sqlitehandler.update_source_status(db_file, res[1], source)
-
+ await sqlitehandler.update_source_status(
+ db_file,
+ res[1],
+ source
+ )
if res[0]:
try:
feed = feedparser.parse(res[0])
if feed.bozo:
- # bozo = ("WARNING: Bozo detected for feed <{}>. "
- # "For more information, visit "
- # "https://pythonhosted.org/feedparser/bozo.html"
- # .format(source))
- # print(bozo)
+ bozo = (
+ "WARNING: Bozo detected for feed: {}\n"
+ "For more information, visit "
+ "https://pythonhosted.org/feedparser/bozo.html"
+ ).format(source)
+ print(bozo)
valid = 0
else:
valid = 1
- await sqlitehandler.update_source_validity(db_file, source, valid)
- except (IncompleteReadError, IncompleteRead, error.URLError) as e:
- print(e)
+ await sqlitehandler.update_source_validity(
+ db_file,
+ source,
+ valid)
+ except (
+ IncompleteReadError,
+ IncompleteRead,
+ error.URLError
+ ) as e:
+ # print(e)
+ # TODO Print error to log
+ None
# NOTE I don't think there should be "return"
# because then we might stop scanning next URLs
# return
# TODO Place these couple of lines back down
# NOTE Need to correct the SQL statement to do so
# NOT SURE WHETHER I MEANT THE LINES ABOVE OR BELOW
-
if res[1] == 200:
# NOT SURE WHETHER I MEANT THE LINES ABOVE OR BELOW
# TODO Place these couple of lines back down
@@ -66,25 +123,60 @@ async def download_updates(db_file):
entries = feed.entries
# length = len(entries)
# await sqlitehandler.remove_entry(db_file, source, length)
- await sqlitehandler.remove_nonexistent_entries(db_file, feed, source)
-
- new_entry = 0
+ await sqlitehandler.remove_nonexistent_entries(
+ db_file,
+ feed,
+ source
+ )
+ # new_entry = 0
for entry in entries:
-
+ if entry.has_key("id"):
+ eid = entry.id
if entry.has_key("title"):
title = entry.title
else:
title = feed["feed"]["title"]
-
if entry.has_key("link"):
- link = entry.link
+ # link = complete_url(source, entry.link)
+ link = await join_url(source, entry.link)
+ link = await trim_url(link)
else:
link = source
-
- exist = await sqlitehandler.check_entry_exist(db_file, title, link)
-
+ # TODO Pass date too for comparion check
+ if entry.has_key("published"):
+ date = entry.published
+ date = await datetimehandler.rfc2822_to_iso8601(date)
+ else:
+ date = None
+ exist = await sqlitehandler.check_entry_exist(
+ db_file,
+ source,
+ eid=eid,
+ title=title,
+ link=link,
+ date=date
+ )
if not exist:
- new_entry = new_entry + 1
+ # new_entry = new_entry + 1
+ if entry.has_key("published"):
+ date = entry.published
+ date = await datetimehandler.rfc2822_to_iso8601(date)
+ # try:
+ # date = datetime.strptime(date, "%a, %d %b %Y %H:%M:%S %z")
+ # except:
+ # date = datetime.strptime(date, '%a, %d %b %Y %H:%M:%S %Z')
+ # finally:
+ # date = date.isoformat()
+ # if parsedate(date): # Is RFC 2822 format
+ # date = parsedate_to_datetime(date) # Process timestamp
+ # date = date.isoformat() # Convert to ISO 8601
+ else:
+ # TODO Just set date = "*** No date ***"
+ # date = datetime.now().isoformat()
+ date = await datetimehandler.now()
+ # NOTE Would seconds result in better database performance
+ # date = datetime.datetime(date)
+ # date = (date-datetime.datetime(1970,1,1)).total_seconds()
# TODO Enhance summary
if entry.has_key("summary"):
summary = entry.summary
@@ -93,164 +185,156 @@ async def download_updates(db_file):
# TODO Limit text length
summary = summary.replace("\n\n", "\n")[:300] + " ⃨"
else:
- summary = '*** No summary ***'
- entry = (title, summary, link, source, 0);
- await sqlitehandler.add_entry_and_set_date(db_file, source, entry)
+ summary = "*** No summary ***"
+ read_status = 0
+ pathname = urlsplit(link).path
+ string = (
+ "{} {} {}"
+ ).format(
+ title,
+ summary,
+ pathname
+ )
+ allow_list = await filterhandler.is_listed(
+ db_file,
+ "allow",
+ string
+ )
+ if not allow_list:
+ reject_list = await filterhandler.is_listed(
+ db_file,
+ "deny",
+ string
+ )
+ if reject_list:
+ print(">>> REJECTED", title)
+ summary = "REJECTED"
+ # summary = ""
+ read_status = 1
+ entry = (
+ title,
+ summary,
+ link,
+ eid,
+ source,
+ date,
+ read_status
+ )
+ await sqlitehandler.add_entry_and_set_date(
+ db_file,
+ source,
+ entry
+ )
+ # print(await datetimehandler.current_time(), entry, title)
+ # else:
+ # print(await datetimehandler.current_time(), exist, title)
+
+
+async def add_feed_no_check(db_file, data):
+ """
+ Add given feed without validity check.
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ data : str
+ URL or URL and Title.
+
+ Returns
+ -------
+ msg : str
+ Status message.
+ """
+ url = data[0]
+ title = data[1]
+ url = await trim_url(url)
+ exist = await sqlitehandler.check_feed_exist(db_file, url)
+ if not exist:
+ msg = await sqlitehandler.add_feed(db_file, url, title)
+ await download_updates(db_file, [url])
+ else:
+ ix = exist[0]
+ name = exist[1]
+ msg = (
+ "> {}\nNews source \"{}\" is already "
+ "listed in the subscription list at "
+ "index {}".format(url, name, ix)
+ )
+ return msg
async def add_feed(db_file, url):
"""
Check whether feed exist, otherwise process it.
- :param db_file: Database filename.
- :param url: URL.
- :return: Status message.
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ url : str
+ URL.
+
+ Returns
+ -------
+ msg : str
+ Status message.
"""
+ msg = None
+ url = await trim_url(url)
exist = await sqlitehandler.check_feed_exist(db_file, url)
-
if not exist:
res = await download_feed(url)
if res[0]:
feed = feedparser.parse(res[0])
title = await get_title(url, feed)
if feed.bozo:
- bozo = ("WARNING: Bozo detected. Failed to load <{}>.".format(url))
+ bozo = (
+ "Bozo detected. Failed to load: {}."
+ ).format(url)
print(bozo)
try:
# tree = etree.fromstring(res[0]) # etree is for xml
tree = html.fromstring(res[0])
except:
- return "Failed to parse URL <{}> as feed".format(url)
-
- print("RSS Auto-Discovery Engaged")
- xpath_query = """//link[(@rel="alternate") and (@type="application/atom+xml" or @type="application/rdf+xml" or @type="application/rss+xml")]"""
- # xpath_query = """//link[(@rel="alternate") and (@type="application/atom+xml" or @type="application/rdf+xml" or @type="application/rss+xml")]/@href"""
- # xpath_query = "//link[@rel='alternate' and @type='application/atom+xml' or @rel='alternate' and @type='application/rss+xml' or @rel='alternate' and @type='application/rdf+xml']/@href"
- feeds = tree.xpath(xpath_query)
- if len(feeds) > 1:
- msg = "RSS Auto-Discovery has found {} feeds:\n\n".format(len(feeds))
- for feed in feeds:
- # # The following code works;
- # # The following code will catch
- # # only valid resources (i.e. not 404);
- # # The following code requires more bandwidth.
- # res = await download_feed(feed)
- # if res[0]:
- # disco = feedparser.parse(res[0])
- # title = disco["feed"]["title"]
- # msg += "{} \n {} \n\n".format(title, feed)
- feed_name = feed.xpath('@title')[0]
- feed_addr = feed.xpath('@href')[0]
- msg += "{}\n{}\n\n".format(feed_name, feed_addr)
- msg += "The above feeds were extracted from\n{}".format(url)
- return msg
- elif feeds:
- url = feeds[0].xpath('@href')[0]
- # Why wouldn't add_feed return a message
- # upon success unless return is explicitly
- # mentioned, yet upon failure it wouldn't?
- return await add_feed(db_file, url)
-
- print("RSS Scan Mode Engaged")
- feeds = {}
- paths = []
- # TODO Test
- cfg_dir = confighandler.get_default_confdir()
- if not os.path.isdir(cfg_dir):
- os.mkdir(cfg_dir)
- cfg_file = os.path.join(cfg_dir, r"url_paths.txt")
- if not os.path.isfile(cfg_file):
- # confighandler.generate_dictionary()
- list = confighandler.get_default_list()
- file = open(cfg_file, "w")
- file.writelines("\n".join(list))
- file.close()
- file = open(cfg_file, "r")
- lines = file.readlines()
- for line in lines:
- paths.extend([line.strip()])
- for path in paths:
- # xpath_query = "//*[@*[contains(.,'{}')]]".format(path)
- xpath_query = "//a[contains(@href,'{}')]".format(path)
- addresses = tree.xpath(xpath_query)
- parted_url = urlparse(url)
- # NOTE Should number of addresses be limited or
- # perhaps be N from the start and N from the end
- for address in addresses:
- address = address.xpath('@href')[0]
- if address.startswith('/'):
- address = parted_url.scheme + '://' + parted_url.netloc + address
- res = await download_feed(address)
- if res[1] == 200:
- try:
- feeds[address] = feedparser.parse(res[0])["feed"]["title"]
- except:
- continue
- if len(feeds) > 1:
- msg = "RSS URL scan has found {} feeds:\n\n".format(len(feeds))
- for feed in feeds:
- # try:
- # res = await download_feed(feed)
- # except:
- # continue
- feed_name = feeds[feed]
- feed_addr = feed
- msg += "{}\n{}\n\n".format(feed_name, feed_addr)
- msg += "The above feeds were extracted from\n{}".format(url)
- return msg
- elif feeds:
- url = list(feeds)[0]
- return await add_feed(db_file, url)
-
- # (HTTP) Request(s) Paths
- print("RSS Arbitrary Mode Engaged")
- feeds = {}
- parted_url = urlparse(url)
- for path in paths:
- address = parted_url.scheme + '://' + parted_url.netloc + path
- res = await download_feed(address)
- if res[1] == 200:
- # print(feedparser.parse(res[0])["feed"]["title"])
- # feeds[address] = feedparser.parse(res[0])["feed"]["title"]
- try:
- title = feedparser.parse(res[0])["feed"]["title"]
- except:
- title = '*** No Title ***'
- feeds[address] = title
-
- # Check whether URL has path (i.e. not root)
- if parted_url.path.split('/')[1]:
- paths.extend([".atom", ".feed", ".rdf", ".rss"]) if '.rss' not in paths else -1
- # if paths.index('.rss'):
- # paths.extend([".atom", ".feed", ".rdf", ".rss"])
- address = parted_url.scheme + '://' + parted_url.netloc + '/' + parted_url.path.split('/')[1] + path
- res = await download_feed(address)
- if res[1] == 200:
- try:
- title = feedparser.parse(res[0])["feed"]["title"]
- except:
- title = '*** No Title ***'
- feeds[address] = title
- if len(feeds) > 1:
- msg = "RSS URL discovery has found {} feeds:\n\n".format(len(feeds))
- for feed in feeds:
- feed_name = feeds[feed]
- feed_addr = feed
- msg += "{}\n{}\n\n".format(feed_name, feed_addr)
- msg += "The above feeds were extracted from\n{}".format(url)
- elif feeds:
- url = list(feeds)[0]
- msg = await add_feed(db_file, url)
- else:
- msg = "No news feeds were found for URL <{}>.".format(url)
+ msg = (
+ "> {}\nFailed to parse URL as feed."
+ ).format(url)
+ if not msg:
+ print("RSS Auto-Discovery Engaged")
+ msg = await feed_mode_auto_discovery(db_file, url, tree)
+ if not msg:
+ print("RSS Scan Mode Engaged")
+ msg = await feed_mode_scan(db_file, url, tree)
+ if not msg:
+ print("RSS Arbitrary Mode Engaged")
+ msg = await feed_mode_request(db_file, url, tree)
+ if not msg:
+ msg = (
+ "> {}\nNo news feeds were found for URL."
+ ).format(url)
else:
- msg = await sqlitehandler.add_feed(db_file, title, url, res)
+ status = res[1]
+ msg = await sqlitehandler.add_feed(
+ db_file,
+ url,
+ title,
+ status
+ )
+ await download_updates(db_file, [url])
else:
- msg = "Failed to get URL <{}>. Reason: {}".format(url, res[1])
+ status = res[1]
+ msg = (
+ "> {}\nFailed to get URL. Reason: {}"
+ ).format(url, status)
else:
ix = exist[0]
name = exist[1]
- msg = "> {}\nNews source \"{}\" is already listed in the subscription list at index {}".format(url, name, ix)
+ msg = (
+ "> {}\nNews source \"{}\" is already "
+ "listed in the subscription list at "
+ "index {}".format(url, name, ix)
+ )
return msg
@@ -258,8 +342,15 @@ async def download_feed(url):
"""
Download content of given URL.
- :param url: URL.
- :return: Document or error message.
+ Parameters
+ ----------
+ url : str
+ URL.
+
+ Returns
+ -------
+ msg: list or str
+ Document or error message.
"""
timeout = aiohttp.ClientTimeout(total=10)
async with aiohttp.ClientSession() as session:
@@ -271,30 +362,438 @@ async def download_feed(url):
try:
doc = await response.text()
# print (response.content_type)
- return [doc, status]
+ msg = [
+ doc,
+ status
+ ]
except:
- # return [False, "The content of this document doesn't appear to be textual."]
- return [False, "Document is too large or is not textual."]
+ # msg = [
+ # False,
+ # ("The content of this document "
+ # "doesn't appear to be textual."
+ # )
+ # ]
+ msg = [
+ False,
+ "Document is too large or is not textual."
+ ]
else:
- return [False, "HTTP Error: " + str(status)]
+ msg = [
+ False,
+ "HTTP Error: " + str(status)
+ ]
except aiohttp.ClientError as e:
- print('Error', str(e))
- return [False, "Error: " + str(e)]
+ # print('Error', str(e))
+ msg = [
+ False,
+ "Error: " + str(e)
+ ]
except asyncio.TimeoutError as e:
# print('Timeout:', str(e))
- return [False, "Timeout: " + str(e)]
+ msg = [
+ False,
+ "Timeout: " + str(e)
+ ]
+ return msg
async def get_title(url, feed):
"""
Get title of feed.
- :param url: URL
- :param feed: Parsed feed
- :return: Title or URL hostname.
+ Parameters
+ ----------
+ url : str
+ URL.
+ feed : dict
+ Parsed feed document.
+
+ Returns
+ -------
+ title : str
+ Title or URL hostname.
"""
try:
title = feed["feed"]["title"]
except:
- title = urlparse(url).netloc
+ title = urlsplit(url).netloc
return title
+
+
+# NOTE Read the documentation
+# https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urljoin
+def complete_url(source, link):
+ """
+ Check if URL is pathname and complete it into URL.
+
+ Parameters
+ ----------
+ source : str
+ Feed URL.
+ link : str
+ Link URL or pathname.
+
+ Returns
+ -------
+ str
+ URL.
+ """
+ if link.startswith("www."):
+ return "http://" + link
+ parted_link = urlsplit(link)
+ parted_feed = urlsplit(source)
+ if parted_link.scheme == "magnet" and parted_link.query:
+ return link
+ if parted_link.scheme and parted_link.netloc:
+ return link
+ if link.startswith("//"):
+ if parted_link.netloc and parted_link.path:
+ new_link = urlunsplit([
+ parted_feed.scheme,
+ parted_link.netloc,
+ parted_link.path,
+ parted_link.query,
+ parted_link.fragment
+ ])
+ elif link.startswith("/"):
+ new_link = urlunsplit([
+ parted_feed.scheme,
+ parted_feed.netloc,
+ parted_link.path,
+ parted_link.query,
+ parted_link.fragment
+ ])
+ elif link.startswith("../"):
+ pathlink = parted_link.path.split("/")
+ pathfeed = parted_feed.path.split("/")
+ for i in pathlink:
+ if i == "..":
+ if pathlink.index("..") == 0:
+ pathfeed.pop()
+ else:
+ break
+ while pathlink.count(".."):
+ if pathlink.index("..") == 0:
+ pathlink.remove("..")
+ else:
+ break
+ pathlink = "/".join(pathlink)
+ pathfeed.extend([pathlink])
+ new_link = urlunsplit([
+ parted_feed.scheme,
+ parted_feed.netloc,
+ "/".join(pathfeed),
+ parted_link.query,
+ parted_link.fragment
+ ])
+ else:
+ pathlink = parted_link.path.split("/")
+ pathfeed = parted_feed.path.split("/")
+ if link.startswith("./"):
+ pathlink.remove(".")
+ if not source.endswith("/"):
+ pathfeed.pop()
+ pathlink = "/".join(pathlink)
+ pathfeed.extend([pathlink])
+ new_link = urlunsplit([
+ parted_feed.scheme,
+ parted_feed.netloc,
+ "/".join(pathfeed),
+ parted_link.query,
+ parted_link.fragment
+ ])
+ return new_link
+
+
+"""
+TODO
+Feed https://www.ocaml.org/feed.xml
+Link %20https://frama-c.com/fc-versions/cobalt.html%20
+
+FIXME
+Feed https://cyber.dabamos.de/blog/feed.rss
+Link https://cyber.dabamos.de/blog/#article-2022-07-15
+"""
+async def join_url(source, link):
+ """
+ Join base URL with given pathname.
+
+ Parameters
+ ----------
+ source : str
+ Feed URL.
+ link : str
+ Link URL or pathname.
+
+ Returns
+ -------
+ str
+ URL.
+ """
+ if link.startswith("www."):
+ new_link = "http://" + link
+ elif link.startswith("%20") and link.endswith("%20"):
+ old_link = link.split("%20")
+ del old_link[0]
+ old_link.pop()
+ new_link = "".join(old_link)
+ else:
+ new_link = urljoin(source, link)
+ return new_link
+
+
+async def trim_url(url):
+ """
+ Check URL pathname for double slash.
+
+ Parameters
+ ----------
+ url : str
+ URL.
+
+ Returns
+ -------
+ url : str
+ URL.
+ """
+ parted_url = urlsplit(url)
+ protocol = parted_url.scheme
+ hostname = parted_url.netloc
+ pathname = parted_url.path
+ queries = parted_url.query
+ fragment = parted_url.fragment
+ while "//" in pathname:
+ pathname = pathname.replace("//", "/")
+ url = urlunsplit([
+ protocol,
+ hostname,
+ pathname,
+ queries,
+ fragment
+ ])
+ return url
+
+
+# TODO Improve scan by gradual decreasing of path
+async def feed_mode_request(db_file, url, tree):
+ """
+ Lookup for feeds by pathname using HTTP Requests.
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ url : str
+ URL.
+ tree : TYPE
+ DESCRIPTION.
+
+ Returns
+ -------
+ msg : str
+ Message with URLs.
+ """
+ feeds = {}
+ parted_url = urlsplit(url)
+ paths = confighandler.get_list()
+ for path in paths:
+ address = urlunsplit([
+ parted_url.scheme,
+ parted_url.netloc,
+ path,
+ None,
+ None
+ ])
+ res = await download_feed(address)
+ if res[1] == 200:
+ # print(feedparser.parse(res[0])["feed"]["title"])
+ # feeds[address] = feedparser.parse(res[0])["feed"]["title"]
+ try:
+ title = feedparser.parse(res[0])["feed"]["title"]
+ except:
+ title = '*** No Title ***'
+ feeds[address] = title
+ # Check whether URL has path (i.e. not root)
+ if parted_url.path.split('/')[1]:
+ paths.extend(
+ [".atom", ".feed", ".rdf", ".rss"]
+ ) if '.rss' not in paths else -1
+ # if paths.index('.rss'):
+ # paths.extend([".atom", ".feed", ".rdf", ".rss"])
+ address = urlunsplit([
+ parted_url.scheme,
+ parted_url.netloc,
+ parted_url.path.split('/')[1] + path,
+ None,
+ None
+ ])
+ res = await download_feed(address)
+ if res[1] == 200:
+ try:
+ title = feedparser.parse(res[0])["feed"]["title"]
+ except:
+ title = '*** No Title ***'
+ feeds[address] = title
+ if len(feeds) > 1:
+ msg = (
+ "RSS URL discovery has found {} feeds:\n```\n"
+ ).format(len(feeds))
+ for feed in feeds:
+ feed_name = feeds[feed]
+ feed_addr = feed
+ msg += "{}\n{}\n\n".format(feed_name, feed_addr)
+ msg += (
+ "```\nThe above feeds were extracted from\n{}"
+ ).format(url)
+ elif feeds:
+ feed_addr = list(feeds)[0]
+ msg = await add_feed(db_file, feed_addr)
+ return msg
+
+
+async def feed_mode_scan(db_file, url, tree):
+ """
+ Scan page for potential feeds by pathname.
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ url : str
+ URL.
+ tree : TYPE
+ DESCRIPTION.
+
+ Returns
+ -------
+ msg : str
+ Message with URLs.
+ """
+ feeds = {}
+ # paths = []
+ # TODO Test
+ paths = confighandler.get_list()
+ for path in paths:
+ # xpath_query = "//*[@*[contains(.,'{}')]]".format(path)
+ xpath_query = "//a[contains(@href,'{}')]".format(path)
+ addresses = tree.xpath(xpath_query)
+ parted_url = urlsplit(url)
+ # NOTE Should number of addresses be limited or
+ # perhaps be N from the start and N from the end
+ for address in addresses:
+ print(address.xpath('@href')[0])
+ print(addresses)
+ address = address.xpath('@href')[0]
+ if "/" not in address:
+ protocol = parted_url.scheme
+ hostname = parted_url.netloc
+ pathname = address
+ address = urlunsplit([
+ protocol,
+ hostname,
+ pathname,
+ None,
+ None
+ ])
+ if address.startswith('/'):
+ protocol = parted_url.scheme
+ hostname = parted_url.netloc
+ pathname = address
+ address = urlunsplit([
+ protocol,
+ hostname,
+ pathname,
+ None,
+ None
+ ])
+ res = await download_feed(address)
+ if res[1] == 200:
+ try:
+ feeds[address] = feedparser.parse(res[0])["feed"]["title"]
+ print(feeds)
+ except:
+ continue
+ if len(feeds) > 1:
+ msg = (
+ "RSS URL scan has found {} feeds:\n```\n"
+ ).format(len(feeds))
+ for feed in feeds:
+ # try:
+ # res = await download_feed(feed)
+ # except:
+ # continue
+ feed_name = feeds[feed]
+ feed_addr = feed
+ msg += "{}\n{}\n\n".format(feed_name, feed_addr)
+ msg += (
+ "```\nThe above feeds were extracted from\n{}"
+ ).format(url)
+ return msg
+ elif feeds:
+ feed_addr = list(feeds)[0]
+ msg = await add_feed(db_file, feed_addr)
+ return msg
+
+
+async def feed_mode_auto_discovery(db_file, url, tree):
+ """
+ Lookup for feeds using RSS autodiscovery technique.
+
+ See: https://www.rssboard.org/rss-autodiscovery
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ url : str
+ URL.
+ tree : TYPE
+ DESCRIPTION.
+
+ Returns
+ -------
+ msg : str
+ Message with URLs.
+ """
+ xpath_query = (
+ '//link[(@rel="alternate") and '
+ '(@type="application/atom+xml" or '
+ '@type="application/rdf+xml" or '
+ '@type="application/rss+xml")]'
+ )
+ # xpath_query = """//link[(@rel="alternate") and (@type="application/atom+xml" or @type="application/rdf+xml" or @type="application/rss+xml")]/@href"""
+ # xpath_query = "//link[@rel='alternate' and @type='application/atom+xml' or @rel='alternate' and @type='application/rss+xml' or @rel='alternate' and @type='application/rdf+xml']/@href"
+ feeds = tree.xpath(xpath_query)
+ if len(feeds) > 1:
+ msg = (
+ "RSS Auto-Discovery has found {} feeds:\n```\n"
+ ).format(len(feeds))
+ for feed in feeds:
+ # # The following code works;
+ # # The following code will catch
+ # # only valid resources (i.e. not 404);
+ # # The following code requires more bandwidth.
+ # res = await download_feed(feed)
+ # if res[0]:
+ # disco = feedparser.parse(res[0])
+ # title = disco["feed"]["title"]
+ # msg += "{} \n {} \n\n".format(title, feed)
+ feed_name = feed.xpath('@title')[0]
+ feed_addr = await join_url(url, feed.xpath('@href')[0])
+ # if feed_addr.startswith("/"):
+ # feed_addr = url + feed_addr
+ msg += "{}\n{}\n\n".format(feed_name, feed_addr)
+ msg += (
+ "```\nThe above feeds were extracted from\n{}"
+ ).format(url)
+ return msg
+ elif feeds:
+ feed_addr = await join_url(url, feeds[0].xpath('@href')[0])
+ # if feed_addr.startswith("/"):
+ # feed_addr = url + feed_addr
+ # NOTE Why wouldn't add_feed return a message
+ # upon success unless return is explicitly
+ # mentioned, yet upon failure it wouldn't?
+ # return await add_feed(db_file, feed_addr)
+ msg = await add_feed(db_file, feed_addr)
+ return msg
\ No newline at end of file
diff --git a/slixfeed/datetimehandler.py b/slixfeed/datetimehandler.py
new file mode 100644
index 0000000..1964ebd
--- /dev/null
+++ b/slixfeed/datetimehandler.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+"""
+https://feedparser.readthedocs.io/en/latest/date-parsing.html
+"""
+
+from datetime import datetime
+from dateutil.parser import parse
+from email.utils import parsedate
+from email.utils import parsedate_to_datetime
+
+async def now():
+ """
+ ISO 8601 Timestamp.
+
+ Returns
+ -------
+ date : ?
+ ISO 8601 Timestamp.
+ """
+ date = datetime.now().isoformat()
+ return date
+
+
+async def current_time():
+ """
+ Print HH:MM:SS timestamp.
+
+ Returns
+ -------
+ date : ?
+ HH:MM:SS timestamp.
+ """
+ now = datetime.now()
+ time = now.strftime("%H:%M:%S")
+ return time
+
+
+async def validate(date):
+ """
+ Validate date format.
+
+ Parameters
+ ----------
+ date : str
+ Timestamp.
+
+ Returns
+ -------
+ date : str
+ Timestamp.
+ """
+ try:
+ parse(date)
+ except:
+ date = now()
+ return date
+
+
+async def rfc2822_to_iso8601(date):
+ """
+ Convert RFC 2822 into ISO 8601.
+
+ Parameters
+ ----------
+ date : str
+ RFC 2822 Timestamp.
+
+ Returns
+ -------
+ date : str
+ ISO 8601 Timestamp.
+ """
+ if parsedate(date):
+ try:
+ date = parsedate_to_datetime(date)
+ date = date.isoformat()
+ except:
+ date = now()
+ return date
diff --git a/slixfeed/filterhandler.py b/slixfeed/filterhandler.py
new file mode 100644
index 0000000..8c5db93
--- /dev/null
+++ b/slixfeed/filterhandler.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+"""
+
+TODO
+
+1) Website-specific filter (i.e. audiobookbay).
+
+2) Exclude websites from filtering (e.g. metapedia).
+
+3) Filter phrases:
+ Refer to sqlitehandler.search_entries for implementation.
+ It is expected to be more complex than function search_entries.
+
+"""
+
+import sqlitehandler
+
+async def set_filter(newwords, keywords):
+ """
+ Append new keywords to filter.
+
+ Parameters
+ ----------
+ newwords : str
+ List of new keywords.
+ keywords : str
+ List of current keywords.
+
+ Returns
+ -------
+ val : str
+ List of current keywords and new keywords.
+ """
+ try:
+ keywords = keywords.split(",")
+ except:
+ keywords = []
+ newwords = newwords.lower().split(",")
+ for word in newwords:
+ word = word.strip()
+ if len(word) and word not in keywords:
+ keywords.extend([word])
+ keywords.sort()
+ val = ",".join(keywords)
+ return val
+
+async def is_listed(db_file, type, string):
+# async def reject(db_file, string):
+# async def is_blacklisted(db_file, string):
+ filter_type = "filter-" + type
+ list = await sqlitehandler.get_settings_value(
+ db_file,
+ filter_type
+ )
+ if list:
+ list = list.split(",")
+ for i in list:
+ if not i or len(i) < 2:
+ continue
+ if i in string.lower():
+ print(">>> ACTIVATE", i)
+ return 1
+ else:
+ return None
+
+"""
+
+This code was tested at module datahandler
+
+ reject = 0
+ blacklist = await sqlitehandler.get_settings_value(
+ db_file,
+ "filter-deny"
+ )
+ # print(">>> blacklist:")
+ # print(blacklist)
+ # breakpoint()
+ if blacklist:
+ blacklist = blacklist.split(",")
+ # print(">>> blacklist.split")
+ # print(blacklist)
+ # breakpoint()
+ for i in blacklist:
+ # print(">>> length", len(i))
+ # breakpoint()
+ # if len(i):
+ if not i or len(i) < 2:
+ print(">>> continue due to length", len(i))
+ # breakpoint()
+ continue
+ # print(title)
+ # print(">>> blacklisted word:", i)
+ # breakpoint()
+ test = (title + " " + summary + " " + link)
+ if i in test.lower():
+ reject = 1
+ break
+
+ if reject:
+ print("rejected:",title)
+ entry = (title, '', link, source, date, 1);
+
+"""
\ No newline at end of file
diff --git a/slixfeed/opmlhandler.py b/slixfeed/opmlhandler.py
new file mode 100644
index 0000000..1340ca0
--- /dev/null
+++ b/slixfeed/opmlhandler.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+"""
+
+{
+ 'bozo': False,
+ 'bozo_exception': None,
+ 'feeds': [
+ {
+ 'url': 'https://kurtmckee.org/tag/listparser/feed',
+ 'title': 'listparser blog',
+ 'categories': [],
+ 'tags': []
+ },
+ {
+ 'url': 'https://github.com/kurtmckee/listparser/commits/develop.atom',
+ 'title': 'listparser changelog',
+ 'categories': [],
+ 'tags': []
+ }
+ ],
+ 'lists': [],
+ 'opportunities': [],
+ 'meta': {
+ 'title': 'listparser project feeds',
+ 'author': {
+ 'name': 'Kurt McKee',
+ 'email': 'contactme@kurtmckee.org',
+ 'url': 'https://kurtmckee.org/'
+ }
+ },
+ 'version': 'opml2'
+ }
+
+"""
+
+import listparser
+import lxml
+
+import sqlitehandler
+import datahandler
+
+async def import_opml(db_file, opml_doc):
+ feeds = listparser.parse(opml_doc)['feeds']
+ for feed in feeds:
+ url = feed['url']
+ title = feed['title']
+ # categories = feed['categories']
+ # tags = feed['tags']
+ await datahandler.add_feed_no_check(db_file, [url, title])
+
+
+# NOTE Use OPyML or LXML
+async def export_opml():
+ result = await sqlitehandler.get_feeds()
diff --git a/slixfeed/sqlitehandler.py b/slixfeed/sqlitehandler.py
index 311f72e..4bfc9fb 100644
--- a/slixfeed/sqlitehandler.py
+++ b/slixfeed/sqlitehandler.py
@@ -1,6 +1,20 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
+"""
+
+TODO
+
+1) Table feeds:
+ category
+ type (atom, rdf, rss0.9. rss2 etc.)
+
+2) Function mark_all_read for entries of given feed
+
+3) Statistics
+
+"""
+
import sqlite3
import asyncio
@@ -8,11 +22,13 @@ from sqlite3 import Error
from datetime import date
import confighandler
+import datahandler
+import datetimehandler
# from eliot import start_action, to_file
-# # with start_action(action_type="list_subscriptions()", db=db_file):
+# # with start_action(action_type="list_feeds()", db=db_file):
# # with start_action(action_type="last_entries()", num=num):
-# # with start_action(action_type="get_subscriptions()"):
+# # with start_action(action_type="get_feeds()"):
# # with start_action(action_type="remove_entry()", source=source):
# # with start_action(action_type="search_entries()", query=query):
# # with start_action(action_type="check_entry()", link=link):
@@ -26,9 +42,16 @@ def create_connection(db_file):
"""
Create a database connection to the SQLite database
specified by db_file.
-
- :param db_file: Database filename.
- :return: Connection object or None.
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+
+ Returns
+ -------
+ conn : object
+ Connection object or None.
"""
conn = None
try:
@@ -43,45 +66,67 @@ def create_tables(db_file):
"""
Create SQLite tables.
- :param db_file: Database filename.
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
"""
with create_connection(db_file) as conn:
- feeds_table_sql = """
- CREATE TABLE IF NOT EXISTS feeds (
- id integer PRIMARY KEY,
- name text,
- address text NOT NULL,
- enabled integer NOT NULL,
- scanned text,
- updated text,
- status integer,
- valid integer
- ); """
- entries_table_sql = """
- CREATE TABLE IF NOT EXISTS entries (
- id integer PRIMARY KEY,
- title text NOT NULL,
- summary text NOT NULL,
- link text NOT NULL,
- source text,
- read integer
- ); """
- # statistics_table_sql = """
- # CREATE TABLE IF NOT EXISTS statistics (
- # id integer PRIMARY KEY,
- # title text NOT NULL,
- # number integer
- # ); """
- settings_table_sql = """
- CREATE TABLE IF NOT EXISTS settings (
- id integer PRIMARY KEY,
- key text NOT NULL,
- value integer
- ); """
+ feeds_table_sql =(
+ "CREATE TABLE IF NOT EXISTS feeds ("
+ "id INTEGER PRIMARY KEY,"
+ "name TEXT,"
+ "address TEXT NOT NULL,"
+ "enabled INTEGER NOT NULL,"
+ "scanned TEXT,"
+ "updated TEXT,"
+ "status INTEGER,"
+ "valid INTEGER"
+ ");"
+ )
+ entries_table_sql = (
+ "CREATE TABLE IF NOT EXISTS entries ("
+ "id INTEGER PRIMARY KEY,"
+ "title TEXT NOT NULL,"
+ "summary TEXT NOT NULL,"
+ "link TEXT NOT NULL,"
+ "entry_id TEXT,"
+ "source TEXT NOT NULL,"
+ "timestamp TEXT,"
+ "read INTEGER"
+ ");"
+ )
+ archive_table_sql = (
+ "CREATE TABLE IF NOT EXISTS archive ("
+ "id INTEGER PRIMARY KEY,"
+ "title TEXT NOT NULL,"
+ "summary TEXT NOT NULL,"
+ "link TEXT NOT NULL,"
+ "entry_id TEXT,"
+ "source TEXT NOT NULL,"
+ "timestamp TEXT,"
+ "read INTEGER"
+ ");"
+ )
+ # statistics_table_sql = (
+ # "CREATE TABLE IF NOT EXISTS statistics ("
+ # "id INTEGER PRIMARY KEY,"
+ # "title TEXT NOT NULL,"
+ # "number INTEGER"
+ # ");"
+ # )
+ settings_table_sql = (
+ "CREATE TABLE IF NOT EXISTS settings ("
+ "id INTEGER PRIMARY KEY,"
+ "key TEXT NOT NULL,"
+ "value INTEGER"
+ ");"
+ )
cur = conn.cursor()
# cur = get_cursor(db_file)
cur.execute(feeds_table_sql)
cur.execute(entries_table_sql)
+ cur.execute(archive_table_sql)
# cur.execute(statistics_table_sql)
cur.execute(settings_table_sql)
@@ -90,8 +135,15 @@ def get_cursor(db_file):
"""
Allocate a cursor to connection per database.
- :param db_file: Database filename.
- :return: Cursor.
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+
+ Returns
+ -------
+ CURSORS[db_file] : object
+ Cursor.
"""
if db_file in CURSORS:
return CURSORS[db_file]
@@ -102,15 +154,25 @@ def get_cursor(db_file):
return CURSORS[db_file]
-async def add_feed(db_file, title, url, res):
+async def add_feed(db_file, url, title=None, status=None):
"""
Add a new feed into the feeds table.
- :param db_file: Database filename.
- :param title: Feed title.
- :param url: URL.
- :param res: XML document.
- :return: Message.
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ url : str
+ URL.
+ title : str, optional
+ Feed Title. The default is None.
+ status : str, optional
+ HTTP status code. The default is None.
+
+ Returns
+ -------
+ msg : str
+ Message.
"""
#TODO consider async with DBLOCK
#conn = create_connection(db_file)
@@ -120,7 +182,7 @@ async def add_feed(db_file, title, url, res):
# exist = await check_feed_exist(db_file, url)
# if not exist:
- # res = await main.download_feed(url)
+ # status = await main.download_feed(url)
# else:
# return "News source is already listed in the subscription list"
@@ -128,44 +190,78 @@ async def add_feed(db_file, title, url, res):
with create_connection(db_file) as conn:
cur = conn.cursor()
# title = feed["feed"]["title"]
- feed = (title, url, 1, res[1], 1)
- sql = """INSERT INTO feeds(name, address, enabled, status, valid)
- VALUES(?, ?, ?, ?, ?) """
+ feed = (title, url, 1, status, 1)
+ sql = (
+ "INSERT INTO feeds("
+ "name, address, enabled, status, valid"
+ ")"
+ "VALUES(?, ?, ?, ?, ?) "
+ )
cur.execute(sql, feed)
source = title if title else '<' + url + '>'
- msg = """> {}\nNews source \"{}\" has been added to subscription list.
- """.format(url, source)
+ msg = (
+ "> {}\nNews source \"{}\" has been added "
+ "to subscription list."
+ ).format(url, source)
return msg
async def remove_feed(db_file, ix):
"""
- Delete a feed by feed id.
+ Delete a feed by feed ID.
- :param db_file: Database filename.
- :param ix: Index of feed.
- :return: Message.
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ ix : str
+ Index of feed.
+
+ Returns
+ -------
+ msg : str
+ Message.
"""
with create_connection(db_file) as conn:
async with DBLOCK:
cur = conn.cursor()
try:
- sql = "SELECT address FROM feeds WHERE id = ?"
+ sql = (
+ "SELECT address "
+ "FROM feeds "
+ "WHERE id = ?"
+ )
# cur
# for i in url:
# url = i[0]
url = cur.execute(sql, (ix,)).fetchone()[0]
- sql = "SELECT name FROM feeds WHERE id = ?"
+ sql = (
+ "SELECT name "
+ "FROM feeds "
+ "WHERE id = ?"
+ )
name = cur.execute(sql, (ix,)).fetchone()[0]
# NOTE Should we move DBLOCK to this line? 2022-12-23
- sql = "DELETE FROM entries WHERE source = ?"
+ sql = (
+ "DELETE "
+ "FROM entries "
+ "WHERE source = ?"
+ )
cur.execute(sql, (url,))
- sql = "DELETE FROM feeds WHERE id = ?"
+ sql = (
+ "DELETE FROM feeds "
+ "WHERE id = ?"
+ )
cur.execute(sql, (ix,))
- msg = "> {}\nNews source \"{}\" has been removed from subscription list.".format(url, name)
+ msg = (
+ "> {}\nNews source \"{}\" has been removed "
+ "from subscription list."
+ ).format(url, name)
except:
- msg = "No news source with ID {}.".format(ix)
+ msg = (
+ "No news source with ID {}."
+ ).format(ix)
return msg
@@ -174,27 +270,50 @@ async def check_feed_exist(db_file, url):
Check whether a feed exists.
Query for feeds by given url.
- :param db_file: Database filename.
- :param url: URL.
- :return: Index ID and Name or None.
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ url : str
+ URL.
+
+ Returns
+ -------
+ result : list
+ List of ID and Name of feed.
"""
cur = get_cursor(db_file)
- sql = "SELECT id, name FROM feeds WHERE address = ?"
+ sql = (
+ "SELECT id, name "
+ "FROM feeds "
+ "WHERE address = ?"
+ )
result = cur.execute(sql, (url,)).fetchone()
return result
-async def get_number_of_items(db_file, str):
+async def get_number_of_items(db_file, table):
"""
Return number of entries or feeds.
- :param cur: Cursor object.
- :param str: "entries" or "feeds".
- :return: Number of rows.
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ table : str
+ "entries" or "feeds".
+
+ Returns
+ -------
+ count : ?
+ Number of rows.
"""
with create_connection(db_file) as conn:
cur = conn.cursor()
- sql = "SELECT count(id) FROM {}".format(str)
+ sql = (
+ "SELECT count(id) "
+ "FROM {}"
+ ).format(table)
count = cur.execute(sql).fetchone()[0]
return count
@@ -203,13 +322,23 @@ async def get_number_of_feeds_active(db_file):
"""
Return number of active feeds.
- :param db_file: Database filename.
- :param cur: Cursor object.
- :return: Number of rows.
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+
+ Returns
+ -------
+ count : ?
+ Number of rows.
"""
with create_connection(db_file) as conn:
cur = conn.cursor()
- sql = "SELECT count(id) FROM feeds WHERE enabled = 1"
+ sql = (
+ "SELECT count(id) "
+ "FROM feeds "
+ "WHERE enabled = 1"
+ )
count = cur.execute(sql).fetchone()[0]
return count
@@ -217,54 +346,124 @@ async def get_number_of_feeds_active(db_file):
async def get_number_of_entries_unread(db_file):
"""
Return number of unread items.
-
- :param db_file: Database filename.
- :param cur: Cursor object.
- :return: Number of rows.
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+
+ Returns
+ -------
+ count : ?
+ Number of rows.
"""
with create_connection(db_file) as conn:
cur = conn.cursor()
- sql = "SELECT count(id) FROM entries WHERE read = 0"
+ sql = (
+ "SELECT count(id) "
+ "FROM entries "
+ "WHERE read = 0"
+ )
count = cur.execute(sql).fetchone()[0]
return count
-async def get_entry_unread(db_file):
+# TODO Read from entries and archives
+async def get_entry_unread(db_file, num=None):
"""
- Check read status of entry.
-
- :param db_file: Database filename.
- :return: News item as message.
+ Extract information from unread entries.
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ num : str, optional
+ Number. The default is None.
+
+ Returns
+ -------
+ entry : str
+ News item message.
"""
+ if not num:
+ num = await get_settings_value(db_file, "quantum")
+ else:
+ num = int(num)
with create_connection(db_file) as conn:
cur = conn.cursor()
- sql = "SELECT id FROM entries WHERE read = 0"
- ix = cur.execute(sql).fetchone()
- if ix is None:
- return False
- ix = ix[0]
- sql = "SELECT title FROM entries WHERE id = :id"
- title = cur.execute(sql, (ix,)).fetchone()[0]
- sql = "SELECT summary FROM entries WHERE id = :id"
- summary = cur.execute(sql, (ix,)).fetchone()[0]
- sql = "SELECT link FROM entries WHERE id = :id"
- link = cur.execute(sql, (ix,)).fetchone()[0]
- entry = "{}\n\n{}\n\n{}".format(title, summary, link)
- async with DBLOCK:
- await mark_as_read(cur, ix)
- # async with DBLOCK:
- # await update_statistics(db_file)
- return entry
+ # sql = "SELECT id FROM entries WHERE read = 0 LIMIT 1"
+ # sql = "SELECT id FROM entries WHERE read = 0 ORDER BY timestamp DESC LIMIT 1"
+ sql = (
+ "SELECT id, title, summary, link "
+ "FROM entries "
+ "WHERE read = 0 "
+ "ORDER BY timestamp "
+ "DESC LIMIT :num"
+ )
+ results = cur.execute(sql, (num,))
+ results = results.fetchall()
+
+ # TODO Add filtering
+ # TODO Do this when entry is added to list and mark it as read
+ # DONE!
+ # results = []
+ # if get_settings_value(db_file, "filter-deny"):
+ # while len(results) < num:
+ # result = cur.execute(sql).fetchone()
+ # blacklist = await get_settings_value(db_file, "filter-deny").split(",")
+ # for i in blacklist:
+ # if i in result[1]:
+ # continue
+ # print("rejected:", result[1])
+ # print("accepted:", result[1])
+ # results.extend([result])
+
+ # news_list = "You've got {} news items:\n".format(num)
+ news_list = ""
+ # NOTE Why doesn't this work without list?
+ # i.e. for result in results
+ # for result in results.fetchall():
+ for result in results:
+ ix = result[0]
+ title = result[1]
+ summary = result[2]
+ link = result[3]
+ if num > 1:
+ news_list += (
+ "\n{}\n{}\n"
+ ).format(
+ str(title),
+ str(link)
+ )
+ else:
+ news_list = (
+ "{}\n\n{}\n\n{}"
+ ).format(
+ str(title),
+ str(summary),
+ str(link)
+ )
+ async with DBLOCK:
+ await mark_as_read(cur, ix)
+ return news_list
async def mark_as_read(cur, ix):
"""
Set read status of entry.
-
- :param cur: Cursor object.
- :param ix: Index of entry.
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ ix : str
+ Index of entry.
"""
- sql = "UPDATE entries SET summary = '', read = 1 WHERE id = ?"
+ sql = (
+ "UPDATE entries "
+ "SET summary = '', read = 1 "
+ "WHERE id = ?"
+ )
cur.execute(sql, (ix,))
@@ -272,8 +471,15 @@ async def statistics(db_file):
"""
Return table statistics.
- :param db_file: Database filename.
- :return: News item as message.
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+
+ Returns
+ -------
+ msg : str
+ Statistics as message.
"""
feeds = await get_number_of_items(db_file, 'feeds')
active_feeds = await get_number_of_feeds_active(db_file)
@@ -283,57 +489,108 @@ async def statistics(db_file):
# """.format(unread_entries, entries, feeds)
with create_connection(db_file) as conn:
cur = conn.cursor()
- sql = "SELECT value FROM settings WHERE key = \"enabled\""
- status = cur.execute(sql).fetchone()[0]
- sql = "SELECT value FROM settings WHERE key = \"interval\""
- interval = cur.execute(sql).fetchone()[0]
- msg = """News items: {} ({})\nNews sources: {} ({})\nUpdate interval: {}\nOperation status: {}
- """.format(unread_entries, entries, active_feeds, feeds, interval, status)
+ keys = []
+ for key in ["enabled", "interval", "quantum"]:
+ sql = (
+ "SELECT value "
+ "FROM settings "
+ "WHERE key = ?"
+ )
+ keys.extend([cur.execute(sql, (key,)).fetchone()[0]])
+ msg = (
+ "```\n"
+ "News items : {} ({})\n"
+ "News sources : {} ({})\n"
+ "Update interval : {}\n"
+ "Items per update : {}\n"
+ "Operation status : {}\n"
+ "```"
+ ).format(
+ unread_entries, entries,
+ active_feeds, feeds,
+ keys[1],
+ keys[2],
+ keys[0]
+ )
return msg
-#TODO statistics
async def update_statistics(cur):
"""
Update table statistics.
-
- :param cur: Cursor object.
+
+ Parameters
+ ----------
+ cur : object
+ Cursor object.
"""
stat_dict = {}
stat_dict["feeds"] = await get_number_of_items(cur, 'feeds')
stat_dict["entries"] = await get_number_of_items(cur, 'entries')
stat_dict["unread"] = await get_number_of_entries_unread(cur=cur)
for i in stat_dict:
- sql = "SELECT id FROM statistics WHERE title = ?"
+ sql = (
+ "SELECT id "
+ "FROM statistics "
+ "WHERE title = ?"
+ )
cur.execute(sql, (i,))
if cur.fetchone():
- sql = "UPDATE statistics SET number = :num WHERE title = :title"
- cur.execute(sql, {"title": i, "num": stat_dict[i]})
+ sql = (
+ "UPDATE statistics "
+ "SET number = :num "
+ "WHERE title = :title"
+ )
+ cur.execute(sql, {
+ "title": i,
+ "num": stat_dict[i]
+ })
else:
- sql = "SELECT count(id) FROM statistics"
+ sql = (
+ "SELECT count(id) "
+ "FROM statistics"
+ )
count = cur.execute(sql).fetchone()[0]
ix = count + 1
- sql = "INSERT INTO statistics VALUES(?,?,?)"
+ sql = (
+ "INSERT INTO statistics "
+ "VALUES(?,?,?)"
+ )
cur.execute(sql, (ix, i, stat_dict[i]))
-# TODO mark_all_read for entries of feed
async def toggle_status(db_file, ix):
"""
Toggle status of feed.
-
- :param db_file: Database filename.
- :param ix: Index of entry.
- :return: Message
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ ix : str
+ Index of entry.
+
+ Returns
+ -------
+ msg : str
+ Message.
"""
async with DBLOCK:
with create_connection(db_file) as conn:
cur = conn.cursor()
try:
#cur = get_cursor(db_file)
- sql = "SELECT name FROM feeds WHERE id = :id"
+ sql = (
+ "SELECT name "
+ "FROM feeds "
+ "WHERE id = :id"
+ )
title = cur.execute(sql, (ix,)).fetchone()[0]
- sql = "SELECT enabled FROM feeds WHERE id = ?"
+ sql = (
+ "SELECT enabled "
+ "FROM feeds "
+ "WHERE id = ?"
+ )
# NOTE [0][1][2]
status = cur.execute(sql, (ix,)).fetchone()[0]
# FIXME always set to 1
@@ -345,11 +602,22 @@ async def toggle_status(db_file, ix):
else:
status = 1
state = "enabled"
- sql = "UPDATE feeds SET enabled = :status WHERE id = :id"
- cur.execute(sql, {"status": status, "id": ix})
- msg = "Updates for '{}' are now {}.".format(title, state)
+ sql = (
+ "UPDATE feeds "
+ "SET enabled = :status "
+ "WHERE id = :id"
+ )
+ cur.execute(sql, {
+ "status": status,
+ "id": ix
+ })
+ msg = (
+ "Updates for '{}' are now {}."
+ ).format(title, state)
except:
- msg = "No news source with ID {}.".format(ix)
+ msg = (
+ "No news source with ID {}."
+ ).format(ix)
return msg
@@ -357,18 +625,38 @@ async def set_date(cur, url):
"""
Set last update date of feed.
- :param cur: Cursor object.
- :param url: URL.
+ Parameters
+ ----------
+ cur : object
+ Cursor object.
+ url : str
+ URL.
"""
today = date.today()
- sql = "UPDATE feeds SET updated = :today WHERE address = :url"
+ sql = (
+ "UPDATE feeds "
+ "SET updated = :today "
+ "WHERE address = :url"
+ )
# cur = conn.cursor()
- cur.execute(sql, {"today": today, "url": url})
+ cur.execute(sql, {
+ "today": today,
+ "url": url
+ })
async def add_entry_and_set_date(db_file, source, entry):
"""
- TODO
+ Add entry to table entries and set date of source in table feeds.
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ source : str
+ Feed URL.
+ entry : list
+ Entry properties.
"""
async with DBLOCK:
with create_connection(db_file) as conn:
@@ -379,49 +667,102 @@ async def add_entry_and_set_date(db_file, source, entry):
async def update_source_status(db_file, status, source):
"""
- TODO
+ Set HTTP status of source in table feeds.
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ source : str
+ Feed URL.
+ status : str
+ Status ID or message.
"""
- sql = "UPDATE feeds SET status = :status, scanned = :scanned WHERE address = :url"
+ sql = (
+ "UPDATE feeds "
+ "SET status = :status, scanned = :scanned "
+ "WHERE address = :url"
+ )
async with DBLOCK:
with create_connection(db_file) as conn:
cur = conn.cursor()
- cur.execute(sql, {"status": status, "scanned": date.today(), "url": source})
+ cur.execute(sql, {
+ "status" : status,
+ "scanned" : date.today(),
+ "url" : source
+ })
async def update_source_validity(db_file, source, valid):
"""
- TODO
+ Set validity status of source in table feeds.
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ source : str
+ Feed URL.
+ valid : boolean
+ 0 or 1.
"""
- sql = "UPDATE feeds SET valid = :validity WHERE address = :url"
+ sql = (
+ "UPDATE feeds "
+ "SET valid = :validity "
+ "WHERE address = :url"
+ )
async with DBLOCK:
with create_connection(db_file) as conn:
cur = conn.cursor()
- cur.execute(sql, {"validity": valid, "url": source})
+ cur.execute(sql, {
+ "validity": valid,
+ "url": source
+ })
async def add_entry(cur, entry):
"""
- Add a new entry into the entries table.
+ Add a new entry row into the entries table.
- :param cur: Cursor object.
- :param entry:
+ Parameters
+ ----------
+ cur : object
+ Cursor object.
+ entry : str
+ Entry properties.
"""
- sql = """ INSERT INTO entries(title, summary, link, source, read)
- VALUES(?, ?, ?, ?, ?) """
+ sql = (
+ "INSERT "
+ "INTO entries("
+ "title, "
+ "summary, "
+ "link, "
+ "entry_id, "
+ "source, "
+ "timestamp, "
+ "read"
+ ") "
+ "VALUES(?, ?, ?, ?, ?, ?, ?)"
+ )
cur.execute(sql, entry)
-# This function doesn't work as expected with bbs and wiki feeds
+# NOTE See remove_nonexistent_entries
+# NOTE This function doesn't work as expected with bbs and docuwiki feeds
async def remove_entry(db_file, source, length):
"""
Maintain list of entries equal to feed.
Check the number returned by feed and delete
existing entries up to the same returned amount.
-
- :param db_file: Database filename.
- :param source:
- :param length:
- :return:
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ source : str
+ Feed URL.
+ length : str
+ Number.
"""
# FIXED
# Dino empty titles are not counted https://dino.im/index.xml
@@ -431,108 +772,242 @@ async def remove_entry(db_file, source, length):
async with DBLOCK:
with create_connection(db_file) as conn:
cur = conn.cursor()
- sql = "SELECT count(id) FROM entries WHERE source = ?"
+ sql = (
+ "SELECT count(id) "
+ "FROM entries "
+ "WHERE source = ?"
+ )
count = cur.execute(sql, (source,)).fetchone()[0]
limit = count - length
if limit:
limit = limit;
- sql = """DELETE FROM entries WHERE id IN (
- SELECT id FROM entries
- WHERE source = :source
- ORDER BY id
- ASC LIMIT :limit)"""
- cur.execute(sql, {"source": source, "limit": limit})
+ sql = (
+ "DELETE FROM entries "
+ "WHERE id "
+ "IN (SELECT id "
+ "FROM entries "
+ "WHERE source = :source "
+ "ORDER BY id "
+ "ASC LIMIT :limit)"
+ )
+ cur.execute(sql, {
+ "source": source,
+ "limit": limit
+ })
+# TODO Move entries that don't exist into table archive.
+# NOTE Entries that are read from archive are deleted.
+# NOTE Unlike entries from table entries, entries from
+# table archive are not marked as read.
async def remove_nonexistent_entries(db_file, feed, source):
"""
Remove entries that don't exist in a given parsed feed.
Check the entries returned from feed and delete non
existing entries
- :param db_file: Database filename.
- :param feed: URL of parsed feed.
- :param source: URL of associated feed.
- """
- async with DBLOCK:
- with create_connection(db_file) as conn:
- cur = conn.cursor()
- sql = "SELECT id, title, link FROM entries WHERE source = ?"
- entries_db = cur.execute(sql, (source,)).fetchall()
- for entry_db in entries_db:
- exist = False
- for entry_feed in feed.entries:
- # TODO better check and don't repeat code
- if entry_feed.has_key("title"):
- title = entry_feed.title
- else:
- title = feed["feed"]["title"]
-
- if entry_feed.has_key("link"):
- link = entry_feed.link
- else:
- link = source
- # TODO better check and don't repeat code
- if entry_db[1] == title and entry_db[2] == link:
- exist = True
- break
- if not exist:
- # TODO Send to table archive
- # TODO Also make a regular/routine check for sources that have been changed (though that can only happen when manually editing)
- sql = "DELETE FROM entries WHERE id = ?"
- cur.execute(sql, (entry_db[0],))
-
-
-async def get_subscriptions(db_file):
- """
- Query table feeds.
-
- :param db_file: Database filename.
- :return: List of feeds.
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ feed : list
+ Parsed feed document.
+ source : str
+ Feed URL. URL of associated feed.
"""
with create_connection(db_file) as conn:
cur = conn.cursor()
- sql = "SELECT address FROM feeds WHERE enabled = 1"
+ sql = (
+ "SELECT id, title, link, entry_id, timestamp, read "
+ "FROM entries "
+ "WHERE source = ?"
+ )
+ items = cur.execute(sql, (source,)).fetchall()
+ entries = feed.entries
+ for entry in entries:
+ valid = False
+ for item in items:
+ # TODO better check and don't repeat code
+ if entry.has_key("id") and item[3]:
+ if entry.id == item[3]:
+ valid = True
+ break
+ else:
+ if entry.has_key("title"):
+ title = entry.title
+ else:
+ title = feed["feed"]["title"]
+ if entry.has_key("link"):
+ link = await datahandler.join_url(source, entry.link)
+ else:
+ link = source
+ if entry.has_key("published") and item[4]:
+ time = await datetimehandler.rfc2822_to_iso8601(entry.published)
+ if (item[1] == title and
+ item[2] == link and
+ item[4] == time):
+ valid = True
+ break
+ else:
+ if (item[1] == title and
+ item[2] == link):
+ valid = True
+ break
+ # TODO better check and don't repeat code
+ if not valid:
+ async with DBLOCK:
+ # TODO Send to table archive
+ # TODO Also make a regular/routine check for sources that
+ # have been changed (though that can only happen when
+ # manually editing)
+ ix = item[0]
+ if item[5] == 1:
+ sql = (
+ "DELETE "
+ "FROM entries "
+ "WHERE id = :ix"
+ )
+ cur.execute(sql, (ix,))
+ else:
+ print(">>> ARCHIVING:")
+ print("title:", item[1])
+ print("link :", item[2])
+ print("id :", item[3])
+ sql = (
+ "INSERT "
+ "INTO archive "
+ "SELECT * "
+ # "SELECT title, summary, "
+ # "link, source, timestamp "
+ "FROM entries "
+ "WHERE entries.id = :ix"
+ )
+ cur.execute(sql, (ix,))
+ sql = (
+ "DELETE "
+ "FROM entries "
+ "WHERE id = :ix"
+ )
+ cur.execute(sql, (ix,))
+
+
+async def get_feeds(db_file):
+ """
+ Query table feeds for Title, URL, Categories, Tags.
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+
+ Returns
+ -------
+ result : list
+ Title, URL, Categories, Tags of feeds.
+ """
+ with create_connection(db_file) as conn:
+ cur = conn.cursor()
+ sql = (
+ "SELECT name, address, type, categories, tags "
+ "FROM feeds"
+ )
result = cur.execute(sql).fetchall()
return result
-async def list_subscriptions(db_file):
+async def get_feeds_url(db_file):
+ """
+ Query active feeds for URLs.
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+
+ Returns
+ -------
+ result : list
+ URLs of active feeds.
+ """
+ with create_connection(db_file) as conn:
+ cur = conn.cursor()
+ sql = (
+ "SELECT address "
+ "FROM feeds "
+ "WHERE enabled = 1"
+ )
+ result = cur.execute(sql).fetchall()
+ return result
+
+
+async def list_feeds(db_file):
"""
Query table feeds and list items.
- :param db_file: Database filename.
- :return: List of feeds.
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+
+ Returns
+ -------
+ msg : str
+ URLs of feeds as message.
"""
cur = get_cursor(db_file)
- sql = "SELECT name, address, updated, id, enabled FROM feeds"
+ sql = (
+ "SELECT name, address, updated, enabled, id "
+ "FROM feeds"
+ )
results = cur.execute(sql)
-
- feeds_list = "List of subscriptions: \n"
+ feeds_list = "\nList of subscriptions:\n```"
counter = 0
for result in results:
counter += 1
- feeds_list += """\n{} \n{} \nLast updated: {} \nID: {} [{}]
- """.format(str(result[0]), str(result[1]), str(result[2]),
- str(result[3]), str(result[4]))
+ feeds_list += (
+ "Name : {}\n"
+ "Address : {}\n"
+ "Updated : {}\n"
+ "Status : {}\n"
+ "ID : {}\n"
+ "\n"
+ ).format(
+ str(result[0]),
+ str(result[1]),
+ str(result[2]),
+ str(result[3]),
+ str(result[4])
+ )
if counter:
- return feeds_list + "\n Total of {} subscriptions".format(counter)
+ return feeds_list + (
+ "```\nTotal of {} subscriptions.\n"
+ ).format(counter)
else:
- msg = ("List of subscriptions is empty. \n"
- "To add feed, send a message as follows: \n"
- "feed add URL \n"
- "Example: \n"
- "add https://reclaimthenet.org/feed/")
+ msg = (
+ "List of subscriptions is empty.\n"
+ "To add feed, send a URL\n"
+ "Try these:\n"
+ # TODO Pick random from featured/recommended
+ "https://reclaimthenet.org/feed/"
+ )
return msg
async def last_entries(db_file, num):
"""
Query entries
-
- :param db_file: Database filename.
- :param num: Number
- :return: List of recent N entries
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ num : str
+ Number.
+
+ Returns
+ -------
+ titles_list : str
+ List of recent N entries as message.
"""
num = int(num)
if num > 50:
@@ -540,81 +1015,194 @@ async def last_entries(db_file, num):
elif num < 1:
num = 1
cur = get_cursor(db_file)
- sql = "SELECT title, link FROM entries ORDER BY ROWID DESC LIMIT :num"
+ # sql = "SELECT title, link FROM entries ORDER BY ROWID DESC LIMIT :num"
+ sql = (
+ "SELECT title, link "
+ "FROM entries "
+ "WHERE read = 0 "
+ "ORDER BY timestamp "
+ "DESC LIMIT :num "
+ )
results = cur.execute(sql, (num,))
-
-
- titles_list = "Recent {} titles: \n".format(num)
+ titles_list = "Recent {} titles:\n".format(num)
for result in results:
- titles_list += "\n{} \n{}".format(str(result[0]), str(result[1]))
+ titles_list += (
+ "\n{}\n{}\n"
+ ).format(
+ str(result[0]),
+ str(result[1])
+ )
return titles_list
+async def search_feeds(db_file, query):
+ """
+ Query feeds.
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ query : str
+ Search query.
+
+ Returns
+ -------
+ titles_list : str
+ Feeds of specified keywords as message.
+ """
+ cur = get_cursor(db_file)
+ sql = (
+ "SELECT name, id, address "
+ "FROM feeds "
+ "WHERE name LIKE ? "
+ "LIMIT 50"
+ )
+ results = cur.execute(sql, [f'%{query}%'])
+ results_list = (
+ "Feeds containing '{}':\n```"
+ ).format(query)
+ counter = 0
+ for result in results:
+ counter += 1
+ results_list += (
+ "\n{} [{}]\n{}\n"
+ ).format(
+ str(result[0]),
+ str(result[1]),
+ str(result[2])
+ )
+ if counter:
+ return results_list + "\n```\nTotal of {} feeds".format(counter)
+ else:
+ return "No feeds found for: {}".format(query)
+
+
async def search_entries(db_file, query):
"""
- Query entries
-
- :param db_file: Database filename.
- :param query: Search query
- :return: Entries with specified keywords
+ Query entries.
+
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ query : str
+ Search query.
+
+ Returns
+ -------
+ titles_list : str
+ Entries of specified keywords as message.
"""
- if len(query) < 2:
- return "Please enter at least 2 characters to search"
-
cur = get_cursor(db_file)
- sql = "SELECT title, link FROM entries WHERE title LIKE ? LIMIT 50"
+ sql = (
+ "SELECT title, link "
+ "FROM entries "
+ "WHERE title LIKE ? "
+ "LIMIT 50"
+ )
results = cur.execute(sql, [f'%{query}%'])
-
- results_list = "Search results for '{}': \n".format(query)
+ results_list = (
+ "Search results for '{}':\n```"
+ ).format(query)
counter = 0
for result in results:
counter += 1
- results_list += """\n{} \n{}
- """.format(str(result[0]), str(result[1]))
+ results_list += (
+ "\n{}\n{}\n"
+ ).format(
+ str(result[0]),
+ str(result[1])
+ )
if counter:
- return results_list + "\n Total of {} results".format(counter)
+ return results_list + "```\nTotal of {} results".format(counter)
else:
return "No results found for: {}".format(query)
-async def check_entry_exist(db_file, title, link):
+async def check_entry_exist(db_file, source, eid=None,
+ title=None, link=None, date=None):
"""
Check whether an entry exists.
- Query entries by title and link.
+ If entry has an ID, check by ID.
+ If entry has timestamp, check by title, link and date.
+ Otherwise, check by title and link.
- :param db_file: Database filename.
- :param link: Entry URL.
- :param title: Entry title.
- :return: Index ID or None.
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ source : str
+ Feed URL. URL of associated feed.
+ eid : str, optional
+ Entry ID. The default is None.
+ title : str, optional
+ Entry title. The default is None.
+ link : str, optional
+ Entry URL. The default is None.
+ date : str, optional
+ Entry Timestamp. The default is None.
+
+ Returns
+ -------
+ bool
+ True or None.
"""
cur = get_cursor(db_file)
- sql = "SELECT id FROM entries WHERE title = :title and link = :link"
- result = cur.execute(sql, {"title": title, "link": link}).fetchone()
- return result
+ if eid:
+ sql = (
+ "SELECT id "
+ "FROM entries "
+ "WHERE entry_id = :eid and source = :source"
+ )
+ result = cur.execute(sql, {
+ "eid": eid,
+ "source": source
+ }).fetchone()
+ elif date:
+ sql = (
+ "SELECT id "
+ "FROM entries "
+ "WHERE "
+ "title = :title and "
+ "link = :link and "
+ "timestamp = :date"
+ )
+ result = cur.execute(sql, {
+ "title": title,
+ "link": link,
+ "timestamp": date
+ }).fetchone()
+ else:
+ sql = (
+ "SELECT id "
+ "FROM entries "
+ "WHERE title = :title and link = :link"
+ )
+ result = cur.execute(sql, {
+ "title": title,
+ "link": link
+ }).fetchone()
+ if result:
+ return True
+ else:
+ None
-# TODO dictionary
-# settings = {
-# "enabled" : {
-# "message": "Updates are {}".format(status),
-# "value": val
-# },
-# "interval" : {
-# "message": "Updates will be sent every {} minutes".format(val),
-# "value": val
-# },
-# "quantom" : {
-# "message": "Every updates will contain {} news items".format(val),
-# "value": val
-# }
-# }
async def set_settings_value(db_file, key_value):
"""
Set settings value.
- :param db_file: Database filename.
- :param key_value: List of key ("enabled", "interval", "quantum") and value (Integer).
- :return: Message.
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ key_value : list
+ key : str
+ enabled, filter-allow, filter-deny,
+ interval, master, quantum, random.
+ value : int
+ Numeric value.
"""
# if isinstance(key_value, list):
# key = key_value[0]
@@ -631,22 +1219,34 @@ async def set_settings_value(db_file, key_value):
with create_connection(db_file) as conn:
cur = conn.cursor()
await set_settings_value_default(cur, key)
- sql = "UPDATE settings SET value = :value WHERE key = :key"
- cur.execute(sql, {"key": key, "value": val})
- if key == 'quantum':
- msg = "Each update will contain {} news items.".format(val)
- elif key == 'interval':
- msg = "Updates will be sent every {} minutes.".format(val)
- else:
- if val:
- status = "disabled"
- else:
- status = "enabled"
- msg = "Updates are {}.".format(status)
- return msg
+ sql = (
+ "UPDATE settings "
+ "SET value = :value "
+ "WHERE key = :key"
+ )
+ cur.execute(sql, {
+ "key": key,
+ "value": val
+ })
+# TODO Place settings also in a file
async def set_settings_value_default(cur, key):
+ """
+ Set default settings value.
+
+ Parameters
+ ----------
+ cur : object
+ Cursor object.
+ key : str
+ Key: enabled, interval, master, quantum, random.
+
+ Returns
+ -------
+ val : str
+ Numeric value.
+ """
# async def set_settings_value_default(cur):
# keys = ["enabled", "interval", "quantum"]
# for i in keys:
@@ -656,11 +1256,19 @@ async def set_settings_value_default(cur, key):
# val = await settings.get_value_default(i)
# sql = "INSERT INTO settings(key,value) VALUES(?,?)"
# cur.execute(sql, (i, val))
- sql = "SELECT id FROM settings WHERE key = ?"
+ sql = (
+ "SELECT id "
+ "FROM settings "
+ "WHERE key = ?"
+ )
cur.execute(sql, (key,))
if not cur.fetchone():
val = await confighandler.get_value_default(key)
- sql = "INSERT INTO settings(key,value) VALUES(?,?)"
+ sql = (
+ "INSERT "
+ "INTO settings(key,value) "
+ "VALUES(?,?)"
+ )
cur.execute(sql, (key, val))
return val
@@ -669,8 +1277,17 @@ async def get_settings_value(db_file, key):
"""
Get settings value.
- :param db_file: Database filename.
- :param key: "enabled", "interval", "quantum".
+ Parameters
+ ----------
+ db_file : str
+ Path to database file.
+ key : str
+ Key: "enabled", "interval", "master", "quantum", "random".
+
+ Returns
+ -------
+ val : str
+ Numeric value.
"""
# try:
# with create_connection(db_file) as conn:
@@ -686,10 +1303,14 @@ async def get_settings_value(db_file, key):
with create_connection(db_file) as conn:
try:
cur = conn.cursor()
- sql = "SELECT value FROM settings WHERE key = ?"
- result = cur.execute(sql, (key,)).fetchone()[0]
+ sql = (
+ "SELECT value "
+ "FROM settings "
+ "WHERE key = ?"
+ )
+ val = cur.execute(sql, (key,)).fetchone()[0]
except:
- result = await set_settings_value_default(cur, key)
- if not result:
- result = await set_settings_value_default(cur, key)
- return result
+ val = await set_settings_value_default(cur, key)
+ if not val:
+ val = await set_settings_value_default(cur, key)
+ return val
diff --git a/slixfeed/xmpphandler.py b/slixfeed/xmpphandler.py
index 92d5dd6..815c44b 100644
--- a/slixfeed/xmpphandler.py
+++ b/slixfeed/xmpphandler.py
@@ -1,38 +1,56 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
-from datetime import datetime
+"""
+
+TODO
+
+1) Deprecate "add" (see above) and make it interactive.
+ Slixfeed: Do you still want to add this URL to subscription list?
+ See: case _ if message_lowercase.startswith("add"):
+
+2) Use loop (with gather) instead of TaskGroup
+
+"""
import asyncio
import os
import slixmpp
+from slixmpp.plugins.xep_0363.http_upload import FileTooBig, HTTPError, UploadServiceNotFound
+
import confighandler
import datahandler
+import datetimehandler
+import filterhandler
import sqlitehandler
+main_task = []
jid_tasker = {}
task_manager = {}
+loop = asyncio.get_event_loop()
+# asyncio.set_event_loop(loop)
-time_now = datetime.now()
+# time_now = datetime.now()
# time_now = time_now.strftime("%H:%M:%S")
-def print_time():
- # return datetime.now().strftime("%H:%M:%S")
- now = datetime.now()
- current_time = now.strftime("%H:%M:%S")
- return current_time
+# def print_time():
+# # return datetime.now().strftime("%H:%M:%S")
+# now = datetime.now()
+# current_time = now.strftime("%H:%M:%S")
+# return current_time
+
+
+async def handle_event():
+ print("Event handled!")
class Slixfeed(slixmpp.ClientXMPP):
"""
- Slixmpp news bot that will send updates
- from feeds it receives.
+ Slixmpp
+ -------
+ News bot that sends updates from RSS feeds.
"""
-
- print("slixmpp.ClientXMPP")
- print(repr(slixmpp.ClientXMPP))
-
def __init__(self, jid, password):
slixmpp.ClientXMPP.__init__(self, jid, password)
@@ -52,7 +70,7 @@ class Slixfeed(slixmpp.ClientXMPP):
self.add_event_handler("message", self.message)
self.add_event_handler("disconnected", self.reconnect)
# Initialize event loop
- self.loop = asyncio.get_event_loop()
+ # self.loop = asyncio.get_event_loop()
async def start(self, event):
@@ -70,116 +88,316 @@ class Slixfeed(slixmpp.ClientXMPP):
"""
self.send_presence()
await self.get_roster()
- await self.select_file()
- self.send_presence(
- pshow="away",
- pstatus="Slixmpp has been restarted.",
- pto="sch@pimux.de"
- )
+ # for task in main_task:
+ # task.cancel()
+ if not main_task:
+ await self.select_file()
async def message(self, msg):
"""
Process incoming message stanzas. Be aware that this also
includes MUC messages and error messages. It is usually
- a good idea to check the messages's type before processing
- or sending replies.
+ a good practice to check the messages's type before
+ processing or sending replies.
- Arguments:
- msg -- The received message stanza. See the documentation
- for stanza objects and the Message stanza to see
- how it may be used.
+ Parameters
+ ----------
+ self : ?
+ Self.
+ msg : str
+ The received message stanza. See the documentation
+ for stanza objects and the Message stanza to see
+ how it may be used.
"""
if msg["type"] in ("chat", "normal"):
action = 0
jid = msg["from"].bare
+
+ db_dir = confighandler.get_default_dbdir()
+ os.chdir(db_dir)
+ if jid + ".db" not in os.listdir():
+ await self.task_jid(jid)
+
message = " ".join(msg["body"].split())
- message = message.lower()
- if message.startswith("help"):
- action = print_help()
- # NOTE: Might not need it
- # elif message.startswith("add "):
- # url = message[4:]
- elif message.startswith("http"):
- url = message
- action = await initdb(jid, datahandler.add_feed, url)
- # action = "> " + message + "\n" + action
- elif message.startswith("quantum "):
- key = message[:7]
- val = message[8:]
- # action = "Every update will contain {} news items.".format(action)
- action = await initdb(jid, sqlitehandler.set_settings_value, [key, val])
- await self.refresh_task(jid, key, val)
- elif message.startswith("interval "):
- key = message[:8]
- val = message[9:]
- # action = "Updates will be sent every {} minutes.".format(action)
- action = await initdb(jid, sqlitehandler.set_settings_value, [key, val])
- await self.refresh_task(jid, key, val)
- elif message.startswith("list"):
- action = await initdb(jid, sqlitehandler.list_subscriptions)
- elif message.startswith("recent "):
- num = message[7:]
- action = await initdb(jid, sqlitehandler.last_entries, num)
- elif message.startswith("remove "):
- ix = message[7:]
- action = await initdb(jid, sqlitehandler.remove_feed, ix)
- elif message.startswith("search "):
- query = message[7:]
- action = await initdb(jid, sqlitehandler.search_entries, query)
- elif message.startswith("start"):
- # action = "Updates are enabled."
- key = "enabled"
- val = 1
- actiona = await initdb(jid, sqlitehandler.set_settings_value, [key, val])
- asyncio.create_task(self.task_jid(jid))
- # print(print_time(), "task_manager[jid]")
- # print(task_manager[jid])
- elif message.startswith("stats"):
- action = await initdb(jid, sqlitehandler.statistics)
- elif message.startswith("status "):
- ix = message[7:]
- action = await initdb(jid, sqlitehandler.toggle_status, ix)
- elif message.startswith("stop"):
+ message_lowercase = message.lower()
+
+ print(await datetimehandler.current_time(), "ACCOUNT: " + str(msg["from"]))
+ print(await datetimehandler.current_time(), "COMMAND:", message)
+
+ match message_lowercase:
+ case "help":
+ action = print_help()
+ case _ if message_lowercase in ["greetings", "hello", "hey"]:
+ action = (
+ "Greeting! I'm Slixfeed The News Bot!"
+ "\n"
+ "Send a URL of a news website to start."
+ )
+ case _ if message_lowercase.startswith("add"):
+ message = message[4:]
+ url = message.split(" ")[0]
+ title = " ".join(message.split(" ")[1:])
+ if url.startswith("http"):
+ action = await datahandler.initdb(
+ jid,
+ datahandler.add_feed_no_check,
+ [url, title]
+ )
+ await self.send_status(jid)
+ else:
+ action = "Missing URL."
+ case _ if message_lowercase.startswith("allow"):
+ key = "filter-" + message[:5]
+ val = message[6:]
+ if val:
+ keywords = await datahandler.initdb(
+ jid,
+ sqlitehandler.get_settings_value,
+ key
+ )
+ val = await filterhandler.set_filter(
+ val,
+ keywords
+ )
+ await datahandler.initdb(
+ jid,
+ sqlitehandler.set_settings_value,
+ [key, val]
+ )
+ action = (
+ "Approved keywords\n"
+ "```\n{}\n```"
+ ).format(val)
+ else:
+ action = "Missing keywords."
+ case _ if message_lowercase.startswith("deny"):
+ key = "filter-" + message[:4]
+ val = message[5:]
+ if val:
+ keywords = await datahandler.initdb(
+ jid,
+ sqlitehandler.get_settings_value,
+ key
+ )
+ val = await filterhandler.set_filter(
+ val,
+ keywords
+ )
+ await datahandler.initdb(
+ jid,
+ sqlitehandler.set_settings_value,
+ [key, val]
+ )
+ action = (
+ "Rejected keywords\n"
+ "```\n{}\n```"
+ ).format(val)
+ else:
+ action = "Missing keywords."
+ case _ if message_lowercase.startswith("http"):
+ url = message
+ action = await datahandler.initdb(
+ jid,
+ datahandler.add_feed,
+ url
+ )
+ # action = "> " + message + "\n" + action
+ await self.send_status(jid)
+ case _ if message_lowercase.startswith("feeds"):
+ query = message[6:]
+ if query:
+ if len(query) > 3:
+ action = await datahandler.initdb(
+ jid,
+ sqlitehandler.search_feeds,
+ query
+ )
+ else:
+ action = (
+ "Enter at least 4 characters to search"
+ )
+ else:
+ action = await datahandler.initdb(
+ jid,
+ sqlitehandler.list_feeds
+ )
+ case _ if message_lowercase.startswith("interval"):
+ # FIXME
+ # The following error occurs only upon first attempt to set interval.
+ # /usr/lib/python3.11/asyncio/events.py:73: RuntimeWarning: coroutine 'Slixfeed.send_update' was never awaited
+ # self._args = None
+ # RuntimeWarning: Enable tracemalloc to get the object allocation traceback
+ key = message[:8]
+ val = message[9:]
+ if val:
+ # action = (
+ # "Updates will be sent every {} minutes."
+ # ).format(action)
+ await datahandler.initdb(
+ jid,
+ sqlitehandler.set_settings_value,
+ [key, val]
+ )
+ await self.refresh_task(
+ jid,
+ self.send_update,
+ key,
+ val
+ )
+ action = (
+ "Updates will be sent every {} minutes."
+ ).format(val)
+ else:
+ action = "Missing value."
+ case _ if message_lowercase.startswith("next"):
+ num = message[5:]
+ await self.send_update(jid, num)
+ await self.send_status(jid)
+ # await self.refresh_task(jid, key, val)
+ case _ if message_lowercase.startswith("quantum"):
+ key = message[:7]
+ val = message[8:]
+ if val:
+ # action = (
+ # "Every update will contain {} news items."
+ # ).format(action)
+ await datahandler.initdb(
+ jid,
+ sqlitehandler.set_settings_value,
+ [key, val]
+ )
+ action = (
+ "Next update will contain {} news items."
+ ).format(val)
+ else:
+ action = "Missing value."
+ case _ if message_lowercase.startswith("random"):
+ action = "Updates will be sent randomly."
+ case _ if message_lowercase.startswith("recent"):
+ num = message[7:]
+ if num:
+ action = await datahandler.initdb(
+ jid,
+ sqlitehandler.last_entries,
+ num
+ )
+ else:
+ action = "Missing value."
+ case _ if message_lowercase.startswith("remove"):
+ ix = message[7:]
+ if ix:
+ action = await datahandler.initdb(
+ jid,
+ sqlitehandler.remove_feed,
+ ix
+ )
+ await self.send_status(jid)
+ else:
+ action = "Missing feed ID."
+ case _ if message_lowercase.startswith("search"):
+ query = message[7:]
+ if query:
+ if len(query) > 1:
+ action = await datahandler.initdb(
+ jid,
+ sqlitehandler.search_entries,
+ query
+ )
+ else:
+ action = (
+ "Enter at least 2 characters to search"
+ )
+ else:
+ action = "Missing search query."
+ case "start":
+ # action = "Updates are enabled."
+ key = "enabled"
+ val = 1
+ await datahandler.initdb(
+ jid,
+ sqlitehandler.set_settings_value,
+ [key, val]
+ )
+ asyncio.create_task(self.task_jid(jid))
+ action = "Updates are enabled."
+ # print(await datetimehandler.current_time(), "task_manager[jid]")
+ # print(task_manager[jid])
+ case "stats":
+ action = await datahandler.initdb(
+ jid,
+ sqlitehandler.statistics
+ )
+ case _ if message_lowercase.startswith("status "):
+ ix = message[7:]
+ action = await datahandler.initdb(
+ jid,
+ sqlitehandler.toggle_status,
+ ix
+ )
+ case "stop":
+ # FIXME
+ # The following error occurs only upon first attempt to stop.
+ # /usr/lib/python3.11/asyncio/events.py:73: RuntimeWarning: coroutine 'Slixfeed.send_update' was never awaited
+ # self._args = None
+ # RuntimeWarning: Enable tracemalloc to get the object allocation traceback
# action = "Updates are disabled."
- try:
- task_manager[jid]["check"].cancel()
- # task_manager[jid]["status"].cancel()
- task_manager[jid]["interval"].cancel()
+ # try:
+ # # task_manager[jid]["check"].cancel()
+ # # task_manager[jid]["status"].cancel()
+ # task_manager[jid]["interval"].cancel()
+ # key = "enabled"
+ # val = 0
+ # action = await datahandler.initdb(
+ # jid,
+ # sqlitehandler.set_settings_value,
+ # [key, val]
+ # )
+ # except:
+ # action = "Updates are already disabled."
+ # # print("Updates are already disabled. Nothing to do.")
+ # # await self.send_status(jid)
key = "enabled"
val = 0
- actiona = await initdb(jid, sqlitehandler.set_settings_value, [key, val])
- await self.send_status(jid)
- print(print_time(), "task_manager[jid]")
- print(task_manager[jid])
- except:
- # action = "Updates are already disabled."
- await self.send_status(jid)
- else:
- action = "Unknown command. Press \"help\" for list of commands"
+ await datahandler.initdb(
+ jid,
+ sqlitehandler.set_settings_value,
+ [key, val]
+ )
+ await self.task_jid(jid)
+ action = "Updates are disabled."
+ case "support":
+ # TODO Send an invitation.
+ action = "xmpp:slixmpp@muc.poez.io?join"
+ case _:
+ action = (
+ "Unknown command. "
+ "Press \"help\" for list of commands"
+ )
if action: msg.reply(action).send()
- print(print_time(), "COMMAND ACCOUNT")
- print("COMMAND:", message)
- print("ACCOUNT: " + str(msg["from"]))
-
async def select_file(self):
"""
Initiate actions by JID (Jabber ID).
- :param self: Self
+ Parameters
+ ----------
+ self : ?
+ Self.
"""
while True:
db_dir = confighandler.get_default_dbdir()
if not os.path.isdir(db_dir):
- msg = ("Slixfeed can not work without a database. \n"
- "To create a database, follow these steps: \n"
- "Add Slixfeed contact to your roster \n"
- "Send a feed to the bot by: \n"
- "add https://reclaimthenet.org/feed/")
- print(print_time(), msg)
+ msg = (
+ "Slixfeed can not work without a database.\n"
+ "To create a database, follow these steps:\n"
+ "Add Slixfeed contact to your roster.\n"
+ "Send a feed to the bot by URL:\n"
+ "https://reclaimthenet.org/feed/"
+ )
+ # print(await datetimehandler.current_time(), msg)
print(msg)
else:
os.chdir(db_dir)
@@ -191,114 +409,165 @@ class Slixfeed(slixmpp.ClientXMPP):
# jid_tasker[jid] = asyncio.create_task(self.task_jid(jid))
# await jid_tasker[jid]
async with asyncio.TaskGroup() as tg:
- print("main task")
- print(print_time(), "repr(tg)")
- print(repr(tg)) #
for file in files:
if file.endswith(".db") and not file.endswith(".db-jour.db"):
jid = file[:-3]
- tg.create_task(self.task_jid(jid))
+ main_task.extend([tg.create_task(self.task_jid(jid))])
+ # main_task = [tg.create_task(self.task_jid(jid))]
# task_manager.update({jid: tg})
- # print(task_manager) # {}
- print(print_time(), "repr(tg) id(tg)")
- print(jid, repr(tg)) # sch@pimux.de
- print(jid, id(tg)) # sch@pimux.de 139879835500624
- #
- # 139879835500624
async def task_jid(self, jid):
"""
JID (Jabber ID) task manager.
- :param self: Self
- :param jid: Jabber ID
+ Parameters
+ ----------
+ self : ?
+ Self.
+ jid : str
+ Jabber ID.
"""
- enabled = await initdb(
+ enabled = await datahandler.initdb(
jid,
sqlitehandler.get_settings_value,
"enabled"
)
- print(print_time(), "enabled", enabled, jid)
+ # print(await datetimehandler.current_time(), "enabled", enabled, jid)
if enabled:
- print("sub task")
- print(print_time(), "repr(self) id(self)")
- print(repr(self))
- print(id(self))
task_manager[jid] = {}
- task_manager[jid]["check"] = asyncio.create_task(check_updates(jid))
- task_manager[jid]["status"] = asyncio.create_task(self.send_status(jid))
- task_manager[jid]["interval"] = asyncio.create_task(self.send_update(jid))
+ task_manager[jid]["check"] = asyncio.create_task(
+ check_updates(jid)
+ )
+ task_manager[jid]["status"] = asyncio.create_task(
+ self.send_status(jid)
+ )
+ task_manager[jid]["interval"] = asyncio.create_task(
+ self.send_update(jid)
+ )
await task_manager[jid]["check"]
await task_manager[jid]["status"]
await task_manager[jid]["interval"]
- print(print_time(), "task_manager[jid].items()")
- print(task_manager[jid].items())
- print(print_time(), "task_manager[jid]")
- print(task_manager[jid])
- print(print_time(), "task_manager")
- print(task_manager)
else:
+ # FIXME
+ # The following error occurs only upon first attempt to stop.
+ # /usr/lib/python3.11/asyncio/events.py:73: RuntimeWarning: coroutine 'Slixfeed.send_update' was never awaited
+ # self._args = None
+ # RuntimeWarning: Enable tracemalloc to get the object allocation traceback
+ try:
+ task_manager[jid]["interval"].cancel()
+ except:
+ None
await self.send_status(jid)
- async def send_update(self, jid):
+
+ async def send_update(self, jid, num=None):
"""
Send news items as messages.
- :param self: Self
- :param jid: Jabber ID
+ Parameters
+ ----------
+ self : ?
+ Self.
+ jid : str
+ Jabber ID.
+ num : str, optional
+ Number. The default is None.
"""
- new = await initdb(
+ # print("Starting send_update()")
+ # print(jid)
+ new = await datahandler.initdb(
jid,
- sqlitehandler.get_entry_unread
+ sqlitehandler.get_entry_unread,
+ num
)
if new:
- print(print_time(), "> SEND UPDATE",jid)
+ print(await datetimehandler.current_time(), "> SEND UPDATE",jid)
self.send_message(
mto=jid,
mbody=new,
mtype="chat"
)
- interval = await initdb(
+ await self.refresh_task(
jid,
- sqlitehandler.get_settings_value,
+ self.send_update,
"interval"
- )
+ )
+ # interval = await datahandler.initdb(
+ # jid,
+ # sqlitehandler.get_settings_value,
+ # "interval"
+ # )
+ # task_manager[jid]["interval"] = loop.call_at(
+ # loop.time() + 60 * interval,
+ # loop.create_task,
+ # self.send_update(jid)
+ # )
+
+ # print(await datetimehandler.current_time(), "asyncio.get_event_loop().time()")
+ # print(await datetimehandler.current_time(), asyncio.get_event_loop().time())
# await asyncio.sleep(60 * interval)
- self.loop.call_at(
- self.loop.time() + 60 * interval,
- self.loop.create_task,
- self.send_update(jid)
- )
+
+ # loop.call_later(
+ # 60 * interval,
+ # loop.create_task,
+ # self.send_update(jid)
+ # )
+
+ # print
+ # await handle_event()
+
async def send_status(self, jid):
"""
Send status message.
- :param self: Self
- :param jid: Jabber ID
+ Parameters
+ ----------
+ self : ?
+ Self.
+ jid : str
+ Jabber ID.
"""
- print(print_time(), "> SEND STATUS",jid)
- unread = await initdb(
- jid,
- sqlitehandler.get_number_of_entries_unread
- )
-
- if unread:
- status_text = "📰 News items: {}".format(str(unread))
- status_mode = "chat"
- else:
- status_text = "🗞 No News"
- status_mode = "available"
-
- enabled = await initdb(
+ print(await datetimehandler.current_time(), "> SEND STATUS",jid)
+ enabled = await datahandler.initdb(
jid,
sqlitehandler.get_settings_value,
"enabled"
)
-
if not enabled:
status_mode = "xa"
+ status_text = "Send \"Start\" to receive news."
+ else:
+ feeds = await datahandler.initdb(
+ jid,
+ sqlitehandler.get_number_of_items,
+ "feeds"
+ )
+ if not feeds:
+ status_mode = "available"
+ status_text = (
+ "📂️ Send a URL from a blog or a news website."
+ )
+ else:
+ unread = await datahandler.initdb(
+ jid,
+ sqlitehandler.get_number_of_entries_unread
+ )
+ if unread:
+ status_mode = "chat"
+ status_text = (
+ "📰 You have {} news items to read."
+ ).format(str(unread))
+ # status_text = (
+ # "📰 News items: {}"
+ # ).format(str(unread))
+ # status_text = (
+ # "📰 You have {} news items"
+ # ).format(str(unread))
+ else:
+ status_mode = "available"
+ status_text = "🗞 No news"
# print(status_text, "for", jid)
self.send_presence(
@@ -306,37 +575,55 @@ class Slixfeed(slixmpp.ClientXMPP):
pstatus=status_text,
pto=jid,
#pfrom=None
- )
-
- await asyncio.sleep(60 * 20)
-
- # self.loop.call_at(
- # self.loop.time() + 60 * 20,
- # self.loop.create_task,
+ )
+ # await asyncio.sleep(60 * 20)
+ await self.refresh_task(
+ jid,
+ self.send_status,
+ "status",
+ "20"
+ )
+ # loop.call_at(
+ # loop.time() + 60 * 20,
+ # loop.create_task,
# self.send_status(jid)
# )
- async def refresh_task(self, jid, key, val):
+ async def refresh_task(self, jid, callback, key, val=None):
"""
- Apply settings on runtime.
+ Apply new setting at runtime.
- :param self: Self
- :param jid: Jabber ID
- :param key: Key
- :param val: Value
+ Parameters
+ ----------
+ self : ?
+ Self.
+ jid : str
+ Jabber ID.
+ key : str
+ Key.
+ val : str, optional
+ Value. The default is None.
"""
+ if not val:
+ val = await datahandler.initdb(
+ jid,
+ sqlitehandler.get_settings_value,
+ key
+ )
if jid in task_manager:
task_manager[jid][key].cancel()
- loop = asyncio.get_event_loop()
- print(print_time(), "loop")
- print(loop)
- print(print_time(), "loop")
task_manager[jid][key] = loop.call_at(
loop.time() + 60 * float(val),
loop.create_task,
- self.send_update(jid)
+ callback(jid)
+ # self.send_update(jid)
)
+ # task_manager[jid][key] = loop.call_later(
+ # 60 * float(val),
+ # loop.create_task,
+ # self.send_update(jid)
+ # )
# task_manager[jid][key] = self.send_update.loop.call_at(
# self.send_update.loop.time() + 60 * val,
# self.send_update.loop.create_task,
@@ -350,16 +637,19 @@ async def check_updates(jid):
"""
Start calling for update check up.
- :param jid: Jabber ID
+ Parameters
+ ----------
+ jid : str
+ Jabber ID.
"""
while True:
- print(print_time(), "> CHCK UPDATE",jid)
- await initdb(jid, datahandler.download_updates)
+ print(await datetimehandler.current_time(), "> CHCK UPDATE",jid)
+ await datahandler.initdb(jid, datahandler.download_updates)
await asyncio.sleep(60 * 90)
# Schedule to call this function again in 90 minutes
- # self.loop.call_at(
- # self.loop.time() + 60 * 90,
- # self.loop.create_task,
+ # loop.call_at(
+ # loop.time() + 60 * 90,
+ # loop.create_task,
# self.check_updates(jid)
# )
@@ -367,84 +657,123 @@ async def check_updates(jid):
def print_help():
"""
Print help manual.
+
+ Returns
+ -------
+ msg : str
+ Message.
"""
- msg = ("Slixfeed - News syndication bot for Jabber/XMPP \n"
- "\n"
- "DESCRIPTION: \n"
- " Slixfeed is a news aggregator bot for online news feeds. \n"
- " Supported filetypes: Atom, RDF and RSS. \n"
- "\n"
- "BASIC USAGE: \n"
- " start \n"
- " Enable bot and send updates. \n"
- " Stop \n"
- " Disable bot and stop updates. \n"
- " batch N \n"
- " Send N updates for each interval. \n"
- " interval N \n"
- " Send an update every N minutes. \n"
- " feed list \n"
- " List subscriptions. \n"
- "\n"
- "EDIT OPTIONS: \n"
- " add URL \n"
- " Add URL to subscription list. \n"
- " remove ID \n"
- " Remove feed from subscription list. \n"
- " status ID \n"
- " Toggle update status of feed. \n"
- "\n"
- "SEARCH OPTIONS: \n"
- " search TEXT \n"
- " Search news items by given keywords. \n"
- " recent N \n"
- " List recent N news items (up to 50 items). \n"
- "\n"
- "STATISTICS OPTIONS: \n"
- " analyses \n"
- " Show report and statistics of feeds. \n"
- " obsolete \n"
- " List feeds that are not available. \n"
- " unread \n"
- " Print number of unread news items. \n"
- "\n"
- "BACKUP OPTIONS: \n"
- " export opml \n"
- " Send an OPML file with your feeds. \n"
- " backup news html\n"
- " Send an HTML formatted file of your news items. \n"
- " backup news md \n"
- " Send a Markdown file of your news items. \n"
- " backup news text \n"
- " Send a Plain Text file of your news items. \n"
- "\n"
- "DOCUMENTATION: \n"
- " Slixfeed \n"
- " https://gitgud.io/sjehuda/slixfeed \n"
- " Slixmpp \n"
- " https://slixmpp.readthedocs.io/ \n"
- " feedparser \n"
- " https://pythonhosted.org/feedparser")
+ msg = (
+ "```\n"
+ "NAME\n"
+ "Slixfeed - News syndication bot for Jabber/XMPP\n"
+ "\n"
+ "DESCRIPTION\n"
+ " Slixfeed is a news aggregator bot for online news feeds.\n"
+ " This program is primarily designed for XMPP.\n"
+ " For more information, visit https://xmpp.org/software/\n"
+ "\n"
+ "BASIC USAGE\n"
+ " start\n"
+ " Enable bot and send updates.\n"
+ " stop\n"
+ " Disable bot and stop updates.\n"
+ " feeds\n"
+ " List subscriptions.\n"
+ " interval N\n"
+ " Set interval update to every N minutes.\n"
+ " next N\n"
+ " Send N next updates.\n"
+ " quantum N\n"
+ " Set N updates for each interval.\n"
+ "\n"
+ "FILTER OPTIONS\n"
+ " allow\n"
+ " Keywords to allow (comma separates).\n"
+ " deny\n"
+ " Keywords to block (comma separates).\n"
+ # " filter clear allow\n"
+ # " Reset allow list.\n"
+ # " filter clear deny\n"
+ # " Reset deny list.\n"
+ "\n"
+ "EDIT OPTIONS\n"
+ " URL\n"
+ " Add URL to subscription list.\n"
+ " add URL TITLE\n"
+ " Add URL to subscription list (without validity check).\n"
+ " remove ID\n"
+ " Remove feed from subscription list.\n"
+ " status ID\n"
+ " Toggle update status of feed.\n"
+ "\n"
+ "SEARCH OPTIONS\n"
+ " feeds TEXT\n"
+ " Search subscriptions by given keywords.\n"
+ " search TEXT\n"
+ " Search news items by given keywords.\n"
+ " recent N\n"
+ " List recent N news items (up to 50 items).\n"
+ "\n"
+ # "STATISTICS OPTIONS\n"
+ # " analyses\n"
+ # " Show report and statistics of feeds.\n"
+ # " obsolete\n"
+ # " List feeds that are not available.\n"
+ # " unread\n"
+ # " Print number of unread news items.\n"
+ # "\n"
+ # "BACKUP OPTIONS\n"
+ # " export opml\n"
+ # " Send an OPML file with your feeds.\n"
+ # " backup news html\n"
+ # " Send an HTML formatted file of your news items.\n"
+ # " backup news md\n"
+ # " Send a Markdown file of your news items.\n"
+ # " backup news text\n"
+ # " Send a Plain Text file of your news items.\n"
+ # "\n"
+ "SUPPORT\n"
+ " support"
+ " Join xmpp:slixmpp@muc.poez.io?join\n"
+ "\n"
+ # "PROTOCOLS\n"
+ # " Supported prootcols are IRC, Matrix and XMPP.\n"
+ # " For the best experience, we recommend you to use XMPP.\n"
+ # "\n"
+ "FILETYPES\n"
+ " Supported filetypes are Atom, RDF and RSS.\n"
+ "\n"
+ "AUTHORS\n"
+ " Laura Harbinger, Schimon Zackary.\n"
+ "\n"
+ "COPYRIGHT\n"
+ " Slixfeed is free software; you can redistribute it and/or\n"
+ " modify it under the terms of the GNU General Public License\n"
+ " as published by the Free Software Foundation; version 3 only\n"
+ "\n"
+ " Slixfeed is distributed in the hope that it will be useful,\n"
+ " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ " GNU General Public License for more details.\n"
+ "\n"
+ "NOTE\n"
+ " Make Slixfeed your own.\n"
+ "\n"
+ " You can run Slixfeed on your own computer, server, and\n"
+ " even on a Linux phone (i.e. Droidian, Mobian NixOS,\n"
+ " postmarketOS). You can also use Termux.\n"
+ "\n"
+ " All you need is one of the above and an XMPP account to\n"
+ " connect Slixfeed to.\n"
+ "\n"
+ "DOCUMENTATION\n"
+ " Slixfeed\n"
+ " https://gitgud.io/sjehuda/slixfeed\n"
+ " Slixmpp\n"
+ " https://slixmpp.readthedocs.io/\n"
+ " feedparser\n"
+ " https://pythonhosted.org/feedparser\n"
+ "\n```"
+ )
return msg
-
-
-# TODO Perhaps this needs to be executed
-# just once per program execution
-async def initdb(jid, callback, message=None):
- """
- Callback function to instantiate action on database.
-
- :param jid: JID (Jabber ID).
- :param callback: Function name.
- :param massage: Optional kwarg when a message is a part or required argument.
- """
- db_dir = confighandler.get_default_dbdir()
- if not os.path.isdir(db_dir):
- os.mkdir(db_dir)
- db_file = os.path.join(db_dir, r"{}.db".format(jid))
- sqlitehandler.create_tables(db_file)
- # await sqlitehandler.set_default_values(db_file)
- if message:
- return await callback(db_file, message)
- else:
- return await callback(db_file)