Ticket #305: music.py

File music.py, 9.8 KB (added by scanner@…, 19 years ago)

"music" app models/music.py file

Line 
1#
2# $Id$
3#
4# Description:
5# This defines the model's for the "music" app in the mediaserv
6# project. These models represent things like 'tracks' 'albums' etc.
7#
8
9import datetime
10
11# We import meta from django.core because that is where all the fields and like
12# stuff is defined.
13#
14from django.core import meta
15
16#############################################################################
17#
18# Here are the django "models" of objects that the mediaserv "music" app cares
19# about
20#
21
22#############################################################################
23#
24class MusicRoot(meta.Model):
25 """Simply because I wanted to store as much configuration information
26 information in our database as seemed useful I have the MusicRoot class. It
27 describes a path on the local file system were music files may be found.
28
29 You can have more than one MusicRoot, obviously.
30 """
31
32 fields = (
33 meta.CharField('directory', maxlength = 1024),
34 meta.DateTimeField('last_scan_started', blank = True, null = True),
35 meta.DateTimeField('last_scan_finished', blank = True, null = True),
36 )
37
38 admin = meta.Admin()
39
40 #########################################################################
41 #
42 def __repr__(self):
43 return self.directory
44
45#############################################################################
46#
47class Artist(meta.Model):
48 """An artist. They will have a one to many relationship with
49 ArtistNames. They may have a simplified_name
50 name, and a many to many relationship with ArtistNames.
51
52 Not sure what other information we will have under the Artist object but it
53 seems to make sense to say that an artist is more than just a name.
54 """
55
56 fields = (
57 meta.CharField('comment', null = True, blank = True, maxlength = 1024),
58 meta.DateTimeField('date_added'),
59 )
60
61 admin = meta.Admin()
62
63 #########################################################################
64 #
65 def __repr__(self):
66 """Return the highest preference artist name, if this artist has any
67 names. If they do not just return the id.
68 """
69 if self.get_artistname_count() > 0:
70 return repr(self.get_artistname_list()[0])
71 else:
72 return str(self.id)
73
74 #########################################################################
75 #
76 def get_simple_name(self):
77 """Look through all the names that this artist has and return the first
78 one that is marked as a simplified name.
79
80 If we find no simplified names then return None.
81 """
82 if self.get_artistname_count() == 0:
83 return None
84 names = self.get_artistname_list()
85 for name in names:
86 if name.simple_char_set:
87 return name
88 return None
89
90#############################################################################
91#
92class ArtistName(meta.Model):
93 """An artist's name. An artist may have more than one name. Each name has a
94 preference. The higher the preference the more this name is the one we
95 should use if we have to present a single name. This name may also be one
96 that is represented in a simple character set - suitable for devices like
97 the rio receiver that can not display kanji.
98 """
99 fields = (
100 meta.CharField('name', maxlength = 512, core = True, unique = True),
101 meta.IntegerField('preference', default = 0),
102 meta.BooleanField('simple_char_set'),
103 meta.ForeignKey(Artist, edit_inline = meta.TABULAR, num_in_admin = 3),
104 )
105
106 ordering = ['-preference']
107
108 #########################################################################
109 #
110 def __repr__(self):
111 return self.name
112
113#############################################################################
114#
115class Album(meta.Model):
116 """An album is a collection of tracks. A track can only appear in one
117 album.
118
119 Do we want to bother with artist/album relationships? I guess not, just get
120 the list of tracks, get the list of artists for the tracks and do a unique
121 set of those.
122
123 Note: We need to have a simple name/name relationship for albums but this
124 is not nearly as complex as it was for artists. Albums are typically only
125 known by one name. We just need a simplified version for devices like the
126 rio receiver.
127
128 Note: When you get the list of tracks associated with an album it should
129 give you the list sorted in the order indicated by the tracks' track_number
130 and disk_number.
131 """
132
133 fields = (
134 meta.CharField('name', maxlength = 512),
135 meta.CharField('simplified_name', maxlength = 512, blank = True,
136 null = True),
137 meta.DateTimeField('date_added'),
138 )
139
140 #########################################################################
141 #
142 def __repr__(self):
143 return self.name
144
145#############################################################################
146#
147class PlayList(meta.Model):
148 """Like an album this is a collection of tracks. Unlike an album, a track
149 can occur more than once in a play list.
150
151 Tracks in a play list need to have a defined order that is determined by
152 the playlist. Not sure how to do this yet.
153 """
154 fields = (
155 meta.CharField('name', maxlength = 512, unique = True),
156 meta.CharField('simplified_name', maxlength = 512, blank = True,
157 null = True),
158 )
159
160 admin = meta.Admin()
161
162 #########################################################################
163 #
164 def __repr__(self):
165 return self.name
166
167#############################################################################
168#
169class Genre(meta.Model):
170 """For better or for worse tracks have a fixed single genre field.
171 We will set the 'id' to be the same as the accepted standard set of genres.
172 """
173 fields = (
174 meta.CharField('name', maxlength = 256, unique = True),
175 meta.IntegerField('genre_id'), # To map to the mp3 id field
176 )
177
178 #########################################################################
179 #
180 def __repr__(self):
181 return self.name
182
183#############################################################################
184#
185class Track(meta.Model):
186 """A track refers to a single playable file of sound/music media. The basic
187 fields are determined from what is available via the id3 tags.
188
189 However things like the 'album' and 'artist' are relations to other object
190 model instances.
191
192 We also keep track of some additional field so that we can echo it back to
193 iTunes potentially. Named things like 'last played time' and 'number of
194 times played.'
195
196 We also keep track of the encoding format of the track. Some players can
197 not play some encodings.
198
199 A track may also have a 'limited_name' field which is a representation of
200 the track's name in simple ASCII so that devices which can not display rich
201 character sets can display a simplified (aka romanized for Japanese track
202 names) instead of displaying gobbedly gook.
203 """
204
205 fields = (
206 meta.CharField('title', maxlength = 512),
207 meta.CharField('filename', maxlength = 1024, db_index = True),
208 meta.CharField('simplified_name', maxlength = 256, blank = True,
209 null = True),
210 meta.IntegerField('year', null = True),
211 meta.IntegerField('play_time'),
212 meta.IntegerField('bit_rate'),
213 meta.BooleanField('vbr'),
214 meta.IntegerField('track_number', default = 0),
215 meta.IntegerField('disc_number', default = 0),
216 meta.IntegerField('play_count', default = 0), # tied to iTunes
217 meta.DateTimeField('last_scanned', blank = True, null = True),
218 meta.DateTimeField('last_played', null = True), # tied to iTunes
219 meta.IntegerField('bpm','beats per minute', null = True), # iTunes
220 meta.CharField('grouping', maxlength = 512, null = True,
221 blank = True), # tied to iTunes
222 meta.CharField('comments', maxlength = 1024, null = True,
223 blank = True), # tied to iTunes
224 meta.ForeignKey(Artist, blank = True, null = True),
225 meta.ForeignKey(Album, blank = True, null = True),
226 meta.ManyToManyField(PlayList, blank = True, null = True),
227 meta.ForeignKey(Genre, blank = True, null = True),
228 meta.ForeignKey(MusicRoot),
229 )
230
231 ordering = ['track_number', 'disc_number']
232
233 #########################################################################
234 #
235 def __repr__(self):
236 return self.title
237
238 #########################################################################
239 #
240 def play_time_string(self):
241 """Convert the playtime we have that is in seconds to a friendlier
242 human readable string. This was cribbed from
243 Eye3D.tag.getPlayTimeString()
244 """
245 total = self.play_time
246 h = total / 3600
247 m = (total % 3600) / 60
248 s = (total % 3600) % 60
249 if h:
250 timeStr = "%d:%.2d:%.2d" % (h, m, s)
251 else:
252 timeStr = "%d:%.2d" % (m, s)
253 return timeStr
254
255#############################################################################
256#
257class Artwork(meta.Model):
258 """iTunes lets us associate multiple pieces of artwork with tracks.
259 I am thinking of letting albums also have artwork associated with them (who
260 would see this, though? Only the web interface so far.)
261
262 A track may have more than one piece of art associated with it.
263 """
264
265 fields = (
266 meta.ImageField('image'),
267 # Maybe we should store some of the file's attributes in our structure?
268 # Image size? encoding?
269 meta.ManyToManyField(Track),
270 )
271
272 admin = meta.Admin()
273
274 #########################################################################
275 #
276## def __repr__(self):
277## return self.file_name
278
Back to Top