diff --git a/.gitignore b/.gitignore index e84f8e1..e27003f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,11 @@ __pycache__/ state/ + +*.egg-info/ + +build/build-exe-config.json + +*.exe + +*.pyo diff --git a/build/build-exe-config.template.json b/build/build-exe-config.template.json new file mode 100644 index 0000000..2ac7d21 --- /dev/null +++ b/build/build-exe-config.template.json @@ -0,0 +1,77 @@ +{ + "version": "auto-py-to-exe-configuration_v1", + "pyinstallerOptions": [ + { + "optionDest": "noconfirm", + "value": true + }, + { + "optionDest": "filenames", + "value": "../launch_standalone.py" + }, + { + "optionDest": "onefile", + "value": true + }, + { + "optionDest": "console", + "value": true + }, + { + "optionDest": "icon_file", + "value": "\\icon.ico" + }, + { + "optionDest": "name", + "value": "BAPSicle" + }, + { + "optionDest": "ascii", + "value": false + }, + { + "optionDest": "clean_build", + "value": true + }, + { + "optionDest": "strip", + "value": false + }, + { + "optionDest": "noupx", + "value": false + }, + { + "optionDest": "uac_admin", + "value": true + }, + { + "optionDest": "uac_uiaccess", + "value": false + }, + { + "optionDest": "win_private_assemblies", + "value": false + }, + { + "optionDest": "win_no_prefer_redirects", + "value": false + }, + { + "optionDest": "bootloader_ignore_signals", + "value": false + }, + { + "optionDest": "datas", + "value": "\\templates;templates/" + }, + { + "optionDest": "datas", + "value": "\\ui-static;ui-static/" + } + ], + "nonPyinstallerOptions": { + "increaseRecursionLimit": false, + "manualArguments": "" + } +} \ No newline at end of file diff --git a/build/build-exe.bat b/build/build-exe.bat new file mode 100644 index 0000000..a494ff4 --- /dev/null +++ b/build/build-exe.bat @@ -0,0 +1,10 @@ +cd /D "%~dp0" +pip install -r requirements.txt +pip install -r requirements-windows.txt +pip install -e ..\ + +python generate-build-exe-config.py + +auto-py-to-exe -c build-exe-config.json -o ./ + +TIMEOUT 5 \ No newline at end of file diff --git a/build/generate-build-exe-config.py b/build/generate-build-exe-config.py new file mode 100644 index 0000000..b84a501 --- /dev/null +++ b/build/generate-build-exe-config.py @@ -0,0 +1,19 @@ +import json +import os + +dir_path = os.path.dirname(os.path.realpath(__file__)) +parent_path = os.path.dirname(dir_path) + +in_file = open('build-exe-config.template.json', 'r') +config = json.loads(in_file.read()) +in_file.close() + +for option in config["pyinstallerOptions"]: + if option["optionDest"] == "icon_file": + option["value"] = dir_path + option["value"] + if option["optionDest"] == "datas": + option["value"] = parent_path + option["value"] + +out_file = open('build-exe-config.json', 'w') +out_file.write(json.dumps(config, indent=2)) +out_file.close() diff --git a/build/icon.ico b/build/icon.ico new file mode 100644 index 0000000..240c4fd Binary files /dev/null and b/build/icon.ico differ diff --git a/build/requirements-windows.txt b/build/requirements-windows.txt new file mode 100644 index 0000000..8af44a0 --- /dev/null +++ b/build/requirements-windows.txt @@ -0,0 +1,2 @@ +pywin32 +auto-py-to-exe \ No newline at end of file diff --git a/install/requirements.txt b/build/requirements.txt similarity index 68% rename from install/requirements.txt rename to build/requirements.txt index a6b9845..0e55fef 100644 --- a/install/requirements.txt +++ b/build/requirements.txt @@ -2,4 +2,5 @@ pygame==2.0.0.dev20 flask mutagen sounddevice -autopep8 \ No newline at end of file +autopep8 +setproctitle \ No newline at end of file diff --git a/install/requirements-windows.txt b/install/requirements-windows.txt deleted file mode 100644 index afd24f6..0000000 --- a/install/requirements-windows.txt +++ /dev/null @@ -1 +0,0 @@ -pywin32 \ No newline at end of file diff --git a/launch_standalone.py b/launch_standalone.py new file mode 100644 index 0000000..2681aff --- /dev/null +++ b/launch_standalone.py @@ -0,0 +1,13 @@ +import multiprocessing +import time + +from server import BAPSicleServer + +if __name__ == '__main__': + # On Windows calling this function is necessary. + # Causes all kinds of loops if not present. + multiprocessing.freeze_support() + server = multiprocessing.Process(target=BAPSicleServer).start() + while True: + time.sleep(1) + pass diff --git a/player.py b/player.py index d119954..53126c5 100644 --- a/player.py +++ b/player.py @@ -1,10 +1,13 @@ -import pygame +from state_manager import StateManager +from mutagen.mp3 import MP3 +from pygame import mixer import time import json -from mutagen.mp3 import MP3 import copy +import os +import setproctitle -from state_manager import StateManager +os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide" class Player(): @@ -24,54 +27,54 @@ class Player(): def isInit(self): try: - pygame.mixer.music.get_busy() + mixer.music.get_busy() except: return False else: return True def isPlaying(self): - return bool(pygame.mixer.music.get_busy()) + return bool(mixer.music.get_busy()) def play(self): - pygame.mixer.music.play(0) + mixer.music.play(0) def pause(self): - pygame.mixer.music.pause() + mixer.music.pause() def unpause(self): - pygame.mixer.music.play(0, self.state.state["pos"]) + mixer.music.play(0, self.state.state["pos"]) def stop(self): - pygame.mixer.music.stop() + mixer.music.stop() def seek(self, pos): if self.isPlaying(): - pygame.mixer.music.play(0, pos) + mixer.music.play(0, pos) else: self.updateState(pos) def load(self, filename): if not self.isPlaying(): self.state.update("filename", filename) - pygame.mixer.music.load(filename) + mixer.music.load(filename) if ".mp3" in filename: song = MP3(filename) self.state.update("length", song.info.length) else: - self.state.update("length", pygame.mixer.Sound(filename).get_length()/1000) + self.state.update("length", mixer.Sound(filename).get_length()/1000) def quit(self): - pygame.mixer.quit() + mixer.quit() def output(self, name=None): self.quit() try: if name: - pygame.mixer.init(44100, -16, 1, 1024, devicename=name) + mixer.init(44100, -16, 1, 1024, devicename=name) else: - pygame.mixer.init(44100, -16, 1, 1024) + mixer.init(44100, -16, 1, 1024) except: return "FAIL:Failed to init mixer, check sound devices." else: @@ -84,7 +87,7 @@ class Player(): if (pos): self.state.update("pos", max(0, pos)) else: - self.state.update("pos", max(0, pygame.mixer.music.get_pos()/1000)) + self.state.update("pos", max(0, mixer.music.get_pos()/1000)) self.state.update("remaining", self.state.state["length"] - self.state.state["pos"]) def getDetails(self): @@ -93,6 +96,7 @@ class Player(): def __init__(self, channel, in_q, out_q): self.running = True + setproctitle.setproctitle("BAPSicle - Player " + str(channel)) self.state = StateManager("channel" + str(channel), self.__default_state) diff --git a/server.py b/server.py index e03680c..302fbb9 100644 --- a/server.py +++ b/server.py @@ -3,6 +3,9 @@ import player from flask import Flask, render_template, send_from_directory, request import json import sounddevice as sd +import setproctitle + +setproctitle.setproctitle("BAPSicle - Server") class BAPSicleServer():