Created
December 23, 2020 17:33
-
-
Save MonoidMusician/b252d9bb1ab30bba12ac4e80558c3120 to your computer and use it in GitHub Desktop.
Simple web app to control mac volume & brightness
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<meta charset="utf-8"/> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Control my mac</title> | |
<style> | |
/* From https://css-tricks.com/styling-cross-browser-compatible-range-inputs-css/ */ | |
input[type=range] { | |
-webkit-appearance: none; | |
margin: 10px 0; | |
width: 100%; | |
} | |
input[type=range]:focus { | |
outline: none; | |
} | |
input[type=range]::-webkit-slider-runnable-track { | |
width: 100%; | |
height: 12.8px; | |
cursor: pointer; | |
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d; | |
background: #ac51b5; | |
border-radius: 25px; | |
border: 0px solid #000101; | |
} | |
input[type=range]::-webkit-slider-thumb { | |
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d; | |
border: 0px solid #000000; | |
height: 20px; | |
width: 39px; | |
border-radius: 7px; | |
background: #65001c; | |
cursor: pointer; | |
-webkit-appearance: none; | |
margin-top: -3.6px; | |
} | |
input[type=range]:focus::-webkit-slider-runnable-track { | |
background: #ac51b5; | |
} | |
input[type=range]::-moz-range-track { | |
width: 100%; | |
height: 12.8px; | |
cursor: pointer; | |
animate: 0.2s; | |
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d; | |
background: #ac51b5; | |
border-radius: 25px; | |
border: 0px solid #000101; | |
} | |
input[type=range]::-moz-range-thumb { | |
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d; | |
border: 0px solid #000000; | |
height: 20px; | |
width: 39px; | |
border-radius: 7px; | |
background: #65001c; | |
cursor: pointer; | |
} | |
input[type=range]::-ms-track { | |
width: 100%; | |
height: 12.8px; | |
cursor: pointer; | |
animate: 0.2s; | |
background: transparent; | |
border-color: transparent; | |
border-width: 39px 0; | |
color: transparent; | |
} | |
input[type=range]::-ms-fill-lower { | |
background: #ac51b5; | |
border: 0px solid #000101; | |
border-radius: 50px; | |
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d; | |
} | |
input[type=range]::-ms-fill-upper { | |
background: #ac51b5; | |
border: 0px solid #000101; | |
border-radius: 50px; | |
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d; | |
} | |
input[type=range]::-ms-thumb { | |
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d; | |
border: 0px solid #000000; | |
height: 20px; | |
width: 39px; | |
border-radius: 7px; | |
background: #65001c; | |
cursor: pointer; | |
} | |
input[type=range]:focus::-ms-fill-lower { | |
background: #ac51b5; | |
} | |
input[type=range]:focus::-ms-fill-upper { | |
background: #ac51b5; | |
} | |
body { | |
padding: 30px; | |
} | |
</style> | |
</head> | |
<body> | |
<div> | |
<label><b style="font-size: 20px">Volume:</b><br/> | |
<input id="volume" type="range" min="0" max="100" step="1"/> | |
</label> | |
</div> | |
<div> | |
<label><b style="font-size: 20px">Brightness:</b><br/> | |
<input id="brightness" type="range" min="0" max="1" step="0.01"/> | |
</label> | |
</div> | |
<button id="refresh">Refresh</button> | |
</body> | |
<script> | |
function send(id, value) { | |
var path = ''+id; | |
fetch(path, {method:"PUT", body:value}); | |
} | |
var refresh = []; | |
function sendoninput(id) { | |
var init = function() { | |
fetch(id).then(r => r.text()).then(v => { | |
document.getElementById(id).value = v; | |
}); | |
} | |
init(); | |
refresh.push(init); | |
document.getElementById(id).oninput = function(e) { | |
send(id, e.target.value); | |
}; | |
} | |
sendoninput("volume"); | |
sendoninput("brightness"); | |
document.getElementById("refresh").onclick = function() { | |
refresh.forEach(f => f()); | |
}; | |
setInterval(function() { | |
refresh.forEach(f => f()); | |
}, 20000); | |
</script> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import os | |
import subprocess | |
import argparse | |
try: | |
import http.server as server | |
except ImportError: | |
# Handle Python 2.x | |
import SimpleHTTPServer as server | |
class Script: | |
def __init__(self, set, get): | |
self.set_script = set | |
self.get_script = get | |
def set(self, v): | |
return Script.run(self.set_script(v)) | |
def get(self): | |
return Script.run(self.get_script) | |
@staticmethod | |
def run(cmd): | |
return subprocess.check_output(cmd).decode('utf-8').strip() | |
class OSAScript(Script): | |
def __init__(self, set, get): | |
self.set_script = set | |
self.get_script = get | |
def set(self, v): | |
return OSAScript.run(self.set_script(v)) | |
def get(self): | |
return OSAScript.run(self.get_script) | |
@staticmethod | |
def run(cmd): | |
return Script.run(["osascript","-e",cmd]) | |
methods = { | |
"/volume": OSAScript( | |
lambda v: "set volume output volume %s" % v, | |
"output volume of (get volume settings)", | |
), | |
# brew install brightness | |
"/brightness": Script( | |
lambda v: ["brightness", str(v)], | |
["bash", "-c", "brightness -l | grep brightness | sed -E \"s/display 0: brightness ([0-9.]+)/\\1/g\""], | |
) | |
} | |
class HTTPRequestHandler(server.SimpleHTTPRequestHandler): | |
"""Extend SimpleHTTPRequestHandler to handle PUT requests""" | |
def end_headers(self): | |
self.send_my_headers() | |
server.SimpleHTTPRequestHandler.end_headers(self) | |
def send_my_headers(self): | |
self.send_header("Cache-Control", "no-cache, no-store, must-revalidate") | |
self.send_header("Pragma", "no-cache") | |
self.send_header("Expires", "0") | |
def do_GET(self): | |
try: | |
method = methods[self.path] | |
reply_body = method.get().encode('utf-8') | |
self.send_response(200) | |
self.send_header("Content-type", "text/html") | |
self.send_header("Content-length", len(reply_body)) | |
self.end_headers() | |
self.wfile.write(reply_body) | |
return | |
except KeyError: | |
server.SimpleHTTPRequestHandler.do_GET(self) | |
def do_PUT(self): | |
try: | |
method = methods[self.path] | |
file_length = int(self.headers['Content-Length']) | |
content = self.rfile.read(file_length).decode('utf-8') | |
reply_body = method.set(content).encode('utf-8') | |
self.send_response(201, 'Set') | |
self.send_header("Content-type", "text/html") | |
self.send_header("Content-length", len(reply_body)) | |
self.end_headers() | |
self.wfile.write(reply_body) | |
except KeyError: | |
self.send_response(404, 'Not found') | |
self.end_headers() | |
if __name__ == '__main__': | |
parser = argparse.ArgumentParser() | |
parser.add_argument('--bind', '-b', default='', metavar='ADDRESS', | |
help='Specify alternate bind address ' | |
'[default: all interfaces]') | |
parser.add_argument('port', action='store', | |
default=8000, type=int, | |
nargs='?', | |
help='Specify alternate port [default: 8000]') | |
args = parser.parse_args() | |
try: | |
server.test(HandlerClass=HTTPRequestHandler, port=args.port, bind=args.bind) | |
except TypeError: | |
server.test(HandlerClass=HTTPRequestHandler) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment