Merge pull request #196488 from SuperSandro2000/changedetectionio

This commit is contained in:
Sandro 2022-10-20 20:25:36 +02:00 committed by GitHub
commit 89e49d87d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 683 additions and 22 deletions

View file

@ -1072,6 +1072,7 @@
./services/web-apps/calibre-web.nix
./services/web-apps/code-server.nix
./services/web-apps/baget.nix
./services/web-apps/changedetection-io.nix
./services/web-apps/convos.nix
./services/web-apps/dex.nix
./services/web-apps/discourse.nix

View file

@ -0,0 +1,218 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.changedetection-io;
in
{
options.services.changedetection-io = {
enable = mkEnableOption (lib.mdDoc "changedetection-io");
user = mkOption {
default = "changedetection-io";
type = types.str;
description = lib.mdDoc ''
User account under which changedetection-io runs.
'';
};
group = mkOption {
default = "changedetection-io";
type = types.str;
description = lib.mdDoc ''
Group account under which changedetection-io runs.
'';
};
listenAddress = mkOption {
type = types.str;
default = "localhost";
description = lib.mdDoc "Address the server will listen on.";
};
port = mkOption {
type = types.port;
default = 5000;
description = lib.mdDoc "Port the server will listen on.";
};
datastorePath = mkOption {
type = types.str;
default = "/var/lib/changedetection-io";
description = lib.mdDoc ''
The directory used to store all data for changedetection-io.
'';
};
baseURL = mkOption {
type = types.nullOr types.str;
default = null;
example = "https://changedetection-io.example";
description = lib.mdDoc ''
The base url used in notifications and `{base_url}` token.
'';
};
behindProxy = mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
Enable this option when changedetection-io runs behind a reverse proxy, so that it trusts X-* headers.
It is recommend to run changedetection-io behind a TLS reverse proxy.
'';
};
environmentFile = mkOption {
type = types.nullOr types.path;
default = null;
example = "/run/secrets/changedetection-io.env";
description = lib.mdDoc ''
Securely pass environment variabels to changedetection-io.
This can be used to set for example a frontend password reproducible via `SALTED_PASS`
which convinetly also deactivates nags about the hosted version.
`SALTED_PASS` should be 64 characters long while the first 32 are the salt and the second the frontend password.
It can easily be retrieved from the settings file when first set via the frontend with the following command:
``jq -r .settings.application.password /var/lib/changedetection-io/url-watches.json``
'';
};
webDriverSupport = mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
Enable support for fetching web pages using WebDriver and Chromium.
This starts a headless chromium controlled by puppeteer in an oci container.
::: {.note}
Playwright can currently leak memory.
See https://github.com/dgtlmoon/changedetection.io/wiki/Playwright-content-fetcher#playwright-memory-leak
:::
'';
};
playwrightSupport = mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
Enable support for fetching web pages using playwright and Chromium.
This starts a headless Chromium controlled by puppeteer in an oci container.
::: {.note}
Playwright can currently leak memory.
See https://github.com/dgtlmoon/changedetection.io/wiki/Playwright-content-fetcher#playwright-memory-leak
:::
'';
};
chromePort = mkOption {
type = types.port;
default = 4444;
description = lib.mdDoc ''
A free port on which webDriverSupport or playwrightSupport listen on localhost.
'';
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = !((cfg.webDriverSupport == true) && (cfg.playwrightSupport == true));
message = "'services.changedetection-io.webDriverSupport' and 'services.changedetion-io.playwrightSupport' cannot be used together.";
}
];
systemd = let
defaultStateDir = cfg.datastorePath == "/var/lib/changedetection-io";
in {
services.changedetection-io = {
wantedBy = [ "mutli-user.target" ];
after = [ "network.target" ];
preStart = ''
mkdir -p ${cfg.datastorePath}
'';
serviceConfig = {
User = cfg.user;
Group = cfg.group;
StateDirectory = mkIf defaultStateDir "changedetion-io";
StateDirectoryMode = mkIf defaultStateDir "0750";
WorkingDirectory = cfg.datastorePath;
Environment = lib.optional (cfg.baseURL != null) "BASE_URL=${cfg.baseURL}"
++ lib.optional cfg.behindProxy "USE_X_SETTINGS=1"
++ lib.optional cfg.webDriverSupport "WEBDRIVER_URL=http://127.0.0.1:${toString cfg.chromePort}/wd/hub"
++ lib.optional cfg.playwrightSupport "PLAYWRIGHT_DRIVER_URL=ws://127.0.0.1:${toString cfg.chromePort}/?stealth=1&--disable-web-security=true";
EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile;
ExecStart = ''
${pkgs.changedetection-io}/bin/changedetection.py \
-h ${cfg.listenAddress} -p ${toString cfg.port} -d ${cfg.datastorePath}
'';
ProtectHome = true;
ProtectSystem = true;
Restart = "on-failure";
};
};
tmpfiles.rules = mkIf defaultStateDir [
"d ${cfg.datastorePath} 0750 ${cfg.user} ${cfg.group} - -"
];
};
users = {
users = optionalAttrs (cfg.user == "changedetection-io") {
"changedetection-io" = {
isSystemUser = true;
group = "changedetection-io";
};
};
groups = optionalAttrs (cfg.group == "changedetection-io") {
"changedetection-io" = { };
};
};
virtualisation = {
oci-containers.containers = lib.mkMerge [
(mkIf cfg.webDriverSupport {
changedetection-io-webdriver = {
image = "selenium/standalone-chrome";
environment = {
VNC_NO_PASSWORD = "1";
SCREEN_WIDTH = "1920";
SCREEN_HEIGHT = "1080";
SCREEN_DEPTH = "24";
};
ports = [
"127.0.0.1:${toString cfg.chromePort}:4444"
];
volumes = [
"/dev/shm:/dev/shm"
];
extraOptions = [ "--network=bridge" ];
};
})
(mkIf cfg.playwrightSupport {
changedetection-io-playwright = {
image = "browserless/chrome";
environment = {
SCREEN_WIDTH = "1920";
SCREEN_HEIGHT = "1024";
SCREEN_DEPTH = "16";
ENABLE_DEBUGGER = "false";
PREBOOT_CHROME = "true";
CONNECTION_TIMEOUT = "300000";
MAX_CONCURRENT_SESSIONS = "10";
CHROME_REFRESH_TIME = "600000";
DEFAULT_BLOCK_ADS = "true";
DEFAULT_STEALTH = "true";
};
ports = [
"127.0.0.1:${toString cfg.chromePort}:3000"
];
extraOptions = [ "--network=bridge" ];
};
})
];
};
};
}

