Giter Club home page Giter Club logo

kimb-technologies / radio-api Goto Github PK

View Code? Open in Web Editor NEW
59.0 11.0 5.0 2.5 MB

Silicon Frontier, Frontier Silicon, or Frontier Nuvola (Smart) Internet Radio alternative Web API — 📻💡

Home Page: https://hub.docker.com/r/kimbtechnologies/radio_api

License: GNU General Public License v3.0

PHP 72.79% JavaScript 4.80% Dockerfile 0.37% HTML 21.05% CSS 0.69% Shell 0.30%
api internet-radio docker docker-image radio-api radio-station podcasts gui stream hama

radio-api's People

Contributors

dirkbaumeister avatar kimbtech avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

radio-api's Issues

Question about nextcloud share

Hello, I tried to link the radio to the mentioned nextcloud share but without success.

Steps I did:

  • I created a nextcloud share without any password protection
  • stored some mp3 files there
  • opened the radio api gui and created a new radio station with nextcloud checkbox and ssl proxy selected
  • at the radio I can see and select the nextcloud share but no music will be played

What did I won't y?

Thank you
stoneubi

Podcasts HTTPS

Einige Podcasts leiten auf URLs mit SSL um, das Radio kann diese nicht lesen. Hier sollte die finale URL herausgefunden werden und diese an das Radio geschickt werden (diese finale URL ist öfter ohne SSL erreichbar.) Bsp: Soundcloud

Andernfalls könnte man per PHP einen Proxy aufbauen (Problem dabei u.a. Header wie Accept-Range die korrekt weitergeleitet und beantwortet werden müssen.)

v2.8.3 with CONF_USE_JSON_CACHE=true errors

I just tested v2.8.3 enabling CONF_USE_JSON_CACHE=true and removing the REDIS-related env vars (I also stopped my redis instance), but then the radio didn't work.

I didn't debug anything so far, but I stopped the container, added the REDIS-related variables again (but left the CONF_USE_JSON_CACHE=true), started the redis server, and everything works again.

Hopefully I'll have time to play with it tomorrow!
Thanks in any case, I would be happy to stop/remove redis from my server.

Originally posted by @reinob in #49 (comment)

Characters with diacritics are stripped

Describe the Bug
After saving as a user-defined stream BBC Radio nan Gàidheal, the à is stripped and only BBC Radio nan Gidheal remains.
Also an issue for stations by the Austrian broadcaster Österreichischer Rundfunk, e.g. Ö1.

To Reproduce
Steps to reproduce the behavior:

  1. Go to /gui
  2. In Name enter a character with a diacritic
  3. Press save
  4. Reload the page. The character has disappeared.

Radio-API Installation

  • Version of Radio-API: 2.8.0
  • Installation mode: Docker
  • DNS redirect via: Router
  • Radio vendor: Roberts
  • Usage of reverse proxy: no

Docs required how to use project without docker.

It seems that it would be good to have documentation how to setup this server without docker. It is required, e.g., for OpenWRT routers (routers can handle low load php-based webpages, but they definitely are not designed to use docker ecosystem!)

Audiobook mode

Add an audiobook mode which allows users to give a nextcloud share and listen to each audiofile in it in a chronological order.

Save the current file and restart from there file.

(Un-)read

Aktuell werden Episoden von Podcasts nur angezeigt, man weiß aber nie, ob man die Episode schon kennt (insbesondere, da nur die Anfänge der Namen sichtbar sind).

Hier wäre ein kleines * am Anfang schön, sofern eine Episode neu (ungehört ist).


Alle neuen Episoden mit * versehen, wenn gehört (die ID mit SearchType=5 und länger keine Liste abgerufen) per Redis speichern (Redis im Volume sichern?).

Need Help

Hello Everyone,

I have since years this radio : radio CGV dr30i.
I have read your very interesting work to save my prefered radios but i am not able to use your files, i dont understand nothing and english is not my language and i have not the capacity to do all request by your files. Google translator of course can help me but the use of your files is too technicial for me.

I have a computer with Windows 11 family connected by Ethernet on Internet with a router (called BOX in France).
I have the radio connected on internet by ethernet
Please consider i am an old person and i need some simple things 😜

Is it possible for you do a software like an internet browser maybe with all requested by the radio to see the list of my prefered radios and maybe to add others web radio and delete the closed radio in the list ? A software i have just to double click on it and all is ready ? Of course I can add some IP adress in a field if necessary but no much more.🤣

Tell me please if my request is possible or not and if you can release it. Or tell me if a software like that can already exists.

Thank you so very much in advance

Got a problem after PHP-Update to 8.3.

Perhaps it is a bug with radio-api on php 8.3. ... or just my faulty config after update.

  • non-docker environment
  • apache + php 8.3
  • dns via pihole points to local apache-server
  • 2 dual radios
  • worked until today with apache+php 8.2

I simply updated my linux and had to update some packages with php-stuff also.
Went from php 8.2. to 8.3.
Had to update the apache-config as well.

After that the radios didn't want to stream again.
First problem: the radios did try a fallback from dual.wifiradiofrontier.com to dual2.wifiradiofrontier.com.
Fixed it by adding dual2.* to the local-dns-records of pihole as well.
But still the radios could not open the menu or find the streams. I must have broken something else.

So I opened dual.wifiradiofrontier.com on a PC and got the gui. I could login and found all streams in the database as usual.
Means, DNS-redirect, modrewrite, and the webserver with php is working.

But: A call to http://dual.wifiradiofrontier.com/setupapp/dual/asp/BrowseXML/loginXML.asp?token=0 on the browser
gives nothing back, but should return: 3a3f5ac48a1dab4e

This is my PHPinfo:
http://tackin.de/radio-api_problem_2024-04-17.html

Could you please have a look at the PHPinfo and perhaps have a guess, where to look.

To solve that for now, I quickly switched to the latest docker-version and all radios are up and running just nice again. But I would like to be able to run it on the Webserver again without the docker-container.

