Skip to content

Commit 01bfb8a

Browse files
authored
Merge pull request #81 from analogcode/dev
Swift Radio Version 2
2 parents 0dd41dc + 22a1917 commit 01bfb8a

File tree

64 files changed

+1908
-2665
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1908
-2665
lines changed

README.md

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
# Swift Radio
22

3-
Swift Radio is an open source radio station app with robust and professional features. This is a fully realized Radio App built entirely in Swift. **Master is now the Xcode 9.0/Swift 4 branch**. Note there is an AVPlayer branch [here](https://github.com/swiftcodex/Swift-Radio-Pro/tree/xcode8).
3+
Swift Radio is an open source radio station app with robust and professional features. This is a fully realized Radio App built entirely in Swift. **Master is now the Xcode 9 / Swift 4 branch**.
44

55
There are over 80 different apps accepted to the app store using this code!
66

7-
![alt text](http://matthewfecher.com/wp-content/uploads/2015/09/screen-1.jpg "Swift Radio")
7+
<p align="center">
8+
<img alt="Swift Radio" src="https://fethica.com/img/web/swift-radio.jpg">
9+
</p>
810

911
## Video
1012
View this [**GETTING STARTED VIDEO**](https://youtu.be/m7jiajCHFvc).
@@ -13,18 +15,22 @@ Give it a quick watch.
1315

1416
## Features
1517

16-
- LastFM API and iTunes API Integration to automatically download Album Art
17-
- Parses metadata from streams (Track & Artist information)
1818
- Ability to update Stations from server or locally. (Update stations anytime without resubmitting to app store!)
1919
- Displays Artist, Track & Album Art on Lock Screen
2020
- Custom views optimized for 5, 6 and 6+ for backwards compatibility
21-
- Compiles with Xcode 9.0 & Swift 4.0
21+
- Compiles with Xcode 9 & Swift 4
22+
- Parses JSON using Swift 4 Codable protocol
2223
- Background audio performance
2324
- Search Bar that can be turned on or off to search stations
2425
- Supports local or hosted station images
2526
- "About" screen with ability to send email & visit website
26-
- Uses industry standard SwiftyJSON library for easy JSON manipulation
2727
- Pull to Refresh stations
28+
- Uses the AVPlayer wrapper library [FRadioPlayer](https://github.com/fethica/FRadioPlayer):
29+
* Automatically download Album Art from iTunes API
30+
* Parses metadata from streams (Track & Artist information)
31+
- Uses [Spring](https://github.com/MengTo/Spring) library:
32+
* Animate UI components
33+
* Download and cache images using ImageLoader class
2834

2935
## Important Notes
3036
- 10.6.17 Update: The AVPlayer branch migrated to Xcode 9/Swift 4 by [@joemcmahon](https://github.com/joemcmahon).
@@ -72,7 +78,7 @@ Some of the things I've built into this Radio code for clients include: Facebook
7278

7379
## Setup
7480

75-
The "SwiftRadio-Settings.swift" file contains some project settings to get you started. If you use LastFM, please enter your own LastFM Key.
81+
The "SwiftRadio-Settings.swift" file contains some project settings to get you started.
7682
Watch this [Getting Started Video](https://youtu.be/m7jiajCHFvc) to get up & running quickly.
7783

7884
## Integration
@@ -95,7 +101,7 @@ Includes an example "stations.json" file. You may upload the JSON file to a serv
95101

96102
## Contributions
97103

98-
Contributions are very welcome. Please create a separate branch (e.g. features/3dtouch). Please do not commit on master.
104+
Contributions are very welcome. Please check out the [dev branch](https://github.com/analogcode/Swift-Radio-Pro/tree/dev), create a separate branch (e.g. features/3dtouch). Please do not commit on master.
99105

100106
## FAQ
101107

@@ -105,20 +111,8 @@ A: Nope. This is completely open source, you can do whatever you want with it. I
105111
Q: How do I make my app support ipv6 networks?
106112
A: For an app to be accepted by Apple to the app store as of June 1, 2016, you CAN NOT use number IP addresses. i.e. You must use something like "http://mystream.com/rock" instead of "http://44.120.33.55/" for your station stream URLs.
107113

108-
Q: Isn't MPMoviePlayer going to be depreciated?
109-
A: Yes, eventually master should be migrated to use AVPlayer instead. If you'd like to work on it, feel free! There are currently two branches that use AVPlayer instead of MPMoviePlayer. A Swift 2/Xcode 7 version [here](https://github.com/swiftcodex/Swift-Radio-Pro/tree/avplayer). and a Swift 2.3/Xcode 8 version [here](https://github.com/swiftcodex/Swift-Radio-Pro/tree/xcode8).
110-
111114
Q: Is there an example of using this with the Spotify API?
112-
A: Yes, there is a branch here that uses it [here]( https://github.com/swiftcodex/Swift-Radio-Pro/tree/avplayer).
113-
114-
Q: How do I use the iTunes API instead of LastFM?
115-
A: In the SwiftRadio-Settings.swift file, set the "useLastFM" key to "false". You do not need an API key to use the iTunes API. It is free.
116-
117-
Q: The LastFM site isn't working properly? I can't create an API key.
118-
A: LastFM will sometimes put API signups on hold. You can check back later or try a different API.
119-
120-
Q: It looks like your LastFM api key and secret might have been left in the code?
121-
A: Yes, people may use it for small amounts of testing. However, I ask that you change it before submitting to the app store. (Plus, it would be self-defeating for someone to submit it to the app store with the testing keys, as it would quickly throttle out and their album art downloads would stop working!)
115+
A: Yes, there is a branch here that uses it [here]( https://github.com/swiftcodex/Swift-Radio-Pro/tree/avplayer) (⚠️ **deprecated**).
122116

123117
Q: Is there another API to get album/track information besides LastFM, Spotify, and iTunes?
124118
A: Rovi has a pretty sweet [music API](http://prod-doc.rovicorp.com/mashery/index.php/Data/APIs/Rovi-Music). The [Echo Nest](http://developer.echonest.com/) has all kinds of APIs that are fun to play with.
@@ -133,10 +127,10 @@ Q: Can you help me add a feature? Can you help me understand the code? Can you h
133127
A: While I have a full-time job and other project obligations, I'd highly recommend you find a developer or mentor in your area to help. The code is well-documented and most developers should be able to help you rather quickly. While I am sometimes available for paid freelance work, see below in the readme, **I am not able to provide any free support or modifications.** Thank you for understanding!
134128

135129
Q: The song names aren't appearing for my station?
136-
A: Check with your stream provider to make sure they are sending Metadata properly. If a station sends data in a unique way, you can modify the way the app parses the metadata in the "metadataUpdated" method in the NowPlayingViewController.
130+
A: Check with your stream provider to make sure they are sending Metadata properly. If a station sends data in a unique way, you can modify the way the app parses the metadata, in the `RadioPlayer` class implement `FRadioPlayerDelegate` method: `radioPlayer(_ player: FRadioPlayer, metadataDidChange rawValue: String?)`.
137131

138132
## Single Station Branch
139-
There's now a branch without the StationsViewController. This is so you can use this code as a starting place for an app for just one radio station. View that [Branch Here](https://github.com/swiftcodex/Swift-Radio-Pro/tree/single-station).
133+
There's now a branch without the StationsViewController. This is so you can use this code as a starting place for an app for just one radio station. View that [Branch Here](https://github.com/swiftcodex/Swift-Radio-Pro/tree/single-station) (⚠️ **deprecated**).
140134

141135
## RadioKit SDK Example
142136

SwiftRadio.xcodeproj/project.pbxproj

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
/* Begin PBXBuildFile section */
1010
2C5545BD1C1124DE00728469 /* SwiftRadioUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C5545BC1C1124DE00728469 /* SwiftRadioUITests.swift */; };
11-
5F22B9E01F72ABEF00CB5911 /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F22B9DF1F72ABEF00CB5911 /* SwiftyJSON.swift */; };
1211
5F22BA3C1F72AD5A00CB5911 /* SpringLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F22BA1E1F72AD3700CB5911 /* SpringLabel.swift */; };
1312
5F22BA3D1F72AD5A00CB5911 /* BlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F22BA1F1F72AD3900CB5911 /* BlurView.swift */; };
1413
5F22BA3E1F72AD5A00CB5911 /* DesignableTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F22BA201F72AD3B00CB5911 /* DesignableTabBarController.swift */; };
@@ -46,7 +45,6 @@
4645
94452E551AD7086800BFE7A5 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94452E541AD7086800BFE7A5 /* AboutViewController.swift */; };
4746
945DB3C21AD58E3A00495EBB /* stations.json in Resources */ = {isa = PBXBuildFile; fileRef = 945DB3C11AD58E3A00495EBB /* stations.json */; };
4847
945DB3C51AD5A6E200495EBB /* NothingFoundCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 945DB3C41AD5A6E200495EBB /* NothingFoundCell.xib */; };
49-
94817DFB1B547D5700D3FA23 /* Player.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94817DFA1B547D5700D3FA23 /* Player.swift */; };
5048
949BBB401ACC9DEE005B7C26 /* DataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 949BBB3F1ACC9DEE005B7C26 /* DataManager.swift */; };
5149
949E5EB01ACB340200AB6280 /* UIImageView+Download.swift in Sources */ = {isa = PBXBuildFile; fileRef = 949E5EAF1ACB340200AB6280 /* UIImageView+Download.swift */; };
5250
94AC70AE1AD05C6200652982 /* RadioStation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94AC70AD1AD05C6200652982 /* RadioStation.swift */; };
@@ -56,6 +54,9 @@
5654
94D260981B45E8B800DE671C /* Track.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D260971B45E8B800DE671C /* Track.swift */; };
5755
94D30EA71AD07A880024FE96 /* StationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D30EA61AD07A880024FE96 /* StationTableViewCell.swift */; };
5856
94E9761C1B1A8F3200F52B1E /* UIImage+DropShadow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94E9761B1B1A8F3200F52B1E /* UIImage+DropShadow.swift */; };
57+
CAA7C15D1FD77F3A003CABDF /* FRadioAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAA7C15B1FD77F3A003CABDF /* FRadioAPI.swift */; };
58+
CAA7C15E1FD77F3A003CABDF /* FRadioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAA7C15C1FD77F3A003CABDF /* FRadioPlayer.swift */; };
59+
CAA8FDB52000614600050F77 /* RadioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAA8FDB42000614600050F77 /* RadioPlayer.swift */; };
5960
/* End PBXBuildFile section */
6061

