Doprava | Pojďme programovat elektroniku | GIS

Šalinoleaks: Odposloucháváme pražské šaliny, autobusy a vlaky a kreslíme je na mapu

  • Kde jsou právě teď pražské tramvaje, autobusy a příměstské vlaky?
  • Zobrazí je oficiální mapa a mobilní aplikace
  • Věděli jste ale, že je k dispozici také API? Dnes si ho vyzkoušíme

Městská a regionální hromadná doprava v Česku patří bezesporu k těm nejlepším na světě. Není divu, na rozdíl třeba od USA u nás došlo k masivnímu a tržnímu rozpuku individuální automobilové dopravy až s pádem minulého režimu.

Vozidla jsou často vybavená přijímačem satelitní polohy, a tak bylo jen otázkou času, než dopravci vyrukují s mobilními a webovými aplikacemi, které na mapě a prakticky v reálnem čase zobrazí blížící se autobus či tramvaj.

První bylo Brno, pak přibyla i Praha, no a obě města dnes zároveň zveřejňují polohová data o svém vozovém parku skrze otevřená a bezplatná API. Využít je může každý z vás a postavit nad nimi prakticky libovolnou aplikaci:

Všechny tramvaje, autobusy a vlaky okolo Prahy

Dnes si to vyzkoušíme na co možná nejjednodušší aplikaci v Javascriptu a HTML. Výsledkem bude soubor salinoleaks.html, který po načtení v prohlížeči zobrazí pomocí knihovny Leaflet mapu OSM, načež se spojí se serverem Golemio API a stáhne z něj obrovský JSON se všemi autobusy, tramvajemi, vlaky a dalšími vozidly, které jsou součástí systému pražské integrované dopravy PID.

Klepněte pro větší obrázekKlepněte pro větší obrázekKlepněte pro větší obrázek
Sledujeme pražskou integrovanou dopravu ve své vlastní mapě se statistikou v javascriptové konzoli prohlížeče 

Aby to mohlo fungovat, nejprve si na webu Golemio API vygenerujeme osobní klíč API, pomocí kterého se budeme identifikovat. Jak už jsme si řekli výše, přístup k API je sice bezplatný, takže se nebojte žádných paušálů, klíč je ale potřeba i z toho důvodu, aby mohl správce systému zablokovat třeba ty uživatele, kteří API příliš zatěžují.

Golemio API, dej mi seznam všech vozidel

Tak, máme klíč v podobě dlouhého textového řetězce a teď už se tedy pojďme zeptat serveru, kde se právě teď pohybují všechna vozidla PID vybavené satelitním přijímačem. Slouží k tomu HTTP GET dotaz /vehiclepositions.

Klepněte pro větší obrázek
Opravdu velmi dlouhá odpověď  – strukturovaný text ve formátu JSON se stovkami vozidel pražské integrované dopravy

Na odkazu výše najdete všechny jeho parametry a když jej zavoláte v té nejjednodušší podobě https://api.golemio.cz/v2/vehiclepositions, tak…

Tak se nic nestane a server odpoví chybovým hlášením, protože nejsme přihlášení. Nepoužili jsme totiž ten klíč API, který musíme serveru odeslat ve speciální hlavičce x-access-token.

Stahujeme JSON v příkazové řádce

Na linuxových systémech by nám v tom pomohl třeba textový HTTP klient cURL a příkaz, který výsledek uloží do souboru praha.json:

curl --header "x-access-token: API klic" https://api.golemio.cz/v2/vehiclepositions > praha.json
Klepněte pro větší obrázek
Stažení obrovského JSON a uložení do souboru praha.json na Linuxu pomocí curl

Na Windows a v jeho PowerShellu bychom téhož dosáhli příkazem:

iwr https://api.golemio.cz/v2/vehiclepositions -Headers @{"x-access-token" = "API klic"} -OutFile praha.json
Klepněte pro větší obrázek
Stažení obrovského JSON a uložení do souboru praha.json v PowerShellu na Windows

Iwr je zkratka pro powershellový HTTP klient Invoke-WebRequest.

A teď si to vyzkoušíme v moderním Javascriptu

