diff --git a/VERSION b/VERSION index 1631f98..d801246 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.26.1 +3.26.2 diff --git a/play-life-backend/main.go b/play-life-backend/main.go index 7e5f427..17e2f5a 100644 --- a/play-life-backend/main.go +++ b/play-life-backend/main.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "compress/gzip" "context" "crypto/rand" "database/sql" @@ -12888,8 +12889,6 @@ func (a *App) extractLinkMetadataHandler(w http.ResponseWriter, r *http.Request) return } - log.Printf("Extracting metadata for URL: %s", req.URL) - // Валидация URL parsedURL, err := url.Parse(req.URL) if err != nil || parsedURL.Scheme == "" || parsedURL.Host == "" { @@ -12925,19 +12924,40 @@ func (a *App) extractLinkMetadataHandler(w http.ResponseWriter, r *http.Request) return } - // Устанавливаем заголовки, имитирующие реальный браузер Chrome - httpReq.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36") + // Устанавливаем заголовки, максимально имитирующие реальный браузер Chrome + // Актуальный User-Agent для Chrome на macOS + httpReq.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36") + + // Accept заголовки для максимальной совместимости httpReq.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7") httpReq.Header.Set("Accept-Language", "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7") - httpReq.Header.Set("Accept-Encoding", "gzip, deflate, br") + httpReq.Header.Set("Accept-Encoding", "gzip, deflate, br, zstd") + + // Заголовки для имитации реального браузера httpReq.Header.Set("Connection", "keep-alive") httpReq.Header.Set("Upgrade-Insecure-Requests", "1") httpReq.Header.Set("Sec-Fetch-Dest", "document") httpReq.Header.Set("Sec-Fetch-Mode", "navigate") httpReq.Header.Set("Sec-Fetch-Site", "none") httpReq.Header.Set("Sec-Fetch-User", "?1") + httpReq.Header.Set("Sec-Ch-Ua", `"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"`) + httpReq.Header.Set("Sec-Ch-Ua-Mobile", "?0") + httpReq.Header.Set("Sec-Ch-Ua-Platform", `"macOS"`) + + // Дополнительные заголовки для лучшей совместимости httpReq.Header.Set("Cache-Control", "max-age=0") httpReq.Header.Set("DNT", "1") + + // Устанавливаем Referer - для некоторых сайтов это важно для обхода защиты + // Используем главную страницу домена как Referer, чтобы имитировать переход с главной + if parsedURL.Host != "" { + referer := fmt.Sprintf("%s://%s/", parsedURL.Scheme, parsedURL.Host) + httpReq.Header.Set("Referer", referer) + } + + // Добавляем небольшую задержку перед запросом для имитации человеческого поведения + // Это может помочь избежать триггера капчи при слишком быстрых запросах + time.Sleep(100 * time.Millisecond) resp, err := client.Do(httpReq) if err != nil { @@ -12947,9 +12967,6 @@ func (a *App) extractLinkMetadataHandler(w http.ResponseWriter, r *http.Request) } defer resp.Body.Close() - // Логируем статус код для отладки - log.Printf("Fetched URL %s, status: %d", req.URL, resp.StatusCode) - // Принимаем успешные статусы (200-299) и некоторые редиректы, которые могут содержать контент if resp.StatusCode < 200 || resp.StatusCode >= 300 { // Для некоторых сайтов можно попробовать прочитать тело даже при не-200 статусе @@ -12960,6 +12977,8 @@ func (a *App) extractLinkMetadataHandler(w http.ResponseWriter, r *http.Request) } // Ограничиваем размер ответа (первые 512KB) + // ВАЖНО: Go's http.Client автоматически декодирует gzip, если заголовок Accept-Encoding установлен + // Но нужно убедиться, что мы читаем декодированные данные limitedReader := io.LimitReader(resp.Body, 512*1024) bodyBytes, err := io.ReadAll(limitedReader) if err != nil { @@ -12968,6 +12987,20 @@ func (a *App) extractLinkMetadataHandler(w http.ResponseWriter, r *http.Request) return } + // Проверяем, является ли это gzip (магические байты: 1f 8b) + // Go's http.Client должен автоматически декодировать gzip, но на всякий случай проверяем + if len(bodyBytes) >= 2 && bodyBytes[0] == 0x1f && bodyBytes[1] == 0x8b { + // Пытаемся декодировать вручную, если автоматическое декодирование не сработало + gzipReader, err := gzip.NewReader(bytes.NewReader(bodyBytes)) + if err == nil { + defer gzipReader.Close() + decompressed, err := io.ReadAll(gzipReader) + if err == nil { + bodyBytes = decompressed + } + } + } + body := string(bodyBytes) metadata := &LinkMetadataResponse{} @@ -13006,6 +13039,15 @@ func (a *App) extractLinkMetadataHandler(w http.ResponseWriter, r *http.Request) titleRe := regexp.MustCompile(`(?i)]*>([^<]+)`) if matches := titleRe.FindStringSubmatch(body); len(matches) > 1 { metadata.Title = strings.TrimSpace(matches[1]) + + // Проверяем, не попали ли мы на страницу капчи + if strings.Contains(strings.ToLower(metadata.Title), "робот") || + strings.Contains(strings.ToLower(metadata.Title), "captcha") || + strings.Contains(strings.ToLower(metadata.Title), "вы не робот") { + metadata.Title = "" + metadata.Image = "" + metadata.Description = "" + } } } diff --git a/play-life-web/package.json b/play-life-web/package.json index 6e74443..8e34f5b 100644 --- a/play-life-web/package.json +++ b/play-life-web/package.json @@ -1,6 +1,6 @@ { "name": "play-life-web", - "version": "3.26.1", + "version": "3.26.2", "type": "module", "scripts": { "dev": "vite",