EME? Cdm? DRM? CENC? IDK! Was Sie brauchen, um Ihren eigenen Video-Player in einem Browser zu erstellen

Was bedeuten all diese Abkürzungen? Was braucht es, um einen Open-Source-Player zu entwickeln, mit dem Sie Videos von Amazon, Sky und anderen Plattformen und Videos von einem beliebigen Anbieter ansehen können? Sebastian Golasch sprach auf der HolyJS 2018 Piter-Konferenz darüber, wie der Video-Streaming-Prozess abläuft. Unter dem Schnitt - Video und Übersetzung seines Berichts.



Sebastian Golasch ist derzeit Entwickler bei der Deutschen Telekom. Er arbeitete lange Zeit mit Java und PHP und wechselte dann zu JS, Python und Rust. Seit sieben Jahren arbeitet er an der proprietären Qivicon Smart Home-Plattform.




Ein bisschen über die Geschichte des Video-Streamings


Schauen wir uns zunächst die Geschichte des Webs an, da wir in 25 Jahren von QuickTime zu Netflix gewechselt sind. Alles begann in den 90er Jahren, als Apple QuickTime erfand. Die Nutzung im Internet begann 1993-1994. Zu diesem Zeitpunkt konnte der Player Videos mit einer Auflösung von 156 × 116 Pixel und einer Frequenz von 10 FPS ohne Hardwarebeschleunigung abspielen (wobei nur Prozessorressourcen verwendet wurden). Dieses Format konzentrierte sich auf eine 9600-Baud-DFÜ-Verbindung - 9600 Bit / s, einschließlich Overhead-Informationen.

Es war die Zeit des Netscape-Browsers. Das Video im Browser sah nicht besonders gut aus, da es nicht im Web enthalten war. Für die Wiedergabe verwendeten wir externe Software (dieselbe QuickTime) mit einer eigenen Oberfläche, die im Browser mithilfe des Einbettungs-Tags visualisiert wurde.



Die Situation wurde etwas besser, als Macromedia den Shockwave Player veröffentlichte (nach der Übernahme von Macromedia durch Adobe wurde er als Adobe Flash Player bekannt). Die erste Version von Shockwave Player wurde 1997 veröffentlicht, die Videowiedergabe wurde jedoch erst 2002 veröffentlicht.

Sie verwendeten den Sorenson Spark alias H.263-Codec. Es wurde für kleine Auflösungen und kleine Dateigrößen optimiert. Was bedeutet das? Ein 43-Sekunden-Video, mit dem der Shockwave Player getestet wurde, wog beispielsweise nur 560 KB. Natürlich wäre es nicht sehr angenehm, einen Film in dieser Qualität zu sehen, aber die Technologie selbst war für diese Zeit interessant. Wie im Fall von QuickTime war jedoch zusätzliche Software erforderlich, damit der Shockwave Player im Browser funktioniert. Dieser Player hatte viele Sicherheitsprobleme, aber das Wichtigste ist, dass das Video immer noch ein Browser-Add-On war.

2007 veröffentlichte Microsoft Silverlight, das etwas an Flash erinnert. Wir werden nicht tief graben, aber alle diese Lösungen hatten etwas gemeinsam - eine Black Box. Alle Spieler arbeiteten als Browser-Add-On, und Sie hatten keine Ahnung, was im Inneren vor sich ging.



< Video/ > Element


2007 schlug Opera vor, das < Video/ > -Tag zu verwenden, dh native Videos in einem Browser zu erstellen. Wir benutzen es heute. Es ist einfach und bequem und jedes Video kann nicht nur angezeigt, sondern auch heruntergeladen werden. Und selbst wenn wir das Herunterladen von Videos nicht zulassen möchten, können wir das Herunterladen in den Browser nicht verbieten. Das Maximum besteht darin, das Herunterladen von Videos zu erschweren.



Das <Video/> ist das genaue Gegenteil der Black Box, und das Anzeigen des Quellcodes ist sehr einfach.



DRM