Dobrá, příkazovou řádku bychom měli, ovšem my si data stáhneme v Javascriptu. Nejprve se ale omluvím čtenářům, kteří holdují prehistorickým verzím webových prohlížečů.

Ty mají v seriálu o programování jednu velkou červenou stopku, já totiž hodlám používat jen moderní verze ECMAScriptu, ze kterého vycházejí i javascriptové implementace v prohlížečích.

Fetch API stáhne obří JSON

Stručně řečeno, pokud tento článek nečtete v Internet Exploreru, ve kterém to fakt nebude fungovat, můžete společně se mnou stáhnout data z webu Golemio pomocí vestavěného javascriptového rozhraní Fetch API pro asynchronní HTTP komunikaci.

Dotaz včetně speciální hlavičky s klíčem a přečtení výsledku ve formátu JSON by mohlo vypadat takto:

fetch("https://api.golemio.cz/v2/vehiclepositions", {method: "GET", headers: {"x-access-token": golemio_klic}})
    .then(response => response.json())
    .then(data => {
        console.log("Stazeny a dekodovany JSON:");
        console.log(data);
    });

Stovky zeměpisných souřadnic

Odpověď ve formátu JSON pro dotaz /vehiclepositions obsahuje pole features, což je vlastně seznam všech evidovaných prostředků PID, které se právě teď pohybují po Praze a v jeho širokém okolí. Během dne to budou vyšší stovky vozidel.

Klepněte pro větší obrázek
Kód výše vypsal do konzole webového prohlížeče objekt dekódovaného JSON

Každá položka dále obsahuje objekty geometry a properties.

Uvnitř geometry najdeme pole coordinates se souřadnicemi zeměpisné délky a šířky vozidla. Na mapu bychom mohli tímto způsobem vykreslit anonymní puntíky a kochat se hustotou pražské integrované dopravy, nicméně v obřím JSONu máme ještě ten objekt properties.

Klepněte pro větší obrázek
Rozbalil jsem první záznam v poli features a jeho vnořené objekty geometry a coordinates, kde konečně najdete údaj o zeměpisné poloze

Properties nabízí hromadu dodatečných informací o spoji. Třeba vnořenou položku properties.last_position.bearing, která obsahuje kurz/azimut vozidla v celých stupních, nebo objekt properties.last_position.delay s dodatečnými údaji o aktuálním zpoždění.

Klepněte pro větší obrázek
V objektu last_position najdete azimut, detaily o zpoždění a také zastávkách

Je to tramvaj? Kam jede? A kdo ji provozuje?

Vše ostatní se skrývá v objektu properties.trip. V podobjektu propertis.trip.gtfs to bude třeba položka route_type, která číselným indexem identifikuje typ linky. Hodnota 0 představuje tramvaj, 1 patří metru, 2 železnici3 autobusu a tak dále.

Jejich kompletní výčet najdete v dokumentaci specifikace GTFS, což je zkratka pro General Transit Feed Specification. Používá ji především Google pro popis veřejné dopravy, no a ostatní se přidali včetně našeho pražského API.

Klepněte pro větší obrázek
Objekt trip nabízí detaily o dopravci a lince 

Další zajímavou položkou je trip_headsign, tedy cíl vozidla (Kladno-Ostrovec), nebo trip_short_name (respektive alternativní route_short_name), která odhalí číslo linky (Os 9826). Položka trip.agency_name.scheduled konečně obsahuje jméno dopravce (ČESKÉ DRÁHY).

Knihovna Leaflet s mapovými podklady OSM

To by mohlo pro začátek stačit, ještě ale potřebujeme tu mapu. Javascriptová knihovna Leaflet funguje podobně jako třeba mapové API od Googlu, ovšem s tím rozdílem, že sama o sobě žádné mapové vrstvy nenabízí.

Může pracovat třeba s překrásnými dlaždicemi od placeného Mapboxu, poradí si ale i se základní mapou OpenStreetMap. Při splnění podmínek fair use můžete komunikovat s jejím mapovým serverem skrze Leaflet, aniž byste zaplatili jediný eurocent.