6162
/* Begin PBXContainerItemProxy section */
@@ -72,7 +73,6 @@
7273
2C5545BA1C1124DE00728469 /* SwiftRadioUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftRadioUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
7374
2C5545BC1C1124DE00728469 /* SwiftRadioUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftRadioUITests.swift; sourceTree = "<group>"; };
7475
2C5545BE1C1124DE00728469 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
75-
5F22B9DF1F72ABEF00CB5911 /* SwiftyJSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftyJSON.swift; sourceTree = "<group>"; };
7676
5F22BA1E1F72AD3700CB5911 /* SpringLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpringLabel.swift; sourceTree = "<group>"; };
7777
5F22BA1F1F72AD3900CB5911 /* BlurView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurView.swift; sourceTree = "<group>"; };
7878
5F22BA201F72AD3B00CB5911 /* DesignableTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DesignableTabBarController.swift; sourceTree = "<group>"; };
@@ -115,7 +115,6 @@
115115
94452E541AD7086800BFE7A5 /* AboutViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = "<group>"; };
116116
945DB3C11AD58E3A00495EBB /* stations.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = stations.json; sourceTree = "<group>"; };
117117
945DB3C41AD5A6E200495EBB /* NothingFoundCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NothingFoundCell.xib; sourceTree = "<group>"; };
118-
94817DFA1B547D5700D3FA23 /* Player.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Player.swift; sourceTree = "<group>"; };
119118
949BBB3F1ACC9DEE005B7C26 /* DataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataManager.swift; sourceTree = "<group>"; };
120119
949E5EAF1ACB340200AB6280 /* UIImageView+Download.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImageView+Download.swift"; sourceTree = "<group>"; };
121120
94AC70AD1AD05C6200652982 /* RadioStation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioStation.swift; sourceTree = "<group>"; };
@@ -126,6 +125,9 @@
126125
94D30EA61AD07A880024FE96 /* StationTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StationTableViewCell.swift; sourceTree = "<group>"; };
127126
94E9761B1B1A8F3200F52B1E /* UIImage+DropShadow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+DropShadow.swift"; sourceTree = "<group>"; };
128127
B90086461BBE40AF00E5372C /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; };
128+
CAA7C15B1FD77F3A003CABDF /* FRadioAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FRadioAPI.swift; sourceTree = "<group>"; };
129+
CAA7C15C1FD77F3A003CABDF /* FRadioPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FRadioPlayer.swift; sourceTree = "<group>"; };
130+
CAA8FDB42000614600050F77 /* RadioPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioPlayer.swift; sourceTree = "<group>"; };
129131
/* End PBXFileReference section */
130132