Sie können jedoch nicht einfach mit der rechten Maustaste auf ein Video auf Netflix klicken und "Speichern unter" auswählen. Der Grund dafür ist DRM (Digital Restrictions Management). Dies ist keine einzelne Technologie oder Anwendung, die eine Aufgabe ausführt. Dies ist ein allgemeiner Begriff für Konzepte wie:

  • Authentifizierung und Benutzerverschlüsselung
  • Inhaltsbasierte Verschlüsselung
  • Definition von Rechten und Anwendung von Beschränkungen
  • Feedback und Update
  • Ausgangssteuerung und Verbindungsschutz
  • Untersuchung und Verfolgung von Eindringlingen
  • Schlüssel- und Lizenzverwaltung

Um zu verstehen, was DRM ist, müssen wir sein Ökosystem untersuchen, dh herausfinden, welche Unternehmen beteiligt sind. Das:

  • Inhaltseigentümer stehen an der Spitze des Ökosystems. Zum Beispiel Disney, MGM oder FIFA. Diese Unternehmen produzieren Inhalte und haben Rechte daran.
  • DRM-Kerne sind Unternehmen, die DRM-Technologie anbieten (z. B. Google, Apple, Microsoft usw.). Derzeit gibt es etwa 7-8 DRM-Technologien von verschiedenen Unternehmen.
  • Dienstanbieter - Entwickeln Sie eine Serversoftware, die Videos verschlüsselt.
  • Browser , die tatsächlich Spieler sind.
  • Inhaltsanbieter sind Unternehmen wie Netflix, Amazon, Sky usw. In der Regel besitzen sie keine Rechte an den Inhalten, sie lizenzieren und vertreiben sie.
  • Chip- / Gerätehersteller sind ebenfalls am Ökosystem beteiligt, da DRM nicht nur Softwaretechnologie ist. Einige Unternehmen (hauptsächlich Chinesen) entwickeln Chips, die Videos codieren und decodieren.

Haben Sie sich jemals gefragt, warum ein Video auf Netflix in einem Browser nicht über eine sehr hohe Auflösung (SD) verfügt? Wenn Sie jedoch dasselbe Video auf einer Apple TV- oder Android TV-Box ansehen, wird derselbe Inhalt in Full HD oder in abgespielt 4K? Dafür ist auch DRM verantwortlich. Tatsache ist, dass Hersteller immer Angst haben, dass Piraten Inhalte stehlen. Je weniger sicher die Umgebung ist, in der die Videodecodierung durchgeführt wird, desto schlechter ist die Qualität, die dem Benutzer angezeigt wird. Wenn die Dekodierung beispielsweise programmgesteuert durchgeführt wird (z. B. in Chrome oder Firefox), wird das Video in der schlechtesten Qualität angezeigt. In einer Umgebung, in der Hardwarefunktionen zum Decodieren verwendet werden (z. B. wenn Android eine GPU verwendet), sind die Möglichkeiten des illegalen Kopierens von Inhalten geringer, und hier ist die Wiedergabequalität höher. Die sicherste Umgebung ist schließlich die vollständige Hardware (Apple TV oder Android TV Box), in der die Dekodierung und Wiedergabe ohne Einbeziehung der Software durchgeführt wird.



Wenn wir jedoch über Browser sprechen, wird die Dekodierung in diesen fast immer von der Software durchgeführt. Unterschiedliche Browser verwenden unterschiedliche Systeme für DRM. Chrome und Firefox verwenden Widevine. Dieses Unternehmen gehört Google und lizenziert seine DRM-Anwendungen. Zum Dekodieren lädt Firefox daher die DRM-Bibliothek von Google herunter. Im Browser können Sie sehen, woher der Download kommt.



Apple verwendet ein eigenes FairPlay-System, das bereits bei der Einführung des ersten iPhone und iPad entwickelt wurde. Microsoft verwendet auch eine eigene Entwicklung namens PlayReady, die direkt in Windows integriert ist. In anderen Fällen wird Widevine am häufigsten verwendet. Dieses System existiert sowohl als Anwendung als auch als Hardwarelösung - Chips, die Videos dekodieren.

Cdm


Die Abkürzung CDM steht für Content Decryption Module. Dies ist eine Software oder Hardware, die auf verschiedene Arten funktionieren kann:

  • Entschlüsseln Sie das Video und rendern Sie es anschließend im Browser mit dem Tag <Video />.
  • Entschlüsseln und dekodieren Sie das Video und übertragen Sie dann die Rohbilder des Videos zur Wiedergabe an den Browser.
  • Entschlüsseln und dekodieren Sie das Video und übertragen Sie dann die Rohbilder des Videos zur Wiedergabe mit der GPU.

