From a18fa8d28834f95e011d6cefac4cbdad9a8ac26c Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Tue, 31 Oct 2023 18:52:39 +0100 Subject: [PATCH] Ability to import wachete XLSX --- changedetectionio/__init__.py | 15 +++++-- changedetectionio/forms.py | 2 + changedetectionio/importer.py | 55 +++++++++++++++++++++++++ changedetectionio/templates/import.html | 6 ++- requirements.txt | 2 +- 5 files changed, 75 insertions(+), 5 deletions(-) diff --git a/changedetectionio/__init__.py b/changedetectionio/__init__.py index 850e9966f..f08732e90 100644 --- a/changedetectionio/__init__.py +++ b/changedetectionio/__init__.py @@ -822,6 +822,7 @@ def changedetection_app(config=None, datastore_o=None): from . import forms if request.method == 'POST': + from .importer import import_url_list, import_distill_io_json # URL List import @@ -845,11 +846,19 @@ def changedetection_app(config=None, datastore_o=None): for uuid in d_importer.new_uuids: update_q.put(queuedWatchMetaData.PrioritizedItem(priority=1, item={'uuid': uuid, 'skip_when_checksum_same': True})) + # Wachete import + from .forms import importForm + form = importForm() + if request.files: + file = request.files['wachete_export'] + from .importer import import_wachete_xlsx + w_importer = import_wachete_xlsx() + w_importer.run(data=file, flash=flash, datastore=datastore) + for uuid in w_importer.new_uuids: + update_q.put(queuedWatchMetaData.PrioritizedItem(priority=1, item={'uuid': uuid, 'skip_when_checksum_same': True})) - form = forms.importForm(formdata=request.form if request.method == 'POST' else None, -# data=default, - ) # Could be some remaining, or we could be on GET + form = forms.importForm(formdata=request.form if request.method == 'POST' else None) output = render_template("import.html", form=form, import_url_list_remaining="\n".join(remaining_urls), diff --git a/changedetectionio/forms.py b/changedetectionio/forms.py index 4177ed802..d393fdda2 100644 --- a/changedetectionio/forms.py +++ b/changedetectionio/forms.py @@ -15,6 +15,7 @@ from wtforms import ( validators, widgets ) +from flask_wtf.file import FileField, FileAllowed from wtforms.fields import FieldList from wtforms.validators import ValidationError @@ -398,6 +399,7 @@ class importForm(Form): from . import processors processor = RadioField(u'Processor', choices=processors.available_processors(), default="text_json_diff") urls = TextAreaField('URLs') + wachete_export = FileField(validators=[FileAllowed(['xlsx'], 'Must be .xlsx file!')]) class SingleBrowserStep(Form): diff --git a/changedetectionio/importer.py b/changedetectionio/importer.py index f046c8952..4adae9d76 100644 --- a/changedetectionio/importer.py +++ b/changedetectionio/importer.py @@ -132,3 +132,58 @@ class import_distill_io_json(Importer): good += 1 flash("{} Imported from Distill.io in {:.2f}s, {} Skipped.".format(len(self.new_uuids), time.time() - now, len(self.remaining_data))) + +class import_wachete_xlsx(Importer): + + def run(self, + data, + flash, + datastore, + ): + good = 0 + now = time.time() + self.new_uuids = [] + + from openpyxl import load_workbook + + try: + wb = load_workbook(data) + except Exception as e: + #@todo correct except + flash("Unable to read export XLSX file, something wrong with the file?", 'error') + return + + sheet_obj = wb.active + + i = 1 + row = 2 + while sheet_obj.cell(row=row, column=1).value: + data = {} + while sheet_obj.cell(row=row, column=i).value: + column_title = sheet_obj.cell(row=1, column=i).value.strip().lower() + column_row_value = sheet_obj.cell(row=row, column=i).value + data[column_title] = column_row_value + + i += 1 + + extras = {} + if data.get('xpath'): + #@todo split by || ? + extras['include_filters'] = [data.get('xpath')] + if data.get('title'): + extras['title'] = [data.get('title').strip()] + + new_uuid = datastore.add_watch(url=data['url'].strip(), + extras=extras, + tag=data.get('folder'), + write_to_disk_now=False) + row += 1 + i = 1 + + if new_uuid: + # Straight into the queue. + self.new_uuids.append(new_uuid) + good += 1 + + flash( + "{} Imported from Wachete xlsx.io in {:.2f}s, {} Skipped.".format(len(self.new_uuids), time.time() - now, 0)) diff --git a/changedetectionio/templates/import.html b/changedetectionio/templates/import.html index 9824ccf56..ab02e763b 100644 --- a/changedetectionio/templates/import.html +++ b/changedetectionio/templates/import.html @@ -8,11 +8,12 @@
-
+
@@ -79,6 +80,9 @@ " rows="25">{{ original_distill_json }}
+
+ {{ render_field(form.wachete_export, class="processor") }} +
diff --git a/requirements.txt b/requirements.txt index 8d0500665..1ffe38c0b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -59,7 +59,7 @@ werkzeug~=2.0.0 # Templating, so far just in the URLs but in the future can be for the notifications also jinja2~=3.1 jinja2-time - +openpyxl # https://peps.python.org/pep-0508/#environment-markers # https://github.com/dgtlmoon/changedetection.io/pull/1009 jq~=1.3; python_version >= "3.8" and sys_platform == "darwin"