DevOps-сниппеты: Docker, Nginx, Git, GitHub Actions
Шестнадцать эксплуатационных сниппетов: многостадийные сборки Docker и контейнеры без root, обратный прокси Nginx с SSL, балансировка и проксирование WebSocket, приёмы Git с rebase, stash и bisect, а также GitHub Actions для CI, деплоя и расписаний.
Всё здесь происходит между «код написан» и «код обслуживает трафик». Четыре инструмента, одна задача: выкатить сборку и удержать её доступной.
Docker: размер образа — это вопрос стадий сборки
Одностадийный образ Node тащит с собой компилятор, dev-зависимости и исходники рядом с тем, что реально запускается. Многостадийная сборка решает это, копируя в чистый рантайм-образ только результат сборки, и разница обычно не маргинальная — это бо́льшая часть образа. Образы поменьше быстрее выкачиваются на каждом деплое и дают меньшую поверхность для сканирования.
Запуск не от root — вторая половина. Контейнеры изолируют слабее виртуальной машины, и процесс, работающий внутри контейнера от root, в конфигурации по умолчанию работает от пользователя, отображаемого в root на хосте. Создание пользователя и переход на него стоят двух строк. Добавление файловой системы только для чтения стоит ещё одной и убирает целый класс закрепления в системе.
Nginx: проксирование простое, WebSocket — исключение
Обратный прокси для HTTP — это четыре директивы. WebSocket требует ещё двух, Upgrade и Connection, потому что без них смены протокола не произойдёт, а проявление сбоя сбивает с толку: рукопожатие возвращает 200 вместо 101, и клиент бесконечно переподключается. Это самый частый вопрос про Nginx у всех, кто добавляет realtime к работающему сайту.
В конфигурации SSL значения по умолчанию важнее всего: генератор конфигураций Mozilla поддерживается в актуальном состоянии, а копирование пятилетнего списка шифров из статьи в блоге — типичный способ не пройти аудит.
Git: три команды для трёх разных ситуаций
Stash — для прерванной работы, к которой вы вернётесь через несколько минут. Интерактивный rebase — для приведения ветки в порядок перед ревью: схлопнуть коммиты «поправил опечатку», чтобы история описывала замысел, а не порядок, в котором мысли приходили в голову. Bisect — для вопроса «когда это сломалось», и он радикально быстрее чтения диффов: находит виновный коммит за считаные шаги независимо от их количества в диапазоне.
GitHub Actions: секреты живут в деплое
Workflow для CI — в основном обвязка. Внимания требует деплой: SSH-ключи место в зашифрованных секретах, а не в репозитории, а workflow по расписанию обязан быть идемпотентным, потому что GitHub не гарантирует точное время запуска и периодически пропускает или задерживает выполнение.
Docker Compose для Node.js + PostgreSQL + Redis
Production-ready docker-compose.yml для Node.js приложения с PostgreSQL и Redis — стандартный стек SaaS-бэкенда.
Как это работает: три сервиса — app (Node.js), db (PostgreSQL 16) и cache (Redis 7) — на общей сети. Приложение ждёт, пока база и кеш станут здоровы, перед запуском. Тома сохраняют данные между перезапусками, .env подгружается автоматически.
services:
app:
build: .
ports:
- "3000:3000"
env_file: .env
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
volumes:
- .:/app
- /app/node_modules
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASS}
POSTGRES_DB: ${DB_NAME}
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
interval: 5s
timeout: 5s
retries: 5
cache:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redisdata:/data
volumes:
pgdata:
redisdata:
# Запустить все сервисы
docker compose up -d
# Смотреть логи приложения
docker compose logs -f app
# Остановить (тома сохраняются)
docker compose down
# Полностью удалить (включая данные)
docker compose down -v
Docker multi-stage сборки для Node.js
Production Dockerfile с multi-stage сборкой — раздельные стадии для зависимостей, сборки и рантайма — минимальный финальный образ.
Как это работает: три стадии. deps устанавливает зависимости, builder компилирует приложение, runner копирует только нужное в минимальный образ. Ни dev-зависимостей, ни исходников — только скомпилированный код и production node_modules.
# Stage 1: Dependencies
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable pnpm && pnpm install --frozen-lockfile
# Stage 2: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN corepack enable pnpm && pnpm build
# Stage 3: Production
FROM node:20-alpine AS runner
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 appuser
COPY --from=builder --chown=appuser:nodejs /app/dist ./dist
COPY --from=builder --chown=appuser:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=appuser:nodejs /app/package.json ./
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
CMD ["node", "dist/index.js"]
docker build -t myapp:latest .
docker images --filter reference=myapp
# Финальный образ ~150MB вместо ~1.2GB
Docker безопасность — non-root пользователь и read-only
Усиление безопасности контейнеров — запуск от непривилегированного пользователя с read-only файловой системой и отключением возможностей ядра.
Как это работает: создание непривилегированного пользователя внутри образа, переключение на него через USER, затем опции безопасности на этапе запуска — --read-only запрещает запись в файловую систему контейнера, --cap-drop=ALL удаляет все возможности ядра, --security-opt=no-new-privileges предотвращает повышение привилегий.
FROM node:20-alpine
RUN addgroup -g 1001 -S appgroup && \
adduser -u 1001 -S appuser -G appgroup
WORKDIR /app
COPY --chown=appuser:appgroup . .
USER appuser
EXPOSE 3000
CMD ["node", "server.js"]
# Запуск с усиленной безопасностью
docker run --rm \
--read-only \
--cap-drop=ALL \
--security-opt=no-new-privileges:true \
--tmpfs /tmp \
-p 3000:3000 \
myapp:latest
# Аналог в docker-compose
# security_opt:
# - no-new-privileges:true
# cap_drop:
# - ALL
# read_only: true
# tmpfs:
# - /tmp
Nginx load balancing между Node.js инстансами
Распределение трафика между несколькими Node.js бэкендами с round-robin, проверками здоровья и пассивным failover — без изменений в приложении.
Как это работает: блок upstream определяет группу бэкенд-серверов. Nginx распределяет запросы по round-robin по умолчанию. Если сервер не отвечает, nginx помечает его недоступным и направляет трафик на оставшиеся.
upstream node_backend {
# Round-robin балансировка (по умолчанию)
server 127.0.0.1:3001;
server 127.0.0.1:3002;
server 127.0.0.1:3003;
# Опционально: наименьшее количество соединений
# least_conn;
# Опционально: привязка по IP
# ip_hash;
# Сервер на обслуживании
# server 127.0.0.1:3004 down;
# Пассивная проверка здоровья
# После 3 ошибок помечать недоступным на 30с
server 127.0.0.1:3005 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://node_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Таймауты
proxy_connect_timeout 5s;
proxy_read_timeout 10s;
proxy_send_timeout 10s;
}
}
# Запуск нескольких Node.js инстансов через PM2
pm2 start server.js -i 3
Nginx reverse proxy с SSL termination
Hardened-конфигурация nginx для проксирования Node.js приложений — SSL termination, rate limiting, заголовки безопасности и gzip.
Как это работает: nginx завершает TLS на границе, перенаправляет запросы на локальный Node.js бэкенд, добавляет заголовки безопасности, ограничение скорости и gzip-сжатие — до того, как запрос дойдёт до приложения.
server {
listen 443 ssl http2;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# Заголовки безопасности
add_header Strict-Transport-Security "max-age=63072000" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Rate limiting
limit_req zone=api burst=20 nodelay;
limit_req_status 429;
# Gzip
gzip on;
gzip_types text/plain text/css application/json application/javascript;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name yourdomain.com;
return 301 https://$host$request_uri;
}
# Проверить конфиг перед перезагрузкой
sudo nginx -t
# Перезагрузить без разрыва соединений
sudo nginx -s reload
Nginx статический сервер с кешированием
Раздача статики (CSS, JS, изображения) с заголовками кеширования на год, gzip-сжатием и SPA-роутингом — без серверного приложения.
Как это работает: nginx отдаёт файлы из /var/www/html напрямую — без прокси. Заголовки кеша указывают браузеру хранить ассеты год; файлы с хешем в имени безопасно кешировать навсегда. Gzip уменьшает объём передачи, try_files включает SPA-роутинг.
server {
listen 80;
server_name example.com;
root /var/www/html;
index index.html;
# Gzip
gzip on;
gzip_types text/plain text/css application/json application/javascript image/svg+xml;
gzip_min_length 256;
# Долгий кеш для версионированных ассетов
location ~* \.(?:css|js|svg|woff2?)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Кеш для изображений на неделю
location ~* \.(?:jpg|jpeg|png|webp|avif)$ {
expires 7d;
add_header Cache-Control "public";
}
# Без кеша для HTML
location ~* \.html?$ {
expires -1;
add_header Cache-Control "no-cache";
}
# SPA fallback
location / {
try_files $uri $uri/ /index.html;
}
# Запрет доступа к скрытым файлам
location ~ /\. {
deny all;
}
}
Nginx WebSocket прокси для real-time приложений
Проксирование WebSocket-соединений через nginx — необходимо для Socket.io, живого чата и совместного редактирования за reverse proxy.
Как это работает: WebSocket-соединения начинаются как HTTP-апгрейд. Заголовки Upgrade и Connection должны явно передаваться. Без этой конфигурации nginx закрывает соединение через 60с. proxy_read_timeout в 1ч держит долгоживущие WebSocket-соединения открытыми.
server {
listen 80;
server_name app.example.com;
location /ws {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
# Заголовки для WebSocket upgrade
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Стандартные proxy-заголовки
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Долгий таймаут для постоянных соединений
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
# Обычный HTTP-трафик
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# Проверка WebSocket-соединения
curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: $(openssl rand -base64 16)" http://app.example.com/ws
Git cherry-pick и bisect — точечная работа с коммитами
Cherry-pick применяет конкретный коммит из любой ветки. Bisect — бинарный поиск по истории для нахождения коммита, внёсшего баг.
Как это работает: cherry-pick берёт diff из одного коммита и применяет к HEAD — без merge и rebase. bisect помечает коммиты как хорошие или плохие, а Git сужает круг до точного коммита, где всё сломалось — обычно за меньше чем 10 шагов даже для тысяч коммитов.
# Применить один коммит
git cherry-pick a1b2c3d
# Применить без авто-коммита
git cherry-pick --no-commit a1b2c3d
# Применить диапазон коммитов
git cherry-pick a1b2c3d..e5f6g7h
# Cherry-pick из другой ветки
git checkout main
git cherry-pick feature-branch~3..feature-branch
# Начать bisect
git bisect start
git bisect bad # текущий коммит сломан
git bisect good v2.0.0 # последний известный рабочий
# Git переключается на середину — тестируем:
git bisect good # или git bisect bad
# Повторяем, пока Git не найдёт первый плохой коммит
# Завершить bisect
git bisect reset
# Посмотреть изменения в коммите
git show a1b2c3d
Git log — фильтрация и форматирование истории
Поиск, фильтрация и форматирование Git-лога — находите коммиты по автору, дате, файлу или содержимому одной строкой.
Как это работает: git log принимает десятки флагов фильтрации. Комбинируйте их, чтобы найти нужные коммиты — кто, когда и зачем изменил файл — без пролистывания нерелевантной истории.
# Одна строка на коммит
git log --oneline
# Граф с ветками
git log --oneline --graph --all
# Коммиты по автору
git log --author="Alex"
# Коммиты после даты
git log --since="2026-06-01"
git log --after="2 weeks ago"
# Коммиты, изменившие файл
git log --oneline -- src/server.ts
# Поиск по сообщению
git log --grep="fix:" --oneline
# Поиск по коду
git log -S "calculateTotal" --oneline
# Коммиты в диапазоне дат
git log --since="2026-06-01" --until="2026-07-01"
# Кастомный формат
git log --pretty=format:"%h %an %ar %s"
# Статистика изменений
git log --stat --oneline
# Последние 5 коммитов
git log -5 --oneline
# Коммиты в ветке, которых нет в main
git log main..feature --oneline
Git squash коммитов и интерактивный rebase
Очистка Git-истории с помощью squash, fixup и интерактивного rebase — читаемый лог коммитов перед мержем.
Как это работает: интерактивный rebase (git rebase -i) открывает редактор, где можно склеить (squash), объединить без сообщения (fixup), переименовать или переупорядочить коммиты. Squash объединяет коммит с предыдущим и позволяет отредактировать сообщение; fixup делает то же самое, но сообщение отбрасывает — идеально для коммитов вида "fix typo" и "wip".
# Склеить последние 3 коммита в один
git rebase -i HEAD~3
# Редактор покажет:
# pick a1b2c3d Add login page
# pick e4f5g6h Fix typo on login page
# pick i7j8k9l Add tests for login
# Меняем на:
# pick a1b2c3d Add login page
# squash e4f5g6h Fix typo on login page
# fixup i7j8k9l Add tests for login
# Сохраняем и закрываем → один чистый коммит
# Склеить все коммиты фича-ветки в один
git checkout feature/my-feature
git rebase -i main
# Пометить все коммиты кроме первого как "squash"
# или однострочник:
git reset --soft main
git commit -m "feat: add my feature"
# Исправить последний коммит (если ещё не запушен)
git add . && git commit --amend --no-edit
# Force push после rebase (только в feature-ветках!)
git push --force-with-lease
Git stash — сохранение и восстановление черновиков
Временно сохраните незакоммиченные изменения через git stash — переключайте ветки, подтягивайте обновления и восстанавливайте работу без потерь.
Как это работает: git stash берёт все отслеживаемые, но незакоммиченные изменения и помещает их в стек. Рабочая директория становится чистой — можно переключать ветки. git stash pop восстанавливает последний stash и удаляет его из стека.
# Сохранить текущие изменения (только отслеживаемые)
git stash
# Сохранить включая новые файлы
git stash -u
# Сохранить с описанием
git stash push -m "WIP: рефакторинг auth middleware"
# Посмотреть все сохранения
git stash list
# stash@{0}: On feature/login: WIP: рефакторинг auth middleware
# stash@{1}: WIP: правки шапки
# Восстановить последний stash
git stash pop
# Восстановить конкретный stash
git stash pop stash@{1}
# Применить stash без удаления из стека
git stash apply stash@{0}
# Создать ветку из stash (решает конфликты)
git stash branch feature/new-branch stash@{0}
# Удалить конкретный stash
git stash drop stash@{1}
# Очистить все stash
git stash clear
GitHub Actions — CI пайплайн для PR
Запуск линтинга, type-check и тестов на каждый pull request до мержа — быстрый отказ с понятными аннотациями в PR.
Как это работает: триггер на pull_request в main — настраивает Node.js, устанавливает зависимости с кешированием, параллельно запускает lint, type-check и тесты, затем загружает результаты как аннотации в PR.
name: CI
on:
pull_request:
branches: [main]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run lint
- run: npm run typecheck
- run: npm test -- --coverage
- uses: dorny/paths-filter@v3
id: changes
with:
filters: |
src:
- 'src/**'
- name: Upload coverage
if: steps.changes.outputs.src == 'true'
uses: codecov/codecov-action@v4
# Требуемые настройки защиты ветки:
# Включить проверку статуса "quality" перед мержем
GitHub Actions — деплой Node.js на VPS через SSH
CI/CD пайплайн, который линтит, тестирует, собирает и деплоит Node.js приложение на VPS через SSH с zero-downtime.
Как это работает: при каждом пуше в main воркфлоу забирает код, устанавливает зависимости, запускает линтинг и тесты, собирает проект, синхронизирует сборку на VPS через rsync по SSH и выполняет zero-downtime перезагрузку через PM2.
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm run build
- name: Deploy via rsync
uses: easingthemes/ssh-deploy@v4
with:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
REMOTE_USER: ${{ secrets.REMOTE_USER }}
SOURCE: .output/
TARGET: /var/www/app/
ARGS: -rlpDzvc --delete
- name: Reload app
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.REMOTE_HOST }}
username: ${{ secrets.REMOTE_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/app
pm2 reload ecosystem.config.js
# Необходимые секреты для воркфлоу:
# SSH_PRIVATE_KEY — ключ деплоя
# REMOTE_HOST — IP или домен VPS
# REMOTE_USER — SSH пользователь
GitHub Actions — сборка и публикация Docker образа
Автоматическая сборка и публикация Docker образа в Docker Hub или GitHub Container Registry на каждый push в main — с кешированием слоёв.
Как это работает: при пуше в main воркфлоу логинится в registry, настраивает Docker Buildx для multi-platform сборок, использует GitHub Actions кеш для слоёв, собирает образ с версионными тегами и публикует. Для PR образ собирается без публикации.
name: Docker Build & Push
on:
push:
branches: [main]
tags: ['v*']
pull_request:
branches: [main]
jobs:
docker:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=semver,pattern={{version}}
type=ref,event=branch
type=sha,format=short
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
GitHub Actions — запланированные задачи по cron
Запуск воркфлоу по расписанию — ежедневные бэкапы, еженедельные обновления зависимостей, почасовые проверки здоровья — через cron-синтаксис.
Как это работает: событие schedule использует POSIX cron-синтаксис. Воркфлоу запускается в заданные интервалы независимо от пушей. workflow_dispatch позволяет запустить вручную для тестирования.
name: Daily Backup
on:
schedule:
# Каждый день в 2:00 UTC
- cron: '0 2 * * *'
workflow_dispatch:
jobs:
backup:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Create database dump
run: |
pg_dump $DATABASE_URL > backup_$(date +%Y-%m-%d).sql
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
- name: Upload to S3-compatible storage
uses: jakejarvis/s3-sync-action@v1
with:
args: --acl private
env:
AWS_S3_BUCKET: ${{ secrets.AWS_BACKUP_BUCKET }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
SOURCE_DIR: .
# Часто используемые расписания:
# Каждый час: 0 * * * *
# Ежедневно в полночь: 0 0 * * *
# Еженедельно в понед: 0 0 * * 1
# Ежемесячно 1-го: 0 0 1 * *
# Каждые 15 минут: */15 * * * *
yt-dlp — полезные Bash-функции для видео, аудио и субтитров
Набор функций для .bashrc / .zshrc для быстрой загрузки видео (до 1080p), экспорта в MP3, очистки субтитров от таймкодов и сохранения превью.
Готовый набор функций для добавления в ваш ~/.bashrc или ~/.zshrc. Использует куки Firefox, Node.js runtime и обходит типичные ограничения скачивания через yt-dlp.
Описание функций и мнемоника для запоминания:
Префикс dlp легко запоминается как DownLoad Please («Скачай, пожалуйста») или сокращение от yt-dlp, а суффикс указывает на нужный формат:
dlpv URL— DownLoad Please Video — скачивание видео в качестве до 1080p (MP4 + M4A).dlpa URL— DownLoad Please Audio — извлечение и конвертация аудио в MP3.dlps URL— DownLoad Please Subtitles — загрузка только чистых субтитров без видео.dlpvs URL— DownLoad Please Video + Subtitles — скачивание видео с очищенными англоязычными субтитрами.dlpvt URL— DownLoad Please Video + Thumbnail — скачивание видео вместе с обложкой.
# video
dlpv() {
yt-dlp --cookies-from-browser Firefox --js-runtime node --remote-components ejs:github -f "bestvideo[height<=1080][ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best" "$1"
}
# audio
dlpa() {
yt-dlp --cookies-from-browser Firefox --js-runtime node --remote-components ejs:github -x --audio-format mp3 -o "%(title)s [%(id)s].%(ext)s" "$1"
}
# video & subtitles
dlpvs() {
yt-dlp --cookies-from-browser Firefox --js-runtime node --remote-components ejs:github --write-subs --write-auto-subs --sub-lang en --sub-format ttml --convert-subs txt --exec before_dl:"sed -e '/^[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9] --> [0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9]$/d' -e '/^[[:digit:]]\{1,3\}$/d' -e 's/<[^>]*>//g' -e '/^[[:space:]]*$/d' -i '' %(requested_subtitles.:.filepath)#q" -f "bestvideo[height<=1080][ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best" "$1"
}
# subtitles
dlps() {
yt-dlp --cookies-from-browser Firefox --js-runtime node --remote-components ejs:github --skip-download --write-subs --write-auto-subs --sub-lang en --sub-format ttml --convert-subs txt --exec before_dl:"sed -e '/^[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9] --> [0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9]$/d' -e '/^[[:digit:]]\{1,3\}$/d' -e 's/<[^>]*>//g' -e '/^[[:space:]]*$/d' -i '' %(requested_subtitles.:.filepath)#q" "$1"
}
# video & thumbnail
dlpvt() {
yt-dlp --cookies-from-browser Firefox --js-runtime node --remote-components ejs:github --write-thumbnail -f "bestvideo[height<=1080][ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best" "$1"
}
Другие подборки сниппетов
Контактная информация
Оставьте заявку или напишите напрямую в телеграм. Я отвечу в течение 24 часов.