Work+Movementのテンプレートを作成しました。
Works.htmlを
「~/Library/Containers/com.me.oyasuhisa.sirabesirabe/Data/Library/Application Support/SirabeSirabe/Templates」
に追加して再起動してください。
「MenuBar->View->Work」を選択してください。
OS X 10.7- のiTunesで再生中の曲の情報(曲名、歌詞など)を表示するアプリケーションです。App Storeで購入することができます。 質問等は、右欄から詳細を選択しコメントから行ってください。
2016-10-26
2016-10-03
Swift - ScriptingBridge - iTunes
RegularExpression/main.swift
Objective-C/iTunesSB.sh
Objective-C/iTunes.h
Objective-C/iTunes.m
iTunes-Bridging-Header.h
iTunes/main.swift
Library/iTunes.swift
iTunesSwift/main.swift
Selection/main.swift
SelectSameGrouping/main.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | let rxMovement = NSRegularExpression(regex: "^\\d\\d .+? - (\\d+)?\\.? ?(.+)")
guard let tracks = Tracks.whose("albumArtist beginswith \"Trifonov\"")
, (0 < tracks.count)
else {
print("Error: No Track")
exit(1)
}
//let update = query(text:"count = \(tracks.count), first track = '\(tracks[0]!.name!)'\nUpdate")
let update = false
tracks.enumerate { i, track in
let name = track.name!
guard let strings = rxMovement.strings(firstMatchIn: name) else {
print("Patttern: '\(rxMovement.pattern)'")
print(" Text: '\(name)'")
exit(1)
}
let number = Int(movementNumber:strings[1])
let movement = strings[2]!
guard update else {
assert(name.hasSuffix(movement))
print(number, movement)
return true
}
if 0 < number {
track.movementNumber = number
}
track.movement = movement
print("\t", track.movementNumber, track.movement)
return true
}
|
iTunes.xcodeproj
Objective-C/iTunesSB.sh
1 2 3 4 5 6 7 8 | #!/bin/sh
app=iTunes.app
path=$(mdfind "kMDItemFSName == '"$app"'")
name=$(mdls -name kMDItemDisplayName -raw $path)
id=$(mdls -name kMDItemCFBundleIdentifier -raw $path)
sdef "$path" | sdp -fh --basename "${name}" -o "${name}SB".h
|
Objective-C/iTunes.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #ifndef iTunes_h
#define iTunes_h
#import "iTunesSB.h"
iTunesApplication *_Nullable GetiTunesApplication();
iTunesTrack *_Nullable getTrack(iTunesTrack *_Null_unspecified track);
@interface Tracks: NSObject
+ (instancetype _Null_unspecified) selection;
+ (instancetype _Null_unspecified) whose:(NSString * _Null_unspecified) clause;
- (instancetype _Null_unspecified) initWithPredicate:(NSPredicate * _Null_unspecified) predicate;
- (iTunesTrack *_Nullable) objectAtIndexedSubscript:(NSUInteger) i;
- (void)enumerate:(BOOL (^_Null_unspecified)( NSInteger index, iTunesTrack *_Null_unspecified track))block;
@property (readonly) NSUInteger count;
@end
#endif /* iTunes_h */
|
Objective-C/iTunes.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | #import "iTunes.h"
//MARK: iTunes
static iTunesApplication *iTunes = NULL;
iTunesApplication *GetiTunesApplication() {
if (iTunes == NULL) {
iTunes = (iTunesApplication *)[SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];
}
return iTunes;
}
//MARK: - Track
iTunesTrack * getTrack(iTunesTrack *track) {
return track.get;
}
static SBObject *selection = NULL;
SBElementArray<iTunesTrack *> *GetSelection() {
if (selection == NULL) {
iTunesApplication *app = GetiTunesApplication();
selection = app.selection;
}
SBElementArray<iTunesTrack *> *tracks = selection.get;
return tracks;
}
iTunesTrack * getTrackAt(SBElementArray<iTunesTrack*>* tracks, NSUInteger i) {
return [tracks objectAtIndex:i];
}
@implementation Tracks
{
SBElementArray<iTunesTrack *> *tracks;
}
+ (instancetype)selection {
return [[Tracks alloc] initBySelection];
}
+ (instancetype)whose:(NSString *)clause {
@try {
NSPredicate *predicate = [NSPredicate predicateWithFormat:clause];
//NSLog(@"'%@'", predicate);
return [[Tracks alloc] initWithPredicate:predicate];
}
@catch (NSException *exception) {
NSLog(@"Error: '%@'\n\t%@", clause, exception.reason);
exit(-1);
}
@finally {
}
}
- (NSUInteger) count {
return tracks.count;
}
- (instancetype)initBySelection {
tracks = GetSelection();
return self;
}
- (instancetype)initWithPredicate:(NSPredicate *)predicate {
iTunesApplication * app = GetiTunesApplication();
tracks = (SBElementArray<iTunesTrack *> *)[app.tracks filteredArrayUsingPredicate:predicate];
return self;
}
- (iTunesTrack *) objectAtIndexedSubscript:(NSUInteger) i {
if (self.count <= i) return nil;
return getTrackAt(tracks, i).get;
}
- (void)enumerate:(BOOL (^)(NSInteger index, iTunesTrack * _Null_unspecified track))block {
NSUInteger count = tracks.count;
for (NSInteger i = 0 ; i < count; i++) { // unsigned -> signed
if (!block(i, tracks[i])) break;
}
}
@end
|
iTunes-Bridging-Header.h
1 | #import "iTunes.h"
|
iTunes/main.swift
1 2 3 4 | let iTunes = GetiTunesApplication()!
print(iTunes.name!)
iTunes.playOnce(true)
print(iTunes.currentTrack.name!)
|
Library/iTunes.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | //MARK: iTunes
public var iTunes:iTunesApplication = {
guard let app = GetiTunesApplication() else {
fatalError("Can't connect.")
}
return app
}()
public enum playerState {
case Stopped
case Playing
case Paused
init() {
switch iTunes.playerState {
case iTunesEPlSPlaying:
self = .Playing
case iTunesEPlSPaused:
self = .Paused
case iTunesEPlSStopped:
self = .Stopped
default:
fatalError("iTunes.playerState")
}}
}
//MARK: iTunesTrack
public func currentTrack() ->iTunesTrack? {
guard let track = iTunes.currentTrack, 0 < track.id() else {
return nil
}
return get(track:track)
}
private func get(track:iTunesTrack?) -> iTunesTrack? {
return getTrack(track)
}
//MARK: Functions
public func query(text: String = "Update") ->Bool {
while true {
print("\(text)? y/N/^D : ", terminator:"")
guard let ans = readLine(strippingNewline: true) else {
print("Canceled.")
exit(-1)
}
switch ans.lowercased() {
case "y", "yes":
return true
case "n", "no":
return false
case "":
return false
default:
break
}}
}
public func rewindAndStepForward(
while ok:@escaping (_ track:iTunesTrack)->Bool,
do execute:(_ track:iTunesTrack)->Bool // true: next, false: break
){
func _ok(_ _track:iTunesTrack?)->Bool {
guard let track = _track else {
return false
}
return (0 < track.id()
&& ok(track))
}
while _ok(currentTrack()) {
iTunes.previousTrack()
}
iTunes.nextTrack()
while true {
guard let track = currentTrack()
, _ok(track)
, execute(track)
else {
break
}
iTunes.nextTrack()
}
}
//MARK: - NSRegularExpression
private extension String {
var nsRange:NSRange {
return NSRange(location:0, length: (self as NSString).length)
}
}
public extension NSRegularExpression {
convenience init(regex:String, options:NSRegularExpression.Options = []) {
do {
try self.init(pattern: regex, options: options)
}
catch let error as NSError {
print(error.localizedDescription)
exit(-1)
}}
func string(byReplacingMatchesIn string: String,
options: NSRegularExpression.MatchingOptions = [],
withTemplate templ: String) -> String {
return self.stringByReplacingMatches(in: string,
options: options,
range: string.nsRange,
withTemplate: templ)
}
func strings(firstMatchIn string: String) ->[String?]? {
let nsstring = string as NSString
guard let match = self.firstMatch(in: string, range: string.nsRange)
else {
return nil
}
var strings:[String?] = []
for i in 0 ..< match.numberOfRanges {
let range = match.rangeAt(i)
strings.append(
range.location == NSNotFound
? nil
: nsstring.substring(with: range))
}
return strings
}
}
//MARK: - Int
private let RomanNumbers:[String] = {
return "I II III IV V VI VII VIII IX X XI XII XIII XIV XV XVI XVII XVIII XIX XX".components(separatedBy:" ")
}()
private var R2N:[String:Int] = {
var table:[String:Int] = [:]
for (i, r) in RomanNumbers.enumerated() {
table[r] = i + 1
}
return table
}()
public extension Int {
init?(roman:String) {
guard let i = R2N[roman] else {
return nil
}
self.init(i)
}
init(movementNumber string:String?) {
self.init(
string == nil
? 0
: Int(string!) ?? Int(roman:string!) ?? 0)
}
var roman:String? {
guard 0 < self && self <= RomanNumbers.count else {
return nil
}
return RomanNumbers[self - 1]
}
}
|
iTunesSwift/main.swift
1 2 3 | print(iTunes.name!)
iTunes.playOnce(true)
print(currentTrack()!.name!)
|
Selection/main.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | if let savedTrack = currentTrack() {
print(savedTrack.name)
}
else {
print("No current track.")
}
print("----")
if let tracks = Tracks.selection() {
print("count = \(tracks.count)")
for i in 0 ..< tracks.count {
let track = tracks[i]!
print(track.name)
}}
print("----")
guard let selection = Tracks.whose("composer contains \"Bach\""),
0 < selection.count else {
exit(1)
}
print("count = \(selection.count)")
selection.enumerate { i, track in
let trackNumber = i + 1
print("\(trackNumber)\t: \(track.name!)")
return trackNumber < 5
}
|
SelectSameGrouping/main.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | // Play another track, then target track
guard let track = currentTrack() else {
print("No Current Track.")
exit(1)
}
let state = playerState(); iTunes.pause()
let position = iTunes.playerPosition
let album = track.album!
let grouping = track.grouping!
let update = query(text:"\(album) | \(grouping)\nUpdate")
rewindAndStepForward(
while: { track in
( album == track.album!
&& grouping == track.grouping!
)},
do: { track in
print(track.grouping!, "|", track.name!)
guard update else {
return true
}
print("<<< Updating >>>")
return true
})
track.playOnce(true)
iTunes.playerPosition = position
if state == .Paused {
iTunes.pause()
}
|
登録:
投稿 (Atom)