Web APP to listen to Rac1 radio station podcasts. Uses React as JS frontend library and GitHub pages to publish it at Rac1 podcast player at Github Pages. There, you will find this repo's gh-pages
branch contents, which are the results of executing yarn build
on this project's GitHub workflow/Actions using this project's source application (See more in the Install section).
The podcasts lister is a pure JS lib, which only depends on abortcontroller-polyfill to help GoogleBot execute modern JS, so you can easily re-use it for other JS projects.
I made this app for 3 reasons:
- I needed a better way to listen to those podcasts (because the official app is not useful to me) and I wanted it to be easily compatible with all my devices.
- Learn modern JavaScript (and some other modern stuff): I've been using JavaScript (mostly with JQuery) since a long time ago. Doing an app on my free time is a good way to me to learn a new language or refreshing it.
- This is an open and free (open, gratis and libre) app. It can serve as:
- Learning material (as I did). You may want to learn some of the libs and APIs used here.
- Share and re-use. You may want to use it as a starting point for your own app, or you may want to add parts of the code to your own app. Please, follow GPLv3.
- This source code and the working APP also serve as presentational card for my '20s frontend abilities. If you want to hire me, send me a PM.
Inspired by my command line Python app Rac1.py, which was not enough for my Android phone ;P
- Joan Domingo's Podcasts-RAC1-Android android app
- emibcn's (me) Rac1.py command line app
- emibcn's (me) Covid Data
Refactored
web application, using Material UI (a still better example of what I can do).
- ReactJS based browser Single Page Application (SPA) and Progressive Web Application (PWA)
<audio>
HTML tag, via react-audio-player- Nice DatePicker to allow listening to any day's podcasts
- Use Fontawesome free icons
- Use react-burger-menu to display off-canvas menu
- Use react-responsive to differentiate display depending on media sizes (design still in construction)
- Use react-translate to translate components
- Use react-helmet to handle changes to HTML document title (in the future, others, like
meta
tags) - Use react-simple-storage to save and retrieve state to and from
localStorage
- Use <HashRouter> to handle date and podcast selection, linking and history (Github Pages doesn't -easily- allows <BrowserRouter>)
- Use and register the Service Worker provided by Create React App, using the default CRA service worker message passing mechanism to allow communicating with it to force an update from within the app using my @3m1/service-worker-updater externalyzed library.
- Use react-modal for showing some pages inside a modal (using React Portals), while player may still be playing in the background.
- Use raw.macro to load raw HTML into bundle (for the Privacy Policy).
- Use react-component/slider for volume control (and possibly others in the future!)
- Use react-component/switch for user tracking opt-in/opt-out, with user's
DoNotTrack
value as default. - Use GoogleAnalytics with React GA (integrated as a React component and a HOC) for usage statistics.
- Respect user's DNT and don't even load it if user agent reports DNT header or a bot user agent is detected, unless the user explicitly opts in to tracking.
- Show modal with privacy policy on first visit.
- Allow users without DNT to explicitly opt out from tracking.
- Report Web Vitals to GA (if enabled) using a dedicated component.
- Send events to GoogleAnalytics (when active) combinig React HOC and React Context at GAListener submodule.
- Use React's Error Boundaries in
ErrorCatcher
component to:- Catch errors created during ReactDOM rendering
- Send them to GoogleAnalytics (when active) to help improve the app
- Allow the user a possible option to recover from the error, which includes a possible app update
- Catch backend errors and route them into ReactDOM, where they will be handled by the
ErrorCatcher
component
- Docker with DockerCompose to start a development container, with all the Create React App goodies
- Always with a coherently time ordered list of available podcasts
- Auto play next podcast when currently played one finishes (as a normal playlist)
- Ability to update podcasts list
- Autoupdate podcasts list when trying to play next podcast after last one, and play the next one (if there is any) after the update finishes
- Show currently playing program metadata: Name, author, schedule, image
keyPress
event handling, via a non-visible<input>
element which focus itself everytimeonBlur
is detected. You can use some of themplayer
default key bindings:LEFT
: seek backwards 10sUP
: seek backwards 1mPAGE UP
: seek backwards 10mRIGHT
: seek forward 10sDOWN
: seek forward 1mPAGE DOWN
: seek forward 10mSHIFT
+UP
/DOWN
or*
//
: Adjust volumeSPACE
/P
: (Un)PauseM
: (Un)MuteENTER
: Jump to next podcastSHIFT
+ENTER
: Jump to previous podcastR
: Update the list of podcasts
- Good UI controls for use with mobile devices (big buttons, disabled key bindings).
- Use MediaSession to show podcast data and more controls on mobile (and some desktops) notifications and lock screens.
- Almost WCAG accessible.
- Very fast:
- Use
<meta rel="preconnect">
to pre-initiate external HTTPS connections early - Use
<meta rel="prefetch">
to begin early download of external very slow server - Use ServiceWorker (SW) to predownload and maintain the assets in cache
- Included manifest and SW to allow adding the app icon to mobile desktop with splash screen
- Very fast backend HTML parser
- Use React.PureComponent where possible
- Use
- Asynchronuosly
fetch
podcast list and pages list HTML page, parse it with RegExp and download remaining pages - Asynchronuosly
fetch
podcasts JSON data - Asynchronuosly
fetch
live podcast data (in HTML) and parse it
- Improve UX: layout, styles, info shown, responsible, controls, ¿bootstrap4?
- Use Streams API to control audio downloading and playing (and editing?)
- Add a section to allow easily play podcasts filtered by program
- Filters via
localStorage
, to easily jump unwanted podcasts - Save volume to
localStorage
and use in all players. - Better internal state handling for player status:
currentPosition
,play
... - Consider using Redux
- There is some issue with memory: 300MB+ for each extra date visited (leak, fragmentation or just JS?). Try to debug and fix it.
- Add tests
You can already use the app on it's public location. But you would like to run a local copy of it, or start the development local server to start developing some changes. Whatever is your case, you need to download the code and its dependencies, build it and serve it somehow. Here, I use git
to download the code, docker
and docker-compose
to contain all the boilerplate out of my system and ensuring a consistent CI/CD, npm
and yarn
to manage the JS dependencies (and building and testing), the create-react-app
(CRA) development server and NGinx for serving the static/built version.
git clone https://github.com/emibcn/Rac1.js.git
cd Rac1.js
Using the provided docker-compose.yml
file, it is possible to build and execute a live environment which can host the application in development mode using WebpackDevServer configured by Create React App (CRA), what helps a lot while actively modifying the files. It is also possible to serve the static version of the app using vanilla NGinx locally.
Of course, you can opt-out and install NodeJS, NPM and yarn
by yourself. Also, you can eject CRA.
It depends on which system you use. Go to Docker documentation to get help adapted to your use case.
Go to Docker Compose and follow instructions, depending on your use case.
This will build the containers images, download system and NodeJS dependencies and launch NodeJS development server at port 3000 and NGinx static server at port 4000:
docker-compose up -d
This will build the containers images:
docker-compose build
docker-compose up -d
docker-compose up
(If you stop this with CTRL+C, container will stop too)
Once the container is started, you can view WebpackDevServer logs executing:
docker-compose logs -f
(You can stop this with CTRL+C)
docker-compose down
By default, the container installs all NPM dependencies using yarn
dependency manager. If you use the provided docker-compose.yml
, the app
directory will be mounted inside the container. This automatically helps maintaining the cache of the installed npm modules and auto refreshing the browser when any file is modified or module added/removed/updated.
Once the container has been started, you can enter inside it to execute commands needing NodeJS. For example:
me@mypc:~/Rac1.js$ docker-compose exec rac1 bash
node@8cf780c7b2bb:~/app$ yarn add react-dom-router
[...]
node@8cf780c7b2bb:~/app$ exit
me@mypc:~/Rac1.js$
Or, in one line:
me@mypc:~/Rac1.js$ docker-compose exec rac1 yarn add react-dom-router
[...]
me@mypc:~/Rac1.js$
If you need root permisions:
me@mypc:~/Rac1.js$ docker-compose exec -u root rac1 bash
root@8cf780c7b2bb:~/app$ apt-get update; apt-get install git; apt-get clean
Or:
docker-compose exec -u root rac1 bash -c 'apt-get update; apt-get install git; apt-get clean'
In order to publish the app, it's needed to build it. This will do some modern JS magic (Babel, WebPack, ...) and create a static version of the app, which can be served as static assets. To do so, it's needed to execute yarn build
on the app's dir:
me@mypc:~/Rac1.js$ docker-compose exec rac1 yarn build
yarn run v1.9.4
$ react-scripts build && yarn sw-epilog && yarn pubgh
Creating an optimized production build...
[...]
Done in 58.15s.
me@mypc:~/Rac1.js$
Open your browser and point it to the development version at http://127.0.0.1:3000 or the static version at http://127.0.0.1:4000/Rac1.js/, or visit the public version at https://emibcn.github.io/Rac1.js/ .