Add NAS config files
This commit is contained in:
Executable
+52
@@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
DB="/home/filebrowser/filebrowser.db"
|
||||
BASE_DIR="/data/personal"
|
||||
FB_USER="filebrowser"
|
||||
MEDIA_GROUP="nasusers"
|
||||
DMN="filebrowser.service"
|
||||
DRY_RUN=false
|
||||
|
||||
if [ -z "$1" ] || [ -z "$2" ]; then
|
||||
echo "Использование: $0 <username> <password>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
USERNAME="$1"
|
||||
PASSWORD="$2"
|
||||
USER_DIR="$BASE_DIR/$USERNAME"
|
||||
|
||||
run() {
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
echo "[DRY-RUN] $*"
|
||||
else
|
||||
"$@"
|
||||
fi
|
||||
}
|
||||
|
||||
echo ">>> Останавливаем демон"
|
||||
run systemctl stop $DMN
|
||||
|
||||
echo ">>> Создаём пользователя в filebrowser"
|
||||
run filebrowser users add "$USERNAME" "$PASSWORD" \
|
||||
--scope "$USERNAME" \
|
||||
--perm.create \
|
||||
--perm.modify \
|
||||
--perm.delete \
|
||||
--perm.rename \
|
||||
--perm.download \
|
||||
--perm.share \
|
||||
-d "$DB"
|
||||
|
||||
echo ">>> Создаём каталог и выставляем права"
|
||||
run mkdir -p "$USER_DIR"
|
||||
run chown root:"$MEDIA_GROUP" "$USER_DIR"
|
||||
run chmod 2770 "$USER_DIR"
|
||||
run setfacl -d -m g:"$MEDIA_GROUP":rwx "$USER_DIR"
|
||||
run setfacl -d -m o::0 "$USER_DIR"
|
||||
|
||||
echo ">>> Запускаемся обратно"
|
||||
run systemctl start $DMN
|
||||
|
||||
echo ">>> Готово! Пользователь $USERNAME создан, папка: $USER_DIR"
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from bandcamp_dl.__main__ import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
TARGET="$1"
|
||||
|
||||
if [ -z "$TARGET" ]; then
|
||||
echo "Использование: fixperms <путь>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -e "$TARGET" ]; then
|
||||
echo "Ошибка: $TARGET не существует"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ">>> Фиксим права на $TARGET"
|
||||
|
||||
chown -R root:nasusers "$TARGET"
|
||||
chmod -R 2770 "$TARGET"
|
||||
setfacl -R -m g:nasusers:rwx "$TARGET"
|
||||
setfacl -R -d -m g:nasusers:rwx "$TARGET"
|
||||
setfacl -R -m o::0 "$TARGET"
|
||||
setfacl -R -d -m o::0 "$TARGET"
|
||||
|
||||
echo ">>> Готово!"
|
||||
Executable
+292
@@ -0,0 +1,292 @@
|
||||
#!/bin/bash
|
||||
|
||||
CONFIG="/home/filebrowser/config"
|
||||
source "$CONFIG"
|
||||
|
||||
# ==================== SHOW ====================
|
||||
|
||||
show_system() {
|
||||
echo "=== Системные пользователи ==="
|
||||
getent passwd | awk -F: '$3 >= 1000 && $3 < 65534 {print $1}'
|
||||
}
|
||||
|
||||
show_samba() {
|
||||
echo "=== Samba ==="
|
||||
pdbedit -L | cut -d: -f1
|
||||
}
|
||||
|
||||
show_filebrowser() {
|
||||
echo "=== Filebrowser ==="
|
||||
systemctl stop filebrowser.service
|
||||
filebrowser users ls -d "$FB_DB" 2>/dev/null | tail -n +3 | awk '{print $2}'
|
||||
systemctl start filebrowser.service
|
||||
}
|
||||
|
||||
show_jellyfin() {
|
||||
echo "=== Jellyfin ==="
|
||||
curl -s "$JF_URL/Users" \
|
||||
-H "X-Emby-Token: $JF_API_KEY" | \
|
||||
python3 -c "import sys,json; [print(u['Name']) for u in json.load(sys.stdin)]"
|
||||
}
|
||||
|
||||
show_all() {
|
||||
show_system
|
||||
echo ""
|
||||
show_samba
|
||||
echo ""
|
||||
show_filebrowser
|
||||
echo ""
|
||||
show_jellyfin
|
||||
}
|
||||
|
||||
# ==================== PASSWORD ====================
|
||||
|
||||
get_password() {
|
||||
local pass1 pass2
|
||||
while true; do
|
||||
read -s -p "Новый пароль: " pass1 >&2
|
||||
echo "" >&2
|
||||
read -s -p "Повтори пароль: " pass2 >&2
|
||||
echo "" >&2
|
||||
if [ "$pass1" = "$pass2" ]; then
|
||||
printf '%s' "$pass1"
|
||||
return
|
||||
fi
|
||||
echo "Пароли не совпадают, попробуй ещё раз" >&2
|
||||
done
|
||||
}
|
||||
|
||||
passwd_samba() {
|
||||
local username="$1"
|
||||
local password="$2"
|
||||
echo "$password" | smbpasswd -s -a "$username"
|
||||
smbpasswd -e "$username"
|
||||
}
|
||||
|
||||
passwd_filebrowser() {
|
||||
local username="$1"
|
||||
local password="$2"
|
||||
systemctl stop filebrowser.service
|
||||
filebrowser users update "$username" --password "$password" -d "$FB_DB"
|
||||
systemctl start filebrowser.service
|
||||
}
|
||||
|
||||
passwd_jellyfin() {
|
||||
local username="$1"
|
||||
local password="$2"
|
||||
local user_id
|
||||
user_id=$(curl -s "$JF_URL/Users" \
|
||||
-H "X-Emby-Token: $JF_API_KEY" | \
|
||||
python3 -c "import sys,json; users=json.load(sys.stdin); [print(u['Id']) for u in users if u['Name']=='$username']")
|
||||
if [ -z "$user_id" ]; then
|
||||
echo "Пользователь $username не найден в Jellyfin"
|
||||
return 1
|
||||
fi
|
||||
curl -s -X POST "$JF_URL/Users/$user_id/Password" \
|
||||
-H "X-Emby-Token: $JF_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"NewPw\": \"$password\"}"
|
||||
echo "Пароль в Jellyfin обновлён"
|
||||
}
|
||||
|
||||
edit_user() {
|
||||
local service="$1"
|
||||
local username="$2"
|
||||
local password
|
||||
password=$(get_password)
|
||||
case "$service" in
|
||||
smb) passwd_samba "$username" "$password" ;;
|
||||
fb) passwd_filebrowser "$username" "$password" ;;
|
||||
jf) passwd_jellyfin "$username" "$password" ;;
|
||||
*)
|
||||
echo "Неизвестный сервис: $service"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ==================== ADD USER ====================
|
||||
|
||||
get_jf_libraries() {
|
||||
curl -s "$JF_URL/Library/VirtualFolders" \
|
||||
-H "X-Emby-Token: $JF_API_KEY" | \
|
||||
python3 -c "import sys,json; [print(f['ItemId']) for f in json.load(sys.stdin)]"
|
||||
}
|
||||
|
||||
add_to_system() {
|
||||
local username="$1"
|
||||
if id "$username" &>/dev/null; then
|
||||
echo ">>> Системный пользователь $username уже существует, пропускаем"
|
||||
else
|
||||
useradd -M -s /sbin/nologin "$username"
|
||||
usermod -aG nasusers "$username"
|
||||
echo ">>> Системный пользователь $username создан"
|
||||
fi
|
||||
}
|
||||
|
||||
add_to_samba() {
|
||||
# local username="$1"
|
||||
# local password="$2"
|
||||
# if pdbedit -L | grep -q "^$username:"; then
|
||||
# echo ">>> Пользователь $username уже есть в Samba, пропускаем"
|
||||
# else
|
||||
# echo "$password" | smbpasswd -s -a "$username"
|
||||
# smbpasswd -e "$username"
|
||||
# echo ">>> Пользователь $username добавлен в Samba"
|
||||
# fi
|
||||
local username="$1"
|
||||
local password="$2"
|
||||
if pdbedit -L | grep -q "^$username:"; then
|
||||
echo ">>> Пользователь $username уже есть в Samba, пропускаем"
|
||||
else
|
||||
# Сначала создаём системную запись в passdb
|
||||
pdbedit -a -u "$username" -t << EOF > /dev/null 2>&1
|
||||
$password
|
||||
$password
|
||||
EOF
|
||||
smbpasswd -e "$username"
|
||||
echo ">>> Пользователь $username добавлен в Samba"
|
||||
fi
|
||||
}
|
||||
|
||||
add_to_filebrowser() {
|
||||
local username="$1"
|
||||
local password="$2"
|
||||
systemctl stop filebrowser.service
|
||||
if filebrowser users ls -d "$FB_DB" 2>/dev/null | grep -q "$username"; then
|
||||
echo ">>> Пользователь $username уже есть в Filebrowser, пропускаем"
|
||||
else
|
||||
filebrowser users add "$username" "$password" \
|
||||
--scope "$username" \
|
||||
--perm.create \
|
||||
--perm.modify \
|
||||
--perm.delete \
|
||||
--perm.rename \
|
||||
--perm.download \
|
||||
--perm.share \
|
||||
-d "$FB_DB"
|
||||
echo ">>> Пользователь $username добавлен в Filebrowser"
|
||||
fi
|
||||
systemctl start filebrowser.service
|
||||
}
|
||||
|
||||
add_to_jellyfin() {
|
||||
local username="$1"
|
||||
local password="$2"
|
||||
|
||||
local exists
|
||||
exists=$(curl -s "$JF_URL/Users" \
|
||||
-H "X-Emby-Token: $JF_API_KEY" | \
|
||||
python3 -c "import sys,json; users=json.load(sys.stdin); print(any(u['Name']=='$username' for u in users))")
|
||||
|
||||
if [ "$exists" = "True" ]; then
|
||||
echo ">>> Пользователь $username уже есть в Jellyfin, пропускаем"
|
||||
return
|
||||
fi
|
||||
|
||||
local result
|
||||
result=$(curl -s -X POST "$JF_URL/Users/New" \
|
||||
-H "X-Emby-Token: $JF_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"Name\": \"$username\", \"Password\": \"$password\"}")
|
||||
|
||||
local user_id
|
||||
user_id=$(echo "$result" | python3 -c "import sys,json; print(json.load(sys.stdin)['Id'])")
|
||||
|
||||
if [ -z "$user_id" ]; then
|
||||
echo ">>> Ошибка создания пользователя $username в Jellyfin"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo ">>> Пользователь $username добавлен в Jellyfin (id: $user_id)"
|
||||
}
|
||||
|
||||
create_homedir() {
|
||||
local username="$1"
|
||||
local user_dir="$BASE_DIR/$username"
|
||||
|
||||
if [ -d "$user_dir" ]; then
|
||||
echo ">>> Каталог $user_dir уже существует, пропускаем"
|
||||
else
|
||||
mkdir -p "$user_dir"
|
||||
chown root:nasusers "$user_dir"
|
||||
chmod 2770 "$user_dir"
|
||||
setfacl -d -m g:nasusers:rwx "$user_dir"
|
||||
setfacl -d -m o::0 "$user_dir"
|
||||
echo ">>> Каталог $user_dir создан с ACL"
|
||||
fi
|
||||
}
|
||||
|
||||
add_user() {
|
||||
local username="$1"
|
||||
local password
|
||||
password=$(get_password)
|
||||
|
||||
echo ""
|
||||
echo ">>> Добавляем пользователя $username..."
|
||||
echo ""
|
||||
|
||||
add_to_system "$username"
|
||||
create_homedir "$username"
|
||||
add_to_samba "$username" "$password"
|
||||
add_to_filebrowser "$username" "$password"
|
||||
add_to_jellyfin "$username" "$password"
|
||||
|
||||
echo ""
|
||||
echo ">>> Готово! Пользователь $username создан во всех системах"
|
||||
}
|
||||
|
||||
# ==================== USAGE ====================
|
||||
|
||||
usage() {
|
||||
echo "Использование: $0 <команда> [аргументы]"
|
||||
echo ""
|
||||
echo "Команды:"
|
||||
echo " list [сервис] показать пользователей (system|smb|fb|jf|all)"
|
||||
echo " passwd <сервис> <user> сменить пароль пользователя"
|
||||
echo " add <username> добавить пользователя во все системы"
|
||||
echo ""
|
||||
echo "Примеры:"
|
||||
echo " $0 list"
|
||||
echo " $0 list jf"
|
||||
echo " $0 passwd smb xalex"
|
||||
echo " $0 passwd fb mammy"
|
||||
echo " $0 add newuser"
|
||||
}
|
||||
|
||||
# ==================== MAIN ====================
|
||||
|
||||
case "${1}" in
|
||||
list)
|
||||
case "${2:-all}" in
|
||||
system) show_system ;;
|
||||
smb) show_samba ;;
|
||||
fb) show_filebrowser ;;
|
||||
jf) show_jellyfin ;;
|
||||
all) show_all ;;
|
||||
*) echo "Неизвестный сервис: $2"; usage; exit 1 ;;
|
||||
esac
|
||||
;;
|
||||
passwd)
|
||||
if [ -z "$2" ] || [ -z "$3" ]; then
|
||||
echo "Использование: $0 passwd <сервис> <username>"
|
||||
exit 1
|
||||
fi
|
||||
edit_user "$2" "$3"
|
||||
;;
|
||||
add)
|
||||
if [ -z "$2" ]; then
|
||||
echo "Использование: $0 add <username>"
|
||||
exit 1
|
||||
fi
|
||||
add_user "$2"
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
echo "Неизвестная команда: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Executable
+114
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import os
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from guessit import guessit
|
||||
|
||||
MEDIA = Path("/data/media")
|
||||
JULY = Path("/data/july")
|
||||
DRY_RUN = "--dry-run" in sys.argv
|
||||
|
||||
VIDEO_EXTENSIONS = {'.mkv', '.mp4', '.avi', '.mov', '.wmv', '.m4v', '.ts', '.m2ts'}
|
||||
|
||||
def log(action, src, dst):
|
||||
if DRY_RUN:
|
||||
print(f"[DRY-RUN] {action}: {src} → {dst}")
|
||||
else:
|
||||
print(f"[{action}] {src} → {dst}")
|
||||
|
||||
def hardlink_tree(src: Path, dst: Path):
|
||||
dst.mkdir(parents=True, exist_ok=True)
|
||||
if src.is_file():
|
||||
target = dst / src.name
|
||||
if not target.exists():
|
||||
if not DRY_RUN:
|
||||
os.link(src, target)
|
||||
else:
|
||||
print(f"[SKIP] уже существует: {target}")
|
||||
elif src.is_dir():
|
||||
for f in src.iterdir():
|
||||
if f.is_file():
|
||||
target = dst / f.name
|
||||
if not target.exists():
|
||||
if not DRY_RUN:
|
||||
os.link(f, target)
|
||||
else:
|
||||
print(f"[SKIP] уже существует: {target}")
|
||||
|
||||
def process(src: Path):
|
||||
name = src.name
|
||||
# Пропускаем не видео
|
||||
if src.is_file() and src.suffix.lower() not in VIDEO_EXTENSIONS:
|
||||
print(f"[SKIP] не видео: {name}")
|
||||
return
|
||||
|
||||
# Для папок — проверяем есть ли внутри видео файлы
|
||||
if src.is_dir():
|
||||
has_video = any(
|
||||
f.suffix.lower() in VIDEO_EXTENSIONS
|
||||
for f in src.rglob("*")
|
||||
if f.is_file()
|
||||
)
|
||||
if not has_video:
|
||||
print(f"[SKIP] нет видео файлов: {name}")
|
||||
return
|
||||
|
||||
info = guessit(name)
|
||||
|
||||
|
||||
info = guessit(name)
|
||||
|
||||
kind = info.get("type")
|
||||
title = info.get("title", name)
|
||||
year = info.get("year")
|
||||
season = info.get("season")
|
||||
|
||||
if kind == "movie":
|
||||
folder_name = f"{title} ({year})" if year else title
|
||||
dst = JULY / "Фильмы" / folder_name
|
||||
log("MOVIE", src, dst)
|
||||
hardlink_tree(src, dst)
|
||||
|
||||
elif kind == "episode":
|
||||
season_str = f"Season {season:02d}" if season else "Season 01"
|
||||
dst = JULY / "Сериалы" / title / season_str
|
||||
log("SERIES", src, dst)
|
||||
hardlink_tree(src, dst)
|
||||
|
||||
else:
|
||||
print(f"[SKIP] не распознан: {name}")
|
||||
|
||||
def main():
|
||||
args = [a for a in sys.argv[1:] if not a.startswith("--")]
|
||||
|
||||
if len(args) == 0:
|
||||
# Автоскан всего /data/media
|
||||
for item in sorted(MEDIA.iterdir()):
|
||||
process(item)
|
||||
|
||||
elif len(args) == 1:
|
||||
# Один элемент — полный путь или имя
|
||||
src = Path(args[0])
|
||||
if not src.is_absolute():
|
||||
src = MEDIA / src
|
||||
process(src)
|
||||
|
||||
elif len(args) == 2:
|
||||
# Вручную: источник + категория/название
|
||||
src = Path(args[0])
|
||||
if not src.is_absolute():
|
||||
src = MEDIA / src
|
||||
dst = JULY / args[1]
|
||||
log("MANUAL", src, dst)
|
||||
hardlink_tree(src, dst)
|
||||
|
||||
else:
|
||||
print("Использование:")
|
||||
print(" linkmedia [--dry-run] # автоскан")
|
||||
print(" linkmedia [--dry-run] <src> # один элемент")
|
||||
print(" linkmedia [--dry-run] <src> <Категория/папка> # вручную")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
rm -rf /data/torrents/*.added
|
||||
|
||||
# /usr/local/bin/plinkmedia "$TR_TORRENT_DIR/$TR_TORRENT_NAME"
|
||||
|
||||
#dnlds='/data/downloads'
|
||||
#files=$(ls $dnlds)
|
||||
|
||||
|
||||
#for i in $files ; do
|
||||
# ext="${i##*.}"
|
||||
# ##### MOVING MOVIES TO MEDIA
|
||||
# if [[ " ${movies[@]} " =~ " ${ext} " ]]; then
|
||||
# mv "$dnlds/$i" /data/media/
|
||||
# fi
|
||||
#done
|
||||
Reference in New Issue
Block a user