View file

@ -42,7 +42,7 @@ buildPythonApplication rec {
click-plugins
elasticsearch
flask-compress
flask_login
flask-login
flask-wtf
html2text
python-dotenv

View file

@ -95,7 +95,7 @@ let
flask
flask-babel
flask_assets
flask_login
flask-login
flask-limiter
frozendict
future

View file

@ -60,7 +60,7 @@ python3Packages.buildPythonApplication rec {
cherrypy
flask-compress
flask-cors
flask_login
flask-login
flask-restful
flask-restx
flask

View file

@ -18,7 +18,7 @@ let
};
pythonDeps = with python.pkgs; [
flask flask_assets flask_login flask-sqlalchemy flask_migrate flask-seasurf flask_mail flask-session flask-sslify
flask flask_assets flask-login flask-sqlalchemy flask_migrate flask-seasurf flask_mail flask-session flask-sslify
mysqlclient psycopg2 sqlalchemy
cffi configobj cryptography bcrypt requests python-ldap pyotp qrcode dnspython
gunicorn python3-saml pytz cssmin rjsmin authlib bravado-core

View file

@ -20,7 +20,7 @@
, deprecated
, dill
, flask
, flask_login
, flask-login
, flask-appbuilder
, flask-caching
, flask-session
@ -159,7 +159,7 @@ buildPythonPackage rec {
flask-caching
flask-session
flask-wtf
flask_login
flask-login
GitPython
graphviz
gunicorn

View file

@ -8,7 +8,7 @@
, email-validator
, flask
, flask-babel
, flask_login
, flask-login
, flask-openid
, flask-sqlalchemy
, flask-wtf
@ -59,7 +59,7 @@ buildPythonPackage rec {
email-validator
flask
flask-babel
flask_login
flask-login
flask-openid
flask-sqlalchemy
flask-wtf

View file

@ -25,7 +25,7 @@
, blinker
, email-validator
, flask
, flask_login
, flask-login
, flask_principal
, flask-wtf
, itsdangerous
@ -57,7 +57,7 @@ buildPythonPackage rec {
blinker
email-validator
flask
flask_login
flask-login
flask_principal
flask-wtf
itsdangerous

View file

@ -0,0 +1,38 @@
{ lib
, buildPythonPackage
, fetchFromGitHub
, lxml
, pytestCheckHook
, requests
}:
buildPythonPackage rec {
pname = "inscriptis";
version = "2.3.1";
format = "setuptools";
src = fetchFromGitHub {
owner = "weblyzard";
repo = "inscriptis";
rev = version;
sha256 = "sha256-an/FTbujN2VnTYa0wngM8ugV1LNHJWM32RVqIbaW0KY=";
};
propagatedBuildInputs = [
lxml
requests
];
checkInputs = [
pytestCheckHook
];
pythonImportsCheck = [ "inscriptis" ];
meta = with lib; {
description = "inscriptis - HTML to text converter";
homepage = "https://github.com/weblyzard/inscriptis";
license = licenses.asl20;
maintainers = with maintainers; [ SuperSandro2000 ];
};
}

View file

@ -9,13 +9,14 @@
buildPythonPackage rec {
pname = "jsonpath-ng";
version = "1.5.2";
version = "1.5.3";
src = fetchFromGitHub {
owner = "h2non";
repo = pname;
rev = "v${version}";
sha256 = "1cxjwhx0nj85a3awnl7j6afnk07awzv45qfwxl5jqbbc9cxh5bd6";
# missing tag https://github.com/h2non/jsonpath-ng/issues/114
rev = "cce4a3d4063ac8af928795acc53beb27a2bfd101";
sha256 = "sha256-+9iQHQs5TQhZFeIqMlsa3FFPfZEktAWy1lSdJU7kZrc=";
};
propagatedBuildInputs = [

View file

@ -0,0 +1,221 @@
{ lib
, stdenv
, buildPythonPackage
, chromium
, ffmpeg
, firefox
, git
, greenlet
, jq
, nodejs
, fetchFromGitHub
, fetchurl
, makeFontsConf
, makeWrapper
, pyee
, python
, pythonOlder
, runCommand
, setuptools-scm
, unzip
}:
let
inherit (stdenv.hostPlatform) system;
throwSystem = throw "Unsupported system: ${system}";
driverVersion = "1.27.1";
driver = let
suffix = {
x86_64-linux = "linux";
aarch64-linux = "linux-arm64";
x86_64-darwin = "mac";
aarch64-darwin = "mac-arm64";
}.${system} or throwSystem;
filename = "playwright-${driverVersion}-${suffix}.zip";
in stdenv.mkDerivation {
pname = "playwright-driver";
version = driverVersion;
src = fetchurl {
url = "https://playwright.azureedge.net/builds/driver/${filename}";
sha256 = {
x86_64-linux = "0x71b4kb8hlyacixipgfbgjgrbmhckxpbmrs2xk8iis7n5kg7539";
aarch64-linux = "125lih7g2gj91k7j196wy5a5746wyfr8idj3ng369yh5wl7lfcfv";
x86_64-darwin = "0z2kww4iby1izkwn6z2ai94y87bkjvwak8awdmjm8sgg00pa9l1a";
aarch64-darwin = "0qajh4ac5lr1sznb2c471r5c5g2r0dk2pyqz8vhvnbk36r524h1h";
}.${system} or throwSystem;
};
sourceRoot = ".";
nativeBuildInputs = [ unzip ];
postPatch = ''
# Use Nix's NodeJS instead of the bundled one.
substituteInPlace playwright.sh --replace '"$SCRIPT_PATH/node"' '"${nodejs}/bin/node"'
rm node
# Hard-code the script path to $out directory to avoid a dependency on coreutils
substituteInPlace playwright.sh \
--replace 'SCRIPT_PATH="$(cd "$(dirname "$0")" ; pwd -P)"' "SCRIPT_PATH=$out"
patchShebangs playwright.sh package/bin/*.sh
'';
installPhase = ''
runHook preInstall
mkdir -p $out/bin
mv playwright.sh $out/bin/playwright
mv package $out/
runHook postInstall
'';
passthru = {
inherit filename;
};
};
browsers-mac = stdenv.mkDerivation {
pname = "playwright-browsers";
version = driverVersion;
src = runCommand "playwright-browsers-base" {
outputHashMode = "recursive";
outputHashAlgo = "sha256";
outputHash = {
x86_64-darwin = "0z2kww4iby1izkwn6z2ai94y87bkjvwak8awdmjm8sgg00pa9l1a";
}.${system} or throwSystem;
} ''
export PLAYWRIGHT_BROWSERS_PATH=$out
${driver}/bin/playwright install
rm -r $out/.links
'';
installPhase = ''
mkdir $out
cp -r * $out/
'';
};
browsers-linux = { withFirefox ? true, withChromium ? true }: let
fontconfig = makeFontsConf {
fontDirectories = [];
};
in runCommand ("playwright-browsers"
+ lib.optionalString (withFirefox && !withChromium) "-firefox"
+ lib.optionalString (!withFirefox && withChromium) "-chromium")
{
nativeBuildInputs = [
makeWrapper
jq
];
} (''
BROWSERS_JSON=${driver}/share/playwright-driver/package/browsers.json
'' + lib.optionalString withChromium ''
CHROMIUM_REVISION=$(jq -r '.browsers[] | select(.name == "chromium").revision' $BROWSERS_JSON)
mkdir -p $out/chromium-$CHROMIUM_REVISION/chrome-linux
# See here for the Chrome options:
# https://github.com/NixOS/nixpkgs/issues/136207#issuecomment-908637738
makeWrapper ${chromium}/bin/chromium $out/chromium-$CHROMIUM_REVISION/chrome-linux/chrome \
--set SSL_CERT_FILE /etc/ssl/certs/ca-bundle.crt \
--set FONTCONFIG_FILE ${fontconfig}
'' + lib.optionalString withFirefox ''
FIREFOX_REVISION=$(jq -r '.browsers[] | select(.name == "firefox").revision' $BROWSERS_JSON)
mkdir -p $out/firefox-$FIREFOX_REVISION
ln -s ${firefox}/bin/firefox $out/firefox-$FIREFOX_REVISION/firefox
'' + ''
FFMPEG_REVISION=$(jq -r '.browsers[] | select(.name == "ffmpeg").revision' $BROWSERS_JSON)
mkdir -p $out/ffmpeg-$FFMPEG_REVISION
ln -s ${ffmpeg}/bin/ffmpeg $out/ffmpeg-$FFMPEG_REVISION/ffmpeg-linux
'');
in
buildPythonPackage rec {
pname = "playwright";
version = "1.27.1";
format = "setuptools";
disabled = pythonOlder "3.7";
src = fetchFromGitHub {
owner = "microsoft";
repo = "playwright-python";
rev = "v${version}";
sha256 = "sha256-cI/4GdkmTikoP9O0Skh/0jCxxRypRua0231iKcxtBcY=";
};
patches = [
# This patches two things:
# - The driver location, which is now a static package in the Nix store.
# - The setup script, which would try to download the driver package from
# a CDN and patch wheels so that they include it. We don't want this
# we have our own driver build.
./driver-location.patch
];
postPatch = ''
# if setuptools_scm is not listing files via git almost all python files are excluded
export HOME=$(mktemp -d)
git init .
git add -A .
git config --global user.email "nixpkgs"
git config --global user.name "nixpkgs"
git commit -m "workaround setuptools-scm"
substituteInPlace setup.py \
--replace "greenlet==1.1.3" "greenlet>=1.1.3" \
--replace "pyee==8.1.0" "pyee>=8.1.0" \
--replace "setuptools-scm==7.0.5" "setuptools-scm>=7.0.5" \
--replace "wheel==0.37.1" "wheel>=0.37.1"
# Skip trying to download and extract the driver.
# This is done manually in postInstall instead.
substituteInPlace setup.py \
--replace "self._download_and_extract_local_driver(base_wheel_bundles)" ""
# Set the correct driver path with the help of a patch in patches
substituteInPlace playwright/_impl/_driver.py \
--replace "@driver@" "${driver}/bin/playwright"
'';
nativeBuildInputs = [ git setuptools-scm ];
propagatedBuildInputs = [
greenlet
pyee
];
postInstall = ''
ln -s ${driver} $out/${python.sitePackages}/playwright/driver
'';
# Skip tests because they require network access.
doCheck = false;
pythonImportsCheck = [
"playwright"
];
passthru = {
inherit driver;
browsers = {
x86_64-linux = browsers-linux { };
aarch64-linux = browsers-linux { };
x86_64-darwin = browsers-mac;
aarch64-darwin = browsers-mac;
}.${system} or throwSystem;
browsers-chromium = browsers-linux { withFirefox = false; };
browsers-firefox = browsers-linux { withChromium = false; };
};
meta = with lib; {
description = "Python version of the Playwright testing and automation library";
homepage = "https://github.com/microsoft/playwright-python";
license = licenses.asl20;
maintainers = with maintainers; [ techknowlogick yrd SuperSandro2000 ];
};
}

View file

@ -0,0 +1,47 @@
diff --git a/playwright/_impl/_driver.py b/playwright/_impl/_driver.py
index f3b911f..d00e509 100644
--- a/playwright/_impl/_driver.py
+++ b/playwright/_impl/_driver.py
@@ -23,11 +23,7 @@ from playwright._repo_version import version
def compute_driver_executable() -> Path:
- package_path = Path(inspect.getfile(playwright)).parent
- platform = sys.platform
- if platform == "win32":
- return package_path / "driver" / "playwright.cmd"
- return package_path / "driver" / "playwright.sh"
+ return Path("@driver@")
if sys.version_info.major == 3 and sys.version_info.minor == 7:
diff --git a/setup.py b/setup.py
index 3487a6a..05112c2 100644
--- a/setup.py
+++ b/setup.py
@@ -141,25 +141,8 @@ class PlaywrightBDistWheelCommand(BDistWheelCommand):
base_wheel_location: str = glob.glob(os.path.join(self.dist_dir, "*.whl"))[0]
without_platform = base_wheel_location[:-7]
for wheel_bundle in wheels:
- download_driver(wheel_bundle["zip_name"])
- zip_file = (
- f"driver/playwright-{driver_version}-{wheel_bundle['zip_name']}.zip"
- )
- with zipfile.ZipFile(zip_file, "r") as zip:
- extractall(zip, f"driver/{wheel_bundle['zip_name']}")
wheel_location = without_platform + wheel_bundle["wheel"]
shutil.copy(base_wheel_location, wheel_location)
- with zipfile.ZipFile(wheel_location, "a") as zip:
- driver_root = os.path.abspath(f"driver/{wheel_bundle['zip_name']}")
- for dir_path, _, files in os.walk(driver_root):
- for file in files:
- from_path = os.path.join(dir_path, file)
- to_path = os.path.relpath(from_path, driver_root)
- zip.write(from_path, f"playwright/driver/{to_path}")
- zip.writestr(
- "playwright/driver/README.md",
- f"{wheel_bundle['wheel']} driver package",
- )
os.remove(base_wheel_location)
if InWheel:
for whlfile in glob.glob(os.path.join(self.dist_dir, "*.whl")):

View file

@ -0,0 +1,31 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p curl gnused nix-prefetch common-updater-scripts
set -euo pipefail
root="$(dirname "$(readlink -f "$0")")"
version=$(curl ${GITHUB_TOKEN:+" -u \":$GITHUB_TOKEN\""} -s https://api.github.com/repos/microsoft/playwright-python/releases/latest | jq -r '.tag_name | sub("^v"; "")')
# Most of the time, this should be the latest stable release of the Node-based
# Playwright version, but that isn't a guarantee, so this needs to be specified
# as well:
setup_py_url="https://github.com/microsoft/playwright-python/raw/v${version}/setup.py"
driver_version=$(curl -Ls "$setup_py_url" | grep '^driver_version =' | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+')
fetch_driver_arch() {
nix-prefetch-url "https://playwright.azureedge.net/builds/driver/playwright-${version}-${1}.zip"
}
replace_sha() {
sed -i "s|$1 = \".\{44,52\}\"|$1 = \"$2\"|" "$root/default.nix"
}
# Replace SHAs for the driver downloads
replace_sha "x86_64-linux" "$(fetch_driver_arch "linux")"
replace_sha "x86_64-darwin" "$(fetch_driver_arch "mac")"
replace_sha "aarch64-linux" "$(fetch_driver_arch "linux-arm64")"
replace_sha "aarch64-darwin" "$(fetch_driver_arch "mac-arm64")"
# Update the version stamps
sed -i "s/driverVersion = \"[^\$]*\"/driverVersion = \"$driver_version\"/" "$root/default.nix"
update-source-version playwright "$version" --rev="v$version"

View file

@ -12,14 +12,15 @@
buildPythonPackage rec {
pname = "selenium";
version = "4.4.2";
version = "4.5.0";
disabled = pythonOlder "3.7";
src = fetchFromGitHub {
owner = "SeleniumHQ";
repo = "selenium";
rev = "refs/tags/selenium-${version}-python"; # check if there is a newer tag with -python suffix
hash = "sha256-sJJ3i4mnGp5fDgo64p6B2vRCqp/Wm99VoyRLyy4nBH8=";
# check if there is a newer tag with or without -python suffix
rev = "refs/tags/selenium-${version}";
hash = "sha256-K90CQYTeX9GKpP0ahxLx2HO5HG0P6MN7jeWmHtfiOns=";
};
postPatch = ''
@ -50,6 +51,6 @@ buildPythonPackage rec {
description = "Bindings for Selenium WebDriver";
homepage = "https://selenium.dev/";
license = licenses.asl20;
maintainers = with maintainers; [ jraygauthier ];
maintainers = with maintainers; [ jraygauthier SuperSandro2000 ];
};
}

View file

@ -19,7 +19,7 @@
, django
, falcon
, flask
, flask_login
, flask-login
, httpx
, pure-eval
, pyramid

View file

@ -2,7 +2,7 @@
, fetchPypi
, buildPythonPackage
, flask
, flask_login
, flask-login
, flask-sqlalchemy
, flexmock
, pytestCheckHook
@ -32,7 +32,7 @@ buildPythonPackage rec {
pytestCheckHook
sqlalchemy-i18n
flask
flask_login
flask-login
flask-sqlalchemy
flexmock
];

View file

@ -0,0 +1,92 @@
{ lib
, fetchFromGitHub
, python3
}:
let
py = python3.override {
packageOverrides = final: prev: {
flask = prev.flask.overridePythonAttrs (old: rec {
version = "2.1.3";
src = old.src.override {
inherit version;
sha256 = "sha256-FZcuUBffBXXD1sCQuhaLbbkCWeYgrI1+qBOjlrrVtss=";
};
});
flask-restful = prev.flask-restful.overridePythonAttrs (old: rec {
disabledTests = old.disabledTests or [ ] ++ [
# fails because of flask or werkzeug downgrade
"test_redirect"
];
});
werkzeug = prev.werkzeug.overridePythonAttrs (old: rec {
version = "2.0.3";
src = old.src.override {
inherit version;
sha256 = "sha256-uGP4/wV8UiFktgZ8niiwQRYbS+W6TQ2s7qpQoWOCLTw=";
};
});
};
};
in
py.pkgs.buildPythonApplication rec {
pname = "changedetection-io";
version = "0.39.20.3";
format = "setuptools";
src = fetchFromGitHub {
owner = "dgtlmoon";
repo = "changedetection.io";
rev = version;
sha256 = "sha256-0Sv/1YoZuSnslQgMOu+uHTxb9QewXPC0tLAvzJA4Aa8=";
};
postPatch = ''
substituteInPlace requirements.txt \
--replace "bs4" "beautifulsoup4" \
--replace "cryptography ~= 3.4" "cryptography" \
--replace "selenium ~= 4.1.0" "selenium"
'';
propagatedBuildInputs = with py.pkgs; [
flask
flask-wtf
eventlet
validators
timeago
inscriptis
feedgen
flask-login
flask-restful
pytz
brotli
requests
urllib3
chardet
wtforms
jsonpath-ng
jq
apprise
paho-mqtt
cryptography
beautifulsoup4
lxml
selenium
werkzeug
playwright
] ++ requests.optional-dependencies.socks;
# tests can currently not be run in one pytest invocation and without docker
doCheck = false;
checkInputs = with py.pkgs; [
pytest-flask
pytestCheckHook
];
meta = with lib; {
homepage = "https://github.com/dgtlmoon/changedetection.io";
description = "Simplest self-hosted free open source website change detection tracking, monitoring and notification service";
license = licenses.asl20;
maintainers = with maintainers; [ SuperSandro2000 ];
};
}

View file

@ -29,7 +29,7 @@ let
buildDeps = with pythonPackages; [
flask
flask-gravatar
flask_login
flask-login
flask_mail
flask_migrate
flask-sqlalchemy

View file

@ -3558,6 +3558,8 @@ with pkgs;
cambalache = callPackage ../development/tools/cambalache { };
changedetection-io = callPackage ../servers/web-apps/changedetection-io { };
clipster = callPackage ../tools/misc/clipster { };
clockify = callPackage ../applications/office/clockify {
@ -10290,6 +10292,8 @@ with pkgs;
playbar2 = libsForQt5.callPackage ../applications/audio/playbar2 { };
playwright = with python3Packages; toPythonApplication playwright;
please = callPackage ../tools/security/please { };
plecost = callPackage ../tools/security/plecost { };

View file

@ -75,6 +75,7 @@ mapAliases ({
face_recognition_models = face-recognition-models; # added 2022-10-15
fake_factory = throw "fake_factory has been removed because it is unused and deprecated by upstream since 2016."; # added 2022-05-30
faulthandler = throw "faulthandler is built into ${python.executable}"; # added 2021-07-12
flask_login = flask-login; # added 2022-10-17
flask_sqlalchemy = flask-sqlalchemy; # added 2022-07-20
flask_testing = flask-testing; # added 2022-04-25
flask_wtf = flask-wtf; # added 2022-05-24

View file

@ -3441,7 +3441,7 @@ in {
flask-limiter = callPackage ../development/python-modules/flask-limiter { };
flask_login = callPackage ../development/python-modules/flask-login { };
flask-login = callPackage ../development/python-modules/flask-login { };
flask_mail = callPackage ../development/python-modules/flask-mail { };
@ -4614,6 +4614,8 @@ in {
inquirer = callPackage ../development/python-modules/inquirer { };
inscriptis = callPackage ../development/python-modules/inscriptis { };
insegel = callPackage ../development/python-modules/insegel { };
installer = callPackage ../development/python-modules/installer { };
@ -7038,6 +7040,10 @@ in {
pkuseg = callPackage ../development/python-modules/pkuseg { };
playwright = callPackage ../development/python-modules/playwright {
inherit (pkgs) jq;
};
pmsensor = callPackage ../development/python-modules/pmsensor { };
ppdeep = callPackage ../development/python-modules/ppdeep { };