Compare commits

17 Commits

Author SHA1 Message Date
327aae5130 changes recording datatype from BLOB to VARCHAR, as I made up my mind and think, that storing the recordings as files somewhere is better than putting them in the database. recording should point to the path where the file can be found. (Maybe is copied and renamed to a nice place within the userspace) 2023-11-10 08:24:00 +01:00
2e9fc3655a updates README 2023-11-09 10:30:14 +01:00
d549b98a82 New feature: sm shows movements that are mastered by the active user 2023-11-09 10:28:28 +01:00
76d44e0dfe updates README 2023-11-09 09:46:40 +01:00
7352af038b moves recording BLOB from table movement to table is_able_to_play, so that recordings can be stored per user, not per movement 2023-11-09 09:40:10 +01:00
69d701d600 updates README with newly planned features 2023-11-09 09:34:11 +01:00
b5041dbc54 updates README 2023-11-08 18:44:46 +01:00
7f9e806c23 New feature: h displays help 2023-11-08 18:43:10 +01:00
ee23e0f0e9 simplifies adding of commands, as those can be added in commands-dictionary. Prepares help-texts as well. 2023-11-08 17:58:29 +01:00
b6dc9bd87b updates README 2023-11-08 12:50:26 +01:00
83c1d82387 New feature: m number_of_work number_of_movement marks single movements as mastered 2023-11-08 12:46:49 +01:00
488a97f3f6 Feature added: sp piece_number shows movements 2023-11-08 12:09:07 +01:00
626dfc25fc adds planned features to README 2023-11-08 07:10:30 +01:00
986eb94add New feature: sc shows composers, and c noc shows pieces by composer 2023-11-08 07:05:58 +01:00
8c311ea739 introduces Known Bugs to Readme 2023-11-07 14:35:43 +01:00
a75a241f30 new feature: m number marks work as mastered for active player and shows movements 2023-11-07 14:32:11 +01:00
10894187b2 new feature show works 2023-10-19 20:35:12 +02:00
3 changed files with 193 additions and 33 deletions

View File

@@ -11,14 +11,29 @@ At the moment, an alpha version is undertaken, with these features:
- The sqlite-database holds a growing number of piano-solo pieces, together with their exact catalogue-numbers and composers.
- Prepared in this database is a table for users (pianists), that marks which of the pieces can be played.
### Application
### Application and usage
- Create new users
- Set an active user
- (planned) Show the pieces stored in the database
- (planned) Mark pieces as masterd for the active user
- Create new users (`n username`)
- Show users (`su`)
- Set an active user (`a number_of_user`)
- Show the pieces stored in the database (`s`)
- Mark pieces as mastered for the active user (`m number_of_work`)
- Show pieces by composer (`c` shows composers, `s number_of_composer` shows pieces)
- Show movements through works (`sw work_number`)
- Mark movement as mastered for active user (`m number_of_work number_of_movement`)
- Show possible commands (`h`)
- Show mastered movements for activated user (`sm`)
- (planned) display, if work or movement is mastered from active user when viewing works and movements
- (planned) Save recordings per movement in db
- (planned) Listen to saved recordings
- (planned) Works are shown sorted (opus, collection e.g. "Walzer", "Sonaten")
## Requirements
- Python 3.9 or higher
- Enough disk space to hold the database
- run `python builddb.py` to build the SQLite-database-file before running `python rep_cli.py`
## Known Bugs
- Marking a piece as mastered the second time, the database wont insert the entry and the program will crash

View File

