Migrate to markdown, add rss feed

pull/16/head v0.3.0
Ivan Reshetnikov 2023-11-12 13:51:31 +05:00
parent a4e952773b
commit 83a4c483c7
No known key found for this signature in database
GPG Key ID: 56C7BAAE859B302C
18 changed files with 416 additions and 589 deletions

View File

@ -1,4 +1,6 @@
import { defineConfig } from 'astro/config'
// https://astro.build/config
export default defineConfig({})
export default defineConfig({
site: 'https://comfycamp.space'
})

36
package-lock.json generated
View File

@ -9,6 +9,7 @@
"version": "0.0.1",
"dependencies": {
"@astrojs/check": "^0.3.0",
"@astrojs/rss": "^3.0.0",
"astro": "^3.5.2",
"typescript": "^5.2.2"
}
@ -128,6 +129,15 @@
"node": ">=18.14.1"
}
},
"node_modules/@astrojs/rss": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@astrojs/rss/-/rss-3.0.0.tgz",
"integrity": "sha512-PMX8iqByk9gtOrusikten/oF5uHjOCZigL6RuXFBUu+xtdKQxXzfIohJ99V2haA4FJjVDyibDTGzXR81POBMxQ==",
"dependencies": {
"fast-xml-parser": "^4.2.7",
"kleur": "^4.1.5"
}
},
"node_modules/@astrojs/telemetry": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.0.4.tgz",
@ -2118,6 +2128,27 @@
"node": ">=8.6.0"
}
},
"node_modules/fast-xml-parser": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.2.tgz",
"integrity": "sha512-rmrXUXwbJedoXkStenj1kkljNF7ugn5ZjR9FJcwmCfcCbtOMDghPajbc+Tck6vE6F5XsDmx+Pr2le9fw8+pXBg==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
},
{
"type": "paypal",
"url": "https://paypal.me/naturalintelligence"
}
],
"dependencies": {
"strnum": "^1.0.5"
},
"bin": {
"fxparser": "src/cli/cli.js"
}
},
"node_modules/fastq": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
@ -5603,6 +5634,11 @@
"node": ">=0.10.0"
}
},
"node_modules/strnum": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz",
"integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA=="
},
"node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",

View File

@ -12,6 +12,7 @@
},
"dependencies": {
"@astrojs/check": "^0.3.0",
"@astrojs/rss": "^3.0.0",
"astro": "^3.5.2",
"typescript": "^5.2.2"
}

1
public/icons/rss.svg Normal file
View File

@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>RSS</title><path fill="white" d="M19.199 24C19.199 13.467 10.533 4.8 0 4.8V0c13.165 0 24 10.835 24 24h-4.801zM3.291 17.415c1.814 0 3.293 1.479 3.293 3.295 0 1.813-1.485 3.29-3.301 3.29C1.47 24 0 22.526 0 20.71s1.475-3.294 3.291-3.295zM15.909 24h-4.665c0-6.169-5.075-11.245-11.244-11.245V8.09c8.727 0 15.909 7.184 15.909 15.91z"/></svg>

After

Width:  |  Height:  |  Size: 414 B

View File

