smartplaylistrules.h

00001  /*****************************************************************************
00002  *   Copyright (C) 2006 by Michael Schulze                                    *
00003  *   mike.s@genion.de                                                         *
00004  *                                                                            *
00005  *  The code contained in this file is free software; you can redistribute    *
00006  *  it and/or modify it under the terms of the GNU Lesser General Public      *
00007  *  License as published by the Free Software Foundation; either version      *
00008  *  2.1 of the License, or (at your option) any later version.                *
00009  *                                                                            *
00010  *  This file is distributed in the hope that it will be useful,              *
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of            *
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00013  *  Lesser General Public License for more details.                           *
00014  *                                                                            *
00015  *  You should have received a copy of the GNU Lesser General Public          *
00016  *  License along with this code; if not, write to the Free Software          *
00017  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *
00018  *                                                                            *
00019  *  iTunes and iPod are trademarks of Apple                                   *
00020  *                                                                            *
00021  *  This product is not supported/written/published by Apple!                 *
00022  *****************************************************************************/
00023 
00024 #ifndef ITUNESDBSMARTPLAYLISTRULES_H
00025 #define ITUNESDBSMARTPLAYLISTRULES_H
00026 
00027 #include <qstring.h>
00028 #include <vector>
00029 
00030 #define ACTION_NOT_BIT 0x02000000
00031 #define ACTION_STRING_BIT 0x01000000
00032 
00033 #define SPL_VALUE_NOW 0x2dae2dae2dae2daeLL
00034 
00035 #define IN_THE_LAST_SECONDS 1
00036 #define IN_THE_LAST_DAYS    86400
00037 #define IN_THE_LAST_WEEKS   604800
00038 
00039 namespace itunesdb {
00040 
00041 /**
00042     Defines Smart Playlist Rules
00043 
00044     @author Michael Schulze
00045 */
00046 
00047 
00048 enum SPLStringField {
00049     FIELD_NAME         = 0x02,
00050     FIELD_ALBUM        = 0x03,
00051     FIELD_ARTIST       = 0x04,
00052     FIELD_GENRE        = 0x08,
00053     FIELD_KIND         = 0x09,
00054     FIELD_COMMENT      = 0x0e,
00055     FIELD_COMPOSER     = 0x12,
00056     FIELD_GROUPING     = 0x27,
00057     FIELD_DESCRIPTION  = 0x36,
00058     FIELD_CATEGORY     = 0x37,
00059     FIELD_TV_SHOW      = 0x3E,
00060     FIELD_ALBUM_ARTIST = 0x47
00061 };
00062 
00063 enum SPLUIntField {
00064     FIELD_BITRATE      = 0x05,
00065     FIELD_SAMPLERATE   = 0x06,
00066     FIELD_YEAR         = 0x07,
00067     FIELD_DATEMODIFIED = 0x0a,
00068     FIELD_TRACKNUMBER  = 0x0b,
00069     FIELD_SIZE         = 0x0c,
00070     FIELD_TIME         = 0x0d,
00071     FIELD_DATEADDED    = 0x10,
00072     FIELD_PLAYCOUNT    = 0x16,
00073     FIELD_LASTPLAYED   = 0x17,
00074     FIELD_DISCNUMBER   = 0x18,
00075     FIELD_RATING       = 0x19,
00076     FIELD_COMPILATION  = 0x1f,
00077     FIELD_BPM          = 0x23,
00078     FIELD_PLAYLISTID   = 0x28,
00079     FIELD_PODCAST      = 0x39,
00080     FIELD_VIDEO_KIND   = 0x3C,
00081     FIELD_SEASON_NR    = 0x3F,
00082     FIELD_SKIP_COUNT   = 0x44,
00083     FIELD_LAST_SKIPPED = 0x45
00084 };
00085 
00086 
00087 enum SPLStringAction {
00088     ACTION_IS_STRING = 0x01000001,
00089     ACTION_CONTAINS = 0x01000002,
00090     ACTION_STARTSWITH = 0x01000004,
00091     ACTION_ENDSWITH = 0x01000008,
00092     ACTION_IS_NOT_STRING = ACTION_IS_STRING ^ ACTION_NOT_BIT,
00093     ACTION_DOESNT_CONTAIN = ACTION_CONTAINS ^ ACTION_NOT_BIT,
00094     ACTION_DOESNT_STARTWITH = ACTION_STARTSWITH ^ ACTION_NOT_BIT,
00095     ACTION_DOESNT_ENDWITH = ACTION_ENDSWITH ^ ACTION_NOT_BIT
00096 };
00097 
00098 
00099 enum SPLUIntAction {
00100     ACTION_IS_UINT = 0x00000001,
00101     ACTION_GREATER_THAN = 0x00000010,
00102     ACTION_GREATER_OR_EQUAL = 0x00000020,
00103     ACTION_LESS_THAN = 0x00000040,
00104     ACTION_LESS_OR_EQUAL = 0x00000080,
00105     ACTION_IN_RANGE = 0x00000100,
00106     ACTION_IN_THE_LAST = 0x00000200,
00107     ACTION_IS_NOT_UINT = ACTION_IS_UINT ^ ACTION_NOT_BIT,
00108     ACTION_NOT_GREATER = ACTION_GREATER_THAN ^ ACTION_NOT_BIT,
00109     ACTION_NOT_GREATER_OR_EQUAL = ACTION_GREATER_OR_EQUAL ^ ACTION_NOT_BIT,
00110     ACTION_NOT_LESS = ACTION_LESS_THAN ^ ACTION_NOT_BIT,
00111     ACTION_NOT_LESS_OR_EQUAL = ACTION_LESS_OR_EQUAL ^ ACTION_NOT_BIT,
00112     ACTION_NOT_IN_RANGE = ACTION_IN_RANGE ^ ACTION_NOT_BIT,
00113     ACTION_NOT_IN_THE_LAST = ACTION_IN_THE_LAST ^ ACTION_NOT_BIT
00114 };
00115 
00116 
00117 enum SPLLimitSort {
00118     LIMIT_SORT_RANDOM        = 0x02,
00119     LIMIT_SORT_SONG_NAME     = 0x03,
00120     LIMIT_SORT_ALBUM         = 0x04,
00121     LIMIT_SORT_ARTIST        = 0x05,
00122     LIMIT_SORT_GENRE         = 0x07,
00123     LIMIT_SORT_RECENTLYADDED = 0x10,
00124     LIMIT_SORT_PLAYCOUNT     = 0x14,
00125     LIMIT_SORT_LASTPLAYED    = 0x15,
00126     LIMIT_SORT_RATING        = 0x17
00127 };
00128 
00129 
00130 enum SPLLimitType {
00131     LIMIT_TYPE_MINUTES   = 1,
00132     LIMIT_TYPE_MEGABYTES = 2,
00133     LIMIT_TYPE_SONGS     = 3,
00134     LIMIT_TYPE_HOURS     = 4,
00135     LIMIT_TYPE_GIGABYTES = 5
00136 };
00137 
00138 
00139 /**
00140  * This class represents a single smart playlist rule.
00141  */
00142 class SmartPlaylistRule {
00143 
00144     friend class SmartPlaylistRuleSet;
00145 
00146     Q_UINT32 mField;
00147     Q_UINT32 mAction;
00148 
00149     const QString mString;
00150 
00151     const Q_UINT64 mFromValue;
00152     const Q_UINT64 mToValue;
00153 
00154     const Q_INT64 mFromDate;
00155     const Q_INT64 mToDate;
00156 
00157     const Q_UINT64 mFromUnits;
00158     const Q_UINT64 mToUnits;
00159 
00160     Q_UINT64 mCalculatedFrom;
00161     Q_UINT64 mCalculatedTo;
00162 
00163 public:
00164 
00165     virtual ~SmartPlaylistRule();
00166 
00167     /**
00168      * Returns the action identifier for this rule
00169      */
00170     Q_UINT32 getAction() const {
00171         return mAction;
00172     }
00173 
00174     /**
00175      * Returns the field identifier for this rule
00176      */
00177     Q_UINT32 getField() const {
00178         return mField;
00179     }
00180 
00181     /**
00182      * Returns the String data for String based rules.
00183      */
00184     const QString& getString() const {
00185         return mString;
00186     }
00187 
00188     /**
00189      * Returns the "from" value as set in the itunesdb rule definition.
00190      * If you need the "from" value actually compared to the desired fields
00191      * use the @c calculatedFrom() method.
00192      */
00193     Q_UINT64 getFromValue() const {
00194         return mFromValue;
00195     }
00196 
00197     /**
00198      * Returns the "to" value as set in the itunesdb rule definition.
00199      * If you need the "to" value actually compared to the desired fields
00200      * use the @c calculatedTo() method.
00201      */
00202     Q_UINT64 getToValue() const {
00203         return mToValue;
00204     }
00205 
00206     /**
00207      * Returns the "from date" as set in the itunesdb rule definition.
00208      * If you need the "from" value actually compared to the desired fields
00209      * use the @c calculatedFrom() method.
00210      */
00211     Q_INT64 getFromDate() const {
00212         return mFromDate;
00213     }
00214 
00215     /**
00216      * Returns the "to date" as set in the itunesdb rule definition.
00217      * If you need the "to" value actually compared to the desired fields
00218      * use the @c calculatedTo() method.
00219      */
00220     Q_INT64 getToDate() const {
00221         return mToDate;
00222     }
00223 
00224     /**
00225      * Returns the "from units" as set in the itunesdb rule definition and
00226      * defines the units the fromDate is measured in.
00227      */
00228     Q_UINT64 getFromUnits() const {
00229         return mFromUnits;
00230     }
00231 
00232     /**
00233      * Returns the "to units" as set in the itunesdb rule definition and
00234      * defines the units the toDate is measured in.
00235      */
00236     Q_UINT64 getToUnits() const {
00237         return mToUnits;
00238     }
00239 
00240     /**
00241      * Returns the "from" value actually compared to the fields in question.
00242      * The value is calculated via ( fromValue + fromDate * fromUnits ).
00243      */
00244     Q_UINT64 calculatedFrom() const;
00245 
00246     /**
00247      * Returns the "to" value actually compared to the fields in question.
00248      * The value is calculated via ( toValue + toDate * toUnits ).
00249      */
00250     Q_UINT64 calculatedTo() const;
00251 
00252     /**
00253      * Writes this SPL TrackPredicate as a SPL Rule to the given stream
00254      * and returns the number of bytes written
00255      */
00256     uint writeToStream( QDataStream& outStream ) const;
00257 
00258     /**
00259      * Returns true if the rule is a string based rule
00260      */
00261     bool isStringBasedRule() const {
00262         return getAction() & ACTION_STRING_BIT;
00263     }
00264 
00265     /**
00266      * Returns a textual represenation of this rule (human readable)
00267      */
00268     virtual const QString toString() const;
00269 
00270 protected:
00271 
00272     /**
00273      * Constructor to create a string based SmartplaylistRule
00274      */
00275     SmartPlaylistRule( SPLStringField field, SPLStringAction action, const QString& testString );
00276 
00277     /**
00278      * Constructor to create an uint based SmartplaylistRule
00279      */
00280     SmartPlaylistRule( SPLUIntField field, SPLUIntAction action,
00281                        Q_UINT64 fromValue, Q_UINT64 toValue,
00282                        Q_INT64 fromDate, Q_INT64 toDate,
00283                        Q_UINT64 fromUnits, Q_UINT64 toUnits );
00284 
00285     /**
00286      * Returns a String describing the action in a human readable way.
00287      * @param action the action to return the String about
00288      * @return a String describing the action in a human readable way.
00289      */
00290     static QString getActionString( uint action );
00291 
00292     /**
00293      * Returns a String describing the given field in a human readable way.
00294      * @param field the field to return the String about
00295      * @return a String describing the given field in a human readable way.
00296      */
00297     static QString getFieldString( uint field );
00298 
00299     /**
00300      * Calculates the value to test the given field with the given action against.
00301      */
00302     static Q_UINT64 calculateTestValue( Q_UINT64 value, Q_INT64 date, Q_UINT64 units );
00303 
00304 };
00305 
00306 
00307 typedef std::vector<SmartPlaylistRule*> RuleList;
00308 
00309 /**
00310  * @brief This class represents all the rules, limits and switches making up a Smart Playlist.
00311  *
00312  * Here is an example on how to create a "recently played" Smart Playlist:
00313  * <pre><code>
00314  *  // enable smart playlist behaviour and get the ruleset
00315  *  SmartPlaylistRuleSet& ruleSet = a_playlist_ptr->enableSmartPlaylist();
00316  *
00317  *  // add the rule "last played in the last 2 weeks"
00318  *  ruleSet.addInTheLastRule( FIELD_LASTPLAYED, false, -2, IN_THE_LAST_WEEKS );
00319  *
00320  *  // limit to the first 30 songs, sorted by last played date
00321  *  ruleSet.setLimits( LIMIT_SORT_LASTPLAYED, LIMIT_TYPE_SONGS, 30 );
00322  *
00323  *  // match ANY rule (doesn't really matter since we only have one rule)
00324  *  ruleSet.setMatchAnyFlag( true );
00325  *
00326  *  // enable live update (updates the playlist on the go)
00327  *  ruleSet.setLiveUpdateFlag( true );
00328  * </code></pre>
00329  */
00330 class SmartPlaylistRuleSet {
00331 
00332     friend class Playlist;
00333 
00334 public:
00335 
00336     SmartPlaylistRuleSet();
00337     virtual ~SmartPlaylistRuleSet();
00338 
00339     /**
00340      * Adds a string based rule to the rule set and returns true if successful.
00341      * @param field field ID to identify the track field in question
00342      * @param action the compare operation to use when comparing the @c field with @c testString
00343      * @param testString the String to compare the @c field with
00344      * @param position the position the rule will be inserted to the rule set. Set to -1 to append the rule to the end
00345      */
00346     virtual bool addStringRule( SPLStringField field,
00347                         SPLStringAction action, const QString& testString, int position = -1 );
00348 
00349     /**
00350      * Adds a uint based rule to the rule set and returns true if successful.<br>
00351      * For rules with plain integer type fields like BPM, rating or play count the
00352      * from and to values need to be set to the range or value you care about.
00353      * See @c addUIntRule( SPLUIntField, SPLUIntAction, Q_UINT64, Q_UINT64) for
00354      * a simpler way to achieve this.<br>
00355      * For timestamp type rules like "last played in the last 2 weeks" you
00356      * need to set the from and to values to the offset of the time range to
00357      * care about, or to SPL_VALUE_NOW if the desired date offset is "now".
00358      * The from and to values declare the time range and the units the time
00359      * is measured in.<br>
00360      * Now, if you need to declare the aforementioned rule you set the time
00361      * range [from-to] to ["now - 2 weeks" - "now"] by setting both the from
00362      * and to values to SPL_VALUE_NOW, set the fromDate to -2 the to date to 0
00363      * and the units to IN_THE_LAST_WEEKS as fromUnits and 1 as toUnits.
00364      * @see @c addInTheLastRule() for a better way to create these kinda rules.
00365      * @see http://ipodlinux.org/ITunesDB#Smart_Playlist_Rules for more details
00366      * @param field field ID to identify the track field in question
00367      * @param action the compare operation to use
00368      * @param fromValue the "from" value
00369      * @param toValue the "to" value
00370      * @param fromDate the "from" date
00371      * @param toDate the "to" date
00372      * @param fromUnits the units the from value is measured in (@c fromValue gets multiplied with the units)
00373      * @param toUnits the units the to value is measured in (@c toValue gets multiplied with the units)
00374      * @param position the position the rule will be inserted to the rule set. Set to -1 to append the rule to the end
00375      */
00376     virtual bool addUIntRule( SPLUIntField field, SPLUIntAction action,
00377                               Q_UINT64 fromValue, Q_UINT64 toValue,
00378                                Q_INT64 fromDate,   Q_INT64 toDate,
00379                               Q_UINT64 fromUnits, Q_UINT64 toUnits, int position = -1 );
00380 
00381     /**
00382      * Convenience method. This creates a UInt based rule setting the from and
00383      * to values as provided and using sane defaults for the rest.
00384      * @param field field ID to identify the track field in question
00385      * @param action the compare operation to use
00386      * @param fromValue the "from" value
00387      * @param toValue the "to" value
00388      * @param position the position the rule will be inserted to the rule set. Set to -1 to append the rule to the end
00389      */
00390     bool addUIntRule( SPLUIntField field, SPLUIntAction action,
00391                               Q_UINT64 fromValue, Q_UINT64 toValue, int position = -1 ) {
00392         return addUIntRule( field, action, fromValue, toValue, 0, 0, 1, 1, position );
00393     }
00394 
00395 
00396     /**
00397      * Convenience method. This creates a UInt based "In The Last" rule with the given parameters
00398      * @param field field ID, to identify the field in question.
00399      * @param negateRule if true, this negates the rule to "Not In The Last"
00400      * @param value the time to evaluate; like in the last [WEEKS|DAYS|HOURS|etc]
00401      * @param units the units the value is mesaured in; base is seconds. The Predefined values IN_THE_LAST_[SECONDS|DAYS|WEEKS] may be used
00402      * @param position the position the rule will be inserted to the rule set. Set to -1 to append the rule to the end
00403      */
00404     bool addInTheLastRule( SPLUIntField field, bool negateRule, Q_INT64 value, Q_UINT64 units, int position = -1 ) {
00405         return addUIntRule( field,
00406                     negateRule ? ACTION_NOT_IN_THE_LAST : ACTION_IN_THE_LAST,
00407                     SPL_VALUE_NOW, SPL_VALUE_NOW, value, 0, units, 1, position );
00408     }
00409 
00410 
00411     /**
00412      * Returns the Rule at the specified position or NULL if no such rule exists.
00413      * @param position the position
00414      * @return the rule at the position or NULL.
00415      */
00416     const SmartPlaylistRule * getRuleAt( uint position ) {
00417         return mRules.at( position );
00418     }
00419 
00420     /**
00421      * Removes the rule at the specified position. The list will be compacted,
00422      * so all the rules after the rule to be removed will be moved one position
00423      * towards the start of the list.
00424      * @param position the position to remove the rule from
00425      * @return true if the operation was successfull, false otherwise.
00426      */
00427     bool removeRuleAt( uint position );
00428 
00429     /**
00430      * Removes all the rule from this RuleSet
00431      */
00432     void clear();
00433 
00434 
00435     /**
00436      * Returns true if the playlist may be updated by the iPod itself.
00437      */
00438     bool isLiveUpdate() const {
00439         return mLiveUpdate;
00440     }
00441 
00442 
00443     /**
00444      * Sets the live update flag.
00445      */
00446     void setLiveUpdateFlag( bool liveupdate );
00447 
00448     /**
00449      * Returns true if the smart playlist checks the rules
00450      */
00451     bool isCheckRules() const {
00452         return mCheckRules;
00453     }
00454 
00455     /**
00456      * Set the checkRules flag.
00457      */
00458     void setCheckRulesFlag( bool checkRules );
00459 
00460     /**
00461      * Returns true if the limits will/need_to be checked
00462      */
00463     bool isCheckLimits() const {
00464         return mCheckLimits;
00465     }
00466 
00467     /**
00468      * Sets the limit for this smart playlist and enable limit checking
00469      */
00470     virtual void setLimits( SPLLimitSort limitSort, SPLLimitType limitType, Q_UINT32 limitValue, bool reverseLimitSort = false );
00471 
00472     /**
00473      * enables or disables limit checking.
00474      */
00475     void enableLimits( bool enable );
00476 
00477     /**
00478      * returns the limit sort field
00479      */
00480     SPLLimitSort getLimitSort() const {
00481         return mLimitSort;
00482     }
00483 
00484     /**
00485      * Returns the limit type
00486      */
00487     SPLLimitType getLimitType() const {
00488         return mLimitType;
00489     }
00490 
00491     /**
00492      * Returns true if only one rule needs to match.
00493      */
00494     bool isMatchAny() const {
00495         return mMatchAny;
00496     }
00497 
00498     /**
00499      * Sets the "match any" flag
00500      */
00501     void setMatchAnyFlag( bool matchAny );
00502 
00503     /**
00504      * Returns true if only "checked" tracks should be matched against the rules.
00505      */
00506     bool checkedTracksOnly() const {
00507         return mCheckedOnly;
00508     }
00509 
00510     /**
00511      * sets the checkedTracksOnlyFlag.
00512      * @param checkedOnly If set to true only "checked" tracks should be matched against the rules.
00513      */
00514     void setCheckedTracksOnlyFlag( bool checkedOnly );
00515 
00516     /**
00517      * Returns the rules making up this smart playlist rule set.
00518      */
00519     const RuleList& getRules() const;
00520 
00521     /**
00522      * Returns the number of rules
00523      */
00524     uint getNumRules() const;
00525 
00526     /**
00527      * Returns a String representation of this rule set.
00528      */
00529     QString toString() const;
00530 
00531 protected:
00532 
00533     // do not copy the rules
00534     SmartPlaylistRuleSet( const SmartPlaylistRuleSet & src );
00535 
00536     /**
00537      * read Rules from type 51 MHOD data, starting at SLst and returns the number of rules read
00538      * @param instream the stream to read from positioned at the MHOD data
00539      * @param length the MHOD data length in bytes (blocklen - headerlen)
00540      * @return the number of rules read from the stream
00541      */
00542     uint readRules( QDataStream & instream, uint length );
00543 
00544     /**
00545      * reads the SPL Header from a type 50 MHOD and returns if the operation succeeded.
00546      * @param instream the stream to read from positioned at the MHOD data
00547      * @param length the MHOD data length in bytes (blocklen - headerlen)
00548      * @return true if the header got read successfully, false otherwise
00549      */
00550     bool readHeader( QDataStream & instream, uint length );
00551 
00552     /**
00553      * Writes the rules back to the stream and returns the number of bytes written.
00554      * @param outstream the stream to write the MHOD51 data to.
00555      * @return the number of bytes written
00556      */
00557     uint writeRules( QDataStream & outstream ) const;
00558 
00559     /**
00560      * Writes the header to the stream as a type 50 MHOD and returns the number of bytes written.
00561      * @param outstream the stream to write the MHOD50 data to.
00562      * @return the number of bytes written
00563      */
00564     uint writeHeader( QDataStream & outstream ) const;
00565 
00566     /***
00567      *
00568      * Header
00569      *
00570      ***/
00571 
00572     bool mMatchAny;
00573 
00574     Q_UINT32 unk5;
00575 
00576     Q_UINT8 mLiveUpdate;
00577     Q_UINT8 mCheckLimits;
00578     Q_UINT8 mCheckRules;
00579     Q_UINT8 mCheckedOnly;
00580     Q_UINT8 mReverseLimitSort;
00581     SPLLimitSort mLimitSort;
00582     SPLLimitType mLimitType;
00583     Q_UINT32 mLimitValue;
00584 
00585     // Attention: copy constructor exists
00586 
00587     RuleList mRules;
00588 
00589     virtual SmartPlaylistRule * createStringRule( SPLStringField field,
00590                                           SPLStringAction action, const QString& testString );
00591 
00592     virtual SmartPlaylistRule * createUIntRule(  SPLUIntField field, SPLUIntAction action,
00593                                          Q_UINT64 fromValue, Q_UINT64 toValue,
00594                                          Q_INT64  fromDate,  Q_INT64 toDate,
00595                                          Q_UINT64 fromUnits, Q_UINT64 toUnits );
00596 
00597 private:
00598 
00599     SmartPlaylistRule * readSingleRule( QDataStream & instream, uint * bytesRead = NULL );
00600 
00601 };
00602 
00603 
00604 }
00605 
00606 #endif

Generated on Wed Nov 28 03:04:38 2007 for libqtpod by  doxygen 1.5.0