Skip to content


Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

AuralCandy.Net - Premium House Music Podcast

This repository contains the source code of AuralCandy.Net. Please note that this application is tailored to our needs - it's not a generic, turn-key podcast platform. This source code is released for educational purposes for anyone who wishes to learn more about developing Contentful applications using Ruby and Sinatra.

This source code is distributed under Unlicense and can be used for non-commericial purposes only. Any commercial use of this source code requires explicit permission from the author. This application comes with absolutely no warranty. The author assumes no responsibility of data loss or any other unintended side-effects.


Teemu Tammela

About Us

AuralCandy.Net is a House Music podcast hosted by the Finnish DJ duo MK-Ultra & Mesmic with more than three decades of combined experience under their belt. Ever since its establishment in 2008 AuralCandy.Net podcasts have reached tens of thousands of listeners from over 150 countries. AuralCandy.Net collaborates with over 50 record labels such as Piston Recordings, Bosh Recordings and Monog Records.

Table of Contents


  • Technology Stack

    • Built upon the Sinatra framework
    • Utilizes Padrino stand-alone helpers
    • Content management and delivery by Contentful
    • Ready to be deployed on Heroku (tested with heroku-20 stack)
    • Includes sample data and Rack::Test unit tests
  • Mobile Friendly Responsive Layout

  • Episode Search

    • Search by brand and genre
    • Pagination and variable items per page
    • Sort by date, title or popularity (requires Chartable integration)
  • Embedded Media Player

    • Saves player state in localStorage
    • Continuous playback between page loads 1)
  • Episode Landing Pages

    • Episode description
    • Genre tags (as defined in MusicRecording schema)
    • Track listing
    • Related recording labels
    • Related episodes
  • RSS/XML Feed

  • Statistics (Optional)

    • Download tracking via Chartable
    • Import Chartable download count to Contentful
  • Search Engine Optimization

  • Performance Optimization

    • Efficient use of caching, content compression and headers on the application level
    • Low amount of HTTP requests and memory footprint
    • JavaScript and SASS asset pipeline via Grunt
    • Full Cloudflare compatibility
  • Certification

1) Unless prevented by browser autoplay policy. See Media Engagement Index documentation for further details. Some browsers like Brave will require explicit permission from user to allow autoplay.



1) Clone or fork the repository and install the required Ruby gems listed in Gemfile via Bundler.

$ git clone
$ cd
$ bundle install

2) Login to Contentful CLI and select the target space.

$ contentful login
$ contentful space use

3) Import content models to target space.

$ contentful space import --content-file import/content-models.json

4) Import example content to target space.

$ contentful space import --content-file import/example-content.json

NOTE! Unit tests (app/test/unit_tests.rb) are designed to match the contents of example-content.json. Altering the example content in Contentful is likely to cause the unit tests to fail. It is recommended to set up two spaces or environments (e.g. production and testing) and keep the unmodified example content in the latter.


Contentful API keys, space ID and Chartable credentials must be set as environment variables. Create a new .env file by copying the example file.

$ cp .env.example .env
$ nano .env

On Heroku environment variables, also known as Config Vars, can be set either via the Dashboard or via Heroku CLI.

$ heroku config:set VARIABLE_NAME=variable_value
Variable Name Description
CONTENTFUL_SPACE_ID Contentful Space ID (source of content).
CONTENTFUL_DELIVERY_KEY Contentful Delivery API key.
CONTENTFUL_MANAGEMENT_KEY Contentful Management API key. 1)
CONTENTFUL_ENVIRONMENT Contentful environment name (e.g. master). 1)
CHARTABLE_PODCAST_ID Chartable team and podcast ID (e.g. auralcandynet). 1)
CHARTABLE_ACCESS_TOKEN Chartable cookie access token. 1) 2)
CHARTABLE_ID Chartable link ID (optional). 3)
APPLE_PODCAST_ID Apple Podcasts ID (optional). 4)

1) Required only by the Chartable import functionality.

2) Chartable does not officially offer a public API, but it's possible to utilize the dashboard JSON end-point by acquiring the access token from a cookie. Login to Chartable dashboard, open the browser's developer tools and look for a request to URL /dashboard?podcast_id=<PODCAST_ID>. The access token can be found in a cookie called remember_token. Please note, that the access token will expire after one year.

3) If ENV["CHARTABLE_ID"] is not set, @audio_url_chartable property found in class Episode simply returns the original Contentful asset URL. Chartable ID can be found at Dashboard → Integrations.

4) If ENV["APPLE_PODCAST_ID"] is set, a apple-itunes-app meta tag will be inserted into the <head> section of the page. Read Apple's Smart App Banners documentation for further information.

Development (Local)

1) Start the application via the heroku local command. Application is now running at http://localhost:9292.

