GB2397205A - Broadcast method and system - Google Patents
Broadcast method and system Download PDFInfo
- Publication number
- GB2397205A GB2397205A GB0405067A GB0405067A GB2397205A GB 2397205 A GB2397205 A GB 2397205A GB 0405067 A GB0405067 A GB 0405067A GB 0405067 A GB0405067 A GB 0405067A GB 2397205 A GB2397205 A GB 2397205A
- Authority
- GB
- United Kingdom
- Prior art keywords
- public
- int
- user
- songs
- new
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Granted
Links
- 238000000034 method Methods 0.000 title claims description 51
- 230000005540 biological transmission Effects 0.000 claims abstract 9
- 238000010187 selection method Methods 0.000 claims 5
- 230000008713 feedback mechanism Effects 0.000 claims 1
- 230000003068 static effect Effects 0.000 description 195
- 239000013598 vector Substances 0.000 description 142
- 230000008676 import Effects 0.000 description 138
- 239000011800 void material Substances 0.000 description 136
- 230000004044 response Effects 0.000 description 47
- 230000001360 synchronised effect Effects 0.000 description 25
- 238000012360 testing method Methods 0.000 description 14
- 239000011159 matrix material Substances 0.000 description 13
- 230000036651 mood Effects 0.000 description 12
- 239000003795 chemical substances by application Substances 0.000 description 10
- 238000005192 partition Methods 0.000 description 10
- 230000008859 change Effects 0.000 description 9
- 230000004622 sleep time Effects 0.000 description 8
- 239000013078 crystal Substances 0.000 description 7
- 238000004364 calculation method Methods 0.000 description 6
- PCHJSUWPFVWCPO-UHFFFAOYSA-N gold Chemical compound [Au] PCHJSUWPFVWCPO-UHFFFAOYSA-N 0.000 description 6
- 239000010931 gold Substances 0.000 description 6
- 229910052737 gold Inorganic materials 0.000 description 6
- 230000008569 process Effects 0.000 description 6
- 230000006870 function Effects 0.000 description 5
- 241000283725 Bos Species 0.000 description 4
- 241001633942 Dais Species 0.000 description 4
- 230000009471 action Effects 0.000 description 4
- 230000008901 benefit Effects 0.000 description 4
- 238000004422 calculation algorithm Methods 0.000 description 4
- 230000008447 perception Effects 0.000 description 4
- 206010013883 Dwarfism Diseases 0.000 description 3
- PEDCQBHIVMGVHV-UHFFFAOYSA-N Glycerine Chemical compound OCC(O)CO PEDCQBHIVMGVHV-UHFFFAOYSA-N 0.000 description 3
- 241000520870 Phoenicurus phoenicurus Species 0.000 description 3
- 206010037660 Pyrexia Diseases 0.000 description 3
- 241000220010 Rhode Species 0.000 description 3
- 239000004927 clay Substances 0.000 description 3
- 238000004891 communication Methods 0.000 description 3
- 230000007717 exclusion Effects 0.000 description 3
- 239000010813 municipal solid waste Substances 0.000 description 3
- 230000029058 respiratory gaseous exchange Effects 0.000 description 3
- 241000283690 Bos taurus Species 0.000 description 2
- XEEYBQQBJWHFJM-UHFFFAOYSA-N Iron Chemical compound [Fe] XEEYBQQBJWHFJM-UHFFFAOYSA-N 0.000 description 2
- 241001673102 Jaya Species 0.000 description 2
- 241000399394 Umma gumma Species 0.000 description 2
- 244000290333 Vanilla fragrans Species 0.000 description 2
- 235000009499 Vanilla fragrans Nutrition 0.000 description 2
- 235000012036 Vanilla tahitensis Nutrition 0.000 description 2
- 241000584803 Xanthosia rotundifolia Species 0.000 description 2
- 240000008042 Zea mays Species 0.000 description 2
- 235000005824 Zea mays ssp. parviglumis Nutrition 0.000 description 2
- 235000002017 Zea mays subsp mays Nutrition 0.000 description 2
- 235000019504 cigarettes Nutrition 0.000 description 2
- 235000005822 corn Nutrition 0.000 description 2
- 238000005516 engineering process Methods 0.000 description 2
- 230000003203 everyday effect Effects 0.000 description 2
- 238000007689 inspection Methods 0.000 description 2
- 239000000203 mixture Substances 0.000 description 2
- 230000001172 regenerating effect Effects 0.000 description 2
- 238000012552 review Methods 0.000 description 2
- MXBCYQUALCBQIJ-RYVPXURESA-N (8s,9s,10r,13s,14s,17r)-13-ethyl-17-ethynyl-11-methylidene-1,2,3,6,7,8,9,10,12,14,15,16-dodecahydrocyclopenta[a]phenanthren-17-ol;(8r,9s,13s,14s,17r)-17-ethynyl-13-methyl-7,8,9,11,12,14,15,16-octahydro-6h-cyclopenta[a]phenanthrene-3,17-diol Chemical compound OC1=CC=C2[C@H]3CC[C@](C)([C@](CC4)(O)C#C)[C@@H]4[C@@H]3CCC2=C1.C1CC[C@@H]2[C@H]3C(=C)C[C@](CC)([C@](CC4)(O)C#C)[C@@H]4[C@@H]3CCC2=C1 MXBCYQUALCBQIJ-RYVPXURESA-N 0.000 description 1
- 206010063659 Aversion Diseases 0.000 description 1
- 241000616862 Belliella Species 0.000 description 1
- 241001423651 Buchnera americana Species 0.000 description 1
- 101100314454 Caenorhabditis elegans tra-1 gene Proteins 0.000 description 1
- 101150029544 Crem gene Proteins 0.000 description 1
- 241000270722 Crocodylidae Species 0.000 description 1
- 235000016936 Dendrocalamus strictus Nutrition 0.000 description 1
- 101150089023 FASLG gene Proteins 0.000 description 1
- 241000447439 Gerres Species 0.000 description 1
- GVGLGOZIDCSQPN-PVHGPHFFSA-N Heroin Chemical compound O([C@H]1[C@H](C=C[C@H]23)OC(C)=O)C4=C5[C@@]12CCN(C)[C@@H]3CC5=CC=C4OC(C)=O GVGLGOZIDCSQPN-PVHGPHFFSA-N 0.000 description 1
- 241000763212 Lype Species 0.000 description 1
- 240000000233 Melia azedarach Species 0.000 description 1
- 101100350959 Mus musculus Ankrd33 gene Proteins 0.000 description 1
- 101100346764 Mus musculus Mtln gene Proteins 0.000 description 1
- 241000257229 Musca <genus> Species 0.000 description 1
- 241001585676 Orthonama obstipata Species 0.000 description 1
- 241000282376 Panthera tigris Species 0.000 description 1
- 241001442654 Percnon planissimum Species 0.000 description 1
- 101100177642 Rattus norvegicus Hgs gene Proteins 0.000 description 1
- 101100230601 Saccharomyces cerevisiae (strain ATCC 204508 / S288c) HBT1 gene Proteins 0.000 description 1
- VYPSYNLAJGMNEJ-UHFFFAOYSA-N Silicium dioxide Chemical compound O=[Si]=O VYPSYNLAJGMNEJ-UHFFFAOYSA-N 0.000 description 1
- 101100313471 Streptomyces sp getA gene Proteins 0.000 description 1
- 241000792914 Valeriana Species 0.000 description 1
- 208000012886 Vertigo Diseases 0.000 description 1
- 239000002253 acid Substances 0.000 description 1
- 150000007513 acids Chemical class 0.000 description 1
- 230000001174 ascending effect Effects 0.000 description 1
- XIWFQDBQMCDYJT-UHFFFAOYSA-M benzyl-dimethyl-tridecylazanium;chloride Chemical compound [Cl-].CCCCCCCCCCCCC[N+](C)(C)CC1=CC=CC=C1 XIWFQDBQMCDYJT-UHFFFAOYSA-M 0.000 description 1
- 230000015556 catabolic process Effects 0.000 description 1
- 239000003086 colorant Substances 0.000 description 1
- 238000004590 computer program Methods 0.000 description 1
- 238000012790 confirmation Methods 0.000 description 1
- 235000014510 cooky Nutrition 0.000 description 1
- LNNWVNGFPYWNQE-GMIGKAJZSA-N desomorphine Chemical compound C1C2=CC=C(O)C3=C2[C@]24CCN(C)[C@H]1[C@@H]2CCC[C@@H]4O3 LNNWVNGFPYWNQE-GMIGKAJZSA-N 0.000 description 1
- 238000011161 development Methods 0.000 description 1
- BTCSSZJGUNDROE-UHFFFAOYSA-N gamma-aminobutyric acid Chemical compound NCCCC(O)=O BTCSSZJGUNDROE-UHFFFAOYSA-N 0.000 description 1
- 239000011521 glass Substances 0.000 description 1
- ZEKANFGSDXODPD-UHFFFAOYSA-N glyphosate-isopropylammonium Chemical compound CC(C)N.OC(=O)CNCP(O)(O)=O ZEKANFGSDXODPD-UHFFFAOYSA-N 0.000 description 1
- 238000011423 initialization method Methods 0.000 description 1
- 230000003993 interaction Effects 0.000 description 1
- 230000002452 interceptive effect Effects 0.000 description 1
- 150000002500 ions Chemical class 0.000 description 1
- 229910052742 iron Inorganic materials 0.000 description 1
- 238000013507 mapping Methods 0.000 description 1
- 230000002853 ongoing effect Effects 0.000 description 1
- 210000000056 organ Anatomy 0.000 description 1
- 230000002085 persistent effect Effects 0.000 description 1
- 235000021110 pickles Nutrition 0.000 description 1
- 235000013446 pixi Nutrition 0.000 description 1
- 230000003389 potentiating effect Effects 0.000 description 1
- 238000012545 processing Methods 0.000 description 1
- 239000011435 rock Substances 0.000 description 1
- 238000000926 separation method Methods 0.000 description 1
- 230000005236 sound signal Effects 0.000 description 1
- 235000019640 taste Nutrition 0.000 description 1
- 231100000889 vertigo Toxicity 0.000 description 1
- SYOKIDBDQMKNDQ-XWTIBIIYSA-N vildagliptin Chemical compound C1C(O)(C2)CC(C3)CC1CC32NCC(=O)N1CCC[C@H]1C#N SYOKIDBDQMKNDQ-XWTIBIIYSA-N 0.000 description 1
- 230000000007 visual effect Effects 0.000 description 1
- 210000004916 vomit Anatomy 0.000 description 1
- 230000008673 vomiting Effects 0.000 description 1
Classifications
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F16/00—Information retrieval; Database structures therefor; File system structures therefor
- G06F16/40—Information retrieval; Database structures therefor; File system structures therefor of multimedia data, e.g. slideshows comprising image and additional audio data
- G06F16/48—Retrieval characterised by using metadata, e.g. metadata not derived from the content or metadata generated manually
-
- H—ELECTRICITY
- H04—ELECTRIC COMMUNICATION TECHNIQUE
- H04N—PICTORIAL COMMUNICATION, e.g. TELEVISION
- H04N21/00—Selective content distribution, e.g. interactive television or video on demand [VOD]
- H04N21/40—Client devices specifically adapted for the reception of or interaction with content, e.g. set-top-box [STB]; Operations thereof
- H04N21/45—Management operations performed by the client for facilitating the reception of or the interaction with the content or administrating data related to the end-user or to the client device itself, e.g. learning user preferences for recommending movies, resolving scheduling conflicts
- H04N21/466—Learning process for intelligent management, e.g. learning user preferences for recommending movies
- H04N21/4668—Learning process for intelligent management, e.g. learning user preferences for recommending movies for recommending content, e.g. movies
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F16/00—Information retrieval; Database structures therefor; File system structures therefor
- G06F16/40—Information retrieval; Database structures therefor; File system structures therefor of multimedia data, e.g. slideshows comprising image and additional audio data
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F16/00—Information retrieval; Database structures therefor; File system structures therefor
- G06F16/60—Information retrieval; Database structures therefor; File system structures therefor of audio data
- G06F16/63—Querying
- G06F16/635—Filtering based on additional data, e.g. user or group profiles
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F16/00—Information retrieval; Database structures therefor; File system structures therefor
- G06F16/60—Information retrieval; Database structures therefor; File system structures therefor of audio data
- G06F16/63—Querying
- G06F16/638—Presentation of query results
- G06F16/639—Presentation of query results using playlists
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F16/00—Information retrieval; Database structures therefor; File system structures therefor
- G06F16/60—Information retrieval; Database structures therefor; File system structures therefor of audio data
- G06F16/68—Retrieval characterised by using metadata, e.g. metadata not derived from the content or metadata generated manually
-
- H—ELECTRICITY
- H04—ELECTRIC COMMUNICATION TECHNIQUE
- H04N—PICTORIAL COMMUNICATION, e.g. TELEVISION
- H04N21/00—Selective content distribution, e.g. interactive television or video on demand [VOD]
- H04N21/40—Client devices specifically adapted for the reception of or interaction with content, e.g. set-top-box [STB]; Operations thereof
- H04N21/43—Processing of content or additional data, e.g. demultiplexing additional data from a digital video stream; Elementary client operations, e.g. monitoring of home network or synchronising decoder's clock; Client middleware
- H04N21/443—OS processes, e.g. booting an STB, implementing a Java virtual machine in an STB or power management in an STB
-
- H—ELECTRICITY
- H04—ELECTRIC COMMUNICATION TECHNIQUE
- H04N—PICTORIAL COMMUNICATION, e.g. TELEVISION
- H04N21/00—Selective content distribution, e.g. interactive television or video on demand [VOD]
- H04N21/40—Client devices specifically adapted for the reception of or interaction with content, e.g. set-top-box [STB]; Operations thereof
- H04N21/47—End-user applications
- H04N21/475—End-user interface for inputting end-user data, e.g. personal identification number [PIN], preference data
- H04N21/4756—End-user interface for inputting end-user data, e.g. personal identification number [PIN], preference data for rating content, e.g. scoring a recommended movie
-
- H—ELECTRICITY
- H04—ELECTRIC COMMUNICATION TECHNIQUE
- H04N—PICTORIAL COMMUNICATION, e.g. TELEVISION
- H04N21/00—Selective content distribution, e.g. interactive television or video on demand [VOD]
- H04N21/40—Client devices specifically adapted for the reception of or interaction with content, e.g. set-top-box [STB]; Operations thereof
- H04N21/47—End-user applications
- H04N21/482—End-user interface for program selection
- H04N21/4825—End-user interface for program selection using a list of items to be played back in a given order, e.g. playlists
-
- H—ELECTRICITY
- H04—ELECTRIC COMMUNICATION TECHNIQUE
- H04N—PICTORIAL COMMUNICATION, e.g. TELEVISION
- H04N21/00—Selective content distribution, e.g. interactive television or video on demand [VOD]
- H04N21/80—Generation or processing of content or additional data by content creator independently of the distribution process; Content per se
- H04N21/81—Monomedia components thereof
- H04N21/8106—Monomedia components thereof involving special audio data, e.g. different tracks for different languages
- H04N21/8113—Monomedia components thereof involving special audio data, e.g. different tracks for different languages comprising music, e.g. song in MP3 format
Landscapes
- Engineering & Computer Science (AREA)
- Theoretical Computer Science (AREA)
- Multimedia (AREA)
- Databases & Information Systems (AREA)
- Physics & Mathematics (AREA)
- General Physics & Mathematics (AREA)
- General Engineering & Computer Science (AREA)
- Data Mining & Analysis (AREA)
- Signal Processing (AREA)
- Library & Information Science (AREA)
- Human Computer Interaction (AREA)
- Software Systems (AREA)
- Reverberation, Karaoke And Other Acoustics (AREA)
Abstract
A user interface for an Internet data stream transmission system, comprising: a media player 102 for playing data streams; a rating tool 106 for receiving user indications regarding a current data stream and indicating a rating for said data stream as currently played by said media player; and a data stream information display 104 for displaying information for said data stream as currently played by said media player; whereby said user can indicate a preference regarding said data stream as currently played by said media player. The rating given by a user assists in the generation of a playlist.
Description
23g7235
BROADCAST METHOD AND SYSTEM
TF,CHNICAL FIELD
This Invention relates to Internet media data streams and the like, and more particularly to a copyught-compliant audio/video/rado broadcast system over the Internet where each Individual user is able to set his or her preferences regarding works played so as to Influence the frequency such works are broadcast to the user.
BACKGROUND ART'
The rise of the Internet has provided many different channels through which media can be presented to ID users. RealNetworks' RealMedia (RTM), Apple QuckTme (RTM), and Windows Media (RTh4) all provide players through which live or prevously-recorded data streams can be displayed, played back, or broadcast to the mdvidual user. Both audio and video are generally available through these programs and provide a higher and more attractive degree of interactivity with the Internet Regular radio broadcasts are based upon a central Individual or station broadcasting songs, or other audio I5 information, e lec tromagnetica by Different red lo stations are separated by their different Gamer frequencies Amplitude modulation (AM) and frequency modulation (FM) provide two means by which radio broadcast can be effected by a transmitter to a receiver. If an individual wants to affect the songs that are played by the radio station, he or she may write, call, fax, e-mail, or otherwise transmit their preferences to the radio station However, one person's preferred music may not be as appreciated by another mdivdual Music can be very personal, often affecting a person at an emDtionai level When the radio station broadcasts a song or other audio signal, all receivers tuned to the carrier frequency pick up the broadcast and either enjoy or suffer the broadcast equally It would be much more advantageous to allow each individual to influence, their own set of song playlists Currently, this is not achievable by wireless broadcast means However, unique data stream addressing available through Internet data processing might provide means by which an Internet radio could be advantageously affected Other Internet broadcasting processes are known, but generally fol low the known radio station format of broadcasting a single song, or data stream, to all users tuned to the station or channel. [n compliance with the Digital Millennium Copyright Act (DMCA), such a radio would have to comply with statutory regulations regarding the broadcast of songs and would generally have to avoid the role of an "on-demand" system, as this might be in violation of statutory regulation so The following patents may have some bearing on the art relevant to the present invention.
U.S. PATENT NUMBER INVENTOR DATE OF ISSUE 6,052,717 Reynolds et al Apri 1 18, Z000 6,038,591 Wolfeetal March 14, 2000 6,031,797 Van Ryan et al. February 29, 2000 6,026,439 Chowdhury et al February 15, 2000 5,987,525 Roberts et al November 16, 1999 5,945,988 W'llamsetal August 31, 1999 5,930,768 Hooban July27, 1999 5,864,868 Contos January 26, 1999 5,819,160 Foladare et al October 6, 1998 U S. PATENT NUMBER INVENTOR DATE OF ISSUE 5,809,246 Goldman September 15, 1998 5,790,423 Lauetal August4, 1998 S,758,2S7 Herzetal May26, 1998 5,740,134 Peterson April 14, 1998 5,726,909 Krkoran March 10, 1998 5,721,827 Logan ct al February24, 1998 5,661,787 Pocock August26, 1997 5,616,876 Cluts Aprd 1, 1997 5,592,511 Schoen et al January 7,1997 5,539,635 Larson, Jr July23, 1996
DISCLOSURE OF INVENTION
The present invention provides a copyright-comphant, broad-based, individually-tailored Intemet media broadcast system and method. The present mventon provides means by which users may individually rate or indicate music, music videos, or other recorded media that they enjoy hearing from a vast musical or other database. Additionally, such users may also indicate the exclusion of music/media that is to their distaste. In so doing, the user interaction is limited to that decsion-makmg role that is necessary for the user to establish his or her preferences The Intcmet radio of the present invention and its method take care of the rest, providing the end user a media or radio channel tailored to his or her own musical tastes In this way, the present invention can be said to "mcrocast," or "narrowcast" the content of lo personalized songlsts to individual listening stations or users As the broadcast uses Internet protocol, each data packet of each data stream has its own individual address, namely, the end-user's data stream player As the present invention is scalable, thousands, even tens or hundreds of thousands of hsteners can be handled by the present invention. With the advance of data-transmssion technology, tens or hundreds of millions of users may be served by, or given access to, a system incorporating the present invention, including the delivery of user-preferred data streams by wireless Is communication links.
Mention Is made herein of the present.nventon with respect to music broadcast to provide a personalized internet, or data stream, radio Note should he taken that use of the term "radio," "music," and the like Includes any recorded datastream content, Including music videos and the hke.
At the core of the present invention is the playlist generator it is the generated songlist that Is associated with the to user's account and indicates to the system which song is to be played next Once a song has been selected, it Is then streamed as data out to the individual's computer (uniquely identified by Internet protocol) As the central server of the system can handle a large number of users at any one time, it becomes possible to serve each user with his or her own individual data stream [n this case, the data stream composes audio and/or video information and serves to establish a situation similar to each user having his or her own individual radio station that he or she programs. The list can be createdin advance end stored,orgenerated,in realtime when needed Collaboratvefilteringtechmquesmaybeusedn construchn6 the playlist She present mventon provides means by which mdvdual hsts of data streams may be defined, modified, and preserved, subject to a variety of mfluenoes and allowing some serendipitous, or random, events to occur
BRIEF DESCRIPTION OF DRAWINGS
figure I is a schematic view ofthe system architecture used to achieve one embodiment ofthe present nvennon.
figure 2 is a screen shot showing a computer desktop with the audio player and user homepage for the present s invention Figure 3 is a screen shot showing a computer desktop with the video player and user homepage for the present mver,ton
BRIEF DESCRIPTION OF APPENDICES
lo The following appendices are incorporated herein by this reference thereto.
Appendix I is an excerpted text listing of a playlist generated in conformance with the present invention Appendix 2 is a source code listing for one embodiment ofthe present invention MODE(S) FOR CARRYING OUT THE INVENTION is The detailed description set forth below in connection with the appended drawings is intended as a descnpton of presently-preferred embodiments of the invention and is not intended to represent the only forms in which the present Invention may be constructed and/or utihzed. The description sets forth the functions and the sequence of steps for constructing and operating the invention in connection with the illustrated embodrnents. However, it is to be understood that the same or equivalent functions and sequences may be accomphshed by different embodiments as still to encompassed within the scope of the invention as defined by the appended claims fbis patent apptcaton Is related to [Jnited States Provisional Patent Application Senal Number60/164,846 filed November 10, 1999 for Internet Radio and Broadcast Method, which application Is incorporated herein by this reference thereto As mentioned above, use ofthe term "radio," "music," and the like includes any recorded datastream content, including music, videos, recorded sports events and concerts, and the like.
In figure I, the general structure of the present system Is shown where the l.AUNCHcast player provides user feedback and Education of song preference through Java (RTM) servlets and JavaScnpt (RTM) code In one embodiment, a Wmdows Media (RTM) player may provide the interface ailowmg the audio and/or video broadcast to take place at the user's computer Other media players now known or developed m the future may also suffice and operate to good advantage Mentioned use of the Wmdows Media (RTM) player system Is to be considered as mdicatng any appropriately functomng media player. Song or video information Is available through both the player and the accompanying data wmdow Rcterrmg now to figure 1, the architecture and system structure of the InteMet radio and broadcast method of the present invention Is shown m schematic fond. The system 100 Is generally focused upon the player 3S 102 The player 102 is the component that the user sees and Is ultimately the arbiter of the media datastream service provided by the present mvenhon As shown m liNgure 1, the player]02 has a song mforrnabon section 104, a rating tool 106, and a player 108 For this last component, the player 108 Is Educated as being a Wmdows Media (RTM) player}however, other media players can also be used to good advantage m order to achieve the prescut nvenbon Through its components, the player 102 is Imked or associated to a number of other sources of information and programs, including Java (RTM) or other servlets The present mvenbon, when Implemented m software, may be so Implemented USUlg the Java (RThi) family of computer program languages A servlet Is Java (RTM) programming that Outs as a past of a network service, such as an H TTP server, in response to requests from chents In this case, the cl lent can be considered to be the player] 02 while the HTTP server can be the servers for the database 160 and the media content hbrary 180 At a center of the present invention Is the player 108 The player 108 allows the content to be broadcast to the individual user and serves as means by which the user can enjoy such content In addition to bemg linked to the media s database l 80, the player l O8 is also m communication with a media gateway servlet l 20 and a playLst generator servlet 122 As discussed m more detail below, these two servlets provide the player the ability to play streaming media in conformance with the present invention The rating tool 106 is coupled to the database 160 via a rating acceptor servlet 130 and a ratings cache serviet 132. As indicated hi Figure 1, the rating acceptor servlet 130 and ratings cache servict 132 are also h1 communication lo with one another, as set forth m more detail below.
The song information component 104 ofthe player I U2 may provide links to other information available through the database 160 or otherwise For example, the song information tool 104 may provide hnks to other user pages 140, a station manager 142, provided home pages of various artists 144, as well as hnks to album pages 146 of such artists or otherwise Additionally, a central homepage 148 may be present that allows travel or Imking to any orall of available pages or services.
Note should be taken that the database 160 is not necessarily the home for the media library 180. In fact, according to present technology, it nnay be more advantageous to provide some means by which hgh-speed access can be provided to the media library 180 By separating the database 160 from the media library 180 fester end better service may be provided to users so they may enjoy the content of datastream bener. Certam infrastructures may allow for to offsiteresdenceofthemedacontained m the medalibraryl80. Pomtersorotherindicatorstosuchinformaton m an Indexed or other form can thereby provide the Imk necessary to deliver the preferred or indicated content by the user from the media hbrary 180 to that same user.
As shown in figure 1, the database 160 may hold a variety oftypes of mformaton, including user data 162, playPsts 164, and song data 166 Such nformabon is stored by the database 60 and updated by the servlets as set forth in the present invention, including the user code set forth m Appendix 2 In figure 2, the player, or playback, wmdow 102 is shown and Is highly interactive with several embedded hyperlinks [n the upper righthand corner of the playback window 102, the mdicaton of "asJordan" is made. By clicking on this Imk. more information about the current station may be given and/or the ability to change such station.
The user's page 140 may be activated and shown upon clicking the username hnk. In the right center of the playback so window, a "RATE IT" window indicator that is the rating tool 106 is given, allowing the individual to rate the current "SONG", the "ARTI S17' perform mg the current song, and/or an "A LBUM" contamng the song Below the "RATE IT" indicator, hyperlinks to "RECENT SONGS", "BUY", and "STATION MANAGER" are present allowing the user to travel to those destinations and either leam more information, purchase or review purchasing information about the current album bemg played, as well as access the station manager for the present invention as Below the song information window 104, icons are given for Play/Pause, Skip This Song, Skip This Song and Never Play It Agam ("delete"), and a Volume control The question mark ("a") shown below the "Song Information area" window is a hyperhnk to a Help file for the playback window 102 and the Internet Radio system of the present invention. These Icons are also shown m the other playback window figures, such as that for the video playback user interface/clent;02 shown in figure 3 0 Figures 2 and 3 show a desktop display of the system 100 m action hrom the user's point of view. A tool tip may be given when the cursor hovers over the song title. The same may be similarly true for the artist and the album currently playing. Note should be taken thatjust as the song rating indicator is highlighted and active m the middle right section of the playback window, the song title is highlighted In the upper portion of the playback wmdow.
Additionally, the left and center middle portion of the playback window provides information regarding fans who have strong positive feelings about the present song, artist, and/or album, as well as an average rating for all users or some subset of users on the system.
Figures 2 and 3 show smal I balloons on the rghthand s ide of the central dark area across from the "Fans " These balloons may have a letter "W" upside ofthem to indicate another listener is currently online and can he engaged via the instant messaging ("win isper") function. Figures 2 and 3 also show graph LC information that may be used for advertsmg or other hyperhaks In generating the playlist of the prescrt Invention, the user can be unformed as to why a particular lo song was picked For other links and presentation of information m the player 102, a tool tip may be presented when the cursor hovers over an area A tool tip is a small window providing succinct information about the item under the cursor when the cursor hovers over that Item.
When the system 100 is updating and obtaining a new data stream from the system for the user, a display may be is given to the user to indicate ongoing activity of the playback system. Such visual activity In the form of animation assures the hstener/vewer that the short span of silence, or "dead air," following a song is only temporary and that a new song will soon play. Generally, m order to promote interactivity and to take advantage ofthe new media that the Internet provides, the windows shown m the Figures 2 and contain ample internal hyperlinks that lead to web pages providing information regarding music, artists 144, and/or their works 146, web pages regarding other users ofthe system (as DJs so or otherwise) 140, and/or web pages regarding the user's control ofthe system (preferences, etc) 142 The default paradigm for the user interface/player 102 Is to allow the user the greatest degree of freedom m expressing preferences and In obtaining that preference information regarding music artists, and their publicationslalbums In this way, the user's experience Is enhanced as he or she hears more of the music he or she hkes Access to purchasing web sites is also made available where users may purchase artists' works Is In implementing the present invention in software, the accompanying source code (Appendix 2) may be used to achieve the present mventon Such code Is subject to copyright protection and Is owned by LAUNCH Media, Inc of Santa Monica, California The generation of a proper playhstcombiningavailable user ratings and a media database forms an irnportantpart of the present mventon. One such playlist as generated by the present invention Is shown in Appendix I and Is an so excerpted form for purposes of explanation. Entries in the playlist have been removed so that the playlist may better serve the explanatory purposes herein without undue length or the sacrifice of sufficient detail Playltst generation occurs when a user launches his chent player 102. A Wmdows Media (RTM) or other player 108 Is embedded m the user's chent player 102 The player 108 opens a call to the playlist generator servlet 122 as executed by the PlaylstGeneratorServlet routme (Appendix 2, page 144). The expected output from as this H IMP call Is an ASX playlist file, which in the present mventon Is a hst of pointers to a script that reads the actual playlist data object from the database 160 The playlist generator servlet 122 parses the particular parameters for this ASX playlist as follows Object GeneratorParameters, userlD (required) the user for whom the playlist is generated, to djlD (default Is userlD) the user whose profile will be used to generate the piayLst, moodlD (default is none) a mood which Is a subset of a profile may be indicated and used to alter the preferences m the playlist and under which to listen (optional); and bandwidth (default is 28 8k, if not read from the user's preferences m the database) the bit rate at which the user wishes to listen The database 160 with the playLst database 164 Is checked for an existing playact by the PlaylstStatus routine (Appendix 2, page 151) If a playLst already exists, it can be used if all the following are met (add PlaylistStatus isStale() returns false) all of the parameters (userlD, dJID, etc) match; there are more than 8 songs lett; the newRatingsCount (counter of new personalization data since last refresh) Is less than 15, and a the playlist is less than a week old If all these conditions are met, the dates for the last time the user listened to an ad, news bit, and tip may be reset and the phylist may be resaved The ASX file Is written out and media player begins to execute by makmg requests to the media gateway 120 to play music If the old playlist cannot be used, a new one is created with the piaylist generator via PlaylistGenerator create() \5 The first step is to retrieve the user's preferences via PlaylistGenerator getOptions() In response the following options are returned.
unratedQuota how much new (not rated) music they want hear in their playlist. The options here are 90, 80, 70, 50, 40, 30, and 20 percent The default is 50 percent.
explicit lyrics Does this user want us to play music with explicit lyrics' True or false.
ha bandwidth if the bandwidth Is not already specified in the generator parameters, it is read from stored data Currently,bandwdthoptonsinclude28. 8,56,andTI/LA19 Thedefaultis288ifavalidsetttngof"none"sfoundin the database A list of all the possible songs available for play (via PlaylistGenerator gatherMeda()) as well as some other data about those songs Is obtained This Is generally done using mairiple threads running at the same time for better performance. The list of songs IS held In a hashtable (as via the Population subrouhne (Appendix 2, page 155)).
The database 160 Is first called to load a history of all the songs played for the user in the last 30 days This is stored m the database as a long string, formatted as. "<Date≥<songlD>,<Date≥<songlD>, . . . " For performance reasons, readmg one strmg trom the database Is faster than reading potentially several thousand rows mdivdually from the database. Dates older than 30 days are Ignored and the last time a song was played overwrites previous plays of a Jo song. Each time a song is played via the media gateway 120, this string is appended After the history loading is complete, a random integer is picked from I to 10. If the value is 1, the date and songlD string is recreated and rewritten to the database. This cleans up the string by removal of songs that were played more than 30 days ago as well as duplicate entries for the same songlD The history loads as a thread, and another database call is made to get the user's, or DJ's, list of subscribed DJs, genres, and radio stations (via PlaylistGenerator getSubscrptions()) for the specific mood requested The result of this call is three lists called DJs, genres, and stations.
Once the subscriptions are available, the ratings are obtained via GetRatings This is also done In a thread. The song hashtable, another hashtable that contains Artist and Album ratings (ItemsProfile), the DJ, and the list of subscribed DJs are all passed to the GetRatings method routine.
ha A retrieval list of users whose ratings are to be retrieved is compiled using the subscribed Dls and the DJ requesting the playlist A request is made to the ratings cache to retrieve all these ratings via RatingsCache getRatings() When the playlist generator has all the ratings, it Is ready to assemble thenn into categorized data structures, based on the properties of each rating. It iterates through all the ratings and stores them in the following manner If the ID of the user is the DJ and the rating Is 0 (an 'X' in the end-user interface), the song Is added to song hashtable (via Population) as an "Excluded" type, meaning that song should never be played The rating Is also added to the average s rating for songs by that artist If the rating is not 0, the song information cache Is m1nediately checked via SonginfoCache get() for data about this song If the data does not ex ash in the cache, it is a song that was rated, but Is not available for play (as possibly not encoded), and the song is immediately marked as an "Excluded" song If all of the above tests pass, the song is added to the song hashtable with a type of"Exphcr" The rating for the song Is included In the calculation of this DJ's average raking of songs by the artist lo Each song that is rated by subscribed Dls is added to the song hashtable. The subscribed DJ's rating for the song is included m the calculation of the subscribed Dais' average rating for this song.
For albums, the ratings profile is obtained from the Item rating profiles. If a ratings profile for an album does not yet exist, then the data regarding the album is retrieved and a ratings profile is created.
If the rater Is the user requesting the playlist, the rating for this item is set to the user's rating However, If the rater is a subscribed DJ, the raking is added to the Dl's average for this album for artists, the rating procedure Is the same as for albums, except any ratings made for the artists tasted as "Various Artists", "Soundtrack", or "Or\gmal Soundtrack" are discarded or Ignored In the relevant calculations.
The top 1000 most popular songs (via 1'1aylistGenerator.getPopular()) in the bandwidth type specified may be added to the song candidate hashtable. This popular list is mantamed in the song information cache Before each song to Is added to the song hashtable, inspection Is made to see if the song is already in the candidate hashtable (perhaps put there by another query) If so, Inspection Is made to make sure that the song Is not oftype "Excluded", or the song Is discarded. If the song Is added to the song hashtable, it is added under the type "Unrated" A maximum of 5000 songs are picked randomly (via PlayLstGenerator.getRandom()) Initially, a count is made of the number of songs contained m each and all of the genres a user has selected (via SonginfoCache.countinGenres()) as Songs may be In multiple genres The number of songs is then divided by the total number of songs in the song information cache If the result is less than 5%, songs are picked directly from a list of songs only in those genres Otherwise, songs can be picked randomly from all available songs This calculation may be perfonned to avoid the situation where a user has selected a small number of genres and picking songs randomly will return only a few songs that are available or allowable for play when considering their genres an In order to select songs only from selected genres, a detcrmnaton is made of the total number of songs to pick (via totalToP'ck) from the lesser of 5000 and the total number of songs in the selected genres. For each genre, a copy of the hst of songs m that genre Is obtained from the song information cache (via SonginfoCache getinGenre()). The number of songs to pick from each genre is determined from the following formula songs to pick = totalToPick * (number of songs m this genre I total number of songs in the selected genres) I he determined number of songs is picked and attempts are made to add the songs to the song hashtable with a type of "Unrated" A song Is not added if it Is already In the hashtable In order to select from all songs, a song is randomly selected 5000 times. Each time, attempts are made to add the song if it Is not already there as picked, as described above. Once the process fimshes adding random songs, all the ratings for the songs are retrieved as are all the dates of when the songs were played for the user The explicit, implicit, to and unrated hats built m the last step are taken and ordered m descending order by score, or rating, using a quicksort or other algorithm The number of songs to pick from each hat is determined. For example, if the size of a playlst is 50 songs, the following may occur If the usems hstening to his own station, the following formula may be used If the user's list of exphct and mphct songs is smaller than 100 songs, 90% of the songs must be picked from the unrated hat to avoid playing the user s rated songs too much. The user's unrated quota may, then, be set to 90 Otherwsc, an unrated quota s may be used from the user's stored options.
Under some circumstances the maximum number of songs available from the exphcit and mphcit song lists Is calculated as follows maxmumRated -playhstS,ze * (100- unriltedQuota) * 0 0i.
The maximum number of songs available from the explicit list may be calculated as lo MaximumExplicit = number of songs m the explicit list * 20 A number of songs to pick from the exphcitly-rated hat may then be: explictToP'ck = playlistSize (100 - unrated quota) * 0 01 * (number of songs m the expbct list / sum of exphct and mphcit songs) * 3), From this the number of Implicit songs is simply.
[5 implicitToPick = maxiumumRated - explctToPick Confirmation can be made to ensure that more explicit songs have not been picked than medicated by maximumExplcit and that no more Implicit songs have been picked than those that are in the impact list The number of unrated songs is then playlistSize - (explicitToPick - implicitToPick) If theusemsllstenmgtoastatlonotherthanhtsownandthenumberofsongsmtheexphcItand implcitlisttotal ID greater than 200, then the following calculations are made.
explicitToPck = Mmimum(playlistS'ze * .50, 20% of explicit songs); and implictToP'ck = Minimum(playlistSze, # of implicit songs) - explicitToPick If, for some reason, a sufficient and/or playlistSize number of songs is not obtained from this calculation, a third ofthe songs is picked from each of explicit, implicit and unrated songs with a cheek to ensure that not more than 20%of as the songs on the rated and unrated lists are picked As a fullback measure if none ofthe methods above used to calculate the number of songs to pick worked, the songs are selected as a third of the playLstS'ze from each hat, making sure not to pick more than 20% of the rated and unrated hsts A list of albums and artists from and by whichsongs have been played for this user m the last 3 hours is copied or otherwise made available to the process set forth herein and the songs for this playlist are picked via to PlaylistGenerator pickSongsO. A hat of all the picks needed is made (via PickList). for example, if there is a piaylistof songs, the bet may contain 10 entries for exphct songs, 20 for imphcit songs, and 20 for unrated songs While there are still songs to pick, Iteration Is made through the following cycle a. randomly pick a song list type (explicit, Implicit, unrated) with a probability based on the proportion of songs to come from each list; as b pick a random song Index from that list (which has already been sorted in descending order of score), based on the following formula (via SongCroup pckRandom()) szeOfList = the number ofsongs in this list; random = a randomly-chosen number between 0 and (sizeOfl,st - 1) + 0 01; and Index of song to pick = ((rend ^ 7) / sizeOfList - I 7) (sizeOfL'st - 1)) 0 This formula allows songs to be picked somewhat randomly, while guaranteeing a high probability that the song picked will come from highest scored Thehgherthe ranking ofthe song In the score matrix, the higher the probabhty it will be picked. This algorithm scales well for any size of hst because it is rank-based, notJust score based The song at that index Is resnoved from the hat I f for some reason a valid song Is not obtained (possibly the song hst already exhausted), another song is added to the hst of types to pick of this type.
Once a song Is picked, its album and artist information are obtained If the artist Is not a "Various Artist" and the sum ofthe number of songs played by this artist and already picked for this playlrst by this artist is greater than or equal to 3, this song cannot be played under the RIAA (Recording Industry AssociatesofAmerica) and/orVMCA(DgitalM'llenmumCopyrightAct)rules Other rules may aisobermplemented m the present Invention to accommodate statutory and other rights and/or restrictions The song Is marked as "rejected" and another song Is added to the list of songs to pick fiom the same hst the to rejected song was pckedffom Thesametestisperformedforalbums, wtl1themaxunumplayedtforexample,being2.
If the song was picked successfully and was within legal or other boundaries, the number of songs picked from this album and by this artist Is incremented. The song Is added to the final list of songs forthe playhst and the order in which the song was picked for the playlist Is marked, or noted If, for some reason, a playlistSze number of songs is not obtained, the existing playlist is deleted and popular is songs are added to the song hashtable, and the song hats are re-sorted and re- picked Ignoring the user's geMes selections.
The picking of news clips Is done simply by picking a specific number of unique news items that are m the specified bandwidth format. A list of available news clips Is stored m the song mformaton cache. Ads may be picked m the same way as news chps are picked However, a difference may be present m the different number of ads to pick Tips may also be picked m the same manner as news clips, with a different number of tips to pick.
to The order of the songs may be randomly shuffled in the playlist and the plainest may be serialized and saved to the database Finally, the ASX file may be returned to the player 108 Every 5 minutes, the player)02/108 "pmgs" the playlist generator]22. If the playhst Is stale or has 8 songs or less leR m it, the playlst generator regenerates the playlist and replaces the one previously saved m the database As an additional enhancement to the present mventron, piayhsts from commercial and other radio stations throughout the United States, and elsewhere, are made available so that playlists may be affected by such radio stations and by popularity of particular musical works.
In achieving the Internet radio of the present invention, a rating acceptor 130 in the form of the RatmgW'dgetServlet routme (Appendix 2, page 171) takes HTTP requests to rate and gets ratings for songs, albums, and artists When a rating is saved, it written to the ratings database and rfthe user who rated the item is designated as being to in the ratings cache, the rating change Is added to the queue of ratings updates.
Once every mmute, the r stings updates are sent to all the ratings caches that have registered their IP address in the database Every hour, the hat of ratings caches are retrieved from the database Every ten minutes, the list <:,f users In the cache are retrieved from the database The song information cache Is Implemented through the SonginfoCache routine (Appendix 2, page 202) and may be a large m-rlemorycache of relatvelystatic data that is used m playLstgeneration It may Include a hat end hashtable of all songs which includes dentifymg numbers, media formats available, average rating, artist and album mformaton, explicit lyrics mark, genres the song is in, and radio stations that play the song Also, other information may be included in the song information cache, Including a hashtable of artist information; a hashtable of album information; a list and hashtable of all ads mciuding identifying numbers and media formats available; a list and hashtable of all news clips so including dentfymg numbers and media formats available, a hat and hashtable of all audio tips including identrfymg numbers and media formats available, a hst ofthe 1000 most popular songs In each media format, lists of all songs in each genre; and a cache of frequently- accessed ratings profiles This last cache Is seen in the RatingsCache routine (Appendix 2, page 164). The song mformaton cache is completely rebuilt once a day from the database The ratmgs cache caches the entire ratings profile for the top 100 users who are known to tee accessed frequently The ratings cache Is implemented through the RatngsCache routine (Appendix 2, page 164) On startup, the ratings cache registers its IF address m the database to subscribe to ratings updates. These users are typically DJs (users with broadcastedorsubscribedratmgs) thathavemanysubscrlbersioruserswhosiniplyuseLAuNckicastfrequently Each ratings cache recalculates the nest frequently-accessed users and writes it to the database every 8 hours At that time, the entire cache is discarded and reread from the database to erase any angering corruption LLach ratings cache checks the database every 10 m minutes for changes in the list of users to be cached and updates the ratings cache as appropriate lo Note should be taken that many ofthe parameters set forth herem are discretionary and advisory. Consequently, those properly and legitimately implementing the present invention may alter such parameters, such as when events occur and event timing as above, according to system operation preferences.
For each user who is not in the ratmgs cache, their ID Is appended to a list of users whose profiles need lo be retrieved from the database 160. Users who have been added to the cache recently have their profiles added to the bat of is ratings to be returned to the PlayhstGenerator routine (Appendix 2, page 132) All non-cached users' ratings are retrieved from the database 160, are appended to the list of ratings, and are returned to the playLst generator 122.
The album and artist ratings are retrieved m a separate query from the song ratings. Each runs In its own thread in parallel for optimal performance The media gateway 120 Is a Java (RTM) servlet that brokers the relationship between the end user's (Windows Media (RTM)) player 108, the database 160, and media hbrary, or Wmdows Media (RTM) server, 180, and logs all media access The MechaGatewayServlet routine (Appendix 2, page 102) performs this function.
Because the clent's Windows Media (RTM) player playhst ( sax file) does not contain any information about the actual songs or ads In the user's playUst, the media gateway 120 contains the logic described below to redirect the user's player to the correct media address on the media library 180 For security reasons, the media gateway 120 may check to see that the client 102 is acccssmg it from the Windows Media (R l M) player cisent 108 (and not a web browser or other appUcaton) If not, it may redirect the user to an error media file The media gateway 120 then pulls the user's ID off the query string and retrieves that user's playlist object from the database 160 The gateway 120 inspects tmestamps m the user's playlist object that mdcate when the user last heard an ad, tip, song or other media item and determines if it Is time to insert an ad, tip, so or news item m the datastream, or just play the next song If the user has not heard an ad, for example, for a pre-defined period of time, the media gateway 120 resets an ad tmestamp and retrieves an ad path from the user's ad playlist and passes that MMS (Microsoft Media (RTM) server) redirect mstructon/address to the end user's Windows Media (RTM) client 108 If no ad Is available, the process continues and plays the next song m the user's playUst If it is not time to play an ad, the as timestamp Is checked to see If it is tune to play a tip l he process then follows the same logic, above, for ads to retrieve and play a tip, Instead of an ad If it is not time to play an ad or tip, the tmestamp Is checked to see If it Is time to play a news item The process then follows the same logic as for ads to retrieve and play a news stem.
If it is not time to play an ad, hp. news Item, or other stream (the usual case), the media gateway 120 retrieves the path of the next song m the playlst and returns that address via an MMS redirect to the clent's Windows Media (RTM) player 108 In all cases, the mcdalD of the ad, tip, or song played Is logged In the database IG0 under that user's ID. fhs logging Information Is used to display what the user is hstemng to on the user's station page and under the "Who's Listening" page. These pages may be associated with the central home page 148 in a manner similar to that of the user pages 140 as history data m the p)aylist generator, and in calculating a Top 100 chart for the most popular songs and/or streams While there may be some preference for an "on-demand" service such that Individuals may pick their own radio playlists, the element of randomness and pleasant surprise Is inherent in the present mventon. Additionally, statutory requirements prevent users from turning the Internet Into their own home stereo system "On-demand" service is generallypreventedbystatuteandmaybcaviolationofcopynght Consequently, anystantoryreguiatons,suchasthe Digital Millenmum Copyright Act (DMCA), and other hnutatians can be programmed automatically mto the present Invention In so doing, the present invention cornples with all applicable law and deUvers to the user a musical in experience generally aligned with his or her preferences Many users often listen to music while doing programm ing or the I ike Such music can now be delivered over the Intemet via the user's very own radio station through the present invention Additionally, users may select other mdviduals or DJs, to influence their musical playlist just as the user does The DJ, online or otherwise, becomes an additional factor in influencing the user's preferences and playlist Some individuals may act as real DJs, serving to |5 provide content to an audience of subscribers through the Internet. Programs of special interest may also be developed and subscribed to by listeners using the present Invention Through the heavily hyperhnked (but easily understandable) interface set forth m the Figures and described above, a user may establish musca I (or other data stream) preferences In establishing such preferences, the music played to the listener is tailored to that listener and provides an enhanced musical experience on an individual basis to While the present mventon has been described with reference to a preferred embodiment or to particular embodiments, It will be understood that various changes and additional variations may be made and equivalents may be substituted for elements thereof without departing from the scope of the nvenbon as defined by the appended claims.
INDUSTRIAL APPLICABILITY
It is an object of the present invention to provide individualized data stream programming according to an ndivdual's preference It Is yet another object ofthe present invention to provide an Internet-based radio or music playing system that Is biased according to each user's preferences.
It is yet another object of the present invention to provide a means by which song playlists may be generated for such an Intemet radio It is an object of the present Invention to provide copynght-comphant media streams for Internet and other networked systems broadcast.
These and other objects, advantages, and the mbustral utility of the present invention will be apparent from a review of the accompanying speciEcaton and drawings Playlist status for userlD 6474126 newRatmgsCount. O moodlD. O djlD 6474126 songsRemaining. 50 medaType: 212 generating because forceRefresh is on regenerating playlist with parameters userlD=6474126, bandwdth=28 8k, moodlD=0, dJID=6474126<PRF> start of createPlayhst O O tap tone, O O total starting gathering threads at 0.0 lap time, 0.0 total GetLastPlayed loaded 618 dates getSubscrptions done 0 063 lap time, 0 063 total All threads started O O lap time, 0.063 total getPopular done 0 047 lap time, 0.11 total getRandom done (picked 5000 songs) 1.281 laptme, 1.391 total genresformoodO64,44,46,48,50,45,47,49,51,G3,67, 1,0,6,7, 10, 11, 12, 13, 14, 15, 16, i7, 18, 19,21,22 23, 24, 68, 69, 13, 74,75, 76, 77, 78, 79, 80, gatherMeda done O O lap time, 1 391 total scores calculated 0.156 lap time, I S47 total recently played albums and artists marked 0.0 lap time, 1 547 total Of 6749 songs, these are the reasons for exclusion. 546 were already excluded, 349 were not encoded, 34 were played m the last 3 hours, 0 had explicit Iyncs, 0 were not m medraType 212, 1292 were not m their genres 482 had an mphct rating of 0 There are 4046 songs available for play ordering O O lap time, 1 547 total finished sorting vectors at O 11 lap time, 1 657 total Available explicit songs 388 O. implicit songs 2334 O. unrated songs 1324.0 Ratio 20 Pickmg explicit songs 17,implcitsongs 23, unrated songs lO,method=UnratedRato start of pickSongs 0.0 lap tme 1.657 total end of pckSongs O O lap time, 1.657 total picked news O O lap time, 1 657 total picked ads 0.015 lap tinne, 1.672 total picked tips 0.0 tap time, 1 672 total playlist has 50 songs shuffling playlist end of createPlaylist O O lap time, 1 672 total starting to save playlist 0016iaptime, 1 6gStoiai done saving playlst 0031 lapt\me, 1 719 tota] <IPRE> SPRY> PlaylistO for userlD6474126 (djlD6474126) m mood O with medaType212, pckCounts exphcit to pick 17, implicit to pick 23, unrated to pick 10 has 50 songs 37409 146690 1022473 1364151 Emitt Rhodes Listen, Listen The Best Of Emitt Rhodes You're A Very lovely Woman - The Merry-&oRound) 37718 43307 1016600 385563 Madonna Erotica Erotica 4568043305 1016600 385517 Madonna The Immaculate Collection Cherish 40237 98477 1025497 900407 Squeeze T he Piccadilly Collection * Loving You Tonight 21825 132410 1027798 1212736 U2 The Best Of 1980-1990 [Limited] New Year's Day 37268 137097 1028125 1259519 Various Artists Made On Earth Untitled Total Echpse 8405 41860 1015516 372519 The Lghtnmg Seeds Sense Sense 31547 91874 1015450 839523 Jackie Leven Forbidden Songs Of The Dying West B'rds Leave Shadows 42209 100072 1028125 1407544 Various Artists Assemblage Vol I Taksu - Lights m a Fat City 39401 105661 1005547 956525 Paula Cole This Fire * Tiger 52454 85650 1024S26 778897 Carly Simon Clouds In My Coffee 1965- 1995 [Box] StuffThat Dreams Are Made Of, The 53486 51128 102 i 142 458446 Pink Floyd Ummagumma Narrow Way Part 1, The - David Gilmour 17982 58282 1025027 526886 Social Distortion Prison Bound Backstreet G'rl 22578 14393 1000398 123761 Bryan Adams So Far So Good Summer Of'69 6947 130669 1009757 1193855 Fun Loves' Criminals 100% Columbian * Big Night Out 39632 113337 1028i25 1011924 Various Artists Pure Moods Crockett's Theme - Jan Hammer 30674 93944 102875G 857682 The Verve Pipe V'lians * Cattle 28189 61860 1026856 559756 They Might Be Giants They Might Be Giants Toddler H'way 16788 23890 1005543 212417 Jude Cole Start The Car Right There Now 37247 137097 1028125 1259512 Various Artists Made On Earth Portnavack Typhoon 28606 64190 1030389 578647 Vanilla Fudge Rock & Roll Windmills Of Your Mind, The - (original mix) 6299 118154 1005865 1062093 Comershop When I Was Born For The7th Time * Brimful Of Asha 29369 74082 1025801 673069 Sting Fields Of Gold. The Best Of Sting 1984- 1994 They Dance Alone (Cueca Solo) 23334 148558 1026856 1386237 They Might Be Giants Miscellaneous T Kiss Me, Son Of God - (alternate version) 53363 50728 1021142 454344 Pink Floyd A Saucerful Of Secrets bet There Be More Light 50557 50901 1020983 455893 Tom Petty Into The Great Wide Open All Or Nothm' 42791 142342 1025039 1327416 Soft Cell Non-Stop Ecstatic Dancing Insecure Me 30719 95006 1021869 867248 R.E M New Adventures In Hi-F' Wake-Up Bomb, The (hve) 42923 148836 1015285 1388605 Ben Lee Breathing Tornados Cigarettes Will K'll You 39860 123837 1018539 1122003 MorcheebaBg Calm Faction 30644 93944 1028256 857672 The Verve Pipe Villains * Drive You Mild 31529 91874 1015450 839517 Jackie Leven Forbidden Songs Of The Dying West Working Alone/A Blessing 39320 92012 1028514 841099 Loudon Wainwright 111 Grown Man Human Cannonball 22344 143220 1000012 1331978 10,000 Maniacs The Earth Pressed Flat * [4/20] Hidden In My Heart 26698 47344 10188G9 423656 Peter Murphy Should The World Fail To Fall Apart God Sends 21660 130952 1021402 1196259 Portishead PNYC * Strangers 26686 47344 1018869 423652 Peter Murphy Should The World Fall To Fall Apart Light Pours Out Of Me, The 39137 87489 1023065 798733 David Lee Roth The Best Lil'A'n't Enough, A 7646 145523 1030217 1352]44 Buddy Holly 20th Century Masters. [4/20] Maybe Baby 44144 25421 1006149 227025 Crosby, Stills & Nash CSN [Box] Southern Cross 21999 135883 1038686 1242702 The Hope Bhster Smle's OK. .1s Jesus Your Pal 39644 113337 1028125 1011928 Vanous Artists Pure Moods Theme From ''Tvvm Peaks - Fire Walk With Me" Angelo Badalament' 50515 50895 1020983 455822 Tom Petty Full Moon Fever Face In The Crowd, A 40510 117098 1018623 1049718 1omssey Maladjusted He Cried 31805 8774] 1013181 801582 Jars Of Clay Jars Of Clay Like A Child 29384 74082 1025801 673074 Sling Fields Of Gold:'T'he Best Of Sting 1984- 1994 We'll Be Together {previously unreleased version) 2562136886 1(112859 328927 INXS X Disappear 28039 60022 1025830 544499 The Stone Roses Second Coming Love Spreads 2626941495 1015374369132LemonheadsComeOnFeelTheLemonheadsintoYourArms 52466 8S650 1024526 778868 Carly Simon Clouds In My Coffee 1965-1995 [Box] Better Not Tell Her 2 songs are by the artist Jackie Leven (1015450) I songs are by the artist Bryan Adams (1000398) I songs are by the artist Paula Cole (1005547) I songs are by the artist Soft Cell (1025Q39) I songs are by the artist Portishead (1021402) 2 songs are by the artist They Might Be Giants (1026856) 1 songs are by the artist Crosby, Stlls&Nash (1006149) I songs are by the artist Vanilla Fudge (1030389) I songs are by the artist Jude Cole (1005543) 2 songs are by the artist Carly Simon (1024526) 2 songs are by the artist Peter Murphy (1018869) I songs are by the artist Social Distortion (1025027)
IS
2 songs are by the artist The Verve Pipe (1028256) 2 songs are by the artist Tom Petty (1020983) I songs are by the artist The Stone Roses (1025830) I songs are by the artist Fun Loving Criminals (1009757) 1 songs are by the artist Morcheeba (1018539) I songs are by the artist R. E.M. (1021869) I songs are by the artist Jars Of Clay (1013181) I songs are by the artist Emitt Rhodes (1022473) songs are by the artist Various Artists (1028125) 2 songs are by the artist Sting (102S801) I songs are by the artist Squeeze (1025497) I songs are by the artist Morrssey (1018623) i songs are by the artist David Lee Roth (1023065) 2 songs are by the artist Madonna (1016600) 1 songs are by the artist Ben Lee (1015285) 2 songs are by the artist Pink Floyd (1021142) I songs are by the artist INXS (1012859) I songs are by the artist London Wanwright 111 (1028514) I songs are by the artist U2 (1027798) I songs are by the artist Lemonheads (1015374) I songs are by the artist The Lightning Seeds (1015576) I songs are by the artist Buddy Holly (1030217) I songs are by the artist 10,000 Maniacs (1000012) I songs are by the artist Comershop (1005865) I songs are by the artist The Hope Blister (1038686) 1 songs are from the album 'I'he Best Of 1980- 1990 [Limited] (13241 D) I songs are from (he album Into The Great Wide Open (50901) I songs are from the album Full Moon Fever (50895) I songs are Mom the album Miscellaneous T (148558) I songs are from the album Come On Feel The Lemonheads (41495) I songs are hrom the album When I Was Born For The 7th Time * (118154) I songs are from the album 20th Century Masters: . [4/20] (145523) I songs are from the album Assemblage Vol. I (100072) I songs are Prom the album Erotica (43307) I songs are from the album The Immaculate Collection (43305) 2 songs are from the album Should The World Fall To Fall Apart (47344) I songs are from the album 100% Columbian * (130669) I songs are from the album Jars Of Clay (87741) I songs are from the album CSN [Box] (25421) I songs are from the album New Adventures In Hi-Fi (95006) 2 songs arc from the album Forbidden Songs Of The Dying West (91874) I songs are from the album Breathing Tornados * (148836) I songs are from the album PNYC * (130952) I songs are from the album Rock & Roll (64190) I songs are from the album Start The Car (23890) I songs are from the album So Far So Good (14393) 2 songs are from the album Fields Of Gold. The Best Of Sung 1984- 1994 (74082) I songs are from the album They Might Be Giants (61860) I songs are from the album Sense (41860) 2 songs are from the album Made On Earth (137097) I songs are from the album MaladJusted (117098) I songs are from the album Smle's OK... (135883) I songs are from the album Listen, Listen The Best Of Emmett Rhodes (146690) I songs are from the album Non-Stop Ecstatic Dancing (142342) I songs are from the album Second Coming (60022) I songs are from the album A Saucerful Of Secrets (50728) I songs are from the album The Best (87489) I songs are from the album [Jmmagumma (51128) I songs are Tom the album X (3G886) 2 songs are from the album Pure Moods (113337) I songs are from the album This Fire * (10566] ) 2 songs are from the album Villains * (93944) I songs are Mom the album Big Calm (123837) I songs are from the album Prison Bound (58282) I songs are From the album The Earth Pressed Flat * L4/20] (143220) 2 songs are trom the album Clouds In My Coffee 1965-1995 [Box] (85650) I songs are from the album The Piccadilly Collection * (98477) I songs are from the album Grown Man (92012) 21 songs (42.0%) are from the random query 6 songs (12 0%) are trom the pop query 6 songs (12 0%) are from the djs query 17 songs (34.0%) are from the rated query 3 songs (6 0%) originated from djAlb 11 songs (22.0%) originated from random 3 songs (6.0%) originated from dJs 6 songs (12 0%) originated from s avg 3 songs (6.0%) originated from artist 7 songs ( 14.000000000000002%) originated from album 17 songs (34 0%) originated from rated Percentile 0% - 20% 40 (80%) Percentile 20% - 40%. 2 (4%) Percentile 40% - 60%: 2 (4%) Percentile 60% - 80%. 4 (8%) Percentile 80% - 100O/D 2 (4%) <p> Item Ratings Artist "The Cure" (1006316) user=O(Not Set) dJs=50/1 --(Not calculated) songAverage=O/O=(Not calculated) songAvgScore=0 0 Artist "Liz Phair" (1020993) user=30 dJs=70/1=70 songAverage=O/O=(Not calculated) songAvgScore=0 0 Artist "Freaky Chakra" (1009573) user=O(Not Set) dJs=O/O=(Not calculated) songAverage=0/1 =0 songAvgScore=39 0 Artist "Duncan Sheik" (1024246) user=O(Not Set) djs=O/O=(Not calculated) songAverage=80/1=80 songAvgScore=59.0 Artist "Tom Petty" (1020983) user=73 dJs=20/1 =20 songAverage=554/8=(Not calculated) songAvgScore=O.O Album "Great Divide" (94571) user=O(Not Set) dJs=70/1=(Not calculated) songAverage=O/O=(Not calculated) songAvgScore=O.O Album "Devil Without A Cause *" (127191) user=20 djs=O/O=(Not calculated) songAverage=O/O=(Not calculated) songAvgScore=0 0 <(entries omitted>.
Artist "Iron City Houserockers" (1012883) user=O(Not Set) djs=O/O=(Noi calculated) songAverage=0/2=0 songAvgScore=26.0 Album "Superunknown" (58747) user=O(Not Set) djs=70/1=70 songAverage=O/O=(Not calculated) songAvgScDre=O.O Artist "To Rococo Rot" (1032453) user=0 djs=O/O=(Not calculated) songAverage=O/O=(Not calculated) songAvgScore=O.O Album "(Not available)" (132i41) user=O(Not Set) dJs=8011=(Not calculated) songAverage=O/O=(Not calculated) songAvgScore=0 Album "Buckcherry" (i43554) user=O(Not Set) dJs=50/1=50 songAverage=O/O=(Not calculated) songAvgScore=0 0 Artist "Jame Blake" (1030814) user=O(Not Set) dJs=60/1=60 songAverage=O/O=(Not calculated) songAvgScore=O.O Album "(Not available)" (45683) user=90 djs=O/O=(Not calculated) songAverage=O/O=(Not calculated) songAvgScore=0.0 Album "(Not available)" (45676) user=90 dJs=O/O=(Not calculated) songAverage=O/O-(Not calculated) songAvgScore=0 Artist "INXS" (1012859) user=O(Not Set) dJs=70/1=70 songAverage=69/2=35 songAvgScore=43 5 Artist "Kenny Wayne Shepherd" (1024272) user=0(Not Set) dis=0/0=(Not calculated) songAverage=0/ 1 =(Not calculated) songAvgScore=0 0 Album "The Ghost Of Tom Joad" (89708) user=0(Not Set) dJs=0/1 =0 songAverage=0/0=(Not calculated) songs vgScore=0.0 Artist "(Notavalable)"(1001434)user=0(NotSet)djs=10/1=(Not calculated) songAveragc=0/0=(Not calculated) songAvgScore=0 0 Explicitly Rated Songs # songlD query origin status ord score lastP. teds impl rating(t) dais netP comm albumlDartisID artist title album 1 372519 rated rated P 5 79 100/30 0/0 49 70/49(1) 52/0 52/0 46/0 41860 1015S76TheLightnngSeeds Sense Sense (14,77,) 2 385517 rated rated P 9 79 100/30 0/0 49 70/49 (1) SZ/0 52/0 49t0 43305 1016600Madonna Cherish The Immaculate Collection (14,28,77,) 3 673074 rated rated P 14 79 100/30 0/0 49 70t49 (1) 52/0 52/0 51/0 74082 1025801 Sting We'll Be Together - (previously unreleased version) Fields Of Gold I he Best Of Sting 1984-i994 (14, 77, ) 4 673069 rated rated P 18 79 100/30 0/0 49 70/49(1) 52/0 52/0 44/0 74082 1025801 Sting They Dance Alone (Cueca Solo) Fields Of Gold.
The Best Of Sting 1984-1994 (14, 77, ) 5123761 rated rated P 22 79 100/30 0/0 49 70/49 (1) 52/0 52/0 48/0 14393 1000398Bryan Adams Summer Of'69 So Far So Good (13, 14, 23, 77, ) 61388605rated rated P 19 79 100/30 0/0 49 70/49 (1) 52/0 52/0 55/0 148836 1015285Ben Lee Cigarettes Will Kill You Breathing Tornados * (14, 77, ) 7 1062093 rated rated P 29 79 100/30 0/0 49 70/49(1) 52/0 52/0 57/0 118154 1005865Coracrshop Brimful Of Asha When I Was Born For The 7th Time * (14, 77, ) 8 867248 rated rated P 16 79 100/30 0/0 49 70/49 (1) 52/0 52/0 40/0 95006 1021869R.E.M Wake-Up Bomb, The (live) New Adventures In Hi-Fi (14, 77, ) 9 227025 rated rated P 42 79 100/30 0/0 49 70/49 (1) 52/0 52/0 48/0 25421 1006149Crosby, Stills & Nash Southern Cross CSN [Box] (13, 14,16,24,77,) 857682 rated rated P 44 79 100/30 0/0 49 70/49 (1) 52/0 52/0 50/0 93944 1028256The Verve Pipe Cattle Villains * (14, 78, ) 11 1081855rated rated N -] 79 100/30 0/0 49 70/49(1) 52/0 52/0 38/0 119843 1024639Sixpence None The Richer We Have Forgonen Sixpence None T he Richer * (14, 17, ) 12454986 rated rated N -1 79 100/30 0/0 49 70/49 (1) 52/0 52/0 46/0 50795 1020940Pet Shop Boys Heart Discography - The Complete Singles. (id, 77, ) 13 455822 rated rated P 31 79 100/30 0/0 49 70/49(1) 52/0 5210 42/0 50895 1020983TomPeny FaceIn lheCrowd,A FullMoon Fever (14, 77, ) 14 664522 rated rated N -1 79 100/30 0/0 49 70/49 (1) 52/0 52/0 47/0 73173 1016600Madonna Secret Bedtime Stories (7, 14, 24, 76, 77, ) 990161 rated rated N -1 79 100/30 0/0 49 70/49(1) 52/0 52/0 44/0 i i0565 iO27386Train Days Train (14, 77, ) 16 544499 rated rated P 12 79 100/30 0/0 49 70/49 (1) 52/0 52/0 47/0 60022 1025830The Stone Roses Love Spreads Second Coming (14, 77, ) 17 857683 rated rated N -1 79 100/30 0/0 49 70/49 (1) 52/0 52/0 49/0 93944 1028256The Verve Pipe Veneer Villains * (14, 78, ) 18 990158 rated rated N-1 79 i00/30 010 49 70/49 (1) 5210 52/0 5010 110565 1027386Trah1 Blind Train (14, 77, ) 191119487rated rated N -1 79]00/30 0/0 49 70/49(1) 52/0 52/0 55/0 123589 1028125VariousArtists Block Rockin'Beats-TheChemical Brothers Digital Empire Electronica's Best (14, 77, ) 458446 rated rated P 33 79 100/30 0/0 49 70/49 (1) 52/0 52/0 37/0 5il28 1021142PmkFloyd NarrowWayPartl,The-DavdGilmour Ummagumma (14, 77, ) <<entries omitted>> 360 830167 rated rated N -1 42 0/0 0/0 42 60/42 (1) 52/0 52/0 49/0 90869 1016358Lush Ladykrilers Lovelife * (14, 77, ) songlD query origin status ord score lastP teds irnpl rating(t) djs netP comm albumlDartslD artist title album 361 345744 rated rated N À1 42 0/0 0/0 42 60/42 (1) 52/0 52/0 49/0 38706 1013691Joumey Faithfully Time CubediBox] (14,77, ) 362 1012355rated rated N -1 42 0/0 0/0 42 60/42 (1) 52/0 52/0 45/0 113423 1023631 Savage Garden To The Moon & Back Savage Garden (14, 77, ) 363673063 rated rated N -1 42 0/0 0/0 42 60/42 (1) 52/0 52/0 47/0 74082 1025801 Sting When We Dance - (previously unreleased) Fields Of Gold The Best Of Sting 1984- 1994 (14, 77, ) 364 1383771 rated rated N -1 42 0/0 0/0 42 60/42 (1) 5210 52/0 46/0 148392 1021623TheProdgy Smack MyBitchUp Fat OfTheLand * (14,77,) 365 499807 rated rated N -1 42 0/0 0/0 42 60/42 (1) 52/0 52/0 51/0 55333 1023239Rush Tom Sawyer Chronicles (14, 77, ) 366 1078501 rated rated N -1 42 0/0 0/0 42 60/42 (1) 52/0 52/0 35/0 li9582 1015272LedZeppelin Thank You-(stereo) BBC Sessions* (14, 77,) 3671327003 rated rated N -1 41 0/0 0/0 41 59/41 (1) 52/0 52/0 43/0 142307 1039472Tommy Henrrksen Dreaming In Colors Tommy Henriksen (14, 77, ) 368 1212748rated rated N -1 40 0/0 0/0 40 57/40(1) 52/0 52/0 63/0 132410 i027798U2 A111 Want Is You The Best Of 1980-1990 [Limited] (14, 77, ) 369 345875 rated random N -1 37 100/30 0/0 7 10/07 (1) 52/0 52/0 36/0 38717 1013699 J oy Of Cooki rig Three Day Loser American Original s (14, 77, ) 370 1233646rated random N -1 37 100/30 0/0 7 10/07 (1) 52/0 52/0 40/0 134584 1037731 Britney Spears Crazy, (You Drive Me) Baby One More Time. [ECU] (14, 77, ) 371 573363 rated random N -1 37 100/30 0/0 7 10/07 (!) 52/0 52/0 40/0 63494 1027743TwistedSrster We're Not GonnaTakelt Big Hits And Nasty Cuts-Best Of Twisted Sister (15,16, ) 372 339153 rated random N -1 37 100/30 0/0 7 10/07(1) 52/0 52/0 41/0 37973 1013350JethroTull Jeffrey Goes ToLeicester Square Stand Up (14,77,) 373 1233649rated random N -1 37 100/30 0/0 7 10/07(1) 52/0 52/0 40/0 134584 1037731 Britney Spears Born To Make You HappyBaby One More Time [ECD] (14, 77, ) 374 1411604rated random N -1 37 100/30 0/0 7 10/07 (1) 52/0 52/0 43/0 50365 1020680The Pastels Baby Honey Suck On The Pastels 1983- 1985 (14, 77, ) 375 870674 rated random N -1 37 100/30 0/0 7 10/07 (1) 52/0 52/0 43/0 95367 1021928 Rage Against The Machine Year Of The Boomerang Evil Empire * (14, 77, ) 376 1233647rated random N -1 36 100/30 0/0 6 09/06 (1) 52/0 52/0 23/0 134584 103773113ntney Spears Sometimes Baby One More Time tECD] (14, 77, ) 377990162 rated rated N -1 35 0/0 0/0 35 50/35 (1) 52/0 52/0 39/0 110S65 1027386Tran Rat Train (14, 77, ) 378 578086 rated rated N -1 35 0/0 0/0 35 50/35 (1) 52/0 52/0 49/0 64109 1028073VanHalen Top OfThe World ForUnlawful Carnal Knowledge (14, 77, ) 379948179 rated rated N -1 35 0/0 0/0 35 50/35 (1) 52/0 52/0 50/0 104678 1015374Lemonheads Ox CarButtonCloth(14, 77,) 380870670 rated rated N -1 35 0/0 0/0 35 50/35 (1) 52/0 S2/0 42/0 95367 1021928RageAgainstTheMachme Down Rodeo Evil Empire * (14, 77. ) 38i 1327649rated rated N -1 35 0/0 0/0 35 50/35 (1) 52/0 52/0 55/0 142358 1003125Blur 1992 13 [Limited Edition] * (14, 77, ) 382 1164473 rated random N -1 33 100/30 0/0 3 04/03(1) 52/0 52/0 40/0 127996 1017147JohnMartyn Glory Box The ChurchWth One Bell * (11, ) 383 1004142rated rated N -1 31 0/0 0/0 31 44/31 (1) 52/0 52/0 50/0 112437 10201S60riginal Soundtrack Da Funk - Daft Punk The Samt (6, ) 384 100S941 rated rated N -1 28 0/0 0/0 28 40/28(1) 52/0 52/0 29/0 112611 1011710Heart StrandedThese Dreams - Heart's Greatest Hits * (14, 77, ) 38S S31917 rated rated N -1 28 0/0 010 28 40/28(1) 52/0 52!0 48/0 58747 102S213Soundgarden Fell On Black Days Superurknown ( id, 77, ) 386 224547 rated rated N -1 25 0/0 0/0 25 36/25 (1) 52/0 52/0 45/0 25172 1006025Crash Test Dummies Untitled God ShufflcdH'sPeet (14, 77, ) 387 991308 rated random N -1 21 0/0 0/0 21 30121 (1) 52/0 52/0 41/0 110722 10093S2 Foo Fighters New Way Home The Colour & The Shape * (14,78,) 388 531918 rated random N -1 14 0/0 010 14 20114(1) S2/0 S2/0 44/0 58747 1025213Soundgarden Mailman Superunknown (14, 77, ) Imphcitly Rated Songs # songlD query organ status ord score iastP teds impl. rating(t) djs netP comm albumlDartslD artist title album 1 5597S6 random album P 6 65 100/20 0/0 45 95/43 (2) 1011 52/0 40/2 61860 1026856They Might Be Giants Toddler H'way They Might Be Giants (14, 77, 2 857672 random dAlb P 2 63 100/20 0/0 43 81/36 (2) 9015 52/0 36/2 93944 1028256The Verve Pipe Drive You Mild Villains * (14, 18, ) 3 1212736ds album P 10 61 100/20 0/0 4i 80/36 (2) 50/3 52/0 53/3 132410 1027798U2 New Year's Day The Best Of 1980-1990 [Limited] (14, 77, ) 4 1212744random album R -1 61 100/20 0/0 41 80/36 (2) 4012 52/0 61/3 132410 1027798U2 Sweetest Thing-(The Single mix) The Best Of 1980-1990 [Limited] (14, 77, ) 778854 random album R -1 61 100120 0/0 41 80/36 (2) S2/3 52/0 46/2 85650 1024526CarlySimon Do The Walls Come Down Clouds In My Coffee 1965-1995 [Box] (14, 77, ) 6 778868 random album P 8 61 100/20 0/0 41 80/36 (2) 52/3 52/0 46/2 85650 1024526Carly Simon Better Not Tell Her Clouds In My Coffee 1965-1995 [Box] (14, 77, ) 7 iO89955random album R -1 61 100/20 0/0 41 80/36 (2) 52/3 52/0 45/2 120604 1017716 J ohn Me l [encamp I Need A Lover The Best That I Cou i d Do (14, 77, ) 8 1089962random album R -1 61 100/20 0/0 41 80/36(2) 5213 5210 45/2 120604 1017716John MellencampAuthorty Song The Best That I Could Do (14, 77, ) 9 385512 random album R -1 61 100/20 0/0 41 80/36(2) 50/3 52/0 47/2 43305 1016600Madonna Papa Don't Preach The Immaculate Collection (14, 28, 77, ) 778844 random album R -] 61 100/20 0/0 41 80/36 (2) 52/3 52/0 42/2 85650 1024526Carly Shnon Play With Me Clouds In My Coffee 1965-1995 [Box] (14,77, ) 11 778877 random album R -i 61 100/20 0/0 41 80/36(2) 52/3 52/0 42/2 85650 1024526Carly Simon Angel From Montgomery - (prev unreleased) Clouds In My Coffee 1965-1995 [Box] (14, 77, ) 12 778855 random album R -1 61 100/20 0/0 41 80/36(2) 52/3 52/0 40/2 85650 1024526Carly S'mon Danny Boy Clouds In My Coffee 1965- 1995 [Box] (14,77, ) 13 1212734random album R -1 61 100/20 0/0 41 80/36(2) 50/3 52/0 41/2 132410 1027798U2 Trash, Trampoline And The Party Girl The Best Of 1980-1990 [Limited] (14, 77, ) 14 778848 random album R -1 60 100/20 0/0 40 80/36 (2) 52/3 52/0 37/2 85650 1024526Carly Simon June Through The Glass Clouds In My Coffee 1965-1995 [Box] (14, 77, ) 385563 dais artist P 38 60 100/20 0/0 40 80/32 (3) 60/6 52/0 49/2 43307 1016600Madonna Erotica Erotica (14, 77, ) 16 778847 random album R -1 60 100/20 0/0 40 80/36 (2) 52/3 52/0 37/2 85650 1024526Carly Simon Boys In The Trees Clouds In My Coffee 1965- 1995 [Box] (14, 77, ) i7 778894 random album R -1 60 100/20 0/0 40 80/36 (2) 52/3 52/0 37/2 85650 1024526Carly Simon Nobody Does It Better Clouds In My Coffee 1965- 1995 [Box] (14, 77, ) 18 778890 random album R -1 60 100/20 0/0 40 80/36 (2) 52/3 52/0 37t2 85650 1024526 Carly S'mon Why Clouds In My Coffee 1965- 1995 [Box] (14, 77, ) 19 778856 random album R -1 60 100/20 0/0 40 80/36 (2) 52/3 52/0 37/2 85650 1024526Carly Simon D'nk's Blues Clouds In My Coffee 1965-1995 [Box] (14, 77, ) 1212752djs album R -1 60 100/20 0/0 40 80/36(2) 40/2 52/0 48/2 132410 1027798 U2 Love Comes Tumbling The Best Of 1980-1990 [Limited; (14, 77, ) <<entries omitted>> 2314 14110i5random random N -1 23 100/20 0/0 3 00/00(4) 0/0 52/0 50/3 111845 1026459TallDwarEs Crocodile Stumpy* (14,77, ) 2315 434293 pop djArt N -1 22 0/0 0/0 22 39/14(4) 40/6 52/0 52/3 48566 1019512Nine Inch Nails Ruiner The Downward Spiral (14, 77, ) 2316 6]5943 pop djArt N -1 22 0/0 0/0 22 39/14 (4) 40/6 52/0 52/3 68246 1022782TomRobinson WmterOf'79,The Powerln The Darkness (14,77, ) 2317 1411059djs random N -1 22 100/20 0/0 2 00/00 (4) 0/0 52/0 42/2 lil845 1026459TallDwarfs Jesus the Beast Stumpy* (14,77, ) 2318 1411054djs random N -1 22 100/20 0/0 2 00/00 (4) 0/0 52/0 40/2 111845 1026459Tall Dwarfs The Severed Head of JulioStumpy * (14, 77, ) 2319 1411069random random N -1 22]00/20 0/0 2 00/00(4) 0/0 52/0 40/2 111845 1026459Tai1 Dwarfs Desscatcd Stumpy' (14, 77, ) 2320 1411070djs random N -1 22 100/20 0/0 2 00/00(4) 0/0 52/0 40/2 111845 1026459Tall Dwarfs Two Mmds Stumpy * (14, 77, ) # songiD query origin status ord score lastP teds Emil ratng(t) djs netP comm albumlDartslD artist title album 2321 931183 dais savg N -1 19 0/0 0/0 19 39/14(4) 2514 52/0 37/2 102305 101208] Robyn Hitchcock Yip Song, The Greatest Hits (14, 77, ) 2322 560002 randonn random N -1 19 0/0 0/0 i9 26/09 (4) 52/8 52/0 47/2 61888 1026872Thinlzzy KillerOnTheLoose 1'feL've (14, 16, 77,) 2323 1125549random artist 11 -1 19 0/0 0/0 19 40/16(3) 10/1 52/0 40/2 124176 1023542Santana Bella Best OfSantana(Legacy)* (14,77, ) 2324 328929 random s avg N -1 19 0/0 0/0]9 43/15 (4) 10/2 52/0 41/2 36886 10128591NXS Faith In Each Other X (14, 77, ) 2325 1073535djs s avg N -1 18 0/0 0/0 18 46/16 (4) 0/0 52/0 46/2 119192 1021186ThePxes Gouge Away Death To The Pixies (14,77,) 2326 1064098random djs N -1 18 0/0 0/0 18 26/09(4) 40/6 52/0 52/3 118335 1030720Apollo Four Forty Ain't Talkin"Bout Dub Electro Glide In Blue (14, 43, ) 2327 651483 random s avg N -1 18 0/0 0/0 18 39/14 (4) 10/2 52/0 47/2 72015 1014381 Carole King Where You Lead A Natural Woman The Ode [Box] (14, 77. ) 2328 829989 random s avg N -i 17 0/0 0/0 17 39/14 (4) 10/2 52/0 46/2 90854 1013280Jefferson Airplane Crazy Miranda Bark (14, 77, ) 2329 553197 djs s avg N -1 17 0/0 0/0 17 39/14 (4) 10/2 52/0 44/2 61087 1026455 talk Talk Renee It's My l.'fe (14, 77, ) 2330 651476 djs sang N -1 17 0/0 0/0 17 39/14(4) 10/2 52/0 41/2 72015 1014381CaroleKng IFeelTheEarth Move A Natural Woman The Ode [Box] (14, 77, ) 2331 504343 dJs savg N -1 15 0/0 0/0 15 39/14(4) 0/0 52/0 34/2 55865 1023614loe Satriani Summer Song The Extremist (14, 77, ) 2332,55176 random random N I 9 0/0 0/0 9 i 5/05 (4) 10/2 52/0 47/2 39927 1014426The Kinks Most Exclusive Residence For Sale (mono) Face To Face (14, 77, ) 2333 1233652djs dJs N -1 8 0/0 0/0 8 09/04 (2) 40/2 52/0 41/2 134584 103773i Brtney Spears 1 Will Still Love You (with Don Philip) Baby One More Time. [ECD] (14, 77, ) 233ó958836 random random N -1 7 0/0 0/0 7 09/03 (4) 10/2 52/0 37/2 105851 1029091TheWho IDon't Even Know Myself Caveat The Isle Of W'ght Festival 1970 * (14,77, ) Unrated Songs # songlD query origin status ord score lastP. teds imply rating(t) dJs netP comm albumIDartislD artist title album 1 1011924random dAlb P 7 54 100/25 0/0 29 52/00 (0) 73/24 52/0 46/5 1 13337 1028125Varous Artists Crockett's Theme - Jan Hammer Pure Moods (10, ) 2 1011928random djAlb P 11 53 100/25 0/0 28 52/00 (0) 73/24 52/0 41/4 113337 1028125Varous Artists Theme From "Iwm Peaks - Fire Walk With Me" - Angelo Badalament' Pure Moods (10, ) 3 423652 pop random P 17 47 100/25 0/0 22 52/00 (0) 52/17 52/0 52/5 47344 1018869PeterMurphy Light Pours OutOfMe,The Should The World Fail To Fall Apart (14, 77, ) 4 423656 pop random P 34 47 100125 0/0 22 52/00 (0) 52117 5210 5215 47344 1018869PeterMurphy God Sends Should TheWorldFailTo Fall Apart (14, 77, ) 1193855pop random P 37 47 100/25 010 22 52/00(0) 52/17 52/0 5215 130669 1009757Fun Lovm'Crunmals Big Night Out 100% Columbian * (14,77,) 6 423649 random random R -1 47 100/25 0/0 22 52/00 (0) 52tl7 52/0 52/5 47344 1018869Peter Murphy Final Solution Should The World Fail To Fail Apart (14, 77, ) 7 1259512random random P 45 47 100/25 0/0 22 52100 (0) 52/17 52/0 52/5 137097 1028125Vanous Artists Portnawack - Typhoon Made On Earth (14, 77, ) 8 1259519random random P 32 47 100/25 0/0 22 52100(0) 52/17 52/0 52J5 137097 1028125Various Artists Untitled - Total Eclipse Made On Earth (14,77,) 9 423657 pop random N -1 47 100/25 0/0 22 52/00(0) 52/17 52/0 52/5 47344 1018869PeterMurphy Blue Heart Should TheWorldFalTo Fall Apart (14, 77, ) 958997 random random N -1 47 100/25 0/0 22 52/00 (0) 52/17 52/0 52/5 105874 1028125Various Artists Freelon - Spacetme Continuum Werks Like a Twelve Inch (14, 77, ) 1i]193846pop random N -1 47 100/25 0/0 22 52/00(0) 52/17 52/0 52/5]30669 1009757Fun Lovin'Crminals View Belongs To Everyone, The 100% Colombian * (14, 77, ) 121193848pop random N -1 47 100/25 0/0 22 52/00(0) 52/17 52/0 52/5 130669 1009757FunLovm'Crmmals Back On The Block 100% Columbian * (14, 77, ) 13 1193844pop random N -1 47]00/25 010 22 52/00(0) 52/17 52/0 52/5 130669 1009757Fun Lovin' Criminals Up On The Hill 100% Columbian * (14,77,) 14 1193845random random N À1 47 100/25 0/0 22 52/00(0) 52/17 52/0 52/5 130669 10097571;unLovin'Cnmmals Love Unlimited 100%Columbian * (14, 77, ) 923902 random random N -1 47 100/25 0/0 22 52/00(0) 52/17 52/0 52/5 101415 1028125 Various ArtistsGrass Roots - Tricky/Roberto Malary Jr.
Tricky Presents Grassroots [EP] (14, 77, ) 161193854pop random N À1 47 100/25 0/0 22 52/00(0) 52/17 52/0 52/5 130669 iO09757FunLovin'Criminals Al)MyT'mels Gone 100% Columbian * (14, 77, ) 17 1193849pop random N -i 47 100125 0/0 22 52/00 (0) 52/17 52/0 52/5 130669 1009757 Fun Lovin' Criminals I 0th Street 100% Colombian * (4,77,) 18 1193852pop random N -1 47 100/25 0/0 22 52/00(0) 52/17 52/0 52/5 130669 1009757Fun Lovm'Crimmals We Are All Very Worried About You 100% Columbian * (14, 77, ) 19 806170 random random N -1 47 100/25 0/0 22 52/00(0) 52/17 52/0 52/5 88136 1028125 Various Artists Man's World, (It's Not) A - Strata 3 The Trip Hop Test Part2 (14,77,) 806163 random random N -1 47 100/25 0/0 22 52/00(0) 52/17 52/0 52/5 88136 1028125Various Artists Anafey - Hip Optimist The Trip Hop Test Part 2 ( i 4, 77, ) <(entries omitted>>.
1304 228812 pop random N -1 22 0/0 0/0 22 52/00(0) 52/17 52/0 52/5 25620 1030126The Crystals I Wonder The Best Of The Crystals (23, ) 1305 228814 pop random N -1 22 0/0 0/0 22 52/00 (0) 52/17 52/0 52/5 25620 1030126The Crystals Girls Can Tell The Best Of The Crystals (23, ) 1306 228798 pop random N -1 22 0/0 0/0 22 52/00(0) 52/17 52/0 52/5 25620 1030126TheCrystals Oh,Yeah,Maybe,Baby The Best OfThe Crystals (23, ) 1307 228810 random random N -1 22 0/0 0/0 22 52/00 (0) 52/17 52/0 52/5 25620 1030126The Crystals Heartbreaker The Best Of The Crystals (23, ) 1308 740607 pop random N -1 22 0/0 0/0 22 52100 (0) 52/17 52/0 52/5 81532 1008091 EBN Get Down Ver. 2 2 Telecommumcation Breakdown [ECD] (14, 77, ) 1309 876063 pop random N -1 22 0/0 0/0 22 52/00 (0) 52/17 52/0 52/5 95946 10124211]owe B. Shag Music For Babes(14, 77, ) 1310 914734 pop random N -1 22 0/0 0/0 22 52/00(0) 52/17 52/0 52/5 100059 1020939Pet Fatherland Pet (14, 77, ) 1311 882981 pop random N -1 22 0/0 0/0 22 52/00(0) 52/17 52/0 52/5 96691 1028125Various Artists Million Town - Strange Cargo (The Kruder & Dortmeister Session) A Joumey Into Ambient Groove 3 (14, 77, ) 1312 1320082pop random N -1 22 0/0 0/0 22 52100(0) 52/17 52/0 52/5 141627 1039729Papa Vegas Something Wrong Hello Vertigo [4/27] (14, 77, ) 1313 1242704pop random N -1 22 0/0 0/0 22 52/00(0) 52/17 52/0 52/5 135883 1038686The Hope Blister Hanky Panky Nohow Smile's OK (14, 77, ) 1314 942415 random random N -1 22 0/0 0/0 22 52/00(0) 52/17 52/0 52/5 103598 1024664 Skeleton Key World's Most Famous Undertaker, The Skeleton Key [EP] (14, 77, ) 1315 1119500pop random N -1 22 0/0 0/0 22 52/00(0) 52/17 52/0 52/5 123589 1028125Various Artists Take California - Propellerheads Digital Empire. Electromca's Best(i4, 77, ) 1316 528565 pop random N - i 22 0/0 0/0 22 52/00 (0) 52/17 52/0 52/5 58464 1025129SonsOfChampim Get High Capitol Gold The Best Of The Sons Of Champln(14, 77, ) 1317528568 pop random N -1 22 0/0 0/0 22 52/00(0) 52/17 52/0 52/5 58464 1025i29SonsOfChamphn It's TimeCapitolGold.The Best Of The Sons Of Champlin (14, 77, ) 1318 942223 random random N -1 22 0/0 0/0 22 52/00(0) 52/17 52/0 52/5 103571 1024799Sloan G Turns To D One Chord To Another (14,77, ) 1319 942219 random random N -1 22 0/0 0/0 22 52/00(0) 52/17 52/0 52/5 103571 1024799Sloan Good In Everyone, The One Chord To Another (14, 77, ) 1320 1017638random random N -1 22 0/0 0/0 22 52/00(0) 52/17 52/0 48/5 114082 1004159Davd Byrne Wicked Little Doll Feehngs * (14, 77, ) # songlD query origin status ord score lastP. teds impl rating(t) djs netP.
comm album1DartislD artist title album 1321 809747 random random N -1 22 0/0 0/0 22 52/00 (0) 52/17 52/0 46/5 88473 1015875 Loop Guru Jungle ADuniya (14, 77, ) 1322 455363 random random N -1 21 0/0 0/0 21 52/00 (0) 52/17 52/0 40/4 50841 1030292Peter&Gordon IFeeiLikeGong Out The Best Of Peter & Gordon (Rhmo) (23, ) 1323 814350 random djArt N -1 18 0/0 0/0 18 52/00 (0) 40/13 52/0 45/5 88938 1021734Pulp Death 11 Separations (14, 77, ) 1324 232378 djs random N -1 12 0/0 0/0 12 52/00(01 20/7 52/0 49/5 26074 iO06547TheDamned SmashitUp(Partsi&2)The Best OfThe Damned (Another) (14, 78, ) </PRE> <XMP><ASX VERSION="3.0" PREVIEWMODE="NO"> <REPEAT> <ENTRY> <REF HREF="http //devweb7 launch com/servlet/gateway7u=6474 i 26&n=O. asp"/> </ENTRY> <ENTRY> <REF HREF="http://devweb7 launch com/servlet/gatewayQu=6474126&n= 1 asp"/> </ENTRY> <ENTRY> <REF HREF="http //devweb7.1aunch.com/servleVgateway?u=6474126&n=2 asp"/> </ENTRY> <ENTRY> <REF HREF="http //devweb7 launch com/servlet/gateway7u=6474126&n=3.asp"/> </ENTRY> <ENTRY> <REF HREF="http //devweb7.1aunch.comiservict/gateway7u=6474126&n=4 asp"/> </ENTRY> <ENTRY> <REF HREF="http //devweb7 launch comiservlet/gatewayqu=6474126&n=S.asp"/> </ENTRY> <ENTRY> <REF H REF="http.//devweb7.1aunch com/servlet/gateway?u=6474126&n=6.asp"/> </ENTRY> <ENTRY> <REF HREF="http //devweb7 launch com/servlet/gatewayQu=6474126&n=7 asp"/> </ENTRY> <ENTRY> <REF HREF="hKp://devweb7 launch.com/servlet/gateway?u=6474126&n=8 asp"/> </ENTRY> <ENTRY> <REF HREF="http //devweb7 launch.com/servlet/gateway?u=6474126&n=9 asp"/> </ENTRY> </REPEAT> <IASX> </XMP>
SOURCE CODE
Internet Radio and Broadcast Method Copyright 1999, 2000 LAUNCH Media, Inc. www.LAUNCH.com ALBUMARTISTDATA 4 ALBUMINFO, 5 ARTISTINFO, 7 AVERAGERATING 8 BANDWIDTH 9 lo BDSRANK 11 CACHEDRATING 12 CLIP 13 CLIPCOLLECTION 17 CLIPSCHEDULE 18 CONSTANTS 21 DBCONNECTION 23 DBEXCEPTION 26
DBPREPAREDSTATEMENT 27
DBRESULTSET 28 DJ 31 DJLIST 32 FREQUENCYCOUNTER 34 GENERATORPARAMETERS 37 GENREINDEX 39 GENRELIST 41 GETADS 43 GETBDSSTATIONS 45 GETGENRES 46 GETITEMRATlNGSPROMDB 47 GETLASTPLAYED 48 GETNEWS 49 GETPLAYLIST 51 GETPLAYLISTSERVERS 52 GETPLAYLISTSERVERSINTEACE 53 App 2- 1 is GETPOPULAR 54 GETRATINGS 55 GETRATINGSCACHEUSERS 59 GETRATINGSCACHEUSERSINTERFACE 61 GETRECENTLYPLAYED 62 GETSONGINFOSERVLET 64 GETSONGItATINGSFROMDB 70 TNTHASH 71 ITEM 72 ITEMSPROFILE 74 MEDIA 76 MEDIAFORMAT 77 MEDIAGATEWAYSERVLET 78 MEDIALIST 83 PICKCOUNT 85 PICKLIST 87 PICKSTATUS 88 PLAYDATAHASH 89 PLAYDATES 90 PLAYLIST 98 PLAYLIST2 105 PLAYLISTCREATORTEST 106 PLAYLISTENTRY 107 PLAYLISTGENERATOR 108 PLAYLISTGENERATORSERVLET 120 PLAYLISTMAKER 125 PLAYLISTPARAMETERS 1 26 PLAYLISTSTATUS 127 POPULARSONGS 130 POPULATION 131 6S RATING 139 RATINGSCAGHE 140 RATINGSPROFILE 1 46 RATINGWIDGETSERVLET 147 App. 2-2 RECLIST, 153 SAVECLIPS 156 SAVEPLAYLIST 1S8 SIMPLECLIP 160 SIMPLECLIPLIST 161 SIMPLEPLAYLIST 162 SONG 165 SONGDATA I67 SONGGROIIP 174 SONGINFO 175 SONGINFOCACHE 178 SONGINFOCACHEUPDATER 185 SONGLIST 186 SONGRATING 189 STATION 190 STATIONLIST 191 UTIL 192 WEIGHTMATRIX 194 App. 2-3 AlbumArtistData package com. Iaunch.PlaylistGenerator public class AlbumArtistData Item album = null; Item artist = null; boolean alreadyTriedAlbum = false; boolean alreadyTriedArtist = false; public void resct() album = null; artist = null; is alreadyTriedAlbum = false; alreadyTriedArtist = false; public Item getAlbum(ltemsProfile items, SongData data) { if (alreadyTriedAlbum) return album; alreadyTriedAlbum = true; albunn = items.get(data.getAlbumlD()); return album; public Item getArtist(ltemsProfile items, SongData data) if (alreadyTriedArtist) return artist; alreadyTriedArtist = true; artist = items.get(data. getArtistlDO); return artist; 40} AlbumArtistDatajava PageIofI I1/05/991:32PM App. 2-4 AlbumInfo package corn.launch.PlaylistGenerator import java.util.Vector; public class Albuminfo { int ID String title; Artistinfo artist; lo Vector genres; public Albuminfo(int ID) this.lD = ID; public String tostring0 return "[albumlD=" + ID + ", title=" + title + ", genres=" + genresString() + ", artist=" + attist.toString() + "]"; 20} public String genresString() if (genres == null) return "(NONE)"; String result = ""; for (int i = 0; i < genres.size(); i++) { result = result.concat(genres.elementAt(i) + ", "); return "(" + result + ")"; public int getArtistlD0 throws Exception if (artist = null) throw new Exception("artist is not set for album " + ID + " (" + title + ") "); return artist.lD; public boolean inGenres(short genrelD) { if (genres == null) return false; return genres.contains(new Sh ort(genrel D)); public boolean inGenres(GenreList userGenres) if (userGenres.allGenres =- true) return true; if (genres == null) 03 return false; App. 2-5 11 do it the other way, check each of the genres the song is 11 in and if it's in the user's genres for (int i = 0; i < genres.size(); i++) Short genrelD = (Short) genres.elennentAt(i); if (userGenres.ex ists(genrel A)) return true; return false; 7S public void addGenre(short genrelD) if(genres = null) genres = new Vector(l,l); 1/ be careful not to add duplicates Short genre = new Short(genrelD); if (!genres.contains(genre)) genres.addE l em ent(n ew S hort(gen re lD)) ; AIbuminfojava Page2 of 2]1/05/99 1:27 PM App. 2-6 ArtistInfo package com. Iaunch.Playl istGenerator; import java.util.Hashtable; public class Artistinfo { int ID; String title
Hashtable songs;
to public Artistinfo(int ID) this.lD = ID; songs = new Hashtable(); is} public String toString() return "[artistID=" + ID + ", title=" + title + "I"; 20} public final static boolean isVariousArtists(int itemlD) return (itemlD == Constants.ARTIST VARIOUS_ARTISTS 11 itemlD == Constants.ARTIST_ORIGINAL_SOUNDTRACK 1l itemlD == Constants.ARTIST_SOUNDTRACK); Artistinfo java Page I of I I 1/05/99 1:37 PM App. 2-7 AverageRating package com. launch. PlaylistGenerator; public class AverageRating extends Rating private short count = 0; private int sum; private boolean calculated = false; public AverageRating() ) super(); public AverageRating(short defaultRating) super(defau ItRating); 15} public void add(int value) sum + = value; count++; zo calculated = false; public short get() calculates); return super.get(); public short count() return count' 30} private void calculate() if (!calculated) 3S if (count > 0) set(Util.average(count, sum)); set = true; to calculated = true; public String toString() String ratingStr= "(Not calculated)"; if (set) ratingStr = "" + rating; return sum + "/" + count "=" + ratingStr; AverageRatingJava Page 2 Of 2 1 1/05/99 1:27 PM App. 2-8 Bandwidth package com.launch.PlaylistGenerator; public class Bandwidth public final static short SPEED 28 = 28; public final static short SPEED 56 = 56 public final static short SPEED 100 = 100; public final static short SPEED_128 = 128; public final static short SPEED 300 = 300; lo public final static short SPEED 500 = 500; private boolean beenset = false; private short value = SPEED 28; l5 public Bandwidth() public Bandwidth(short speed) value = speed; beenset = true; public Bandwidth(String speed) if (speed == null) beenset = false; else if (speed.equals("28")) set(SPEED 28); else if(speed.equals("56")) set(SPEED 56); else if (speed.equals(" l 00")) set(SPEED I 00); so else if(speed. equals("l28")) set(SPEED]28); else if(speed.equals("300")) set(SPEED 300); else if(speed.equals(n500")) set(SPEED 500); else beenset= false; public String toString() if(value=SPEED 28) return "28.8k"; elseif(value==SPEED 56) return "56k"; 450 else if(value == SPEED 100) App. 2-9 return " I00k"; else if(value o SPEED 128) retum " 128k"; else if(value== SPEED_300) retum "300k" else if (value = SPEED 500) retum "56k" return "UNKNOWN (" + value + ")"; public short get() return value; 7s public void set(short speed) if(speed==SPEED 28 1l speed == SPEED 56 ao li speed == SPEED 100 speed == SPEED 128 speed == SPEED 300 1l speed == SPEED_500) as value = speed; beenset = true; else beenset= false 90} public boolean load(DBConnection cone, int userlD) try DBResultSet rs = conn.executeSQL("exec sp_a 1 50UserPreference GetValue xsxx " + userlD); if (!rs.getBOF() && !rs.getEOF()) IDO { set(rs. getShort("iDefaultBandwidth")); catch (DBException oops) I05 Util. debug("DB Exception in Bandwidth:: load: " + oops.getMcssageO); retuM isSet(); o public boolean isSet() return beenset; Bandwidthjava Page 3 of 3 11/05/99 1:32 PM App. 2-10 BDSRank package com.launch.PlaylistGenerator; public class BDSRank short stationlD; byte rank; public BDSRank(short stationlD, byte rank) lo this.stationlD= stationlD; this.rank = rank; public String toString() { return stationlD + ":" + rank; to BDSRank. java Page I of I 11/05/99 1:26 PM App. 2-11 CachedRating package com. launch.PlaylistGenerator; import java.io.*; import java.util.Date; /** * This class is used to model a single rating in the cache. **/
public final class CachedRating implements Serializable lo public int userlD; public int itemlD; public byte rating; public byte type; private Date created = new Date(); /A------.-------------- public CachedRating(int userlD, int itemlD, byte rating, byte type) this. userlD = userlD; i this.itemlD = itemlD; this.rating = rating; this.type = type; public final String toString0 2S { return("user:" + userlD + ", itemlD:" + itemlD + ", rating:" + rating + ", type:" + typeString(type) + ", date:" + created.toString() + Util.newLine); public final static String typeString(byte type) if (type == Constants.lTEM_TYPE_SONG) return "song"; else if (type == Constants. iTEM_TYPE_ALB UM) return "album"; else if(type == Constants.lTEM_TYPE ARTIST) return "artist"; return "unknown" public String hashKeyO return itemlD + ":" + type 45} CachedRatingJava Page I of I 11/05/99 1:35 PM App. 2-12 Clip package com. launch.PlaylistGenerator import java.util.Date; public class Clip { public final static byte TYPE NONE = 0; public final static byte TYPE_NEWS = I public final static byte TYPE AD = 2 public final static byte TYPE_INTERSTITIAI. = 3 to public final static byte TYPE_Tll'= 4 public final static byte TYPE SONG - 5 public final static byte TYPE BROADCAST 5; public int ID; IS public byte type; public int medialD; public Date lastPlayed; public String name, directory, server, filepath; public MediaList media; byte origin; private boolean set= false public Clip(byte type) this.type = type; } media = new MediaList(); {public Clip(int ID, byte type) this(type) this.lD = iD; public Clip(int ID, byte type, int medialD, String name, Date lastPlayed) this(lD, type); this.lD = ID this.medialD = nnedialD; this.name = name } this lastPlayed = lastPlayed; public byte typeO { return type; } public boolean isSet() { return set; } private void setDirectory(String newDir) if (!newDir.equals(" ")) { directory = newDir; public void logPlay(DBConnection cone, int userlD) { String sql = ""; if (type == TYPE_SONG) sq] = "exec sp_lcLogPiaySong_isud " + userlD A- ", " + medialD + ", " + ID + ", " + À50 origm; App. 2-13 else if (type -- TYPE AD) sql = "exec sp IcLogPlayAd_isud " + userlD + ", " + rnedialD + ", " + ID; else if (type == TYPE_NEWS) sql = "exec sp icLogPlayNews isud " + userlD + ", " + medialD + ", " + ID; else if (type == TYPE TIP) sql = "exec sp IcLogPlayTip isud " + userlD + ", " + medialD + ", " + ID; // elseif(type==TYPE BROADCAST) // sql = "exec sp IcLogPlayBroadcast isux " + userlD + ", " + mediaType; try conn.executeUpdate(sql, true); catch (DRException e) { System.err. printin("DBException in Clip:logPlay:" + e.toString()); public boolean getPath(DBConnection cone, ClipSchedule schedule) if(type==TYPE NONE) return false; SimpleClipList list = null; if (type = TYPE_SONG) list = schedule.playlist.songs; elseif(type==TYPE AD) list = schedule.piayiist. ads; else if(type == TYPE TIP) list = schedule.playlist.tips; else if (type == TYPE_NEWS) $5 list = schedule.playlist.news; if(list == null) return false; oo SimpleClip yip = list.pop(); jf (yjp == null) return false; os medialD = yip.medialD; ID =yip.lD; origin = yip.origin; n o try DBResultSet rs = conn.executeSQL("exec sp IcGetMediaPath_xsxx " + medialD); if(!rs. getBOF0&&!rs.getEOF()) fl5 { setDirectory(rs.getString("directory")); server = rs.getString("server"); fi lepath = rs.getString("filepath "); set = true; App. 2-14 catch (DBException e) |25 System.err.printin("DBException in Clip::getPath: " + e.toString()); return set; /* public boolean pop(DBConnection cone, int userlD, int context) set= false; try { DBResultSet rs; String the command; int contextNum = 0; o if (context > I) contextNum = 1; if(type=TYPE BROADCAST) the command="exec " + BROADCAST SP + " " + userlD + ", " + type + ", " + I45 context; else String stored proc = null; if (type=TYPE AD)stored proc=ADS SP; else if (type == TYPE TIP) stored proc = TIPS SP; elseif(type==TYPE NEWS)stored proc=NEWS SP; else stored proc= SONG SP; the command= "exec " + stored proc + " " + userlD + ", " + contextNum; 155} rs = conn.executeSQL(the command); if (!rs.getBOF() && !rs.getEOF()) setDirectory(rs.getString("directory")); server = rs.getString("server"); filepath = rs.getString("filepath"); set = true; 165} catch (DBException e) Systern.err.printin("DBException in Clip::pop " + e.toString()); return isSet(); */ !75 public String path() return server + directory +'t/'l } + filepath; public String toString() App. 2-15 { retum "Clip type (" + typeName() + "), id = " + medialD +", lastPlayed = " + lastPlayed + ", media = " + media.toString() + ", path = " + path(); public PlaylistEntry toPlaylistEntry(short mediaType) PlaylistEntry entry = new PiaylistEntry() entry.medialD= media. getlD(mediaType) entry.titie = name; entry. fi l epath = media. get F i lepath(m ed iaType); retum entry; 20S public SimpleClip toSimpleClip(short mediaType) return new SimpleClip(lD, media.getlD(mediaType)); 2tU public String typeName() switch(type) case TYPE_AD: retum "Ad" case TYPE BROADCAST: retum "Broadcast"; case TYPE INTERSTITIAL: return "Interstitial"; Z20 case TYPE NEWS: return "News"; case TYPE TIP: retum "Tip" case TYPE SONG: 225 return "Song"; retum "?"; ) public String URL() return server 23S + directory + / + filepath; 240} Clipjava Page 5 of 5 11/05t99 1:32 PM App. 2-16 ClipCollection package com.launch.PlaylistGenerator import java.util. Hashtable public class ClipCollection extends Hashtable { public Clip put(int cliplD, Clip aClip) retum (Clip) put(new Integer(cliplD), aClip); public Clip get (int clipID) return (Clip) get(new Integer(cliplD)); 15} ClipCoilection java Page I of I 11/05/99 1:26 PM App. 2-17 ClipSchedule package com. Iaunch.Playl istGenerator; import java.util.Date; import javax.servlet.ServletOutputStream public class ClipSchedule private Date dbDate; private int userlD, lastBroadcast, currentBroadcast o, private boolean set = false; public SimplePlaylist playlist; public ClipSchedule (int userlD) { this.userlD = userlD ) , public void init(DBConnection cone) { set= false; try DBResultSet rs = conn.executeSQL("exec sp IcGetClipSchedule xsxx " + userlD) if(!rs.getBOF() && !rs.getEOF()) dbDate = rs.getThnestamp("dbDate"); lastBroadcast = rs. getint("lastBroadcastlD") o currentBroadcast = rs.getint("broadcastlD") playlist = SimplePiaylist.fromBytes(rs.getBytes("playlist")); else { dbDate = new Date(); 11 the f rst time a playlist is created for a user, the dates will be null if(playlist!=null) if (playlist.]astAd == null) playlist.lastAd = dbDate; if(playlist.lastNews == null) playlist.lastNews = dbDate; if (playlist.lastTip == null) playlist.lastTip = dbDate; set= true; catch (DBException e) { System.err.printin("DBException in ClipSchedule::init:" + e.toString()); private long dateDiff(Date diffMe) if(diffMe -- null) diffMe - new Date(0); App. 2-18 retum (long) ((dbDate.getTime() - diffMe. getTime()) / ( 1000.0 * 60)); public byte nextClipType(boolean debug, ServletOutputStream out) long adDiff, newsDiff, tipDiff; while (true) { adDi ff = dateDiff(piayl ist. IastAd); newsDiff = dateDiff(pl ayl ist. IastNews); tipDiff = dateDiff(playlist.lastTip); if (debug) Util.out(out, "dbDate is " + dbDate toString0); Util.out(out, "lastAdDate is " + playlist.lastAd); BO Util.out(out, "next ad in " + (Constants.AD THRESHOLD - adDiff) + " minutes"); Utii.out(out, "lastNewsDate is " + playlist.lastNews); Util.out(out, "next news clip in " + (Constants. NEWS_THRESHOLD B5newsDiff) + " minutes"); Util.out(out, "lastTipDate is " + playlist.lastTip); Util.out(out, "next tip in " + (Constants.TIP THRESHOLD - tipDiff) + " minutes"); 90} if (playlist == null) System.err. printin(new Date().toString() + " nextClipType: userID " + userTD + " has no/invalid playlist"); return Clip.TYPE NONE; } _ i f (currentBro ad cast > last B roadc ast) co ( if(debug) Util.out(out, "getting broadcast"); last B road cast = currentBroadcast; retum Clip.TYPE BROADCAST; elseif(adDiff≥Constants.AD THRESHOLD) if (debug) Util.out(out, "playing AD"); playlist.lastAd = dbDate; 0 if (playl ist.ads. isEmpty()) System err.printin(new Date().toString() - - " userlD " + userlD + " is out of ads"); else return Clip.TYPE AD; ll5} else if (newsDiff ≥ Constants.NEWS THRESHOLD) if(debug) Util.out(out, "playing NEWS"); playlist.lastNews = dbDate; if (playlist.news.isEmply()) System.err.printin(new Date().toString() + " userlD " -t userlD + " is App. 2-19 out of news"); else I25 return Clip.TYPE NEWS; elseif(tipDiff> =Constants.TIP THRESHOLD) t3 if(debug) Util.out(out, "playing TIP"); playlist.lastTip = dbDate; i f (playl ist.tips. isEmpty()) System.err. printin(new Date().toString() + " userlD " + userlD + " is out of tips"); else return Ciip.TYPE_TIP; else I43 { if(debug) Util.out(out, "playing SONG"); if (playlist.songs.isEmptyO) System.err.printin(new Date(). toString() + " userlD " + userlD + " is out of songs"); return Clip.TYPE NONE; else 1553 return Clip.TYPE SONG; /Ireturn Clip.TYPE_NONE; IS5 3 ClipSchedulejava Page 3 of 3 11/05/99 1:35 PM App. 2-20 Constants package com.launch.PlaylistG enerator; public interface Constants // live /* public final static String DB SOURCE = "LAUNCHcast"; public final static String DB_USERNAME = "dbClient" public final static String DB PASSWORD = "83kareem23" lo public final static String DB_DBNAME = "dbLaunchProd" public final static String DB SERVER = "209.67.158. 19", i/ DB3 public final static short DB_PORT = 1433 public final static String STREAM_URL = "http://lcplaylist.launch. com/servlet/gateway" public final static String STREAM_SERVER = "http://lcstream.launch.com"; 1/ development public final static String DB_SOURCE = "LAUNCHcast"; public final static String DB USERNAME = "dbClient"; public final static String DB PASSWORD = "291diocy99" to public final static String DB DBNAME = "dbLaunehProd" public final static String DB SERVER = "Zeus" public final static short DB PORT = ]433 public final static String STREAM URL = "http://devweb7.1aunch.com/servleVgateway" public final static String STREAM SERVER = "http://devweb7.1aunch.con/F" as public final static int RIAA_MAX SONGS_FROM ALBUM = 2; public finalstaticintRIAA MAX SONGS BY ARTIST =3; public final static int BDS SCORE MAX POINTS = 41 public final static int BDS SCORE_POINTBAR = 20 public final static int DEFAULT LASTPLAYED SCORE = 100; ID public final static int DEFAULT MEDIATYPE = 21 1, // 16 Mono public final static int DEFAULT_UNRATED RATIO= 50; public final static int DEFAULT PICK FACTOR = 7; public final static int DEFAULT BDS SCORE = 0 public final static intMAX_PERCENT RATED SONGS TO PICK =20 public final static int NEW USER UNRATED RATIO 90 public final static int MIN RATINGS TO HONOR RATIO = 100; public final static int MIN SIZE FOR_NO UNRATED = 200; public final static int MAX ORDINAL = 1000 // for calculating implicit based on other song ratings to public final static int MAX SONGS_BY ARTIST = 4 // random picking public final static int RANDOM_SONGS_COUNT = 5000 /I this is a percent of the total number of songs in the database publiefinal static int MIN SONGS_IN GENRES TO GET RANDOM = 5 publiefinal static int MIN RATING FOR_RATED SOURCE =35; // songs with average rating above this are considered popular // also change th is at the top of LA UNCHCast/player/getsongin no public final static int POPULAR THRESHOLD = 58 public final static int DEFAULT RATING = 52, // global average for all songs public final static int DEFAULT DIS SCORE = DEFAULT_RATING public final static int DEFAULT_NETP SCORE = DEFAUI.T_RATING, public final static byte DEFAULT_COMMRATING = DEFAULT RATING public final static int MAX RATINGS TO_GET = 500 public final static int MAX_DJ RATINGS_TO_GET = 500 public final static int ARTIST VARIOUS_ARTISTS = 1028125; public final static int ARTIST ORIGINAL_SOUNDTRACK = 1020156 public final static int ARTIST_SOUND1RACK = 1036715; public final static int DEFAULT_PLAYLIST_SIZE -- 50; public final static int MAX_NEWS_ITEMS - 0; App. 2-21 public final static int MAX ADS = 20 public final static int MAX TIPS ITEMS = 0 public final static int REFRESH_AT SONGS LEFT = 8; public final static intREFRESH_AT NEW RATINGS COUNT = 15; public final static int AD THRESHOLD = 30 public final static int NEWS THRESHOLD = 99999999; public final static int TIP THRESHOLD = 99999999 public final static byte ITEM TYPE SONG = 1 public final static byte ITEM TYPE ALBUM = 2; to public final static byte ITEM TYPE ARTIST = 3 1/ the size of the ratings cache FOR EACH user public final static int RATINGS CACI-lE INITIAL_SIZE = 2000 public final static int RATING UPDATE_LIST INITIAL SIZE = 100 1/ for updating the ratings caches public static final int PROPAGATE DIRTY RATING SLEEP TIME = 60 * 1000, 11 every 60 seconds public static final String POST HEADER = "POST /servlet/playlist HTTP/I.0"; public static final int PORT NUMBER = 80; Constantsjava Page 2 of 2 11/05/99 1:24 PM App. 2-22 DBConnection package com.launch.PlaylistGenerator; import java.util.Properties; import com.inet.tds.TdsDriver; s importjava. sql.SQLException;
import java.sql.Statement;
import java.sql.CoMection import java.sql.Driver; import java.sql. DriverManager o import java.util.Date public class DBConrection private Connection cone; s public static Driver DBDriver; public DBConnectionO throws DBException if(DBConnection.DBDriver== null) DBConnection. initializeDriver(); if(DBConnection.DBDriver == null) return; String url = "jdbc:inetdae:" + Constants.DB SERVER + ":" + Constants.DB_POR T + "9sql7=true&database=" + Constants.DB DBNAME + "&user=" + Constants.DB_USERNAME + "&password=" + Constants.DB_PASSWORD + ""; try o conn = DBConnection.DBDriver. connect(url, null); catch (SQLException oops) throw new DBException(oops); 45} catch (Exception err) Util.debug("Exception. " + err.toStringO); 50} private static void initializeDriver() DBDriver = new com.inet.tds. TdsDriver(); private DB ResultSet execute(String sq l, boolean printSQI.) throws DB Exception so if (printSQL) App. 2-23 Util.debugpJtil.newLine + Thread. currentThreadO.getName() + " Running SQL: " + sq l); DBResultSet myRs = new DBResultSetO; try // if we don't have a query, don't run it. Jt'll hang if (sql.length() ≤ 0) return myRs;
Statement query = conn.createStatement();
if (query.execute(sql)) myRs.setResultSet(querY.getResUltset(!); catch (SQLException oops) System err.printin(lJtil.newLine + (new Date()). toString() + " DBException: " + Thread.currentThread().getName() + " Running SQL: " + sql + ", exception: " + oops.toString()); oops. printStackTraceO; throw new DBException(oops); return myRs public void executeUpdate(String sql, boolean printSQL.) throws DBException tO if (printSQL) Uti l.debug(Uti l. newLine + Thread. currentThread(). getName() + " Running SQL: " + sql) ; try // if we don't have a query, don't run it. It'll hang if (sql length() ≤ 0) retum;
Statement query = conn.createStatement();
q uery. execute Update(sq l) ; catch (SQL Excepti on oops) ]05 // when we call a stored proc that gets a text pointer this happens, // so ignore it if(oops.getMessage().indexOf("Unknown datatype") > -1) // System.err.printin("ignoring unknown datatype exception"); 0 return; System.err.printin(Util.newLine + (new Date()).toString() + " DBException: " + Thread.currentThreadO.getName0 + " Running SQL: " + sql + ", exception: " + oops.toStringO); us oops.printStackTrace(); throw new DBException(oops); I20 public DBResultSet executeSQL(String sql) throws DBException App. 2-24 return execute(sql, true); 325} public DBResultSet executeSQL(String sql, boolean printSQL) throws DBException retum execute(sql, printSQL); |30} public DBPreparedStatement prepareStatement(String sql) throws DBException U5 try return new DBPreparedStatement(conn.prepareStatement(sq 1)); catch (SQLException oops) |40 { System.err.printin(Util.newLine + (new Date()).toStringO + " DBException in prepareStatennent: " + Thread.currentThread().getName() + ", exception: " + oops.toString()) oops.printStackTrace(); throw new DBException(oops); |45} public boolean close() throws DBException { if (cone = null) retum false; try |55 { con n. cl ose(); conn = null; return true; |60 catch (SQLException oops) throw new DBException(oops); t65 public void finalize() throws DBException /1 in case someone forgets close(); ]70} DBConnection java Page 4 of 4 1 1/05/99 1:3 7 PM App. 2-25 so DBException package com. Iaunch.P]ayl istGenerator; import java.sql.SQLException; public class DBException extends Exception s { SQLException Cops; public DBException(SQLException cops) lo this.oops = Cops; public String getMessage() Is return oops. toString(); DBExceptionjava Page I of I 11/05/99 1:26 PM App. 2-26 s!
DBPreparedStatement
package com.launch.PlaylistGenerator;
import java.sqI PreparedStatement;
import java.sql.SQLException; s import java.util.Date;
public class DBPreparedStatement
PreparedStatement statement;
o public DBPreparedStatement(PreparedStatement statement)
this.statement = statement } ,
|5 public void setBytes(int parameterlndex, byte x[]) throws DBException try
if(statement!= null) 2D {
statement.setBytes(parameterlndex, x); } }
catch (SQLException e) Z5 { throw new DBException(e); public void executeUpdate() throws DBException Util.debug(Util.newLine + Thread. currentThread().getName() + " Running prepared statement");
if (statement == null)
return; try
statement.executeUpdate(); 4o
catch (SQLException oops) System.err.printin(Util.newLine + (new Date()). toString() + " DBException: " + Thread.currentThreadO.getName() + " Running Statement, exception: " + oops.toString()); oops.printStackTrace() ; throw new DBException(oops);
SD
DBPreparedStatementjava Page I of I i 1/05/99 1:32 PM App. 2-27 :2 DBResultSet package com.launch.PiaylistGenerator; import java.util.Date; import java.sql.ResultSet; import java.sql.SQLException; import java.sql. Timestamp; import java.io.lnputStream; public class DBResultSet o private ResultSet rs; private boolean atEOF = false; private boolean atBOF = true; public void setResultSet(ResultSet aRS) throws DBException try rs= aRS; if (rs!= null) atBOF= !rs.next(); 20} catch (SQLException oops) throw new DBException(oops); 25} public int getint(String columnName) throws DBException try o retum rs.getint(columnName); catch (SQLException oops) throw new DBException(oops); 35} public int getint(int position) throws DBException try { retum rs.getint(position); catch (SQLException oops) throw new DBException(oops); public InputStream getAsciiStream(String columnName) throws DBException { try retum rs. getAsci i Stream(col umnNam e); catch (SQl,Exception oops) throw new DBException(oops); App. 2- 28 public short getShort(String columnName) throws DBException try t55 return rs.getShort(columnName); catch (SQLException oops) throw new DBException(oops); 70} public boolean getBoolean(String columnName) throws DBException try { return rs.getBoo lean(col umnName); catch (SQLException oops) ao throw new DBException(oops); public byte[] getBytes(String columnName) throws DBException { t{ry return rs. getBytes(columnName); catch (SQLException oops) throw new DBException(oops); } } public float getFloat(String columnName) throws DBException t{ry oo return rs.getFloat(columnName); catch (SQLException oops) throw new DBException(oops); t05} public float getFloat(int position) throws DBException try t10 { return rs.getFloat(position); catch (SQLException oops) U5 throw new DBException(oops); public String getString(String columnName) throws DBException t{ry return rs. getString(col umnNam e); App. 2-29 S4 catch (SQLException oops) 1?5 { throw new DBException(oops); } } public Date getDate(String columnName) throws DBException { try retum rs.getDate(columnNam e); catch (SQl. Exception oops) throw new DBException(oops); public Ti mestamp getTimestamp(String co l umnName) throws DB Exception try return rs. getTinnestamp(co lumnName); 145} catch (SQLException oops) throw now DBException(oops); public boolean getBOF() throws DBException retum atBOF; public boolean getEOF() throws DBException retum atEOF; public void next() throws DBException { try atEOF =!rs.next(); catch (SQLException oops) throw new DBException(oops); } } no public boolean wasNull() throws DBException try retum rs.wasNull(); t75 catch (SQLException oops) throw new DBException(oops); rao} DBResultSetjavaPage 4 of 4 11/05/99 1:32 PM App. 2-30 ss
DJ
package com. Iaunch.Playl istGenerator public class DJ public int userlD; public String alias; {public DJ (int id, String name) this(id); flu alias = name; public DJ (int id) Is userlD = id; DJ Java Page I of I 11/05199 1:26 PM App. 2-3] Dnist package com. Iaunch. PlaylistGenerator; import java.util.Vector; public class DJList extends Vector { public DJ djAt(int i) retum (DJ) elementAt(;); o public String inl.ist() Integer list[1 = new Integer[size()]; int last = 0; for (int i = 0; i < this.size(); i++) o list[i] = new Integer(djAt(i).userlD); retum Utiljoin(", ", list); s public boolean load(DBConnection cone, int userlD, int moodlD) short djCount = 0; try DBResultSet rs = conn.executeSQL("exec sp_lcoGetDJs_xsxx " + userlD + ", " + moodlD); while (!rs.getBOF() && !rs.getEOF()) addElement(new DJ(rs.getint("djlD"))); rs.next(); djCount++; 4S Utii. debug(Thread.currentThread().getName() + " added " + djCount + " DJs"); catch (DBException oops) Util.debug("DB Exception in DlList::load: " + oops.getMessage()); retum (djCount > 0); public Vector aslDVector() Vector users = new Vector(10); for (int i = 0; i < this.size(); i++) App. 2-32 S7 users.addElement(new Integer(((DJ) elementAt(i)).userlD)); 6S return users; DlListjava Page 2 of 2 11/05/99 1:28 PM App. 2-33 FrequencyCounter package com.launch.PlaylistGenerator; import java.util.*; /** * FrequencyCounter is a Hashtable of the form (Object, integer) * <br><br> * okay I realize the getLargest and getSmallestValue * methods are very inefficient (CPU wise) but these methods * aren't called often, if they are then some one should tic * do an nlog(n) sort on thenn then just pick out the largest * after that **/ public class FrequencyCounter extends Hashtable Is public FrequencyCounter() public FrequencyCounter(int i) { super(i); public void incrementValue(Object o) { integer i=(lnteger)get(o); if (i==null) put(o, new Integer(])); else put(o, new Integer((i.intValue())+ l)); public FrequencyCounter getl.argest(int n) FrequencyCounter fc=new FrequencyCounter(n+10); Integer temp int; Object temp object; Object smallest value key=null; int smallest value; Enumeration e=keys(); while (e.hasMoreElements()) { temp object=e.nextElement(); temp int=(lnteger) get(temp object); if (fc.size()≥n) { smallest value key=fc. getSmallestValue(); smallest value=((lnteger)fc.get(smallest_value key)). intValue(); if(temp_int.intValue()>smallest value) 0 fc.remove(smallest value key); App. 2-34 fc.put(temp object, temp ins); else } fc put(temp_object, temp ins); 70return(fc); /** return null if list is emrJty */ public Object getSmailestValue() int smallest value=lnteger.MAX VALUE; Object smallest value key=null; o int temp_int; Object temp object; Enumeration e=keys(); while(e. hasMoreElements()) s temp object=e.nextElement(); temp int=((lnteger) get(temp object)).intValue(); if(temp int<smallest value) { smallest value=temp int; smallest value key=temp object; } return(smallest_value key); //*** *# * **** ** * * ** ****$* ******** * ** * ** ** ** * **$* ** ** * **** * * 11 The following is a test function public static void main(String argv[) os FrequencyCounter fc=new FrequencyCounter(); fc. incrementValue("one "); fc.incrementValue("two"); fc.incrementValue("two"); o fc. incrementValue("three"); fc.incrementValue("three"); fc. incrcmentValue("three"); s fc.incrementValue("four"); fc. incrementValue("four"); fc.incrementValue("four"); fc. incrementValue("four"); System.out.printin(fc); :o System.out.printin("smallest "+ fc.getSmallestValue()); System.out. printin("largest 2" + fc.getLargest(2)); App. 2-35 |25 FrequencyCounterjava Page 3 of 3 l i/05/99 1:28 PM App. 2-36 Gl GeneratorParameters package com. launch. PlaylistGenerator; import javax. servlet.htip.HttpServletRequest public class GeneratorParameters private int userlD, moodlD, djlD private Bandwidth speed; lo private boolean debug, matrix, forceRefresh, dontsa.
private MediaFormat format; private boolean moodlDSet = false private boolean djlDSet = false; private int debugFormat = Util.DISPLAY TEXT; public Bandwidth speed() to return speed; public MediaFormat formatO return format; public int debugFormatO so return debugFormat; public int userlD() return userlD; public int moodlD() do return moodID; public int djlD() if (dJlDSet) return djlD; return userlD: so public boolean debug() return debug; public boolean matrix() rehire matrix; App. 2-37 public boolean forceRefresh() 62 return forceRefresh; public boolean dontsaveO return dontsave; public GeneratorParameters(HttpServletRequest request) debug = (request.getParameter("ralph") != null) matrix = (request. getParameter"matr.x") ,= nullj forceRefresh = (request. getParameter("forceRefresh") != null); dontsave = (request. getParameter("dontsave") != null); String debugFormatString = req uest. getParameter("format") o if (debugFormatString!= null && debugFormatString.equals("html")) debugFormat = Util.DISPLAY HTML; try userlD = Integer.parselnt(request.getParameter("u")), } BS catch (NumberFormatException e) userlD = 0; } try { moodlD = Integer. parselnt(request.getParameter("m")), catch (NumberFormatException e) { moodlD = 0; moodlDSet = false,} moodlDSet = true; try djlD = Integer. parselnt(request.getParameter("d")), } catch NumberFormatException e) { djlD = userlD; djlDSet = false;} djlDSet = true; if (djlD ≤ 0) djlD = userlD; djlDSet = false; oo} speed = new Bandwidth(request. getParameter("b")); format = new MediaFormat(); o GeneratorParametersJava Page20f2 11/05/991:24PM App. 2-38 GenreIndex package com.launch. PlaylistGenerator import java.util.Hashtable; import java.util.Vector; public class Genreladex extends Hashtable public Genreludex(int x, int y) o super(x, y); public void add(short index, Songinfo info) SongList list = get(index); if (list == null) list = new SongListO; put(new Short(index) , list); list.addElement(info); 25} public SongList get(int index) return (Songl,ist) get(new Short((short) index)); 30} public int countinGcareList(GenreList myGenres) int result = 0; SongList list; for (int i = 0; i < myGenres.size(); i++) list = get(myGenres.genreAt(i)); if (list!= null) result += list.size(); return result; /* * * retums a COPY of the list of songs in genres */ public SongList getinGenreList(GenreList myGenres) SongList result = new SongList(); for (int i = 0; i < myGenres.size(); i++) result.addElements(get(myGenres. genreAt(i))); 60} App. 2-39 return result; 64 /** 6S returns a COPY of the list of songs in a genre public SongList getinGenre(int genrelD) SongList list = get(genrelD); SongList result; if (list -- scull) list = new SongList(); result = (SongList) list.cloneO; return result; Genrelndex.java Page20f2 11/05/991:28PM App. 2-40 6s GenreList package cone. Iaunch. PlaylistGenerator import java.util. Hashtable public class GenreList s { private int genres[]; private Hashtable hash; private byte next; public boolean allGenres = true; public GenreList() I5 hash = new Hashtable(I, I); } genres = new int[ | 00]; public int add(short genrelD) { allGenres = false; hash. put(new Sh ort(genrel D), new Boo l ean(true)) genres[next] = genrelD next++; } return genres[next - 1]; public int size() ao { return next; public int genreAt(int pos) { return genres[pos]; public boolean exists(Short gerueID) { if (next == 0) return true; else return hash. containsKey(genrelD); public String toString() { String result = ""; for (int i = 0; i < size(); i++) result = result.concat(genreAt(i) + ", "); return result; 50} App. 2-41 GenreListjava Page 2 of 2 11/05/99 1:26 PM Ann. 2-42 GetAds package com.launch.PlaylistGenerator import java.util. Date; import java.util.Vector public class GetAds extends Thread Vector ads int userlD; short mediaType; public GetAds(Vector ads, in t userlD, short med iaType) this.ads = ads; this.userlD = userlD 3 thismediaType = mediaType; public void runO Date startDate = new Date(); o Thread.currentThread().setName("GetAds"); int rowCount = 0; int count = 0; Clip aClip; int cliplD, medialD Date lastPlayed; String clipName; String sql = new String("exec sp IcGetAds xsxx " + userlD + ,. ..
+ mediaType try DBConnection conn = new DBConnectionO DBResultSet rs = conn.executeSQL(sql) while (!rs.getBOF0 && !rs.getEOF() && count < Constants.MAX ADS) ads.addElement(new Ciip(rs.getint("cliplD"), Clip.TYPE AD, rs.getint("medialD"), rs.getString("clipName"), rs.getDate(" iastPlayed"))); count++; rs.next() rowCount+; conn.close(); catch (DBException oops) Util.debug("DB Exception: " + oops.getMessage()); Util. debug(Thread.currentThreadO.getName() + " added " + count + " ads") À50 IJtil.printElapsedTime(Thread.currentThreadO.getName(), startDatc); App. 2-43 ? } 68 GetAdsJava Page20f2 11/05/991:37PM App,. 2-44 CetBDSStatons package com.launch.PlaylistGenerator; mport java. util.Date; public class GetBDSStations extends Thread { int userlD; int moodlD StationList stations; public GetBDSStations(int userlD, int moodlD, StationList stations) this.userlD = userlD; this.moodlD = moodlD |5 this.stations = stations; public void run() Date startDate = new DateO; o Thread.currentThread O.setName("GetB DSStations "); int rowCount = 0; String sql = "sp IcGetBDSNames xsxx " + userlD + ", " + moodlD; try DBConnection conn = new DBConnection(); DBResultSet rs = conn. executeSQL(sql); while (!rs.getBOF() && !rs.getEOF()) int bdslD = rs. getint("bdslD"); stations.addElement(new Station(bdslD)); rowCount++; rs. next(); o conn.closeO; catch (DBException oops) Util.debug("DB Exception in GetBDSStations: " + oops.getMessage()); Util.debug(Thread. currentThread().getName() + " got " t rowCount + " BDS station subscriptions"); so Uti l.printElapsedTime(Thread.currentThread(). getName(), startDate); GetBDSStationsjava Page I of I I Z/05199 1:38 PM App. 2-45 GetGenres package com. Iaunch. Playl istGenerator; import java. util.Date public class GetGenres extends Thread s { GenreList genres; int dilD; int moodlD; public GetGenres{GenreList genres, int djlD, int moodlD) this.genres -- genres; this.moodlD = moodlD; s this.djlD = djlD; public void run() o Date startDate = new Date(); Thread.currentThread(). setName("GetGenres"); int rowCount = 0; try DBConnection conn = new DBConnection(); DBResultSet rs = conn.executeSQL("exec sp IcGetGenreNamesForUser xsxx " + djlD ", " + moodlD); while (!rs.getBOF() && !rs.getEOF()) as genres. add((short) rs.getint("genrel D")); rowCount++; rs.nextO; conn.close(); catch (DBException oops) Util.debug("DB Exception: " i- oops.getMessage()) ; 45} Util.debug(Thread.currentfhread().getName() + " added " + rowCount + " genres"); Util.printElapsedTime(Thread.currentThread().getName(), startDate); 50} GetGenresJava Yage I of I 11/05/99 1:38 PM App. 2-46 GetItemRatingsFromDB package com.launch.PlaylistGenerator importjava.util. * public final class GetitemRatingsFromDB extends Thread { private Vector userlDs; private Vector results; /1. . ... . ....
public GetitemRatingsFromDB(Vector userlDs, Vector results) o ( this. userlDs = userlDs this.results = results; i public void run() |5 { Thread. currentThread().setName("GetitemRatings FromDB ") Util.debug(Thread.currentThread().getNameO + " thread started"); Date startDate = new Date() ; try String sql = "SELECT iUserlD FK userlD, iSourceTablelD L type, iltemlD FK itemlD, tiRating rating FROM al251temRating WHERF, iUserlD FK 111 (" + RatingsCache. GetVectorAsCommaDelimitedList(userlDs) + ')'; DBConnection conn = new DBConnection() DBResultSet rs = connexeculesQL(sql); CachedRating cr; byte type; while (!rs.getBOF0 && !rs.getEOFO) cr = new CachedRating(rs.getint("userlD"), rs. getint("itemlD"), (byte) rs. getin t( " rat ing "), so urceTab le lDToType(rs. getint( " type "))) ; results.addElement(cr); rs.nextO; conn. close() 3 ' catch (DBException oops) 43 { System.err.printin("DBException in GetitemRatingsFromDB: " + oops.getMessageO); Util. printElapsedTime(Thread.currentThread().getNameO, startDate); 45} public final static byte sourceTablelDToType (int type) if (type == 260) return Constants.lTEM TYPE ARTIST; /1 assume album (243) return Constants.lTEM TYPE_ALBUM; GetitemRatingsFromDB j ava Page 2 of 2 1 1/05/99] :32 PM App. 2-47 GetLastPlayed 72 package com.launch.P1aylistGenerator import java.util. Date; import java.text.DateFormat; import javax.servlet. ServletOutputStream public class GetLastPlayed extends Thread PlayDates lastPlayed; int userlD; ro ServletOutputStream out; public GetLastPlayed(PlayDates lastPlayed, int userlD, ServietOutputStreAm out) thislasiplayed = iastPlayed; this.userlD = userlD; this.out = out; public void run() Date startDate = new Date(); Th read. currentTh read O. setNarn e(" GetLastP layed "); //returns. songlD, lastPlayed try DBCoMection conn = new DBCoMection(); startDate); Util.printElapsedTime(Thread.currentThread().getilame() + " got a dbCoMection", lastPlayed.load(coM, userlD); Util printElapsedTime(Thread.currentThread() getName() + " loaded dates", startDate) // ths s somewhat expensve, so only do it every so often if(Util. random(10)== 1) Util.debug("resaving lastPlayed for user " + userlD) lastPlayed.save(conn); 40} COM.C]OSeO; catch (DBException oops) { Util. debug("DB Exception: " + oops.getMessage()); Uti l. out(out, Thread. currentThread().getName() + " loaded " + lastPlayed. size() + " dates") Util.prlntElapsedTime(Thread.currentThreadO.getName() + "done GetLastPlayed", startDate); GetLastPlayedjava Page 2 of 2 11/05/99 1:35 PM App. 2-48 GetNews package com.launch.PlaylistGenerator; import java. util.Date; import java.util.Vector; s public class GetNews extends Thread Vector news; int userlD; short mediaType; o int moodlD; public GetNews(Vector news, int userlD, short mediaType, int moodlD) this.news = news; s this.userlD = userlD; this.mediaType = mediaType; this.moodlD = moodlD; public void run() { Date startDate = new Date(); Thread. currentThread().setName("GetNews "); int rowCount = 0; int count = 0; Clip aClip; int cliplD, medialD; Date lastPiayed; String clipName; /* sp IcGetNews xsxx userlD int, moodlD int, mediaType int returns cliplD, clipName, medialD, lastPiayed */ String sqi = new String("exec sp_lcGetNews_xsxx " + userlD +,.
+ moodlD + ,.
+ mediaType ); try DBConnection conn = new DBConnection(); DBResultSet rs = conn.executeSQL(sql); while(!rs.getBOF() && !rs.getEOF() && count < Constants.MAX NWS_ITEMS) news.addElement(new Clip(rs.getint("cliplD"), Clip.TYPE_NEWS, rs.getint("mediaID "), rs.getString("clipName"), rs. getDate("lastPlayed"))); count+; rs.next(); rowCount++; 60} App. 2-49 conn.close(); catch (DBException Cops) { Util.debug("DB Exception: " + oops.getMessage()); Util.debug(Thread.currentThreadO.getName() + " added " + count + " news items"); Util.printElapsedTime(Thread.currentThread(). getName()'startDate); GetNewsjava Page 2 of 2 1 1/05/99 i:38 PM App. 2-50 GetPlaylist package com. Iaunch. Playl istGenerator; import java.util. Date; public class GetPlaylist extends Thread { Population songs; int useriD; SonginfoCache cache; o public GetPlaylist(Population songs, int useril), SonginfoCache cache) this.songs = songs; this.userlD = userlD; this.cache = cache; i5} public void runO Date startDate = new DateO; Thread.currentThreadO.setName("GetPlaylist") Songinfo info = null; SimpleClip clip; int songlD; int rowCount = 0; tiry DBConnection conn = new DBCoMeclion() startDate); Util.printElapsedTime(Thread.currentThread() .getName() + " got a dbConnection", SimplePlaylist playlist = SimplePlaylist.load(coM, userlD) if (piaylist!= null) for (int i = 0; i < playlist.songs.size(); i++) { clip = (SimpleClip) playlist.songs. elementAt(i); songlD = ciip.lD; songs. initSong(songlD, Song. EXCLUDED); info = (Songinfo) cache.get(songlD, SonginfoCache.TYPE SONG); songs. artistCounts.increment(info.album.artist.lD); songs.albumCounts. increment(info.album. ID); rowCount++; } } COM.closeO; So} catch (DBException oops) Util.debug("DB Exception: " + oops.getMessage()); Util. debug(Thread.currentThread().getName() + " excluded " + rowCount + " songs") Util.printElapsedTime(Thread.currentThread().getName(), startDate) ; o GetPlaylist java Page 2 of 2 11/05/991:34 PM App. 2-51 GetPlaylistServers package com.launch.PlaylistGenerator import java.util. *; /** *$/ public final class GetP1aylistServers extends Thread public static int SLEEP TIME = (3600*1000)- // every hour public static int EXPECTED SERVER_COUNT = 10 o private Ge,PlaylistServersinterface personToNotify; /1 - - -- - - - - /** param personToNoti must not be null. **/
s publ ic GetP layl istServers(GetPlayl istSetvers Interface personToNotify) this.personToNotify=personToNotify; public void run() { Thread.currentThreadO.setName("getPlaylistServers") Util.debug(Thread. currentThread().getName() + " thread started"); DBConnection cone; DBResultSet rs; Vector v; Date benchmark_date try while (personToNotify!=null) oo { benchmark date=new Date(); v=new Vector(EXPECTED_SERVER_COUN? ); conn = new DBConnection(); rs=conn. executeSQL("execsp IcGetRatingsCacheServers xsxd"); while (!rs.getBOF() && !rs.getEOF()) v.addElement(rs.getString("server")); rs.nextO; conn. close(); personToNotify. updatePlaylistServers(v); Util. printElapsedTime(Thread.currentThread().getNameO + ". get " + v.sze() + " rows", benchmark date); Thread.sleep(SLEEP TIME); catch (Exception e) System.err.printin(new Date().toString() + " Fatal Exception in so CetPlaylistServers:" + e.toString()); Util.debug(Thread.currentThread() .getName() " thread done"); GetPlaylistServersjava Page 2 of 2 11/05/99 1:37 PM App. 2-52 GetPlaylistServersInterface package com. launch. PlaylistGenerator Import java.util. * pub I ic interface GetPlayl istServers I nterface /** * param playlistServers will be a vector of strings, each string is an ip address of the form A/ lo public void updatePiaylistServers(Vector playlistServers); GetPlaylistServersinterface.Java Page I of 1 1]105/99 1:28 PM App. 2-53 GetPopular package com.launch.PlaylistGenerator; import jaYa.util.Date; public class GetPopular extends Thread { Population songs SongList list; public GetPopular(Population songs, SongList list) lo { this.songs = songs; this.list = list public void runO { Date startDate = new Datc(); Thread.currentThreadO.setName("GetPopular"); Song ditty; SongData data; Songinfo info; int rowCount = 0; if (list!= null) { for (int i = 0; i < list.size(); i++) info= list.elementAt(i); data = songs. getSongData(info.songlD); if (data!= null) // we can't add it, but let's append the info while we're here data. setinfo(info); else data = songs. initSongGetData(info.songlD, Song. UNRATED); if(data!= null) data.querySource = data. SOURCE POPULAR; data. setinfo(info); rowCount++; 50} lJtil.debug(Thread.currentThread(). getName() + " added " + rowCount + " songs") Vtil.printElapsedTime(Thread. currentThreadO.getName(), startDate); 55} GetPopuiarjava Page 2 of 2 11/05/99 1:38 PM App. 2-54 GetRatings package com.launch.P] aylistGenerator; import java.util.Date; import java.util.Vector; importjava.util.Enumeration; import javax.servlet. ServletOutputStream; public class GetRatings extends Thread ItemsProfile profile; o int uscrlD; DJList djs; Population songs; SonginfoCache cache; ServletOutputStream out; public GetRatings(Population songs, ItemsProfile profile, int userlD, DJList djs, SonginfoCache cache, ServletOutputStream out) this.profile = profile; o this.userlD = userlD; this.djs = djs; this.cache = cache; this. songs = songs; s public void run() Date startDate= new Date(); Thread. currentThreadO.setName("GetRatings"); o int rowCount= 0; 11 make a users vector from the users and djs Vector users = djs. aslDVector(); users. ad dE l ement(new In tege r(userl D)); Util.out(out, "GetRatings getting ratings for users " 4- users.toString()); Vector ratings = cache.ratingsCache.getRatings(users); o Util. printElapsedTime("GetRatings after all ratings retreived", startDate); CachedRating cached; int djlD, itemlD; byte rating, type; SongData data; short songType = Song. EXPLICIT; Songinfo info; int artistlD; Item theJtem; int songRatings = 0; int itemRatings = 0; int userSongRatings = 0; int useritemRatings = 0; int djSongRatings = 0; int djitemRatings = 0; for (Enumeration e = ratings.eiements(); e.hasMoreElements() ;) { App. 255 cached = (CachedRating) e.nextElement(); djlD = cached.userlD; itemlD = cached.itemlD; rating = cached.rating; type = cached.type; /10 is not a valid userld /I ratings < 0 mean it was unrated if (djlD!= 0 11 rating < 0) { if(type==Constants.lTEM TYPE SONG) songRatings++; 11 store the user's rating if (userlD == djlD) to userSongRatings++; if (rating == 0) songs.initSong(itemlD, Song. EXCLUDED) as info = (Songinfo) cache.get(itemlD SonginfoCache.TYPE SONG); addToAverage(info, 0); else { data = songs.initSongGetData(itemlD, songType); if(data!= null) info = (Songinfo) cache.get(itemlD, SonginfoCache.TYPE SONG); /1 if the song isn't in the cache, it's not loo encoded // and we can't play it if(info == null) songs. in itSong(itemlD Song. EXCLUDED); else data. sets n fo( info); u o data.querySource= SongData. SOURCE RATED; data.rating.set(rating SongRating.RATING SOURCE EXPLICIT); // add this rating to all ratings by this user for the artist addToAverage(info, rating); } } 120} else // this is another user's song rating App. 2-56 djSongRatings++; data = songs.initSongGetData(itemlD, Song.UNRATED); if(data!=null) |30 { data.querySource = SongData. SOURCE_DJS; data. dj sA vera ge. add (rat i n g) ; I3S} 1/ don't count various artists ratings o elseif(!(type==Constants.lTEM TYPE ARTIST&& Artstinfo.'sVariousArtists(itemlD))) itemRatings++; theltem = profile.put(itemlD); if(djlD == userlD) useritemRatings++; theltem. userRating.set(rating); else I55 djitemRatings++; theltem.djsAverage. add(rating); rowCount++; Uti1.out(out, Thread.currentThread().getName() + " added " I65 + songRatings + " song ratings (" + userSongRatings + " user, " + djSongRatings + " dj) " + "and " + itemRatings + " item ratings (" + useritemRatings + " user, " + djitemRatings + " dj)" Util.printElapsedTime(Thread.currentThread(). getName(), startDate); I75 private void addToAverage(Songinfo info, int rating) if(info!=nuil) (profile.put(info.album.artist.1D)).songAverage.add(rating); I80 private String userCriteria() App. 2-57 82 if (djs.size() ≤ 0) return " = " + userlD; return "IN (" + userlD + ", " + djs.inList() + ")"; } } GetRatingsjava Page 4 of 4 1 1/05/99 1:35 PM App. 258 GetRatingsCacheUsers package com.launch.PlaylistGenerator; import java. util.*; import java.net. *; s /** **l public final class GetRatingsCacheUsers extends Thread private static int SLEEP TIME = (10 * 60 * 000); 11 update every 10 minutes o prvate static int EXPECTED_TOP_USER SIZE = 100 private GetRatingsCacheUsersinterface personToNotify, pnvate static final int UPDATE_DB CACHED_USERS_SLEEP C0hNT = 6 8; /I three times every day (k*8*SLEF;P TIME // . t5 /* * * param personToNotif,v must not be null. **l
public GetRatingsCacheUsers(GetRatingsCacheUsersinterface personToNotify) o this.personToNotify = personToNotify; public void run() Thread. currentThreadO.setName("GetRatingsCacheUsers") Util.debug(Thread. currentThreadO.getName() + " thread started"); DBConnection cone; String mylP; DBResultSet rs; Vector v; o Date benchmark date; try mylP = InetAddress.getLocalHost().getHostAddress(); int update_db users_list = UPDATE_DB_CAC! IED_U S ERS_S LEEP_CO UNT; while (personToNotify!= null) benchmark date = new Date() v = new Vector(EXPECTED_TOP_USER SIZE); o cone= new DBConnection(); rs = conn.executeSQL("exec sp IcGetUsersToCache isxd "'+ mylP + while (!rs.getBOF() && !rs.getEOFO) v. addElement(new Integer(rs.getint("userlD"))); rs.next(); personToNotif>. updateCachedUsers(v) Util.printElapsedTime(Thread.currentThread(). getName() + ", get " + v.stze() + " rows", benchmark date); Thread. sleep(SLEEP_TIME); /A- f (update db_users_list c= o // do the update Util.debug(new Date().toStringO + " Updating RatmgsCacheVserList"); try App. 2-59
Hashtable h =
personToNotify.getMostFrequentlyUsedUsers(EXPECTED TOP USER_S1ZE); if (h!= null && h.size() > 0) String the command = "exec sp IcDeleteRatingsCacheUsers_xxxd"; conn.executeSQr (the_commar.d'; ?0 Enumeration e = h.keys(); while (e.hasMoreElements()) the command="exec sp IcAddRatingsCacheUser lxxx " + e.nextElement(); ?5 coM.executeSQL(the command); conn.cioseO; ID} catch (DBException dbe) System.err.printin(new Date().toString() + " DBException in GetRatingsCacheUsers: " + dbe.toString()); dbe.printStackTrace(); update_db_users_list = UPDATE DB CACHED_USERS SLEEP_COUNT; 90} else Util. debug("update_db users_list is " + update_db users_list); update_db_users list--; 95} COM.closeO; IDD} catch (Exception e) System.err.printin(new Date().toString() + " Fatal Exception in GetRatingsCacheUsers: " + e. getMessage()); e.printStackTrace(); Util.debug(Thread.currentThread(). getName() a- " thread done"); uo GetRatingsCacheUsersjava Page 2 of 3 11/05/99 1:23 PM App. 2-60 GetRatingsCacheUsersInterface package com. launch.PlaylistGenerator import java.util.; publ ic interface GetR atingsCacheUsers I nterface { /** * (param topUsers will be a vector of Integers, where each integer is a userlD public void updateCachedUsers(Vector topUsers); /#.
* This method will return a hash of (Integer USERID, Intger Requests) @,param i is the number of users to get @,return null if no statistics public Hashtable getMostFrequentlyUsedUsers(int i); GetRatingsCacheUsersinterfacejava Page I of I 11/05/99 1:28 PM App. 2-61 GetRecentlyPlayed package com.launch. PlaylistGenerator import java.util.Date; public class GetRecentlyPlayed extends Thread { Population songs; int userlD; public GetRecentlyPiayed(Population songs, int userlD) o { this.songs = songs; this.userlD= userlD; public void run() s { Date startDate = new DateO; Thread.currentThread O.setName( "GetRecentlyPlayed"); int rowCount = 0; String sql = new String("exec sp_lcGetRecentlyPlayedSongs_xsxx " ± userlD); int songlD, albumlD, artistlD; try DBConnection conn = new DBCoMection0 DBResultSet rs -conn.executeSQL(sql); ac while(!rs.getBOF() && !rs.getEOF()) // returns songlD, albumlD, artistlD, lastPlayed albumlD = rs. getint("albumlD"); songlD = rs.getint("songlD"); artistlD = rs. getint("artistlD"); // don't play these songs so soon again 4 0 S O n g s. i n i t S o n g ( s o n g I D, S o n g. E X C L U D E D) ; songs.artistCounts.increment(artistlD); songs.albumCounts. increment(albumlD); rs.nextO; rowCount++; con n. cl os e() ; catch (DBException oops) Util.debug("DBException: " + oops.getMessage()); Util. debug(Thread.currentThread().getName() + " added " + rowCount + " songs") Uti i. printElapsedTime(Thread.currentThread().getName(), startDate); App. 2-62 3 87 GetRecentlyPlayed Java Page 2 of 2 1 1/05/99 1:26 PM App. 2-63 GetSongInfoServlet package com.launch.PlaylistGenerator; import java. util. *; import java.io.*; import java.net. *; import javax.servlet.*; import javax.servlet.http. *; o * * GetSonglnfoServlet * author Jeff Boulter */ public class GetSonginfoServlet extends HttpServlet public static final byte 0NLINE_TIMEOUT = 10; 1/ /** zo * Handle requests */ publ ic void doGet ( HttpServletRequest request HttpServletResponse response 25) throws ServletException, lOException String userlD; String volume; String dj I D; o String djName; String djPosessive; String songName = ""; String albumName = "" String artistName = ""; int songlD = 0; int album ID = 0 int artistlD = 0; int commRating = 0 Date dateAdded = new Date(); o byte origin = 0; int medialD = 0; int year = 0; int songRating = -1; int albumRating = -1 int artistRating= -i; 11 get stream for output ServletOutputStream out; response. setContentType("text/htm I "); out = response.getOutputStream(); response. setHeader("Pragma", "no-cache") response.setHeader("Cache-control", "no- cache"); response.setHeader("Expires", "O") try userlD = request. getParameter("rater") if(userlD == null) out.printin("no userlD passed"); return; 3 App. 2-64 DBConnection conn = new DBConnection(); dj ID = request. getParameter("dj I D"); djName = request.getParameter("djName"); if (djlD == null il djl D.equals(userlD)) { djName= "You"; djPosessive = "Your"; else o ( djPosessive = djName + "'s"; DBResultSet rs = conn. executeSQL("cxec sp_lcGetPlayinginfoForUser xsxx " + userlD); while (!rs. getBOF() && !rs.getEOF()) songName = rs.getString("song"); albumName = rs. getString("album"); artistName = rs.getString("artist"); so songlD = rs. getint("songlD"); albumlD = rs.getl nt("albuml D"); artistlD = rs. getint("artistlD"); commRating = rs.getint("comm Rati ng"); if (commRating ≤ 0) { commRating = - I;} origin = (byte) rs.getint("origin") ; medialD = rs.getint("medialD"); year = rs.getint("year"); dateAdded = rs.getTirnestamp("dateAdded"); songRating = rs.getint("songRating"); albumRating = rs.getint("albumRating"); artistRating= rs. getint("artistRating"); rs.next(); int exclusive = isExclusive(albumName); int newStatus = isNew(dateAdded); int popular = isPopular(commRating); String djs = ""; if(origin == SongData.SOURCE_DJS ALBUM) 00 djs = djRatings(conn, userlD, albumlD, Constants.lTEM_TYPE_ALBUM); else if(origin == SongData.SOURCE_DJS ARTIST) djs = djRatings(conn, userlD, artistlD, Constants.lTEM_TYPE ARTIST); s else djs = djRatings(conn, userlD, songlD, Constants.lTEM_TYPE_SONG); out.print( u o "media_id=" + medialD + "&" + "song_id=" + songlD + "&" + "song_name=" + escape(songName) + "&" + "album id=" + albumlD + "&" + "album name=" + escape(albumName + s formatAlbumYear(year)) + "&" + "artist id=" + artistlD + "&" + "artist name=" + escape(artistName) + "&" + "exclusive=" + exclusive + "&" + "comm rating=" + commRating + "&" + "new=" + newStatus + "&" + "origin=" + escape(SongData.originText(origin, djName, djPosessive)) r"&" App. 2-65 + "popular=" + popular + "&" + "song_rating=" + songRating + "&" + "song rating type=I" + "&" + "album_rating=" + albumRating + "&" +"album rating_type=l"+"&" -t "artist_rating=" + artistRating + "&" +"artist_rating type=)" + djs + fans(conn, songlD) + radioStations(conn, userlD, songlD) 1 "&ticker_text=&image url=" // not used 135); volume = request. getParameter("volume"); saveVolume(conn, userlD, volume) co nn. clos e() ; 140} catch (DBException e) System.err.printin("DBException " + e. getMessage()); e.printStackTrace(); 3 catch (Exception e) out. printin("Exception raised: " + e); e.printStackTrace(); 150} out,close(); private void savcVolume(DBConnection cone, String userlD, String volumeStr) throws DBException I55 { if (volumeStr == null) return; double volume = 0; try { Double dblVolume = new Double(volumeStr) if (dblVotume!= null) volume = dblVolume.doubleValue0; catch (Exception e) return; if (volume > 0 && volume ≤ 100) { conn.executeSQL("exec sp IcSetVolume isux " + userlD 1'', " 1 volume); private String djRatings(DBConnection cone, String userlD, int itemlD, String storedProc, String ,s variableName) throws DBException String result= ""; String djName; String ratingStr; so int rating; int count= I; DBResultSet rs = conn. executeSQL("exec " + storedProc + " " + userlD + ", " + itemlD); while (!rs.getBOF() && !rs.getEOF()) App. 2-66 ]85 rating = rs.getint("rating"); if (rating ≤ 0) ratingStr= "X"; else ratingStr= "" + rating; result = result.concat( I95 "&" + variableName + "_namc" + count + "=" + escape(rs.getString("a I ias ")) + "&" + variableName -t " id" + count + "=" + rs.getint("userlD") + "&" + variableName + " vatue + count + '='+ ratingStr + "&" + variableName " online" + count + "=" + isOnline(rs. getint("minutesSincePlay")) ); count++; rs.next(); retum result; private String djRatings(DBComection cone, String userlD, int itemlD, byte itemType) throws 210 DBException if (itemType == Constants.lTEM TYPE_SONG) retum djRatings(conn, userlD, itemlD "Sp IcGetUserDJRatingsForSonglD_xsxx", "dj rating"); else if (itemType == Constants.lTEM_TYPE_ALBUM) return djRatings(conn userlD, itemlD 220 "Sp IcGetUserDJRatingsForAlbumlD_xsxx", "dj_rating"j; elseif(itemType==Constants.lTEM TYPE_ARTIST) retum djRatings(conn, userlD, itemlD 225 "Sp IcGetUserDJRatingsForArtistlD xsxx","dj rating"); retum ""; private String radioStations(DBConnection cone, String userlD, int songlD) throws DBException int count = 0; String result= ""; 235 DBResultSet rs = conn.executeSQL("exec sp IcGetSubscribedBDSStationsPlayingSong xsxx " + userlD + ", " + songlD); while (!rs.getBOF() && !rs.getEOF()) result = result.concat( 2dO "&radio_id" + count + "=" + rs.getint("bdsStationlD") + "&radio_name" + count + "=" + escape(rs.getString("callLehers") + "
" + rs.getString("description")) );
count++; 2dS rs.next(); App. 2-67 retum result; 92 private String fans(DBConnection cone, int songlD) throws DBException 250 { String result = ""; int count = 1; int rating; String ratingStr = ""; 255 DBResultSet rs = conn.executeSQL("exec sp IcGetFans_xsxx " + songlD); while (!rs.getBOF() && !rs.getEOF() && count ≤ 5) result = resuit.concat( "&fan_name" + count + "=" + escape(rs.getString("alias")) 260 i- "&fan_ id " + count + "=" + rs. getint("userID ") + "&fan_onihe" + count- "=" isOnline(rs.getlut("minutesSincePiay")) ); count++; 265 rs.next(); if(count> I &&!rs.getEOF()) result = result. concat("&fan_id" + count + "=0" + "&fan name" + count + 270 "=more "); retum result; 275 private String formatAlbumYear(int year) jf (year > 0) retum " (" + year + ")"; 280} retum " "; private int isExclusive(String albumName) 2BS if(albumName!= null) if (albumName.indexOf("Launch Live") > -1) retum 1; retum 0; private int isOnline (int lastPlay) 295 { if (ONLINE_TIMEOUT > lastPlay) retum 1; 30'3 retum 0; private int isPopular (int commRating) if (commRating > Constants.POPULAR_THRESHOLD) return 1; retum 0; App. 2-68 } 93 330 private int isNew (Date dateAdded) if (dateAdded == null) return 0; 315} long twoWeeks = Util.MILLISECONDS_IN SECOND * Util.SECONDS_IN MINUTE * Util.MINUTES_IN_HOUR * Util.HOURS_lN_DAY zo id; Date now = new Dale(); if (now.gctTime() - dateAdded.getl ime() twoWeeks) return 1; 3Z5} return 0; private String escape(String thing) 330 if (thing == null) return ""; return URLEncoder.encode(thing); public void inn' (ServletConfig config) throws ServletException super. init(config); 340} public void destroy() 345 /* eof *1 GetSonginfoServletjava Page 8 of 8 11/05/991:38 PM App. 269 GetSongRatingsFromDB package com.launch.PlaylistGenerator; import java. util.*; public final class GetSongRatingsFromDB extends Thread private Vector userlDs; private Vector results; y, . public GetSongRatingsFromDB(Veclor userlDs, Vector results) o this.userlDs= userlDs; this.results = results; public void run() |5 { Thread. currentThread().setName("GetSongRatingsFromDB"); Util.debug(Thread. currentThread().getName() + " thread started"); Date startDate = new Date(); try String sql = "SELECT iUserlD FK userlD, iSonglD_FK songlD, iRating rating FROM a200SongRating WHERE iUserlD FK IN (" + RatingsCache. GetVectorAsCommaDelimitedList(userlDs) + )'; DBConnection conn = new DBConnection(); DBResultSet rs = conn.executeSQL(sql); CachedRating cr; while (!rs.getBOF() && !rs.getEOF()) cr = new CachedRating(rs. getint("userlD"), rs.getint("songlD"), (byte)rs.getint("rating"), Constants.lTEM TYPE_SONG); resu lts. ad d E l em ent(cr) ; rs.next(); 3S conn.close(); catch (DBException oops) System.err.printin("DBException in GetSongRatingsFromDB: " + oops.getMessage()); Uti i.p rintElapsedTime(Th read. curren tThread () . getName(), startD ate); s GetSongRatingsFromDBjava Page i of I 11/05/991:32 PM App. 2-70 IntHash package com. Iaunch. PlaylistGenerator inoport java.util.Hashtable /** , * A hashtable that uses ints as keys and values. */
* public class IntHash extends Hashtable public synchronized int get(int key) o { Ol>ject thing = gct(new Integer(key)); if (thing a= null) return O; I5 else return ((Integer) thing).intValue(); public synchronized int put(int key, int value) put(new Integer(key), new lnteger(value)); return value private synchronized int change(int key, int valueChange) return put(key, get(key) + valueChange); public synchronized int increment(int key) return change(key, 1); public synchronized int decrement(int key) } return change(key, - ] ); public synchronized int increment(int key, int howMuch) o return change(key, howMuch); public synchronized int decrement(int key, int howMuch) return change(key, -howMuch); 5} IntHashjava Page I of I I]/OS/99 1:26 PM App. 2-71 Item package com. launch.PlaylistCenerstor public class Item s public final static byte TYPE ANY = 0 public final static byte TYPE ALBUM 1 public final static byte TYPE ARTIST = 2 public final static byte TYPE UNKNOWN - 10 to public int itemlD public Rating userRating; private boolean songAvgScoreCalculated = false; Is private double songAvgScore; // the average rating fronn all djs for this tiem public AverageRating djsAverage; // average rating of all songs by an artist public AverageRating songAverage; public double songAverageScore(Artistinfo info) 2S if (!songAvgScoreCalculated) songAvgScoreCalculated = true; so double songsByArtist Math.min(info.songs.size(), Constants.MAX SONGS BY ARTIST) ; double songsRated = Math.m in(songA verage. count() Constants.MAX SONGS BY ARTIST); // deviation from the average songAvgScore = ((songAverage.getO Constants.DEFAULT RATING) * (songsRated / songsByArtist)) + Constants.DEFAULT RATING; return songAvgScore; public boolean inGenres = false; public byte getType() if (itemlD == 0) return TYPE UNKNOWN else if (itemlD < 1000000) so return TYPE ALBUM else return TYPE ARTIST; ss public String typeName() byte type = getType(); if (type == TYPE_AI-BUM) return "Album"; App. 2-72 else if (type = TYPE_ARTIST) return "Artist"; else return "Unknown"; public Item() o userRating = new Rating(); djsAverage = new AverageRating(); songAverage= new AverageRating(); s public Item(int itemlD) this(); this. itemlD= itemlD; public String toString(SonginfoCache cache) String title = "(Not available)"; byte type = getType(); if (type == TYPE_ARTIST) so Artistinfo artist = (Artistinfo) cache.get(itemlD, SonginfoCache. TYPE_ARTIST); if (artist!= null) title = artist.title; ff else if (type == TYPE_ALBUM) Albuminfo album = (A lbum info) cache.get(itemlD, SonginfoCache.TY PE ALBUM); if(album!= null) 0O title = album.title; return typeName() + " V"' + title + "\" (" + itemlD + ") " + "user=" + userRating.toString() + " djs=" + djsAverage.toString() + " songAverage=" + songAverage.toString() + " songAvgScore=" + songAvgScore; o Item java Page 2 of 2 1 1/05/99 1:24 PM App. 2-73 ItemsProfile package com.launch.PlaylistGenerator; import java.util.Hashtable; import java.util.Enumeration import javax.servlet. ServletOutputStream public class ItemsProfile private Hashtable hash Jo, public ItemsProfile() } hash = new Hashtable(); public synchronized Item get(int itemlD) } return get(new Integer(itemlD)); public synchronized Item get(lateger itemlD) } return (Item) hashget(itemlD); /** * puts a new item in the hash and returns it.
* If it's already there, just return it public synchronized Item put(int itemlD) Integer ID = new Integer(itemlD); Item it = get(lD); if (it == null) it = new Item(itemlD); hash.put(lD, it); return it; else return it; public void print(ServletOutputStream out, SonginfoCache cache) for (Enumeration e = hash.keys(); e.hasMoreElementsO;) { Item an item = get((loteger) e. n extElementO) ; Util.out(out, anitem.toString(cache)); public String inList(byte type) String list= ""; for (Enumeration e = hash.keys(); e.hasMoreElements() ;) App. 2-74 Item an]tem = get((lnteger) e.nextElement()); if (type == Item.TYPE_ANY 1l anitem.getTypeO == type)list = list.concat(anitem.itemlD ","); 1/ remove that extra comma if (list.length() > 0) list = list.substring(O, list length() - i); return list; 75) ItemsProfilejava Page 2 of 2 11/05/99 1:32 PM App. 2-75 Media package com. I aunch. P lay l istG en erator; public class Media int medialD; short mediaType; String filepath; public Media(int medialD, short mediaType, String filepath) o { this. medialD = medialD; this mediaType = mediaType; this.filepath - filepath; public String toString() retun1 mediaType + ": " + medialD; n public static short getMediaType(Bandwidth speed, MediaFommat format) if (form at.get() == Med iaFormat. WINDOWSMEDI A) if (speed.get() == Bandwidth. SPEED_28) retum 21 1; elseif(speed.get()==Bandwidth.SPEED 56) return 147; else if(speed.get() ≥ Bandwidth.SPEED 100) retum 212; else retum 0; return 0; 35} public static Bandwidth typeToBandwidth(short mediaType) if(mediaType == 211) retum new Bandwidth(Bandwidth.SPEED_28); else if(mediaType== 147) return new Bandwidth(Bandwidth.SPEED_56); else if (mediaType == 212) return new Bandwidth(Bandwidth.SPEED_100); return new Bandwidth(); Mediajava Page] of I 11/05/991:28 PM App. 2-76 10] MediaE7ormat package com. launch. PlaylistGenerator; public class MediaFormat public final static byte WINDOWSMEDIA = 1; public final static byte REALMEDIA = 2 public final static byte QUICKTIME = 3; private boolean beenset = false; !O private byte value; 11 when we start supporting more than one format, just take this out public MediaFormat() { value = WINDOWSMEDIA; beenset = true; zo public MediaFormat(byte format) value= format; beenset = true; Z5 public byte getO return value public void set(byte format) if.
value = fomnat; beenset = true; 35} public boolean isSet() return beenset; 40} public String toString() if(value == WINDOWSMEDIA) retum"WindowsMedia"; else if(value = REALMED1A) return "RealMedia"; else if(value == QUICKTIME) return "QuickTime"; return "UNKNOWN"; MediaFormatJava Page I of I 1]/05/99 1:25 PM App. 2-77 MediaGatewayServlet package com.launch.PlaylistCenerator; import java.io. *; import java.net.*; s import javax.servlet.*; import javax.servlet.http. *; import java.util.*; /** lo * PlaylistGeneratorServletjava 8/16/99 * Servlet that redirects to media * Copyright (c) ] 999 Launch, Inc. * ( author Jeff Boulter IS */ public final class MediaGatewayServlet extends HttpServlet /** what browser signature we look for t/ private static final String mpSignature = "NSPlayer"; to /** when we get an unauthorized browser, play this */ private static final String unauthorizedBrowser = "audio/errors/unauthorizedbrowser.asf''; /** when we get an unauthorized user, play this */ private static final String unauthorizedUser = "audio/errors/unauthorizeduser.asf"; /** when we get an unauthorized user, play this */ private static final String outOfMedia = "audio/errors/outotrnedia.asf"; /* * how many tries we take to get media */ private static final int MAX ITERATIONS = 5; /* * this is the header that media player uses toe indicate which query it is */ private static final String CONTEXT TAG = "requesl-context="; so /** To work around a problem with reading multiple headers with the same name in servlet 2.0 + jrun, we look for these headers to determine the context */ private static final String FIRST REQUES P PRAGMA = "xClientGUID"; private static final String SECOND_REQUEST PRAGMA = "stream-switch-entry"; private static final String REQUEST CONTEXT = "request-context="; private static final int STREAMING_MEDIA_TIMEOUT=1000*60* 15; /** * Handle requests */ public final void doGet (HttpServletRequest request, HttpServletResponse response) throws to ServletException, lOException 1/ Util.debug("MediaRedirectServlet:doGet() received a request"); DBConnection conn = null; ServletOutputStream out = null; int context; int userlD=-I; boolean debug=false; try // get connections and streams conn = new DBConnection(); out = response. getOutputStream(); 11 get parameters from http debug = (request.getParameter("ralph") != null); // setup response data set Response H eaders(response) ; setResponseContentType(response, debug); 11 get parameters from http userlD= Integer.parselnt(request. getParameter("u")); so if(!checkUserAgent(request.getHeader("USER AGENT"), debug,out)) App. 2-78 return; 11 muck with clip and clip schedule ClipSchedule schedule = new ClipSchedule(userlD); schedule.init(conn); //db call I Clip aClip = null; int iteration; boolean done = false; // keep going until we get a good path for (itcratior, = 0; iteration < MAX_iTERATIONS do& Done; iteration r+) aClip = new Clip(schedule. nextClipType(debug, out)); if (aClip == null 1l aClip.typet) == Clip.TYPE NONE) done= true; System.err.printin("uscr " + userlD + " is out of songs to play"); so else 11 get the paths and stuff as aClip.getPath(conn, schedule); 11 db call 2 if (aClip isSet()) done = true; 9C else done = true; System.err. printin("user " + userlD + " is out of media of type " + aClip.typeName() + " to play"); 11 update the playlist ice schedule.playlist.save(conn, userlD); 11 db call 3 if (aClip == null) out.printin(Constants.STPúAM_SERVER + "/" "a outOfMedia); else Clog the play aClip.logPlay(conn, userlD); 11 db call 4 // get the U RL out.printin(aClip.URL()); } } catch tNumberFonnatException e) li5 { out.printin("Bad userld"); 11 print out the MMS path to redirect to if (debug) l2C out. printin("redirecting to " + unauthorizedUser); else App. 2-79 out. printin(Constants.STREAM_SERVER + "/" + unauthorizedUser) catch (Throwable e) System.err.printin("Generic Exception in MediaGateway for userlD " + userlD + ": " + |30 e.getMessage()); e.printStackTrace(); {finally |35 try if (out!=null) out.close(); |40} if (conn!=null) conn.close(); 345} catch (SocketException se) 11 don't do anything, the person disconnected, no error, (or mediaplayer sampled first 32 bytes.) i50} catch (Exception el) e I.printStackTrace(); private final boolean checkUserAgent(String agent, boolean debug, ServletOutputStreann out) throws lOException |60 if (!(agent!=null && agent.startsWith(mpSignature))) if (debug) out. printin("invalid useragent. Would stream " + unauthorizedBrowser); return true; else out.printin(Constants.STREAM_SERVER + "/" + unauthorizedBrowser); 170} return(false); {else |75 return(true); } } private fnal void setResponseContentType(HttpServletResponse response, boolean debug) t80 if (debug) response.setContentType("text/plain "); else App. 2-80 { response.setContentType("video/x-ms-asf"); } } private final void setResponseHeaders(HttpServletResponse response) I90 { response. setHeader("Pragma", "no-cache"); response.setHeader("Cache-control", "nocache"); response.setHeader("Expires", O'); /* private static final void readFileToOutputStream(String filename, HttpServietResponse response, boolean debug) readFileToOutputStream(new File(filename), response, debug) ; 200} private static final void readFileToOutputStrcam(File the_fiie, HttpServletResponse response, boolean debug) try 205 { BufferedinputStream bis=new BufferedinputStream(new FilelnputStream(the file)); BufferedOutputStream bos=new BufferedOutputStream(response. getOutputStream()); bos.flush(); //this is to ward off any problems I think there might be a jrun problem with initializing the output stream fast enough, i.e. before we get there...
2lC BufferedWriter br=new BufferedWriter(new OutputStreamWriter(bos)); if (debug) Util.out(response.getOutputStream(), "streaming file " + the file + " of size " + the_file.length()); else 2 5 response. setContentLength((int)the fi le. length()); 1/ System.err.printin("streaming file " + the file + " of size " + the_file.length()); RedirectStream redirecting stream=new RedirectStream(bis, bos, debug, response.getOutputStream()); redirecting_stream.startO; 220 redirecting streamjoin(STREAMING MEDIA TIMEOUT, 0); if(redirecting stream.isAlive())redirecting_stream.stopO; //System.err.printin("finished streaming"); catch (SocketException se) 1/ don't do anything, the person disconnected, no error, (or mediaplayer sampled first 32 bytes.) catch (FileNotFoundException be) 230 { System. err.printin("readFileToOutputStream could not find file " + the file + " for reading:" + fe.getMessage()); catch (Exception c) 235 { e. printStackTrace(); private int getContext(HttpServletRequest request) 240 { try String pragma = request.getHcader("pragma"); 11 Util.debug("pragma is " + pragma); 245 if(pragma == null) return 0; App. 2-81 intindex=pragma. indexOf(REQUEST CONTEXT) Utl.debug("index is " i- index) if (index c a) 250 { return 0; else 255 int start = index + REQUEST_CONTEXT.length() String contextNum = pragma.subsiring(slart start + I) Util.debug("contextNum is " + contextNuruj retur.!rteger.parselnt(contextNumj; 2hO // when I can read multiple headers with the same name i should use the below code int location=pragma. indexOf(CONTEXT TAG) 11 1ocation=location+CONTEXT TAG lengthO; ant last location // for(last location--location,last location<pragma.length()&& 265 pragma charAt(last location)!=','; last location++); // return(lnteger.parselut(pragma.substring(location, last location))); catch (Exception e) 270 Util.debug("Exception caught in getContext: " + e.toStringO) return 0; #/ 275} MediaGatewayServletjava Page 7 of 7 11/05/99 1:24 PM App. 2-82 MediaList package com. Iaunch. Playi istGenerator; import java.util. Vector; public class MediaList s { private Vector media = new Vector(O, I) ; public void add(short mediaType, int medialD, String filepath) o media. addElement(new Media(media!D, medieType, filepath)J; public boolean inType(short media l ype) Media test; for (int i = 0; i < media.sizeO; i++ ) test = (Media) media.elementAt(i); if(test.mediaType == mediaType) return true; 25} return false; o public int getlD(short mediaType) for (int i = 0; i < media.size(); i++) Media aMedia = (Media) media. elementAt(i); if(aMedia.mediaType = mediaType) return aMedia.medialD; return 0 public String getFilepath(short mediaType) for (int i = 0; i < media.size(); i++) Media aMedia = (Media) media.elementAt(i); if(aMedia. mediaType== mediaType) return aMedia f lepath; return null; public int size() retum media.size(); App. 2-83 public Media typeAt(int index) return (Media) media.elementAt(index); public String toString() String result = ""; if (media == null) return "(none)"; for (int i = 0, i < media sizeO; i++) 7S result = result.concat(media.elementAt(i).toStringO + ","); return "(" + result + ")"; SO) MediaListjava Page 2 of 2 1 1/05/99 1:28 PM App. 2-84 PickCount package com. launch. PlaylistGenerator import javax.servlet. ServletOutputStream; /** */ public class PickCount int explicit; int implicit; lo int unrated; String method = ""; public PickCount(int userlD, int djlD, int ratio, int playlistSize, Population songs, ServletOutputStream out) |5 float explicitSize = songs.explicit.size(); float implicitSize = songs. implicit.size(); float unratedSize = songs.unrated.size(); Util.out(out, "Available: explicit songs: " + explicitSize + ", implicit songs: " + implicitSize + " unrated songs: " + unratedSize); to Util.out(out, "Ratio: " + ratio); // if you're listening to someone else's station, try to not listen to any unrated songs if (userlD == djlD) // let's try to use their ratio Is double totalRated = (explicitSize + implicitSize); if(totalRated<Constants.MIN RATINGS_TO HONOR RATIO) method = "New User Unrated Ratio" ratio=Constants.NEW USER UNRATED RATIO; 3 _ int maxPlicit = (ins) Math.round(playlistSize * (100 ratio) * 0.01); int maxRatedToPick = (ins) Math.round(explicitSize * Constants. MAX_PERCENT RATED_SONGS TO_PICK*0.01); // pick three times as much from rated int explicitToPick = (ins) Math. round(playlistSize * (100 - ratio) * 0.01 * (explicitSize / totalRated) * 3); int implicitToPick = maxPlicit - explicitToPick explicit = (ins) Math. min(maxRatedToPick explicitToPick) implicit = (ins) Math. nnin(implicitSize, impiicitToPick); do // pick up the slack ha unrated unrated = (playlistSize - explicit - implicit); method = "Unrated Ratio"; // if you're listening to someone else's station and they have enough ratings // don't play unrated else if ((explicitSize + implicitSize) > Constants. MIN SIZE FOR NO UNRATED) explicit - (hit) Math.round(playlistSize * 0.50); explicit = (ins) Math.round(Math.min(explicit, (explicitSize * Constants. MAX PERCENT RATED_SONGS TO PICK) * 0.01)); implicit= (hit) Math. min(playlistSize, implicitSize) - explicit; method = "DJ play - no unrated" // if we didn't get enough, use the default method if (explicit + implicit < playlistSize) { explicit = (ins) Math.round(playlistSize * 0. 33); explicit = (ins) Math.round(Math.min(explicit, (explicitSize * Constants.MAX PERCENT RATED_SONGS TO PICK)/100.0)); implicit = (ins) Math. round(playlistSize * 0.33); Implicit = (ins) Math.round(Math.m in(implic it, (implicitSize * App. 2-85 Constants.MAX_PERCENT_RATED_SONGS_TO_PICK)/ 100.0)); unrated = playlistSize - explicit - implicit; method = "DJ play - not enough rated"; 11 if neither of these worked else explicit = (ins) Math. round(playlistSize * 0.33); to explicit = (ins) Math.round(Math. min(explicit, (explicitSize * Constants.MAX_PERCENT_RATED_SONGS_TO_PICK)/ 100.0)); implicit - (int) Math.round(playlistSize * 0.33); implicit = (ins) Math.round(Math.min(implicit, (implicitSize * ('onstants.MAX_PERCENT_RATED_SONGS_TO PICK) / I00.0)); unrated = playlistSize - explicit - implicit; method = "Default 33/33/33 method"; Util.out(out, "Picking: explicit songs: " + explicit + ", implicit songs: " + implicit + ", unrated songs: " + unrated + ", method = " + method 85); public String toString() return "explicit to pick: " so + explicit + ", implicit to pick: " + implicit + ", unrated to pick: " + unrated; as} public void reset() explicit = 0; implicit = 0; loo unrated = 0; PickCountjava Page 3 of 3 11/05/99 1:24 PM App. 2-86 PickList package com.launch.PiaylistGenerator import java.uti l. Vector; public class PickList extends Vector { public PickList(PickCount counts) // make a list of all the song types that we need to pick for (mt = 0; i < counts.explicit; i++) lo addElement(Song.EXPLICIT) for (int i = 0, i < counts.implicit; i++) addElement(Song.lMPLICIT) for (int i = 0; i < counts. unrated; i ++) addElement(Song. UNRATED); public void addEiement(short value) t } addEIement(new Short(value)); to public void reAdd (short type, Vector songCroup, Population songs) // try to pick Mom the same bucket again if (songGroup.size() > 0) addElement(type); // otherwise, try the other ones else if (songs.explicit.size() > 0) addElement(Song.EXPLICIT) else if (songs.implicit.sizeO > 0) addElement(Song.lMPLICIT) else if (songs.unrated.size() > 0) addElement(Song.UNRATED); public short getRandomO if (size() < 0) return 0 int lucky = (ins) Util.random(size() - 1) // figure out what group to pick from short type = ((Short) elementAt(lucky)).shortValue() so removeEiementAt(lucky); return type; PickListJava Page 2 of 2 1 1./Q5./99:27 PM App. 2-87 PickStatus package com.launch.PlaylistGenerator; public class PickStatus public final static int NOT PICKED = 0; public final static int REJECTED = 2; public final static int PICKED = 1; int status; o int order = -1; short percentile; public String toString() l5 retum toDisplayString(Util. Dl SPLA Y_TEXT); public String toDisplayString(int displayType) String redStart = ""; String greenStart = ""; String fontEnd = ""; if (displayType == Util. DISPLAY_HTML) redStart = "<FONT COLOR=red><B>" greenStart = "<FONT COLOR=green><B>"; fontEnd = "</B></FONT>"; 3 switch (status) { case NOT_PICKED: retum "N "; case PICKED: retum greenStart + " P " + fontEnd; case REJECTED: retum redStart + " R" + fontEnd; default: retum " "; } } PickStatusjava Page I of I 11/05/99 1:26 PM App. 2-88 PlayDataHash package com.launch PlaylistGenerator import java.util.Enumeration; public class PlayDataHash extends IntHash ( public String toString() String myString = ""; in for (Enumeration e = keys(); e.hasMoreElements() ;) { /I debug.write("interation " + i++); int stationlD = ((Integer) e. nextElement()).intValueO; int rank = get(stationlD); myString = myString. concat( "stationlD: " + stationlD + =.. + rank + } "\n"); } return myString; 2S} PlayDataHaskjava Page I of I 11/05/99 1:26 PM App 2-89 PlayDates package com. launch. P layl istGenerator; import java.util. Hashtable; import java.util. Date; importjava.util.Enumeration; import java.text.SimpleDateFonmat importjava.io.lnputStreamReader; import java. text.ParsePosition import java.io.lOException 0 import java.util.Calendar public class PiayDates private static final String dateformat = "yyyy-MM-dd HH:mm:ss"; private Hashtable hash int userlD; double secondsinDay = Util.MlLLISECONDS IN SECOND * zo Util. SECONDS [N MINUTE * Util.MINUTES IN HOUR * Util.HOURS IN DAY // for date parsing private static StringBuffer year = new StringBuffer(" 1234") private static StringBuffer month = new StringBuffer(" l 2") private static StringBuffcr day = new StringBuffer("12"); private static StringBuffer hour = new StringBuffer("12") private static StringBuffer minutes - new StringBuffer(" l 2") so public Date dbDate = nev'Date(); private boolean loaded = false; public PlayDatesO { hash = new HashtableO; public void put(int songlD, Date iastPlayed) { // the common case is that they will have NOT played this song before // so create the Integer object in anticipation that wc will use it for // the put as wetl.
Integer i = new Integer(songlD); Date before = get(i); // save only the most recent play of a song if(before == null 1I before. getTimeO < lastPlayed.getTime()) hash. pu t( i, lastPl ayed) public Date get(int songID) return (Date) hash.get(new Integer(songlD)); App. 2-90 } 115 public Date get(lnteger songlD) retune (Date) hash.get(songlD); l public Enumeration keysO o return hash.keys(); public void remove(lnteger songlD) hash.remove(songlD); public int sizeO BO return hash.size(); BS public String toString() String result = ""; for (Enumeration e = hash. keys(); e.hasMoreElementsO,) Integer songlD = (Integer) e.nextElement() Date playedAt = get(songlD) result = result.concat("{" + songlD F " = " t playedAt + "3 "); retun, result 9S) ' public String toDBStringO Date startDate = new DateO; StringBuffer buffer = new StringBuffer(100000); Calendar cal = Calendar.getinstance(); Integer songlD; Date playedAt; for (Enumeration e = hash.keysO; e.hasMoreElements() ,) { songlD = (Integer) e.nextElement() playedAt = get(songlD); I/ System.out.printin(playedAt); cal.setTime(playedAt); buffer.append(cal.get(Calendar.YEAR) + "-" + leadingZero(cal.get(Calendar.MONTH) + I) + "-" + leadngZero(cal.get(Calendar.DAY OF MONTH)) " " + leadmgZero(cal.get(Calendar.HOUR OF_DAY)) + "." songlD + " "); + leadingZero(cal.get(Calendar.MINUTE)) + ":00=" + App. 291 I/ result = result.concat(formatter.format(playedAt) + "=" + songlD + ","); Util. printElapsedTime("toDBString", startDate); return buffer.toString(); public static final String leadingZero (int value) if(value< 10) return "0" + value; rehrn value t- ""; public float getScore(lnteger songlD) { Date lastPlayed = get(songlD); if(lastPlayed == null) return 0; double secoodsSincePlayed = new Date().getTime() - lastPlayed.getTime() double daysSincePlayed = secondsSincePlayed / secondsinDay double logValue = Math.log(daysSincePlayed + 0.01); rehurn (float) Math.min(iO0, (22.0 * logValue)); 150} public void save(DBConnection cone) 1/ Date dateStarted = new Date(); if (! loaded) return; try I60 conn. executeUpdate("exec sp IcSavePlayHistoryText isux " + userlD + ", "' + toDBString() + ""', false); catch (DBException e) I65 System.err. printin("DBException in PlayDates:save: " + e.toString()); // Util.printElapsedTime("save", dateStarted); public void markRecentlyPlayed(SonginfoCache cache, Population songs) double now = dbDate.getTime(); double lastThreeHours = Util.MILLISECONDS IN SECOND * Util.SECONDS IN MINUTE $ Util.MINUTES IN HOUR * Integer songlD; so Date playedAt; Songinfo info; int artistlD, albumlD; for (Enumeration e = hash. keys(); e.hasMorcElements() ;) App. 2-92 IBS songlD = (Integer) e. nextElement(); playedAt = get(songlD); if (now - playedAt.getTime() < lastThreeHours) o /I mark songs played in the last three hours // so as to comply with the RIAA rules ll and make sure we don't pick too many later in fo = (Songinfo) cache. get(songl D, SonginfoCache. TYPE SONG); if (info!= null) f artistlD-info.getArtistlD(); albumlD = info. getAlbumlD(); // "various artists" albums don't count if (!Artistinfo. isVariousArtists(artistlD)) songs.artistCounts.increment(artistlD); 205 songs.albumCounts. increment(album I D); } } public void oldLoad(DBConnection cone, int userlD) this.userlD- userlD; try String sql = "exec sp IcoGetLastPlayed xsxx " + userlD DBResultSet rs = conn. executeSQL(sql); loaded = true; Date lastDate; int songlD; 225 while (!rs.getBOF() && !rs.getEOF()) songlD = rs.getint("songlD"); lastDate = rs.getTimestamp("lastPlayed"); put(songlD, lastDate); rs.next() ; catch (DBException e) System.err.printin("DBException in PlayDates. oldLoad: " + e.toString()); 240} public void load(DBConnection cone, int userlD) 245 { App. 2-93 11X Date startDate = new DateO; // be careful of the SQL Server TEXTSIZE parameter which is by default 64KB this.userlD = userlD; double aDay = Util.MlLLISECONDS IN SECOND * Util.SECONDS IN_MINUTE * 255 Util.MINUTES IN HOUR * Util.HOURS_IN_DAY; doubic aMonth = aDay * lltil.DAYS_IN MONTI-; 760 try String sql = "exec sp IcGetSongHistoryText xsxx " + userlD; 265 DBResultSet rs = conn.executeSQL(sql); Util.printElapsedTime("LP: ran getsonghistorytext", startDate); if(!rs.getBOF0&& !rs.getEOF()) 270 loaded = true; char[] stuff= new char[]00000]; InputStreamReader reader = new InputStreamReader(rs. getAsci i Stream("played")); Util. printElapsedTime("LP: created reader", startDate); dbDate = rs. getTimestamp("dbDate "); long dbDateTime = dbDate.getTime(); 280 reader.read(stu; Util.printElapsedTitne("LP: read into stuff'' startDate); Calendar cal = Calendar.getinstance(); int lastStart = 0; int songlD = o; 285 // SimpleDateFormat formanerl = ncw SimpleDateFormat(PlayDates. dateFormat); 1/ ParsePosition pos = new ParsePosition(0); Date datePlayed = null; 290 String parseme = new String(); long length = stuff.length; for (int i = 0; i < length; i++) 295 { switch (stuff[i]) case'=' aoo // parseme = new String(stuff, lastStart, i - lastStart); // pos.setindex(0); // datePlayed = formaKerl.parse(parseme, pos); datePlayed = parseDate(stuff, lastStart, car); 305 // System. out.printi n("date is " + date P layed); // if (datePlayed == null) // { // pos.setindex(0); App. 2-94 310 // } datePlayed= formatter2.parse(parseme, pos); lastStart = i + 1; break; case'.
315 Gaul;,; parseme = new String(stuff, lastStart, i - lastStan); try 32U} songlD= inieger.parselnt(parseme); catch (NumberFormatException c) { } 1/ save 'em 325 // also don't save them if they're > 30 days old if (songlD > 0 && datePlayed!= null && ((dbDateTime datePiayed.getTime()) < aMonth)) put(s ongl D, date Played) ; 330 songlD = 0, /I reset datePlayed - null; // reset lastStart= i + 1; break case 0: // we're at the end of the string startDate); Util.printElapsedTimc("LP: found null at char " + i, return, } 3 345 catch (DBException cops) Util.debug("DBException in PlayDates.ioad: " + oops.getMessage()); catch (lOException Cops) 350 { Util. debug("lOException in PlayDates.load: " + oops.getMessage()); /** 355 * Why? Because SimpleDateE'ormat is *way* too slow.
private final Date parseDate(charl] chars, int start, Calendar Cal) // 1999-10-13 17:19:00 360 // 0123456789012345678 I* String year, month, day, hour, minutes year = new String(chars, start, 4); month = new String(chars, start + 5, 2); 365 day -- new String(chars, start + 8, 2); hour = new String(chars, start + I], 2); minutes = new String(chars, start + 14, 2); APD. 2-95 year.setCharAt(O, chars[start + O]); year.setCharAt(I, chars[start I]); year.setCharAt(2, chars[start + 2]); year.setCharAt(3, chars[start + 3]); month.setCharAt(O, chars[start + 5]); month.setCharAt(I, chars[start + 6]) ; day. setCharAt(O, chars[start.+ 8]); BO day.setCharAt(l, chars[start + 9]); hour.setCharAt(O, chars[start + 11]); hour.setCharAt(1, chars[start + 12]); 3B5 minutes.setCharAt(O, chars[start + 14]); minutes.setCharAt(l, chars[start+ 15]); int yearlnt = 0, monthint = 0, dayint = 0, hourlnt = 0, minutesint = 0; /I try 390 // { yearlnt = parselnt(year); monthint = parselut(month); dayint = parselnt(day); 395 hourlnt = parselnt(hour); minutesint = parselnt(minutes); // } // catch (NumberFormatException e) { return null;} 400 // cal.clear(); cal.set(yearlnt, monthint - 1, dayint, hourlut, minutesint, 0); } retum cal getTime(); private static final int parselnt(StringBuffer s) int result = 0; intlast=s.length()- 1; for (int i = last; i ≥ 0; i--) result += char2int(s.charAt(i)) Math.pow( i 0, last i); return result; private final static int char2int(char ch) 420 { switch (ch) case 'l': retum 1; 425 case'2': retum 2; case '3': retum 3; case '4': O retum 4; case '5': retum 5; App. 2-96 case'6': return 6; 435 case'7': return 7; case '8': return 8; case '9': 440 return 9; default: return O; PlayDatcs Java Page 9 of 9 1 I/05/99 1:35 PM App. 2-97 Playlist package com. Iaunch.Playl istG enerator import Java.util. Vector import java.util.Hashtable; import java.util. Enumeration import java.util.Date public class Playlist Vector media; o Vector news; Vector ads Vector tips, int 1D; int userlD; int djlD; int moodlD short mediaType; boolean debug; boolean popularOnly = false PickCount counts public final static int BUCKET COUNT = 5 private int lastindex int buckets[l; IntHash artists; IntHash albums; public Playlist() artists = new IntHashO; albums = new IntHash() counts = null; media = new Vector(); news = new Vector(); ads = new Vector(); tips = new Vector(); buckets = new int[BUCKET COUNT]; lastindex = -1; } debug = false; public Playlist(int playlistlD) { thisO; } ID = piaylistlD; public void resetSourcesO { for (int i = 0; i < BUCKET COUNT; i++) } buckets[j] = 0; private void saveOrigins(DBConnection cone) { String listString= ""; SongData data for (int i = 0; i media.size(); i++) listString = listString.concat(((SongData) media.elementAt(i)). originTclListO); try 60} conn.executeSQL("exec sp IcSaveOrigins_ixxd " + userlD + ", "'+ listString + ""'); App. 2-98 catch (DBException oops) Util.debug("DB Exception: " + oops.getMessage()); public Playlist2 toPlaylist2() Playlist2 result = new Playlist2(); // copy playlist o for (int i = 0; i c media.size(); i++) result.songs. addElement(((SongData) media.cle:nentAt(i)).toPiaylistEntry(mediaType)); // copy news for (int i = 0; i < news.size(); i++) result.news. addElement(((Clip) news.elementAt(i)).toPlaylistEntry(mediaType)); // copy ads o for (int i = 0; i ads.size(); i++) result.ads. addElement(((Clip) ads.elementAt(i)).toPlaylistEntry(mediaType)); // copy tips for (int i = 0; i < tips.size(); i++) result.tips. addElement(((Clip) tips.elementAt(i)).toPlaylistEntry(mediaType)); return result; 3 public String toStringO IntH as h artistCount = new I n t Hash () intHash albumCount = new IntHash(); IntHash querySource = new IntHash() H as h ta b le q u erySourceNam e = n ew Has htab l e(); IntHash originSource = new IntHash(); Hashtable originSourceName = new Hashtable() ; Hash ta b l e art is tNa m es = n ew Ha shtab l e() ; oo Hashtable albumNames = new Hashtable(); String result = "Playlist " t- ID + " for userlD " + userlD + " (dilD " + djlD + ") in mood " " moodlD + " with mediaType " + mediaType + ", pickCounts: " + counts ros + " has " + media.size() + " songs:" + UtitnewL.ine; for (int i = 0; i < media sizeO; i++) SongData data = (SongData) media.elementAt(i); no String songStr = data. getMedialD(mediaType) + " " + data.getAlbumlD() + " " + data.getArtistlD() + " " + data.songlD + " " + data.getArtistName() + " " tl5 + data.getAlbumNameO + " " + data.getSongName() + Util.newLine; q u eryS ource. in crem en t(data. q uery So urce) ; querySourceName.put(new Integer(data.querySource), data. sourceString(data.qucrySource)); :o byte origin = data.origin(); origin Source. increm ent(origi n) ; originSourceName.put(new Integer(origin), data,sourceString(origin)); App. 2-99 artistCount.increment(data.getArtistlD()); album Count. increment(data. getA lbumlD0); t}5 if (data.getArtistName() ! = nu l l) artistNames.put(new Integer(data.getArtistlD()), data.getArtistName()); if (data.getAlbumName() != null) albumNames.put(new Integer(data.getAlbumlD()), data.getAlbumName()); result = result.concat(songStr); I30} result= result.concat(l)tii.newLine); for (Enumeration e = artistCount. keys(); e.hasMoreElements() ,) { int artistlD = ((Integer) e.nextElement() ).intValue(); String artistStr = artistCount.get(artistlD) + " songs are by the artist " + artistNames.get(new Integer(artistlD)) + ( + artistlD + ") '' Utl.newL'ne; result = result.concat(artistStr); 140} result = result. concat(Util.newLine); for (Enumeration e = albunnCount.keysO; e. hasMoreEiementsO;) int albumlD = ((Integer) e.nextElement()).intValue(); String albumStr = albumCount.get(albumlD) + " songs are from the album " + albumNames.get(new Integer(albumlD)) + ( + albumlD + ") l' + Util.newLine; result = result.concat(albumStr); 150} result = result. concat(Util.newLine); for (Enumeration e = querySource.keysO; e. hasMoreElements() ,) { int source = ((Integer) e.nextElement()).intValue() ; nt songCount = querySource.get(source); IS5 double doubleCount = new Double(songCount).doubleValue(); String str= songCount + " songs (" + ((doubleCount / length()) * 100) + "%) are from the " so + querySourceName.get(new Integer(source)) + " query" + Util.newLinc; result = result.concat(str); l'5S} result = result. concat(Util.newLine); for (Enumeration e = originSource.keys(); c. hasMoreElemenrs() ;) { int source = ((Integer) e.nextEiementO).intValue(); int songCount = originSource.get(source); o double doubleCount = new Double(songCount).doubicValue(); String str = songCount + " songs (" + ((doubieCount / length()) * 100) + "/O) orgmated from " s + originSourceName.get(new Integer(source)) + Util.newLine; result = result.concat(str); su result = result. concat(Util.newLine); int bucketSize = 100/ BUCKET COUNT; doub le p lay l istLength = med ia.sizeO; for (int i = 0; i < BUCKET COUNT; i++) App. 2- 100 IS5 resultresult.concat( "Percentile " + (i bucketSize) + "% - " + ((i + ]) * bucketSize) + "%: " + bucketsti] + " (" Util.newLine); + Util.fix(l 00 (buckets[i] / playlistLength), 2, 0) + "%)" + return (result + Util.newLine); public int length 0 { } return media size(); public void append (SongData song) float bucketSize = (new Float(10] )) floatValue0 / (new Float(B UCKET_COUNT)). floatValue() int bucket = (ins) Math.floor(song.staLus.percentite / bucketSize); /1 Util.debug("adding medialD " + song.medialD // + " in percentile " + song.status.percentile + " (bucket " 11 + bucket + ")"); 205 media.addElement(song); buckets[bucket]++; public Playlist shuMeO 230 Vector newList = new Vector(media.size()); int rend = 0; vvhile (media.size() > 0) rend = (ins) Util. random (media size() - I); 215 Object m = media.elementAt(rand) media.removeElementAt(rand); newList. addElement(m); media = newList 220 return this; public int nextOrdinal(DBConnection cone) int ordinal = 1; 22S try DBResultSet rs = conn.executeSQL("exec sp IcGetOrdinaliD_xsxx " + userlD); while (!rs.gerBOF() && !rs.getEOF() 230 ordinal = rs.getint("ordinal"); rs.next() conn.executeSQL("exec sp IcUpdatePlaylistData ixxd " + userlD + ", " 23S + djlD + ", " + moodlD + ", " + mediaType); catch (DBException oops) 240 { Util.debug("DB Exception in Playlist::nextOrdinal: " + oops.getMessage()); return ordinal 24S public void deleteHighOrdinals(DBConnection com,, int ordinal) App. 2- 101 try conn.executeSQL("exec sp_lcDeletePlaylistRange xxxd " 250 + userlD + ", " + ordinal); catch (DBException oops) 255 Util.debug("DB Exception in Playlist::deleteHighOrdinals " + oops. getMessage()); private SimpicPlaylist toSimplePlaylist() 260 SimplePlaylist result = new SimplePlaylist(); result. med iaType = this.mediaType; result.djlD = this.djlD; result.moodlD = this.moodlD; 265 // COpy playlist for (int i = 0; i < media.size(); i++) result.songs. addElement(((SongData) media.elementAt(i)).toSimpleClip(mediaType)); 270 // copy news fo r (in t i = 0; i c news. s ize() ; i+ +) result.news. addElement(((Clip) news.elementAt(i)).toSimpleClip(mediaType)); 275 // copy ads for (int i = 0; i < ads sizeo; i++) result.ads. addElement(((Clip) ads.elementAt(i)).toSimpleClip(mediaType)); 280 // COpy tips for (i nt i = 0; i < tips. size(); i++) result.tips. addElement(((Clip) tips.elementAt(i)).toSimpleClip(mediaType)); 285 retum result; public void save (DBConnection cone, SimpleP1aylist oldPlaylist) 250 Date startDate = new DateO; SimplePlaylist thoreau = toSimplePlaylist(); Util.printElapsedTime("Convert to SimplePlaylist", startDate); if (oldPlaylist!= null) thoreau.lastAd = oldPlaylist.lastAd; thoreau.lastNews = oldPlaylist.lastNews; 300 thoreau.lastTip = oldPlaylist.lastTip; thoreau.save(conn, userlD); 305 Util.printElapsedTime("SavePlaylist", startDate); /* App. 2-102 public boolean save (DBConnection cone) 310 { if (length() ≤ 0) return false; boolean resetOrdinal = false; int highOrdinal, ordinal; 315 Date startDate = new Date(); highOrdinal = ordinal = nextOrdinal(conn) ; if(highOrdinal>MAX ORDINAL) ordinal= 1; 370 resetOrdinai = true; Util.printElapsedTime("GetOrdinal", startDate); Thread saveNews = new SavcClips(news, "sp_lcSaveNewsPlaylist ixxd", ordinal, mediaType, userlD); 325 Thread saveAds = new SaveClips(ads, "sp lcSaveAdsPlaylist ixxd", ordinal, mediaType, userlD); Thread saveTips = new SaveClips(tips, "sp lcSaveTipsPlaylist ixxd", ordinal, mediaType, userlD); int partition = (ins) Math.round(media.size() / 4.0); 330 Thread savePlaylistl = new SavePlaylist(this, O. partition, ordinal); Thread savePlaylist2 = new SavePlaylist(this, partition, partition * 2, ordinal + partition); Thread savePlaylist3 - new SavePlaylist(this, partition * 2, partition * 3, ordinal + (partition * 2)); Thread savePlaylist4 = new SavePlaylist(this, partition * 3, media.size(), ordinal + (partition * 3)); savePlaylistl.start(); 335 savePlaylist2 startO; savePlaylist3.start(); savePlaylist4.startO; saveNews startO; saveAds.start(); 340 saveTips.start(); deleteHighOrdinals(conn, highOrdinal- 1); 1/ everybody done yet? saveOrigins(conn); tty 345 { saveNews joinO; saveAds join(); saveTips join(); savePlaylistl joinO; 350 savePlaylist2 joinO; savePlaylist3 join(); savePlaylist4 joinO; catch (InterruptedException e) 355 { Util.debug("Playlist::save was interrupted while waiting"); Util.printElapsedTime("SavePlaylist", startDate); return true; 3550} */ private void saveClips(DBConnection cone, Vector clips, String storedProc) 365 for (int i = 0; i c clips.size(); i4+) Clip aClip = (Clip) clips. elemcntAt(i); String sql = "exec " + storedProc + " i' +ID+" t' 370 + aClip.medialD + ", " App. 2-103 + mediaType + ", " + userlD; try 375 DBResultSet rs = conn.executcSQL(sql); catch (DBException oops) Uti l. debug(" DB Except ion: " + oops.getMessage()) ; 380} public String newLine() 385 return Util.newLine; public String toASX() String asx = ''<ASX VERSION=\"3.0\" PREVIEWMODE=\"NO\">" + Utii.newLine 390 + Util.tab() + "<REPEAT>" + Util.newLine; String streamURL = Constants.STREAM URL + "?u=" + userlD; for (int i = 0; i < 10; i++) 395 asx = asx.concat(Util.tab(2) 4 "<ENTRY>" + Util.newLine + Util.tab(3) + "<REF HREF=\"" + streamURL 400 + "&n=" +; + ".asp" + "\"/>" + Util.newLine + Util.tab(2) 405 + "</ENTRY>" + Util.newLine); asx = asx.concat(Util.tab() + "</REPEAT> " +Util.newLine + "</ASX>" + Uti].newLine); return asx; 40} Playlistjava Page 10 of 10 11/05/99]:38 PM App. 2-104 Playlist2 package com.iaunch. PiaylistGenerator; import java.util.*; 1/ s /** * Author Ted Leung * Aversion 1999-09-22 **/ /1 - lo public final class Playlist2 implements java.io.Serializable //********************************************************************** 1/ variables //******************4****************************** Is /** all these vectors contain exclusively Strings which are directory/filename of audio files */ pubhc Vector songs; public Vector news; public Vector ads; public Vector tips; //*****$*********** // methods //****** * ** ** **** ******* * ***** *** * ***** *** *** *** * *** **** Z5 public Playlist2() songs = new Vector(50); news = new Vector(l O); ads = new Vector(l O); tips = new Vector(10); // - - /** **/ // - -- -_- _ _ __ _ __ __ _ _ _ _ _ _ _ _ _ _ _ _ __ public final String toString() return ( "songs="+songs.toString() + ", " + "news="+news.toString() + ", " + "ads="+ads.toStringO + "' " + 'tips=+tips.toStringO 45); //********************************* ******* ********* ** Piaylist2 java Page 2 of 2 I J /05/99 1:28 PM App. 2-105 PlaylistCreatorTest package com. launch.PlaylistGenerator public class PlaylistCreatorTest public static void main(String[] ergs) Utli.debug("using database server " + Constants. DB SERVER); lo SonginfoCache songCache = new SonginfoCache(null); songCache.ratingsCache = new RatingsCacheO; // PlaylistParameters params = new PlaylistParameters(3771, null, 0, 13302) PlaylistParameters params = new PlaylistParameters(6474 126, null, 0, 6474]26) PlaylistGenerator gen = new PlaylistGenerator(params, songCache, null) Playlist playlist = gen.create(true, null); gen. toMatrix(null, Uti l. DISPLAY TEXT) } systemexit(o); to} PlaylistCreatorTestjava Page I of I 11/05/99 1:35 PM App. 2-106 PlaylistEntry package com. launch. Playl istG en erator; import java.io.*; public class PlayIistEntry implements Serializable { public String title, filepath, songTitle, albumTitle, artistTitle; public int medialD, songlD, albumlD, artistlD; lo public short implicit; public byte origin; PlaylistEntryjavaPage I of I I 1/05/99 1:28 PM App. 2-107 PlaylistGenerator package com.launch.PlaylistGenerator; import java.util. Vector; import java.util.Date; import javax.servlet.ServletOutputStream; import java.util.Enumeration; public class PlaylistGenerator public final static byte RATER DJ = 1; lo public final static byte RATER BUS = 2 public final static byte RATER GENRE = 3; private short factor = (short) Constants.DEFAULT_PICK_FACTOR private short ratio = (short) Constants. DEFAULT UNRATED RATIO; prvateintplaylistSize =Constants.DEFAULT PLAYLIST SIZE; private int playlistlD; private boolean haveTitles = false; private Date startDate; private Date lastDate; private int userlD; ! to private int djlD; private int moodlD; private short mediaType; private IntHash ratings; private ItemsProfile items; Is private PlayDates lastPlayed; private Population songs; private Vector news private Vector ads; private Vector tips; so private DJList djs; private GenreList genres; private Bandwidth speed; private MediaFormat format; private StationList stations; private ServletOutputStream out; private SonginfoCache songCache; private boolean playExplicitLyrics = true; so * Creates a new playlist generator. */
public PlaylistGenerator() songs = new PopulationO; news = new Vector(); ads = new VectorO; tips = new VectorO; ratings = new IntHash(); djs = new DJList(); items = new ItemsProfile() lastPlayed = new PlayDates(); genres = new GenreList(); } stations = new StationList(); ss public PlaylistGenerator (PlaylistParameters params, SonginfoCache cache, ServletOutputStream out) this(); userlD = params.userlD; moodlD = paranns.moodlD; so djlD = params. djJD; App. 2-108 if(djlD ≤ 0) djlD = userlD; speed = params.speed; 555 format = params.format; playlistSize = params.playlistSize; songCache = cache; this.out = out; to private void getRandom() Date startDate -- new Date(); Song ditty; SongData data; Is Songinfo info; SongList songfest; int rowCount = 0 double pickCount; double totalSongs; so /I the simple way lo songList = cache.getinGenres(genres); pickCount = Math. min(songList.size(), this.RANDOM SONGS_COUNT); // import them all if (pickCount = songList.size()) for (int i = 0; i < pickCount; i++) info = songList.elementAt(i); so rowCount += addRandom(info, SongData.SOURCE_RANDOM); /1 import a random subset else { for (int i = 0; i < pickCount; ink) info = songList.pickRandom(); rowCount += addRandom(info, SongData. SOURCE_RANDOM); IN} */ 11 the faster(?) but way more complicated way int songCount = songCache. countinGenres(genres); I05 tota]Songs = songCache.size(SonginfoCacne. TYPE_SONG) double percent = (songCount / totalSongs) ! 00.0 Util. printElapsedTime("GetRandom done counting in genres", startDate); // the problem is if we pick randomly and they want songs from loo /1 only a few genres, we're probably not going to get enough to create 11 a playlist. So instead, if there's not a whole lot of songs in those genres, 11 just get them directly from the genres instead of taking our chances with random Util.debug("getRandom: " + songCount + " non-unique songs in genres (" + percent + "%)"); if (percent < Constants. MIN_SONGS_IN_GENRES_TO_GET RANDOM) Il5 { Util debug("getRandom. getting directly from genres") 11 get the list of songs from each genre // choose the number to pick from each, proportional to the number of songs // pick them i20 int totalToPick = Math.min(Constants.RANDOM_SONGS_COtJNT, songCount); {for (int i = 0; i c genressize(); i++) App. 2-109 songList = songCache. getinGenrc(genres.genreAt(i)); pckCount = totalToPick * (songList.size() / ((double) songCount)); I25 for (int j = 0; j < pickCount; j+) info = songList.pickRandom(); if(info!= mll) |30 rowCount += addRandom(info SongData.SOURCE GENRES); 135} else Util. debug("getRandom: picking randomly from all songs") for (int i = 0; i < Constants.RANDOM_SONGS_COUNT, i++) I40 { /I this is really fasl info = songCache.randomSong() // this is realiy slow rowCount += addRandom(info, SongData.SOURCE_RANDOM) ; I45} Util.debug("getRandom added " + rowCount + " songs") Util. printElapsedTime("GetRandonn done", startDate); private int addRandom(Songinfo info, byte source) SongData data = songs. initSongGetData(in fo.songlD, Song. UNRATED) if (data!= null) data. querySource = source data.setinfo(info); return 1; retum O; 10} private void getPopular(SongList list) Date startDate = new DateO Song ditty; SongData data; Songinfo info, int rowCount = 0; if (list!= null) o for (int i = 0; i < list.size(); i±i) info= list.elementAt(i); data = songs. getSongData(info.songlD); if(data!=null) { 1/ we can't add it, but let's append the info while we're here data. setlnfo(info); else o { dfa(td s!ongs initSongGetData(into songlD, Song UNRATED); data.querySource = data.SOURCE_POPULAR; App. 2-110 data. setinfo(info); rowCount++; I90} Util.debug("getPopular added " + rowCount + " songs"); /** * Gets all the required media and data to generate a playlist.
i95 */ pri\,ate void gatherMedia(DRConncction cone) Thread getLastPlayed = new GetLastPlayed(lastPlayed, userln, out); Utii.out(out, "starting gathering threads at " + timeStampO); zoo // try to start them in ascending order of speed getLastPlayed.start(); 1/ get djs, genres, and teds subscriptions getSubscriptions(conn, djlD, moodlD); Util.out(out, "getSubscriptions done " + timeStamp()); 205 // we need to wait for the djs to come in first Thread getRatings = new GetRatings(songs, items, dJlD, djs, songCache, out) getRatings.start() ; Util.out(out, "All threads started " + timeStamp()); 1/ getpopular and getrandom should not be threads since they are purely processor bound now 210 getPopular(songCache.getPopular(mediaType)); Util.out(out, "getPopular done " + timeStampO); getRandomO; Util.out(out, "getRandom done (picked " + Constants.RANDOM SONGS_COUNT + " songs)" + time Stamp()); Util.out(out, "genres for mood " + moodlD + ":" + genres.toString()); // wait for them to finish try getRatings join(); getLastPlayed joinO; catch (InterruptedException oops) Util.debug("loterruptedException: " + oops. toStringO); 225} Util.out(out, "gatherMedia done " + timeStamp()); public void getSubscriptions(DBConnection cone, int userlD, int moodlD) 230 Date started = new DateO; try DBResultSet rs = conn.executeSQL("exec sp IcoGetAIISubscriptions xsxx " + userlD + ", " 235 + moodlD); int raterlD; int raterType; while (!rs.getBOF() && !rs. getEOF()) 240 raterlD = rs.getint("raterlD"); raterType = rs.getint("raterType"); if(raterType == RATER DJ) djs. addElement(new DJ(raterlD)); 245} else if (raterType == RATER_GENRE) App. 2-111 genres.add((short) raterlD); 250 else if(raterType == RATER BDS) statlons.addElement(new Station(raterlD)); 255 rs.next(); Utii.debug("getSubscriptions added" - djs.size() t " DJs, '' tgenres.size() + " Genres, " i60 + stations. size() + " Stations"); catch (D B Ex cepti on oops) Util.debug("DB Exception in getSubscriptions " + oops.getMessage()); 265} Uti 1. printElapsedTi me("getSubscriptions took ", started); /$* Calculates scores for all the songs and puts them into the various vectors 270 */ public void processSongs() byte result; WeightMatrix weights = new WeightMatrixO; 275 Integer songlD; Song aSong; SongData data; short type; Date playedAt; 280 Songinfo info; int good = 0; int tested = 0; int artistlD, albumlD; Item albumitem; 2IS Item artistitem; AlbumArtistData albumAndArtist = new AlbumArtistData(); IntHash reasons = new IntHashO; 290 double now = lastPlayed.dbDate.getTirne(); double lastThreeHours = Util.MILl.ISECONDS IN SECOND * Util.SECONDS IN MINUTE * Util.MINUTES IN HOUR 4 3; 295 for (Enumeration e = songs.keysO; e.hasMoreElements() ;) tested++; albumAndArtist.reset(); songlD = (Integer) e.nextEiement0; aSong = songs. get(songlD); data = aSong.getData(); 305 if(aSong.getTypeO == Song.EXCLUDED) reasons.increment(] ); App. 2-112 else 310 { 1/ add the song info info = data.getinfo(); 1/ get the song info from the cache if (info == null) { info = (Song in fo) songCache.get(songlD, SonginfoCache.TYPE_SONG); data.setinfo(info); 320 // if it's still null, it's not encoded if (info == null) aSong. setType(Song.EXCLU DED); reasons. increment(2); 325 continue; /J ok, we have the song info.
// add last played playedAt= lastPlayed.get(songlD); 330 if(playedAt!= null) lastPlayed.remove(songlD); /I don't play the same song twice in a 3 hour period 335 if (now - playedAt.getTime() < lastThreeHours) 11 mark songs played in the last three hours 11 so as to comply with the RiAA rules 11 and make sure we don't pick too many later 340 artistlD = data.getArtistlD(); albumlD = data.getAlbumlD(); /1 "various artists" albums don't count if (! Artistinfo. isVariousA rtists(artistlD)) 345 songs.artistCounts. increment(artistl D); songs.albumCounts. increment(albumlD); 11 make sure we don't play this again so soon aSong.setType(Song.EXCLUDED) ; 350 reasons. increment(3); continue; data.lastPlayed= lastPlayed. getScore(songlD); 355 // check for bad words if(!playExplicitLyrics && info. hasExplicitLyrics()) aSong.setType(Song.EXCLUDED); reasons.incrennent(4); 350 continue; // now check for media in the type we need i f (! in fo. med ia. inType(mediaType)) 36S aSong.setType(Song.EXCLUDED); reasons. increment(S); continue; 1/ check for valid genres 370 if(!info.album.in(,enres(genres)) App. 2-113 11 for popular songs, don't exclude them, 11 otherwise we won't be able to default to them 11 if the genre restrictions are too tight 375 if(data.querySource == data.SOURCE_l'OPULAR) songs.remove(songlD); reasons. increment(6); So aSong.setType(Song.EXCLUDED); continue; 11 we got this far, so try to calculate an implicit rating result = data. calculatelmplicit(items, albumAndArtist); 385 if (result == SongData.EXCLUDE_ME) aSong.setType(Song. EXC L.UDED); reasons. increment(7); continue; 390} if(result == SongData.MAKE_ME IMPLICIT) aSong.setType(Song.lM PLICI T); data.caiculateDJs(items, albumAndArtist); 395 data.score(weights, stations); songs.implicit.addElement(data); good++ ; else 400 { type = aSong.getType(); 11 put the song in a list to pick from later if(type== Song.EXPLICIT) 40S // your djs don't matter if you explicitly rated the song songs. explicit.addElement(data); else if (type == Song.lMPLICIT) 'o data.calculateDJs(items, albumAndArtist); songs.implicit. addElement(data); else if(type== Song.UNRATED) 415 data.calculateDJs(items, albumAndArtist); songs. unrated. addE lement(d ata) ; 11 calculate the score data.score(weights, stations); 420 good++; 425 Util.out(out, "scores calculated " + thneStamp()); /I for all the songs we didn't get for whatever reason, make sure we 11 are accounting for their plays for compliance with RIAA rules lastPlayed.markRecentlyPlayed(songCache, songs); 43,3 Util.out(out, "reccatly played albums and artists marked " a timeStamp()); Util.out(out, "Of " + tested + " songs, these are the reasons for exclusion " App. 2-1 14 + reasons.get(l) + " were already excluded' " + reasons.get(2) t- " were not encoded, " 435 + reasons.get(3) + " were played in the last 3 hours, " + reasons.get(4) + " had explicit Iyrics, " + reasons.get(5) + " were not in mediaType " + mediaType + ", " + reasons.get(6) + " were not in their genres, " + reasons.get(7) + " had an implicit rating of 0."); 440 Util.out(out, "There are " + good + " songs available for play"); /** * Gets a user's preferences for their playlists */ 4ó5 public boolean gctOptions(DBConnection cone) int rowCount 0; short tempRatio; short bandwidth = 0; 450 // returns: ratio, factor, mediaType String sql = "exec sp IcGetPreferences_xsxx " + userlD; try DBResultSet rs = conn. executeSQL(sql); 455 if (!rs.getBOF0 && !rs.getEOF()) tempRatio = (short) rs. getint("unratedQuota"); if (tempRatio > 0 && tempRatio < 100) ratio = tempRatio; 460 playExplicitLyrics = rs.getBoolean("explicit"); I/ if there was no mediatype set from the parameters II set it to the default if (!speed isSet()) speed.set(rs.getShort("bandwidth")); rowCount++; catch (DBException oops) 470 { Util.debug("DB Exception in getOptions: " + oops. getMessage()); med i aType = Med i a. getMed iaType(speed, format) ; Util. debug("Play dirty songs?: " + playExp]icitLyrics); 475 Util.debug("Bandwidth: " + speed.toString()); Util.debug("Format: " + format.toString()); Utii.debug("mediaType: " + mediaType); return (rowCount > 0); 480 /* * * Creates a playlist. */
public Playlist createPlaylist(DBConnection cone) 485 Util.out(out, "start of createPlaylist " + timeStamp()); Playlist playlist = new Playlist(playlistlD); gatherMedia(conn); processSongs(); playlist = makePlaylist(factor, ratio, playlistSize, playlist); 490 Uti].out(out, "end of createPlaylist " + timeStamp()); return playlist; private void logCreate(DBCon1ection cone) App. 2-115 495 try conn.cxecuteSQL("exec sp_lcLogPlaylist lxxx " + userlD + ", " +djlD+"," 500 + moodlD + ", " +O+ ", " + mediaType + ", " + elapsedTime() ); 505} catch (DBException e) Util.debug("DBException in logCreatc: " s e.toString()); 510} /** * Creates and immediately saves a playlist. */
public Playlist create(boolean save, SimplePlaylist oldPlaylist) { DB Con n ecti on conn = nu l l; Playlist playlist= null; try 52D conn = new DBConnection(); getOptions(conn); playlist = createPlaylist(conn); Util.out(out, "starting to save playlist " + timeStamp()); if (save) 525 playlist.save(conn, oldPlaylist); logCreate(conn); Util.out(out, "done saving playlist " + timeStamp()); conn.cioseO; 550 catch (DBException oops) Util.out(out, "DBException in create: " + oops.getMessage()); catch (Throwable e) 535 { System.err.printin("Generic Exception caught in PlaylistGenerator: " + e.toString()); e. printStackTrace(); return playlist; 540} public Playlist makePlaylist(int factor, int ratio, int playlistSize, Playlist playlist) Util.out(out, "ordering..." + timeStarnp()); songs.sort(songs.explicit); 545 songs.sort(songs.implicit); songs.sort(songs.unrated); Util.out(out, "finished sorting vectors at " + timeStanop()); playlist.counts = new PickCount(userlD, djlD, ratio, playlistSize, songs, out); 11 set up the piaylist 550 playlist.userlD = this.userlD; playlist.moodlD = this.moodlD; playlist.djlD = this.djlD; playlist.mediaType= this.mediaType; 11 copy the list of albms and artists recently played 555 // for the RIAA rules p]aylist.albums = (IntHash) songs.albumCounts. clone(); App. 2-116 playlist.artists = (IntHash) songs.artistCounts. clone(); 1/ pick songs pickSongs(playlist); 560 // check if we got everything we need if (playlist.media.size() < playlistSize) Util.out(out, "We only got i' + playlist.media.size() + " songs for user " + playlist.userlD + ". Playing popular music in mediaIype " + mediaType); 565 // uh oh, we didn't get enough songs; play popular stuff playlist. counts.explicit = 0; playlist.counts.implicit = 0; p iayl ist. counts. unrated = p l ayl istS ize; playlist.albums = (IntHash) songs. alburnCounts.clone(); 570 playlist.artists = (IntHash) songs.artistCounts.clone(); playl ist. resetSources(); playlist.media.removeA]IElements(); playlist.popularOnly= true; 575 songs.importPopular(songCachc.getPopular(mediaType), lastPlayed, playExplicitLyrics); pickSongs(playlist); /I pick news pickNews(playlist); 5ao Util.out(out, "picked news ''+ timeStamp()); 11 pick ads pickAds(playlist); Util.out(out, "picked ads " + timeStamp()); 11 pick tips 5g5 pickTips(playlist); Util.out(out, "picked tips " + timeStarnp()); Util.out(out, "playlist has " + playlist.length() + " songs"); Util. out(out, "shuffling playlist..."); return playlist.shuffle(); 590} public void pickNews(Playlist list) list.news = songCache. randomClipList(SonginfoCache.TYPE_NEWS, mediaType, Constants.MAX NEWS ITEMS) _ _, 595} public void pickAds(Playlist list) list.ads = songCache. randomClipList(SonginfoCache.TYPE_AD, mediaType, Constants.MAX_ADS); 600) public void pickTips(Playlist fist) list.tips = songCachc. randomClipList(SonginfoCache.TYPE_TIP, mediaType, Constants. MAX_TIPS_ITEMS); 605} public Playlist pickSongs (Playlist list) Util. out(out, "start of pickSongs " timeStamp()); PickList pickTypes = new Pickl.ist(list.counts); 610 int pickOrder = 0; int iteration = 0; int artistlD, albumlD, artistCount, albumCount; short type; SongData pick; 515 SongGroup songGroup; while (pickTypes.size() > 0) iteration++; App. 2- 117 pick = null; 620 songGroup = null; 11 get a group to pick from type = pickTypes.getRandom(); if (type == Song.EXPLICIT && songs.explicit.size() > 0) 625 songGroup = songs.expl icit; else if (type == Song.lMPLICIT && songs. implicit.size() > 0) songGroup = songs.implicit; 630 3 else type = Song. UNRATED; sDngGroup = songs.unrated; 635} 11 pick a random song from a group pick = songGroup.pickRandom(factor); 11 if we have none of that type, try another if (pick == null) 640 { pickTypes.reAdd(type, songGroup, songs); continue; artistlD = pick. getArtistlD0; 64S albumlD = pick.getAlbumlD(); artistcount = 0; albumCount = 0; 11 check for RIAA compliance 11 various artists and soundtracks don't count 650 if (!Artistinfo.isVariousArtists(artistlD)) artistCount= list.artists. get(artistlD); albumCount = list.albums.get(albumlD); if (artistCount ≥ Constants.RIAA_MAX_SONGS BY_ARTI ST 11 albumCount ≥ Constants.RIAA MAX_SONGS_FROM_ALBUM) 655 { pick.status. status = PickStatus.REIECTED; 11 Util.debug("Song rejected by RIAA"); 11 we have too many from this artist or album. Try again.
pickTypes.reAdd(type, songCroup, songs); 660 continue; 11 increment the album and artist counts if (!Artistinfo. isVariousArtists(artistlD)) list.artists.increment(artistlD); 66S list.albums.increment(albumlD); 11 add it to the playlist list.append(pick); pick. status. status = P ickStatus. PICKED; p i ck. status. order = ++p ickOrder; 670} songs. ordered = false; Util.out(out, "end of pickSongs " - timeStamp()); return list; 675 public void toMatrix(ServletOutputStream out, int displayType) songs. order(); String h 1 begin -- ""; String hlend = ""; 6SO if (displayTypc == Util.DISPLAY_HTML) App. 2-118 hlbegin = "<P><H1>"; hIend= "</HI>"; 685 Util.out(out, h l begin + "Item Ratings" + hl end + Util.newLine); itcms.print(out, songCache); Util.out(out, h l begin + "Explicitly Rated Songs" t- hl end + Util.newLine); songs.toMatrix(out, Song.EXPI,ICIl, displayType); Util.out(out, hi begin + "Implicitly Rated Songs" + h lend + Util.newLine); 690 songs.toMatrix(out, Song.lMPLICIT, display l ype); Util.out(out, h I begin + "Uuated Songs" + h I end + Util.newl ine); songs.toMatrix(out, Song. UNRATED, displayType); il t hlbegin + "Excluded Songs" + hicnd + Util.newL.ine 11 songs.excludedList(); 695 3 public String timeStamp() Date now = new Datc(); if(startDate== null) 7DO startDate = lastDate = now; double cliff= (now.getTime() - lastDate.getTime()) / 1000.0; double total = (now. getTirne() - startDate.getTime()) / I OOO.O; 705 lastDate = now; return Util.newLine t "------------------------------- -------" + Util.newLine + cliff+ " lap time, " + total + " total" + Utii.newLine + "--------------------------------------" + Util.newLine; 710} public doubic elapsedTime() Date now = new Datc(); if(startDate == null) ( startDate= lastDate = now; return (now.getTime() - startDate.getTime()) II OOO.O; 72D} PlaylistGenerator.java Page 18 of 18 11/05/99 1:24 PM APD. 2-119 P1aylistGeneratorSerlet package conn.launch.PlaylistGenerator; import java. io. *; s mport javax.servlet.http.HttpServlet impon javax. servlet.http.HttpServletRequest mport javax.servlet.http. HttpServletResponse mport javax.servlet.ServletConfig unport javax. servlet.ServietException o importjavax.servlet.ServletOutputSirearn import jaYa.util. * # r -------------- -.
s r P]aylistGeneratorServletjava 6/30/99 Servlet that creates LA UNCHcast playlists * Copyright (c) 1999 Launch, Inc * (author Jeff Boulter r; public class PlaylistGeneratorServlet extends HttpServlet { SonginfoCache songCache Thread cacheUpdater; public void generatePlaylist(HtipServletRequest request { HttpServletResponse response) throws lOException // get stream for output ServletOutputStream out = response. getOutputStream() j f ( erat drPbarameters prop = new Gen eratOrp 3s e Ise response. setCon tentType("texVplain "); response. setContcntType("video/x-ms-asf'); PiaylistP rameters params - new Pla list Pa is Y Parameters stah'5 i St(atUs)statUs = new Playliststus(prop us (IPD (P)), if (prop.debugO) out.print(status.toStringO); boolean generate = true s 1I no need to regenerate fight now, use an old playlist f (prop. forceRefreshO) if(prop.debugO) ou1.printin("generating because forceRefresh is on"); so else if(status.isStaleO) if(prop.debug()) out. printin("generating because the playlist is stale"); else if (prop.speed() .isSet() && (prop.speed().get() != status.speed.get())) if (prop.debug()) out.printin("generating because the medial ypes are different"); else if (prop.formatO.isSet0 && (prop.fonnat().get() != status.forrnat.get())) if (prop.debug()) out.printin("generating because the media formats are different") APD. 2-120 3]45 else if (prop.moodlD() != status. moodlD) 65} if(prop.debug()) out.printin("generating because the moods are different"); {else if(prop.djlDO!= status.djlD) if(prop.debug()) out. printin("generating because the djs are different") else generate = false; f (!generate) // ve can use an old playlist // reset the ad, news, and tip dates 5U if (status.playlist!= null) } statUs.resetDates(); Playlist pinylist = new PlDylist0; e5 playlist. userlD = status.userlD; out.print(playlist.toASX()); 90} cise // we have to generate the playlist ServletOutputStrearn outStream = null; if (prop. debug()) outStream = out; oo ''<PRE>"); out.printin("regenerating playlist with parameters: " + params.toStringO + out flusl,(); P aylistGenerator gen = new PlayLstGenera 8yli5t playlist = gen create(!prop dOntsave0or(pairl)ams, sOngCache, outstream); if (prop.debug()) out.printin("</PRE>"); if (prop. debugFormatO == Util.DISPLAY TEXT) out.printin("<PRE>") out. println(playlist.toStringO <P if (prop.matrix()) // out.printin("<FONT SIZE=-]>") gen.toMatrix(out, prop.debugFor-mat()) } outprintln("</FONT>); t20 if(prop debugFormal() --- Util.DISPLAY TEXT) out.printin("</PRF>") out.prmtin("<XMP>" 1 playlist toASX() + "</XMP>") App. 2-121 t46 else t25 out.print(playlist.toASX()); out.close() public void refreshPlaylist(HttpServletRequest request { llttpScrvletResponse response) tiuows lOException // get stream for output t3S ServietOutputStream out = response. gctOutputStrcam() responsc.setContent] ype("text/plain") /! this is thc stuffcoming in on the query string GeeratorParameters prop = new CeneratorParameters(request) PlaylistParameters params = new PlaylistParameters(prop); o // this is what's in their current playlist PlaylistStatus status = new PlaylistStatus(prop.userlD()) status. init(out); if (prop.debug()) out.print(status.toStringO); if (stahs. isStale()) ServletOutputStreann outStream = null; params = new PlaylistParameters(status) if (prop.debug()) outStream = out; ut printin("refreshing playlist with parameters: " + params.toString()); 160) PlaylistGenerator gen = new PlaylistGenerator(params, songCache, outStream) Playhst playlst = gen.create(!prop.dontsave(), status.playlist) ; {else out.printin("No need to refresh playlist now"); o out.closc(); public void doGet ( HttpServletRequest request HttpServletResponse response ]75) throws ServletException, lOException { {ry //Util.debug("PlaylistGeneratorServlet recieved a Get") // prevent caching response.setleader("Pragma", "no-cache") response. setHeader("Cache-control", "no-cache") response.setHeader("Expires", "0"); App. 2-122 385 // figure out what we need to do String actionStr= request. getParameter("action") if (actionStr == null) actionStr = new String("generate"); if (actionStr.equals("refresh")) { } refreshplaylist(request' respOnse); else if(actionStr. equals("cachestatus")) ServletOutputStrearn out = responsc. gefOuipurSrream() response.setContentType("text/p la in "); songCache. ratingsCache.status(out, request.getParameter("detail") != null); oul. close(); 200} else //defau It action generatePlaylist(request, response); 205} catch (Throwable e) f e.toStringO); System.err.printin(new Date(). toString() + " Caught an exception in doGet: " 210 e.printStackTrace() public void doPost(HttpServletRequest req. ilttpServletResponse resp) throws ServletException, { Util. debug("PlaylistGeneratorServ]et recieved a Post"); try 220 String user_agent=req.getHeader("USER AGENT"); if (user agent. equals(com.launch.misc.constants.PLAYLlST SERVER)) // need to generate play list and return it GeneratorParameters prop = new GeneratorParameters(req) 225 PlaylistParameters params = new PlaylistParameters(prop); PlaylistGenerator gen = new PlaylistGenerator(params, songCache, null) Playlist playlist = gen.create(true, null); 230 Playlist2 playlist2 = playlist.toPlaylist2(); ObjectOutputStream oos=new ObjectOutputStream(resp.getOutputStream()) oos. wrteObject(playlist2); oos.flust() oos.close(), 235 3 else if(user agent. equals(com.launch.misc.constants.RAT[NG_V/IDGET)) /I need to update cache with new info 240 int data size=req.getContentLength(); byte b[]=new byte[data size]; req.getinputStream().read(b,0,data size); Vector v=(Vector)(new ObjectinputStream(new ByteArrayinputStream (b))).readObj ect(); 24S Util.debug("received a list of changed ratings " 3- v) //need to tell cache ofthese changes App. 2-123 Enumeration e=v.elements() ; while (e.hasMoreElements()) 250 { songCache.ratingsCache. putlntoCache((CachedRating)e.nextElement()); else 255 { person: " + user_agent); Systern.err.printin("PlaylistGeneratorServlet received a post from an unknown 260 catch (Throwable t) t.printStackTrace(); 265 /. * * Initialization method * */ 270 public void inn' (ServletConfig config) throws ServietException super. in i t(con fig); songCache = new SonginfoCache(null) 11 start the updater thread cache Updater = new Song] nfoCacheUpdater(this) 275 cacheUpdater.setPriority(Thread.MIN_PRIOR]TY) cacheUpdater.start(); songCache.ratingsCache = new RatingsCache(); 2RO /** * Destroy method * get rid of the apt 285 * servlets "should have" a destroy method for garbage collection public void destroy() cacheUpdater.stop(); cacheUpdater = null; 2go songCache = null; 3} PlaylistGeneratorServletjava Page 5 of 5 1 1/05/99 1:21 PM App. 2-124 PlaylistMaker package com.launch. PlaylistGenerator mportJavax.servlet.ServletC)utputStream; th j5 is the dumb class for ASP public class PlaylistMaker public PlaylistGencrator generator o public P,aylist playlist; public PlaylistMaker() generator = nevv PlaylistGeneratorO; public void init(int userlD, int djlD, short mediaType, int mood}D, int playlistlD) 3 //generator.init(userlD, djlD, moodID); public int make() playlist = generator.create(false, nul1); retum playlist.lD; public int makeAndSave() o playlist = generator.create(true, null) retum playlist.lD; ' public void toMatrix(ServletOutputStream out, int displayType) generator. toMatrix(out, displayType); public String toASX() } retum playlist toASX(); 45} PlaylistMakerjava Page I of I 1]/05/99 1:32 PM App. 2-125 PlaylistParameters package conn.launch.PlaylistGenerator public class PlaylistParameters int userlD; int djlD; int playlistSize= Constants.DEFAULT_Pl,AYi IST_SIZE int moodlD; o Bandwidth speed = new BandwidthO hediaTormat format = new MediaFormat() public P1aylistParameters(h1t userlD) this.userlD = djlD = userlD; |5} public PlaylistParameters(int userlD, Bandwidth speed, int moodlD) this(userlD); if (speed!= null) this.speed = speed; this.tnoodlD = moodlD; public PlaylistParameters(int userlO, Bandwidth speed, int moodlD, int djlD) ao this(userlD, speed, moodlD); if (djlD > 0) } this djlD = djlD; p U b l i c P l a y i i s t P a r a m e t e r s ( P l a y i i s t S t a t u s s t a t u s) th is(status.userlD, status.speed, status. moodlD, status. dj lD); public 1'1aylistParameters(GeneratorParameters prop) this(prop.userlDO, prop. speedO, prop.moodlD(), prop.djlDO); public String toString() return "userlD=" + userlD + ", " + "bandwidth=" + speed.toString() + ", " + "moodlD=" + rnoodlD + ", " + "djlD=" + djlD; PlaylistPararneters.java Page 2 of 2 1 1/05/99 1:35 PM App. 2-126 l PlaylistStatus package corn.launch.PlaylistGenerator; import java.util.Date; import javax.servlet.ServletOutputStream; public class PlaylistStatus int userlD, newRatingsCount, moodlD, djlD, songsRemaining short mediaType; o Date lastPlaylist = new Date(); MediaForrnat fonnat; Bandwidth speed; Date dbDate = ncw Date(); public SimplePlaylist playlist; public PlaylistStatus(int userlD) { format= new MediaFormat(MediaFormat. WINDOWSMEDIA) this.user]Dc user1D; public String toStringO return "Playlist status for userlD " + userlD + ":" + Util.newLine + " newRatingsCount: " + newRatingsCount + Util.newLine t- " moodlD: " + moodlD + Util.newLine o + " djlD: " + dilD + Util.newLine + " songsRemaining: " + songsRemaining 1 Util.newLine - " mediaType: " + mediaType + Util.ncwLine; public void init(ServletOutputStream out) try DBConnection con n = new DB Connecti on() ; DBResultSet rs = conn.executeSQL("exec sp_lcGetPlaylistinfoForUser xsxx " + userlDj; while (!rs.getBOF() && !rs.getEOF()) { newRatingsCount = rs.getl'1f(''newRatirigsCount''); lastPlaylist = rs. getTimestamp("lastPlaylist"); dbDate = rs.getTimestamp("dbDate"); playlist = SimplePlaylist.fromBytes(rs.getBytes("playlist")); rs.next(); if(playlist!=nuli) ( songsRemaining = playlist.songs.size(); moodlD = playlist.moodlD djlD = playlist.djlD; mediaType = playlist.mediaType; speed = Media.type loBandwidth(n1ediaTypc); 50} App. 2-127 conn.close(); catch (DBException oops) Util.out(out, "DBException in PlaylistStatus. init: " + oops.toString()); public void resetDates() if (playlisl == null) retUm; Util.debug(new Date().toString() + " Playlist OK, just resetting datcs for userlD " + userlD) playhst.resetDates(dbDate); playlist. save(userlD); public boolean isStale() double oneWeek = Util.MILLISECONDS IN SECOND * Util.SECONDS_IN M]NUTE * Util.MINUTES IN HOUR * Util.HOURS IN DAY * Util.DAYS IN WEEK; so if(songsRemaining≤Constants.REFRESH AT SONGS LEFT) rehn1 true; /1 if you're listening to someone else's station, your new ratings // won't make a difference dj]D) if(newRatingsCount≥Constants.REFRESH AT NEW RATINGS COUNT&&userlD== retune true; if (new Date().getTime() - lastPlaylist,getTime() > oneWeek) ro return tne; retum false; /* public void flushPlaylist(Serv]etOutputStream out) try no DBConnection conn = new DBCoMection() DBResultSet rs = conn.executeSQL("exec sp_lcFlushPlaylist xxud " + userlD); conn.close(); catch (DBException oops) Il5 { Util.out(out, "DBException in PlaylistStatus::flushPlaylist: " + oops.toString()); zo public void deletePlaylist(ServletOutputStream out) try App. 2-128 { ]53 DBConnection cone = new DBConnection() I25 DBResultSet rs - conn.executeSQI.("exec sp IcDeletcPlaylist_xxud " + userlD); catch (DBException cops) i30 Util.out(out, "DBException in PlaylistStatus::deletePlaylist: " + oops.toString()); public void resetClipSchedule() t ry DBConnection conn = new DBConnection() |40 DBResultSet rs = conn.executeSQL("exec sp_lcResetClipSchedule_xxux " - a userlD}; catch (DBException cops) I45 Util.debug("DBException in PlaylistStatus::resetDates: " + oops.toString()); a/ {5D PlaylistStatusjava Page30f3 11/05/991:24 PM AND. 2-129 PopularSongs package com.launch.PlaylistGenerator; import java.util.Vector; import java.util.Hashtable; import java.util.Enumeration public class PopularSongs private Hashtable byMedia; o public Songl ist get(short mediaType) return (SongList) byMedia get(new Short(mediaType)); public PopularSongs(Hashtable songs, Hashtabie mediaTypes) byMedia = new Hashtable(l); // make a list of all songs and sort them SongList all = new SongList(songs); all.sort(); // create each of the song lists for (Enumeration e = mediaTypes.keys(); e.hasMoreElements();) { Short mediaType = new Short(((lnteger) e. nextEiementO).shortValue()); byMedia.put(mediaType, new SongList()); o Songinfo info; Media track; SongList list; 1/ put each into a separate list for each medial ype for (int i = 0; i < all.size(); i++) info = all.elementAt(i); for (int j = 0; j < info.media. size(); j++) { track= info.media.typeAt(); iist = ((SongList) byMedia. get(new Short(track.mediaType))); list.addElement(info); 1/ truncate each list to the top 1000 most popular songs for (Enumeration e = mediaTypes.keys(); e.hasMoreElements();) so { Short mediaType = new Short(((lntcger) e.nextElement()).shortValue()); list - (Songl.ist) byMedia. get(mediaType) list.setSize( I 000); PopularSongs.java Page 2 of 2] 1/05/99] :24 PM App. 2-130 Population package com.launch. PlaylistGenerator; import Java.util.Enumeration import java.util.Date; import java.text.SimpleDateFormat import java.util.Vector import java. util.Hashtable; import javax.servlet.ServletOutputStream; import Java. text.L)ateFormat lo public class Popaiation /* private int readers = 0 is private int writersWaiting 0; private boolean writing= false; */ private boolean haveTitles = false public boolean ordered = false; public SongGroup explicit public SongGroup implicit; public SongGroup unrated; private llashtable hash; public IntHasil artistCounts public IntHash albumCounts; public PopulationO explicit = new SongGroup(); mptct = new SongGroup(); unrated = new SongGroup(), artistCounts = new IntHash(); a l bum Counts = new IntH ash(); hash = new HashtableO; /* public synchronized void addReaderO a readers; public synchronized void removeReader() --readers; if(readers == 0) } n tifYAil(); public synchronized void reques(Write() ++writersWaiting; App. 2-131 15G public synchronized void finishWrite() --writersWaiting; if (writersWaiting == 0) { notifyAI l(); */ /I returns this song if it's valid for adding data, null otherwise public synchronized Song initSong(int songlD, short type) { if (type ≤ o) return null; boolean result = true; /* requestWrite(); while (readers > 0) try { wait(); } catch (InterruptedException e) {} writing = true; */ Song song = get(songlD); if (song == null) ff song = new Song(songlD, type); put(songlD, song); 11 if it's excluded, it's not valid for modifying if(type== Song.EXCLUDED) loo result = false; else result = song.set Fype(type); 105} if (result) return song; loo 11 writing= false; 11 finishWriteO; return null; n5 public synchronized SongData initSongGetData(int songlD, short type) Song aSong = initSong(songlD, type); if(aSong == null) loo return null; return aSong.getData(); App. 2132 } 157 I25 public synchronized SongData getSongData(int songlD) return getSongData(new Integer(songlD)); loo public synchronized SongData getSongData(lnteger songlD) Song s = get(songlD); if(s=- null) return null; return s gctData(); loo public synchronized SongData getSongData(int songlD, short type) SongData result = mill; /* I45 synchronized (this) while (writersWaiting > 0) So try { waitO; } catch (InterruptedException e) { } acidReader(); */ Song song = get(songlD); 1/ there's no song for that ID; Did you call initSong? |60 If (song!= null && type ≥ song.getType()) result = song.getData(); I/ removeReader(); return result; i65 public synchronized Song get(int songlD) return get(new Integer(songlD)); public synchronized Song get(lnteger songlD) } return (Song) hash get(songlD); public synchronized Song rernove(int songlD) lBO} ret urn rem ove(new I nteger(song lD)); public synchronized Song remove(lnteger songlD) return (Song) hash.remove(songlD); App. 2133 18S} private synchronized Song put(int songlD, Song song) return (Song) hash.put(new Integer(songlD), song); 90} private int available() int i = 0; ! 5 for (E2numeration e = hash.keys(); e hasMoreElements() ;) { Song song - get((luteger) euextElement()); if (so ng. type! = S ong. EXCL U DED) 203 { i++; return i; 205} public Enumeration keys() return hash. keys(); 210} public Yoid order() createVectors(); 215 sortVectors(); public int excludedCount() 220 int result = 0; for (Enumeration e = hash.keys(); e.hasMoreElements() ;) Song song = get(((lnteger) e.nextElement()).intValue()); if(song.tYpe == Song.EXCLUDED) result++; 230 renrn result; public boolean isEligible(int songlD, ht artistlD, int albumlD) ( Song song = get(songlD); if (song!= n u l l && song.type == Song. EXCI.UDED) return false; if ((artistCounts.get(atistlD) < Constants. RIAA_MAX_SONGS BY_ARTIST) && (albumCounts.get(albuml[)) < Con.stants.RIAA_MAX_SONGS_FROM_ALBUM)) return true; 245 rehrn false; ApD. 2-134 public void createVectors() 250 { explicit. removeAIIElementsO; implicit.removeAIIElements(); unrated. removeAIIElements(); 2s, for (Enumtration e = hash.keys(); e. hasMoreElements();) { // Utilxlebug("interation " -r i); Song rnySong - get((loteger) e nextElement()); t'O if (mySong!= nul 1) Song Data data = mySong.get Data() ; if (mySong.type == Song.EXPLICIT) 7t,5 explicit.addElement(data); else if (mySong.type == Song. lMPLICIT) implicit.addElement(data); else if (mySong.type!= Song.EXCLUDED) unraied. addElement(data); 270} public void importPopular(SongList abunch, PlayDates lastPlayed, boolean playBadWords) 275 { SongTnfo info; SongData data; Song ditty; int added = 0; unrated.setSize(0); long now = new Date() .getTime(); 285 long lastThreeHours = Util.Mll.LISECONDS IN_SECOND * Util.SECONDS IN_MlNUTE * Util.MTNUTES IN_HOUR * 3; so long playedTime = 0; Date playedAt; for (int i = 0; i < abunch.size(); i++) 295 { info = abunch, elementAt(i); playedAt= lastPlayed.get(info.songlD); 11 don't play songs twice within 3 hours 300 if (playedAt == null 11 (now - playedAt.getTime()) > lastThreeHours) if(playBadWords 11!hfo.hasExplicitLyrics()) data hlitSongCctData(info. sorglD, Song.lLNRATF.D); if (data!= null) App. 2-135 o data.setinfo(info); unrated.addElement(data); added±; 315} Util.debug("import popular added " + added -t " songs"); public void sortVectors() sort(explicit, 0, explicit.size() - ) sort(itnplicit, 0, implicit.size() - Ij; 325 sort(unrated, 0, unrated.size() - ]); // Util.debug("after sorting, ratedVector is: " + ratedVector.toString()) // [Jti l.debug("after sorting, unratedVector is: " + unrated Vector.to String()); ordered = true; 330} public void sort(Vector a) sort(a, 0, a. size() - I); 335} private void sort(Vector a hit from int to) 340 // quicksort // If there is nothing to sort, return if ((a == null) || (a.size() < 2)) return; int i = from, j = to; SongData center = (SongData) a. elementAt((from + to) / 2); do { 350 while(() < to) && (center.score < ((SongData) a.elementAt(i)).score)) i++; while(j > from) && (center.score > ((SongData) a.elementAt(j)).score) ) j--; SongData temp = (SongData) a.eiementAt(i); a.setElementAt(a. elemelltAt(;), i); 355 a.setElernentAt(temp, j); // swap elements if(i ≤i) { i++;i--; } } while(i ≤j); if (from < j) sort(a, from, j); // recursively sort the rest if(i < to) sort(a, i, to); public String toString() String result ""; App. 2-136 for (Enumeration e = hash.keys(); e.hasMoreElements() ;) { int songlD = ((Integer) e.nextElement()).intValue(); Song song = get(songlD); result= result.concat("songlC) " + songlD + " = " + song.toString() Util.newLine); return result; public String sourceCr:>unt() 335 { Intidash counts = new lntHash(); String explicitList= ""; for (Enumeration e = hash.keys(); e.hasMoreElements() ;) f Song song = get(((lnteger) e.nextElement()).intValue()); if (song.getType() == Song. EXPLICIT) 395 explicitList explicitList.concat(song.songlD + ", "); counts. increment(song.type); return "counts EXPLICIT = " + counts.get(Song. EXPLiClT) + " (" + explicitList + ") " 405 + " IMPLICIT= " + counts.get(Song.lMPLICIT) + " EXCLUDED = " + counts.gct(Song.EXCL.UDED); public void toMatrix(ServletOutputStream out, int songType, int displayType) String delim = "''; String prefix = ""; 415 Slring suffix = "''; String rowPrefix = ""; String rowSuffix = ""; String bold = ""; String unbold = ''"; if(displayType== Util.DISPl..AY,l] TML) delim = "</TD><TD>"; prefix = "<TABLE CELLPADDING=I CEI,I.SPACING=0> "; 425 suffix = "</TABLE>"; rowPretix - "<TR><TD>"; rowSuffix = "</TD></TR>"; bold = "<B><FONT SIZE=\"-1\">"; unbold = "</FONT></P5>''; 430} else App. 2-137 delim = "\t" 43S Util.out(out, prefix); String header = Util. newLine + rowPrefix + bold + IJtil.join(unbold + dclim + bold, SongData.namesArray()) + unbold + rowSuffix; Vector v - null; d45 if (songType = Song.EXPL.ICIT) v = explicit else if(songType =Song.lMPLICIT) v = implicit; else 450 V = unrated; if (v!= nul 1) 455 for (int i = 0; i < v.size(); i++) SongData data= (SongData) v. elementAt(i); if (i % 40 == 0) 460 Util.out(out, header); Util.out(out, data.tuDisplayString(displayType, (i + ]))); 465} Util.out(ot, suffix); Population java Page 9 of 9 11/05/99 1:38 PM App. 2-138 ]G3 Rating package com.launch. PlaylistGencrator; public class Rating s protected short rating; protected boolean set = false public Rating() 10) /** * create one with a default *l public Rating(short defaultRating) } rating = defaultRating; 2C public boolean isSct() retune set; public void set(short newRating) rating = newRating; set = true; public short get() r eturn rating; public String toString() if (!set) return rating + "(Not Set)"; else return "" + rating; 45} Rating.java Page I of I 11/Oa/99 1:28 PM App. 2-]39 RatingsCache package com.launch. PlaylistGenerator; import java.util.*; import javax.servlet. ServletOutputStream; import java.io.lOException; public final class RatingsCache implements GetRatingsCacheUsersInterface, Constants /** * This Hashtable wit' be ofthe forth lo * (Integer userlI), Hashtable CachedRating objects), if the Data in * the cache is invalid the entry will be of the form * (Integemseril), INVALID DA TV) * <br> * The Hashtable of CachedRating objects is of the form (integer itemlD, CachedRating) * */ private Hashtable ratings List = new Hashtab l e( I) private GetRatingsCacheUsers gtu; private FrequencyCounter freoLcounter = new frequencyCounter(RATINGS CACHE INITIAI_SIZE); private Date lastUpdated = new Date(); private Date lastReset = new Date(); // ------- -----_ - __ __ - _ _ _ _ _ _ _ _ _ _ _ _ _ public RatingsCache() gtu = new GetRatingsCacheUsers(this); so /I the following line is for testing purposes only, rem it out otherwise.
/I gtu.SLEEP_TIME=5*60*1000; gtu start(); /** * This method will get a list of rating for the given userids $ (0param userid an array of ints representing userids, each entry should be a valid userlD, do not pad with zeros.
* Return a Vector of CachedRating objects **/ public final Vector getRatings(Vector users) 1/ // algorithm // // check for userid in Hashtable // if found add to vector of ratings // else build list of unbound things // get list of unbound things from database Vector allRatings - new Vector(); Integer userlD; Hashtable ratingProfile Vector nonCachedUsers = new Vector(users.size()); Date startDate = new Date(); Enunneration e = uscrs.elements() while (e.hasMoreE1ements()) userlD -(Integer) e. nextElement0; ratingProfile = (Hashtable) ratingsList.get(userlD); if (ratingProfile == null) { App. 2-140 t65 Util.debug("RatingsCache MISS on user " + userlD); nonCachedUsers.addElcment(userl D); else { 1/ benchmark_datel = new Date(); Util.debug("RatingsCache HIT on user " + userlD); appendToVector(allRatings, ratingProfile.elements()); o // Util. printtClapsedTirne("Get from cache, " + temp_hash.size() + " entries", benchmark_date 1); freq counter.hicrernentValue(useriD); s if (nonCachedUsers.size() > 0) MergeVectors(allRatings, getRatingsFromDatabase(nonCachedUsers)); Util.printElapsedTime(Thrcad. currentThread().gctName() + ", got " + allRatings.size() + " ratings ", startDate); return allRatings; public final void updateCachcdUsers(Vector v) { setCachedUserlDs(v); public Hashtable getMostFrequentlyUsedUsers(int i) Hashtable h = freq counter.getLargest(i); gO Vector v = new Vector(h. size()); 1/ when we do this, also refresh the cache 1/ to clean out any iingering data corruption Util.dehug(new Date(). toString() + " Resctting ratings cache"); // clear the users in the cache setCachedUserlDs(v); oo lastReset= new Date(); /I put user hash into vector appendToVector(v, h.keys()); // get all the ratings setCachedUserlDs(v); return h; /** **/ public f nal void setCachedUserlDs(Vcctor userlDs) r5 lastUpdated = new Date(); Vector cachedUsers = (Vector) userlDs.clone(); Date benchmark_date = new Date(); if (cachedUsers.size() ≤ 0) { ratingsl,ist = ncw Hashtable(l); Util.dcbug("setCachedUserlDs: no users passed"); App. 2-141 return; 725 Enumeration e = ratingsList.keys(); Integer userlD; // find the differences between the users already in the cache // and the new list of users // leave that result hi cachedUsers t30 // interate through each user in the current cache while (e. hasMoreElements()) userlD = (Integer) e.nextEiement(); 13S // are they in the new list? if (cachedUsers.contains(userlD)) // cool, just remove them from the new list cachedUsers. removeElement(userlD); 40} else // they've been removed ratingsList.remove(userlD); I45} Vector newRatings = new Vector(); // get all the ratings for the new cached users if (cachedUsers.size() > 0) newRatings = getRatingsFromDatabase(cachedUsers); e = newRatings. elementsO; while (e.hasMoreElements()) putintoCache((CaciredRating) e. nextElement()); cise Util.debug(new Date().toString() + " setCachedUserlDs: no new users in cache''); Util. printElapsedTime("refreshed cached users and loaded " + newRatings.size() + " entries", benchmark_date); /** * **/ private final Vector getRatingsFromDatabase(Vector userlDs) / - // algorithm //- --- // query database for info // build vector from resultsets.
Vector results = new Vector(RATINCS CACIIE INITIAL_SIZE) Date benchrnark_date = new Date(); trio //--- get item rating -(ietitemRatingsFrornDB item Ratings = new Getitem RatingsFromDB(userlDs, results); 11--- get song rating -- GetSongRatingsFrornDF3 songRatings = new GetSongRathgsFromDB(userlDs, App. 2-142 j45 results); songRatings.start(); item Rat ings.start(); //--- must wait for the two threads to finish -- try { itemRatings join(); songRatings.join(); catch (InterruptedException c) { Svstem.err.printin("PlaylistCache: interrupted waiting for ratings, km not cleanning up"); //--- done getting just return values -- oo Util.printElapsedTime("GetRatingsFromDatabase, " + results.size() + " entries", b en ch m ark_da t e) ; return results; /** 205 * appends the contents of vector2 into vectorl **/ private static final void MergeVectors(Vector vector!, Vector vector2) vectorl. ensureCapacity(vectorl.size() + vector2.size()); No Enumeration e = vector2.elements(); while (e.hasMoreElements()) vectorl.addEiement(e. nextElement()); 215} public static final void append foVector(Vector v, Enumeration e) while (e.hasMoreElements()) 220 v.addElcment(e.nextElement()); public static final String GetVectorAsComrnaVelimitedL.ist(Vector v) 225 if (v==tIull) return("t'); String s =v.toString(); int vector_length=s.length(); if (vector_length ≥ 3) 2;0 return(s.substring( l,vector_length- I)); else retum(""); 235} /* * This method acids the value to the hashtable pointed to by the key, if the key does not exist yet it will create the first entry and the Hashtable 240 * */ public final void putintoCache(CachedRating value) RatingsProfile profile = null; 245 Integer userlD = new lnteger(value.userlD) l/ this could be more efficient if we inserted all the ratings for a particular user all at once App. 2-143 if (ratingsList.containsKey(userlD)) profile (RatingsProfile) ratingsList.get(userlD); 250} else profile=newRatingsProfile(RATINGS_CACHE INITIAL SIZE); ratingsList. put(userlD, profile); 255} if (value.rating < 0) 1/ unrate profile. remove(value.hashKey()); 263} else f profile.put(value.hashKey(), value);255} public final String toString() return ratingsList.toString(); public final String userList() String result = ""; 275 Enumeration e = ratings List. keys(); Integer userlD; while (e. hasMoreElements()) 250 userlD = (Integer) e.nextEien1ent(); result = result.concat(userlD + '', "); retum result; 285} public final void status(ServletOitputStream out, boolean detail) throws lOException out.print("RatingsCache has " + ratingsList.size() + " users" + Util.newLine 290 + "Last Updated at " + lastUpdated.toString() + Util.newLine + "Last Reset at " + lastReset.to.String() - Util.newLine + "UserList is " + userl.ist() + 295 Util.newLine); Enumeration e = ratingsList.keys(); Integer userlD; RatingsProfile profile; while (e.hasMoreElements()) userlD = (Integer) e. nextElement(); out.print(lJtil.ncwline + "Profi]e for userlD " a- userlD r ":" Util.newLine); profile = (RatingsProf le) rathigsl.ist.get(userlV); if (profile == null) App. 2-144 out.print("NULL!" + Util.newLinc); else 315 + " songs, " out.print(lltil.newLine + profile.colnt(Constants. lTE1Vt_TYPE SONG) profile.count(Constants.lTEM_TYPE ALBUM) 4- " albums, " profile,count(Constants.lTEM_TYPE ARTIST) " artists, " 12n -! profile.cowt((hytc) 0) " total" i- Util.newl.ine); if (detai 1) out.print(profile.toString()); 325} 3 3 RatingsCachejava Page 2 of 7 11/05/99 1:23 PM App. 2-145 RatngsProfile package com.launch.PlaylistGenerator; import java.util. Hashtable; import java util.Enumeration; s public class RatingsProfile extends Hashtable public RatingsProfile(int capacity) super(capacity); o} public int count(byte type) int count = 0; if (type ≤ 0) retum size(); {else Enumeration e= keys(); String key; CachedRating rating; while (e. hasMoreElements()) key = (String) e.nextElement(); rating = get(key); if (rating.type == type) count++; retum COUtit; o public CachedRating get(String key) return (CachedRating) super.get(key); public String roString() String result= ""; Enumeration e = keys(); while (e. hasMoreElements()) result = result.concat((gct((String) e.nextElement())). toString()); retum result; } } RatingsProfile.java Page20f2]1/05/99 1:35PM App. 2-146 RatingWidgetServlet package com.launch. PlaylistGenerator; import java.util.*; import java.io.*; s import java. net.*; import javax.servlet.*; import javax.servlet.http.*; /** o * * RatingWidgetSeivlet.java 7/8/99 * Initial Serviet for rathgs Widget * Copyright (c) 1999 LAUNCI-I Mcdia, Inc. * (!author lon Heiner 5 - - - - . _ _- -_ _ -_ _.. _ _ _ _ _ _. _ _ _ _ _ _ _ */ public class RatingWidgetServlet extends HttpServlet implements GetRatingsCacheUsersinterface, GetPlaylistServersinterface, Runnable o private Vector cachedUsers = new Vector(l); private CetRatingsCacheUsers gtu; private Vector playlistServers = new Vector( I); private GetPlaylistServers gps; /** This vector contains CachedRating objects */ private Vector dirtyRatings = new Vector(Constants.RATING_UPDATE_LIST_INITIAL_SIZE); private Thread myThread; / /** * Handle requests */ public void doGet ( HttpServletRequest request, HttpServletResponse response ) throws ServletException, lOException { String sEvent; String sRater; String sRatce; int iRateeType; o String sRating; int raterlD = 0; 1/ get parameters sEvent = request.getParameter("action"); // get stream for output ServletOutputStream out; response. setContentType("text/plain"); response. set Header("Pragma", "no-cache "); response.setHeader("Cache-control", "no-cache"); response. setHeader("Expires","0"); out = response.getOutputStreann(); try DBConnection conn = new DBConnection(); iC(sEvent.equa]s("lNlT")) sRater = request.getParameter("rater"); sRatee = request.getParameter("ratee"); iRateeType = Integer.parselnt( reqlest.getParameter(''ratee_type") ); ADD. 2- 147 int rating = -1; 11 not rated boolean implicit= false; String sql = ""; 11 SONG case if (iRateeTypc == Constants.lTEM TYPE_SONG)
sql = "exec sp_lcGetSonginfoSummary xsxx "
+ sRater + "," + sRatee; elseif(iRateeTypc==Constants.lTEM IYPE AL.BUM) 7S sql = "exec sp_lc(ietArtistOrAlbumRating_xsxx " + sRatee + "," + sRater; BO} else sql = "exec sp_lcGetArtistOrAlbumRating_xsxx " ss + sRatee + "," + sRater; DBResultSet rs = conn.executeSQL(sql); if (!rs.getBOF() && !rs.getEOF()) rating = rs.getint("rating"); out.println("rating_value=" + rating + "&Implicit indicator=nDt implicit"); 95} else if(sEvent. equals("RATING_EVENT")) /* Do update to LaunchCast Ratings Database */ sRater = request. getParameter("rater"); try raterlD Integer.parselnt(sRater); 305 catch (NumberFormatException e) tiuow new Exception("RatingWidgetServlet: rating received for invalid user: " + sRater); if (raterlD ≤ 0) throw new Exception(''RathigWidgetServlet: rating received for invalid user: " + raterlD); tI5} sRatee = request. getParameter("ratee"); iRateeType = Integer.parselnt( request. getParameter("ratee_type") ); sRating = request.getParanneter("rating"); // song case if (iRateeTypc == Constants. ITEM TYPE_SONG) App. 2-148 conn. executeUpdate("exec sp_lcRateSongUser_isux " + raterlD + "," t- sRatee + "," + sRating, true); ao} /1 album case else if (iRateeType = Constants.lTEM_TYPE_ALBUM) conn. executeUpdate("exec sp IcRateltemUser isux " rater|D -E "," + sRatee -t '','' 140]- sRating, true); // artist case else )45 conn.executeUpdate("exec sp_lcRateltemUser_isux " 4- raterlD + "," + sRatee + ",'' + sRating, tme); ouLprintin("confirrnation=rating confirnned"); if (cachedUsers contains(new Integer(raterlD))) I55 { CachedRating cr = new CachedRating(raterlD, Integer. parselnt(s Ratee), Byte. parseByte(s Rat i ng), (byte) iRateeType); dirtyRatings.addElennent(cr); Util.debug("Addcd change to ratings cache update queue: " + cr); else |65 oUt.printlO("erTor"); conn.close(); catch(DBException e) { o out. printin("DBException: " -E e.getMessage()); System.err.printin(new Date(). toString() + " DBException in RatingWidgetServlet: " + e toString()); catch(Exception e) out.printin("Exception raised: " + e); System.err. printh(new Date().toString() + " Exception in RatingWidgetServlet: " + e.toString()); out.close(); 130} public void inn' (ServletConfig config) throws ServletException { super.init(config); try { App. 2-149 |85 gtu = new GetRatingsCacheUsers(this); gps = new GetPlaylistServers(this); 11 the following 2 lines are for testing purposes only, rem them out otherwise.
// gtu.SLEEP_TIME=1 *20*1000; 11 gps.SLEEP_TIME=1*20*1000; ggs.start(); gtu.slart(); myThread = new Thread(this); myThread.start(); t95 catch (Exception e) throw new ServletException (); } /** * Destroy mctilod * act rid of the api * servlets ''should have" a destroy method for garbage collection *l public void destroy() { gps.stop(); gtu.stop(); 205} // .--__ ________ public void updateCachedUsers(Vector topUsers) cachedUsers = topUsers; 20} public void updatePlaylistServers(Vector v) playlistServers = v; public void run() 11 once every N minutes go update all cached ratings with some new ratings Util.debug("RatingWidgetServlet notify playlistgenerators of changed rating - thread started "); Z20 try Vector temp_dirty ratings; Enumeration enum; Socket s; 225 ByteArrayOutputStream bags; ObjectOutputStream 408; OutputStream os; BufferedWriter bw; byte b[]; 230 String server_ip -- null; while (dirtyRatings!= null) try 235 { if (dirtyRatings.size() > 0) baos = new ByteArrayOutputStream(1000); 408 = new ObjectOutputStream(baos); temp_dirty_ratings = d irtyRatings; dirtvRatings = new Vector(Constants.RATING UPDATE LIST_INITIAL SIZE); 1/ need to send info to cached servers here.
oos.writeObjecl(temp_dirty_rathgs); ors. USt1(); Apr>. 2-150 b=baos. toByteArray(); enum = playlistServers.elements(); while (enum. hasMoreElements()) 250 { try 11 Lhis nested try / catch is so if one server is down the others get updated too.
255 server_ip=(String)enum.nextElement(); Util.debug(ncw Datc().toString() + " RatingWidgetServlet: Sending changed ratings to: " + server_ip + " this vector: " + remp_dirty ratings); s=new Socket(server ip Constants.PORT MJM13ER); zo os=s.getOutputStream(); bw=new BufferedWriter(new OutputStrealnWriter(os)); bw.write(Constants.POST HEADER); 26S bw.newLine(); bw.write(com.launch.misc.constants.USER AGENT+":"+ com. launch.misc.constants.RATING_WIDGET); bw.newLine(); 270 bw.write("Content-length: " + b. Iength); bw.newLine(); bw.newLine(); bw.flush(); 275 os.write(b); os.flush(); os.close(); catch (Exception el) System.err. printin((new Date()).toString() + " Error contacting ratings cache at " + server ip); //e I.printStackTrace(); 285} catch (Exception e2) 290 { System.err. printin((new Date()).toString() + " Enor in RatingWidgetServlet CacheUpdater while loop"); e2.printStackTrace(); Thread.sleep(Constants. PROPAGATE_DIRTY RATING_SLEEP TIME); catch (Exception e) System.err. printin(new Date().toString() + " Fatal Error in RatingWidgetScrvet updater thread "); e.printStackTrace(); 305 Util.debug("RatingWidgetServlet notify playlistgenerat'rs of changed rating - thread done"); public Hashtable getMostFrequentlyUsedUsers(int i) ADD. 2-151 17fi 30return nu I I; /* eof */ RatingWidgetServletjava Page 7 of 7 11/05/99 1:35 PM App. 2-152 RecList package com.launch.PlaylistGenerator; import java.util.Vector; /** s * Launch Media, Inc Copyright]999 * Recommendation List - class which encapsulates recommendations coming from the net perceptions engine lo * RECOMMENDED USAGE $ to access values within a Recl,ist object: * * * void someFunction(RecList aRec) { * * if ( aRec.setToFirstRec() ) { * do { * System.out.printin( aRec.getidentifier() + ": " + aRec. getPredietedRating() ); } while aRec.incrernent(); * } * * * * The "prediction result" object in net perceptions is NOT * persistent so is unusable outside of a carefully controlled * environment * * Further, developers withal LAUNCH should not be exposed * to Net Perceptions data struenres (as they are ugly) * * file: ieunchNetPjava * ("author Jon Heiner * Since 7-30-99 */ public class RecList { private final static int kGrowVectorBy = 4; private Vector theRees; private int theNumRecs = 0; so private int thelndex = 1; /* Rec -- inner class * encapsulates the ID and predicted * value for the item in the list; * the inner values are made public * for convenience; they are exposed * to this class, but are not intented * to be used outside of this implementation */ public class Rec { public int thelD; public float theVahe; /* Rec - creation method * the variables should be immutable */ public Rec(int ilD, float fValue) { theValue = fValue; thelD= ilD; so /*$ RecList - creation method App 2- 153 * creates an empty rec list, which we will then add * Recs to; if you try to pull values fiom this it will * indicate that this is not possible */ public RecList() { theRecs = new Vector(O, kGrowVectorBy); 1/ create an empty vector /** RecList - creation method w/ ergs * creates a rec list with one element; use the add * method to add more values to it */ public RecList(int ilD, float fValue) { theRecs - new Vector(O, kGrowVectorBy); // create an empty vector this. add(ilD, [Value); 7S} /** compact * called once the RecList has been created and * all items are added */ 8U public void compact() { theRecs.trimToSize(); /** setToFirstRec * called to set us to the first rec * if this returns false, then there are * no recommendations in the list. */
public boolean setToFirstRec() { theludex = 0; if (theNumRecs > 0) return true; return false; /** increment * moves the internal pointer to the next item * returns false if there are no more Recs in * the'list. */
public boolean increment() { oo thelndex++; if (thelndex < theNumRecs) retum true; retum false; /** getidentifier * returns the item ID for the current item * in the Rec List */ public int getidentifier() { return (ins) ((Rec) theRecs.elementAt(thelndex)).thelD; 'o} /** getPredictedRating * returns the percentage value which is the * pred icted value */ n 5 public float getPredictedRating() { return (float) ((Rec) theRecs.e]ementAt(thelndex)).tl1eValue; /** add * adds a new value to the Rec list :o * returns false if the values entered # are invalid, (e.g.: ild < 0) */ App. 2-154 public void add(int ilD, float fValue) { theNumRecs++; I25 theRecs.addElement(new Rec(ilD, fValue) ); /** length * returns the numberofelements in the Rec list I30 */ public int length() { return thcNumRecs; /** createStubRecList * used to return "good" bogus values rather * than values generated from Net Perceptions * useful for testing and stubbing */ public static RecList createStubRecList() { no RecList aRecList = new RecList(74082, (float) 0. 5); aRecList.add(l]6377, (float) 0.6); aRecList.add(1233 12, (float) 0.7); aRecList.add(899, (float) 0.8); aRecList.add(58075, (float) 0.9); his return aRecList; /* * test * test class */ public static class Test { /* public static void main(String [] ergs) { System.out.printin( "debug O"); |55 RecList aRec = createStubRecLisl(); System.out.printin("debug 1''); if ( aRec.setToFirstRec() ) { System.out.printin( "debug 2"); do { System. out.printin( "debug 3"); System.out.printin( aRec.getidentifier() + ": " + aRec.getPredictedRating() ); System.out.printin( "debug 4"); 165} while ( aRec.increment() ); */ 170} RecListjava Page 4 of 4 11/05/99 1:26 PM App. 2-155 SaveClips package com.launch.PlaylistGenerator; hnport java.util.Vector; import java.util.Date; public class SaveClips extends TIuead Vector clips; String storedProc; int ordinal D short mediaType ht userlD; public SaveClips(Vector clips, String storedProc, int ordinal, short mediaType, int userlD) this.clips = clips; this.storedProc = storedProc; this.mediaType = mediaType; this.userlD = userlD; this. ordinal = ordinal; 20} puolic void run() Datc startDate = new Date(); Thread.currentThread().setName("SaveClips for " + storedProc); int rowCount = 0; if (clips.size() ≤ 0) return; try DBConnection conn = new DBConnection(); String sql = ""; Clip aClip; for (int i - O; i < clips. size(); i-+) o aClip = (Clip) clips.elementAt(i); sql = sql.concat(" exec " + storedl'roc + " " + ordinal i ", " + aClip.media.getlD(media lype) -", " + mediaType + ", " + userlD); ordinal++; rowCount++; 3 conn. executeSQL(sql); conn.close(); catch (DBException oops) Util.debug(''DB Exception: " + oops.getMessage()); APD. 2-156 Util.debug(Thread. cunrentThread().getName() + '' saved " + rowCount + " clips") Util. printElapsedTime(Thread.cun-entThread().gctName(), startDate); SaveClipsJava Page202 11/05/991:25PM App. 2-157 SavePlaylist package com. launch.PlaylistGenerator import java.util.Date; public class SavePlaylist ex!cnds Thread { Playlist list; int ordinal, to, from, public SavePlaylist(Playlist list, int from int to, in! ordinal) o tIis.list = list; this.ordinal = ordinal; this to - to; this.from = From; public void nm() Date startDate = new Date(); Thread.currentThreadO. setName("SavePlaylist (" + from + "-" + to + ")"); int rowCount = 0; try Z5 DBConnection conn = new DBConnection(); String sql = ""; SongData data; short origin; for (int i = from; i < to; i-+) data = (SongData) list. media.elementAt(i); s if (list.popularOnly) origin = (short) SongData. SOURCE_FORCED_POPULAR; else origin = (short) data.origin(); if (data. querySource == SongData.SOURCE_RATED) origin = (short) data.rating. getSource(); // sql = sql.concat('' exec sp IcSaveMediaPlaylist_ixxd " + ordinal + ", " + data.getMediaiD(list.mediaType) + ", " + list.mediaType + ", " + list.userlD i '', t' + data.implicit + ", " + origin); ordinal++; rowCount++; CoM. eXeCUteSQL(Sql); conn.close(); catch (DBException oops) Util.debug("DB F:xception: " oops.getMessage()); App. 2-158 L1til.debug(Thread currentThread().getName() + " saved " + rowCount + " songs") } Utl prlOtElapscdTme(Thread.currentThread().getName(), startDate); SavePlaylistjava Page 2 of 2 1 1/05/99 1:25 PM App. 2-159 SimpleClip package com.launch.PlaylistGenerator import java.io.Serializable; public class SimpleClip implements Serializable int medialD; int ID; byte orighl; public String toStrh() o { return "cliplD=" + ID + ", medialD=" + medialD -r ", origin=" + origin; /** * Contructor for ads, news, tips */ public SimpleClip(int ID, int medialD) this.medialD = medialD; o this.lD = ID; * Constructor for songs */ public SimpleClip(int ID, int medialD, byte origin) this(lD, medialD); this.origin = origin; SimpleClip.java l'age I of I 11/05/99 1:32 PM App. 2-150 SimpleClipList package com.launch. PlaylistGenerator; import java.util.Vector; public class SimpleClipList extends Vector { public SimpleClipl.ist(int size) super(size); A} public SimpleClip pop() if (size() > 0) |5 { SimpleClip clip = (SimpleClip) elementAt(O); removeElementAt(O); retum clip; returr null; 2S SimpleClipListjava Page I of I 11/05/99 1:32 PM App. 2-16] SimplePlaylist package com.launch.PlaylistGenerator; import java.util. Vector; import java.io.Serializable; import java.io.ByteArrayOutputStream; i mport j ave. i o. Obj ectOutputStream; import java.io. ObjectinputStream; import java.io.ByteArrayinputStream; importJavaatil. Date; o public class SintplePlaylist implements Serializahle SimpleClipl. ist news - ncw SimpleClipList(10); SimpleClipList ads = new SimpleClipList(10); SimpleClipl.ist tips = new SimpleClipList(10); s SimpleClipList songs = new SimpleClipList(50); Date lastAd; Date lastNews Date lastTip; short mediaType; int moodlD; int dilD; public String toString() return "ads=" + ads.toString() + ", " + "news=" + news,toString() + ", " + "songs=" + songs.toString() + ", " + "tipse" i- tips.toString(); public void resetDates(Date newDate) { lastAd = lastNews = lastTip = newDate; public void save(int userlD) { try ( DB Connection con n = new DBConnection(): save(conn, userlD); catch (DBException e) Systcm.err.printin(new Date().toString() + " DBException in SimplePlaylist:save: " + e.toString()); e.printStackTrace(); public void save(DBConnection cone, int userlD) try String sqD- "exec sp_lcSavePlaylist ixxd " useril) ", ?"; App. 2-162 DBPreparedStatement statement conn.prepareStatement(sql); byte[] b - toByteAnray();
statement.setBytes( I, toByteArray());
statcment.executeUpdate(); catch (DBException e) System.err.prhtln(new Date().toStririg() + " DBExccption in SimplePlaylist save:''+ e.toString() ); 75} public static SimplePlaylist fromBytes(byte[] b) f if (b == mll 1I b.length ≤ 0) RO retum null; try ByteArrayinputStream bais = new ByteArrayinputStream(b);
RS
if(bais == null) retun1 null; ObjectinputStream ois = new ObjectinputStrcam(bais); if(ois == null) retune null; retum (SimplePlaylist) ois.readObject(); 95} catch (Throwable e) System.err. printin("Exception in SimplePlaylist:fromAytcs:" e.toString()); 00 retUm nu 11; public static SimplePlaylist load(DBConnection cone, int userlD) String sql = "exec sp_lcGetPlaylist xsxx " + userlD; t{ry DBResultSet rs = conn.executeSQL.(sql); retun SimplePlaylist.fromBytes(rs. getBytes("playlist")); catch (Throwable e) n5 Systcm.err. printin("Exception in SimplePlaylist:load " + e.toString()); retune null; 12D private byte[] toByteArray() try App. 2-163 ByteArrayOutputStream bans = new ByteArrayOutputStream(); ObjectOutputStream 408 = new ObjectOulputStream(baos); oos.writeObject(this); return baos.toByteArray() ; catch (Th.rowable t) 1 System.err.printin("toByteArray died: " + t. toString()); t.printStackTrace(); return mill; 135} SimplePlaylistjava Page 3 of 3 11/05/99 1:35 PM App. 2-164 Song package com.launch. PlaylistGenerator public class Song public final static short EXCLUDED = 4; public final static short EXPLICIT = 3; public final static short IMPLICIT = 2; public final static short UNRATED = 1; public final static short ANY = 0; public int songlD; public short type = ANY; private SongData data = null; |5 public Song(int songlD, short type) this.songlD = songlD; setType(type) public String toString() return "Song " + songlD + ", type = " + typeString() + ", data = " + ((data == null) ? "null": data.toString()); public String typeString() switch (Iype) case ANY: return "ANY"; case EXPLICIT: return "EXPLICIT"; case IMPLICIT: return "IMPLICIT"; case UNRATED: return "UNRATED"; case EXCLUDED: return "EXCLUDED"; default: return "UNKNOWN" // this should wait for setType so public SongData getDataO return data; 1/ this should vomit for setType public short get I ype() return type; App. 2-165 1/ returns whether or not this is suitable for setting SongData public boolean setType(short newType) short oldType = type; if (newType -- = type) return true; else if (newType < type) return false; to else ype = newType; 1/ add or delete song data if'(newType =- EXCLUDED) 11 if (oldType!= 0) 1/ Util.debug(Thread.currcntThread().getName() + ": deleting data for song " + songlD + ", oldType was " + oldType); to data = null; else if(oldType == ANY && (newType == EXPLICIT 1I newType == IMPLICIT 1I newType == data = new SongData(songID); return true ' go 3 Songjava Page 2 of 2 11/05/99]:26 PM App. 2-165 SongData package com.launch. PlaylistGenerator; public class SongData int songful; byte querySource; public AverageRating djsAverage; double score, netp, lo implicit, confidence, lastPlayed, teds, ratingF, djsF, netpF, commRatingF, l as tP l ayed F. bdsF; to private Songinfo info; private Rating djs = new Rating((short) Constants. DEFAULT DJS_SCORE); private byte djSource = SOURCE_DJS; public SongRating rating; PickStatus status public final static byte SOURCE_RATED = 1; public final static byte SOURCE IMYLICIT_ALBUM = 2; public final static byte SOURCE_IMPLICIT ARTIST = 3; public final static byte SOURCE_IMPLICIT SONG = 4; public final static byte SOURCE_DJS = 5; Jo public final static byte SOURCE_DJS SONG = 5; public final static byte SOURCE_BDS = 6; public final static byte SOURCE_POPULAR = 7; public final static byte SOURCE_RANDOM = 8; public final static byte SOURCE_NETP = 9; public final static byte SOURCE ALL = 10; public final static byte S0URCE_RECENTLY_PLAYED = I I, public final static byte SOURCE_FORCED_POPULAR = 12; public final static byte SOURCE_GENRES = 13; public final static byte SOURCE DJS_ALBUM = 14; to public final static byte SOURCE DJS_ARTIST = Z5; public final static byte DO_NOTHING = 0; public final static byte MAKE ME IMPLICIT = 1; public final static byte EXCLUnE ME e 2; public SongData(int songlD) { lastPlayed = Constants.DEFAULT_LASTPLAYED_SCORE; djsAverage = new AverageRating((short) Constants.DEFAULT DJS_SCORE); status = new PickStatus(); netp = Constants.DEFAULT_NE'I'P SCORE; this.songID = songlD; rating = new SongRating(); public boolean equals(SongData otherData) return (songlD == otherData.songlD); public byte origin() double maxValue = 0; byte maxSource = SOURCE RANDOM; App. 2-167 byte ratingSource = 0; if (rating.isSet()) ratingSource= rating.getSource(); if (info.commRating > maxValue && info.commRating > Constants.POPVLAR_THRESHOLD && ratingSource!= I) maxValue = info.commRating; maxSource = SOURCE_POPULAR; to if (djs.isSet() && djs.get() ≥ maxValue 8& djs.get() > 0 && ratingSource!= I) maxValue - djs.get(); maxSource = djSource; /* if(netP > maxValue) maxValue = netP; maxSource = SOURCE_NE'I'P; SO} */ if (teds > 0 && teds ≥ maxValue && ratingSource!= I) maxValue = teds; maxSource = SOURCE BDS; 11 according to the weight matrix, if there's an explicit rating, I/that's the only source 11 but let's lie to people because they don't like it when we say so 11 we played lowly-rated songs for them 11 even though that's what we say we will play anyway if (rating.isSet()) short value = rating.get(); if (value > Constants. MIN_RATING_FOR_RA'l'ED_SOl.JRCE && value ≥ maxValue) maxValue = value; maxSource= ratingSource; 100} plies, lies, lies.
if(maxVaiue < Constants.MIN RATING_FOR_RATED_SOURCE) maxSource = SOURCE RANDOM; I05} return maxSource; public void calculateDJs(ltemsProfile items, AlbumArtistData albumAndArtist) us 1/ put in the dctault djs. set(djsAverage.get()); djSource = SOURCE_DIS_SONG; if(djsAverage.count() < 0) US djSource = SOURCE_R ANDOM; Item albumitem = albumAndArtist. getAlbum(itcms, this); Item artistitem = albumAndAhist-getArtist(items' this); // don't calculate implicit ratings based on various artists if (artistitem!= null && Artistinfo.isVariousArtists(artistitem.itemlD)) { artistitem = null; App. 2-168 if (albumitem!= null && albumitem.d jsAverage.count() > 0) djs.set(albumitem.djsAverage.get()); djSource = SOURCE_D.1S_AI.BUM; else if(artistitem!= null && artistitem.djsAvcrage. count() > 0) 230 djs.set(artistitem.djsAverage.get()); djSource = SOURCE DJS ARTIST; I35 public byte calculatelnnplicit(ltemsProfile items, AlburnArtistl)ata albumAndArtist) if (!rating.isSet()) Item albumitem = albumAndArtist. getAlbum(items, this); o Itenn artistitem = albumAndArtist. getArtist(items, this); 1/ don't calculate implicit ratings based on various artists if (artist] tem!= null && Artistinfo.isVariousArtists(artistitcm.itemlD)) artistitern = null; t45} if (albumitem!= null && albumitemaserRating.isSet()) f short albumRating = albumitem.userRating.get(); if (al bumRating == 0) t50 retum EXCLUI)E_ME; else rating.set(albumRating, SongRating. RATING_SOURCE_FROM ALBUM); return MAKE_ME_IMPLICIT; else if (artistitern!= null && artistitem.userRating.isSet()) co short artistRating = artistitem.userRating.get(); if (artistRating == o) return EXCLUDE_ME; else rating.set(artistRating, SongRating. RATING_SOURCE_FROM_ARTIST); retum MAKE_ME_IMPL.ICIT; else if (artistitcm!= null && artistitem.songAvcrage.count() > 0) rating. set((short) artistitem.songAverageScore(info.album.artist), SongRating. RATiNG SOURCE_AVERAGE_SONG RATING_BY_ARTIST); retum MAKE_MF._IMPLICIT; 175} retum DO_NOTHENG; public void setBDS(short score) i80 { teds = score; public double getBDS() App. 2-169 i85 retum teds; public void score(WeightMatrix w, Stationl.ist stations) // score teds teds = info.bdsScore(stations); byte s rating.getSource(); /* // we're not using confiecnce right now. Take it out for speed confidence = 0; tg5 if(ratingSource!=SongRathg.RATiNG SOURCE EXP!.!CIT) if(djs!= DEFAUL.T_L)]S_SC()RE) confidence += 10; if (netp > 0) confidence += 10; if (info.comm Rating > 0) confidence += 10; */ 205 // implicit rating is based on ratings data ratingF = (rating.get() * w.matrix[s][WeightMatrix.RATING]); djsF =(djs.get() w.matrix[s] [WeightMatrix.DJS]); netpF =(netp * w.matrix[s][WeightMatrix.NETP]); commRatingF = (info.commRating * w.matrix[s]tWeightMatrix.COMM_RATING]); :'o lastPlayedF= (lastl'layed * w.matrix[s][WeightMatrix.LAST PLAYED]); bdsF = (teds * w.matrix[s][WeightMatrix.BDS]); implicit = ratingF + djsF + netpF -i- commRatingF; 1/ score is based on other factors score = implicit -r lastPlayedF + bdsF; 215 // confidence += w.mattix[s][WeightMatrix.CONFIDENCE]; pitblic void setinfo(Songinfo stuff) info = stuff, ?20} public Songinfo getinfoO return info; 225 public boolean isinfoSet() return (info!= null); public int getArtistlD() 230 { retrim info.album.artist.lD; public int getAlbumlD() 235 retum info album.lD; public String getArtistName() retum hfo.album. artist.title; 240} public String getAlbumName() return info.album.title; 245 public int getMedialD(short mediaTypc) App. 2-170 return info.media. getlD(mcdiaType); public String getSongName() 250 { return info.title public String sourceString(byte source) 255 switch (source) { case SOURCE RECEN I LY_PLAYED: return "recent"; case SOURCE RATED: retun, "rated"; :60 case SOURCE_IMPLICIT ALBUM: return "album" case SOURCE IMPLICIT ARTIST: return "artist"; case SOURCE IMPLICIT_SONG: 265 return "s avg"; case SOURCE DJS: retune "djs"; case SOURCE_DJS ALBUM: return "djAlb"; 270 case SOURCE_DJS_ARTIST: retune "djArt"; case SOURCE_BDS: retune "bds"; case SOURCE POPULAR: 2?5 retunn"pop"; case SOURCE_RANDOM: return "random"; case SOlJRCE_NETP: return "netp"; zso case SOURCE GENRES: return "genres"; case SOURCF._ALL: return "all"; default: 285 rehire"?"; public static String origin l ext(byte origin, String singularDI, String posessiveDJ) ago switch (origin) case SOURCE RATED: return (singularDJ + " rated this song"); case SOURCE IMPLICIT_ALBUM: 295 return (singularDJ + " rated this album"); case SOURCE IMPLICIT ARTIST: retune (singularDJ + " rated this artist"); case SOURCE IMPLICIT SONG: return (singularDJ + " rated other songs by this artist"); a00 case SOURCE DJS: return (posessiveDJ + " DJs rated this song"); case SOURCE DJS ALBUM: retune (posessiveDJ + " DJs rated this album"); case SOURCF. _DJS ARTIST: 305 retune (posessiveDJ + " DJs rated this artist"); case SOURCE ADS: retune (posessive[)J + " radio stations play this song"); case SOURCE POPULAR: App. 2-171 return "Thissong is popular on LAUNCHcast stations" case SOURCE_RANDOM: return "This song is a random pick"; case SOURCE NETP: return "Song recommendations"; case SOURCE FORCED_POPUL.AR: return "Popular - choose more gerres for your music."; return ""; public String toS!rin6() 320 { return "sorglD:" + songlD + ", " "score: " a score -F ", " + "implicit:" + implicit + ", " + ''conOdenee: " + confidence + ", " 325 + "lastPlayed:" F lastPlayed -F ", " + "rating:" + rating + ", " + "ratingSource:" + rating.getSource() + ", " + "bds:" + teds + ", " + "djs:" a- djs.get() + ", " 330 1- "source:" + sourceShing(querySource) + Util.newLine; public PlaylistEntry toPlaylistEntry(short mediaType) PlaylistEntry result = new PlaylistEntry(); 335 result.albumlD = getAlbumlD(); result.artistlD = getArtistlD() resuit. al bumTitle = info.al bum.title; result. artistTitle = info.a1 bum. artist. title; result.filepath = info.media.getFilepath(mediaType); 340 result.medialD = getMedialD(mediaType); result.songlD = songlD; result.songTitle = info.title; result.title = info title; return result 345} public SimpleCiip toSimpleClip(short mediaType) return new SimpleClip(songlD, getMedialD(mediaType), origin()); 350} public String toDisplayString(int displayType, int count) String delim = ""; 355 String prefix = ""; Srring suffix = ""; Strh1g bgcolor= ""; if(displayType == Util.DISPI.AY_IITMI.) 350 if(count % 2 == 0) bgcolor = ''#CCCCFF"; e Ise bgcolor= "white"; delim = "</FONJ></TD><TD BGCOLOR=" a bgcolor + "><FONT SIZE=\"-2\">"; 365 prefix = "<TR><TD BGCOLOR=" + bgcolor + "><FONT SIZE=\"-2\">"; suffix = "<IFONT></TD>/TR>"; else { delim = "\t"; App. 2-172 retum (prcf x + count -- delim + songlD + delim + sourceString(querySource) Àr delim + sourceString(origin()) 375 + delim + status.toDisplayString(displayType) + delim + status.order + delim + Util.fix(score, 2, O) + delim + Math.round(lastPlayed) +''/" + Math.round(lastPiayedF) + delim t Math.round(bds) + "/" 4- Math.round(bdsF) 330 + delim + Math.round(implicit) + delim + Ut:l.fix(ratirg.get(), O. 2) a "i'+ Util.tix(ratingF, O. 2) + " (" + rating.ge.tSource() - ")" i- delim + Math.round(djs.get()) + "/" + Math.round(djsF) + delim t Math.round(netp) + "/" + Math.round(netpF) 385 + delim + Math.round(info.commRating) + "/" t- Math.round(commRatingF) + delim + getAlbumlD() + delim + getArtistlD() + delim + getArtistName() + deiim t- getSoligNalile() 39U + delim + getAlbumNatne() + delim + info.album.genresString() + suffix ); 395 public String originTclList() return "{" + songlD + " " + origin() + " " + Math.round(implicit) -t "} "; public static String[] namesArray() 4CO { String[] names = { "rr:', "songlD", "query", "origin", "status", "ord'', "score", "lastP.", "teds ", 410 "impl. ", "rating(t)", "djs", "netP.", "comm", "albumlD", "artislD", "artist", "title", "albutn", 420} . return names; SongData.java Page 10 of 10 1 1105199 1:24 PM App. 2-173 SongGroup package com.launch.PlaylistGenerator; import java.util.Vector; public class SongGroup extends Vector { public SongData pickRandorn(int factor) int ieftinList = size(); lo if (leftinl. ist <:= 0) return mill; double rend = Util.random(leftinList - 1) + 0. 00001; int pick[ndex = (ins) Math.round((Math.pow(rand, factor) / Math. pow(leftinList - 1, factor)) * (ieftinList - I)); SongData pick = (SongData) elementAt(pickindex); double pickDouble = pickindex; pick.status.percentile = (short) Math. round((pickDouble / size()) * 100); removeElementAt(pickindex); return pick; 20} SongGroup.java Page I of I 11/05/99 i:28 PM App. 2-174 SongInfo package com.launch.PlaylistGenerator; import java.util.Vector; public class Songinfo { int songlD; byte comm Rating - Constants. DEFAULT_COMMRATING; privarc boolean explicit = false; o Albuminfo album; String title; private Vector bdsRanks; public MediaList media; s public Songinfo(int songlD) this.songlD = songlD; media = new MediaList(); public void addBDSRank(BDSRank rank) if (bdsRanks == null) bdsRanks = new Vector(l, 1); bdsRanks.addElement(rank); public int getArtistlD() /* throws Exception */ { retum album.artist.1D; I* if(album =--- null) throw new Exception("album is not sct for Songinfo songlD " + songlD + "(" + title + retum album.getArtistlD(); */ s public int getAlbumlD() /* throws F.xception */ /* if (album == null) ( tiurow new Exception (" album is not set for Songi n fo songlD " + songlD + "(" + title + ), */ return album.lD; public double bdsScore(StationList stations) so { App. 2-175 if(bdsRanks c null 1l stations.size() ≤ 0) retum Constants.DEFAULT_BDS SCORE; int i = 0; int pointBar = Constants.BDS_SCORE POINTBAR; float maxPoints = Constants.BDS SCORE MAX_POINTS float totalpoints = 0; float numStations = 0; 7D BDSRank rank; Station sta; for (int j = 0; j < bdsRanks.size(); j+t-) f rank = (BDSRank) bdsRanks.elementAt(j); sta = stations.get(rank. stationlD); if (sta!= null) f o totalpoints += (maxPoints - rank.rank); numStations±; double potentialStations = stations.size(); double score = ((((totalpo ints / potentia lStations) / maxPoints) + (n um Stations / potent ia lStations) ) * 1 50.0); return score public String bdsString() String result = ""; if (bdsRanks == null) return "(none)"; oo for (int i = 0; i < bdsRanks. sizeO; i++) resu lt = result.concat(bdsRanks.elementAt(i).toString() + ", "), return "(" + result + ")"; public String toString() retlm "songlD=" + songlD + ", " 0 + "title=" + title + ", " + "cornmRating=" + comnRating + ", " + "media=" + med ia. to Stri ng() 4- "bUsRanks=" + bdsString() + "album=" + album.toString(); ]15} public void setExplicitLyrics(boolean badStuff) explicit = badStuff; ao} public boolean hasExplicitLyrics() App. 2-176 2o1 return explicit; t25} Songinfojava Page 3 of 3 1 1105/99 1:35 PM App. 2-177 SongInfoCache package com.launch.PlaylistGenerator import java.util.Hashtable; import java.util.Enumeration; import javax.servlet. ServletOutputStream; import java.util.Date; import java.util.Vector; public class SonginfoCache lo private Hashtable songs; private Hashtable albums; private Hashtable artists; private Songinfo songList[]; private Hashtable ads; t5 private Hashtable news private Hashtable tips; private Clip adList[]; private Clip newsList[]; private Clip tipList[]; to private IntHash mediaTypes; public PopularSongs popular; public RatingsCacheratingsCache; private Gelrelndex genres; public final static byte TYPE SONG = I as public final static byte TYPE ALBUM = 2; public final static byte TYPE ARTIST= 3 public final static byte TYPE AD = 4; public final static byte TYPE NEWS = 5; public final static byte 1 YPE_TIP = 6 to private ServictOutputStream out; public Date lastUpdate; public SonginfoCache(ServletOutputStream out) // use memory most efficiently with load factor I songs = new Hashtable(50000); albums = new Hashtable(3000); artists = new Hashtable(1500); ads = new Hashtable(); news = new Hashtable(); so tips = new Hashtable(); mediaTypes = new IntHash(); genres = new Genrelndex(lOQ, !); popuiate(); lastUpdate = new Date(); 45) public Songl.ist getPopular(short rnediaType) } return popular get(mediaType); public Songl.ist getinGenres(GerireList myGenres) return genres.getinGenreList(myGcnres); public SongList getinGenue(int geiuelD) 5S { return genres. getinG enre(genrel D); public int countinGenues(GenreList myGcares) return genres.countinGcnrel. ist(myGenres); App. 2-178 private void populateO try DBConnection conn = new DBCoMection() DBResultSet rs = coM.executeSQL("exec sp IcoGetSongDataCache xsxx") nt songlD, mediaType, rank, stationlD, rowCount; short genrelD; 7 String fi lePath; Sorrginfo aSong; Artistinfo anArtist; Albuminfo anAlbum; rowCourit - 0; while (!rs.getBOF() && !rs.getEOF()) songlD = rs. getint("songlD"); nnediaType = rs.getint("mediaType"); aSong = (SongTnfo) init(songlD, SonginfoCache.TYPE_SONG) rs.getString( filePath"); filcPath = rs.getString("server") + rs.getString("directory") + "\\" + aSong.media. add((short) mediaType, rs.getint("medialD"), fiiePath) aSong.title = rs. getString("song"); anArtist = (Artistin fo) in it(rs.getint("artistlD ") S5 SonginfoCache.TYPE ARTIST); anArtist.title = rs getString("artist"); anArtist.songs.put(new Integer(songlD), aSong); anAlbum = (Albuminfo) init(rs.getint("albumlD") SonginfoCache.TYPE_ALBUM); so anAlbum.title = rs.getString("album"); aSong.setExplicitLyrics(rs.getint("explicit")== 1); /1 add year and date added anAlbum.artist = anArtist; aSong.album = anAlbum; nnediaTypes.increment(mediaType); rowCount++; rs.nextO; Util. debug("SonginfoCache:populate loaded " + rowCount + " media") oo rs = coM. executeSQL("exec sp_icoGetCommRatingCache_xsxx") rowCount = 0; while (!rs getBOF0 && !rs.getEOF0) songlD = rs.getint("songlD"); os aSong = (Songinfo) get(songlD, SonginfoCache.TYPE_SONG); if (aSong!= null) aSong. cornmRating = (byte) rs.getint("comrnRating"); ro rowCount±t; rs.next() Util.debug("SonginfoCache:populate loaded " + rowCount + " commRatings") n5 rs = coM.executeSQL("exec sp_lcoGetGenreCache_xsxx") while (!rs. getBOF() && !rs.getEOF()) gcnrelD = (short) rs.getint("geturclD"); songlD = rs.getTnt("songlD"), :o aSong = (Songinfo) get(songlD, SongirifoCacile. l YPE_SONG); if (aSong!= null && aSong.album!= null) App. 2-179 aSong.album. addGenre(genrelD); gerues.add(genrelD, aSong); rowCount±; rs.next(); Util.debug("SonginDoCache:populate loaded " + rowCount + " genre mappings"); o rowCount = 0; rs = conn.executeSQL("exec sp_lcoGetHDSCache xsxx"); while (!rs.getBOF() && !rs.getEOF()) songlD = rs.getint("songlD"); aSong = (Songinfo) get(songlD, TYPE_SONG); if (aSong!= mll) rank = rs. getint("rank"); stationlD = rs.getint("stationlD"); 0 rowCount++; aSong.addBDSRank(new BDSRank((short) stationlD, (byte) rank) ); rs.next(); I45 Util.debug("SonginfoCache:populate loaded " + rowCount + " teds Ranks"); /1 import ads rowCount = 0; rs = conn.executeSQL("exec sp IcoGetAdCache xsxx"); Clip ad; int cliplD; while (!rs.getBOF() && !rs.getEOF()) ciiplD = rs.getint("cliplD"); /1 filePath = rs.getString("server") + rs.getString("directory") + "/" + rs.getString("fiiePath"); ad = (Clip) init(cliplD, TYPE AD); 11 ad.name = rs.getString("clipName"); ad.media.add((short) rs. getint("mediaType"), rs.getint(''medialD"), null); i6C rowCount++; rs. next(); Util.debug("SonginfoCache:populate loaded " + rowCount + " ad media"); /1 import news rs = conn.executeSQL("exec sp IcoGetNewsCache_xsxx"); rowCount = 0 Clip newsbit; while (!rs.getBOF() && !rs.getEOF()) I70 cliplD = rs.getint("cliplD"); filePath = rs.getString("server") + rs. getString("directory") - "\\" + rs.getString("filePath"); newsbit = (Clip) init(cliplD, TYPE NEWS); newsbit.name = rs.getString("clipName"); newshit.media.add((short) rs.getint("mediaType"), rs.getint("medialD"), filePath); rowCount±; rs.next(); i80 Util.debug("SonginfoCache:populate loaded '' + rowCount + " news media"); /1 import tips rs = conn.executeSQL("exec sp IcoGetTipCache_xsxx''); rowCount- 0; Clip tip; App. 2-180 I35 while (!rs.getBOF() && !rs.getEOF()) cliplD = rs.getint("cliplD"); filePath = rs.getString("server") + rs. getString("directory") + "\\" + rs.getString("filePath"); tip = (Clip) init(cliplD, TYPE TIP); tip.name = rs.getString("clipName") tip.media. add((short) rs.getint("mediaType"), rs.getint("medialD"), filePath); rowCount++; rs.next(); .5} Util.debug("SongintoCache:populate loaded " + rowCount -i " tip media"); conn.closeO; catch (DBException oops) { System. out.printin("DBException in cache populate: " + oops.getMessage()); 1/ populate the songs array songL ist = new Song in fo[songs.size()]; 205 inti=0; for (Enumeration e = songs.keys(); e.hasMoreElements() ;) { songList[i] = (Songinfo) songs.get((lnteger) e.nextElement()); i++; // populate the ads array adList = new Clip[ads.size()]; i -0; for (Enumeration e = ads.keys(); e.hasMoreElements() ;) { adList[i] = (Clip) ads.get((lnteger) e.nextElement()); i++; // populate the news array newsl.ist = new C]ipnews.si%e()]; i =O; 220 for (Enumeration e = news.keys(); e.hasMoreElements() ;) { newsList[i] = (Cl ip) news. get((l nteger) e. nextE lement()); i++; // populate the tips array 225 tipList = new Clip[tips.size()l; i =O; for (Enumeralion e = tips. keys(); e.hasMoreElements() ;) { tipEi st[i] = (C l ip) ti ps. get((lnteger) c.next El em ent()); i++; 230} // make popular lists popular = new PopularSongs(songs, mediaTypes) Util. debug("SonginfoCache:populate done"); 235 private Hashtable getHash(byte type) if (type == TYPE_SONG) retum songs; else if (type == TYPE ALBUM) 240 return albums else if(type == TYPE ARTIST) return artists else if (type == TYPE AD) return ads; 245 elseif(type==TYPE NEWS) return news; App. 2-181 else if (type == TYPE_TIP) retum tips; return null; 250} public Object init(int ID, byte type) if(gctHash(type).containsKey(new Integer(lD))) 255 retum get(lD, type); case { return put(lD, type); 260 ? public Object get(lnteger ID, byte type) } retum (getHash(type)).get(lD); 265 public Object get(int ID, byte type) return get(new Integer(lD), type) ; private Object makeNcw(int ID, byte type) 270 { if(type==TYPE SONG) return new Songinfo(lD); elseif(type==TYPE ALBUM) return new Aibuminfo(lD) ; 275 else if (type == TYPE ARTIST) return new ArtistinDo(lD) else if (type == TYPE_AD) return new Clip(lD, Clip.TYPE_AD); else if (type == TYPE_NEWS) 280 return new Clip(lD, Clip.TYPE_NEWS); else if (type == TYPE_TIP) return new Clip(lD, Clip.TYPE TIP); retum null; 285 private Object put(int [D, byte type) Hashtable hash = getHash(type); Object thing = makeNew(lD, type); hash.put(new lnteger(lD), thing); 290 retum thing; public Songinfo randomSong() long index = Util. random(songList.length - 1); 295 if (index > songList.length - I) return null; return songList[(int) index]; public Enumeration keys(byte type) 30D { if (type == TYPE_SONG) retum songs.keys(); else if (type = TYPE_ALBUM) return albums.keys(); 305 elseif(type=--TYPE ARTIST) retum artists.keys(); else if (type == TYPF_AD) retum ads.keys(); App. 2-182 else if (type == TYPE_NEWS) 310 return news.keys(); else if (type == TYPE_TIP) return tips.keys(); return null; 375 public int size(byte type) Hashtable hash = getHash(type); if (hash!= null) return hash.size(); 320 return 0; private Clip[1 getClipList(byte type) if (type == TYPE AD) 325 return adList; else if (type cc TYPE_NEWS) return newsList; else if (type == TYPE_TIP) return tipList; 33D return null; public Clip randomClip(bytc type) Clip[] clips = getClipListtype); 335 if (clips == null il clips.length ≤ 0) return null; return clips[(int) Util.random(clips.length - 1)]; public Vector randomClipList(byte type, short mediaType, int max) 340 { Vector list = new Vector(); Clip hip; 1/ stop if we have enough or we've iterated too many times for (int i = 0; i < (max * 10) && iist.size() < nnax; i++) 345 { int iterations = maxi boolean cool = false; boolean done = false; do 350 { bip = randomClip(type); iterations- /1 maybe we didn't get one if (bip == null) 355 { done = true; else ( 360 // we got one that f ts! cool=(bip.media.inType(mediaType)&& !list. contains(bip)); // we've got to stop sometime done c (cool 11 iterations < 0); 355} while (!done); // if it was cool, go ahead if (cool) list.addElement(bip); 370} App. 2- 183 return list; SonginfoCache Java Page 9 of 9 1 1/05/99 1:32 PM App. 2- 184 SongInfoCacheUpdater package com.launch.PlaylistGenerator; import javax.servlet.http.HttpServlet; import java.util.Date; s public class SonginfoCacheUpdater extends Thread PlaylistCeneratorServlet servlet; public SonginfoCache!Jpdater(Playl istGener atorServiet serviet) Jo { Lhis.servlet = servlet; public void run() Thread. currentThread(). setName( "SonginfoCacheUpdater"); 1/ update every day long timeToSleep = Util.MJLLISECONDS_IN_SECOND * Util. SECONDS IN_MINUTE * Util.MINUTES_IN_HOUR * Util.HOURS_IN_DAY; while (true) try { Thread.sleep(timeToSleep); } catch (InterruptedException e) {}; try l)til.debug("updating song cache at " new Date()); Util.debug("last update was at " + servlet.songCache.lastUpdate); 11 make a new cache SonginfoCache cache = new SonginfoCache(null); /I make sure to copy over the ratingsCache too!!! cache.ratingsCache = servlet.songCache.ratingsCache; so 11 install the new cache servlet. songCache = cache; Util.debug("finished updating song cache at " new Date()); Util.debug("iast update is now at " -a servlet.songCache. lastUpdate); catch (Throwable e) System.err. printin(''SonginfoCacheUpdater caught an exception: " + e.toString()); e. printStackTrace(); 50} SonginfoCacheUpdaterjava Paged of 2] 1/05/99 1:38 PM App. 2-185 SongList package com.launch.PlaylistGenerator; import java. util.Vector; import java.util.Hashtable; hnport java.utii.Enumeration; public class SongList implements Cloneable private Vector list = new Vector() private Hashtable unique= new l-lashtable(); o private boolean ordered = t-aise; public Songl.ist() /#* s * Creates a SongList from a Hashtable of songs public SongList(Hashtable songs) Songinfo info = null; zo Integer songlD; for (Enumeration e = songs.keys(); e. hasMoreElements() ;) songlD = (Integer) e.nextElement(); info = (Songinfo) songs. get(songlD); Z5 addElement(info); public SongList(Hashtable songs, short mediaType) inleger songlD; Songinfo info = null; for (Enumeration e = songs.keys(); e.hasMoreElcments();) songlD = (Integer) ealextElement(); info = (Songinfo) songs.get(songlD); if (info.media.inType(mediaType)) addElement(info); i pub]ic void addElement(Songinfo info) Integer ID = new Integer(info.songlD); 1/ check unique constraint if (unique.get(lD) == null) list. addElement(info); unique.put(lD, info); public void addElements(SongList list) if (list == null) return for (int i = 0; i < list.size(); i++) addElement(list.elementAt(i)); 60} App. 2-186 public void sort() sort(this, 0, list.sizeO - 1) ordered = true; 65} public int size() return list.size(); public Songinfo elementAt(hit index) ( return (Songinfo) list.elementAt(index); public void setSize(int newSize) { list. setSize(newSize); private void sort(Songl.ist a, hit from, int to) so // quicksott 1/ If there is nothing to sort, return if ((a == null) || (a.size() < 2)) return; int i = from, j = to as Songinfo center = a.elementAt((from + to) / 2); do while(() < to) && (center.commRating < a.elementAt(i).commRating) ) i++; while((j > from) && (center.commRating > a.elementAt(J).commRating) ) j--; if (i < j) f Songinfo lemp = a.elementAt(i); a.setElementAt(a. elementAt0'), i); a.setElementAt(temp, I); // swap elements if (i ≤ j) { i++, j--, } } while(i ≤ j); if (from <j) sort(a, from, j); /I recursively sort the rest if (i < to) sort(a, i, to); loo public void setElementAt(Songinfo info, int index) list.setElementAt(info, index); public Songinfo pickRandom() I05 { if (size() ≤ 0) return null int lucky = (ins) Utii. random(size() - I); if (lucky < 0) no return null Songinfo info = elementAt(lucky), list.removeElementAt(lucky) return info; ) n5 public Object clone() SongList result = new SongList(); result. ordered = this. ordered result. unique = (Hashtable) un ique. c lone(); result. list = (Vector) list.clone(); return result; App. 2 187 SongListjava Page 3 of 3 11/05/99 1:34 PM App 2- 188 SongRating package conn.launch. PlaylistGenerator; public class SongRating public final static byte RATINC_SOURCE_NONE = 0; public final static byte RATING_SOURCE_EXPLICIT = 1; public hnal static byte RATING_SOURCE FROM_ALBUM = 2 public final static byte RATING_SOURCE FROM_ARTIS-t = 3; lo public flea! static byte RATIN(i.OURCE_AVER^GF. SONG RATING BY_ARTIST= 4; private short rating = (short) Constants.DEFAbJLT_RA I ING; private boolean set = false, private byte type;
IS
public boolean isSet() return set; public short set(short newRating, byte newType) rating= newRating; type = newType; set = true; retun1 rating; public short get() return rating; public byte getSource() return type; 40} SongRatingjava Page I of I 11/05/99 1:38 PM App. 2-189 Station package com. launch. Playl istGenerator; public class Station s int ID; public Station(int stationlD) ID = stationlD; in} Station lava Page I of l i i/05/99 1:26 PM App. 2-190 StationList package com. Iaunch. Playl istGenerator; import java.util.Vector; public class StationList { private Vector slist; public StationList() o { slist -- new \'ector(); public Station stationAt(int i) s { retun, (Station) slist.elementAt(i); public void addElement(Station s) { slist.addEiement(s); public int size() { return slist.size(); public String inList() { Integer list[] = new Integcr[sizc()]; int last = 0; for (int i = 0; i < slist.size(); i++) listti] = new Integer(stationAt(i).lD); retune Util join(", ", list); public Station get(int stationlD) for (int i = 0; i < slist.size(); i++) { if (stationAt(i).lD == stationlD) return stationAt(i); 50} retune null; StationListjava Pagelofl 11/05/99 i:26PM App. 2-191 Util package com. launch.PlaylistGenerator; import java.io.OutputStream; import java.util. Date; importjavax.servlet.ServletOutputStream; import java.io.lOException; public class IJtil public static final int MILLISECONDS_IN_SECOND = 1000; lo public static Anti int SECONDS IN MINUTE = 60; public static final int MlNUfES_IN_I-IOUR = 60; public static final int HOURS IN DAY = 24; public static final int DAYS_IN_WEEK = 7; public static final int DAYS_IN MONTH = 30; public static final int DISPLAY_TEXT = 0; public static finli int DISPLAY HTML = 1; public static final String newLine = "V\n"; public static final short average(double count, double sum) if (count == 0) return 0; return (short) Math.round(sum / count); public static final long random(int ceiling) { return Math.round(Math.rando1n() * ceiling); public static final String join (String delim, Object values[]) String result = ""; cot i = 0; for (; i < values.length; i++) result = result. concat(values[i].toString() + delim); if (i > lo) result = result. substring(0, (result. length() - del im. length())) ; return result; public static final String fix(double number, int precision, int zeroFill) to double power = Math.pow( 10, precision); double fixed = Math. round(number * power) / power; String mantissa = new Long(Math. round(fixed)).toString(); String result = mantissa; for (int i = mantissa. lengtl1(); i < zeroFill; i+ t) 4S result = new String("0" + result); return result; public static final void out(ServletOutputStream stream, String whatever) try if (stream == null) System. out. pri nt i n(whatever); else stream. pri n t l n (whatever); catch (lOException e) 6U} App. 2-192 public static final void debug(String info) } System Out println(info); public final static String tab(int times) String result ""; for (int i = 0; i times; i++) result -- resuit. concat(" "); return result; public static final void markQueryFinished(String threadName, Date startDate) Util.debug(newLine + threadName + " started getting data after " + ((new Date().getTime() - slartDate.getTime()) / 1000.0) + " seconds" + newLine); so public static final void printElapsedTime(String threadName, Date startDate) Vtil.debug(newLine + new Date().toString() + " " threadName 4- " took " + ((new Date().getTime() - startDate.getTime()) / 1000.0) + " seconds" + newLine); 85} public static final String tah() return tab(l); 70} Util.javaPage 3 of 3 11/05/99 1:37 PM App. 2-193 WeightMatrix 218 package com.launch.PlaylistGeneralor; public class WeightMatrix s public final static byte RATING = 0; public final static byte DJS = 1; public final static byte NETP = 2 public final static byte COMM_RATING = 3 public final static byte LAST_PLAYED = 4; lo public final static byte BDS = 5; public final static byte CONFIDENCE = 6; /I rating, djs, netp, commRating, lastPlayecl, teds, conf public double matrixt][] = { {0.00, 0 33, 0.00, 0. 10, 0.25, 0.20, 0.0}, II no rating (0.70, 0.00, 0.00, 0.00, 0.30, 0.00, 100.0}, /l explicit rating {0.45, 0.05, 0.00, 0.05, 0.20, 0.20, 50.0}, // album rating only {0.40, 0.10, 0.00, 0.05, 0.20, 0.20, 30.0}, // artist only {0.35, 0 15, 0.00, 0.05, 0.20, 0.20, 20.0} //cross-propagated song ratings } } WeightMatrix.java Page I of I] 1/05/99 1:32 PM Ayp. 2-194
Claims (25)
- A user interface for an Internet data stream transmission system, comprising: a media player for playing data streams; a rating tool for receiving user indications regarding a current data stream and indicating a rating for said data stream as currently played by said media player; and a data stream information display for displaying information for said data stream as currently played by said media player; whereby said user can indicate a preference regarding said data stream as currently played by said media player.
- 2. The user interface of claim 1, further comprising: a playlist generator for generating playlists of data streams for said media player, said playlist generator selecting data streams according to preferences indicated by said user.
- 3. The user interface of claim 2, wherein said data streams selected by said playlist generator are selected in compliance with applicable copyright law.
- 4. A method of broadcasting data streams through a computer network to a user's computer, the method comprising the steps of: providing a database of data streams; selecting a data stream according to a selection method, wherein said selection method is influenced but not controlled by said user; transmitting one of said data streams to said user's computer according to said selection method; receiving feedback expressing a preference from said user regarding said transmitted data stream; and updating said selection method to better reflect said user preference; whereby data streams transmitted to said user are biased according to said user preference.
- 5. The method of claim 4, wherein said step of selecting a data stream includes the step of generating a list of data streams to transmit to said user's computer, said step of transmitting one of said data streams includes the step of transmitting one of said listed data streams to said user's computer, and said step of updating said selection method includes the step of updating said list of data streams to better reflect said user preference.
- 6. The method of claim 4 or 5, further comprising the step of: receiving feedback expressing preferences from sources other than said user.
- 7. The method of claim 6, wherein said step of receiving preferences from sources other than said user comprises the step of: receiving feedback expressing preferences from at least one of other users, commercial radio stations and lists of popular songs.
- 8. The method of any of claims 5 to 7, further comprising the steps of: informing said user generally regarding said database and said data streams; and querying said user as to data stream preference prior to generating an initial transmission list of data streams; whereby said initial list reflects general preferences of said user.
- 9. The method of any of claims 5 to 8, wherein said transmitted data stream is removed from said transmission list.
- 10. The method of claim 9, wherein said data stream removed from said transmission list is listed on a transmitted data stream list.
- 11. The method of any of claims 4 to 10, wherein said data streams are selected from at least one of songs and videos.
- 12. The method of any of claims 4 to I 1, wherein, in said step of transmitting one of said data streams, said one of said data streams is transmitted in conformance with applicable copyright law.
- 13. The method of claim 12, wherein all said transmitted data streams are transmitted in conformance with applicable copyright law.
- 14. A data stream system for providing preferred data streams to a user, comprising: a connection to a computer network connected to a computer:' f said user; a database of data streams available to said computer network; a data stream controller for transmitting data streams to said user's computer according to a selection program; and a user interface coupled to said user's computer and operative to receive said data streams for said user and provide a feedback mechanism for said user so that said user may indicate a preference regarding data streams transmitted by said data stream controller; wherein said selection program is operative to receive indications from said user and modify its selection of data streams for transmission to said user's computer according to said user preference, said indications influencing but not controlling said selection program, whereby data streams selected by said selection program are biased according to said user preference.
- 15. The system of claim 14, wherein said computer network comprises the Internet.
- 16. The system of claim 14 or 15, wherein said database is a Song database and said data streams are songs.
- 17. The system of claim 14 or 15, wherein said database is a music video database and said data streams are music videos.
- 18. The system of any of claims 14 to 17, wherein said user interface comprises an electronic media player.
- 19. The system of any of claims 14 to 17, wherein said user interface comprises: a media player for playing data streams; a rating tool for receiving user indications regarding a current data stream and indicating a rating for said data stream as currently played by said media player; and a data stream information display for displaying information for said data stream as currently played by said media player; whereby said user can indicate a preference regarding said data stream as currently played by said media player.
- 20. The system of claim 19, wherein said user interface further comprises: a playlist generator for generating playlists of data streams for said media player, said playlist generator selecting data streams according to preferences indicated by said user.
- 21. The system of any of claims 14 to 20, wherein said selection program creates a list of data streams for transmission to said user.
- 22. The system of claim 21, wherein said selection program modifies said list of data streams for transmission to said user according to said user preference.
- 23. The system of any of claims 14 to 22, wherein said data stream controller is operative to transmit data streams in compliance with applicable copyright law.
- 24. The system of claim 23, wherein said data stream controller is operative to transmit all of said data streams in compliance with applicable copyright law.
- 25. A user interface for an Internet data stream transmission system substantially as hereinbefore described with reference to the accompanying drawings.
Applications Claiming Priority (2)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
US16484699P | 1999-11-10 | 1999-11-10 | |
GB0210736A GB2372682B (en) | 1999-11-10 | 2000-11-09 | Broadcast method and system |
Publications (3)
Publication Number | Publication Date |
---|---|
GB0405067D0 GB0405067D0 (en) | 2004-04-07 |
GB2397205A true GB2397205A (en) | 2004-07-14 |
GB2397205B GB2397205B (en) | 2004-09-15 |
Family
ID=32510393
Family Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
GB0405067A Expired - Fee Related GB2397205B (en) | 1999-11-10 | 2000-11-09 | A user interface for an internet data stream transmission system |
Country Status (1)
Country | Link |
---|---|
GB (1) | GB2397205B (en) |
Cited By (31)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
WO2009152576A1 (en) * | 2008-06-18 | 2009-12-23 | Political Media (Australia) Limited | Assessing ditigal content across a communications network |
US7680959B2 (en) | 2006-07-11 | 2010-03-16 | Napo Enterprises, Llc | P2P network for providing real time media recommendations |
US7865522B2 (en) | 2007-11-07 | 2011-01-04 | Napo Enterprises, Llc | System and method for hyping media recommendations in a media recommendation system |
US7970922B2 (en) | 2006-07-11 | 2011-06-28 | Napo Enterprises, Llc | P2P real time media recommendations |
US8059646B2 (en) | 2006-07-11 | 2011-11-15 | Napo Enterprises, Llc | System and method for identifying music content in a P2P real time recommendation network |
US8060525B2 (en) | 2007-12-21 | 2011-11-15 | Napo Enterprises, Llc | Method and system for generating media recommendations in a distributed environment based on tagging play history information with location information |
US8090606B2 (en) | 2006-08-08 | 2012-01-03 | Napo Enterprises, Llc | Embedded media recommendations |
US8112720B2 (en) | 2007-04-05 | 2012-02-07 | Napo Enterprises, Llc | System and method for automatically and graphically associating programmatically-generated media item recommendations related to a user's socially recommended media items |
US8117193B2 (en) | 2007-12-21 | 2012-02-14 | Lemi Technology, Llc | Tunersphere |
US8200602B2 (en) | 2009-02-02 | 2012-06-12 | Napo Enterprises, Llc | System and method for creating thematic listening experiences in a networked peer media recommendation environment |
US8285776B2 (en) | 2007-06-01 | 2012-10-09 | Napo Enterprises, Llc | System and method for processing a received media item recommendation message comprising recommender presence information |
US8285595B2 (en) | 2006-03-29 | 2012-10-09 | Napo Enterprises, Llc | System and method for refining media recommendations |
US8316015B2 (en) | 2007-12-21 | 2012-11-20 | Lemi Technology, Llc | Tunersphere |
US8327266B2 (en) | 2006-07-11 | 2012-12-04 | Napo Enterprises, Llc | Graphical user interface system for allowing management of a media item playlist based on a preference scoring system |
US8396951B2 (en) | 2007-12-20 | 2013-03-12 | Napo Enterprises, Llc | Method and system for populating a content repository for an internet radio service based on a recommendation network |
US8494899B2 (en) | 2008-12-02 | 2013-07-23 | Lemi Technology, Llc | Dynamic talk radio program scheduling |
US8620699B2 (en) | 2006-08-08 | 2013-12-31 | Napo Enterprises, Llc | Heavy influencer media recommendations |
US8667161B2 (en) | 2000-09-07 | 2014-03-04 | Black Hills Media | Personal broadcast server system for providing a customized broadcast |
US8688841B2 (en) | 2008-06-05 | 2014-04-01 | Modena Enterprises, Llc | System and method for content rights based on existence of a voice session |
US8805831B2 (en) | 2006-07-11 | 2014-08-12 | Napo Enterprises, Llc | Scoring and replaying media items |
US8839141B2 (en) | 2007-06-01 | 2014-09-16 | Napo Enterprises, Llc | Method and system for visually indicating a replay status of media items on a media device |
US8874655B2 (en) | 2006-12-13 | 2014-10-28 | Napo Enterprises, Llc | Matching participants in a P2P recommendation network loosely coupled to a subscription service |
US8903843B2 (en) | 2006-06-21 | 2014-12-02 | Napo Enterprises, Llc | Historical media recommendation service |
US8983950B2 (en) | 2007-06-01 | 2015-03-17 | Napo Enterprises, Llc | Method and system for sorting media items in a playlist on a media device |
US9003056B2 (en) | 2006-07-11 | 2015-04-07 | Napo Enterprises, Llc | Maintaining a minimum level of real time media recommendations in the absence of online friends |
US9037632B2 (en) | 2007-06-01 | 2015-05-19 | Napo Enterprises, Llc | System and method of generating a media item recommendation message with recommender presence information |
US9060034B2 (en) | 2007-11-09 | 2015-06-16 | Napo Enterprises, Llc | System and method of filtering recommenders in a media item recommendation system |
US9164993B2 (en) | 2007-06-01 | 2015-10-20 | Napo Enterprises, Llc | System and method for propagating a media item recommendation message comprising recommender presence information |
US9224150B2 (en) | 2007-12-18 | 2015-12-29 | Napo Enterprises, Llc | Identifying highly valued recommendations of users in a media recommendation network |
US9224427B2 (en) | 2007-04-02 | 2015-12-29 | Napo Enterprises LLC | Rating media item recommendations using recommendation paths and/or media item usage |
US9734507B2 (en) | 2007-12-20 | 2017-08-15 | Napo Enterprise, Llc | Method and system for simulating recommendations in a social network for an offline user |
Families Citing this family (6)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
US20020002039A1 (en) | 1998-06-12 | 2002-01-03 | Safi Qureshey | Network-enabled audio device |
US8725740B2 (en) | 2008-03-24 | 2014-05-13 | Napo Enterprises, Llc | Active playlist having dynamic media item groups |
US8484311B2 (en) | 2008-04-17 | 2013-07-09 | Eloy Technology, Llc | Pruning an aggregate media collection |
US8484227B2 (en) | 2008-10-15 | 2013-07-09 | Eloy Technology, Llc | Caching and synching process for a media sharing system |
US8880599B2 (en) | 2008-10-15 | 2014-11-04 | Eloy Technology, Llc | Collection digest for a media sharing system |
US7657337B1 (en) | 2009-04-29 | 2010-02-02 | Lemi Technology, Llc | Skip feature for a broadcast or multicast media station |
Citations (4)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
GB2306869A (en) * | 1995-11-03 | 1997-05-07 | Patrik Garten | Software for customised radio program |
US5790935A (en) * | 1996-01-30 | 1998-08-04 | Hughes Aircraft Company | Virtual on-demand digital information delivery system and method |
US5913040A (en) * | 1995-08-22 | 1999-06-15 | Backweb Ltd. | Method and apparatus for transmitting and displaying information between a remote network and a local computer |
US5977964A (en) * | 1996-06-06 | 1999-11-02 | Intel Corporation | Method and apparatus for automatically configuring a system based on a user's monitored system interaction and preferred system access times |
-
2000
- 2000-11-09 GB GB0405067A patent/GB2397205B/en not_active Expired - Fee Related
Patent Citations (4)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
US5913040A (en) * | 1995-08-22 | 1999-06-15 | Backweb Ltd. | Method and apparatus for transmitting and displaying information between a remote network and a local computer |
GB2306869A (en) * | 1995-11-03 | 1997-05-07 | Patrik Garten | Software for customised radio program |
US5790935A (en) * | 1996-01-30 | 1998-08-04 | Hughes Aircraft Company | Virtual on-demand digital information delivery system and method |
US5977964A (en) * | 1996-06-06 | 1999-11-02 | Intel Corporation | Method and apparatus for automatically configuring a system based on a user's monitored system interaction and preferred system access times |
Cited By (37)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
US8667161B2 (en) | 2000-09-07 | 2014-03-04 | Black Hills Media | Personal broadcast server system for providing a customized broadcast |
US8285595B2 (en) | 2006-03-29 | 2012-10-09 | Napo Enterprises, Llc | System and method for refining media recommendations |
US8903843B2 (en) | 2006-06-21 | 2014-12-02 | Napo Enterprises, Llc | Historical media recommendation service |
US9003056B2 (en) | 2006-07-11 | 2015-04-07 | Napo Enterprises, Llc | Maintaining a minimum level of real time media recommendations in the absence of online friends |
US8327266B2 (en) | 2006-07-11 | 2012-12-04 | Napo Enterprises, Llc | Graphical user interface system for allowing management of a media item playlist based on a preference scoring system |
US8422490B2 (en) | 2006-07-11 | 2013-04-16 | Napo Enterprises, Llc | System and method for identifying music content in a P2P real time recommendation network |
US7680959B2 (en) | 2006-07-11 | 2010-03-16 | Napo Enterprises, Llc | P2P network for providing real time media recommendations |
US7970922B2 (en) | 2006-07-11 | 2011-06-28 | Napo Enterprises, Llc | P2P real time media recommendations |
US8059646B2 (en) | 2006-07-11 | 2011-11-15 | Napo Enterprises, Llc | System and method for identifying music content in a P2P real time recommendation network |
US10469549B2 (en) | 2006-07-11 | 2019-11-05 | Napo Enterprises, Llc | Device for participating in a network for sharing media consumption activity |
US8805831B2 (en) | 2006-07-11 | 2014-08-12 | Napo Enterprises, Llc | Scoring and replaying media items |
US8090606B2 (en) | 2006-08-08 | 2012-01-03 | Napo Enterprises, Llc | Embedded media recommendations |
US8620699B2 (en) | 2006-08-08 | 2013-12-31 | Napo Enterprises, Llc | Heavy influencer media recommendations |
US8874655B2 (en) | 2006-12-13 | 2014-10-28 | Napo Enterprises, Llc | Matching participants in a P2P recommendation network loosely coupled to a subscription service |
US9224427B2 (en) | 2007-04-02 | 2015-12-29 | Napo Enterprises LLC | Rating media item recommendations using recommendation paths and/or media item usage |
US8112720B2 (en) | 2007-04-05 | 2012-02-07 | Napo Enterprises, Llc | System and method for automatically and graphically associating programmatically-generated media item recommendations related to a user's socially recommended media items |
US8434024B2 (en) | 2007-04-05 | 2013-04-30 | Napo Enterprises, Llc | System and method for automatically and graphically associating programmatically-generated media item recommendations related to a user's socially recommended media items |
US9037632B2 (en) | 2007-06-01 | 2015-05-19 | Napo Enterprises, Llc | System and method of generating a media item recommendation message with recommender presence information |
US8983950B2 (en) | 2007-06-01 | 2015-03-17 | Napo Enterprises, Llc | Method and system for sorting media items in a playlist on a media device |
US9164993B2 (en) | 2007-06-01 | 2015-10-20 | Napo Enterprises, Llc | System and method for propagating a media item recommendation message comprising recommender presence information |
US8839141B2 (en) | 2007-06-01 | 2014-09-16 | Napo Enterprises, Llc | Method and system for visually indicating a replay status of media items on a media device |
US8285776B2 (en) | 2007-06-01 | 2012-10-09 | Napo Enterprises, Llc | System and method for processing a received media item recommendation message comprising recommender presence information |
US7865522B2 (en) | 2007-11-07 | 2011-01-04 | Napo Enterprises, Llc | System and method for hyping media recommendations in a media recommendation system |
US9060034B2 (en) | 2007-11-09 | 2015-06-16 | Napo Enterprises, Llc | System and method of filtering recommenders in a media item recommendation system |
US9224150B2 (en) | 2007-12-18 | 2015-12-29 | Napo Enterprises, Llc | Identifying highly valued recommendations of users in a media recommendation network |
US9734507B2 (en) | 2007-12-20 | 2017-08-15 | Napo Enterprise, Llc | Method and system for simulating recommendations in a social network for an offline user |
US8396951B2 (en) | 2007-12-20 | 2013-03-12 | Napo Enterprises, Llc | Method and system for populating a content repository for an internet radio service based on a recommendation network |
US8117193B2 (en) | 2007-12-21 | 2012-02-14 | Lemi Technology, Llc | Tunersphere |
US8316015B2 (en) | 2007-12-21 | 2012-11-20 | Lemi Technology, Llc | Tunersphere |
US8060525B2 (en) | 2007-12-21 | 2011-11-15 | Napo Enterprises, Llc | Method and system for generating media recommendations in a distributed environment based on tagging play history information with location information |
US8688841B2 (en) | 2008-06-05 | 2014-04-01 | Modena Enterprises, Llc | System and method for content rights based on existence of a voice session |
WO2009152576A1 (en) * | 2008-06-18 | 2009-12-23 | Political Media (Australia) Limited | Assessing ditigal content across a communications network |
US9491509B2 (en) | 2008-06-18 | 2016-11-08 | Ipowow! Development Pty Ltd. | Assessing digital content across a communications network |
US9848240B2 (en) | 2008-06-18 | 2017-12-19 | Ipowow International Corp. | Assessing digital content across a communications network |
US8494899B2 (en) | 2008-12-02 | 2013-07-23 | Lemi Technology, Llc | Dynamic talk radio program scheduling |
US8200602B2 (en) | 2009-02-02 | 2012-06-12 | Napo Enterprises, Llc | System and method for creating thematic listening experiences in a networked peer media recommendation environment |
US9824144B2 (en) | 2009-02-02 | 2017-11-21 | Napo Enterprises, Llc | Method and system for previewing recommendation queues |
Also Published As
Publication number | Publication date |
---|---|
GB2397205B (en) | 2004-09-15 |
GB0405067D0 (en) | 2004-04-07 |
Similar Documents
Publication | Publication Date | Title |
---|---|---|
GB2397205A (en) | Broadcast method and system | |
AU2008207504B2 (en) | Internet Radio and Broadcast Method | |
US9164993B2 (en) | System and method for propagating a media item recommendation message comprising recommender presence information | |
CN103827912B (en) | Network-based music partner system and method | |
US8713009B2 (en) | Associating objects in databases by rate-based tagging | |
US20080082922A1 (en) | System for providing secondary content based on primary broadcast | |
US20080083003A1 (en) | System for providing promotional content as part of secondary content associated with a primary broadcast | |
US8285776B2 (en) | System and method for processing a received media item recommendation message comprising recommender presence information | |
US20040019497A1 (en) | Method and system for providing listener-requested music over a network | |
AU2001271980A1 (en) | Online playback system with community bias | |
EP1307831A1 (en) | Online playback system with community bias | |
KR20070040196A (en) | System and method for providing online community service for digital contents | |
JP4139253B2 (en) | Streaming delivery method | |
JP2002207925A (en) | Advertisement system and recording medium | |
KR101736776B1 (en) | Sound Processing Method for Game Client, and On Line Game Service System Linked with Real Time Music Service | |
Masouri | Greensleeves | |
Crider | Constructing and performing an on-air radio identity in a changing media landscape | |
Nolen | Zeitgeist: get ready for the Cuban invasion:... the music of Havana--old and new--promises to follow swing as the next big trend |
Legal Events
Date | Code | Title | Description |
---|---|---|---|
732E | Amendments to the register in respect of changes of name or changes affecting rights (sect. 32/1977) |
Free format text: REGISTERED BETWEEN 20100812 AND 20100818 |
|
732E | Amendments to the register in respect of changes of name or changes affecting rights (sect. 32/1977) |
Free format text: REGISTERED BETWEEN 20140102 AND 20140108 |
|
PCNP | Patent ceased through non-payment of renewal fee |
Effective date: 20191109 |