itunes-controller 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. data/.buildpath +5 -0
  2. data/.gitignore +3 -0
  3. data/.project +17 -0
  4. data/.rvmrc +81 -0
  5. data/LICENSE +674 -0
  6. data/README +27 -0
  7. data/Rakefile +27 -0
  8. data/TODO +8 -0
  9. data/bin/addFiles.rb +35 -0
  10. data/bin/dummyiTunesController.rb +109 -0
  11. data/bin/itunesController.rb +78 -0
  12. data/bin/listDeadTracks.rb +45 -0
  13. data/bin/listNewTracks.rb +88 -0
  14. data/bin/recreateTrackCache.rb +31 -0
  15. data/bin/refreshFiles.rb +42 -0
  16. data/bin/removeDeadTracks.rb +31 -0
  17. data/bin/removeFiles.rb +42 -0
  18. data/bin/trackInfo.rb +50 -0
  19. data/itunes-controller.gemspec +24 -0
  20. data/jar-stuff.sh +24 -0
  21. data/lib/itunesController/application.rb +127 -0
  22. data/lib/itunesController/cachedcontroller.rb +188 -0
  23. data/lib/itunesController/config.rb +95 -0
  24. data/lib/itunesController/controller_creator.rb +29 -0
  25. data/lib/itunesController/controllserver.rb +583 -0
  26. data/lib/itunesController/database/backend.rb +41 -0
  27. data/lib/itunesController/database/database.rb +166 -0
  28. data/lib/itunesController/database/sqlite3_backend.rb +67 -0
  29. data/lib/itunesController/debug.rb +124 -0
  30. data/lib/itunesController/dummy_itunes_track.rb +40 -0
  31. data/lib/itunesController/dummy_itunescontroller.rb +142 -0
  32. data/lib/itunesController/itunescontroller.rb +90 -0
  33. data/lib/itunesController/itunescontroller_factory.rb +51 -0
  34. data/lib/itunesController/kinds.rb +138 -0
  35. data/lib/itunesController/logging.rb +119 -0
  36. data/lib/itunesController/macosx_itunescontroller.rb +204 -0
  37. data/lib/itunesController/platform.rb +53 -0
  38. data/lib/itunesController/sqlite_creator.rb +35 -0
  39. data/lib/itunesController/track.rb +39 -0
  40. data/lib/itunesController/version.rb +25 -0
  41. data/lib/itunesController/windows_itunescontroller.rb +145 -0
  42. data/test/base_server_test_case.rb +125 -0
  43. data/test/dummy_client.rb +44 -0
  44. data/test/test_server.rb +312 -0
  45. metadata +185 -0
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/ruby -I../lib
2
+ #
3
+ # A command line util used to remove tracks to the iTunes library
4
+ #
5
+ # Author:: John-Paul Stanford <dev@stanwood.org.uk>
6
+ # Copyright:: Copyright (C) 2011 John-Paul.Stanford <dev@stanwood.org.uk>
7
+ # License:: GNU General Public License v3 <http://www.gnu.org/licenses/>
8
+ #
9
+
10
+ require 'itunesController/application'
11
+ require 'itunesController/sqlite_creator'
12
+
13
+ class App < ItunesController::Application
14
+
15
+ # Used to display the command line useage
16
+ def displayUsage()
17
+ puts("Usage: "+@appName+" [options] files...")
18
+ puts("")
19
+ puts(genericOptionDescription())
20
+ end
21
+
22
+ def checkAppOptions()
23
+ if ARGV.length == 0
24
+ usageError("No files given.")
25
+ end
26
+ end
27
+
28
+ def createController
29
+ return ItunesController::SQLLiteControllerCreator.new
30
+ end
31
+
32
+ def execApp(controllerCreator)
33
+ controller = controllerCreator.createController()
34
+ ARGV.each do | path |
35
+ controller.updateTrack(path)
36
+ end
37
+ end
38
+ end
39
+
40
+ app=App.new("refreshTracks.rb")
41
+ app.exec()
42
+
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/ruby -I../lib
2
+ #
3
+ # A command line util used to remove tracks from iTunes whoes files can't be found.
4
+ #
5
+ # Author:: John-Paul Stanford <dev@stanwood.org.uk>
6
+ # Copyright:: Copyright (C) 2011 John-Paul.Stanford <dev@stanwood.org.uk>
7
+ # License:: GNU General Public License v3 <http://www.gnu.org/licenses/>
8
+ #
9
+
10
+ require 'itunesController/cachedcontroller'
11
+ require 'itunesController/sqlite_creator'
12
+ require 'itunesController/debug'
13
+ require 'itunesController/logging'
14
+ require 'itunesController/application'
15
+
16
+ class App < ItunesController::Application
17
+
18
+ def createController
19
+ return ItunesController::SQLLiteControllerCreator.new
20
+ end
21
+
22
+ def execApp(controllerCreator)
23
+ controller = controllerCreator.createController()
24
+ count=controller.removeDeadTracks()
25
+ ItunesController::ItunesControllerLogging::info("Removed #{count} dead tracks")
26
+ end
27
+ end
28
+
29
+ app=App.new("removeDeadTracks.rb")
30
+ app.exec()
31
+
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/ruby -I../lib
2
+ #
3
+ # A command line util used to remove tracks to the iTunes library
4
+ #
5
+ # Author:: John-Paul Stanford <dev@stanwood.org.uk>
6
+ # Copyright:: Copyright (C) 2011 John-Paul.Stanford <dev@stanwood.org.uk>
7
+ # License:: GNU General Public License v3 <http://www.gnu.org/licenses/>
8
+ #
9
+
10
+ require 'itunesController/cachedcontroller'
11
+ require 'itunesController/sqlite_creator'
12
+ require 'itunesController/application'
13
+
14
+ class App < ItunesController::Application
15
+
16
+ # Used to display the command line useage
17
+ def displayUsage()
18
+ puts("Usage: "+@appName+" [options] files...")
19
+ puts("")
20
+ puts(genericOptionDescription())
21
+ end
22
+
23
+ def checkAppOptions()
24
+ if ARGV.length == 0
25
+ usageError("No files given.")
26
+ end
27
+ end
28
+
29
+ def createController
30
+ return ItunesController::SQLLiteControllerCreator.new
31
+ end
32
+
33
+ def execApp(controllerCreator)
34
+ controller = controllerCreator.createController()
35
+ ARGV.each do | path |
36
+ controller.removeTrack(path)
37
+ end
38
+ end
39
+ end
40
+
41
+ app=App.new("removeFiles.rb")
42
+ app.exec()
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/ruby -I../lib
2
+ #
3
+ # A command line util used to remove tracks to the iTunes library
4
+ #
5
+ # Author:: John-Paul Stanford <dev@stanwood.org.uk>
6
+ # Copyright:: Copyright (C) 2011 John-Paul.Stanford <dev@stanwood.org.uk>
7
+ # License:: GNU General Public License v3 <http://www.gnu.org/licenses/>
8
+ #
9
+
10
+ require 'itunesController/sqlite_creator'
11
+ require 'itunesController/cachedcontroller'
12
+ require 'itunesController/debug'
13
+ require 'itunesController/logging'
14
+ require 'itunesController/application'
15
+
16
+ class App < ItunesController::Application
17
+
18
+ # Used to display the command line useage
19
+ def displayUsage()
20
+ puts("Usage: "+@appName+" [options] files...")
21
+ puts("")
22
+ puts(genericOptionDescription())
23
+ end
24
+
25
+ def checkAppOptions()
26
+ if ARGV.length == 0
27
+ usageError("No files given.")
28
+ end
29
+ end
30
+
31
+ def createController
32
+ return ItunesController::SQLLiteControllerCreator.new
33
+ end
34
+
35
+ def execApp(controllerCreator)
36
+ controller = controllerCreator.createController()
37
+ ARGV.each do | path |
38
+ track=controller.getTrack(path)
39
+ if (track!=nil)
40
+ ItunesController::ItunesControllerDebug::printTrack(track)
41
+ else
42
+ ItunesController::ItunesControllerLogging::error("Unable to find track")
43
+ end
44
+ ItunesController::ItunesControllerLogging::info("")
45
+ end
46
+ end
47
+ end
48
+
49
+ app=App.new("trackInfo.rb")
50
+ app.exec()
@@ -0,0 +1,24 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require 'itunesController/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'itunes-controller'
6
+ s.version = ItunesController::VERSION
7
+ s.date = '2012-02-06'
8
+ s.summary = "TCP command server that can be used to control iTunes headlessly"
9
+ s.description = "A application to control enable iTunes to be operated on a headless server without the GUI. It provides a TCP server which can be connected to locally or remote by other applications to control iTunes"
10
+ s.authors = ["John-Paul Stanford"]
11
+ s.email = 'dev@stanwood.org.uk'
12
+ s.homepage = 'http://code.google.com/p/itunes-remote-control-server/'
13
+ s.files = `git ls-files`.split("\n")
14
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
15
+ s.require_paths = ["lib"]
16
+ s.has_rdoc = 'yard'
17
+ s.rdoc_options = [ '--main', 'README' ]
18
+ s.extra_rdoc_files = [ 'LICENSE', 'README' ]
19
+ s.add_development_dependency('yard')
20
+ s.add_development_dependency('rake')
21
+ s.add_development_dependency('test-unit')
22
+ s.add_dependency('escape')
23
+ s.add_dependency('sqlite3')
24
+ end
@@ -0,0 +1,24 @@
1
+ #!/bin/bash
2
+
3
+ GEMS=""
4
+ GEMS="$GEMS sqlite3"
5
+ GEMS="$GEMS escape"
6
+ GEMS="$GEMS itunes-controller"
7
+
8
+ JRUBY_ARGS="--1.9"
9
+
10
+ # Compile the gem
11
+ jruby $JRUBY_ARGS -S rake gem
12
+ if [ $? -ne 0 ]
13
+ then
14
+ exit 1
15
+ fi
16
+
17
+ # Create the jar
18
+ jruby $JRUBY_ARGS -S gem install -i ./itunes-controller $GEMS --no-rdoc --no-ri
19
+ jar cf itunes-controller-dummy-server.jar -C itunes-controller .
20
+
21
+ rm -rf ./itunes-controller
22
+
23
+ # Display the results
24
+ jruby $JRUBY_ARGS -ritunes-controller-dummy-server.jar -S gem list
@@ -0,0 +1,127 @@
1
+ #
2
+ # Copyright (C) 2011-2012 John-Paul.Stanford <dev@stanwood.org.uk>
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ #
17
+ # Author:: John-Paul Stanford <dev@stanwood.org.uk>
18
+ # Copyright:: Copyright (C) 2011 John-Paul.Stanford <dev@stanwood.org.uk>
19
+ # License:: GNU General Public License v3 <http://www.gnu.org/licenses/>
20
+ #
21
+
22
+
23
+ require 'itunesController/cachedcontroller'
24
+ require 'itunesController/logging'
25
+ require 'itunesController/version'
26
+
27
+ require 'rubygems'
28
+ require 'optparse'
29
+
30
+ module ItunesController
31
+
32
+ class Application
33
+
34
+ def initialize(appName)
35
+ @appName = appName
36
+ @options = {}
37
+ @options[:logFile] = nil
38
+ end
39
+
40
+ def genericOptionDescription()
41
+ result=[]
42
+ result.push("Specific options:")
43
+ result.push(" -f, --log_file FILE Optional paramter used to log messages to")
44
+ result.push(" -l, --log_config LEVEL Optional paramter used to log level [DEBUG|INFO|WARN|ERROR]")
45
+ result.push(" -v, --version Display version of the application")
46
+ result.push(" -h, --help Display this screen")
47
+ return result.join("\n")
48
+ end
49
+
50
+ # Used to display the command line useage
51
+ def displayUsage()
52
+ puts("Usage: "+@appName+" [options]")
53
+ puts("")
54
+ puts(genericOptionDescription())
55
+ end
56
+
57
+ # Used to display a error message and the command line usesage
58
+ # @param [String] message The error message
59
+ def usageError(message)
60
+ $stderr.puts "ERROR: "+message
61
+ displayUsage()
62
+ exit(1)
63
+ end
64
+
65
+ # Used to check the command line options are valid
66
+ def checkOptions
67
+ checkAppOptions
68
+ end
69
+
70
+ def parseOptions
71
+ optparse = OptionParser.new do|opts|
72
+ opts.banner = "Usage: "+@appName+" [options]"
73
+ opts.separator ""
74
+ opts.separator "Specific options:"
75
+
76
+ opts.on('-f','--log_file FILE','Optional paramter used to log messages to') do |value|
77
+ @options[:logFile] = value
78
+ ItunesController::ItunesControllerLogging::setLogFile(@options[:logFile])
79
+ end
80
+ opts.on('-l','--log_config LEVEL','Optional paramter used to log level [DEBUG|INFO|WARN|ERROR]') do |value|
81
+ @options[:logConfig] = value
82
+ ItunesController::ItunesControllerLogging::setLogLevelFromString(@options[:logConfig])
83
+ end
84
+ parseAppOptions(opts)
85
+
86
+ opts.on_tail( '-v', '--version', 'Display version of the application' ) do
87
+ puts "itunes-remote-control-server "+ItunesController::VERSION
88
+ puts "Copyright (C) 2012 John-Paul Stanford"
89
+ puts "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>."
90
+ puts "This is free software: you are free to change and redistribute it."
91
+ puts "There is NO WARRANTY, to the extent permitted by law."
92
+ puts ""
93
+ puts "Authors: John-Paul Stanford <dev@stanwood.org.uk>"
94
+ puts "Website: http://code.google.com/p/itunes-remote-control-server/"
95
+ end
96
+ opts.on_tail( '-h', '--help', 'Display this screen' ) do
97
+ puts opts
98
+ exit
99
+ end
100
+ end
101
+ optparse.parse!
102
+ checkOptions()
103
+ end
104
+
105
+ def exec()
106
+ parseOptions
107
+ controllerCreator = createController()
108
+ execApp(controllerCreator)
109
+ #controller.close()
110
+ end
111
+
112
+ def getOptions()
113
+ return @options
114
+ end
115
+
116
+ def parseAppOptions(opts)
117
+ end
118
+
119
+ def checkAppOptions()
120
+ end
121
+
122
+ def execApp(controllerCreator)
123
+ raise "ERROR: Your trying to instantiate an abstract class"
124
+ end
125
+
126
+ end
127
+ end
@@ -0,0 +1,188 @@
1
+ # Copyright (C) 2011-2012 John-Paul.Stanford <dev@stanwood.org.uk>
2
+ #
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
+ #
16
+ # Author:: John-Paul Stanford <dev@stanwood.org.uk>
17
+ # Copyright:: Copyright (C) 2011 John-Paul.Stanford <dev@stanwood.org.uk>
18
+ # License:: GNU General Public License v3 <http://www.gnu.org/licenses/>
19
+ #
20
+
21
+ require 'itunesController/logging'
22
+ require 'itunesController/itunescontroller'
23
+ require 'itunesController/database/database'
24
+ require 'itunesController/track'
25
+
26
+ module ItunesController
27
+
28
+ class CachedController
29
+
30
+ def initialize(controller,databaseBackend)
31
+ @controller = controller
32
+ @database = ItunesController::Database.new(@controller,databaseBackend)
33
+ @cachedOnCreate=cacheTracks()
34
+ end
35
+
36
+ def getCachedTracksOnCreate()
37
+ return @cachedOnCreate
38
+ end
39
+
40
+ def removeTrack(path)
41
+ trackInfo=@database.getTrack(path)
42
+ if (trackInfo==nil)
43
+ ItunesController::ItunesControllerLogging::error("Unable to find track with path: "+path)
44
+ return nil
45
+ end
46
+ removeTrackByInfo(trackInfo)
47
+ end
48
+
49
+ def removeTrackByInfo(trackInfo)
50
+ ItunesController::ItunesControllerLogging::debug("Removing track: '#{trackInfo}'")
51
+ foundTracks=@controller.searchLibrary(trackInfo.title)
52
+ if (foundTracks==nil || foundTracks.length==0)
53
+ ItunesController::ItunesControllerLogging::error("Unable to find track #{trackInfo}'")
54
+ return nil
55
+ end
56
+ foundTracks.each do | t |
57
+ if (@controller.getTrackDatabaseId(t) == trackInfo.databaseId)
58
+ @controller.removeTracksFromLibrary([t])
59
+ count=@database.getParam(ItunesController::Database::PARAM_KEY_TRACK_COUNT,0).to_i
60
+ count=count-1
61
+ @database.setParam(ItunesController::Database::PARAM_KEY_TRACK_COUNT,count)
62
+ if (trackInfo.location!=nil)
63
+ ItunesController::ItunesControllerLogging::info("Remove track '#{trackInfo.location}' from iTunes library")
64
+ else
65
+ ItunesController::ItunesControllerLogging::info("Remove track with databaseId '#{trackInfo.databaseId}' from iTunes library")
66
+ end
67
+ @database.removeTrack(trackInfo)
68
+ end
69
+ end
70
+ end
71
+
72
+ def updateTrack(path)
73
+ trackInfo=@database.getTrack(path)
74
+ if (trackInfo==nil)
75
+ ItunesController::ItunesControllerLogging::debug("Unable to find track with path: "+path)
76
+ return nil
77
+ end
78
+ foundTracks=@controller.searchLibrary(trackInfo.title)
79
+ foundTracks.each do | t |
80
+ if (@controller.getTrackDatabaseId(t) == trackInfo.databaseId)
81
+ @controller.refreshTracks([t])
82
+ ItunesController::ItunesControllerLogging::info("Refreshed track '#{trackInfo.location}' metadata")
83
+ end
84
+ end
85
+ end
86
+
87
+ def addTrack(path)
88
+ ItunesController::ItunesControllerLogging::debug("Adding track #{path}")
89
+ ids=@controller.addFilesToLibrary([path])
90
+ if (ids.length==1)
91
+ if (@database.getTrackById(ids[0].databaseId)!=nil)
92
+ ItunesController::ItunesControllerLogging::info("Track '#{path}' allready in the database with the id #{ids[0].databaseId}")
93
+ return nil
94
+ end
95
+ track=ids[0]
96
+ @database.addTrack(track)
97
+ count=@database.getParam(ItunesController::Database::PARAM_KEY_TRACK_COUNT,0).to_i
98
+ count=count+1
99
+ @database.setParam(ItunesController::Database::PARAM_KEY_TRACK_COUNT,count)
100
+ ItunesController::ItunesControllerLogging::info("Added track '#{path}' with id #{ids[0].databaseId}")
101
+ return track
102
+ else
103
+ ItunesController::ItunesControllerLogging::info("Uable to add track #{path}")
104
+ return nil
105
+ end
106
+ end
107
+
108
+ def getTrack(path)
109
+ trackInfo=@database.getTrack(path)
110
+ if (trackInfo==nil)
111
+ ItunesController::ItunesControllerLogging::debug("Unable to find track with path: "+path)
112
+ return nil
113
+ end
114
+ foundTracks=@controller.searchLibrary(trackInfo.title)
115
+ tracks=[]
116
+ foundTracks.each do | t |
117
+ if (@controller.getTrackDatabaseId(t) == trackInfo.databaseId)
118
+ tracks.push(t)
119
+ end
120
+ end
121
+ if (tracks.length==1)
122
+ return tracks[0]
123
+ else
124
+ return nil
125
+ end
126
+ end
127
+
128
+ def trackInLibrary?(path)
129
+ trackInfo=@database.getTrack(path)
130
+ return (trackInfo!=nil)
131
+ end
132
+
133
+ def cacheTracks(force=false)
134
+ if (force || needsRecacheTracks())
135
+ ItunesController::ItunesControllerLogging::info("Caching tracks...")
136
+ @database.removeTracks()
137
+ @database.setParam(ItunesController::Database::PARAM_KEY_TRACK_COUNT,@controller.getTrackCount())
138
+ size=@controller.getTracks() { |t,count,size,dead|
139
+ if (dead)
140
+ ItunesController::ItunesControllerLogging::warn("Found dead track with databaseID #{t.databaseId}")
141
+ @database.addDeadTrack(t)
142
+ else
143
+ @database.addTrack(t)
144
+ end
145
+ }
146
+ return true
147
+ else
148
+ ItunesController::ItunesControllerLogging::debug("Tracks uptodate")
149
+ end
150
+ return false
151
+ end
152
+
153
+ def findDeadTracks()
154
+ return @database.getDeadTracks()
155
+ end
156
+
157
+ def removeDeadTracks()
158
+ count=0
159
+ deadTracks=findDeadTracks()
160
+ deadTracks.each do | track |
161
+ removeTrackByInfo(track)
162
+ count+=1
163
+ end
164
+ return count
165
+ end
166
+
167
+ def getItunesVersion
168
+ return @controller.version
169
+ end
170
+
171
+ def close()
172
+ @database.close()
173
+ end
174
+
175
+ private
176
+ def needsRecacheTracks()
177
+ # TODO better checks for changes between the cache and iTunes
178
+ count=@controller.getTrackCount()
179
+ cacheCount=@database.getParam(ItunesController::Database::PARAM_KEY_TRACK_COUNT,0).to_i
180
+ if (count!=cacheCount)
181
+ ItunesController::ItunesControllerLogging::debug("Need to reach tracks. iTunes has #{count} and cache has #{cacheCount}.")
182
+ return true
183
+ end
184
+ return false
185
+ end
186
+ end
187
+
188
+ end