Authentication for token-protected stream

I'm trying to get my Roberts 94i (based on the Silicon Frontier Venice 6.5 platform, firmware ir-mmi-FS2026-0500-0515-Stream94i_V2.14.35c.EX86167-V1.04), working with BBC Radio streams (again).
NB: BBC now uses MPEG-DASH, standard, Mozilla Developer Guide.

BBC streams use token-authenticated URLs, which means entering such a URL into favorites works only while the token is valid (a couple of days). After that, a new token is needed.

Packet capture reveals the following:

  1. Radio obtains an preliminary token by querying
    roberts.wifiradiofrontier.com/setupapp/Roberts/asp/BrowseXML/loginXML.asp?token=0

  2. Preliminary token is returned in an XML
    <EncryptedToken>3a3f5ac48a1dab4e</EncryptedToken>

  3. Radio requests stream URL
    roberts.wifiradiofrontier.com/setupapp/Roberts/asp/BrowseXML/Search.asp?sSearchtype=3&Search=1022963300812989&mac=df5a6f351be63ed3a85ea39f2aa9fd8a&dlang=eng&fver=8&ven=rob29

  4. MPD is returned:

    <?xml version="1.0" encoding="utf-8"?>
    <MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:dvb="urn:dvb:dash:dash-extensions:2014-1"
      xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
      type="dynamic" availabilityStartTime="1969-12-31T23:59:44Z"
      minimumUpdatePeriod="PT6H" timeShiftBufferDepth="PT6H" maxSegmentDuration="PT7S" minBufferTime="PT3.200S"
      profiles="urn:dvb:dash:profile:dvb-dash:2014,urn:dvb:dash:profile:dvb-dash:isoff-ext-live:2014"
      publishTime="2023-09-04T15:44:11">
        <UTCTiming schemeIdUri="urn:mpeg:dash:utc:http-iso:2014" value="http://time.akamai.com/?iso" />
        <BaseURL dvb:priority="1" dvb:weight="1" serviceLocation="cf">http://as-dash-ww.live.cf.md.bbci.co.uk/pool_904/live/ww/bbc_radio_fourfm/bbc_radio_fourfm.isml/dash/</BaseURL>
        <Period id="1" start="PT0S">
        <AdaptationSet group="1" contentType="audio" lang="en" minBandwidth="48000" maxBandwidth="96000"
                       segmentAlignment="true" audioSamplingRate="48000" mimeType="audio/mp4" codecs="mp4a.40.5" startWithSAP="1">
            <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
            <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
            <SegmentTemplate timescale="48000" initialization="bbc_radio_fourfm-$RepresentationID$.dash"
                           media="bbc_radio_fourfm-$RepresentationID$-$Number$.m4s" startNumber="1" duration="307200"/>
            <Representation id="audio=48000" bandwidth="48000"/>
            <Representation id="audio=96000" bandwidth="96000"/>
        </AdaptationSet>
      </Period>
    </MPD>
    
  5. Radio then sends this:
    redirect.airable.io/1807976396573832

  6. Which returns:
    http://open.live.bbc.co.uk/mediaselector/6/redir/version/2.0/mediaset/audio-syndication/proto/http/transferformat/dash/vpid/bbc_radio_fourfm?jwt_auth=eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjIiLCJpc3MiOiJ1ay5jby5iYmNfcmFkaW9zcGkiLCJhYWYiOnRydWV9.eyJzdWIiOiJjb20uYWlyYWJsZW5vdyIsImF1ZCI6ImJiY3JhZGlvIiwiY3ZpZHMiOlsidXJuOmJiYzpwaXBzOnBpZDpiYmNfcmFkaW9fZm91cmZtIl0sImlzcyI6InVrLmNvLmJiY19yYWRpb3NwaSIsImlhdCI6MTcwNjQ1OTU2NSwidmVyIjoxLCJleHAiOjE3MDY2MzIzNjV9.C1fdKHvoKgYxgtJEavBk-EfsatmeFTsrCHNqJTvUYfDb8ylgs3lQDaAtCoIHoneGQq5iUBBmdwmOrUYNAk_T5w

  7. Radio then sends the above URL, which returns a slightly different MPD:

    <?xml version="1.0" encoding="utf-8"?>
    <MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:dvb="urn:dvb:dash:dash-extensions:2014-1"
      xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
      type="dynamic" availabilityStartTime="1969-12-31T23:59:44Z"
      minimumUpdatePeriod="PT6H" timeShiftBufferDepth="PT6H" maxSegmentDuration="PT7S" minBufferTime="PT3.200S"
      profiles="urn:dvb:dash:profile:dvb-dash:2014,urn:dvb:dash:profile:dvb-dash:isoff-ext-live:2014"
      publishTime="2023-09-04T15:44:11">
        <UTCTiming schemeIdUri="urn:mpeg:dash:utc:http-iso:2014" value="http://time.akamai.com/?iso" />
        <BaseURL dvb:priority="1" dvb:weight="1" serviceLocation="ak">http://as-dash-ww-live.akamaized.net/pool_904/live/ww/bbc_radio_fourfm/bbc_radio_fourfm.isml/dash/</BaseURL>
        <Period id="1" start="PT0S">
        <AdaptationSet group="1" contentType="audio" lang="en" minBandwidth="48000" maxBandwidth="96000"
                       segmentAlignment="true" audioSamplingRate="48000" mimeType="audio/mp4" codecs="mp4a.40.5" startWithSAP="1">
            <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
            <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
            <SegmentTemplate timescale="48000" initialization="bbc_radio_fourfm-$RepresentationID$.dash"
                           media="bbc_radio_fourfm-$RepresentationID$-$Number$.m4s" startNumber="1" duration="307200"/>
            <Representation id="audio=48000" bandwidth="48000"/>
            <Representation id="audio=96000" bandwidth="96000"/>
        </AdaptationSet>
      </Period>
    </MPD>
    
  8. Radio then requests:
    open.live.bbc.co.uk/mediaselector/6/redir/version/2.0/mediaset/audio-syndication/proto/http/transferformat/dash/vpid/bbc_radio_fourfm?jwt_auth=eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjIiLCJpc3MiOiJ1ay5jby5iYmNfcmFkaW9zcGkiLCJhYWYiOnRydWV9.eyJzdWIiOiJjb20uYWlyYWJsZW5vdyIsImF1ZCI6ImJiY3JhZGlvIiwiY3ZpZHMiOlsidXJuOmJiYzpwaXBzOnBpZDpiYmNfcmFkaW9fZm91cmZtIl0sImlzcyI6InVrLmNvLmJiY19yYWRpb3NwaSIsImlhdCI6MTcwNjQ1OTU2NSwidmVyIjoxLCJleHAiOjE3MDY2MzIzNjV9.C1fdKHvoKgYxgtJEavBk-EfsatmeFTsrCHNqJTvUYfDb8ylgs3lQDaAtCoIHoneGQq5iUBBmdwmOrUYNAk_T5w

  9. Which finally returns a playable stream URL:
    http://a.files.bbci.co.uk/ms6/live/344XXXXX-XXXX-XXXX-XXXX-XXXXXXXXXA4B/audio/simulcast/dash/uk/pc_hd_abr_v2/cf/bbc_radio_fourfm.mpd (token redacted)

