Compare commits
8 Commits
ticket-132
...
fetch-back
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4cc76c310e | ||
|
|
6d907b6e0d | ||
|
|
948ef7ade4 | ||
|
|
4c53859a4f | ||
|
|
fcedbbca99 | ||
|
|
0ba139f8f9 | ||
|
|
a9431191fc | ||
|
|
774451f256 |
2
.github/workflows/containers.yml
vendored
2
.github/workflows/containers.yml
vendored
@@ -98,6 +98,7 @@ jobs:
|
|||||||
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7
|
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7
|
||||||
cache-from: type=local,src=/tmp/.buildx-cache
|
cache-from: type=local,src=/tmp/.buildx-cache
|
||||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
cache-to: type=local,dest=/tmp/.buildx-cache
|
||||||
|
provenance: false
|
||||||
|
|
||||||
# A new tagged release is required, which builds :tag and :latest
|
# A new tagged release is required, which builds :tag and :latest
|
||||||
- name: Build and push :tag
|
- name: Build and push :tag
|
||||||
@@ -116,6 +117,7 @@ jobs:
|
|||||||
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7
|
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7
|
||||||
cache-from: type=local,src=/tmp/.buildx-cache
|
cache-from: type=local,src=/tmp/.buildx-cache
|
||||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
cache-to: type=local,dest=/tmp/.buildx-cache
|
||||||
|
provenance: false
|
||||||
|
|
||||||
- name: Image digest
|
- name: Image digest
|
||||||
run: echo step SHA ${{ steps.vars.outputs.sha_short }} tag ${{steps.vars.outputs.tag}} branch ${{steps.vars.outputs.branch}} digest ${{ steps.docker_build.outputs.digest }}
|
run: echo step SHA ${{ steps.vars.outputs.sha_short }} tag ${{steps.vars.outputs.tag}} branch ${{steps.vars.outputs.branch}} digest ${{ steps.docker_build.outputs.digest }}
|
||||||
|
|||||||
2
.github/workflows/test-container-build.yml
vendored
2
.github/workflows/test-container-build.yml
vendored
@@ -10,11 +10,13 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- requirements.txt
|
- requirements.txt
|
||||||
- Dockerfile
|
- Dockerfile
|
||||||
|
- .github/workflows/*
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- requirements.txt
|
- requirements.txt
|
||||||
- Dockerfile
|
- Dockerfile
|
||||||
|
- .github/workflows/*
|
||||||
|
|
||||||
# Changes to requirements.txt packages and Dockerfile may or may not always be compatible with arm etc, so worth testing
|
# Changes to requirements.txt packages and Dockerfile may or may not always be compatible with arm etc, so worth testing
|
||||||
# @todo: some kind of path filter for requirements.txt and Dockerfile
|
# @todo: some kind of path filter for requirements.txt and Dockerfile
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ from flask_wtf import CSRFProtect
|
|||||||
from changedetectionio import html_tools
|
from changedetectionio import html_tools
|
||||||
from changedetectionio.api import api_v1
|
from changedetectionio.api import api_v1
|
||||||
|
|
||||||
__version__ = '0.40.1.0'
|
__version__ = '0.40.1.1'
|
||||||
|
|
||||||
datastore = None
|
datastore = None
|
||||||
|
|
||||||
@@ -417,6 +417,7 @@ def changedetection_app(config=None, datastore_o=None):
|
|||||||
has_unviewed=datastore.has_unviewed,
|
has_unviewed=datastore.has_unviewed,
|
||||||
hosted_sticky=os.getenv("SALTED_PASS", False) == False,
|
hosted_sticky=os.getenv("SALTED_PASS", False) == False,
|
||||||
queued_uuids=[q_uuid.item['uuid'] for q_uuid in update_q.queue],
|
queued_uuids=[q_uuid.item['uuid'] for q_uuid in update_q.queue],
|
||||||
|
system_default_fetcher=datastore.data['settings']['application'].get('fetch_backend'),
|
||||||
tags=existing_tags,
|
tags=existing_tags,
|
||||||
watches=sorted_watches
|
watches=sorted_watches
|
||||||
)
|
)
|
||||||
@@ -638,8 +639,6 @@ def changedetection_app(config=None, datastore_o=None):
|
|||||||
|
|
||||||
visualselector_data_is_ready = datastore.visualselector_data_is_ready(uuid)
|
visualselector_data_is_ready = datastore.visualselector_data_is_ready(uuid)
|
||||||
|
|
||||||
# Only works reliably with Playwright
|
|
||||||
visualselector_enabled = os.getenv('PLAYWRIGHT_DRIVER_URL', False) and default['fetch_backend'] == 'html_webdriver'
|
|
||||||
|
|
||||||
# JQ is difficult to install on windows and must be manually added (outside requirements.txt)
|
# JQ is difficult to install on windows and must be manually added (outside requirements.txt)
|
||||||
jq_support = True
|
jq_support = True
|
||||||
@@ -655,6 +654,9 @@ def changedetection_app(config=None, datastore_o=None):
|
|||||||
if (watch.get('fetch_backend') == 'system' and system_uses_webdriver) or watch.get('fetch_backend') == 'html_webdriver':
|
if (watch.get('fetch_backend') == 'system' and system_uses_webdriver) or watch.get('fetch_backend') == 'html_webdriver':
|
||||||
is_html_webdriver = True
|
is_html_webdriver = True
|
||||||
|
|
||||||
|
# Only works reliably with Playwright
|
||||||
|
visualselector_enabled = os.getenv('PLAYWRIGHT_DRIVER_URL', False) and is_html_webdriver
|
||||||
|
|
||||||
output = render_template("edit.html",
|
output = render_template("edit.html",
|
||||||
browser_steps_config=browser_step_ui_config,
|
browser_steps_config=browser_step_ui_config,
|
||||||
current_base_url=datastore.data['settings']['application']['base_url'],
|
current_base_url=datastore.data['settings']['application']['base_url'],
|
||||||
|
|||||||
@@ -31,11 +31,13 @@ def sigterm_handler(_signo, _stack_frame):
|
|||||||
def main():
|
def main():
|
||||||
global datastore
|
global datastore
|
||||||
global app
|
global app
|
||||||
ssl_mode = False
|
|
||||||
host = ''
|
|
||||||
port = os.environ.get('PORT') or 5000
|
|
||||||
do_cleanup = False
|
|
||||||
datastore_path = None
|
datastore_path = None
|
||||||
|
do_cleanup = False
|
||||||
|
host = ''
|
||||||
|
ipv6_enabled = False
|
||||||
|
port = os.environ.get('PORT') or 5000
|
||||||
|
ssl_mode = False
|
||||||
|
|
||||||
# On Windows, create and use a default path.
|
# On Windows, create and use a default path.
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
@@ -46,7 +48,7 @@ def main():
|
|||||||
datastore_path = os.path.join(os.getcwd(), "../datastore")
|
datastore_path = os.path.join(os.getcwd(), "../datastore")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(sys.argv[1:], "Ccsd:h:p:", "port")
|
opts, args = getopt.getopt(sys.argv[1:], "6Ccsd:h:p:", "port")
|
||||||
except getopt.GetoptError:
|
except getopt.GetoptError:
|
||||||
print('backend.py -s SSL enable -h [host] -p [port] -d [datastore path]')
|
print('backend.py -s SSL enable -h [host] -p [port] -d [datastore path]')
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
@@ -66,6 +68,10 @@ def main():
|
|||||||
if opt == '-d':
|
if opt == '-d':
|
||||||
datastore_path = arg
|
datastore_path = arg
|
||||||
|
|
||||||
|
if opt == '-6':
|
||||||
|
print ("Enabling IPv6 listen support")
|
||||||
|
ipv6_enabled = True
|
||||||
|
|
||||||
# Cleanup (remove text files that arent in the index)
|
# Cleanup (remove text files that arent in the index)
|
||||||
if opt == '-c':
|
if opt == '-c':
|
||||||
do_cleanup = True
|
do_cleanup = True
|
||||||
@@ -133,13 +139,15 @@ def main():
|
|||||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||||
app.wsgi_app = ProxyFix(app.wsgi_app, x_prefix=1, x_host=1)
|
app.wsgi_app = ProxyFix(app.wsgi_app, x_prefix=1, x_host=1)
|
||||||
|
|
||||||
|
s_type = socket.AF_INET6 if ipv6_enabled else socket.AF_INET
|
||||||
|
|
||||||
if ssl_mode:
|
if ssl_mode:
|
||||||
# @todo finalise SSL config, but this should get you in the right direction if you need it.
|
# @todo finalise SSL config, but this should get you in the right direction if you need it.
|
||||||
eventlet.wsgi.server(eventlet.wrap_ssl(eventlet.listen((host, port), socket.AF_INET6),
|
eventlet.wsgi.server(eventlet.wrap_ssl(eventlet.listen((host, port), s_type),
|
||||||
certfile='cert.pem',
|
certfile='cert.pem',
|
||||||
keyfile='privkey.pem',
|
keyfile='privkey.pem',
|
||||||
server_side=True), app)
|
server_side=True), app)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
eventlet.wsgi.server(eventlet.listen((host, int(port)), socket.AF_INET6), app)
|
eventlet.wsgi.server(eventlet.listen((host, int(port)), s_type), app)
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ base_config = {
|
|||||||
'consecutive_filter_failures': 0, # Every time the CSS/xPath filter cannot be located, reset when all is fine.
|
'consecutive_filter_failures': 0, # Every time the CSS/xPath filter cannot be located, reset when all is fine.
|
||||||
'extract_text': [], # Extract text by regex after filters
|
'extract_text': [], # Extract text by regex after filters
|
||||||
'extract_title_as_title': False,
|
'extract_title_as_title': False,
|
||||||
'fetch_backend': None,
|
'fetch_backend': 'system',
|
||||||
'filter_failure_notification_send': strtobool(os.getenv('FILTER_FAILURE_NOTIFICATION_SEND_DEFAULT', 'True')),
|
'filter_failure_notification_send': strtobool(os.getenv('FILTER_FAILURE_NOTIFICATION_SEND_DEFAULT', 'True')),
|
||||||
'has_ldjson_price_data': None,
|
'has_ldjson_price_data': None,
|
||||||
'track_ldjson_price_data': None,
|
'track_ldjson_price_data': None,
|
||||||
|
|||||||
@@ -673,3 +673,13 @@ class ChangeDetectionStore:
|
|||||||
self.data['settings']['application']['notification_urls'][i] = re.sub(r, r'{{\1}}', url)
|
self.data['settings']['application']['notification_urls'][i] = re.sub(r, r'{{\1}}', url)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Some setups may have missed the correct default, so it shows the wrong config in the UI, although it will default to system-wide
|
||||||
|
def update_10(self):
|
||||||
|
for uuid, watch in self.data['watching'].items():
|
||||||
|
try:
|
||||||
|
if not watch.get('fetch_backend', ''):
|
||||||
|
watch['fetch_backend'] = 'system'
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
return
|
||||||
|
|||||||
@@ -91,7 +91,12 @@
|
|||||||
<a class="external" target="_blank" rel="noopener" href="{{ watch.link.replace('source:','') }}"></a>
|
<a class="external" target="_blank" rel="noopener" href="{{ watch.link.replace('source:','') }}"></a>
|
||||||
<a class="link-spread" href="{{url_for('form_share_put_watch', uuid=watch.uuid)}}"><img class="status-icon" src="{{url_for('static_content', group='images', filename='spread.svg')}}" class="status-icon icon icon-spread" title="Create a link to share watch config with others" /></a>
|
<a class="link-spread" href="{{url_for('form_share_put_watch', uuid=watch.uuid)}}"><img class="status-icon" src="{{url_for('static_content', group='images', filename='spread.svg')}}" class="status-icon icon icon-spread" title="Create a link to share watch config with others" /></a>
|
||||||
|
|
||||||
{%if watch.get_fetch_backend == "html_webdriver" %}<img class="status-icon" src="{{url_for('static_content', group='images', filename='Google-Chrome-icon.png')}}" title="Using a chrome browser" />{% endif %}
|
{% if watch.get_fetch_backend == "html_webdriver"
|
||||||
|
or ( watch.get_fetch_backend == "system" and system_default_fetcher == 'html_webdriver' )
|
||||||
|
%}
|
||||||
|
<img class="status-icon" src="{{url_for('static_content', group='images', filename='Google-Chrome-icon.png')}}" title="Using a chrome browser" />
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{%if watch.is_pdf %}<img class="status-icon" src="{{url_for('static_content', group='images', filename='pdf-icon.svg')}}" title="Converting PDF to text" />{% endif %}
|
{%if watch.is_pdf %}<img class="status-icon" src="{{url_for('static_content', group='images', filename='pdf-icon.svg')}}" title="Converting PDF to text" />{% endif %}
|
||||||
{% if watch.last_error is defined and watch.last_error != False %}
|
{% if watch.last_error is defined and watch.last_error != False %}
|
||||||
<div class="fetch-error">{{ watch.last_error }}
|
<div class="fetch-error">{{ watch.last_error }}
|
||||||
|
|||||||
Reference in New Issue
Block a user