Trotz der Unterstützung der GPU wird die zweite Option am häufigsten verwendet (zumindest bei Chrome und Firefox).

Dekodieren und Dekodieren von Ebenen im Browser


Wie funktioniert das alles zusammen? Um dies zu verstehen, sehen Sie sich die Dekodierungs- und Entschlüsselungsebenen im Browser an. Sie sind unterteilt in:

  • JavaScript-Anwendung - teilt dem Computer mit, welches Video ich ansehen werde.
  • Ein Browser ist ein Player, der Videoinhalte wiedergibt.
  • Modul zur Entschlüsselung von Inhalten.
  • Bei der Verwaltung digitaler Rechte dreht sich alles um die Videodekodierung (ich könnte mir keine bessere Notation einfallen lassen, also habe ich es so genannt).
  • Vertrauenswürdige Laufzeit.
  • In diesem Fall sind die ersten beiden Komponenten ein DRM-Player, das Inhaltsentschlüsselungsmodul ist ein DRM-Client und die letzten beiden Komponenten sind der DRM-Kern.




Was passiert, wenn Sie ein Video in einem Browser abspielen, sehen Sie im Bild unten. Sie ist natürlich etwas verwirrend: Es gibt viele Pfeile und Farben. Ich werde es Schritt für Schritt durchgehen und reale Fälle verwenden, um es klarer zu machen



Wir werden Netflix als Beispiel verwenden. Ich habe eine Debugging-App geschrieben.

Ich begann damit, wo, glaube ich, jeder von Ihnen anfangen würde: Ich habe mir die Anfragen angesehen, die Netflix beim Starten eines Videos stellt, und ich habe eine große Anzahl von Aufnahmen gesehen.



Wenn Sie jedoch nur diejenigen belassen, die für die Wiedergabe des Videos wirklich benötigt werden, stellt sich heraus, dass es nur drei davon gibt: Manifest, Lizenz und das erste Fragment des Videos.



Der Netflix-Player ist in JavaScript geschrieben und enthält über 76.000 Codezeilen. Natürlich kann ich ihn nicht vollständig analysieren. Ich möchte jedoch die Hauptteile zeigen, die für die Wiedergabe geschützter Videos erforderlich sind.

Wir beginnen mit der Vorlage:



EME


Bevor wir uns jedoch mit den Funktionen befassen, müssen wir uns mit einer anderen Technologie vertraut machen - EME (Encrypted Media Extensions, Encrypted Media Extensions). Diese Technologie führt keine Entschlüsselung und Entschlüsselung durch, sondern ist nur eine Browser-API. EME dient als Schnittstelle für CDM, für KeySystem, für einen Server mit einer Lizenz und für einen Server, auf dem Inhalte gespeichert sind.

Beginnen wir also mit getKeySystemConfig.



Es sollte bedacht werden, dass es vom Anbieter abhängt, so dass die Konfiguration, die ich hier präsentiere, für Netflix funktioniert, aber beispielsweise nicht für Amazon.

In dieser Konfiguration müssen wir dem Backend-System mitteilen, welche vertrauenswürdige Laufzeitstufe wir anbieten können. Dies kann eine sichere Hardware-Dekodierung oder eine sichere Software-Dekodierung sein. Das heißt, wir teilen dem System mit, welche Hardware und Software für die Wiedergabe verwendet wird. Und das bestimmt die Qualität des Inhalts.



Schauen Sie sich nach der Konfiguration die Konfiguration an, um ein erstes MediaKeySystem zu erstellen.



Hier beginnt die Interaktion mit dem Modul zur Inhaltsentschlüsselung. Sie müssen der API mitteilen, welches DRM-System und welches KeySystem wir verwenden. In unserem Fall ist dies Widevine.



Der nächste Schritt ist für alle Systeme optional, für Netflix jedoch erforderlich. Auch hier hängt seine Notwendigkeit vom Anbieter ab. Wir müssen ein Serverzertifikat auf unsere mediaKeys anwenden. Serverzertifikate sind einfacher Text in einer Netflix Cadmium.js-Datei, der leicht kopiert werden kann. Und wenn wir es auf mediaKeys anwenden, wird die gesamte Kommunikation zwischen dem Server mit der Lizenz und unserem Browser dank der Verwendung dieses Zertifikats sicher.



