Skip to content

Commit

Permalink
Merge branch '2018-11-2-history-pt2' into 2018-11-04-history2
Browse files Browse the repository at this point in the history
  • Loading branch information
skiptomyliu committed Nov 10, 2018
2 parents 1d5f9a0 + 2f30e38 commit f17de5d
Show file tree
Hide file tree
Showing 16 changed files with 260 additions and 123 deletions.
Binary file modified App/Milkshake.dmg
Binary file not shown.
8 changes: 8 additions & 0 deletions Milkshake.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
050687AA1FF80950007B9F39 /* playlisticon.png in Resources */ = {isa = PBXBuildFile; fileRef = 050687A91FF8094F007B9F39 /* playlisticon.png */; };
050687AC1FF81B28007B9F39 /* thumbs-up-on.png in Resources */ = {isa = PBXBuildFile; fileRef = 050687AB1FF81B28007B9F39 /* thumbs-up-on.png */; };
050EE4B1218E7B6D00B6E5A8 /* history.png in Resources */ = {isa = PBXBuildFile; fileRef = 050EE4B0218E7B6D00B6E5A8 /* history.png */; };
050EE4B32195CAAC00B6E5A8 /* thumbs-down-on.png in Resources */ = {isa = PBXBuildFile; fileRef = 050EE4B22195CAAB00B6E5A8 /* thumbs-down-on.png */; };
050EE4B521967B0B00B6E5A8 /* History.swift in Sources */ = {isa = PBXBuildFile; fileRef = 050EE4B421967B0B00B6E5A8 /* History.swift */; };
0513C74B20098E4200B84483 /* Callback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0513C74A20098E4200B84483 /* Callback.swift */; };
0513C794200BB7C800B84483 /* MyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0513C793200BB7C800B84483 /* MyButton.swift */; };
051C3DDD1FF94BF500D1212F /* back.png in Resources */ = {isa = PBXBuildFile; fileRef = 051C3DDC1FF94BF500D1212F /* back.png */; };
Expand Down Expand Up @@ -99,6 +101,8 @@
050687A91FF8094F007B9F39 /* playlisticon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = playlisticon.png; sourceTree = "<group>"; };
050687AB1FF81B28007B9F39 /* thumbs-up-on.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumbs-up-on.png"; sourceTree = "<group>"; };
050EE4B0218E7B6D00B6E5A8 /* history.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = history.png; sourceTree = "<group>"; };
050EE4B22195CAAB00B6E5A8 /* thumbs-down-on.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumbs-down-on.png"; sourceTree = "<group>"; };
050EE4B421967B0B00B6E5A8 /* History.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = History.swift; sourceTree = "<group>"; };
0513C74A20098E4200B84483 /* Callback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Callback.swift; sourceTree = "<group>"; };
0513C793200BB7C800B84483 /* MyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyButton.swift; sourceTree = "<group>"; };
051C3DDC1FF94BF500D1212F /* back.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = back.png; sourceTree = "<group>"; };
Expand Down Expand Up @@ -192,6 +196,7 @@
0513C74A20098E4200B84483 /* Callback.swift */,
05ED20F31FCDB1F300123317 /* CellSelectedProtocol.swift */,
05ED20F51FCE543200123317 /* DJ.swift */,
050EE4B421967B0B00B6E5A8 /* History.swift */,
05ED21031FD2563400123317 /* Music.swift */,
05ED21121FD6ED8E00123317 /* MusicItem.swift */,
059C04B2201EB1030007E456 /* MutableCollection+shuffle.swift */,
Expand Down Expand Up @@ -324,6 +329,7 @@
050687911FF6CD2F007B9F39 /* thumbs-up.png */,
050687AB1FF81B28007B9F39 /* thumbs-up-on.png */,
050687931FF6CD34007B9F39 /* thumbs-down.png */,
050EE4B22195CAAB00B6E5A8 /* thumbs-down-on.png */,
05D4F5EF217CEE5100283085 /* milkshake_512x512.png */,
);
name = resources;
Expand Down Expand Up @@ -417,6 +423,7 @@
050687941FF6CD34007B9F39 /* thumbs-down.png in Resources */,
05AAD9E62002F6DF00CE8A18 /* guitar.png in Resources */,
050EE4B1218E7B6D00B6E5A8 /* history.png in Resources */,
050EE4B32195CAAC00B6E5A8 /* thumbs-down-on.png in Resources */,
050687A81FF7F160007B9F39 /* playcell.png in Resources */,
050687A41FF70FAC007B9F39 /* menu.png in Resources */,
05D4F5F0217CEE5100283085 /* milkshake_512x512.png in Resources */,
Expand Down Expand Up @@ -547,6 +554,7 @@
05ED20E71FCD2FBD00123317 /* SearchTableCellView.swift in Sources */,
059A061E200D66EB003C81F1 /* NIFFTHelper.swift in Sources */,
05412FEC1FDF73720067DCFE /* PlayerViewController.swift in Sources */,
050EE4B521967B0B00B6E5A8 /* History.swift in Sources */,
05ED20E21FCD125C00123317 /* ResultsViewController.swift in Sources */,
05ED20F11FCD440500123317 /* MyWindow.swift in Sources */,
);
Expand Down
Binary file not shown.
2 changes: 1 addition & 1 deletion Milkshake/API.swift
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ class API: NSObject {
func callbackAlbum(results: [String: AnyObject], callbackHandler: @escaping(_ Dictionary:[String:AnyObject]) -> ()) {
let items = Util.parseAlbumIntoTracks(album: results)
var trackIds = [String]()
for item in items{
for item in items {
trackIds.append(item.pandoraId!)
}
self.annotateObjectsSimple(trackIds: trackIds, results:results, callbackHandler: callbackHandler)
Expand Down
3 changes: 2 additions & 1 deletion Milkshake/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, LoginProtocol {
var music: Music? // pointer to either dj or radio
var dj: DJ
var radio: Radio

var history: History
var windowController: NSWindowController?
var loginWindowController: NSWindowController?
var isArtAnimate: Bool = false
Expand Down Expand Up @@ -125,6 +125,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, LoginProtocol {
self.api = API()
self.dj = DJ()
self.radio = Radio()
self.history = History()
super.init()
}

Expand Down
9 changes: 0 additions & 9 deletions Milkshake/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -173,15 +173,6 @@
</menuItem>
<menuItem title="Help" id="wpr-3q-Mcd">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
<items>
<menuItem title="Milkshake Help" keyEquivalent="?" id="FKE-Sm-Kum">
<connections>
<action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
Expand Down
3 changes: 0 additions & 3 deletions Milkshake/DJ.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
// Created by Dean Liu on 11/28/17.
// Copyright © 2017 Dean Liu. All rights reserved.
//

import Cocoa
import AVKit

Expand Down Expand Up @@ -56,7 +55,6 @@ class DJ: Music {
func reset() {
self.tracksIdx = -1
self.isShuffled = false

self.tracks.removeAll()
self.tracksStr.removeAll()
self.tracksShuffled.removeAll()
Expand Down Expand Up @@ -88,7 +86,6 @@ class DJ: Music {
if self.isShuffled == false && self.shuffle {
self.enableShuffle()
}

if self.tracks.count > 0 {
// XXX Switching to radio wont save the track
// nested here because radio.playNext will cause double preflight
Expand Down
122 changes: 122 additions & 0 deletions Milkshake/History.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//
// History.swift
// Milkshake
//
// Created by Dean Liu on 11/9/18.
// Copyright © 2018 Dean Liu. All rights reserved.
//

import Cocoa

//enum RatingType: Int {
// case THUMBDOWN
// case THUMBUP
// case NONE
//}

class History: NSObject {

private var thumbsMap:[String: Int] = [:]
private var MAX_ITEMS = 30

func getThumbForId(pandoraId: String) -> Int {
if let result = thumbsMap[pandoraId] {
return result
}
return 0
}

override init() {
super.init()
}

class func getListenerHistoryKey() -> String{
let appDelegate = NSApplication.shared.delegate as! AppDelegate
let listener_history = String(format:"%@_history", appDelegate.listenerId)
return listener_history
}

class func getListenerRatingKey() -> String{
let appDelegate = NSApplication.shared.delegate as! AppDelegate
let listener_history = String(format:"%@_ratings", appDelegate.listenerId)
return listener_history
}

class func getArchiveThumbsMap() -> [String: Int]{
let historyRatingData = UserDefaults.standard.object(forKey: History.getListenerRatingKey()) as? Data
var thumbsMap:[String: Int] = [:]
if let historyRatingData = historyRatingData {
thumbsMap = NSKeyedUnarchiver.unarchiveObject(with: historyRatingData) as? [String: Int] ?? [:]
}
return thumbsMap
}

class func getArchiveMusic() -> [MusicItem] {
let historyData = UserDefaults.standard.object(forKey: History.getListenerHistoryKey()) as? Data
var historyArray = [] as [MusicItem]
if let historyData = historyData {
historyArray = NSKeyedUnarchiver.unarchiveObject(with: historyData) as? [MusicItem] ?? []
}
return historyArray
}

func storeThumbForId(pandoraId: String, rating: Int) {
self.thumbsMap = History.getArchiveThumbsMap()
self.thumbsMap[pandoraId] = rating
self.saveArchiveThumbs()
}

func saveArchiveThumbs() {
let encodedData = NSKeyedArchiver.archivedData(withRootObject: self.thumbsMap)
UserDefaults.standard.set(encodedData, forKey: History.getListenerRatingKey())
}

// Remove any IDs from thumb map / rating that doesn't exist in our history array
func cleanUp(thumbsMap: [String:Int], historyArray:[MusicItem]) -> [String:Int]{
var thumbsMap = thumbsMap
let pandoraIds = thumbsMap.keys
var historyIds: [String] = []
for item in historyArray {
if let pandoraId = item.pandoraId {
historyIds.append(pandoraId)
}
}
for pid in pandoraIds {
if !historyIds.contains(pid) {
thumbsMap[pid] = nil
}
}
return thumbsMap
}

func fetchMusicFromHistory() -> [MusicItem] {
let historyArray = History.getArchiveMusic()
if self.thumbsMap.count <= 0 {
self.thumbsMap = History.getArchiveThumbsMap()
self.thumbsMap = self.cleanUp(thumbsMap: self.thumbsMap, historyArray: historyArray)
self.saveArchiveThumbs()
}
for item in historyArray {
let pandoraId = item.pandoraId ?? ""
item.rating = thumbsMap[pandoraId] ?? item.rating
}
return historyArray
}

func saveToHistory(item: MusicItem) -> [MusicItem] {
self.storeThumbForId(pandoraId: item.pandoraId!, rating: item.rating)
var historyArray = History.getArchiveMusic()
if historyArray.count > MAX_ITEMS {
let removed = historyArray.removeLast()
self.thumbsMap[removed.pandoraId!] = nil
}
print("Total thumb map")
print(self.thumbsMap)
print(self.thumbsMap.count)
item.cellType = CellType.HISTORY
historyArray.insert(item, at: 0)
let encodedData = NSKeyedArchiver.archivedData(withRootObject: historyArray)
UserDefaults.standard.set(encodedData, forKey: History.getListenerHistoryKey())
return historyArray
}
}
2 changes: 1 addition & 1 deletion Milkshake/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key>
<string>1.0.2</string>
<key>CFBundleVersion</key>
<string>15</string>
<string>19</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.music</string>
<key>LSMinimumSystemVersion</key>
Expand Down
4 changes: 2 additions & 2 deletions Milkshake/MainViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ class MainViewController: NSViewController {
historyHeader.name = "PLAY HISTORY"
historyHeader.isHeader = true
if self.historyResultsViewController.search_results.count <= 0 {
var historyArray = Util.fetchFromHistory()
var historyArray = appDelegate.history.fetchMusicFromHistory()
historyArray.insert(historyHeader, at: 0)
self.historyResultsViewController.setResults(results: historyArray)
}
Expand Down Expand Up @@ -554,7 +554,7 @@ extension MainViewController: MusicChangedProtocol {
func musicPreflightChangedProtocol(item: MusicItem) {
// Update history vc
if (item.pandoraId != nil) {
_ = Util.saveToHistory(item: item)
_ = appDelegate.history.saveToHistory(item: item)
self.historyResultsViewController.insertMusicItem(item: item, index: 1)
}
}
Expand Down
12 changes: 11 additions & 1 deletion Milkshake/NowPlayingViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -228,14 +228,24 @@ class NowPlayingViewController: NSViewController {

// Actions
@IBAction func thumbsDown(_ sender: Any) {
self.item.rating = -1
let appDelegate = NSApplication.shared.delegate as! AppDelegate
appDelegate.radio.thumbDown()
appDelegate.history.storeThumbForId(pandoraId: self.item.pandoraId!, rating: -1)
}

@IBAction func thumbsUp(_ sender: Any) {
let appDelegate = NSApplication.shared.delegate as! AppDelegate
appDelegate.radio.thumbUp()
self.thumbsUpButton.isToggle = !self.thumbsUpButton.isToggle
if self.thumbsUpButton.isToggle {
appDelegate.radio.thumbUp()
self.item.rating = 1
appDelegate.history.storeThumbForId(pandoraId: self.item.pandoraId!, rating: 1)
} else {
appDelegate.radio.unthumbUp()
self.item.rating = 0
appDelegate.history.storeThumbForId(pandoraId: self.item.pandoraId!, rating: 0)
}
}

@IBAction func skipSong(_ sender: Any) {
Expand Down
67 changes: 42 additions & 25 deletions Milkshake/Radio.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,31 +47,34 @@ class Radio: Music {
}

override func playNext() {
// If we are out, we fetch for more
if self.stationIdx+1 > self.stationTracks.count-1 {
let prevToken = self.stationTracks[self.stationIdx].trackToken!
self.playStation(stationId: self.stationId, isStationStart: false, lastPlayedTrackToken: prevToken)
} else {
self.stationIdx = (self.stationIdx + 1)
let urlStr = self.stationTracks[self.stationIdx].audioURL!
// self.curPlayingItem = self.stationTracks[self.stationIdx]
let musicItem = self.stationTracks[self.stationIdx]

// We make an additional API call to annotate for additional info we need:
// artistId, dominant color and albumId
if let pandoraId = musicItem.pandoraId {
let appDelegate = NSApplication.shared.delegate as! AppDelegate
appDelegate.api.annotateObjectsSimple(trackIds:[pandoraId]) {
(results) in
if let trackDict = results[pandoraId] as? Dictionary<String, AnyObject> {
if let icon = trackDict["icon"] {
musicItem.dominantColor = icon["dominantColor"] as? String
let appDelegate = NSApplication.shared.delegate as! AppDelegate
appDelegate.dj.tracks.removeAll()
if self.stationTracks.count > 0 {
// If we are out, we fetch for more
if self.stationIdx+1 > self.stationTracks.count-1 {
let prevToken = self.stationTracks[self.stationIdx].trackToken!
self.playStation(stationId: self.stationId, isStationStart: false, lastPlayedTrackToken: prevToken)
} else {
self.stationIdx = (self.stationIdx + 1)
let urlStr = self.stationTracks[self.stationIdx].audioURL!
let musicItem = self.stationTracks[self.stationIdx]

// We make an additional API call to annotate for additional info we need:
// artistId, dominant color and albumId
if let pandoraId = musicItem.pandoraId {
let appDelegate = NSApplication.shared.delegate as! AppDelegate
appDelegate.api.annotateObjectsSimple(trackIds:[pandoraId]) {
(results) in
if let trackDict = results[pandoraId] as? Dictionary<String, AnyObject> {
if let icon = trackDict["icon"] {
musicItem.dominantColor = icon["dominantColor"] as? String
}
musicItem.artistId = trackDict["artistId"] as? String
musicItem.albumId = trackDict["albumId"] as? String
}
musicItem.artistId = trackDict["artistId"] as? String
musicItem.albumId = trackDict["albumId"] as? String
self.musicPreflightChange()
self.playAudio(item:musicItem, url: urlStr)
}
self.musicPreflightChange()
self.playAudio(item:musicItem, url: urlStr)
}
}
}
Expand All @@ -82,8 +85,10 @@ class Radio: Music {
}

func thumbDown() {

let appDelegate = NSApplication.shared.delegate as? AppDelegate
let trackToken = self.stationTracks[self.stationIdx].trackToken!
let musicItem = self.stationTracks[self.stationIdx]
let trackToken = musicItem.trackToken!
appDelegate!.api.addFeedback(trackToken: trackToken, isPositive: false) { responseDict in
print("Thumbsdown feedback response: ")
print(responseDict)
Expand All @@ -93,13 +98,25 @@ class Radio: Music {

func thumbUp() {
let appDelegate = NSApplication.shared.delegate as? AppDelegate
let trackToken = self.stationTracks[self.stationIdx].trackToken!
let musicItem = self.stationTracks[self.stationIdx]
let trackToken = musicItem.trackToken!
appDelegate!.api.addFeedback(trackToken: trackToken, isPositive: true) { responseDict in
print("Thumbsup Feedback response: ")
print(responseDict)
}
}

func unthumbUp() {
let appDelegate = NSApplication.shared.delegate as? AppDelegate
let musicItem = self.stationTracks[self.stationIdx]
let trackToken = musicItem.trackToken!
appDelegate!.api.deleteFeedback(trackToken: trackToken, isPositive: false) { responseDict in
print("UNTHUMBDOWN Feedback response: ")
print(responseDict)
appDelegate!.history.storeThumbForId(pandoraId: musicItem.pandoraId!, rating: 0)
}
}

@objc override func itemDidFinishPlaying(notification: NSNotification) {
// If not crossfade, play next item. Otherwise this will double call.
if self.crossFade == false {
Expand Down
Loading

0 comments on commit f17de5d

Please sign in to comment.