WIP
This commit is contained in:
@@ -642,20 +642,23 @@ def changedetection_app(config=None, datastore_o=None):
|
||||
enabled_tabs.append('visual-selector')
|
||||
enabled_tabs.append('text-filters-and-triggers')
|
||||
|
||||
if watch.get('fetch_processor') == 'image':
|
||||
enabled_tabs.append('visual-selector')
|
||||
|
||||
output = render_template("edit.html",
|
||||
uuid=uuid,
|
||||
watch=watch,
|
||||
form=form,
|
||||
enabled_tabs = enabled_tabs,
|
||||
has_empty_checktime=using_default_check_time,
|
||||
has_default_notification_urls=True if len(datastore.data['settings']['application']['notification_urls']) else False,
|
||||
using_global_webdriver_wait=default['webdriver_delay'] is None,
|
||||
current_base_url=datastore.data['settings']['application']['base_url'],
|
||||
emailprefix=os.getenv('NOTIFICATION_MAIL_BUTTON_PREFIX', False),
|
||||
enabled_tabs = enabled_tabs,
|
||||
form=form,
|
||||
has_default_notification_urls=True if len(datastore.data['settings']['application']['notification_urls']) else False,
|
||||
has_empty_checktime=using_default_check_time,
|
||||
playwright_enabled=os.getenv('PLAYWRIGHT_DRIVER_URL', False),
|
||||
settings_application=datastore.data['settings']['application'],
|
||||
using_global_webdriver_wait=default['webdriver_delay'] is None,
|
||||
uuid=uuid,
|
||||
visualselector_data_is_ready=visualselector_data_is_ready,
|
||||
visualselector_enabled=visualselector_enabled,
|
||||
playwright_enabled=os.getenv('PLAYWRIGHT_DRIVER_URL', False)
|
||||
watch=watch,
|
||||
)
|
||||
|
||||
return output
|
||||
@@ -809,6 +812,8 @@ def changedetection_app(config=None, datastore_o=None):
|
||||
|
||||
previous_version = dates[-2]
|
||||
|
||||
datastore.set_last_viewed(uuid, time.time())
|
||||
|
||||
output = render_template("diff-image.html",
|
||||
watch=watch,
|
||||
extra_stylesheets=extra_stylesheets,
|
||||
@@ -1074,7 +1079,13 @@ def changedetection_app(config=None, datastore_o=None):
|
||||
new_img = watch.history[watch.newest_history_key]
|
||||
prev_img = watch.history[compare_date]
|
||||
|
||||
img = image_diff.render_diff(new_img, prev_img)
|
||||
try:
|
||||
img = image_diff.render_diff(new_img, prev_img)
|
||||
except ValueError as e:
|
||||
print ("EXCEPTION: Diff image - got exception {} reverting to raw image without rendering difference".format(str(e)))
|
||||
with open(new_img, 'rb') as f:
|
||||
img = f.read()
|
||||
|
||||
|
||||
resp = make_response(img)
|
||||
resp.headers['Content-Type'] = 'image/jpeg'
|
||||
@@ -1243,7 +1254,7 @@ def changedetection_app(config=None, datastore_o=None):
|
||||
extras['fetch_processor']=fetch_processor
|
||||
if fetch_processor == 'image':
|
||||
extras['fetch_backend'] = 'html_webdriver'
|
||||
|
||||
|
||||
new_uuid = datastore.add_watch(url=url,
|
||||
tag=request.form.get('tag').strip(),
|
||||
extras=extras
|
||||
|
||||
@@ -421,9 +421,9 @@ class base_html_playwright(Fetcher):
|
||||
# acceptable screenshot quality here
|
||||
try:
|
||||
# Quality set to 1 because it's not used, just used as a work-around for a bug, no need to change this.
|
||||
page.screenshot(type='jpeg', clip={'x': 1.0, 'y': 1.0, 'width': 1280, 'height': 1024}, quality=1)
|
||||
#page.screenshot(type='jpeg', clip={'x': 1.0, 'y': 1.0, 'width': 1280, 'height': 1024}, quality=1)
|
||||
# The actual screenshot
|
||||
self.screenshot = page.screenshot(type='jpeg', full_page=True, quality=int(os.getenv("PLAYWRIGHT_SCREENSHOT_QUALITY", 72)))
|
||||
self.screenshot = page.screenshot(type='jpeg', full_page=True, quality=int(os.getenv("PLAYWRIGHT_SCREENSHOT_QUALITY", 82)))
|
||||
except Exception as e:
|
||||
context.close()
|
||||
browser.close()
|
||||
|
||||
@@ -89,8 +89,13 @@ class perform_site_check(fetch_processor):
|
||||
if 'image' in fetcher.headers['content-type']:
|
||||
self.contents = fetcher.raw_content
|
||||
else:
|
||||
# should be element if the filter is set, no?
|
||||
self.contents = fetcher.screenshot
|
||||
|
||||
# Used for visual-selector
|
||||
self.xpath_data = fetcher.xpath_data
|
||||
self.screenshot = fetcher.screenshot
|
||||
|
||||
image = Image.open(io.BytesIO(self.contents))
|
||||
|
||||
# @todo different choice?
|
||||
|
||||
@@ -33,8 +33,8 @@ def render_diff(fpath_imageA, fpath_imageB):
|
||||
# bounding box on both input images to represent where the two
|
||||
# images differ
|
||||
(x, y, w, h) = cv2.boundingRect(c)
|
||||
cv2.rectangle(imageA, (x, y), (x + w, y + h), (0, 0, 255), 2)
|
||||
cv2.rectangle(imageB, (x, y), (x + w, y + h), (0, 0, 255), 2)
|
||||
cv2.rectangle(imageA, (x, y), (x + w, y + h), (0, 0, 255), 1)
|
||||
cv2.rectangle(imageB, (x, y), (x + w, y + h), (0, 0, 255), 1)
|
||||
|
||||
#return cv2.imencode('.jpg', imageB)[1].tobytes()
|
||||
return cv2.imencode('.jpg', imageA)[1].tobytes()
|
||||
|
||||
149
changedetectionio/static/images/picture-frame.svg
Normal file
149
changedetectionio/static/images/picture-frame.svg
Normal file
@@ -0,0 +1,149 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 20.745352 20.745251"
|
||||
xml:space="preserve"
|
||||
width="20.745352"
|
||||
height="20.745251"
|
||||
sodipodi:docname="picture-frame.svg"
|
||||
inkscape:version="1.1.1 (1:1.1+202109281949+c3084ef5ed)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||
id="namedview31"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:zoom="24.215073"
|
||||
inkscape:cx="11.810825"
|
||||
inkscape:cy="10.158962"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1056"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g1325" /><defs
|
||||
id="defs57">
|
||||
|
||||
|
||||
</defs>
|
||||
<g
|
||||
id="g22"
|
||||
transform="translate(-141.68664,-143.32441)">
|
||||
|
||||
|
||||
|
||||
|
||||
<g
|
||||
id="g986"
|
||||
transform="matrix(0.09174031,0,0,0.09174031,139.41786,139.41786)"><g
|
||||
id="g1313" /><g
|
||||
id="g18">
|
||||
|
||||
|
||||
<g
|
||||
id="g1325"
|
||||
transform="matrix(1.0989302,0,0,1.0989302,-30.889712,-13.037446)"><g
|
||||
id="g1413"><rect
|
||||
x="58.112999"
|
||||
y="58.112999"
|
||||
style="fill:#95e1d3"
|
||||
width="190.77765"
|
||||
height="190.77299"
|
||||
id="rect4"
|
||||
rx="0"
|
||||
ry="0" /><polygon
|
||||
style="fill:#eaffd0"
|
||||
points="117.389,248.887 183.138,135.007 248.887,248.887 "
|
||||
id="polygon6" /><polygon
|
||||
style="fill:#eaffd0"
|
||||
points="100.26,175.887 58.113,248.887 117.389,248.887 129.898,227.221 "
|
||||
id="polygon8" /><circle
|
||||
style="fill:#fce38a"
|
||||
cx="141.82001"
|
||||
cy="119.433"
|
||||
r="16.547001"
|
||||
id="circle10" /><path
|
||||
style="fill:#414042"
|
||||
d="M 248.887,50.613 H 58.113 c -4.142,0 -7.5,3.357 -7.5,7.5 v 190.773 c 0,4.118 3.362,7.5 7.5,7.5 h 59.276 131.498 c 4.06,0 7.5,-3.304 7.5,-7.5 V 58.113 c 0,-4.142 -3.358,-7.5 -7.5,-7.5 z m -7.5,15 v 155.283 l -51.754,-89.64 c -2.886,-4.998 -10.11,-4.988 -12.99,0 l -46.745,80.965 -23.143,-40.085 c -2.886,-4.998 -10.11,-4.988 -12.99,0 l -28.151,48.76 V 65.613 Z m -141.127,125.274 20.978,36.335 -7.823,13.549 -0.356,0.616 H 71.103 Z m 30.12,50.5 6.013,-10.415 c 0.001,-0.002 0.002,-0.004 0.003,-0.006 l 46.742,-80.959 52.759,91.38 z"
|
||||
id="path14" /><path
|
||||
style="fill:#414042"
|
||||
d="m 141.82,143.48 c 13.259,0 24.046,-10.787 24.046,-24.047 0,-13.26 -10.787,-24.047 -24.046,-24.047 -13.259,0 -24.046,10.787 -24.046,24.047 0,13.26 10.786,24.047 24.046,24.047 z m 0,-33.093 c 4.988,0 9.046,4.059 9.046,9.047 0,4.988 -4.058,9.047 -9.046,9.047 -4.988,0 -9.046,-4.059 -9.046,-9.047 -0.001,-4.989 4.057,-9.047 9.046,-9.047 z"
|
||||
id="path16" /></g></g>
|
||||
</g></g>
|
||||
</g>
|
||||
<g
|
||||
id="g24"
|
||||
transform="translate(-141.68664,-143.32441)">
|
||||
</g>
|
||||
<g
|
||||
id="g26"
|
||||
transform="translate(-141.68664,-143.32441)">
|
||||
</g>
|
||||
<g
|
||||
id="g28"
|
||||
transform="translate(-141.68664,-143.32441)">
|
||||
</g>
|
||||
<g
|
||||
id="g30"
|
||||
transform="translate(-141.68664,-143.32441)">
|
||||
</g>
|
||||
<g
|
||||
id="g32"
|
||||
transform="translate(-141.68664,-143.32441)">
|
||||
</g>
|
||||
<g
|
||||
id="g34"
|
||||
transform="translate(-141.68664,-143.32441)">
|
||||
</g>
|
||||
<g
|
||||
id="g36"
|
||||
transform="translate(-141.68664,-143.32441)">
|
||||
</g>
|
||||
<g
|
||||
id="g38"
|
||||
transform="translate(-141.68664,-143.32441)">
|
||||
</g>
|
||||
<g
|
||||
id="g40"
|
||||
transform="translate(-141.68664,-143.32441)">
|
||||
</g>
|
||||
<g
|
||||
id="g42"
|
||||
transform="translate(-141.68664,-143.32441)">
|
||||
</g>
|
||||
<g
|
||||
id="g44"
|
||||
transform="translate(-141.68664,-143.32441)">
|
||||
</g>
|
||||
<g
|
||||
id="g46"
|
||||
transform="translate(-141.68664,-143.32441)">
|
||||
</g>
|
||||
<g
|
||||
id="g48"
|
||||
transform="translate(-141.68664,-143.32441)">
|
||||
</g>
|
||||
<g
|
||||
id="g50"
|
||||
transform="translate(-141.68664,-143.32441)">
|
||||
</g>
|
||||
<g
|
||||
id="g52"
|
||||
transform="translate(-141.68664,-143.32441)">
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
@@ -578,3 +578,15 @@ ul {
|
||||
display: inline;
|
||||
height: 26px;
|
||||
vertical-align: middle; }
|
||||
|
||||
#quickwatch-fetch-processor {
|
||||
color: #fff;
|
||||
font-size: 80%; }
|
||||
#quickwatch-fetch-processor ul {
|
||||
padding: 0px;
|
||||
list-style-type: none; }
|
||||
#quickwatch-fetch-processor ul li {
|
||||
display: inline-block;
|
||||
margin-right: 1em; }
|
||||
#quickwatch-fetch-processor ul li label:hover {
|
||||
cursor: pointer; }
|
||||
|
||||
@@ -803,4 +803,24 @@ ul {
|
||||
padding: 0.5rem;
|
||||
border-radius: 5px;
|
||||
color: #ff3300;
|
||||
}
|
||||
}
|
||||
|
||||
#quickwatch-fetch-processor {
|
||||
color: #fff;
|
||||
font-size: 80%;
|
||||
|
||||
ul {
|
||||
padding: 0px;
|
||||
list-style-type: none;
|
||||
li {
|
||||
display: inline-block;
|
||||
margin-right: 1em;
|
||||
label {
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,9 +28,7 @@
|
||||
{% if 'visual-selector' in enabled_tabs %}
|
||||
<li class="tab"><a id="visualselector-tab" href="#visualselector">Visual Filter Selector</a></li>
|
||||
{%endif%}
|
||||
{% if 'text-filters-and-triggers' in enabled_tabs %}
|
||||
<li class="tab"><a href="#filters-and-triggers">Filters & Triggers</a></li>
|
||||
{%endif%}
|
||||
<li class="tab"><a href="#notifications">Notifications</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -158,6 +156,7 @@ User-Agent: wonderbra 1.0") }}
|
||||
</div>
|
||||
|
||||
<div class="tab-pane-inner" id="filters-and-triggers">
|
||||
{% if 'text-filters-and-triggers' in enabled_tabs %}
|
||||
<div class="pure-control-group">
|
||||
<strong>Pro-tips:</strong><br/>
|
||||
<ul>
|
||||
@@ -169,12 +168,14 @@ User-Agent: wonderbra 1.0") }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<fieldset>
|
||||
<div class="pure-control-group">
|
||||
{{ render_checkbox_field(form.check_unique_lines) }}
|
||||
<span class="pure-form-message-inline">Good for websites that just move the content around, and you want to know when NEW content is added, compares new lines against all history for this watch.</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
<div class="pure-control-group">
|
||||
{% set field = render_field(form.css_filter,
|
||||
placeholder=".class-name or #some-id, or other CSS selector rule.",
|
||||
@@ -201,6 +202,9 @@ User-Agent: wonderbra 1.0") }}
|
||||
href="https://github.com/dgtlmoon/changedetection.io/wiki/CSS-Selector-help">here for more CSS selector help</a>.<br/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{% if 'text-filters-and-triggers' in enabled_tabs %}
|
||||
|
||||
<div class="pure-control-group">
|
||||
{{ render_field(form.subtractive_selectors, rows=5, placeholder="header
|
||||
footer
|
||||
@@ -276,6 +280,8 @@ Unavailable") }}
|
||||
</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="tab-pane-inner visual-selector-ui" id="visualselector">
|
||||
|
||||
@@ -15,14 +15,18 @@
|
||||
<div>
|
||||
{{ render_simple_field(form.url, placeholder="https://...", required=true) }}
|
||||
{{ render_simple_field(form.tag, value=active_tag if active_tag else '', placeholder="watch group") }}
|
||||
<span>
|
||||
{{ render_simple_field(form.watch_submit_button, title="Watch this URL!" ) }}
|
||||
{{ render_simple_field(form.edit_and_watch_submit_button, title="Edit first then Watch") }}
|
||||
</span>
|
||||
{% if webdriver_enabled %}
|
||||
<br/>
|
||||
{{ render_field(form.fetch_processor) }}
|
||||
<div id="quickwatch-fetch-processor">
|
||||
{{ render_field(form.fetch_processor) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div>
|
||||
{{ render_simple_field(form.watch_submit_button, title="Watch this URL!" ) }}
|
||||
{{ render_simple_field(form.edit_and_watch_submit_button, title="Edit first then Watch") }}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
@@ -95,7 +99,7 @@
|
||||
<a href="{{url_for('form_share_put_watch', uuid=watch.uuid)}}"><img style="height: 1em;display:inline-block;" src="{{url_for('static_content', group='images', filename='spread.svg')}}" /></a>
|
||||
|
||||
{%if watch.fetch_backend == "html_webdriver" %}<img style="height: 1em; display:inline-block;" src="{{url_for('static_content', group='images', filename='Google-Chrome-icon.png')}}" />{% endif %}
|
||||
|
||||
{%if watch.fetch_processor == "image" %}<img style="height: 1em; display:inline-block;" src="{{url_for('static_content', group='images', filename='picture-frame.svg')}}" />{% endif %}
|
||||
{% if watch.last_error is defined and watch.last_error != False %}
|
||||
<div class="fetch-error">{{ watch.last_error }}</div>
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user