From bbcf1dabd26bb4e93aa4780d1771c3b449c068ec Mon Sep 17 00:00:00 2001 From: NunoSempere Date: Tue, 28 Mar 2023 11:19:11 -0600 Subject: Revert "tweak: move things around" This reverts commit ca59138a2aef96960381f986b8c683634e4d8e63. --- README.md | 2 +- build/rose-mklink | 17 - config.def.h | 111 + config.h | 110 + extra/screenshots/1-startup.png | Bin 262932 -> 0 bytes extra/screenshots/2-blog.png | Bin 546534 -> 0 bytes extra/screenshots/3-multiple-tabs.png | Bin 175909 -> 0 bytes extra/screenshots/4-money-stuff-raw.png | Bin 255892 -> 0 bytes extra/screenshots/5-money-stuff-readability.png | Bin 203170 -> 0 bytes .../artifacts/compile_flags/compile_flags.txt | 27 - .../artifacts/compile_flags/get-compile-flags.sh | 5 - extra/user-scripts/styles/images/style-nuno.png | Bin 182500 -> 0 bytes .../user-scripts/styles/images/style-original.png | Bin 178824 -> 0 bytes extra/user-scripts/styles/style-nuno.css | 52 - extra/user-scripts/styles/style-original.css | 37 - .../ubuntu-20.04/install-with-dependencies.sh | 27 - .../ubuntu-20.04/rose-images/rose-1.png | Bin 640116 -> 0 bytes .../ubuntu-20.04/rose-images/rose-2.png | Bin 485022 -> 0 bytes .../ubuntu-20.04/rose-images/rose-desktop-icon.png | Bin 756923 -> 0 bytes .../ubuntu-20.04/rose-images/rose-homepage.png | Bin 485022 -> 0 bytes .../ubuntu-20.04/rose-images/rose-src.txt | 1 - extra/user-scripts/ubuntu-20.04/rose.desktop | 9 - extra/user-scripts/valgrind-notes.md | 9 - plugins/libre_redirect/README.md | 3 + plugins/libre_redirect/libre_redirect.c | 84 + plugins/libre_redirect/libre_redirect.h | 6 + plugins/libre_redirect/str_replace_start.c | 65 + plugins/libre_redirect/str_replace_start.h | 4 + .../str_replace_test/build-example.sh | 11 + plugins/libre_redirect/str_replace_test/example.c | 19 + plugins/readability/README.md | 2 + plugins/readability/readability | Bin 0 -> 17056 bytes plugins/readability/readability.c | 30 + plugins/readability/readability.h | 8 + plugins/readability/readability.js | 2401 ++++++++++++++++++++ plugins/readability/recompute_READABILITY_N.sh | 8 + plugins/stand_in/stand_in.c | 27 + plugins/stand_in/stand_in.h | 23 + plugins/style/README.md | 5 + plugins/style/recompute_STYLE_N.sh | 8 + plugins/style/style.c | 30 + plugins/style/style.h | 8 + plugins/style/style.js | 49 + rose-mklink | 17 + rose.c | 473 ++++ screenshots/1-startup.png | Bin 0 -> 262932 bytes screenshots/2-blog.png | Bin 0 -> 546534 bytes screenshots/3-multiple-tabs.png | Bin 0 -> 175909 bytes screenshots/4-money-stuff-raw.png | Bin 0 -> 255892 bytes screenshots/5-money-stuff-readability.png | Bin 0 -> 203170 bytes src/config.def.h | 111 - src/config.h | 110 - src/plugins/libre_redirect/README.md | 3 - src/plugins/libre_redirect/libre_redirect.c | 84 - src/plugins/libre_redirect/libre_redirect.h | 6 - src/plugins/libre_redirect/str_replace_start.c | 65 - src/plugins/libre_redirect/str_replace_start.h | 4 - .../str_replace_test/build-example.sh | 11 - .../libre_redirect/str_replace_test/example.c | 19 - src/plugins/readability/README.md | 2 - src/plugins/readability/readability | Bin 17056 -> 0 bytes src/plugins/readability/readability.c | 30 - src/plugins/readability/readability.h | 8 - src/plugins/readability/readability.js | 2401 -------------------- src/plugins/readability/recompute_READABILITY_N.sh | 8 - src/plugins/stand_in/stand_in.c | 27 - src/plugins/stand_in/stand_in.h | 23 - src/plugins/style/README.md | 5 - src/plugins/style/recompute_STYLE_N.sh | 8 - src/plugins/style/style.c | 30 - src/plugins/style/style.h | 8 - src/plugins/style/style.js | 49 - src/rose.c | 473 ---- src/style.css | 52 - style.css | 52 + .../artifacts/compile_flags/compile_flags.txt | 27 + .../artifacts/compile_flags/get-compile-flags.sh | 5 + user-scripts/styles/images/style-nuno.png | Bin 0 -> 182500 bytes user-scripts/styles/images/style-original.png | Bin 0 -> 178824 bytes user-scripts/styles/style-nuno.css | 52 + user-scripts/styles/style-original.css | 37 + .../ubuntu-20.04/install-with-dependencies.sh | 27 + user-scripts/ubuntu-20.04/rose-images/rose-1.png | Bin 0 -> 640116 bytes user-scripts/ubuntu-20.04/rose-images/rose-2.png | Bin 0 -> 485022 bytes .../ubuntu-20.04/rose-images/rose-desktop-icon.png | Bin 0 -> 756923 bytes .../ubuntu-20.04/rose-images/rose-homepage.png | Bin 0 -> 485022 bytes user-scripts/ubuntu-20.04/rose-images/rose-src.txt | 1 + user-scripts/ubuntu-20.04/rose.desktop | 9 + user-scripts/valgrind-notes.md | 9 + 89 files changed, 3722 insertions(+), 3722 deletions(-) delete mode 100755 build/rose-mklink create mode 100644 config.def.h create mode 100644 config.h delete mode 100644 extra/screenshots/1-startup.png delete mode 100644 extra/screenshots/2-blog.png delete mode 100644 extra/screenshots/3-multiple-tabs.png delete mode 100644 extra/screenshots/4-money-stuff-raw.png delete mode 100644 extra/screenshots/5-money-stuff-readability.png delete mode 100644 extra/user-scripts/artifacts/compile_flags/compile_flags.txt delete mode 100644 extra/user-scripts/artifacts/compile_flags/get-compile-flags.sh delete mode 100644 extra/user-scripts/styles/images/style-nuno.png delete mode 100644 extra/user-scripts/styles/images/style-original.png delete mode 100644 extra/user-scripts/styles/style-nuno.css delete mode 100644 extra/user-scripts/styles/style-original.css delete mode 100644 extra/user-scripts/ubuntu-20.04/install-with-dependencies.sh delete mode 100644 extra/user-scripts/ubuntu-20.04/rose-images/rose-1.png delete mode 100644 extra/user-scripts/ubuntu-20.04/rose-images/rose-2.png delete mode 100644 extra/user-scripts/ubuntu-20.04/rose-images/rose-desktop-icon.png delete mode 100644 extra/user-scripts/ubuntu-20.04/rose-images/rose-homepage.png delete mode 100644 extra/user-scripts/ubuntu-20.04/rose-images/rose-src.txt delete mode 100755 extra/user-scripts/ubuntu-20.04/rose.desktop delete mode 100644 extra/user-scripts/valgrind-notes.md create mode 100644 plugins/libre_redirect/README.md create mode 100644 plugins/libre_redirect/libre_redirect.c create mode 100644 plugins/libre_redirect/libre_redirect.h create mode 100644 plugins/libre_redirect/str_replace_start.c create mode 100644 plugins/libre_redirect/str_replace_start.h create mode 100644 plugins/libre_redirect/str_replace_test/build-example.sh create mode 100644 plugins/libre_redirect/str_replace_test/example.c create mode 100644 plugins/readability/README.md create mode 100755 plugins/readability/readability create mode 100644 plugins/readability/readability.c create mode 100644 plugins/readability/readability.h create mode 100644 plugins/readability/readability.js create mode 100755 plugins/readability/recompute_READABILITY_N.sh create mode 100644 plugins/stand_in/stand_in.c create mode 100644 plugins/stand_in/stand_in.h create mode 100644 plugins/style/README.md create mode 100755 plugins/style/recompute_STYLE_N.sh create mode 100644 plugins/style/style.c create mode 100644 plugins/style/style.h create mode 100644 plugins/style/style.js create mode 100755 rose-mklink create mode 100644 rose.c create mode 100644 screenshots/1-startup.png create mode 100644 screenshots/2-blog.png create mode 100644 screenshots/3-multiple-tabs.png create mode 100644 screenshots/4-money-stuff-raw.png create mode 100644 screenshots/5-money-stuff-readability.png delete mode 100644 src/config.def.h delete mode 100644 src/config.h delete mode 100644 src/plugins/libre_redirect/README.md delete mode 100644 src/plugins/libre_redirect/libre_redirect.c delete mode 100644 src/plugins/libre_redirect/libre_redirect.h delete mode 100644 src/plugins/libre_redirect/str_replace_start.c delete mode 100644 src/plugins/libre_redirect/str_replace_start.h delete mode 100644 src/plugins/libre_redirect/str_replace_test/build-example.sh delete mode 100644 src/plugins/libre_redirect/str_replace_test/example.c delete mode 100644 src/plugins/readability/README.md delete mode 100755 src/plugins/readability/readability delete mode 100644 src/plugins/readability/readability.c delete mode 100644 src/plugins/readability/readability.h delete mode 100644 src/plugins/readability/readability.js delete mode 100755 src/plugins/readability/recompute_READABILITY_N.sh delete mode 100644 src/plugins/stand_in/stand_in.c delete mode 100644 src/plugins/stand_in/stand_in.h delete mode 100644 src/plugins/style/README.md delete mode 100755 src/plugins/style/recompute_STYLE_N.sh delete mode 100644 src/plugins/style/style.c delete mode 100644 src/plugins/style/style.h delete mode 100644 src/plugins/style/style.js delete mode 100644 src/rose.c delete mode 100644 src/style.css create mode 100644 style.css create mode 100644 user-scripts/artifacts/compile_flags/compile_flags.txt create mode 100644 user-scripts/artifacts/compile_flags/get-compile-flags.sh create mode 100644 user-scripts/styles/images/style-nuno.png create mode 100644 user-scripts/styles/images/style-original.png create mode 100644 user-scripts/styles/style-nuno.css create mode 100644 user-scripts/styles/style-original.css create mode 100644 user-scripts/ubuntu-20.04/install-with-dependencies.sh create mode 100644 user-scripts/ubuntu-20.04/rose-images/rose-1.png create mode 100644 user-scripts/ubuntu-20.04/rose-images/rose-2.png create mode 100644 user-scripts/ubuntu-20.04/rose-images/rose-desktop-icon.png create mode 100644 user-scripts/ubuntu-20.04/rose-images/rose-homepage.png create mode 100644 user-scripts/ubuntu-20.04/rose-images/rose-src.txt create mode 100755 user-scripts/ubuntu-20.04/rose.desktop create mode 100644 user-scripts/valgrind-notes.md diff --git a/README.md b/README.md index 4e02b2f..3205ad6 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ You can see some screenshots in the [screenshots](./screenshots) folder. ### To do -- [x] Look into using a makefile. +- [ ] Look into using a makefile. - [ ] Look at using relative rather than absolute paths - [ ] Figure out if downloading files is doable. - [ ] Figure out better way to have plugins diff --git a/build/rose-mklink b/build/rose-mklink deleted file mode 100755 index f016aae..0000000 --- a/build/rose-mklink +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -test "$1" = "--help" || test -z "$1" && { - printf "%s\n" "usage: rose-mklink " \ - "Create a /usr/bin link to a website." - exit -} - -test -z "$2" || { - test -f "/usr/bin/$1" && { - echo "/usr/bin/$1 already exists, remove it first" - exit 1 - } - - printf "#!/bin/sh\n\nrose %s" "$2" > /usr/bin/$1 - chmod +x /usr/bin/$1 -} diff --git a/config.def.h b/config.def.h new file mode 100644 index 0000000..4ba77e6 --- /dev/null +++ b/config.def.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2022 mini-rose + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and any associated documentation + * files to modify, copy, merge, publish, distribute and/or + * sublicense copies of this sotware for their own use. + * This code does not come with any warranty. + * + * Author: fenze + */ + +#include + +/* See more: + * https://webkitgtk.org/reference/webkit2gtk/stable/class.Settings.html */ +#define WEBKIT \ + "enable-back-forward-navigation-gestures", true, \ + "enable-developer-extras", true, \ + "enable-smooth-scrolling", false + +#define GTK \ + "gtk-application-prefer-dark-theme", true, \ + "gtk-enable-animations", false + +#define HOME "https://lite.duckduckgo.com/html/" +#define SEARCH "https://lite.duckduckgo.com/html/?q=%s" +#define CACHE_DIR "/home/fenze/.cache/rose" + +#define KEY(x) GDK_KEY_##x +#define ZOOM 1 /* Starting zoom level */ +#define ZOOM_VAL .1 /* Zooming value in zoomin/zoomout functions */ +#define BG_COLOR "#1E1E2E" /* or e.g., "#FEFEFE" if not using dark theme */ +#define WIDTH 500 +#define HEIGHT 400 + +typedef enum { + goback, + goforward, + refresh, + refresh_force, + back_to_home, + toggle_fullscreen, + zoomin, + zoomout, + zoom_reset, + next_tab, + prev_tab, + close_tab, + show_searchbar, + show_finder, + finder_next, + finder_prev, + newtab, + /*prettify,*/ + hidebar +} func; + +#define SFT 1 << 0 +#define CTRL 1 << 2 +#define ALT 1 << 3 + +static struct { + unsigned mod; + unsigned key; + func id; +} keys[] = { + { CTRL, KEY(h), goback }, + { CTRL, KEY(l), goforward }, + { CTRL, KEY(r), refresh }, + { CTRL | SFT, KEY(R), refresh_force }, + { CTRL | SFT, KEY(H), back_to_home }, + { CTRL, KEY(equal), zoomin }, + { CTRL, KEY(minus), zoomout }, + { CTRL, KEY(0), zoom_reset }, + { ALT, KEY(h), prev_tab }, + { ALT, KEY(l), next_tab }, + { CTRL, KEY(w), close_tab }, + { 0x0, KEY(F11), toggle_fullscreen }, + { CTRL, KEY(e), show_searchbar }, + { CTRL, KEY(f), show_finder }, + { CTRL, KEY(n), finder_next }, + { CTRL | SFT, KEY(N), finder_prev }, + { CTRL, KEY(t), newtab }, + { CTRL, KEY(p), prettify }, + { 0x0, KEY(Escape), hidebar } +}; +/* For controls more akin to normal browsers, use: +{ + { CTRL, KEY(h), goback }, + { CTRL, KEY(j), goforward }, + { CTRL, KEY(r), refresh }, + { CTRL | SFT, KEY(R), refresh_force }, + { CTRL | SFT, KEY(H), back_to_home }, + { CTRL, KEY(equal), zoomin }, + { CTRL, KEY(minus), zoomout }, + { CTRL, KEY(0), zoom_reset }, + { CTRL, KEY(Page_Down), prev_tab }, + { CTRL, KEY(Page_Up), next_tab }, + { CTRL, KEY(w), close_tab }, + { 0x0, KEY(F11), toggle_fullscreen }, + { CTRL, KEY(l), show_searchbar }, + { CTRL, KEY(f), show_finder }, + { CTRL, KEY(n), finder_next }, + { CTRL | SFT, KEY(N), finder_prev }, + { CTRL, KEY(p), prettify }, + +}; +*/ +/* Reference for the key shorthand: + * */ diff --git a/config.h b/config.h new file mode 100644 index 0000000..7a4e3bf --- /dev/null +++ b/config.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2022 Nuño Sempere. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and any associated documentation + * files to modify, copy, merge, publish, distribute and/or + * sublicense copies of this sotware for their own use. + * This code does not come with any warranty. + * + */ + +#include +#include + +/* See more: + * https://webkitgtk.org/reference/webkit2gtk/stable/class.Settings.html */ +#define WEBKIT \ + "enable-back-forward-navigation-gestures", true, "enable-developer-extras", true, \ + "enable-smooth-scrolling", false + +#define GTK "gtk-application-prefer-dark-theme", false, "gtk-enable-animations", false +#define ROSE_HOMEPAGE true +#define HOME ROSE_HOMEPAGE ? "file:///home/loki/Documents/core/software/fresh/C/rose-browser/rosenrot/user-scripts/ubuntu-20.04/rose-images/rose-homepage.png" : "https://lite.duckduckgo.com/html" +#define SEARCH "https://lite.duckduckgo.com/html/?q=%s" +#define CACHE_DIR "/home/loki/.cache/rose" + +#define WIDTH 1920 +#define HEIGHT 1080 +#define KEY(x) GDK_KEY_##x +#define ZOOM 1.4 /* Starting zoom level.*/ +#define ZOOM_VAL .1 /* Zooming value in zoomin/zoomout functions */ +#define BG_COLOR "#FEFEFE" /* "FEFEFE", "#1E1E2E" */ +#define DEBUG false + +typedef enum { + goback, + goforward, + refresh, + refresh_force, + back_to_home, + toggle_fullscreen, + zoomin, + zoomout, + zoom_reset, + next_tab, + prev_tab, + close_tab, + show_searchbar, + show_finder, + finder_next, + finder_prev, + new_tab, + prettify, + hide_bar +} func; + +#define SFT 1 << 0 +#define CTRL 1 << 2 +#define ALT 1 << 3 + +static struct { + unsigned mod; + unsigned key; + func id; +} keys[] = { + { CTRL, KEY(h), goback }, + { CTRL, KEY(j), goforward }, + { CTRL, KEY(r), refresh }, + { CTRL | SFT, KEY(R), refresh_force }, + { CTRL | SFT, KEY(H), back_to_home }, + { CTRL, KEY(equal), zoomin }, + { CTRL, KEY(minus), zoomout }, + { CTRL, KEY(0), zoom_reset }, + { CTRL, KEY(Page_Up), prev_tab }, + { CTRL, KEY(Page_Down), next_tab }, + { CTRL, KEY(t), next_tab }, + { CTRL, KEY(w), close_tab }, + { 0x0, KEY(F11), toggle_fullscreen }, + { CTRL, KEY(l), show_searchbar }, + { CTRL, KEY(k), hide_bar }, + { CTRL, KEY(f), show_finder }, + { CTRL, KEY(n), finder_next }, + { CTRL | SFT, KEY(N), finder_prev }, + { CTRL, KEY(p), prettify } +}; +/* ^ For controls more akin to normal browsers */ +/* Reference for the key shorthand: + * */ + +/* Old controls: { + { CTRL, KEY(h), goback }, + { CTRL, KEY(l), goforward }, + { CTRL, KEY(r), refresh }, + { CTRL | SFT, KEY(R), refresh_force }, + { CTRL | SFT, KEY(H), back_to_home }, + { CTRL, KEY(equal), zoomin }, + { CTRL, KEY(minus), zoomout }, + { CTRL, KEY(0), zoom_reset }, + { ALT, KEY(h), prev_tab }, + { CTRL, KEY(k), hide_searchbar }, + { ALT, KEY(l), next_tab }, + { CTRL, KEY(w), close_tab }, + { 0x0, KEY(F11), toggle_fullscreen }, + { CTRL, KEY(e), show_searchbar }, + { CTRL, KEY(f), show_finder }, + { CTRL, KEY(n), finder_next }, + { CTRL | SFT, KEY(N), finder_prev }, + { CTRL, KEY(p), prettify } +}; +*/ diff --git a/extra/screenshots/1-startup.png b/extra/screenshots/1-startup.png deleted file mode 100644 index 1691ee6..0000000 Binary files a/extra/screenshots/1-startup.png and /dev/null differ diff --git a/extra/screenshots/2-blog.png b/extra/screenshots/2-blog.png deleted file mode 100644 index ceb423e..0000000 Binary files a/extra/screenshots/2-blog.png and /dev/null differ diff --git a/extra/screenshots/3-multiple-tabs.png b/extra/screenshots/3-multiple-tabs.png deleted file mode 100644 index 2d60c9d..0000000 Binary files a/extra/screenshots/3-multiple-tabs.png and /dev/null differ diff --git a/extra/screenshots/4-money-stuff-raw.png b/extra/screenshots/4-money-stuff-raw.png deleted file mode 100644 index 2b8c959..0000000 Binary files a/extra/screenshots/4-money-stuff-raw.png and /dev/null differ diff --git a/extra/screenshots/5-money-stuff-readability.png b/extra/screenshots/5-money-stuff-readability.png deleted file mode 100644 index d9afdbd..0000000 Binary files a/extra/screenshots/5-money-stuff-readability.png and /dev/null differ diff --git a/extra/user-scripts/artifacts/compile_flags/compile_flags.txt b/extra/user-scripts/artifacts/compile_flags/compile_flags.txt deleted file mode 100644 index 7fd8daf..0000000 --- a/extra/user-scripts/artifacts/compile_flags/compile_flags.txt +++ /dev/null @@ -1,27 +0,0 @@ --I/usr/include/webkitgtk-4.0 --I/usr/include/glib-2.0 --I/usr/lib/glib-2.0/include --I/usr/include/sysprof-4 --I/usr/include/gtk-3.0 --I/usr/include/pango-1.0 --I/usr/include/harfbuzz --I/usr/include/freetype2 --I/usr/include/libpng16 --I/usr/include/libmount --I/usr/include/blkid --I/usr/include/fribidi --I/usr/include/cairo --I/usr/include/lzo --I/usr/include/pixman-1 --I/usr/include/gdk-pixbuf-2.0 --I/usr/include/gio-unix-2.0 --I/usr/include/cloudproviders --I/usr/include/atk-1.0 --I/usr/include/at-spi2-atk/2.0 --I/usr/include/at-spi-2.0 --I/usr/include/dbus-1.0 --I/usr/lib/dbus-1.0/include --I/usr/include/libsoup-2.4 --I/usr/include/libxml2 --pthread - diff --git a/extra/user-scripts/artifacts/compile_flags/get-compile-flags.sh b/extra/user-scripts/artifacts/compile_flags/get-compile-flags.sh deleted file mode 100644 index aaa9e01..0000000 --- a/extra/user-scripts/artifacts/compile_flags/get-compile-flags.sh +++ /dev/null @@ -1,5 +0,0 @@ -DEPS='webkit2gtk-4.0' -INCS=`pkg-config --cflags ${DEPS}` -LIBS=`pkg-config --libs ${DEPS}` -echo $INCS -echo $LIBS diff --git a/extra/user-scripts/styles/images/style-nuno.png b/extra/user-scripts/styles/images/style-nuno.png deleted file mode 100644 index e9e6bbe..0000000 Binary files a/extra/user-scripts/styles/images/style-nuno.png and /dev/null differ diff --git a/extra/user-scripts/styles/images/style-original.png b/extra/user-scripts/styles/images/style-original.png deleted file mode 100644 index 65c7ffb..0000000 Binary files a/extra/user-scripts/styles/images/style-original.png and /dev/null differ diff --git a/extra/user-scripts/styles/style-nuno.css b/extra/user-scripts/styles/style-nuno.css deleted file mode 100644 index c7c07b6..0000000 --- a/extra/user-scripts/styles/style-nuno.css +++ /dev/null @@ -1,52 +0,0 @@ -@define-color Surface0 #313244; -@define-color Surface1 #45475a; -@define-color Base #1e1e2e; -@define-color Mantle #181825; -@define-color Lavender #b4befe; -@define-color Text #cdd6f4; - -* { - padding: 0px; - margin: 0px; - outline-color: @Lavender; - color: @Text; - border-color: white; - font-size: 16px; - /*@Base; */ - /* border-bottom-color: @Base; */ -} - -window, notebook, headerbar { - background: @Base; -} - -tabs { - background-color: @Base; - padding: 3px; - outline-color: white; - border-color: @Base; -} - -tab { - background-color: @Base; - margin: 2px 5px 2px 0px; - padding: 5px; - border-style: solid; - /*border-color: white; - border-bottom-color: white; - outline-color: white; - margin: 5px; - padding-left: 10px; - padding-right: 10px; */ -} - -entry { - background-color: @Surface0; - padding-left: 10px; -} - -entry:focus { - background-color: @Surface0; - padding-left: 10px; - -} diff --git a/extra/user-scripts/styles/style-original.css b/extra/user-scripts/styles/style-original.css deleted file mode 100644 index 45805d7..0000000 --- a/extra/user-scripts/styles/style-original.css +++ /dev/null @@ -1,37 +0,0 @@ -@define-color Surface0 #313244; -@define-color Surface1 #45475a; -@define-color Base #1e1e2e; -@define-color Mantle #181825; -@define-color Lavender #b4befe; -@define-color Text #cdd6f4; - -* { - padding: 0px; - margin: 0px; - outline-color: @Lavender; - color: @Text; - border-bottom-color: @Base; -} - -window, notebook, headerbar { - background: @Base; -} - -tabs { - background-color: @Base; - padding: 3px; -} - -tab { - background-color: @Base; - margin: 5px; -} - -entry { - background-color: @Surface0; - padding-left: 10px; -} - -entry:focus { - box-shadow: none; -} diff --git a/extra/user-scripts/ubuntu-20.04/install-with-dependencies.sh b/extra/user-scripts/ubuntu-20.04/install-with-dependencies.sh deleted file mode 100644 index 940abe1..0000000 --- a/extra/user-scripts/ubuntu-20.04/install-with-dependencies.sh +++ /dev/null @@ -1,27 +0,0 @@ -# Dependencies -sudo apt install libwebkit2gtk-4.0-dev -sudo apt install clang -# sudo apt instal sudo apt install gstreamer1.0-plugins-good gstreamer1.0-libav - -# Adblock -git clone https://github.com/jun7/wyebadblock -cd wyebadblock -make -sudo make install -cd .. - -# Rose config -user=$(whoami) -mkdir -p /home/$user/.cache/rose -cp ../../config.def.h ../../config.h # you should also probably customize this yourself. -sed "s/fenze/$user/g" ../../config.h - -# sudo bash ../../install.sh -cd ../.. -make build # or just make -sudo make install - -cd - -# Ubuntu desktop icon -chmod +x rose.desktop -sudo cp rose.desktop /usr/share/applications diff --git a/extra/user-scripts/ubuntu-20.04/rose-images/rose-1.png b/extra/user-scripts/ubuntu-20.04/rose-images/rose-1.png deleted file mode 100644 index f2c546a..0000000 Binary files a/extra/user-scripts/ubuntu-20.04/rose-images/rose-1.png and /dev/null differ diff --git a/extra/user-scripts/ubuntu-20.04/rose-images/rose-2.png b/extra/user-scripts/ubuntu-20.04/rose-images/rose-2.png deleted file mode 100644 index 9944beb..0000000 Binary files a/extra/user-scripts/ubuntu-20.04/rose-images/rose-2.png and /dev/null differ diff --git a/extra/user-scripts/ubuntu-20.04/rose-images/rose-desktop-icon.png b/extra/user-scripts/ubuntu-20.04/rose-images/rose-desktop-icon.png deleted file mode 100644 index 163494f..0000000 Binary files a/extra/user-scripts/ubuntu-20.04/rose-images/rose-desktop-icon.png and /dev/null differ diff --git a/extra/user-scripts/ubuntu-20.04/rose-images/rose-homepage.png b/extra/user-scripts/ubuntu-20.04/rose-images/rose-homepage.png deleted file mode 100644 index 9944beb..0000000 Binary files a/extra/user-scripts/ubuntu-20.04/rose-images/rose-homepage.png and /dev/null differ diff --git a/extra/user-scripts/ubuntu-20.04/rose-images/rose-src.txt b/extra/user-scripts/ubuntu-20.04/rose-images/rose-src.txt deleted file mode 100644 index 30650de..0000000 --- a/extra/user-scripts/ubuntu-20.04/rose-images/rose-src.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/extra/user-scripts/ubuntu-20.04/rose.desktop b/extra/user-scripts/ubuntu-20.04/rose.desktop deleted file mode 100755 index 80a5176..0000000 --- a/extra/user-scripts/ubuntu-20.04/rose.desktop +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env xdg-open -[Desktop Entry] -Version=1.0 -Type=Application -Terminal=false -Exec= /usr/bin/rose %u -Name=Rose -Comment=Minimalistic browser -Icon=/home/loki/Documents/core/software/fresh/C/rose-browser/rosenrot/user-scripts/ubuntu-20.04/rose-images/rose-desktop-icon.png diff --git a/extra/user-scripts/valgrind-notes.md b/extra/user-scripts/valgrind-notes.md deleted file mode 100644 index 1fa2e1d..0000000 --- a/extra/user-scripts/valgrind-notes.md +++ /dev/null @@ -1,9 +0,0 @@ -In case you arrive at a segmentation fault when working on rose, you can use valgrind. - -To do this, you can compile rose with the `DEBUG` value in `build.sh` set to `-g` - -and then: - -``` -valgrind --track-origins=yes ./rose -``` diff --git a/plugins/libre_redirect/README.md b/plugins/libre_redirect/README.md new file mode 100644 index 0000000..f3f58c9 --- /dev/null +++ b/plugins/libre_redirect/README.md @@ -0,0 +1,3 @@ +## About + +This code automatically redirects webpage to their open-source frontends. It is based on \ No newline at end of file diff --git a/plugins/libre_redirect/libre_redirect.c b/plugins/libre_redirect/libre_redirect.c new file mode 100644 index 0000000..3794add --- /dev/null +++ b/plugins/libre_redirect/libre_redirect.c @@ -0,0 +1,84 @@ +#include +#include +#include + +#include "str_replace_start.h" + +#define LIBRE_N 19 + +/* Uncomment for debug */ +/* #define DEBUG */ + +/* Inspired by https://libredirect.github.io/, but in C. */ + +void str_init(char* str, int n) +{ + for (int i = 0; i < n; i++) + str[i] = ' '; + str[n] = '\0'; +} // could also use + +int libre_redirect(const char* uri, char* output) +{ + int l1 = strlen(uri); + int l2 = strlen(output); + int len; + char tmp_uri[l2++]; + char tmp_output[l2++]; + + if ((l2 - l1) < LIBRE_N) { +#ifdef DEBUG + printf("Not enough memory\n"); +#endif + return 1; // not enough memory. + } else { + strcpy(tmp_uri, uri); // strcpy also copies the terminating '\0' + strcpy(tmp_output, output); + + char* annoying_sites[] = { + "https://www.youtube.com", + "https://www.reddit.com", + "https://medium.com", + "https://translate.google.com", + // "https://forum.effectivealtruism.org", + "https://www.bloomberg.com", + "https://twitter.com" + }; + + char* alternatives[] = { + "https://yt.artemislena.eu", + "https://teddit.nunosempere.com", + "https://scribe.rip", + "https://simplytranslate.org/", + // "https://ea.greaterwrong.com", + "https://archive.is/https://www.bloomberg.com", + "https://nitter.net" + }; + + len = sizeof(annoying_sites) / sizeof(annoying_sites[0]); + + for (int i = 0; i < len; i++) { + int replace_check = str_replace_start(tmp_uri, annoying_sites[i], + alternatives[i], output); + if (replace_check == 2) { +#ifdef DEBUG + printf("tmp_uri: %s\n", tmp_uri); + printf("output: %s\n", output); +#endif + return 2; + } else if (replace_check == 1) { +#ifdef DEBUG + printf("replace_check failed\n"); +#endif + return 1; + } + strcpy(tmp_uri, output); + str_init(output, l2); + } + strcpy(output, tmp_uri); + } +#ifdef DEBUG + printf("No match found\n\n"); +#endif + return 0; +} diff --git a/plugins/libre_redirect/libre_redirect.h b/plugins/libre_redirect/libre_redirect.h new file mode 100644 index 0000000..150c95e --- /dev/null +++ b/plugins/libre_redirect/libre_redirect.h @@ -0,0 +1,6 @@ +#pragma once + +#define LIBRE_N 19 + +int libre_redirect(const char* uri, char* uri_filtered); +void str_init(char* str, int n); diff --git a/plugins/libre_redirect/str_replace_start.c b/plugins/libre_redirect/str_replace_start.c new file mode 100644 index 0000000..d1fe083 --- /dev/null +++ b/plugins/libre_redirect/str_replace_start.c @@ -0,0 +1,65 @@ +#include +#include +#include + +#define DEBUG false + +/* +See also: +* +* https://github.com/irl/la-cucina/blob/master/str_replace.c +*/ + +int str_replace_start(const char* string, const char* target, const char* replacement, char* output) +{ + int l1 = strlen(string); + int l2 = strlen(target); + int l3 = strlen(replacement); + int l4 = strlen(output); + if (DEBUG) + printf("%d,%d,%d,%d\n", l1, l2, l3, l4); + // if(DEBUG) printf("%s,%s,%s,%s\n", string, target, replacement, output); + + if ((l4 < (l1 - l2 + l3)) || l4 < l1) { + // Not enough memory in output string. + if (DEBUG) + printf("String not long enough.\n"); + return 1; + } + /* else if(l1 < l2){ + // Not even possible that there is a match. + if(DEBUG) printf("Target larger than string.\n"); + strcpy(output, string); + } */ + else { + if (DEBUG) + printf("Looking for a match for %s in %s.\n", target, string); + int match = true; + for (int i = 0; i < l2; i++) { + if (string[i] != target[i]) { + match = false; + break; + } + } + if (match) { + if (DEBUG) + printf("Found match.\n"); + for (int i = 0; i < l3; i++) { + output[i] = replacement[i]; + } + int counter = l3; + for (int i = l2; i < l1; i++) { + output[counter] = string[i]; + counter++; + } + output[counter] = '\0'; + return 2; // success + } else { + if (DEBUG) + printf("Did not find match.\n"); + strcpy(output, string); + } + } + + return 0; +} diff --git a/plugins/libre_redirect/str_replace_start.h b/plugins/libre_redirect/str_replace_start.h new file mode 100644 index 0000000..78c79b5 --- /dev/null +++ b/plugins/libre_redirect/str_replace_start.h @@ -0,0 +1,4 @@ +#pragma once + +int str_replace_start(const char* string, const char* target, + const char* replacement, char* output); diff --git a/plugins/libre_redirect/str_replace_test/build-example.sh b/plugins/libre_redirect/str_replace_test/build-example.sh new file mode 100644 index 0000000..a9f8022 --- /dev/null +++ b/plugins/libre_redirect/str_replace_test/build-example.sh @@ -0,0 +1,11 @@ +#!/bin/bash +CC=gcc + +FLAGS="-std=c99 -Wall -lm" + +SRC=example.c +REQS="../str_replace_start.c ../libre_redirect.c" + +echo -e "\n\n\n" +$CC $FLAGS $SRC $REQS -o example + diff --git a/plugins/libre_redirect/str_replace_test/example.c b/plugins/libre_redirect/str_replace_test/example.c new file mode 100644 index 0000000..b93634a --- /dev/null +++ b/plugins/libre_redirect/str_replace_test/example.c @@ -0,0 +1,19 @@ +#include "../libre_redirect.h" +#include +#include + +int main() +{ + char uri[] = "https://reddit.com/r/blah"; + + int l = LIBRE_N + strlen(uri) + 1; + char uri_filtered[l]; + str_init(uri_filtered, l); + + if (!libre_redirect(uri, uri_filtered)) { + printf("Filtered uri: %s\n", uri_filtered); + } else { + printf("Uri: %s\n", uri); + // failure; do something with the original uri. + } +} diff --git a/plugins/readability/README.md b/plugins/readability/README.md new file mode 100644 index 0000000..2a19a8e --- /dev/null +++ b/plugins/readability/README.md @@ -0,0 +1,2 @@ +This code reimplements firefox readability mode. Code taken from + diff --git a/plugins/readability/readability b/plugins/readability/readability new file mode 100755 index 0000000..2c70985 Binary files /dev/null and b/plugins/readability/readability differ diff --git a/plugins/readability/readability.c b/plugins/readability/readability.c new file mode 100644 index 0000000..bc2f02f --- /dev/null +++ b/plugins/readability/readability.c @@ -0,0 +1,30 @@ +#include +#include +#include +#define READABILITY_N 85133 + 1000 + +void read_readability_js(char* string) +{ + FILE* fp = fopen("/home/loki/Documents/core/software/fresh/C/rose-browser/rosenrot/plugins/readability/readability.js", "r"); + if (!fp) { // fp is NULL, fopen failed + fprintf(stderr, "Failed to open file\n"); + string = NULL; + return; + } + int i = 0; + int c; + while ((c = fgetc(fp)) != EOF) { + string[i++] = c; + } + string[i] = '\0'; + fclose(fp); +} + +/* +int main(){ + char* readability_js = malloc(READABILITY_N+1); + read_readability_js(readability_js); + printf("%s", readability_js); + free(readability_js); +} +*/ diff --git a/plugins/readability/readability.h b/plugins/readability/readability.h new file mode 100644 index 0000000..6a21a8c --- /dev/null +++ b/plugins/readability/readability.h @@ -0,0 +1,8 @@ +#ifndef READABILITY +#define READABILITY + +#define READABILITY_N 85133 + 1000 + +void read_readability_js(char* string); + +#endif diff --git a/plugins/readability/readability.js b/plugins/readability/readability.js new file mode 100644 index 0000000..0532bba --- /dev/null +++ b/plugins/readability/readability.js @@ -0,0 +1,2401 @@ +/*eslint-env es6:false*/ +/* + * Copyright (c) 2010 Arc90 Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This code is heavily based on Arc90's readability.js (1.7.1) script + * available at: http://code.google.com/p/arc90labs-readability + */ + +/** + * Public constructor. + * @param {HTMLDocument} doc The document to parse. + * @param {Object} options The options object. + */ +function Readability(doc, options) { + // In some older versions, people passed a URI as the first argument. Cope: + if (options && options.documentElement) { + doc = options; + options = arguments[2]; + } else if (!doc || !doc.documentElement) { + throw new Error("First argument to Readability constructor should be a document object."); + } + options = options || {}; + + this._doc = doc; + this._docJSDOMParser = this._doc.firstChild.__JSDOMParser__; + this._articleTitle = null; + this._articleByline = null; + this._articleDir = null; + this._articleSiteName = null; + this._attempts = []; + + // Configurable options + this._debug = !!options.debug; + this._maxElemsToParse = options.maxElemsToParse || this.DEFAULT_MAX_ELEMS_TO_PARSE; + this._nbTopCandidates = options.nbTopCandidates || this.DEFAULT_N_TOP_CANDIDATES; + this._charThreshold = options.charThreshold || this.DEFAULT_CHAR_THRESHOLD; + this._classesToPreserve = this.CLASSES_TO_PRESERVE.concat(options.classesToPreserve || []); + this._keepClasses = !!options.keepClasses; + this._serializer = options.serializer || function(el) { + return el.innerHTML; + }; + this._disableJSONLD = !!options.disableJSONLD; + + // Start with all flags set + this._flags = this.FLAG_STRIP_UNLIKELYS | + this.FLAG_WEIGHT_CLASSES | + this.FLAG_CLEAN_CONDITIONALLY; + + + // Control whether log messages are sent to the console + if (this._debug) { + let logNode = function(node) { + if (node.nodeType == node.TEXT_NODE) { + return `${node.nodeName} ("${node.textContent}")`; + } + let attrPairs = Array.from(node.attributes || [], function(attr) { + return `${attr.name}="${attr.value}"`; + }).join(" "); + return `<${node.localName} ${attrPairs}>`; + }; + this.log = function () { + if (typeof dump !== "undefined") { + var msg = Array.prototype.map.call(arguments, function(x) { + return (x && x.nodeName) ? logNode(x) : x; + }).join(" "); + dump("Reader: (Readability) " + msg + "\n"); + } else if (typeof console !== "undefined") { + let args = Array.from(arguments, arg => { + if (arg && arg.nodeType == this.ELEMENT_NODE) { + return logNode(arg); + } + return arg; + }); + args.unshift("Reader: (Readability)"); + console.log.apply(console, args); + } + }; + } else { + this.log = function () {}; + } +} + +Readability.prototype = { + FLAG_STRIP_UNLIKELYS: 0x1, + FLAG_WEIGHT_CLASSES: 0x2, + FLAG_CLEAN_CONDITIONALLY: 0x4, + + // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType + ELEMENT_NODE: 1, + TEXT_NODE: 3, + + // Max number of nodes supported by this parser. Default: 0 (no limit) + DEFAULT_MAX_ELEMS_TO_PARSE: 0, + + // The number of top candidates to consider when analysing how + // tight the competition is among candidates. + DEFAULT_N_TOP_CANDIDATES: 5, + + // Element tags to score by default. + DEFAULT_TAGS_TO_SCORE: "section,h2,h3,h4,h5,h6,p,td,pre".toUpperCase().split(","), + + // The default number of chars an article must have in order to return a result + DEFAULT_CHAR_THRESHOLD: 500, + + // All of the regular expressions in use within readability. + // Defined up here so we don't instantiate them repeatedly in loops. + REGEXPS: { + // NOTE: These two regular expressions are duplicated in + // Readability-readerable.js. Please keep both copies in sync. + unlikelyCandidates: /-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|footer|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i, + okMaybeItsACandidate: /and|article|body|column|content|main|shadow/i, + + positive: /article|body|content|entry|hentry|h-entry|main|page|pagination|post|text|blog|story/i, + negative: /-ad-|hidden|^hid$| hid$| hid |^hid |banner|combx|comment|com-|contact|foot|footer|footnote|gdpr|masthead|media|meta|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i, + extraneous: /print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single|utility/i, + byline: /byline|author|dateline|writtenby|p-author/i, + replaceFonts: /<(\/?)font[^>]*>/gi, + normalize: /\s{2,}/g, + videos: /\/\/(www\.)?((dailymotion|youtube|youtube-nocookie|player\.vimeo|v\.qq)\.com|(archive|upload\.wikimedia)\.org|player\.twitch\.tv)/i, + shareElements: /(\b|_)(share|sharedaddy)(\b|_)/i, + nextLink: /(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i, + prevLink: /(prev|earl|old|new|<|«)/i, + tokenize: /\W+/g, + whitespace: /^\s*$/, + hasContent: /\S$/, + hashUrl: /^#.+/, + srcsetUrl: /(\S+)(\s+[\d.]+[xw])?(\s*(?:,|$))/g, + b64DataUrl: /^data:\s*([^\s;,]+)\s*;\s*base64\s*,/i, + // See: https://schema.org/Article + jsonLdArticleTypes: /^Article|AdvertiserContentArticle|NewsArticle|AnalysisNewsArticle|AskPublicNewsArticle|BackgroundNewsArticle|OpinionNewsArticle|ReportageNewsArticle|ReviewNewsArticle|Report|SatiricalArticle|ScholarlyArticle|MedicalScholarlyArticle|SocialMediaPosting|BlogPosting|LiveBlogPosting|DiscussionForumPosting|TechArticle|APIReference$/ + }, + + UNLIKELY_ROLES: [ "menu", "menubar", "complementary", "navigation", "alert", "alertdialog", "dialog" ], + + DIV_TO_P_ELEMS: new Set([ "BLOCKQUOTE", "DL", "DIV", "IMG", "OL", "P", "PRE", "TABLE", "UL" ]), + + ALTER_TO_DIV_EXCEPTIONS: ["DIV", "ARTICLE", "SECTION", "P"], + + PRESENTATIONAL_ATTRIBUTES: [ "align", "background", "bgcolor", "border", "cellpadding", "cellspacing", "frame", "hspace", "rules", "style", "valign", "vspace" ], + + DEPRECATED_SIZE_ATTRIBUTE_ELEMS: [ "TABLE", "TH", "TD", "HR", "PRE" ], + + // The commented out elements qualify as phrasing content but tend to be + // removed by readability when put into paragraphs, so we ignore them here. + PHRASING_ELEMS: [ + // "CANVAS", "IFRAME", "SVG", "VIDEO", + "ABBR", "AUDIO", "B", "BDO", "BR", "BUTTON", "CITE", "CODE", "DATA", + "DATALIST", "DFN", "EM", "EMBED", "I", "IMG", "INPUT", "KBD", "LABEL", + "MARK", "MATH", "METER", "NOSCRIPT", "OBJECT", "OUTPUT", "PROGRESS", "Q", + "RUBY", "SAMP", "SCRIPT", "SELECT", "SMALL", "SPAN", "STRONG", "SUB", + "SUP", "TEXTAREA", "TIME", "VAR", "WBR" + ], + + // These are the classes that readability sets itself. + CLASSES_TO_PRESERVE: [ "page" ], + + // These are the list of HTML entities that need to be escaped. + HTML_ESCAPE_MAP: { + "lt": "<", + "gt": ">", + "amp": "&", + "quot": '"', + "apos": "'", + }, + + /** + * Run any post-process modifications to article content as necessary. + * + * @param Element + * @return void + **/ + _postProcessContent: function(articleContent) { + // Readability cannot open relative uris so we convert them to absolute uris. + this._fixRelativeUris(articleContent); + + this._simplifyNestedElements(articleContent); + + if (!this._keepClasses) { + // Remove classes. + this._cleanClasses(articleContent); + } + }, + + /** + * Iterates over a NodeList, calls `filterFn` for each node and removes node + * if function returned `true`. + * + * If function is not passed, removes all the nodes in node list. + * + * @param NodeList nodeList The nodes to operate on + * @param Function filterFn the function to use as a filter + * @return void + */ + _removeNodes: function(nodeList, filterFn) { + // Avoid ever operating on live node lists. + if (this._docJSDOMParser && nodeList._isLiveNodeList) { + throw new Error("Do not pass live node lists to _removeNodes"); + } + for (var i = nodeList.length - 1; i >= 0; i--) { + var node = nodeList[i]; + var parentNode = node.parentNode; + if (parentNode) { + if (!filterFn || filterFn.call(this, node, i, nodeList)) { + parentNode.removeChild(node); + } + } + } + }, + + /** + * Iterates over a NodeList, and calls _setNodeTag for each node. + * + * @param NodeList nodeList The nodes to operate on + * @param String newTagName the new tag name to use + * @return void + */ + _replaceNodeTags: function(nodeList, newTagName) { + // Avoid ever operating on live node lists. + if (this._docJSDOMParser && nodeList._isLiveNodeList) { + throw new Error("Do not pass live node lists to _replaceNodeTags"); + } + for (const node of nodeList) { + this._setNodeTag(node, newTagName); + } + }, + + /** + * Iterate over a NodeList, which doesn't natively fully implement the Array + * interface. + * + * For convenience, the current object context is applied to the provided + * iterate function. + * + * @param NodeList nodeList The NodeList. + * @param Function fn The iterate function. + * @return void + */ + _forEachNode: function(nodeList, fn) { + Array.prototype.forEach.call(nodeList, fn, this); + }, + + /** + * Iterate over a NodeList, and return the first node that passes + * the supplied test function + * + * For convenience, the current object context is applied to the provided + * test function. + * + * @param NodeList nodeList The NodeList. + * @param Function fn The test function. + * @return void + */ + _findNode: function(nodeList, fn) { + return Array.prototype.find.call(nodeList, fn, this); + }, + + /** + * Iterate over a NodeList, return true if any of the provided iterate + * function calls returns true, false otherwise. + * + * For convenience, the current object context is applied to the + * provided iterate function. + * + * @param NodeList nodeList The NodeList. + * @param Function fn The iterate function. + * @return Boolean + */ + _someNode: function(nodeList, fn) { + return Array.prototype.some.call(nodeList, fn, this); + }, + + /** + * Iterate over a NodeList, return true if all of the provided iterate + * function calls return true, false otherwise. + * + * For convenience, the current object context is applied to the + * provided iterate function. + * + * @param NodeList nodeList The NodeList. + * @param Function fn The iterate function. + * @return Boolean + */ + _everyNode: function(nodeList, fn) { + return Array.prototype.every.call(nodeList, fn, this); + }, + + /** + * Concat all nodelists passed as arguments. + * + * @return ...NodeList + * @return Array + */ + _concatNodeLists: function() { + var slice = Array.prototype.slice; + var args = slice.call(arguments); + var nodeLists = args.map(function(list) { + return slice.call(list); + }); + return Array.prototype.concat.apply([], nodeLists); + }, + + _getAllNodesWithTag: function(node, tagNames) { + if (node.querySelectorAll) { + return node.querySelectorAll(tagNames.join(",")); + } + return [].concat.apply([], tagNames.map(function(tag) { + var collection = node.getElementsByTagName(tag); + return Array.isArray(collection) ? collection : Array.from(collection); + })); + }, + + /** + * Removes the class="" attribute from every element in the given + * subtree, except those that match CLASSES_TO_PRESERVE and + * the classesToPreserve array from the options object. + * + * @param Element + * @return void + */ + _cleanClasses: function(node) { + var classesToPreserve = this._classesToPreserve; + var className = (node.getAttribute("class") || "") + .split(/\s+/) + .filter(function(cls) { + return classesToPreserve.indexOf(cls) != -1; + }) + .join(" "); + + if (className) { + node.setAttribute("class", className); + } else { + node.removeAttribute("class"); + } + + for (node = node.firstElementChild; node; node = node.nextElementSibling) { + this._cleanClasses(node); + } + }, + + /** + * Converts each and uri in the given element to an absolute URI, + * ignoring #ref URIs. + * + * @param Element + * @return void + */ + _fixRelativeUris: function(articleContent) { + var baseURI = this._doc.baseURI; + var documentURI = this._doc.documentURI; + function toAbsoluteURI(uri) { + // Leave hash links alone if the base URI matches the document URI: + if (baseURI == documentURI && uri.charAt(0) == "#") { + return uri; + } + + // Otherwise, resolve against base URI: + try { + return new URL(uri, baseURI).href; + } catch (ex) { + // Something went wrong, just return the original: + } + return uri; + } + + var links = this._getAllNodesWithTag(articleContent, ["a"]); + this._forEachNode(links, function(link) { + var href = link.getAttribute("href"); + if (href) { + // Remove links with javascript: URIs, since + // they won't work after scripts have been removed from the page. + if (href.indexOf("javascript:") === 0) { + // if the link only contains simple text content, it can be converted to a text node + if (link.childNodes.length === 1 && link.childNodes[0].nodeType === this.TEXT_NODE) { + var text = this._doc.createTextNode(link.textContent); + link.parentNode.replaceChild(text, link); + } else { + // if the link has multiple children, they should all be preserved + var container = this._doc.createElement("span"); + while (link.firstChild) { + container.appendChild(link.firstChild); + } + link.parentNode.replaceChild(container, link); + } + } else { + link.setAttribute("href", toAbsoluteURI(href)); + } + } + }); + + var medias = this._getAllNodesWithTag(articleContent, [ + "img", "picture", "figure", "video", "audio", "source" + ]); + + this._forEachNode(medias, function(media) { + var src = media.getAttribute("src"); + var poster = media.getAttribute("poster"); + var srcset = media.getAttribute("srcset"); + + if (src) { + media.setAttribute("src", toAbsoluteURI(src)); + } + + if (poster) { + media.setAttribute("poster", toAbsoluteURI(poster)); + } + + if (srcset) { + var newSrcset = srcset.replace(this.REGEXPS.srcsetUrl, function(_, p1, p2, p3) { + return toAbsoluteURI(p1) + (p2 || "") + p3; + }); + + media.setAttribute("srcset", newSrcset); + } + }); + }, + + _simplifyNestedElements: function(articleContent) { + var node = articleContent; + + while (node) { + if (node.parentNode && ["DIV", "SECTION"].includes(node.tagName) && !(node.id && node.id.startsWith("readability"))) { + if (this._isElementWithoutContent(node)) { + node = this._removeAndGetNext(node); + continue; + } else if (this._hasSingleTagInsideElement(node, "DIV") || this._hasSingleTagInsideElement(node, "SECTION")) { + var child = node.children[0]; + for (var i = 0; i < node.attributes.length; i++) { + child.setAttribute(node.attributes[i].name, node.attributes[i].value); + } + node.parentNode.replaceChild(child, node); + node = child; + continue; + } + } + + node = this._getNextNode(node); + } + }, + + /** + * Get the article title as an H1. + * + * @return string + **/ + _getArticleTitle: function() { + var doc = this._doc; + var curTitle = ""; + var origTitle = ""; + + try { + curTitle = origTitle = doc.title.trim(); + + // If they had an element with id "title" in their HTML + if (typeof curTitle !== "string") + curTitle = origTitle = this._getInnerText(doc.getElementsByTagName("title")[0]); + } catch (e) {/* ignore exceptions setting the title. */} + + var titleHadHierarchicalSeparators = false; + function wordCount(str) { + return str.split(/\s+/).length; + } + + // If there's a separator in the title, first remove the final part + if ((/ [\|\-\\\/>»] /).test(curTitle)) { + titleHadHierarchicalSeparators = / [\\\/>»] /.test(curTitle); + curTitle = origTitle.replace(/(.*)[\|\-\\\/>»] .*/gi, "$1"); + + // If the resulting title is too short (3 words or fewer), remove + // the first part instead: + if (wordCount(curTitle) < 3) + curTitle = origTitle.replace(/[^\|\-\\\/>»]*[\|\-\\\/>»](.*)/gi, "$1"); + } else if (curTitle.indexOf(": ") !== -1) { + // Check if we have an heading containing this exact string, so we + // could assume it's the full title. + var headings = this._concatNodeLists( + doc.getElementsByTagName("h1"), + doc.getElementsByTagName("h2") + ); + var trimmedTitle = curTitle.trim(); + var match = this._someNode(headings, function(heading) { + return heading.textContent.trim() === trimmedTitle; + }); + + // If we don't, let's extract the title out of the original title string. + if (!match) { + curTitle = origTitle.substring(origTitle.lastIndexOf(":") + 1); + + // If the title is now too short, try the first colon instead: + if (wordCount(curTitle) < 3) { + curTitle = origTitle.substring(origTitle.indexOf(":") + 1); + // But if we have too many words before the colon there's something weird + // with the titles and the H tags so let's just use the original title instead + } else if (wordCount(origTitle.substr(0, origTitle.indexOf(":"))) > 5) { + curTitle = origTitle; + } + } + } else if (curTitle.length > 150 || curTitle.length < 15) { + var hOnes = doc.getElementsByTagName("h1"); + + if (hOnes.length === 1) + curTitle = this._getInnerText(hOnes[0]); + } + + curTitle = curTitle.trim().replace(this.REGEXPS.normalize, " "); + // If we now have 4 words or fewer as our title, and either no + // 'hierarchical' separators (\, /, > or ») were found in the original + // title or we decreased the number of words by more than 1 word, use + // the original title. + var curTitleWordCount = wordCount(curTitle); + if (curTitleWordCount <= 4 && + (!titleHadHierarchicalSeparators || + curTitleWordCount != wordCount(origTitle.replace(/[\|\-\\\/>»]+/g, "")) - 1)) { + curTitle = origTitle; + } + + return curTitle; + }, + + /** + * Prepare the HTML document for readability to scrape it. + * This includes things like stripping javascript, CSS, and handling terrible markup. + * + * @return void + **/ + _prepDocument: function() { + var doc = this._doc; + + // Remove all style tags in head + this._removeNodes(this._getAllNodesWithTag(doc, ["style"])); + + if (doc.body) { + this._replaceBrs(doc.body); + } + + this._replaceNodeTags(this._getAllNodesWithTag(doc, ["font"]), "SPAN"); + }, + + /** + * Finds the next node, starting from the given node, and ignoring + * whitespace in between. If the given node is an element, the same node is + * returned. + */ + _nextNode: function (node) { + var next = node; + while (next + && (next.nodeType != this.ELEMENT_NODE) + && this.REGEXPS.whitespace.test(next.textContent)) { + next = next.nextSibling; + } + return next; + }, + + /** + * Replaces 2 or more successive
elements with a single

