580 lines
20 KiB
Python
Executable file
580 lines
20 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
"""
|
|
Scorelib - A score library management programm
|
|
|
|
Copyright (C) 2015 - 2016 Marcel Kapfer (mmk2410) <marcelmichaelkapfer@yahoo.co.nz>
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
"""
|
|
|
|
import sqlite3
|
|
import readline
|
|
import getpass
|
|
import os
|
|
|
|
USER = getpass.getuser()
|
|
CONFIG = "/home/" + USER + "/.scorelib/"
|
|
DBPATH = CONFIG + "scorelib.db"
|
|
|
|
class Piece:
|
|
""" A class for working with scores """
|
|
|
|
def __init__(self, piece=None):
|
|
if piece is None:
|
|
raise NameError("No piece list given")
|
|
if piece['id'] is None:
|
|
raise NameError("No piece id given")
|
|
self.pieceid = piece['id']
|
|
self.name = piece['name']
|
|
self.composer = piece['composer']
|
|
self.opus = piece['opus']
|
|
self.key = piece['key']
|
|
self.book = piece['book']
|
|
|
|
def get_list(self):
|
|
""" Returns a list for sending to the database """
|
|
piece = (self.name, self.composer, self.opus, self.key, self.book, self.pieceid)
|
|
return piece
|
|
|
|
def print_piece(self):
|
|
""" prints the current piece """
|
|
print(
|
|
"""
|
|
Name: {}
|
|
Composer: {}
|
|
Opus: {}
|
|
Key: {}
|
|
Book: {}
|
|
""".format(self.name, self.composer, self.opus, self.key, self.book))
|
|
|
|
def delete(self):
|
|
"""
|
|
Delete a item
|
|
"""
|
|
con = None
|
|
try:
|
|
con = sqlite3.connect(DBPATH)
|
|
cur = con.cursor()
|
|
sqlcmd = "DELETE FROM Scores WHERE id = " + str(self.pieceid)
|
|
cur.execute(sqlcmd)
|
|
con.commit()
|
|
except sqlite3.Error as err:
|
|
print("Error: %s" % err.args[0])
|
|
finally:
|
|
if con:
|
|
con.close()
|
|
|
|
def change(self):
|
|
""")
|
|
Change a item
|
|
"""
|
|
# Updating the values
|
|
name = rlinput("Name: ", self.name)
|
|
self.name = name or self.name
|
|
self.composer = rlinput("Composer: ", self.composer)
|
|
self.opus = rlinput("Opus: ", self.opus)
|
|
self.key = rlinput("Key: ", self.key)
|
|
self.book = rlinput("Book: ", self.book)
|
|
# Pushing changes to the database
|
|
con = sqlite3.connect(DBPATH)
|
|
print(self.get_list)
|
|
with con:
|
|
cur = con.cursor()
|
|
cur.execute("UPDATE Scores SET Name=?, Composer=?, Opus=?, Key=?, Book=? WHERE Id=?",\
|
|
self.get_list())
|
|
con.commit()
|
|
|
|
|
|
def rlinput(prompt, prefill=''):
|
|
""" Function for advanced input (preset user input) """
|
|
readline.set_startup_hook(lambda: readline.insert_text(prefill))
|
|
try:
|
|
return input(prompt)
|
|
finally:
|
|
readline.set_startup_hook()
|
|
|
|
def initialize():
|
|
"""
|
|
Initializing the database by creating a table
|
|
"""
|
|
|
|
print("Initializing the database...")
|
|
|
|
os.mkdir(CONFIG, 0o755)
|
|
|
|
con = None
|
|
|
|
try:
|
|
con = sqlite3.connect(DBPATH)
|
|
|
|
cur = con.cursor()
|
|
|
|
cur.execute(
|
|
"CREATE TABLE Scores( \
|
|
Id INTEGER PRIMARY KEY ASC NOT NULL, \
|
|
Name TEXT NOT NULL, \
|
|
Composer TEXT, \
|
|
Opus TEXT, \
|
|
Key TEXT, \
|
|
Book TEXT);"
|
|
)
|
|
|
|
except sqlite3.Error as err:
|
|
print("Error: %s" % err.args[0])
|
|
return 1
|
|
|
|
finally:
|
|
if con:
|
|
con.close()
|
|
|
|
return 0
|
|
|
|
def destroy():
|
|
"""
|
|
Destroys the table.
|
|
"""
|
|
print("Destroying all informations...")
|
|
|
|
con = None
|
|
|
|
try:
|
|
con = sqlite3.connect(DBPATH)
|
|
|
|
cur = con.cursor()
|
|
|
|
cur.execute("DROP TABLE IF EXISTS Scores")
|
|
|
|
except sqlite3.Error as err:
|
|
print("Error: %s" % err.args[0])
|
|
return 1
|
|
|
|
finally:
|
|
if con:
|
|
con.close()
|
|
|
|
return 0
|
|
|
|
def add():
|
|
""" Add a entry to the database """
|
|
while True:
|
|
title = input("Title: ")
|
|
if title:
|
|
break
|
|
else:
|
|
print("You have to enter the name of the piece")
|
|
piece = {"id": 0, "name":title}
|
|
piece['composer'] = input("Composer: ")
|
|
piece['opus'] = input("Opus: ")
|
|
piece['key'] = input("Key: ")
|
|
piece['book'] = input("Book: ")
|
|
|
|
try:
|
|
new_piece = Piece(piece)
|
|
except NameError as err:
|
|
print("Error: %s" % err.args[0])
|
|
return -1
|
|
|
|
new_piece.print_piece()
|
|
|
|
con = None
|
|
|
|
try:
|
|
con = sqlite3.connect(DBPATH)
|
|
|
|
cur = con.cursor()
|
|
|
|
sqlcmd = "INSERT INTO Scores VALUES(NULL,'"\
|
|
+ piece['name'] + "','" \
|
|
+ piece['composer'] + "','" \
|
|
+ piece['opus'] + "','" \
|
|
+ piece['key'] + "','" \
|
|
+ piece['book'] + "')"
|
|
|
|
cur.execute(sqlcmd)
|
|
|
|
con.commit()
|
|
|
|
except sqlite3.Error as err:
|
|
print("Error: %s" % err.args[0])
|
|
return 1
|
|
|
|
finally:
|
|
if con:
|
|
con.close()
|
|
|
|
return 0
|
|
|
|
def list_scores():
|
|
"""
|
|
List all available scores
|
|
"""
|
|
|
|
con = None
|
|
|
|
try:
|
|
|
|
con = sqlite3.connect(DBPATH)
|
|
|
|
cur = con.cursor()
|
|
|
|
cur.execute("SELECT * FROM Scores")
|
|
|
|
print()
|
|
|
|
while True:
|
|
|
|
row = cur.fetchone()
|
|
|
|
if row is None:
|
|
break
|
|
|
|
print(
|
|
"""
|
|
Piece number: {}
|
|
Name: {}
|
|
Composer: {}
|
|
Opus: {}
|
|
Key: {}
|
|
Book: {}
|
|
""".format(row[0], row[1], row[2], row[3], row[4], row[5])
|
|
)
|
|
|
|
|
|
except sqlite3.Error as err:
|
|
print("Error: %s" % err.args[0])
|
|
return 1
|
|
|
|
finally:
|
|
if con:
|
|
con.close()
|
|
|
|
return 0
|
|
|
|
def edit_get_id():
|
|
""" Get the piece id from the user"""
|
|
pieceid = None
|
|
while True:
|
|
pieceid = input("Enter the piece number: ")
|
|
if pieceid == 'quit':
|
|
return 0
|
|
elif pieceid and pieceid.isdigit():
|
|
con = sqlite3.connect(DBPATH)
|
|
piecerow = None
|
|
with con:
|
|
cur = con.cursor()
|
|
cur.execute("SELECT * FROM Scores WHERE Id=" + str(pieceid))
|
|
piecerow = cur.fetchone()
|
|
if piecerow is None:
|
|
print("No Piece with this number available.")
|
|
else:
|
|
break
|
|
else:
|
|
print("Input must be a valid number!")
|
|
return piecerow
|
|
|
|
|
|
def edit():
|
|
"""Function for editing the pieces"""
|
|
# Ask piece id from user
|
|
piecerow = edit_get_id()
|
|
|
|
# Getting the piece information
|
|
piecedata = {"id": piecerow[0], "name": piecerow[1], "composer": piecerow[2],\
|
|
"opus": piecerow[3], "key": piecerow[4], "book": piecerow[5]}
|
|
piece = Piece(piecedata)
|
|
print("Piece Information:")
|
|
piece.print_piece()
|
|
|
|
# edit prompt
|
|
while True:
|
|
edtcmd = input(" (edit) > ")
|
|
if edtcmd in ['help', '?', 'usage']:
|
|
helpedittext()
|
|
elif edtcmd in ['done', 'q']:
|
|
return 0
|
|
elif edtcmd in ['print', 'p']:
|
|
piece.print_piece()
|
|
elif edtcmd in ['delete', 'd']:
|
|
piece.delete()
|
|
return 0
|
|
elif edtcmd in ['edit', 'change', 'c', 'e']:
|
|
piece.change()
|
|
else:
|
|
helpedittext(True)
|
|
|
|
def search():
|
|
""" Search through the database """
|
|
term = input("Search for: ")
|
|
con = sqlite3.connect(DBPATH)
|
|
with con:
|
|
cur = con.cursor()
|
|
cur.execute("SELECT * FROM Scores")
|
|
rows = cur.fetchall()
|
|
for item in range(1, 6):
|
|
if item == 1:
|
|
print("By name\n")
|
|
elif item == 2:
|
|
print("By Composer\n")
|
|
elif item == 3:
|
|
print("By Opus\n")
|
|
elif item == 4:
|
|
print("By Key\n")
|
|
elif item == 5:
|
|
print("By Book\n")
|
|
for row in rows:
|
|
if term in row[item]:
|
|
piecedata = {"id": row[0], "name": row[1], "composer": row[2],\
|
|
"opus": row[3], "key": row[4], "book": row[5]}
|
|
piece = Piece(piecedata)
|
|
print("Piece number: %s" % str(row[0]))
|
|
piece.print_piece()
|
|
|
|
|
|
def helpedittext(doneshit=False):
|
|
""" print the edit help text """
|
|
if doneshit:
|
|
print("The entered command ist not available.")
|
|
print(
|
|
"""
|
|
Edit help text:
|
|
|
|
help, ?, usage Print edit help
|
|
done, q Done editing piece; back to main menu
|
|
print, p Print piece information
|
|
delete, d Delete this item and go back to main menu
|
|
edit, change, c, e Change the values of the item
|
|
"""
|
|
)
|
|
|
|
def helptext(doneshit=False):
|
|
""" print the help text """
|
|
if doneshit:
|
|
print("The entered command is not available.")
|
|
print(
|
|
"""
|
|
Scorelib v0.1.2
|
|
A program for managing your music score collection
|
|
|
|
Author:
|
|
Marcel Kapfer (mmk2410) <marcelmichaelkapfer@yahoo.co.nz>
|
|
|
|
License:
|
|
GPL v3
|
|
|
|
Help:
|
|
|
|
help, usage, ? prints this text
|
|
add, new, a add a new piece
|
|
list, l list all pieces
|
|
edit, e edit a piece (piece number required)
|
|
search, s search for a piece
|
|
init initializes the database
|
|
kill destroys the database
|
|
quit, exit, x, q close Scorelib
|
|
|
|
"""
|
|
)
|
|
|
|
|
|
def main():
|
|
""" Main """
|
|
print(
|
|
"""
|
|
Scorelib Copyright (C) 2015 - 2016 Marcel Kapfer (mmk2410)
|
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
This is free software, and you are welcome to redistribute it under certain
|
|
conditions; type `show c' for details.
|
|
|
|
"""
|
|
)
|
|
|
|
while True:
|
|
cmd = input(" > ")
|
|
|
|
if cmd in ['usage', 'help', '?']:
|
|
helptext()
|
|
elif cmd == 'show w':
|
|
print(
|
|
"""
|
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
|
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER
|
|
PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE
|
|
QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
|
|
DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
|
"""
|
|
)
|
|
elif cmd == 'show c':
|
|
print(
|
|
"""
|
|
4. Conveying Verbatim Copies.
|
|
|
|
You may convey verbatim copies of the Program's source code as you receive it,
|
|
in any medium, provided that you conspicuously and appropriately publish on each
|
|
copy an appropriate copyright notice; keep intact all notices stating that this
|
|
License and any non-permissive terms added in accord with section 7 apply to the
|
|
code; keep intact all notices of the absence of any warranty; and give all
|
|
recipients a copy of this License along with the Program.
|
|
|
|
You may charge any price or no price for each copy that you convey, and you may
|
|
offer support or warranty protection for a fee.
|
|
|
|
5. Conveying Modified Source Versions.
|
|
|
|
You may convey a work based on the Program, or the modifications to produce it
|
|
from the Program, in the form of source code under the terms of section 4,
|
|
provided that you also meet all of these conditions:
|
|
|
|
a) The work must carry prominent notices stating that you modified it, and
|
|
giving a relevant date.
|
|
b) The work must carry prominent notices stating that it is released under
|
|
this License and any conditions added under section 7. This requirement
|
|
modifies the requirement in section 4 to “keep intact all notices”.
|
|
c) You must license the entire work, as a whole, under this License to
|
|
anyone who comes into possession of a copy. This License will therefore
|
|
apply, along with any applicable section 7 additional terms, to the whole of
|
|
the work, and all its parts, regardless of how they are packaged. This
|
|
License gives no permission to license the work in any other way, but it
|
|
does not invalidate such permission if you have separately received it.
|
|
d) If the work has interactive user interfaces, each must display
|
|
Appropriate Legal Notices; however, if the Program has interactive
|
|
interfaces that do not display Appropriate Legal Notices, your work need
|
|
not make them do so.
|
|
|
|
A compilation of a covered work with other separate and independent works, which
|
|
are not by their nature extensions of the covered work, and which are not
|
|
combined with it such as to form a larger program, in or on a volume of a
|
|
storage or distribution medium, is called an “aggregate” if the compilation and
|
|
its resulting copyright are not used to limit the access or legal rights of the
|
|
compilation's users beyond what the individual works permit. Inclusion of a
|
|
covered work in an aggregate does not cause this License to apply to the other
|
|
parts of the aggregate.
|
|
|
|
6. Conveying Non-Source Forms.
|
|
|
|
You may convey a covered work in object code form under the terms of sections
|
|
4 and 5, provided that you also convey the machine-readable Corresponding
|
|
Source under the terms of this License, in one of these ways:
|
|
|
|
a) Convey the object code in, or embodied in, a physical product (including
|
|
a physical distribution medium), accompanied by the Corresponding Source
|
|
fixed on a durable physical medium customarily used for software
|
|
interchange.
|
|
b) Convey the object code in, or embodied in, a physical product (including
|
|
a physical distribution medium), accompanied by a written offer, valid for
|
|
at least three years and valid for as long as you offer spare parts or
|
|
customer support for that product model, to give anyone who possesses the
|
|
object code either (1) a copy of the Corresponding Source for all the
|
|
software in the product that is covered by this License, on a durable
|
|
physical medium customarily used for software interchange, for a price no
|
|
more than your reasonable cost of physically performing this conveying of
|
|
source, or (2) access to copy the Corresponding Source from a network
|
|
server at no charge.
|
|
c) Convey individual copies of the object code with a copy of the written
|
|
offer to provide the Corresponding Source. This alternative is allowed only
|
|
occasionally and noncommercially, and only if you received the object code
|
|
with such an offer, in accord with subsection 6b.
|
|
d) Convey the object code by offering access from a designated place
|
|
(gratis or for a charge), and offer equivalent access to the Corresponding
|
|
Source in the same way through the same place at no further charge. You
|
|
need not require recipients to copy the Corresponding Source along with the
|
|
object code. If the place to copy the object code is a network server, the
|
|
Corresponding Source may be on a different server (operated by you or a
|
|
third party) that supports equivalent copying facilities, provided you
|
|
maintain clear directions next to the object code saying where to find the
|
|
Corresponding Source. Regardless of what server hosts the Corresponding
|
|
Source, you remain obligated to ensure that it is available for as long as
|
|
needed to satisfy these requirements.
|
|
e) Convey the object code using peer-to-peer transmission, provided you
|
|
inform other peers where the object code and Corresponding Source of the
|
|
work are being offered to the general public at no charge under subsection
|
|
6d.
|
|
|
|
A separable portion of the object code, whose source code is excluded from the
|
|
Corresponding Source as a System Library, need not be included in conveying the
|
|
object code work.
|
|
|
|
A “User Product” is either (1) a “consumer product”, which means any tangible
|
|
personal property which is normally used for personal, family, or household
|
|
purposes, or (2) anything designed or sold for incorporation into a dwelling.
|
|
In determining whether a product is a consumer product, doubtful cases shall be
|
|
resolved in favor of coverage. For a particular product received by a particular
|
|
user, “normally used” refers to a typical or common use of that class of
|
|
product, regardless of the status of the particular user or of the way in which
|
|
the particular user actually uses, or expects or is expected to use, the
|
|
product. A product is a consumer product regardless of whether the product has
|
|
substantial commercial, industrial or non-consumer uses, unless such uses
|
|
represent the only significant mode of use of the product.
|
|
|
|
“Installation Information” for a User Product means any methods, procedures,
|
|
authorization keys, or other information required to install and execute
|
|
modified versions of a covered work in that User Product from a modified version
|
|
of its Corresponding Source. The information must suffice to ensure that the
|
|
continued functioning of the modified object code is in no case prevented or
|
|
interfered with solely because modification has been made.
|
|
|
|
If you convey an object code work under this section in, or with, or
|
|
specifically for use in, a User Product, and the conveying occurs as part of a
|
|
transaction in which the right of possession and use of the User Product is
|
|
transferred to the recipient in perpetuity or for a fixed term (regardless of
|
|
how the transaction is characterized), the Corresponding Source conveyed under
|
|
this section must be accompanied by the Installation Information. But this
|
|
requirement does not apply if neither you nor any third party retains the
|
|
ability to install modified object code on the User Product (for example, the
|
|
work has been installed in ROM).
|
|
|
|
The requirement to provide Installation Information does not include a
|
|
requirement to continue to provide support service, warranty, or updates for a
|
|
work that has been modified or installed by the recipient, or for the User
|
|
Product in which it has been modified or installed. Access to a network may be
|
|
denied when the modification itself materially and adversely affects the
|
|
operation of the network or violates the rules and protocols for communication
|
|
across the network.
|
|
|
|
Corresponding Source conveyed, and Installation Information provided, in accord
|
|
with this section must be in a format that is publicly documented (and with an
|
|
implementation available to the public in source code form), and must require no
|
|
special password or key for unpacking, reading or copying.
|
|
"""
|
|
)
|
|
elif cmd in ['quit', 'exit', 'x', 'q']:
|
|
print("Good Bye!")
|
|
exit(0)
|
|
elif cmd == 'init':
|
|
status = initialize()
|
|
if status == 1:
|
|
print("A database error occurred. Please try again.")
|
|
elif cmd == 'kill':
|
|
status = destroy()
|
|
if status == 1:
|
|
print("A database error occurred. Please try again.")
|
|
elif cmd in ['add', 'new', 'a']:
|
|
status = add()
|
|
if status == 1:
|
|
print("A database error occurred. Please try again.")
|
|
elif status == -1:
|
|
print("An input you made was not accepted.")
|
|
elif cmd in ['list', 'l']:
|
|
list_scores()
|
|
elif cmd in ['edit', 'e']:
|
|
edit()
|
|
elif cmd in ['search', 's']:
|
|
search()
|
|
else:
|
|
helptext(True)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|