איך Spotify השתמשה ב-Picture-in-Picture API כדי לבנות את המיני-נגן של Spotify

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

ב-Spotify, שירות המינויים הפופולרי ביותר בעולם לסטרימינג של אודיו, אנחנו שואפים להמשיך לשפר את האופן שבו משתמשים צורכים תוכן וידאו ואודיו. הוא מציע ספרייה נרחבת של מוזיקה, פודקאסטים וספרי אודיו, ולכן מתאים למיליוני משתמשים מדי יום במכשירים ניידים, במחשב ובפלטפורמות אחרות.

לאחרונה השיקו ב-Spotify את המיני-נגן של Spotify עבור לקוחות המחשב ונגני האינטרנט שלה. המיני-נגן מיועד להציע פקדי הפעלה חיוניים בחלון קטן וקומפקטי שנשאר למעלה, ומספק למשתמשים גישה קבועה ל-Spotify. זה כבר זמן רב להשלים את התכונה הזו, והיא מאפשרת למשתמשים לבצע מספר משימות בו-זמנית בצורה חלקה באפליקציות ובחלונות שונים תוך כדי שהם נהנים מהאומנים, מהפלייליסטים ומהפודקאסטים האהובים עליהם ב-Spotify.

השלב הבא הוא סקירה מפורטת של פיתוח המיני-נגן, החל מ'פריצת לוח הציור' הראשונית ועד לגרסה המתקדמת והידידותית יותר למשתמש, שמובנית ב-Document Picture-in-Picture API החדש.

"פריצת לוח הציור"

האיטרציה הראשונית של המיני-נגן הושקה ב-2019 בנגן האינטרנט של Spotify כפרויקט הפריצה. המטרה הייתה להשתמש ב-Picture-in-Picture (PiP) API for <video> של הדפדפן כדי להציג את עטיפת האלבום בחלון שתמיד פתוח. עם זאת, ממשק ה-API הזה נועד בעיקר לרכיבי וידאו, ולא ניתן היה להציג תמונות של עטיפת האלבום. כדי לעקוף את הבעיה ב-Spotify, צריך לעבד את עטיפת האלבום לרכיב בד קנבס ולהשתמש בשיטה captureStream() HTMLCanvasElement כדי לקבל אובייקט MediaStream בזמן אמת. השידור הזה משמש כמקור של הסרטון שמשמש את ה-API של 'תמונה בתוך תמונה'. הגישה הזו התבססה על דוגמת 'פלייליסט של אודיו' ב-Google Chrome.

מערכת Spotify שילבה את אזור העריכה עם רכיבי ה-handler המתאימים של הפעולות שהוגדרו ב-Media Session API כדי לקבוע אילו לחצני נגן יופיעו בחלון 'תמונה בתוך תמונה'. כך המשתמשים קיבלו חלון צף עם עיצוב אלבום ולחצני נגן, שאפשר להשתמש בהם כדי לשלוט בהפעלה ולהתמקד במשימות אחרות.

צילום מסך של חלון המיני-נגן הבסיסי ב-Spotify.

כך היה אפשר להפעיל מיני-נגן בסיסי ב-Spotify. אבל לגישה היו כמה מגבלות:

  • אין תמיכה בכתוביות בסרטונים בתוך החלון של 'תמונה בתוך תמונה'. כיוון שאפליקציית Spotify התבקשה להציג כתוביות בכל הסרטונים, היא נאלצה לסגור את החלון של 'תמונה בתוך תמונה' ברגע שמתחילה הפעלת סרטון.
  • לחצני הנגן גלויים רק אם ההפעלה מתבצעת באופן מקומי. שירות Spotify מאפשר הפעלה מרחוק באמצעות Spotify Connect (ופרוטוקולים אחרים) ורוצה שהמשתמש יוכל לשלוט גם בהפעלה הזו.
  • אין תמיכה בהתאמה אישית של המראה והסגנון של 'תמונה בתוך תמונה'. ב-Spotify יש אפשרות להציג רק גרפיקה ולהשתמש בלחצני הנגן שמסופקים על ידי Chrome, וכך הם לא יכולים להוסיף את המיתוג של Spotify או לחצנים נוספים לנגן.

היעדר שליטה בממשק המשתמש וחוסר היכולת להוסיף כאן תכונות ספציפיות של Spotify (לדוגמה, סימון טראק ב'לייק') גרם להם לחשוב שהגישה הזו לא מתאימה ללקוח שלהם למחשבים.