Férovým použitím je zejména to, že tímto způsobem nebude mapový server zatěžovat nějaká hypotetická velká komerční služba s hromadou návštěvníků. U té se předpokládá, že si stáhne surová vektorová data OSM a spustí si mapový server na své vlastní náklady. My kutilové se ale do mlhavých podmínek samozřejmě vejdeme.

Vytvoříme objekt mapy

Zobrazení mapy v Javascriptu je opravdu jednoduché. V HTML stačí vytvořit kontejner DIV s patřičným ID:

<div id="mapa"></div>

A v Javascriptu jej pak napojíme na objekt mapy knihovny Leaflet, přičemž rovnou určíme i souřadnice středu mapy (z.š. a z.d.) a míru přiblížení (vyšší číslo, větší přiblížení):

let mapa = L.map("mapa").setView([50.0835494, 14.4341414], 8);

Nastartovali jsme objekt mapy, ještě ji ale musíme napojit na nějakou službu poskytovatele mapových dlaždic. Jak už jsme si řekli, zvolíme projekt OSM, takže zbytek kódu by mohl vypadat takto:

let dlazdice = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
    attribution: 'Bastl: <a href="https://www.zive.cz">Živě.cz</a> | ' +
                 'Data: <a href="https://pid.cz/">PID</a> | ' +
                 'API: <a href="https://golemio.cz/projects">Golemio</a> | ' +
                 'Mapa: <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(mapa);

Součástí napojení vrstvy s dlaždicemi OSM je i uživatelská patička, která se zobrazí v pravém dolním rohu a obsahuje údaje o autorských právech a zdrojích. Čerpáme z OSM, takže pro splnění licenčních podmínek nesmí chybět odkaz. I kdyby to nebyla povinnost, je to přinejmenším slušnost!

Klepněte pro větší obrázek
A takto vypadá výsledek. Rozměry mapy lze nastavit v CSS. Viz kompletní kód na konci článku nebo na GitHubu

Značka v mapě s ikonou tramvaje

Mapa je zatím prázdná, když se ale vrátíme k JSONu s aktuálními pozicemi vozidel pražské integrované dopravy, můžeme nad mapu vynést markery – značky. A jelikož známe typ jednotlivých vozidel (ona položka route_type), mohla by mít každá značka specifickou ikonu podle toho, jestli se jedná o tramvaj, autobus, vlak a tak dále.

Značku s vlastní ikonou vytvoříme takto:

let ikona = L.icon({iconUrl:"tramvaj.png", iconSize:[24,24]});
let znacka = L.marker([50.1589, 16.4789], {icon: ikona}).addTo(mapa);

Jak vidno, jako ikonu značky použijeme obrázek tramvaj.png, který jsme si stáhli z webu flaticon.com. Obrázek má velikost 24x24 pixelů. Parametry 50.1589 a 16.47899 v objektu nové značky odpovídají zeměpisné šířce a délce a parametrem icon odkážeme na ikonu, kterou jsme si vytvořili v předchozím kroku.

Klepněte pro větší obrázek
Značka s ikonou tramvaje

Po klepnutí se zobrazí bublina s detaily spoje

Aby byla naše mapa interaktivní, po klepnutí na libovolnou značku v mapě se zobrazí bublina s detaily o konkrétním vozidlu, respektive lince. Použijeme údaje, které jsme vyčetli ze sekce properties u každé položky obřího pole features s jednotlivými vozidly, které právě teď eviduje API.

Jak na to? Bublinu připojíme ke značce pomocí metody bindPopup, jejímž parametrem je HTML kód, který se po klepnutí zobrazí v dialogu:

znacka.bindPopup("<h2>Linka 1234</h2>" +
                 "<b>Vozidlo</b>: Vlak<br>" +
                 "<b>Dopravce:</b> České dráhy<br />" +
                 "<b>Jede do:</b> Čmelákovice<br />"+
                 "<b>Nízkopodlažní:</b> Ano");

A to je celé. Jakmile náš Javascript projde celé pole JSON, vykreslí klidně i stovky dílčích značek nad mapou. Tu můžete libovolně přibližovat, posouvat a pro detail klikat na značky.

Klepněte pro větší obrázek
Připojili jsme ke značce bublinu s vlastním HTML

