finished base version 1.0 and as such the app is fully functional though there might still be bugs around and also some improvements will be made later on

This commit is contained in:
janis
2022-03-10 22:50:29 +01:00
parent 8bb93c3957
commit 17b2bb1fa2
9 changed files with 503 additions and 12 deletions

2
.idea/MusicPlayer.iml generated
View File

@@ -2,7 +2,7 @@
<module type="PYTHON_MODULE" version="4"> <module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager"> <component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" /> <content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" /> <orderEntry type="jdk" jdkName="Python 3.10" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
</module> </module>

2
.idea/misc.xml generated
View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8" project-jdk-type="Python SDK" /> <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" />
</project> </project>

122
bin/csv_parsers.py Normal file
View File

@@ -0,0 +1,122 @@
"""@package docstring
This is a simplification of the csv module"""
import csv
class CsvRead:
"""This is a class that reads csv files and depending on the module selected does do different things with it"""
def __init__(self):
self.__imp = ""
self.__raw = ""
self.__raw_list = ""
def importing(self, path):
"""Returns a list of the imported csv-file, requires path, either direct system path or relative path"""
self.__imp = open(path)
self.__raw = csv.reader(self.__imp, delimiter=',')
self.__raw_list = list(self.__raw)
self.__imp.close()
return self.__raw_list
class CsvWrite:
"""This is a class that modifies csv files"""
def __init__(self):
self.__impl = []
self.__strpop = []
self.__removed = []
self.__removing = 0
self.__change = 0
self.__appending = 0
self.__imp = []
self.__raw = []
def rem_str(self, path, row):
"""Opens the csv-file in write mode which is specified as an argument either as direct or relative path"""
self.__imp = open(path)
self.__raw = csv.reader(self.__imp, delimiter=',')
self.__impl = list(self.__raw)
self.__removed = self.__impl.pop(row + 1)
with open(path, "w") as removedata:
self.__removing = csv.writer(removedata, delimiter=',', quoting=csv.QUOTE_MINIMAL)
self.__removing.writerow(self.__impl.pop(0))
while len(self.__impl) > 0:
with open(path, "a") as removedata:
self.__removing = csv.writer(removedata, delimiter=',', quoting=csv.QUOTE_MINIMAL)
self.__removing.writerow(self.__impl.pop(0))
self.__imp.close()
removedata.close()
def chg_str(self, path, row, pos, new_value):
"""Opens the csv-file in write mode to change a value, e.g. if a recipes is changed."""
self.__imp = open(path)
self.__raw = csv.reader(self.__imp, delimiter=',')
self.__impl = list(self.__raw)
self.__strpop = self.__impl.pop(row)
self.__strpop.pop(pos)
self.__strpop.insert(pos, new_value)
self.__impl.insert(row, self.__strpop)
with open(path, "w") as changedata:
self.__change = csv.writer(changedata, delimiter=',', quoting=csv.QUOTE_MINIMAL)
self.__change.writerow(self.__impl.pop(0))
while len(self.__impl) > 0:
with open(path, "a") as changedata:
self.__removing = csv.writer(changedata, delimiter=',', quoting=csv.QUOTE_MINIMAL)
self.__removing.writerow(self.__impl.pop(0))
self.__imp.close()
changedata.close()
def chg_str_rem(self, path, row, pos):
"""Opens the csv-file in write mode to change a value, e.g. if a recipes is changed."""
self.__imp = open(path)
self.__raw = csv.reader(self.__imp, delimiter=',')
self.__impl = list(self.__raw)
self.__strpop = self.__impl.pop(row)
self.__strpop.pop(pos)
self.__strpop.pop(pos)
self.__impl.insert(row, self.__strpop)
with open(path, "w") as changedata:
self.__change = csv.writer(changedata, delimiter=',', quoting=csv.QUOTE_MINIMAL)
self.__change.writerow(self.__impl.pop(0))
while len(self.__impl) > 0:
with open(path, "a") as changedata:
self.__removing = csv.writer(changedata, delimiter=',', quoting=csv.QUOTE_MINIMAL)
self.__removing.writerow(self.__impl.pop(0))
self.__imp.close()
changedata.close()
def chg_str_add(self, path, row, new_value1, new_value2):
"""Opens the csv-file in write mode to change a value, e.g. if a recipes is changed."""
self.__imp = open(path)
self.__raw = csv.reader(self.__imp, delimiter=',')
self.__impl = list(self.__raw)
self.__strpop = self.__impl.pop(row)
self.__strpop.append(new_value1)
self.__strpop.append(new_value2)
self.__impl.insert(row, self.__strpop)
with open(path, "w") as changedata:
self.__change = csv.writer(changedata, delimiter=',', quoting=csv.QUOTE_MINIMAL)
self.__change.writerow(self.__impl.pop(0))
while len(self.__impl) > 0:
with open(path, "a") as changedata:
self.__removing = csv.writer(changedata, delimiter=',', quoting=csv.QUOTE_MINIMAL)
self.__removing.writerow(self.__impl.pop(0))
self.__imp.close()
changedata.close()
def app_str(self, path, value):
"""Opens the csv-file in append mode and writes given input. CsvWrite.app_str(path, value).
Path can be specified both as direct or relative. value is a list. Will return an error if type of value is
not a list."""
with open(path, "a") as appenddata:
self.__appending = csv.writer(appenddata, delimiter=',', quoting=csv.QUOTE_MINIMAL)
self.__appending.writerow(value)
appenddata.close()
def write_str(self, path, value):
with open(path, "w") as writedata:
self.__change = csv.writer(writedata, delimiter=',', quoting=csv.QUOTE_MINIMAL)
self.__change.writerow(value)
writedata.close()