@ -1,40 +1,56 @@
<footer>
<a href="https://m.comfycamp.space/@lumin" rel="me" target="_blank">
<img
src="/icons/mastodon.svg"
width="18px"
height="18px"
alt="Mastodon logo"
/>
Mastodon
</a>
<a href="https://matrix.to/#/@lumin:matrix.comfycamp.space" target="_blank">
<img
src="/icons/matrix.svg"
width="18px"
height="18px"
alt="Matrix logo"
/>
Matrix
</a>
<a href="mailto:admin@comfycamp.space" target="_blank">
<img
src="/icons/envelope-solid.svg"
width="18px"
height="18px"
alt="Email icon"
/>
admin@comfycamp.space
</a>
<a href="https://github.com/ordinary-dev/comfycamp/issues/new" target="_blank">
<img
src="/icons/github.svg"
width="18px"
height="18px"
alt="Github logo"
/>
Обратная связь
</a>
<h2>Сайт</h2>
<div class="list">
<a href="/rss.xml">
<img
src="/icons/rss.svg"
width="18px"
height="18px"
alt="RSS logo"
/>
RSS
</a>
<a href="https://github.com/ordinary-dev/comfycamp/issues/new" target="_blank">
<img
src="/icons/github.svg"
width="18px"
height="18px"
alt="Github logo"
/>
Обратная связь
</a>
</div>
<h2>Автор</h2>
<div class="list">
<a href="https://m.comfycamp.space/@lumin" rel="me" target="_blank">
<img
src="/icons/mastodon.svg"
width="18px"
height="18px"
alt="Mastodon logo"
/>
Mastodon
</a>
<a href="https://matrix.to/#/@lumin:matrix.comfycamp.space" target="_blank">
<img
src="/icons/matrix.svg"
width="18px"
height="18px"
alt="Matrix logo"
/>
Matrix
</a>
<a href="mailto:admin@comfycamp.space" target="_blank">
<img
src="/icons/envelope-solid.svg"
width="18px"
height="18px"
alt="Email icon"
/>
admin@comfycamp.space
</a>
</div>
</footer>
<style>
@ -46,14 +62,15 @@
padding-bottom: 40px;
}
footer > a {
.list {
display: flex;
gap: 16px;
flex-wrap: wrap;
}
footer div > a {
display: flex;
gap: 8px;
align-items: center;
margin-top: 16px;
}
footer svg {
color: white;
}
</style>

View File

@ -1,35 +0,0 @@
---
interface Props {
date: string
title: string
href: string
}
const { date, title, href } = Astro.props
---
<div class="note">
<div class="date">{ date }</div>
<div class="dash">—</div>
<a href={href}>{ title }</a>
</div>
<style>
.note {
margin-bottom: 15px;
}
.dash {
display: none;
}
@media screen and (min-width: 600px) {
.note {
display: flex;
gap: 6px;
margin-bottom: 5px;
}
.dash {
display: block;
}
}
</style>

View File

@ -1,25 +0,0 @@
---
interface Props {
createdAt: string
updatedAt: string
}
const { createdAt, updatedAt } = Astro.props
---
<div class="metadata">
<p>Дата создания: { createdAt }</p>
{ updatedAt !== createdAt && <p>Последнее обновление: { updatedAt }</p> }
</div>
<style>
.metadata {
color: #aaa;
margin-top: 16px;
margin-bottom: 32px;
}
.metadata p {
margin-top: 6px;
margin-bottom: 6px;
}
</style>

15
src/content/config.ts Normal file
View File

@ -0,0 +1,15 @@
import { z, defineCollection } from 'astro:content'
const notesCollection = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.date(),
updatedAt: z.date().optional(),
}),
})
export const collections = {
'notes': notesCollection,
}

View File

@ -0,0 +1,34 @@
---
title: "Беспечная Гляденовская гора"
description: "Путешествие до Гляденовской горы."
pubDate: 2023-10-16
---
Гляденовская гора - это красивый лес в Перми, за которым прячется деревянная часовня.
Здесь не будет рассказов про историю горы, ведь я не являюсь ни историком, ни археологом,
оставлю это занятие более компетентным людям.
Я всего лишь хочу показать вам это место от лица обывателя,
и, может быть, это сподвигнет вас отправиться когда-нибудь в небольшое путешествие.
![Фотография поля с видом на пермский аэропорт](/carefree-mountain/1.webp)
Гляденовская гора находится недалеко от пермского аэропорта.
Если до него самого добраться не составит большого труда, то дальше придётся идти вдоль дороги, хоть и совсем недолго.
Вскоре вы зайдете в лес, тогда идти станет проще и интереснее.
Теперь, когда мы наконец-то в лесу, где нет проезжающих мимо машин, можно расслабиться.
Дальнейший путь представляет из себя череду деревянных ступенек.
Спускаться по ним довольно легко, но ещё проще подскользнуться.
![Деревянные ступеньки в лесу](/carefree-mountain/2.webp)
![Белочка](/carefree-mountain/3.webp)
![Деревянные ступеньки в лесу](/carefree-mountain/4.webp)
В конце пути нас ожидает деревянная церковь.
Теперь можно неспеша осмотреться вокруг.
В таких местах почти ничего не просиходит, внешнего мира как будто не существует.
Он остался там, за горой, здесь же царит тишина и спокойствие.
![Деревянная церковь в лесу](/carefree-mountain/5.webp)
*Удивительное рядом.*

View File

