Q102 Mobile App
Love Q102? There’s an app for that!
Download the free Q102 app and enjoy your favorite radio station whenever, wherever!
Register and log in for the chance to win amazing prizes while you listen.
Q102 keeps it fresh by playing today’s hit music, and the award-winning air staff keeps it fun! Wake up with Jeff & Jenn Morning Show, weekdays from 5 a.m. to 10 a.m. — home of Second Date Update™. Join Tim, Fritsch and Mollie for the day's biggest Cincinnati stories 10 a.m.-11 a.m. on the Hot List. Mollie Watson covers middays from 11 a.m. to 3 p.m., and Roy, Nat & Freddy Mac will keep you entertained every weekday afternoon 3-7 p.m. Kay keeps it live from 7 p.m. to midnight, finishing the out the day by taking requests and playing the newest tunes from your favorite artists.
Stay up-to-date with all the latest Hollywood and music news, as well as what’s happening in your local community including concert pre-sales and more. Create a personalized profile to like songs and favorite artists. And get going in the morning with the integrated alarm clock!
Your favorite radio station is just a tap a way with this fun, interactive app!
Features:
- Stream Q102 live
- Get notifications about concerts, deals, entertainment news and more
- Listen for your chance to win great rewards and prizes and enter to win app-exclusive prizes
- Learn more about the artists you love
- Wake up with the Q102 alarm clock
- Easily access all Q102 podcasts
- Your personalized profile that you use to listen on WKRQ.com is the same as your app profile
Listening Rewards
View more rewards
Listening Leaders
'; this.div = document.querySelectorAll(this.divSelector)[0]; this.div.appendChild(html); }; this.removeUrlProtocol = function(url) { var newstr = url.replace('http://', '//'); return newstr; }; // subscribe events this.subscribeEvents = function() { var _this = this; for (var i in this.configChannels) { var channelName = this.configChannels[i]; var channel = this.pusher.subscribe(channelName); for (var j in this.events) { var eventName = this.events[j]; channel.bind(eventName, function(data) { _this.pusherEvent(channelName, eventName, data); }); } _this.channels.push(channel); } }; // process real time `cue` event from Pusher.com this.pusherEvent = function(channelName, eventName, pusherData) { this.processTrack(pusherData); }; // grabs the latest track from the api this.ajaxLatestTrack = function() { var endpoint = this.endpoint + '/hll_widget_nowplaying_cues.php'; var data = { 'limit': '1' }; var _this = this; var httpRequest = new XMLHttpRequest(); httpRequest.open('POST', endpoint); httpRequest.setRequestHeader("Content-type", "application/json"); httpRequest.send(JSON.stringify(data)); httpRequest.onreadystatechange = function () { if (httpRequest.readyState == 4 && httpRequest.status == 200) { var json = JSON.parse(httpRequest.responseText); _this.processTrack(json.data.response[0]); } } }; // process the track data and update the HTML this.processTrack = function(d) { var trackId = d.data.musicbrainz_recording;var type = d.type;var artist = d.data.artist || '';var trackName = d.data.description || '';var art = this.removeUrlProtocol(d.data.art_url || "https://www.wkrq.com/wp-content/plugins/hbi-player-widgets//assets/img/track.png");art = art + '?ver=2';// workaround: ignore spots for nowif (type !== 'song') {return;} this.div.querySelectorAll('.artist .details')[0].innerHTML = artist; this.div.querySelectorAll('.track .details')[0].innerHTML = trackName; this.div.getElementsByClassName('album-art-img')[0].src = art; }; // grabs the latest track from the api this.ajaxLatestEvents = function() { var endpoint = this.endpoint + '/hll_widget_livebar_events.php'; var data = { limit: 1 }; var _this = this; var httpRequest = new XMLHttpRequest(); httpRequest.open('POST', endpoint); httpRequest.setRequestHeader("Content-type", "application/json"); httpRequest.send(JSON.stringify(data)); httpRequest.onreadystatechange = function () { if (httpRequest.readyState == 4 && httpRequest.status == 200) { var json = JSON.parse(httpRequest.responseText); _this.processEvent(json.data.response[0]); } } }; // process the track data and update the HTML this.processEvent = function(element) { var obj = {}; obj.eventId = element.id; obj.title = element.name || ''; obj.photo = element.photo || "https://www.wkrq.com/wp-content/plugins/hbi-player-widgets//assets/img/event.png"; obj.formatStartTime = moment(element.start_date).format('h:mma'); obj.startTime = element.start_date; obj.endTime = element.end_date; obj.timeRange = function() { let start_date = moment(element.start_date); let end_date = moment(element.end_date); let default_format = 'h:mma'; let start_day_format = (default_format); let end_day_format = (default_format); // If start and end dates both fall in AM or PM, make it brief // Example: 10:00-11:00am vs 10:00am-11:00am if(start_date.format('a') === end_date.format('a')) { start_day_format = 'h:mm'; } // Remove minutes if 00 if(start_date.minutes() == 0) { start_day_format = 'h'; } if(end_date.minutes() == 0) { end_day_format = 'ha'; } return start_date.format(start_day_format) + "-" + end_date.format(end_day_format); }; this.div.querySelectorAll('.artist .details')[0].innerHTML = obj.timeRange(); this.div.querySelectorAll('.track .details')[0].innerHTML = obj.title; this.div.getElementsByClassName('album-art-img')[0].src = obj.photo; // Start timer this.setEventTimer(); }; // Set timer for event refresh this.setEventTimer = function() { var _this = this; setTimeout(function(){ _this.ajaxLatestEvents(); }, this.eventRefreshTime); }; // grabs the latest rewards this.ajaxLatestRewards = function() { var endpoint = this.endpoint + '/hll_widget_nowplaying_rewards.php'; var data = {}; var _this = this; var httpRequest = new XMLHttpRequest(); httpRequest.open('POST', endpoint); httpRequest.setRequestHeader("Content-type", "application/json"); httpRequest.send(JSON.stringify(data)); httpRequest.onreadystatechange = function () { if (httpRequest.readyState == 4 && httpRequest.status == 200) { var json = JSON.parse(httpRequest.responseText); _this.processRewards(json.data); } } }; // process the event reward and update the HTML this.processRewards = function(d) { var _this = this; // remove ones that shouldn't be shown var d = d.filter(function(x) { if(x.in_widgets === true) { return true; } return false; }); // randomly sort the array of rewards var d = d.sort(function(a, b){return 0.5 - Math.random()}); // then sort featured rewards to the top d.sort(function(x) { return x.featured === false; }); var i = 0; for(i in d) { if(i > 1) { break; } // reward properties var rewardObject = d[i]; var id = rewardObject.id; var title = rewardObject.title; var image = this.removeUrlProtocol(rewardObject.photo); var type = rewardObject.type; var hours = Math.floor(rewardObject.hours / 3600); var hoursLabel = hours == 1 ? 'hour' : 'hours'; if(type == 'geolocation') {type = 'app'; } // element var rewardElement = this.div.getElementsByClassName('reward-'+i)[0]; rewardElement.getElementsByClassName('img')[0].getElementsByTagName('img')[0].src = image; rewardElement.getElementsByClassName('content')[0].getElementsByClassName('details')[0].innerHTML = title; if(hours > 0) { rewardElement.getElementsByClassName('content')[0].getElementsByClassName('info')[0].getElementsByClassName('time')[0].innerHTML = hours + ' ' + hoursLabel; } rewardElement.getElementsByClassName('reward-featured-url')[0].setAttribute('href',"https://live.wkrq.com/listen/rewards/" + id + "/?utm_source=station-website&utm_medium=widget&utm_campaign=listening-leaders"); // reward type badge var typeBadge = rewardElement.getElementsByClassName('content')[0].getElementsByClassName('info')[0].getElementsByClassName('type-badge')[0]; var typeBadgeclassListAsArray = new Array(typeBadge.classList.length); for (var j = 0, len = typeBadge.classList.length; j < len; j++) { typeBadgeclassListAsArray[j] = typeBadge.classList[j]; } typeBadgeclassListAsArray.forEach(function(className) { typeBadge.classList.remove(className); }); // Custom badge label var badgeLabel = type; if (badgeLabel === 'app' || badgeLabel === 'qrcode' || badgeLabel === 'geolocation') { badgeLabel = 'app'; } if (badgeLabel === 'smartspeaker') { badgeLabel = 'alexa'; } if (badgeLabel === 'promocode') { badgeLabel = 'promo code'; } typeBadge.innerHTML = badgeLabel; typeBadge.classList.add('type-badge','reward-type-'+type); // show reward element rewardElement.classList.remove("hide"); i++; } // If rewards available, show wrapper if(d && d.length > 0) { var rewardsWrapper = this.div.getElementsByClassName('rewards-wrapper')[0]; rewardsWrapper.classList.remove("hide"); } // Start timer this.setRewardsTimer(); }; // Set timer for rewards refresh this.setRewardsTimer = function() { var _this = this; setTimeout(function(){ _this.ajaxLatestRewards(); }, this.rewardsRefreshTime); }; // grabs the latest user listening data this.ajaxLatestListeners = function() { var endpoint = this.endpoint + '/hll_widget_nowplaying_listeners.php'; var data = { 'limit': this.listenerCount }; var _this = this; var httpRequest = new XMLHttpRequest(); httpRequest.open('POST', endpoint); httpRequest.setRequestHeader("Content-type", "application/json"); httpRequest.send(JSON.stringify(data)); httpRequest.onreadystatechange = function () { if (httpRequest.readyState == 4 && httpRequest.status == 200) { var json = JSON.parse(httpRequest.responseText); _this.processListeners(json.data[0]); } } }; // process the track data and update the HTML this.processListeners = function(d) { // Main element var sections = this.div.getElementsByClassName('types-sections')[0]; // Loop through each type for(x in d) { var type = x; var typeData = d[x]; var typeElement = sections.getElementsByClassName('type-section ' + type)[0]; if(!typeElement) { continue; } // Loop through each listener only a certain number of times var listenerElements = []; var i = 0; for(i in typeData) { if(i > this.listenerCount - 1) { break; } // Listener data var listener = typeData[i]; var firstName = listener.first_name; var lastName = listener.last_name; var displayName = (lastName) ? firstName + ' ' + lastName.charAt(0) + '.' : firstName; var photo = this.removeUrlProtocol(listener.photo || "https://www.wkrq.com/wp-content/plugins/hbi-player-widgets//assets/img/user.png"); var hours = Math.floor(listener.total_duration / 3600); var minutes = Math.floor(listener.total_duration / 60 % 60); // Create listener element var element = document.createElement('div'); element.setAttribute('class','listener'); var imgDiv = document.createElement('div'); imgDiv.setAttribute('class', 'img'); var img = document.createElement('img'); img.setAttribute('src', photo); imgDiv.appendChild(img) element.appendChild(imgDiv); var content = document.createElement('div'); content.setAttribute('class', 'content'); var name = document.createElement('div'); name.setAttribute('class', 'name'); name.innerHTML = displayName; content.appendChild(name); var info = document.createElement('div'); info.setAttribute('class', 'info'); var hoursElement = document.createElement('span'); hoursElement.setAttribute('class', 'hours time'); hoursElement.style.color = ""; hoursElement.innerHTML = hours; var minutesElement = document.createElement('span'); minutesElement.setAttribute('class', 'minutes time'); minutesElement.style.color = ""; minutesElement.innerHTML = minutes; var hoursLabel = document.createElement('strong'); hoursLabel.innerHTML = 'Hrs'; var minutesLabel = document.createElement('strong'); minutesLabel.innerHTML = 'Mins'; info.appendChild(hoursElement); info.appendChild(hoursLabel); info.appendChild(minutesElement); info.appendChild(minutesLabel); content.appendChild(info); element.appendChild(content); // Add element to array listenerElements.push(element); i++; } // Remove current listener elements and add new ones while (typeElement.hasChildNodes()) { typeElement.removeChild(typeElement.lastChild); } listenerElements.forEach(function(element) { typeElement.appendChild(element); }); } // If listeners available, show wrapper if(d) { var listenersWrapper = this.div.getElementsByClassName('listeners-wrapper')[0]; listenersWrapper.classList.remove("hide"); } // Start timer this.setListenerTimer(); }; // Set timer for listener refresh this.setListenerTimer = function() { var _this = this; setTimeout(function(){ _this.ajaxLatestListeners(); }, this.listenerRefreshTime); }; this.createListenerEventListener = function() { var _this = this; this.hllforEach(this.div.querySelectorAll(".types-menu .type"), function(index, element){ element.addEventListener('click', function(event) { event.preventDefault(); _this.changeListenerTypeSection(event.target); }); }); }; this.changeListenerTypeSection = function(element) { var listenerSection = this.div.getElementsByClassName('listeners-wrapper')[0]; var targetType = element.getAttribute('data-type-target'); var menuItem = listenerSection.querySelectorAll('[data-type-target="' + targetType + '"]')[0]; var typeSection = listenerSection.querySelectorAll('.type-section.'+targetType)[0]; if(menuItem && typeSection) { var active = listenerSection.querySelectorAll(".active"); for( var x=0; x < active.length; x++ ) { var element = active[x]; element.classList.remove('active'); } menuItem.classList.add('active'); typeSection.classList.add('active'); } }; /* * forEach method, could be shipped as part of an Object Literal/Module * - https://toddmotto.com/ditch-the-array-foreach-call-nodelist-hack/ */ this.hllforEach = function (array, callback, scope) { for (var i = 0; i < array.length; i++) { callback.call(scope, i, array[i]); // passes back stuff we need } };};// Set and intializenew hllNowPlayingWidgetObject('player-widget-listeningleaders-6681085deb2ba').init();