131133
/* Begin PBXFrameworksBuildPhase section */
@@ -158,7 +160,7 @@
158160
5F22B9DE1F72A8D800CB5911 /* Libraries */ = {
159161
isa = PBXGroup;
160162
children = (
161-
5F22B9DF1F72ABEF00CB5911 /* SwiftyJSON.swift */,
163+
CAA7C15A1FD77F3A003CABDF /* FRadioPlayer */,
162164
5F22BA1D1F72ACF100CB5911 /* Spring */,
163165
);
164166
path = Libraries;
@@ -223,12 +225,14 @@
223225
9409E1181ABF6FEA00312E2B /* SwiftRadio */ = {
224226
isa = PBXGroup;
225227
children = (
226-
94D2608E1B45D0F800DE671C /* ViewControllers */,
227228
94D2608F1B45D11800DE671C /* Cells */,
229+
94AC70AF1AD05C7400652982 /* Networking */,
228230
94823F861B5576F4004EC711 /* Data */,
229231
94E976191B1A8BFB00F52B1E /* Model */,
230-
94AC70AF1AD05C7400652982 /* Networking */,
232+
94D2608E1B45D0F800DE671C /* ViewControllers */,
231233
9409E11B1ABF6FEA00312E2B /* AppDelegate.swift */,
234+
CAA8FDB42000614600050F77 /* RadioPlayer.swift */,
235+
94D260901B45D20000DE671C /* SwiftRadio-Settings.swift */,
232236
9409E1221ABF6FEA00312E2B /* Main.storyboard */,
233237
9409E1251ABF6FEA00312E2B /* Images.xcassets */,
234238
9409E1191ABF6FEA00312E2B /* Supporting Files */,
@@ -242,7 +246,6 @@
242246
isa = PBXGroup;
243247
children = (
244248
9409E11A1ABF6FEA00312E2B /* Info.plist */,
245-
94D260901B45D20000DE671C /* SwiftRadio-Settings.swift */,
246249
5FDEE0211F72FF980064333C /* LaunchScreen.storyboard */,
247250
);
248251
name = "Supporting Files";
@@ -269,8 +272,8 @@
269272
children = (
270273
94452E541AD7086800BFE7A5 /* AboutViewController.swift */,
271274
94D1D0A41AD6D6230022CA11 /* InfoDetailViewController.swift */,
272-
9409E13F1ABF78B000312E2B /* NowPlayingViewController.swift */,
273275
94452E4E1AD6F24700BFE7A5 /* PopUpMenuViewController.swift */,
276+
9409E13F1ABF78B000312E2B /* NowPlayingViewController.swift */,
274277
942A3F361AE43DF80011396E /* StationsViewController.swift */,
275278
);
276279
name = ViewControllers;
@@ -299,12 +302,20 @@
299302
isa = PBXGroup;
300303
children = (
301304
94AC70AD1AD05C6200652982 /* RadioStation.swift */,
302-
94817DFA1B547D5700D3FA23 /* Player.swift */,
303305
94D260971B45E8B800DE671C /* Track.swift */,
304306
);
305307
name = Model;
306308
sourceTree = "<group>";
307309
};
310+
CAA7C15A1FD77F3A003CABDF /* FRadioPlayer */ = {
311+
isa = PBXGroup;
312+
children = (
313+
CAA7C15B1FD77F3A003CABDF /* FRadioAPI.swift */,
314+
CAA7C15C1FD77F3A003CABDF /* FRadioPlayer.swift */,
315+
);
316+
path = FRadioPlayer;
317+
sourceTree = "<group>";
318+
};
308319
/* End PBXGroup section */
309320

310321
/* Begin PBXNativeTarget section */
@@ -361,7 +372,7 @@
361372
};
362373
9409E1151ABF6FEA00312E2B = {
363374
CreatedOnToolsVersion = 6.2;
364-
DevelopmentTeam = G24WJ3XCZ3;
375+
DevelopmentTeam = G24WJ3XCZ3;
365376
LastSwiftMigration = 0900;
366377
SystemCapabilities = {
367378
com.apple.BackgroundModes = {
@@ -430,7 +441,6 @@
430441
5F22BA401F72AD5A00CB5911 /* SpringImageView.swift in Sources */,
431442
5F22BA511F72AD5A00CB5911 /* TransitionZoom.swift in Sources */,
432443
5F22BA471F72AD5A00CB5911 /* DesignableTextField.swift in Sources */,
433-
5F22B9E01F72ABEF00CB5911 /* SwiftyJSON.swift in Sources */,
434444
5F22BA4C1F72AD5A00CB5911 /* ImageLoader.swift in Sources */,
435445
5F22BA451F72AD5A00CB5911 /* DesignableLabel.swift in Sources */,
436446
94D260911B45D20000DE671C /* SwiftRadio-Settings.swift in Sources */,
@@ -452,7 +462,9 @@
452462
94452E551AD7086800BFE7A5 /* AboutViewController.swift in Sources */,
453463
5F22BA551F72AD5A00CB5911 /* AutoTextView.swift in Sources */,
454464
94D260981B45E8B800DE671C /* Track.swift in Sources */,
465+
CAA7C15E1FD77F3A003CABDF /* FRadioPlayer.swift in Sources */,
455466
5F22BA3F1F72AD5A00CB5911 /* LoadingView.swift in Sources */,
467+
CAA8FDB52000614600050F77 /* RadioPlayer.swift in Sources */,
456468
5F22BA4F1F72AD5A00CB5911 /* TransitionManager.swift in Sources */,
457469
5F22BA531F72AD5A00CB5911 /* SpringAnimation.swift in Sources */,
458470
94452E4F1AD6F24700BFE7A5 /* PopUpMenuViewController.swift in Sources */,
@@ -466,7 +478,7 @@
466478
942A3F371AE43DF80011396E /* StationsViewController.swift in Sources */,
467479
5F22BA501F72AD5A00CB5911 /* Spring.swift in Sources */,
468480
94AC70AE1AD05C6200652982 /* RadioStation.swift in Sources */,
469-
94817DFB1B547D5700D3FA23 /* Player.swift in Sources */,
481+
CAA7C15D1FD77F3A003CABDF /* FRadioAPI.swift in Sources */,
470482
5F22BA481F72AD5A00CB5911 /* DesignableButton.swift in Sources */,
471483
);
472484
runOnlyForDeploymentPostprocessing = 0;
Binary file not shown.

SwiftRadio/AboutViewController.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,16 @@ class AboutViewController: UIViewController {
3333
let configuredMailComposeViewController = configureMailComposeViewController(recepients: receipients, subject: subject, messageBody: messageBody)
3434

3535
if canSendMail() {
36-
self.present(configuredMailComposeViewController, animated: true, completion: nil)
36+
present(configuredMailComposeViewController, animated: true, completion: nil)
3737
} else {
3838
showSendMailErrorAlert()
3939
}
4040
}
4141

4242
@IBAction func websiteButtonDidTouch(_ sender: UIButton) {
43-
4443
// Use your own website here
45-
if let url = URL(string: "http://matthewfecher.com") {
46-
UIApplication.shared.openURL(url)
47-
}
44+
guard let url = URL(string: "http://matthewfecher.com") else { return }
45+
UIApplication.shared.openURL(url)
4846
}
4947

5048
}

0 commit comments

Comments
 (0)