מסמכים במצב 'תמונה בתוך תמונה': האבולוציה של המיני-נגן

בתחילת 2023, נודע ב-Spotify על העניין המחודש של Google Chrome בהשקת API חדש שיאפשר הצגה של תוכן HTML שרירותי בתוך חלון 'תמונה בתוך תמונה', שנקרא Document Picture-in-Picture API. הפיתוחים האלה ריגשו את Spotify, כי הם יעניקו לה שליטה מלאה על מראה החלון של 'תמונה בתוך תמונה'. Spotify עבד בשיתוף עם הצוות של Chrome במהלך גרסת המקור לניסיון לפיתוח מיני-נגן חדש שמבוסס על Document Picture-in-Picture API.

ממשק ה-API של 'תמונה-בתוך-מסמך' של המסמך מאפשר לפתוח חלון חדש שפועל כל הזמן, שאליו תוכלו לצרף רכיבים. הנגן של Spotify Web Player הוא אפליקציית אינטרנט של React, ולכן מערכת Spotify השתמשה בשיטה createPortal() של ReactDOM כדי לעבד רכיבים מותאמים אישית בחלון'תמונה בתוך תמונה' באפליקציה הראשית. כך היא נותנת שליטה מלאה על המראה והתכונות של המיני-נגן.

גם ממשק ה-API החדש של Document Picture-in-Picture שטיפל בבעיות הקודמות של Spotify:

  • סרטונים בתוך החלון של 'תמונה בתוך תמונה' הם רכיבי וידאו רגילים ויש בהם תמיכה מלאה בכתוביות.
  • כשיש שליטה מלאה בממשק המשתמש, אפשר להציג את לחצני הנגן גם כשההפעלה מתבצעת מרחוק באמצעות Spotify Connect.
  • ב-Spotify הצליחה לשלב את לחצני העיצוב והסגנון של הנגן, ולשפר את חוויית המשתמש.
  • החברה הצליחה להביא תמיכה ב-Document PiP API ללקוח שולחן העבודה של Spotify. כתוצאה מכך, החברה יכולה להביא את המיני-נגן למיליוני משתמשים במחשב.

צילום מסך של חלון המיני-נגן החדש ב-Spotify.

איך יוצרים חלון עם תמונה בתוך תמונה באמצעות React

הדוגמה הבאה ממחישה איך אפשר להשתמש במסמך תמונה בתוך תמונה ב-React, בדיוק כמו הצוות של Spotify. ייווצרו שני רכיבים של React: MyFeature ו-PiPContainer.

הרכיב MyFeature אחראי לניהול החלון של 'תמונה בתוך תמונה'. מתבצע רינדור של לחצן להחלפת מצב של חלון 'תמונה בתוך תמונה' ולעבד את הרכיב PiPContainer. המינוי גם נרשם לאירוע "pagehide" של חלון 'תמונה בתוך תמונה' כדי לעדכן את המצב כשהחלון נסגר.

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>
    </>
  );
};

הרכיב PiPContainer משתמש במתודה createPortal() של ReactDOM כדי לעבד תוכן בחלון 'תמונה בתוך תמונה'.

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;
};

מה עושים אחר כך

אנחנו ממשיכים לפתח את Spotify ולעודד חידושים, והחברות שלהם ממשיכה לשפר את המיני-נגן, ומתכוננים להמשיך לשפר את התכונות ואת חוויית המשתמש שלה. הם עדיין לא יכולים להתחייב לפיצ'רים מסוימים, אבל הם מתרגשים לקראת האפשרויות העתידיות של המיני-נגן.

צילום מסך של הצורות השונות בחלון המיני-נגן ב-Spotify.

ממשק ה-API של מסמך 'תמונה בתוך תמונה' מספק גמישות ושליטה ליצירת מיני-נגן אינטואיטיבי וידידותי יותר למשתמש. אני מקווה שספקי דפדפנים אחרים יבחינו בהזדמנויות שקיימות ב-API הזה וישקלו לשלב תמיכה בו. כך אפשר לספק ב-Spotify חוויה עקבית ומשופרת לכל המשתמשים, ללא קשר לדפדפן שהם בחרו.

אישורים

תודה לכל מי שמעורב בבניית המיני-נגן ב-Spotify.

ב-Spotify רוצים גם להודות לצוות Google Chrome על שיתוף הפעולה ועל שיתוף המשוב מ-Spotify לגבי ה-Document Picture-in-Picture API.