Como o Spotify usou a API Picture-in-Picture para criar o miniplayer do Spotify

Guido Kessels
Guido Kessels
François Beaufort
François Beaufort

O Spotify, o serviço de assinatura de streaming de áudio mais popular do mundo, busca continuamente melhorar a maneira como os usuários consomem conteúdo de áudio e vídeo. Com uma extensa biblioteca de músicas, podcasts e audiolivros, o app atende milhões de usuários diariamente em dispositivos móveis, PC e outras plataformas.

Recentemente, o Spotify lançou o Miniplayer do Spotify para clientes de desktop e de player da Web. O miniplayer foi criado para oferecer controles de mídia essenciais em uma janela pequena e compacta que fica na parte de cima, oferecendo aos usuários acesso constante ao Spotify. Esse recurso foi muito solicitado e permite que os usuários realizem várias tarefas em diferentes janelas e apps enquanto curtem seus artistas, playlists e podcasts favoritos no Spotify.

Confira a seguir uma visão detalhada do desenvolvimento do miniplayer, desde a "hack de tela" inicial até a versão mais avançada e fácil de usar criada na nova API Document Picture-in-Picture.

O "truque de tela"

A iteração inicial do miniplayer foi lançada em 2019 no Web Player do Spotify como um projeto de hackers. O objetivo era utilizar a API Picture-in-Picture (PiP) para <video> do navegador para exibir a capa do álbum em uma janela sempre em primeiro plano. No entanto, essa API foi projetada principalmente para elementos de vídeo e não era possível mostrar imagens de arte do álbum. O Spotify contornou isso renderizando a arte do álbum em um elemento de tela e usando o método HTMLCanvasElement captureStream() para obter um objeto MediaStream em tempo real. Esse stream serve como a fonte do vídeo usado para a API picture-in-picture. Essa abordagem foi baseada na amostra da playlist de áudio do Google Chrome.

O Spotify combinou a tela com os gerenciadores de ação adequados definidos na API Media Session para controlar quais controles do player apareceriam na janela picture-in-picture. Isso deu aos usuários uma janela flutuante com a arte do álbum e os controles do player, que eles poderiam usar para controlar a reprodução enquanto se concentravam em outras tarefas.

Captura de tela da janela básica do miniplayer do Spotify.

Isso permitiu que o Spotify tivesse um miniplayer básico. No entanto, a abordagem tinha várias limitações:

  • Legendas de vídeo não são compatíveis com a janela picture-in-picture. Como o Spotify precisava mostrar legendas em todos os vídeos, foi necessário fechar a janela picture-in-picture assim que o vídeo começava a ser reproduzido.
  • Os controles do player só ficam visíveis quando a reprodução ocorre localmente. O Spotify permite a reprodução remota usando o Spotify Connect (e outros protocolos) e quer que o usuário possa controlar essa reprodução também
  • Não é possível personalizar a aparência da janela picture-in-picture. O Spotify só pode exibir obras de arte e usar os controles do player fornecidos pelo Chrome, impedindo que adicionem a marca do Spotify ou outros controles do player.

A falta de controle sobre a interface do usuário e a incapacidade de adicionar recursos específicos do Spotify aqui (por exemplo, gostar de uma faixa) significa que a equipe não achava que essa abordagem era adequada para o cliente de desktop.

Documente picture-in-picture: a evolução do miniplayer

No início de 2023, o Spotify soube do novo interesse do Google Chrome em lançar uma nova API que permitisse a exibição de conteúdo HTML arbitrário na janela picture-in-picture, conhecida como API Document Picture-in-Picture. Esse desenvolvimento foi empolgante para o Spotify, porque daria a eles controle total sobre a aparência da janela picture-in-picture. O Spotify colaborou com a equipe do Chrome durante o Teste de origem para desenvolver um novo miniplayer integrado à API Document Picture-in-Picture.

