From b9ef3cdc35370cf3dc203d1da8a24fc95b002826 Mon Sep 17 00:00:00 2001 From: ad Date: Wed, 9 May 2018 21:34:44 +0300 Subject: [PATCH 1/3] + music widget --- MTMR.xcodeproj/project.pbxproj | 4 + MTMR/CustomButtonTouchBarItem.swift | 4 +- MTMR/ItemsParsing.swift | 16 ++ MTMR/TouchBarController.swift | 4 + MTMR/Widgets/MusicBarItem.swift | 374 ++++++++++++++++++++++++++++ 5 files changed, 400 insertions(+), 2 deletions(-) create mode 100644 MTMR/Widgets/MusicBarItem.swift diff --git a/MTMR.xcodeproj/project.pbxproj b/MTMR.xcodeproj/project.pbxproj index a85279c..c5e3efc 100644 --- a/MTMR.xcodeproj/project.pbxproj +++ b/MTMR.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ 6042B6AA2083E27000C525C8 /* DeprecatedCarbonAPI.c in Sources */ = {isa = PBXBuildFile; fileRef = 6042B6A92083E27000C525C8 /* DeprecatedCarbonAPI.c */; }; 607EEA4B2087835F009DA5F0 /* WeatherBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607EEA4A2087835F009DA5F0 /* WeatherBarItem.swift */; }; 607EEA4D2087A8DA009DA5F0 /* CurrencyBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607EEA4C2087A8DA009DA5F0 /* CurrencyBarItem.swift */; }; + 60C44AFD20A373A100C0EC91 /* MusicBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C44AFC20A373A100C0EC91 /* MusicBarItem.swift */; }; 60F7D454208CC31400ABF5D2 /* InputSourceBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60F7D453208CC31400ABF5D2 /* InputSourceBarItem.swift */; }; B0008E552080286C003AD4DD /* SupportHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0008E542080286C003AD4DD /* SupportHelpers.swift */; }; B04B7BB72087398C00C835D0 /* BatteryBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B04B7BB62087398C00C835D0 /* BatteryBarItem.swift */; }; @@ -68,6 +69,7 @@ 6042B6A92083E27000C525C8 /* DeprecatedCarbonAPI.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = DeprecatedCarbonAPI.c; sourceTree = ""; }; 607EEA4A2087835F009DA5F0 /* WeatherBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherBarItem.swift; sourceTree = ""; }; 607EEA4C2087A8DA009DA5F0 /* CurrencyBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyBarItem.swift; sourceTree = ""; }; + 60C44AFC20A373A100C0EC91 /* MusicBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicBarItem.swift; sourceTree = ""; }; 60F7D453208CC31400ABF5D2 /* InputSourceBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputSourceBarItem.swift; sourceTree = ""; }; B0008E542080286C003AD4DD /* SupportHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportHelpers.swift; sourceTree = ""; }; B04B7BB62087398C00C835D0 /* BatteryBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryBarItem.swift; sourceTree = ""; }; @@ -230,6 +232,7 @@ 607EEA4C2087A8DA009DA5F0 /* CurrencyBarItem.swift */, 6042B6A62083E03A00C525C8 /* AppScrubberTouchBarItem.swift */, 60F7D453208CC31400ABF5D2 /* InputSourceBarItem.swift */, + 60C44AFC20A373A100C0EC91 /* MusicBarItem.swift */, ); path = Widgets; sourceTree = ""; @@ -356,6 +359,7 @@ B0008E552080286C003AD4DD /* SupportHelpers.swift in Sources */, 6042B6A72083E03A00C525C8 /* AppScrubberTouchBarItem.swift in Sources */, B082B253205C7D8000BC04DC /* AppDelegate.swift in Sources */, + 60C44AFD20A373A100C0EC91 /* MusicBarItem.swift in Sources */, B059D624205E04F3006E6B86 /* CustomButtonTouchBarItem.swift in Sources */, 6027D1BA2080E52A004FFDC7 /* VolumeViewController.swift in Sources */, 607EEA4B2087835F009DA5F0 /* WeatherBarItem.swift in Sources */, diff --git a/MTMR/CustomButtonTouchBarItem.swift b/MTMR/CustomButtonTouchBarItem.swift index c3ede21..7bbe24a 100644 --- a/MTMR/CustomButtonTouchBarItem.swift +++ b/MTMR/CustomButtonTouchBarItem.swift @@ -9,8 +9,8 @@ import Cocoa class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegate { - private let tapClosure: (() -> ())? - private let longTapClosure: (() -> ())? + public var tapClosure: (() -> ())? + public var longTapClosure: (() -> ())? private(set) var button: NSButton! private var singleClick: NSClickGestureRecognizer! diff --git a/MTMR/ItemsParsing.swift b/MTMR/ItemsParsing.swift index 4cfe593..831db5f 100644 --- a/MTMR/ItemsParsing.swift +++ b/MTMR/ItemsParsing.swift @@ -125,6 +125,17 @@ class SupportedTypesHolder { }, "sleep": { _ in return (item: .staticButton(title: "☕️"), action: .shellScript(executable: "/usr/bin/pmset", parameters: ["sleepnow"]), longAction: .none, parameters: [:]) }, "displaySleep": { _ in return (item: .staticButton(title: "☕️"), action: .shellScript(executable: "/usr/bin/pmset", parameters: ["displaysleepnow"]), longAction: .none, parameters: [:])}, + "music": { decoder in + enum CodingKeys: String, CodingKey { case refreshInterval } + let container = try decoder.container(keyedBy: CodingKeys.self) + let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) + return ( + item: .music(interval: interval ?? 1800.00), + action: .none, + longAction: .none, + parameters: [:] + ) + }, ] static let sharedInstance = SupportedTypesHolder() @@ -157,6 +168,7 @@ enum ItemType: Decodable { case weather(interval: Double, units: String, api_key: String, icon_type: String) case currency(interval: Double, from: String, to: String) case inputsource() + case music(interval: Double) private enum CodingKeys: String, CodingKey { case type @@ -185,6 +197,7 @@ enum ItemType: Decodable { case weather case currency case inputsource + case music } init(from decoder: Decoder) throws { @@ -223,6 +236,9 @@ enum ItemType: Decodable { self = .currency(interval: interval, from: from, to: to) case .inputsource: self = .inputsource() + case .music: + let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0 + self = .music(interval: interval) } } } diff --git a/MTMR/TouchBarController.swift b/MTMR/TouchBarController.swift index bef8cf8..36ae53a 100644 --- a/MTMR/TouchBarController.swift +++ b/MTMR/TouchBarController.swift @@ -37,6 +37,8 @@ extension ItemType { return "com.toxblh.mtmr.currency" case .inputsource(): return "com.toxblh.mtmr.inputsource." + case .music(interval: _): + return "com.toxblh.mtmr.music." } } @@ -206,6 +208,8 @@ class TouchBarController: NSObject, NSTouchBarDelegate { barItem = CurrencyBarItem(identifier: identifier, interval: interval, from: from, to: to, onTap: action, onLongTap: longAction) case .inputsource(): barItem = InputSourceBarItem(identifier: identifier, onTap: action, onLongTap: longAction) + case .music(interval: let interval): + barItem = MusicBarItem(identifier: identifier, interval: interval, onLongTap: longAction) } if case .width(let value)? = item.additionalParameters[.width], let widthBarItem = barItem as? CanSetWidth { diff --git a/MTMR/Widgets/MusicBarItem.swift b/MTMR/Widgets/MusicBarItem.swift new file mode 100644 index 0000000..2b83ba9 --- /dev/null +++ b/MTMR/Widgets/MusicBarItem.swift @@ -0,0 +1,374 @@ +// +// MusicBarItem.swift +// MTMR +// +// Created by Daniel Apatin on 05.05.2018. +// Copyright © 2018 Anton Palgunov. All rights reserved. +// + +import Cocoa +import ScriptingBridge + +class MusicBarItem: CustomButtonTouchBarItem { + private let interval: TimeInterval + private var songTitle: String? + private var timer: Timer? + let buttonSize = NSSize(width: 21, height: 21) + + let playerBundleIdentifiers = [ + "com.apple.iTunes", + "com.spotify.client", + "com.coppertino.Vox", + "com.google.Chrome", + "com.apple.Safari" + ] + + init(identifier: NSTouchBarItem.Identifier, interval: TimeInterval, onLongTap: @escaping () -> ()) { + self.interval = interval + + super.init(identifier: identifier, title: "⏳", onTap: onLongTap, onLongTap: onLongTap) + + button.bezelColor = .clear + button.imageScaling = .scaleProportionallyDown + button.imagePosition = .imageLeading + button.image?.size = NSSize(width: 24, height: 24) + + self.tapClosure = { [weak self] in self?.playPause() } + self.longTapClosure = { [weak self] in self?.nextTrack() } + + DispatchQueue.main.async { + self.updatePlayer() + } + } + + @objc func marquee(){ + let str = self.button.title + if (str.count > 10) { + let indexFirst = str.index(str.startIndex, offsetBy: 0) + let indexSecond = str.index(str.startIndex, offsetBy: 1) + self.button.title = String(str.suffix(from: indexSecond)) + String(str[indexFirst]) + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc func playPause() { + for ident in playerBundleIdentifiers { + if let musicPlayer = SBApplication(bundleIdentifier: ident) { + if (musicPlayer.isRunning) { + if (musicPlayer.className == "SpotifyApplication") { + let mp = (musicPlayer as SpotifyApplication) + mp.playpause!() + } else if (musicPlayer.className == "ITunesApplication") { + let mp = (musicPlayer as iTunesApplication) + mp.playpause!() + } else if (musicPlayer.className == "VOXApplication") { + let mp = (musicPlayer as VoxApplication) + mp.playpause!() + } else if (musicPlayer.className == "SafariApplication") { + // You must enable the 'Allow JavaScript from Apple Events' option in Safari's Develop menu to use 'do JavaScript'. + let safariApplication = musicPlayer as SafariApplication + let safariWindows = safariApplication.windows?().compactMap({ $0 as? SafariWindow }) + for window in safariWindows! { + for tab in window.tabs!() { + let tab = tab as! SafariTab + if (tab.URL?.starts(with: "https://music.yandex.ru"))! { + safariApplication.doJavaScript!("document.getElementsByClassName('player-controls__btn_play')[0].click()", in: tab) + break + } else if ((tab.URL?.starts(with: "https://vk.com/audios"))! || (tab.URL?.starts(with: "https://vk.com/music"))!) { + safariApplication.doJavaScript!("document.getElementsByClassName('audio_page_player_play')[0].click()", in: tab) + break + } else if (tab.URL?.starts(with: "https://www.youtube.com/watch"))! { + safariApplication.doJavaScript!("document.getElementById('movie_player').click()", in: tab) + break + } + } + } + } + // else if (musicPlayer.className == "GoogleChromeApplication") { + // let chromeApplication = musicPlayer as GoogleChromeApplication + // let chromeWindows = chromeApplication.windows?().compactMap({ $0 as? GoogleChromeWindow }) + // for window in chromeWindows! { + // for tab in window.tabs!() { + // let tab = tab as! GoogleChromeTab + // if (tab.URL?.starts(with: "https://music.yandex.ru"))! { + // chromeApplication.executeJavaScript!(javascript: "document.getElementsByClassName('player-controls__btn_play')[0].click()") + // break + // } else if ((tab.URL?.starts(with: "https://vk.com/audios"))! || (tab.URL?.starts(with: "https://vk.com/music"))!) { + // chromeApplication.executeJavaScript!(javascript: "document.getElementsByClassName('audio_page_player_ctrl')[0].click()") + // break + // } else if (tab.URL?.starts(with: "https://www.youtube.com/watch"))! { + // chromeApplication.executeJavaScript!(javascript: "alert(document.title)") // , id: tab + // break // document.getElementById('movie_player').click() + // } + // } + // } + // } + break + } + } + } + } + + @objc func nextTrack() { + for ident in playerBundleIdentifiers { + if let musicPlayer = SBApplication(bundleIdentifier: ident) { + if (musicPlayer.isRunning) { + if (musicPlayer.className == "SpotifyApplication") { + let mp = (musicPlayer as SpotifyApplication) + mp.nextTrack!() + } else if (musicPlayer.className == "ITunesApplication") { + let mp = (musicPlayer as iTunesApplication) + mp.nextTrack!() + } else if (musicPlayer.className == "VOXApplication") { + let mp = (musicPlayer as VoxApplication) + mp.next!() + } else if (musicPlayer.className == "SafariApplication") { + // You must enable the 'Allow JavaScript from Apple Events' option in Safari's Develop menu to use 'do JavaScript'. + let safariApplication = musicPlayer as SafariApplication + let safariWindows = safariApplication.windows?().compactMap({ $0 as? SafariWindow }) + for window in safariWindows! { + for tab in window.tabs!() { + let tab = tab as! SafariTab + if (tab.URL?.starts(with: "https://music.yandex.ru"))! { + safariApplication.doJavaScript!("document.getElementsByClassName('player-controls__btn_next')[0].click()", in: tab) + break + } else if ((tab.URL?.starts(with: "https://vk.com/audios"))! || (tab.URL?.starts(with: "https://vk.com/music"))!) { + safariApplication.doJavaScript!("document.getElementsByClassName('audio_page_player_next')[0].click()", in: tab) + break + } else if (tab.URL?.starts(with: "https://www.youtube.com/watch"))! { + safariApplication.doJavaScript!("document.getElementsByClassName('ytp-next-button')[0].click()", in: tab) + break + } + } + } + } + break + } + } + } + } + + func updatePlayer() { + var iconUpdated = false + var titleUpdated = false + + for var ident in playerBundleIdentifiers { + if let musicPlayer = SBApplication(bundleIdentifier: ident) { + if (musicPlayer.isRunning) { + var tempTitle = "" + if (musicPlayer.className == "SpotifyApplication") { + tempTitle = (musicPlayer as SpotifyApplication).title + } else if (musicPlayer.className == "ITunesApplication") { + tempTitle = (musicPlayer as iTunesApplication).title + } else if (musicPlayer.className == "VOXApplication") { + tempTitle = (musicPlayer as VoxApplication).title + } else if (musicPlayer.className == "SafariApplication") { + let safariApplication = musicPlayer as SafariApplication + let safariWindows = safariApplication.windows?().compactMap({ $0 as? SafariWindow }) + for window in safariWindows! { + for tab in window.tabs!() { + let tab = tab as! SafariTab + if (tab.URL?.starts(with: "https://music.yandex.ru"))! { + // if (!(tab.name?.hasSuffix("на Яндекс.Музыке"))!) { + tempTitle = (tab.name)! + break + // } + } else if ((tab.URL?.starts(with: "https://vk.com/audios"))! || (tab.URL?.starts(with: "https://vk.com/music"))!) { + tempTitle = (tab.name)! + break + } else if (tab.URL?.starts(with: "https://www.youtube.com/watch"))! { + tempTitle = (tab.name)! + break + } + } + } + if tempTitle == "" { + ident = "" + } + } else if (musicPlayer.className == "GoogleChromeApplication") { + let chromeApplication = musicPlayer as GoogleChromeApplication + let chromeWindows = chromeApplication.windows?().compactMap({ $0 as? GoogleChromeWindow }) + for window in chromeWindows! { + for tab in window.tabs!() { + let tab = tab as! GoogleChromeTab + if (tab.URL?.starts(with: "https://music.yandex.ru"))! { + if (!(tab.title?.hasSuffix("на Яндекс.Музыке"))!) { + tempTitle = tab.title! + break + } + } else if ((tab.URL?.starts(with: "https://vk.com/audios"))! || (tab.URL?.starts(with: "https://vk.com/music"))!) { + tempTitle = tab.title! + break + } else if (tab.URL?.starts(with: "https://www.youtube.com/watch"))! { + tempTitle = tab.title! + break + } + } + } + if tempTitle == "" { + ident = "" + } + } + + if (tempTitle == self.songTitle) { + DispatchQueue.main.asyncAfter(deadline: .now() + self.interval) { [weak self] in + self?.updatePlayer() + } + return + } else { + self.songTitle = tempTitle + } + + if (self.songTitle != "") { + self.button.cell?.title = " " + self.songTitle! + " " + titleUpdated = true + self.timer?.invalidate() + self.timer = nil + self.timer = Timer.scheduledTimer(timeInterval: 0.25, target: self, selector: #selector(self.marquee), userInfo: nil, repeats: true) + } + if ident != "" { + if let appPath = NSWorkspace.shared.absolutePathForApplication(withBundleIdentifier: ident) { + self.button.image = NSWorkspace.shared.icon(forFile: appPath) + self.button.image?.size = self.buttonSize + self.button.imagePosition = .imageLeft + iconUpdated = true + } + } + break + } + } + } + + DispatchQueue.main.async { + if !iconUpdated { + self.button.cell?.image = nil + } + + if !titleUpdated { + self.button.cell?.title = "" + } + } + DispatchQueue.main.asyncAfter(deadline: .now() + self.interval) { [weak self] in + self?.updatePlayer() + } + } +} + +@objc protocol SpotifyApplication { + @objc optional var currentTrack: SpotifyTrack {get} + @objc optional func nextTrack() + @objc optional func previousTrack() + @objc optional func playpause() +} +extension SBApplication: SpotifyApplication{} + +@objc protocol SpotifyTrack { + @objc optional var artist: String {get} + @objc optional var name: String {get} +} +extension SBObject: SpotifyTrack{} + +extension SpotifyApplication { + var title: String { + guard let t = currentTrack else { return "" } + return (t.artist ?? "") + " — " + (t.name ?? "") + } +} + + +@objc protocol iTunesApplication { + @objc optional var currentTrack: iTunesTrack {get} + @objc optional func playpause() + @objc optional func nextTrack() + @objc optional func previousTrack() +} +extension SBApplication: iTunesApplication{} + +@objc protocol iTunesTrack { + @objc optional var artist: String {get} + @objc optional var name: String {get} +} +extension SBObject: iTunesTrack{} + +extension iTunesApplication { + var title: String { + guard let t = currentTrack else { return "" } + return (t.artist ?? "") + " — " + (t.name ?? "") + } +} + + + +@objc protocol VoxApplication { + @objc optional func playpause() + @objc optional func next() + @objc optional func previous() + @objc optional var track: String {get} + @objc optional var artist: String {get} +} +extension SBApplication: VoxApplication{} + +extension VoxApplication { + var title: String { + return (artist ?? "") + " — " + (track ?? "") + } +} + + +@objc public protocol SBObjectProtocol: NSObjectProtocol { + func get() -> Any! +} + +@objc public protocol SBApplicationProtocol: SBObjectProtocol { + func activate() + var delegate: SBApplicationDelegate! { get set } +} + +@objc public protocol SafariApplication: SBApplicationProtocol { + @objc optional func windows() -> SBElementArray + @objc optional func doJavaScript(_ x: String!, in in_: Any!) -> Any // Applies a string of JavaScript code to a document. +} +extension SBApplication: SafariApplication {} + +@objc public protocol SafariWindow: SBObjectProtocol { + @objc optional var name: String { get } // The title of the window. + @objc optional func tabs() -> SBElementArray + // @objc optional var document: SafariDocument { get } // The document whose contents are displayed in the window. + // @objc optional func setCurrentTab(_ currentTab: SafariTab!) // The current tab. +} +extension SBObject: SafariWindow {} + +//@objc public protocol SafariDocument: SBObjectProtocol { +// @objc optional var name: String { get } // Its name. +// @objc optional var URL: String { get } // The current URL of the document. +//} +//extension SBObject: SafariDocument {} + +@objc public protocol SafariTab: SBObjectProtocol { + @objc optional var URL: String { get } // The current URL of the tab. + @objc optional var name: String { get } // The name of the tab. +} +extension SBObject: SafariTab {} + + + +@objc public protocol GoogleChromeApplication: SBApplicationProtocol { + @objc optional func windows() -> SBElementArray + @objc optional func executeJavaScript(javascript: String!) -> Any // Applies a string of JavaScript code to a document. //, id: Any! +} +extension SBApplication: GoogleChromeApplication {} + +@objc public protocol GoogleChromeWindow: SBObjectProtocol { + @objc optional var name: String { get } // The title of the window. + @objc optional func tabs() -> SBElementArray +} +extension SBObject: GoogleChromeWindow {} + +@objc public protocol GoogleChromeTab: SBObjectProtocol { + @objc optional var URL: String { get } // The current URL of the tab. + @objc optional var title: String { get } // The name of the tab. +} +extension SBObject: GoogleChromeTab {} From 3bc75b54c0891d4029ea1a7d9fcceaaf0e6bd07a Mon Sep 17 00:00:00 2001 From: Serg Date: Sat, 12 May 2018 20:19:11 +0700 Subject: [PATCH 2/3] naive backport of compact map to old swift --- MTMR.xcodeproj/project.pbxproj | 4 ++++ MTMR/GeneralExtensions.swift | 11 +++++++++++ 2 files changed, 15 insertions(+) create mode 100644 MTMR/GeneralExtensions.swift diff --git a/MTMR.xcodeproj/project.pbxproj b/MTMR.xcodeproj/project.pbxproj index c5e3efc..d4e619f 100644 --- a/MTMR.xcodeproj/project.pbxproj +++ b/MTMR.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 36300E8F20A2CF3400B31C71 /* AppleScriptDefinitionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36300E8E20A2CF3400B31C71 /* AppleScriptDefinitionTests.swift */; }; 36300E9120A2D2B200B31C71 /* BackgroundColorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36300E9020A2D2B200B31C71 /* BackgroundColorTests.swift */; }; 368EDDE720812A1D00E10953 /* ScrollViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 368EDDE620812A1D00E10953 /* ScrollViewItem.swift */; }; + 36A778BE20A6C27100B38714 /* GeneralExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36A778BD20A6C27100B38714 /* GeneralExtensions.swift */; }; 36C2ECD7207B6DAE003CDA33 /* TimeTouchBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36C2ECD6207B6DAE003CDA33 /* TimeTouchBarItem.swift */; }; 36C2ECD9207B74B4003CDA33 /* AppleScriptTouchBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36C2ECD8207B74B4003CDA33 /* AppleScriptTouchBarItem.swift */; }; 36C2ECDB207C3FE7003CDA33 /* ItemsParsing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36C2ECDA207C3FE7003CDA33 /* ItemsParsing.swift */; }; @@ -55,6 +56,7 @@ 36300E8E20A2CF3400B31C71 /* AppleScriptDefinitionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleScriptDefinitionTests.swift; sourceTree = ""; }; 36300E9020A2D2B200B31C71 /* BackgroundColorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundColorTests.swift; sourceTree = ""; }; 368EDDE620812A1D00E10953 /* ScrollViewItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollViewItem.swift; sourceTree = ""; }; + 36A778BD20A6C27100B38714 /* GeneralExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralExtensions.swift; sourceTree = ""; }; 36BDC22F207CDA8600FCFEBE /* TECHNICAL_DEBT.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = TECHNICAL_DEBT.md; sourceTree = ""; }; 36C2ECD2207B3B1D003CDA33 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 36C2ECD6207B6DAE003CDA33 /* TimeTouchBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeTouchBarItem.swift; sourceTree = ""; }; @@ -175,6 +177,7 @@ B09EB1E3207C082000D5C1E0 /* HapticFeedback.swift */, 368EDDE620812A1D00E10953 /* ScrollViewItem.swift */, B05600D22083E9BB00EB218D /* CustomSlider.swift */, + 36A778BD20A6C27100B38714 /* GeneralExtensions.swift */, ); path = MTMR; sourceTree = ""; @@ -366,6 +369,7 @@ 6042B6AA2083E27000C525C8 /* DeprecatedCarbonAPI.c in Sources */, B09EB1E4207C082000D5C1E0 /* HapticFeedback.swift in Sources */, 60F7D454208CC31400ABF5D2 /* InputSourceBarItem.swift in Sources */, + 36A778BE20A6C27100B38714 /* GeneralExtensions.swift in Sources */, 36C2ECDB207C3FE7003CDA33 /* ItemsParsing.swift in Sources */, B0A7E9AA205D6AA400EEF070 /* KeyPress.swift in Sources */, 36C2ECD7207B6DAE003CDA33 /* TimeTouchBarItem.swift in Sources */, diff --git a/MTMR/GeneralExtensions.swift b/MTMR/GeneralExtensions.swift new file mode 100644 index 0000000..fe8d36f --- /dev/null +++ b/MTMR/GeneralExtensions.swift @@ -0,0 +1,11 @@ +import Foundation + +#if swift(>=4.1) + // compactMap supported +#else + extension Sequence { + func compactMap(_ transform: (Self.Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult] { + return try flatMap(transform) + } + } +#endif From 5c7be625b6f118f48240ae23bb095e2e519c9bcc Mon Sep 17 00:00:00 2001 From: Serg Date: Sun, 13 May 2018 00:11:47 +0700 Subject: [PATCH 3/3] fix warnings, switch track of only first player running --- MTMR/Widgets/MusicBarItem.swift | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/MTMR/Widgets/MusicBarItem.swift b/MTMR/Widgets/MusicBarItem.swift index b15c13d..fca7be6 100644 --- a/MTMR/Widgets/MusicBarItem.swift +++ b/MTMR/Widgets/MusicBarItem.swift @@ -57,12 +57,15 @@ class MusicBarItem: CustomButtonTouchBarItem { if (musicPlayer.className == "SpotifyApplication") { let mp = (musicPlayer as SpotifyApplication) mp.playpause!() + return } else if (musicPlayer.className == "ITunesApplication") { let mp = (musicPlayer as iTunesApplication) mp.playpause!() + return } else if (musicPlayer.className == "VOXApplication") { let mp = (musicPlayer as VoxApplication) mp.playpause!() + return } else if (musicPlayer.className == "SafariApplication") { // You must enable the 'Allow JavaScript from Apple Events' option in Safari's Develop menu to use 'do JavaScript'. let safariApplication = musicPlayer as SafariApplication @@ -71,14 +74,14 @@ class MusicBarItem: CustomButtonTouchBarItem { for tab in window.tabs!() { let tab = tab as! SafariTab if (tab.URL?.starts(with: "https://music.yandex.ru"))! { - safariApplication.doJavaScript!("document.getElementsByClassName('player-controls__btn_play')[0].click()", in: tab) - break + _ = safariApplication.doJavaScript!("document.getElementsByClassName('player-controls__btn_play')[0].click()", in: tab) + return } else if ((tab.URL?.starts(with: "https://vk.com/audios"))! || (tab.URL?.starts(with: "https://vk.com/music"))!) { - safariApplication.doJavaScript!("document.getElementsByClassName('audio_page_player_play')[0].click()", in: tab) - break + _ = safariApplication.doJavaScript!("document.getElementsByClassName('audio_page_player_play')[0].click()", in: tab) + return } else if (tab.URL?.starts(with: "https://www.youtube.com/watch"))! { - safariApplication.doJavaScript!("document.getElementById('movie_player').click()", in: tab) - break + _ = safariApplication.doJavaScript!("document.getElementById('movie_player').click()", in: tab) + return } } } @@ -115,12 +118,15 @@ class MusicBarItem: CustomButtonTouchBarItem { if (musicPlayer.className == "SpotifyApplication") { let mp = (musicPlayer as SpotifyApplication) mp.nextTrack!() + return } else if (musicPlayer.className == "ITunesApplication") { let mp = (musicPlayer as iTunesApplication) mp.nextTrack!() + return } else if (musicPlayer.className == "VOXApplication") { let mp = (musicPlayer as VoxApplication) mp.next!() + return } else if (musicPlayer.className == "SafariApplication") { // You must enable the 'Allow JavaScript from Apple Events' option in Safari's Develop menu to use 'do JavaScript'. let safariApplication = musicPlayer as SafariApplication @@ -129,19 +135,18 @@ class MusicBarItem: CustomButtonTouchBarItem { for tab in window.tabs!() { let tab = tab as! SafariTab if (tab.URL?.starts(with: "https://music.yandex.ru"))! { - safariApplication.doJavaScript!("document.getElementsByClassName('player-controls__btn_next')[0].click()", in: tab) - break + _ = safariApplication.doJavaScript!("document.getElementsByClassName('player-controls__btn_next')[0].click()", in: tab) + return } else if ((tab.URL?.starts(with: "https://vk.com/audios"))! || (tab.URL?.starts(with: "https://vk.com/music"))!) { - safariApplication.doJavaScript!("document.getElementsByClassName('audio_page_player_next')[0].click()", in: tab) - break + _ = safariApplication.doJavaScript!("document.getElementsByClassName('audio_page_player_next')[0].click()", in: tab) + return } else if (tab.URL?.starts(with: "https://www.youtube.com/watch"))! { - safariApplication.doJavaScript!("document.getElementsByClassName('ytp-next-button')[0].click()", in: tab) - break + _ = safariApplication.doJavaScript!("document.getElementsByClassName('ytp-next-button')[0].click()", in: tab) + return } } } } - break } } }