Skip to content

Commit

Permalink
Merge branch 'master' into use-pyppeteerstealth
Browse files Browse the repository at this point in the history
  • Loading branch information
dgtlmoon committed May 17, 2024
2 parents df3dae1 + add2c65 commit a4150b9
Show file tree
Hide file tree
Showing 55 changed files with 695 additions and 414 deletions.
4 changes: 4 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ updates:
directory: /
schedule:
interval: "weekly"
"caronc/apprise":
versioning-strategy: "increase"
schedule:
interval: "daily"
groups:
all:
patterns:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test-only.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ jobs:
echo "run test with unittest"
docker run test-changedetectionio bash -c 'python3 -m unittest changedetectionio.tests.unit.test_notification_diff'
docker run test-changedetectionio bash -c 'python3 -m unittest changedetectionio.tests.unit.test_watch_model'
docker run test-changedetectionio bash -c 'python3 -m unittest changedetectionio.tests.unit.test_jinja2_security'
# All tests
echo "run test with pytest"
Expand Down
8 changes: 1 addition & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,13 +257,7 @@ Supports managing the website watch list [via our API](https://changedetection.i
Do you use changedetection.io to make money? does it save you time or money? Does it make your life easier? less stressful? Remember, we write this software when we should be doing actual paid work, we have to buy food and pay rent just like you.


Firstly, consider taking out an officially supported [website change detection subscription](https://changedetection.io?src=github) , even if you don't use it, you still get the warm fuzzy feeling of helping out the project. (And who knows, you might just use it!)

Or directly donate an amount PayPal [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/donate/?hosted_button_id=7CP6HR9ZCNDYJ)

Or BTC `1PLFN327GyUarpJd7nVe7Reqg9qHx5frNn`

<img src="https://raw.githubusercontent.com/dgtlmoon/changedetection.io/master/docs/btc-support.png" style="max-width:50%;" alt="Support us!" />
Consider taking out an officially supported [website change detection subscription](https://changedetection.io?src=github) , even if you don't use it, you still get the warm fuzzy feeling of helping out the project. (And who knows, you might just use it!)

## Commercial Support

Expand Down
7 changes: 4 additions & 3 deletions changedetectionio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

# Read more https://github.com/dgtlmoon/changedetection.io/wiki

__version__ = '0.45.16'
__version__ = '0.45.22'

from distutils.util import strtobool
from changedetectionio.strtobool import strtobool
from json.decoder import JSONDecodeError
import os
#os.environ['EVENTLET_NO_GREENDNS'] = 'yes'
os.environ['EVENTLET_NO_GREENDNS'] = 'yes'
import eventlet
import eventlet.wsgi
import getopt
Expand Down Expand Up @@ -175,6 +175,7 @@ def hide_referrer(response):
# proxy_set_header Host "localhost";
# proxy_set_header X-Forwarded-Prefix /app;


if os.getenv('USE_X_SETTINGS'):
logger.info("USE_X_SETTINGS is ENABLED")
from werkzeug.middleware.proxy_fix import ProxyFix
Expand Down
2 changes: 1 addition & 1 deletion changedetectionio/api/api_v1.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import os
from distutils.util import strtobool
from changedetectionio.strtobool import strtobool

from flask_expects_json import expects_json
from changedetectionio import queuedWatchMetaData
Expand Down
11 changes: 4 additions & 7 deletions changedetectionio/blueprint/browser_steps/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#
#

from distutils.util import strtobool
from changedetectionio.strtobool import strtobool
from flask import Blueprint, request, make_response
import os

Expand Down Expand Up @@ -84,7 +84,9 @@ def start_browsersteps_session(watch_uuid):
# Tell Playwright to connect to Chrome and setup a new session via our stepper interface
browsersteps_start_session['browserstepper'] = browser_steps.browsersteps_live_ui(
playwright_browser=browsersteps_start_session['browser'],
proxy=proxy)
proxy=proxy,
start_url=datastore.data['watching'][watch_uuid].get('url')
)

# For test
#browsersteps_start_session['browserstepper'].action_goto_url(value="http://example.com?time="+str(time.time()))
Expand Down Expand Up @@ -167,11 +169,6 @@ def browsersteps_ui_update():
step_n = int(request.form.get('step_n'))
is_last_step = strtobool(request.form.get('is_last_step'))

if step_operation == 'Goto site':
step_operation = 'goto_url'
step_optional_value = datastore.data['watching'][uuid].get('url')
step_selector = None

# @todo try.. accept.. nice errors not popups..
try:

Expand Down
18 changes: 13 additions & 5 deletions changedetectionio/blueprint/browser_steps/browser_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from loguru import logger

from changedetectionio.content_fetchers.base import manage_user_agent
from changedetectionio.safe_jinja import render as jinja_render

# Two flags, tell the JS which of the "Selector" or "Value" field should be enabled in the front end
# 0- off, 1- on
Expand Down Expand Up @@ -48,6 +49,10 @@
# ONLY Works in Playwright because we need the fullscreen screenshot
class steppable_browser_interface():
page = None
start_url = None

def __init__(self, start_url):
self.start_url = start_url

# Convert and perform "Click Button" for example
def call_action(self, action_name, selector=None, optional_value=None):
Expand All @@ -64,14 +69,12 @@ def call_action(self, action_name, selector=None, optional_value=None):
action_handler = getattr(self, "action_" + call_action_name)

# Support for Jinja2 variables in the value and selector
from jinja2 import Environment
jinja2_env = Environment(extensions=['jinja2_time.TimeExtension'])

if selector and ('{%' in selector or '{{' in selector):
selector = str(jinja2_env.from_string(selector).render())
selector = jinja_render(template_str=selector)

if optional_value and ('{%' in optional_value or '{{' in optional_value):
optional_value = str(jinja2_env.from_string(optional_value).render())
optional_value = jinja_render(template_str=optional_value)

action_handler(selector, optional_value)
self.page.wait_for_timeout(1.5 * 1000)
Expand All @@ -88,6 +91,10 @@ def action_goto_url(self, selector=None, value=None):
logger.debug(f"Time to goto URL {time.time()-now:.2f}s")
return response

# Incase they request to go back to the start
def action_goto_site(self, selector=None, value=None):
return self.action_goto_url(value=self.start_url)

def action_click_element_containing_text(self, selector=None, value=''):
if not len(value.strip()):
return
Expand Down Expand Up @@ -195,10 +202,11 @@ class browsersteps_live_ui(steppable_browser_interface):

browser_type = os.getenv("PLAYWRIGHT_BROWSER_TYPE", 'chromium').strip('"')

def __init__(self, playwright_browser, proxy=None, headers=None):
def __init__(self, playwright_browser, proxy=None, headers=None, start_url=None):
self.headers = headers or {}
self.age_start = time.time()
self.playwright_browser = playwright_browser
self.start_url = start_url
if self.context is None:
self.connect(proxy=proxy)

Expand Down
6 changes: 4 additions & 2 deletions changedetectionio/blueprint/check_proxies/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ def long_task(uuid, preferred_proxy):
import time
from changedetectionio.content_fetchers import exceptions as content_fetcher_exceptions
from changedetectionio.processors import text_json_diff
from changedetectionio.safe_jinja import render as jinja_render

status = {'status': '', 'length': 0, 'text': ''}
from jinja2 import Environment, BaseLoader

contents = ''
now = time.time()
Expand Down Expand Up @@ -64,7 +64,9 @@ def long_task(uuid, preferred_proxy):
status.update({'status': 'OK', 'length': len(contents), 'text': ''})

if status.get('text'):
status['text'] = Environment(loader=BaseLoader()).from_string('{{text|e}}').render({'text': status['text']})
# parse 'text' as text for safety
v = {'text': status['text']}
status['text'] = jinja_render(template_str='{{text|e}}', **v)

status['time'] = "{:.2f}s".format(time.time() - now)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

from distutils.util import strtobool
from changedetectionio.strtobool import strtobool
from flask import Blueprint, flash, redirect, url_for
from flask_login import login_required
from changedetectionio.store import ChangeDetectionStore
Expand Down
8 changes: 7 additions & 1 deletion changedetectionio/blueprint/tags/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@ def tags_overview_page():
from .form import SingleTag
add_form = SingleTag(request.form)
sorted_tags = sorted(datastore.data['settings']['application'].get('tags').items(), key=lambda x: x[1]['title'])

from collections import Counter

tag_count = Counter(tag for watch in datastore.data['watching'].values() if watch.get('tags') for tag in watch['tags'])

output = render_template("groups-overview.html",
form=add_form,
available_tags=sorted_tags,
form=add_form,
tag_count=tag_count
)

return output
Expand Down
6 changes: 3 additions & 3 deletions changedetectionio/blueprint/tags/templates/edit-tag.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{% extends 'base.html' %}
{% block content %}
{% from '_helpers.jinja' import render_field, render_checkbox_field, render_button %}
{% from '_common_fields.jinja' import render_common_settings_form %}
{% from '_helpers.html' import render_field, render_checkbox_field, render_button %}
{% from '_common_fields.html' import render_common_settings_form %}
<script>
const notification_base_url="{{url_for('ajax_callback_send_notification_test', watch_uuid=uuid)}}";
const notification_base_url="{{url_for('ajax_callback_send_notification_test', mode="group-settings")}}";
</script>

<script src="{{url_for('static_content', group='js', filename='tabs.js')}}" defer></script>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% extends 'base.html' %}
{% block content %}
{% from '_helpers.jinja' import render_simple_field, render_field %}
{% from '_helpers.html' import render_simple_field, render_field %}
<script src="{{url_for('static_content', group='js', filename='jquery-3.6.0.min.js')}}"></script>

<div class="box">
Expand All @@ -27,6 +27,7 @@
<thead>
<tr>
<th></th>
<th># Watches</th>
<th>Tag / Label name</th>
<th></th>
</tr>
Expand All @@ -45,7 +46,8 @@
<td class="watch-controls">
<a class="link-mute state-{{'on' if tag.notification_muted else 'off'}}" href="{{url_for('tags.mute', uuid=tag.uuid)}}"><img src="{{url_for('static_content', group='images', filename='bell-off.svg')}}" alt="Mute notifications" title="Mute notifications" class="icon icon-mute" ></a>
</td>
<td class="title-col inline">{{tag.title}}</td>
<td>{{ "{:,}".format(tag_count[uuid]) if uuid in tag_count else 0 }}</td>
<td class="title-col inline"> <a href="{{url_for('index', tag=uuid) }}">{{ tag.title }}</a></td>
<td>
<a class="pure-button pure-button-primary" href="{{ url_for('tags.form_tag_edit', uuid=uuid) }}">Edit</a>&nbsp;
<a class="pure-button pure-button-primary" href="{{ url_for('tags.delete', uuid=uuid) }}" title="Deletes and removes tag">Delete</a>
Expand Down
2 changes: 1 addition & 1 deletion changedetectionio/content_fetchers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
from distutils.util import strtobool
from changedetectionio.strtobool import strtobool
from loguru import logger
from changedetectionio.content_fetchers.exceptions import BrowserStepsStepException
import os
Expand Down
22 changes: 12 additions & 10 deletions changedetectionio/content_fetchers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,24 +112,26 @@ def get_all_headers(self):

def browser_steps_get_valid_steps(self):
if self.browser_steps is not None and len(self.browser_steps):
valid_steps = filter(
lambda s: (s['operation'] and len(s['operation']) and s['operation'] != 'Choose one' and s['operation'] != 'Goto site'),
self.browser_steps)
valid_steps = list(filter(
lambda s: (s['operation'] and len(s['operation']) and s['operation'] != 'Choose one'),
self.browser_steps))

# Just incase they selected Goto site by accident with older JS
if valid_steps and valid_steps[0]['operation'] == 'Goto site':
del(valid_steps[0])

return valid_steps

return None

def iterate_browser_steps(self):
def iterate_browser_steps(self, start_url=None):
from changedetectionio.blueprint.browser_steps.browser_steps import steppable_browser_interface
from playwright._impl._errors import TimeoutError, Error
from jinja2 import Environment
jinja2_env = Environment(extensions=['jinja2_time.TimeExtension'])

from changedetectionio.safe_jinja import render as jinja_render
step_n = 0

if self.browser_steps is not None and len(self.browser_steps):
interface = steppable_browser_interface()
interface = steppable_browser_interface(start_url=start_url)
interface.page = self.page
valid_steps = self.browser_steps_get_valid_steps()

Expand All @@ -143,9 +145,9 @@ def iterate_browser_steps(self):
selector = step['selector']
# Support for jinja2 template in step values, with date module added
if '{%' in step['optional_value'] or '{{' in step['optional_value']:
optional_value = str(jinja2_env.from_string(step['optional_value']).render())
optional_value = jinja_render(template_str=step['optional_value'])
if '{%' in step['selector'] or '{{' in step['selector']:
selector = str(jinja2_env.from_string(step['selector']).render())
selector = jinja_render(template_str=step['selector'])

getattr(interface, "call_action")(action_name=step['operation'],
selector=selector,
Expand Down
4 changes: 2 additions & 2 deletions changedetectionio/content_fetchers/playwright.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def run(self,

# Re-use as much code from browser steps as possible so its the same
from changedetectionio.blueprint.browser_steps.browser_steps import steppable_browser_interface
browsersteps_interface = steppable_browser_interface()
browsersteps_interface = steppable_browser_interface(start_url=url)
browsersteps_interface.page = self.page

response = browsersteps_interface.action_goto_url(value=url)
Expand Down Expand Up @@ -172,7 +172,7 @@ def run(self,

# Run Browser Steps here
if self.browser_steps_get_valid_steps():
self.iterate_browser_steps()
self.iterate_browser_steps(start_url=url)

self.page.wait_for_timeout(extra_wait * 1000)

Expand Down
Loading

0 comments on commit a4150b9

Please sign in to comment.