JWT decoded as follows:

    Header:
    {
      "alg": "ES256",
      "typ": "JWT",
      "kid": "2",
      "iss": "uk.co.bbc_radiospi",
      "aaf": true
    }
    Payload:
    {
      "sub": "com.airablenow",
      "aud": "bbcradio",
      "cvids": [
        "urn:bbc:pips:pid:bbc_radio_fourfm"
      ],
      "iss": "uk.co.bbc_radiospi",
      "iat": 1706459565,
      "ver": 1,
      "exp": 1706632365
    }

(valid for two days).

Now I know I never signed into anything, nor was there another mechanism to register the radio somewhere.
In other words, whatever the authentication mechanism is, it must rely on knowable properties the radio can transmit, e.g. the User-Agent FS L IR/0.1, or possibly the MAC (starting with 00:22:61), although I couldn't find that in any of the packets.

Can we replicate this authentication mechanism to get a valid token, and rotate that as needed?

Rewirting of URLs with parameters

There is an issue with the rewriting of URLs. I'm using lighttpd, and rewrite works fine.

But, the incoming URLs are like these :
/setupapp/fs/asp/BrowseXML/loginXML.asp?token=0
/setupapp/fs/asp/BrowseXML/Search.asp?sSearchtype=3&Search=8641682810150088&mac=&dlang=eng&fver=7

The rewrite says : rewrite ^(.*)$ /index.php?uri=$1 last;

but in such a case, that would means that the final url has 2 ? in it :
/index.php**?uri=/setupapp/fs/asp/BrowseXML/loginXML.asp?**token=0

which obviously cannot work.
How to make this work ?

"Update Available" still shown after Update

After a successful update the "Update Available" banner may be still shown, while no update is available.
(The Problem is the caching of the Update Available status.)

Thus, after an update Radio-API should check again for new updates and if there are none, hide the banner.

Medion MD88289 shows "Network Error" when being redirected to Radio API

Hello,

I am trying to set up Radio-API using Docker on a Synology NAS. As far as I can tell, everything seems to be set up correctly. I can reach the Radio-API GUI from every computer inside of the LAN by using its local domain radioapi.local (it then asks for the GUI code, as expected). Also, Radio-DNS is up and running and by using nslookup from Windows, I can confirm that the alternative DNS can be reached and provides the expected output.

However, my Internet Radio Medion MD88289 starts showing "Network Error" in the "Internet Radio" - mode as soon as I set it up for the alternative DNS. It is then still able to access the local Fritz!Box MediaServer, for instance and play music from it. But the Internet Radio function is no longer working. It also does not show the link to the Nuvola Service with the respective device code any more when I try to open the list of favorites.

Can you provide any hints for further diagnosis?

Docs required how to use it without docker.

It seems that it would be good to have documentation how to setup this server without docker. It is required, e.g., for OpenWRT routers (routers can handle low load php-based webpages, but they definitely are not designed to use docker ecosystem!)

Domain GUI and Radio

In some cases it may be helpful, if the domain name used with the GUI is different to the domain names used withe the radio.

This is because the radio will use tampered DNS answers while the devices accessing the GUI may not.

Uncaught RedisException: Connection refused

The goal is to run version 2.8.1 as docker container on a QNAP TS-253 (v 5.1.4.2696) using Container Station v3.0.5.623 to cater to a Robert 94i locally (only).

On starting up the container, I get the following PHP error message:

Fatal error: Uncaught RedisException: Connection refused in /php-code/classes/RedisCache.php:44 Stack trace: #0 /php-code/classes/RedisCache.php(44): Redis->pconnect('127.0.0.1', 6379) #1 /php-code/classes/Cache.php(131): RedisCache->__construct('allowed_domains') #2 /php-code/classes/Config.php(143): Cache->__construct('allowed_domains') #3 /php-code/classes/Login.php(20): Config::checkAccess() #4 /php-code/gui/index.php(18): Login->__construct() #5 {main} thrown in /php-code/classes/RedisCache.php on line 44
[~] # docker logs 1bab3a4b530d

Fatal error: Uncaught RedisException: Connection refused in /php-code/classes/RedisCache.php:44
Stack trace:
#0 /php-code/classes/RedisCache.php(44): Redis->pconnect('127.0.0.1', 6379)
#1 /php-code/classes/Cache.php(131): RedisCache->__construct('allowed_domains')
#2 /php-code/classes/Config.php(250): Cache->__construct('allowed_domains')
#3 /startup.php(24): Config::parseAllowedDomain(true)
#4 {main}
  thrown in /php-code/classes/RedisCache.php on line 44
