Skip to content

Commit

Permalink
Prep for 0.1.0 release
Browse files Browse the repository at this point in the history
  • Loading branch information
pierremtb committed Sep 4, 2019
1 parent bb585d9 commit a853943
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 32 deletions.
Binary file added icon.icns
Binary file not shown.
23 changes: 23 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from setuptools import setup

APP = ['src/CastMenu.py']
DATA_FILES = []
OPTIONS = {
'argv_emulation': True,
'plist': {
'LSUIElement': True,
'CFBundleIdentifier': 'com.pierrejacquier.castmenu',
'CFBundleGetInfoString': 'CastMenu. Control your Chromecast-enabled devices from the macOS Menu.',
'CFBundleDisplayName': 'CastMenu',
},
'packages': ['rumps', 'keyboard', 'pychromecast'],
'iconfile': 'icon.icns',
'resources': ['src/icons/cast_connected.png', 'src/icons/cast_disconnected.png'],
}

setup(
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app'],
)
30 changes: 30 additions & 0 deletions src/CastMenu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import keyboard
import os
import subprocess
import sys
import platform

from app import CastMenuApp

def _mac_elevate():
"""Relaunch asking for root privileges."""
print("Relaunching with root permissions")
# applescript = ('do shell script "python3 ./src/CastMenu.py" '
# 'with administrator privileges')
applescript = ('do shell script "../MacOS/CastMenu" '
'with administrator privileges')
exit_code = subprocess.call(['osascript', '-e', applescript])
sys.exit(exit_code)

def _elevate():
"""Elevate user permissions if needed"""
if platform.system() == 'Darwin':
try:
os.setuid(0)
except OSError:
_mac_elevate()

_elevate()
app = CastMenuApp()
app.run()
keyboard.wait()
57 changes: 42 additions & 15 deletions src/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
CONFIG_NAME = "config.json"
CONFIG_PATH = os.path.join(CONFIG_DIR, CONFIG_NAME)
DEFAULT_CONFIG = {
"DEVICE_NAME": "Desk Speaker",
"DEVICE_NAME": "Chromecast Audio",
"PREV_KEY": "f15",
"PLAY_KEY": "f16",
"NEXT_KEY": "f17",
Expand All @@ -24,30 +24,42 @@
"VOLD_KEY": "Volume Down",
"VOLU_KEY": "Volume Up"
}
# ICONS_PATH = "src/icons"
ICONS_PATH = "."

class CastMenuApp(rumps.App):

def __init__(self):
super(CastMenuApp, self).__init__("", quit_button=None)

self.config = self.getConfig()
self.__setCastIcon(False)

self.chromecasts = []
self.hotkeys = []

self.deviceName = self.config["DEVICE_NAME"]

try:
self.device = Device(self)
self.setMenu()
self.setMenu(connected=True)
self.setHotkeys()
except:
print("hey")
# self.__onDeviceSelectedClicked()
self.setMenu(connected=False)
self.__onDeviceSelectedClicked()

def setMenu(self):
def __setCastIcon(self, playing=True):
if playing:
self.icon = os.path.join(ICONS_PATH, "cast_connected.png")
return
self.icon = os.path.join(ICONS_PATH, "cast_disconnected.png")

def setMenu(self, connected=True):
self.prevItem = rumps.MenuItem("Previous", callback=lambda _: self.device.previous())
self.playPauseItem = rumps.MenuItem("Play", callback=lambda _: self.__onPlayPauseClicked())
self.volumeDescItem = rumps.MenuItem("Volume")
self.nextItem = rumps.MenuItem("Next", callback=lambda _: self.device.next())

self.volumeDescItem = rumps.MenuItem("Volume", callback=lambda _: self.__onMuteClicked())
self.volumeItem = rumps.SliderMenuItem(value=0, min_value=0, max_value=100, callback=lambda item: self.__onVolumeChanged(item.value))

self.preferencesItem = rumps.MenuItem("Preferences")
Expand All @@ -60,19 +72,28 @@ def setMenu(self):
self.preferencesItem.add(None)
for key in ["PREV_KEY", "PLAY_KEY", "NEXT_KEY", "MUTE_KEY", "VOLD_KEY", "VOLU_KEY"]:
self.preferencesItem.add(rumps.MenuItem(f"{KEY_NAMES[key]}: {self.config[key]}", callback=self.__onKeyClicked))
self.preferencesItem.add(None)
self.reattachKeysItem = rumps.MenuItem("Reload conf", callback=lambda _: self.__init__())
self.preferencesItem.add(self.reattachKeysItem)

