Squash commits

This commit is contained in:
sn4il 2023-07-10 10:54:15 +03:00 committed by Sn4il
parent 5a8279ec68
commit 57c550a693
225 changed files with 5727 additions and 1420 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.hugo_build.lock
public

30
README.md Normal file
View File

@ -0,0 +1,30 @@
# Обновленный TheDroth.Rocks
## Подготовка
- Установить Docker
- Загрузить образ с [Hugo](https://hub.docker.com/r/klakegg/hugo):
```
docker pull klakegg/hugo
```
## Запуск
- Перейти в корневой каталог с проектом
- Выполнить запуск Hugo сервера
1) Для тестов:
```
docker run --rm -v $(pwd):/src -p 1313:1313 klakegg/hugo server
```
2) Для прода:
```
docker run -v $(pwd):/src -p 1313:1313 klakegg/hugo
```
## Мини FAQ
- ```config.yml``` - основной файл настройки сайта.
- Записи (странички) складываются в ```content/core``` и имеют ```.md``` формат.
- Если нужно, чтобы страницы не отображались на главном экране - расположите их в директории отличной от ```content/core```. Например, для блога можно использовать ```content/blog```.
- Картинки лежат в ```static```.
## Документация
- [Hugo Docker](https://hub.docker.com/r/klakegg/hugo)
- [Hugo Docs](https://gohugo.io/documentation/)
- [Template Repo](https://github.com/adityatelange/hugo-PaperMod)
- [Template miniFAQ](https://adityatelange.github.io/hugo-PaperMod/posts/papermod/papermod-faq/)

6
archetypes/default.md Normal file
View File

@ -0,0 +1,6 @@
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---

3
baseconfig.toml Normal file
View File

@ -0,0 +1,3 @@
baseURL = 'http://example.org/'
languageCode = 'en-us'
title = 'My New Hugo Site'

148
config.yml Normal file
View File

@ -0,0 +1,148 @@
baseURL: "https://thedroth.rocks"
title: TheDrothRocks!
paginate: 5
theme: PaperMod
enableRobotsTXT: true
buildDrafts: false
buildFuture: false
buildExpired: false
# googleAnalytics: UA-123-45
minify:
disableXML: true
minifyOutput: true
params:
env: production # to enable google analytics, opengraph, twitter-cards and schema.
title: TheDroth Rocks!
description: "TheДроты рулят"
keywords: [Blog, Portfolio, PaperMod]
author: ["nothing", "sn4il"]
# author: ["Me", "You"] # multiple authors
images: ["<link or path of image for opengraph, twitter-cards>"]
DateFormat: "January 2, 2006"
defaultTheme: auto # dark, light
disableThemeToggle: false
ShowReadingTime: true
ShowShareButtons: true
ShowPostNavLinks: true
ShowBreadCrumbs: true
ShowCodeCopyButtons: false
ShowWordCount: true
ShowRssButtonInSectionTermList: true
UseHugoToc: true
disableSpecial1stPost: false
disableScrollToTop: false
comments: false
hidemeta: false
hideSummary: false
showtoc: false
tocopen: false
params:
# mainSections:
# - core
# - blog
assets:
# disableHLJS: true # to disable highlight.js
# disableFingerprinting: true
favicon: "/images/favicon.png"
favicon16x16: "/images/favicon.png"
favicon32x32: "/images/favicon.png"
apple_touch_icon: "<link / abs url>"
safari_pinned_tab: "<link / abs url>"
label:
text: "TheDroth.Rocks"
icon: "/images/thedroth_logo.png"
iconHeight: 35
# profile-mode
profileMode:
enabled: false # needs to be explicitly set
title: ExampleSite
subtitle: "This is subtitle"
imageUrl: "<img location>"
imageWidth: 120
imageHeight: 120
imageTitle: my image
buttons:
- name: Posts
url: posts
- name: Tags
url: tags
# home-info mode
homeInfoParams:
Title: "Привет всем TheDroth'ам \U0001F44B"
Content: Добро пожаловать на наш сайт!
socialIcons:
- name: lemmy
url: "https://asocial.thedroth.rocks/"
- name: gitea
url: "https://git.thedroth.rocks/TheDroth/thedroth-rocks"
- name: piped
url: "https://piped.thedroth.rocks/"
analytics:
google:
SiteVerificationTag: "XYZabc"
bing:
SiteVerificationTag: "XYZabc"
yandex:
SiteVerificationTag: "XYZabc"
cover:
hidden: true # hide everywhere but not in structured data
hiddenInList: true # hide on list pages and home
hiddenInSingle: true # hide on single page
# editPost:
# URL: "https://github.com/<path_to_repo>/content"
# Text: "Suggest Changes" # edit text
# appendFilePath: true # to append file path to Edit link
# for search
# https://fusejs.io/api/options.html
fuseOpts:
isCaseSensitive: false
shouldSort: true
location: 0
distance: 1000
threshold: 0.4
minMatchCharLength: 0
keys: ["title", "permalink", "summary", "content"]
menu:
main:
- identifier: our-services
name: Наши сервисы
url: /core/our-services/
weight: 10
- identifier: proxy
name: Проксирующие сервисы
url: /core/proxy/
weight: 20
- identifier: tos
name: ToS
url: https://git.thedroth.rocks/TheDroth/ToS/src/branch/main/README.md
weight: 30
- identifier: blog
name: Блог
url: /tags/blog/
weight: 40
# Read: https://github.com/adityatelange/hugo-PaperMod/wiki/FAQs#using-hugos-syntax-highlighter-chroma
pygmentsUseClasses: true
markup:
highlight:
noClasses: false
# anchorLineNos: true
# codeFences: true
# guessSyntax: true
# lineNos: true
# style: monokai

28
content/blog/redesign.md Normal file
View File

@ -0,0 +1,28 @@
---
title: "Редизайн"
date: 2023-10-26T08:30:03+03:00
weight: 2
tags: ["blog"]
author: "sn4il"
showToc: false
TocOpen: false
draft: false
hidemeta: false
comments: false
description: "Все сервисы, которые мы проксируем. Заголовки - ссылки."
disableHLJS: true # to disable highlightjs
disableShare: false
disableHLJS: false
hideSummary: false
searchHidden: true
ShowReadingTime: false
ShowBreadCrumbs: true
ShowPostNavLinks: true
ShowWordCount: false
ShowRssButtonInSectionTermList: true
UseHugoToc: true
---
# Смена дизайна
Благодаря усилиям товарища Nothing, сайт переведён с олдскульного статического HTML на Hugo. Теперь мы не только симпатично смотримся, но и можем вести блог. Здесь будут публиковаться изменения и планы касательно сервисов и дальнейшего развития проекта. И, возможно, внутренние новости от команды.

45
content/core/donate.md Normal file
View File

@ -0,0 +1,45 @@
---
title: "Donate!"
date: 2023-10-26T09:00:03+03:00
weight: 3
# aliases: ["/first"]
#tags: ["donae"]
author: "sn4il"
# author: ["Me", "You"] # multiple authors
showToc: true
TocOpen: false
draft: false
hidemeta: false
comments: false
description: "Поддержка - это хорошо, а материальная поддержка - всегда спасибо!"
disableHLJS: true # to disable highlightjs
disableShare: false
disableHLJS: false
hideSummary: false
searchHidden: true
ShowReadingTime: false
ShowBreadCrumbs: true
ShowPostNavLinks: true
ShowWordCount: false
ShowRssButtonInSectionTermList: true
UseHugoToc: true
---
Больше спасибо, что посетили данную страницу! Обращаем ваше внимание, что материальная поддержка вовсе не обязательна и вы можете пользоваться всеми нашими ресурсами абсолютно бесплатно!
## Способы поддержки
### Единоразово
- Банковская карта:
```
номер карты
```
- Донат с сообщением: [Donationalerts](), [Boosty]()
- Криптовалюта:
- btc:
```
номер кошелька
```
### Подписка
Подписаться можно на [Boosty]()
## Зачем мне Вас поддерживать?

View File

@ -0,0 +1,52 @@
---
title: "Наши сервисы"
date: 2023-10-26T09:00:03+03:00
weight: 1
# aliases: ["/first"]
tags: ["first"]
# author: "nothing"
author: ["nothing", "sn4il"] # multiple authors
showToc: true
TocOpen: false
draft: false
hidemeta: false
comments: false
description: "Наши собственные сервисы."
disableHLJS: true # to disable highlightjs
disableShare: false
disableHLJS: false
hideSummary: false
searchHidden: true
ShowReadingTime: true
ShowBreadCrumbs: true
ShowPostNavLinks: true
ShowWordCount: true
ShowRssButtonInSectionTermList: true
UseHugoToc: true
---
Список сервисов, расположенных на серверах TheDroth. Все сервисы из данного списка "подчиняются" нашему [ToS]([https](https://git.thedroth.rocks/TheDroth/ToS/src/branch/main/README.md)), а потому настоятельно рекомендуем ознакомиться с ним перед началом взаимодействия с ресурсами.
## [Asocial](https://asocial.thedroth.rocks)
[![](../../images/lemmy.png)](https://asocial.thedroth.rocks/)
Lemmy - федеративный форум-аггрегатор ссылок в стиле Reddit
## [TheДротский поиск SearXNG](https://search.thedroth.rocks/)
[![](../../images/searx.png)](https://search.thedroth.rocks/)
Метапоисковый сервис (поиск через Google, Bing, DuckDuckGo...)
## [Gitea](https://git.thedroth.rocks)
[![](../../images/git.png)](https://git.thedroth.rocks/)
Хранилище исходных кодов
## [RSS Bridge](https://rss.thedroth.rocks/)
[![](../../images/rss.png)](https://rss.thedroth.rocks/)
Конвертация новостных лент в RSS

48
content/core/proxy.md Normal file
View File

@ -0,0 +1,48 @@
---
title: "Проксирующие сервисы"
date: 2023-10-26T09:00:03+03:00
weight: 2
# aliases: ["/first"]
#tags: ["first"]
#author: "nothing"
author: ["nothing", "sn4il"] # multiple authors
showToc: false
TocOpen: false
draft: false
hidemeta: false
comments: false
description: "Все сервисы, которые мы проксируем."
disableHLJS: true # to disable highlightjs
disableShare: false
disableHLJS: false
hideSummary: false
searchHidden: true
ShowReadingTime: false
ShowBreadCrumbs: true
ShowPostNavLinks: true
ShowWordCount: false
ShowRssButtonInSectionTermList: true
UseHugoToc: true
---
Список прокси — альтернативных фронтэндов для централизованных сервисов (Youtube, Wikipedia...), облегчающих взаимодействие с последними.
## [Piped](https://piped.thedroth.rocks/)
[![](../../images/piped.png)](https://piped.thedroth.rocks/)
Лёгкий приватный интерфейс для YouTube, умеюший автоматически проматывать рекламные вставки. Зачем кормить гугл, если можно не кормить...
## [WikiLess](https://wiki.thedroth.rocks/)
[![](../../images/wikiless.png)](https://wiki.thedroth.rocks)
Wikipedia без ненужных элементов и трекеров
## [Mozhi](https://tl.thedroth.rocks/)
[![](../../images/tl.png)
](https://tl.thedroth.rocks/)
Интерфейс для множества сервисов-переводчиков

26
content/example.md Normal file
View File

@ -0,0 +1,26 @@
---
title: "Наши сервисы" # Название материала
date: 2020-09-15T11:30:03+00:00 # Дата создания материала
weight: 1 # "Важность материала. Чем ниже 'важность' - тем выше в списке будет находится"
# aliases: ["/first"] #
tags: ["first"] # теги. Необходимо материалы помечать по тегам для того, чтобы проще было находить нужный матриеал
author: "nothing" # один автор материала
author: ["nothing", "sn4il"] # много авторов материала
showToc: true # оглавление загаловков в материале. True - показывать заголовки в материале
TocOpen: true # оглавление загаловков в материале. True - показывать заголовки в материале
draft: true # "черновик". True - материал виден публично и считается опубликованным. False - его не видно.
hidemeta: false #
comments: false # Комментарии
description: "Наши собственные сервисы. Заголовки - ссылки." # Небольшая аннотация под заголовком
disableHLJS: true # to disable highlightjs
disableShare: false # иконки "поделиться" внизу материала. True - иконок не будет.
disableHLJS: false #
hideSummary: true # Описание материала до входа на сам материал. True - скрыть описание, оставить только заголовок.
searchHidden: true #
ShowReadingTime: true # Приблизительное время на чтение. True - показывать.
ShowBreadCrumbs: true #
ShowPostNavLinks: true # Кнопки "другой материал" внизу материала. True - показывать кнопки.
ShowWordCount: true # Количество слов в материале. True - показывать кол-во слов.
ShowRssButtonInSectionTermList: true #
UseHugoToc: false #
---

1
css/picnic.min.css vendored

File diff suppressed because one or more lines are too long

186
dither.py
View File

@ -1,186 +0,0 @@
#!/usr/local/bin/python3.8
import hitherdither
import os
import argparse
import shutil
from PIL import Image
import logging
parser = argparse.ArgumentParser(
"""
This script recursively traverses folders and creates dithered versions of the images it finds.
These are stored in the same folder as the images in a folder called "dithers".
"""
)
parser.add_argument(
'-d', '--directory', help="Set the directory to traverse", default="."
)
parser.add_argument(
'-rm', '--remove', help="Removes all the folders with dithers and their contents", action="store_true"
)
parser.add_argument(
'-c', '--colorize', help="Colorizes the dithered images", action="store_true"
)
parser.add_argument(
'-v', '--verbose', help="Print out more detailed information about what this script is doing", action="store_true"
)
args = parser.parse_args()
image_ext = [".jpg", ".JPG", ".jpeg", ".png", ".gif", ".webp", ".tiff", ".bmp"]
content_dir = args.directory
if args.verbose:
logging.basicConfig(level=logging.DEBUG)
else:
logging.basicConfig(level=logging.INFO)
exclude_dirs = set(["dithers"])
logging.info("Dithering all images in {} and subfolders".format(content_dir))
logging.debug("excluding directories: {}".format("".join(exclude_dirs)))
def colorize(source_image, category):
"""
Picks a colored dithering palette based on the post category.
"""
colors = {
'low-tech': hitherdither.palette.Palette([(30,32,40), (11,21,71),(57,77,174),(158,168,218),(187,196,230),(243,244,250)]),
'obsolete': hitherdither.palette.Palette([(9,74,58), (58,136,118),(101,163,148),(144,189,179),(169,204,195),(242,247,246)]),
'high-tech': hitherdither.palette.Palette([(86,9,6), (197,49,45),(228,130,124),(233,155,151),(242,193,190),(252,241,240)]),
'grayscale': hitherdither.palette.Palette([(25,25,25), (75,75,75),(125,125,125),(175,175,175),(225,225,225),(250,250,250)])
}
if category:
for i in colors.keys():
if i in category.lower():
color = colors[i]
logging.info("Applying color palette '{}' for {}".format(i, category))
break
else:
logging.info("No category for {}, {}".format(source_image, category))
print("No category for {}, {}".format(source_image, category))
color = colors['grayscale']
else:
logging.info("No category for {}, {}".format(source_image, category))
print("No category for {}, {}".format(source_image, category))
color = colors['grayscale']
return color
def dither_image(source_image, output_image, category ='high-tech'):
#see hitherdither docs for different dithering algos and settings
# if args.colorize:
# palette = colorize(source_image, category)
# else:
# palette = hitherdither.palette.Palette([(25,25,25), (75,75,75),(125,125,125),(175,175,175),(225,225,225),(250,250,250)])
try:
img= Image.open(source_image).convert('RGB')
img.thumbnail((800,800), Image.LANCZOS)
#palette = palettes[category]
#palette = hitherdither.palette.Palette.create_by_median_cut(img)
palette = hitherdither.palette.Palette(
[0x080000, 0x201A0B, 0x432817, 0x492910,
0x234309, 0x5D4F1E, 0x9C6B20, 0xA9220F,
0x2B347C, 0x2B7409, 0xD0CA40, 0xE8A077,
0x6A94AB, 0xD5C4B3, 0xFCE76E, 0xFCFAE2]
)
threshold = [96, 96, 96]
img_dithered = hitherdither.ordered.bayer.bayer_dithering(img, palette, threshold, order=8)
#if args.colorize:
# img_dithered = colorize(img_dithered, category)
# logging.debug("Created {} in category {}".format(img_dithered, category))
img_dithered.save(output_image, optimize=True)
except Exception as e:
logging.debug(" failed to convert {}".format(source_image))
logging.debug(e)
def delete_dithers(content_dir):
logging.info("Deleting 'dither' folders in {} and below".format(content_dir))
for root, dirs, files in os.walk(content_dir, topdown=True):
if root.endswith('dithers'):
shutil.rmtree(root)
logging.info("Removed {}".format(root))
def parse_front_matter(md):
with open(md) as f:
contents = f.readlines()
cat = None
for l in contents:
if l.startswith("categories: "):
cat = l.split("categories: ")[1]
cat = cat.strip("[")
cat = cat.strip()
cat = cat.strip("]")
logging.debug("Categories: {} from {}".format(cat, l.strip()))
return cat
prev_root = None
if args.remove:
delete_dithers(
os.path.abspath(content_dir)
)
else:
for root, dirs, files in os.walk(os.path.abspath(content_dir), topdown=True):
logging.debug("Checking next folder {}".format(root))
dirs[:] = [d for d in dirs if d not in exclude_dirs]
category = None
if prev_root is None:
prev_root = root
if prev_root is not root:
if files:
if any(x.endswith(tuple(image_ext)) for x in files):
if not os.path.exists(os.path.join(root,'dithers')):
os.mkdir(os.path.join(root,'dithers'))
logging.info(" created in {}".format(root))
if args.colorize:
#iterate over md files to find one with a category
if not category:
for i in os.listdir(root):
if i.startswith('index'):
category2 = parse_front_matter(os.path.join(root,i))
break
for fname in files:
if fname.endswith(tuple(image_ext)):
file_, ext = os.path.splitext(fname)
source_image= os.path.join(root,fname)
output_image = os.path.join(os.path.join(root, 'dithers'), file_+'_dithered.png')
if not os.path.exists(output_image):
if not args.colorize:
category2 = "high-tech"
dither_image(source_image,output_image, category2)
logging.info(" converted {}".format(fname))
logging.debug(output_image)
else:
logging.debug("Dithered version of {} found, skipping".format(fname))
prev_root = root
logging.info("Done dithering")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
git.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

View File

@ -1,15 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import absolute_import
from . import data
from . import math
from . import ordered
from . import diffusion
from . import palette
from . import utils
from .__version__ import __version__, version

Binary file not shown.

View File

@ -1,17 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
__version__.py
-----------
:copyright: 2017-05-10 by hbldh <henrik.blidh@nedomkull.com>
"""
from __future__ import division
from __future__ import print_function
from __future__ import absolute_import
# Version information.
__version__ = "0.1.7"
version = __version__ # backwards compatibility name

View File

@ -1,89 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
try:
import pathlib2 as pathlib
except ImportError:
import pathlib
try:
from urllib import urlopen
except ImportError:
from urllib.request import urlopen
from PIL import Image
def scene():
"""Chrono Cross PNG image used in Yliluoma's web page.
:return: The PIL image of the Chrono Cross scene.
"""
image_path = pathlib.Path(__file__).resolve().parent.joinpath("scene.png")
image_url = "http://bisqwit.iki.fi/jutut/kuvat/ordered_dither/scene.png"
return _image(image_path, image_url)
def scene_undithered():
"""Chrono Cross PNG image rendered directly with specified palette.
:return: The PIL image of the undithered Chrono Cross scene.
"""
return _image(
pathlib.Path(__file__).resolve().parent.joinpath("scenenodither.png"),
"http://bisqwit.iki.fi/jutut/kuvat/ordered_dither/scenenodither.png",
)
def scene_bayer0():
"""Chrono Cross PNG image dithered using ordered Bayer matrix method.
:return: The PIL image of the ordered Bayer matrix dithered
Chrono Cross scene.
"""
return _image(
pathlib.Path(__file__).resolve().parent.joinpath("scenebayer0.png"),
"http://bisqwit.iki.fi/jutut/kuvat/ordered_dither/scenebayer0.png",
)
def _image(pth, url):
"""Load image specified in ``path``. If not present,
fetch it from ``url`` and store locally.
:param str or :class:`~pathlib.Path` pth:
:param str url: URL from where to fetch the image.
:return: The :class:`~PIL.Image` requested.
"""
if pth.exists():
return Image.open(str(pth))
else:
r = urlopen(url)
with open(str(pth), "wb") as f:
f.write(r.read())
return _image(pth, url)
def palette():
return [
0x080000,
0x201A0B,
0x432817,
0x492910,
0x234309,
0x5D4F1E,
0x9C6B20,
0xA9220F,
0x2B347C,
0x2B7409,
0xD0CA40,
0xE8A077,
0x6A94AB,
0xD5C4B3,
0xFCE76E,
0xFCFAE2,
]

Binary file not shown.

View File

@ -1,193 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
:mod:`diffusion`
=======================
.. moduleauthor:: hbldh <henrik.blidh@swedwise.com>
Created on 2016-09-12, 11:34
"""
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import absolute_import
import numpy as np
_DIFFUSION_MAPS = {
"floyd-steinberg": (
(1, 0, 7 / 16),
(-1, 1, 3 / 16),
(0, 1, 5 / 16),
(1, 1, 1 / 16),
),
"atkinson": (
(1, 0, 1 / 8),
(2, 0, 1 / 8),
(-1, 1, 1 / 8),
(0, 1, 1 / 8),
(1, 1, 1 / 8),
(0, 2, 1 / 8),
),
"jarvis-judice-ninke": (
(1, 0, 7 / 48),
(2, 0, 5 / 48),
(-2, 1, 3 / 48),
(-1, 1, 5 / 48),
(0, 1, 7 / 48),
(1, 1, 5 / 48),
(2, 1, 3 / 48),
(-2, 2, 1 / 48),
(-1, 2, 3 / 48),
(0, 2, 5 / 48),
(1, 2, 3 / 48),
(2, 2, 1 / 48),
),
"stucki": (
(1, 0, 8 / 42),
(2, 0, 4 / 42),
(-2, 1, 2 / 42),
(-1, 1, 4 / 42),
(0, 1, 8 / 42),
(1, 1, 4 / 42),
(2, 1, 2 / 42),
(-2, 2, 1 / 42),
(-1, 2, 2 / 42),
(0, 2, 4 / 42),
(1, 2, 2 / 42),
(2, 2, 1 / 42),
),
"burkes": (
(1, 0, 8 / 32),
(2, 0, 4 / 32),
(-2, 1, 2 / 32),
(-1, 1, 4 / 32),
(0, 1, 8 / 32),
(1, 1, 4 / 32),
(2, 1, 2 / 32),
),
"sierra3": (
(1, 0, 5 / 32),
(2, 0, 3 / 32),
(-2, 1, 2 / 32),
(-1, 1, 4 / 32),
(0, 1, 5 / 32),
(1, 1, 4 / 32),
(2, 1, 2 / 32),
(-1, 2, 2 / 32),
(0, 2, 3 / 32),
(1, 2, 2 / 32),
),
"sierra2": (
(1, 0, 4 / 16),
(2, 0, 3 / 16),
(-2, 1, 1 / 16),
(-1, 1, 2 / 16),
(0, 1, 3 / 16),
(1, 1, 2 / 16),
(2, 1, 1 / 16),
),
"sierra-2-4a": (
(1, 0, 2 / 4),
(-1, 1, 1 / 4),
(0, 1, 1 / 4),
),
}
def error_diffusion_dithering(image, palette, method="floyd-steinberg", order=2):
"""Perform image dithering by error diffusion method.
.. note:: Error diffusion is totally unoptimized and therefore very slow.
It is included more as a reference implementation than as a useful
method.
Reference:
http://bisqwit.iki.fi/jutut/kuvat/ordered_dither/error_diffusion.txt
Quantization error of *current* pixel is added to the pixels
on the right and below according to the formulas below.
This works nicely for most static pictures, but causes
an avalanche of jittering artifacts if used in animation.
Floyd-Steinberg:
* 7
3 5 1 / 16
Jarvis-Judice-Ninke:
* 7 5
3 5 7 5 3
1 3 5 3 1 / 48
Stucki:
* 8 4
2 4 8 4 2
1 2 4 2 1 / 42
Burkes:
* 8 4
2 4 8 4 2 / 32
Sierra3:
* 5 3
2 4 5 4 2
2 3 2 / 32
Sierra2:
* 4 3
1 2 3 2 1 / 16
Sierra-2-4A:
* 2
1 1 / 4
Stevenson-Arce:
* . 32
12 . 26 . 30 . 16
. 12 . 26 . 12 .
5 . 12 . 12 . 5 / 200
Atkinson:
* 1 1 / 8
1 1 1
1
:param :class:`PIL.Image` image: The image to apply error
diffusion dithering to.
:param :class:`~hitherdither.colour.Palette` palette: The palette to use.
:param str method: The error diffusion map to use.
:param int order: Metric parameter ``ord`` to send to
:method:`numpy.linalg.norm`.
:return: The error diffusion dithered PIL image of type
"P" using the input palette.
"""
ni = np.array(image, "float")
diff_map = _DIFFUSION_MAPS.get(method.lower())
for y in range(ni.shape[0]):
for x in range(ni.shape[1]):
old_pixel = ni[y, x]
old_pixel[old_pixel < 0.0] = 0.0
old_pixel[old_pixel > 255.0] = 255.0
new_pixel = palette.pixel_closest_colour(old_pixel, order)
quantization_error = old_pixel - new_pixel
ni[y, x] = new_pixel
for dx, dy, diffusion_coefficient in diff_map:
xn, yn = x + dx, y + dy
if (0 <= xn < ni.shape[1]) and (0 <= yn < ni.shape[0]):
ni[yn, xn] += quantization_error * diffusion_coefficient
return palette.create_PIL_png_from_rgb_array(np.array(ni, "uint8"))

View File

@ -1,21 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
exceptions
-----------
:copyright: 2017-05-10 by hbldh <henrik.blidh@nedomkull.com>
"""
from __future__ import division
from __future__ import print_function
from __future__ import absolute_import
class HitherDitherError(Exception):
pass
class PaletteCouldNotBeCreatedError(Exception):
pass

View File

@ -1,3 +0,0 @@
from . import bayer
from . import yliluoma
from . import cluster

View File

@ -1,88 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
bayer_dithering
-----------
:copyright: 2016-09-09 by hbldh <henrik.blidh@nedomkull.com>
"""
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import absolute_import
import numpy as np
def B(n, transposed=False):
"""Get the Bayer matrix with side of length ``n``.
Will only work if ``n`` is a power of 2.
Reference: http://caca.zoy.org/study/part2.html
:param int n: Power of 2 side length of matrix.
:return: The Bayer matrix.
"""
return (1 + I(n, transposed)) / (1 + (n * n))
def I(n, transposed=False):
"""Get the index matrix with side of length ``n``.
Will only work if ``n`` is a power of 2.
Reference: http://caca.zoy.org/study/part2.html
:param int n: Power of 2 side length of matrix.
:param bool transposed:
:return: The index matrix.
"""
if n == 2:
if transposed:
return np.array([[0, 3], [2, 1]], "int")
else:
return np.array([[0, 2], [3, 1]], "int")
else:
smaller_I = I(n >> 1, transposed)
if transposed:
return np.bmat(
[
[4 * smaller_I, 4 * smaller_I + 3],
[4 * smaller_I + 2, 4 * smaller_I + 1],
]
)
else:
return np.bmat(
[
[4 * smaller_I, 4 * smaller_I + 2],
[4 * smaller_I + 3, 4 * smaller_I + 1],
]
)
def bayer_dithering(image, palette, thresholds, order=8):
"""Render the image using the ordered Bayer matrix dithering pattern.
:param :class:`PIL.Image` image: The image to apply
Bayer ordered dithering to.
:param :class:`~hitherdither.colour.Palette` palette: The palette to use.
:param thresholds: Thresholds to apply dithering at.
:param int order: The size of the Bayer matrix.
:return: The Bayer matrix dithered PIL image of type "P"
using the input palette.
"""
bayer_matrix = B(order)
ni = np.array(image, "uint8")
thresholds = np.array(thresholds, "uint8")
xx, yy = np.meshgrid(range(ni.shape[1]), range(ni.shape[0]))
xx %= order
yy %= order
factor_threshold_matrix = np.expand_dims(bayer_matrix[yy, xx], axis=2) * thresholds
new_image = ni + factor_threshold_matrix
return palette.create_PIL_png_from_rgb_array(new_image)

View File

@ -1,67 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
bayer_dithering
-----------
:copyright: 2016-09-09 by hbldh <henrik.blidh@nedomkull.com>
"""
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import absolute_import
import numpy as np
_CLUSTER_DOT_MATRICES = {
4: np.array([[12, 5, 6, 13], [4, 0, 1, 7], [11, 3, 2, 8], [15, 10, 9, 14]], "float")
/ 16.0,
8: np.array(
[
[24, 10, 12, 26, 35, 47, 49, 37],
[8, 0, 2, 14, 45, 59, 61, 51],
[22, 6, 4, 16, 43, 57, 63, 53],
[30, 20, 18, 28, 33, 41, 55, 39],
[34, 46, 48, 36, 25, 11, 13, 27],
[44, 57, 60, 50, 9, 1, 3, 15],
[42, 56, 62, 52, 23, 7, 5, 17],
[32, 40, 54, 38, 31, 21, 19, 29],
],
"float",
)
/ 64.0,
(5, 3): np.array([[9, 3, 0, 6, 12], [10, 4, 1, 7, 13], [11, 5, 2, 8, 14]], "float")
/ 15.0,
}
def cluster_dot_dithering(image, palette, thresholds, order=4):
"""Render the image using the ordered Bayer matrix dithering pattern.
Reference: http://caca.zoy.org/study/part2.html
:param :class:`PIL.Image` image: The image to apply the
ordered dithering to.
:param :class:`~hitherdither.colour.Palette` palette: The palette to use.
:param thresholds: Thresholds to apply dithering at.
:param int order: The size of the Bayer matrix.
:return: The Bayer matrix dithered PIL image of type "P"
using the input palette.
"""
cluster_dot_matrix = _CLUSTER_DOT_MATRICES.get(order)
if cluster_dot_matrix is None:
raise NotImplementedError("Only order 4 and 8 is implemented as of yet.")
ni = np.array(image, "uint8")
thresholds = np.array(thresholds, "uint8")
xx, yy = np.meshgrid(range(ni.shape[1]), range(ni.shape[0]))
xx %= order
yy %= order
factor_threshold_matrix = (
np.expand_dims(cluster_dot_matrix[yy, xx], axis=2) * thresholds
)
new_image = ni + factor_threshold_matrix
return palette.create_PIL_png_from_rgb_array(new_image)

View File

@ -1 +0,0 @@
from ._algorithm_one import yliluomas_1_ordered_dithering

View File

@ -1,180 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
algorithm_one
-----------
:copyright: 2016-09-12 by hbldh <henrik.blidh@nedomkull.com>
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import numpy as np
from ._utils import color_compare, CCIR_LUMINOSITY
from ..bayer import I
def _get_mixing_plan_matrix(palette, order=8):
mixing_matrix = []
colours = {}
colour_component_distances = []
nn = order * order
for i in range(len(palette)):
for j in range(i, len(palette)):
for ratio in range(0, nn):
if i == j and ratio != 0:
break
# Determine the two component colors.
c_mix = _colour_combine(palette, i, j, ratio / nn)
hex_colour = palette.rgb2hex(*c_mix.tolist())
colours[hex_colour] = (i, j, ratio / nn)
mixing_matrix.append(c_mix)
c1 = np.array(palette[i], "int")
c2 = np.array(palette[j], "int")
cmpval = (
color_compare(c1, c2)
* 0.1
* (np.abs((ratio / float(nn)) - 0.5) + 0.5)
)
colour_component_distances.append(cmpval)
mixing_matrix = np.array(mixing_matrix)
colour_component_distances = np.array(colour_component_distances)
for c in mixing_matrix:
assert palette.rgb2hex(*c.tolist()) in colours
return mixing_matrix, colours, colour_component_distances
def _colour_combine(palette, i, j, ratio):
c1, c2 = np.array(palette[i], "int"), np.array(palette[j], "int")
return np.array(c1 + ratio * (c2 - c1), "uint8")
def _improved_mixing_error_fcn(
colour, mixing_matrix, colour_component_distances, luma_mat=None
):
"""Compares two colours using the Psychovisual model.
The simplest way to adjust the psychovisual model is to
add some code that considers the difference between the
two pixel values that are being mixed in the dithering
process, and penalizes combinations that differ too much.
Wikipedia has an entire article about the topic of comparing
two color values. Most of the improved color comparison
functions are based on the CIE colorspace, but simple
improvements can be done in the RGB space too. Such a simple
improvement is shown below. We might call this RGBL, for
luminance-weighted RGB.
:param :class:`numpy.ndarray` colour: The colour to estimate error to.
:param :class:`numpy.ndarray` mixing_matrix: The rgb
values of mixed colours.
:param :class:`numpy.ndarray` colour_component_distances: The colour
distance of the mixed colours.
:return: :class:`numpy.ndarray`
"""
colour = np.array(colour, "int")
if luma_mat is None:
luma_mat = mixing_matrix.dot(CCIR_LUMINOSITY / 1000.0 / 255.0)
luma_colour = colour.dot(CCIR_LUMINOSITY) / (255.0 * 1000.0)
luma_diff_squared = (luma_mat - luma_colour) ** 2
diff_colour_squared = ((colour - mixing_matrix) / 255.0) ** 2
cmpvals = diff_colour_squared.dot(CCIR_LUMINOSITY) / 1000.0
cmpvals *= 0.75
cmpvals += luma_diff_squared
cmpvals += colour_component_distances
return cmpvals
def yliluomas_1_ordered_dithering(image, palette, order=8):
"""A dithering method that weighs in color combinations of palette.
N.B. tri-tone dithering is not implemented.
:param :class:`PIL.Image` image: The image to apply
Bayer ordered dithering to.
:param :class:`~hitherdither.colour.Palette` palette: The palette to use.
:param int order: The Bayer matrix size to use.
:return: The dithered PIL image of type "P" using the input palette.
"""
bayer_matrix = I(order, transposed=True) / 64.0
ni = np.array(image, "uint8")
xx, yy = np.meshgrid(range(ni.shape[1]), range(ni.shape[0]))
factor_matrix = bayer_matrix[yy % order, xx % order]
# Prepare all precalculated mixed colours and their respective
mixing_matrix, colour_map, colour_component_distances = _get_mixing_plan_matrix(
palette
)
mixing_matrix = np.array(mixing_matrix, "int")
luma_mat = mixing_matrix.dot(CCIR_LUMINOSITY / 1000.0 / 255.0)
color_matrix = np.zeros(ni.shape[:2], dtype="uint8")
for x, y in zip(np.nditer(xx), np.nditer(yy)):
min_index = np.argmin(
_improved_mixing_error_fcn(
ni[y, x, :], mixing_matrix, colour_component_distances, luma_mat
)
)
closest_mix_colour = mixing_matrix[min_index, :].tolist()
closest_mix_hexcolour = palette.rgb2hex(*closest_mix_colour)
plan = colour_map.get(closest_mix_hexcolour)
color_matrix[y, x] = plan[1] if (factor_matrix[y, x] < plan[-1]) else plan[0]
return palette.create_PIL_png_from_closest_colour(color_matrix)
def _evaluate_mixing_error(
desired_colour,
mixed_colour,
component_colour_1,
component_colour_2,
ratio,
component_colour_compare_value=None,
):
"""Compare colours and weigh in component difference.
double EvaluateMixingError(int r,int g,int b,
int r0,int g0,int b0,
int r1,int g1,int b1,
int r2,int g2,int b2,
double ratio)
{
return ColorCompare(r,g,b, r0,g0,b0)
+ ColorCompare(r1,g1,b1, r2,g2,b2) * 0.1
* (fabs(ratio-0.5)+0.5);
}
:param desired_colour:
:param mixed_colour:
:param component_colour_1:
:param component_colour_2:
:param ratio:
:param component_colour_compare_value:
:return:
"""
if component_colour_compare_value is None:
return color_compare(desired_colour, mixed_colour) + (
color_compare(component_colour_1, component_colour_2)
* 0.1
* (np.abs(ratio - 0.5) + 0.5)
)
else:
return (
color_compare(desired_colour, mixed_colour) + component_colour_compare_value
)

View File

@ -1,42 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
_utils
-----------
:copyright: 2016-09-23 by hbldh <henrik.blidh@nedomkull.com>
"""
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import absolute_import
import numpy as np
# CCIR 601 luminosity
CCIR_LUMINOSITY = np.array([299.0, 587.0, 114.0])
def color_compare(c1, c2):
"""Compare the difference of two RGB values, weigh by CCIR 601 luminosity
double ColorCompare(int r1,int g1,int b1, int r2,int g2,int b2)
{
double luma1 = (r1*299 + g1*587 + b1*114) / (255.0*1000);
double luma2 = (r2*299 + g2*587 + b2*114) / (255.0*1000);
double lumadiff = luma1-luma2;
double diffR = (r1-r2)/255.0, diffG = (g1-g2)/255.0, diffB = (b1-b2)/255.0;
return (diffR*diffR*0.299 + diffG*diffG*0.587 + diffB*diffB*0.114)*0.75
+ lumadiff*lumadiff;
}
:return: float
"""
luma_diff = c1.dot(CCIR_LUMINOSITY) / (255.0 * 1000.0) - c2.dot(CCIR_LUMINOSITY) / (
255.0 * 1000.0
)
diff_col = (c1 - c2) / 255.0
return ((diff_col ** 2).dot(CCIR_LUMINOSITY / 1000.0) * 0.75) + (luma_diff ** 2)

View File

@ -1,246 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
palette
-----------
:copyright: 2016-09-09 by hbldh <henrik.blidh@nedomkull.com>
"""
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import absolute_import
import numpy as np
from PIL import Image
from PIL.ImagePalette import ImagePalette
from hitherdither.exceptions import PaletteCouldNotBeCreatedError
try:
string_type = basestring
except NameError:
string_type = str
def hex2rgb(h):
if isinstance(h, string_type):
return hex2rgb(int(h[1:] if h.startswith("#") else h, 16))
return (h >> 16) & 0xFF, (h >> 8) & 0xFF, h & 0xFF
def rgb2hex(r, g, b):
return (r << 16) + (g << 8) + b
def _get_all_present_colours(im):
"""Returns a dict of RGB colours present.
N.B. Do not use this except for testing purposes.
Reference: http://stackoverflow.com/a/4643911
:param im: The image to get number of colours in.
:type im: :class:`~PIL.Image.Image`
:return: A dict of contained RGB colours as keys.
:rtype: dict
"""
from collections import defaultdict
by_color = defaultdict(int)
for pixel in im.getdata():
by_color[pixel] += 1
return by_color
class Palette(object):
"""The :mod:`~hitherdither` implementation of a colour palette.
Can be instantiated in from colour specifications in the following forms:
- ``uint8`` numpy array of size ``[N x 3]``
- ``uint8`` numpy array of size ``[3N]``
- :class:`~PIL.ImagePalette.ImagePalette`
- :class:`~PIL.Image.Image`
- list of hex values
- list of RGB tuples
"""
def __init__(self, data):
if isinstance(data, np.ndarray):
if data.ndim == 1:
self.colours = data.reshape((3, len(data) // 3))
else:
self.colours = data
self.hex = [rgb2hex(*colour) for colour in data]
elif isinstance(data, ImagePalette):
_tmp = np.frombuffer(data.palette, "uint8")
self.colours = _tmp.reshape((3, len(_tmp) // 3))
self.hex = [rgb2hex(*colour) for colour in data]
elif isinstance(data, Image.Image):
if data.palette is None:
raise PaletteCouldNotBeCreatedError(
"Image of mode {0} has no PIL palette. "
"Make sure it is of mode P.".format(data.mode)
)
_colours = data.getcolors()
_n_colours = len(_colours)
_tmp = np.array(data.getpalette())[: 3 * _n_colours]
self.colours = _tmp.reshape((3, len(_tmp) // 3)).T
self.hex = [rgb2hex(*colour) for colour in self]
elif isinstance(data, (list, tuple)):
if isinstance(data[0], string_type):
# Assume hex strings
self.hex = data
self.colours = np.array([hex2rgb(c) for c in data])
elif isinstance(data[0], int):
# Assume hex values
self.hex = data # TODO: Convert to hex string.
self.colours = np.array([hex2rgb(c) for c in data])
else:
# Assume RGB tuples
self.colours = np.array(data)
self.hex = [rgb2hex(*colour) for colour in data]
def __iter__(self):
for colour in self.colours:
yield colour
def __len__(self):
return self.colours.shape[0]
def __getitem__(self, item):
if isinstance(item, int):
return self.colours[item, :]
else:
raise IndexError("Can only reference colours by integer values.")
def render(self, colours):
return np.array(np.take(self.colours, colours, axis=0), "uint8")
def image_distance(self, image, order=2):
ni = np.array(image, "float")
distances = np.zeros((ni.shape[0], ni.shape[1], len(self)), "float")
for i, colour in enumerate(self):
distances[:, :, i] = np.linalg.norm(ni - colour, ord=order, axis=2)
return distances
def image_closest_colour(self, image, order=2):
return np.argmin(self.image_distance(image, order=order), axis=2)
def pixel_distance(self, pixel, order=2):
return np.array([np.linalg.norm(pixel - colour, ord=order) for colour in self])
def pixel_closest_colour(self, pixel, order=2):
return self.colours[
np.argmin(self.pixel_distance(pixel, order=order)), :
].copy()
@classmethod
def create_by_kmeans(cls, image):
raise NotImplementedError()
@classmethod
def create_by_median_cut(cls, image, n=16, dim=None):
img = np.array(image)
# Create pixel buckets to simplify sorting and splitting.
if img.ndim == 3:
pixels = img.reshape((img.shape[0] * img.shape[1], img.shape[2]))
elif img.ndim == 2:
pixels = img.reshape((img.shape[0] * img.shape[1], 1))
def median_cut(p, dim=None):
"""Median cut method.
Reference:
https://en.wikipedia.org/wiki/Median_cut
:param p: The pixel array to split in two.
:return: Two numpy arrays, split by median cut method.
"""
if dim is not None:
sort_dim = dim
else:
mins = p.min(axis=0)
maxs = p.max(axis=0)
sort_dim = np.argmax(maxs - mins)
argument = np.argsort(p[:, sort_dim])
p = p[argument, :]
m = np.median(p[:, sort_dim])
split_mask = p[:, sort_dim] >= m
return [p[~split_mask, :].copy(), p[split_mask, :].copy()]
# Do actual splitting loop.
bins = [
pixels,
]
while len(bins) < n:
new_bins = []
for bin in bins:
new_bins += median_cut(bin, dim)
bins = new_bins
# Average over pixels in each bin to create
colours = np.array(
[np.array(bin.mean(axis=0).round(), "uint8") for bin in bins], "uint8"
)
return cls(colours)
def create_PIL_png_from_closest_colour(self, cc):
"""Create a ``P`` PIL image with this palette.
Avoids the PIL dithering in favour of our own.
Reference: http://stackoverflow.com/a/29438149
:param :class:`numpy.ndarray` cc: A ``[M x N]`` array with integer
values representing palette colour indices to build image from.
:return: A :class:`PIL.Image.Image` image of mode ``P``.
"""
pa_image = Image.new("P", cc.shape[::-1])
pa_image.putpalette(self.colours.flatten().tolist())
im = Image.fromarray(np.array(cc, "uint8")).im.convert("P", 0, pa_image.im)
try:
# Pillow >= 4
return pa_image._new(im)
except AttributeError:
# Pillow < 4
return pa_image._makeself(im)
def create_PIL_png_from_rgb_array(self, img_array):
"""Create a ``P`` PIL image from a RGB image with this palette.
Avoids the PIL dithering in favour of our own.
Reference: http://stackoverflow.com/a/29438149
:param :class:`numpy.ndarray` img_array: A ``[M x N x 3]`` uint8
array representing RGB colours.
:return: A :class:`PIL.Image.Image` image of mode ``P`` with colours
available in this palette.
"""
cc = self.image_closest_colour(img_array, order=2)
pa_image = Image.new("P", cc.shape[::-1])
pa_image.putpalette(self.colours.flatten().tolist())
im = Image.fromarray(np.array(cc, "uint8")).im.convert("P", 0, pa_image.im)
try:
# Pillow >= 4
return pa_image._new(im)
except AttributeError:
# Pillow < 4
return pa_image._makeself(im)
@staticmethod
def hex2rgb(x):
return hex2rgb(x)
@staticmethod
def rgb2hex(r, g, b):
return rgb2hex(r, g, b)

View File

@ -1,27 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
:mod:`utils`
=======================
.. moduleauthor:: hbldh <henrik.blidh@swedwise.com>
Created on 2016-09-12, 09:50
"""
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import absolute_import
import numpy as np
from PIL import Image
def np2pil(img):
return Image.fromarray(np.array(img, "uint8"))
def pil2np(img):
return np.array(img, "uint8")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 551 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 749 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 570 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 400 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

View File

@ -1,196 +0,0 @@
<!DOCTYPE HTML>
<html>
<head profile="https://thedroth.rocks">
<link rel="icon"
type="image/png"
href="favicon.png" />
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>TheDroth Rocks! </title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/picnic.min.css">
<style>
aside a.top {
font-size: 0;
position: fixed;
bottom: 0;
font-weight: bold;
width: 180px;
padding: .6em 0;
margin-bottom: 0;
border-radius: .3em .3em 0 0;
transition: all .3s ease;
}
aside a.top.visible {
font-size: 1em;
}
aside .links a.button {
text-align: left;
}
@media all and (max-width: 1000px) {
aside a.pseudo.top {
background: rgba(255, 255, 255, .8);
width: 100%;
left: 0;
text-align: center;
z-index: 100;
}
}
.documentation article > h2 {
margin: -2em 0 .6em;
padding: 3em 0 0;
line-height: 1;
}
.documentation article > h3 {
margin-bottom: .6em;
}
.documentation aside h2 {
margin-top: 0;
padding: 1.25em 0;
line-height: 1;
}
.documentation aside a.pseudo {
color: #0074D9;
margin: 0;
}
.documentation > section {
background: #fff;
text-align: left;
width: 90%;
max-width: 960px;
margin: 0 auto;
padding: 80px 0 0;
}
.documentation article > h1 {
margin: 0;
padding: 0.6em 0;
font-size: 2em;
line-height: 1.5;
}
.documentation aside a.button {
display: block;
}
.documentation pre[class*="language-"] {
margin-top: 10px;
margin-bottom: 40px;
}
.documentation .index pre {
margin: 0;
font-size: .9em;
}
</style>
</head>
<body>
<nav class="fedi">
<!-- <font size="1.5em"> -->
<a href="https://thedroth.rocks" class="brand">
<img class="logo" src="dithers/thedroth_logo.png" />
</a>
<!-- responsive-->
<input id="bmenub" type="checkbox" class="show">
<label for="bmenub" class="burger pseudo button">меню</label>
<div class="menu">
<a href="index.html#proxy" class="pseudo button">Проксирующие сервисы</a>
<a href="index.html#selfhosted" class="pseudo button">Собственные сервисы</a>
<a href="index.html#blog" class="pseudo button">TheДротский бложик</a>
</div>
<!-- </font> -->
</nav>
<main id="home" class="documentation">
<section class="flex">
<article class="card four-fifth-1000">
<header>TheDrothские сервисы</header>
<section class="flex">
<article class="card">
<center>
<header id="proxy">Проксирующие</header>
<div class="flex">
<h4>Piped</h4>
<p>Лёгкий приватный интерфейс для YouTube, умеюший автоматически проматывать рекламные вставки. Зачем кормить гугл, если можно не кормить...</p>
<a href="https://piped.thedroth.rocks"><img src="dithers/piped.png" width="60%"></a>
</div>
<hr>
<div class="flex">
<h4>Teddit</h4>
<p>Быстрый и лёгкий фронтэнд для Reddit</p>
<a href="https://teddit.thedroth.rocks"><img src="dithers/teddit.png" width="60%"></a>
</div>
<!-- <hr>
<div class="flex">
<h4>Nitter</h4>
<p>Интерфейс для Twitter, избавленный от всего лишнего</p>
<a href="https://nitter.thedroth.rocks"><img src="dithers/nitter.png" width="60%"></a>
</div>
-->
<hr>
<div class="flex">
<h4>Rural Dictionary</h4>
<p>Фронтэнд для Urban Dictionary. Знакомься с современным фольклором и сленгом без корпоративной слежки!</p>
<a href="https://rd.thedroth.rocks"><img src="dithers/rd.png" width="60%"></a>
</div>
<hr>
<div class="flex">
<h4>WikiLess</h4>
<p>Wikipedia без ненужных элементов и трекеров</p>
<a href="https://wiki.thedroth.rocks"><img src="dithers/wikiless.png" width="60%"></a>
</div>
</center>
</article>
</section>
<section class="flex">
<article class="card">
<center>
<header id="selfhosted">Собственные</header>
<div class="flex">
<h4>Git</h4>
<p>Хранилище исходных кодов</p>
<a href="https://git.thedroth.rocks"><img src="dithers/git.png" width="60%"></a>
</div>
<hr>
<div class="flex">
<h4>TheДротский Фонк</h4>
<p>FunkWhale — хостинг музыки и подкастов</p>
<a href="https://fonk.thedroth.rocks"><img src="dithers/fonk.png" width="60%"></a>
</div>
<hr>
<div class="flex">
<h4>RSS Bridge</h4>
<p>Конвертация новостных лент в RSS</p>
<a href="https://rss.thedroth.rocks"><img src="dithers/rss.png" width="60%"></a>
</div>
</center>
</article>
</section>
</article>
<article class="card four-fifth-1000">
<section class="flex">
<article class="card">
<div class="flex" id="blog"> <center>
<span>
<iframe style="border:none;" width="90%" height="700px" seamless src="https://blog.thedroth.rocks"></iframe> </span>
<span>
</center>
</div>
</article>
</section>
</article>
</section>
</main>
<section>
<hr>
<a href="https://gitflic.ru/project/the_sn4il/thedroth-rocks">Исходный код сайта</a>
</section>
</body>
</html>

4
js/jquery.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,8 +0,0 @@
function dropme() {
var x = document.getElementById("rtopnav");
if (x.className === "topnav") {
x.className += " responsive";
} else {
x.className = "topnav";
}
}

View File

@ -1,36 +0,0 @@
function openModal() {
document.getElementById("myModal").style.display = "block";
}
function closeModal() {
document.getElementById("myModal").style.display = "none";
}
var slideIndex = 1;
showSlides(slideIndex);
function plusSlides(n) {
showSlides(slideIndex += n);
}
function currentSlide(n) {
showSlides(slideIndex = n);
}
function showSlides(n) {
var i;
var slides = document.getElementsByClassName("mySlides");
var dots = document.getElementsByClassName("demo");
var captionText = document.getElementById("caption");
if (n > slides.length) {slideIndex = 1}
if (n < 1) {slideIndex = slides.length}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[slideIndex-1].style.display = "block";
dots[slideIndex-1].className += " active";
captionText.innerHTML = dots[slideIndex-1].alt;
}

BIN
piped.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

4
public/404.html Normal file
View File

@ -0,0 +1,4 @@
<!doctype html><html lang=en dir=auto><head><meta charset=utf-8><meta http-equiv=x-ua-compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name=robots content="index, follow"><title>404 Page not found | TheDrothRocks!</title><meta name=keywords content><meta name=description content="ExampleSite description"><meta name=author content="Me"><link rel=canonical href=https://thedroth.rocks/404.html><meta name=google-site-verification content="XYZabc"><meta name=yandex-verification content="XYZabc"><meta name=msvalidate.01 content="XYZabc"><link crossorigin=anonymous href=/assets/css/stylesheet.5cfc680b1eeaeef9efbced92d46c2a9e876b72ee14fba85846afc4cff9e6e6f8.css integrity="sha256-XPxoCx7q7vnvvO2S1Gwqnodrcu4U+6hYRq/Ez/nm5vg=" rel="preload stylesheet" as=style><link rel=icon href=https://thedroth.rocks/images/favicon.png><link rel=icon type=image/png sizes=16x16 href=https://thedroth.rocks/images/favicon.png><link rel=icon type=image/png sizes=32x32 href=https://thedroth.rocks/images/favicon.png><link rel=apple-touch-icon href=https://thedroth.rocks/%3Clink%20/%20abs%20url%3E><link rel=mask-icon href=https://thedroth.rocks/%3Clink%20/%20abs%20url%3E><meta name=theme-color content="#2e2e33"><meta name=msapplication-TileColor content="#2e2e33"><noscript><style>#theme-toggle,.top-link{display:none}</style><style>@media(prefers-color-scheme:dark){:root{--theme:rgb(29, 30, 32);--entry:rgb(46, 46, 51);--primary:rgb(218, 218, 219);--secondary:rgb(155, 156, 157);--tertiary:rgb(65, 66, 68);--content:rgb(196, 196, 197);--hljs-bg:rgb(46, 46, 51);--code-bg:rgb(55, 56, 62);--border:rgb(51, 51, 51)}.list{background:var(--theme)}.list:not(.dark)::-webkit-scrollbar-track{background:0 0}.list:not(.dark)::-webkit-scrollbar-thumb{border-color:var(--theme)}}</style></noscript><meta property="og:title" content="404 Page not found"><meta property="og:description" content="ExampleSite description"><meta property="og:type" content="website"><meta property="og:url" content="https://thedroth.rocks/404.html"><meta property="og:image" content="https://thedroth.rocks/%3Clink%20or%20path%20of%20image%20for%20opengraph,%20twitter-cards%3E"><meta property="og:site_name" content="ExampleSite"><meta name=twitter:card content="summary_large_image"><meta name=twitter:image content="https://thedroth.rocks/%3Clink%20or%20path%20of%20image%20for%20opengraph,%20twitter-cards%3E"><meta name=twitter:title content="404 Page not found"><meta name=twitter:description content="ExampleSite description"></head><body class=list id=top><script>localStorage.getItem("pref-theme")==="dark"?document.body.classList.add("dark"):localStorage.getItem("pref-theme")==="light"?document.body.classList.remove("dark"):window.matchMedia("(prefers-color-scheme: dark)").matches&&document.body.classList.add("dark")</script><header class=header><nav class=nav><div class=logo><a href=https://thedroth.rocks/ accesskey=h title="TheDroth.Rocks (Alt + H)"><img src=https://thedroth.rocks/images/thedroth_logo.png alt aria-label=logo height=35>TheDroth.Rocks</a><div class=logo-switches><button id=theme-toggle accesskey=t title="(Alt + T)"><svg id="moon" xmlns="http://www.w3.org/2000/svg" width="24" height="18" viewBox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg><svg id="sun" xmlns="http://www.w3.org/2000/svg" width="24" height="18" viewBox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg></button></div></div><ul id=menu><li><a href=https://thedroth.rocks/our-services/ title="Наши сервисы"><span>Наши сервисы</span></a></li><li><a href=https://thedroth.rocks/proxy/ title="Проксирующие сервисы"><span>Проксирующие сервисы</span></a></li><li><a href=https://git.thedroth.rocks/TheDroth/ToS/src/branch/main/README.md title=ToS><span>ToS</span>&nbsp;<svg fill="none" shape-rendering="geometricPrecision" stroke="currentcolor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" viewBox="0 0 24 24" height="12" width="12"><path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6"/><path d="M15 3h6v6"/><path d="M10 14 21 3"/></svg></a></li><li><a href=https://thedroth.rocks/blog/ title=Блог><span>Блог</span></a></li></ul></nav></header><main class=main><div class=not-found>404</div></main><footer class=footer><span>&copy; 2023 <a href=https://thedroth.rocks/>TheDrothRocks!</a></span>
<span>Powered by
<a href=https://gohugo.io/ rel="noopener noreferrer" target=_blank>Hugo</a> &
<a href=https://github.com/adityatelange/hugo-PaperMod/ rel=noopener target=_blank>PaperMod</a></span></footer><a href=#top aria-label="go to top" title="Go to Top (Alt + G)" class=top-link id=top-link accesskey=g><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 6" fill="currentcolor"><path d="M12 6H0l6-6z"/></svg></a><script>let menu=document.getElementById("menu");menu&&(menu.scrollLeft=localStorage.getItem("menu-scroll-position"),menu.onscroll=function(){localStorage.setItem("menu-scroll-position",menu.scrollLeft)}),document.querySelectorAll('a[href^="#"]').forEach(e=>{e.addEventListener("click",function(e){e.preventDefault();var t=this.getAttribute("href").substr(1);window.matchMedia("(prefers-reduced-motion: reduce)").matches?document.querySelector(`[id='${decodeURIComponent(t)}']`).scrollIntoView():document.querySelector(`[id='${decodeURIComponent(t)}']`).scrollIntoView({behavior:"smooth"}),t==="top"?history.replaceState(null,null," "):history.pushState(null,null,`#${t}`)})})</script><script>var mybutton=document.getElementById("top-link");window.onscroll=function(){document.body.scrollTop>800||document.documentElement.scrollTop>800?(mybutton.style.visibility="visible",mybutton.style.opacity="1"):(mybutton.style.visibility="hidden",mybutton.style.opacity="0")}</script><script>document.getElementById("theme-toggle").addEventListener("click",()=>{document.body.className.includes("dark")?(document.body.classList.remove("dark"),localStorage.setItem("pref-theme","light")):(document.body.classList.add("dark"),localStorage.setItem("pref-theme","dark"))})</script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>Categories on TheDrothRocks!</title>
<link>https://thedroth.rocks/categories/</link>
<description>Recent content in Categories on TheDrothRocks!</description>
<image>
<title>TheDrothRocks!</title>
<url>https://thedroth.rocks/%3Clink%20or%20path%20of%20image%20for%20opengraph,%20twitter-cards%3E</url>
<link>https://thedroth.rocks/%3Clink%20or%20path%20of%20image%20for%20opengraph,%20twitter-cards%3E</link>
</image>
<generator>Hugo -- gohugo.io</generator><atom:link href="https://thedroth.rocks/categories/index.xml" rel="self" type="application/rss+xml" />
</channel>
</rss>

46
public/core/index.xml Normal file
View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Cores on TheDrothRocks!</title>
<link>https://thedroth.rocks/core/</link>
<description>Recent content in Cores on TheDrothRocks!</description>
<generator>Hugo -- gohugo.io</generator>
<lastBuildDate>Tue, 15 Sep 2020 11:30:03 +0000</lastBuildDate><atom:link href="https://thedroth.rocks/core/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Наши сервисы</title>
<link>https://thedroth.rocks/core/our-services/</link>
<pubDate>Tue, 15 Sep 2020 11:30:03 +0000</pubDate>
<guid>https://thedroth.rocks/core/our-services/</guid>
<description>Данная страница - сборник ссылок на сервисы, которые хранятся на наших серверах. Все сервисы из данного списка &amp;ldquo;подчинаяются&amp;rdquo; нашему ToS, а потому настоятельно рекомендуем ознакомиться с ним перед началом взаимодействия с ресурсами.
Asocial Lemmy - федеративный форум-аггрегатор ссылок в стиле Reddit
TheДротский поиск SearXNG Метапоисковый сервис (поиск через Google, Bing, DuckDuckGo&amp;hellip;)
Gitea Хранилище исходных кодов
RSS Bridge Конвертация новостных лент в RSS</description>
</item>
<item>
<title>Проксирующие сервисы</title>
<link>https://thedroth.rocks/core/proxy/</link>
<pubDate>Tue, 15 Sep 2020 11:30:03 +0000</pubDate>
<guid>https://thedroth.rocks/core/proxy/</guid>
<description>Piped Лёгкий приватный интерфейс для YouTube, умеюший автоматически проматывать рекламные вставки. Зачем кормить гугл, если можно не кормить&amp;hellip;
WikiLess Wikipedia без ненужных элементов и трекеров</description>
</item>
<item>
<title>Donate!</title>
<link>https://thedroth.rocks/core/donate/</link>
<pubDate>Tue, 15 Sep 2020 11:30:03 +0000</pubDate>
<guid>https://thedroth.rocks/core/donate/</guid>
<description>Больше спасибо, что посетили данную страницу! Обращаем ваше внимание, что материальная поддержка вовсе не обязательно и вы можете пользоваться всеми нашими ресурсами абсолютно бесплатно!
Способы поддержки Единоразово Банковская карта: номер карты Донат с сообщением: Donationalerts, Boosty
Криптовалюта:
btc: номер кошелька Подписка Подписаться можно на Boosty
Зачем мне Вас поддерживать? </description>
</item>
</channel>
</rss>

BIN
public/images/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
public/images/lemmy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
public/images/searx.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

4
public/index.html Normal file

File diff suppressed because one or more lines are too long

33
public/index.xml Normal file
View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>TheDrothRocks!</title>
<link>https://thedroth.rocks/</link>
<description>Recent content on TheDrothRocks!</description>
<image>
<title>TheDrothRocks!</title>
<url>https://thedroth.rocks/%3Clink%20or%20path%20of%20image%20for%20opengraph,%20twitter-cards%3E</url>
<link>https://thedroth.rocks/%3Clink%20or%20path%20of%20image%20for%20opengraph,%20twitter-cards%3E</link>
</image>
<generator>Hugo -- gohugo.io</generator>
<lastBuildDate>Tue, 15 Sep 2020 11:30:03 +0000</lastBuildDate><atom:link href="https://thedroth.rocks/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Наши сервисы</title>
<link>https://thedroth.rocks/our-services/</link>
<pubDate>Tue, 15 Sep 2020 11:30:03 +0000</pubDate>
<guid>https://thedroth.rocks/our-services/</guid>
<description>Наши собственные сервисы. Заголовки - ссылки.</description>
</item>
<item>
<title>Проксирующие сервисы</title>
<link>https://thedroth.rocks/proxy/</link>
<pubDate>Tue, 15 Sep 2020 11:30:03 +0000</pubDate>
<guid>https://thedroth.rocks/proxy/</guid>
<description>Все сервисы, которые мы проксируем. Заголовки - ссылки.</description>
</item>
</channel>
</rss>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Tags on My New Hugo Site</title>
<link>http://example.org/tags/</link>
<description>Recent content in Tags on My New Hugo Site</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language><atom:link href="http://example.org/tags/index.xml" rel="self" type="application/rss+xml" />
</channel>
</rss>

1
public/page/1/index.html Normal file
View File

@ -0,0 +1 @@
<!doctype html><html lang=en><head><title>https://thedroth.rocks/</title><link rel=canonical href=https://thedroth.rocks/><meta name=robots content="noindex"><meta charset=utf-8><meta http-equiv=refresh content="0; url=https://thedroth.rocks/"></head></html>

5
public/proxy/index.html Normal file

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More