├── _includes ├── css │ └── site │ │ ├── screen.css │ │ └── mobile.css ├── icons │ ├── apple.png │ └── favicon.ico ├── img │ └── site │ │ ├── loading.png │ │ ├── ajax-loader-black.gif │ │ └── ajax-loader-white.gif ├── php │ ├── Ajax.php │ ├── Volume.php │ └── PageBuilder.php └── js │ └── site │ ├── init.js │ └── volume.js ├── README.md └── index.php /_includes/css/site/screen.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_includes/icons/apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orangespaceman/mac-volume-control-php-js/master/_includes/icons/apple.png -------------------------------------------------------------------------------- /_includes/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orangespaceman/mac-volume-control-php-js/master/_includes/icons/favicon.ico -------------------------------------------------------------------------------- /_includes/img/site/loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orangespaceman/mac-volume-control-php-js/master/_includes/img/site/loading.png -------------------------------------------------------------------------------- /_includes/img/site/ajax-loader-black.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orangespaceman/mac-volume-control-php-js/master/_includes/img/site/ajax-loader-black.gif -------------------------------------------------------------------------------- /_includes/img/site/ajax-loader-white.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orangespaceman/mac-volume-control-php-js/master/_includes/img/site/ajax-loader-white.gif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mac-volume-control-php-js 2 | 3 | A PHP-based volume controller for a mac 4 | 5 | ## Post 6 | 7 | [https://f90.co.uk/labs/mac-php-js-volume-control/](https://f90.co.uk/labs/mac-php-js-volume-control/) 8 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | buildPage($volume->volume); -------------------------------------------------------------------------------- /_includes/php/Ajax.php: -------------------------------------------------------------------------------- 1 | 0) { 3 | 4 | // check what to do 5 | require_once("./Volume.php"); 6 | $volume = new Volume; 7 | $method = $_POST['method']; 8 | unset($_POST['method']); 9 | 10 | // 11 | switch ($method) { 12 | 13 | case "getVolume": 14 | $result = $volume->getVolume(); 15 | echo json_encode($result); 16 | break; 17 | 18 | 19 | case "setVolume": 20 | $vol = intval($_POST['val']); 21 | $result = $volume->setVolume($vol); 22 | echo json_encode($result); 23 | break; 24 | 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /_includes/js/site/init.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Site global JS file 3 | */ 4 | 5 | /** 6 | * on Dom ready functionality 7 | */ 8 | $(document).ready(function() { 9 | 10 | // add an extra class to the element for JS-only styling 11 | $("body").addClass("js"); 12 | 13 | // hide scroll bar 14 | window.scrollTo(0,1); 15 | 16 | // init vol control 17 | volume.init({ 18 | ajaxPath: "./_includes/php/Ajax.php", 19 | interval: 10 20 | }); 21 | }); 22 | 23 | 24 | /* 25 | * Window load calls for all pages 26 | */ 27 | $(window).load(function() { 28 | 29 | }); -------------------------------------------------------------------------------- /_includes/php/Volume.php: -------------------------------------------------------------------------------- 1 | getVolume(); 19 | } 20 | 21 | 22 | /* 23 | * 24 | */ 25 | function getVolume() { 26 | $this->volume = shell_exec('osascript -e "output volume of (get volume settings)"'); 27 | return array("volume" => $this->volume); 28 | } 29 | 30 | 31 | /* 32 | * 33 | */ 34 | function setVolume($vol) { 35 | shell_exec("osascript -e 'set volume output volume ".$vol."'"); 36 | return $this->getVolume(); 37 | } 38 | 39 | 40 | /* 41 | * 42 | */ 43 | function mute() { 44 | shell_exec("osascript -e 'set volume output volume 0'"); 45 | return $this->getVolume(); 46 | } 47 | 48 | 49 | /* 50 | * 51 | */ 52 | function volumeUp() { 53 | shell_exec("osascript -e 'set volume output volume (get (output volume of (get volume settings)) + 5)'"); 54 | return $this->getVolume(); 55 | } 56 | 57 | 58 | 59 | /* 60 | * 61 | */ 62 | function volumeDown() { 63 | shell_exec("osascript -e 'set volume output volume (get (output volume of (get volume settings)) - 5)'"); 64 | return $this->getVolume(); 65 | } 66 | } -------------------------------------------------------------------------------- /_includes/php/PageBuilder.php: -------------------------------------------------------------------------------- 1 | 22 | 23 | 24 | Volume 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 |
45 | 57 | 61 |
62 |
63 | 64 | 65 | '; 66 | 67 | return $return; 68 | } 69 | } -------------------------------------------------------------------------------- /_includes/css/site/mobile.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Mobile CSS 3 | */ 4 | /* resets */ 5 | * { margin:0; padding:0; } 6 | 7 | body { 8 | font:62.5%/1.25 Helvetica, Arial, sans-serif; 9 | background:#000; 10 | } 11 | 12 | ul { list-style:none; } 13 | a { text-decoration:none; } 14 | 15 | /* global */ 16 | #horizon { 17 | position:absolute; 18 | left: 0px; 19 | text-align: center; 20 | top: 50%; 21 | width: 100%; 22 | } 23 | 24 | #wrapper { 25 | margin: 0px auto; 26 | position: relative; 27 | text-align: left; 28 | background: -webkit-gradient(linear,left bottom,left top,color-stop(0.09, rgb(0,0,0)),color-stop(0.78, rgb(122,122,122))); 29 | } 30 | 31 | 32 | /* footer */ 33 | footer { 34 | overflow:auto; 35 | } 36 | 37 | h1 { 38 | font-size:24px; 39 | color:#f4f4f4; 40 | float:left; 41 | } 42 | 43 | h2 { 44 | float:right; 45 | font-size:16px; 46 | margin:4px 10px 0 0; 47 | } 48 | 49 | h2 a { 50 | display:block; 51 | } 52 | 53 | h2 a span { 54 | display:block; 55 | float:right; 56 | margin:2px 0 0 5px; 57 | width:16px; 58 | height:16px; 59 | border-radius:8px; 60 | } 61 | 62 | h2 a { 63 | color:#ccc; 64 | } 65 | h2 a span, 66 | ul#vol li a span { 67 | background:#ccc; 68 | /*-webkit-box-shadow: 0px 0px 10px #fff;*/ 69 | } 70 | 71 | h2 a.mute-on { 72 | color:#0f4; 73 | } 74 | h2 a.mute-on span, 75 | ul#vol li.active a span { 76 | background:#0f4; 77 | -webkit-box-shadow: 0px 0px 20px #0f4; 78 | } 79 | 80 | 81 | /* vol */ 82 | ul#vol { 83 | clear:both; 84 | } 85 | 86 | ul#vol li { 87 | float:left; 88 | position:relative; 89 | height:100%; 90 | } 91 | 92 | ul#vol li a, 93 | ul#vol li a span { 94 | display:block; 95 | width:100%; 96 | height:100%; 97 | position:absolute; 98 | left:0; 99 | bottom:0; 100 | /*background:#f90;*/ 101 | text-indent:-9999px; 102 | } 103 | 104 | ul#vol li#vol-0 a span { height:1%;} 105 | ul#vol li#vol-10 a span { height:10%;} 106 | ul#vol li#vol-20 a span { height:20%;} 107 | ul#vol li#vol-30 a span { height:30%;} 108 | ul#vol li#vol-40 a span { height:40%;} 109 | ul#vol li#vol-50 a span { height:50%;} 110 | ul#vol li#vol-60 a span { height:60%;} 111 | ul#vol li#vol-70 a span { height:70%;} 112 | ul#vol li#vol-80 a span { height:80%;} 113 | ul#vol li#vol-90 a span { height:90%;} 114 | ul#vol li#vol-100 a span { height:100%;} 115 | 116 | ul#vol li#vol-80.active a span { 117 | background:#fe0; 118 | -webkit-box-shadow: 0px 0px 20px #fe0; 119 | } 120 | ul#vol li#vol-90.active a span { 121 | background:#f90; 122 | -webkit-box-shadow: 0px 0px 20px #f90; 123 | } 124 | ul#vol li#vol-100.active a span { 125 | background:#f00; 126 | -webkit-box-shadow: 0px 0px 20px #f00; 127 | } 128 | 129 | 130 | /* loader */ 131 | span#loading { 132 | position:absolute; 133 | right:10px; 134 | bottom:10px; 135 | display:block; 136 | width:16px; 137 | height:16px; 138 | background-image:url(../../img/site/ajax-loader-black.gif); 139 | background-position:right bottom; 140 | background-repeat:no-repeat; 141 | display:none; 142 | } 143 | 144 | span#loading.show { 145 | display:block; 146 | } 147 | 148 | 149 | /* landscape (as default) */ 150 | /*@media (max-width: 480px) {*/ 151 | #horizon { 152 | margin-top:-160px; 153 | } 154 | 155 | #wrapper { 156 | width:480px; 157 | height:320px; 158 | } 159 | 160 | ul#vol { 161 | padding-top:50px; 162 | height:200px; 163 | margin:0 30px 20px 30px; 164 | } 165 | 166 | ul#vol li { 167 | width:30px; 168 | margin-right:7px; 169 | } 170 | 171 | h2 { 172 | margin-right:20px; 173 | } 174 | 175 | footer { 176 | width:420px; 177 | margin:0 auto; 178 | } 179 | /*}*/ 180 | 181 | /* portrait */ 182 | @media (max-width: 320px) { 183 | 184 | #horizon { 185 | min-width: 320px; 186 | margin-top: -240px; 187 | } 188 | 189 | #wrapper { 190 | width:320px; 191 | height:480px; 192 | } 193 | 194 | ul#vol { 195 | width:300px; 196 | height:340px; 197 | margin:0 auto 20px auto; 198 | padding-top:50px; 199 | } 200 | 201 | ul#vol li { 202 | width:20px; 203 | margin-right:7px; 204 | } 205 | 206 | h2 { 207 | margin-right:10px; 208 | } 209 | 210 | footer { 211 | width:300px; 212 | margin:0 auto; 213 | } 214 | } -------------------------------------------------------------------------------- /_includes/js/site/volume.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Volume 3 | * 4 | */ 5 | var volume = function(){ 6 | 7 | // obj: volume text element 8 | var $volText = null, 9 | 10 | 11 | // obj: volume checking interval 12 | volInterval = null, 13 | 14 | 15 | // int: current volume 16 | currentVolume = null, 17 | 18 | 19 | // bool: is currently muted? 20 | isMuted = false, 21 | 22 | 23 | // int: volume before mute was pressed 24 | preMutedVolume = null, 25 | 26 | 27 | // obj: loading element 28 | loader = null, 29 | 30 | 31 | // array - volume blocks 32 | $volumeBlocks = null; 33 | 34 | 35 | /** 36 | * The options passed through to this function 37 | * 38 | * @var Object 39 | * @private 40 | */ 41 | var options = { 42 | 43 | /** 44 | * The location of the AJAX script on the server 45 | * 46 | * @var String 47 | */ 48 | ajaxPath : null, 49 | 50 | /** 51 | * The interval time (in seconds) between volume checks 52 | * 53 | * 54 | */ 55 | interval : 10 56 | }; 57 | 58 | 59 | /** 60 | * Initialise the functionality 61 | * @param {Object} options The initialisation options 62 | * @return void 63 | * @public 64 | */ 65 | var init = function(initOptions) { 66 | 67 | // save any options sent through to the intialisation script, if set 68 | for (var option in options) { 69 | if (!!initOptions[option] || initOptions[option] === false) { 70 | options[option] = initOptions[option]; 71 | } 72 | 73 | // error check, if no element is specified then stop 74 | if (!options[option] && options[option] !== false && options[option] !== 0) { 75 | throw('Required option not specified: ' + option); 76 | //return false; 77 | } 78 | } 79 | 80 | // get volume text element 81 | $volText = $("#volume-level"); 82 | 83 | 84 | // get current volume 85 | currentVolume = $volText.text(); 86 | 87 | 88 | // get all volume blocks 89 | $volumeBlocks = $("ul#vol a"); 90 | 91 | 92 | // set volume controls 93 | $volumeBlocks.bind('click', function(e){ 94 | e.preventDefault(); 95 | this.blur(); 96 | setVolumeFromBlock(this); 97 | }); 98 | 99 | 100 | // set up mute 101 | $("h2#mute a").bind('click', function(e){ 102 | e.preventDefault(); 103 | this.blur(); 104 | mutePressed(this); 105 | }); 106 | 107 | 108 | // add loader 109 | loader = $("").attr('id', 'loading').appendTo('#wrapper'); 110 | 111 | 112 | // set up initial volume blocks 113 | adjustBlocks(); 114 | 115 | 116 | // check volume every x seconds 117 | volInterval = setInterval(getVolume, options.interval * 1000); 118 | }; 119 | 120 | 121 | /* 122 | * 123 | */ 124 | var mutePressed = function(el) { 125 | 126 | // condition : mute? 127 | if (!isMuted) { 128 | isMuted = true; 129 | preMutedVolume = currentVolume; 130 | setVolume(0); 131 | $(el).addClass('mute-on'); 132 | 133 | // restore volume 134 | } else { 135 | isMuted = false; 136 | setVolume(preMutedVolume); 137 | preMutedVolume = null; 138 | $(el).removeClass('mute-on'); 139 | } 140 | }; 141 | 142 | 143 | 144 | /* 145 | * 146 | */ 147 | var getVolume = function() { 148 | _ajax("getVolume"); 149 | }; 150 | 151 | 152 | 153 | /* 154 | * 155 | */ 156 | var setVolume = function(vol) { 157 | _ajax("setVolume", vol); 158 | }; 159 | 160 | 161 | 162 | /* 163 | * 164 | */ 165 | var _ajax = function(method, val) { 166 | 167 | showLoader(); 168 | 169 | var postData, response; 170 | 171 | postData = 'method='+method; 172 | 173 | if (!!val) { 174 | postData += '&val='+val; 175 | } 176 | 177 | postData += '&random='+Math.random(); 178 | 179 | // submit request 180 | response = $.post( 181 | options.ajaxPath, 182 | postData, 183 | function(data, textStatus){ 184 | 185 | var result = $.parseJSON(data); 186 | currentVolume = result.volume; 187 | $volText.text(result.volume); 188 | 189 | adjustBlocks(); 190 | 191 | hideLoader(); 192 | 193 | //console.log(result); 194 | 195 | }); 196 | }; 197 | 198 | 199 | /* 200 | * 201 | */ 202 | var adjustBlocks = function() { 203 | 204 | $volumeBlocks.each(function(counter){ 205 | var $block = $(this); 206 | var blockVolume = parseInt($block.parent().attr('id').split('-')[1], 10); 207 | if ((blockVolume-2) <= currentVolume) { 208 | $block.parent().addClass('active'); 209 | } else { 210 | $block.parent().removeClass('active'); 211 | } 212 | }); 213 | }; 214 | 215 | 216 | /* 217 | * 218 | */ 219 | var setVolumeFromBlock = function(el) { 220 | $block = $(el); 221 | var blockVolume = parseInt($block.parent().attr('id').split('-')[1], 10); 222 | setVolume(blockVolume); 223 | }; 224 | 225 | 226 | /* 227 | * 228 | */ 229 | var showLoader = function() { 230 | 231 | loader.addClass('show'); 232 | 233 | }; 234 | 235 | 236 | 237 | /* 238 | * 239 | */ 240 | var hideLoader = function() { 241 | 242 | loader.removeClass('show'); 243 | 244 | }; 245 | 246 | 247 | 248 | /** 249 | * Return value, expose certain methods above 250 | */ 251 | return { 252 | init: init 253 | }; 254 | }(); --------------------------------------------------------------------------------