$ heroku local -p 9292

2) Alternatively, use rerun to automatically restart the application upon file save. rerun is included in the Gemfile and is installed as part of bundle install. By default rerun is set to monitor changes in the *.rb files in the app/ directory. Settings are found in the .rerun configuration file.

$ rerun rackup

3) Default environment is development. Set production environment via the APP_ENV variable.

$ export APP_ENV=production

NOTE! Global variable $base_url (set in app/modules/podcast/defaults.rb) forces HTTPS in production mode. This may break some links while running the application in production mode on a local workstation. You may disable this feature by commenting the following line in app/modules/podcast/defaults.rb.

$base_url = $base_url.sub("http://", "https://") unless settings.development?

Production (Heroku)

1) Create a new Heroku application via the dashboard.

2) Login to Heroku and associate the repository with the Heroku application.

$ heroku login
$ heroku git:remote -a <APP_NAME>

3) Deploy commits to production by pushing to Heroku master repository.

$ git push heroku master

The default URL of the application is More domains can be attached to the application via the Settings tab in the dashboard.

NOTE! Before deploying your site to public production environment, change the line Sitemap: in public/robots.txt to match the domain of your production site.


Asset Pipeline

1) Install the required npm packages listed in package.json.

$ npm install

2) Launch the task runner while working with JavaScripts and stylesheets. Upon file save, *.js and *.scss files in directories /assets/javascripts/ and /assets/sass/ will be combined and compressed into target directories /public/javascripts/ and /public/stylesheets/ as configured in Gruntfile.js.

$ grunt watch

Application Structure

Configuration for development and production environments is set in app/app.rb. See Sinatra documentation for further details about configuration settings.

Directory Description
app/assets JavaScripts and SASS stylesheets.
app/classes Classes for wrapping content objects.
app/modules Contentful clients, Chartable functionality and application modules.
app/public Static files (images, compiled JavaScripts and CSS stylesheets etc.).
app/views ERB view templates and partials.


Modules are included and registered in app/app.rb. Modules follow Sinatra's standard modular extensions pattern.

Directory Module Description
app/modules/contentful delivery.rb Contentful Delivery API client.
app/modules/contentful management.rb Contentful Management API client.
app/modules/chartable chartable.rb Chartable download count import.
app/modules/podcast defaults.rb Shared defaults (brands, genres, search form parameters and footer).
app/modules/podcast helpers.rb Generic helpers, mostly for parsing strings for various purposes.
app/modules/podcast queries.rb Query content from Contentful and wrap it to objects (registered as helpers).
app/modules/podcast routes.rb Route and URL parameter handling.

Content Models & Classes

Classes are included in app/app.rb. Classes are wrappers for corresponding Contentful content models. Classes are used for formatting field values, handling related content by wrapping them with appropriate classes, adding helper methods as object properties and defining the accessible properties of said class.

Content Model Contentful ID Class Description
Brand brand brand.rb Podcast brand 1).
DJ author dj.rb Author DJ of a podcast episode.
Episode episode episode.rb Podcast episode.
Label label label.rb Recording label related to an episode.
Navigation Anchor navigationAnchor navigation_anchor.rb Navigation menu in-page anchor.
Navigation Link navigationLink navigation_link.rb Navigation menu internal or external URL.

1) Brand content model is also used to manage site's default settings and navigation menu links and anchors. Each Brand instance can have its unique navigation menu.

Audio File Hosting

Contentful's free Community tier service package enforces a maximum asset size of 50MB, which is insufficient for podcast usage. Therefor the Episode content type is designed with external audio file hosting such as Amazon S3 in mind. Please note, that Dropbox and Google Drive are not suitable for audio file hosting, as they introduce too many redirects and latency issues.

However, if you have Team or Enterprise service package and wish to host audio files in Contentful and use the asset reference field type, simply apply the following modifications.

1) Add a file attachment field called Audio to the Episode content type.

2) Modify the @audio_url and @file_size property definitions in app/classes/episode.rb as follows.

@audio_url = entry.fields[:audio].url
@file_size = entry.fields[:audio].file.details['size']

3) Remove fields File URL and File Size from the Episode content type.

Importing Chartable Downloads

Run the dedicated Rake task to import download statistics from Chartable. On Heroku it's recommended to execute the task daily via the free Scheduler add-on.

$ rake chartable:import

Unit Testing

Run the dedicated Rake task to perform unit tests for all routes defined in routes.rb using the Rack::Test library. Test cases are defined in app/test/unit_tests.rb.

NOTE! Enviromental variables CONTENTFUL_DELIVERY_KEY_TEST and CONTENTFUL_SPACE_ID_TEST set in the .env file enable to use different Contentful space for testing and for actual production content.

$ rake test:run