[21-Jan-2024 18:06:41] NOTICE: fpm is running, pid 15
[21-Jan-2024 18:06:41] NOTICE: ready to handle connections
127.0.0.1 -  21/Jan/2024:18:07:11 +0000 "GET /index.php" 200
127.0.0.1 -  21/Jan/2024:18:07:13 +0000 "GET /gui/index.php" 200

Environment variables

Key Value
CONF_ALLOWED_DOMAIN all
CONF_CACHE_EXPIRE 1200
CONF_DOMAIN http://192.168.2.51
CONF_LOG_DIR /php-code/data
CONF_SHUFFLE_MUSIC true
DEV dev
DOCKER_MODE true
GPG_KEYS 1198C0117593497A5EC5C199286AF1F9897469DC C28D937575603EB4ABB725861C0779DC5C0A9DE4A FD8691FDAEDF03BDF6E460563F15A9B715376CA
PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PHPIZE_DEPS autoconf dpkg-dev dpkg file g++ gcc libc-dev make pkgconf re2c
PHP_ASC_URL https://www.php.net/distributions/php-8.3.1.tar.xz.asc
PHP_CFLAGS -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
PHP_CPPFLAGS -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
PHP_INI_DIR /usr/local/etc/php
PHP_LDFLAGS -Wl,-O1 -pie
PHP_SHA256 56445b1771b2ba5b7573453f9e8a9451e2d810b1741a352fa05259733b1e9758
PHP_URL https://www.php.net/distributions/php-8.3.1.tar.xz
PHP_VERSION 8.3.1

Troubleshooting

  1. http://192.168.2.51/setupapp/iden/asp/BrowseXML/loginXML.asp?token=0 → Success
  2. http://192.168.2.51/setupapp/iden/asp/BrowseXML/loginXML.asp?gofile=&mac=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&dlang=eng&fver=4&ven=iden00 → Failure
  3. Get the GUI-Code from the preceding response and try to used it to access the GUI at http://192.168.2.51/gui/ → Failure

Despite the CONF_LOG_DIR variable, I do not see any kind of log file in /php-code/data directory, only the radio files:

/php-code/data # ls -la
total 24
drwxrwxrwx    2 www-data www-data      4096 Jan 21 02:37 .
drwxr-xr-x    1 root     root          4096 Dec 31 04:27 ..
-rw-r--r--    1 www-data www-data       694 Dec 31 04:28 env.json
-rw-r--r--    1 www-data www-data       218 Jan 21 02:00 my_stations.json
-rw-r--r--    1 www-data www-data         3 Dec 31 04:28 podcasts_1.json
-rw-r--r--    1 www-data www-data       215 Dec 31 04:28 radios_1.json

There is no content in /var/log/nginx/error.log:

var/log/nginx # cat error.log 
/var/log/nginx # 

The shell on the container itself does not provide much useful output:

/php-code # nc 127.0.0.1 6379
/php-code # nc 192.168.2.51 6379
/php-code # ps -ef
PID   USER     TIME  COMMAND
    1 root      0:00 sh /startup.sh
   10 root      0:00 nginx: master process nginx -g pid /tmp/nginx.pid;
   11 www-data  0:00 nginx: worker process
   12 www-data  0:00 nginx: worker process
   13 www-data  0:00 nginx: worker process
   14 www-data  0:00 nginx: worker process
   15 root      0:00 php-fpm: master process (/usr/local/etc/php-fpm.conf)
   16 www-data  0:00 php-fpm: pool www
   17 www-data  0:00 php-fpm: pool www
   25 root      0:00 /bin/sh
   32 root      0:00 /bin/sh
   42 root      0:00 ps -ef

From ps, I get this impression Redis is simply not running. Is Redis supposed to come part of the container, or is there an implicit expectation that the host runs a Redis instance?
How can I continue troubleshooting this issue?

Screenshot of the GUI in README.md

One or two screenshots of the GUI in README.md would be nice.

