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()
}
|
- Guide -
返信削除Xcode 8, Swift 3
New Project
1 File > New > Project...
2 macOS > macOS > Command Line Tool
3 Product Name: iTunes
Language: Swift
Headers Group
1 File > New > Group
2 rename: Headers
iTunesSB.h
1 File > New > File
2 macOS > Shell Script
3 NewFolder: Objective-C
Save As: iTunesSB.sh
Uncheck Target Membership
4 Edit Objectiv-C/iTunesSB.sh
5 File > New > Target
6 Cross-platform > External Buld System
7 Project Name: iTunesSB.h
8 Select iTunes.project > TARGETS:iTunesSB.h > Info
9 Build Tool: /bin/sh
Arguments: iTunesSB.sh
Directory: Objective-C
off: Pass build settings in environment
10 Select iTunesSB.h from scheme pop up menu or Produce > Scheme
11 Push ▶︎
12 Select Headers group
13 File > Add Files to
14 Select Objective-C/iTunesSB.h
iTunes.h, iTunes.m
1 Create Library Group
2 New Objective-C/iTunes.m(group:Library)
3 Select Creating Birdiging Header
4 New Objective-C/iTunes.h(group:Header)
5 Edit iTunes.h and iTunes.m
iTunes-Bridging-Header.h
1 Select iTunes.xcodeproj > PROJECT:iTunes
2 Build Setting > Objective-C Bridge Header > iTunes = iTunes-Bridging-Header.h
3 Edit iTunes-Bridging-Header.h
iTunes/main.swift
1 Select scheme: iTunes
2 Edit iTunes/main.swift
3 Build and Run
iTunesSwift/main.swift
1 New Target iTunesSwift
2 Select scheme: iTunesSwift
3 New File Library/iTunes.swift(group:Library)
4 Edit Library/iTunes.swift
5 Edit iTunesSwift/main.swift
6 View > Utilities > Show File Inspector
7 iTumes.m, iTunes.swift: check Taget Menbership:iTunesSwift
8 Build and Run
New Targets
Selection
SelectGrouping
RegularExpression