@ -0,0 +1,119 @@
---
title: "Свободные альтернативы популярным сервисам"
description: "Список самых популярных независимых альтернатив коммерческим социальным сетям и сервисам."
pubDate: 2023-08-27
updatedAt: 2023-10-01
---
Это статья для тех, кто никогда не слышал про альтернативы современным социальным сетям и сервисам.
Мы стали слишком сильно полагаться на централизованные сервисы, такие как vk, youtube, telegram или twitter.
Если у вас начали появляться претензии, будь то цензура, отсутствие нужных функций или
пренебрежительное отношение к личным данным, я предлагаю вам обратить внимание на альтернативы,
которые вы можете запустить на своем сервере.
Хотя, строго говоря, иметь свой сервер вовсе не обязательно,
но в таком случае вы должны доверять владельцу сервера, ведь именно он будет хранить ваши данные.
Это не особо касается социальных сетей без личных сообщений, там всё и так публично.
Мессенджеры, поддерживающие шифрование, защищают вас от лишних глаз, можете без опасений выбирать публичный сервер.
А вот хранить файлы у незнакомцев я бы не стал.
## Социальные сети - Fediverse
![Скриншот fediverse.party](/selfhosted/fediverse-party.webp)
Fediverse - это группа из нескольких социальных сетей, представляющие аналоги популярным сервисам.
| Оригинальный сервис | Альтернативы |
| --- | --- |
| Twitter | [Mastodon](https://joinmastodon.org/), [Misskey](https://misskey-hub.net/en/) и [Pleroma](https://pleroma.social/) |
| Vk, Facebook | [Friendica](https://friendi.ca/) |
| Instagram | [Pixelfed](https://pixelfed.org/) |
| Reddit | [Lemmy](https://join-lemmy.org/) |
| YouTube | [Peertube](https://joinpeertube.org/) |
| Soundcloud | [Funkwhale](https://funkwhale.audio/) |
Создать свой сервер может любой желающий, и его пользователи смогут общаться с пользователями на других серверах.
Зачастую можно общаться даже с пользователями других платформ.
Если вы ищете простое место для старта, рекомендую обратить внимание на mastodon.
Выберите сервер, на котором вы хотите зарегистрироваться,
в этом вам может помочь [каталог русскоязычных серверов](https://ru.index.community/communities).
Вот парочка советов:
* Ознакомтесь с правилами сервера. На разных серверах модераторы могут запрещать разные вещи.
* Не регистрируйтесь на больших серверах. Вы не получите от этого особых плюсов, а лишь усилите централизацию.
У меня есть свой [сервер mastodon](https://m.comfycamp.space), жду вас в гости!
## Мессенджеры - Matrix, XMPP
![Скриншот matirx.org](/selfhosted/matrix.webp)
В мире децентрализованного общения сейчас популярны 2 протокола: xmpp (ранее jabber) и matrix.
Идея такая же, как и в случае с fediverse: любой желающий может поднять свой сервер, а пользователи разных серверов могут общаться между собой.
По сравнению с другими платформами, например telegram или whatsapp,
вы получаете end-to-end шифрование на всех устройствах и множество клиентов с открытым исходным кодом,
а для регистрации не нужно указывать номер телефона.
Какой из них вам понравится больше - сказать тяжело. Попробуйте оба.
## Облако - Nextcloud
![Скриншот менеджера файлов в nextcloud](/selfhosted/nextcloud.webp)
[Nextcloud](https://nextcloud.com/) - это больше, чем просто облако.
Это и хранилище файлов, и календарь, и задачи, и контакты, и ещё много всего.
Своим функционалом nextcloud способен заменить целые экосистемы.
При желании к nextcloud можно подключить офисный редакторор, например onlyoffice, тогда nextcloud превращается ещё и в альтернативу Google Docs.
Это может быть очень кстати для разных компаний.
Список контактов, календари и задачи можно синхронизировать между своими устройствами.
Для этого используются обычные протоколы сaldav и carddav.
## Стриминг - Jellyfin
![Скриншот jellyfin с открытой страницей фильма](/selfhosted/jellyfin.webp)
[Jellyin](https://jellyfin.org/) - это ваш личный стриминговый сервис.
Вы просто указываете путь до вашей медиатеки и получаете возможность смотреть и слушать её онлайн.
Jellyfin поддерживает фильмы, сериалы, музыку, аудиокниги и комиксы.
Jellyfin может перекодировать файлы на лету, если посчитает, что ваше устройство не поддерживает исходный формат.
Это зачастую необходимо для браузеров, так как они могут воспроизодить только самые простые форматы.
Если вы хотите снизить нагрузку на сервер, можно найти клиенты, позволяющие транслировать видео напрямую в ваш плеер
(см. [jellyfin-mpv-shim](https://github.com/jellyfin/jellyfin-mpv-shim).
Jellyfin поддерживает DLNA, а это значит, что в пару кликов можно включить любой фильм на телевизоре, который находится в той же сети, что и сервер.
А ещё можно организовывать комнаты для просмотра и синхронизировать воспроизведение на нескольких устройствах, если вы хотите посмотреть
что-нибудь в компании.
Jellyfin - это не обязательно синоним пиратства.
Вы можете стримить легально приобретенный контент, если у вас есть такое желание.
## Фото и видео - Photoprism
![Скриншот photoprism, на котором видно несколько фотографий](/selfhosted/photoprism.webp)
Многие пользуются сервисами от Apple или Google, чтобы хранить личные фотографии и видео.
Если вам становится некомфортно от мысли, что компании, владеющие рекламными сетями,
имеют доступ к вашим фотографиям, можно обратиться к [Photoprism](https://www.photoprism.app/).
Photoprism позволяет легко просматривать фото в браузере, редактировать метатеги,
и даже умеет распознавать объекты на фото (хотя, честно говоря, эта функция работает не идеально).
Вы можете создавать альбомы и делиться ими с другими людьми.
Загружать фото можно через веб-интерфейс, импортировать с директории на вашем сервере или же
загружать их по протоколу webdav с того же nextcloud.
Photoprism умеет конвертировать фотографии формата raw, чтобы их можно было открыть в браузере.
Также вы без проблем можете загрузить свои видео, они при необходимости будут сконвертированы.
## Вместо заключения - Awesome Selfhosted
Один из самых популярных репозиториев на Github: [Awesome Selfhosted](https://github.com/awesome-selfhosted/awesome-selfhosted).
Это большой список всевозможных сервисов, которые вы можете запустить на своем сервере.
В этой статье я не покрыл и 10% доступных вариантов. Однако, надеюсь, что я смог хотя бы приоткрыть дверь в эту кроличью нору.

View File

@ -0,0 +1,38 @@
---
title: "Мыс Стрелка"
description: "Фотографии с путешествия на мыс Стрелка."
pubDate: 2023-11-11
---
*Некоторые вещи стоят того, чтобы встать в 6 утра в воскресенье.*
## Куда мы едем?
Мыс Стрелка - это скала, у которой соединяются 2 реки: Кама и Чусовая.
Находится она недалеко от города, добраться до ближайших деревень можно на электричке,
а дальше нужно пару километров пройти пешком.
Точную дорогу мы заранее не посмотрели и пришли не на скалу, а к её основанию.
Подняться, как оказалось, можно и у самой скалы, в самом тяжёлом месте есть верёвка.
![Вершина скалы](/strelka/1.jpg)
![Вид с мыса Стрелка](/strelka/2.jpg)
![Вид с мыса Стрелка](/strelka/3.jpg)
На вершине скалы довольно ветрено, но красиво.
Совсем рядом находятся макушки деревьев, а дальше только вода.
Спустившись буквально на пару шагов можно укрыться от ветра и отдохнуть.
Если вы оказались здесь осенью, то чай будет очень кстати.
![Пьем чай на скале](/strelka/4.jpg)
## Путь обратно
У нас оставалось несколько часов до электрички, поэтому мы отправились изучать ближайшие деревни.
Вроде бы мы находились совсем недалеко от города, но атмосфера уже другая.
![Железная дорога в деревне](/strelka/5.jpg)
Наши похождения закончились довольно быстро, но на станции можно спокойно дождаться электрички.
В итоге получилось короткое, но запоминающееся путешествие.

1
src/env.d.ts vendored
View File

@ -1 +1,2 @@
/// <reference path="../.astro/types.d.ts" />
/// <reference types="astro/client" />

View File

@ -1,6 +1,13 @@
---
import Layout from '../layouts/Layout.astro'
import Note from '../components/Note.astro'
import { getCollection } from 'astro:content'
const notes = await getCollection('notes')
notes.sort((a, b) => {
if (a.data.pubDate < b.data.pubDate) return 1
if (a.data.pubDate > b.data.pubDate) return -1
return 0
})
---
<Layout title="Уютный домик">
@ -14,22 +21,31 @@ import Note from '../components/Note.astro'
</p>
<h2>Заметки</h2>
<Note
date="11 ноября 2023"
title="Мыс Стрелка"
href="/notes/strelka/"
/>
<Note
date="16 октября 2023"
title="Беспечная Гляденовская гора"
href="/notes/carefree-mountain/"
/>
<Note
date="27 августа 2023"
title="Свободные альтернативы популярным сервисам"
href="/notes/self-hosting/"
/>
{notes.map(note => (
<div class="note">
<div class="date">{note.data.pubDate.toLocaleDateString("ru", {year: "numeric", month: "long", day: "numeric"})}</div>
<div class="dash">—</div>
<a href={`/notes/${note.slug}/`}>{ note.data.title }</a>
</div>
))}
</Layout>
<style>
.note {
margin-bottom: 15px;
}
.dash {
display: none;
}
@media screen and (min-width: 600px) {
.note {
display: flex;
gap: 6px;
margin-bottom: 5px;
}
.dash {
display: block;
}
}
</style>

View File

@ -0,0 +1,54 @@
---
import { getCollection } from 'astro:content'
import Layout from '../../layouts/Layout.astro'
export async function getStaticPaths() {
const blogEntries = await getCollection('notes')
return blogEntries.map(entry => ({
params: { slug: entry.slug },
props: { entry },
}))
}
const { entry } = Astro.props
const { Content } = await entry.render()
const formatDate = (date: Date) => {
return date.toLocaleDateString("ru", {year: "numeric", month: "long", day: "numeric"})
}
---
<Layout title={entry.data.title} description={entry.data.description}>
<h1>{entry.data.title}</h1>
<div class="metadata">
<p>Дата создания: { formatDate(entry.data.pubDate) }</p>
{ entry.data.updatedAt !== undefined && entry.data.updatedAt !== entry.data.pubDate && (
<p>Последнее обновление: { formatDate(entry.data.updatedAt) }</p>
)}
</div>
<div class="content">
<Content />
</div>
</Layout>
<style>
.metadata {
color: #aaa;
margin-top: 16px;
margin-bottom: 32px;
}
.metadata p {
margin-top: 6px;
margin-bottom: 6px;
}
.content {
img {
width: 100%;
}
th, td {
border: 1px solid #eee;
padding: 6px 10px;
}
table {
border-collapse: collapse;
}
}
</style>

View File

@ -1,123 +0,0 @@
---
import Layout from '../../layouts/Layout.astro'
import NoteMetadata from '../../components/NoteMetadata.astro'
---
<Layout title="Беспечная Гляденовская гора">
<h1>Беспечная Гляденовская гора</h1>
<NoteMetadata createdAt="16 октября 2023" updatedAt="16 октября 2023" />
<p>
Гляденовская гора - это красивый лес в Перми, за которым прячется деревянная часовня.
Здесь не будет рассказов про историю горы, ведь я не являюсь ни историком, ни археологом,
оставлю это занятие более компетентным людям.
Я всего лишь хочу показать вам это место от лица обывателя,
и, может быть, это сподвигнет вас отправиться когда-нибудь в небольшое путешествие.
</p>
<img
src="/carefree-mountain/1.webp"
alt="Фотография поля с видом на пермский аэропорт"
class="wideImg"
loading="lazy"
/>
<p>
Гляденовская гора находится недалеко от пермского аэропорта.
Если до него самого добраться не составит большого труда, то дальше придётся идти вдоль дороги, хоть и совсем недолго.
Вскоре вы зайдете в лес, тогда идти станет проще и интереснее.
</p>
<p>
Теперь, когда мы наконец-то в лесу, где нет проезжающих мимо машин, можно расслабиться.
Дальнейший путь представляет из себя череду деревянных ступенек.
Спускаться по ним довольно легко, но ещё проще подскользнуться.
<p>
<div class="firstPhotoGroup">
<div>
<img
src="/carefree-mountain/2.webp"
alt="Деревянные ступеньки в лесу"
loading="lazy"
/>
</div>
<div>
<img
src="/carefree-mountain/3.webp"
alt="Белочка"
loading="lazy"
/>
</div>
<div>
<img
src="/carefree-mountain/4.webp"
alt="Деревянные ступеньки в лесу"
loading="lazy"
/>
</div>
</div>
<p>
В конце пути нас ожидает деревянная церковь.
Теперь можно неспеша осмотреться вокруг.
В таких местах почти ничего не просиходит, внешнего мира как будто не существует.
Он остался там, за горой, здесь же царит тишина и спокойствие.
</p>
<img
src="/carefree-mountain/5.webp"
alt="Деревянная церковь в лесу"
class="wideImg"
loading="lazy"
/>
<p><i>Удивительное рядом.</i></p>
</Layout>
<style>
.wideImg {
width: 100%;
}
.firstPhotoGroup {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 450px 310px;
grid-template-areas:
"first first"
"second third";
gap: 10px;
}
@media screen and (max-width: 800px) {
.firstPhotoGroup {
grid-template-rows: 450px 450px 450px;
grid-template-columns: 1fr;
grid-template-areas:
"first"
"second"
"third";
}
}
.firstPhotoGroup > div {
position: relative;
}
.firstPhotoGroup > div > img {
object-fit: cover;
width: 100%;
height: 100%;
}
.firstPhotoGroup > div:nth-child(1) {
grid-area: first;
}
.firstPhotoGroup > div:nth-child(2) {
grid-area: second;
}
.firstPhotoGroup > div:nth-child(3) {
grid-area: third;
}
</style>

View File

@ -1,258 +0,0 @@
---
import Layout from '../../layouts/Layout.astro'
import NoteMetadata from '../../components/NoteMetadata.astro'
---
<Layout title="Свободные альтернативы популярным сервисам">
<h1>Свободные альтернативы популярным сервисам</h1>
<NoteMetadata createdAt="27 августа 2023" updatedAt="1 октября 2023" />
<p>
Это статья для тех, кто никогда не слышал про альтернативы современным социальным сетям и сервисам.
</p>
<p>
Мы стали слишком сильно полагаться на централизованные сервисы, такие как vk, youtube, telegram или twitter.
Если у вас начали появляться претензии, будь то цензура, отсутствие нужных функций или
пренебрежительное отношение к личным данным, я предлагаю вам обратить внимание на альтернативы,
которые вы можете запустить на своем сервере.
</p>
<p>
Хотя, строго говоря, иметь свой сервер вовсе не обязательно,
но в таком случае вы должны доверять владельцу сервера, ведь именно он будет хранить ваши данные.
Это не особо касается социальных сетей без личных сообщений, там всё и так публично.
Мессенджеры, поддерживающие шифрование, защищают вас от лишних глаз, можете без опасений выбирать публичный сервер.
А вот хранить файлы у незнакомцев я бы не стал.
</p>
<h2>Социальные сети - Fediverse</h2>
<img
src="/selfhosted/fediverse-party.webp"
alt="Скриншот fediverse.party"
loading="lazy"
/>
<p class="attribution">Скриншот <a href="https://fediverse.party" target="_blank">fediverse.party</a>.</p>
<p>
Fediverse - это группа из нескольких социальных сетей, представляющие аналоги популярным сервисам.
</p>
<table>
<tr>
<th>Оригинальный сервис</th>
<th>Альтернативы</th>
</tr>
<tr>
<td>Twitter</td>
<td>
<a href="https://joinmastodon.org/" target="_blank">Mastodon</a>,
<a href="https://misskey-hub.net/en/" target="_blank">misskey</a> и
<a href="https://pleroma.social/" target="_blank">pleroma</a>
</td>
</tr>
<tr>
<td>Vk, facebook</td>
<td>
<a href="https://friendi.ca/" target="_blank">Friendica</a>
</td>
</tr>
<tr>
<td>Instagram</td>
<td>
<a href="https://pixelfed.org/" target="_blank">Pixelfed</a>
</td>
</tr>
<tr>
<td>Reddit</td>
<td>
<a href="https://join-lemmy.org/" target="_blank">Lemmy</a>
</td>
</tr>
<tr>
<td>YouTube</td>
<td>
<a href="https://joinpeertube.org/" target="_blank">Peertube</a>
</td>
</tr>
<tr>
<td>Soundcloud</td>
<td>
<a href="https://funkwhale.audio/" target="_blank">Funkwhale</a>
</td>
</tr>
</table>
<p>
Создать свой сервер может любой желающий, и его пользователи смогут общаться с пользователями на других серверах.
Зачастую можно общаться даже с пользователями других платформ.
</p>
<p>
Если вы ищете простое место для старта, рекомендую обратить внимание на mastodon.
Выберите сервер, на котором вы хотите зарегистрироваться,
в этом вам может помочь <a href="https://ru.index.community/communities" target="_blank">каталог русскоязычных серверов</a>.
</p>
<p>
Вот парочка советов:
<ul>
<li>Ознакомтесь с правилами сервера. На разных серверах модераторы могут запрещать разные вещи.</li>
<li>Не регистрируйтесь на больших серверах. Вы не получите от этого особых плюсов, а лишь усилите централизацию.</li>
</ul>
</p>
<p>
У меня есть <a href="https://m.comfycamp.space" target="_blank">свой сервер mastodon</a>, жду вас в гости!
</p>
<h2>Мессенджеры - Matrix, XMPP</h2>
<img
src="/selfhosted/matrix.webp"
alt="Скриншот matirx.org"
loading="lazy"
/>
<p class="attribution">Скриншот <a href="https://matrix.org/" target="_blank">matrix.org</a>.</p>
<p>
В мире децентрализованного общения сейчас популярны 2 протокола: xmpp (ранее jabber) и matrix.
Идея такая же, как и в случае с fediverse: любой желающий может поднять свой сервер, а пользователи разных серверов могут общаться между собой.
</p>
<p>
По сравнению с другими платформами, например telegram или whatsapp,
вы получаете end-to-end шифрование на всех устройствах и множество клиентов с открытым исходным кодом,
а для регистрации не нужно указывать номер телефона.
</p>
<p>
Какой из них вам понравится больше - сказать тяжело. Попробуйте оба.
</p>
<h2>Облако - Nextcloud</h2>
<img
src="/selfhosted/nextcloud.webp"
alt="Скриншот менеджера файлов в nextcloud"
loading="lazy"
/>
<p>
<a href="https://nextcloud.com/" target="_blank">Nextcloud</a> - это больше, чем просто облако.
Это и хранилище файлов, и календарь, и задачи, и контакты, и ещё много всего.
Своим функционалом nextcloud способен заменить целые экосистемы.
</p>
<p>
При желании к nextcloud можно подключить офисный редакторор, например onlyoffice, тогда nextcloud превращается ещё и в альтернативу Google Docs.
Это может быть очень кстати для разных компаний.
</p>
<p>
Список контактов, календари и задачи можно синхронизировать между своими устройствами.
Для этого используются обычные протоколы сaldav и carddav.
</p>
<h2>Стриминг - Jellyfin</h2>
<img
src="/selfhosted/jellyfin.webp"
alt="Скриншот jellyfin с открытой страницей фильма Taxi Driver"
loading="lazy"
/>
<p>
<a href="https://jellyfin.org/" target="_blank">Jellyfin</a> - это ваш личный стриминговый сервис.
</p>
<p>
Вы просто указываете путь до вашей медиатеки и получаете возможность смотреть и слушать её онлайн.
Jellyfin поддерживает фильмы, сериалы, музыку, аудиокниги и комиксы.
</p>
<p>
Jellyfin может перекодировать файлы на лету, если посчитает, что ваше устройство не поддерживает исходный формат.
Это зачастую необходимо для браузеров, так как они могут воспроизодить только самые простые форматы.
Если вы хотите снизить нагрузку на сервер, можно найти клиенты, позволяющие транслировать видео напрямую в ваш плеер
(см. <a href="https://github.com/jellyfin/jellyfin-mpv-shim" target="_blank">jellyfin-mpv-shim</a>).
</p>
<p>
Jellyfin поддерживает DLNA, а это значит, что в пару кликов можно включить любой фильм на телевизоре, который находится в той же сети, что и сервер.
А ещё можно организовывать комнаты для просмотра и синхронизировать воспроизведение на нескольких устройствах, если вы хотите посмотреть
что-нибудь в компании.
</p>
<p>
Jellyfin - это не обязательно синоним пиратства.
Вы можете стримить легально приобретенный контент, если у вас есть такое желание.
</p>
<h2>Фото и видео - Photoprism</h2>
<img
src="/selfhosted/photoprism.webp"
alt="Скриншот photoprism, на котором видно несколько фотографий"
loading="lazy"
/>
<p>
Многие пользуются сервисами от Apple или Google, чтобы хранить личные фотографии и видео.
Если вам становится некомфортно от мысли, что компании, владеющие рекламными сетями,
имеют доступ к вашим фотографиям, можно обратиться к <a href="https://www.photoprism.app/" target="_blank">Photoprism</a>.
</p>
<p>
Photoprism позволяет легко просматривать фото в браузере, редактировать метатеги,
и даже умеет распознавать объекты на фото (хотя, честно говоря, эта функция работает не идеально).
Вы можете создавать альбомы и делиться ими с другими людьми.
</p>
<p>
Загружать фото можно через веб-интерфейс, импортировать с директории на вашем сервере или же
загружать их по протоколу webdav с того же nextcloud.
</p>
<p>
Photoprism умеет конвертировать фотографии формата raw, чтобы их можно было открыть в браузере.
Также вы без проблем можете загрузить свои видео, они при необходимости будут сконвертированы.
</p>
<h2>Вместо заключения - Awesome Selfhosted</h2>
<p>
Один из самых популярных репозиториев на Github: <a href="https://github.com/awesome-selfhosted/awesome-selfhosted" target="_blank">Awesome Selfhosted</a>.
Это большой список всевозможных сервисов, которые вы можете запустить на своем сервере.
В этой статье я не покрыл и 10% доступных вариантов. Однако, надеюсь, что я смог хотя бы приоткрыть дверь в эту кроличью нору.
</Layout>
<style>
img {
width: 100%;
}
.attribution {
margin-top: 10px;
margin-bottom: 20px;
font-style: italic;
text-align: right;
}
table {
margin-bottom: 20px;
border-collapse: collapse;
}
table, td, th {
border: 1px solid #676767;
}
td, th {
padding: 6px 8px;
text-align: left;
}
</style>

View File

@ -1,89 +0,0 @@
---
import Layout from '../../layouts/Layout.astro'
import NoteMetadata from '../../components/NoteMetadata.astro'
---
<Layout title="Мыс Стрелка">
<h1>Мыс Стрелка</h1>
<NoteMetadata createdAt="11 ноября 2023" updatedAt="11 ноября 2023" />
<p>
<i>Некоторые вещи стоят того, чтобы встать в 6 утра в воскресенье.</i>
</p>
<h2>Куда мы едем?</h2>
<p>
Мыс Стрелка - это скала, у которой соединяются 2 реки: Кама и Чусовая.
Находится она недалеко от города, добраться до ближайших деревень можно на электричке,
а дальше нужно пару километров пройти пешком.
</p>
<p>
Точную дорогу мы заранее не посмотрели и пришли не на скалу, а к её основанию.
Подняться, как оказалось, можно и у самой скалы, в самом тяжёлом месте есть верёвка.
</p>
<img
src="/strelka/1.jpg"
alt="Вершина скалы"
/>
<div class="row">
<img
src="/strelka/2.jpg"
alt="Вид с мыса Стрелка"
/>
<img
src="/strelka/3.jpg"
alt="Вид с мыса Стрелка"
/>
</div>
<p>
На вершине скалы довольно ветрено, но красиво.
Совсем рядом находятся макушки деревьев, а дальше только вода.
<p>
<p>
Спустившись буквально на пару шагов можно укрыться от ветра и отдохнуть.
Если вы оказались здесь осенью, то чай будет очень кстати.
</p>
<img
src="/strelka/4.jpg"
alt="Пьем чай на скале"
/>
<h2>Путь обратно</h2>
<p>
У нас оставалось несколько часов до электрички, поэтому мы отправились изучать ближайшие деревни.
Вроде бы мы находились совсем недалеко от города, но атмосфера уже другая.
</p>
<img
src="/strelka/5.jpg"
alt="Железная дорога в деревне"
/>
<p>
Наши похождения закончились довольно быстро, но на станции можно спокойно дождаться электрички.
В итоге получилось короткое, но запоминающееся путешествие.
</p>
</Layout>
<style>
img {
width: 100%;
}
.row {
display: flex;
gap: 5px;
}
@media screen and (max-width: 800px) {
.row {
flex-direction: column;
}
}
</style>

23
src/pages/rss.xml.ts Normal file
View File

@ -0,0 +1,23 @@
import type { APIContext } from 'astro'
import rss from '@astrojs/rss'
import { getCollection } from 'astro:content'
export async function GET(context: APIContext) {
const notes = await getCollection('notes')
notes.sort((a, b) => {
if (a.data.pubDate < b.data.pubDate) return 1
if (a.data.pubDate > b.data.pubDate) return -1
return 0
})
return rss({
title: 'Уютный домик',
description: 'Заметки с сайта comfycamp.space',
site: context.site || "https://comfycamp.space",
items: notes.map((note) => ({
title: note.data.title,
pubDate: note.data.pubDate,
description: note.data.description,
link: `/notes/${note.slug}/`,
})),
})
}