26
bin/filepathanalysis.py Normal file
View File

@@ -0,0 +1,26 @@
import os
class PathAnalysis:
def __init__(self):
self.__output = []
self.__input = []
self.__file_extension = ""
self.__filepath = ""
self.__returns = []
self.__names = []
def validsonglistcreator(self, path):
self.__input = os.listdir(path)
for self.item in self.__input:
self.__file_extension = self.item[(len(self.item) - 4):]
if self.__file_extension == ".mp3" or self.__file_extension == ".wav":
self.__filepath = str(path)
self.__filepath += f"/{str(self.item)}"
self.__names.append(self.item)
self.__output.append(self.__filepath)
else:
pass
self.__returns.append(self.__output)
self.__returns.append(self.__names)
return self.__returns

View File

@@ -1,6 +1,11 @@
RootScreen: RootScreen:
Home: Home:
Main: Main:
ShowcaseS
###########
# POPUPS
###########
<PathMissingPU>: <PathMissingPU>:
title: "NOTICE!" title: "NOTICE!"
@@ -20,6 +25,46 @@ RootScreen:
on_release: on_release:
root.dismiss() root.dismiss()
<PathWrongPU>:
title: "NOTICE!"
font_size: 50
size_hint: 0.5, 0.4
auto_dismiss: False
GridLayout:
cols:1
Label:
text: "Path without any mp3/wav files specified"
font_size: 18
Label:
text: "Please enter another path and try again"
font_size: 15
Button:
text:"Ok"
on_release:
root.dismiss()
<invalidpathPU>:
title: "NOTICE!"
font_size: 50
size_hint: 0.5, 0.4
auto_dismiss: False
GridLayout:
cols:1
Label:
text: "Invalid path specified"
font_size: 18
Label:
text: "Please enter a valid path and try again"
font_size: 15
Button:
text:"Ok"
on_release:
root.dismiss()
###########
# SCREENS
###########
<Home>: <Home>:
name: "Home" name: "Home"
md_bg_color: app.theme_cls.accent_color md_bg_color: app.theme_cls.accent_color
@@ -42,6 +87,7 @@ RootScreen:
hint_text: "Path to Folder containing the Music files" hint_text: "Path to Folder containing the Music files"
pos_hint: {"x":0.2, "y":0.5} pos_hint: {"x":0.2, "y":0.5}
size_hint_x: 0.6 size_hint_x: 0.6
text: "/home/janis/Downloads"
Button: Button:
text: "Start" text: "Start"
color: app.theme_cls.primary_color color: app.theme_cls.primary_color
@@ -52,11 +98,74 @@ RootScreen:
root.change_screen() root.change_screen()
<Main>: <Main>:
on_pre_enter: root.initialize()
name: "Main" name: "Main"
GridLayout: GridLayout:
cols: 1 cols: 1
GridLayout:
cols: 2
Button:
text: "Next"
on_release:
root.nextsong()
Button:
text: "Rewind"
on_release:
root.rewindsong()
Button:
text: "Play"
id: pp_button
on_release:
root.playmusic()
GridLayout:
cols: 2
Button: Button:
text: "Back" text: "Back"
on_release: on_release:
app.root.current = "Home" root.go_back()
Button:
text: "Showcase"
on_release:
app.root.current = "Showcase"
root.manager.transition.direction = "left"
<ShowcaseS>:
on_pre_enter: root.screen_updater_start()
name: "Showcase"
md_bg_color: (0, 0, 0, 1)
FloatLayout:
Label:
text: "Currently Playing"
pos_hint: {"y": 0.4}
font_size: 35
color: app.theme_cls.primary_color
MDProgressBar:
orientation: "horizontal"
value: 100
pos_hint: {"y": 0.35}
color: app.theme_cls.primary_dark
Label:
id: current_song
text: "Currently playing Song will appear here"
pos_hint: {"y": 0.25}
font_size: 30
color: app.theme_cls.primary_color
Label:
text: "upcoming"
font_size: 25
color: app.theme_cls.primary_color
Label:
id: upcoming_songs
text: "Upcoming Songs will appear here"
pos_hint: {"y": -0.25}
font_size: 20
color: app.theme_cls.primary_color
Button:
text: "back"
font_size: 10
size_hint: 0.05, 0.05
background_color: app.theme_cls.accent_light
on_release:
app.root.current = "Main"
root.manager.transition.direction = "right"

