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,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