View Javadoc

1   package org.musicontroller.service;
2   
3   import java.io.File;
4   import java.io.FileNotFoundException;
5   import java.io.IOException;
6   import java.io.InputStream;
7   import java.net.URI;
8   import java.net.URL;
9   import java.net.URLConnection;
10  import java.util.ArrayList;
11  import java.util.Collection;
12  import java.util.Date;
13  import java.util.HashMap;
14  import java.util.HashSet;
15  import java.util.Iterator;
16  import java.util.LinkedList;
17  import java.util.List;
18  import java.util.Map;
19  import java.util.Set;
20  import java.util.Map.Entry;
21  
22  import org.apache.log4j.Logger;
23  import org.musicontroller.DJ;
24  import org.musicontroller.core.AIBag;
25  import org.musicontroller.core.AIRelation;
26  import org.musicontroller.core.Artist;
27  import org.musicontroller.core.Band;
28  import org.musicontroller.core.Contract_PS;
29  import org.musicontroller.core.Keyword;
30  import org.musicontroller.core.KeywordCycleException;
31  import org.musicontroller.core.Keywordbag;
32  import org.musicontroller.core.Link;
33  import org.musicontroller.core.Playlist;
34  import org.musicontroller.core.Song;
35  import org.musicontroller.dao.BagAndKeywordUtils;
36  import org.musicontroller.dao.Dao;
37  import org.musicontroller.gui.edit.PlaylistMergeBean;
38  import org.musicontroller.gui.edit.SongBean;
39  import org.musicontroller.gui.edit.TrackList;
40  import org.musicontroller.importer.MusicArchiveBean;
41  import org.musicontroller.importer.MusicArchiveEntryBean;
42  import org.musicontroller.security.IUser;
43  import org.musicontroller.security.User;
44  import org.musicontroller.streaming.StreamMaster;
45  import org.varienaja.comments.Comment;
46  import org.varienaja.comments.CommentService;
47  import org.varienaja.util.coverart.CoverArtManager;
48  import org.varienaja.util.coverart.CoverArtProcessor;
49  import org.varienaja.util.coverart.CoverArtSearchResult;
50  import org.varienaja.util.coverart.ICoverArtFinder;
51  
52  /**
53   * Deliver services for adding and removing Musicians to songs.
54   * 
55   * @author Hans Drexler
56   * @version $Id: McServiceImpl.java,v 1.1 2010/03/16 18:55:42 varienaja Exp $
57   */
58  public class McServiceImpl implements McService {
59  
60  	private Dao _dao;
61  	/**
62  	 * Getter for the DAO.
63  	 * @return The DAO.
64  	 */
65  	public Dao getDao() {
66  		return _dao;
67  	}
68  		
69  	/**
70  	 * Setter for the DAO.
71  	 * @param dao The DAO.
72  	 */
73  	public void setDao(Dao dao) {
74  		_dao = dao;
75  	}
76  
77  	public Band addBand(String bandName) {
78  		if (bandName == null) {
79  			return null;
80  		}
81  		if(bandName.trim().length()==0) {
82  			return null;
83  		}
84  		Band result = getDao().searchBand(bandName);
85  		if(result==null) {
86  			result = new Band();
87  			result.setName(bandName);
88  			result.setInserted(new Date());
89  			getDao().save(result);
90  		}
91  		return result;
92  	}
93  	
94  	public void addMusician(Playlist playlist, String artistfirstname, String artistlastname, String instruments, String tracks) {
95  		if(artistlastname==null) {
96  			return;
97  		}
98  		if(instruments==null || "".equals(instruments)) {
99  			return;
100 		}
101 		if(playlist==null) {
102 			return;
103 		}
104 		TrackList tracklist = null;
105 		if(tracks==null) {
106 			tracklist = TrackList.createInstance(playlist);
107 		} else { 	
108 			tracklist = TrackList.createInstance(tracks);
109 		}
110 		Set<AIRelation> relationsToAdd = BagAndKeywordUtils.createRelations(artistfirstname,artistlastname,null,instruments);
111 
112 		/*
113 		 * Construct a map of all PS contracts in the playlist sharing the same set of AI relations. We will
114 		 * use this map to retrieve the AIBag for each different set of AI relations only once and then setting
115 		 * it in all songs with that set of AI relations. This is needed because getAIBag() is implemented
116 		 * inefficiently. Songs that are not in the track list are ignored.
117 		 */
118 		Map<Set<AIRelation>,Set<Contract_PS>> songRelationMap = new HashMap<Set<AIRelation>,Set<Contract_PS>>();
119 		for(Contract_PS contract : playlist.getSongs()) {
120 			if(tracklist.contains(contract.getRowno())) {
121 				Song song = contract.getSong();
122 				Set<AIRelation> relations = new HashSet<AIRelation>();
123 				if (song.getAibag()!=null) {
124 					relations.addAll(song.getAibag().getRelations());
125 				}
126 				Set<Contract_PS> songSet = null;
127 				if(songRelationMap.containsKey(relations)) {
128 					songSet = songRelationMap.get(relations);
129 				} else {
130 					songSet = new HashSet<Contract_PS>();
131 					songRelationMap.put(relations, songSet);
132 				}
133 				songSet.add(contract);
134 			}
135 		}
136 		
137 		for(Entry<Set<AIRelation>,Set<Contract_PS>> entry : songRelationMap.entrySet()) {
138 			Set<AIRelation> targetSet = new HashSet<AIRelation>();
139 			targetSet.addAll(entry.getKey());
140 			targetSet.addAll(relationsToAdd);
141 			AIBag bagForThisSet = BagAndKeywordUtils.getAIBag(targetSet);
142 			for(Contract_PS contract : entry.getValue()) {
143 				Song song = contract.getSong();
144 				song.setAibag(bagForThisSet);
145 				_dao.save(song);
146 			}
147 		}		
148 	}
149 	
150 	public void addMusician(Song song, String artistfirstname, String artistlastname, String instruments) {
151 		if(song==null) {
152 			return;
153 		}
154 		if(artistlastname==null) {
155 			return;
156 		}
157 		if(instruments==null || "".equals(instruments)) {
158 			return;
159 		}
160 		Set<AIRelation> relations = BagAndKeywordUtils.createRelations(artistfirstname,artistlastname,song.getBand(),instruments);
161 		// Merge with already existing relations.
162 		if (song.getAibag()!=null) {
163 			for(AIRelation existingRelation : song.getAibag().getRelations()) {
164 				relations.add(existingRelation);
165 			}
166 		}
167 		AIBag newBag = BagAndKeywordUtils.getAIBag(relations);
168 		song.setAibag(newBag);
169 		_dao.save(song);	
170 	}
171 
172 	public Artist getArtistById(long artistId) {
173 		return getDao().getArtistById(artistId);
174 	}
175 	
176 	public void addSongToPlaylist(Song song, Playlist playlist, int songIndex) {
177 		if(playlist==null) {
178 			return;
179 		}
180 		playlist.addSong(song, songIndex);
181 		_dao.save(playlist);
182 	}
183 	
184 	public void deleteMusician(Playlist playlist, String artistfirstname, String artistlastname, String instruments, String tracks) {
185 		if(artistlastname==null) {
186 			return;
187 		}
188 		if(instruments==null || "".equals(instruments)) {
189 			return;
190 		}
191 		if(playlist==null) {
192 			return;
193 		}
194 		TrackList tracklist = null;
195 		if(tracks==null) {
196 			tracklist = TrackList.createInstance(playlist);
197 		} else { 	
198 			tracklist = TrackList.createInstance(tracks);
199 		}
200 		// Check the existence of the artist before building the relations, because this method
201 		// should never create an artist.
202 		Artist removedArtist = getDao().searchArtist(artistfirstname, artistlastname);
203 		if(removedArtist==null) {
204 			return;
205 		}
206 		Set<AIRelation> relationsToDelete = BagAndKeywordUtils.createRelations(artistfirstname,artistlastname,null,instruments);
207 		
208 		/*
209 		 * Construct a map of all PS contracts in the playlist sharing the same set of AI relations. We will
210 		 * use this map to retrieve the AIBag for each different set of AI relations only once and then setting
211 		 * it in all songs with that set of AI relations. This is needed because getAIBag() is implemented
212 		 * inefficiently. Songs that are not in the track list are ignored.
213 		 */
214 		Map<Set<AIRelation>,Set<Contract_PS>> songRelationMap = new HashMap<Set<AIRelation>,Set<Contract_PS>>();
215 		for(Contract_PS contract : playlist.getSongs()) {
216 			if(tracklist.contains(contract.getRowno())) {
217 				Song song = contract.getSong();
218 				Set<AIRelation> relations = new HashSet<AIRelation>();
219 				if (song.getAibag()!=null) {
220 					relations.addAll(song.getAibag().getRelations());
221 				}
222 				Set<Contract_PS> songSet = null;
223 				if(songRelationMap.containsKey(relations)) {
224 					songSet = songRelationMap.get(relations);
225 				} else {
226 					songSet = new HashSet<Contract_PS>();
227 					songRelationMap.put(relations, songSet);
228 				}
229 				songSet.add(contract);
230 			}
231 		}
232 
233 		for(Entry<Set<AIRelation>,Set<Contract_PS>> entry : songRelationMap.entrySet()) {
234 			Set<AIRelation> targetSet = new HashSet<AIRelation>();
235 			targetSet.addAll(entry.getKey());
236 			targetSet.removeAll(relationsToDelete);
237 			AIBag bagForThisSet = BagAndKeywordUtils.getAIBag(targetSet);
238 			for(Contract_PS contract : entry.getValue()) {
239 				Song song = contract.getSong();
240 				song.setAibag(bagForThisSet);
241 				_dao.save(song);
242 			}
243 		}		
244 	}	
245 
246 	public void deleteMusician(Song song, String artistfirstname, String artistlastname, String instruments) {
247 		Artist artist = _dao.searchArtist(artistfirstname, artistlastname);
248 		if(artist == null) {
249 			return;
250 		}
251 		if(instruments==null || "".equals(instruments)) {
252 			return;
253 		}
254 		if(song == null) {
255 			return;
256 		}
257 		Set<AIRelation> relationsToDelete = BagAndKeywordUtils.createRelations(artistfirstname,artistlastname,null,instruments);
258 		
259 		
260 		if(song.getAibag()!=null) {
261 			List<AIRelation> songRelations = song.getAibag().getRelations();
262 			Set<AIRelation> targetRelations = new HashSet<AIRelation>();
263 			targetRelations.addAll(songRelations);
264 			for(AIRelation delrel: relationsToDelete) {
265 				long artistid = delrel.getArtist_id();
266 				long instsrid = delrel.getInstrument_id();
267 				for(AIRelation testrel: targetRelations) {
268 					if (testrel.getArtist_id()==artistid && testrel.getInstrument_id()==instsrid) {
269 						targetRelations.remove(testrel);
270 						break;
271 					}
272 				}
273 			}
274 			AIBag newBag = BagAndKeywordUtils.getAIBag(targetRelations);
275 			song.setAibag(newBag);
276 			_dao.save(song);
277 		}		
278 	}
279 
280 	public void editSongsOfPlaylist(Playlist playlist,List<SongBean> songbeans) {
281 		Map<Long,SongBean> beanMap = new HashMap<Long, SongBean>();
282 		for(SongBean songbean: songbeans) {
283 			long songid = songbean.getSongId();
284 			beanMap.put(songid,songbean);
285 			Song song = getDao().getSongById(songid);
286 			song.setName(songbean.getSongname());
287 			song.setLength(songbean.getSonglength() * 1000);
288 			Keywordbag targetBag = BagAndKeywordUtils.getKeywordBag(songbean.getSongKeywords());
289 			song.setKeywordbag(targetBag);
290 			getDao().save(song);
291 		}
292 		// Update the song indexes
293 		if(playlist!=null) {
294 			for (Contract_PS contract: playlist.getSongs()) {
295 				Song song = contract.getSong();
296 				SongBean bean = beanMap.get(song.getId());
297 				if(bean!=null) {
298 					contract.setRowno(bean.getSongIndex());
299 				}
300 			}
301 			getDao().save(playlist);
302 		}
303 	}
304 
305 	public void addKeywordsToPlaylist(Playlist playlist, String keywords, TrackList tracks) {
306 		if(playlist==null) {
307 			return;
308 		}
309 		for(Contract_PS contract : playlist.getSongs()) {
310 			if(tracks==null || tracks.contains(contract.getRowno())) {
311 				Song song = contract.getSong();
312 				Keywordbag oldBag = song.getKeywordbag();
313 				if(oldBag==null) {
314 					song.setKeywordbag(BagAndKeywordUtils.getKeywordBag(keywords));
315 				} else {
316 					// Do not alter the keyword bag of the song, because the bag may be shared
317 					// with other songs. Instead, make a copy of the keywords.
318 					List<Keyword> songKeywords = new ArrayList<Keyword>(); 
319 					songKeywords.addAll(oldBag.getKeywords());
320 					List<Keyword> newKeywords = BagAndKeywordUtils.getKeywordList(keywords);
321 					songKeywords.addAll(newKeywords);
322 					song.setKeywordbag(BagAndKeywordUtils.getKeywordBag(songKeywords));
323 				}
324 				getDao().save(song);
325 			}
326 		}
327 	}
328 
329 	public void removeKeywordsFromPlaylist(Playlist playlist, String keywords, TrackList tracks) {
330 		if(playlist==null) {
331 			return;
332 		}
333 		for(Contract_PS contract : playlist.getSongs()) {
334 			if(tracks==null || tracks.contains(contract.getRowno())) {
335 				Song song = contract.getSong();
336 				Keywordbag oldBag = song.getKeywordbag();
337 				if(oldBag==null) {
338 					// nothing to do...
339 					break;
340 				} else {
341 					// Do not alter the keyword bag of the song, because the bag may be shared
342 					// with other songs. Instead, make a copy of the keywords.
343 					List<Keyword> songKeywords = new ArrayList<Keyword>(); 
344 					songKeywords.addAll(oldBag.getKeywords());
345 					List<Keyword> removeKeywords = BagAndKeywordUtils.getKeywordList(keywords);
346 					songKeywords.removeAll(removeKeywords);
347 					song.setKeywordbag(BagAndKeywordUtils.getKeywordBag(songKeywords));
348 				}
349 				getDao().save(song);
350 			}
351 		}
352 	}
353 
354 	public void setPlaylistProperties(Playlist playlist, String playlistName, Date releaseDate) {
355 		if(playlistName!=null && playlistName.length()>0) {
356 			playlist.setName(playlistName.trim());
357 		}
358 		if(releaseDate!=null) {
359 			playlist.setReleasedate(releaseDate);
360 		}
361 		getDao().save(playlist);
362 	}
363 	
364 	public Playlist createPlaylist(String playlistname) {
365 		if(playlistname==null) {
366 			return null;
367 		}
368 		if(playlistname.trim().length()==0) {
369 			return null;
370 		}
371 		Playlist playlist = new Playlist();
372 		playlist.setName(playlistname);
373 		playlist.setInserted(new Date());
374 		getDao().save(playlist);
375 		return playlist;
376 	}
377 
378 
379 	public Playlist getPlaylistById(long playlistid) {
380 		return getDao().getPlaylistById(playlistid, null);
381 	}
382 
383 	public void mergePlaylist(Playlist playlist, IUser user, List<PlaylistMergeBean> mergeBeanList) {
384 		// Merge this playlist with others, if requested.
385 		for (PlaylistMergeBean bean: mergeBeanList) {
386 			if (bean.getMergeIndicator()) {
387 				Playlist mergeThis = getDao().getPlaylistById(bean.getPlaylistId(), user);
388 				getDao().mergePlaylists(playlist,mergeThis);
389 			}
390 		}
391 	}
392 	
393 	public List<SongBean> constructSongBeanList(Playlist playlist) {
394 		List<SongBean> result = new ArrayList<SongBean>();
395 		if(playlist==null) {
396 			return result;
397 		}
398 		for (Contract_PS contract: playlist.getSongs()) {
399 			Song song = contract.getSong();
400 			SongBean bean = new SongBean();
401 			bean.setSongId(song.getId());
402 			bean.setSongIndex(contract.getRowno());
403 			bean.setBandname(song.getBand().getName());
404 			bean.setBandId(song.getBand().getId());
405 			bean.setSongname(song.getName());
406 			bean.setSonglength(song.getLength() / 1000);
407 			bean.setSongKeywords(song.listKeywords());
408 			result.add(bean);
409 		}
410 		return result;
411 	}
412 	
413 	public List<PlaylistMergeBean> constructMergeBeanList(Playlist playlist) {
414 		List<PlaylistMergeBean> result = new ArrayList<PlaylistMergeBean>();
415 		if(playlist==null) {
416 			return result;
417 		}
418 		List<Playlist> sameNamePlaylists = getDao().searchPlaylist(playlist.getName());
419 		sameNamePlaylists.remove(playlist);
420 		for(Playlist mergePlaylist: sameNamePlaylists) {
421 			PlaylistMergeBean bean = new PlaylistMergeBean();
422 			bean.setPlaylistId(mergePlaylist.getId());
423 			bean.setPlaylistDescription(mergePlaylist.getId()+": "+mergePlaylist.getName());
424 			bean.setMergeIndicator(false);
425 			result.add(bean);
426 		}
427 		return result;
428 	}
429 	
430 	public Collection<CoverArtSearchResult> getCoverArtList(Playlist playlist) {
431 		if(playlist==null) {
432 			return new ArrayList<CoverArtSearchResult>();
433 		}
434     	ICoverArtFinder p = new CoverArtProcessor();
435     	String band;
436     	try {
437     		band = playlist.getSongs().iterator().next().getSong().getBand().getName();
438     	} catch (Exception e) {
439     		band = "Various";
440     	}
441     	Collection<CoverArtSearchResult> covers = p.findCoverURLs(band, playlist.getName());
442     	
443 		return covers;
444 	}
445 	
446 	public Collection<CoverArtSearchResult> getCoverArtList(String bandName, String playlistName) {
447 		if(bandName==null||bandName.length()<1||playlistName==null||playlistName.length()<1) {
448 			return new ArrayList<CoverArtSearchResult>();
449 		}
450     	ICoverArtFinder p = new CoverArtProcessor();
451     	Collection<CoverArtSearchResult> covers = p.findCoverURLs(bandName, playlistName);
452 		return covers;		
453 	}
454 	
455 	public Song createSong(String songname, Band band, int length, Set<String> keywords, String destination) {
456 		if(songname==null) {
457 			return null;
458 		}
459 		if(songname.trim().length()==0) {
460 			return null;
461 		}
462 		if(band==null) {
463 			return null;
464 		}
465 		if(keywords==null) {
466 			keywords = new HashSet<String>();
467 		}
468 		if(destination==null) {
469 			return null;
470 		}
471 		Link newlink = new Link();
472 		newlink.setUrl(destination);
473 		getDao().save(newlink);
474 		Song newSong = new Song();
475 		newSong.setName(songname);
476 		newSong.setBand(band);
477 		newSong.setLink(newlink);
478 		newSong.setLength(length);
479 		newSong.setInserted(new Date());
480 		for(String keywordtext : keywords) {
481 			Keyword kw = getDao().searchKeyword(keywordtext);
482 			if (kw==null) {
483 				kw = new Keyword();
484 				kw.setName(keywordtext);
485 				try {
486 					kw.setParent(null);
487 				} catch (KeywordCycleException e) {
488 					// Ignore. setParent(null) must never throw an exception.
489 				}
490 				getDao().save(kw);
491 			}
492 			BagAndKeywordUtils.addKeywordToSong(newSong,kw);
493 		}
494 		getDao().save(newSong);
495 		return newSong;
496 	}
497 	
498 	public Song getSongById(long songid) {
499 		return getDao().getSongById(songid);
500 	}
501 	
502 	public Playlist getUpcoming(long userid) {
503 		Playlist playlist = new Playlist();
504 		DJ dj = StreamMaster.getDJByUser(userid);
505 		if(dj!=null) {
506 			int counter=0;
507 			for (long songid : dj.peek(6)) {
508 				playlist.addSong(getDao().getSongById(songid),++counter);
509 			}
510 		}		
511 		return playlist;
512 	}
513 	
514 	public void setSongProperties(Song song, String name, String bandName, int msecs, String keywords) {
515 		if(song==null) {
516 			return;
517 		}
518 		if(name!=null) {
519 			name = name.trim();
520 			if(name.length()>0) {
521 				song.setName(name);
522 			}
523 		}
524 		if(msecs>0) {
525 			song.setLength(msecs);
526 		}
527 		// Compare typed band name with current. Change if necessary.
528 		if(bandName!=null) {
529 			bandName = bandName.trim();
530 			if(bandName.length()>0) {
531 				if(!song.getBand().getName().equals(bandName)) {
532 					Band targetBand = getDao().searchBand(bandName);
533 					if (targetBand == null) {
534 						targetBand = new Band();
535 						targetBand.setName(bandName);
536 						getDao().save(targetBand);
537 					}
538 					song.setBand(targetBand);
539 				}				
540 			}
541 		}
542 		// Save changed keywords
543 		Keywordbag targetBag = BagAndKeywordUtils.getKeywordBag(keywords);
544 		song.setKeywordbag(targetBag);
545 		getDao().save(song);
546 	}
547 
548 	public List<Playlist> getSongPlaylists(Song song) {
549 		return getDao().listPlaylists(song);
550 	}
551 
552 	public Playlist getSongNeighbours(Song song, IUser user) {
553 		if(song==null) {
554 			return new Playlist();
555 		}
556 		return getDao().getNeighbours(song.getId(), user);
557 	}
558 
559 	public Playlist getSongsByBand(Band band) {
560 		if(band==null) {
561 			return new Playlist();
562 		}
563 		return getDao().songsByBand(band.getId());
564 	}
565 
566 	public Band getBandById(long bandid) {
567 		return getDao().getBandById(bandid);
568 	}
569 
570 	public List<Playlist> getBandPlaylists(Band band) {
571 		return getDao().listPlaylists(band);
572 	}
573 
574 	public void setBandProperties(Band band, String bandName) {
575 		// Trim whitespace from the new band name.
576 		if(bandName!=null) {
577 			bandName = bandName.trim();
578 			// Check if the band name has changed.
579 			if(!bandName.equals(band.getName())) {
580 				// If the user changed the band name, check if there already
581 				// is a band with that name. If so, merge the two bands.
582 				Band mergeBand = getDao().searchBand(bandName);
583 				if(mergeBand!=null) {
584 					// Merge the two bands. The band named in the "band"
585 					// variable does no longer exist in the database after
586 					// mergeBands() finishes. Change it into the band that
587 					// it is merged into.
588 					getDao().mergeBands(mergeBand, band);
589 					band = mergeBand;
590 				} else {
591 					// Just change the band name
592 					band.setName(bandName);					
593 				}
594 			}
595 		}
596 		getDao().save(band);
597 	}
598 
599 	public List<Object[]> listBands(IUser user) {
600 		return getDao().listBands(user);
601 	}
602 
603 	public Keyword getKeywordById(Long id) {
604 		return getDao().getKeywordById(id);
605 	}
606 
607 	public List<Keywordbag> getKeywordBagsWithKeywords(List<Long> selectedKeywordIds) {
608 		List<Keyword> keywords = new LinkedList<Keyword>();
609 		if (selectedKeywordIds!=null) {
610 			for (Long keywordid : selectedKeywordIds) {
611 				keywords.add(getDao().getKeywordById(keywordid));
612 			}
613 			return getDao().listKeywordsBags(keywords);
614 		} else {
615 			return null;
616 		}
617 	}
618 
619 	public List<Object[]> listKeywords(IUser user, List<Keywordbag> bags) {
620 		return getDao().listKeywords(user, bags);
621 	}
622 
623 	public Playlist songsByKeywordbags(List<Keywordbag> bags, User user, int maxResults) {
624 		return getDao().songsByKeywordbags(bags, user, maxResults);
625 	}
626 
627 	public void setPlaylistCoverArt(Playlist playlist, CoverArtSearchResult selected) throws IOException {
628 		if (selected==null || playlist==null) {
629 			return;
630 		}
631 		URI uri = selected.getURI();
632 		if(uri==null) {
633 			return;
634 		}
635 		if(!uri.isAbsolute()) {
636 			uri = URI.create("file:"+uri.toString());
637 		}
638 		URL url = uri.toURL();
639 		URLConnection urlc = url.openConnection();
640 		urlc.setRequestProperty("user-agent","Mozilla/5.0"); //Google wants a user-agent.
641 		InputStream imageStream = urlc.getInputStream();
642 		CoverArtManager.purge(playlist.getId());
643 		CoverArtManager.add(playlist.getId(), imageStream);
644 		imageStream.close();
645 	}
646 
647 	public File attemptToDownloadCoverArt(long playlistid, int size) {
648 		if (!CoverArtManager.contains(playlistid, size)) { //download!
649 			if (!CoverArtManager.contains(playlistid, 0)) {
650 				Logger.getLogger(McService.class).debug("Original coverart not found; downloading...");
651 				downloadCover(playlistid);
652 			}
653 			Logger.getLogger(McService.class).debug("Resized coverart not found; creating...");
654 			try {
655 				CoverArtManager.scale(playlistid, size);
656 			} catch (FileNotFoundException e) {
657 				Logger.getLogger(McService.class).error("Error resizing coverart: "+e);
658 			}
659 		}
660 		return CoverArtManager.get(playlistid, size);
661 	}
662 	
663     /**
664      * @param playlistid
665      */
666     private void downloadCover(long playlistid) {
667 		Playlist playlist = getPlaylistById(playlistid);
668 		Collection<CoverArtSearchResult> searchresult = getCoverArtList(playlist);
669     	CoverArtProcessor p = new CoverArtProcessor();
670     	
671     	boolean succes = false;
672     	Iterator<CoverArtSearchResult> it = searchresult.iterator();
673     	while (!succes && it.hasNext()) {
674     		CoverArtSearchResult test = it.next();
675     		InputStream in = null;
676    			try {
677    	   			in = p.getCover(test,playlist.getId());
678    	   			CoverArtManager.add(playlistid,in);
679     			succes = true;
680     		} catch (IOException e) {
681     			Logger.getLogger(McService.class).debug("Exception downloading coverart, trying next searchresult");
682     		} finally {
683     			try {
684     				if (in!=null) in.close();
685     			} catch (IOException e) {
686         			Logger.getLogger(McService.class).debug("Error closing inputstream.");
687     			}
688     		}
689     	}
690     }
691 
692 	public Set<Comment> getReviews(Playlist playlist) {
693 		CommentService service = new CommentService();
694 		return service.getComments(playlist);
695 	}
696 
697 	public Set<Comment> getReviews(Band band) {
698 		CommentService service = new CommentService();
699 		return service.getComments(band);
700 	}
701 	
702 	public List<Playlist> findImportedPlaylist(MusicArchiveBean archive) {
703 		List<Playlist> candidates = new ArrayList<Playlist>();
704 		if(archive==null) {
705 			return candidates;
706 		}
707 		Set<String> playlistNames = new HashSet<String>();
708 		for(MusicArchiveEntryBean entry: archive.getEntrySet()) {
709 			if(entry.getPlaylistName()!=null && entry.getPlaylistName().trim().length()>0) {
710 				playlistNames.add(entry.getPlaylistName());
711 			}
712 		}
713 		// TODO: This can be implemented more efficiently if searchPlaylist accepts an array of names to search.
714 		for(String playlistName : playlistNames ) {
715 			List<Playlist> playlistsSameName = getDao().searchPlaylist(playlistName);
716 			if(playlistsSameName.size()>0) {
717 					candidates.addAll(playlistsSameName);
718 			}
719 		}
720 		return candidates;
721 	}
722 	
723 	public Set<Playlist> guessPlaylistsInArchive(MusicArchiveBean archive) {
724 		Set<Playlist> candidates = new HashSet<Playlist>();
725 		if(archive==null) {
726 			return candidates;
727 		}
728 		// Step 1: If a persistent playlist with the same name and artist exists, use that.
729 		String bandNameCandidate = guessBandNameOfArchive(archive);
730 		List<Playlist> persistentCandidates = findImportedPlaylist(archive);
731 		for(Playlist persistentCandidate: persistentCandidates) {
732 			for(Contract_PS songContracts: persistentCandidate.getSongs()) {
733 				if(songContracts.getSong().getBand().getName().equalsIgnoreCase(bandNameCandidate)) {
734 					candidates.add(persistentCandidate);
735 					break;
736 				}
737 			}
738 		}
739 		// The above will fail in the case of an album with various artists each performing
740 		// one song. The playlist name will match, but no song of the same artist can be found.
741 		// If no candidates are found, but there is a playlist with the same name, use that.
742 		if(candidates.isEmpty()) {
743 			candidates.addAll(persistentCandidates);
744 		}
745 		return candidates;
746 	}
747 
748 	public String guessBandNameOfArchive(MusicArchiveBean archive) {
749 		Set<String> bandNames = new HashSet<String>();
750 		String bandName = null;
751 		if(archive==null) {
752 			return "Unknown";
753 		}
754 		for(MusicArchiveEntryBean entry: archive.getEntrySet()) {
755 			if(entry.getBandName()!=null && entry.getBandName().trim().length()>0) {
756 				bandNames.add(entry.getBandName());
757 			}
758 		}
759 		if(bandNames.size()==0) {
760 			bandName = "Unknown";
761 		} else if(bandNames.size()==1) {
762 			bandName = bandNames.iterator().next();
763 		} else {
764 			bandName = "Various";
765 		}		
766 		return bandName;
767 	}
768 
769 	public List<Playlist> searchPlaylistByName(String playlistName) {
770 		return getDao().searchPlaylist(playlistName);
771 	}
772 
773 }