This exercise is to enhance playgen, so that it generates a PlayList based on the tag values of visited Mp3Files. To achieve this, we need multi-dimensional property constraints.
Two classes from libdataobjects can help you solve this problem. ConstraintGroup is a class you can reuse for multidimensional Constraints. Each Constraint is a piece of a query, so a query can be represented by a ConstraintGroup.
usage: playgen [options] filespec [options] are optional. filespec can be a directory to scan, or a list of mp3 files to add to playlist. Directories are recursed. Additional options can be: (filter options) -p Good - filter on Preference -p 5 - equivalent to preference Good -p "Very Good" - Need double quotes around this one -g Chill - filter on Chill genre -a ".*gabriel.*" - regex filter on artists - need doublequotes around regex -b albumpattern - filter on album title -s songpattern - filter on song title Advanced queries: If the same switch appears multiple times, OR the values together. -p Excellent -p "Very Good" (either can be true) If different switches appear on the same query AND them together. -p Excellent -g Ambient (both must be true). -p "6,7" - Allow preferences 6 and 7 only -p "4:9" - Filter on preferences of the subrange 4 to 9 -p "0,5:" - filter on preferences undefined, or anything better than "good" -p "1,2,3" - only preferences "badtaste", "poor" and "none" example: playgen ./music/comedy/weirdal make a playlist of all the songs in that directory, without any filtering, and send to standard output. playgen -o "weirdalsbest.m3u" -p "Excellent" ./music/ comedy/weirdal Should go into the weirdal directory and spit out only the "Excellent" tracks, saving them to a file. playgen -g "(Rock|Classical|Dub)" ./music/techno Filter on genres - since you e using regular expressions to match, you have the full regular expression query language here.
In Figure 25.6, the UML diagram shows one possible way of organizing your code. You are free to deviate from this diagram as you design your own solution.
You might think of your program in the following way.
1. | Given an ArgumentList, create an object that represents the collection of field/value pairs as a set of constraints. |
2. | Use FileVisitor to visit each file in filespec. |
3. | Use FileTagger to extract the ID3 information of each MP3 file. |
4. | After you have extracted the ID3 information, check whether the object satisfies the constraints specified. |
5. | If the object satisfies your constraints, we want to make a copy of the FileTaggers attributes in a new Mp3File object and add the Mp3File to the PlayList returned by playgen (instead of adding the actual FileTagger, which we will reuse for the next visited file). |
6. | Return a PlayList with the selected songs. |
7. | Write a factory for Query objects, called QueryFactory, and a function, called newQuery, to handle all instance creation. class QueryFactory { Query * QueryFactory::newQuery(QStringList[2] args); };
|