Edit: also just noticed that
The image of [Radio DNS](https://hub.docker.com/r/kimbtechnologies/radio_api) is available for
should read
The image of [Radio DNS](https://hub.docker.com/r/kimbtechnologies/radio_dns) is available for

For standalone Radio-API version more elaborated configuration is needed

Hello!

Thanks a lot for SUCH fast changes, but some more are required: the standalone version required to obtain possibility to store config, saved station list and so on to the user-configured directories. I can explain: there are a lot devices that are run at not-so-much-enduring storage. It means that Raspberries and other similar SBCs very frequently have SDcard as filesystem storage. Or eMMC, or norFlash, or even USB flash. In any case the maximum number of writes for the each flash memory cell is VERY limited, so all current writings have to be made to /var/... or to /tmp... (it depends upon system architecture, for OpenWRT both /tmp and /var are mapped to the RAMdrive). So current station list and, especially, cache, should go to user-configured directory, or at least to something like /var/RadioAPI rather than ./data.
From the other point of view, configuration should be stored permanently, of course.
May we have additionally the full list of php extensions that are required?
And the last one (at least for now): we can use our own reverse proxies that seems suitable to us (e.g. haproxy for openwrt), how to switch off built-in php proxying feature?

Many thanks in advance!

Question and not issue

After a while I was able to get this wonderful setup to fly. My issue was a wrong setting in pihole to reroute the needed website. Solved it with this link:

https://medium.com/@containeroo/using-pi-hole-to-route-your-services-internally-2ff495093718

I do have a Hama IR 100 and the radio connected to my local provided server.

Question: the radio takes long to operate. This means that resolving the tuner list or loading a radio station takes long (about 30 second).

Does any one else realize this issue? Are there any tipps to speed up the system. Are there any puffer setting are something similar?

My setting is: proxmox server with Ubuntu lxc container, docker and portainer. The service is not published to the internet. The gui address is a local address.

Thank you
stoneubi

No GUI interface on the web server. My installation settings are wrong?

Radio-API Installation

  • Version of Radio-API: Version 2.8
  • Installation mode: Docker (import docker-compose.yml to CasaOS LXC [PROXMOX])
  • DNS redirect via: Adguard Home
  • Radio vendor: TechniSat DIGIRADIO-631
  • Usage of reverse proxy: no
  • Does another radio use your installation of Radio-API: no

Describe the Issue

  • No GUI interface on the web server.

Error Message or Log Files

In portainer.io:

Warning: Redis::pconnect(): php_network_getaddresses: getaddrinfo for redis failed: Name does not resolve in /php-code/classes/RedisCache.php on line 44
Fatal error: Uncaught RedisException: php_network_getaddresses: getaddrinfo for redis failed: Name does not resolve in /php-code/classes/RedisCache.php:44

Stack trace:
#0 /php-code/classes/RedisCache.php(44): Redis->pconnect('redis', 6379)
#1 /php-code/classes/Cache.php(131): RedisCache->__construct('allowed_domains')
#2 /php-code/classes/Config.php(250): Cache->__construct('allowed_domains')
#3 /startup.php(24): Config::parseAllowedDomain(true)

}
thrown in /php-code/classes/RedisCache.php on line 44
[31-Dec-2023 20:55:01] NOTICE: fpm is running, pid 16
[31-Dec-2023 20:55:01] NOTICE: ready to handle connections
127.0.0.1 - 31/Dec/2023:20:55:22 +0000 "GET /index.php" 200

My settings for docker-compose:

name: resilient_khalid
services:
radio_api:
cpu_shares: 50
command: []
container_name: radio-api
depends_on:
redis:
condition: service_started
required: true
deploy:
resources:
limits:
memory: 2048M
environment:
- CONF_ALLOWED_DOMAIN=all
- CONF_CACHE_EXPIRE=1200
- CONF_DOMAIN=http://casaos.lan/
- CONF_REDIS_HOST=redis
- CONF_SHUFFLE_MUSIC=true
- CONF_STREAM_JSON=false
image: kimbtechnologies/radio_api:latest
ports:
- target: 80
published: "8090"
protocol: tcp
restart: always
volumes:
- type: bind
source: /DATA/Media/TECHNISAT/data
target: /php-code/data
- type: bind
source: /DATA/Media/TECHNISAT
target: /php-code/media
devices: []
cap_add: []
network_mode: bridge
privileged: false
redis:
cpu_shares: 50
command: []
container_name: radio-api-redis
deploy:
resources:
limits:
memory: 2048M
image: redis:alpine
ports:
- target: 6379
published: "6379"
protocol: tcp
restart: always
volumes: []
devices: []
cap_add: []
environment: []
network_mode: bridge
privileged: false
x-casaos:
author: self
category: self
hostname: casaos.lan
icon: ""
index: /
port_map: "8090"
scheme: http
store_app_id: resilient_khalid
title:
custom: technisat

Better "Own Streams"

Currently the "Own Streams" feature seems a bit strange. Thus, update it to a more straight forward idea.
Generally, its a bit similar to a RSS Feed for a podcast, but it retrieves JSON files created for Radio-API.


New "Own Streams":

Only one config. value CONF_STREAM_JSON which points to a url with an json file/ response of the form:

[
  {
    "name" : "Name of File", 
    "url" : "http://my-stream.url/file.mp3"
    "live" : false
  },
  {
    "name" : "Name of Stream", 
    "url" : "http://my-stream.url/live.m3u"
    "live" : true
  },
  ...
]

The Radio-API then shows an entry for each item in the json file and allows to play the given url .
Using live can be choose if the file needs to be played as radio station (= live stream but no play/ pause, no fast forward) or as podcast episode (= entire file available and supports play/ pause, fast forward).

KIMB-technologies/Radio-API

Hello
I have 4 wifi radios: all 4 were previously connected to wifi.

Now I have connected 2 to Lan and the broadcast list has disappeared on both (back to the original Frontier broadcast list). Switched the 2 back to wifi and still I can't get their list - what am I doing wrong?

Is it not possible to connect the radio to the Lan to get the broadcast list from them? KIMB-technologies/Radio-API

thx
Sepp

Multiuser

Aktuell gibt es eine große Bibliothek für alle. Hier sollte die ID jedes Radio zu einer anderen Bibliothek führen.

Dazu eine ID im Menü des Radio, die in der GUI eingegeben die spezifische Bibliothek anzeigt.

Musik Stream

Use a Nextcloud folder as Radio Station, in a way that all audio files in the folder are played one after one.
Create and use a M3U file as stream url.

Backup and Restore function

It would be great to have an backup and restore function for the entire system configuration and radios.

E.g. I need to transfer the actual docker image from on server to another server.

In this case it would we good to open the GUI and to have a button called backup. This backup function should export the existing system and all radios including all stations to one file, which could the saved at the local pc. After that I would like to install the new docker image at another server and once the docker image is up and running, I would like to open the GUI and import the backup file. This should overwrite the whole system and should import all radios with all radio stations assigned to the radios.

At the last step I would change the dns settings to address the new ip and viola the transfer has been finished. If I now switch on the radio everything would be the same and no changes have to be done on the radio.

This function could also be used for regular backups 👍😃

Maybe you could implement this useful function.

Thank you so much
Stoneubi

Einstellungen : Reihenfolge ändern

Hallo,
kann man die Reihenfolge der 4 unten genannten Punkte ändern:

[Podcast →]
[Radiosender →]
[Radio-Browser →]
[GUI-Code: xxx →]

Wenn es möglich ist würde ich gerne den Radiosender auf Platz 1 haben.

Kann ich das selber wo einstellen ?

Danke im vorraus tolles API

lg Sepp

Unable to start a backup

Hi!
In the past I did my backups or relocation of the radio-API just by copying the ./data - folder to the new site. But now I wanted to try your new backup-function.
I tested the Nondockerversion with Apache. Works great with a tiny "less than 1MB-Storagefootprint" for the domain. ;-)
But ....
I found no direct-link to do a "Backup" in the GUI by clicking on it. So I just called:
http://wifiradiofrontier.com/gui/im-export.php
I added a token to env.json as suggested : "Nutzen Sie z.B. den Token TbscOdOBJjeVHrtB6CAw"
After that I called the page ../gui/im-export.php again and got the same message as before. "Der Import und Export ist für diese Installation deaktiviert! ...."

