главная|main page

состояние|status

блог|blog

файлы|files

программы|software

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Davydov <lotigara@lotigara.ru>2025-03-20 18:00:01 +0300
committerIvan Davydov <lotigara@lotigara.ru>2025-03-20 18:00:01 +0300
commitf9d08843e323f5473c4ef5e45e988b7542262567 (patch)
treecca2fa2260cdb1ffd4e92431fdc25b140a1d0200
parent330f0b978ca2f3635fdd1ca5ea79e1ffd959301c (diff)
Add Git support from a PR in the upstream and customize for my website
-rw-r--r--.body_begin.template1
-rw-r--r--.config154
-rw-r--r--.footer.template4
-rw-r--r--.gitignore5
-rw-r--r--.header.template8
-rw-r--r--.title.template10
-rwxr-xr-xbb.sh118
-rw-r--r--blog.css13
-rw-r--r--feed.rss41
-rw-r--r--main.css16
10 files changed, 343 insertions, 27 deletions
diff --git a/.body_begin.template b/.body_begin.template
new file mode 100644
index 0000000..f658d36
--- /dev/null
+++ b/.body_begin.template
@@ -0,0 +1 @@
+<input type="checkbox" id="theme-switch">
diff --git a/.config b/.config
new file mode 100644
index 0000000..ea3b033
--- /dev/null
+++ b/.config
@@ -0,0 +1,154 @@
+# Blog title
+global_title="Блог самохостера Lotigara"
+# The typical subtitle for each blog
+global_description="Заметки какого-то школьника на тему ИТ"
+# The public base URL for this blog
+global_url="https://www.lotigara.ru/blog"
+# organise the blog in a git-repo
+git_repo="true"
+git_push_on_commit="true"
+git_push_options=""
+
+# Your name
+global_author="Ivan Davydov"
+# You can use twitter or facebook or anything for global_author_url
+global_author_url="https://www.lotigara.ru"
+# Your email
+global_email="lotigara@lotigara.ru"
+
+# CC by-nc-nd is a good starting point, you can change this to "&copy;" for Copyright
+global_license="CC-BY"
+
+# If you have a Google Analytics ID (UA-XXXXX) and wish to use the standard
+# embedding code, put it on global_analytics
+# If you have custom analytics code (i.e. non-google) or want to use the Universal
+# code, leave global_analytics empty and specify a global_analytics_file
+global_analytics=""
+global_analytics_file=""
+
+# Leave this empty (i.e. "") if you don't want to use feedburner,
+# or change it to your own URL
+global_feedburner=""
+
+# Change this to your username if you want to use twitter for comments
+global_twitter_username=""
+# Default image for the Twitter cards. Use an absolute URL
+global_twitter_card_image=""
+# Set this to false for a Twitter button with share count. The cookieless version
+# is just a link.
+global_twitter_cookieless="true"
+# Default search page, where tweets more than a week old are hidden
+global_twitter_search="twitter"
+
+# Change this to your disqus username to use disqus for comments
+global_disqus_username=""
+
+
+# Blog generated files
+# index page of blog (it is usually good to use "index.html" here)
+index_file="index.html"
+number_of_index_articles="8"
+# global archive
+archive_index="all_posts.html"
+tags_index="all_tags.html"
+
+# Non blogpost files. Bashblog will ignore these. Useful for static pages and custom content
+# Add them as a bash array, e.g. non_blogpost_files=("news.html" "test.html")
+non_blogpost_files=("")
+
+# site map file
+blog_sitemap="sitemap.xml"
+# feed file (rss in this case)
+blog_feed="feed.rss"
+number_of_feed_articles="10"
+# "cut" blog entry when putting it to index page. Leave blank for full articles in front page
+# i.e. include only up to first '<hr>', or '----' in markdown
+cut_do="cut"
+# When cutting, cut also tags? If "no", tags will appear in index page for cut articles
+cut_tags="yes"
+# Regexp matching the HTML line where to do the cut
+# note that slash is regexp separator so you need to prepend it with backslash
+cut_line='<hr ?\/?>'
+# save markdown file when posting with "bb post -m". Leave blank to discard it.
+save_markdown="yes"
+# prefix for tags/categories files
+# please make sure that no other html file starts with this prefix
+prefix_tags="tag_"
+# personalized header and footer (only if you know what you're doing)
+# DO NOT name them .header.html, .footer.html or they will be overwritten
+# leave blank to generate them, recommended
+header_file=".header.template"
+footer_file=".footer.template"
+# extra content to add just after we open the <body> tag
+# and before the actual blog content
+body_begin_file=".body_begin.template"
+# extra content to add just before we close </body>
+body_end_file=""
+# extra content to ONLY on the index page AFTER `body_begin_file` contents
+# and before the actual content
+body_begin_file_index=""
+# CSS files to include on every page, f.ex. css_include=('main.css' 'blog.css')
+# leave empty to use generated
+css_include=("/var/www/html/css/main.css" "/var/www/html/css/responsivity.css" "/var/www/html/css/theme.css" "/var/www/html/css/third-party.css")
+# HTML files to exclude from index, f.ex. post_exclude=('imprint.html 'aboutme.html')
+html_exclude=()
+
+# Localization and i18n
+# "Comments?" (used in twitter link after every post)
+template_comments="Comments?"
+# "Read more..." (link under cut article on index page)
+template_read_more="Читать далее..."
+# "View more posts" (used on bottom of index page as link to archive)
+template_archive="Больше заметок"
+# "All posts" (title of archive page)
+template_archive_title="Все заметки"
+# "All tags"
+template_tags_title="Все метки"
+# "posts" (on "All tags" page, text at the end of each tag line, like "2. Music - 15 posts")
+template_tags_posts="заметок"
+template_tags_posts_2_4="заметки" # Some slavic languages use a different plural form for 2-4 items
+template_tags_posts_singular="заметка"
+# "Posts tagged" (text on a title of a page with index of one tag, like "My Blog - Posts tagged "Music"")
+template_tag_title="Заметки с меткой"
+# "Tags:" (beginning of line in HTML file with list of all tags for this article)
+template_tags_line_header="Метки:"
+# "Back to the index page" (used on archive page, it is link to blog index)
+template_archive_index_page="Вернуться к начальной странице"
+# "Subscribe" (used on bottom of index page, it is link to RSS feed)
+template_subscribe="Подписаться"
+# "Subscribe to this page..." (used as text for browser feed button that is embedded to html)
+template_subscribe_browser_button="Подписаться на эту страницу..."
+# "Tweet" (used as twitter text button for posting to twitter)
+template_twitter_button="Tweet"
+template_twitter_comment="&lt;Type your comment here but please leave the URL so that other people can follow the comments&gt;"
+
+# The locale to use for the dates displayed on screen
+date_format="%B %d, %Y"
+date_locale="ru_RU.UTF-8"
+date_inpost="bashblog_timestamp"
+# Don't change these dates
+date_format_full="%a, %d %b %Y %H:%M:%S %z"
+date_format_timestamp="%Y%m%d%H%M.%S"
+date_allposts_header="%B %Y"
+# Data format for sitemap
+date_format_sitemap="%Y/%m/%d"
+
+# Perform the post title -> filename conversion
+# Experts only. You may need to tune the locales too
+# Leave empty for no conversion, which is not recommended
+# This default filter respects backwards compatibility
+convert_filename="iconv -f utf-8 -t ascii//translit | sed 's/^-*//' | tr [:upper:] [:lower:] | tr ' ' '-' | tr -dc '[:alnum:]-'"
+
+# URL where you can view the post while it's being edited
+# same as global_url by default
+# You can change it to path on your computer, if you write posts locally
+# before copying them to the server
+preview_url="$HOME/bashblog/preview"
+
+# Markdown location. Trying to autodetect by default.
+# The invocation must support the signature 'markdown_bin in.md > out.html'
+[[ -f Markdown.pl ]] && markdown_bin=./Markdown.pl || markdown_bin=$(which Markdown.pl 2>/dev/null || which markdown 2>/dev/null)
+
+### CUSTOM OPTIONS
+title_file=".title.template"
+protect_email=""
diff --git a/.footer.template b/.footer.template
new file mode 100644
index 0000000..ca22778
--- /dev/null
+++ b/.footer.template
@@ -0,0 +1,4 @@
+<div class="section_header section_header_last">
+ <p>(c) Ivan Davydov 2025. Делайте с этим документом всё, что хотите!</p><hr/>
+ <a href="https://www.lotigara.ru/blog">Веб-сайт самохостера Lotigara</a> сгенерирован при помощи <a href="https://github.com/jakimfett/bashblog">Bashblog</a>. Исходные коды этой версии Bashblog можно найти <a href="https://www.lotigara.ru/files/bashblog">здесь</a>.</div>
+</div>
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ac767bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+*.html
+*.xml
+*.md
+drafts/
+.*.tar.gz
diff --git a/.header.template b/.header.template
new file mode 100644
index 0000000..9f33022
--- /dev/null
+++ b/.header.template
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <link href="/css/main.css" rel="stylesheet" />
+ <link href="/css/theme.css" rel="stylesheet" />
+ <link href="/css/third-party.css" rel="stylesheet" />
+ <link href="/css/responsivity.css" rel="stylesheet" />
diff --git a/.title.template b/.title.template
new file mode 100644
index 0000000..ce3f96f
--- /dev/null
+++ b/.title.template
@@ -0,0 +1,10 @@
+<div class="page_header floating_element">
+ <h1 class="floating_element">Блог самохостера Lotigara</h1>
+</div>
+<div class="floating_element">
+ <h4 style="display:inline"><a style="color:white" href="/">главная|main page</a></h4>
+ <h4 style="display:inline"><a style="color:white" href="/status.php">состояние|status</a></h4>
+ <p style="display:inline">блог|blog</p>
+ <h4 style="display:inline"><a style="color:white" href="/files">файлы|files</a></h4>
+ <label id="switch-label" for="theme-switch"></label>
+</div>
diff --git a/bb.sh b/bb.sh
index b041a5e..8629d07 100755
--- a/bb.sh
+++ b/bb.sh
@@ -18,6 +18,10 @@ global_config=".config"
global_variables() {
global_software_name="BashBlog"
global_software_version="2.10"
+ # organise the blog in a git-repo
+ git_repo="false"
+ git_push_on_commit="false"
+ git_push_options=""
# Blog title
global_title="My fancy blog"
@@ -323,7 +327,10 @@ edit() {
parse_file "$TMPFILE" "$edit_timestamp" "$filename"
else
parse_file "$TMPFILE" "$edit_timestamp" # this command sets $filename as the html processed file
- [[ ${1##*.} == md ]] && mv "$1" "${filename%%.*}.md" 2>/dev/null
+ if [[ ${1##*.} == md ]]; then
+ mv "$1" "${filename%%.*}.md" 2>/dev/null
+ [[ "$git_repo" == 'true' ]] && git add "${filename%%.*}.md"
+ fi
fi
rm "$TMPFILE"
fi
@@ -331,6 +338,10 @@ edit() {
touch -t "$touch_timestamp" "$1"
chmod 644 "$filename"
echo "Posted $filename"
+ if [[ $git_repo == 'true' ]]; then
+ git add $filename
+ commit_message="Update $filename"
+ fi
tags_after=$(tags_in_post "$filename")
relevant_tags=$(echo "$tags_before $tags_after" | tr ',' ' ' | tr ' ' '\n' | sort -u | tr '\n' ' ')
if [[ ! -z $relevant_tags ]]; then
@@ -453,7 +464,7 @@ create_html_page() {
[[ -n $body_begin_file ]] && cat "$body_begin_file"
[[ $filename = $index_file* ]] && [[ -n $body_begin_file_index ]] && cat "$body_begin_file_index"
# body divs
- echo '<div id="divbodyholder">'
+ echo '<div id="divbodyholder"><div class="inner_page">'
echo '<div class="headerholder"><div class="header">'
# blog title
echo '<div id="title">'
@@ -466,12 +477,12 @@ create_html_page() {
# one blog entry
if [[ $index == no ]]; then
echo '<!-- entry begin -->' # marks the beginning of the whole post
- echo "<h3><a class=\"ablack\" href=\"$file_url\">"
+ echo "<div class=\"section_header\"><a class=\"ablack\" href=\"$file_url\">"
# remove possible <p>'s on the title because of markdown conversion
title=${title//<p>/}
title=${title//<\/p>/}
echo "$title"
- echo '</a></h3>'
+ echo '</a></div>'
if [[ -z $timestamp ]]; then
echo "<!-- $date_inpost: #$(LC_ALL=$date_locale date +"$date_format_timestamp")# -->"
else
@@ -503,7 +514,7 @@ create_html_page() {
# page footer
cat .footer.html
# close divs
- echo '</div></div>' # divbody and divbodyholder
+ echo '</div></div></div>' # divbody, inner_page and divbodyholder
disqus_footer
[[ -n $body_end_file ]] && cat "$body_end_file"
echo '</body></html>'
@@ -636,6 +647,12 @@ EOF
draft=drafts/$title.$fmt
mv "$TMPFILE" "$draft"
+ if [[ $git_repo == 'true' ]]; then
+ git add $draft
+ git commit -m"$commit_message""drafted $draft; " # will exit soon, no later opportunity to commit
+ [[ $git_push_on_commit == 'true' ]] && git push
+ echo "Add $draft"
+ fi
chmod 600 "$draft"
rm "$filename"
delete_includes
@@ -657,11 +674,16 @@ EOF
if [[ $fmt == md && -n $save_markdown ]]; then
mv "$TMPFILE" "${filename%%.*}.md"
+ [[ $git_repo == 'true' ]] && git add "${filename%%.*}.md"
else
rm "$TMPFILE"
fi
chmod 644 "$filename"
echo "Posted $filename"
+ if [[ $git_repo == 'true' ]]; then
+ git add $filename
+ commit_message="Add ${filename%%.*}"
+ fi
relevant_tags=$(tags_in_post $filename)
if [[ -n $relevant_tags ]]; then
relevant_posts="$(posts_with_tags $relevant_tags) $filename"
@@ -710,6 +732,7 @@ all_posts() {
mv "$archive_index.tmp" "$archive_index"
chmod 644 "$archive_index"
rm "$contentfile"
+ [[ $git_repo == 'true' ]] && git add $archive_index
}
# Create an index page with all the tags
@@ -745,6 +768,7 @@ all_tags() {
mv "$tags_index.tmp" "$tags_index"
chmod 644 "$tags_index"
rm "$contentfile"
+ [[ $git_repo == 'true' ]] && git add $tags_index
}
# Generate the index.html with the content of the latest posts
@@ -782,6 +806,7 @@ rebuild_index() {
create_html_page "$contentfile" "$newindexfile" yes "$global_title" "$global_author"
rm "$contentfile"
mv "$newindexfile" "$index_file"
+ [[ $git_repo == 'true' ]] && git add $index_file
chmod 644 "$index_file"
}
@@ -799,7 +824,7 @@ posts_with_tags() {
(($# < 1)) && return
set -- "${@/#/$prefix_tags}"
set -- "${@/%/.html}"
- sed -n '/^<h3><a class="ablack" href="[^"]*">/{s/.*href="\([^"]*\)">.*/\1/;p;}' "$@" 2> /dev/null
+ sed -n '/^<div class="section_header"><a class="ablack" href="[^"]*">/{s/.*href="\([^"]*\)">.*/\1/;p;}' "$@" 2> /dev/null
}
# Rebuilds tag_*.html files
@@ -856,7 +881,9 @@ rebuild_tags() {
tagname=${tagname%.tmp.html}
create_html_page "$i" "$prefix_tags$tagname.html" yes "$global_title &mdash; $template_tag_title \"$tagname\"" "$global_author"
rm "$i"
+ [[ $git_repo == 'true' ]] && git add $prefix_tags$tagname.html
done < <(ls -t ./"$prefix_tags"*.tmp.html 2>/dev/null)
+ commit_message="Rebuild tags"
echo
}
@@ -864,7 +891,7 @@ rebuild_tags() {
#
# $1 the html file
get_post_title() {
- awk '/<h3><a class="ablack" href=".+">/, /<\/a><\/h3>/{if (!/<h3><a class="ablack" href=".+">/ && !/<\/a><\/h3>/) print}' "$1"
+ awk '/<div class="section_header"><a class="ablack" href=".+">/, /<\/a><\/div>/{if (!/<div class="section_header"><a class="ablack" href=".+">/ && !/<\/a><\/div>/) print}' "$1"
}
# Return the post author
@@ -987,14 +1014,17 @@ make_rss() {
mv "$rssfile" "$blog_feed"
chmod 644 "$blog_feed"
+ [[ $git_repo == true ]] && git add $blog_feed
}
# generate headers, footers, etc
create_includes() {
- {
+ if [[ -f $title_file ]]; then cp "$title_file" .title.html
+ else {
echo "<h1 class=\"nomargin\"><a class=\"ablack\" href=\"$global_url/$index_file\">$global_title</a></h1>"
echo "<div id=\"description\">$global_description</div>"
- } > ".title.html"
+ } > ".title.html"
+ fi
if [[ -f $header_file ]]; then cp "$header_file" .header.html
else {
@@ -1013,10 +1043,14 @@ create_includes() {
if [[ -f $footer_file ]]; then cp "$footer_file" .footer.html
else {
- protected_mail=${global_email//@/&#64;}
- protected_mail=${protected_mail//./&#46;}
+ if [[ $protect_email == true ]]; then
+ protected_mail=${global_email//@/&#64;}
+ protected_mail=${protected_mail//./&#46;}
+ else
+ protected_mail=${global_email}
+ fi
echo "<div id=\"footer\">$global_license <a href=\"$global_author_url\">$global_author</a> &mdash; <a href=\"mailto:$protected_mail\">$protected_mail</a><br>"
- echo 'Generated with <a href="https://github.com/cfenollosa/bashblog">bashblog</a>, a single bash script to easily create blogs like this one</div>'
+ echo '<a href=\"$global_url\">$global_title</a> is generated with <a href="https://github.com/cfenollosa/bashblog">bashblog</a>, a single bash script to easily create blogs like this one</div>'
} >> ".footer.html"
fi
}
@@ -1071,6 +1105,8 @@ create_css() {
blockquote img{margin:12px 0px;}
blockquote iframe{margin:12px 0px;}' > main.css
fi
+
+ [[ $git_repo == 'true' ]] && git add $css_include
}
# Regenerates all the single post entries, keeping the post content but modifying
@@ -1101,8 +1137,10 @@ rebuild_all_entries() {
mv "$i.rebuilt" "$i"
chmod 644 "$i"
touch -t "$timestamp" "$i"
+ [[ $git_repo == 'true' ]] && git add $i
rm "$contentfile"
done
+ commit_message="Rebuild all entries"
echo ""
}
@@ -1134,10 +1172,20 @@ reset() {
echo "Are you sure you want to delete all blog entries? Please write \"Yes, I am!\" "
read -r line
if [[ $line == "Yes, I am!" ]]; then
- rm .*.html ./*.html ./*.css ./*.rss &> /dev/null
+ if [[ $git_repo == 'true' ]]; then
+ git rm .*.html ./*.html ./*.css ./*.rss &> /dev/null
+ git commit -m"$commit_message""resetted the blog; " # has to be commited right here as will be exited right after.
+ [[ $git_push_on_commit == 'true' ]] && git push
+ else
+ rm .*.html ./*.html ./*.css ./*.rss &> /dev/null
+ fi
echo
echo "Deleted all posts, stylesheets and feeds."
- echo "Kept your old '.backup.tar.gz' just in case, please delete it manually if needed."
+ if [[ $git_repo == 'true' ]]; then
+ echo "Didn't reset the git repo just in case, please do so manually if needed."
+ else
+ echo "Kept your old '.backup.tar.gz' just in case, please delete it manually if needed."
+ fi
else
echo "Phew! You dodged a bullet there. Nothing was modified."
fi
@@ -1192,6 +1240,8 @@ do_main() {
global_variables
[[ -f $global_config ]] && source "$global_config" &> /dev/null
global_variables_check
+ # create git repo if wanted and not there yet
+ [[ $git_repo == 'true' && ! -d "./.git/" ]] && git init
# Check for $EDITOR
[[ -z $EDITOR ]] &&
@@ -1214,19 +1264,21 @@ do_main() {
fi
fi
- # Test for existing html files
- if ls ./*.html &> /dev/null; then
- # We're going to back up just in case
- tar -c -z -f ".backup.tar.gz" -- *.html &&
- chmod 600 ".backup.tar.gz"
- elif [[ $1 == rebuild ]]; then
- echo "Can't find any html files, nothing to rebuild"
- exit
- fi
+ if [[ $git_repo != 'true' ]]; then # don't use tar-backups when already using git
+ # Test for existing html files
+ if ls ./*.html &> /dev/null; then
+ # We're going to back up just in case
+ tar -c -z -f ".backup.tar.gz" -- *.html &&
+ chmod 600 ".backup.tar.gz"
+ elif [[ $1 == rebuild ]]; then
+ echo "Can't find any html files, nothing to rebuild"
+ exit
+ fi
- # Keep first backup of this day containing yesterday's version of the blog
- [[ ! -f .yesterday.tar.gz || $(date -r .yesterday.tar.gz +'%d') != "$(date +'%d')" ]] &&
- cp .backup.tar.gz .yesterday.tar.gz &> /dev/null
+ # Keep first backup of this day containing yesterday's version of the blog
+ [[ ! -f .yesterday.tar.gz || $(date -r .yesterday.tar.gz +'%d') != "$(date +'%d')" ]] &&
+ cp .backup.tar.gz .yesterday.tar.gz &> /dev/null
+ fi
[[ $1 == reset ]] &&
reset && exit
@@ -1235,7 +1287,15 @@ do_main() {
create_includes
[[ $1 == post ]] && write_entry "$@"
[[ $1 == rebuild ]] && rebuild_all_entries && rebuild_tags
- [[ $1 == delete ]] && rm "$2" &> /dev/null && rebuild_tags
+ if [[ $1 == delete ]]; then
+ if [[ $git_repo == 'true' ]]; then
+ git rm $2 &> /dev/null
+ commit_message="Delete $2"
+ else
+ rm "$2" &> /dev/null
+ fi
+ rebuild_tags
+ fi
if [[ $1 == edit ]]; then
if [[ $2 == -n ]]; then
edit "$3"
@@ -1251,6 +1311,10 @@ do_main() {
make_rss
make_sitemap
delete_includes
+ if [[ $git_repo == 'true' ]]; then
+ git commit -m"$commit_message"
+ [[ $git_push_on_commit == 'true' ]] && git push $git_push_options
+ fi
}
diff --git a/blog.css b/blog.css
new file mode 100644
index 0000000..cc655b9
--- /dev/null
+++ b/blog.css
@@ -0,0 +1,13 @@
+#title{font-size: x-large;}
+ a.ablack{color:black !important;}
+ li{margin-bottom:8px;}
+ ul,ol{margin-left:24px;margin-right:24px;}
+ #all_posts{margin-top:24px;text-align:center;}
+ .subtitle{font-size:small;margin:12px 0px;}
+ .content p{margin-left:24px;margin-right:24px;}
+ h1{margin-bottom:12px !important;}
+ #description{font-size:large;margin-bottom:12px;}
+ h3{margin-top:42px;margin-bottom:8px;}
+ h4{margin-left:24px;margin-right:24px;}
+ img{max-width:100%;}
+ #twitter{line-height:20px;vertical-align:top;text-align:right;font-style:italic;color:#333;margin-top:24px;font-size:14px;}
diff --git a/feed.rss b/feed.rss
new file mode 100644
index 0000000..464272b
--- /dev/null
+++ b/feed.rss
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
+<channel><title>Блог самохостера Lotigara</title><link>https://www.lotigara.ru/blog/index.html</link>
+<description>Заметки какого-то школьника на тему ИТ</description><language>en</language>
+<lastBuildDate>Thu, 20 Mar 2025 13:28:19 +0300</lastBuildDate>
+<pubDate>Thu, 20 Mar 2025 13:28:19 +0300</pubDate>
+<atom:link href="https://www.lotigara.ru/blog/feed.rss" rel="self" type="application/rss+xml" />
+<item><title>
+Fast Transition (Wi-Fi Roaming) with OpenWrt and KeeneticOS
+</title><description><![CDATA[
+
+<h5>tested on KeeneticOS v3.8.7 &amp; OpenWrt v23.05.5</h5>
+
+<p>First, set up FT on your OpenWrt devices.</p>
+
+<p>Then, change the mode of your Keenetic (?) devices to Extender (there are Repeater/Extender and Access Point/Extender, the last is the recommended).</p>
+
+<p>Go to the <code>Access Point/Extender (Repeater/Extender) &gt; Home segment</code> menu. Change the settings of the Wi-Fi network to those ones in OpenWrt.</p>
+
+<p>Scroll below to the "Roaming for wireless devices" section. Enable "Fast transition (802.11r)" and write your mobility domain ID converted to the ASCII format.</p>
+
+<p>You can use an online converter like this one: <a href="https://www.rapidtables.com/convert/number/hex-to-ascii.html">https://www.rapidtables.com/convert/number/hex-to-ascii.html</a>. Keep the "Mobility domain key" field unedited.</p>
+
+<p>Press the "Save" button. Now you have a so-called "Wi-Fi system" with use of both KeeneticOS and OpenWrt!</p>
+
+<p>Метки: <a href='tag_keeneticos.html'>keeneticos</a>, <a href='tag_openwrt.html'>openwrt</a>, <a href='tag_wifi.html'>wifi</a>, <a href='tag_wifi-roaming.html'>wifi-roaming</a></p>
+
+
+
+
+
+
+
+
+
+<!-- text end -->
+]]></description><link>https://www.lotigara.ru/blog/fast-transition-wi-fi-roaming-with-openwrt-and-keeneticos.html</link>
+<guid>https://www.lotigara.ru/blog/./fast-transition-wi-fi-roaming-with-openwrt-and-keeneticos.html</guid>
+<dc:creator>Ivan Davydov</dc:creator>
+<pubDate>Fri, 07 Mar 2025 19:40:59 +0300</pubDate></item>
+</channel></rss>
diff --git a/main.css b/main.css
new file mode 100644
index 0000000..63670fe
--- /dev/null
+++ b/main.css
@@ -0,0 +1,16 @@
+body{font-family:Georgia,"Times New Roman",Times,serif;margin:0;padding:0;background-color:#F3F3F3;}
+ #divbodyholder{padding:5px;background-color:#DDD;width:100%;max-width:874px;margin:24px auto;}
+ #divbody{border:solid 1px #ccc;background-color:#fff;padding:0px 48px 24px 48px;top:0;}
+ .headerholder{background-color:#f9f9f9;border-top:solid 1px #ccc;border-left:solid 1px #ccc;border-right:solid 1px #ccc;}
+ .header{width:100%;max-width:800px;margin:0px auto;padding-top:24px;padding-bottom:8px;}
+ .content{margin-bottom:5%;}
+ .nomargin{margin:0;}
+ .description{margin-top:10px;border-top:solid 1px #666;padding:10px 0;}
+ h3{font-size:20pt;width:100%;font-weight:bold;margin-top:32px;margin-bottom:0;}
+ .clear{clear:both;}
+ #footer{padding-top:10px;border-top:solid 1px #666;color:#333333;text-align:center;font-size:small;font-family:"Courier New","Courier",monospace;}
+ a{text-decoration:none;color:#003366 !important;}
+ a:visited{text-decoration:none;color:#336699 !important;}
+ blockquote{background-color:#f9f9f9;border-left:solid 4px #e9e9e9;margin-left:12px;padding:12px 12px 12px 24px;}
+ blockquote img{margin:12px 0px;}
+ blockquote iframe{margin:12px 0px;}