Kdybychom chtěli zobrazovat situaci v reálném čase, stačí se dopravního API dotazovat průběžně a obnovovat údaje nad mapou. Nicméně pozor, ten JSON je opravdu rozměrný – jsou to stovky vozidel –, takže byste v takovém případě měli zvážit frekvenci, abyste server zbytečně nezatěžovali a neporušili pravidla fair use.

Klepněte pro větší obrázek
Když vše složíme dohromady, získáme kompletní pohled na aktuální stav PID

To je už ale úkol pro vás a pro hlubší studium aplikačního rozhraní, které nabízí desítky dalších parametrů a funkcí.

Zdrojový kód

Na závěr nesmí chybět kompletní zdrojový kód salinoleaks.html. Stačí jej uložit do stejnojmenného souboru, do konstanty golemio_klic vložit vlastní klíč API, který jsme si vygenerovali v úvodu článku, a soubor načíst ve webovém prohlížeči.

<!DOCTYPE html>
<html lang="cs">
    <head>
        <title>Šalinoleaks: PRAHA</title>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin=""/>
        <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>

        <style>
            .leaflet-container {
                width: 1024px;
                height: 768px;
                max-width: 100%;
                max-height: 100%;
            }
        </style>

        <script>
            // Pomocny objekt s typy vozidel podle formatu GTFS a vlastnosti route_type
            // Viz https://developers.google.com/transit/gtfs/reference#routestxt
            // Kazde vozidlo ma svoji ikonu a pocitadlo pro statistiku 
            let vozidla_typy = {
                "0": {"ikona": L.icon({iconUrl:"tram.png", iconSize:[24,24]}), "nazev": "Tramvaj", "pocet": 0},
                "1": {"ikona": L.icon({iconUrl:"metro.png", iconSize:[24,24]}), "nazev": "Metro", "pocet": 0},
                "2": {"ikona": L.icon({iconUrl:"train.png", iconSize:[24,24]}), "nazev": "Vlak", "pocet": 0},
                "3": {"ikona": L.icon({iconUrl:"bus.png", iconSize:[24,24]}), "nazev": "Autobus", "pocet": 0},
                "4": {"ikona": L.icon({iconUrl:"ship.png", iconSize:[24,24]}), "nazev": "Loď", "pocet": 0},
                "5": {"ikona": L.icon({iconUrl:"tram.png", iconSize:[24,24]}), "nazev": "Lanová tramvaj", "pocet": 0},
                "6": {"ikona": L.icon({iconUrl:"lift.png", iconSize:[24,24]}), "nazev": "Lanovka", "pocet": 0},
                "7": {"ikona": L.icon({iconUrl:"lift.png", iconSize:[24,24]}), "nazev": "Pozemní lanovka", "pocet": 0},
                "11": {"ikona": L.icon({iconUrl:"bus.png", iconSize:[24,24]}), "nazev": "Trolejbus", "pocet": 0},
                "12": {"ikona": L.icon({iconUrl:"train.png", iconSize:[24,24]}), "nazev": "Jednokolejka", "pocet": 0}
            };

            // Pomocny objekt pro statistiku dopravcu
            let dopravci = {};

            // Pomocne pole se znackami vsech vozidel v mape
            // Nevyuzivame jej, ale mohlo by pomoci s dalsim managementem
            // Treba s mazanim znacek, filtrovanim atp.
            let vozidla_markery = [];

            // Klic do systemu Golemio, ktere pro PID zpracovava
            // aplikacni rozhrani o pohybu vozidel. Je soucasti
            // HTTP dotazu na server https://api.golemio.cz
            // Klic si muzete bezplatne vygenerovat na webu:
            // https://api.golemio.cz/api-keys/dashboard
            // Dokumentaci ke Golemio API najdete na webu:
            // https://golemioapi.docs.apiary.io/#reference/public-transport/realtime-vehicle-positions/get-all-vehicle-positions
            // !!! BEZ RUCNIHO NASTAVENI TETO HODNOTY NEBUDE MAPA FUNGOVAT !!!
            const golemio_klic = "";


            // Po nacteni stranky spust tuto funkci
            window.onload = () =>{

                // Objekt mapy Leaflet vycentrovane na souradnice stredu Prahy a priblizeni 10 (vyssí cislo, vyssi priblizeni)
                // Dokumentace knihovny Leaflet: https://leafletjs.com/SlavaUkraini/reference.html
                let mapa = L.map("mapa").setView([50.0835494, 14.4341414], 8);

                // Objekt poskytovatele mapovych dlazdic pro Leaflet
                // Pouziji bezplartny pristup k OSM
                // Pozor, dodruzjte politiku fair use a nepretezujte OSM!
                // Mohl bych pouzit take placeny Mapbox a dalsi poskytovatele 
                // V mape nezapomenu uvest zdroje dat "attribution", ktere se zobrazi v paticce
                let dlazdice = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
                    attribution: 'Bastl: <a href="https://www.zive.cz">Živě.cz</a> | ' +
                                 'Data: <a href="https://pid.cz/">PID</a> | ' +
                                 'API: <a href="https://golemio.cz/projects">Golemio</a> | ' +
                                 'Mapa: <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
                }).addTo(mapa);

                // Spojim se asynchronne s HTTP serverem Golemio, ktere zpracovava API pro ROPID
                // a polozim dotaz /vehiclepositions, ktery vrati obrovsky JSON
                // s polohami vsech vozidel prazske integrovane dopravy
                console.log("Stahuji šaliny a další věci, které jezdí v Praze...");
                fetch("https://api.golemio.cz/v2/vehiclepositions", {
                    method: "GET",
                    // V HTTP dotazu musi byt hlavicka x-access-token,
                    // ktera obsahuje osobni klic API
                    headers: {
                        "Content-Type": "application/json; charset=utf-8",
                        "x-access-token": golemio_klic
                    }
                })
                    .then(response => response.json()) // Pokud jsem ziskal odpoved, interpretuji ji jako JSON
                    .then(data => { // Objekt "data" nyni obsahuje citelny JSON

                        // Jednotliva vozdila jsou ve vnorenem poli features,
                        // a tak pro kontrolu vypisu jeho delku
                        console.log(`Ale ne, v Praze a okolí se pohybuje ${data.features.length} prostředků MHD. To je více než v Brně!`);
                        
                        // Projdu pole features s vozdily
                        for(const vozidlo of data.features){
                            let zd = vozidlo.geometry.coordinates[0]; // Zemepisna delka vozdila
                            let zs = vozidlo.geometry.coordinates[1]; // Zemepisna sirka vozidla
                            let linka = vozidlo.properties.trip; // Informace o lince a vozidlu

                            // Typ linky ve form8tu GTFS
                            // Viz https://developers.google.com/transit/gtfs/reference#routestxt
                            let typ = linka.gtfs.route_type;

                            // Navysim pocitadlo zjisteneho dopravniho prostredku kvuli statistice
                            vozidla_typy[typ].pocet++;
                            
                            // Podle GPS polohy a typu vozidla vytvorim na mape znacku s konkretni ikonou
                            let marker = L.marker([zs, zd], {icon: vozidla_typy[typ].ikona}).addTo(mapa);

                            // Po klepnuti na znacku se zobrazi bublina s popisem linky
                            let nizkopodlazni = (linka.wheelchair_accessible)? "ano" : "ne";
                            let cislo_linky = (linka.gtfs.trip_short_name != null)? linka.gtfs.trip_short_name : linka.gtfs.route_short_name;
                            marker.bindPopup(`<h2>Linka ${cislo_linky}</h2>` +
                                             `<b>Vozidlo</b>: ${vozidla_typy[typ].nazev}<br>` + 
                                             `<b>Dopravce:</b> ${linka.agency_name.scheduled}<br />` +
                                             `<b>Jede do:</b> ${linka.gtfs.trip_headsign}<br />` +
                                             `<b>Nízkopodlažní:</b> ${nizkopodlazni}`);

                            // pridam znacku do pole znacek, kdybych s nim ichtel dale hroamdne pracovat
                            // Treba kdybych je chtel smazat
                            vozidla_markery.push(marker);

                            // Aktualizuji pocitadlo dopravcu
                            if(dopravci.hasOwnProperty(linka.agency_name.scheduled)) dopravci[linka.agency_name.scheduled]++;
                            else dopravci[linka.agency_name.scheduled] = 1;
                        }

                        // Na zaver vypisu statisrtiku vozdel, tedy pocet pro kazdy typ
                        console.log("---------------------------------------------------");
                        console.log("Statistika vozidel:");
                        for (const [vozidlo, vlastnosti] of Object.entries(vozidla_typy)) {
                            console.log(` ${vlastnosti.nazev}: ${vlastnosti.pocet}`);
                        }

                        // A také statistiku dopravcu, tedy pocet vozdel, ktere prave vypravili
                        console.log("---------------------------------------------------");
                        console.log("Statistika dopravcu:");
                        for (const [operator, pocet] of Object.entries(dopravci)) {
                            console.log(` ${operator}: ${pocet}`);
                        }

                        // A jeste vypisu kompletni JSON, pro dalsi studium, co vsechno obsahuje
                        console.log("---------------------------------------------------");
                        console.log("Surový JSON:");
                        console.log(data)

                    })
                    // V pripade jakekoliv chyby zobrazim v konzoli chybove hlaseni
                    .catch(e => {
                        console.log("Ale ně, něco se pokazilo. Uklidni se u pořadu Týden Živě, a pak to zkus znovu!");
                        console.log(e);
                    });
            }

        </script>
    </head>
    <body>
        <h1>Šalinoleaks: PRAHA</h1>
        <div id="mapa"></div>
    </body>