Wenn dies erledigt ist, müssen wir uns dem ursprünglichen Element des Videos zuwenden und sagen: „Ok, dies ist das Schlüsselsystem, das wir verwenden möchten, und dies ist das Hallo-Video-Tag. Lass uns dich vereinen. “



Und hier ist die letzte Funktion, die Sie zum Konfigurieren des Videosystems benötigen.



Dies ist eine DRM-Sitzung oder MediaKeySession. Dies sind nur die Daten, die vom Anbieter an das Entschlüsselungsmodul gesendet werden, das die Anforderungen mit ihnen signiert. Diese Daten sind auch einfacher Text, der hinter mehreren Funktionen in der Netflix-Player-Datei verborgen ist, von wo ich sie kopiert habe.



Wenn wir create.Session für das mediaKeys-Objekt aufrufen, müssen wir angeben, welches Video wir unterstützen. In diesem Fall ist es mp4. Dies bringt uns zurück zum Messaging-Kontext mit unserem CDM-System. Wir benötigen auch Netflix, um das Base64-Serverzertifikat in jedem Formular anzuwenden, aber all diese Konfigurationen in der Erstellungssitzung werden wiederum abhängig vom DRM-System bereitgestellt.



Die letzte Funktion hier unten - keySession.generateRequest erstellt eine Lizenzanforderung im Hintergrund. Oder CDM erstellt im Hintergrund eine Lizenzanforderung. Mit anderen Worten, dies sind binäre Rohdaten, die wir an den lizenzierten Server senden müssen, um im Gegenzug eine gültige Lizenz zu erhalten.



Hier ist cenc von Interesse. Es ist ein ISO-Verschlüsselungsstandard, der ein Sicherheitsschema für MP3-Videos definiert. In WebM wird dies anders aufgerufen, aber die Funktion führt dieselbe aus.

handleMessage ist die von uns konfigurierte EventListener-Schnittstelle. Wenn dieses Ereignis durch das Nachrichtenereignis in keySession ausgelöst wird, wissen wir, dass wir bereit sind, eine Lizenz vom Server zu erhalten.



Und in diesem Rückruf erhalten wir nur eine Anfrage an einen Server mit einer Lizenz, die einige Binärdaten enthält (diese können je nach Anbieter auch unterschiedlich sein). Wir verwenden diese Daten, um die aktuelle Sitzung durch Hinzufügen einer Lizenz zu aktualisieren. Das heißt, sobald wir eine gültige Lizenz vom Server erhalten haben, weiß unser CDM, dass wir das Video entschlüsseln und entschlüsseln können.



Wenn wir dies auf das folgende Diagramm anwenden, erhalten wir Folgendes: Wir möchten das Video abspielen, und die JavaScript-Anwendung sagt: „Hallo, Browser! Ich möchte das Video abspielen! “ - verwendet dann verschlüsselte Medienerweiterungen und fordert bei Lizenzfunktionen in Widevine CDM eine Lizenz an. Diese Anfrage wird dann an den Browser zurückgesendet, und wir können sie gegen eine gültige Lizenz auf dem Lizenzserver eintauschen. Anschließend müssen wir diese Lizenz zurück an CDM übertragen. Dieser Vorgang wurde im obigen Code gezeigt.



Beachten Sie jedoch, dass wir noch keine Sekunde des Videos verloren haben und dies alle tun müssen, um in Zukunft einige Videos abspielen zu können.

MSE


Eine weitere Technologie, die wir erforschen müssen, ist MSE (Media Source Extensions). Sie kann als Halbschwester von EME (Encrypted Media Extensions) bezeichnet werden. Dies ist auch eine Browser-API, die nichts mit DRM zu tun hat. Ich sehe es als Programmierschnittstelle zu < Video/ > Src. Mit ihm können Sie binäre Streams in JavaScript erstellen und Videofragmente auf das < Video/ > -Element anwenden. Dank dessen wird die Quelle des < Video/ > -Tags dynamisch.

So können wir die Erweiterungen für Multimedia-Quellen verwenden, das Video instanziieren und darauf zugreifen und dann die Videofragmente in Teilen herunterladen und auf das < Video/ > -Tag anwenden.