96
bin/player.py Normal file
View File

@@ -0,0 +1,96 @@
import pygame.mixer as mx
import bin.csv_parsers
import copy
import bin.filepathanalysis
import pygame
import time
pa = bin.filepathanalysis.PathAnalysis()
cvr = bin.csv_parsers.CsvRead()
cvw = bin.csv_parsers.CsvWrite()
class Player:
def __init__(self):
self.__running = 1
self.event = ""
self.__recent_change = 1000000
self.__imports = []
self.information = []
self.current_playing_pos = 0
def start_playing(self):
# initialize playing
if pygame.get_init() == True:
pass
else:
pygame.init()
self.path = cvr.importing("./data/temp.csv").pop(0)
self.__imports = pa.validsonglistcreator(self.path.pop())
self.playlist = self.__imports.pop(0)
self.playlist_backup = copy.deepcopy(self.playlist)
self.information = self.__imports.pop(0)
mx.init()
self.current_playing = self.playlist.pop(0)
mx.music.load(self.current_playing)
mx.music.play()
mx.music.pause()
def infoupdater(self):
self.transmission = []
cvw.write_str("./data/songtemp.csv", [self.current_playing_pos])
cvw.app_str("./data/songtemp.csv", self.information)
def musicmanager(self, inst, other):
self.start_playing()
self.infoupdater()
while self.__running == 1:
if self.__recent_change < 1:
pass
else:
self.__recent_change -= 1
# instructions from main class
if other.value == 1:
other.value = 0
mx.music.unload()
if len(self.playlist) > 0:
pass
else:
self.playlist = copy.deepcopy(self.playlist_backup)
self.current_playing_pos = -1
self.current_playing = self.playlist.pop(0)
self.current_playing_pos += 1
mx.music.load(self.current_playing)
mx.music.play()
self.__recent_change = 1000000
self.infoupdater()
elif other.value == 2:
mx.music.rewind()
other.value = 0
elif other.value == 3:
self.__recent_change = 1000000
other.value = 0
else:
if inst.value == 1:
mx.music.unpause()
else:
mx.music.pause()
# Main event-checking part
if mx.music.get_busy() is False and inst.value == 1 and self.__recent_change == 0:
mx.music.unload()
if len(self.playlist) > 0:
pass
else:
self.playlist = copy.deepcopy(self.playlist_backup)
self.current_playing_pos = -1
self.current_playing = self.playlist.pop(0)
self.current_playing_pos += 1
mx.music.load(self.current_playing)
mx.music.play()
self.__recent_change = 10000000
self.infoupdater()
else:
pass

2
data/songtemp.csv Normal file
View File

@@ -0,0 +1,2 @@
0
Metaheuristic - Freedom Trail Studio.mp3,Heal You - Freedom Trail Studio.mp3,Straw Squeak.mp3
1 0
2 Metaheuristic - Freedom Trail Studio.mp3,Heal You - Freedom Trail Studio.mp3,Straw Squeak.mp3

1
data/temp.csv Normal file
View File

@@ -0,0 +1 @@
/home/janis/Downloads
1 /home/janis/Downloads

View File