</html>
Diskuze (48) Další článek: Nový web ProUkrainu.cz: Vydavatelství Czech News Center pomáhá lidem, kteří prchají před válkou

Témata článku: Google, Windows, Linux, Doprava, Programování, Pojďme programovat elektroniku, USA, Internet Explorer, Mapy, Brno, České dráhy, Praha, Javascript, GPS, GitHub, API, OpenStreetMap, GIS, JSON, Fetch API, Ropid, Mapa, Ikona, PowerShell, CSS



Sex manželských párů? Jen výjimečně. Ložnice ovládnou roboti s umělou inteligencí

Sex manželských párů? Jen výjimečně. Ložnice ovládnou roboti s umělou inteligencí

** Sex manželských párů jen při zvláštních příležitostech. ** Ložnice ovládnou sexuální roboti s umělou inteligencí. ** I to je jeden ze závěrů Mezinárodní robotické konference.

Filip KůželJiří Liebreich
RobotiSexUmělá inteligence
Recenze hry Teenage Mutant Ninja Turtles: Shredder’s Revenge. Hrdinové, kteří nestárnou

Recenze hry Teenage Mutant Ninja Turtles: Shredder’s Revenge. Hrdinové, kteří nestárnou

Leonardo, Raphaelo, Michelangelo, Donatello, Tříska, April a další jsou opět tady. Dáte jim šanci v pixel artovém beat 'em up retru?