I might have got something wrong.
But a link to "click to make a backup" should be added to the gui anyway.

I also want to thank you for your current work investment to this project.
It's already really working fine and every little extra you provide, is an other cherry on the cake. ;-)

DUAL IR6 - Radio not supported

After bringing the Radio-API container finally up on my Raspi4 I tested it with my Dual IR6. It did not work and the radio could not connect to a stream. I guess the communication with frontier is a bit different on that device.
I made a TCP-Dump on the router filtered by the Radios MAC-address while the Radio powers up and connects to Frontier to dive into it.
I can provide this Dump to investigate whats going on and how you probably could adapt to this (and other) Radios in the code as well.
Someone interested?

Display Version at GUI

It would be nice to have the installed Version displayed at the GUI. E.g. installed version is 2.5.

It would also be even better to see at the same page that an new version is available.

Thank you very much for your effort and very good radio api.

I also found out that my Hama IR 100 as an option at system configuration that the radio will be still connected to the lan / wifi even at standby modus. Once activated the reload / restart after the wakeup from standby will be 10 times faster.

Thx you,
Stoneubi

Radio Station Database

Integrate a list of radio stations via the API of https://www.radio-browser.info/
There are two possibilities to do this:

  1. Add a feature to search the list of stations in the web gui of Radio-API. Thus, it is not necessary to manually get the streaming urls of radio stations. (The display in the radio stays unchanged.)
  2. Add stations from „Radio-Browser“ to the items displayed by the radio (as a new folder/ category). Possibly add a search etc.

Update own Streams via interval

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when ...

Describe the solution you'd like
Since GRUNDIG discontinued a vtuner service on December 24th, 2023, my Sonoclock radio was completely unusable.
With the pretty cool project here, I was able to get the whole thing up and running again.
Since I like to listen to music streams from Twitch and extract them with other software and make them available locally via the icecast server, I thought that the own streams function was perfect for this.
The own stream json file appears to only be read once at startup.
Is there an option to read the whole thing at intervals? The background is that these streams are not always online and I would like to only make the streams visible when they are live?

Additional context
First of all, none

LG Ralf

No multi-platform-build image available to run it on a Pi?

Hi!

Not sure if it is appropriate to open this as an issue. Please just close it if I'm wrong.
Tried to run the container on a Raspi 4.

I run into a docker-compose error:
radio_api The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested

And later this may have lead to the following error:
exec /usr/local/bin/docker-php-entrypoint: exec format error

It would be absolutely great to have a docker-container for a Raspberry Pi to run it in my local home-network.

btw: I tried to build an image from the repo on my RaspberryPi today which failed also redis-related.

Does this software require redis dependency to function?

Hello

For several days I have been attempting to install this software with mixed results. Bottom line it passses your first test - getting the token but that is about it. I have been able to fix all errors except the one getting access denied by redis:

2024/02/24 21:09:23 | stdout | thrown in /php-code/classes/RedisCache.php on line 44 -- | -- | -- 2024/02/24 21:09:23 | stdout | #4 {main} 2024/02/24 21:09:23 | stdout | #3 /startup.php(24): Config::parseAllowedDomain(true) 2024/02/24 21:09:23 | stdout | #2 /php-code/classes/Config.php(250): Cache->__construct('allowed_domains') 2024/02/24 21:09:23 | stdout | #1 /php-code/classes/Cache.php(131): RedisCache->__construct('allowed_domains') 2024/02/24 21:09:23 | stdout | #0 /php-code/classes/RedisCache.php(44): Redis->pconnect('127.0.0.1', 6379) 2024/02/24 21:09:23 | stdout | Stack trace: 2024/02/24 21:09:23 | stdout | Fatal error: Uncaught RedisException: Connection refused in /php-code/classes/RedisCache.php:44

I am I supposed to run another docker with redis? I have tried that with same results. Even if Frontier doesn't pull the plug in March, I would still like this for my sangean. Thank you.

Setup Test Program

Sometimes it is a bit fiddely to set up Radio-API (DNS queries, server names, ...).

Thus, it could be helpful to provide a tester application. The application should be a multi platform executable. Then, this executable can be run on a computer in the same network the radio is in and the executable will check the setup
and connection and give hints about all problems and possible error causes.

Implement this (possibly using GoLang) and provide the executables for Linux, MacOS, Windows.

No update

Stream names does not update, cause the DataList is only updated when changing the podcasts or radios.

Medion Radio - Network Timeout

Hi, I have also a Medion Radio here. I am running the docker radio-api and radio-dns on proxmox.

I have three Pixis Radio running well with that setup. I am using CONF_IP.

The Medion Radio got on Startup this "Network Error".

Any ideas?

Originally posted by @Demel75 in #34 (comment)

Question ("How To" Videos)

Hello
I have a question.
Now that frontier nuvola wants to add fees, it would be nice if beginners could also use your Radip API. Would it be possible to provide a video of the complete installation to make it easier to understand? I have a server at AllInk, but I can't really get any further with the instructions.

Sonoro radio not supported?

Tip

Please also see Troubleshooting.

Radio-API Installation

  • Version of Radio-API: latest
  • Installation mode: Docker
  • DNS redirect via: tried with and without
  • Radio vendor: Sonoro
  • Usage of reverse proxy: no
  • Does another radio use your installation of Radio-API: no

Describe the Issue
Received a Sonoro Stream radio, noticed the expiration of the link for stream radio on the website, so I found your project. The docker runs successfully, I get to the GUI code website. However, I am not able to get the GUI code from the radio. I did a tcpdump during the connection, and see the part, whenever I try to get a station list

