This commit is contained in:
2025-08-14 13:19:19 +00:00
parent 86034c8e12
commit bb64b2dde4
3 changed files with 278 additions and 14 deletions

271
WEBTORRENT_PLAYER.md Normal file
View File

@@ -0,0 +1,271 @@
# 🎬 NeoMovies WebTorrent Player
Современный плеер для просмотра торрент файлов прямо в браузере с умной интеграцией TMDB.
## 🚀 Особенности
-**Полностью клиентский** - все торренты обрабатываются в браузере
-**Умная навигация** - автоматическое определение сезонов и серий
-**TMDB интеграция** - красивые названия серий вместо имен файлов
-**Мультиформат** - поддержка MP4, AVI, MKV, WebM и других
-**Потоковое воспроизведение** - начинает играть до полной загрузки
-**Прогресс загрузки** - отображение скорости и процента загрузки
## 📋 API Endpoints
### Открытие плеера
```http
GET /api/v1/webtorrent/player?magnet={MAGNET_LINK}
```
или через заголовок:
```http
GET /api/v1/webtorrent/player
X-Magnet-Link: {MAGNET_LINK}
```
### Получение метаданных
```http
GET /api/v1/webtorrent/metadata?query={SEARCH_QUERY}
```
## 💻 Примеры использования
### 1. Простое открытие плеера
```javascript
const magnetLink = "magnet:?xt=urn:btih:...";
const encodedMagnet = encodeURIComponent(magnetLink);
window.open(`/api/v1/webtorrent/player?magnet=${encodedMagnet}`);
```
### 2. Открытие через заголовок
```javascript
fetch('/api/v1/webtorrent/player', {
headers: {
'X-Magnet-Link': magnetLink
}
}).then(response => {
// Открыть в новом окне
window.open(URL.createObjectURL(response.blob()));
});
```
### 3. Получение метаданных
```javascript
fetch('/api/v1/webtorrent/metadata?query=Breaking Bad')
.then(response => response.json())
.then(data => {
if (data.success) {
console.log('Метаданные:', data.data);
// data.data содержит информацию о сериале/фильме
}
});
```
## 🎮 Управление плеером
### Клавиши управления
- **Space** - пауза/воспроизведение
- **Click** - выбор серии/файла
### UI элементы
- **Информация о медиа** - название, год, описание (верхний левый угол)
- **Список файлов** - выбор серий/частей (нижняя панель)
- **Информация о серии** - название и описание текущей серии
- **Прогресс загрузки** - скорость и процент загрузки
## 🔧 Как это работает
### 1. Загрузка торрента
```mermaid
graph LR
A[Magnet Link] --> B[WebTorrent Client]
B --> C[Parse Metadata]
C --> D[Filter Video Files]
D --> E[Display File List]
```
### 2. Получение метаданных
```mermaid
graph LR
A[Torrent Name] --> B[Extract Title]
B --> C[Search TMDB]
C --> D[Get Movie/TV Data]
D --> E[Get Seasons/Episodes]
E --> F[Display Smart Names]
```
### 3. Воспроизведение
```mermaid
graph LR
A[Select File] --> B[Stream from Torrent]
B --> C[Render to Video Element]
C --> D[Show Progress]
```
## 📊 Структура ответа метаданных
### Для фильмов
```json
{
"success": true,
"data": {
"id": 155,
"title": "Тёмный рыцарь",
"type": "movie",
"year": 2008,
"posterPath": "https://image.tmdb.org/t/p/w500/...",
"backdropPath": "https://image.tmdb.org/t/p/w500/...",
"overview": "Описание фильма...",
"runtime": 152,
"genres": [
{"id": 28, "name": "боевик"},
{"id": 80, "name": "криминал"}
]
}
}
```
### Для сериалов
```json
{
"success": true,
"data": {
"id": 1396,
"title": "Во все тяжкие",
"type": "tv",
"year": 2008,
"posterPath": "https://image.tmdb.org/t/p/w500/...",
"overview": "Описание сериала...",
"seasons": [
{
"seasonNumber": 1,
"name": "Сезон 1",
"episodes": [
{
"episodeNumber": 1,
"seasonNumber": 1,
"name": "Пилот",
"overview": "Описание серии...",
"runtime": 58
}
]
}
],
"episodes": [
{
"episodeNumber": 1,
"seasonNumber": 1,
"name": "Пилот",
"overview": "Описание серии..."
}
]
}
}
```
## 🛡️ Безопасность
### ⚠️ ВАЖНО: Клиентский подход
- Торренты обрабатываются **ТОЛЬКО в браузере пользователя**
- Сервер **НЕ ЗАГРУЖАЕТ** и **НЕ ХРАНИТ** торрент файлы
- API используется только для получения метаданных из TMDB
- Полное соответствие законодательству - сервер не участвует в торрент активности
### 🔒 Приватность
- Никакая торрент активность не логируется на сервере
- Магнет ссылки не сохраняются в базе данных
- Пользовательские данные защищены стандартными методами API
## 🌟 Умные функции
### Автоматическое определение серий
Плеер автоматически распознает:
- **S01E01** - формат сезон/серия
- **Breaking.Bad.S01E01** - название с сезоном
- **Game.of.Thrones.1x01** - альтернативный формат
### Красивые названия
Вместо:
```
Breaking.Bad.S01E01.720p.BluRay.x264-DEMAND.mkv
```
Показывает:
```
S1E1: Пилот
```
### Информация о сериях
- Название серии из TMDB
- Описание эпизода
- Продолжительность
- Изображения (постеры)
## 🎯 Примеры интеграции
### React компонент
```jsx
function WebTorrentPlayer({ magnetLink }) {
const openPlayer = () => {
const url = `/api/v1/webtorrent/player?magnet=${encodeURIComponent(magnetLink)}`;
window.open(url, '_blank', 'fullscreen=yes');
};
return (
<button onClick={openPlayer} className="play-button">
🎬 Смотреть в WebTorrent
</button>
);
}
```
### Получение метаданных перед открытием
```javascript
async function openWithMetadata(magnetLink, searchQuery) {
try {
// Получаем метаданные
const metaResponse = await fetch(`/api/v1/webtorrent/metadata?query=${encodeURIComponent(searchQuery)}`);
const metadata = await metaResponse.json();
if (metadata.success) {
console.log('Найдено:', metadata.data.title, metadata.data.type);
}
// Открываем плеер
const playerUrl = `/api/v1/webtorrent/player?magnet=${encodeURIComponent(magnetLink)}`;
window.open(playerUrl, '_blank');
} catch (error) {
console.error('Ошибка:', error);
}
}
```
## 🔧 Технические детали
### Поддерживаемые форматы
- **Видео**: MP4, AVI, MKV, MOV, WMV, FLV, WebM, M4V
- **Кодеки**: H.264, H.265/HEVC, VP8, VP9
- **Аудио**: AAC, MP3, AC3, DTS
### Требования браузера
- Современные браузеры с поддержкой WebRTC
- Chrome/Edge 45+, Firefox 42+, Safari 11+
- Поддержка WebTorrent API
### Производительность
- Потоковое воспроизведение с первых секунд
- Умное кэширование наиболее просматриваемых частей
- Адаптивная буферизация в зависимости от скорости
## 🚦 Статусы ответов
| Код | Описание |
|-----|----------|
| 200 | Успешно - плеер загружен или метаданные найдены |
| 400 | Отсутствует magnet ссылка или query параметр |
| 404 | Метаданные не найдены в TMDB |
| 500 | Внутренняя ошибка сервера |
---
**🎬 NeoMovies WebTorrent Player** - современное решение для просмотра торрентов с соблюдением всех требований безопасности и законности! 🚀