Ladislav Novák
RecenzeArkádyAkce
Jak poznat, že máte možná hacknutý telefon? Toto je devět symptomů, které můžete pozorovat

Jak poznat, že máte možná hacknutý telefon? Toto je devět symptomů, které můžete pozorovat

** Jak poznat, že je váš smartphone hacknutý? ** Hledejte známky po nestandardním chování telefonu ** Stačí když telefon vydrží méně nebo topí i v klidovém režimu...

Martin Chroust
Jak...Malware
Nový hit. Tahle appka vám udělá profilovku jako od pouličního ilustrátora

Nový hit. Tahle appka vám udělá profilovku jako od pouličního ilustrátora

** Aplikace NewProfilePic se na Androidu stala hitem ** Můžete si v ní vytvořit profesionálně vypadající profilovky ** Pozor ale na agresivní cenovou politiku za Pro verzi

Martin Chroust
FotografieUmělá inteligenceMobilní aplikace
Sociální síť BeReal jde proti proudu. Žádné filtry a přetvařování, tohle má být čistá realita

Sociální síť BeReal jde proti proudu. Žádné filtry a přetvařování, tohle má být čistá realita

** BeReal je novou hvězdou mezi sociálními sítěmi ** Ukazuje pouze všední realitu běžných dní ** Aplikace vám jednou denně dá dvě minuty na poslání vlastní fotky

Martin Chroust
BeRealMobilní aplikaceSociální sítě