The 2 most important environments in the docker-compose.yml are set as follows:

      - CONF_DOMAIN=http://wifiradiofrontier.com/ # the domain where the system is hosted
      - CONF_RADIO_DOMAIN=http://sonoro.wifiradiofrontier.com # different domain to use for connections of the radio (if set CONF_DOMAIN is for GUI)

Am I doing something wrong?

Error Message or Log Files

23:45:41.895181 IP (tos 0x0, ttl 64, id 50777, offset 0, flags [none], proto UDP (17), length 90)
    192.168.250.254.53 > 192.168.250.29.50895: [bad udp cksum 0x76c5 -> 0x7998!] 7 ServFail q: A? sonoro.wifiradiofrontier.com. 1/0/0 sonoro.wifiradiofrontier.com. [8h15m8s] A 217.33.180.98 (62)
23:45:41.902998 IP (tos 0x0, ttl 60, id 236, offset 0, flags [none], proto UDP (17), length 75)
    192.168.250.29.50896 > 192.168.250.254.53: [udp sum ok] 8+ A? sonoro2.wifiradiofrontier.com. (47)
23:45:41.926911 IP (tos 0x0, ttl 64, id 50778, offset 0, flags [none], proto UDP (17), length 91)
    192.168.250.254.53 > 192.168.250.29.50896: [bad udp cksum 0x76c6 -> 0xead8!] 8 ServFail q: A? sonoro2.wifiradiofrontier.com. 1/0/0 sonoro2.wifiradiofrontier.com. [11m2s] A 217.33.180.97 (63)
23:45:43.475659 IP (tos 0x0, ttl 60, id 237, offset 0, flags [none], proto UDP (17), length 74)
    192.168.250.29.50897 > 192.168.250.254.53: [udp sum ok] 9+ A? sonoro.wifiradiofrontier.com. (46)
23:45:43.500623 IP (tos 0x0, ttl 64, id 50876, offset 0, flags [none], proto UDP (17), length 90)
    192.168.250.254.53 > 192.168.250.29.50897: [bad udp cksum 0x76c5 -> 0x7995!] 9 ServFail q: A? sonoro.wifiradiofrontier.com. 1/0/0 sonoro.wifiradiofrontier.com. [8h15m7s] A 217.33.180.98 (62)
23:45:43.511639 IP (tos 0x0, ttl 60, id 238, offset 0, flags [none], proto UDP (17), length 75)
    192.168.250.29.50898 > 192.168.250.254.53: [udp sum ok] 10+ A? sonoro2.wifiradiofrontier.com. (47)
23:45:43.536196 IP (tos 0x0, ttl 64, id 50879, offset 0, flags [none], proto UDP (17), length 91)
    192.168.250.254.53 > 192.168.250.29.50898: [bad udp cksum 0x76c6 -> 0xebd4!] 10 ServFail q: A? sonoro2.wifiradiofrontier.com. 1/0/0 sonoro2.wifiradiofrontier.com. [11m1s] A 217.33.180.97 (63)
23:45:45.981796 IP (tos 0x0, ttl 60, id 239, offset 0, flags [none], proto UDP (17), length 74)
    192.168.250.29.50899 > 192.168.250.254.53: [udp sum ok] 11+ A? sonoro.wifiradiofrontier.com. (46)
23:45:46.006766 IP (tos 0x0, ttl 64, id 50978, offset 0, flags [none], proto UDP (17), length 90)
    192.168.250.254.53 > 192.168.250.29.50899: [bad udp cksum 0x76c5 -> 0x7994!] 11 ServFail q: A? sonoro.wifiradiofrontier.com. 1/0/0 sonoro.wifiradiofrontier.com. [8h15m4s] A 217.33.180.98 (62)
23:45:46.009885 IP (tos 0x0, ttl 60, id 240, offset 0, flags [none], proto UDP (17), length 75)
    192.168.250.29.50900 > 192.168.250.254.53: [udp sum ok] 12+ A? sonoro2.wifiradiofrontier.com. (47)
23:45:46.034061 IP (tos 0x0, ttl 64, id 50981, offset 0, flags [none], proto UDP (17), length 91)
    192.168.250.254.53 > 192.168.250.29.50900: [bad udp cksum 0x76c6 -> 0xeed0!] 12 ServFail q: A? sonoro2.wifiradiofrontier.com. 1/0/0 sonoro2.wifiradiofrontier.com. [10m58s] A 217.33.180.97 (63)
23:45:47.430817 IP (tos 0x0, ttl 1, id 241, offset 0, flags [none], proto UDP (17), length 155)
    192.168.250.29.57040 > 239.255.255.250.1900: [udp sum ok] UDP, length 127
23:45:47.576991 IP (tos 0x0, ttl 60, id 242, offset 0, flags [none], proto UDP (17), length 74)
    192.168.250.29.50901 > 192.168.250.254.53: [udp sum ok] 13+ A? sonoro.wifiradiofrontier.com. (46)
23:45:47.601526 IP (tos 0x0, ttl 64, id 51021, offset 0, flags [none], proto UDP (17), length 90)
    192.168.250.254.53 > 192.168.250.29.50901: [bad udp cksum 0x76c5 -> 0x7991!] 13 ServFail q: A? sonoro.wifiradiofrontier.com. 1/0/0 sonoro.wifiradiofrontier.com. [8h15m3s] A 217.33.180.98 (62)
23:45:47.604721 IP (tos 0x0, ttl 60, id 243, offset 0, flags [none], proto UDP (17), length 75)
    192.168.250.29.50902 > 192.168.250.254.53: [udp sum ok] 14+ A? sonoro2.wifiradiofrontier.com. (47)
23:45:47.628718 IP (tos 0x0, ttl 64, id 51023, offset 0, flags [none], proto UDP (17), length 91)
    192.168.250.254.53 > 192.168.250.29.50902: [bad udp cksum 0x76c6 -> 0xefcc!] 14 ServFail q: A? sonoro2.wifiradiofrontier.com. 1/0/0 sonoro2.wifiradiofrontier.com. [10m57s] A 217.33.180.97 (63)