self.aboutItem = rumps.MenuItem("About", callback=lambda item: os.system("open \"\" https://pierrejacquier.com/castmenu"))
self.quitItem = rumps.MenuItem("Quit", callback=lambda item: rumps.quit_application())

self.menu.clear()
self.menu = [self.playPauseItem, self.volumeDescItem, self.volumeItem, None, self.preferencesItem, self.quitItem]
self.menu = [self.prevItem, self.playPauseItem, self.nextItem, None,
self.volumeDescItem, self.volumeItem, None,
self.preferencesItem, self.aboutItem, self.quitItem]


def setHotkeys(self):
keyboard.add_hotkey(self.config["PREV_KEY"], lambda: self.device.previous())
keyboard.add_hotkey(self.config["PLAY_KEY"], lambda: self.device.togglePlay())
keyboard.add_hotkey(self.config["NEXT_KEY"], lambda: self.device.next())
keyboard.add_hotkey(self.config["MUTE_KEY"], lambda: self.device.toggleMute())
keyboard.add_hotkey(self.config["VOLD_KEY"], lambda: self.device.volumeDown())
keyboard.add_hotkey(self.config["VOLU_KEY"], lambda: self.device.volumeUp())
for hk in self.hotkeys:
keyboard.remove_hotkey(hk)
self.hotkeys.append(keyboard.add_hotkey(self.config["PREV_KEY"], lambda: self.device.previous()))
self.hotkeys.append(keyboard.add_hotkey(self.config["PLAY_KEY"], lambda: self.device.togglePlay()))
self.hotkeys.append(keyboard.add_hotkey(self.config["NEXT_KEY"], lambda: self.device.next()))
self.hotkeys.append(keyboard.add_hotkey(self.config["MUTE_KEY"], lambda: self.device.toggleMute()))
self.hotkeys.append(keyboard.add_hotkey(self.config["VOLD_KEY"], lambda: self.device.volumeDown()))
self.hotkeys.append(keyboard.add_hotkey(self.config["VOLU_KEY"], lambda: self.device.volumeUp()))

def __onPlayPauseClicked(self):
self.device.togglePlay()
Expand Down Expand Up @@ -118,13 +139,19 @@ def __updateVolumeDesc(self, volume):
def setDevice(self, device):
self.device = device

def updateData(self, deviceName, title, playButtonText, volume):
def updateData(self, deviceName, title, playerIsPaused, volume):
playButtonText = "Pause"
if playerIsPaused:
title += " (:)"
playButtonText = "Play"
self.deviceName = deviceName
self.deviceSelectedItem.title = f"Device: {self.deviceName}"
self.title = title
self.playPauseItem.title = playButtonText
self.volumeItem.value = volume
self.__updateVolumeDesc(volume)
if title != None:
self.title = title
self.__setCastIcon(playing=title != None)

def editConfigKey(self, key, value):
self.config[key] = value
Expand Down
14 changes: 6 additions & 8 deletions src/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ def __init__(self, app):


def connect(self):
self.app.title = f"Connecting to {self.app.deviceName}…"
# self.app.title = f"Connecting to {self.app.deviceName}…"
self.app.title = ""

self.app.chromecasts = pychromecast.get_chromecasts()
potentialSpeakers = [cc for cc in self.app.chromecasts if cc.device.friendly_name == self.app.deviceName]
Expand All @@ -32,7 +33,7 @@ def connect(self):
self.speaker.wait()
print(self.speaker.status)
print("\nREADY!\n")
self.app.title = f"Connected to {self.app.deviceName}!"
# self.app.title = f"Connected to {self.app.deviceName}!"

self.previous_volume = self.__getVolume()
listener = StatusMediaListener(self.__onMediaChanged)
Expand All @@ -47,12 +48,9 @@ def sendAction(self, action):

def __onMediaChanged(self, status):
volume = int(self.__getVolume() * 100)
title = f"{status.artist}{status.title}"
playButtonText = "Pause"
if status.player_is_paused:
title += " (:)"
playButtonText = "Play"
self.app.updateData(self.app.deviceName, title, playButtonText, volume)
if status.artist != None and status.title != None:
title = f"{status.artist} > {status.title}"
self.app.updateData(self.app.deviceName, title, status.player_is_paused, volume)

def __setVolume(self, volume):
self.sendAction(lambda: self.speaker.set_volume(volume))
Expand Down
Binary file added src/icons/cast_connected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/icons/cast_disconnected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 0 additions & 9 deletions src/main.py

This file was deleted.

0 comments on commit a853943

Please sign in to comment.