PageRenderTime 24ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/musicscan/src/main/scala/local/choonweb/musicscan/MongoPersister.scala

http://github.com/etaoins/choonweb
Scala | 109 lines | 82 code | 19 blank | 8 comment | 2 complexity | cf874dbe2fa0ed423e52232229bba72a MD5 | raw file
  1. package local.choonweb.musicscan
  2. import scala.actors._
  3. import org.jaudiotagger.tag._
  4. import com.mongodb.casbah.Imports._
  5. import java.util.Date
  6. class MongoPersister(mongoDB : MongoDB) extends Actor {
  7. val trackColl = mongoDB("tracks")
  8. val scanColl = mongoDB("scans")
  9. // Create our indexes
  10. trackColl.ensureIndex(MongoDBObject("path" -> 1), null, true)
  11. trackColl.ensureIndex(MongoDBObject("tag.artist" -> 1))
  12. trackColl.ensureIndex(MongoDBObject("tag.album" -> 1))
  13. trackColl.ensureIndex(MongoDBObject("tag.title" -> 1))
  14. trackColl.ensureIndex(MongoDBObject("keywords" -> 1))
  15. scanColl.ensureIndex(MongoDBObject("finished" -> -1))
  16. // Tracks if we've actually done anything
  17. var dirty = false
  18. def act() {
  19. loop {
  20. react {
  21. case AudioFileScanned(relativePath, audioFile) =>
  22. def tagInformation(tag : org.jaudiotagger.tag.Tag) : MongoDBObject = {
  23. val tagBuilder = MongoDBObject.newBuilder
  24. tagBuilder += "artist" -> tag.getFirst(FieldKey.ARTIST)
  25. try {
  26. tagBuilder += "album" -> tag.getFirst(FieldKey.ALBUM)
  27. }
  28. catch {
  29. case e : NullPointerException => // Epic don't care
  30. }
  31. tagBuilder += "title" -> tag.getFirst(FieldKey.TITLE)
  32. return tagBuilder.result
  33. }
  34. def fileInformation(file : java.io.File) : MongoDBObject = {
  35. val fileBuilder = MongoDBObject.newBuilder
  36. fileBuilder += "size" -> file.length
  37. fileBuilder += "lastModified" -> new Date(file.lastModified)
  38. return fileBuilder.result
  39. }
  40. def keywords(tag : org.jaudiotagger.tag.Tag) : Set[String] = {
  41. def findKeywords(key : FieldKey) : Set[String] = {
  42. try {
  43. val words = """[\w']+""".r.findAllIn(tag.getFirst(key))
  44. // Convert to lowercase as Mongo is case sensitive
  45. val lowercaseWords = for (word <- words) yield word.toLowerCase
  46. // Remove dupes
  47. return lowercaseWords.toSet
  48. }
  49. catch {
  50. case e : NullPointerException =>
  51. }
  52. return Set()
  53. }
  54. var keywords = findKeywords(FieldKey.ARTIST)
  55. keywords ++= findKeywords(FieldKey.ALBUM)
  56. keywords ++= findKeywords(FieldKey.TITLE)
  57. return keywords
  58. }
  59. try {
  60. // This is what we're upserting based on
  61. val indexBuilder = MongoDBObject.newBuilder
  62. indexBuilder += "path" -> relativePath
  63. val index = indexBuilder.result
  64. // Add the tag to a high level track object
  65. val trackBuilder = MongoDBObject.newBuilder
  66. trackBuilder += "tag" -> tagInformation(audioFile.getTag())
  67. trackBuilder += "file" -> fileInformation(audioFile.getFile())
  68. trackBuilder += "duration" -> audioFile.getAudioHeader().getTrackLength()
  69. trackBuilder += "seen" -> new Date()
  70. trackBuilder += "keywords" -> keywords(audioFile.getTag)
  71. trackBuilder ++= index
  72. val track = trackBuilder.result
  73. trackColl.update(index, track, upsert = true, multi = false)
  74. dirty = true
  75. }
  76. catch {
  77. case e : NullPointerException => // Don't save the track
  78. }
  79. case TagExtractionDone() =>
  80. if (dirty) {
  81. // Record our scan
  82. val scanDoc = MongoDBObject("finished" -> new Date())
  83. scanColl.insert(scanDoc)
  84. }
  85. exit()
  86. }
  87. }
  88. }
  89. }
  90. // vim: set ts=4 sw=4 et: