Merge remote-tracking branch 'librey/main' into librey

This commit is contained in:
Fijxu 2023-09-29 02:33:28 -03:00
commit 517839ae24
53 changed files with 640 additions and 434 deletions

10
.dockerignore Normal file
View File

@ -0,0 +1,10 @@
.github/
.git/
.gitignore
.dockerignore
config.php.example
docker-compose.yml
Dockerfile
opensearch.xml.example
README.md
docker-old/

View File

@ -22,10 +22,14 @@ jobs:
uses: ASzc/change-string-case-action@v5
with:
string: ${{ github.event.repository.name }}
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- uses: docker/build-push-action@v4
with:
context: .
file: Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: |
ghcr.io/${{ steps.owner.outputs.lowercase }}/${{ steps.repo.outputs.lowercase }}:latest

View File

@ -1,10 +1,10 @@
# syntax = edrevo/dockerfile-plus
ARG VERSION="3.18"
FROM alpine:${VERSION} AS librey
FROM alpine:3.18
WORKDIR "/var/www/html"
ADD "." "."
# Docker metadata contains information about the maintainer, such as the name, repository, and support email
# Please add any necessary information or correct any incorrect information
# See more: https://docs.docker.com/config/labels-custom-metadata/
LABEL name="LibreY" \
description="Framework and javascript free privacy respecting meta search engine" \
@ -18,28 +18,25 @@ LABEL name="LibreY" \
# Change or add new arguments to customize the image generated by 'docker build' command
ARG DOCKER_SCRIPTS="docker"
ARG NGINX_PORT=8080
# Set this argument during build time to indicate that the path is for php's www.conf
ARG WWW_CONFIG="/etc/php82/php-fpm.d/www.conf"
# Customize the environment during both execution and build time by modifying the environment variables added to the container's shell
# When building your image, make sure to set the 'TZ' environment variable to your desired time zone location, for example 'America/Sao_Paulo'
# See more: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
ENV TZ="America/New_York"
RUN apk add gettext --no-cache
# Install required packages
RUN apk add gettext php82 php82-fpm php82-dom php82-curl php82-json php82-apcu nginx --no-cache
# The following lines import all Dockerfiles from other folders so that they can be built together in the final build
INCLUDE+ docker/php/php.dockerfile
INCLUDE+ docker/server/nginx.dockerfile
# Include docker scripts, docker images, and the 'GNU License' in the LibreY container
ADD "." "/var/www/html"
# Set permissions for script files as executable scripts inside 'docker/scripts' directory
RUN chmod u+x "${DOCKER_SCRIPTS}/php/prepare.sh" &&\
chmod u+x "${DOCKER_SCRIPTS}/server/prepare.sh" &&\
chmod u+x "${DOCKER_SCRIPTS}/entrypoint.sh" &&\
chmod u+x "${DOCKER_SCRIPTS}/attributes.sh"
# Configure PHP-FPM to listen on a Unix socket instead of a TCP port, which is more secure and efficient
RUN touch /run/php-fpm82.sock && chown nginx:nginx "/run/php-fpm82.sock"
RUN sed -i 's/^\s*listen = 127.0.0.1:9000/listen = \/run\/php-fpm82.sock/' ${WWW_CONFIG} &&\
sed -i 's/^\s*;\s*listen.owner = nobody/listen.owner = nginx/' ${WWW_CONFIG} &&\
sed -i 's/^\s*;\s*listen.group = nobody/listen.group = nginx/' ${WWW_CONFIG} &&\
sed -i 's/^\s*;\s*listen.mode = 0660/listen.mode = 0660/' ${WWW_CONFIG}
EXPOSE ${NGINX_PORT}
# Configures the container to be run as an executable.
ENTRYPOINT ["/bin/sh", "-c", "docker/entrypoint.sh"]
ENTRYPOINT ["/bin/sh", "-c", "docker/entrypoint.sh"]

View File

@ -15,17 +15,22 @@
### Instances
> If you host using CloudFlare, this will be mentioned in the instances list.
You can access the full list of LibreX and LibreY instances on one of the following updated LibreY instances:
| Clearnet | TOR | I2P | Country |
|-|-|-|-|
| [search.ahwx.org](https://search.ahwx.org/) | [](http://hyy7rcvknwb22v4nnoar635wntiwr4uwzhiuyimemyl4fz6k7tahj5id.onion) | ❌ | 🇳🇱 NL |
| [librex.me](https://librex.me/) | [](http://librex.revvybrr6pvbx4n3j4475h4ghw4elqr4t5xo2vtd3gfpu2nrsnhh57id.onion/) | [](http://revekebotog64xrrammtsmjwtwlg3vqyzwdurzt2pu6botg4bejq.b32.i2p/) | 🇨🇦 CA |
| [librex.revvy.de](https://librex.revvy.de/) | [](http://librex.revvybrr6pvbx4n3j4475h4ghw4elqr4t5xo2vtd3gfpu2nrsnhh57id.onion/) | [](http://revekebotog64xrrammtsmjwtwlg3vqyzwdurzt2pu6botg4bejq.b32.i2p/) | 🇨🇦 CA |
| [search.davidovski.xyz](https://search.davidovski.xyz/) | ❌ | ❌ | 🇬🇧 GB |
| [librey.nohost.network](https://librey.nohost.network/) | ❌ | ❌ | 🇲🇽 MX |
You can find a list of instances on any LibreY instance by accessing /instances.php.<br>
Alternatively look at `instances.json` where the list is generated from.<br><br>
While the official instances may be more updated and have better uptime, please consider using another person's instances as these are heavily overloaded.<br>
Support the community. ❤️<br><br>
Instance list on [@codedipper](https://github.com/codedipper)'s instance:<br>
[librex.me](https://librex.me/instances.php)<br>
[librex.revvy.de](https://librex.revvy.de/instances.php)<br>
[Tor](http://librex.revvybrr6pvbx4n3j4475h4ghw4elqr4t5xo2vtd3gfpu2nrsnhh57id.onion/instances.php)<br>
[I2P](http://revekebotog64xrrammtsmjwtwlg3vqyzwdurzt2pu6botg4bejq.b32.i2p/instances.php)<br>
<br>
[@Ahwxorg](https://github.com/Ahwxorg)'s instance:<br>
[search.ahwx.org](https://search.ahwx.org/instances.php)<br>
[Tor](http://hyy7rcvknwb22v4nnoar635wntiwr4uwzhiuyimemyl4fz6k7tahj5id.onion/instances.php)<br>
<br>
[@davidovski](https://github.com/davidovski)'s instance:<br>
[search.davidovski.xyz](https://search.davidovski.xyz/instances.php)<br>
<br>

9
SECURITY.md Normal file
View File

@ -0,0 +1,9 @@
# Security Policy
## Supported Versions
Basically the latest commit. We don't really do versioning with LibreY.
## Reporting a Vulnerability
Please join #librey:ahwx.org on Matrix and please DM me (@ahwx:ahwx.org) or if Matrix is absolutely impossible, email me; ahwx *at* ahwx *dot* org

6
auto_updater.sh Normal file
View File

@ -0,0 +1,6 @@
#!/bin/sh
while true; do
git stash
git pull
sleep 60
done

View File

@ -23,6 +23,9 @@
// how long in minutes to put google/other instances on cooldown if they aren't responding
"request_cooldown" => 25,
// how long in minutes to store results for in the cache
"cache_time" => 20,
/*
Preset privacy friendly frontends for users, these can be overwritten by users in the settings
e.g.: Preset the invidious instance URL: "instance_url" => "https://yewtu.be",

View File

@ -1,23 +1,32 @@
version: "2.1"
version: "3"
services:
librey:
image: ahwxorg/librey:latest
image: ghcr.io/ahwxorg/librey:latest
container_name: librey
network_mode: bridge
ports:
- 8080:8080
environment:
- PUID=1000
- PGID=1000
- VERSION=docker
- TZ=America/New_York
- CONFIG_GOOGLE_DOMAIN=com
- CONFIG_GOOGLE_LANGUAGE_SITE=en
- CONFIG_GOOGLE_LANGUAGE_RESULTS=en
- CONFIG_TEXT_SEARCH_ENGINE=google
- CONFIG_LANGUAGE=en
- CONFIG_NUMBER_OF_RESULTS=10
- CONFIG_INVIDIOUS_INSTANCE=https://invidious.snopyta.org
- CONFIG_DISABLE_BITTORRENT_SEARCH=false
- CONFIG_HIDDEN_SERVICE_SEARCH=false
- CONFIG_INSTANCE_FALLBACK=true
- CONFIG_WIKIPEDIA_LANGUAGE=en
- CONFIG_RATE_LIMIT_COOLDOWN=25
- CONFIG_CACHE_TIME=20
- CONFIG_TEXT_SEARCH_ENGINE=google
- CURLOPT_PROXY_ENABLED=false
- CURLOPT_PROXY=192.0.2.53:8388
- CURLOPT_PROXYTYPE=CURLPROXY_HTTP
- CURLOPT_USERAGENT=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:116.0) Gecko/20100101 Firefox/116.0
- CURLOPT_FOLLOWLOCATION=true
volumes:
- ./nginx_logs:/var/log/nginx
- ./php_logs:/var/log/php7
restart: unless-stopped
watchtower: # Watchtower is not required but highly recommended, since Watchtower will re-pull and restart the LibreY container automatically whenever there's an update.
image: containrrr/watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock

View File

@ -3,15 +3,14 @@
- [Introduction](#introduction)
- [Running a docker container](#running-a-docker-container)
- [Running a Docker container through the Docker hub](#running-a-docker-container-through-the-docker-hub)
- [Running a Docker container through ghcr](#running-a-docker-container-through-ghcr)
- [Running a Docker container with composer](#running-a-docker-container-with-composer)
- [Environment variables that can be set in the Docker container](#environment-variables-that-can-be-set-in-the-docker-container)
- [OpenSearch](#opensearch)
- [Search Config](#search-config)
- [Wikipedia](#wikipedia)
- [Applications](#applications)
- [Engines](#engines)
- [Curl](#curl)
- [Search Configuration](#search)
- [Frontend Configuration](#frontends)
- [Search Engine Configuration](#engines)
- [cURL Configuration](#curl)
- [OpenSearch Configuration](#opensearch)
- [Docker version issues](#docker-version-issues)
- [Building a docker image](#building-a-docker-image)
- [Support for different architectures](#support-for-different-architectures)
@ -20,7 +19,7 @@
Dockerized librey is a way to provide users with yet another way to self-host their own projects with a view to privacy. If you wish to help, please start by looking for bugs in used docker configurations.
### Running a Docker container through the Docker hub
### Running a Docker container through ghcr
To run librey in a docker container, you can simply use the command:
@ -32,7 +31,15 @@ docker run -d \
-e CONFIG_GOOGLE_LANGUAGE="en" \
-e CONFIG_WIKIPEDIA_LANGUAGE="en" \
-p 8080:8080 \
librey/librey:latest
ghcr.io/ahwxorg/librey:latest
```
Also run with watchtower for auto-updating: (optional)
```sh
docker run -d \
--name librey-watchtower-1 \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower
```
<br>
@ -40,26 +47,38 @@ docker run -d \
### Running a Docker container with composer
```yml
version: "2.1"
version: "3"
services:
librey:
image: librey/librey:latest
image: ghcr.io/ahwxorg/librey:latest
container_name: librey
network_mode: bridge
ports:
- 8080:8080
environment:
- PUID=1000
- PGID=1000
- VERSION=docker
- TZ="America/New_York"
- CONFIG_GOOGLE_DOMAIN="com"
- CONFIG_GOOGLE_LANGUAGE="en"
- CONFIG_WIKIPEDIA_LANGUAGE="en"
- CONFIG_GOOGLE_DOMAIN=com
- CONFIG_LANGUAGE=en
- CONFIG_NUMBER_OF_RESULTS=10
- CONFIG_INVIDIOUS_INSTANCE=https://invidious.snopyta.org
- CONFIG_DISABLE_BITTORRENT_SEARCH=false
- CONFIG_HIDDEN_SERVICE_SEARCH=false
- CONFIG_INSTANCE_FALLBACK=true
- CONFIG_RATE_LIMIT_COOLDOWN=25
- CONFIG_CACHE_TIME=20
- CONFIG_TEXT_SEARCH_ENGINE=google
- CURLOPT_PROXY_ENABLED=false
- CURLOPT_PROXY=192.0.2.53:8388
- CURLOPT_PROXYTYPE=CURLPROXY_HTTP
- CURLOPT_USERAGENT=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:116.0) Gecko/20100101 Firefox/116.0
- CURLOPT_FOLLOWLOCATION=true
volumes:
- ./nginx_logs:/var/log/nginx
- ./php_logs:/var/log/php7
restart: unless-stopped
watchtower: # Watchtower is not required but highly recommended, since Watchtower will re-pull and restart the LibreY container automatically whenever there's an update.
image: containrrr/watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
```
<br>
@ -70,53 +89,25 @@ This docker image was developed with high configurability in mind, so here is th
<br>
### OpenSearch
### Search
| Variables | Default | Examples | Description |
|:----------|:-------------|:---------|:------|
| OPEN_SEARCH_TITLE | "LibreY" | string | [OpenSearch XML](https://developer.mozilla.org/en-US/docs/Web/OpenSearch) |
| OPEN_SEARCH_DESCRIPTION | "Framework and javascript free privacy respecting meta search engine" | string | [OpenSearch XML](https://developer.mozilla.org/en-US/docs/Web/OpenSearch) |
| OPEN_SEARCH_ENCODING | "UTF-8" | "UTF-8" | [OpenSearch XML](https://developer.mozilla.org/en-US/docs/Web/OpenSearch) |
| OPEN_SEARCH_LONG_NAME | "librey Search" | string | [OpenSearch XML](https://developer.mozilla.org/en-US/docs/Web/OpenSearch) |
| OPEN_SEARCH_HOST | "http://localhost:8080" | string | Host used to identify librey on the network |
<br>
### Search Config
| Variables | Default | Examples | Description |
|:----------|:-------------|:---------|:------|
| CONFIG_GOOGLE_DOMAIN | "com" | "com", "com.br", "com.es" | Defines which Google domain the search will be done, change according to your country |
| CONFIG_GOOGLE_LANGUAGE | "en" | "pt", "es", "ru" | Defines the language in which searches will be done, see the list of supported languages [here](https://developers.google.com/custom-search/docs/ref_languages). |
| CONFIG_GOOGLE_NUMBER_OF_RESULTS | "10" | "10", "20", "30" | Number of results for Google to return each page. |
| CONFIG_GOOGLE_DOMAIN | "com" | "com", "com.br", "cat", "se" | Defines which Google domain the search will be done on, change according to your country. |
| CONFIG_LANGUAGE | "en" | "zh-Hans", "fil", "no" | Defines the language in which searches will be done, see the list of supported languages [here](https://developers.google.com/custom-search/docs/ref_languages). |
| CONFIG_NUMBER_OF_RESULTS | 10 | integer | Number of results for Google to return each page. |
| CONFIG_INVIDIOUS_INSTANCE | "https://invidious.snopyta.org" | string | Defines the host that will be used to do video searches using Invidious. |
| CONFIG_DISABLE_BITTORRENT_SEARCH | false | boolean | Defines whether bittorrent search will be disabled |
| CONFIG_BITTORRENT_TRACKERS | "&tr=http://nyaa.tracker.wf:7777/announce&tr=udp://open.stealth.si:80/announce&tr=udp://tracker.opentrackr.org:1337/announce&tr=udp://exodus.desync.com:6969/announce&tr=udp://tracker.torrent.eu.org:451/announce" | string | Set list of bittorrent trackers for torrent search. |
| CONFIG_HIDDEN_SERVICE_SEARCH | false | boolean | Defines whether hidden service search will be disabled |
| CONFIG_INSTANCE_FALLBACK | true | boolean | Choose whether or not to use the API on the backend to request to another LibreX/Y instance in case of rate limiting. |
| CONFIG_INVIDIOUS_INSTANCE | "https://invidious.namazso.eu" | string | Defines the host that will be used to do video searches using invidious |
| CONFIG_HIDDEN_SERVICE_SEARCH | false | boolean | Defines whether safesearch will be enabled or disabled |
| CONFIG_DISABLE_BITTORRENT_SEARCH | false | boolean | Defines whether bittorrent support will be enabled or disabled |
| CONFIG_BITTORRENT_TRACKERS | "http://nyaa.tracker.wf:7777/announce" | string | Bittorrent trackers, see the complete example in the `config.php` file. |
<br>
### Wikipedia
| CONFIG_RATE_LIMIT_COOLDOWN | 25 | integer | Time in minutes to wait before sending requests to Google again after a rate limit. |
| CONFIG_CACHE_TIME | 20 | integer | Time in minutes to store results for in the cache. |
### Frontends
| Variables | Default | Examples | Description |
|:----------|:-------------|:---------|:------|
| CONFIG_WIKIPEDIA_LANGUAGE | "en" | "pt", "es", "hu" | Adds language support for Wikipedia results |
<br>
### Engines
| Variables | Default | Examples | Description |
|:----------|:-------------|:---------|:------|
| CONFIG_TEXT_SEARCH_ENGINE | "google" | "google", "duckduckgo" | Change your text search engine. |
<br>
### Applications
| Variables | Default | Examples | Description |
|:----------|:-------------|:---------|:------|
| APP_INVIDIOUS | "" | string | Integration with external self-hosted apps, configure the desired host. |
| APP_INVIDIOUS | "" | "https://example.com", string | Integration with external self-hosted apps, configure the desired host. |
| APP_RIMGO | "" | string | Integration with external self-hosted apps, configure the desired host. |
| APP_SCRIBE | "" | string | Integration with external self-hosted apps, configure the desired host. |
| APP_GOTHUB | "" | string | Integration with external self-hosted apps, configure the desired host. |
@ -131,22 +122,37 @@ This docker image was developed with high configurability in mind, so here is th
| APP_SUDS | "" | string | Integration with external self-hosted apps, configure the desired host. |
| APP_BIBLIOREADS | "" | string | Integration with external self-hosted apps, configure the desired host. |
<br>
### Curl
### Engines
| Variables | Default | Examples | Description |
|:----------|:-------------|:---------|:------|
| CONFIG_TEXT_SEARCH_ENGINE | "google" | "google", "duckduckgo" | Integration with external self-hosted apps, configure the desired host. |
### cURL
| Variables | Default | Examples | Description |
|:----------|:-------------|:---------|:------|
| CURLOPT_PROXY_ENABLED | false | boolean | If you want to use a proxy, you need to set this variable to true. |
| CURLOPT_PROXY | "" | "127.0.0.1:8080" | Set the proxy using the ip and port to be used |
| CURLOPT_PROXYTYPE | "CURLPROXY_HTTP" | "CURLPROXY_SOCKS4A" "CURLPROXY_SOCKS5" "CURLPROXY_SOCKS5_HOSTNAME" | Set the type of proxy connection (if you enabled it). |
| CURLOPT_RETURNTRANSFER | true | boolean | **TODO** |
| CURLOPT_ENCODING | "" | string | Defines the encode that curl should use to display the texts correctly |
| CURLOPT_USERAGENT | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36" | string | This variable defines the 'User-Agent' that curl will use to attempt to avoid being blocked |
| CURLOPT_CUSTOMREQUEST | "GET" | "HEAD", "OPTIONS" | Defines the HTTP method that curl will use to make the request |
| CURLOPT_MAXREDIRS | 5 | number | **TODO** |
| CURLOPT_TIMEOUT | 18 | number | Sets the maximum time curl will wait for a response before timing out |
| CURLOPT_VERBOSE | false | boolean | Specifies whether curl should display detailed information on stdout about the request and response when making requests. Setting to 'true' enables verbose mode |
| CURLOPT_PROXY | "" | "192.0.2.53:8388" | Set the proxy using the ip and port to be used. |
| CURLOPT_PROXYTYPE | "CURLPROXY_HTTP" | "CURLPROXY_SOCKS4A", "CURLPROXY_SOCKS5", "CURLPROXY_SOCKS5_HOSTNAME" | Set the type of proxy connection (if you enabled it). |
| CURLOPT_RETURNTRANSFER | true | boolean | Return the transfer as a string of the return value of curl_exec() instead of outputting it directly. |
| CURLOPT_ENCODING | "" | string | Return the transfer as a string of the return value of curl_exec() instead of outputting it directly. |
| CURLOPT_USERAGENT | "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:116.0) Gecko/20100101 Firefox/116.0" | string | This variable defines the 'User-Agent' that curl will use to attempt to avoid being blocked. |
| CURLOPT_IPRESOLVE | "CURL_IPRESOLVE_WHATEVER" | "CURL_IPRESOLVE_V4", "CURL_IPRESOLVE_V6" | Use a fixed IP version for making requests, or what DNS prefers. |
| CURLOPT_CUSTOMREQUEST | "GET" | "POST", "CONNECT" | Defines the HTTP method that curl will use to make the request. |
| CURLOPT_MAXREDIRS | 5 | integer | The maximum amount of HTTP redirections to follow, only enabled with CURLOPT_FOLLOWLOCATION. |
| CURLOPT_TIMEOUT | 3 | integer | The maximum amount of time for cURL requests to complete. |
| CURLOPT_VERBOSE | false | boolean | Whether to output verbose information. |
| CURLOPT_FOLLOWLOCATION | true | boolean | Whether to follow any Location header. Required for instance fallback. |
### OpenSearch
| Variables | Default | Examples | Description |
|:----------|:-------------|:---------|:------|
| OPEN_SEARCH_TITLE | "LibreY" | string | [OpenSearch XML](https://developer.mozilla.org/en-US/docs/Web/OpenSearch) |
| OPEN_SEARCH_DESCRIPTION | "Framework and javascript free privacy respecting meta search engine" | string | [OpenSearch XML](https://developer.mozilla.org/en-US/docs/Web/OpenSearch) |
| OPEN_SEARCH_ENCODING | "UTF-8" | "UTF-8" | [OpenSearch XML](https://developer.mozilla.org/en-US/docs/Web/OpenSearch) |
| OPEN_SEARCH_LONG_NAME | "LibreY Search" | string | [OpenSearch XML](https://developer.mozilla.org/en-US/docs/Web/OpenSearch) |
| OPEN_SEARCH_HOST | "http://localhost:80" | string | Host used to identify librey on the network |
<br>
@ -190,7 +196,7 @@ docker build -t librey:latest .
Supported architectures for the official librey images include the same ones supported by Alpine itself, which are typically denoted as `linux/386`, `linux/amd64`, `linux/arm/v6`. If you need support for a different architecture, such as `linux/arm/v7`, you can modify the 'Dockerfile' to use a more comprehensive base image like `ubuntu:latest` instead.
In this case, you must run the `build` process specifying the desired architecture as shown in the example below:
In this case, you must run the `buildx` process specifying the desired architecture as shown in the example below:
```sh
docker buildx build \

View File

@ -19,19 +19,16 @@ export OPEN_SEARCH_HOST=${OPEN_SEARCH_HOST:-"127.0.0.1"}
# Replace the 'config.php' script, which contains the most common search engine configurations, with these environment setups
# These environment setups can be found in 'config.php', and the default configurations can be useful for most use cases
export CONFIG_GOOGLE_DOMAIN="${CONFIG_GOOGLE_DOMAIN:-"com"}"
export CONFIG_GOOGLE_LANGUAGE_SITE="${CONFIG_GOOGLE_LANGUAGE_SITE:-"en"}"
export CONFIG_GOOGLE_LANGUAGE_RESULTS="${CONFIG_GOOGLE_LANGUAGE_RESULTS:-"en"}"
export CONFIG_GOOGLE_NUMBER_OF_RESULTS="${CONFIG_GOOGLE_NUMBER_OF_RESULTS:-"10"}"
export CONFIG_INSTANCE_FALLBACK="${CONFIG_INSTANCE_FALLBACK:-true}"
export CONFIG_INVIDIOUS_INSTANCE="${CONFIG_INVIDIOUS_INSTANCE:-"invidious.snopyta.org"}"
export CONFIG_HIDDEN_SERVICE_SEARCH=${CONFIG_HIDDEN_SERVICE_SEARCH:-false}
export CONFIG_GOOGLE_DOMAIN=${CONFIG_GOOGLE_DOMAIN:-"com"}
export CONFIG_LANGUAGE=${CONFIG_LANGUAGE:-"en"}
export CONFIG_NUMBER_OF_RESULTS=${CONFIG_NUMBER_OF_RESULTS:-10}
export CONFIG_INVIDIOUS_INSTANCE=${CONFIG_INVIDIOUS_INSTANCE:-"https://invidious.snopyta.org"}
export CONFIG_DISABLE_BITTORRENT_SEARCH=${CONFIG_DISABLE_BITTORRENT_SEARCH:-false}
export CONFIG_BITTORRENT_TRACKERS="${CONFIG_BITTORRENT_TRACKERS:-"&tr=http://nyaa.tracker.wf:7777/announce&tr=udp://open.stealth.si:80/announce&tr=udp://tracker.opentrackr.org:1337/announce&tr=udp://exodus.desync.com:6969/announce&tr=udp://tracker.torrent.eu.org:451/announce"}"
# The settings that will be used to handle Wikipedia results displayed on the librey search page
# the settings below can be edited via environment variables.
export CONFIG_WIKIPEDIA_LANGUAGE=${CONFIG_WIKIPEDIA_LANGUAGE:-${CONFIG_GOOGLE_LANGUAGE}}
export CONFIG_BITTORRENT_TRACKERS=${CONFIG_BITTORRENT_TRACKERS:-"&tr=http://nyaa.tracker.wf:7777/announce&tr=udp://open.stealth.si:80/announce&tr=udp://tracker.opentrackr.org:1337/announce&tr=udp://exodus.desync.com:6969/announce&tr=udp://tracker.torrent.eu.org:451/announce"}
export CONFIG_HIDDEN_SERVICE_SEARCH=${CONFIG_HIDDEN_SERVICE_SEARCH:-false}
export CONFIG_INSTANCE_FALLBACK="${CONFIG_INSTANCE_FALLBACK:-true}"
export CONFIG_RATE_LIMIT_COOLDOWN="${CONFIG_RATE_LIMIT_COOLDOWN:-25}"
export CONFIG_CACHE_TIME="${CONFIG_CACHE_TIME:-20}"
# Supported apps integration configuration. These empty spaces can be set up using free hosts as pointers
# A particular example is using the "https://yewtu.be" or a self-hosted host to integrate the invidious app to librey
@ -59,11 +56,13 @@ export CURLOPT_PROXY=${CURLOPT_PROXY:-""}
export CURLOPT_PROXYTYPE=${CURLOPT_PROXYTYPE:-"CURLPROXY_HTTP"}
export CURLOPT_RETURNTRANSFER=${CURLOPT_RETURNTRANSFER:-true}
export CURLOPT_ENCODING=${CURLOPT_ENCODING:-""}
export CURLOPT_USERAGENT="${CURLOPT_USERAGENT:-"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"}"
export CURLOPT_USERAGENT=${CURLOPT_USERAGENT:-"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:116.0) Gecko/20100101 Firefox/116.0"}
export CURLOPT_IPRESOLVE=${CURLOPT_IPRESOLVE:-"CURL_IPRESOLVE_WHATEVER"}
export CURLOPT_CUSTOMREQUEST="${CURLOPT_CUSTOMREQUEST:-"GET"}"
export CURLOPT_MAXREDIRS=${CURLOPT_MAXREDIRS:-5}
export CURLOPT_TIMEOUT=${CURLOPT_TIMEOUT:-18}
export CURLOPT_TIMEOUT=${CURLOPT_TIMEOUT:-3}
export CURLOPT_VERBOSE=${CURLOPT_VERBOSE:-true}
export CURLOPT_FOLLOWLOCATION=${CURLOPT_FOLLOWLOCATION:-true}
# These shell functions will be available for use by any function calls
function AwkTrim() { awk '{$1=$1};1'; }

View File

@ -1,17 +1,16 @@
<?php
return (object) array(
"google_domain" => "${CONFIG_GOOGLE_DOMAIN}",
"google_language_site" => "${CONFIG_GOOGLE_LANGUAGE_SITE}",
"google_language_results" => "${CONFIG_GOOGLE_LANGUAGE_RESULTS}",
"google_number_of_results" => "${CONFIG_GOOGLE_NUMBER_OF_RESULTS}",
"wikipedia_language" => "${CONFIG_WIKIPEDIA_LANGUAGE}",
"language" => "${CONFIG_LANGUAGE}",
"number_of_results" => ${CONFIG_NUMBER_OF_RESULTS},
"invidious_instance_for_video_results" => "${CONFIG_INVIDIOUS_INSTANCE}",
"disable_bittorent_search" => ${CONFIG_DISABLE_BITTORRENT_SEARCH},
"bittorent_trackers" => "${CONFIG_BITTORRENT_TRACKERS}",
"disable_hidden_service_search" => ${CONFIG_HIDDEN_SERVICE_SEARCH},
"instance_fallback" => ${CONFIG_INSTANCE_FALLBACK},
"request_cooldown" => ${CONFIG_RATE_LIMIT_COOLDOWN},
"cache_time" => ${CONFIG_CACHE_TIME},
"frontends" => array(
"invidious" => array(
@ -34,7 +33,7 @@
),
"gothub" => array(
"instance_url" => "${APP_GOTHUB}",
"project_url" => "https://codeberg.org/gothub/gothub/wiki/Instances",
"project_url" => "https://codeberg.org/gothub/gothub#instances",
"original_name" => "GitHub",
"original_url" => "github.com"
),
@ -44,10 +43,9 @@
"original_name" => "Twitter",
"original_url" => "twitter.com"
),
"libreddit" => array(
"instance_url" => "${APP_LIBREREDDIT}",
"project_url" => "https://github.com/spikecodes/libreddit",
"project_url" => "https://github.com/libreddit/libreddit-instances/blob/master/instances.md",
"original_name" => "Reddit",
"original_url" => "reddit.com"
),
@ -61,23 +59,23 @@
"instance_url" => "${APP_WIKILESS}",
"project_url" => "https://github.com/Metastem/wikiless#instances",
"original_name" => "Wikipedia",
"original_url" => "wikipedia.com"
"original_url" => "wikipedia.org"
),
"quetre" => array(
"instance_url" => "${APP_QUETRE}",
"project_url" => "https://github.com/zyachel/quetre",
"project_url" => "https://github.com/zyachel/quetre#instances",
"original_name" => "Quora",
"original_url" => "quora.com"
),
"libremdb" => array(
"instance_url" => "${APP_LIBREMDB}",
"project_url" => "https://github.com/zyachel/libremdb",
"project_url" => "https://github.com/zyachel/libremdb#instances",
"original_name" => "IMDb",
"original_url" => "imdb.com"
),
"breezewiki" => array(
"instance_url" => "${APP_BREEZEWIKI}",
"project_url" => "https://gitdab.com/cadence/breezewiki",
"project_url" => "https://docs.breezewiki.com/Links.html",
"original_name" => "Fandom",
"original_url" => "fandom.com"
),
@ -101,23 +99,25 @@
)
),
"preferred_engines" => array(
"text" => "${CONFIG_TEXT_SEARCH_ENGINE}"
),
"curl_settings" => array(
CURLOPT_PROXY => "${CURLOPT_PROXY}",
CURLOPT_PROXYTYPE => "${CURLOPT_PROXYTYPE}",
CURLOPT_PROXYTYPE => ${CURLOPT_PROXYTYPE},
CURLOPT_RETURNTRANSFER => ${CURLOPT_RETURNTRANSFER},
CURLOPT_ENCODING => "${CURLOPT_ENCODING}",
CURLOPT_USERAGENT => "${CURLOPT_USERAGENT}",
CURLOPT_IPRESOLVE => CURL_IPRESOLVE_WHATEVER,
CURLOPT_IPRESOLVE => ${CURLOPT_IPRESOLVE},
CURLOPT_CUSTOMREQUEST => "${CURLOPT_CUSTOMREQUEST}",
CURLOPT_PROTOCOLS => CURLPROTO_HTTPS | CURLPROTO_HTTP,
CURLOPT_REDIR_PROTOCOLS => CURLPROTO_HTTPS | CURLPROTO_HTTP,
CURLOPT_MAXREDIRS => ${CURLOPT_MAXREDIRS},
CURLOPT_TIMEOUT => ${CURLOPT_TIMEOUT},
CURLOPT_VERBOSE => ${CURLOPT_VERBOSE}
CURLOPT_VERBOSE => ${CURLOPT_VERBOSE},
CURLOPT_FOLLOWLOCATION => ${CURLOPT_FOLLOWLOCATION}
)
);
?>

View File

@ -1,10 +1,7 @@
#!/bin/sh
# Due to an issue with Docker's 'CMD' directive, the following scripts are not executing as expected.
# This workaround has been implemented to resolve the issue for now
sh "docker/php/prepare.sh"
sh "docker/server/prepare.sh"
/bin/sh -c docker/env-substitution.sh
/bin/sh -c /usr/sbin/php-fpm8
/bin/sh -c /usr/sbin/php-fpm82
exec nginx -g "daemon off;"

View File

@ -1,23 +1,24 @@
#!/bin/sh
echo "[PREPARE] docker/server/prepare.sh'"
# Load all environment variables from 'attributes.sh' using the command 'source /path/attributes.sh'
source "docker/attributes.sh"
# This condition creates the Unix socket if 'php-fpm8.sock' does not already exist.
# This fixes an issue where Nginx starts but does not serve content
if [ ! -d "/run/php8" ] || [ ! -S "/run/php8/php-fpm8.sock" ]; then
mkdir "/run/php8"
touch "/run/php8/php-fpm8.sock"
chmod 660 "/run/php8/php-fpm8.sock"
chown nginx:nginx "/run/php8/php-fpm8.sock"
fi
# The lines below will replace the environment variables in the templates with the corresponding variables listed above. To accomplish this, the GNU 'envsubst' package will be used
# The lines below will replace the environment variables in the templates with the corresponding variables listed above if the config file is not yet provided. To accomplish this, the GNU 'envsubst' package will be used
# Although not recommended (if you do not know what you are doing), you still have the option to add new substitution file templates using any required environment variables
[[ ! -s ${CONFIG_PHP_TEMPLATE} ]] && cat 'docker/php/config.php' | envsubst > ${CONFIG_PHP_TEMPLATE};
[[ ! -s ${CONFIG_OPEN_SEARCH_TEMPLATE} ]] && cat 'docker/php/opensearch.xml' | envsubst > ${CONFIG_OPEN_SEARCH_TEMPLATE};
[[ ! -s ${CONFIG_PHP_TEMPLATE} ]] && cat 'docker/config.php' | envsubst > ${CONFIG_PHP_TEMPLATE};
[[ ! -s ${CONFIG_OPEN_SEARCH_TEMPLATE} ]] && cat 'docker/opensearch.xml' | envsubst > ${CONFIG_OPEN_SEARCH_TEMPLATE};
export OPEN_SEARCH_HOST_FOR_NGINX="$(echo "${OPEN_SEARCH_HOST}" | cut -d "/" -f 3 | cut -d ":" -f 1)"
if [[ ! -s ${CONFIG_NGINX_TEMPLATE} ]]; then
cat 'docker/nginx.conf' | envsubst '${OPEN_SEARCH_HOST_FOR_NGINX}' > ${CONFIG_NGINX_TEMPLATE};
mv "docker/fastcgi.conf" /etc/nginx/fastcgi.conf
chown nginx:nginx "/etc/nginx/fastcgi.conf"
chown nginx:nginx "/etc/nginx/http.d/librey.conf"
fi
# If it is empty or proxy is not enabled, we are using sed to delete
# any line that contains the string 'CURLOPT_PROXY' or 'CURLOPT_PROXYTYPE'

View File

@ -2,6 +2,10 @@ server {
listen 8080;
server_name ${OPEN_SEARCH_HOST_FOR_NGINX} localhost;
add_header Content-Security-Policy "default-src 'none'; style-src 'self'; img-src 'self'";
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff";
root /var/www/html;
index index.php;
@ -10,7 +14,7 @@ server {
}
location ~ \.php$ {
fastcgi_pass unix:/run/php8/php-fpm8.sock;
fastcgi_pass unix:/run/php-fpm82.sock;
fastcgi_index index.php;
include fastcgi.conf;
}

View File

@ -1,65 +0,0 @@
# Set this argument during build time to indicate that the path is for php's www.conf
ARG WWW_CONFIG="/etc/php8/php-fpm.d/www.conf"
# Configure 'opensearch.xml' with librey configuration metadata, such as the encoding and the host that stores the site
# These configurations will replace the 'opensearch.xml' inside '.dockers/templates' for the best setup for your instance
ENV OPEN_SEARCH_TITLE="LibreY"
ENV OPEN_SEARCH_DESCRIPTION="Framework and javascript free privacy respecting meta search engine"
ENV OPEN_SEARCH_ENCODING="UTF-8"
ENV OPEN_SEARCH_LONG_NAME="LibreY search"
ENV OPEN_SEARCH_HOST="http://127.0.0.1:${NGINX_PORT}"
# Replace the 'config.php' script, which contains the most common search engine configurations, with these environment setups
# These environment setups can be found in 'config.php', and the default configurations can be useful for most use cases
ENV CONFIG_GOOGLE_DOMAIN="com"
ENV CONFIG_GOOGLE_LANGUAGE_SITE="en"
ENV CONFIG_GOOGLE_LANGUAGE_RESULTS="en"
ENV CONFIG_GOOGLE_NUMBER_OF_RESULTS="10"
ENV CONFIG_INSTANCE_FALLBACK=true
ENV CONFIG_INVIDIOUS_INSTANCE="https://invidious.snopyta.org"
ENV CONFIG_HIDDEN_SERVICE_SEARCH=false
ENV CONFIG_DISABLE_BITTORRENT_SEARCH=false
ENV CONFIG_BITTORRENT_TRACKERS="&tr=http://nyaa.tracker.wf:7777/announce&tr=udp://open.stealth.si:80/announce&tr=udp://tracker.opentrackr.org:1337/announce&tr=udp://exodus.desync.com:6969/announce&tr=udp://tracker.torrent.eu.org:451/announce"
# Supported apps integration configuration. These empty spaces can be set up using free hosts as pointers
# A particular example is using the "https://yewtu.be" or a self-hosted host to integrate the invidious app to librey
ENV APP_INVIDIOUS=""
ENV APP_RIMGO=""
ENV APP_SCRIBE=""
ENV APP_GOTHUB=""
ENV APP_NITTER=""
ENV APP_LIBREREDDIT=""
ENV APP_PROXITOK=""
ENV APP_WIKILESS=""
ENV APP_QUETRE=""
ENV APP_LIBREMDB=""
ENV APP_BREEZEWIKI=""
ENV APP_ANONYMOUS_OVERFLOW=""
ENV APP_SUDS=""
ENV APP_BIBLIOREADS=""
# Preferred search engines.
ENV CONFIG_TEXT_SEARCH_ENGINE="google"
# GNU/Curl configurations. Leave 'CURLOPT_PROXY' blank whether you don't need to use a proxy for requests
# Generally, a proxy is needed when your IP address is blocked by search engines in response to multiple requests within a short time frame. In these cases, it is recommended to use rotating proxies
ENV CURLOPT_PROXY_ENABLED=false
ENV CURLOPT_PROXY=""
ENV CURLOPT_PROXYTYPE="CURLPROXY_HTTP"
ENV CURLOPT_RETURNTRANSFER=true
ENV CURLOPT_ENCODING=""
ENV CURLOPT_USERAGENT="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"
ENV CURLOPT_CUSTOMREQUEST="GET"
ENV CURLOPT_MAXREDIRS=5
ENV CURLOPT_TIMEOUT=18
ENV CURLOPT_VERBOSE=true
# Install PHP-FPM using Alpine's package manager, apk
# Configure PHP-FPM to listen on a Unix socket instead of a TCP port, which is more secure and efficient
RUN apk add php8 php8-fpm php8-dom php8-curl php8-json php8-apcu --no-cache --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing &&\
sed -i 's/^\s*listen = 127.0.0.1:9000/listen = \/run\/php8\/php-fpm8.sock/' ${WWW_CONFIG} &&\
sed -i 's/^\s*;\s*listen.owner = nobody/listen.owner = nginx/' ${WWW_CONFIG} &&\
sed -i 's/^\s*;\s*listen.group = nobody/listen.group = nginx/' ${WWW_CONFIG} &&\
sed -i 's/^\s*;\s*listen.mode = 0660/listen.mode = 0660/' ${WWW_CONFIG}
CMD [ "/bin/sh", "-c", "docker/php/prepare.sh" ]

View File

@ -1,9 +0,0 @@
# Install Nginx with FastCGI enabled, optimizing its performance for serving content
RUN apk add nginx
# Forward request and error logs to docker log collector
# RUN ln -sf /dev/stdout /var/log/nginx/access.log &&\
# ln -sf /dev/stderr /var/log/nginx/error.log
# After executing the 'docker run' command, run the 'prepare.sh' script
CMD [ "/bin/sh", "-c", "docker/server/prepare.sh" ]

View File

@ -1,21 +0,0 @@
#!/bin/sh
echo "[PREPARE] docker/server/prepare.sh'"
# Load all environment variables from 'attributes.sh' using the command 'source /path/attributes.sh'
source "docker/attributes.sh"
export OPEN_SEARCH_HOST_FOR_NGINX="$(echo "${OPEN_SEARCH_HOST}" | cut -d "/" -f 3 | cut -d ":" -f 1)"
# The lines below will replace the environment variables in the templates with the corresponding variables listed above. To accomplish this, the GNU 'envsubst' package will be used
# Although not recommended (if you do not know what you are doing), you still have the option to add new substitution file templates using any required environment variables
if [[ ! -s ${CONFIG_NGINX_TEMPLATE} ]]; then
cp "docker/server/fastcgi.conf" /etc/nginx/fastcgi.conf
cp "docker/server/nginx.conf" /etc/nginx/http.d/librey.conf
# To address issues with 'nginx.conf', the following lines will ensure that these configurations remain executable
chmod u+x "/etc/nginx/fastcgi.conf"
chmod u+x "/etc/nginx/http.d/librey.conf"
cat 'docker/server/nginx.conf' | envsubst '${OPEN_SEARCH_HOST_FOR_NGINX}' > ${CONFIG_NGINX_TEMPLATE};
fi

View File

@ -7,16 +7,86 @@
<title>LibreY - Donate</title>
</head>
<body>
<div class="misc-container">
<h1>Donate to the original developer of LibreX, a project LibreY tries to improve.</h1>
<h2>Bitcoin (BTC):</h2>
<p>bc1qs43kh6tvhch02dtsp7x7hcrwj8fwe4rzy7lp0h</p>
<img src="static/images/btc.png" alt="btc qr code" width="150" height="150"/>
<h2>Monero (XMR):</h2>
<p>41dGQr9EwZBfYBY3fibTtJZYfssfRuzJZDSVDeneoVcgckehK3BiLxAV4FvEVJiVqdiW996zvMxhFB8G8ot9nBFqQ84VkuC</p>
<img src="static/images/xmr.png" alt="xmr qr code" width="150" height="150"/>
<h1>Donate to the person that forked LibreX into LibreY</h1>
<a href="https://ahwx.org/donate.php">Click here</a>
<div class="donate-container">
<!-- librex dev -->
<h2>
Donate to the original developer of Libre<span class="Y">X</span>, a
project LibreY tries to improve.
</h2>
<div class="flexbox-column">
<div class="qr-box">
<div class="inner-wrap">
<h3>Bitcoin [BTC]</h3>
<p>bc1qs43kh6tvhch02dtsp7x7hcrwj8fwe4rzy7lp0h</p>
</div>
<img
src="/static/images/btc.png"
height="160"
width="160"
alt="btc qr code"
/>
</div>
<div class="qr-box">
<div class="inner-wrap">
<h3>Monero [XMR]</h3>
<p>
41dGQr9EwZBfYBY3fibTtJZYfssfRuzJZDSVDeneoVcgckehK3BiLxAV4FvEVJiVqdiW996zvMxhFB8G8ot9nBFqQ84VkuC
</p>
</div>
<img
src="/static/images/xmr.png"
height="160"
width="160"
alt="xmr qr code (hnhx)"
/>
</div>
<hr class="small-line" />
<!-- librey dev -->
<h2>
Donate to the person that forked LibreX into Libre<span class="Y"
>Y</span
>
</h2>
<div class="qr-box">
<div class="inner-wrap">
<h3>Monero [XMR]</h3>
<p>
4ArntPzKpu32s4z2XqYhyaY1eUeUBKtCzJqEqxWtF5mCi5vR6sdhh32Hd2fk9FjeUxYDtaaUexUqoRNxrgfrtuXs4XpgMNJ
</p>
</div>
<img
src="/static/images/xmr-ahwx.png"
height="160"
width="160"
alt="xmr qr code (ahwx)"
/>
</div>
<div class="flex-row">
<a href="https://ko-fi.com/Ahwxorg" target="_blank"
><img
src="/static/images/kofi.png"
alt="kifi img"
height="50"
width="auto"
/></a>
<a href="https://www.buymeacoffee.com/ahwx" target="_blank">
<img
src="/static/images/buy-me-a-coffee.png"
height="50"
width="auto"
alt="buy-me-a-coffee img"
/></a>
</div>
</div>
</div>
<?php require "misc/footer.php"; ?>

View File

@ -6,8 +6,7 @@
return "https://ahmia.fi/search/?q=" . urlencode($this->query);
}
public function get_results() {
$response = curl_multi_getcontent($this->ch);
public function parse_results($response) {
$results = array();
$xpath = get_xpath($response);
@ -24,6 +23,7 @@
array (
"title" => $title ? htmlspecialchars($title) : "No description provided",
"url" => htmlspecialchars($url),
// base_url is to be removed in the future, see #47
"base_url" => htmlspecialchars(get_base_url($url)),
"description" => htmlspecialchars($description)
)
@ -33,8 +33,8 @@
return $results;
}
public static function print_results($results) {
TextSearch::print_results($results);
public static function print_results($results, $opts) {
TextSearch::print_results($results, $opts);
}
}
?>

View File

@ -5,9 +5,7 @@
return "https://1337x.to/search/$query/1/";
}
public function get_results() {
$response = curl_multi_getcontent($this->ch);
public function parse_results($response) {
$xpath = get_xpath($response);
$results = array();

View File

@ -21,7 +21,7 @@
);
}
public function get_results() {
public function parse_results($response) {
$results = array();
foreach ($this->requests as $request) {
if ($request->successful())
@ -34,7 +34,7 @@
return $results;
}
public static function print_results($results) {
public static function print_results($results, $opts) {
echo "<div class=\"text-result-container\">";
if (empty($results)) {

View File

@ -6,8 +6,7 @@
return "https://$this->SOURCE/?q=" . urlencode($this->query);
}
public function get_results() {
$response = curl_multi_getcontent($this->ch);
public function parse_results($response) {
$xpath = get_xpath($response);
$results = array();

View File

@ -4,8 +4,7 @@
return "http://rutor.info/search/" . urlencode($this->query);
}
public function get_results() {
$response = curl_multi_getcontent($this->ch);
public function parse_results($response) {
$xpath = get_xpath($response);
$results = array();

View File

@ -4,8 +4,7 @@
return "https://apibay.org/q.php?q=" . urlencode($this->query);
}
public function get_results() {
$response = curl_multi_getcontent($this->ch);
public function parse_results($response) {
$results = array();
$json_response = json_decode($response, true);

View File

@ -5,8 +5,7 @@
return "https://torrentgalaxy.to/torrents.php?search=$query#results";
}
public function get_results() {
$response = curl_multi_getcontent($this->ch);
public function parse_results($response) {
$xpath = get_xpath($response);
$results = array();

View File

@ -4,9 +4,8 @@
return "https://yts.mx/api/v2/list_movies.json?query_term=" . urlencode($this->query);
}
public function get_results() {
public function parse_results($response) {
$response = curl_multi_getcontent($this->ch);
global $config;
$results = array();
$json_response = json_decode($response, true);

View File

@ -6,16 +6,14 @@
return "$this->instance_url/api/v1/search?q=$query";
}
public function get_results() {
public function parse_results($response) {
$results = array();
$response = curl_multi_getcontent($this->ch);
$json_response = json_decode($response, true);
foreach ($json_response as $response) {
if ($response["type"] == "video") {
$title = $response["title"];
$url = "https://youtube.com/watch?v=" . $response["videoId"];
$url = check_for_privacy_frontend($url, $this->opts);
$uploader = $response["author"];
$views = $response["viewCount"];
$date = $response["publishedText"];
@ -25,6 +23,7 @@
array (
"title" => htmlspecialchars($title),
"url" => htmlspecialchars($url),
// base_url is to be removed in the future, see #47
"base_url" => htmlspecialchars(get_base_url($url)),
"uploader" => htmlspecialchars($uploader),
"views" => htmlspecialchars($views),
@ -38,13 +37,14 @@
return $results;
}
public static function print_results($results) {
public static function print_results($results, $opts) {
echo "<div class=\"text-result-container\">";
foreach($results as $result) {
$title = $result["title"];
$url = $result["url"];
$base_url = $result["base_url"];
$url = check_for_privacy_frontend($url, $opts);
$base_url = get_base_url($url);
$uploader = $result["uploader"];
$views = $result["views"];
$date = $result["date"];

View File

@ -7,11 +7,10 @@
}
public function get_request_url() {
return $this->instance . "api.php?" . opts_to_params($this->opts);
return $this->instance . "api.php?" . opts_to_params($this->opts) . "&nfb=1";
}
public function get_results() {
$response = curl_exec($this->ch);
public function parse_results($response) {
$response = json_decode($response, true);
if (!$response)
return array();
@ -47,13 +46,17 @@
$instance = array_pop($instances);
if (!$instance)
break;
if (parse_url($instance)["host"] == parse_url($_SERVER['HTTP_HOST'])["host"])
continue;
$librex_request = new LibreXFallback($instance, $opts, null);
$results = $librex_request->get_results();
if (count($results) > 1)
if (!empty($results))
return $results;
// on fail then do this
@ -62,7 +65,11 @@
} while (!empty($instances));
return array();
return array(
"error" => array(
"message" => "No results found. Unable to fallback to other instances."
)
);
}
?>

View File

@ -7,9 +7,9 @@
return "https://lite.qwant.com/?q=$query&t=images&p=$page";
}
public function get_results() {
public function parse_results($response) {
$results = array();
$xpath = get_xpath(curl_multi_getcontent($this->ch));
$xpath = get_xpath($response);
if (!$xpath)
return $results;
@ -24,7 +24,6 @@
$encoded_url_split1 = explode("==/", $encoded_url)[1];
$encoded_url_split2 = explode("?position", $encoded_url_split1)[0];
$real_url = urldecode(base64_decode($encoded_url_split2));
$real_url = check_for_privacy_frontend($real_url, $this->opts);
$alt = $image->getAttribute("alt");
$thumbnail = urlencode($image->getAttribute("src"));
@ -43,7 +42,7 @@
return $results;
}
public static function print_results($results) {
public static function print_results($results, $opts) {
echo "<div class=\"image-result-container\">";
foreach($results as $result)
@ -51,6 +50,7 @@
$thumbnail = urlencode($result["thumbnail"]);
$alt = $result["alt"];
$url = $result["url"];
$url = check_for_privacy_frontend($url, $opts);
echo "<a title=\"$alt\" href=\"$url\" target=\"_blank\">";
echo "<img src=\"image_proxy.php?url=$thumbnail\">";

View File

@ -4,9 +4,7 @@
return "https://cdn.moneyconvert.net/api/latest.json";
}
public function get_results() {
$response = curl_multi_getcontent($this->ch);
public function parse_results($response) {
$split_query = explode(" ", $this->query);
$base_currency = strtoupper($split_query[1]);

View File

@ -8,9 +8,7 @@
return "https://api.dictionaryapi.dev/api/v2/entries/en/$word_to_define";
}
public function get_results() {
$response = curl_multi_getcontent($this->ch);
public function parse_results($response) {
$json_response = json_decode($response, true);
if (!array_key_exists("title", $json_response))

View File

@ -1,6 +1,6 @@
<?php
class IPRequest extends EngineRequest {
function get_results() {
public function parse_results($response) {
return array(
"special_response" => array(
"response" => $_SERVER["REMOTE_ADDR"],

View File

@ -5,9 +5,7 @@
return "https://check.torproject.org/torbulkexitlist";
}
public function get_results() {
$response = curl_multi_getcontent($ch);
public function parse_results($response) {
$formatted_response = strpos($response, $_SERVER["REMOTE_ADDR"]) ? "It seems like you are using Tor" : "It seems like you are not using Tor";
$source = "https://check.torproject.org";

View File

@ -1,6 +1,6 @@
<?php
class UserAgentRequest extends EngineRequest {
function get_results() {
public function parse_results($response) {
return array(
"special_response" => array(
"response" => $_SERVER["HTTP_USER_AGENT"],

View File

@ -4,8 +4,7 @@
return "https://wttr.in/@" . $_SERVER["REMOTE_ADDR"] . "?format=j1";
}
public function get_results() {
$response = curl_multi_getcontent($this->ch);
public function parse_results($response) {
$json_response = json_decode($response, true);
if (!$json_response)

View File

@ -1,18 +1,18 @@
<?php
class WikipediaRequest extends EngineRequest {
public function get_request_url() {
$this->wikipedia_language = $this->opts->language;
$this->wikipedia_domain = "wikipedia.org";
$query_encoded = urlencode($this->query);
if (!in_array($this->wikipedia_language, json_decode(file_get_contents("static/misc/wikipedia_langs.json"), true)))
$this->wikipedia_language = "en";
$languages = json_decode(file_get_contents("static/misc/languages.json"), true);
return "https://$this->wikipedia_language.wikipedia.org/w/api.php?format=json&action=query&prop=extracts%7Cpageimages&exintro&explaintext&redirects=1&pithumbsize=500&titles=$query_encoded";
if (array_key_exists($this->opts->language, $languages))
$this->wikipedia_domain = $languages[$this->opts->language]["wikipedia"] . ".wikipedia.org";
return "https://$this->wikipedia_domain/w/api.php?format=json&action=query&prop=extracts%7Cpageimages&exintro&explaintext&redirects=1&pithumbsize=500&titles=$query_encoded";
}
public function get_results() {
$response = curl_multi_getcontent($this->ch);
public function parse_results($response) {
$json_response = json_decode($response, true);
$first_page = array_values($json_response["query"]["pages"])[0];
@ -22,7 +22,7 @@
$description = substr($first_page["extract"], 0, 250) . "...";
$source = check_for_privacy_frontend("https://$this->wikipedia_language.wikipedia.org/wiki/$this->query", $this->opts);
$source = "https://$this->wikipedia_domain/wiki/$this->query";
$response = array(
"special_response" => array(
"response" => htmlspecialchars($description),

View File

@ -19,30 +19,30 @@
if (isset($_COOKIE["safe_search"]))
$url .= "&safe=medium";
return $url;
}
public function get_results() {
public function parse_results($response) {
$results = array();
$xpath = get_xpath(curl_multi_getcontent($this->ch));
$xpath = get_xpath($response);
if (!$xpath)
return $results;
foreach($xpath->query("/html/body/div[1]/div[". count($xpath->query('/html/body/div[1]/div')) ."]/div/div/div/div") as $result)
{
foreach($xpath->query("/html/body/div[1]/div[". count($xpath->query('/html/body/div[1]/div')) ."]/div/div/div[contains(@class, 'web-result')]/div") as $result) {
$url = $xpath->evaluate(".//h2[@class='result__title']//a/@href", $result)[0];
if ($url == null)
continue;
if (!empty($results)) // filter duplicate results
{
if (!empty($results)) { // filter duplicate results
if (end($results)["url"] == $url->textContent)
continue;
}
$url = $url->textContent;
$url = check_for_privacy_frontend($url, $this->opts);
$title = $xpath->evaluate(".//h2[@class='result__title']", $result)[0];
$description = $xpath->evaluate(".//a[@class='result__snippet']", $result)[0];
@ -50,6 +50,7 @@
array (
"title" => htmlspecialchars($title->textContent),
"url" => htmlspecialchars($url),
// base_url is to be removed in the future, see #47
"base_url" => htmlspecialchars(get_base_url($url)),
"description" => $description == null ?
"No description was provided for this site." :
@ -57,7 +58,7 @@
)
);
}
return $results;
return $results;
}
}

View File

@ -26,9 +26,9 @@
}
public function get_results() {
public function parse_results($response) {
$results = array();
$xpath = get_xpath(curl_multi_getcontent($this->ch));
$xpath = get_xpath($response);
if (!$xpath)
return $results;
@ -53,7 +53,6 @@
}
$url = $url->textContent;
$url = check_for_privacy_frontend($url, $this->opts);
$title = $xpath->evaluate(".//h3", $result)[0];
$description = $xpath->evaluate(".//div[contains(@class, 'VwiC3b')]", $result)[0];
@ -62,6 +61,7 @@
array (
"title" => htmlspecialchars($title->textContent),
"url" => htmlspecialchars($url),
// base_url is to be removed in the future, see #47
"base_url" => htmlspecialchars(get_base_url($url)),
"description" => $description == null ?
"No description was provided for this site." :
@ -70,6 +70,12 @@
);
}
if (empty($results) && !str_contains($response, "Our systems have detected unusual traffic from your computer network.")) {
$results["error"] = array(
"message" => "There are no results. Please try different keywords!"
);
}
return $results;
}
}

View File

@ -12,9 +12,6 @@
if (substr($this->query, 0, 1) == "!" || substr($last_word_query, 0, 1) == "!")
check_ddg_bang($this->query, $opts);
if (has_cooldown($this->engine, $this->opts->cooldowns))
return;
if ($this->engine == "google") {
require "engines/text/google.php";
@ -26,38 +23,53 @@
$this->engine_request = new DuckDuckGoRequest($opts, $mh);
}
if (has_cooldown($this->engine, $this->opts->cooldowns) && !has_cached_results($this->engine_request->url)) {
// TODO dont add it in the first place
curl_multi_remove_handle($mh, $this->engine_request->ch);
$this->engine_request = null;
return;
}
require "engines/special/special.php";
$this->special_request = get_special_search_request($opts, $mh);
}
public function get_results() {
if (!$this->engine_request)
public function parse_results($response) {
if (!isset($this->engine_request))
return array();
$results = $this->engine_request->get_results();
if ($this->special_request) {
$special_result = $this->special_request->get_results();
if ($special_result)
$results = array_merge(array($special_result), $results);
}
if (count($results) <= 1)
if (empty($results)) {
set_cooldown($this->engine, ($opts->request_cooldown ?? "1") * 60, $this->opts->cooldowns);
} else {
if ($this->special_request) {
$special_result = $this->special_request->get_results();
if ($special_result)
$results = array_merge(array($special_result), $results);
}
}
return $results;
}
public static function print_results($results) {
public static function print_results($results, $opts) {
if (empty($results))
if (empty($results)) {
echo "<div class=\"text-result-container\"><p>An error occured fetching results</p></div>";
return;
}
if (array_key_exists("error", $results)) {
echo "<div class=\"text-result-container\"><p>" . $results["error"]["message"] . "</p></div>";
return;
}
$special = $results[0];
if (array_key_exists("did_you_mean", $special))
{
if (array_key_exists("did_you_mean", $special)) {
$didyoumean = $special["did_you_mean"];
$new_url = "/search.php?q=" . urlencode($didyoumean);
echo "<p class=\"did-you-mean\">Did you mean ";
@ -65,33 +77,34 @@
echo "?</p>";
}
if (array_key_exists("special_response", $special))
{
if (array_key_exists("special_response", $special)) {
$response = $special["special_response"]["response"];
$source = $special["special_response"]["source"];
echo "<p class=\"special-result-container\">";
if (array_key_exists("image", $special["special_response"]))
{
if (array_key_exists("image", $special["special_response"])) {
$image_url = $special["special_response"]["image"];
echo "<img src=\"image_proxy.php?url=$image_url\">";
}
echo $response;
if ($source)
if ($source) {
$source = check_for_privacy_frontend($source, $opts);
echo "<a href=\"$source\" target=\"_blank\">$source</a>";
}
echo "</p>";
}
echo "<div class=\"text-result-container\">";
foreach($results as $result)
{
foreach($results as $result) {
if (!array_key_exists("title", $result))
continue;
$title = $result["title"];
$url = $result["url"];
$base_url = $result["base_url"];
$url = check_for_privacy_frontend($url, $opts);
$base_url = get_base_url($url);
$description = $result["description"];
echo "<div class=\"text-result-wrapper\">";
@ -107,8 +120,7 @@
}
}
function check_ddg_bang($query, $opts)
{
function check_ddg_bang($query, $opts) {
$bangs_json = file_get_contents("static/misc/ddg_bang.json");
$bangs = json_decode($bangs_json, true);
@ -120,22 +132,18 @@
$bang_url = null;
foreach($bangs as $bang)
{
if ($bang["t"] == $search_word)
{
foreach($bangs as $bang) {
if ($bang["t"] == $search_word) {
$bang_url = $bang["u"];
break;
}
}
if ($bang_url)
{
if ($bang_url) {
$bang_query_array = explode("!" . $search_word, $query);
$bang_query = trim(implode("", $bang_query_array));
$request_url = str_replace("{{{s}}}", str_replace('%26quot%3B','%22', urlencode($bang_query)), $bang_url);
$request_url = check_for_privacy_frontend($request_url, $opts);
header("Location: " . $request_url);
die();

View File

@ -2,11 +2,18 @@
"instances": [
{
"clearnet": "https://search.ahwx.org/",
"tor": "http://hyy7rcvknwb22v4nnoar635wntiwr4uwzhiuyimemyl4fz6k7tahj5id.onion/",
"tor": "http://wn5jl6fxlzzfenlyu3lc4q7jpw2saplrywxvxtvqbguotwd4y5cjeuqd.onion/",
"i2p": null,
"country": "NL",
"librey": true
},
{
"clearnet": "https://search2.ahwx.org/",
"tor": "http://hyy7rcvknwb22v4nnoar635wntiwr4uwzhiuyimemyl4fz6k7tahj5id.onion/",
"i2p": null,
"country": "FR",
"librey": true
},
{
"clearnet": "https://librex.me/",
"tor": "http://librex.revvybrr6pvbx4n3j4475h4ghw4elqr4t5xo2vtd3gfpu2nrsnhh57id.onion/",
@ -28,6 +35,13 @@
"country": "CL",
"librey": true
},
{
"clearnet": "https://lx.vern.cc/",
"tor": "http://lx.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion/",
"i2p": "http://vernziqfqvweijfaacmwazohgpdo2bt2ib2jlupt2pwwu27bhgxq.b32.i2p/",
"country": "US",
"librey": true
},
{
"clearnet": "https://librey.org/",
"tor": "http://jxhkfulu6wpdl4apuy4dyivuowmpprvsd7e3el2z73crq7fmyv7rjkyd.onion/",
@ -35,6 +49,13 @@
"country": "US",
"librey": true
},
{
"clearnet": "https://librex.supernets.org/",
"tor": "http://ouosr2fq3lktngcvbz4r4op2lab5hbiz5y6g6toorsgieb7elet76jad.onion/",
"i2p": null,
"country": "US",
"librey": true
},
{
"clearnet": "https://search.davidovski.xyz/",
"tor": null,
@ -77,47 +98,47 @@
"country": "MX",
"librey": true
},
{
"clearnet": "https://lx.vern.cc/",
"tor": "http://lx.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion/",
"i2p": "http://vernziqfqvweijfaacmwazohgpdo2bt2ib2jlupt2pwwu27bhgxq.b32.i2p/",
"country": "US",
"librey": false
},
{
"clearnet": "https://lx.owo.si/",
"tor": "http://lx.pk47sgwhncn5cgidm7bofngmh7lc7ukjdpk5bjwfemmyp27ovl25ikyd.onion/",
"i2p": "http://d4vi3tvfui2rfzsxr33tin4a6542heulf4mhkokdpbhbcejlg3la.b32.i2p/",
"country": "DE",
"librey": false
},
{
"clearnet": "https://search.spaceint.fr/",
"tor": null,
"i2p": null,
"country": "FR",
"librey": false
},
{
"clearnet": "https://search.pabloferreiro.es/",
"tor": null,
"i2p": null,
"country": "DE",
"librey": false
"librey": true
},
{
"clearnet": "https://librex.ratakor.com/",
"clearnet": "https://search.ratakor.com/",
"tor": null,
"i2p": null,
"country": "FR",
"librey": false
"librey": true
},
{
"clearnet": "https://search.tildevarsh.in/",
"clearnet": "https://librex.yogeshlamichhane.com.np/",
"tor": null,
"i2p": null,
"country": "IN",
"librey": false
"country": "FI",
"librey": true
},
{
"clearnet": "https://librey.baczek.me/",
"tor": null,
"i2p": null,
"country": "PL",
"librey": true
},
{
"clearnet": "https://lx.benike.me/",
"tor": null,
"i2p": null,
"country": "DE",
"librey": true
},
{
"clearnet": "https://search.seitan-ayoub.lol/",
"tor": null,
"i2p": null,
"country": "DE",
"librey": true
},
{
"clearnet": "https://librex.myroware.eu/",
@ -139,20 +160,6 @@
"i2p": null,
"country": "PL",
"librey": false
},
{
"clearnet": "https://lx.benike.monster/",
"tor": null,
"i2p": null,
"country": "DE",
"librey": false
},
{
"clearnet": "https://librex.pardesicat.xyz/",
"tor": null,
"i2p": null,
"country": "KR",
"librey": false
}
]
}

View File

@ -44,7 +44,7 @@
<title>LibreY - instances</title>
</head>
<body>
<div class="misc-container">
<center>
<h2>Libre<span class="Y">Y</span> instances</h2>
<?php
@ -56,6 +56,7 @@
list_instances($librex_instances);
?>
</center>
</div>
<?php require "misc/footer.php"; ?>

View File

@ -1,4 +1,8 @@
<?php
if (!function_exists("apcu_fetch"))
error_log("apcu is not installed! Please consider installing php-pecl-apcu for significant performance improvements");
function load_cooldowns() {
if (function_exists("apcu_fetch"))
return apcu_exists("cooldowns") ? apcu_fetch("cooldowns") : array();
@ -19,4 +23,23 @@
function has_cooldown($instance, $cooldowns) {
return ($cooldowns[$instance] ?? 0) > time();
}
function has_cached_results($url) {
if (function_exists("apcu_exists"))
return apcu_exists("cached:$url");
return false;
}
function store_cached_results($url, $results, $ttl = 0) {
if (function_exists("apcu_store") && !empty($results))
return apcu_store("cached:$url", $results, $ttl);
}
function fetch_cached_results($url) {
if (function_exists("apcu_fetch"))
return apcu_fetch("cached:$url");
return array();
}
?>

View File

@ -1,15 +1,21 @@
<?php
require "misc/cooldowns.php";
abstract class EngineRequest {
protected $DO_CACHING = true;
function __construct($opts, $mh) {
$this->query = $opts->query;
$this->page = $opts->page;
$this->mh = $mh;
$this->opts = $opts;
$url = $this->get_request_url();
if (!$url)
$this->url = $this->get_request_url();
if (!$this->url)
return;
$this->ch = curl_init($url);
if (has_cached_results($this->url))
return;
$this->ch = curl_init($this->url);
if ($opts->curl_settings)
curl_setopt_array($this->ch, $opts->curl_settings);
@ -23,17 +29,39 @@
}
public function successful() {
return curl_getinfo($this->ch)['http_code'] == '200';
return (isset($this->ch) && curl_getinfo($this->ch)['http_code'] == '200')
|| has_cached_results($this->url);
}
abstract function get_results();
static public function print_results($results){}
abstract function parse_results($response);
public function get_results() {
if (!isset($this->url))
return $this->parse_results(null);
if ($this->DO_CACHING && has_cached_results($this->url))
return fetch_cached_results($this->url);
if (!isset($this->ch))
return $this->parse_results(null);
$response = $this->mh ? curl_multi_getcontent($this->ch) : curl_exec($this->ch);
$results = $this->parse_results($response) ?? array();
if ($this->DO_CACHING && !empty($results))
store_cached_results($this->url, $results, $this->opts->cache_time * 60);
return $results;
}
public static function print_results($results, $opts) {}
}
function load_opts() {
$opts = require "config.php";
$opts->request_cooldown ??= 25;
$opts->cache_time ??= 25;
$opts->query = trim($_REQUEST["q"] ?? "");
$opts->type = (int) ($_REQUEST["t"] ?? 0);
@ -47,7 +75,7 @@
$opts->disable_frontends = (int) ($_REQUEST["nf"] ?? 0) == 1 || isset($_COOKIE["disable_frontends"]);
$opts->language = $_REQUEST["lang"] ?? trim(htmlspecialchars($_COOKIE["language"] ?? $opts->language));
$opts->language = $_REQUEST["lang"] ?? trim(htmlspecialchars($_COOKIE["language"] ?? $opts->language ?? "en"));
$opts->do_fallback = (int) ($_REQUEST["nfb"] ?? 0) == 0;
if (!$opts->instance_fallback) {
@ -60,6 +88,8 @@
$opts->frontends[$frontend]["instance_url"] = $_COOKIE[$frontend] ?? $opts->frontends[$frontend]["instance_url"];
}
$opts->curl_settings[CURLOPT_FOLLOWLOCATION] ??= true;
return $opts;
}
@ -70,7 +100,6 @@
$params .= "p=$opts->page";
$params .= "&q=$query";
$params .= "&t=$opts->type";
$params .= "&nfb=" . ($opts->do_fallback ? 0 : 1);
$params .= "&safe=" . ($opts->safe_search ? 1 : 0);
$params .= "&nf=" . ($opts->disable_frontends ? 1 : 0);
$params .= "&ns=" . ($opts->disable_special ? 1 : 0);
@ -113,7 +142,6 @@
}
function fetch_search_results($opts, $do_print) {
require "misc/cooldowns.php";
$opts->cooldowns = load_cooldowns();
$start_time = microtime(true);
@ -128,7 +156,7 @@
$results = $search_category->get_results();
if (count($results) <= 1) {
if (empty($results)) {
require "engines/librex/fallback.php";
$results = get_librex_results($opts);
}
@ -137,7 +165,7 @@
return $results;
print_elapsed_time($start_time);
$search_category->print_results($results);
$search_category->print_results($results, $opts);
return $results;
}

View File

@ -1,8 +1,7 @@
<?php
function get_base_url($url) {
$split_url = explode("/", $url);
$base_url = $split_url[0] . "//" . $split_url[2] . "/";
return $base_url;
$parsed = parse_url($url);
return $parsed["scheme"] . "://" . $parsed["host"] . "/";
}
function get_root_domain($url) {

View File

@ -1,6 +1,5 @@
<?php
require "misc/search_engine.php";
$opts = load_opts();
// Reset all cookies when resetting, or before saving new cookies
if (isset($_REQUEST["reset"]) || isset($_REQUEST["save"])) {
@ -29,6 +28,8 @@
die();
}
$opts = load_opts();
require "misc/header.php";
?>
@ -59,7 +60,7 @@
<option value=\"ubuntu\">Ubuntu</option>
<option value=\"tokyo_night\">Tokyo night</option>";
if (isset($_COOKIE["theme"])) {
if (isset($opts->theme)) {
$theme = $opts->theme;
$themes = str_replace($theme . "\"", $theme . "\" selected", $themes);
}
@ -97,19 +98,31 @@
<div class="settings-textbox-container">
<div>
<span>Language</span>
<select name="language">
<?php
// TODO make this a dropdown
echo "<input type=\"text\" name=\"language\" placeholder=\"any\" value=\"" . htmlspecialchars($opts->language ?? "") . "\">";
$languages = json_decode(file_get_contents("static/misc/languages.json"), true);
$options = "";
$options .= "<option value=\"\" " . (!isset($opts->language) ? "selected" : "") . ">Any</option>";
foreach ($languages as $lang_code => $language) {
$name = $language["name"];
$selected = $opts->language == $lang_code ? "selected" : "";
$options .= "<option value=\"$lang_code\" $selected>$name</option>";
}
echo $options;
?>
</select>
</div>
<div>
<label>Number of results per page</label>
<input type="number" name="number_of_results" value="<?php echo htmlspecialchars($opts->number_of_results ?? "10") ?>" >
</div>
<div>
<label>Safe search</label>
<input type="checkbox" name="safe_search" <?php echo $opts->safe_search ? "checked" : ""; ?> >
</div>
</div>
<div>
<label>Safe search</label>
<input type="checkbox" name="safe_search" <?php echo $opts->safe_search ? "checked" : ""; ?> >
</div>
<div>

View File

@ -151,7 +151,7 @@ a:hover,
.misc-container {
text-align: center;
word-wrap: break-word;
width: 450px;
width: 460px;
margin-left: auto;
margin-right: auto;
margin-bottom: 100px;
@ -319,8 +319,7 @@ a[title] {
}
.footer-container a {
margin-left: 15px;
margin-right: 15px;
margin-right: 30px;
}
.hide {
@ -339,6 +338,60 @@ a[title] {
color: #ff79c6;
}
/* donate css start */
.donate-container {
width: 700px;
margin-left: auto;
margin-right: auto;
margin-bottom: 100px;
}
.flexbox-column {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
gap: 10px;
}
.inner-wrap {
width: 500px;
padding: 20px;
}
.qr-box {
background-color: var(--search-container-background-color);
border: 1px solid var(--search-container-background-border);
border-radius: 10px 0px 0px 10px;
width: 100%;
display: flex;
word-wrap: break-word;
align-items: center;
justify-content: space-between;
}
.flex-row {
width: 700px;
height: auto;
display: flex;
flex-direction: row;
justify-content: space-evenly;
}
hr.small-line {
/* background-color: #f1f3f4; */
border: 2px solid var(--main-fg);
height: 0px;
width: 100px;
margin: 30px;
border-radius: 2px;
}
/* donate css end */
@media only screen and (max-width: 1320px) {
.special-result-container {
position: relative;
@ -485,4 +538,53 @@ a[title] {
margin-left: 20px;
}
/* dontate css start*/
.donate-container {
margin-bottom: 100px;
width: 95%;
text-align: center;
}
.qr-box {
display: flex;
flex-direction: column;
word-wrap: break-word;
align-items: center;
justify-content: space-between;
word-wrap: break-word;
height: auto;
}
.qr-box {
border-radius: 10px;
flex-direction: column;
align-items: center;
}
.inner-wrap {
width: 80%;
text-align: center;
}
.qr-box img {
width: 40%;
height: auto;
padding: 20px;
}
.flex-row {
flex-direction: column;
align-items: center;
gap: 5px;
width: 0;
}
.flex-row a img {
width: 220px;
height: auto;
}
/* donate css end */
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

BIN
static/images/kofi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
static/images/xmr-ahwx.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
["ab","ace","ady","af","ak","als","am","an","ang","ar","arc","ary","arz","as","ast","atj","av","avk","awa","ay","az","azb","ba","ban","bar","bat-smg","bcl","be","be-tarask","bg","bh","bi","bjn","bm","bn","bo","bpy","br","bs","bug","bxr","ca","cbk-zam","cdo","ce","ceb","ch","chr","chy","ckb","co","cr","crh","cs","csb","cu","cv","cy","da","de","din","diq","dsb","dty","dv","dz","ee","el","eml","en","eo","es","et","eu","ext","fa","ff","fi","fiu-vro","fj","fo","fr","frp","frr","fur","fy","ga","gag","gan","gcr","gd","gl","glk","gn","gom","gor","got","gu","gv","ha","hak","haw","he","hi","hif","hr","hsb","ht","hu","hy","hyw","ia","id","ie","ig","ik","ilo","inh","io","is","it","iu","ja","jam","jbo","jv","ka","kaa","kab","kbd","kbp","kg","ki","kk","kl","km","kn","ko","koi","krc","ks","ksh","ku","kv","kw","ky","la","lad","lb","lbe","lez","lfn","lg","li","lij","lld","lmo","ln","lo","lt","ltg","lv","mad","mai","map-bms","mdf","mg","mhr","mi","min","mk","ml","mn","mnw","mr","mrj","ms","mt","mwl","my","myv","mzn","na","nah","nap","nds","nds-nl","ne","new","nia","nl","nn","no","nostalgia","nov","nqo","nrm","nso","nv","ny","oc","olo","om","or","os","pa","pag","pam","pap","pcd","pdc","pfl","pi","pih","pl","pms","pnb","pnt","ps","pt","qu","rm","rmy","rn","ro","roa-rup","roa-tara","ru","rue","rw","sa","sah","sat","sc","scn","sco","sd","se","sg","sh","shn","si","simple","sk","skr","sl","sm","smn","sn","so","sq","sr","srn","ss","st","stq","su","sv","sw","szl","szy","ta","tcy","te","tet","tg","th","ti","tk","tl","tn","to","tpi","tr","ts","tt","tum","tw","ty","tyv","udm","ug","uk","ur","uz","ve","vec","vep","vi","vls","vo","wa","war","wo","wuu","xal","xh","xmf","yi","yo","za","zea","zh","zh-classical","zh-min-nan","zh-yue","zu","zh-hans","zh-hant","zh-cn","zh-hk","zh-mo","zh-my","zh-sg","zh-tw"]