NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name OLD ADC Monitor Improver // @description Various ADC ticket monitor display improvements. // @author mileswilford // @version 3.2.0 // @require http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.11.2/moment.min.js // @include http://monitor.drafthouse.com/monitor.aspx* // @include https://monitor.drafthouse.com/monitor.aspx* // ==/UserScript== $(document).ready(function() { var ADC_MI_VERSION = "3.2.0"; var STAGING_MODE = true; /* CONFIGURABLES ---------------------------------------------------------------- */ var titleReplaces = [ ['Drafthouse Films: ', ''], ['2D ', ''], ['3D ', '3D ', 'show-3d'], ['PRIVATE EVENT 59 min', 'PCE/TECH', 'pce-tech'], ['PRIVATE EVENT 29 min', 'PCE/TECH', 'pce-tech'], ['Private Party', 'Private Party', 'pce-tech'], ['PCE Tech Check', 'PCE Tech Check', 'pce-tech'], ['Girlie Night: ', ''], ['Action Pack: ' , ''], ['Mondo x Chiller: ', ''], ['Advance Victory Screening: ', ''], ['Victory Screening: ', ''], ['Kids Camp: ', 'Kids: '], ['Promo Screening: ', ''] ]; var virtualScreens = { '0002' : 3, '0007' : 11, "0102" : 8, "0103" : 8, '0901' : 7, "1401" : 9 }; /* END CONFIGURABLES ----------------------------------------------------------- */ // Parses times into miliseconds, conscientious of the fact that times before 5AM are tomorrow. function timeParse(timeString) { var timeFormat = "h:mm A"; var parsedTimeMoment = moment(timeString, timeFormat); if (parsedTimeMoment.hour() < 5) { parsedTimeMoment.add(1, 'days'); } return parsedTimeMoment.toDate().getTime(); } function getURLParameter(param) { var query = window.location.search.substring(1); var vars = query.split("&"); for (var i = 0; i < vars.length ; i++) { var pair = vars[i].split("="); if (pair[0] == param){ return pair[1]; } } return false; } // Returns the time as a numerical percent // Parses the time if it is fed a string function getTimePercent(time) { if (typeof time == 'string') { time = timeParse(time); } return ((time - firstAndLastTime[0])/(firstAndLastTime[1] - firstAndLastTime[0]) * 100); } // Add version number for reference and lines toggle $('body').append($("<div>").text("ADC MI " + ADC_MI_VERSION).css({ "position" : "fixed", "bottom" : 0, "right" : 0, "opacity" : 0.3 }).prepend("<label id='adcmi-gridlines'><input type='checkbox'/> Toggle Lines </label>")); // Add timer block $('body').append($("<div>").text("30").css({ "position": "fixed", "bottom" : 0, "left" : 0, "opacity" : 0.6 }).addClass('timer-block')); // Add scheduling mode toggle $('body').append($('<div><label id="adcmi-scheduling"><input type="checkbox" /> Scheduling Mode </label>').css({ "position" : "fixed", "bottom" : 0, "left" : "4em", "opacity" : 0.6 })); $('body').append($('<div id="adcmi-scheduling-info">').css({ "position" : "absolute", "top" : 0, "right" : 0 })); // The written instructions $('.theater').after($('<div>').text("Dark lines represent check drop time in the show. Dark area represents time elapsed. Pink areas represent 30-minute preshows.") .css('text-align', 'center')); // Gets me the first and last times of the day in ms form in an array firstAndLastTime = (function () { var alltimes = []; $('.timestart, .timeend').each(function() { var theTime = $(this).text(); alltimes.push(timeParse(theTime)); }); alltimes.sort(); return [alltimes[0], alltimes[alltimes.length-1]]; })(); // Moves left point 30 minutes left to allow for 1st preshow firstAndLastTime[0] -= 1000 * 60 * 30; // Some front-end cleanup and prep for my absolute positioning // Fade the virtual screen if (virtualScreens[getURLParameter('siteid')]) { $('.screen:nth-of-type(' + virtualScreens[getURLParameter('siteid')] + ')') .css({'opacity' : 0.35, 'border' : 0}); } // Hide some stuff that is useless or rendered obsolete by this script $('.layout').hide(); // Remove now-redundant intermissions $('.intermission').remove(); $('.format').remove(); // Provide a box-space and adjust borders for screens $('.screen').css({ 'position' : 'relative', 'height' : 92 }); // Fixes firefox display bug related to box-sizing $('.seats').css({ 'position' : 'relative', 'top' : '-4px' }); // Will later set the positions of the screenings $('.screen > span').attr('style', '').css({ 'position' : 'absolute', 'top' : 0, 'bottom' : 0, 'border': 0 }).each(function() { var $this = $(this); var seats = $this.find('.seats').text().split(' '); var numSold = parseInt(seats[0], 10); var numLeft = parseInt(seats.pop(), 10); var seatingPercent = (numSold / (numSold + numLeft)); var red; var green; var blue; var yellowPoint = 0.6; if (seatingPercent < yellowPoint) { // red = 255 * (seatingPercent / yellowPoint); // green = 255; // blue = 0; red = 150; green = 150; blue = 150; } else { red = 255; green = 255 * Math.pow((1 - seatingPercent)/(1 - yellowPoint), 1); blue = 0; } $after = $('<div>').css({ 'position' : 'absolute', 'top' : 0, 'bottom' : 0, 'left' : 0, 'right' : 0, 'z-index' : -5 }); $after.css('background-color', 'rgba(' + Math.round(red) + ', ' + Math.round(green) + ', ' + Math.round(blue) + ', .3)'); $this.append($after); $this.css('background-color', 'white'); }); $('div').css('border-color', 'transparent'); // Provide a box-space for the count meter $('.theater').css({'position' : 'relative', 'overflow' : 'hidden'}) // Add theater numbers .prepend($('<div>').addClass('theater-count').css({ 'position' : 'absolute', 'top' : 0, 'bottom' : 0 })); // Format titles and execute titleReplaces $('.title').css('text-align', 'center').each(function() { var title = $(this).text(); for (var i = 0; i < titleReplaces.length; i++) { if (titleReplaces[i][2] && title.indexOf(titleReplaces[i][0]) != -1) { // Later, these classes are hooks to run additional changes $(this).addClass(titleReplaces[i][2]); } title = title.replace(titleReplaces[i][0], titleReplaces[i][1]); } $(this).text(title); }); // Make sure Not On Sale shows are always the bottom of the stack $('.notonsale').each(function() { $(this).parent().css({ 'z-index': 0, 'background-color' : '#DDF' }); }); // Add theater numbers var screenCounter = 0; $('.screen').each(function() { screenCounter++; $(this).prepend($('<div>').text(screenCounter).css({ 'position' : 'absolute', 'top' : 0, 'bottom' : 0, 'left' : 0, 'font-size' : '4em' })); }); // Absolutely position each show's left and right sides $('.screen > span').each(function() { var startTime = $(this).find('.timestart').text(); var endTime = $(this).find('.timeend').text(); $(this).css({ 'left' : getTimePercent(startTime) + '%', 'right' : (100 - getTimePercent(endTime)) + '%' }); }); // Get the current time in ms, conscientious of the fact that times before 5AM are tomorrow. var now = (function() { var current = moment(); if (current.hour() < 5) { current.add(1, 'days'); } return current; })(); // Create current time meter edge and position it absolutely // It does NOT need to move automatically - the monitor auto-refreshes too quickly for it to matter // First get the current date as YYYYMMDD var nowString = (function() { var current = moment(now); var year = current.year().toString(); var month = (function() { var month = current.month() + 1; if (month < 10) { return "0" + month.toString(); } else { return month.toString(); } })(); var day = (function() { var day = current.date(); if (day < 10) { return "0" + day; } else { return day.toString(); } })(); return year + month + day; })(); // Check the URL parameters to make sure it is looking at current day var dateParam = getURLParameter('date'); if (dateParam == nowString || !dateParam) { // Insert the meter $('.theater').append($('<div>').css({ 'background-color' : 'rgba(0, 0, 0, 0.15)', 'pointer-events' : 'none', 'padding-top' : $('.theater').height(), 'position' : 'absolute', 'top' : 0, 'bottom' : 0, 'left' : 0, 'right' : 100-getTimePercent(now.toDate().getTime()) + '%', 'z-index' : 1000 })); } // Creates a check-drop line marker and position it absolutely. // This must be done in pixels, which means the window will need to reload after it resizes. function minutesToPixels(minutes) { var fourtyMinMs = minutes * 60 * 1000; var fourtyMinPercent = getTimePercent(firstAndLastTime[0] + fourtyMinMs); var theaterWidth = $('.theater').width(); return theaterWidth * (fourtyMinPercent/100); } $('.screen > span').append($('<div>').addClass('timedrop-line').css({ 'background-color' : 'rgba(0, 0, 0, 0.4)', 'position' : 'absolute', 'top' : '1.8em', 'bottom' : 0, 'right' : minutesToPixels(40) + 'px', 'width' : '2px', 'z-index' : 1000 })).prepend($('<div>').addClass('preshow-marker').css({ 'position' : 'absolute', 'top' : 1, 'bottom' : 1, 'left' : -minutesToPixels(30)-1, 'width' : minutesToPixels(30)-1, 'background-color' : '#FDE', 'opacity' : 0.5 })); $(window).resize(function() { $('.timedrop-line').css('right', minutesToPixels(40) + 'px'); $('.preshow-marker').css({ 'left' : -minutesToPixels(30)-1, 'width' : minutesToPixels(30)-1 }) }); // In this module, execute special show-based title-replace scripts (function() { $('.pce-tech').parent().css("overflow", "hidden").find('.timedrop, .timedrop-line').remove(); $('.show-3d').parent().append($('<div>').css({ 'background-image' : 'url(data:image/png;base64,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)', 'background-position' : 'center center', 'background-repeat' : 'no-repeat', 'background-opacity' : 0.5, 'pointer-events' : 'none', 'opacity' : 0.5, 'position' : 'absolute', 'top' : 0, 'bottom' : 0, 'left' : 0, 'right' : 0 })); })(); // Buttons and configurations module (function() { function toggleBorders(borderType) { $('.adcmi-screen').css('border-top', "5px solid " + borderType); } $('#adcmi-gridlines').click(function() { if ($(this).find('input').is(':checked')) { toggleBorders('black'); if (localStorage) { localStorage.setItem('showGridlines', 'true'); } } else { toggleBorders('transparent'); if (localStorage) { localStorage.setItem('showGridlines', 'false'); } } }); if (localStorage && localStorage.getItem('showGridlines') == 'true') { $('#adcmi-gridlines').click(); toggleBorders('black'); } function toggleSchedulingMode(onOff) { if (onOff) { $('.notonsale').parent().find('.preshow-marker').show(); $('#adcmi-scheduling-info').show(); } else { $('.notonsale').parent().find('.preshow-marker').hide(); $('#adcmi-scheduling-info').hide(); } } $('#adcmi-scheduling').click(function() { if ($(this).find('input').is(':checked')) { toggleSchedulingMode(true); if (localStorage) { localStorage.setItem('schedulingMode', 'true'); } } else { toggleSchedulingMode(false); if (localStorage) { localStorage.setItem('schedulingMode', 'false'); } } }); if (localStorage && localStorage.getItem('schedulingMode') == 'true') { $('#adcmi-scheduling').find('input').prop('checked', true); } else { toggleSchedulingMode(false); } })(); // Finally, make sure the site is reloading correctly in case the native auto reload isn't working. // Do this once every 30 seconds // TODO: reload in background? (function() { var timerCount = 30; var timerExpires = 0; // 35 seconds var $timerBlock = $('.timer-block'); function refreshTimer() { timerCount--; if (timerCount <= timerExpires) { location.reload(); } else { $timerBlock.text(timerCount); } } if (!STAGING_MODE) {setInterval(refreshTimer, 1000);} })(); });