diff --git a/changedetectionio/blueprint/watchlist/__init__.py b/changedetectionio/blueprint/watchlist/__init__.py
new file mode 100644
index 000000000..fb57b2ee4
--- /dev/null
+++ b/changedetectionio/blueprint/watchlist/__init__.py
@@ -0,0 +1,114 @@
+import flask_login
+import os
+import time
+import timeago
+
+from flask import Blueprint, request, make_response, render_template, redirect, url_for, flash, session
+from flask_login import current_user
+from flask_paginate import Pagination, get_page_parameter
+
+from changedetectionio import forms
+from changedetectionio.store import ChangeDetectionStore
+from changedetectionio.auth_decorator import login_optionally_required
+from changedetectionio.strtobool import strtobool
+
+def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMetaData):
+ watchlist_blueprint = Blueprint('watchlist', __name__, template_folder="templates")
+
+ @watchlist_blueprint.route("/", methods=['GET'])
+ @login_optionally_required
+ def index():
+ active_tag_req = request.args.get('tag', '').lower().strip()
+ active_tag_uuid = active_tag = None
+
+ # Be sure limit_tag is a uuid
+ if active_tag_req:
+ for uuid, tag in datastore.data['settings']['application'].get('tags', {}).items():
+ if active_tag_req == tag.get('title', '').lower().strip() or active_tag_req == uuid:
+ active_tag = tag
+ active_tag_uuid = uuid
+ break
+
+ # Redirect for the old rss path which used the /?rss=true
+ if request.args.get('rss'):
+ return redirect(url_for('rss.feed', tag=active_tag_uuid))
+
+ op = request.args.get('op')
+ if op:
+ uuid = request.args.get('uuid')
+ if op == 'pause':
+ datastore.data['watching'][uuid].toggle_pause()
+ elif op == 'mute':
+ datastore.data['watching'][uuid].toggle_mute()
+
+ datastore.needs_write = True
+ return redirect(url_for('watchlist.index', tag = active_tag_uuid))
+
+ # Sort by last_changed and add the uuid which is usually the key..
+ sorted_watches = []
+ with_errors = request.args.get('with_errors') == "1"
+ errored_count = 0
+ search_q = request.args.get('q').strip().lower() if request.args.get('q') else False
+ for uuid, watch in datastore.data['watching'].items():
+ if with_errors and not watch.get('last_error'):
+ continue
+
+ if active_tag_uuid and not active_tag_uuid in watch['tags']:
+ continue
+ if watch.get('last_error'):
+ errored_count += 1
+
+ if search_q:
+ if (watch.get('title') and search_q in watch.get('title').lower()) or search_q in watch.get('url', '').lower():
+ sorted_watches.append(watch)
+ elif watch.get('last_error') and search_q in watch.get('last_error').lower():
+ sorted_watches.append(watch)
+ else:
+ sorted_watches.append(watch)
+
+ form = forms.quickWatchForm(request.form)
+ page = request.args.get(get_page_parameter(), type=int, default=1)
+ total_count = len(sorted_watches)
+
+ pagination = Pagination(page=page,
+ total=total_count,
+ per_page=datastore.data['settings']['application'].get('pager_size', 50), css_framework="semantic")
+
+ sorted_tags = sorted(datastore.data['settings']['application'].get('tags').items(), key=lambda x: x[1]['title'])
+ output = render_template(
+ "watch-overview.html",
+ # Don't link to hosting when we're on the hosting environment
+ active_tag=active_tag,
+ active_tag_uuid=active_tag_uuid,
+ app_rss_token=datastore.data['settings']['application'].get('rss_access_token'),
+ datastore=datastore,
+ errored_count=errored_count,
+ form=form,
+ guid=datastore.data['app_guid'],
+ has_proxies=datastore.proxy_list,
+ has_unviewed=datastore.has_unviewed,
+ hosted_sticky=os.getenv("SALTED_PASS", False) == False,
+ pagination=pagination,
+ queued_uuids=[q_uuid.item['uuid'] for q_uuid in update_q.queue],
+ search_q=request.args.get('q','').strip(),
+ sort_attribute=request.args.get('sort') if request.args.get('sort') else request.cookies.get('sort'),
+ sort_order=request.args.get('order') if request.args.get('order') else request.cookies.get('order'),
+ system_default_fetcher=datastore.data['settings']['application'].get('fetch_backend'),
+ tags=sorted_tags,
+ watches=sorted_watches
+ )
+
+ if session.get('share-link'):
+ del(session['share-link'])
+
+ resp = make_response(output)
+
+ # The template can run on cookie or url query info
+ if request.args.get('sort'):
+ resp.set_cookie('sort', request.args.get('sort'))
+ if request.args.get('order'):
+ resp.set_cookie('order', request.args.get('order'))
+
+ return resp
+
+ return watchlist_blueprint
\ No newline at end of file
diff --git a/changedetectionio/templates/watch-overview.html b/changedetectionio/blueprint/watchlist/templates/watch-overview.html
similarity index 87%
rename from changedetectionio/templates/watch-overview.html
rename to changedetectionio/blueprint/watchlist/templates/watch-overview.html
index 0be142bab..2af9e61fd 100644
--- a/changedetectionio/templates/watch-overview.html
+++ b/changedetectionio/blueprint/watchlist/templates/watch-overview.html
@@ -46,12 +46,12 @@
{% endif %}
{% if search_q %}
Searching "{{search_q}}"
{% endif %}
@@ -72,14 +72,14 @@
{% set link_order = "desc" if sort_order == 'asc' else "asc" %}
{% set arrow_span = "" %}
- | # |
+ # |
|
- Website |
+ Website |
{% if any_has_restock_price_processor %}
Restock & Price |
{% endif %}
- Last Checked |
- Last Changed |
+ Last Checked |
+ Last Changed |
|
@@ -104,12 +104,12 @@
{{ loop.index+pagination.skip }} |
{% if not watch.paused %}
-
+
{% else %}
-
+
{% endif %}
{% set mute_label = 'UnMute notification' if watch.notification_muted else 'Mute notification' %}
-
+
|
{{watch.title if watch.title is not none and watch.title|length > 0 else watch.url}}
@@ -210,7 +210,7 @@
{% if errored_count %}
-
- With errors ({{ errored_count }})
+ With errors ({{ errored_count }})
{% endif %}
{% if has_unviewed %}
diff --git a/changedetectionio/flask_app.py b/changedetectionio/flask_app.py
index 229ad9833..da7dc7965 100644
--- a/changedetectionio/flask_app.py
+++ b/changedetectionio/flask_app.py
@@ -342,105 +342,14 @@ def changedetection_app(config=None, datastore_o=None):
return None
+ # Root route redirects to watchlist blueprint
@app.route("/", methods=['GET'])
@login_optionally_required
def index():
- global datastore
- from changedetectionio import forms
-
- active_tag_req = request.args.get('tag', '').lower().strip()
- active_tag_uuid = active_tag = None
-
- # Be sure limit_tag is a uuid
- if active_tag_req:
- for uuid, tag in datastore.data['settings']['application'].get('tags', {}).items():
- if active_tag_req == tag.get('title', '').lower().strip() or active_tag_req == uuid:
- active_tag = tag
- active_tag_uuid = uuid
- break
-
-
- # Redirect for the old rss path which used the /?rss=true
- if request.args.get('rss'):
- return redirect(url_for('rss.feed', tag=active_tag_uuid))
-
- op = request.args.get('op')
- if op:
- uuid = request.args.get('uuid')
- if op == 'pause':
- datastore.data['watching'][uuid].toggle_pause()
- elif op == 'mute':
- datastore.data['watching'][uuid].toggle_mute()
-
- datastore.needs_write = True
- return redirect(url_for('index', tag = active_tag_uuid))
-
- # Sort by last_changed and add the uuid which is usually the key..
- sorted_watches = []
- with_errors = request.args.get('with_errors') == "1"
- errored_count = 0
- search_q = request.args.get('q').strip().lower() if request.args.get('q') else False
- for uuid, watch in datastore.data['watching'].items():
- if with_errors and not watch.get('last_error'):
- continue
-
- if active_tag_uuid and not active_tag_uuid in watch['tags']:
- continue
- if watch.get('last_error'):
- errored_count += 1
-
- if search_q:
- if (watch.get('title') and search_q in watch.get('title').lower()) or search_q in watch.get('url', '').lower():
- sorted_watches.append(watch)
- elif watch.get('last_error') and search_q in watch.get('last_error').lower():
- sorted_watches.append(watch)
- else:
- sorted_watches.append(watch)
-
- form = forms.quickWatchForm(request.form)
- page = request.args.get(get_page_parameter(), type=int, default=1)
- total_count = len(sorted_watches)
-
- pagination = Pagination(page=page,
- total=total_count,
- per_page=datastore.data['settings']['application'].get('pager_size', 50), css_framework="semantic")
-
- sorted_tags = sorted(datastore.data['settings']['application'].get('tags').items(), key=lambda x: x[1]['title'])
- output = render_template(
- "watch-overview.html",
- # Don't link to hosting when we're on the hosting environment
- active_tag=active_tag,
- active_tag_uuid=active_tag_uuid,
- app_rss_token=datastore.data['settings']['application'].get('rss_access_token'),
- datastore=datastore,
- errored_count=errored_count,
- form=form,
- guid=datastore.data['app_guid'],
- has_proxies=datastore.proxy_list,
- has_unviewed=datastore.has_unviewed,
- hosted_sticky=os.getenv("SALTED_PASS", False) == False,
- pagination=pagination,
- queued_uuids=[q_uuid.item['uuid'] for q_uuid in update_q.queue],
- search_q=request.args.get('q','').strip(),
- sort_attribute=request.args.get('sort') if request.args.get('sort') else request.cookies.get('sort'),
- sort_order=request.args.get('order') if request.args.get('order') else request.cookies.get('order'),
- system_default_fetcher=datastore.data['settings']['application'].get('fetch_backend'),
- tags=sorted_tags,
- watches=sorted_watches
- )
-
- if session.get('share-link'):
- del(session['share-link'])
-
- resp = make_response(output)
-
- # The template can run on cookie or url query info
- if request.args.get('sort'):
- resp.set_cookie('sort', request.args.get('sort'))
- if request.args.get('order'):
- resp.set_cookie('order', request.args.get('order'))
-
- return resp
+ # Get all query string parameters
+ args = request.args.copy()
+ # Redirect to watchlist blueprint, keeping all query parameters
+ return redirect(url_for('watchlist.index', **args))
@app.route("/static//", methods=['GET'])
def static_content(group, filename):
@@ -529,10 +438,13 @@ def changedetection_app(config=None, datastore_o=None):
import changedetectionio.blueprint.rss as rss
app.register_blueprint(rss.construct_blueprint(datastore), url_prefix='/rss')
+
import changedetectionio.blueprint.ui as ui
app.register_blueprint(ui.construct_blueprint(datastore, update_q, running_update_threads, queuedWatchMetaData))
+ import changedetectionio.blueprint.watchlist as watchlist
+ app.register_blueprint(watchlist.construct_blueprint(datastore, update_q, queuedWatchMetaData), url_prefix='')
# @todo handle ctrl break
ticker_thread = threading.Thread(target=ticker_thread_check_time_launch_checks).start()
diff --git a/changedetectionio/tests/util.py b/changedetectionio/tests/util.py
index c4e6b3161..517603c50 100644
--- a/changedetectionio/tests/util.py
+++ b/changedetectionio/tests/util.py
@@ -108,7 +108,7 @@ def get_UUID_for_tag_name(client, name):
def extract_rss_token_from_UI(client):
import re
res = client.get(
- url_for("index"),
+ url_for("watchlist.index"),
)
m = re.search('token=(.+?)"', str(res.data))
token_key = m.group(1)
@@ -118,7 +118,7 @@ def extract_rss_token_from_UI(client):
def extract_UUID_from_client(client):
import re
res = client.get(
- url_for("index"),
+ url_for("watchlist.index"),
)
# {{api_key}}
@@ -133,7 +133,7 @@ def wait_for_all_checks(client):
# because sub-second rechecks are problematic in testing, use lots of delays
time.sleep(1)
while attempt < 60:
- res = client.get(url_for("index"))
+ res = client.get(url_for("watchlist.index"))
if not b'Checking now' in res.data:
break
logging.getLogger().info("Waiting for watch-list to not say 'Checking now'.. {}".format(attempt))
|