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 famoso do mundo, tem como objetivo melhorar continuamente a forma como os usuários consomem conteúdo de áudio e vídeo. Com uma extensa biblioteca de músicas, podcasts e audiolivros, o serviço atende milhões de usuários diariamente em dispositivos móveis, PCs e outras plataformas.

Recentemente, o Spotify lançou o Spotify Miniplayer para clientes de desktop e do player da Web. O Miniplayer foi projetado para oferecer controles de reprodução essenciais em uma janela pequena e compacta que fica no topo, proporcionando aos usuários acesso constante ao Spotify. Esse é um recurso muito solicitado e permite que os usuários realizem várias tarefas em diferentes janelas e apps enquanto curtem os artistas, playlists e podcasts favoritos no Spotify.

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

O "hack de tela"

A iteração inicial do Miniplayer foi lançada em 2019 no player da Web do Spotify como um projeto de hack. O objetivo era usar a API Picture-in-Picture (PiP) do navegador para <video> para mostrar a arte do álbum em uma janela sempre visível. No entanto, essa API foi projetada principalmente para elementos de vídeo, e não era possível mostrar imagens de capa de álbuns. O Spotify contorna isso renderizando a arte do álbum em um elemento de tela e usando o método HTMLCanvasElement captureStream() para conseguir um objeto MediaStream em tempo real. Esse stream serve como a fonte do vídeo usado para a API PiP. Essa abordagem foi baseada no exemplo de "playlist de áudio" do Google Chrome.

O Spotify combinou a tela com os manipuladores de ação adequados definidos na API Media Session para controlar quais controles do player apareceriam na janela PiP. Isso deu aos usuários uma janela flutuante com a arte do álbum e controles do player, que eles podiam 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:

  • Não há suporte para legendas de vídeo na janela PiP. Como o Spotify precisava mostrar legendas em todos os vídeos, a janela PiP era fechada assim que um vídeo começava a ser reproduzido.
  • Os controles do player só ficam visíveis se a reprodução estiver acontecendo localmente. O Spotify permite a reprodução remota usando o Spotify Connect (e outros protocolos) e quer que o usuário também possa controlar essa reprodução
  • Não há suporte para personalizar a aparência da janela PiP. O Spotify só podia mostrar a arte e usar os controles do player fornecidos pelo Chrome, o que impedia a adição da marca do Spotify ou de outros controles do player.

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

Picture-in-Picture de documentos: a evolução do miniplayer

No início de 2023, o Spotify soube do interesse renovado do Google Chrome em lançar uma nova API que permitisse que conteúdo HTML arbitrário fosse exibido dentro da janela PiP, conhecida como API Document Picture-in-Picture. Esse desenvolvimento foi empolgante para o Spotify, porque daria a ele controle total sobre a aparência da janela PiP. O Spotify colaborou com a equipe do Chrome durante o Origin Trial para desenvolver um novo miniplayer criado com base na API Picture-in-Picture de documentos.

A API Document PiP permite abrir uma nova janela sempre ativada à qual 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 PiP do aplicativo principal, 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 PiP são elementos de vídeo normais e têm suporte total 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.
  • Eles conseguiram oferecer suporte à API Document PiP ao cliente de desktop do Spotify, permitindo que o miniplayer fosse disponibilizado para milhões de usuários de desktop.

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 modo Picture-in-Picture de documentos 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. Ele renderiza um botão que alterna 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 avançando e inovando, ele continua comprometido em aprimorar o Miniplayer e planeja refinar ainda mais os recursos e a experiência do usuário. Embora ainda não seja possível se comprometer com recursos específicos, eles estão animados com as possibilidades futuras do Miniplayer.

Captura de tela das 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. A esperança é que outros fornecedores de navegadores percebam as oportunidades que essa API oferece e considerem incorporar o suporte a ela. Isso permitiria que o Spotify oferecesse uma experiência consistente e aprimorada para todos os usuários, independentemente do navegador escolhido.

Agradecimentos

Agradecemos a todos na Spotify que estiveram envolvidos na criação do miniplayer.

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