itunes-controller 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,53 @@
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
+ module ItunesController
23
+
24
+ class Platform
25
+
26
+ def self.getUserHomeDir()
27
+ homes = ["HOME", "HOMEPATH"]
28
+ realHome = homes.detect {|h| ENV[h] != nil}
29
+ if not realHome
30
+ raise "Could not find home directory"
31
+ end
32
+
33
+ return ENV[realHome]
34
+ end
35
+
36
+ def self.isWindows()
37
+ return RUBY_PLATFORM =~ /mswin|mingw/
38
+ end
39
+
40
+ def self.isMacOSX()
41
+ return RUBY_PLATFORM =~ /darwin/
42
+ end
43
+
44
+ def self.isLinux()
45
+ return RUBY_PLATFORM =~ /linux/
46
+ end
47
+
48
+ def self.isJRuby()
49
+ return RUBY_PLATFORM =~ /java/
50
+ end
51
+ end
52
+ end
53
+
@@ -0,0 +1,35 @@
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
+ require 'itunesController/database/sqlite3_backend'
23
+ require 'itunesController/itunescontroller_factory'
24
+ require 'itunesController/controller_creator'
25
+
26
+ module ItunesController
27
+
28
+ class SQLLiteControllerCreator < ControllerCreator
29
+ def createController()
30
+ dbBackend = ItunesController::SQLite3DatabaseBackend.new(nil)
31
+ return ItunesController::CachedController.new(ItunesController::ITunesControllerFactory::createController(),dbBackend)
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,39 @@
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
+ module ItunesController
23
+
24
+ # Used to store track information
25
+ class Track
26
+ attr_accessor :location,:databaseId,:title
27
+
28
+ def initialize(location,databaseId,title)
29
+ @location = location
30
+ @databaseId = databaseId
31
+ @title = title
32
+ end
33
+
34
+ def to_s
35
+ return "Location: '#{@location}' - Database ID: #{@databaseId} - Title: '#{@title}' "
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,25 @@
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
+ module ItunesController
23
+ # The itunes-remote-control-server version
24
+ VERSION = "0.1.0"
25
+ end
@@ -0,0 +1,145 @@
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
+ require 'itunesController/itunescontroller'
23
+ require 'itunesController/kinds'
24
+ require 'itunesController/debug'
25
+ require 'itunesController/logging'
26
+ require 'win32ole'
27
+
28
+ module ItunesController
29
+
30
+ class WindowsITunesController < ItunesController::BaseITunesController
31
+
32
+ # The constructor
33
+ def initialize
34
+ @iTunes = WIN32OLE.new('iTunes.Application')
35
+ @libraryPlaylists=@iTunes.LibraryPlaylist
36
+ end
37
+
38
+ # Used to get the iTunes version
39
+ # @return [String] The itunes version
40
+ def version
41
+ return @iTunes.version.to_s+" (Windows)"
42
+ end
43
+
44
+ # Used to tell iTunes to refresh a list of tracks data from the info stored in the files
45
+ # @param [Array] tracks A list of tracks to fresh
46
+ def refreshTracks(tracks)
47
+ tracks.reverse.each do | track |
48
+ track.UpdateInfoFromFile
49
+ end
50
+ end
51
+
52
+ # Used to remove tracks from the libaray
53
+ # @param [Array] tracks A list of tracks to remove from the itunes libaray
54
+ def removeTracksFromLibrary(tracks)
55
+ tracks.reverse.each do | track |
56
+ track.Delete
57
+ end
58
+ end
59
+
60
+ # Used to add a list of files to the itunes library
61
+ # @param [Array[String]] A list of files to add to the itunes library
62
+ # @return [Array[ItunesController::Track]] List of ids of the new tracks once they are in the database
63
+ def addFilesToLibrary(files)
64
+ tracks=[]
65
+ files.each do | file |
66
+ if (!File.exist?(file))
67
+ ItunesController::ItunesControllerLogging::error("Unable to find file #{file}")
68
+ else
69
+ itracks=@libraryPlaylists.AddFile(file)
70
+ if (itracks!=nil)
71
+ itracks=itracks.Tracks
72
+ for i in (1..itracks.Count())
73
+ itrack=itracks.Item(i)
74
+ track=ItunesController::Track.new(file,itrack.TrackDatabaseID,itrack.Name)
75
+ tracks.push(track)
76
+ end
77
+ else
78
+ ItunesController::ItunesControllerLogging::error("Unable to add file '#{file}'")
79
+ end
80
+ end
81
+ end
82
+
83
+ return tracks;
84
+ end
85
+
86
+ def getTracks(&b)
87
+ ItunesController::ItunesControllerLogging::debug("Retriving track information...")
88
+ playlist=@libraryPlaylists
89
+ fileTracks = playlist.Tracks
90
+ size = fileTracks.Count()
91
+ count = 1
92
+ for count in (1..size)
93
+ track=fileTracks.Item(count)
94
+ location=track.location
95
+ dead=false
96
+ if (location!=nil)
97
+ if (!File.exist?(location))
98
+ dead = true
99
+ end
100
+ else
101
+ dead = true
102
+ end
103
+ if (count % 1000 == 0)
104
+ ItunesController::ItunesControllerLogging::debug("Found tracks #{count} of #{size}")
105
+ end
106
+ if (track.name!=nil)
107
+ b.call(ItunesController::Track.new(location,track.TrackDatabaseID,track.name),count,size,dead)
108
+ end
109
+ count=count+1
110
+ end
111
+ ItunesController::ItunesControllerLogging::debug("Found tracks #{count-1} of #{size}")
112
+ return size
113
+ end
114
+
115
+ # Used to find the number of tracks in the library
116
+ # @return [Number] The number of tracks
117
+ def getTrackCount()
118
+ return @libraryPlaylists.Tracks.Count()
119
+ end
120
+
121
+ # Used to search the itunes library
122
+ # @param term The search term
123
+ # @return [Array] a list of iTunes track that match the search term
124
+ def searchLibrary(term)
125
+ tracks=[]
126
+ playlist=@libraryPlaylists
127
+ foundTracks = playlist.Search(term,1)
128
+ if (foundTracks!=nil)
129
+ foundTracks.each do | t |
130
+ tracks.push(t)
131
+ end
132
+ end
133
+
134
+ return tracks
135
+ end
136
+
137
+ # Used to get the database of a itunes track
138
+ # @abstract Must be overridden
139
+ # @param track the track
140
+ # @return The database id
141
+ def getTrackDatabaseId(track)
142
+ return track.TrackDatabaseID()
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,125 @@
1
+
2
+ require 'tempfile'
3
+ require 'test/unit'
4
+ require 'socket'
5
+ require 'timeout'
6
+
7
+ require 'itunesController/platform'
8
+ require 'itunesController/config'
9
+ require 'itunesController/dummy_itunescontroller'
10
+ require 'itunesController/controllserver'
11
+ require 'itunesController/cachedcontroller'
12
+ require 'itunesController/controller_creator'
13
+
14
+ require 'itunesController/database/sqlite3_backend'
15
+
16
+ class DummyControllerCreator < ItunesController::ControllerCreator
17
+
18
+ def initialize(controller)
19
+ @controller = controller
20
+ end
21
+
22
+ def createController()
23
+ return @controller
24
+ end
25
+ end
26
+
27
+ class BaseServerTest < Test::Unit::TestCase
28
+
29
+ USER="test"
30
+ PASSWORD="testpass"
31
+ MIN_PORT_NUMBER = 5000
32
+ MAX_PORT_NUMBER = 9000
33
+
34
+ attr_accessor :server,:port
35
+
36
+ def portOpen?(ip, port, seconds=1)
37
+ Timeout::timeout(seconds) do
38
+ begin
39
+ TCPSocket.new(ip, port).close
40
+ true
41
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
42
+ false
43
+ end
44
+ end
45
+ rescue Timeout::Error
46
+ false
47
+ end
48
+
49
+ def findAvaliablePort
50
+ port=BaseServerTest::MIN_PORT_NUMBER
51
+ while (port < BaseServerTest::MAX_PORT_NUMBER )
52
+ if !portOpen?("127.0.0.1",port)
53
+ return port
54
+ end
55
+ port+=1
56
+ end
57
+ return -1
58
+ end
59
+
60
+ def setupServer(tracks=nil)
61
+ ItunesController::DummyITunesController::resetCommandLog()
62
+ ItunesController::DummyITunesController::resetTracks()
63
+ if (tracks!=nil)
64
+ tracks.each do | track |
65
+ ItunesController::DummyITunesController::forceAddTrack(track)
66
+ end
67
+ end
68
+
69
+ ItunesController::DummyITunesController::getCommandLog().take_while {
70
+ | el |
71
+ }
72
+ @dbFile = Tempfile.new('dummyDatabase.db')
73
+ itunes = ItunesController::DummyITunesController.new
74
+ dbBackend = ItunesController::SQLite3DatabaseBackend.new(@dbFile.path)
75
+ controller = ItunesController::CachedController.new(itunes,dbBackend)
76
+ config=ItunesController::ServerConfig.new
77
+ config.port = findAvaliablePort
78
+ @port = config.port
79
+ config.username = BaseServerTest::USER
80
+ config.password = BaseServerTest::PASSWORD
81
+ @server=ItunesController::ITunesControlServer.new(config,config.port,DummyControllerCreator.new(controller))
82
+ end
83
+
84
+ def teardownServer
85
+ @server.stop
86
+ while !@server.stopped?
87
+ end
88
+ @server.join
89
+ @dbFile.unlink
90
+ end
91
+
92
+ def test_dummy
93
+ end
94
+
95
+ def assertCommandLog(expected)
96
+ sleep(2)
97
+ @server.waitForEmptyJobQueue()
98
+ actual=ItunesController::DummyITunesController::getCommandLog()
99
+ error=false
100
+ if (expected.size()!=actual.size())
101
+ puts("Worng number of command log entries")
102
+ error = true
103
+ end
104
+
105
+
106
+ for i in (0..expected.size())
107
+ if (expected[i]!=actual[i])
108
+ error=true
109
+ end
110
+ end
111
+ if (error)
112
+ puts("Command log did not match expected.")
113
+ puts("Expected:")
114
+ expected.each do | line |
115
+ puts(" "+line)
116
+ end
117
+ puts("Actual:")
118
+ actual.each do | line |
119
+ puts(" "+line)
120
+ end
121
+ raise("Command log did not match expected.")
122
+ end
123
+ end
124
+
125
+ end
@@ -0,0 +1,44 @@
1
+
2
+ require 'net/telnet'
3
+
4
+ require 'itunesController/controllserver'
5
+
6
+ class DummyClient
7
+
8
+ DEFAULT_TIMEOUT=40
9
+
10
+ def connect(hostname,port)
11
+ @client=Net::Telnet::new('Host' => hostname,
12
+ 'Port' => port,
13
+ 'Telnetmode' => false)
14
+ @client.waitfor('String'=>"001 hello")
15
+ sendCommand("HELO",220)
16
+ end
17
+
18
+
19
+ def disconnect
20
+ @client.close
21
+ end
22
+
23
+ def login(username,password)
24
+ sendCommand(ItunesController::CommandName::LOGIN+":"+username,222);
25
+ sendCommand(ItunesController::CommandName::PASSWORD+":"+password,223);
26
+ end
27
+
28
+ def sendCommand(cmd, expectedCode,timeout=DummyClient::DEFAULT_TIMEOUT)
29
+ @client.cmd(cmd) do | response |
30
+ if (response!=nil)
31
+ response.each_line do | line |
32
+ if ( line =~ /(\d+).*/)
33
+ code=$1
34
+ if (code.to_i==expectedCode)
35
+ return;
36
+ end
37
+ end
38
+ end
39
+ end
40
+ raise "Did not recive expected response from server"
41
+ end
42
+ end
43
+
44
+ end