. + * Whitespace between
elements are ignored. For example: + *

foo
bar


abc
+ * will become: + *
foo
bar

abc

+ */ + _replaceBrs: function (elem) { + this._forEachNode(this._getAllNodesWithTag(elem, ["br"]), function(br) { + var next = br.nextSibling; + + // Whether 2 or more
elements have been found and replaced with a + //

block. + var replaced = false; + + // If we find a
chain, remove the
s until we hit another node + // or non-whitespace. This leaves behind the first
in the chain + // (which will be replaced with a

later). + while ((next = this._nextNode(next)) && (next.tagName == "BR")) { + replaced = true; + var brSibling = next.nextSibling; + next.parentNode.removeChild(next); + next = brSibling; + } + + // If we removed a
chain, replace the remaining
with a

. Add + // all sibling nodes as children of the

until we hit another
+ // chain. + if (replaced) { + var p = this._doc.createElement("p"); + br.parentNode.replaceChild(p, br); + + next = p.nextSibling; + while (next) { + // If we've hit another

, we're done adding children to this

. + if (next.tagName == "BR") { + var nextElem = this._nextNode(next.nextSibling); + if (nextElem && nextElem.tagName == "BR") + break; + } + + if (!this._isPhrasingContent(next)) + break; + + // Otherwise, make this node a child of the new

. + var sibling = next.nextSibling; + p.appendChild(next); + next = sibling; + } + + while (p.lastChild && this._isWhitespace(p.lastChild)) { + p.removeChild(p.lastChild); + } + + if (p.parentNode.tagName === "P") + this._setNodeTag(p.parentNode, "DIV"); + } + }); + }, + + _setNodeTag: function (node, tag) { + this.log("_setNodeTag", node, tag); + if (this._docJSDOMParser) { + node.localName = tag.toLowerCase(); + node.tagName = tag.toUpperCase(); + return node; + } + + var replacement = node.ownerDocument.createElement(tag); + while (node.firstChild) { + replacement.appendChild(node.firstChild); + } + node.parentNode.replaceChild(replacement, node); + if (node.readability) + replacement.readability = node.readability; + + for (var i = 0; i < node.attributes.length; i++) { + try { + replacement.setAttribute(node.attributes[i].name, node.attributes[i].value); + } catch (ex) { + /* it's possible for setAttribute() to throw if the attribute name + * isn't a valid XML Name. Such attributes can however be parsed from + * source in HTML docs, see https://github.com/whatwg/html/issues/4275, + * so we can hit them here and then throw. We don't care about such + * attributes so we ignore them. + */ + } + } + return replacement; + }, + + /** + * Prepare the article node for display. Clean out any inline styles, + * iframes, forms, strip extraneous

tags, etc. + * + * @param Element + * @return void + **/ + _prepArticle: function(articleContent) { + this._cleanStyles(articleContent); + + // Check for data tables before we continue, to avoid removing items in + // those tables, which will often be isolated even though they're + // visually linked to other content-ful elements (text, images, etc.). + this._markDataTables(articleContent); + + this._fixLazyImages(articleContent); + + // Clean out junk from the article content + this._cleanConditionally(articleContent, "form"); + this._cleanConditionally(articleContent, "fieldset"); + this._clean(articleContent, "object"); + this._clean(articleContent, "embed"); + this._clean(articleContent, "footer"); + this._clean(articleContent, "link"); + this._clean(articleContent, "aside"); + + // Clean out elements with little content that have "share" in their id/class combinations from final top candidates, + // which means we don't remove the top candidates even they have "share". + + var shareElementThreshold = this.DEFAULT_CHAR_THRESHOLD; + + this._forEachNode(articleContent.children, function (topCandidate) { + this._cleanMatchedNodes(topCandidate, function (node, matchString) { + return this.REGEXPS.shareElements.test(matchString) && node.textContent.length < shareElementThreshold; + }); + }); + + this._clean(articleContent, "iframe"); + this._clean(articleContent, "input"); + this._clean(articleContent, "textarea"); + this._clean(articleContent, "select"); + this._clean(articleContent, "button"); + this._cleanHeaders(articleContent); + + // Do these last as the previous stuff may have removed junk + // that will affect these + this._cleanConditionally(articleContent, "table"); + this._cleanConditionally(articleContent, "ul"); + this._cleanConditionally(articleContent, "div"); + + // replace H1 with H2 as H1 should be only title that is displayed separately + this._replaceNodeTags(this._getAllNodesWithTag(articleContent, ["h1"]), "h2"); + + // Remove extra paragraphs + this._removeNodes(this._getAllNodesWithTag(articleContent, ["p"]), function (paragraph) { + var imgCount = paragraph.getElementsByTagName("img").length; + var embedCount = paragraph.getElementsByTagName("embed").length; + var objectCount = paragraph.getElementsByTagName("object").length; + // At this point, nasty iframes have been removed, only remain embedded video ones. + var iframeCount = paragraph.getElementsByTagName("iframe").length; + var totalCount = imgCount + embedCount + objectCount + iframeCount; + + return totalCount === 0 && !this._getInnerText(paragraph, false); + }); + + this._forEachNode(this._getAllNodesWithTag(articleContent, ["br"]), function(br) { + var next = this._nextNode(br.nextSibling); + if (next && next.tagName == "P") + br.parentNode.removeChild(br); + }); + + // Remove single-cell tables + this._forEachNode(this._getAllNodesWithTag(articleContent, ["table"]), function(table) { + var tbody = this._hasSingleTagInsideElement(table, "TBODY") ? table.firstElementChild : table; + if (this._hasSingleTagInsideElement(tbody, "TR")) { + var row = tbody.firstElementChild; + if (this._hasSingleTagInsideElement(row, "TD")) { + var cell = row.firstElementChild; + cell = this._setNodeTag(cell, this._everyNode(cell.childNodes, this._isPhrasingContent) ? "P" : "DIV"); + table.parentNode.replaceChild(cell, table); + } + } + }); + }, + + /** + * Initialize a node with the readability object. Also checks the + * className/id for special names to add to its score. + * + * @param Element + * @return void + **/ + _initializeNode: function(node) { + node.readability = {"contentScore": 0}; + + switch (node.tagN