├── .gitignore ├── .gitmodules ├── CONTRIBUTING.md ├── LICENSE ├── Podfile ├── Podfile.lock ├── README.md ├── SoundcloudPlayer.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── StreamCloud Beta.xcscheme │ └── StreamCloud.xcscheme ├── SoundcloudPlayer.xcworkspace └── contents.xcworkspacedata ├── SoundcloudPlayer ├── AppDelegate.h ├── AppDelegate.m ├── AppleMediaKeyController.h ├── AppleMediaKeyController.m ├── ArtworkOverlayView.h ├── ArtworkOverlayView.m ├── Base.lproj │ └── MainMenu.xib ├── ClickableTableView.h ├── ClickableTableView.m ├── ClickableTextField.h ├── ClickableTextField.m ├── ConnectButtonCell.h ├── ConnectButtonCell.m ├── Images.xcassets │ ├── AppIcon Beta.appiconset │ │ ├── Contents.json │ │ ├── beta-128.png │ │ ├── beta-128@2x.png │ │ ├── beta-16.png │ │ ├── beta-16@2x.png │ │ ├── beta-256.png │ │ ├── beta-256@2x.png │ │ ├── beta-32.png │ │ ├── beta-32@2x.png │ │ ├── beta-512.png │ │ └── beta-512@2x.png │ ├── AppIcon.appiconset │ │ ├── AppIcon128.png │ │ ├── AppIcon128@2x.png │ │ ├── AppIcon16.png │ │ ├── AppIcon16@2x.png │ │ ├── AppIcon256.png │ │ ├── AppIcon256@2x.png │ │ ├── AppIcon32.png │ │ ├── AppIcon32@2x.png │ │ ├── AppIcon512.png │ │ ├── AppIcon512@2x.png │ │ └── Contents.json │ ├── icon-lastfm.imageset │ │ ├── Contents.json │ │ ├── icon-lastfm.png │ │ └── icon-lastfm@2x.png │ ├── menuBarIcon.imageset │ │ ├── Contents.json │ │ ├── menuBarIcon.png │ │ └── menuBarIcon@2x.png │ ├── menuBarIcon_active.imageset │ │ ├── Contents.json │ │ ├── menuBarIcon_active.png │ │ └── menuBarIcon_active@2x.png │ ├── plaetzchen.imageset │ │ ├── Contents.json │ │ ├── plaetzchen.png │ │ └── plaetzchen@2x.png │ └── zutrinken.imageset │ │ ├── Contents.json │ │ ├── zutrinken.png │ │ └── zutrinken@2x.png ├── IsRepostedLabelView.h ├── IsRepostedLabelView.m ├── LoadSpeakerOverlayView.h ├── LoadSpeakerOverlayView.m ├── LowerShadowView.h ├── LowerShadowView.m ├── MouseOverImageView.h ├── MouseOverImageView.m ├── NSImage+RoundedCorners.h ├── NSImage+RoundedCorners.m ├── NextButtonCell.h ├── NextButtonCell.m ├── OAuth2Client.framework │ ├── Headers │ ├── OAuth2Client │ ├── Resources │ └── Versions │ │ ├── A │ │ ├── Headers │ │ │ ├── NSData+NXOAuth2.h │ │ │ ├── NSString+NXOAuth2.h │ │ │ ├── NSURL+NXOAuth2.h │ │ │ ├── NXOAuth2.h │ │ │ ├── NXOAuth2AccessToken.h │ │ │ ├── NXOAuth2Account.h │ │ │ ├── NXOAuth2AccountStore.h │ │ │ ├── NXOAuth2Client.h │ │ │ ├── NXOAuth2ClientDelegate.h │ │ │ ├── NXOAuth2Connection.h │ │ │ ├── NXOAuth2ConnectionDelegate.h │ │ │ ├── NXOAuth2Constants.h │ │ │ ├── NXOAuth2FileStreamWrapper.h │ │ │ ├── NXOAuth2PostBodyStream.h │ │ │ ├── NXOAuth2Request.h │ │ │ └── NXOAuth2TrustDelegate.h │ │ ├── OAuth2Client │ │ └── Resources │ │ │ └── Info.plist │ │ └── Current ├── PlayPauseButtonCell.h ├── PlayPauseButtonCell.m ├── PlayPauseOverlayView.h ├── PlayPauseOverlayView.m ├── PlayingIndicatorView.h ├── PlayingIndicatorView.m ├── PreviousButtonCell.h ├── PreviousButtonCell.m ├── ProgressIndicatorView.h ├── ProgressIndicatorView.m ├── ProgressSliderCell.h ├── ProgressSliderCell.m ├── ProgressSliderView.h ├── ProgressSliderView.m ├── RepeatButtonCell.h ├── RepeatButtonCell.m ├── SeperatorView.h ├── SeperatorView.m ├── SettingsViewController.h ├── SettingsViewController.m ├── SharedAudioPlayer.h ├── SharedAudioPlayer.m ├── ShuffleButtonCell.h ├── ShuffleButtonCell.m ├── SoundCloudAPI.framework │ ├── Headers │ ├── Resources │ ├── SoundCloudAPI │ └── Versions │ │ ├── A │ │ ├── Headers │ │ │ ├── SCAPI.h │ │ │ ├── SCAccount+Private.h │ │ │ ├── SCAccount.h │ │ │ ├── SCConstants.h │ │ │ ├── SCRequest.h │ │ │ ├── SCSoundCloud+Private.h │ │ │ └── SCSoundCloud.h │ │ ├── Resources │ │ │ └── Info.plist │ │ └── SoundCloudAPI │ │ └── Current ├── SoundCloudAPIClient.h ├── SoundCloudAPIClient.m ├── SoundCloudItem.h ├── SoundCloudItem.m ├── SoundCloudPlaylist.h ├── SoundCloudPlaylist.m ├── SoundCloudTrack.h ├── SoundCloudTrack.m ├── SoundCloudUser.h ├── SoundCloudUser.m ├── SoundcloudPlayer-Info.plist ├── SoundcloudPlayer-Prefix.pch ├── SoundcloudPlayer.entitlements ├── StatusBarPlayerViewController.h ├── StatusBarPlayerViewController.m ├── StatusBarPlayerViewController.xib ├── StreamCloudApplication.h ├── StreamCloudApplication.m ├── StreamCloudStyles.h ├── StreamCloudStyles.m ├── TrackCellForPlaylistItemView.h ├── TrackCellForPlaylistItemView.m ├── TrackCellView.h ├── TrackCellView.m ├── UpperShadowView.h ├── UpperShadowView.m ├── VolumeButtonCell.h ├── VolumeButtonCell.m ├── WhiteBackgroundView.h ├── WhiteBackgroundView.m ├── en.lproj │ ├── Credits.rtf │ └── InfoPlist.strings ├── main.m └── singleton.h ├── SoundcloudPlayerTests ├── SoundcloudPlayerTests-Info.plist ├── SoundcloudPlayerTests.m └── en.lproj │ └── InfoPlist.strings ├── StreamCloud copy-Info.plist ├── streamcloud-icons.pcvd └── streamcloud_beta.plist /.gitignore: -------------------------------------------------------------------------------- 1 | # CocoaPods 2 | # 3 | # We recommend against adding the Pods directory to your .gitignore. However 4 | # you should judge for yourself, the pros and cons are mentioned at: 5 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control? 6 | # 7 | Pods/ 8 | ######################### 9 | # .gitignore file for Xcode4 / OS X Source projects 10 | # 11 | # NB: if you are storing "built" products, this WILL NOT WORK, 12 | # and you should use a different .gitignore (or none at all) 13 | # This file is for SOURCE projects, where there are many extra 14 | # files that we want to exclude 15 | # 16 | # For updates, see: http://stackoverflow.com/questions/49478/git-ignore-file-for-xcode-projects 17 | ######################### 18 | 19 | ##### 20 | # OS X temporary files that should never be committed 21 | 22 | .DS_Store 23 | *.swp 24 | *.lock 25 | profile 26 | !Podfile.lock 27 | 28 | #### 29 | # Xcode temporary files that should never be committed 30 | # 31 | # NB: NIB/XIB files still exist even on Storyboard projects, so we want this... 32 | 33 | *~.nib 34 | 35 | 36 | #### 37 | # Xcode build files - 38 | # 39 | # NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "DerivedData" 40 | 41 | DerivedData/ 42 | 43 | # NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "build" 44 | 45 | build/ 46 | 47 | 48 | ##### 49 | # Xcode private settings (window sizes, bookmarks, breakpoints, custom executables, smart groups) 50 | # 51 | # This is complicated: 52 | # 53 | # SOMETIMES you need to put this file in version control. 54 | # Apple designed it poorly - if you use "custom executables", they are 55 | # saved in this file. 56 | # 99% of projects do NOT use those, so they do NOT want to version control this file. 57 | # ..but if you're in the 1%, comment out the line "*.pbxuser" 58 | 59 | *.pbxuser 60 | *.mode1v3 61 | *.mode2v3 62 | *.perspectivev3 63 | # NB: also, whitelist the default ones, some projects need to use these 64 | !default.pbxuser 65 | !default.mode1v3 66 | !default.mode2v3 67 | !default.perspectivev3 68 | 69 | 70 | #### 71 | # Xcode 4 - semi-personal settings, often included in workspaces 72 | # 73 | # You can safely ignore the xcuserdata files - but do NOT ignore the files next to them 74 | # 75 | 76 | xcuserdata 77 | 78 | 79 | #### 80 | # XCode 4 workspaces - more detailed 81 | # 82 | # Workspaces are important! They are a core feature of Xcode - don't exclude them :) 83 | # 84 | # Workspace layout is quite spammy. For reference: 85 | # 86 | # (root)/ 87 | # (project-name).xcodeproj/ 88 | # project.pbxproj 89 | # project.xcworkspace/ 90 | # contents.xcworkspacedata 91 | # xcuserdata/ 92 | # (your name)/xcuserdatad/ 93 | # xcuserdata/ 94 | # (your name)/xcuserdatad/ 95 | # 96 | # 97 | # 98 | # Xcode 4 workspaces - SHARED 99 | # 100 | # This is UNDOCUMENTED (google: "developer.apple.com xcshareddata" - 0 results 101 | # But if you're going to kill personal workspaces, at least keep the shared ones... 102 | # 103 | # 104 | !xcshareddata 105 | 106 | 107 | #### 108 | # Xcode 4 - Deprecated classes 109 | # 110 | # Allegedly, if you manually "deprecate" your classes, they get moved here. 111 | # 112 | # We're using source-control, so this is a "feature" that we do not want! 113 | 114 | *.moved-aside 115 | 116 | 117 | #### 118 | # XCode 4 build-schemes 119 | # 120 | # PRIVATE ones are stored inside xcuserdata 121 | !xcschemes 122 | 123 | *.idea 124 | 125 | Pods 126 | *.trace 127 | *.xccheckout 128 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "OAuth2Client"] 2 | path = OAuth2Client 3 | url = https://github.com/nxtbgthng/OAuth2Client.git 4 | [submodule "CocoaSoundCloudAPI"] 5 | path = CocoaSoundCloudAPI 6 | url = https://github.com/soundcloud/CocoaSoundCloudAPI.git 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We love pull requests. Take a look at the [issues](https://github.com/plaetzchen/StreamCloud/issues) and filter by milestones to see what features are planned for the next release. Naturally we appreciate all kind of improvements. Here's a quick guide how to contribute. 4 | 5 | 1. Fork, then clone the repo: 6 | 7 | $ git clone git@github.com:your-username/StreamCloud.git 8 | 9 | 2. Create your feature branch: 10 | 11 | $ git checkout -b my-new-feature 12 | 13 | 3. Commit your changes: 14 | 15 | $ git commit -am 'Added some feature' 16 | 17 | 4. Push to the branch: 18 | 19 | $ git push origin my-new-feature 20 | 21 | 5. Submit a new [pull request](https://github.com/plaetzchen/StreamCloud/compare). 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2015 Peter Amende, Philip Brechler 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 16 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 18 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 19 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 | OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | 3 | platform :osx, '10.8' 4 | 5 | abstract_target 'defaults' do 6 | pod 'AFNetworking', '~> 2.3' 7 | pod 'AXStatusItemPopup', :git => 'https://github.com/plaetzchen/AXStatusItemPopup.git', :tag => '0.0.5' 8 | pod 'LastFm', :inhibit_warnings => true 9 | pod 'HockeySDK-Mac', '~> 2.1' 10 | pod 'MASShortcut', '~> 1.2' 11 | 12 | target 'StreamCloud' 13 | target 'StreamCloud Beta' 14 | end 15 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - AFNetworking (2.5.4): 3 | - AFNetworking/NSURLConnection (= 2.5.4) 4 | - AFNetworking/NSURLSession (= 2.5.4) 5 | - AFNetworking/Reachability (= 2.5.4) 6 | - AFNetworking/Security (= 2.5.4) 7 | - AFNetworking/Serialization (= 2.5.4) 8 | - AFNetworking/UIKit (= 2.5.4) 9 | - AFNetworking/NSURLConnection (2.5.4): 10 | - AFNetworking/Reachability 11 | - AFNetworking/Security 12 | - AFNetworking/Serialization 13 | - AFNetworking/NSURLSession (2.5.4): 14 | - AFNetworking/Reachability 15 | - AFNetworking/Security 16 | - AFNetworking/Serialization 17 | - AFNetworking/Reachability (2.5.4) 18 | - AFNetworking/Security (2.5.4) 19 | - AFNetworking/Serialization (2.5.4) 20 | - AXStatusItemPopup (0.0.5) 21 | - HockeySDK-Mac (2.1.0) 22 | - KissXML (5.0) 23 | - LastFm (1.15.0): 24 | - KissXML (~> 5.0) 25 | - MASShortcut (1.3.1) 26 | 27 | DEPENDENCIES: 28 | - AFNetworking (~> 2.3) 29 | - AXStatusItemPopup (from `https://github.com/plaetzchen/AXStatusItemPopup.git`, tag `0.0.5`) 30 | - HockeySDK-Mac (~> 2.1) 31 | - LastFm 32 | - MASShortcut (~> 1.2) 33 | 34 | EXTERNAL SOURCES: 35 | AXStatusItemPopup: 36 | :git: https://github.com/plaetzchen/AXStatusItemPopup.git 37 | :tag: 0.0.5 38 | 39 | CHECKOUT OPTIONS: 40 | AXStatusItemPopup: 41 | :git: https://github.com/plaetzchen/AXStatusItemPopup.git 42 | :tag: 0.0.5 43 | 44 | SPEC CHECKSUMS: 45 | AFNetworking: 05edc0ac4c4c8cf57bcf4b84be5b0744b6d8e71e 46 | AXStatusItemPopup: 88877807fba6a95676656ad150867edd82979f99 47 | HockeySDK-Mac: c9a7743fbe181e1a1dd027043d708d65ce4c2726 48 | KissXML: ce643413d618ad69886d0d43c3792b7dedfe476e 49 | LastFm: 28c752f8e8646531524a123ce7f6722bbfc9d3c5 50 | MASShortcut: 65f5fac12bbdd3622abcb8175a633f68f553c60f 51 | 52 | PODFILE CHECKSUM: ea70c3b4a7078dfe6e0bcd0caebd9003a529b830 53 | 54 | COCOAPODS: 1.0.0 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # StreamCloud 2 | 3 | StreamCloud is a free SoundCloud app for Mac. 4 | 5 | * [Website](http://streamcloud.cc/) 6 | * [AppStore](https://itunes.apple.com/app/streamcloud/id894578573) 7 | 8 | ## How to build 9 | 10 | $ git clone git@github.com:streamcloudapp/StreamCloud.git 11 | $ cd StreamCloud 12 | $ pod install 13 | $ open SoundcloudPlayer.xcworkspace 14 | 15 | ## Contributing 16 | 17 | If you want to push StreamCloud to the next level say hi on [Twitter](https://twitter.com/StreamCloudApp) or via [email](mailto:mail@streamcloud.cc), take a look at our [contribution guide](https://github.com/streamcloudapp/StreamCloud/blob/master/CONTRIBUTING.md) and take a look at the [issues](https://github.com/streamcloudapp/StreamCloud/issues) with a lot of awesome features. 18 | 19 | For visual tasks hit on [zutrinken](https://github.com/zutrinken) to get access to the design sources. All graphics are managed with [PaintCode](http://www.paintcodeapp.com/). 20 | 21 | ## Copyright & License 22 | 23 | Copyright (c) 2014-2015 Peter Amende, Philip Brechler - Released under the [MIT license](https://github.com/streamcloudapp/StreamCloud/blob/master/LICENSE). 24 | -------------------------------------------------------------------------------- /SoundcloudPlayer.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SoundcloudPlayer.xcodeproj/xcshareddata/xcschemes/StreamCloud Beta.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 70 | 72 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /SoundcloudPlayer.xcodeproj/xcshareddata/xcschemes/StreamCloud.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 63 | 69 | 70 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /SoundcloudPlayer.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SoundcloudPlayer/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 20.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AXStatusItemPopup.h" 11 | #import "StatusBarPlayerViewController.h" 12 | #import "ProgressSliderView.h" 13 | 14 | @interface AppDelegate : NSObject 15 | 16 | @property (assign) IBOutlet NSWindow *window; 17 | @property (nonatomic, strong) IBOutlet ProgressSliderView *playerTimeSlider; 18 | @property (nonatomic, strong) IBOutlet NSTextField *timeToGoLabel; 19 | @property (nonatomic, strong) IBOutlet NSTextField *timeGoneLabel; 20 | @property (nonatomic, strong) IBOutlet NSTableView *tableView; 21 | @property (nonatomic, strong) IBOutlet NSSlider *playerVolumeSlider; 22 | @property (nonatomic, strong) IBOutlet NSPopover *volumePopover; 23 | @property (nonatomic, strong) IBOutlet NSButton *volumeButton; 24 | @property (nonatomic, strong) AXStatusItemPopup *statusItemPopup; 25 | @property (nonatomic, strong) StatusBarPlayerViewController *statusBarPlayerViewController; 26 | @property (nonatomic) BOOL atBottom; 27 | @property (nonatomic, strong) IBOutlet NSPanel *aboutPanel; 28 | @property (nonatomic, strong) IBOutlet NSSegmentedControl *switchStreamLikesSegmentedControl; 29 | @property (nonatomic) NSInteger currentlySelectedStream; 30 | 31 | @property (nonatomic, strong) IBOutlet NSPanel *settingsPanel; 32 | 33 | @property (nonatomic, strong) IBOutlet NSMenuItem *trackNameDockMenuItem; 34 | 35 | @property (nonatomic, strong) IBOutlet NSTextField *loginTextField; 36 | @property (nonatomic, strong) IBOutlet NSButton *loginButton; 37 | 38 | - (IBAction)playButtonAction:(id)sender; 39 | - (IBAction)nextButtonAction:(id)sender; 40 | - (IBAction)previousButtonAction:(id)sender; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /SoundcloudPlayer/AppleMediaKeyController.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppleMediaKeyController.h 3 | // 4 | // Modified by Gaurav Khanna on 8/17/10. 5 | // SOURCE: http://github.com/sweetfm/SweetFM/blob/master/Source/HMediaKeys.h 6 | // 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without restriction, 11 | // including without limitation the rights to use, copy, modify, 12 | // merge, publish, distribute, sublicense, and/or sell copies of 13 | // the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be 17 | // included in all copies or substantial portions of the Software. 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 22 | // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 23 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | #import "singleton.h" 28 | #import 29 | 30 | extern NSString * const MediaKeyPlayPauseNotification; 31 | extern NSString * const MediaKeyNextNotification; 32 | extern NSString * const MediaKeyPreviousNotification; 33 | 34 | @interface AppleMediaKeyController : NSObject { 35 | CFMachPortRef _eventPort; 36 | CFRunLoopSourceRef _runLoopSource; 37 | } 38 | 39 | @property(nonatomic, assign, readonly) CFMachPortRef eventPort; 40 | 41 | + (id)sharedController; 42 | 43 | @end -------------------------------------------------------------------------------- /SoundcloudPlayer/AppleMediaKeyController.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppleMediaKeyController.m 3 | // 4 | // Modified by Gaurav Khanna on 8/17/10. 5 | // SOURCE: http://github.com/sweetfm/SweetFM/blob/master/Source/HMediaKeys.m 6 | // SOURCE: http://stackoverflow.com/questions/2969110/cgeventtapcreate-breaks-down-mysteriously-with-key-down-events 7 | // 8 | // 9 | // Permission is hereby granted, free of charge, to any person 10 | // obtaining a copy of this software and associated documentation 11 | // files (the "Software"), to deal in the Software without restriction, 12 | // including without limitation the rights to use, copy, modify, 13 | // merge, publish, distribute, sublicense, and/or sell copies of 14 | // the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 23 | // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 24 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | // 27 | 28 | #import "AppleMediaKeyController.h" 29 | 30 | NSString * const MediaKeyPlayPauseNotification = @"MediaKeyPlayPauseNotification"; 31 | NSString * const MediaKeyNextNotification = @"MediaKeyNextNotification"; 32 | NSString * const MediaKeyPreviousNotification = @"MediaKeyPreviousNotification"; 33 | 34 | #define NX_KEYSTATE_UP 0x0A 35 | #define NX_KEYSTATE_DOWN 0x0B 36 | 37 | @implementation AppleMediaKeyController 38 | 39 | @synthesize eventPort = _eventPort; 40 | 41 | MAKE_SINGLETON(AppleMediaKeyController, sharedController) 42 | 43 | CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) { 44 | if(type == kCGEventTapDisabledByTimeout) 45 | CGEventTapEnable([[AppleMediaKeyController sharedController] eventPort], TRUE); 46 | 47 | if(type != NX_SYSDEFINED) 48 | return event; 49 | 50 | NSEvent *nsEvent = [NSEvent eventWithCGEvent:event]; 51 | 52 | if([nsEvent subtype] != 8) 53 | return event; 54 | 55 | int data = (int)[nsEvent data1]; 56 | int keyCode = (data & 0xFFFF0000) >> 16; 57 | int keyFlags = (data & 0xFFFF); 58 | int keyState = (keyFlags & 0xFF00) >> 8; 59 | BOOL keyIsRepeat = (keyFlags & 0x1) > 0; 60 | 61 | if(keyIsRepeat) 62 | return event; 63 | 64 | NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; 65 | switch (keyCode) { 66 | case NX_KEYTYPE_PLAY: 67 | if(keyState == NX_KEYSTATE_DOWN) 68 | [center postNotificationName:MediaKeyPlayPauseNotification object:(AppleMediaKeyController *)refcon]; 69 | if(keyState == NX_KEYSTATE_UP || keyState == NX_KEYSTATE_DOWN) 70 | return NULL; 71 | break; 72 | case NX_KEYTYPE_FAST: 73 | if(keyState == NX_KEYSTATE_DOWN) 74 | [center postNotificationName:MediaKeyNextNotification object:(AppleMediaKeyController *)refcon]; 75 | if(keyState == NX_KEYSTATE_UP || keyState == NX_KEYSTATE_DOWN) 76 | return NULL; 77 | break; 78 | case NX_KEYTYPE_REWIND: 79 | if(keyState == NX_KEYSTATE_DOWN) 80 | [center postNotificationName:MediaKeyPreviousNotification object:(AppleMediaKeyController *)refcon]; 81 | if(keyState == NX_KEYSTATE_UP || keyState == NX_KEYSTATE_DOWN) 82 | return NULL; 83 | break; 84 | } 85 | return event; 86 | } 87 | 88 | - (id)init { 89 | if(self = [super init]) { 90 | CFRunLoopRef runLoop; 91 | 92 | _eventPort = CGEventTapCreate(kCGSessionEventTap, 93 | kCGHeadInsertEventTap, 94 | kCGEventTapOptionDefault, 95 | CGEventMaskBit(NX_SYSDEFINED), 96 | tapEventCallback, 97 | self); 98 | 99 | if(_eventPort == NULL) { 100 | NSLog(@"Fatal Error: Event Tap could not be created"); 101 | return self; 102 | } 103 | 104 | _runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorSystemDefault, _eventPort, 0); 105 | 106 | if(_runLoopSource == NULL) { 107 | NSLog(@"Fatal Error: Run Loop Source could not be created"); 108 | return self; 109 | } 110 | 111 | runLoop = CFRunLoopGetCurrent(); 112 | 113 | if(runLoop == NULL) { 114 | NSLog(@"Fatal Error: Couldn't get current threads Run Loop"); 115 | return self; 116 | } 117 | 118 | CFRunLoopAddSource(runLoop, _runLoopSource, kCFRunLoopCommonModes); 119 | } 120 | return self; 121 | } 122 | 123 | - (void)dealloc { 124 | CFRelease(_eventPort); 125 | CFRelease(_runLoopSource); 126 | [super dealloc]; 127 | } 128 | 129 | @end -------------------------------------------------------------------------------- /SoundcloudPlayer/ArtworkOverlayView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ArtworkOverlayView.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 19.01.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ArtworkOverlayView : NSView 12 | 13 | - (void)hideWithFadeOut; 14 | @end 15 | -------------------------------------------------------------------------------- /SoundcloudPlayer/ArtworkOverlayView.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // ArtworkOverlayView.m 4 | // SoundcloudPlayer 5 | // 6 | // Created by Philip Brechler on 19.01.15. 7 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 8 | // 9 | 10 | #import "ArtworkOverlayView.h" 11 | #import "StreamCloudStyles.h" 12 | 13 | @import QuartzCore; 14 | 15 | @implementation ArtworkOverlayView 16 | 17 | - (void)drawRect:(NSRect)dirtyRect { 18 | [[StreamCloudStyles orangeDark] setFill]; 19 | NSRectFill(dirtyRect); 20 | } 21 | 22 | - (void)hideWithFadeOut { 23 | [[NSAnimationContext currentContext] setDuration:0.7]; 24 | [self.animator setAlphaValue:0.0]; 25 | 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /SoundcloudPlayer/ClickableTableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ClickableTableView.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 29.07.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ClickableTableView : NSTableView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SoundcloudPlayer/ClickableTableView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ClickableTableView.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 29.07.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "ClickableTableView.h" 10 | 11 | @implementation ClickableTableView 12 | 13 | - (void)mouseDown:(NSEvent *)theEvent { 14 | [super mouseDown:theEvent]; 15 | if ([theEvent clickCount] == 1 ) { 16 | NSPoint selfPoint = [self convertPoint:theEvent.locationInWindow fromView:nil]; 17 | NSInteger row = [self rowAtPoint:selfPoint]; 18 | if (row>=0) [[self viewAtColumn:0 row:row makeIfNecessary:NO] 19 | mouseDown:theEvent]; 20 | } 21 | } 22 | 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /SoundcloudPlayer/ClickableTextField.h: -------------------------------------------------------------------------------- 1 | // 2 | // ClickableTextField.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 29.07.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ClickableTextField : NSTextField 12 | 13 | @property (nonatomic, strong) NSString *urlToOpen; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /SoundcloudPlayer/ClickableTextField.m: -------------------------------------------------------------------------------- 1 | // 2 | // ClickableTextField.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 29.07.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "ClickableTextField.h" 10 | 11 | @interface ClickableTextField () 12 | 13 | @property (nonatomic, strong) NSTrackingArea *trackingArea; 14 | 15 | @end 16 | 17 | @implementation ClickableTextField 18 | 19 | - (id)initWithCoder:(NSCoder *)aDecoder { 20 | self = [super initWithCoder:aDecoder]; 21 | if (self){ 22 | [self commonInit]; 23 | } 24 | return self; 25 | } 26 | 27 | - (id)initWithFrame:(NSRect)frameRect { 28 | self = [super initWithFrame:frameRect]; 29 | if (self){ 30 | [self commonInit]; 31 | } 32 | return self; 33 | } 34 | 35 | - (void)commonInit { 36 | [[NSCursor pointingHandCursor] set]; 37 | } 38 | 39 | - (void)mouseDown:(NSEvent *)theEvent { 40 | if (self.urlToOpen){ 41 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:_urlToOpen]]; 42 | } 43 | } 44 | 45 | - (void)mouseEntered:(NSEvent *)theEvent { 46 | if (self.urlToOpen) { 47 | [[NSCursor pointingHandCursor] set]; 48 | NSMutableAttributedString *str = [[self attributedStringValue] mutableCopy]; 49 | 50 | [str addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:NSUnderlineStyleSingle] range:NSMakeRange(0, str.length)]; 51 | 52 | [self setAttributedStringValue:str]; 53 | } 54 | } 55 | 56 | - (void)mouseExited:(NSEvent *)theEvent { 57 | if (self.urlToOpen) { 58 | [[NSCursor arrowCursor] set]; 59 | NSMutableAttributedString *str = [[self attributedStringValue] mutableCopy]; 60 | 61 | [str removeAttribute:NSUnderlineStyleAttributeName range:NSMakeRange(0, str.length)]; 62 | 63 | [self setAttributedStringValue:str]; 64 | } 65 | } 66 | 67 | - (void)updateTrackingAreas { 68 | [super updateTrackingAreas]; 69 | [self removeTrackingArea:_trackingArea]; 70 | _trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options: (NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow) owner:self userInfo:nil]; 71 | [self addTrackingArea:_trackingArea]; 72 | } 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /SoundcloudPlayer/ConnectButtonCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ConnectButtonCell.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 25.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ConnectButtonCell : NSButtonCell 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SoundcloudPlayer/ConnectButtonCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // ConnectButtonCell.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 25.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "ConnectButtonCell.h" 10 | #import "StreamCloudStyles.h" 11 | @implementation ConnectButtonCell 12 | 13 | - (void)drawBezelWithFrame:(NSRect)frame inView:(NSView *)controlView { 14 | [StreamCloudStyles drawLoginButtonWithFrame:frame]; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "beta-16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "beta-16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "beta-32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "beta-32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "beta-128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "beta-128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "beta-256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "beta-256@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "beta-512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "beta-512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-128.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-128@2x.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-16.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-16@2x.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-256.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-256@2x.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-32.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-32@2x.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-512.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon Beta.appiconset/beta-512@2x.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon128.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon128@2x.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon16.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon16@2x.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon256.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon256@2x.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon32.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon32@2x.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon512.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/AppIcon512@2x.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "AppIcon16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "AppIcon16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "AppIcon32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "AppIcon32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "AppIcon128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "AppIcon128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "AppIcon256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "AppIcon256@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "AppIcon512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "AppIcon512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/icon-lastfm.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "icon-lastfm.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x", 11 | "filename" : "icon-lastfm@2x.png" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/icon-lastfm.imageset/icon-lastfm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/icon-lastfm.imageset/icon-lastfm.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/icon-lastfm.imageset/icon-lastfm@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/icon-lastfm.imageset/icon-lastfm@2x.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/menuBarIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "menuBarIcon.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x", 11 | "filename" : "menuBarIcon@2x.png" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/menuBarIcon.imageset/menuBarIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/menuBarIcon.imageset/menuBarIcon.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/menuBarIcon.imageset/menuBarIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/menuBarIcon.imageset/menuBarIcon@2x.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/menuBarIcon_active.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "menuBarIcon_active.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x", 11 | "filename" : "menuBarIcon_active@2x.png" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/menuBarIcon_active.imageset/menuBarIcon_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/menuBarIcon_active.imageset/menuBarIcon_active.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/menuBarIcon_active.imageset/menuBarIcon_active@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/menuBarIcon_active.imageset/menuBarIcon_active@2x.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/plaetzchen.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "plaetzchen.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x", 11 | "filename" : "plaetzchen@2x.png" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/plaetzchen.imageset/plaetzchen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/plaetzchen.imageset/plaetzchen.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/plaetzchen.imageset/plaetzchen@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/plaetzchen.imageset/plaetzchen@2x.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/zutrinken.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "zutrinken.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x", 11 | "filename" : "zutrinken@2x.png" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/zutrinken.imageset/zutrinken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/zutrinken.imageset/zutrinken.png -------------------------------------------------------------------------------- /SoundcloudPlayer/Images.xcassets/zutrinken.imageset/zutrinken@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/Images.xcassets/zutrinken.imageset/zutrinken@2x.png -------------------------------------------------------------------------------- /SoundcloudPlayer/IsRepostedLabelView.h: -------------------------------------------------------------------------------- 1 | // 2 | // IsRepostedLabelView.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 16.01.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface IsRepostedLabelView : NSView 12 | 13 | @property (nonatomic, strong) NSString *reposterName; 14 | @end 15 | -------------------------------------------------------------------------------- /SoundcloudPlayer/IsRepostedLabelView.m: -------------------------------------------------------------------------------- 1 | // 2 | // IsRepostedLabelView.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 16.01.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "IsRepostedLabelView.h" 10 | #import "StreamCloudStyles.h" 11 | 12 | @implementation IsRepostedLabelView 13 | 14 | - (void)drawRect:(NSRect)dirtyRect { 15 | [StreamCloudStyles drawTrackIsRepostWithFrame:NSMakeRect(0.5, 1.5, 9, 9)]; 16 | 17 | NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; 18 | [paragraphStyle setLineBreakMode:NSLineBreakByTruncatingTail]; 19 | [self.reposterName drawInRect:NSMakeRect(13, -0.5, CGRectGetWidth(self.frame)-CGRectGetHeight(self.frame)-4, 15) withAttributes:@{NSFontAttributeName:[NSFont fontWithName:@"HelveticaNeue" size:10],NSForegroundColorAttributeName:[StreamCloudStyles grayMediumLight],NSParagraphStyleAttributeName:paragraphStyle}]; 20 | 21 | } 22 | 23 | - (void)setReposterName:(NSString *)reposterName { 24 | _reposterName = reposterName; 25 | [self setNeedsDisplay:YES]; 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /SoundcloudPlayer/LoadSpeakerOverlayView.h: -------------------------------------------------------------------------------- 1 | // 2 | // LoadSpeakerOverlayView.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 04.08.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LoadSpeakerOverlayView : NSView 12 | 13 | @property (nonatomic) BOOL showLargeIcon; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /SoundcloudPlayer/LoadSpeakerOverlayView.m: -------------------------------------------------------------------------------- 1 | // 2 | // LoadSpeakerOverlayView.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 04.08.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "LoadSpeakerOverlayView.h" 10 | #import "StreamCloudStyles.h" 11 | @implementation LoadSpeakerOverlayView 12 | 13 | - (void)setShowLargeIcon:(BOOL)showLargeIcon { 14 | _showLargeIcon = showLargeIcon; 15 | [self setNeedsDisplay:YES]; 16 | } 17 | 18 | - (void)drawRect:(NSRect)dirtyRect { 19 | [StreamCloudStyles drawPlayingOverlayWithFrame:self.frame]; 20 | } 21 | @end 22 | -------------------------------------------------------------------------------- /SoundcloudPlayer/LowerShadowView.h: -------------------------------------------------------------------------------- 1 | // 2 | // LowerShadowView.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 19.01.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LowerShadowView : NSView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SoundcloudPlayer/LowerShadowView.m: -------------------------------------------------------------------------------- 1 | // 2 | // LowerShadowView.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 19.01.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "LowerShadowView.h" 10 | #import "StreamCloudStyles.h" 11 | @implementation LowerShadowView 12 | 13 | - (void)drawRect:(NSRect)dirtyRect { 14 | [StreamCloudStyles drawPlaylistLowerShadowOverlayWithFrame:dirtyRect]; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /SoundcloudPlayer/MouseOverImageView.h: -------------------------------------------------------------------------------- 1 | // 2 | // MouseOverImageView.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 26.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SoundCloudTrack.h" 11 | #import "SoundCloudPlaylist.h" 12 | #import "PlayPauseOverlayView.h" 13 | #import "SharedAudioPlayer.h" 14 | #import "LoadSpeakerOverlayView.h" 15 | 16 | @interface MouseOverImageView : NSImageView 17 | 18 | @property (nonatomic) NSInteger row; 19 | @property (nonatomic) id objectToPlay; 20 | @property (nonatomic) BOOL showLargePlayPauseView; 21 | @property (nonatomic) BOOL playing; 22 | @property (nonatomic, strong) PlayPauseOverlayView *playPauseOverlayView; 23 | @property (nonatomic, strong) LoadSpeakerOverlayView *loadSpeakerOverlayView; 24 | 25 | - (void)cursorEntered; 26 | - (void)cursorExited; 27 | - (void)loadArtworkImageWithURL:(NSURL *)artworkURL; 28 | @end 29 | -------------------------------------------------------------------------------- /SoundcloudPlayer/MouseOverImageView.m: -------------------------------------------------------------------------------- 1 | // 2 | // MouseOverImageView.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 26.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "MouseOverImageView.h" 10 | #import "PlayPauseOverlayView.h" 11 | #import "SharedAudioPlayer.h" 12 | #import "LoadSpeakerOverlayView.h" 13 | #import "AFNetworking.h" 14 | #import "ArtworkOverlayView.h" 15 | 16 | @interface MouseOverImageView () 17 | 18 | @property (nonatomic, strong) NSTrackingArea *trackingArea; 19 | @property (nonatomic) BOOL mouseOver; 20 | 21 | @property (nonatomic, strong) ArtworkOverlayView *artworkOverlayView; 22 | 23 | @end 24 | 25 | @implementation MouseOverImageView 26 | 27 | - (id)initWithFrame:(NSRect)frame 28 | { 29 | self = [super initWithFrame:frame]; 30 | if (self) { 31 | [self commonInit]; 32 | } 33 | return self; 34 | } 35 | 36 | 37 | - (id)initWithCoder:(NSCoder *)aDecoder { 38 | self = [super initWithCoder:aDecoder]; 39 | if (self){ 40 | [self commonInit]; 41 | } 42 | return self; 43 | } 44 | 45 | - (void)commonInit { 46 | 47 | self.artworkOverlayView = [[ArtworkOverlayView alloc] initWithFrame:NSMakeRect(0, 0, self.frame.size.width, self.frame.size.height)]; 48 | [self addSubview:self.artworkOverlayView]; 49 | 50 | self.playPauseOverlayView = [[PlayPauseOverlayView alloc] initWithFrame:NSMakeRect(0, 0, self.frame.size.width, self.frame.size.height)]; 51 | [self.playPauseOverlayView setHidden:YES]; 52 | [self.playPauseOverlayView setRow:self.row]; 53 | [self addSubview:self.playPauseOverlayView]; 54 | 55 | self.loadSpeakerOverlayView = [[LoadSpeakerOverlayView alloc] initWithFrame:NSMakeRect(0, 0, self.frame.size.width, self.frame.size.height)]; 56 | [self.loadSpeakerOverlayView setHidden:YES]; 57 | [self addSubview:self.loadSpeakerOverlayView]; 58 | 59 | 60 | [self setWantsLayer: YES]; 61 | self.layer.cornerRadius = 2.0; 62 | self.layer.masksToBounds = YES; 63 | } 64 | 65 | - (void)drawRect:(NSRect)dirtyRect 66 | { 67 | [super drawRect:dirtyRect]; 68 | 69 | } 70 | 71 | - (void)setShowLargePlayPauseView:(BOOL)showLargePlayPauseView { 72 | _showLargePlayPauseView = showLargePlayPauseView; 73 | [self.playPauseOverlayView setShowLargeIcons:showLargePlayPauseView]; 74 | } 75 | 76 | - (void)dealloc { 77 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 78 | } 79 | 80 | # pragma mark - Setters 81 | 82 | - (void)setImage:(NSImage *)image { 83 | [super setImage:image]; 84 | if (!image){ 85 | [self.artworkOverlayView setHidden:NO]; 86 | [self.artworkOverlayView setAlphaValue:1.0]; 87 | } 88 | } 89 | 90 | 91 | - (void)setRow:(NSInteger)row { 92 | _row = row; 93 | [self.playPauseOverlayView setRow:row]; 94 | } 95 | 96 | - (void)setObjectToPlay:(NSDictionary *)objectToPlay { 97 | _objectToPlay = objectToPlay; 98 | [self.playPauseOverlayView setObjectToShow:objectToPlay]; 99 | } 100 | 101 | - (void)setPlaying:(BOOL)playing { 102 | _playing = playing; 103 | [self.loadSpeakerOverlayView setHidden:!playing]; 104 | [self.playPauseOverlayView setHidden:YES]; 105 | } 106 | 107 | # pragma mark - Loading Artwork 108 | 109 | - (void)loadArtworkImageWithURL:(NSURL *)artworkURL { 110 | if (artworkURL){ 111 | AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; 112 | manager.responseSerializer = [AFImageResponseSerializer serializer]; 113 | [manager GET:artworkURL.absoluteString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { 114 | [self setImage:responseObject]; 115 | [self.artworkOverlayView hideWithFadeOut]; 116 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 117 | NSLog(@"Failed to get image %@",error); 118 | }]; 119 | } 120 | } 121 | 122 | # pragma mark - Mouse Handling 123 | 124 | - (void)cursorEntered { 125 | self.mouseOver = YES; 126 | [self.playPauseOverlayView setHidden:NO]; 127 | [self.loadSpeakerOverlayView setHidden:YES]; 128 | [self.playPauseOverlayView setNeedsDisplay:YES]; 129 | } 130 | 131 | - (void)cursorExited { 132 | self.mouseOver = NO; 133 | [self.playPauseOverlayView setHidden:YES]; 134 | [self setPlaying:_playing]; 135 | } 136 | 137 | - (void)mouseDown:(NSEvent *)theEvent { 138 | if (self.objectToPlay == [[SharedAudioPlayer sharedPlayer] currentItem]) 139 | [[SharedAudioPlayer sharedPlayer] togglePlayPause]; 140 | else if ([[[SharedAudioPlayer sharedPlayer] streamItemsToShowInTableView]indexOfObject:[[[SharedAudioPlayer sharedPlayer]currentItem] playlistTrackIsFrom]] == self.row) 141 | [[SharedAudioPlayer sharedPlayer] togglePlayPause]; 142 | else { 143 | if ([[SharedAudioPlayer sharedPlayer].streamItemsToShowInTableView containsObject:self.objectToPlay] && [SharedAudioPlayer sharedPlayer].sourceType != CurrentSourceTypeStream){ 144 | [[SharedAudioPlayer sharedPlayer] switchToStream]; 145 | } else if ([[SharedAudioPlayer sharedPlayer].favoriteItemsToShowInTableView containsObject:self.objectToPlay] && [SharedAudioPlayer sharedPlayer].sourceType != CurrentSourceTypeFavorites) { 146 | [[SharedAudioPlayer sharedPlayer] switchToFavorites]; 147 | } 148 | 149 | NSInteger clickedRow = self.row; 150 | id clickedItem = self.objectToPlay; 151 | if ([SharedAudioPlayer sharedPlayer].sourceType == CurrentSourceTypeStream) { 152 | if ([clickedItem isKindOfClass:[SoundCloudPlaylist class]]){ 153 | clickedItem = [[[SharedAudioPlayer sharedPlayer] streamItemsToShowInTableView] objectAtIndex:clickedRow+1]; 154 | } 155 | 156 | NSInteger objectToPlay = [[[SharedAudioPlayer sharedPlayer] streamItemsToShowInTableView] indexOfObject:clickedItem]; 157 | [[SharedAudioPlayer sharedPlayer] jumpToItemAtIndex:objectToPlay]; 158 | } else if ([SharedAudioPlayer sharedPlayer].sourceType == CurrentSourceTypeFavorites) { 159 | if ([clickedItem isKindOfClass:[SoundCloudPlaylist class]]){ 160 | clickedItem = [[[SharedAudioPlayer sharedPlayer] favoriteItemsToShowInTableView] objectAtIndex:clickedRow+1]; 161 | } 162 | 163 | NSInteger objectToPlay = [[[SharedAudioPlayer sharedPlayer] favoriteItemsToShowInTableView] indexOfObject:clickedItem]; 164 | [[SharedAudioPlayer sharedPlayer] jumpToItemAtIndex:objectToPlay]; 165 | 166 | } 167 | [self.playPauseOverlayView setHidden:YES]; 168 | } 169 | [self.playPauseOverlayView setNeedsDisplay:YES]; 170 | } 171 | 172 | 173 | @end 174 | -------------------------------------------------------------------------------- /SoundcloudPlayer/NSImage+RoundedCorners.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSImage+RoundedCorners.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 04.08.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSImage (RoundedCorners) 12 | 13 | - (NSImage *)roundCornersImageCornerRadius:(NSInteger)radius; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /SoundcloudPlayer/NSImage+RoundedCorners.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSImage+RoundedCorners.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 04.08.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "NSImage+RoundedCorners.h" 10 | 11 | @implementation NSImage (RoundedCorners) 12 | 13 | 14 | void addRoundedRectToPath(CGContextRef context, CGRect rect, float ovalWidth, float ovalHeight) 15 | { 16 | float fw, fh; 17 | if (ovalWidth == 0 || ovalHeight == 0) { 18 | CGContextAddRect(context, rect); 19 | return; 20 | } 21 | CGContextSaveGState(context); 22 | CGContextTranslateCTM (context, CGRectGetMinX(rect), CGRectGetMinY(rect)); 23 | CGContextScaleCTM (context, ovalWidth, ovalHeight); 24 | fw = CGRectGetWidth (rect) / ovalWidth; 25 | fh = CGRectGetHeight (rect) / ovalHeight; 26 | CGContextMoveToPoint(context, fw, fh/2); 27 | CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1); 28 | CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1); 29 | CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1); 30 | CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1); 31 | CGContextClosePath(context); 32 | CGContextRestoreGState(context); 33 | } 34 | 35 | - (NSImage *)roundCornersImageCornerRadius:(NSInteger)radius { 36 | int w = (int) self.size.width; 37 | int h = (int) self.size.height; 38 | 39 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 40 | CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst); 41 | 42 | CGContextBeginPath(context); 43 | CGRect rect = CGRectMake(0, 0, w, h); 44 | addRoundedRectToPath(context, rect, radius, radius); 45 | CGContextClosePath(context); 46 | CGContextClip(context); 47 | 48 | CGImageRef cgImage = [[NSBitmapImageRep imageRepWithData:[self TIFFRepresentation]] CGImage]; 49 | 50 | CGContextDrawImage(context, CGRectMake(0, 0, w, h), cgImage); 51 | 52 | CGImageRef imageMasked = CGBitmapContextCreateImage(context); 53 | CGContextRelease(context); 54 | CGColorSpaceRelease(colorSpace); 55 | 56 | NSImage *tmpImage = [[NSImage alloc] initWithCGImage:imageMasked size:self.size]; 57 | NSData *imageData = [tmpImage TIFFRepresentation]; 58 | NSImage *image = [[NSImage alloc] initWithData:imageData]; 59 | 60 | return image; 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /SoundcloudPlayer/NextButtonCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // NextButtonCell.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 23.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NextButtonCell : NSButtonCell 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SoundcloudPlayer/NextButtonCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // NextButtonCell.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 23.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "NextButtonCell.h" 10 | #import "StreamCloudStyles.h" 11 | @implementation NextButtonCell 12 | 13 | - (void)drawBezelWithFrame:(NSRect)frame inView:(NSView *)controlView { 14 | [StreamCloudStyles drawNextButtonWithFrame:frame]; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Headers: -------------------------------------------------------------------------------- 1 | Versions/Current/Headers -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/OAuth2Client: -------------------------------------------------------------------------------- 1 | Versions/Current/OAuth2Client -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Resources: -------------------------------------------------------------------------------- 1 | Versions/Current/Resources -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/Headers/NSData+NXOAuth2.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+NXOAuth2.h 3 | // OAuth2Client 4 | // 5 | // Created by Thomas Kollbach on 18.05.11 6 | // 7 | // Copyright 2011 nxtbgthng. All rights reserved. 8 | // 9 | // Licenced under the new BSD-licence. 10 | // See README.md in this repository for 11 | // the full licence. 12 | // 13 | 14 | #import 15 | 16 | 17 | @interface NSData (NXOAuth2) 18 | 19 | 20 | #pragma mark Digest 21 | 22 | - (NSData *)nx_SHA1Digest; 23 | - (NSString *)nx_SHA1Hexdigest; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/Headers/NSString+NXOAuth2.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+NXOAuth2.h 3 | // OAuth2Client 4 | // 5 | // Created by Ullrich Schäfer on 07.10.09. 6 | // 7 | // Copyright 2010 nxtbgthng. All rights reserved. 8 | // 9 | // Licenced under the new BSD-licence. 10 | // See README.md in this repository for 11 | // the full licence. 12 | // 13 | 14 | #import 15 | 16 | 17 | @interface NSString (NXOAuth2) 18 | 19 | + (NSString *)nxoauth2_stringWithUUID; 20 | 21 | + (NSString *)nxoauth2_stringWithEncodedQueryParameters:(NSDictionary *)parameters; 22 | - (NSDictionary *)nxoauth2_parametersFromEncodedQueryString; 23 | 24 | - (NSString *)nxoauth2_URLEncodedString; 25 | - (NSString *)nxoauth2_URLDecodedString; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/Headers/NSURL+NXOAuth2.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSURL+NXOAuth2.h 3 | // OAuth2Client 4 | // 5 | // Created by Ullrich Schäfer on 07.10.09. 6 | // 7 | // Copyright 2010 nxtbgthng. All rights reserved. 8 | // 9 | // Licenced under the new BSD-licence. 10 | // See README.md in this repository for 11 | // the full licence. 12 | // 13 | 14 | #import 15 | 16 | @interface NSURL (NXOAuth2) 17 | 18 | - (NSURL *)nxoauth2_URLByAddingParameters:(NSDictionary *)parameters; 19 | 20 | /*! 21 | * returns the value of the first parameter on the query string that matches the key 22 | * returns nil if key was not found 23 | */ 24 | - (NSString *)nxoauth2_valueForQueryParameterKey:(NSString *)key; 25 | 26 | - (NSURL *)nxoauth2_URLWithoutQueryString; 27 | - (NSString *)nxoauth2_URLStringWithoutQueryString; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/Headers/NXOAuth2.h: -------------------------------------------------------------------------------- 1 | // 2 | // NXOAuth2.h 3 | // OAuth2Client 4 | // 5 | // Created by Ullrich Schäfer on 13.09.10. 6 | // 7 | // Copyright 2010 nxtbgthng. All rights reserved. 8 | // 9 | // Licenced under the new BSD-licence. 10 | // See README.md in this repository for 11 | // the full licence. 12 | // 13 | 14 | #import "NXOAuth2Client.h" 15 | #import "NXOAuth2ClientDelegate.h" 16 | #import "NXOAuth2AccessToken.h" 17 | #import "NXOAuth2Connection.h" 18 | #import "NXOAuth2ConnectionDelegate.h" 19 | #import "NXOAuth2TrustDelegate.h" 20 | #import "NXOAuth2Constants.h" 21 | #import "NXOAuth2FileStreamWrapper.h" 22 | #import "NXOAuth2PostBodyStream.h" 23 | #import "NXOAuth2AccountStore.h" 24 | #import "NXOAuth2Account.h" 25 | #import "NXOAuth2Request.h" 26 | 27 | #pragma mark Helpers 28 | 29 | #import "NSURL+NXOAuth2.h" 30 | #import "NSString+NXOAuth2.h" 31 | #import "NSData+NXOAuth2.h" 32 | -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/Headers/NXOAuth2AccessToken.h: -------------------------------------------------------------------------------- 1 | // 2 | // NXOAuth2AccessToken.h 3 | // OAuth2Client 4 | // 5 | // Created by Ullrich Schäfer on 27.08.10. 6 | // 7 | // Copyright 2010 nxtbgthng. All rights reserved. 8 | // 9 | // Licenced under the new BSD-licence. 10 | // See README.md in this repository for 11 | // the full licence. 12 | // 13 | 14 | #import 15 | #import 16 | 17 | 18 | @interface NXOAuth2AccessToken : NSObject { 19 | @private 20 | NSString *accessToken; 21 | NSString *refreshToken; 22 | NSString *tokenType; 23 | NSDate *expiresAt; 24 | NSSet *scope; 25 | NSString *responseBody; 26 | } 27 | @property (nonatomic, readonly) NSString *accessToken; 28 | @property (nonatomic, readonly) NSString *refreshToken; 29 | @property (nonatomic, readonly) NSString *tokenType; 30 | @property (nonatomic, readonly) NSDate *expiresAt; 31 | @property (nonatomic, readonly) BOOL doesExpire; 32 | @property (nonatomic, readonly) BOOL hasExpired; 33 | @property (nonatomic, readonly) NSSet *scope; 34 | @property (nonatomic, readonly) NSString *responseBody; 35 | 36 | + (id)tokenWithResponseBody:(NSString *)responseBody; 37 | + (id)tokenWithResponseBody:(NSString *)responseBody tokenType:(NSString *)tokenType; 38 | 39 | - (id)initWithAccessToken:(NSString *)accessToken; 40 | - (id)initWithAccessToken:(NSString *)accessToken refreshToken:(NSString *)refreshToken expiresAt:(NSDate *)expiryDate; 41 | - (id)initWithAccessToken:(NSString *)accessToken refreshToken:(NSString *)refreshToken expiresAt:(NSDate *)expiryDate scope:(NSSet *)scope; 42 | - (id)initWithAccessToken:(NSString *)accessToken refreshToken:(NSString *)refreshToken expiresAt:(NSDate *)expiryDate scope:(NSSet *)scope responseBody:(NSString *)responseBody; 43 | - (id)initWithAccessToken:(NSString *)accessToken refreshToken:(NSString *)refreshToken expiresAt:(NSDate *)expiryDate scope:(NSSet *)scope responseBody:(NSString *)responseBody tokenType:(NSString*)tokenType; // designated 44 | 45 | - (void)restoreWithOldToken:(NXOAuth2AccessToken *)oldToken; 46 | 47 | #pragma mark Keychain Support 48 | 49 | //TODO: Support alternate KeyChain Locations 50 | 51 | + (id)tokenFromDefaultKeychainWithServiceProviderName:(NSString *)provider; 52 | - (void)storeInDefaultKeychainWithServiceProviderName:(NSString *)provider; 53 | - (void)removeFromDefaultKeychainWithServiceProviderName:(NSString *)provider; 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/Headers/NXOAuth2Account.h: -------------------------------------------------------------------------------- 1 | // 2 | // NXOAuth2Account.h 3 | // OAuth2Client 4 | // 5 | // Created by Tobias Kräntzer on 12.07.11. 6 | // 7 | // Copyright 2011 nxtbgthng. All rights reserved. 8 | // 9 | // Licenced under the new BSD-licence. 10 | // See README.md in this repository for 11 | // the full licence. 12 | // 13 | 14 | #import 15 | 16 | @class NXOAuth2Client; 17 | @class NXOAuth2AccessToken; 18 | 19 | #pragma mark Notifications 20 | 21 | extern NSString * const NXOAuth2AccountDidChangeUserDataNotification; 22 | extern NSString * const NXOAuth2AccountDidChangeAccessTokenNotification; 23 | extern NSString * const NXOAuth2AccountDidLoseAccessTokenNotification; 24 | extern NSString * const NXOAuth2AccountDidFailToGetAccessTokenNotification; 25 | 26 | #pragma mark - 27 | 28 | @interface NXOAuth2Account : NSObject { 29 | @private 30 | NSString *accountType; 31 | NSString *identifier; 32 | id userData; 33 | NXOAuth2Client *oauthClient; 34 | NXOAuth2AccessToken *accessToken; 35 | } 36 | 37 | #pragma mark Accessors 38 | 39 | @property (nonatomic, copy, readonly) NSString *accountType; 40 | @property (nonatomic, copy, readonly) NSString *identifier; 41 | @property (nonatomic, copy) id userData; 42 | 43 | @property (nonatomic, strong, readonly) NXOAuth2Client *oauthClient; 44 | @property (nonatomic, strong, readonly) NXOAuth2AccessToken *accessToken; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/Headers/NXOAuth2AccountStore.h: -------------------------------------------------------------------------------- 1 | // 2 | // NXOAuth2AccountStore.h 3 | // OAuth2Client 4 | // 5 | // Created by Tobias Kräntzer on 12.07.11. 6 | // 7 | // Copyright 2011 nxtbgthng. All rights reserved. 8 | // 9 | // Licenced under the new BSD-licence. 10 | // See README.md in this repository for 11 | // the full licence. 12 | // 13 | 14 | #import 15 | 16 | #import "NXOAuth2TrustDelegate.h" 17 | 18 | @class NXOAuth2Account; 19 | @class NXOAuth2Connection; 20 | 21 | #pragma mark Notifications 22 | 23 | extern NSString * const NXOAuth2AccountStoreDidFailToRequestAccessNotification; 24 | extern NSString * const NXOAuth2AccountStoreAccountsDidChangeNotification; 25 | 26 | extern NSString * const NXOAuth2AccountStoreNewAccountUserInfoKey; 27 | 28 | #pragma mark Configuration 29 | 30 | extern NSString * const kNXOAuth2AccountStoreConfigurationClientID; 31 | extern NSString * const kNXOAuth2AccountStoreConfigurationSecret; 32 | extern NSString * const kNXOAuth2AccountStoreConfigurationAuthorizeURL; 33 | extern NSString * const kNXOAuth2AccountStoreConfigurationTokenURL; 34 | extern NSString * const kNXOAuth2AccountStoreConfigurationRedirectURL; 35 | extern NSString * const kNXOAuth2AccountStoreConfigurationScope; 36 | extern NSString * const kNXOAuth2AccountStoreConfigurationTokenType; 37 | extern NSString * const kNXOAuth2AccountStoreConfigurationTokenRequestHTTPMethod; 38 | 39 | 40 | /* 41 | * Requires a NSDictionary as a value. 42 | * They are passed onto the authentication request as additional query parameters. 43 | * The dictionary may not contain the keys "grant_type", "client_id", "client_secret", 44 | * "username", "password", "redirect_uri", "code", "assertion_type" and "assertion" are not allowed. 45 | */ 46 | extern NSString * const kNXOAuth2AccountStoreConfigurationAdditionalAuthenticationParameters; 47 | 48 | 49 | #pragma mark Account Type 50 | 51 | extern NSString * const kNXOAuth2AccountStoreAccountType; 52 | 53 | 54 | #pragma mark Handler 55 | 56 | typedef NXOAuth2TrustMode(^NXOAuth2TrustModeHandler)(NXOAuth2Connection *connection, NSString *hostname); 57 | typedef NSArray *(^NXOAuth2TrustedCertificatesHandler)(NSString *hostname); 58 | typedef void(^NXOAuth2PreparedAuthorizationURLHandler)(NSURL *preparedURL); 59 | 60 | 61 | #pragma mark - 62 | 63 | @interface NXOAuth2AccountStore : NSObject { 64 | @private 65 | NSMutableDictionary *pendingOAuthClients; 66 | NSMutableDictionary *accountsDict; 67 | NSMutableDictionary *configurations; 68 | NSMutableDictionary *trustModeHandler; 69 | NSMutableDictionary *trustedCertificatesHandler; 70 | } 71 | 72 | + (id)sharedStore; 73 | 74 | #pragma mark Accessors 75 | 76 | @property(nonatomic, strong, readonly) NSArray *accounts; 77 | - (NSArray *)accountsWithAccountType:(NSString *)accountType; 78 | - (NXOAuth2Account *)accountWithIdentifier:(NSString *)identifier; 79 | 80 | 81 | #pragma mark Configuration 82 | 83 | - (void)setClientID:(NSString *)aClientID 84 | secret:(NSString *)aSecret 85 | authorizationURL:(NSURL *)anAuthorizationURL 86 | tokenURL:(NSURL *)aTokenURL 87 | redirectURL:(NSURL *)aRedirectURL 88 | forAccountType:(NSString *)anAccountType; 89 | 90 | - (void)setClientID:(NSString *)aClientID 91 | secret:(NSString *)aSecret 92 | scope:(NSSet *)theScope 93 | authorizationURL:(NSURL *)anAuthorizationURL 94 | tokenURL:(NSURL *)aTokenURL 95 | redirectURL:(NSURL *)aRedirectURL 96 | keyChainGroup:(NSString *)aKeyChainGroup 97 | forAccountType:(NSString *)anAccountType; 98 | 99 | - (void)setClientID:(NSString *)aClientID 100 | secret:(NSString *)aSecret 101 | scope:(NSSet *)theScope 102 | authorizationURL:(NSURL *)anAuthorizationURL 103 | tokenURL:(NSURL *)aTokenURL 104 | redirectURL:(NSURL *)aRedirectURL 105 | keyChainGroup:(NSString *)aKeyChainGroup 106 | tokenType:(NSString *)aTokenType 107 | forAccountType:(NSString *)anAccountType; 108 | 109 | - (void)setConfiguration:(NSDictionary *)configuration forAccountType:(NSString *)accountType; 110 | 111 | - (NSDictionary *)configurationForAccountType:(NSString *)accountType; 112 | 113 | 114 | #pragma Trust Mode Handler 115 | 116 | - (void)setTrustModeHandlerForAccountType:(NSString *)accountType block:(NXOAuth2TrustModeHandler)handler; 117 | - (NXOAuth2TrustModeHandler)trustModeHandlerForAccountType:(NSString *)accountType; 118 | 119 | - (void)setTrustedCertificatesHandlerForAccountType:(NSString *)accountType block:(NXOAuth2TrustedCertificatesHandler)handler; 120 | - (NXOAuth2TrustedCertificatesHandler)trustedCertificatesHandlerForAccountType:(NSString *)accountType; 121 | 122 | 123 | #pragma mark Manage Accounts 124 | 125 | - (void)requestAccessToAccountWithType:(NSString *)accountType; 126 | - (void)requestAccessToAccountWithType:(NSString *)accountType withPreparedAuthorizationURLHandler:(NXOAuth2PreparedAuthorizationURLHandler)aPreparedAuthorizationURLHandler; 127 | - (void)requestAccessToAccountWithType:(NSString *)accountType username:(NSString *)username password:(NSString *)password; 128 | - (void)requestAccessToAccountWithType:(NSString *)accountType assertionType:(NSURL *)assertionType assertion:(NSString *)assertion; 129 | - (void)requestClientCredentialsAccessWithType:(NSString *)accountType; 130 | - (void)addAccount:(NXOAuth2Account *)account; 131 | - (void)removeAccount:(NXOAuth2Account *)account; 132 | 133 | 134 | #pragma mark Handle OAuth Redirects 135 | 136 | - (BOOL)handleRedirectURL:(NSURL *)URL; 137 | 138 | @end 139 | -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/Headers/NXOAuth2Client.h: -------------------------------------------------------------------------------- 1 | // 2 | // NXOAuth2Client.h 3 | // OAuth2Client 4 | // 5 | // Created by Ullrich Schäfer on 27.08.10. 6 | // 7 | // Copyright 2010 nxtbgthng. All rights reserved. 8 | // 9 | // Licenced under the new BSD-licence. 10 | // See README.md in this repository for 11 | // the full licence. 12 | // 13 | 14 | #import 15 | 16 | #import "NXOAuth2ClientDelegate.h" 17 | #import "NXOAuth2ConnectionDelegate.h" 18 | 19 | extern NSString * const NXOAuth2ClientConnectionContextTokenRequest; 20 | extern NSString * const NXOAuth2ClientConnectionContextTokenRefresh; 21 | 22 | @class NXOAuth2Connection, NXOAuth2AccessToken; 23 | 24 | /*! 25 | * The OAuth 2.0 client 26 | * Only supports WebServer & Password flow at the moment 27 | * 28 | * - oauth2 draft 10 http://tools.ietf.org/html/draft-ietf-oauth-v2-10 29 | * - not thread save 30 | */ 31 | 32 | //TODO: Link to documentation 33 | 34 | @interface NXOAuth2Client : NSObject { 35 | @protected 36 | BOOL authenticating; 37 | BOOL persistent; 38 | 39 | NSString *clientId; 40 | NSString *clientSecret; 41 | 42 | NSSet *desiredScope; 43 | NSString *userAgent; 44 | NSString *assertion; 45 | NSString *keyChainGroup; 46 | 47 | // server information 48 | NSURL *authorizeURL; 49 | NSURL *tokenURL; 50 | NSString *tokenType; 51 | 52 | // token exchange 53 | NXOAuth2Connection *authConnection; 54 | NXOAuth2AccessToken *accessToken; 55 | NSMutableArray *waitingConnections; //for connections that are waiting for successful authorisation 56 | NSInteger refreshConnectionDidRetryCount; 57 | 58 | // delegates 59 | NSObject* __unsafe_unretained delegate; // assigned 60 | } 61 | 62 | @property (nonatomic, readonly, getter = isAuthenticating) BOOL authenticating; 63 | 64 | @property (nonatomic, copy, readonly) NSString *clientId; 65 | @property (nonatomic, copy, readonly) NSString *clientSecret; 66 | @property (nonatomic, copy, readonly) NSString *tokenType; 67 | @property (nonatomic, strong, readwrite) NSDictionary *additionalAuthenticationParameters; 68 | 69 | @property (nonatomic, copy) NSSet *desiredScope; 70 | @property (nonatomic, copy) NSString *tokenRequestHTTPMethod; // defaults to POST 71 | @property (nonatomic, copy) NSString *userAgent; 72 | @property (nonatomic, copy) NSString *acceptType; // defaults to application/json 73 | 74 | @property (nonatomic, strong) NXOAuth2AccessToken *accessToken; 75 | @property (nonatomic, unsafe_unretained) NSObject* delegate; 76 | 77 | 78 | /*! 79 | * If set to NO, the access token is not stored any keychain, will be removed if it was. 80 | * Defaults to YES 81 | */ 82 | @property (nonatomic, assign, readwrite, getter=isPersistent) BOOL persistent; 83 | 84 | /*! 85 | * Initializes the Client 86 | */ 87 | - (id)initWithClientID:(NSString *)clientId 88 | clientSecret:(NSString *)clientSecret 89 | authorizeURL:(NSURL *)authorizeURL 90 | tokenURL:(NSURL *)tokenURL 91 | delegate:(NSObject *)delegate; 92 | 93 | - (id)initWithClientID:(NSString *)clientId 94 | clientSecret:(NSString *)clientSecret 95 | authorizeURL:(NSURL *)authorizeURL 96 | tokenURL:(NSURL *)tokenURL 97 | accessToken:(NXOAuth2AccessToken *)accessToken 98 | keyChainGroup:(NSString *)keyChainGroup 99 | persistent:(BOOL)shouldPersist 100 | delegate:(NSObject *)delegate; 101 | 102 | - (id)initWithClientID:(NSString *)clientId 103 | clientSecret:(NSString *)clientSecret 104 | authorizeURL:(NSURL *)authorizeURL 105 | tokenURL:(NSURL *)tokenURL 106 | accessToken:(NXOAuth2AccessToken *)accessToken 107 | tokenType:(NSString *)tokenType 108 | keyChainGroup:(NSString *)keyChainGroup 109 | persistent:(BOOL)shouldPersist 110 | delegate:(NSObject *)delegate; 111 | 112 | - (BOOL)openRedirectURL:(NSURL *)URL; 113 | 114 | 115 | #pragma mark Authorisation Methods 116 | 117 | /*---------------------------------* 118 | * Use ONE of the following flows: * 119 | *---------------------------------*/ 120 | 121 | /*! 122 | * Authenticate usind a web URL (Web Server Flow) 123 | * returns the URL to be opened to get access grant 124 | */ 125 | - (NSURL *)authorizationURLWithRedirectURL:(NSURL *)redirectURL; 126 | 127 | /*! 128 | * Authenticate with username & password (User Credentials Flow) 129 | */ 130 | - (void)authenticateWithClientCredentials; 131 | - (void)authenticateWithUsername:(NSString *)username password:(NSString *)password; 132 | 133 | /*! 134 | * Authenticate with assertion (Assertion Flow) 135 | */ 136 | - (void)authenticateWithAssertionType:(NSURL *)assertionType assertion:(NSString *)assertion; 137 | 138 | 139 | #pragma mark Public 140 | 141 | - (void)requestAccess; 142 | 143 | - (void)refreshAccessToken; 144 | - (void)refreshAccessTokenAndRetryConnection:(NXOAuth2Connection *)retryConnection; 145 | 146 | @end -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/Headers/NXOAuth2ClientDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // NXOAuth2ClientDelegate.h 3 | // OAuth2Client 4 | // 5 | // Created by Gernot Poetsch on 14.09.10. 6 | // 7 | // Copyright 2010 nxtbgthng. All rights reserved. 8 | // 9 | // Licenced under the new BSD-licence. 10 | // See README.md in this repository for 11 | // the full licence. 12 | // 13 | 14 | #import "NXOAuth2Constants.h" 15 | #import "NXOAuth2TrustDelegate.h" 16 | 17 | @class NXOAuth2Client; 18 | 19 | @protocol NXOAuth2ClientDelegate 20 | 21 | @required 22 | /*! 23 | * When this is called on the delegate, you are supposed to invoke the appropriate authentication method in the client. 24 | */ 25 | - (void)oauthClientNeedsAuthentication:(NXOAuth2Client *)client; 26 | 27 | @optional 28 | - (void)oauthClientDidGetAccessToken:(NXOAuth2Client *)client; 29 | - (void)oauthClientDidLoseAccessToken:(NXOAuth2Client *)client; 30 | - (void)oauthClientDidRefreshAccessToken:(NXOAuth2Client *)client; 31 | - (void)oauthClient:(NXOAuth2Client *)client didFailToGetAccessTokenWithError:(NSError *)error; 32 | 33 | @end -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/Headers/NXOAuth2Connection.h: -------------------------------------------------------------------------------- 1 | // 2 | // NXOAuth2Connection.h 3 | // OAuth2Client 4 | // 5 | // Created by Ullrich Schäfer on 27.08.10. 6 | // 7 | // Copyright 2010 nxtbgthng. All rights reserved. 8 | // 9 | // Licenced under the new BSD-licence. 10 | // See README.md in this repository for 11 | // the full licence. 12 | // 13 | 14 | #import 15 | 16 | #import "NXOAuth2Constants.h" 17 | 18 | @class NXOAuth2Client; 19 | @protocol NXOAuth2ConnectionDelegate; 20 | 21 | 22 | /*! 23 | * The connection 24 | * 25 | * NXOAuth2Connection is a wrapper around NXURLConnection. 26 | * It's main purpose is to simplify the delegates & to provide a context 27 | * ivar that can be used to put a connection object in a certain context. 28 | * The context may be compared to a tag. 29 | * 30 | * NXOAuth2Connection only provides asynchronous connections as synchronous 31 | * connections are strongly discouraged. 32 | * 33 | * The connection works together with the OAuth2 Client to sign a request 34 | * before sending it. If no client is passed in the connection will sent 35 | * unsigned requests. 36 | */ 37 | 38 | 39 | #ifndef NXOAuth2ConnectionDebug 40 | #define NXOAuth2ConnectionDebug 0 41 | #endif 42 | 43 | 44 | 45 | extern NSString * const NXOAuth2ConnectionDidStartNotification; 46 | extern NSString * const NXOAuth2ConnectionDidEndNotification; 47 | 48 | 49 | typedef void(^NXOAuth2ConnectionResponseHandler)(NSURLResponse *response, NSData *responseData, NSError *error); 50 | typedef void(^NXOAuth2ConnectionSendingProgressHandler)(unsigned long long bytesSend, unsigned long long bytesTotal); 51 | 52 | 53 | @interface NXOAuth2Connection : NSObject { 54 | @private 55 | NSURLConnection *connection; 56 | NSMutableURLRequest *request; 57 | NSURLResponse *response; 58 | NSDictionary *requestParameters; 59 | 60 | NSMutableData *data; 61 | BOOL savesData; 62 | 63 | id context; 64 | NSDictionary *userInfo; 65 | 66 | NXOAuth2Client *client; 67 | 68 | NSObject *__unsafe_unretained delegate; // assigned 69 | 70 | NXOAuth2ConnectionResponseHandler responseHandler; 71 | NXOAuth2ConnectionSendingProgressHandler sendingProgressHandler; 72 | 73 | BOOL sendConnectionDidEndNotification; 74 | 75 | #if (NXOAuth2ConnectionDebug) 76 | NSDate *startDate; 77 | #endif 78 | } 79 | 80 | @property (nonatomic, unsafe_unretained) NSObject *delegate; 81 | @property (nonatomic, strong, readonly) NSData *data; 82 | @property (nonatomic, assign) BOOL savesData; 83 | @property (nonatomic, assign, readonly) long long expectedContentLength; 84 | @property (nonatomic, strong, readonly) NSURLResponse *response; 85 | @property (nonatomic, assign, readonly) NSInteger statusCode; 86 | @property (nonatomic, strong) id context; 87 | @property (nonatomic, strong) NSDictionary *userInfo; 88 | @property (nonatomic, strong, readonly) NXOAuth2Client *client; 89 | 90 | - (id) initWithRequest:(NSMutableURLRequest *)request 91 | requestParameters:(NSDictionary *)requestParameters 92 | oauthClient:(NXOAuth2Client *)client 93 | sendingProgressHandler:(NXOAuth2ConnectionSendingProgressHandler)sendingProgressHandler 94 | responseHandler:(NXOAuth2ConnectionResponseHandler)responseHandler; 95 | 96 | - (id)initWithRequest:(NSMutableURLRequest *)request 97 | requestParameters:(NSDictionary *)requestParameters 98 | oauthClient:(NXOAuth2Client *)client 99 | delegate:(NSObject *)delegate; 100 | 101 | - (void)cancel; 102 | 103 | - (void)retry; 104 | 105 | @end 106 | -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/Headers/NXOAuth2ConnectionDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // NXOAuth2ConnectionDelegate.h 3 | // OAuth2Client 4 | // 5 | // Created by Ullrich Schäfer on 27.08.10. 6 | // 7 | // Copyright 2010 nxtbgthng. All rights reserved. 8 | // 9 | // Licenced under the new BSD-licence. 10 | // See README.md in this repository for 11 | // the full licence. 12 | // 13 | 14 | #import "NXOAuth2Constants.h" 15 | #import "NXOAuth2TrustDelegate.h" 16 | 17 | @class NXOAuth2Connection; 18 | 19 | 20 | @protocol NXOAuth2ConnectionDelegate 21 | @optional 22 | 23 | /*! 24 | * The connection did receive a response. 25 | * 26 | * This method is not called if the response was a 401 with an expired token & a refresh token. 27 | * If so, then the token is refreshed & the connection will be automagically retried. 28 | */ 29 | - (void)oauthConnection:(NXOAuth2Connection *)connection didReceiveResponse:(NSURLResponse *)response; 30 | 31 | /*! 32 | * The connection did finish and recieved the whole data. 33 | */ 34 | - (void)oauthConnection:(NXOAuth2Connection *)connection didFinishWithData:(NSData *)data; 35 | 36 | /*! 37 | * The connection did fail with an error 38 | * 39 | * The domain of the error is NXOAuth2ErrorDomain. 40 | * Check the error code to see if it's been an HTTP error (NXOAuth2HTTPErrorCode). If so you can get the original error from the userInfo with the key NXOAuth2HTTPErrorKey 41 | */ 42 | - (void)oauthConnection:(NXOAuth2Connection *)connection didFailWithError:(NSError *)error; 43 | 44 | /*! 45 | * The connection recieved a new chunk of bytes. 46 | * 47 | * Note: use connection.data.length and connection.expectedContentLength to get the overall progress 48 | */ 49 | - (void)oauthConnection:(NXOAuth2Connection *)connection didReceiveData:(NSData *)data; 50 | 51 | /*! 52 | * The connection did send new data 53 | */ 54 | - (void)oauthConnection:(NXOAuth2Connection *)connection didSendBytes:(unsigned long long)bytesSend ofTotal:(unsigned long long)bytesTotal; 55 | 56 | /*! 57 | * The connection received a redirect response 58 | */ 59 | - (void)oauthConnection:(NXOAuth2Connection *)connection didReceiveRedirectToURL:(NSURL *)redirectURL; 60 | 61 | 62 | @end -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/Headers/NXOAuth2Constants.h: -------------------------------------------------------------------------------- 1 | // 2 | // NXOAuth2Constants.h 3 | // OAuth2Client 4 | // 5 | // Created by Ullrich Schäfer on 27.08.10. 6 | // 7 | // Copyright 2010 nxtbgthng. All rights reserved. 8 | // 9 | // Licenced under the new BSD-licence. 10 | // See README.md in this repository for 11 | // the full licence. 12 | // 13 | 14 | #import 15 | 16 | 17 | #pragma mark OAuth2 Errors 18 | 19 | extern NSString * const NXOAuth2ErrorDomain; // domain 20 | 21 | // Error Codes from http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-3.2.1 22 | 23 | /* 24 | * The request is missing a required parameter, includes an 25 | * unsupported parameter or parameter value, or is otherwise 26 | * malformed. 27 | */ 28 | extern NSInteger const NXOAuth2InvalidRequestErrorCode; // -1001 29 | 30 | /* 31 | * The client identifier provided is invalid. 32 | */ 33 | extern NSInteger const NXOAuth2InvalidClientErrorCode; // -1002 34 | 35 | /* 36 | * The client is not authorized to use the requested response 37 | * type. 38 | */ 39 | extern NSInteger const NXOAuth2UnauthorizedClientErrorCode; // -1003 40 | 41 | /* 42 | * The redirection URI provided does not match a pre-registered 43 | * value. 44 | */ 45 | extern NSInteger const NXOAuth2RedirectURIMismatchErrorCode; // -1004 46 | 47 | /* 48 | * The end-user or authorization server denied the request. 49 | */ 50 | extern NSInteger const NXOAuth2AccessDeniedErrorCode; // -1005 51 | 52 | /* 53 | * The requested response type is not supported by the 54 | * authorization server. 55 | */ 56 | extern NSInteger const NXOAuth2UnsupportedResponseTypeErrorCode;// -1006 57 | 58 | /* 59 | * The requested scope is invalid, unknown, or malformed. 60 | */ 61 | extern NSInteger const NXOAuth2InvalidScopeErrorCode; // -1007 62 | 63 | 64 | // Custom Error codes 65 | 66 | /* 67 | * The connection failed because the token expired and could not be refreshed 68 | */ 69 | extern NSInteger const NXOAuth2CouldNotRefreshTokenErrorCode; // -2001 70 | 71 | 72 | #pragma mark HTTP Errors 73 | 74 | extern NSString * const NXOAuth2HTTPErrorDomain; // domain 75 | 76 | // The error code represents the http status code 77 | 78 | 79 | #pragma mark TLS Trust Modes 80 | 81 | /* 82 | * Implement the connection:trustModeForHostname: method from the 83 | * NXOAuth2ConnectionDelegate protocol to specify how certificates provided by 84 | * TLS/SSL secured hosts should be trusted. 85 | * If connection:trustModeForHostname: is not implemented the default 86 | * NXOAuth2TrustModeSystem is assumed. 87 | * 88 | * Note that you can return multiple flags. If you to a match on any trust mode 89 | * will be interpreted as trusting the server (basically the are ORed) 90 | * 91 | * If you specify NXOAuth2TrustModeSpecificCertificate you need to also 92 | * implement connection:trustedCertificatesDERDataForHostname: and provide the 93 | * trusted certificate as DER-encoded NSData. NXOAuth2TrustModeSpecificCertificate 94 | * just ensures that any certificate in the chain is equal to the provided one. 95 | * 96 | * See SecCertificateCreateWithData and SecCertificateCopyData from the 97 | * Security Framework for further reference. 98 | */ 99 | 100 | typedef enum { 101 | NXOAuth2TrustModeAnyCertificate = 1 << 0, 102 | NXOAuth2TrustModeSystem = 1 << 1, 103 | NXOAuth2TrustModeSpecificCertificate = 1 << 2 104 | } NXOAuth2TrustMode; 105 | 106 | 107 | 108 | extern NSString * const NXOAuth2AccountStoreErrorKey; 109 | 110 | -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/Headers/NXOAuth2FileStreamWrapper.h: -------------------------------------------------------------------------------- 1 | // 2 | // NXOAuth2FileStreamWrapper.h 3 | // OAuth2Client 4 | // 5 | // Created by Ullrich Schäfer on 27.08.10. 6 | // 7 | // Copyright 2010 nxtbgthng. All rights reserved. 8 | // 9 | // Licenced under the new BSD-licence. 10 | // See README.md in this repository for 11 | // the full licence. 12 | // 13 | 14 | #import 15 | 16 | 17 | @interface NXOAuth2FileStreamWrapper : NSObject { 18 | NSInputStream *stream; 19 | unsigned long long contentLength; 20 | NSString *fileName; 21 | NSString *contentType; 22 | } 23 | @property (nonatomic, strong, readonly) NSInputStream *stream; 24 | @property (nonatomic, assign, readonly) unsigned long long contentLength; 25 | @property (nonatomic, copy, readonly) NSString *fileName; 26 | @property (nonatomic, copy) NSString *contentType; // optional DEFAULT: "application/octettstream" 27 | 28 | + (id)wrapperWithStream:(NSInputStream *)stream contentLength:(unsigned long long)contentLength DEPRECATED_ATTRIBUTE; 29 | - (id)initWithStream:(NSInputStream *)stream contentLength:(unsigned long long)contentLength DEPRECATED_ATTRIBUTE; 30 | 31 | + (id)wrapperWithStream:(NSInputStream *)stream contentLength:(unsigned long long)contentLength fileName:(NSString *)fileName; 32 | - (id)initWithStream:(NSInputStream *)stream contentLength:(unsigned long long)contentLength fileName:(NSString *)fileName; 33 | 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/Headers/NXOAuth2PostBodyStream.h: -------------------------------------------------------------------------------- 1 | // 2 | // NXOAuth2PostBodyStream.h 3 | // OAuth2Client 4 | // 5 | // Created by Ullrich Schäfer on 27.08.10. 6 | // 7 | // Copyright 2010 nxtbgthng. All rights reserved. 8 | // 9 | // Licenced under the new BSD-licence. 10 | // See README.md in this repository for 11 | // the full licence. 12 | // 13 | 14 | 15 | #import 16 | 17 | 18 | @interface NXOAuth2PostBodyStream : NSInputStream { 19 | NSString *boundary; 20 | 21 | NSArray *contentStreams; 22 | NSInputStream *currentStream; // assigned (is retained by contentStreams) 23 | NSUInteger streamIndex; 24 | 25 | unsigned long long numBytesTotal; 26 | } 27 | 28 | - (id)initWithParameters:(NSDictionary *)postParameters; 29 | 30 | @property (readonly) NSString *boundary; 31 | @property (readonly) unsigned long long length; 32 | 33 | @end 34 | 35 | 36 | -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/Headers/NXOAuth2Request.h: -------------------------------------------------------------------------------- 1 | // 2 | // NXOAuth2Request.h 3 | // OAuth2Client 4 | // 5 | // Created by Tobias Kräntzer on 13.07.11. 6 | // 7 | // Copyright 2011 nxtbgthng. All rights reserved. 8 | // 9 | // Licenced under the new BSD-licence. 10 | // See README.md in this repository for 11 | // the full licence. 12 | // 13 | 14 | #import 15 | 16 | #import "NXOAuth2Connection.h" 17 | 18 | @class NXOAuth2Account; 19 | 20 | @interface NXOAuth2Request : NSObject { 21 | @private 22 | NSDictionary *parameters; 23 | NSURL *resource; 24 | NSString *requestMethod; 25 | NXOAuth2Account *account; 26 | NXOAuth2Connection *connection; 27 | NXOAuth2Request *me; 28 | } 29 | 30 | 31 | #pragma mark Class Methods 32 | 33 | + (void)performMethod:(NSString *)method 34 | onResource:(NSURL *)resource 35 | usingParameters:(NSDictionary *)parameters 36 | withAccount:(NXOAuth2Account *)account 37 | sendProgressHandler:(NXOAuth2ConnectionSendingProgressHandler)progressHandler 38 | responseHandler:(NXOAuth2ConnectionResponseHandler)responseHandler; 39 | 40 | 41 | #pragma mark Lifecycle 42 | 43 | - (id)initWithResource:(NSURL *)url method:(NSString *)method parameters:(NSDictionary *)parameter; 44 | 45 | 46 | #pragma mark Accessors 47 | 48 | @property (nonatomic, strong, readwrite) NXOAuth2Account *account; 49 | 50 | @property (nonatomic, strong, readwrite) NSString *requestMethod; 51 | @property (nonatomic, strong, readwrite) NSURL *resource; 52 | @property (nonatomic, strong, readwrite) NSDictionary *parameters; 53 | 54 | 55 | #pragma mark Signed NSURLRequest 56 | 57 | - (NSURLRequest *)signedURLRequest; 58 | 59 | 60 | #pragma mark Perform Request 61 | 62 | - (void)performRequestWithSendingProgressHandler:(NXOAuth2ConnectionSendingProgressHandler)progressHandler 63 | responseHandler:(NXOAuth2ConnectionResponseHandler)responseHandler; 64 | 65 | 66 | #pragma mark Cancel 67 | 68 | - (void)cancel; 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/Headers/NXOAuth2TrustDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // NXOAuth2TrustDelegate.h 3 | // OAuth2Client 4 | // 5 | // Created by Thomas Kollbach on 24.05.11. 6 | // 7 | // Copyright 2011 nxtbgthng. All rights reserved. 8 | // 9 | // Licenced under the new BSD-licence. 10 | // See README.md in this repository for 11 | // the full licence. 12 | // 13 | 14 | #import 15 | #import "NXOAuth2Constants.h" 16 | 17 | @class NXOAuth2Connection; 18 | 19 | /*! 20 | * The delegate of the NXOAuth2Connection or the NXOAuth2Client can both 21 | * optionally implement this protocol to ensure specific trust modes. 22 | * 23 | * If a NXOAuth2Connection is created with a NXOAuth2Client set and both 24 | * delegates conform to the NXOAuth2TrustDelegate protocol, the NXOAuth2Client's 25 | * delegate is used. 26 | */ 27 | 28 | @protocol NXOAuth2TrustDelegate 29 | 30 | @optional 31 | 32 | /*! 33 | * Specifies Trust mode for the specific hostname. See NXOAuth2Constants.h for constants 34 | */ 35 | -(NXOAuth2TrustMode)connection:(NXOAuth2Connection *)connection trustModeForHostname:(NSString *)hostname; 36 | 37 | /*! 38 | * Array of NSData objects that contains the trusted certificates for the hostname. 39 | */ 40 | -(NSArray *)connection:(NXOAuth2Connection *)connection trustedCertificatesForHostname:(NSString *)hostname; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/OAuth2Client: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/OAuth2Client.framework/Versions/A/OAuth2Client -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/A/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 13D65 7 | CFBundleDevelopmentRegion 8 | English 9 | CFBundleExecutable 10 | OAuth2Client 11 | CFBundleIdentifier 12 | com.nxtbgthng.OAuth2Client 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.2.3 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | DTCompiler 24 | com.apple.compilers.llvm.clang.1_0 25 | DTPlatformBuild 26 | 5B1008 27 | DTPlatformVersion 28 | GM 29 | DTSDKBuild 30 | 13C64 31 | DTSDKName 32 | macosx10.9 33 | DTXcode 34 | 0511 35 | DTXcodeBuild 36 | 5B1008 37 | 38 | 39 | -------------------------------------------------------------------------------- /SoundcloudPlayer/OAuth2Client.framework/Versions/Current: -------------------------------------------------------------------------------- 1 | A -------------------------------------------------------------------------------- /SoundcloudPlayer/PlayPauseButtonCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // CustomButtonCell.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 23.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PlayPauseButtonCell : NSButtonCell 12 | 13 | @property (nonatomic) BOOL playing; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /SoundcloudPlayer/PlayPauseButtonCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // CustomButtonCell.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 23.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "PlayPauseButtonCell.h" 10 | #import "StreamCloudStyles.h" 11 | #import "SharedAudioPlayer.h" 12 | 13 | @implementation PlayPauseButtonCell 14 | 15 | - (id)initWithCoder:(NSCoder *)aDecoder { 16 | self = [super initWithCoder:aDecoder]; 17 | if (self){ 18 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(markAsPlaying:) name:@"SharedAudioPlayerIsPlaying" object:nil]; 19 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(markAsPausing:) name:@"SharedAudioPlayerIsPausing" object:nil]; 20 | } 21 | return self; 22 | } 23 | 24 | - (void)drawBezelWithFrame:(NSRect)frame inView:(NSView *)controlView { 25 | [StreamCloudStyles drawPlayPauseButtonWithFrame:frame playing:[SharedAudioPlayer sharedPlayer].audioPlayer.rate]; 26 | } 27 | 28 | - (void)markAsPlaying:(NSNotification *)notification { 29 | [self setPlaying:YES]; 30 | } 31 | 32 | - (void)markAsPausing:(NSNotification *)notification { 33 | [self setPlaying:NO]; 34 | } 35 | 36 | - (void)setPlaying:(BOOL)playing { 37 | _playing = playing; 38 | [self setEnabled:NO]; 39 | [self setEnabled:YES]; 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /SoundcloudPlayer/PlayPauseOverlayView.h: -------------------------------------------------------------------------------- 1 | // 2 | // PlayPauseOverlayView.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 26.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PlayPauseOverlayView : NSView 12 | 13 | @property (nonatomic) NSInteger row; 14 | @property (nonatomic) id objectToShow; 15 | @property (nonatomic) BOOL showLargeIcons; 16 | @end 17 | -------------------------------------------------------------------------------- /SoundcloudPlayer/PlayPauseOverlayView.m: -------------------------------------------------------------------------------- 1 | // 2 | // PlayPauseOverlayView.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 26.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "PlayPauseOverlayView.h" 10 | #import "StreamCloudStyles.h" 11 | #import "SharedAudioPlayer.h" 12 | #import "SoundCloudPlaylist.h" 13 | #import "SoundCloudTrack.h" 14 | 15 | @implementation PlayPauseOverlayView 16 | 17 | - (id)initWithFrame:(NSRect)frame 18 | { 19 | self = [super initWithFrame:frame]; 20 | if (self) { 21 | // Initialization code here. 22 | } 23 | return self; 24 | } 25 | 26 | - (void)setShowLargeIcons:(BOOL)showLargeIcons { 27 | _showLargeIcons = showLargeIcons; 28 | [self setNeedsDisplay:YES]; 29 | } 30 | 31 | - (void)drawRect:(NSRect)dirtyRect 32 | { 33 | [super drawRect:dirtyRect]; 34 | BOOL playing = NO; 35 | if ([[SharedAudioPlayer sharedPlayer] currentItem] == self.objectToShow && [SharedAudioPlayer sharedPlayer].audioPlayer.rate) { 36 | playing = YES; 37 | } else if ([[[SharedAudioPlayer sharedPlayer] streamItemsToShowInTableView]indexOfObject:[[[SharedAudioPlayer sharedPlayer]currentItem] playlistTrackIsFrom]] == self.row && [SharedAudioPlayer sharedPlayer].audioPlayer.rate ) { 38 | playing = YES; 39 | } 40 | if (self.showLargeIcons){ 41 | [StreamCloudStyles drawLargePlayPauseOverlayWithFrame:self.frame playing:playing]; 42 | } else { 43 | [StreamCloudStyles drawPlayPauseOverlayWithFrame:self.frame playing:playing]; 44 | } 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /SoundcloudPlayer/PlayingIndicatorView.h: -------------------------------------------------------------------------------- 1 | // 2 | // PlayingIndicatorView.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 24.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PlayingIndicatorView : NSView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SoundcloudPlayer/PlayingIndicatorView.m: -------------------------------------------------------------------------------- 1 | // 2 | // PlayingIndicatorView.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 24.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "PlayingIndicatorView.h" 10 | #import "StreamCloudStyles.h" 11 | @implementation PlayingIndicatorView 12 | 13 | - (id)initWithCoder:(NSCoder *)aDecoder { 14 | self = [super initWithCoder:aDecoder]; 15 | if (self){ 16 | } 17 | return self; 18 | } 19 | 20 | - (void)drawRect:(NSRect)dirtyRect { 21 | [StreamCloudStyles drawPlayingIndicatorWithFrame:NSMakeRect(0, 0, self.frame.size.width, self.frame.size.height)]; 22 | } 23 | 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /SoundcloudPlayer/PreviousButtonCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // PreviousButtonCell.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 23.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PreviousButtonCell : NSButtonCell 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SoundcloudPlayer/PreviousButtonCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // PreviousButtonCell.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 23.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "PreviousButtonCell.h" 10 | #import "StreamCloudStyles.h" 11 | 12 | @implementation PreviousButtonCell 13 | 14 | - (void)drawBezelWithFrame:(NSRect)frame inView:(NSView *)controlView { 15 | [StreamCloudStyles drawPreviousButtonWithFrame:frame]; 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /SoundcloudPlayer/ProgressIndicatorView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ProgressIndicatorView.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 24.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ProgressIndicatorView : NSView 12 | 13 | @property (nonatomic) float progress; 14 | @end 15 | -------------------------------------------------------------------------------- /SoundcloudPlayer/ProgressIndicatorView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ProgressIndicatorView.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 24.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "ProgressIndicatorView.h" 10 | #import "StreamCloudStyles.h" 11 | #import "SharedAudioPlayer.h" 12 | 13 | @implementation ProgressIndicatorView 14 | 15 | - (id)initWithFrame:(NSRect)frame 16 | { 17 | self = [super initWithFrame:frame]; 18 | if (self) { 19 | [self commonInit]; 20 | } 21 | return self; 22 | } 23 | 24 | - (id)initWithCoder:(NSCoder *)aDecoder { 25 | self = [super initWithCoder:aDecoder]; 26 | if (self){ 27 | [self commonInit]; 28 | } 29 | return self; 30 | } 31 | 32 | - (void)commonInit { 33 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateProgress) name:@"SharedAudioPlayerUpdatedTimePlayed" object:nil]; 34 | } 35 | 36 | - (void)drawRect:(NSRect)dirtyRect 37 | { 38 | [super drawRect:dirtyRect]; 39 | 40 | [StreamCloudStyles drawProgressIndicatorViewWithPercentShown:floorf(self.progress)]; 41 | } 42 | 43 | - (void)updateProgress { 44 | float timeGone = CMTimeGetSeconds([SharedAudioPlayer sharedPlayer].audioPlayer.currentTime); 45 | float durationOfItem = CMTimeGetSeconds([SharedAudioPlayer sharedPlayer].audioPlayer.currentItem.duration); 46 | //float timeToGo = durationOfItem - timeGone; 47 | float progress = (timeGone/durationOfItem)*100; 48 | if (!isnan(progress)){ 49 | self.progress = progress; 50 | [self setNeedsDisplay:YES]; 51 | } 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /SoundcloudPlayer/ProgressSliderCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ProgressSliderCell.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 26.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ProgressSliderCell : NSSliderCell 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SoundcloudPlayer/ProgressSliderCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // ProgressSliderCell.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 26.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "ProgressSliderCell.h" 10 | #import "ProgressSliderView.h" 11 | #import "StreamCloudStyles.h" 12 | @implementation ProgressSliderCell 13 | 14 | - (void)drawKnob:(NSRect)knobRect { 15 | [StreamCloudStyles drawProgressSliderKnobWithFrame:knobRect]; 16 | } 17 | 18 | - (void)drawBarInside:(NSRect)aRect flipped:(BOOL)flipped { 19 | [StreamCloudStyles drawProgressSliderTrackWithFrame:aRect]; 20 | 21 | } 22 | 23 | - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { 24 | [super drawInteriorWithFrame:cellFrame inView:controlView]; 25 | NSRect trackRect = NSMakeRect(3, 6, controlView.frame.size.width-6,7); 26 | [StreamCloudStyles drawProgressSliderTrackWithFrame:trackRect]; 27 | if (self.doubleValue > 0) { 28 | NSRect leftRect = NSMakeRect(3.5, -0.5, ((controlView.frame.size.width-7)*(self.doubleValue/100)), 20); 29 | [StreamCloudStyles drawProgressSliderProgressWithFrame:NSIntegralRect(leftRect)]; 30 | } else { 31 | NSRect leftRect = NSMakeRect(3.5, -0.5, 2, 20); 32 | [StreamCloudStyles drawProgressSliderProgressWithFrame:NSIntegralRect(leftRect)]; 33 | } 34 | [self drawKnob]; 35 | } 36 | 37 | - (void)stopTracking:(NSPoint)lastPoint at:(NSPoint)stopPoint inView:(NSView *)controlView mouseIsUp:(BOOL)flag { 38 | [super stopTracking:lastPoint at:stopPoint inView:controlView mouseIsUp:flag]; 39 | ProgressSliderView *parentView = (ProgressSliderView *)controlView; 40 | [parentView setClicked:NO]; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /SoundcloudPlayer/ProgressSliderView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ProgressSliderView.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 26.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ProgressSliderView : NSSlider 12 | 13 | @property (nonatomic) BOOL clicked; 14 | @end 15 | -------------------------------------------------------------------------------- /SoundcloudPlayer/ProgressSliderView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ProgressSliderView.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 26.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "ProgressSliderView.h" 10 | 11 | @implementation ProgressSliderView 12 | 13 | - (id)initWithFrame:(NSRect)frame 14 | { 15 | self = [super initWithFrame:frame]; 16 | if (self) { 17 | self.clicked = NO; 18 | } 19 | return self; 20 | } 21 | 22 | - (void)drawRect:(NSRect)dirtyRect 23 | { 24 | [super drawRect:dirtyRect]; 25 | 26 | // Drawing code here. 27 | } 28 | 29 | - (void)mouseDown:(NSEvent *)theEvent { 30 | self.clicked = YES; 31 | [super mouseDown:theEvent]; 32 | } 33 | 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /SoundcloudPlayer/RepeatButtonCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // RepeatButtonCell.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 24.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RepeatButtonCell : NSButtonCell 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SoundcloudPlayer/RepeatButtonCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // RepeatButtonCell.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 24.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "RepeatButtonCell.h" 10 | #import "StreamCloudStyles.h" 11 | #import "SharedAudioPlayer.h" 12 | 13 | @implementation RepeatButtonCell 14 | 15 | - (id)initWithCoder:(NSCoder *)aDecoder { 16 | self = [super initWithCoder:aDecoder]; 17 | if (self){ 18 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(repeatModeChanged) name:@"SharedAudioPlayerChangedRepeatMode" object:nil]; 19 | } 20 | return self; 21 | } 22 | 23 | - (void)drawBezelWithFrame:(NSRect)frame inView:(NSView *)controlView { 24 | RepeatMode repeatMode = [[SharedAudioPlayer sharedPlayer] repeatMode]; 25 | switch (repeatMode) { 26 | case RepeatModeNone: 27 | [StreamCloudStyles drawRepeatButtonWithFrame:frame repeatMode:1]; 28 | break; 29 | case RepeatModeAll: 30 | [StreamCloudStyles drawRepeatButtonWithFrame:frame repeatMode:2]; 31 | break; 32 | case RepeatModeTrack: 33 | [StreamCloudStyles drawRepeatButtonWithFrame:frame repeatMode:3]; 34 | break; 35 | } 36 | } 37 | 38 | - (void)repeatModeChanged { 39 | [self setEnabled:NO]; 40 | [self setEnabled:YES]; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SeperatorView.h: -------------------------------------------------------------------------------- 1 | // 2 | // SeperatorView.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 24.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SeperatorView : NSView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SeperatorView.m: -------------------------------------------------------------------------------- 1 | // 2 | // SeperatorView.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 24.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "SeperatorView.h" 10 | #import "StreamCloudStyles.h" 11 | 12 | @implementation SeperatorView 13 | 14 | - (void)drawRect:(NSRect)dirtyRect { 15 | [StreamCloudStyles drawSeperatorViewWithFrame:dirtyRect]; 16 | } 17 | @end 18 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SettingsViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SettingsViewController.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 22.05.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MASShortcutView.h" 11 | 12 | @interface SettingsViewController : NSViewController 13 | 14 | @property (nonatomic, strong) IBOutlet NSTextField *lastFMUserNameField; 15 | @property (nonatomic, strong) IBOutlet NSTextField *lastFMPasswordField; 16 | @property (nonatomic, strong) IBOutlet NSButton *useLastFMButton; 17 | @property (nonatomic, strong) IBOutlet NSTextField *lastFMConnectionStateField; 18 | @property (nonatomic, strong) IBOutlet MASShortcutView *playPauseShortcutView; 19 | @property (nonatomic, strong) IBOutlet MASShortcutView *prevShortcutView; 20 | @property (nonatomic, strong) IBOutlet MASShortcutView *nextShortcutView; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SettingsViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SettingsViewController.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 22.05.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "SettingsViewController.h" 10 | #import "LastFm.h" 11 | #import "MASShortcutView.h" 12 | #import "MASShortcutView+UserDefaults.h" 13 | #import "MASShortcut+UserDefaults.h" 14 | #import "MASShortcut+Monitoring.h" 15 | #import "AppDelegate.h" 16 | 17 | 18 | 19 | @implementation SettingsViewController 20 | 21 | - (instancetype)initWithCoder:(NSCoder *)coder { 22 | self = [super initWithCoder:coder]; 23 | if (self){ 24 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewWillAppear) name:@"MainWindowOpenSettings" object:nil]; 25 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidDisappear) name:@"MainWindowCloseSettings" object:nil]; 26 | } 27 | return self; 28 | } 29 | 30 | - (void)viewWillAppear { 31 | [super viewWillAppear]; 32 | [self.useLastFMButton setState:[[NSUserDefaults standardUserDefaults] integerForKey:@"useLastFM"]]; 33 | if ([[NSUserDefaults standardUserDefaults] stringForKey:@"lastFMUserName"]) 34 | [self.lastFMUserNameField setStringValue:[[NSUserDefaults standardUserDefaults] stringForKey:@"lastFMUserName"]]; 35 | if ([[NSUserDefaults standardUserDefaults] stringForKey:@"lastFMPassword"]) 36 | [self.lastFMPasswordField setStringValue:[[NSUserDefaults standardUserDefaults] stringForKey:@"lastFMPassword"]]; 37 | if (self.useLastFMButton.state > 0){ 38 | [self.useLastFMButton.cell setTitle:NSLocalizedString(@"Scrobbling", nil)]; 39 | } else { 40 | [self.useLastFMButton.cell setTitle:NSLocalizedString(@"Not Scrobbling", nil)]; 41 | } 42 | if ([[NSUserDefaults standardUserDefaults] stringForKey:@"lastFMSessionKey"]){ 43 | [self.lastFMConnectionStateField setStringValue:NSLocalizedString(@"Connected", nil)]; 44 | } else { 45 | [self.lastFMConnectionStateField setStringValue:NSLocalizedString(@"Not connected", nil)]; 46 | } 47 | 48 | self.playPauseShortcutView.associatedUserDefaultsKey = @"PlayPauseShortcut"; 49 | 50 | self.nextShortcutView.associatedUserDefaultsKey = @"NextShortcut"; 51 | 52 | self.prevShortcutView.associatedUserDefaultsKey = @"PreviousShortcut"; 53 | 54 | } 55 | 56 | - (void)viewDidDisappear { 57 | [super viewDidDisappear]; 58 | [[NSUserDefaults standardUserDefaults] setInteger:self.useLastFMButton.state forKey:@"useLastFM"]; 59 | [[NSUserDefaults standardUserDefaults] setObject:self.lastFMUserNameField.stringValue forKey:@"lastFMUserName"]; 60 | [[NSUserDefaults standardUserDefaults] setObject:self.lastFMPasswordField.stringValue forKey:@"lastFMPassword"]; 61 | [[NSUserDefaults standardUserDefaults] synchronize]; 62 | } 63 | 64 | - (IBAction)scrobbleStateSwitchAction:(id)sender { 65 | if (self.useLastFMButton.state == 0) { 66 | [self.lastFMConnectionStateField setStringValue:NSLocalizedString(@"Not connected", nil)]; 67 | [self.useLastFMButton.cell setTitle:NSLocalizedString(@"Not Scrobbling", nil)]; 68 | [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"lastFMSessionKey"]; 69 | } else { 70 | [[LastFm sharedInstance] getSessionForUser:self.lastFMUserNameField.stringValue password:self.lastFMPasswordField.stringValue successHandler:^(NSDictionary *result) { 71 | NSLog(@"Got LastFM Session"); 72 | NSString *lastFMSessionKey = [result objectForKey:@"key"]; 73 | if (lastFMSessionKey){ 74 | [[NSUserDefaults standardUserDefaults] setObject:lastFMSessionKey forKey:@"lastFMSessionKey"]; 75 | [self.lastFMConnectionStateField setStringValue:NSLocalizedString(@"Connected", nil)]; 76 | [self.useLastFMButton.cell setTitle:NSLocalizedString(@"Scrobbling", nil)]; 77 | } else { 78 | [self.lastFMConnectionStateField setStringValue:NSLocalizedString(@"Not connected", nil)]; 79 | [self.useLastFMButton.cell setTitle:NSLocalizedString(@"Not Scrobbling", nil)]; 80 | [self showAlertForLastFMFailure]; 81 | } 82 | } failureHandler:^(NSError *error) { 83 | NSLog(@"No LastFM Session"); 84 | [self.lastFMConnectionStateField setStringValue:NSLocalizedString(@"Not connected", nil)]; 85 | [self.useLastFMButton.cell setTitle:NSLocalizedString(@"Not Scrobbling", nil)]; 86 | [self showAlertForLastFMFailure]; 87 | }]; 88 | } 89 | } 90 | 91 | - (IBAction)lastFMUserPasswordFieldAction:(id)sender { 92 | 93 | } 94 | 95 | - (void)showAlertForLastFMFailure { 96 | NSAlert *lastFMAlert = [NSAlert alertWithMessageText:NSLocalizedString(@"Could not get access to Last.FM!", nil) defaultButton:NSLocalizedString(@"Damn!", nil) alternateButton:nil otherButton:nil informativeTextWithFormat:@"Maybe you entered a wrong username or password?"]; 97 | [lastFMAlert runModal]; 98 | } 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SharedAudioPlayer.h: -------------------------------------------------------------------------------- 1 | // 2 | // SharedAudioPlayer.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 21.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SoundCloudItem.h" 11 | #import "SoundCloudTrack.h" 12 | #import "SoundCloudPlaylist.h" 13 | #import "SoundCloudUser.h" 14 | 15 | typedef enum : NSUInteger { 16 | RepeatModeNone, 17 | RepeatModeAll, 18 | RepeatModeTrack, 19 | } RepeatMode; 20 | 21 | typedef enum : NSUInteger { 22 | CurrentSourceTypeStream, 23 | CurrentSourceTypeFavorites, 24 | } CurrentSourceType; 25 | 26 | @import AVFoundation; 27 | 28 | @interface SharedAudioPlayer : NSObject 29 | 30 | @property (nonatomic, strong) AVQueuePlayer *audioPlayer; 31 | @property (nonatomic, strong) NSMutableArray *itemsToPlay; 32 | @property (nonatomic, strong) NSMutableArray *streamItemsToShowInTableView; 33 | @property (nonatomic, strong) NSMutableArray *favoriteItemsToShowInTableView; 34 | @property (nonatomic, strong) NSMutableArray *shuffledItemsToPlay; 35 | @property (nonatomic) BOOL shuffleEnabled; 36 | @property (nonatomic) NSInteger positionInPlaylist; 37 | @property (nonatomic, strong) NSURL *nextStreamPartURL; 38 | @property (nonatomic, strong) NSURL *nextFavoritesPartURL; 39 | @property (nonatomic) RepeatMode repeatMode; 40 | @property (nonatomic) CurrentSourceType sourceType; 41 | @property (nonatomic ,strong) NSMutableArray *scrobbledItems; 42 | 43 | + (SharedAudioPlayer *)sharedPlayer; 44 | - (void)insertStreamItems:(NSArray *)items; 45 | - (void)insertFavoriteItems:(NSArray *)items; 46 | - (void)togglePlayPause; 47 | - (void)previousItem; 48 | - (void)nextItem; 49 | - (void)jumpToItemAtIndex:(NSInteger)item; 50 | - (void)advanceToTime:(float)timeToGo; 51 | - (SoundCloudTrack *)currentItem; 52 | - (void)getNextSongs; 53 | - (void)toggleRepeatMode; 54 | - (void)reset; 55 | - (void)switchToFavorites; 56 | - (void)switchToStream; 57 | @end 58 | -------------------------------------------------------------------------------- /SoundcloudPlayer/ShuffleButtonCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ShuffleButtonCell.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 24.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ShuffleButtonCell : NSButtonCell 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SoundcloudPlayer/ShuffleButtonCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // ShuffleButtonCell.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 24.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "ShuffleButtonCell.h" 10 | #import "StreamCloudStyles.h" 11 | #import "SharedAudioPlayer.h" 12 | 13 | @interface ShuffleButtonCell () 14 | 15 | @property (nonatomic) BOOL shuffeling; 16 | 17 | @end 18 | 19 | @implementation ShuffleButtonCell 20 | 21 | - (id)initWithCoder:(NSCoder *)aDecoder { 22 | self = [super initWithCoder:aDecoder]; 23 | if (self){ 24 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(shuffleStarted) name:@"SharedAudioPlayShuffleStarted" object:nil]; 25 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(shuffleEnded) name:@"SharedAudioPlayShuffleEnded" object:nil]; 26 | } 27 | return self; 28 | } 29 | - (void)drawBezelWithFrame:(NSRect)frame inView:(NSView *)controlView { 30 | [StreamCloudStyles drawShuffleButtonWithFrame:frame active:[SharedAudioPlayer sharedPlayer].shuffleEnabled]; 31 | } 32 | 33 | - (void)shuffleStarted { 34 | self.shuffeling = YES; 35 | [self setEnabled:NO]; 36 | [self setEnabled:YES]; 37 | } 38 | 39 | - (void)shuffleEnded { 40 | self.shuffeling = NO; 41 | [self setEnabled:NO]; 42 | [self setEnabled:YES]; 43 | } 44 | @end 45 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudAPI.framework/Headers: -------------------------------------------------------------------------------- 1 | Versions/Current/Headers -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudAPI.framework/Resources: -------------------------------------------------------------------------------- 1 | Versions/Current/Resources -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudAPI.framework/SoundCloudAPI: -------------------------------------------------------------------------------- 1 | Versions/Current/SoundCloudAPI -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudAPI.framework/Versions/A/Headers/SCAPI.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011 nxtbgthng for SoundCloud Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | * 16 | * For more information and documentation refer to 17 | * http://soundcloud.com/api 18 | * 19 | */ 20 | 21 | #import "SCConstants.h" 22 | #import "SCSoundCloud.h" 23 | #import "SCAccount.h" 24 | #import "SCRequest.h" 25 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudAPI.framework/Versions/A/Headers/SCAccount+Private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011 nxtbgthng for SoundCloud Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | * 16 | * For more information and documentation refer to 17 | * http://soundcloud.com/api 18 | * 19 | */ 20 | 21 | #import 22 | 23 | #import "SCAccount.h" 24 | 25 | #pragma mark Notifications 26 | 27 | extern NSString * const SCAccountDidChangeUserInfoNotification; 28 | 29 | #pragma mark - 30 | 31 | @interface SCAccount (Private) 32 | 33 | @property (nonatomic, readonly) NXOAuth2Account *oauthAccount; 34 | @property (nonatomic, copy) NSDictionary *userInfo; 35 | - (id)initWithOAuthAccount:(NXOAuth2Account *)account; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudAPI.framework/Versions/A/Headers/SCAccount.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011 nxtbgthng for SoundCloud Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | * 16 | * For more information and documentation refer to 17 | * http://soundcloud.com/api 18 | * 19 | */ 20 | 21 | #import 22 | 23 | #pragma mark Notifications 24 | 25 | extern NSString * const SCAccountDidFailToGetAccessToken; 26 | 27 | @class NXOAuth2Account; 28 | 29 | @interface SCAccount : NSObject { 30 | @private 31 | NXOAuth2Account *oauthAccount; 32 | } 33 | 34 | #pragma mark Accessors 35 | 36 | @property (nonatomic, readonly) NSString *identifier; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudAPI.framework/Versions/A/Headers/SCConstants.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011 nxtbgthng for SoundCloud Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | * 16 | * For more information and documentation refer to 17 | * http://soundcloud.com/api 18 | * 19 | */ 20 | 21 | #import 22 | 23 | 24 | #pragma mark OAuth2 Configuration 25 | 26 | extern NSString * const kSCAccountType; 27 | 28 | extern NSString * const kSCConfigurationClientID; 29 | extern NSString * const kSCConfigurationSecret; 30 | extern NSString * const kSCConfigurationRedirectURL; 31 | extern NSString * const kSCConfigurationSandbox; 32 | extern NSString * const kSCConfigurationAPIURL; 33 | extern NSString * const kSCConfigurationAuthorizeURL; 34 | 35 | extern NSString * const kSCSoundCloudAPIURL; 36 | extern NSString * const kSCSoundCloudAccessTokenURL; 37 | extern NSString * const kSCSoundCloudAuthURL; 38 | 39 | extern NSString * const kSCSoundCloudSandboxAPIURL; 40 | extern NSString * const kSCSoundCloudSandboxAccessTokenURL; 41 | extern NSString * const kSCSoundCloudSandboxAuthURL; 42 | 43 | extern NSString * const kTermsOfServiceURL; 44 | extern NSString * const kPrivacyPolicyURL; 45 | 46 | extern float const kSCBorderRadius; 47 | 48 | extern NSUInteger const kSCUsernameTextFieldTag; 49 | extern NSUInteger const kSCPasswordTextFieldTag; -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudAPI.framework/Versions/A/Headers/SCRequest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011 nxtbgthng for SoundCloud Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | * 16 | * For more information and documentation refer to 17 | * http://soundcloud.com/api 18 | * 19 | */ 20 | 21 | #import 22 | 23 | typedef void(^SCRequestResponseHandler)(NSURLResponse *response, NSData *responseData, NSError *error); 24 | typedef void(^SCRequestSendingProgressHandler)(unsigned long long bytesSend, unsigned long long bytesTotal); 25 | 26 | enum SCRequestMethod { 27 | SCRequestMethodGET = 0, 28 | SCRequestMethodPOST, 29 | SCRequestMethodPUT, 30 | SCRequestMethodDELETE, 31 | SCRequestMethodHEAD 32 | }; 33 | typedef enum SCRequestMethod SCRequestMethod; 34 | 35 | @class NXOAuth2Request; 36 | @class SCAccount; 37 | 38 | @interface SCRequest : NSObject { 39 | @private 40 | NXOAuth2Request *oauthRequest; 41 | } 42 | 43 | 44 | #pragma mark Class Methods 45 | 46 | + (id) performMethod:(SCRequestMethod)aMethod 47 | onResource:(NSURL *)resource 48 | usingParameters:(NSDictionary *)parameters 49 | withAccount:(SCAccount *)account 50 | sendingProgressHandler:(SCRequestSendingProgressHandler)progressHandler 51 | responseHandler:(SCRequestResponseHandler)responseHandler; 52 | 53 | + (void)cancelRequest:(id)request; 54 | 55 | 56 | #pragma mark Initializer 57 | 58 | - (id)initWithMethod:(SCRequestMethod)aMethod resource:(NSURL *)aResource; 59 | 60 | #pragma mark Accessors 61 | 62 | @property (nonatomic, readwrite, retain) SCAccount *account; 63 | 64 | @property (nonatomic, assign) SCRequestMethod requestMethod; 65 | @property (nonatomic, readwrite, retain) NSURL *resource; 66 | @property (nonatomic, readwrite, retain) NSDictionary *parameters; 67 | 68 | 69 | #pragma mark Signed NSURLRequest 70 | 71 | - (NSURLRequest *)signedURLRequest; 72 | 73 | #pragma mark Perform Request 74 | 75 | //TODO Consider this 76 | // - Why not to -performRequestWithSendingHandler:responseHandler: ? 77 | // - Why Resource instead of URL ? 78 | // - Need documentation in why there is no –addMultiPartData:withName:type: 79 | 80 | - (void)performRequestWithSendingProgressHandler:(SCRequestSendingProgressHandler)progressHandler 81 | responseHandler:(SCRequestResponseHandler)responseHandler; 82 | 83 | #pragma Cancel Request 84 | 85 | - (void)cancel; 86 | 87 | @end 88 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudAPI.framework/Versions/A/Headers/SCSoundCloud+Private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011 nxtbgthng for SoundCloud Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | * 16 | * For more information and documentation refer to 17 | * http://soundcloud.com/api 18 | * 19 | */ 20 | 21 | #import "SCSoundCloud.h" 22 | 23 | @interface SCSoundCloud (Private) 24 | 25 | + (SCSoundCloud *)shared; 26 | 27 | #pragma mark Configuration 28 | 29 | + (NSDictionary *)configuration; 30 | 31 | #pragma mark Manage Accounts 32 | 33 | - (void)requestAccessWithUsername:(NSString *)username password:(NSString *)password; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudAPI.framework/Versions/A/Headers/SCSoundCloud.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010, 2011 nxtbgthng for SoundCloud Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | * 16 | * For more information and documentation refer to 17 | * http://soundcloud.com/api 18 | * 19 | */ 20 | 21 | #import 22 | 23 | #pragma mark Notifications 24 | 25 | extern NSString * const SCSoundCloudAccountDidChangeNotification; 26 | extern NSString * const SCSoundCloudDidFailToRequestAccessNotification; 27 | 28 | 29 | #pragma mark Handler 30 | 31 | typedef void(^SCPreparedAuthorizationURLHandler)(NSURL *preparedURL); 32 | 33 | 34 | #pragma mark - 35 | 36 | @class SCAccount; 37 | 38 | @interface SCSoundCloud : NSObject 39 | 40 | #pragma mark Accessors 41 | 42 | + (SCAccount *)account; 43 | 44 | 45 | #pragma mark Manage Accounts 46 | 47 | + (void)requestAccessWithPreparedAuthorizationURLHandler:(SCPreparedAuthorizationURLHandler)aPreparedAuthorizationURLHandler; 48 | + (void)removeAccess; 49 | 50 | 51 | #pragma mark Configuration 52 | 53 | + (void)setClientID:(NSString *)aClientID 54 | secret:(NSString *)aSecret 55 | redirectURL:(NSURL *)aRedirectURL; 56 | 57 | #pragma mark OAuth2 Flow 58 | 59 | + (BOOL)handleRedirectURL:(NSURL *)URL; 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudAPI.framework/Versions/A/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 13D65 7 | CFBundleDevelopmentRegion 8 | English 9 | CFBundleExecutable 10 | SoundCloudAPI 11 | CFBundleIdentifier 12 | com.yourcompany.SoundCloudAPI 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 2.0b6 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 2.0b6 23 | DTCompiler 24 | com.apple.compilers.llvm.clang.1_0 25 | DTPlatformBuild 26 | 5B1008 27 | DTPlatformVersion 28 | GM 29 | DTSDKBuild 30 | 13C64 31 | DTSDKName 32 | macosx10.9 33 | DTXcode 34 | 0511 35 | DTXcodeBuild 36 | 5B1008 37 | 38 | 39 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudAPI.framework/Versions/A/SoundCloudAPI: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/SoundcloudPlayer/SoundCloudAPI.framework/Versions/A/SoundCloudAPI -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudAPI.framework/Versions/Current: -------------------------------------------------------------------------------- 1 | A -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudAPIClient.h: -------------------------------------------------------------------------------- 1 | // 2 | // SoundCloudAPIClient.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 25.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SoundCloudAPIClient : NSObject 12 | 13 | + (SoundCloudAPIClient *)sharedClient; 14 | - (void)login; 15 | - (void)logout; 16 | - (BOOL)isLoggedIn; 17 | - (void)getInitialStreamSongs; 18 | - (void)getStreamSongsWithURL:(NSString *)url; 19 | - (void)getInitialFavoriteSongs; 20 | - (void)getFavoriteSongsWithURL:(NSString *)url; 21 | - (void)reloadStream; 22 | @end 23 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudAPIClient.m: -------------------------------------------------------------------------------- 1 | // 2 | // SoundCloudAPIClient.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 25.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "SoundCloudAPIClient.h" 10 | #import 11 | #import "SharedAudioPlayer.h" 12 | #import "SoundCloudItem.h" 13 | 14 | @implementation SoundCloudAPIClient 15 | 16 | - (id)init { 17 | self = [super init]; 18 | if (self){ 19 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadStream) name:SCSoundCloudAccountDidChangeNotification object:nil]; 20 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didFailToAuthenticate) name:SCSoundCloudDidFailToRequestAccessNotification object:nil]; 21 | } 22 | return self; 23 | } 24 | 25 | + (SoundCloudAPIClient *)sharedClient { 26 | static dispatch_once_t once; 27 | static SoundCloudAPIClient* sharedClient; 28 | dispatch_once(&once, ^{ 29 | sharedClient = [[self alloc] init]; 30 | }); 31 | return sharedClient; 32 | } 33 | 34 | - (void)login { 35 | [SCSoundCloud requestAccessWithPreparedAuthorizationURLHandler:^(NSURL *preparedURL){ 36 | // Load the URL in a web view or open it in an external browser 37 | [[NSWorkspace sharedWorkspace] openURL:preparedURL]; 38 | }]; 39 | } 40 | 41 | 42 | - (void)logout { 43 | [[NSURLCache sharedURLCache] removeAllCachedResponses]; 44 | [SCSoundCloud removeAccess]; 45 | [self didFailToAuthenticate]; 46 | } 47 | 48 | - (void)didFailToAuthenticate { 49 | [[NSNotificationCenter defaultCenter] postNotificationName:@"SoundCloudAPIClientDidFailToAuthenticate" object:nil]; 50 | [[SharedAudioPlayer sharedPlayer] reset]; 51 | } 52 | - (BOOL)isLoggedIn { 53 | SCAccount *account = [SCSoundCloud account]; 54 | if (!account.identifier) { 55 | return NO; 56 | } else { 57 | return YES; 58 | } 59 | } 60 | 61 | - (void)reloadStream { 62 | [[NSURLCache sharedURLCache] removeAllCachedResponses]; 63 | [[SharedAudioPlayer sharedPlayer] reset]; 64 | [self getInitialStreamSongs]; 65 | [self getInitialFavoriteSongs]; 66 | } 67 | 68 | - (void)getInitialStreamSongs { 69 | SCAccount *account = [SCSoundCloud account]; 70 | 71 | [SCRequest performMethod:SCRequestMethodGET 72 | onResource:[NSURL URLWithString:@"https://api-v2.soundcloud.com/stream?limit=25"] 73 | usingParameters:nil 74 | withAccount:account 75 | sendingProgressHandler:nil 76 | responseHandler:^(NSURLResponse *response, NSData *data, NSError *error){ 77 | // Handle the response 78 | if (error) { 79 | NSLog(@"Ooops, something went wrong: %@", [error localizedDescription]); 80 | } else { 81 | NSLog(@"Got data, yeah"); 82 | NSError *error; 83 | id objectFromData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; 84 | if (!error){ 85 | NSArray *itemsFromResponse = [SoundCloudItem soundCloudItemsFromResponse:objectFromData]; 86 | [[SharedAudioPlayer sharedPlayer] insertStreamItems:itemsFromResponse]; 87 | } 88 | } 89 | }]; 90 | 91 | [SCRequest performMethod:SCRequestMethodGET 92 | onResource:[NSURL URLWithString:@"https://api.soundcloud.com/me"] 93 | usingParameters:nil 94 | withAccount:account 95 | sendingProgressHandler:nil 96 | responseHandler:^(NSURLResponse *response, NSData *data, NSError *error){ 97 | // Handle the response 98 | if (error) { 99 | NSLog(@"Ooops, something went wrong: %@", [error localizedDescription]); 100 | } else { 101 | NSLog(@"Got data, yeah"); 102 | NSError *error; 103 | id objectFromData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; 104 | if (!error){ 105 | if ([objectFromData isKindOfClass:[NSDictionary class]]){ 106 | NSNumber *userId = [objectFromData objectForKey:@"id"]; 107 | [[NSUserDefaults standardUserDefaults] setObject:userId forKey:@"scUserId"]; 108 | [[NSUserDefaults standardUserDefaults] synchronize]; 109 | } 110 | } 111 | } 112 | }]; 113 | 114 | } 115 | 116 | 117 | - (void)getStreamSongsWithURL:(NSString *)url { 118 | SCAccount *account = [SCSoundCloud account]; 119 | 120 | [SCRequest performMethod:SCRequestMethodGET 121 | onResource:[NSURL URLWithString:url] 122 | usingParameters:nil 123 | withAccount:account 124 | sendingProgressHandler:nil 125 | responseHandler:^(NSURLResponse *response, NSData *data, NSError *error){ 126 | // Handle the response 127 | if (error) { 128 | NSLog(@"Ooops, something went wrong: %@", [error localizedDescription]); 129 | } else { 130 | NSLog(@"Got data, yeah"); 131 | NSError *error; 132 | id objectFromData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; 133 | if (!error){ 134 | if ([objectFromData isKindOfClass:[NSDictionary class]]) { 135 | NSArray *itemsToInsert = [SoundCloudItem soundCloudItemsFromResponse:objectFromData]; 136 | [[SharedAudioPlayer sharedPlayer]insertStreamItems:itemsToInsert]; 137 | } 138 | } 139 | } 140 | }]; 141 | 142 | } 143 | 144 | - (void)getInitialFavoriteSongs { 145 | SCAccount *account = [SCSoundCloud account]; 146 | 147 | [SCRequest performMethod:SCRequestMethodGET 148 | onResource:[NSURL URLWithString:[NSString stringWithFormat:@"https://api-v2.soundcloud.com/users/%@/track_likes?limit=12&offset=0&linked_partitioning=1",[[NSUserDefaults standardUserDefaults] objectForKey:@"scUserId"]]] 149 | usingParameters:nil 150 | withAccount:account 151 | sendingProgressHandler:nil 152 | responseHandler:^(NSURLResponse *response, NSData *data, NSError *error){ 153 | // Handle the response 154 | if (error) { 155 | NSLog(@"Ooops, something went wrong: %@", [error localizedDescription]); 156 | } else { 157 | NSLog(@"Got data, yeah"); 158 | NSError *error; 159 | id objectFromData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; 160 | if (!error){ 161 | if ([objectFromData isKindOfClass:[NSDictionary class]]) { 162 | NSArray *itemsToInsert = [SoundCloudItem soundCloudItemsFromResponse:objectFromData]; 163 | [[SharedAudioPlayer sharedPlayer]insertFavoriteItems:itemsToInsert]; 164 | 165 | } 166 | } 167 | } 168 | }]; 169 | 170 | } 171 | 172 | - (void)getFavoriteSongsWithURL:(NSString *)url { 173 | SCAccount *account = [SCSoundCloud account]; 174 | 175 | [SCRequest performMethod:SCRequestMethodGET 176 | onResource:[NSURL URLWithString:url] 177 | usingParameters:nil 178 | withAccount:account 179 | sendingProgressHandler:nil 180 | responseHandler:^(NSURLResponse *response, NSData *data, NSError *error){ 181 | // Handle the response 182 | if (error) { 183 | NSLog(@"Ooops, something went wrong: %@", [error localizedDescription]); 184 | } else { 185 | NSLog(@"Got data, yeah"); 186 | NSError *error; 187 | id objectFromData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; 188 | if (!error){ 189 | if ([objectFromData isKindOfClass:[NSDictionary class]]) { 190 | NSArray *itemsToInsert = [SoundCloudItem soundCloudItemsFromResponse:objectFromData]; 191 | [[SharedAudioPlayer sharedPlayer]insertFavoriteItems:itemsToInsert]; 192 | } 193 | } 194 | } 195 | }]; 196 | } 197 | 198 | @end 199 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // SoundCloudItem.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 14.01.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef enum : NSUInteger { 12 | SoundCloudItemTypeUnknown, 13 | SoundCloudItemTypeTrack, 14 | SoundCloudItemTypePlaylist, 15 | SoundCloudItemTypeTrackRepost, 16 | SoundCloudItemTypePlaylistRepost 17 | } SoundCloudItemType; 18 | 19 | @class SoundCloudUser; 20 | @interface SoundCloudItem : NSObject 21 | 22 | @property (nonatomic, strong) NSDate *createdAt; 23 | @property (nonatomic) SoundCloudItemType type; 24 | @property (nonatomic, strong) NSString *uuid; 25 | @property (nonatomic) id item; 26 | @property (nonatomic, strong) SoundCloudUser *user; 27 | @property (nonatomic, strong) NSURL *nextHref; 28 | 29 | + (NSArray *)soundCloudItemsFromResponse:(id)response; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // SoundCloudItem.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 14.01.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "SoundCloudItem.h" 10 | #import "SoundCloudUser.h" 11 | #import "SoundCloudTrack.h" 12 | #import "SoundCloudPlaylist.h" 13 | 14 | @implementation SoundCloudItem 15 | 16 | - (instancetype)initWithCollectionDict:(NSDictionary *)dict { 17 | self = [super init]; 18 | if (self){ 19 | self.createdAt = [NSDate date]; 20 | self.type = SoundCloudItemTypeUnknown; 21 | NSString *typeString = [dict objectForKey:@"type"]; 22 | NSString *kindString = [dict objectForKey:@"kind"]; 23 | self.user = [SoundCloudUser userForDict:[dict objectForKey:@"user"]]; 24 | 25 | if (kindString && [kindString isEqualToString:@"like"]){ 26 | if ([dict objectForKey:@"track"] && [[dict objectForKey:@"track"] isKindOfClass:[NSDictionary class]]){ 27 | self.type = SoundCloudItemTypeTrack; 28 | self.item = [SoundCloudTrack trackForDict:[dict objectForKey:@"track"] withPlaylist:nil repostedBy:nil]; 29 | } else if ([dict objectForKey:@"playlist"] && [[dict objectForKey:@"playlist"] isKindOfClass:[NSDictionary class]]){ 30 | self.type = SoundCloudItemTypePlaylist; 31 | self.item = [SoundCloudPlaylist playlistForDict:[dict objectForKey:@"playlist"] repostedBy:nil]; 32 | } 33 | } else { 34 | if ([typeString isEqualToString:@"track"]) { 35 | self.type = SoundCloudItemTypeTrack; 36 | self.item = [SoundCloudTrack trackForDict:[dict objectForKey:@"track"] withPlaylist:nil repostedBy:nil]; 37 | } else if ([typeString isEqualToString:@"track-repost"]) { 38 | self.type = SoundCloudItemTypeTrackRepost; 39 | self.item = [SoundCloudTrack trackForDict:[dict objectForKey:@"track"] withPlaylist:nil repostedBy:self.user]; 40 | } else if ([typeString isEqualToString:@"playlist"]){ 41 | self.type = SoundCloudItemTypePlaylist; 42 | self.item = [SoundCloudPlaylist playlistForDict:[dict objectForKey:@"playlist"] repostedBy:nil]; 43 | } else if ([typeString isEqualToString:@"playlist-repost"]) { 44 | self.type = SoundCloudItemTypePlaylistRepost; 45 | self.item = [SoundCloudPlaylist playlistForDict:[dict objectForKey:@"playlist"] repostedBy:self.user]; 46 | } 47 | self.uuid = [dict objectForKey:@"uuid"]; 48 | } 49 | } 50 | return self; 51 | } 52 | 53 | + (NSArray *)soundCloudItemsFromResponse:(id)response { 54 | if ([response isKindOfClass:[NSDictionary class]]){ 55 | NSMutableArray *arrayToReturn = [NSMutableArray array]; 56 | NSArray *collectionArray = [response objectForKey:@"collection"]; 57 | if (collectionArray && [collectionArray isKindOfClass:[NSArray class]]) { 58 | for (NSDictionary *collectionItem in collectionArray){ 59 | SoundCloudItem *itemFromCollectionItem = [[SoundCloudItem alloc]initWithCollectionDict:collectionItem]; 60 | if ([[response objectForKey:@"next_href"] isKindOfClass:[NSString class]]) 61 | itemFromCollectionItem.nextHref = [NSURL URLWithString:[response objectForKey:@"next_href"]]; 62 | [arrayToReturn addObject:itemFromCollectionItem]; 63 | } 64 | } 65 | return [NSArray arrayWithArray:arrayToReturn]; 66 | } else { 67 | return nil; 68 | } 69 | } 70 | @end 71 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudPlaylist.h: -------------------------------------------------------------------------------- 1 | // 2 | // SoundCloudPlaylist.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 14.01.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class SoundCloudUser; 12 | @interface SoundCloudPlaylist : NSObject 13 | 14 | @property (nonatomic, strong) NSURL *artworkUrl; 15 | @property (nonatomic, strong) NSDate *createdAt; 16 | @property (nonatomic, strong) NSString *descriptionText; 17 | @property (nonatomic) NSTimeInterval duration; 18 | @property (nonatomic, strong) NSString *genre; 19 | @property (nonatomic, strong) NSDate *lastModified; 20 | @property (nonatomic, strong) NSString *license; 21 | @property (nonatomic, strong) NSNumber *likesCount; 22 | @property (nonatomic, strong) NSURL *permalinkUrl; 23 | @property (nonatomic, strong) NSNumber *repostsCount; 24 | @property (nonatomic) BOOL streamable; 25 | @property (nonatomic, strong) NSString *tagList; 26 | @property (nonatomic, strong) NSString *title; 27 | @property (nonatomic, strong) NSNumber *trackCount; 28 | @property (nonatomic, strong) NSArray *tracks; 29 | @property (nonatomic, strong) NSNumber *identifier; 30 | @property (nonatomic, strong) SoundCloudUser *user; 31 | @property (nonatomic, strong) SoundCloudUser *repostBy; 32 | 33 | + (SoundCloudPlaylist *)playlistForDict:(NSDictionary *)dict repostedBy:(SoundCloudUser *)repostedBy; 34 | @end 35 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudPlaylist.m: -------------------------------------------------------------------------------- 1 | // 2 | // SoundCloudPlaylist.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 14.01.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "SoundCloudPlaylist.h" 10 | #import "SoundCloudUser.h" 11 | #import "SoundCloudTrack.h" 12 | #import 13 | 14 | @implementation SoundCloudPlaylist 15 | 16 | - (instancetype)initWithDict:(NSDictionary *)dict { 17 | self = [super init]; 18 | if (self){ 19 | if ([[dict objectForKey:@"artwork_url"] isKindOfClass:[NSString class]]) 20 | self.artworkUrl = [NSURL URLWithString:[dict objectForKey:@"artwork_url"]]; 21 | self.createdAt = [NSDate date]; 22 | self.descriptionText = [dict objectForKey:@"description"]; 23 | self.duration = [[dict objectForKey:@"duration"] doubleValue]/1000; 24 | self.genre = [dict objectForKey:@"genre"]; 25 | self.lastModified = [NSDate date]; 26 | self.license = [dict objectForKey:@"license"]; 27 | self.likesCount = [dict objectForKey:@"likes_count"]; 28 | if ([[dict objectForKey:@"permalink_url"] isKindOfClass:[NSString class]]) 29 | self.permalinkUrl = [NSURL URLWithString:[dict objectForKey:@"permalink_url"]]; 30 | self.repostsCount = [dict objectForKey:@"reposts_count"]; 31 | self.streamable = YES; 32 | self.tagList = [dict objectForKey:@"tag_list"]; 33 | self.title = [dict objectForKey:@"title"]; 34 | self.trackCount = [dict objectForKey:@"track_count"]; 35 | self.identifier = [dict objectForKey:@"id"]; 36 | self.user = [SoundCloudUser userForDict:[dict objectForKey:@"user"]]; 37 | } 38 | return self; 39 | } 40 | 41 | + (SoundCloudPlaylist *)playlistForDict:(NSDictionary *)dict repostedBy:(SoundCloudUser *)repostedBy { 42 | SoundCloudPlaylist *playlistToReturn = [[SoundCloudPlaylist alloc]initWithDict:dict]; 43 | [[NSNotificationCenter defaultCenter] postNotificationName:@"SoundCloudPlaylistTracksWillLoad" object:playlistToReturn]; 44 | [playlistToReturn loadTracksForPlaylist]; 45 | if (repostedBy) 46 | playlistToReturn.repostBy = repostedBy; 47 | return playlistToReturn; 48 | } 49 | 50 | - (void)loadTracksForPlaylist { 51 | SCAccount *account = [SCSoundCloud account]; 52 | 53 | [SCRequest performMethod:SCRequestMethodGET 54 | onResource:[NSURL URLWithString:[NSString stringWithFormat:@"https://api.soundcloud.com/playlists/%@",self.identifier]] 55 | usingParameters:nil 56 | withAccount:account 57 | sendingProgressHandler:nil 58 | responseHandler:^(NSURLResponse *response, NSData *data, NSError *error){ 59 | // Handle the response 60 | if (error) { 61 | NSLog(@"Ooops, something went wrong: %@", [error localizedDescription]); 62 | } else { 63 | NSLog(@"Got data, yeah"); 64 | NSError *error; 65 | id objectFromData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; 66 | if (!error){ 67 | if ([objectFromData isKindOfClass:[NSDictionary class]]){ 68 | if ([objectFromData objectForKey:@"tracks"]){ 69 | NSMutableArray *tracksCache = [NSMutableArray array]; 70 | for (NSDictionary *track in [objectFromData objectForKey:@"tracks"]) { 71 | [tracksCache addObject:[SoundCloudTrack trackForDict:track withPlaylist:self repostedBy:nil]]; 72 | } 73 | self.tracks = [NSArray arrayWithArray:tracksCache]; 74 | [[NSNotificationCenter defaultCenter] postNotificationName:@"SoundCloudPlaylistTracksLoaded" object:self]; 75 | } 76 | } 77 | } else { 78 | [[NSNotificationCenter defaultCenter] postNotificationName:@"SoundCloudPlaylistFailedToLoadTracks" object:self]; 79 | } 80 | } 81 | }]; 82 | } 83 | @end 84 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudTrack.h: -------------------------------------------------------------------------------- 1 | // 2 | // SoundCloudTrack.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 14.01.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @import AVFoundation; 12 | @class SoundCloudPlaylist; 13 | @class SoundCloudUser; 14 | 15 | @interface SoundCloudTrack : NSObject 16 | 17 | @property (nonatomic, readonly) AVPlayerItem *playerItem; 18 | @property (nonatomic, strong) NSURL *artworkUrl; 19 | @property (nonatomic, strong) NSNumber *commentCount; 20 | @property (nonatomic, strong) NSDate *createdAt; 21 | @property (nonatomic, strong) NSString *descriptionText; 22 | @property (nonatomic, strong) NSNumber *downloadCount; 23 | @property (nonatomic, strong) NSURL *downloadUrl; 24 | @property (nonatomic) BOOL downloadable; 25 | @property (nonatomic) NSTimeInterval duration; 26 | @property (nonatomic, strong) NSString *genre; 27 | @property (nonatomic, strong) NSString *labelName; 28 | @property (nonatomic, strong) NSDate *lastModified; 29 | @property (nonatomic, strong) NSString *license; 30 | @property (nonatomic, strong) NSNumber *likesCount; 31 | @property (nonatomic, strong) NSURL *permalinkUrl; 32 | @property (nonatomic, strong) NSNumber *playbackCount; 33 | @property (nonatomic, strong) NSNumber *repostsCount; 34 | @property (nonatomic, strong) NSURL *streamingUrl; 35 | @property (nonatomic) BOOL streamable; 36 | @property (nonatomic, strong) NSString *tagList; 37 | @property (nonatomic, strong) NSString *title; 38 | @property (nonatomic, strong) NSDate *updatedAt; 39 | @property (nonatomic, strong) NSURL *uri; 40 | @property (nonatomic, strong) SoundCloudUser *user; 41 | @property (nonatomic ,strong) NSURL *waveformUrl; 42 | @property (nonatomic, strong) SoundCloudUser *repostedBy; 43 | 44 | @property (nonatomic, strong) SoundCloudPlaylist *playlistTrackIsFrom; 45 | 46 | + (SoundCloudTrack *)trackForDict:(NSDictionary *)dict withPlaylist:(SoundCloudPlaylist *)playlist repostedBy:(SoundCloudUser *)repostedBy; 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudTrack.m: -------------------------------------------------------------------------------- 1 | // 2 | // SoundCloudTrack.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 14.01.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "SoundCloudTrack.h" 10 | #import "SoundCloudUser.h" 11 | #define CLIENT_ID @"909c2edcdbd7b312b48a04a3f1e6b40c" 12 | 13 | @interface SoundCloudTrack () 14 | 15 | @property (nonatomic, readwrite) AVPlayerItem *playerItem; 16 | 17 | @end 18 | 19 | @implementation SoundCloudTrack 20 | 21 | - (instancetype)initWithDict:(NSDictionary *)dict { 22 | self = [super init]; 23 | if (self){ 24 | if ([[dict objectForKey:@"artwork_url"] isKindOfClass:[NSString class]]) 25 | self.artworkUrl = [NSURL URLWithString:[dict objectForKey:@"artwork_url"]]; 26 | self.commentCount = [dict objectForKey:@"comment_count"]; 27 | self.createdAt = [NSDate date]; 28 | self.descriptionText = [dict objectForKey:@"description"]; 29 | self.downloadCount = [dict objectForKey:@"download_count"]; 30 | if ([[dict objectForKey:@"download_url"] isKindOfClass:[NSString class]]) 31 | self.downloadUrl = [NSURL URLWithString:[dict objectForKey:@"download_url"]]; 32 | self.downloadable = [[dict objectForKey:@"downloadable"] boolValue]; 33 | self.duration = [[dict objectForKey:@"duration"] doubleValue]/1000; 34 | self.genre = [dict objectForKey:@"genre"]; 35 | self.labelName = [dict objectForKey:@"label_name"]; 36 | self.lastModified = [NSDate date]; 37 | self.license = [dict objectForKey:@"license"]; 38 | self.likesCount = [dict objectForKey:@"likes_count"]; 39 | if ([[dict objectForKey:@"permalink_url"] isKindOfClass:[NSString class]]) 40 | self.permalinkUrl = [NSURL URLWithString:[dict objectForKey:@"permalink_url"]]; 41 | self.playbackCount = [dict objectForKey:@"playback_count"]; 42 | self.repostsCount = [dict objectForKey:@"reposts_count"]; 43 | if ([[dict objectForKey:@"stream_url"] isKindOfClass:[NSString class]]) 44 | self.streamingUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@?client_id=%@&allow_redirects=False",[dict objectForKey:@"stream_url"],CLIENT_ID]]; 45 | self.streamable = [[dict objectForKey:@"streamable"] boolValue]; 46 | if (self.streamable && !self.streamingUrl) { 47 | self.streamingUrl = [NSURL URLWithString:[NSString stringWithFormat:@"https://api.soundcloud.com/tracks/%@/stream?client_id=%@",[dict objectForKey:@"id"],CLIENT_ID]]; 48 | } 49 | self.tagList = [dict objectForKey:@"tag_list"]; 50 | if ([dict objectForKey:@"title"]) 51 | self.title = [dict objectForKey:@"title"]; 52 | else 53 | self.title = @""; 54 | self.updatedAt = [NSDate date]; 55 | if ([[dict objectForKey:@"uri"] isKindOfClass:[NSString class]]) 56 | self.uri = [NSURL URLWithString:[dict objectForKey:@"uri"]]; 57 | self.user = [SoundCloudUser userForDict:[dict objectForKey:@"user"]]; 58 | if ([[dict objectForKey:@"waveform_url"] isKindOfClass:[NSString class]]) 59 | self.waveformUrl = [NSURL URLWithString:[dict objectForKey:@"waveform_url"]]; 60 | if (self.streamable) 61 | self.playerItem = [AVPlayerItem playerItemWithURL:self.streamingUrl]; 62 | } 63 | return self; 64 | } 65 | 66 | + (SoundCloudTrack *)trackForDict:(NSDictionary *)dict withPlaylist:(SoundCloudPlaylist *)playlist repostedBy:(SoundCloudUser *)repostedBy { 67 | SoundCloudTrack *trackToReturn = [[SoundCloudTrack alloc]initWithDict:dict]; 68 | trackToReturn.playlistTrackIsFrom = playlist; 69 | trackToReturn.repostedBy = repostedBy; 70 | return trackToReturn; 71 | } 72 | 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudUser.h: -------------------------------------------------------------------------------- 1 | // 2 | // SoundCloudUser.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 14.01.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SoundCloudUser : NSObject 12 | 13 | @property (nonatomic, strong) NSURL *avatarUrl; 14 | @property (nonatomic, strong) NSNumber *identifier; 15 | @property (nonatomic, strong) NSString *kind; 16 | @property (nonatomic, strong) NSDate *lastModified; 17 | @property (nonatomic, strong) NSString *permalink; 18 | @property (nonatomic, strong) NSURL *permalinkUrl; 19 | @property (nonatomic ,strong) NSURL *userUri; 20 | @property (nonatomic, strong) NSString *username; 21 | 22 | + (SoundCloudUser *)userForDict:(NSDictionary *)dict; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundCloudUser.m: -------------------------------------------------------------------------------- 1 | // 2 | // SoundCloudUser.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 14.01.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "SoundCloudUser.h" 10 | 11 | @implementation SoundCloudUser 12 | 13 | - (instancetype)initWithDict:(NSDictionary *)dict { 14 | self = [super init]; 15 | if (self){ 16 | if ([[dict objectForKey:@"avatar_url"] isKindOfClass:[NSString class]]) 17 | self.avatarUrl = [NSURL URLWithString:[dict objectForKey:@"avatar_url"]]; 18 | self.identifier = [dict objectForKey:@"id"]; 19 | self.kind = [dict objectForKey:@"kind"]; 20 | self.lastModified = [NSDate date]; 21 | self.permalink = [dict objectForKey:@"permalink"]; 22 | if ([[dict objectForKey:@"permalink_url"] isKindOfClass:[NSString class]]) 23 | self.permalinkUrl = [NSURL URLWithString:[dict objectForKey:@"permalink_url"]]; 24 | if ([[dict objectForKey:@"uri"] isKindOfClass:[NSString class]]) 25 | self.userUri = [NSURL URLWithString:[dict objectForKey:@"uri"]]; 26 | self.username = [dict objectForKey:@"username"]; 27 | } 28 | return self; 29 | } 30 | 31 | 32 | + (SoundCloudUser *)userForDict:(NSDictionary *)dict { 33 | SoundCloudUser *userToReturn = [[SoundCloudUser alloc]initWithDict:dict]; 34 | return userToReturn; 35 | } 36 | @end 37 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundcloudPlayer-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | de.call-a-nerd.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.4.2 21 | CFBundleSignature 22 | ???? 23 | CFBundleURLTypes 24 | 25 | 26 | CFBundleTypeRole 27 | Editor 28 | CFBundleURLName 29 | de.call-a-nerd.StreamCloud 30 | CFBundleURLSchemes 31 | 32 | streamcloud 33 | 34 | 35 | 36 | CFBundleVersion 37 | 443 38 | LSApplicationCategoryType 39 | public.app-category.music 40 | LSMinimumSystemVersion 41 | ${MACOSX_DEPLOYMENT_TARGET} 42 | NSHumanReadableCopyright 43 | Copyright © 2014 Call a Nerd. All rights reserved. 44 | NSMainNibFile 45 | MainMenu 46 | NSPrincipalClass 47 | StreamCloudApplication 48 | 49 | 50 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundcloudPlayer-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #ifdef __OBJC__ 8 | #import 9 | #endif 10 | -------------------------------------------------------------------------------- /SoundcloudPlayer/SoundcloudPlayer.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.network.client 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SoundcloudPlayer/StatusBarPlayerViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatusBarPlayerViewController.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 24.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface StatusBarPlayerViewController : NSViewController 12 | 13 | @property (nonatomic ,strong) IBOutlet NSImageView *coverArtImageView; 14 | @property (nonatomic, strong) IBOutlet NSTextField *artistLabel; 15 | @property (nonatomic, strong) IBOutlet NSTextField *trackLabel; 16 | @property (nonatomic, strong) IBOutlet NSImageView *overlayImageView; 17 | - (IBAction)playPauseButtonAction:(id)sender; 18 | - (IBAction)nextButtonAction:(id)sender; 19 | - (IBAction)previousButtonAction:(id)sender; 20 | - (IBAction)shuffleButtonAction:(id)sender; 21 | - (IBAction)repeatButtonAction:(id)sender; 22 | - (void)reloadImage; 23 | @end 24 | -------------------------------------------------------------------------------- /SoundcloudPlayer/StatusBarPlayerViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatusBarPlayerViewController.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 24.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "StatusBarPlayerViewController.h" 10 | #import "SharedAudioPlayer.h" 11 | #import "AFNetworking.h" 12 | #import "NSImage+RoundedCorners.h" 13 | #import "StreamCloudStyles.h" 14 | #import "SoundCloudTrack.h" 15 | #import "SoundCloudUser.h" 16 | 17 | @implementation StatusBarPlayerViewController 18 | 19 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { 20 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 21 | if (self){ 22 | 23 | } 24 | return self; 25 | } 26 | 27 | - (void)awakeFromNib { 28 | [self.coverArtImageView setImage:[StreamCloudStyles imageOfSoundCloudLogoWithFrame:NSMakeRect(0, 0, 320, 320)]]; 29 | [self.overlayImageView setImage:[StreamCloudStyles imageOfImageOverlayGradientViewWithFrame:NSMakeRect(0, 0, 320, 320)]]; 30 | 31 | [self reloadImage]; 32 | } 33 | 34 | - (void)reloadImage { 35 | SoundCloudTrack *currentObject = [SharedAudioPlayer sharedPlayer].currentItem; 36 | if (currentObject) { 37 | [self.trackLabel setStringValue:currentObject.title]; 38 | BOOL useAvatar = YES; 39 | if (currentObject.artworkUrl){ 40 | AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; 41 | manager.responseSerializer = [AFImageResponseSerializer serializer]; 42 | useAvatar = NO; 43 | NSString *artworkURL = currentObject.artworkUrl.absoluteString; 44 | artworkURL = [artworkURL stringByReplacingOccurrencesOfString:@"large" withString:@"t500x500"]; 45 | [manager GET:artworkURL parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { 46 | [self.coverArtImageView setImage:[responseObject roundCornersImageCornerRadius:4]]; 47 | 48 | 49 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 50 | NSLog(@"Failed to get image %@",error); 51 | }]; 52 | 53 | } 54 | [self.artistLabel setStringValue:currentObject.user.username]; 55 | if (useAvatar && currentObject.user.avatarUrl){ 56 | AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; 57 | manager.responseSerializer = [AFImageResponseSerializer serializer]; 58 | NSString *avatarURL = currentObject.user.avatarUrl.absoluteString; 59 | avatarURL = [avatarURL stringByReplacingOccurrencesOfString:@"large" withString:@"t500x500"]; 60 | [manager GET:avatarURL parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { 61 | [self.coverArtImageView setImage:[responseObject roundCornersImageCornerRadius:4]]; 62 | 63 | 64 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 65 | NSLog(@"Failed to get image %@",error); 66 | }]; 67 | } 68 | } 69 | 70 | } 71 | 72 | # pragma mark - IBActions 73 | 74 | - (IBAction)playPauseButtonAction:(id)sender { 75 | [[SharedAudioPlayer sharedPlayer] togglePlayPause]; 76 | } 77 | - (IBAction)nextButtonAction:(id)sender { 78 | [[SharedAudioPlayer sharedPlayer] nextItem]; 79 | } 80 | - (IBAction)previousButtonAction:(id)sender { 81 | [[SharedAudioPlayer sharedPlayer] previousItem]; 82 | } 83 | - (IBAction)shuffleButtonAction:(id)sender { 84 | [[SharedAudioPlayer sharedPlayer] setShuffleEnabled:![SharedAudioPlayer sharedPlayer].shuffleEnabled]; 85 | } 86 | - (IBAction)repeatButtonAction:(id)sender { 87 | [[SharedAudioPlayer sharedPlayer] toggleRepeatMode]; 88 | } 89 | 90 | @end 91 | -------------------------------------------------------------------------------- /SoundcloudPlayer/StatusBarPlayerViewController.xib: -------------------------------------------------------------------------------- 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 | 51 | 63 | 75 | 87 | 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 | -------------------------------------------------------------------------------- /SoundcloudPlayer/StreamCloudApplication.h: -------------------------------------------------------------------------------- 1 | // 2 | // StreamCloudApplication.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 16.07.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface StreamCloudApplication : NSApplication 13 | 14 | 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /SoundcloudPlayer/StreamCloudApplication.m: -------------------------------------------------------------------------------- 1 | // 2 | // StreamCloudApplication.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 16.07.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "StreamCloudApplication.h" 10 | #define SPSystemDefinedEventMediaKeys 8 11 | #define NX_KEYTYPE_PLAY 16 12 | #define NX_KEYTYPE_NEXT 17 13 | #define NX_KEYTYPE_PREVIOUS 18 14 | #define NX_KEYTYPE_FAST 19 15 | #define NX_KEYTYPE_REWIND 20 16 | 17 | @implementation StreamCloudApplication 18 | 19 | - (void)sendEvent:(NSEvent *)event 20 | { 21 | #pragma clang diagnostic push 22 | #pragma clang diagnostic ignored "-Wundeclared-selector" 23 | if ([event type] == NSKeyDown) 24 | { 25 | 26 | NSString *str = [event characters]; 27 | if([str characterAtIndex:0] == 0x20) // spacebar 28 | { 29 | [super sendAction:@selector(spaceBarPressed:) to:nil from:self]; 30 | } 31 | else if ([str characterAtIndex:0] == 0xF703) // right Arrow 32 | { 33 | 34 | [super sendAction:@selector(rightKeyPressed:) to:nil from:self]; 35 | } else if ([str characterAtIndex:0] == 0xF702) // left Arrow 36 | { 37 | [super sendAction:@selector(leftKeyPressed:) to:nil from:self]; 38 | } 39 | else // added this 40 | [super sendEvent:event]; // 41 | 42 | } else if ([event type] == NSSystemDefined && [event subtype] == SPSystemDefinedEventMediaKeys) { 43 | int keyCode = (([event data1] & 0xFFFF0000) >> 16); 44 | int keyFlags = ([event data1] & 0x0000FFFF); 45 | BOOL keyIsPressed = (((keyFlags & 0xFF00) >> 8)) == 0xA; 46 | int keyRepeat = (keyFlags & 0x1); 47 | if (keyIsPressed && keyRepeat == 0) { 48 | switch (keyCode) { 49 | case NX_KEYTYPE_PLAY: 50 | [super sendAction:@selector(spaceBarPressed:) to:nil from:self]; 51 | break; 52 | case NX_KEYTYPE_NEXT: 53 | case NX_KEYTYPE_FAST: 54 | [super sendAction:@selector(rightKeyPressed:) to:nil from:self]; 55 | break; 56 | case NX_KEYTYPE_PREVIOUS: 57 | case NX_KEYTYPE_REWIND: 58 | [super sendAction:@selector(leftKeyPressed:) to:nil from:self]; 59 | break; 60 | default: 61 | break; 62 | } 63 | } 64 | } 65 | else // and this 66 | [super sendEvent:event]; 67 | # pragma clang diagnostic pop 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /SoundcloudPlayer/StreamCloudStyles.h: -------------------------------------------------------------------------------- 1 | // 2 | // StreamCloudStyles.h 3 | // StreamCloud 4 | // 5 | // Created by Peter Amende on 19.01.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | // Generated by PaintCode (www.paintcodeapp.com) 9 | // 10 | 11 | #import 12 | #import 13 | 14 | 15 | @interface StreamCloudStyles : NSObject 16 | 17 | // Colors 18 | + (NSColor*)orangeLight; 19 | + (NSColor*)orangeDark; 20 | + (NSColor*)grayMedium; 21 | + (NSColor*)grayDark; 22 | + (NSColor*)grayMediumLight; 23 | + (NSColor*)grayLight; 24 | + (NSColor*)seperatorColor; 25 | + (NSColor*)artistLabelColor; 26 | + (NSColor*)durationLabelColor; 27 | 28 | // Gradients 29 | + (NSGradient*)orangeGradient; 30 | 31 | // Drawing Methods 32 | + (void)drawPlayPauseButtonWithFrame: (NSRect)frame playing: (BOOL)playing; 33 | + (void)drawNextButtonWithFrame: (NSRect)frame; 34 | + (void)drawPreviousButtonWithFrame: (NSRect)frame; 35 | + (void)drawShuffleButtonWithFrame: (NSRect)frame active: (BOOL)active; 36 | + (void)drawRepeatButtonWithFrame: (NSRect)frame repeatMode: (CGFloat)repeatMode; 37 | + (void)drawVolumeSettingsWithFrame: (NSRect)frame volumeToShow: (CGFloat)volumeToShow; 38 | + (void)drawPlayingIndicatorWithFrame: (NSRect)frame; 39 | + (void)drawPlayPauseOverlayWithFrame: (NSRect)frame playing: (BOOL)playing; 40 | + (void)drawTrackDownloadWithFrame: (NSRect)frame; 41 | + (void)drawTrackRepostWithFrame: (NSRect)frame; 42 | + (void)drawTrackLikeWithFrame: (NSRect)frame; 43 | + (void)drawSeperatorViewWithFrame: (NSRect)frame; 44 | + (void)drawPlayingOverlayWithFrame: (NSRect)frame; 45 | + (void)drawLargePlayPauseOverlayWithFrame: (NSRect)frame playing: (BOOL)playing; 46 | + (void)drawSetListOpenClose; 47 | + (void)drawTrackDetailWithFrame: (NSRect)frame; 48 | + (void)drawTrackIsRepostWithFrame: (NSRect)frame; 49 | + (void)drawPlaylistUpperShadowOverlayWithFrame: (NSRect)frame; 50 | + (void)drawPlaylistLowerShadowOverlayWithFrame: (NSRect)frame; 51 | + (void)drawLoginButtonWithFrame: (NSRect)frame; 52 | + (void)drawSoundCloudLogoWithFrame: (NSRect)frame; 53 | + (void)drawProgressSliderTrackWithFrame: (NSRect)frame; 54 | + (void)drawProgressSliderProgressWithFrame: (NSRect)frame; 55 | + (void)drawProgressIndicatorViewWithPercentShown: (CGFloat)percentShown; 56 | + (void)drawProgressSliderKnobWithFrame: (NSRect)frame; 57 | + (void)drawIconFollowerWithFrame: (NSRect)frame; 58 | + (void)drawIconTracksWithFrame: (NSRect)frame active: (BOOL)active; 59 | + (void)drawTabTracksWithFrame: (NSRect)frame; 60 | + (void)drawTabProfileWithFrame: (NSRect)frame; 61 | + (void)drawIconFavoritesWithFrame: (NSRect)frame active: (BOOL)active; 62 | 63 | // Generated Images 64 | + (NSImage*)imageOfPlayPauseButtonWithFrame: (NSRect)frame playing: (BOOL)playing; 65 | + (NSImage*)imageOfNextButtonWithFrame: (NSRect)frame; 66 | + (NSImage*)imageOfPreviousButtonWithFrame: (NSRect)frame; 67 | + (NSImage*)imageOfShuffleButtonWithFrame: (NSRect)frame active: (BOOL)active; 68 | + (NSImage*)imageOfRepeatButtonWithFrame: (NSRect)frame repeatMode: (CGFloat)repeatMode; 69 | + (NSImage*)imageOfPlayingIndicatorWithFrame: (NSRect)frame; 70 | + (NSImage*)imageOfImageOverlayGradientViewWithFrame: (NSRect)frame; 71 | + (NSImage*)imageOfSoundCloudLogoWithFrame: (NSRect)frame; 72 | + (NSImage*)imageOfMenuBarIconWithActive: (BOOL)active; 73 | + (NSImage*)imageOfIconTracksWithFrame: (NSRect)frame active: (BOOL)active; 74 | + (NSImage*)imageOfIconFavoritesWithFrame: (NSRect)frame active: (BOOL)active; 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /SoundcloudPlayer/TrackCellForPlaylistItemView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TrackCellForPlaylistItemView.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 28.07.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "TrackCellView.h" 11 | #import "SeperatorView.h" 12 | #import "UpperShadowView.h" 13 | #import "LowerShadowView.h" 14 | 15 | @interface TrackCellForPlaylistItemView : TrackCellView 16 | 17 | @property (nonatomic, strong) IBOutlet SeperatorView *seperatorView; 18 | @property (nonatomic, strong) IBOutlet UpperShadowView *upperShadowView; 19 | @property (nonatomic, strong) IBOutlet LowerShadowView *lowerShadowView; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /SoundcloudPlayer/TrackCellForPlaylistItemView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TrackCellForPlaylistItemView.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 28.07.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "TrackCellForPlaylistItemView.h" 10 | #import "StreamCloudStyles.h" 11 | 12 | @implementation TrackCellForPlaylistItemView 13 | 14 | - (void)awakeFromNib { 15 | [super awakeFromNib]; 16 | [self.artworkView setShowLargePlayPauseView:YES]; 17 | } 18 | 19 | - (void)drawRect:(NSRect)dirtyRect 20 | { 21 | NSRect bounds = [self bounds]; 22 | 23 | if (super.mouseInside){ 24 | [[NSColor colorWithWhite:0.92 alpha:1.000]set]; 25 | } else { 26 | [[NSColor colorWithWhite:0.97 alpha:1.000]set]; 27 | } 28 | 29 | NSRectFill(bounds); 30 | 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /SoundcloudPlayer/TrackCellView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TrackCellView.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 24.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MouseOverImageView.h" 11 | #import "ClickableTextField.h" 12 | @interface TrackCellView : NSTableCellView 13 | 14 | @property (nonatomic, strong) IBOutlet ClickableTextField *titleLabel; 15 | @property (nonatomic, strong) IBOutlet MouseOverImageView *artworkView; 16 | @property (nonatomic, strong) IBOutlet ClickableTextField *artistLabel; 17 | @property (nonatomic, strong) IBOutlet NSTextField *durationLabel; 18 | @property (nonatomic ,strong) IBOutlet NSButton *pausePlayButton; 19 | @property (nonatomic, strong) IBOutlet NSView *playingIndicatiorView; 20 | @property (nonatomic, strong) IBOutlet NSView *seperatorView; 21 | @property (nonatomic) NSInteger row; 22 | @property (nonatomic) BOOL mouseInside; 23 | 24 | - (void)markAsPlaying:(BOOL)playing; 25 | @end 26 | -------------------------------------------------------------------------------- /SoundcloudPlayer/TrackCellView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TrackCellView.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 24.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "TrackCellView.h" 10 | #import "StreamCloudStyles.h" 11 | 12 | @interface TrackCellView () 13 | 14 | @property (nonatomic, strong) NSTrackingArea *trackingArea; 15 | 16 | @property (nonatomic) BOOL markedAsPlaying; 17 | 18 | @end 19 | 20 | @implementation TrackCellView 21 | 22 | - (void)awakeFromNib { 23 | [self.artistLabel setTextColor:[StreamCloudStyles artistLabelColor]]; 24 | [self markAsPlaying:NO]; 25 | [self.durationLabel setTextColor:[StreamCloudStyles durationLabelColor]]; 26 | } 27 | 28 | - (id)initWithCoder:(NSCoder *)aDecoder { 29 | self = [super initWithCoder:aDecoder]; 30 | if (self){ 31 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateTrackingAreas) name:@"SongTableViewDidScroll" object:nil]; 32 | } 33 | return self; 34 | } 35 | 36 | - (BOOL)canDrawSubviewsIntoLayer { 37 | return YES; 38 | } 39 | 40 | - (void)dealloc { 41 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 42 | } 43 | 44 | - (void)setRow:(NSInteger)row { 45 | _row = row; 46 | [self.artworkView setRow:row]; 47 | } 48 | 49 | - (void)setMouseInside:(BOOL)mouseInside { 50 | _mouseInside = mouseInside; 51 | [self setNeedsDisplay:YES]; 52 | } 53 | 54 | - (void)markAsPlaying:(BOOL)playing { 55 | if (playing){ 56 | [self.playingIndicatiorView setHidden:NO]; 57 | [self.playingIndicatiorView setNeedsDisplay:YES]; 58 | [self.titleLabel setTextColor:[StreamCloudStyles orangeDark]]; 59 | } else { 60 | [self.playingIndicatiorView setHidden:YES]; 61 | [self.titleLabel setTextColor:[NSColor blackColor]]; 62 | 63 | } 64 | [self.artworkView setPlaying:playing]; 65 | [self setMarkedAsPlaying:playing]; 66 | } 67 | 68 | - (void)setMarkedAsPlaying:(BOOL)markedAsPlaying { 69 | _markedAsPlaying = markedAsPlaying; 70 | self.mouseInside = _mouseInside; 71 | [self setNeedsDisplay:YES]; 72 | } 73 | 74 | 75 | # pragma mark - Drawing 76 | 77 | - (void)drawRect:(NSRect)dirtyRect 78 | { 79 | NSRect bounds = [self bounds]; 80 | 81 | if (_mouseInside){ 82 | [[NSColor colorWithRed:0.98 green:0.98 blue:0.98 alpha:1] set]; 83 | } else { 84 | [[NSColor colorWithRed:1 green:1 blue:1 alpha:1] set]; 85 | } 86 | 87 | NSRectFill(bounds); 88 | 89 | } 90 | 91 | # pragma mark - MouseDown 92 | 93 | - (void)mouseDown:(NSEvent *)theEvent { 94 | NSPoint selfPoint = [self convertPoint:theEvent.locationInWindow fromView:nil]; 95 | if (CGRectContainsPoint(self.artistLabel.frame, selfPoint)) { 96 | [self.artistLabel mouseDown:theEvent]; 97 | } 98 | if (CGRectContainsPoint(self.titleLabel.frame, selfPoint)) { 99 | [self.titleLabel mouseDown:theEvent]; 100 | } 101 | } 102 | 103 | # pragma mark - Mouse Over Managment 104 | 105 | - (void) createTrackingArea { 106 | int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways); 107 | _trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds] 108 | options:opts 109 | owner:self 110 | userInfo:nil]; 111 | [self addTrackingArea:_trackingArea]; 112 | 113 | NSPoint mouseLocation = [[self window] mouseLocationOutsideOfEventStream]; 114 | mouseLocation = [self convertPoint: mouseLocation fromView: nil]; 115 | 116 | if (NSPointInRect(mouseLocation, self.bounds)){ 117 | [self mouseEntered:nil]; 118 | } else { 119 | [self mouseExited:nil]; 120 | } 121 | 122 | } 123 | 124 | 125 | - (void)updateTrackingAreas { 126 | [self removeTrackingArea:_trackingArea]; 127 | [self createTrackingArea]; 128 | [super updateTrackingAreas]; 129 | } 130 | 131 | - (void)mouseEntered:(NSEvent *)theEvent { 132 | [self setMouseInside:YES]; 133 | [self setNeedsDisplay:YES]; 134 | [self.artworkView cursorEntered]; 135 | } 136 | 137 | - (void)mouseExited:(NSEvent *)theEvent { 138 | [self setMouseInside:NO]; 139 | [self setNeedsDisplay:YES]; 140 | [self.artworkView cursorExited]; 141 | } 142 | 143 | 144 | @end 145 | -------------------------------------------------------------------------------- /SoundcloudPlayer/UpperShadowView.h: -------------------------------------------------------------------------------- 1 | // 2 | // UpperShadowView.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 19.01.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UpperShadowView : NSView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SoundcloudPlayer/UpperShadowView.m: -------------------------------------------------------------------------------- 1 | // 2 | // UpperShadowView.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 19.01.15. 6 | // Copyright (c) 2015 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "UpperShadowView.h" 10 | #import "StreamCloudStyles.h" 11 | 12 | @implementation UpperShadowView 13 | 14 | - (void)drawRect:(NSRect)dirtyRect { 15 | [StreamCloudStyles drawPlaylistUpperShadowOverlayWithFrame:dirtyRect]; 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /SoundcloudPlayer/VolumeButtonCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // VolumeButtonCell.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 25.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface VolumeButtonCell : NSButtonCell 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SoundcloudPlayer/VolumeButtonCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // VolumeButtonCell.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 25.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "VolumeButtonCell.h" 10 | #import "StreamCloudStyles.h" 11 | #import "SharedAudioPlayer.h" 12 | @implementation VolumeButtonCell 13 | 14 | - (void)drawBezelWithFrame:(NSRect)frame inView:(NSView *)controlView { 15 | float volumeToUse =[SharedAudioPlayer sharedPlayer].audioPlayer.volume*100; 16 | if ([SharedAudioPlayer sharedPlayer].audioPlayer){ 17 | [StreamCloudStyles drawVolumeSettingsWithFrame:frame volumeToShow:volumeToUse]; 18 | } else { 19 | [StreamCloudStyles drawVolumeSettingsWithFrame:frame volumeToShow:100]; 20 | } 21 | } 22 | 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /SoundcloudPlayer/WhiteBackgroundView.h: -------------------------------------------------------------------------------- 1 | // 2 | // WhiteBackgroundView.h 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 25.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface WhiteBackgroundView : NSView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SoundcloudPlayer/WhiteBackgroundView.m: -------------------------------------------------------------------------------- 1 | // 2 | // WhiteBackgroundView.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 25.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import "WhiteBackgroundView.h" 10 | 11 | @implementation WhiteBackgroundView 12 | 13 | - (id)initWithFrame:(NSRect)frame 14 | { 15 | self = [super initWithFrame:frame]; 16 | if (self) { 17 | // Initialization code here. 18 | } 19 | return self; 20 | } 21 | 22 | - (void)drawRect:(NSRect)dirtyRect 23 | { 24 | [super drawRect:dirtyRect]; 25 | 26 | [[NSColor whiteColor] setFill]; 27 | NSRectFill(dirtyRect); 28 | [super drawRect:dirtyRect]; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /SoundcloudPlayer/en.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} 2 | {\colortbl;\red255\green255\blue255;} 3 | \paperw9840\paperh8400 4 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural 5 | 6 | \f0\b\fs24 \cf0 Engineering: 7 | \b0 \ 8 | Some people\ 9 | \ 10 | 11 | \b Human Interface Design: 12 | \b0 \ 13 | Some other people\ 14 | \ 15 | 16 | \b Testing: 17 | \b0 \ 18 | Hopefully not nobody\ 19 | \ 20 | 21 | \b Documentation: 22 | \b0 \ 23 | Whoever\ 24 | \ 25 | 26 | \b With special thanks to: 27 | \b0 \ 28 | Mom\ 29 | } 30 | -------------------------------------------------------------------------------- /SoundcloudPlayer/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /SoundcloudPlayer/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // SoundcloudPlayer 4 | // 5 | // Created by Philip Brechler on 20.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, const char * argv[]) 12 | { 13 | return NSApplicationMain(argc, argv); 14 | } 15 | -------------------------------------------------------------------------------- /SoundcloudPlayer/singleton.h: -------------------------------------------------------------------------------- 1 | #define MAKE_SINGLETON(class_name, shared_method_name) \ 2 | + (id)shared_method_name { \ 3 | static dispatch_once_t pred; \ 4 | static class_name * z ## class_name ## _ = nil; \ 5 | dispatch_once(&pred, ^{ \ 6 | z ## class_name ## _ = [[self alloc] init]; \ 7 | }); \ 8 | return z ## class_name ## _; \ 9 | } \ 10 | - (id)copy { \ 11 | return self; \ 12 | }/* 13 | - (id)retain { \ 14 | return self; \ 15 | } \ 16 | - (NSUInteger)retainCount { \ 17 | return UINT_MAX; \ 18 | } \ 19 | - (void)release { \ 20 | } \ 21 | - (id)autorelease { \ 22 | return self; \ 23 | } 24 | */ -------------------------------------------------------------------------------- /SoundcloudPlayerTests/SoundcloudPlayerTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | de.call-a-nerd.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SoundcloudPlayerTests/SoundcloudPlayerTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // SoundcloudPlayerTests.m 3 | // SoundcloudPlayerTests 4 | // 5 | // Created by Philip Brechler on 20.06.14. 6 | // Copyright (c) 2014 Call a Nerd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SoundcloudPlayerTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation SoundcloudPlayerTests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /SoundcloudPlayerTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /StreamCloud copy-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | de.call-a-nerd.$(PRODUCT_NAME:rfc1034identifier) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.4.2 21 | CFBundleSignature 22 | ???? 23 | CFBundleURLTypes 24 | 25 | 26 | CFBundleTypeRole 27 | Editor 28 | CFBundleURLName 29 | de.call-a-nerd.StreamCloud 30 | CFBundleURLSchemes 31 | 32 | streamcloudbeta 33 | 34 | 35 | 36 | CFBundleVersion 37 | 450 38 | LSApplicationCategoryType 39 | public.app-category.music 40 | LSMinimumSystemVersion 41 | ${MACOSX_DEPLOYMENT_TARGET} 42 | NSHumanReadableCopyright 43 | Copyright © 2014 Call a Nerd. All rights reserved. 44 | NSMainNibFile 45 | MainMenu 46 | NSPrincipalClass 47 | StreamCloudApplication 48 | 49 | 50 | -------------------------------------------------------------------------------- /streamcloud-icons.pcvd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/streamcloudapp/StreamCloud/c2c96fb98653790d1159f23f3b8667723f9faad8/streamcloud-icons.pcvd -------------------------------------------------------------------------------- /streamcloud_beta.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beta_over 6 | 7 | 8 | 9 | --------------------------------------------------------------------------------