Skip to content

Commit

Permalink
Merge pull request #81 from analogcode/dev
Browse files Browse the repository at this point in the history
Swift Radio Version 2
  • Loading branch information
fethica authored Jan 22, 2018
2 parents 0dd41dc + 22a1917 commit 01bfb8a
Show file tree
Hide file tree
Showing 64 changed files with 1,908 additions and 2,665 deletions.
40 changes: 17 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# Swift Radio

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).
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**.

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

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

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

## Features

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

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

## Setup

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

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

## Contributions

Contributions are very welcome. Please create a separate branch (e.g. features/3dtouch). Please do not commit on master.
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.

## FAQ

Expand All @@ -105,20 +111,8 @@ A: Nope. This is completely open source, you can do whatever you want with it. I
Q: How do I make my app support ipv6 networks?
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.

Q: Isn't MPMoviePlayer going to be depreciated?
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).

Q: Is there an example of using this with the Spotify API?
A: Yes, there is a branch here that uses it [here]( https://github.com/swiftcodex/Swift-Radio-Pro/tree/avplayer).

Q: How do I use the iTunes API instead of LastFM?
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.

Q: The LastFM site isn't working properly? I can't create an API key.
A: LastFM will sometimes put API signups on hold. You can check back later or try a different API.

Q: It looks like your LastFM api key and secret might have been left in the code?
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!)
A: Yes, there is a branch here that uses it [here]( https://github.com/swiftcodex/Swift-Radio-Pro/tree/avplayer) (⚠️ **deprecated**).

Q: Is there another API to get album/track information besides LastFM, Spotify, and iTunes?
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.
Expand All @@ -133,10 +127,10 @@ Q: Can you help me add a feature? Can you help me understand the code? Can you h
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!

Q: The song names aren't appearing for my station?
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.
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?)`.

## Single Station Branch
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).
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**).

## RadioKit SDK Example

Expand Down
38 changes: 25 additions & 13 deletions SwiftRadio.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

/* Begin PBXBuildFile section */
2C5545BD1C1124DE00728469 /* SwiftRadioUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C5545BC1C1124DE00728469 /* SwiftRadioUITests.swift */; };
5F22B9E01F72ABEF00CB5911 /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F22B9DF1F72ABEF00CB5911 /* SwiftyJSON.swift */; };
5F22BA3C1F72AD5A00CB5911 /* SpringLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F22BA1E1F72AD3700CB5911 /* SpringLabel.swift */; };
5F22BA3D1F72AD5A00CB5911 /* BlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F22BA1F1F72AD3900CB5911 /* BlurView.swift */; };
5F22BA3E1F72AD5A00CB5911 /* DesignableTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F22BA201F72AD3B00CB5911 /* DesignableTabBarController.swift */; };
Expand Down Expand Up @@ -46,7 +45,6 @@
94452E551AD7086800BFE7A5 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94452E541AD7086800BFE7A5 /* AboutViewController.swift */; };
945DB3C21AD58E3A00495EBB /* stations.json in Resources */ = {isa = PBXBuildFile; fileRef = 945DB3C11AD58E3A00495EBB /* stations.json */; };
945DB3C51AD5A6E200495EBB /* NothingFoundCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 945DB3C41AD5A6E200495EBB /* NothingFoundCell.xib */; };
94817DFB1B547D5700D3FA23 /* Player.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94817DFA1B547D5700D3FA23 /* Player.swift */; };
949BBB401ACC9DEE005B7C26 /* DataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 949BBB3F1ACC9DEE005B7C26 /* DataManager.swift */; };
949E5EB01ACB340200AB6280 /* UIImageView+Download.swift in Sources */ = {isa = PBXBuildFile; fileRef = 949E5EAF1ACB340200AB6280 /* UIImageView+Download.swift */; };
94AC70AE1AD05C6200652982 /* RadioStation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94AC70AD1AD05C6200652982 /* RadioStation.swift */; };
Expand All @@ -56,6 +54,9 @@
94D260981B45E8B800DE671C /* Track.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D260971B45E8B800DE671C /* Track.swift */; };
94D30EA71AD07A880024FE96 /* StationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D30EA61AD07A880024FE96 /* StationTableViewCell.swift */; };
94E9761C1B1A8F3200F52B1E /* UIImage+DropShadow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94E9761B1B1A8F3200F52B1E /* UIImage+DropShadow.swift */; };
CAA7C15D1FD77F3A003CABDF /* FRadioAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAA7C15B1FD77F3A003CABDF /* FRadioAPI.swift */; };
CAA7C15E1FD77F3A003CABDF /* FRadioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAA7C15C1FD77F3A003CABDF /* FRadioPlayer.swift */; };
CAA8FDB52000614600050F77 /* RadioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAA8FDB42000614600050F77 /* RadioPlayer.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand All @@ -72,7 +73,6 @@
2C5545BA1C1124DE00728469 /* SwiftRadioUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftRadioUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
2C5545BC1C1124DE00728469 /* SwiftRadioUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftRadioUITests.swift; sourceTree = "<group>"; };
2C5545BE1C1124DE00728469 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
5F22B9DF1F72ABEF00CB5911 /* SwiftyJSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftyJSON.swift; sourceTree = "<group>"; };
5F22BA1E1F72AD3700CB5911 /* SpringLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpringLabel.swift; sourceTree = "<group>"; };
5F22BA1F1F72AD3900CB5911 /* BlurView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurView.swift; sourceTree = "<group>"; };
5F22BA201F72AD3B00CB5911 /* DesignableTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DesignableTabBarController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -115,7 +115,6 @@
94452E541AD7086800BFE7A5 /* AboutViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = "<group>"; };
945DB3C11AD58E3A00495EBB /* stations.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = stations.json; sourceTree = "<group>"; };
945DB3C41AD5A6E200495EBB /* NothingFoundCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NothingFoundCell.xib; sourceTree = "<group>"; };
94817DFA1B547D5700D3FA23 /* Player.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Player.swift; sourceTree = "<group>"; };
949BBB3F1ACC9DEE005B7C26 /* DataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataManager.swift; sourceTree = "<group>"; };
949E5EAF1ACB340200AB6280 /* UIImageView+Download.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImageView+Download.swift"; sourceTree = "<group>"; };
94AC70AD1AD05C6200652982 /* RadioStation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioStation.swift; sourceTree = "<group>"; };
Expand All @@ -126,6 +125,9 @@
94D30EA61AD07A880024FE96 /* StationTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StationTableViewCell.swift; sourceTree = "<group>"; };
94E9761B1B1A8F3200F52B1E /* UIImage+DropShadow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+DropShadow.swift"; sourceTree = "<group>"; };
B90086461BBE40AF00E5372C /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; };
CAA7C15B1FD77F3A003CABDF /* FRadioAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FRadioAPI.swift; sourceTree = "<group>"; };
CAA7C15C1FD77F3A003CABDF /* FRadioPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FRadioPlayer.swift; sourceTree = "<group>"; };
CAA8FDB42000614600050F77 /* RadioPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioPlayer.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -158,7 +160,7 @@
5F22B9DE1F72A8D800CB5911 /* Libraries */ = {
isa = PBXGroup;
children = (
5F22B9DF1F72ABEF00CB5911 /* SwiftyJSON.swift */,
CAA7C15A1FD77F3A003CABDF /* FRadioPlayer */,
5F22BA1D1F72ACF100CB5911 /* Spring */,
);
path = Libraries;
Expand Down Expand Up @@ -223,12 +225,14 @@
9409E1181ABF6FEA00312E2B /* SwiftRadio */ = {
isa = PBXGroup;
children = (
94D2608E1B45D0F800DE671C /* ViewControllers */,
94D2608F1B45D11800DE671C /* Cells */,
94AC70AF1AD05C7400652982 /* Networking */,
94823F861B5576F4004EC711 /* Data */,
94E976191B1A8BFB00F52B1E /* Model */,
94AC70AF1AD05C7400652982 /* Networking */,
94D2608E1B45D0F800DE671C /* ViewControllers */,
9409E11B1ABF6FEA00312E2B /* AppDelegate.swift */,
CAA8FDB42000614600050F77 /* RadioPlayer.swift */,
94D260901B45D20000DE671C /* SwiftRadio-Settings.swift */,
9409E1221ABF6FEA00312E2B /* Main.storyboard */,
9409E1251ABF6FEA00312E2B /* Images.xcassets */,
9409E1191ABF6FEA00312E2B /* Supporting Files */,
Expand All @@ -242,7 +246,6 @@
isa = PBXGroup;
children = (
9409E11A1ABF6FEA00312E2B /* Info.plist */,
94D260901B45D20000DE671C /* SwiftRadio-Settings.swift */,
5FDEE0211F72FF980064333C /* LaunchScreen.storyboard */,
);
name = "Supporting Files";
Expand All @@ -269,8 +272,8 @@
children = (
94452E541AD7086800BFE7A5 /* AboutViewController.swift */,
94D1D0A41AD6D6230022CA11 /* InfoDetailViewController.swift */,
9409E13F1ABF78B000312E2B /* NowPlayingViewController.swift */,
94452E4E1AD6F24700BFE7A5 /* PopUpMenuViewController.swift */,
9409E13F1ABF78B000312E2B /* NowPlayingViewController.swift */,
942A3F361AE43DF80011396E /* StationsViewController.swift */,
);
name = ViewControllers;
Expand Down Expand Up @@ -299,12 +302,20 @@
isa = PBXGroup;
children = (
94AC70AD1AD05C6200652982 /* RadioStation.swift */,
94817DFA1B547D5700D3FA23 /* Player.swift */,
94D260971B45E8B800DE671C /* Track.swift */,
);
name = Model;
sourceTree = "<group>";
};
CAA7C15A1FD77F3A003CABDF /* FRadioPlayer */ = {
isa = PBXGroup;
children = (
CAA7C15B1FD77F3A003CABDF /* FRadioAPI.swift */,
CAA7C15C1FD77F3A003CABDF /* FRadioPlayer.swift */,
);
path = FRadioPlayer;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -361,7 +372,7 @@
};
9409E1151ABF6FEA00312E2B = {
CreatedOnToolsVersion = 6.2;
DevelopmentTeam = G24WJ3XCZ3;
DevelopmentTeam = G24WJ3XCZ3;
LastSwiftMigration = 0900;
SystemCapabilities = {
com.apple.BackgroundModes = {
Expand Down Expand Up @@ -430,7 +441,6 @@
5F22BA401F72AD5A00CB5911 /* SpringImageView.swift in Sources */,
5F22BA511F72AD5A00CB5911 /* TransitionZoom.swift in Sources */,
5F22BA471F72AD5A00CB5911 /* DesignableTextField.swift in Sources */,
5F22B9E01F72ABEF00CB5911 /* SwiftyJSON.swift in Sources */,
5F22BA4C1F72AD5A00CB5911 /* ImageLoader.swift in Sources */,
5F22BA451F72AD5A00CB5911 /* DesignableLabel.swift in Sources */,
94D260911B45D20000DE671C /* SwiftRadio-Settings.swift in Sources */,
Expand All @@ -452,7 +462,9 @@
94452E551AD7086800BFE7A5 /* AboutViewController.swift in Sources */,
5F22BA551F72AD5A00CB5911 /* AutoTextView.swift in Sources */,
94D260981B45E8B800DE671C /* Track.swift in Sources */,
CAA7C15E1FD77F3A003CABDF /* FRadioPlayer.swift in Sources */,
5F22BA3F1F72AD5A00CB5911 /* LoadingView.swift in Sources */,
CAA8FDB52000614600050F77 /* RadioPlayer.swift in Sources */,
5F22BA4F1F72AD5A00CB5911 /* TransitionManager.swift in Sources */,
5F22BA531F72AD5A00CB5911 /* SpringAnimation.swift in Sources */,
94452E4F1AD6F24700BFE7A5 /* PopUpMenuViewController.swift in Sources */,
Expand All @@ -466,7 +478,7 @@
942A3F371AE43DF80011396E /* StationsViewController.swift in Sources */,
5F22BA501F72AD5A00CB5911 /* Spring.swift in Sources */,
94AC70AE1AD05C6200652982 /* RadioStation.swift in Sources */,
94817DFB1B547D5700D3FA23 /* Player.swift in Sources */,
CAA7C15D1FD77F3A003CABDF /* FRadioAPI.swift in Sources */,
5F22BA481F72AD5A00CB5911 /* DesignableButton.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
Binary file not shown.
8 changes: 3 additions & 5 deletions SwiftRadio/AboutViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,16 @@ class AboutViewController: UIViewController {
let configuredMailComposeViewController = configureMailComposeViewController(recepients: receipients, subject: subject, messageBody: messageBody)

if canSendMail() {
self.present(configuredMailComposeViewController, animated: true, completion: nil)
present(configuredMailComposeViewController, animated: true, completion: nil)
} else {
showSendMailErrorAlert()
}
}

@IBAction func websiteButtonDidTouch(_ sender: UIButton) {

// Use your own website here
if let url = URL(string: "http://matthewfecher.com") {
UIApplication.shared.openURL(url)
}
guard let url = URL(string: "http://matthewfecher.com") else { return }
UIApplication.shared.openURL(url)
}

}
Expand Down
Loading

0 comments on commit 01bfb8a

Please sign in to comment.