Der Punkt ist, dass Sie beim Ansehen eines zweistündigen Videos nicht warten möchten, bis es vollständig geladen ist. Stattdessen schneiden Sie es in kleine Stücke mit einer Größe von etwa 30 Sekunden bis 2 Minuten und wenden sie einzeln auf das < Video/ > -Element an.

Sobald unser MediaSource-Puffer bereit und mit dem < Video/ > -Element verknüpft ist, können wir einen SourceBuffer hinzufügen. Wir müssen ihm noch einmal sagen, welches Videoformat und welche Codecs wir verwenden, und dann wird es erstellt.



Schließlich können wir jetzt einzelne Fragmente abrufen und sie mithilfe der Append-Methode an das <Video /> -Element in unserem SourceBuffer senden und ein dynamisch erstelltes Video empfangen. Es kann auch für andere Anwendungsfälle verwendet werden, in denen Benutzer verschiedene Elemente des Videos unabhängig voneinander kombinieren und ihre eigenen Videos erstellen können, aber ich möchte nicht zu tief darauf eingehen.



Dies ist also fast der letzte Schritt, den wir unternehmen müssen. Sie haben ein Vertriebsnetzwerk, Sie haben Fragmente, und dann sendet der Browser die verschlüsselten und komprimierten Fragmente an das CDM, wo die Entschlüsselung und möglicherweise die Dekodierung durchgeführt wird. Anschließend werden die entschlüsselten und unkomprimierten Fragmente an den Browser zurückgesendet, wo sie visualisiert und angezeigt werden.



Manifest


Aber es gibt noch einen Punkt. Woher wissen wir, welche Fragmente wir herunterladen müssen, von wo und wann wir sie herunterladen müssen? Und dies ist der letzte Teil, die fehlende Anfrage aus dem Manifest. Wenn wir Netflix nach einem Manifest abfragen, benötigt es viele Daten. Wenn wir nur ein Video abspielen möchten, ist es uns wichtig, welches DRM-System wir verwenden, welches Video wir ansehen möchten (Netflix-ID, die von der URL kopiert werden kann) und Profile. Profile bestimmen, in welcher Auflösung wir Video empfangen und in welcher Sprache wir Audiospuren empfangen, in welchem ​​Format (Stereo, Dolby Digital usw.), ob wir Untertitel verwenden usw.



MPEG-DASH


Das am häufigsten verwendete Manifestformat ist MPEG-DASH. Es stimmt, Apple verwendet ein anderes Format - HSL, das anscheinend einer Liste von Dateien im alten Winamp-Player ähnelt. Aber Widevine und Microsoft verwenden genau MPEG-DASH. Es basiert auf XML und definiert alles: Dauer, Puffergröße, Inhaltstypen, wann welche Fragmente geladen werden, Fragmente für unterschiedliche Auflösungen sowie adaptives Bitraten-Switching. Letzteres bedeutet, dass die Wiedergabe nicht stoppt, wenn ein Benutzer beispielsweise ein Video ansieht und gleichzeitig die Download-Geschwindigkeit sinkt, sondern sich die Videoqualität einfach verschlechtert. Dies liegt an der Tatsache, dass das Manifest dieselben Teile für unterschiedliche Auflösungen definiert, sie haben dieselbe Dauer und dieselben Indizes. Wenn die Download-Geschwindigkeit abnimmt, kann der Browser daher einfach zu einem Stream mit einer niedrigeren Auflösung wechseln, ohne den Download anzuhalten und ohne die Daten zu puffern.

So sieht das Manifest für Guardians of the Galaxy aus. Darin können wir sehen, dass Menschen mit unterschiedlichen Download-Geschwindigkeiten Videos mit unterschiedlicher Qualität erhalten, sowie die Tatsache, dass es Audiospuren für Menschen mit Hörbehinderungen gibt. Es werden auch Untertitel geschrieben.



Wir haben eine Dauer und einen Hinweis auf die Zeit, ab der die Wiedergabe gestartet werden soll. Diese Funktion wird beispielsweise verwendet, wenn Sie die Anzeige unterbrechen und dann wieder zum Video zurückkehren, beginnend an der Stelle, an der Sie aufgehört haben.



Es gibt auch wieder Robustheit, die besagt: Dieses Fragment kann nur verloren gehen, wenn Ihr System die Anforderungen erfüllt. In diesem Fall handelt es sich um Hardware-Decodierung - Hardware Secure Codecs.



