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.
- data/.buildpath +5 -0
- data/.gitignore +3 -0
- data/.project +17 -0
- data/.rvmrc +81 -0
- data/LICENSE +674 -0
- data/README +27 -0
- data/Rakefile +27 -0
- data/TODO +8 -0
- data/bin/addFiles.rb +35 -0
- data/bin/dummyiTunesController.rb +109 -0
- data/bin/itunesController.rb +78 -0
- data/bin/listDeadTracks.rb +45 -0
- data/bin/listNewTracks.rb +88 -0
- data/bin/recreateTrackCache.rb +31 -0
- data/bin/refreshFiles.rb +42 -0
- data/bin/removeDeadTracks.rb +31 -0
- data/bin/removeFiles.rb +42 -0
- data/bin/trackInfo.rb +50 -0
- data/itunes-controller.gemspec +24 -0
- data/jar-stuff.sh +24 -0
- data/lib/itunesController/application.rb +127 -0
- data/lib/itunesController/cachedcontroller.rb +188 -0
- data/lib/itunesController/config.rb +95 -0
- data/lib/itunesController/controller_creator.rb +29 -0
- data/lib/itunesController/controllserver.rb +583 -0
- data/lib/itunesController/database/backend.rb +41 -0
- data/lib/itunesController/database/database.rb +166 -0
- data/lib/itunesController/database/sqlite3_backend.rb +67 -0
- data/lib/itunesController/debug.rb +124 -0
- data/lib/itunesController/dummy_itunes_track.rb +40 -0
- data/lib/itunesController/dummy_itunescontroller.rb +142 -0
- data/lib/itunesController/itunescontroller.rb +90 -0
- data/lib/itunesController/itunescontroller_factory.rb +51 -0
- data/lib/itunesController/kinds.rb +138 -0
- data/lib/itunesController/logging.rb +119 -0
- data/lib/itunesController/macosx_itunescontroller.rb +204 -0
- data/lib/itunesController/platform.rb +53 -0
- data/lib/itunesController/sqlite_creator.rb +35 -0
- data/lib/itunesController/track.rb +39 -0
- data/lib/itunesController/version.rb +25 -0
- data/lib/itunesController/windows_itunescontroller.rb +145 -0
- data/test/base_server_test_case.rb +125 -0
- data/test/dummy_client.rb +44 -0
- data/test/test_server.rb +312 -0
- metadata +185 -0
@@ -0,0 +1,90 @@
|
|
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
|
+
# This is the base class of all itunes controller.
|
25
|
+
# @abstract This class should be overridden to implement the class that talks to iTunes.
|
26
|
+
class BaseITunesController
|
27
|
+
|
28
|
+
# The constructor
|
29
|
+
def initialize()
|
30
|
+
end
|
31
|
+
|
32
|
+
# Used to get the iTunes version
|
33
|
+
# @abstract Must be overridden
|
34
|
+
# @return [String] The itunes version
|
35
|
+
def version
|
36
|
+
raise "ERROR: Your trying to instantiate an abstract class"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Used to remove tracks from the libaray
|
40
|
+
# @abstract Must be overridden
|
41
|
+
# @param [Array] tracks A list of tracks to remove from the itunes libaray
|
42
|
+
def removeTracksFromLibrary(tracks)
|
43
|
+
raise "ERROR: Your trying to instantiate an abstract class"
|
44
|
+
end
|
45
|
+
|
46
|
+
# Used to add a list of files to the itunes library
|
47
|
+
# @abstract Must be overridden
|
48
|
+
# @param [Array[String]] A list of files to add to the itunes library
|
49
|
+
# @return [Array[ItunesController::Track]] List of ids of the new tracks once they are in the database
|
50
|
+
def addFilesToLibrary(files)
|
51
|
+
raise "ERROR: Your trying to instantiate an abstract class"
|
52
|
+
end
|
53
|
+
|
54
|
+
# Used to tell iTunes to refresh a list of tracks data from the info stored in the files
|
55
|
+
# @abstract Must be overridden
|
56
|
+
# @param [Array] tracks A list of tracks to fresh
|
57
|
+
def refreshTracks(tracks)
|
58
|
+
raise "ERROR: Your trying to instantiate an abstract class"
|
59
|
+
end
|
60
|
+
|
61
|
+
# @abstract Must be overridden
|
62
|
+
def getTracks(&b)
|
63
|
+
raise "ERROR: Your trying to instantiate an abstract class"
|
64
|
+
end
|
65
|
+
|
66
|
+
# Used to search the itunes library
|
67
|
+
# @param term The search term
|
68
|
+
# @return [Array] a list of iTunes track that match the search term
|
69
|
+
# @abstract Must be overridden
|
70
|
+
def searchLibrary(term)
|
71
|
+
raise "ERROR: Your trying to instantiate an abstract class"
|
72
|
+
end
|
73
|
+
|
74
|
+
# Used to find the number of tracks in the library
|
75
|
+
# @abstract Must be overridden
|
76
|
+
# @return [Number] The number of tracks
|
77
|
+
def getTrackCount()
|
78
|
+
raise "ERROR: Your trying to instantiate an abstract class"
|
79
|
+
end
|
80
|
+
|
81
|
+
# Used to get the database of a itunes track
|
82
|
+
# @abstract Must be overridden
|
83
|
+
# @param track the track
|
84
|
+
# @return The database id
|
85
|
+
def getTrackDatabaseId(track)
|
86
|
+
raise "ERROR: Your trying to instantiate an abstract class"
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,51 @@
|
|
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/platform'
|
23
|
+
if ItunesController::Platform::isWindows()
|
24
|
+
require 'itunesController/windows_itunescontroller.rb'
|
25
|
+
elsif ItunesController::Platform::isMacOSX()
|
26
|
+
require 'itunesController/macosx_itunescontroller.rb'
|
27
|
+
else
|
28
|
+
raise("Unsupported operating system #{RUBY_PLATFORM}.")
|
29
|
+
end
|
30
|
+
|
31
|
+
require 'itunesController/database/database'
|
32
|
+
|
33
|
+
module ItunesController
|
34
|
+
|
35
|
+
# This is a factory class used to create a iTunes controller for the current platform
|
36
|
+
class ITunesControllerFactory
|
37
|
+
|
38
|
+
# Used to create the iTunes controller for different platforms
|
39
|
+
# @return [ItunesController::BaseITunesController] The itunes controller
|
40
|
+
# @raise If the platform is unsupported
|
41
|
+
def self.createController()
|
42
|
+
if ItunesController::Platform::isWindows()
|
43
|
+
return ItunesController::WindowsITunesController.new()
|
44
|
+
elsif ItunesController::Platform::isMacOSX()
|
45
|
+
return ItunesController::MacOSXITunesController.new()
|
46
|
+
else
|
47
|
+
raise("Unsupported operating system #{RUBY_PLATFORM}.")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,138 @@
|
|
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
|
+
# A enum of special kinds
|
25
|
+
# @attr [Number] kind The Source kind ID
|
26
|
+
# @attr [String] String the source display name
|
27
|
+
class SpecialKind
|
28
|
+
attr_accessor :kind, :displayName
|
29
|
+
def initialize(kind,displayName)
|
30
|
+
@kind = kind
|
31
|
+
@displayName = displayName
|
32
|
+
end
|
33
|
+
|
34
|
+
# The Audio Book kind
|
35
|
+
Audiobooks=SpecialKind.new(1800630337,"Audiobooks")
|
36
|
+
# The folder kind
|
37
|
+
Folder=SpecialKind.new(1800630342,"Folder")
|
38
|
+
# The movie kind
|
39
|
+
Movies=SpecialKind.new(1800630345,"Movies")
|
40
|
+
# The music kind
|
41
|
+
Music=SpecialKind.new(1800630362,"Music")
|
42
|
+
# The none kind
|
43
|
+
None=SpecialKind.new(1800302446,"None")
|
44
|
+
# The party shuffle kind
|
45
|
+
PartyShuffle=SpecialKind.new(1800630355,"Party Shuffle")
|
46
|
+
# The pod cast kind
|
47
|
+
Podcasts=SpecialKind.new(1800630352,"Podcasts")
|
48
|
+
# The purchased music kind
|
49
|
+
PurchasedMusic=SpecialKind.new(1800630349,"Purchased Music")
|
50
|
+
# The TV show kind
|
51
|
+
TVShows=SpecialKind.new(1800630356,"TV Shows")
|
52
|
+
# The video kind
|
53
|
+
Videos=SpecialKind.new(1800630358,"Videos")
|
54
|
+
# The genius kind
|
55
|
+
Genius=SpecialKind.new(1800630343,"Genius")
|
56
|
+
# The iTunesU kind
|
57
|
+
ITunesU=SpecialKind.new(1800630357,"iTunes U")
|
58
|
+
# The library kind
|
59
|
+
Library=SpecialKind.new(1800630348,"Library")
|
60
|
+
# The unknown kind
|
61
|
+
Unknown=SpecialKind.new(-1,"Unknown")
|
62
|
+
|
63
|
+
@@values=[Audiobooks,Folder,Movies,Music,
|
64
|
+
None,PartyShuffle,Podcasts,PurchasedMusic,
|
65
|
+
TVShows, Videos,Genius,ITunesU,Library,Unknown]
|
66
|
+
|
67
|
+
# A class scoped method used to get the kind associated with the kind ID
|
68
|
+
# @param kind The kind ID
|
69
|
+
# @return [ItunesController::SourceKind] The source kind object
|
70
|
+
def self.fromKind(kind)
|
71
|
+
@@values.each { | v1 |
|
72
|
+
if (v1.kind==kind)
|
73
|
+
return v1
|
74
|
+
end
|
75
|
+
}
|
76
|
+
return SpecialKind.new(v1,"Unknown")
|
77
|
+
end
|
78
|
+
|
79
|
+
# Used pretty print the kind to a string
|
80
|
+
# @return A string containing the kind display name and ID
|
81
|
+
def to_s
|
82
|
+
return "#{displayName} (#{kind})"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Enum of source kinds
|
87
|
+
# @attr [Number] kind The Source kind ID
|
88
|
+
# @attr [String] String the source display name
|
89
|
+
class SourceKind
|
90
|
+
|
91
|
+
attr_accessor :kind, :displayName
|
92
|
+
|
93
|
+
# The constructor
|
94
|
+
# @param [Number] kind The kind ID
|
95
|
+
# @param [String] displayName The kind display name
|
96
|
+
def initialize(kind,displayName)
|
97
|
+
@kind = kind
|
98
|
+
@displayName = displayName
|
99
|
+
end
|
100
|
+
|
101
|
+
# The Audio CD Source Kind
|
102
|
+
AudioCD=SourceKind.new(1799439172,"Audio CD")
|
103
|
+
# The Device Source Kind
|
104
|
+
Device=SourceKind.new(1799644534,"Device")
|
105
|
+
# The iPod Source Kind
|
106
|
+
IPod=SourceKind.new(1800433508,"iPod")
|
107
|
+
# The Library Source Kind
|
108
|
+
Library=SourceKind.new(1800169826,"Library")
|
109
|
+
# The MP3 CD Source Kind
|
110
|
+
MP3CD=SourceKind.new(1800225604,"MP3 CD")
|
111
|
+
# The Radio Tuner Source Kind
|
112
|
+
RadioTuner=SourceKind.new(1800697198,"Radio Tuner")
|
113
|
+
# The Shared Libarary Source Kind
|
114
|
+
SharedLibrary=SourceKind.new(1800628324,"Shared Library")
|
115
|
+
# The Unknown Source Kind
|
116
|
+
Unknown=SourceKind.new(1800760938,"Unknown")
|
117
|
+
|
118
|
+
@@values=[AudioCD,Device,IPod,Library,MP3CD,RadioTuner,SharedLibrary,Unknown]
|
119
|
+
|
120
|
+
# A class scoped method used to get the kind associated with the kind ID
|
121
|
+
# @param kind The kind ID
|
122
|
+
# @return [ItunesController::SourceKind] The source kind object
|
123
|
+
def self.fromKind(kind)
|
124
|
+
@@values.each { | v1 |
|
125
|
+
if (v1.kind==kind)
|
126
|
+
return v1
|
127
|
+
end
|
128
|
+
}
|
129
|
+
return SourceKind.new(v1,"Unknown")
|
130
|
+
end
|
131
|
+
|
132
|
+
# Used pretty print the kind to a string
|
133
|
+
# @return A string containing the kind display name and ID
|
134
|
+
def to_s
|
135
|
+
return "#{displayName} (#{kind})"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,119 @@
|
|
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 ItunesControllerLogging
|
25
|
+
DEBUG=1
|
26
|
+
INFO=2
|
27
|
+
WARN=3
|
28
|
+
ERROR=4
|
29
|
+
|
30
|
+
# The log file, if defined then logging opertions will be sent to this file
|
31
|
+
@@logFile = nil
|
32
|
+
@@logLevel = INFO
|
33
|
+
|
34
|
+
# Used to set the location of the log file
|
35
|
+
# @param [String] file The log file location
|
36
|
+
def self.setLogFile(file)
|
37
|
+
@@logFile = file
|
38
|
+
end
|
39
|
+
|
40
|
+
# Use to set the loggin level
|
41
|
+
# @param [Number] level The logging level
|
42
|
+
def self.setLogLevel(level)
|
43
|
+
@@logLevel = level
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.setLogLevelFromString(level)
|
47
|
+
if (level=="DEBUG")
|
48
|
+
@@logLevel = DEBUG
|
49
|
+
elsif (level=="INFO")
|
50
|
+
@@logLevel = INFO
|
51
|
+
elsif (level=="WARN")
|
52
|
+
@@logLevel = WARN
|
53
|
+
elsif (level=="ERROR")
|
54
|
+
@@logLevel = ERROR
|
55
|
+
else
|
56
|
+
error("Unkown log configuration '#{level}'")
|
57
|
+
exit(1)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Used to print logging information at info level
|
62
|
+
# @param [String] msg The message to print
|
63
|
+
def self.info(msg)
|
64
|
+
if @@logLevel <= INFO
|
65
|
+
printMsg(msg)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Used to print logging information at warn level
|
70
|
+
# @param [String] msg The message to print
|
71
|
+
def self.warn(msg)
|
72
|
+
if @@logLevel <= WARN
|
73
|
+
printMsg(msg)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Used to print logging information at debug level
|
78
|
+
# @param [String] msg The message to print
|
79
|
+
def self.debug(msg)
|
80
|
+
if @@logLevel <= DEBUG
|
81
|
+
msg="DEBUG:"+msg
|
82
|
+
printMsg(msg)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Used to print logging information at debug level
|
87
|
+
# @param [String] msg The message to print
|
88
|
+
# @param exception If not nil then this exception detials will be printed
|
89
|
+
def self.error(msg,exception=nil)
|
90
|
+
if @@logLevel <= ERROR
|
91
|
+
msg="ERROR:"+msg
|
92
|
+
printMsg(msg,true)
|
93
|
+
if (exception!=nil)
|
94
|
+
printMsg(" - #{exception.message}",true)
|
95
|
+
exception.backtrace.each do | line |
|
96
|
+
printMsg(" * #{line}",true)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def self.printMsg(msg,error=false)
|
105
|
+
if (@@logFile!=nil)
|
106
|
+
out_file = File.open(@@logFile,"a") do | f |
|
107
|
+
f.puts(msg)
|
108
|
+
end
|
109
|
+
else
|
110
|
+
if (error)
|
111
|
+
$stderr.puts(msg)
|
112
|
+
else
|
113
|
+
$stdout.puts(msg)
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,204 @@
|
|
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
|
+
# References:
|
23
|
+
# - http://code.google.com/p/itunes-rem-dupes/source/browse/trunk/itunes_update_library.rb?r=22
|
24
|
+
# - http://guides.macrumors.com/Deleting_Songs_From_iTunes
|
25
|
+
# - http://macscripter.net/viewtopic.php?id=22726
|
26
|
+
|
27
|
+
require 'itunesController/itunescontroller'
|
28
|
+
require 'itunesController/kinds'
|
29
|
+
require 'itunesController/debug'
|
30
|
+
require 'itunesController/logging'
|
31
|
+
require 'itunesController/track'
|
32
|
+
require 'rubygems'
|
33
|
+
require 'escape'
|
34
|
+
require 'open3'
|
35
|
+
require 'osx/cocoa'
|
36
|
+
|
37
|
+
include OSX
|
38
|
+
OSX.require_framework 'ScriptingBridge'
|
39
|
+
|
40
|
+
module ItunesController
|
41
|
+
|
42
|
+
# This is a iTunes controller class used to talk to itunes. This runs on macosx and makes
|
43
|
+
# use of the OSC ruby bindings. It also uses application "osascript" to execute apple scripts.
|
44
|
+
class MacOSXITunesController < ItunesController::BaseITunesController
|
45
|
+
|
46
|
+
# The constructor
|
47
|
+
def initialize()
|
48
|
+
@iTunes = SBApplication.applicationWithBundleIdentifier:'com.apple.iTunes'
|
49
|
+
library=getSourceLibrary()
|
50
|
+
@libraryPlaylists=library.libraryPlaylists
|
51
|
+
end
|
52
|
+
|
53
|
+
# Used to get the iTunes version
|
54
|
+
# @return [String] The itunes version
|
55
|
+
def version
|
56
|
+
return @iTunes.version.to_s+" (Mac OSX)"
|
57
|
+
end
|
58
|
+
|
59
|
+
# Used to tell iTunes to refresh a list of tracks data from the info stored in the files
|
60
|
+
# @param [Array] tracks A list of tracks to fresh
|
61
|
+
def refreshTracks(tracks)
|
62
|
+
ItunesController::ItunesControllerLogging::debug("refreshing tracks...")
|
63
|
+
tracks.reverse.each do | track |
|
64
|
+
track.refresh
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Used to remove tracks from the libaray
|
69
|
+
# @param [Array] tracks A list of tracks to remove from the itunes libaray
|
70
|
+
def removeTracksFromLibrary(tracks)
|
71
|
+
ItunesController::ItunesControllerLogging::debug("removing tracks...")
|
72
|
+
tracks.reverse.each do | track |
|
73
|
+
track.delete
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Used to add a list of files to the itunes library
|
78
|
+
# @param [Array[String]] A list of files to add to the itunes library
|
79
|
+
# @return [Array[ItunesController::Track]] List of ids of the new tracks once they are in the database
|
80
|
+
def addFilesToLibrary(files)
|
81
|
+
tracks=[]
|
82
|
+
files.each do | file |
|
83
|
+
script="tell application \"iTunes\"\n"
|
84
|
+
script=script+" set theTrack to (add POSIX file \"#{file}\")\n"
|
85
|
+
script=script+" return (database ID of theTrack & name of theTrack)\n"
|
86
|
+
script=script+"end tell\n"
|
87
|
+
output=executeScript(script)
|
88
|
+
if (output =~ /(\d+), (.*)/)
|
89
|
+
track=ItunesController::Track.new(file,$1.to_i,$2)
|
90
|
+
tracks.push(track)
|
91
|
+
else
|
92
|
+
ItunesController::ItunesControllerLogging::error("Unable to add file '#{file}': " + output)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
return tracks;
|
97
|
+
end
|
98
|
+
|
99
|
+
# Used to get the database of a itunes track
|
100
|
+
# @param track the track
|
101
|
+
# @return The database id
|
102
|
+
def getTrackDatabaseId(track)
|
103
|
+
return track.databaseID
|
104
|
+
end
|
105
|
+
|
106
|
+
def getTracks(&b)
|
107
|
+
ItunesController::ItunesControllerLogging::debug("Retriving track information...")
|
108
|
+
playlist=@libraryPlaylists[0]
|
109
|
+
fileTracks = playlist.fileTracks
|
110
|
+
size = fileTracks.length()
|
111
|
+
count = 1
|
112
|
+
fileTracks.each do | track |
|
113
|
+
location=track.location
|
114
|
+
path=nil
|
115
|
+
dead=false
|
116
|
+
if (location!=nil && location.isFileURL)
|
117
|
+
path=location.path
|
118
|
+
if (!File.exist?(location.path))
|
119
|
+
dead = true
|
120
|
+
end
|
121
|
+
else
|
122
|
+
dead = true
|
123
|
+
end
|
124
|
+
|
125
|
+
if (count % 1000 == 0)
|
126
|
+
ItunesController::ItunesControllerLogging::debug("Found tracks #{count} of #{size}")
|
127
|
+
end
|
128
|
+
if (track.name!=nil)
|
129
|
+
b.call(ItunesController::Track.new(path,track.databaseID,track.name),count,size,dead)
|
130
|
+
end
|
131
|
+
count=count+1
|
132
|
+
end
|
133
|
+
ItunesController::ItunesControllerLogging::debug("Found tracks #{count-1} of #{size}")
|
134
|
+
return size
|
135
|
+
end
|
136
|
+
|
137
|
+
# Used to find the number of tracks in the library
|
138
|
+
# @return [Number] The number of tracks
|
139
|
+
def getTrackCount()
|
140
|
+
playlist=@libraryPlaylists[0]
|
141
|
+
return playlist.fileTracks.length()
|
142
|
+
end
|
143
|
+
|
144
|
+
# Used to search the itunes library
|
145
|
+
# @param term The search term
|
146
|
+
# @return [Array] a list of iTunes track that match the search term
|
147
|
+
def searchLibrary(term)
|
148
|
+
tracks=[]
|
149
|
+
@libraryPlaylists.each do | playlist |
|
150
|
+
#foundTracks = playlist.searchFor(term,'kSrS')
|
151
|
+
foundTracks = playlist.searchFor_only_(term,1799449708)
|
152
|
+
if (foundTracks!=nil)
|
153
|
+
foundTracks.each do | t |
|
154
|
+
tracks.push(t)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
return tracks
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
# Used to get the libaray iTunes source
|
164
|
+
# @return The iTunes source for the library
|
165
|
+
def getSourceLibrary()
|
166
|
+
@iTunes.sources.each do |source|
|
167
|
+
if (source.kind == SourceKind::Library.kind)
|
168
|
+
return source
|
169
|
+
end
|
170
|
+
end
|
171
|
+
return nil
|
172
|
+
end
|
173
|
+
|
174
|
+
# Used to find playlists of a given media kind
|
175
|
+
# @param types The types
|
176
|
+
# @return [Array] A list of playlists
|
177
|
+
def findPlaylists(types)
|
178
|
+
playlists=[]
|
179
|
+
library=getSourceLibrary()
|
180
|
+
if (library==nil)
|
181
|
+
raise("Unable to find iTunes library")
|
182
|
+
end
|
183
|
+
|
184
|
+
library.userPlaylists.each do |pl|
|
185
|
+
kind=SpecialKind::fromKind(pl.specialKind)
|
186
|
+
types.each do |type|
|
187
|
+
if (kind.kind == type.kind)
|
188
|
+
playlists.push(pl)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
return playlists
|
194
|
+
end
|
195
|
+
|
196
|
+
# Used to execute a apple script using the system "osascript" command.
|
197
|
+
# @private
|
198
|
+
# @param script the Script contents
|
199
|
+
def executeScript(script)
|
200
|
+
stdin, stdout, stderr = Open3.popen3(Escape.shell_command(["osascript","-e",script]))
|
201
|
+
return stdout.readlines.join('\n').strip
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|