BIN
neomovies-api Executable file

Binary file not shown.

View File

@@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
"net/http"
"os"
"strings"
"github.com/MarceloPetrucio/go-scalar-api-reference"
@@ -25,9 +24,10 @@ func (h *DocsHandler) RedirectToDocs(w http.ResponseWriter, r *http.Request) {
}
func (h *DocsHandler) GetOpenAPISpec(w http.ResponseWriter, r *http.Request) {
baseURL := determineBaseURL(r)
_ = determineBaseURL(r)
spec := getOpenAPISpecWithURL(baseURL)
// Use relative server URL to inherit correct scheme/host from the browser/proxy
spec := getOpenAPISpecWithURL("/")
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*")
@@ -37,10 +37,11 @@ func (h *DocsHandler) GetOpenAPISpec(w http.ResponseWriter, r *http.Request) {
}
func (h *DocsHandler) ServeDocs(w http.ResponseWriter, r *http.Request) {
baseURL := determineBaseURL(r)
_ = determineBaseURL(r)
// Use relative SpecURL so the browser automatically uses the current origin and protocol
htmlContent, err := scalar.ApiReferenceHTML(&scalar.Options{
SpecURL: fmt.Sprintf("%s/openapi.json", baseURL),
SpecURL: "/openapi.json",
CustomOptions: scalar.CustomOptions{
PageTitle: "Neo Movies API Documentation",
},
@@ -59,15 +60,10 @@ func (h *DocsHandler) ServeDocs(w http.ResponseWriter, r *http.Request) {
}
func determineBaseURL(r *http.Request) string {
if envBase := os.Getenv("BASE_URL"); envBase != "" {
return envBase
}
// Defaults
// Prefer proxy headers and request info over environment to avoid wrong scheme on platforms like Vercel
proto := ""
host := r.Host
// RFC 7239 Forwarded header: e.g. "for=1.2.3.4; proto=https; host=example.com"
if fwd := r.Header.Get("Forwarded"); fwd != "" {
for _, part := range strings.Split(fwd, ";") {
kv := strings.SplitN(strings.TrimSpace(part), "=", 2)
@@ -89,7 +85,6 @@ func determineBaseURL(r *http.Request) string {
}
}
// Fallback to X-Forwarded-* headers
if proto == "" {
if p := r.Header.Get("X-Forwarded-Proto"); p != "" {
proto = strings.ToLower(strings.TrimSpace(strings.Split(p, ",")[0]))
@@ -99,7 +94,6 @@ func determineBaseURL(r *http.Request) string {
host = strings.TrimSpace(strings.Split(xfh, ",")[0])
}
// Last resort: infer from TLS
if proto == "" {
if r.TLS != nil {
proto = "https"
@@ -108,7 +102,6 @@ func determineBaseURL(r *http.Request) string {
}
}
// Respect X-Forwarded-Port if host has no explicit port and it is non-default
if xfp := r.Header.Get("X-Forwarded-Port"); xfp != "" && !strings.Contains(host, ":") {
isDefault := (proto == "http" && xfp == "80") || (proto == "https" && xfp == "443")
if !isDefault {