Für denselben Teil des Videos können Sie eine beliebige Anzahl von Fragmenten mit unterschiedlichen Auflösungen bestimmen.



Anschließend erhalten Sie die URL zum Laden des Fragments, und der Bereichsparameter zeigt den Wertebereich in Millisekunden an.



Dies ist der letzte Teil. Manchmal erhalten Sie auch ein Manifest vom CDN. Einige Anbieter verfügen über einen separaten Server für die Fragmentübermittlung. Meistens stammen sie jedoch von demselben Computer wie die Manifestfunktionalität. Wenn wir das Manifest heruntergeladen haben, wissen wir, welche Fragmente wir herunterladen müssen, können eine Anfrage nach Fragmenten senden und dann von CDM entschlüsseln und entschlüsseln.



Im Allgemeinen ist das alles. Alles, was oben gesagt wurde, reicht aus, um einen Open-Source-Player zum Ansehen von Videos von Amazon, Sky und anderen Plattformen sowie zum Ansehen von Videos von fast jedem Anbieter zu entwickeln.

Msl


Netflix hielt es für sinnvoll, eine zusätzliche Nachrichtenverschlüsselung zwischen dem Browser und dem Server hinzuzufügen. Sie nannten es die "Nachrichtensicherheitsschicht", die Nachrichtensicherheitsschicht oder MSL. Es macht nichts direkt mit dem Video, es ist nur eine zusätzliche Verschlüsselungsebene. Einer der Gründe für die Implementierung von MSL ist, dass HTTPS nicht sicher genug ist. MSL hingegen ist Open Source, sodass Sie immer sehen können, wie es funktioniert. Hier werde ich mich nicht mit diesem Thema befassen, und wenn Sie interessiert sind, finden Sie in ihrem Blog immer Informationen darüber, warum Netflix MSL macht. GitHub verfügt über eine detaillierte Dokumentation zu seiner Implementierung und den funktionierenden Implementierungen in Java.

Es gibt auch eine Python-Implementierung , die wir mit Freunden geschrieben haben. Soweit ich weiß, ist dies der einzige funktionierende Open Source-Client für Netflix. Er arbeitet mit Kodi Media Center zusammen. Zur Visualisierung können Sie den VLC Player oder eine andere geeignete Software verwenden.

Und wieder die "Black Box"


Sie haben also gesehen, was wir für die Implementierung benötigen und wie oft ich CDM erwähnt habe - die „Black Box“, die von Google heruntergeladen wird. So haben wir das Video wieder in die „Black Box“ zurückgebracht. Das schöne <Video /> -Element ist uns wieder verborgen. Wir haben Software von Drittanbietern hinzugefügt, die uns hilft, aber gleichzeitig geschlossen ist und die wir nicht verwalten können. Es kann viele unauffällige Dinge tun: Nachverfolgung, Analyse, Senden von Daten ...



Dazu sagte Tim Berners Lee: "Im Allgemeinen ist es wichtig, EME als eine relativ sichere Online-Umgebung zu erhalten, in der Sie Filme ansehen können, sowie als die bequemste und eine, die es Teil des vernetzten Diskurses der Menschheit macht."

Es gibt aber auch andere Meinungen dazu. Insbesondere von der Electronic Frontiers Foundation, die vor dem Aufkommen von DRM Mitglied des W3C war. Sie sagen Folgendes: „2013 war EFF enttäuscht zu erfahren, dass das W3C das Standardisierungsprojekt für EME-verschlüsselte Medienerweiterungen übernommen hat. Tatsächlich handelt es sich um eine API, deren einzige Funktion darin bestand, DRM eine führende Rolle im Browser-Ökosystem zu verschaffen. Wir werden weiter dafür kämpfen, dass das Internet frei und offen ist. "Wir werden die US-Regierung weiterhin verklagen, um Gesetze aufzuheben, die DRM so giftig machen, und wir werden weiterhin auf der Ebene des globalen Rechts kämpfen."

Es fällt mir schwer zu sagen, wie ich damit umgehen soll. , , , . , Netflix, . , , .

, 24-25 , HolyJS 2018 Moscow , «The Universal Serial Web» : WebUSB, USB- . -, .

PS 1- . , — 50% .

Source: https://habr.com/ru/post/de426727/


All Articles