• Как правильно хостить и проигрывать видео в 2020?

    ValdikSS
    @ValdikSS
    То есть получается, что отдача одним файлом и браузерный декод, вышли намного эффективнее чем то, что мы делали через HLS. ¯\_( ツ)_/¯
    Разумеется.
    HLS для VoD используют в двух случаях:
    1. Если нужно, прямо необходимо, автоматически подстраивать качество видео, не выбирая его руками;
    2. Если нужно шифровать куски видео для каждого клиента индивидуально (DRM).

    В остальных случаях, особого резона использовать HLS/DASH нет, т.к. для воспроизведения в браузере он требует media source и javascript-плеер, а обычное HTML5-видео — нет.

    Мы посмотрели кучу стриминговых сервисов, большая часть из них отдавала все свои стримы в формате m3u8, и никаких проблем при этом люди не испытывали. Соответственно назрела куча вопросов о том, как таки стоит делать и в чем могла быть ошибка и как это исправить на будущее.

    Чтобы понять, в чём могла быть ошибка, нужно хотя бы получить какой-то отладочный вывод, или повторить ошибку.
    Во-первых, стандарта HLS «два»: ранний допускает использование контейнера MPEG-TS (.ts), более поздний добавляет поддержку .mp4. MPEG-TS поддерживается лучше, и проще в использовании и на этапе нарезки.

    У меня однажды были точно такие же симптомы, что у вас. Оказалось, что на домене осталась старая DNS A-запись, указывающая на неработающий IP-адрес уже несуществующего сервера. И всё, на удивление, работало, и работало достаточно стабильно, но периодически поток прерывался с ошибками.

    Сложно делать предположения без отладочных данных.

    1) Как правильно хостить файлы на сервере? Нужна ли разбивка при помощи HLS\DASH? Где-то видел что эти технологии нужно использовать в паре, так как каждая из них имеет свою браузерную поддержку.
    Для видеофайлов не требуется какой-то особый подход к размещению на диске. HLS поддерживается только мобильными браузерами (многими, но не всеми), а DASH не поддерживается никакими современными браузерами. Вам в любом случае придётся использовать javascript-плеер, который самостоятельно будет собирать поток из HLS/DASH и воспроизводить через media source, поэтому принципиальной разницы нет. Использовать и HLS, и DASH одновременно точно ни к чему.

    2) Должны ли быть на сервере какие-то специфичные настройки, для эффективной отдачи статического медиа-контента?
    Да не особо. Так как у вас многогигабитный канал, можно попробовать настроить сетевую подсистему (если речь о Linux), а именно увеличить TCP-буферы, буферы отправки и получения, количество conntrack-соединений (может, ошибки соединения возникают по причине лимита conntrack? В dmesg заглядывали?).

    3) Медиа-плеер. Возможно, причина ошибок связана с плеером, который использовали на клиенте?
    Может, безусловно. Плееры содержат достаточно сложный код: парсеры и демуксеры контейнеров, работа с HLS, media source, совместимость с разными браузерами.

    Например, в этом проекте, люди заходили с телевизора, а на tizen flowplayer не работал, от слова совсем.
    Рекомендую попробовать clappr.io — один из немногих, корректно работающих на устаревшем браузере Blackberry.

    4) Шифрование\защита файлов. Как по мне отдача чистых mp4 файлов, небезопасна от слова совсем.
    Зачем нужно защищать ваши файлы, если вы и так их проигрываете? Может, следует подумать о людях и об удобстве просмотра, и предоставить ссылку, которую можно открыть в нормальном видеоплеере, или скачать фильм в виде файла? Не понимаю эту дурацкую тенденцию.
    Ответ написан
    2 комментария
  • Best practice бэкенда на express?

    @ned4ded
    Верстка, Фронтенд
    я просто оставлю это здесь
    Ответ написан
    Комментировать
  • Как проверять пароль на достаточную сложность?

    dasnein
    @dasnein
    Используйте регулярные выражения

    function validate(pass) {
      if (pass.length >= 8) {
        if (/[^a-zA-Z0-9]/.test(pass)) {
          return 'NO'
        }
      
        if (/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/.test(pass)) {
          return 'YES'
        }
      }
      
      return 'NO'
    }
    
    validate('123ASDDASD') // NO
    validate('123qwe_ASD') // NO
    validate('123qwe') // NO
    validate('123qweASD') // YES
    Ответ написан
    Комментировать
  • Node.js фреймворк для написания api?

    @vshvydky
    express.js inversify-express-utils
    express или koa + routing-controllers
    fastify happi и тп...
    Ответ написан
    2 комментария
  • Можно-ли скачать видео с YouTube используя DevTools?

    Есть такая «секретная» ссылка: www.youtube.com/get_video_info?video_id=XXXXXX
    Вместо XXXXXX подставьте хэш видео, который в ссылке на ролик, типа youtu.be/BWCiWZtrWXU после слеша.

    По этой (первой) ссылке вернутся URL-encoded данные. Распакуйте их и возьмите параметр url_encoded_fmt_stream_map. Его значение опять надо распаковать как URL-параметры. И из результата вытащить параметр url – это ссылка на единый скачивабельный видеофайл.

    Например, в консоли браузера:
    function getUrlParams(search) {
        let hashes = search.slice(search.indexOf('?') + 1).split('&')
        let params = {}
        hashes.map(hash => {
            let [key, val] = hash.split('=')
            params[key] = decodeURIComponent(val)
        })
    
        return params
    }
    var s = '------'; // здесь длиннющая строка из ответа /get_video_info
    var a = getUrlParams(s);
    var b = getUrlParams(a.url_encoded_fmt_stream_map);
    console.log(b.url); // эту ссылку открываем в браузере - это скачиваемый видеофайл


    Очень надеюсь, что вы покопаетесь в этих данных более подробно, разберётесь, как получать прямые ссылки на скачиваемые файлы во всех форматах и размерах, которые предлагает YouTube, и напишете короткий материал на Хабр по результатам, а также опубликуете gist с рабочим кодом для консоли браузера.
    Ответ написан
    3 комментария
  • Как из flask передать роутер на react?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    1. Выпилить из проекта JQuery.
    2. Почитать документацию React о том как работать с формами.
    3. По-хорошему, добавить в проект Redux.

    Простой пример решения вашей проблемы без использования Redux:
    class Main extends Component {
      state = {
        isInitializing: true,
        isSignedIn: false,
        user: null,
      };
    
      async componentDidMount() {
        // тут достаем токен, например, из cookie
        const token = storage.get(TOKEN_KEY); 
        
        if (token) {
           // тут сетим токен в заголовки по-умолчанию библиотеки для HTTP-запросов
          api.setHeader('Authorization', `Bearer ${token}`);
    
          const user = await api.getUser();
    
          this.setState({ user, isSignedIn: true, isInitializing: false });
        } else {
          this.setState({ isInitializing: false });
        }
      }
    
      render() {
        const { isSignedIn, isInitializing } = this.state;
        
        // на время инициализации показываем ProgressBar
        if (isInitializing) return <ProgressBar />;    
    
        return (
          <code lang="html">
            <Router>
              <div id = 'content'>
                {isSignedIn ? (
                  <React.Fragment>
                    <Route path='/feed' exact component={Feed} />
                    <Redirect from='/' to="/feed" />
                  </React.Fragment>
                ) : (
                  <React.Fragment>
                    <Route path='/' exact component={Auth} />
                    <Redirect from="/feed" to="/" />
                  </React.Fragment>
                )}
              </div>
            </Router>
          </code>
        );
      }
    }


    Все же, советую использовать redux. А в качестве HTTP клиента - axios.
    При использовании redux процесс инициализации выносится в action:

    const store = configureStore();
    store.dispatch(init()); // начинаем процесс инициализации еще до монтирования приложения
    
    ReactDOM.render(
      <Provider store={store}>
        <Main />
      </Provider>, document.getElementById('main'),
    );
    Ответ написан
    Комментировать
  • Как учить нативный WebGL?

    k12th
    @k12th
    console.log(`You're pulling my leg, right?`);
    Комментировать
  • Как учить нативный WebGL?

    Комментировать
  • Чем заменить функцию .map() в моем случае?

    @askhat
    На вопрос ответил автор вопроса, я в свою очередь попытаюсь объяснить что произошло.

    Рендер в реакте всегда идёт по наименее трудозатратному пути, а именно вычисляет дельту (разницу) между новым стейтом и предыдущим, если таковой имеется. Например:

    class TodoList extends React.Component {
      state = {
        todos: [
          'Commit',
          'Push'
        ]
      }
      render() {
        return <ul>
          {this.state.todos.map(item => {
            return <li>{ todo }</li>
          }
        </ul>
      }
    }


    Если стейт компонента изменится, скажем при добавление элемента в начало списка todos, так что он станет таким:

    const todos = [
      'Init',
      'Commit',
      'Push'
    ]


    Реакт вычислит два древа VirtualDOM:

    // Начальный стейт
    <ul>
      <li>Commit</li>
      <li>Push</li>
    </ul>
    // Добавлен элемент
    <ul>
      <li>Init</li> // <- разница начинается здесь и до конца древа
      <li>Commit</li>
      <li>Push</li>
    </ul>


    Здесь выполняется работа которой можно было бы избежать. К примеру если бы элемент был добавлен в конец списка:

    const todos = [
      'Commit',
      'Push',
      'Merge'
    ]


    То реакт получил бы на сравнение другие два древа элементов:

    // Начальный стейт
    <ul>
      <li>Commit</li>
      <li>Push</li>
    </ul>
    // Добавлен элемент
    <ul>
      <li>Commit</li>
      <li>Push</li>
      <li>Merge</li> <- разница начинается здесь, от начала и до сих по ничего не менялось
    </ul>


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

    Совершенно очевидно что <li>Commit</li> и <li>Push</li> не менялись, однако реакт недостаточно умён чтобы это понять. Чтобы помочь ему следует воспользоваться специальным пропом key={}. Он может быть значением любого типа, единственно требование — значение должно стабильно идентифицировать соответствующие данные.

    Если бы компонент выглядел так:

    class TodoList extends React.Component {
      state = {
        todos: [
          { id: 0, text: 'Commit' },
          { id: 1, text: 'Push' }
        ]
      }
      render() {
        return <ul>
          {this.state.todos.map(item => {
            return <li key={todo.id}>{ todo.text }</li>
          }
        </ul>
      }
    }


    То добавление элемента в начало массива, породило бы следующий стейт:

    const todos = [
      { id: 2, text: 'Init' },
      { id: 0, text: 'Commit' },
      { id: 1, text: 'Push' }
    ]


    И, снова, два древа элементов:

    // Начальный стейт
    <ul>
      <li>Commit</li> // id 0
      <li>Push</li> // id 1
    </ul>
    // Добавлен элемент
    <ul>
      <li>Init</li> // id 2 новый элемент отобразится в начале
      <li>Commit</li> // id 0
      <li>Push</li> // id 1 
    </ul>


    Благодаря подсказке, реакт не учтёт в дельте элементы чьи идентификаторы не изменились, и, как следствие, не будет делать лишних действий.

    Таким образом использовать индекс в массиве в качестве ключа — не лучшая идея, особенно если массив будет меняться. По той же причине не следует использовать Math.random() в качестве ключа, так вы почти гарантировано будете всегда получать нестабильные идентификаторы.

    Подробнее об этом можно почитать здесь — Reconciliation.
    Ответ написан
    5 комментариев
  • Где почитать истории о формировании малых команд с неопытными людьми?

    @ponaehal
    Возьмите одного сытого но знающего, обратите его в свою веру и уполномочьте принимать решения в рамках обозначенных вами задач.
    Ответ написан
    Комментировать
  • Как сделать ник в виде брута?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Разбить строку посимвольно в массив, заменять символы на случайные. По ходу времени двигать слева направо позицию, до которой строка «отгадана» – там уже символы не заменять. Накрученный массиво снова собрать в строку и показать. Эту процедуру расчёта одного «кадра» повторить через небольшую задержку по времени. Повторять до тех пор, пока вся строка не «разгадается».

    (function( nick, el) {
      var L = nick.length
        ,cursor = 0
        ,arr
        ,timeout
        ,prob = 0.05 // вероятность "разгадывания" очередной позиции
        ,rate = 25  // частота "кадров" в секунду
        ,delay = 1000 / rate
      ;
    
      function tweak() {  
        arr = nick.split('');
        for(pos = cursor; pos < L; pos++) {
          arr[pos] = String.fromCharCode(
            1024 + Math.round( (1279 - 1024) * Math.random() )
          );
        }
        el.innerText = arr.join('');
        
        if( cursor === L) return; // done
        
        if( Math.random() < prob) cursor++;
        timeout = window.setTimeout( tweak, delay);
      }
    
      tweak();
      
    })( "Sergei Sokolov", document.getElementById("effect") )


    fiddle
    Ответ написан
    8 комментариев
  • Как использовать функцию внутри функции внутри класса?

    Ivanq
    @Ivanq
    Знаю php, js, html, css
    А точно с self правильно пробовали?
    var self = this;
    this.player.addEventListener('ended', function (){
                self.nextSong();
                console.log('Audio file ended');
            });

    Должно работать. Но, честно говоря, так теперь мужики не пишут. Не по-ES6'овски! Надо писать так:
    this.player.addEventListener('ended', () => {
                this.nextSong();
                console.log('Audio file ended');
            });
    Ответ написан
    1 комментарий
  • Как использовать функцию внутри функции внутри класса?

    sHinE
    @sHinE
    веб-разработчик, php/js/mysql и сопутствующее
    Стрелочные функции вроде для этого как раз, чтобы this пробрасывать.
    Вот так не работает?
    this.player.addEventListener('ended', () => {
                this.nextSong();
                console.log('Audio file ended');
            });
    Ответ написан
    1 комментарий
  • Можете подсказать хороший онлайн тест на знание английского языка?

    @nirvimel
    огромное количество тестов предлагают пройти их бесплатно, но вот результат после 20-30 минут мучения только за деньги

    Очень странно. Почему мне такие никогда не подались?
    Вот на вскидку: то, что нашел у себя в закладках:
    1. esl.about.com/qz/Intermediate-Level-English-Review-Quiz - тест на intermediate уровень. Стилизован под бланк письменного теста, только интерактивный, сразу показывает правильный ответ и соответствующее правило.
    2. esl.about.com - целый каталог таких тестов.
    3. www.englishtag.com/tests/level_test_intermediate_B1.asp - интересен тем, что кроме стандартных заданий с выбором одного ответа из трех/четырех, есть задания на расстановку (drag&drop) множества слов во множество возможных позиции (суть в том, что гораздо сложнее угадать правильный ответ чисто случайно).

    Не ручаюсь за то, насколько данные тесты можно считать эталонными, но, по крайней мере, они полностью бесплатные.
    Ответ написан
    2 комментария
  • Как сверстать шапку?

    paulradzkov
    @paulradzkov
    Дизайнер, верстальщик, начальник отдела UI
    Это нужно делать градиентом:
    - сверстать 6 цветов градиентом,
    - поставить background-size: 600px 4px — чтобы каждая полоска была равно 100px,
    - повторять фон только горизонтально background-repeat: repeat-x;

    .container {
        margin: auto;
        background: #FFF;
        max-width: 960px;
        background-image: linear-gradient(to right,
            #50B5AD 0%,     #50B5AD 16.67%,
            #FFBBB7 16.67%, #FFBBB7 33.33%,
            #F8506C 33.33%, #F8506C 50%,
            #ADB347 50%,    #ADB347 66.67%,
            #F5CE42 66.67%, #F5CE42 83.33%,
            #A2DBD6 83.33%, #A2DBD6 100%);
        background-size: 600px 4px;
        background-repeat: repeat-x;
    }


    codepen.io/paulradzkov/pen/eZydxg
    Ответ написан
    Комментировать
  • Что за единицы используются в letter-spacing в фотошопе?

    svistiboshka
    @svistiboshka
    живые веб интерфейсы
    X / 1000 = Y

    Where X is the value of the letter-spacing in Photoshop and Y is the value in em to use in CSS

    Photoshop to em “formula”


    X * S / 1000 = P

    Where X is equal to the letter-spacing value in Photoshop, S is the font-size in pixels (which is equal to the value in point provided you’re working in 72dpi) and P is the resulted value in px to use in CSS

    Photoshop to px “formula”
    Ответ написан
    Комментировать