A API Document PiP permite abrir uma nova janela sempre ativada em que você pode anexar elementos. Como o Spotify Web Player é um aplicativo da Web React, o Spotify usou o método createPortal() do ReactDOM para renderizar componentes personalizados na janela picture-in-picture do aplicativo principal, oferecendo controle total sobre a aparência e os recursos do miniplayer.

A nova API Document Picture-in-Picture também resolveu os problemas anteriores do Spotify:

  • Os vídeos na janela picture-in-picture são elementos de vídeo comuns e têm suporte completo para legendas.
  • Com controle total sobre a interface, os controles do player podem ser mostrados mesmo quando a reprodução está acontecendo remotamente usando o Spotify Connect.
  • O Spotify conseguiu incorporar a aparência e os controles do player, melhorando a experiência do usuário.
  • Ela passou a oferecer suporte à API Document PiP para o cliente de desktop do Spotify, levando o miniplayer a milhões de usuários de computador.

Captura de tela da nova janela do miniplayer do Spotify.

Criar uma janela picture-in-picture usando o React

O exemplo a seguir demonstra como usar o Document Picture-in-Picture no React, assim como a equipe do Spotify. Você vai criar dois componentes do React: MyFeature e PiPContainer.

O componente MyFeature é responsável por gerenciar a janela picture-in-picture. Ela renderiza um botão que ativa a janela picture-in-picture e renderiza o componente PiPContainer. Ele também se inscreve no evento "pagehide" da janela picture-in-picture para atualizar o estado quando a janela é fechada.

const MyFeature = () => {
  const [pipWindow, setPiPWindow] = useState<Window | null>(
    documentPictureInPicture.window
  );

  const handleClick = useCallback(async () => {
    if (pipWindow) {
      pipWindow.close();
    } else {
      const newWindow = await documentPictureInPicture.requestWindow();
      setPiPWindow(newWindow);
    }
  }, [pipWindow]);

  useEffect(() => {
    const handleWindowClose = (): void => {
      setPiPWindow(null);
    };

    pipWindow?.addEventListener("pagehide", handleWindowClose);

    return () => {
      pipWindow?.removeEventListener("pagehide", handleWindowClose);
    };
  }, [pipWindow]);

  return (
    <>
      <button onClick={handleClick}>
        {pipWindow ? "Close PiP Window" : "Open PiP Window"}
      </button>
      <PiPContainer pipWindow={pipWindow}>Hello World 👋!</PiPContainer>
    </>
  );
};

O componente PiPContainer usa o método createPortal() do ReactDOM para renderizar conteúdo na janela picture-in-picture.

type Props = PropsWithChildren<{
  pipWindow: Window | null;
}>;

const PiPContainer = ({ pipWindow, children }: Props) => {
  useEffect(() => {
    if (pipWindow) {
      cloneStyles(window.document, pipWindow.document);
    }
  }, [pipWindow]);

  return pipWindow ? createPortal(children, pipWindow.document.body) : null;
};

A seguir

À medida que o Spotify continua a avançar e inovar, o compromisso deles é melhorar o miniplayer e planejam melhorar ainda mais os recursos e a experiência do usuário. A empresa ainda não pode usar recursos específicos, mas está empolgada com as possibilidades futuras do miniplayer.

Captura de tela mostrando as diferentes formas da janela do miniplayer do Spotify.

A API Document Picture-in-Picture oferece flexibilidade e controle para criar um miniplayer mais intuitivo e fácil de usar. Esperamos que outros fornecedores de navegadores observem as oportunidades que essa API oferece e considere incorporar o suporte a elas. Isso permitiria que o Spotify proporcionasse uma experiência consistente e aprimorada para todos os usuários, independentemente do navegador escolhido.

Agradecimentos

Agradecemos a todos no Spotify que se envolveram na criação do miniplayer.

O Spotify também agradece à equipe do Google Chrome pela colaboração e por levar em consideração o feedback do Spotify para a API Document Picture-in-Picture.