@@ -6,8 +6,20 @@ class Session:
self.user = -1
self.db_agent = db_agent
self.resultstring = 'no results yet'
self.commands = {'a': (self.set_user, 'Set an active user\n Usage: a number_of_user'),
'c': (self.show_composers, 'Shows composers'),
'h': (self.show_help, 'Displays this help document'),
'm': (self.mark_work_as_mastered, 'Marks work or movement as mastered for the active user\n Usage: m number_of_work, m number_of_work number_of_movement'),
'n': (self.create_new_user, 'Creates new user\n Usage: n firstname name'),
's': (self.show_works, 'Show the works stored in the database\n Usage: s, s number_of_composer'),
'sm': (self.show_mastered, 'Show mastered movements for activated user'),
'sw': (self.show_movements, 'Show movements of a work\n Usage: sw work_number'),
'su': (self.show_users, 'Show all users'),
'q': (self.quit, 'Quits the program')
}
def set_user(self, db_index):
def set_user(self, arguments):
db_index = arguments[0]
self.user = db_index
return 'User set'
@@ -27,31 +39,86 @@ class Session:
def invoke_command(self, command, arguments):
self.resultstring = ''
if command == 'a':
self.resultstring += self.set_user(arguments[0])
elif command == 'n':
self.create_new_user(arguments[0], arguments[1])
self.resultstring += f'Created new user {arguments[0]} {arguments[1]}.'
elif command == 's':
self.resultstring += self.show_works()
elif command == 'su':
self.resultstring += self.show_users()
elif command == 'q':
self.resultstring += 'Bye-bye'
if command in self.commands.keys():
self.resultstring += self.commands[command][0](arguments)
else:
self.resultstring += 'Could not understand command.'
def result(self):
return self.resultstring
def create_new_user(self, first_name, name):
def create_new_user(self, arguments):
first_name, name = arguments[0], arguments[1]
sql_command = f'''
INSERT INTO pianist (first_name, sec_name)
VALUES ("{first_name}", "{name}");
'''
self.db_agent.execute(sql_command)
return f'Created new user {first_name} {name}.'
def show_users(self):
def show_composers(self, _):
sql_command = '''
SELECT id, first_name, name
FROM composer
ORDER BY name
'''
result_list = self.db_agent.execute(sql_command).fetchall()
fun_resultstring = ''
for item in result_list:
fun_resultstring += f'{item[0]}: {item[2]}, {item[1]}\n'
return fun_resultstring
def show_help(self, arguments):
fun_resultstring = ''
if len(arguments) > 0:
qu_com = arguments[0]
if qu_com in self.commands:
fun_resultstring += f'{qu_com}: {self.commands[qu_com][1]}'
else:
fun_resultstring += f'Command {qu_com} not known, for help press h'
else:
for key, value in self.commands.items():
fun_resultstring += f'{key}: {value[1]}\n'
return fun_resultstring
def show_mastered(self, _):
fun_resultstring = 'Please activate user'
if not self.user == -1:
sql_command = f'''
SELECT work_id
FROM is_able_to_play
WHERE pianist_id = {self.user}
GROUP BY work_id
'''
list_of_work_ids = self.db_agent.execute(sql_command).fetchall()
list_of_works = list()
for item in list_of_work_ids:
list_of_works.append(work_under_id(item[0], self.db_agent))
fun_resultstring = 'All mastered movements:\n'
for work in list_of_works:
for mov_number in work.values['movements'].keys():
# check if movement is mastered
sql_command = f'''
SELECT *
FROM is_able_to_play
WHERE work_id = {work.id()}
AND mov_id = {mov_number}
AND pianist_id = {self.user}
'''
is_mastered = len(self.db_agent.execute(sql_command).fetchall()) > 0
if is_mastered:
fun_resultstring += f'{work.id()} {mov_number}. {work.pretty_mov(mov_number)}\n'
return fun_resultstring
def show_movements(self, arguments):
work_id = arguments[0]
work = work_under_id(work_id, self.db_agent)
fun_resultstring = ''
for mov_number in work.values['movements'].keys():
fun_resultstring += f'{mov_number}. {work.pretty_mov(mov_number)}\n'
return fun_resultstring
def show_users(self, _):
sql_command = '''
SELECT * FROM pianist;
'''
@@ -61,19 +128,54 @@ class Session:
fun_resultstring += f'{item[0]}: {item[1]} {item[2]}\n'
return fun_resultstring
def show_works(self):
sql_command = '''
def show_works(self, arguments):
if len(arguments) > 0:
restraint = f'comp_id = {arguments[0]}'
else:
restraint = '1 = 1'
sql_command = f'''
SELECT id
FROM work
WHERE {restraint}
'''
list_of_work_ids = self.db_agent.execute(sql_command).fetchall()
# GET WORKS OUT!
return ''
list_of_works = list()
for item in list_of_work_ids:
list_of_works.append(work_under_id(item[0], self.db_agent))
fun_resultstring = ''
for work in list_of_works:
fun_resultstring += f'{work.id()}: {work.pretty_string()}\n'
return fun_resultstring
def mark_work_as_mastered(self, arguments):
work_id = arguments[0]
resultstring = 'adding:\n'
work = work_under_id(work_id, self.db_agent)
if len(arguments) > 1: # in case there is a movement number given
mov_number = int(arguments[1])
sql_command = f'''
INSERT INTO is_able_to_play (work_id, mov_id, pianist_id)
VALUES ({work_id}, {mov_number}, {self.user})
'''
self.db_agent.execute(sql_command)
resultstring += f'{work.pretty_mov(mov_number)}\n'
else: # mark all movements of the work as mastered
for mov_number in work.values['movements'].keys():
sql_command = f'''
INSERT INTO is_able_to_play (work_id, mov_id, pianist_id)
VALUES ({work_id}, {mov_number}, {self.user})
'''
self.db_agent.execute(sql_command)
resultstring += f'{work.pretty_mov(mov_number)}\n'
return resultstring
def quit(self, _):
return 'Bye bye!'
# End session
class Werk_unter_id:
class work_under_id:
# con = sqlite3.connect('repertoire.db')
# reader = con.cursor()
@@ -108,12 +210,12 @@ class Werk_unter_id:
saetze = dict()
nummern = set()
suw_liste = self.reader.execute(sql_suw).fetchall()
# 0 work_id, 1 mov_number, 2 numb, 3 designation, 4 mus_key, 5 recording
# 0 work_id, 1 mov_number, 2 numb, 3 designation, 4 mus_key
for satz in suw_liste:
saetze[satz[1]] = satz[2], satz[3], satz[4]
if not satz[2] is None:
nummern.add(satz[2])
self.values['Sätze'] = saetze
self.values['movements'] = saetze
if len(nummern) == 1:
self.sätze_unter_nummer = True
self.values['numb'] = nummern.pop()
@@ -127,6 +229,51 @@ class Werk_unter_id:
else:
return sammlung
def id(self):
return self.values['id']
def pretty_string(self):
ret_str = ''
for key in ['first_name', 'name',
'title', 'opus',
'main_key', 'alias',
'work_directory','wd_number']:
if not self.values[key] is None:
if key == 'opus':
ret_str += f'op. {self.values[key]} '
else:
ret_str += f'{self.values[key]} '
return ret_str
def pretty_mov(self, mov_number):
ret_str = ''
for key in ['first_name', 'name',
'title', 'mov_title', 'opus', 'numb',
'main_key', 'alias',
'movements',
'work_directory','wd_number']:
if key in self.values.keys() and not self.values[key] is None:
if key == 'opus':
ret_str += f'op. {self.values[key]} '
elif key == 'name':
ret_str += f'{self.values[key]}, '
elif key == 'numb':
ret_str += f'Nr. {self.values[key]} '
elif key == 'movements':
if self.values[key][mov_number][1] is None:
ret_str += ''
else:
if len(self.values[key]) > 1:
ret_str += f'{mov_number}. {self.values[key][mov_number][1]} '
else:
ret_str += f'{self.values[key][mov_number][1]} '
elif key == 'title':
if self.values['mov_title'] is None:
ret_str += f'{self.values[key]} '
else:
ret_str += f'{self.values[key]} '
return ret_str
def __str__(self):
ret_str = ''
for key, value in self.values.items():
@@ -134,12 +281,12 @@ class Werk_unter_id:
ret_str += f'{key}: {value}\n'
return ret_str
# End Werk_unter_id
# End work_under_id
def parse_user_input(user_in):
def parse_user_input(user_in, session):
split_user_in = user_in.split()
command = split_user_in[0]
if command in ('a', 'n', 'q', 's', 'su'):
if command in session.commands.keys():
arguments = split_user_in[1:]
return (command, arguments)
else:
@@ -149,9 +296,8 @@ def command_line_loop(session):
user_in = ''
while not user_in == 'q':
user_in = input(f'Piano-Repertoire: {session.get_active_user()} >>> ')
command, arguments = parse_user_input(user_in)
command, arguments = parse_user_input(user_in, session)
session.invoke_command(command, arguments)
# print(f'command: {command}, arguments: {arguments}')
print(session.result())
def main():
@@ -164,6 +310,5 @@ def main():
con.close()
print('db-connection closed. Bye-bye!')
if __name__ == '__main__':
main()

View File

@@ -27,7 +27,6 @@ CREATE TABLE movement (
numb VARCHAR(15),
designation VARCHAR(63),
mus_key VARCHAR(15),
recording BLOB,
PRIMARY KEY(work_id, mov_number),
FOREIGN KEY(work_id) REFERENCES work(id)
);
@@ -50,6 +49,7 @@ CREATE TABLE is_able_to_play(
mov_id INTEGER NOT NULL,
pianist_id INTEGER NOT NULL,
days_to_practice INTEGER DEFAULT 7,
recording VARCHAR(255),
PRIMARY KEY(work_id, mov_id, pianist_id),
FOREIGN KEY(work_id, mov_id) REFERENCES movement(work_id, mov_number),
FOREIGN KEY(pianist_id) REFERENCES pianist(id)