Skip to content

Commit

Permalink
✨ Allow sorting assets by likes (roundware#17)
Browse files Browse the repository at this point in the history
* 🎉 Implement sorting assets by likes

* Allow project setting for sort by likes

* Space out api method call

* 🐛 Fix typo of by_like

* ✏️ Fix typo of sorting "by_like"

* 📝 Add documentation to SortMethod

* 🚑 Use less-than-or-equal
  • Loading branch information
loafofpiecrust authored Jul 1, 2019
1 parent 6514fbd commit db34c49
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 7 deletions.
17 changes: 13 additions & 4 deletions RWFramework/RWFramework/Playlist/Playlist.swift
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ extension Playlist {
}.filter { (asset, rank) in
rank != .discard
}.sorted { a, b in
a.1.rawValue < b.1.rawValue
a.1.rawValue <= b.1.rawValue
}.sorted { a, b in
// play less played assets first
let dataA = userAssetData[a.0.id]
Expand Down Expand Up @@ -269,16 +269,21 @@ extension Playlist {
opts["created__gte"] = dateFormatter.string(from: date)
}

return rw.apiGetAssets(opts).then { data -> () in
return Promise {
let data = try await(rw.apiGetAssets(opts))
self.lastUpdate = Date()
self.allAssets.append(contentsOf: data)

print("\(data.count) added assets")

// Ensure all sort methods are setup before sorting.
_ = try await(all(self.sortMethods.map { $0.onRefreshAssets(in: self) }))

// Sort the asset pool.
for sortMethod in self.sortMethods {
self.allAssets.sort(by: { a, b in
sortMethod.sortRanking(for: a, in: self) < sortMethod.sortRanking(for: b, in: self)
})
}
print("\(data.count) added assets")
}.catch { err in
print(err)
self.lastUpdate = Date()
Expand Down Expand Up @@ -322,6 +327,8 @@ extension Playlist {
}

func start() {
DispatchQueue.promises = .global()

RWFramework.sharedInstance.isPlaying = false

// Starts a session and retrieves project-wide config.
Expand All @@ -339,6 +346,8 @@ extension Playlist {
self.sortMethods = [SortRandomly()]
case "by_weight":
self.sortMethods = [SortByWeight()]
case "by_like":
self.sortMethods = [SortByLikes()]
default: break
}
}
Expand Down
46 changes: 45 additions & 1 deletion RWFramework/RWFramework/Playlist/SortMethod.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@

import Foundation
import SwiftyJSON
import Promises

protocol SortMethod {
/**
The sorting ranking of the given asset.
Assets will be sorted in ascending order of their rank.
Thus, returning a negatized result effectively causes
assets to be in descending order.
*/
func sortRanking(for asset: Asset, in playlist: Playlist) -> Double
/// Load any data required before sorting.
func onRefreshAssets(in playlist: Playlist) -> Promise<Void>
}

extension SortMethod {
/// By default does nothing when assets are refreshed.
func onRefreshAssets(in playlist: Playlist) -> Promise<Void> {
return Promise(())
}
}


Expand All @@ -16,4 +33,31 @@ struct SortByWeight: SortMethod {
func sortRanking(for asset: Asset, in playlist: Playlist) -> Double {
return -asset.weight
}
}
}

class SortByLikes: SortMethod {
private var assetVotes: [Int: Int]? = nil

func sortRanking(for asset: Asset, in playlist: Playlist) -> Double {
if let votes = assetVotes?[asset.id] {
return Double(-votes)
} else {
return 0.0
}
}

func onRefreshAssets(in playlist: Playlist) -> Promise<Void> {
let projectId = playlist.project.id
return RWFramework.sharedInstance.apiGetVotesSummary(
type: "like",
projectId: projectId.description
).then { data -> Void in
let voteData = try JSON(data: data).array
self.assetVotes = voteData?.reduce(into: [Int: Int]()) { acc, data in
let assetId = data["asset_id"].int!
let votes = data["asset_votes"].int!
acc[assetId] = votes
}
}
}
}
1 change: 1 addition & 0 deletions RWFramework/RWFramework/RWFramework.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ private lazy var __once: () = { () -> Void in
DynamicTagFilter("_ten_most_recent_days", MostRecentFilter(days: 10))
], sortBy: [
SortRandomly(),
SortByLikes(),
])

// Audio - Stream (see RWFrameworkAudioPlayer.swift)
Expand Down
5 changes: 4 additions & 1 deletion RWFramework/RWFramework/RWFrameworkAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,6 @@ extension RWFramework {
}.catch { error in
self.rwPostAssetsIdVotesFailure(error)
self.apiProcessError(nil, error: error, caller: "apiPostAssetsIdVotes")

}
}

Expand All @@ -572,6 +571,10 @@ extension RWFramework {
self.apiProcessError(nil, error: error, caller: "apiGetAssetsIdVotes")
}
}

func apiGetVotesSummary(type: String? = nil, projectId: String? = nil, assetId: String? = nil) -> Promise<Data> {
return httpGetVotesSummary(type: type, projectId: projectId, assetId: assetId)
}

public func apiGetSpeakers(_ dict: [String:String]) -> Promise<[Speaker]> {
return httpGetSpeakers(dict).then { data -> [Speaker] in
Expand Down
8 changes: 8 additions & 0 deletions RWFramework/RWFramework/RWFrameworkHTTP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,14 @@ extension RWFramework: URLSessionDelegate, URLSessionTaskDelegate, URLSessionDat
func httpGetAssetsIdVotes(_ asset_id: String) -> Promise<Data> {
return getData(from: RWFrameworkURLFactory.getAssetsIdVotesURL(asset_id))
}

func httpGetVotesSummary(type: String?, projectId: String?, assetId: String?) -> Promise<Data> {
return getData(from: RWFrameworkURLFactory.getVotesSummaryURL([
"type": type ?? "",
"asset_id": assetId ?? "",
"project_id": projectId ?? ""
]))
}


func httpGetSpeakers(_ dict: [String:String]) -> Promise<Data> {
Expand Down
8 changes: 7 additions & 1 deletion RWFramework/RWFramework/RWFrameworkURLFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ open class RWFrameworkURLFactory {
return "\(api())/assets/\(asset_id)/votes/"
}

class func getVotesSummaryURL(_ dict: [String:String]) -> String {
return "\(api())/votes/summary/\(dict.toUrlQuery())"
}

class func postEventsURL() -> String {
return "\(api())/events/"
}
Expand All @@ -126,7 +130,9 @@ fileprivate extension Dictionary where Key == String, Value == String {
result += "?"
}
for (key, value) in self {
result += (key + "=" + value + "&")
if !value.isEmpty {
result += (key + "=" + value + "&")
}
}
return result
}
Expand Down

0 comments on commit db34c49

Please sign in to comment.