Задать вопрос
  • Стоит ли использовать файловый сервер в проекте?

    @rPman
    Чем больше зависимостей, тем сложнее поддержка в будущем.

    Для крупных проектов (в смысле пользовательской базы) отказоустойчивость (готовые решения, поддержка от разработчиков компонентов) может оказаться предпочтительнее своих велосипедов.

    Для мелких проектов (когда пользователей обслужить может один человек он же разработчик), выносить такую простую задачу в отдельную компоненту - это оверинженеринг, лишняя работа и проблемы.

    Я настоятельно рекомендую не городить лишних сущностей и хранить файлы на том же веб сервере как статические. Если нужны ограничения доступа, то используй штатные инструменты авторизации веб сервера либо свой велосипед. Это 10-15 строк кода, например файлы изначально хранятся в не опубликованном каталоге, а при предоставлении доступа к файлу в публичном создается симлинк, в имени которого id сессии (например id_сессии/id_файла причем если доступ сразу ко всем файлам, то достаточно линка на каталог по id_сессии), а при отзыве доступа, удаляются все симлинки с указанным id сессии.

    Бонусом получаешь максимально ресурсоэффективный способ хранения и публикации файлов, минусом наверное только свой uploader писать (в наше время начинающие разработчики просто обязаны пройти через написание своих велосипедов типа upload файла, обслуживание очереди задач по времени и т.п. иначе такое городят, смотреть на этот кошмар невозможно)
    Ответ написан
    5 комментариев
  • Как исправить игнорирование кода при импорте в python?

    @dim5x
    ЗИ, ИБ. Помогли? Поблагодарите. Отметьте ответом.
    Используйте коги: https://discordpy.readthedocs.io/en/stable/ext/com...

    main.py:
    import discord
    from discord.ext import commands
    
    intents = discord.Intents.default()
    intents.message_content = True
    
    bot = commands.Bot(command_prefix="!", intents=intents)
    
    async def load_extensions():
        await bot.load_extension("ticket")  # Загружаем Cog без .py
    
    @bot.event
    async def on_ready():
        print(f"Бот {bot.user} готов!")
        await load_extensions()
    
    bot.run("***")


    ticket.py:
    from discord.ext import commands
    
    class TicketsCog(commands.Cog):
        def __init__(self, bot):
            self.bot = bot
    
        @commands.command(name="systicket")
        async def systicket(self, ctx):
            """Обработка команды !systicket"""
            # логика команды
            await ctx.send("Система тикетов работает!")  # Пример ответа
    
    async def setup(bot):
        await bot.add_cog(TicketsCog(bot))  # Важно: await и новое API discord.py 2.0+
    Ответ написан
    Комментировать
  • Почему так долго распаковывается архив весом всего 36мб?

    15432
    @15432
    Системный программист ^_^
    На каждый распаковываемый файл система должна завести новую запись в файловой системе. В результате жесткий диск вынужден мотать головкой чтения/записи туда-сюда на каждый мелкий файл, из-за чего очень сильно падает скорость. Если вы хоть раз копировали 10000 файлов в папке на медленную USB флешку, вы должны были заметить, что много мелких файлов копируются в сотни раз медленнее, чем один большой
    Ответ написан
    4 комментария
  • Как создать кнопки в ТГ боте Golang (telegram-bot-api)?

    memrook
    @memrook
    Пример есть в репозитории telegram-bot-api

    package main
    
    import (
    	"log"
    	"os"
    
    	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
    )
    
    var numericKeyboard = tgbotapi.NewInlineKeyboardMarkup(
    	tgbotapi.NewInlineKeyboardRow(
    		tgbotapi.NewInlineKeyboardButtonURL("1.com", "http://1.com"),
    		tgbotapi.NewInlineKeyboardButtonData("2", "2"),
    		tgbotapi.NewInlineKeyboardButtonData("3", "3"),
    	),
    	tgbotapi.NewInlineKeyboardRow(
    		tgbotapi.NewInlineKeyboardButtonData("4", "4"),
    		tgbotapi.NewInlineKeyboardButtonData("5", "5"),
    		tgbotapi.NewInlineKeyboardButtonData("6", "6"),
    	),
    )
    
    func main() {
    	bot, err := tgbotapi.NewBotAPI(os.Getenv("TELEGRAM_APITOKEN"))
    	if err != nil {
    		log.Panic(err)
    	}
    
    	bot.Debug = true
    
    	log.Printf("Authorized on account %s", bot.Self.UserName)
    
    	u := tgbotapi.NewUpdate(0)
    	u.Timeout = 60
    
    	updates := bot.GetUpdatesChan(u)
    
    	// Loop through each update.
    	for update := range updates {
    		// Check if we've gotten a message update.
    		if update.Message != nil {
    			// Construct a new message from the given chat ID and containing
    			// the text that we received.
    			msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text)
    
    			// If the message was open, add a copy of our numeric keyboard.
    			switch update.Message.Text {
    			case "open":
    				msg.ReplyMarkup = numericKeyboard
    
    			}
    
    			// Send the message.
    			if _, err = bot.Send(msg); err != nil {
    				panic(err)
    			}
    		} else if update.CallbackQuery != nil {
    			// Respond to the callback query, telling Telegram to show the user
    			// a message with the data received.
    			callback := tgbotapi.NewCallback(update.CallbackQuery.ID, update.CallbackQuery.Data)
    			if _, err := bot.Request(callback); err != nil {
    				panic(err)
    			}
    
    			// And finally, send a message containing the data received.
    			msg := tgbotapi.NewMessage(update.CallbackQuery.Message.Chat.ID, update.CallbackQuery.Data)
    			if _, err := bot.Send(msg); err != nil {
    				panic(err)
    			}
    		}
    	}
    }
    Ответ написан
    Комментировать
  • Как получить бессрочный VK API токен для управления аккаунтом?

    opium
    @opium
    Просто люблю качественно работать
    Получи токен старым способом от аккаунта через скрипты на том же гитхабе их же полно было
    Ответ написан
    3 комментария
  • Как вывести крайние диалоги пользователей?

    kawabanga
    @kawabanga
    В общем ключе вот так -
    SELECT * FROM
    (SELECT max(id) as maxId, from_id 
    GROUP BY from_id
    WHERE from_id in (1,2,3)
    ORDER BY maxId desc
    ) as t1
    INNER JOIN messages m on t1.maxId = m.id


    ЧатГПТ Laravel далее код сгенерировал, выглядит корректно. Заметьте, что первую часть запроса в любом случае выполнять через Query Builder, но можно вывести ее в получение конкретных id последних сообщений. И дальше двумя, можно отдельными запросами уже через модель - получить данные по сообщениям и пользователям. Они будут работать по первичным ключам и срабатывать моментально.
    А можно просто добавить жадную загрузку по связи Users на втором запросе, что в целом облегчит вам задачу и не нужно будет связывать далее сообщение и его автора.
    // Подзапрос для получения maxId и from_id
    $subQuery = (new Query())
        ->select(['maxId' => 'MAX(id)', 'from_id'])
        ->from('messages')
        ->where(['from_id' => [1, 2, 3]])
        ->groupBy('from_id')
        ->orderBy(['maxId' => SORT_DESC]);
    
    // Основной запрос с INNER JOIN
    $query = (new Query())
        ->select('*')
        ->from(['t1' => $subQuery])
        ->innerJoin('messages m', 't1.maxId = m.id');
    
    // Выполнение запроса
    $results = $query->all();
    Ответ написан
    Комментировать
  • Долгая обработка SQL запроса?

    Lord_of_Rings
    @Lord_of_Rings Куратор тега Python
    Дунадан - северный странник. Злой, но очень добрый
    Можно использовать подзапрос вместо двух запросов и цикла, если я не ошибаюсь
    cur.execute('''DELETE FROM parsing
                   WHERE parsing_user_id IN (SELECT user_full_data_user_id FROM user_full_data)''')
    Ну и, конечно, sqlite - это не для таких БД

    P. S. Можно ещё индексы сделать к столбцам
    CREATE INDEX idx_user_full_data_user_id ON user_full_data(user_full_data_user_id);
    CREATE INDEX idx_parsing_user_id ON parsing(parsing_user_id);
    Ответ написан
    1 комментарий
  • Почему в параметр функции идёт только последний индекс?

    Vindicar
    @Vindicar
    RTFM!
    Поздравляю, ты попался на лямбду.
    Лямбды сохраняют ссылки на переменные, а не их значения.
    lambda _: set_default_microphone(index) сохранит ссылку на index, а потому все лямбды будут видеть одно и то же значение index, которое было установлено последним.
    Это можно обойти, сохранив ссылку при объявлении лямбды. Самый простой способ - засунуть сохраняемое значение в значение по умолчанию для неиспользуемого параметра. Значения по умолчанию для параметров вычисляются один раз при объявлении функции, в т.ч. лямбды.
    Например, так:
    lambda _, *, ind=index: set_default_microphone(ind)

    Ну или даже так:
    lambda _, *, index=index: set_default_microphone(index)
    Ответ написан
    2 комментария
  • Как избежать зависание textarea при обработке большого массива?

    @historydev Куратор тега JavaScript
    long long long long long .... int
    <input type="text" id="textarea">

    // Код воркера в виде строки
    const workerCode = `
      self.onmessage = (event) => {
        const largeArray = event.data;
        
        // Выполнение тяжелой обработки массива
        for (let i = 0; i < largeArray.length; i++) {
          // Например: largeArray[i] = someProcessing(largeArray[i]);
          largeArray[i] *= 2; // Пример обработки: удваиваем каждый элемент
        }
    
        // Отправка обработанных данных обратно в главный поток
        self.postMessage(largeArray);
      };
    `;
    
    // Создание Blob из строки с кодом воркера
    const blob = new Blob([workerCode], { type: 'application/javascript' });
    // Создание объекта Worker из URL на Blob
    const worker = new Worker(URL.createObjectURL(blob));
    
    // Обработка сообщений от воркера
    worker.onmessage = (event) => {
      const processedArray = event.data;
      console.log('Обработанный массив:', processedArray);
      // Можно обновить интерфейс или использовать данные
    };
    
    // Пример массива для обработки
    const largeArray = new Array(1e6).fill(15);
    
    function debounce(func, delay) {
      let timeout;
      return function(...args) {
          clearTimeout(timeout);
          timeout = setTimeout(() => func.apply(this, args), delay);
      };
    }
    
    const handleInput = debounce(() => {
      worker.postMessage(largeArray);
    }, 300); // Вызываем через 300 мс после окончания ввода
    
    // Пример добавления обработчика для textarea
    textarea.addEventListener('input', (event) => {
      console.log(event.target.value);
      handleInput();
    });
    Ответ написан
    1 комментарий
  • Что пытается сделать злоумышленник на моем сайте?

    На первом скрине, похоже, атака через "Stacked Queries". Хацкер надеется, что вы не отфильтровали входящие данные.

    Допустим у вас из бройзера приходит ID товара. И в программе запрос:

    SELECT * FROM products WHERE productid={нефильтрованный ID};


    Хакер отправляет вместо ID товара следующее:

    1; SELECT pg_sleep(25)


    В результате получится запрос:

    SELECT * FROM products WHERE productid=1; SELECT pg_sleep(25);


    И ваш сервер при каждом таком запросе будет спать 25 секунд. И порядочное количество таких запросов в случае удачи атаки смогут повесить вам там всё.

    То, что он продолжает долбиться, ничего не значит. Он, наверняка, использует какого-то бота, где накиданы в кучу различные векторы атаки, и они все применяются, пока ваш сервер не упадёт в результате срабатывания какой-то из них.
    Ответ написан
    Комментировать
  • Клики по динамически созданным кнопкам в форме ajax?

    ThunderCat
    @ThunderCat Куратор тега PHP
    {PHP, MySql, HTML, JS, CSS} developer
    делегирование.
    +$(".form-submit").on("click", ".product__add", function () {
    -$(".product__add").on("click", function () {
    Ответ написан
    Комментировать
  • Как ускорить загрузку js?

    delphinpro
    @delphinpro Куратор тега JavaScript
    frontend developer
    window.addEventListener('DOMContentLoaded', function() {
        let game = localStorage.getItem('game');
        document.getElementById('game').innerHTML = game;
    });
    Ответ написан
    7 комментариев
  • Почему не работает pattern на input?

    Elaryks
    @Elaryks
    Проверка с помощью атрибута pattern срабатывает непосредственно перед отправкой формы. Кроме того, это не запретит ввод символов, отличных от цифр, а лишь покажет уведомление в случае несоответствия. Вашу же задачу можно решить несколькими способами.
    Первый вариант: <input type="number" />. Из особенностей: он допускает ввод некоторых символов, отличающихся от цифр (например, "+" и "e").
    Второй вариант: перехватывать событие onChange у поля ввода:
    const [value, setValue] = useState('')
    
    const handleInputChange = (e) => {
      setValue(e.target.value.replace(/\D/g, ''))
    }
    
    <input value={value} onChange={handleInputChange} />
    Ответ написан
    Комментировать
  • Как отправить разные изображения для сообщений с одинаковым содержанием в Telebot?

    Vindicar
    @Vindicar
    RTFM!
    Тебе нужен автомат состояний (finite state machine, FSM). Не знаю, есть ли его реализация в комплекте с telebot, но идея простая: нужно помнить, что пользователь делал раньше, т.е. иметь хранилище ключ-значение вида "id пользователя -> состояние+доп. инфа". В простейшем варианте хватит и словаря (если тебе не критично, чтобы сведения переживали перезагрузку бота).
    Ответ написан
    Комментировать
  • Как на сайте отобразить MJPG поток, который требует digest авторизации?

    Anastasia2306
    @Anastasia2306
    PHP-разработчик.
    Это не будет работать в таком виде, потому что это на уровне браузера стоит защита от таких вот конструкций. Вы правильно указали, что без PHP тут не обойтись. Я бы как-то решила этот вопрос:

    <?php
    $url = 'http://192.168.1.8/cgi-bin/mjpg/video.cgi?channel=1&subtype=1';
    
    // Функция для digest-авторизации
    function digest_parse($txt)
    {
        $needed_parts = array('nonce'=>1, 'realm'=>1, 'qop'=>1);
        $data = array();
        $keys = implode('|', array_keys($needed_parts));
    
        preg_match_all('@('.$keys.')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $txt, $matches, PREG_SET_ORDER);
    
        foreach ($matches as $m) {
            $data[$m[1]] = $m[3] ? $m[3] : $m[4];
            unset($needed_parts[$m[1]]);
        }
    
        return $needed_parts ? false : $data;
    }
    
    // Инициализация cURL
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HEADER, 1);
    
    // получения заголовков www-Authenticate
    $response = curl_exec($ch);
    
    // разбор заголовк а WWW-Authenticate
    if (preg_match('/^WWW-Authenticate: Digest (.*)$/im', $response, $matches)) {
        $digest_parts = digest_parse($matches[1]);
    
        // Создание заголовка Authorization
        // Здесь также надо сгенерить правильный ответ на основе полученных данных и вашего логина и пароля
        // наподобие этого
        $digest_response = ''; // ответ
    
        // Установка опций для cURL с заголовком Authorization
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Digest username="adminka", realm="'.$digest_parts['realm'].'", nonce="'.$digest_parts['nonce'].'", uri="/cgi-bin/mjpg/video.cgi?channel=1&subtype=1", response="'.$digest_response.'", qop='.$digest_parts['qop'].', nc=00000001, cnonce="d41d8cd98f00b204e9800998ecf8427e"'));
    }
    
    // Удаление предыдущих заголовков
    curl_setopt($ch, CURLOPT_HEADER, 0);
    
    // Передача потока клиенту
    curl_exec($ch);
    curl_close($ch);
    ?>


    Ну а потом уже смело в теге img можно сделать так:
    <img src="вашскрипт.php" width="720" height="480">

    Пример с PHP кодом не полный - я лишь натолкнула вас на мысль, как это может работать. Удачи!
    Ответ написан
    1 комментарий
  • Как ограничить количество подключений прокси в Pyrogram?

    Mike_Ro
    @Mike_Ro Куратор тега Python
    Python, JS, WordPress, SEO, Bots, Adversting
    в Pyrogram документации не нашел подобного

    Все верно, Pyrogram не настолько гибкий по прокси, в сравнение с Telethon. Используйте внешний менеджер подключений/проксей и не будите зависеть от конкретной библиотеки, например:
    import asyncio
    from pyrogram import Client
    from pyrogram.errors import PyrogramError
    
    class ProxyManager:
        def __init__(self, app, max_retries=5, retry_delay=1, proxy=None):
            self.app = app
            self.max_retries = max_retries
            self.retry_delay = retry_delay
            self.proxy = proxy
            self.client = None
    
        async def connect(self):
            for attempt in range(1, self.max_retries + 1):
                try:
                    print(f"Connection attempt #{attempt}")
                    self.client = Client(**self.app, proxy=self.proxy)
                    await self.client.start()
                    print("The connection was established successfully.")
    
                except PyrogramError as e:
                    print(f"Connection error: {e}")
                    if attempt == self.max_retries:
                        print("The maximum number of connection attempts has been reached, stop!")
                        break
    
                    await asyncio.sleep(self.retry_delay)
    
        async def disconnect(self):
            if self.client:
                await self.client.stop()
                print("Connection is closed.")
    
    app = {
        'api_id': 'YOUR_API_ID',
        'api_hash': 'YOUR_API_HASH',
        'session_name': 'your_session_name'
    }
    
    proxy = {
        'scheme': 'http',  # or 'socks5'
        'hostname': 'your.proxy.hostname',
        'port': 1080,
        'username': 'user',
        'password': 'password'
    }
    
    # test run
    async def main():
        manager = ProxyManager(app, max_retries=3, retry_delay=2, proxy=proxy)
        await manager.connect()
        await manager.disconnect()
    
    asyncio.run(main())
    Ответ написан
    1 комментарий
  • Ошибка 403 при парсинге сайта?

    Mike_Ro
    @Mike_Ro Куратор тега Python
    Python, JS, WordPress, SEO, Bots, Adversting
    Обнаружил некую защиту "на лоха", а значит request и обычный selenium не справятся, буду использовать selenium + selenium-stealth (пример от сюда) + chrome + socks5 (рабочий, на момент теста):
    import time
    from selenium import webdriver
    from selenium.webdriver.chrome.service import Service
    from selenium.webdriver.chrome.options import Options
    from selenium_stealth import stealth
    
    proxy = '45.132.75.19:23820'
    
    options = Options()
    options.add_argument('--proxy-server=socks5://' + proxy)
    options.add_argument("--disable-blink-features=AutomationControlled")
    options.add_argument("window-size=1920,1080")
    # options.add_argument("--incognito")
    options.add_argument("--disable-extensions")
    options.add_argument("--disable-plugins-discovery")
    options.add_argument("--start-maximized")
    options.add_experimental_option("excludeSwitches", ["enable-automation"])
    options.add_experimental_option('useAutomationExtension', False)
    
    executable_path = './chromedriver-121.0.6167.85.exe'
    
    service = Service(executable_path=executable_path)
    driver = webdriver.Chrome(service=service, options=options)
    
    stealth(driver,
            languages=["en-US", "en"],
            vendor="Google Inc.",
            platform="Win64",
            webgl_vendor="Intel Inc.",
            renderer="Intel Iris OpenGL Engine",
            fix_hairline=True,
            run_on_insecure_origins=True,
            user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.6167.85 Safari/537.36',
            )
    
    try:
        driver.get('https://allegro.pl/kategoria/laptopy-491')
        time.sleep(30)
        print(driver.page_source)
    finally:
        driver.quit()

    Chromedriver качать здесь, он должен совпадать с мажорной версией Вашего Chrome браузера, который будет использовать Selenium.

    65c1e056ad6db620469150.png
    Ответ написан
    Комментировать
  • Как создавать, принимать и обрабатывать socket?

    1. Вебсокеты - это сложновато.
    2. Вебсокеты на PHP - вдвойне сложно. Проблема в том, что PHP задуман как скриптовый язык, т.е. скрипт выполняется заканчивает свою работу. А вебсокет - это постоянное соединение, т.е нам надо, чтобы программа постоянно крутилась в фоне. Вебсокеты можно реализовать на PHP, но, как персонально мне кажется, проще будет выучить Go )) , или же, как в ответе уважаемого Артём , сделать сервер на ноде.
    3. Если ваш чат не такой супер-функциональный, как чат в мессенджерах, то вместо вебсокетов можно обойтись SSE (Server Sent Events). SSE так же требует постоянного соединения, но всё работает через HTTP, и это ну прямо намного проще. Единственный недостаток - это то, что SSE работает только в одну сторону: от сервера в браузер. Т.е. запросы из браузера можно получать обычным POST запросом, а отдавать обратно информацию уже через SSE.

    С SSE есть два пути:
    1. Написать сервер самому, используя какую-то простую библиотеку вроде этой https://github.com/hhxsv5/php-sse
    2. Но я бы сделал ещё проще. Есть такой великолепный проект под названием Mercure https://mercure.rocks
    Это отдельный сервис на Go, задача которого как раз поддерживать SSE соединение и отправлять сообщения в браузеры. Сервис сидит в фоне, а браузеры подписываются на события через EventSource буквально в три строчки, как описано тут https://mercure.rocks/docs/getting-started
    Прелесть этого в том, что для того, чтобы отправить сообщение всем браузерам из кода на PHP, вам надо просто сделать обычный POST запрос на специальный адрес этого сервиса Mercure с телом самого сообщения и его id. Т.е. вам не надо делать никаких долгоживущих процессов на PHP, всё будет работать как раньше.

    Т.е. подытожим:
    - Браузеры пользователей подписываются на события в Mercure
    - Пользователь 1 отправляет текстовое сообщение обычным POST запросом на обычный PHP сайт.
    - PHP сайт получает этот POST запрос, определяет, что его надо отправить Пользователю 2, и отправляет соответствующее сообщение обычным POST запросом в сервис Mercure
    - Mercure отправляет сообщение Пользователю 2 через SSE, на которые он подписан.
    - Сообщение появляется у него на страничке
    Ответ написан
    5 комментариев
  • Как спарсить видео с whatsapp web?

    zkrvndm
    @zkrvndm
    Архитектор решений
    Сначала надо запустить видео, тогда вот эта ссылка заменится на blob и уже его качаешь.
    Ответ написан
    2 комментария
  • Держать громкость на одном уровне без изменения?

    Lastor
    @Lastor
    В чем сила, брат? В ньютонах.
    Главная сложность в том, что для каждого исходника требуются индивидуальные настройки.
    Амплитуда сигнала это одно, а воспринимаемая громкость - совсем другое.
    В индустрии это называют RMC, не понимая порой что это значит.
    Многие понимают RMS как воспринимаемую громкость в то время как это всего лишь среднеквадратичное значение уровня сигнала.
    Ухо (восприятие) работает несколько иначе. Как именно хорошо описано в учебнике Алдошиной
    А порой даже в рамках одного трека параметры требуется автоматизировать.
    В этом случае повезло. Получилось без автоматизации, но это просто случайность.
    Результат

    Я использовал плагины waves:
    Настройки
    Компрессор:
    64c6ff0ce3238046300781.png
    Лимитер:
    64c6ffb7d564f557449810.png
    Ответ написан
    Комментировать