23:45:48.632817 IP (tos 0x0, ttl 255, id 244, offset 0, flags [none], proto UDP (17), length 532)
    192.168.250.29.5353 > mdns.mcast.net.5353: [udp sum ok] 0*- [0q] 10/0/4 sonoroSTREAM 30589088d044._undok._tcp.local. (Cache flush) [1h15m] TXT "VendorID=undok" "DeviceInfoLocation=/dd.xml" "FsAPILocation=/fsapi", _services._dns-sd._udp.local. [1h15m] PTR _undok._tcp.local., _undok._tcp.local. [1h15m] PTR sonoroSTREAM 30589088d044._undok._tcp.local., 29.250.168.192.in-addr.arpa. (Cache flush) [2m] PTR sonoroSTREAM-30589088d044.local., sonoroSTREAM 30589088d044._spotify-connect._tcp.local. (Cache flush) [1h15m] TXT "CPath=/goform/spotifyConfig" "VERSION=1.0", _services._dns-sd._udp.local. [1h15m] PTR _spotify-connect._tcp.local., _spotify-connect._tcp.local. [1h15m] PTR sonoroSTREAM 30589088d044._spotify-connect._tcp.local., sonoroSTREAM 30589088d044._undok._tcp.local. (Cache flush) [2m] SRV sonoroSTREAM-30589088d044.local.:80 0 0, sonoroSTREAM-30589088d044.local. (Cache flush) [2m] A 192.168.250.29, sonoroSTREAM 30589088d044._spotify-connect._tcp.local. (Cache flush) [2m] SRV sonoroSTREAM-30589088d044.local.:80 0 0 ar: sonoroSTREAM 30589088d044._undok._tcp.local. (Cache flush) [1h15m] NSEC, 29.250.168.192.in-addr.arpa. (Cache flush) [2m] NSEC, sonoroSTREAM 30589088d044._spotify-connect._tcp.local. (Cache flush) [1h15m] NSEC, sonoroSTREAM-30589088d044.local. (Cache flush) [2m] NSEC (504)
23:45:52.260203 IP (tos 0x0, ttl 60, id 245, offset 0, flags [none], proto UDP (17), length 74)
    192.168.250.29.50903 > 192.168.250.254.53: [udp sum ok] 15+ A? sonoro.wifiradiofrontier.com. (46)
23:45:52.285362 IP (tos 0x0, ttl 64, id 51257, offset 0, flags [none], proto UDP (17), length 90)
    192.168.250.254.53 > 192.168.250.29.50903: [bad udp cksum 0x76c5 -> 0x7992!] 15 ServFail q: A? sonoro.wifiradiofrontier.com. 1/0/0 sonoro.wifiradiofrontier.com. [8h14m58s] A 217.33.180.98 (62)
23:45:52.288760 IP (tos 0x0, ttl 60, id 246, offset 0, flags [none], proto UDP (17), length 75)
    192.168.250.29.50904 > 192.168.250.254.53: [udp sum ok] 16+ A? sonoro2.wifiradiofrontier.com. (47)
23:45:52.313829 IP (tos 0x0, ttl 64, id 51259, offset 0, flags [none], proto UDP (17), length 91)
    192.168.250.254.53 > 192.168.250.29.50904: [bad udp cksum 0x76c6 -> 0xf4c8!] 16 ServFail q: A? sonoro2.wifiradiofrontier.com. 1/0/0 sonoro2.wifiradiofrontier.com. [10m52s] A 217.33.180.97 (63)
23:45:57.450231 IP (tos 0x0, ttl 1, id 247, offset 0, flags [none], proto UDP (17), length 155)
    192.168.250.29.57040 > 239.255.255.250.1900: [udp sum ok] UDP, length 127

Please add type = "Dir" in the station-favorites database.json

Hi!

In the radiolist we have the type: "radio" and "nextcloud"
We could use/need also: "Dir" (Directroy).

With that it is possible to browse through other external directrories like with this link:
http://shim-sec.wifiradiofrontier.com/vtuner/radios/country/8777677923440934?&startItems=1&endItems=100

And this Item-link is only usable for the radio if it's transmitted with type <ItemType>Dir</ItemType>
As long as Type is "Station" it will not be able to follow that item-link.

With that we would be able to browse the open frontier-database without a login or an account.
You can then add any new radiostation from this list to the internal radiopresets if a radio supports internal presets like mine.

The also given Bookmark link in the dir-listing is somehow useless but the station would play from the internal stored preset-url.

I guess there is not much to change in the code to make that fly.

Greetings!

GUI

Die Eingabe von Podcasts und Radios besser machen:

  • Radio
    • Eigene Bilder hochladen und URL der Bilder besser prüfen
    • Dropdown der Kategorien
  • Podcasts
    • Nextcloud oder RSS auswählen
    • passendes Feld für URL je nach Auswahl
    • Proxy für Audiodatein bzw. finale URL angeben (siehe #1) de/ aktivieren

Radio Display Translation

Currently the Radio displays most content in English, here a translations feature would be nice. (As already used for the web GUI).

Use the &dlang=ger or &dlang=eng values provided by the radio.

Add the translations somehow to class Output.

time.wifiradiofrontier.com

Hi,

I do have a question about the time handling. As decribed I managed my DNS resolver, pi-hole, do transfer all request for any *.wifiradiofrontier.com request to my / our great radio api.

On my HAMA100IR radio I can configure that the radio should sync the time automatically. According to my log files this is done connecting to time.wifiradiofrontier.com. As I re-route all the request for *.wifiradiofrontier.com to the radio api I wonder if the radio api handels the time request.

I think, this is not the case actually as my radio won't set up the right time automatically and I have to do this manually at the moment. This is not a big thing but as I recognize from my radio the time isn't always correct. Within a period of 4 week the radio is 2 to 3 minutes above correct time and therefore I don't think that the time is synced correctly for the moment.

Many thanks
Stoneubi

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.