@@ -1,10 +1,26 @@
import playsound as ps import multiprocessing
import os import os
from kivy.core.window import Window, Config
from kivy.uix.screenmanager import ScreenManager from kivy.uix.screenmanager import ScreenManager
from kivymd.uix.screen import MDScreen from kivymd.uix.screen import MDScreen
from kivymd.app import MDApp from kivymd.app import MDApp
from kivy.base import Builder from kivy.base import Builder
from kivy.uix.popup import Popup from kivy.uix.popup import Popup
from kivy.clock import Clock
import bin.csv_parsers
import bin.filepathanalysis
import bin.player
import pygame
import pygame.mixer as mx
import copy
import time
pl = bin.player.Player()
pa = bin.filepathanalysis.PathAnalysis()
cvr = bin.csv_parsers.CsvRead()
cvw = bin.csv_parsers.CsvWrite()
########### ###########
@@ -16,6 +32,14 @@ class PathMissingPU(Popup):
pass pass
class PathWrongPU(Popup):
pass
class invalidpathPU(Popup):
pass
########### ###########
# SCREENS # SCREENS
########### ###########
@@ -24,23 +48,128 @@ class PathMissingPU(Popup):
class Home(MDScreen): class Home(MDScreen):
def change_screen(self): def change_screen(self):
if self.ids.filepath.text != "": if self.ids.filepath.text != "":
self.manager.current = "Main" self.analyse_dir()
self.manager.transition.directio = "right"
else: else:
self.openpathmpu() self.openpathmpu()
def analyse_dir(self):
try:
self.__fcontent = os.listdir(self.ids.filepath.text)
self.__good_files = 0
for self.item in self.__fcontent:
self.__filextension = self.item[(len(self.item) - 4):]
if self.__filextension == ".mp3" or self.__filextension == ".wav":
self.__good_files += 1
else:
pass
# self.__good_files = 1
if self.__good_files > 0:
cvw.write_str("./data/temp.csv", [self.ids.filepath.text])
self.manager.current = "Main"
self.manager.transition.direction = "left"
else:
self.openpathfpu()
except:
self.ivpathpu()
def openpathmpu(self): def openpathmpu(self):
self.pmpu = PathMissingPU() self.pmpu = PathMissingPU()
self.pmpu.open() self.pmpu.open()
def openpathfpu(self):
self.wppu = PathWrongPU()
self.wppu.open()
def ivpathpu(self):
self.ivppu = invalidpathPU()
self.ivppu.open()
class Main(MDScreen): class Main(MDScreen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.instructions = multiprocessing.Value('i', 0)
self.others = multiprocessing.Value('i', 0)
self.keyboard = Window.request_keyboard(None, self)
self.keyboard.bind(on_key_down=self.key_pressed)
self.quit_requests = 0
def key_pressed(self, keyboard, keycode, text, modifiers):
# print(keycode[1])
self.key = keycode[1]
if self.key == "spacebar":
self.playmusic()
elif self.key == "right":
self.nextsong()
elif self.key == "left":
self.rewindsong()
else:
pass pass
def initialize(self):
try:
if self.mplayer.is_alive() == True:
pass
else:
self.mplayer = multiprocessing.Process(name="player", target=pl.musicmanager, args=(self.instructions, self.others,))
self.mplayer.start()
except:
self.mplayer = multiprocessing.Process(name="player", target=pl.musicmanager, args=(self.instructions, self.others,))
self.mplayer.start()
def playmusic(self):
self.others.value = 3
if self.instructions.value == 0:
self.instructions.value = 1
self.ids.pp_button.text = "Pause"
else:
self.instructions.value = 0
self.ids.pp_button.text = "Play"
def nextsong(self):
self.others.value = 1
def rewindsong(self):
self.others.value = 2
def go_back(self):
try:
self.mplayer.kill()
except:
pass
self.manager.current = "Home"
self.manager.transition.direction = "right"
class ShowcaseS(MDScreen):
def screen_updater_start(self):
Clock.schedule_interval(self.screen_updating, 2)
def screen_updating(self, waste):
self.__info = cvr.importing("./data/songtemp.csv")
self.__currents_imp = self.__info.pop(0)
self.__currents = int(self.__currents_imp.pop(0))
self.__upcoming = self.__info.pop(0)
self.__current = self.__upcoming.pop(self.__currents)
self.ids.current_song.text = self.__current[:(len(self.__current) - 4)]
if len(self.__upcoming) <= self.__currents:
self.ids.upcoming_songs.text = "No more songs in Queue"
else:
self.__upcoming2 = str(self.__upcoming.pop(self.__currents))
self.__upcoming_output = self.__upcoming2[:(len(self.__upcoming2) - 4)]
self.__length_output = 0
for i in range(len(self.__upcoming) - self.__currents):
if self.__length_output > 5:
pass
else:
self.__upcoming2 = str(self.__upcoming.pop(self.__currents))
self.__upcoming_output += f"\n{self.__upcoming2[:(len(self.__upcoming2) - 4)]}"
self.__length_output += 1
self.ids.upcoming_songs.text = self.__upcoming_output
class RootScreen(ScreenManager): class RootScreen(ScreenManager):
pass pass
class MusicPlayer(MDApp): class MusicPlayer(MDApp):
def build(self): def build(self):
self.title = "MusicPlayer" self.title = "MusicPlayer"
@@ -50,6 +179,12 @@ class MusicPlayer(MDApp):
return Builder.load_file("./bin/gui/gui.kv") return Builder.load_file("./bin/gui/gui.kv")
if __name__ == "__main__": if __name__ == "__main__":
Config.set('graphics', 'width', '800')
Config.set('graphics', 'height', '600')
Config.set('graphics', 'resizable', True)
Config.set('kivy', 'exit_on_escape', '0')
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
Config.set('graphics', 'window_state', 'normal')
Config.set('graphics', 'fullscreen', False)
Config.write()
MusicPlayer().run() MusicPlayer().run()
# ps.playsound("/mnt/sda3/Music/Videos/Songs/Ancient.mp3")