# Pony.fm - A community for pony fan music. # Copyright (C) 2015 Peter Deltchev # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . module.exports = angular.module('ponyfm').factory('playlists', [ '$rootScope', '$state', '$http', 'auth' ($rootScope, $state, $http, auth) -> playlistDef = null filterDef = null playlists = {} playlistPages = [] class Query cacheDef: null page: 1 listeners: [] constructor: (@availableFilters) -> @filters = {} @hasLoadedFilters = false @resetFilters() resetFilters: -> _.each @availableFilters, (filter, name) => if filter.type == 'single' @filters[name] = _.find filter.values, (f) -> f.isDefault else @filters[name] = {title: 'Any', selectedArray: [], selectedObject: {}} clearFilter: (type) -> @cachedDef = null @page = 1 filter = @availableFilters[type] if filter.type == 'single' @filters[type] = _.find filter.values, (f) -> f.isDefault else currentFilter = @filters[type] currentFilter.selectedArray = [] currentFilter.selectedObject = {} currentFilter.title = 'Any' setPage: (page) -> @page = page @cachedDef = null setFilter: (type, value) -> @cachedDef = null @page = 1 @filters[type] = value toFilterString: -> parts = [] _.each @availableFilters, (filter, name) => filterName = filter.name if filter.type == 'single' return if @filters[name].query == '' parts.push(filterName + '-' + @filters[name].query) else return if @filters[name].selectedArray.length == 0 parts.push(filterName + '-' + _.map(@filters[name].selectedArray, (f) -> f.id).join '-') return parts.join '!' fromFilterString: (str) -> @hasLoadedFilters = true @cachedDef = null @resetFilters() filters = (str || "").split '!' for queryFilter in filters parts = queryFilter.split '-' queryName = parts[0] filterName = null filter = null for name,f of @availableFilters continue if f.name != queryName filterName = name filter = f return if !filter if filter.type == 'single' filterToSet = _.find filter.values, (f) -> f.query == parts[1] filterToSet = (_.find filter.values, (f) -> f.isDefault) if filterToSet == null @setFilter filterName, filterToSet else @toggleListFilter filterName, id for id in _.rest parts, 1 listen: (listener) -> @listeners.push listener @cachedDef.done listener if @cachedDef fetch: () -> return @cachedDef if @cachedDef @cachedDef = new $.Deferred() playlistDef = @cachedDef query = '/api/web/playlists?' parts = ['page=' + @page] _.each @availableFilters, (filter, name) => if filter.type == 'single' parts.push @filters[name].filter else queryName = filter.filterName for item in @filters[name].selectedArray parts.push queryName + "[]=" + item.id query += parts.join '&' $http.get(query).success (playlists) => @playlists = playlists for listener in @listeners listener playlists playlistDef.resolve playlists playlistDef.promise() self = pinnedPlaylists: [] filters: {} createQuery: -> new Query self.filters loadFilters: -> return filterDef if filterDef filterDef = new $.Deferred() self.filters.sort = type: 'single' name: 'sort' values: [ {title: 'Most Favourited', query: 'favourites', isDefault: true, filter: 'order=favourite_count,desc'} {title: 'Most Viewed', query: 'plays', isDefault: false, filter: 'order=view_count,desc'}, {title: 'Most Downloaded', query: 'downloads', isDefault: false, filter: 'order=download_count,desc'}, {title: 'Alphabetical', query: 'alphabetical', isDefault: false, filter: 'order=title,asc'}, {title: 'Latest', query: 'latest', isDefault: false, filter: 'order=created_at,desc'}, {title: 'Track count', query: 'tracks', isDefault: false, filter: 'order=track_count,desc'}, ] self.mainQuery = self.createQuery() filterDef.resolve self filterDef.promise() fetchList: (page, force) -> force = force || false page = 1 if !page return playlistPages[page] if !force && playlistPages[page] playlistDef = new $.Deferred() $http.get('/api/web/playlists?page=' + page).success (playlists) -> playlistDef.resolve playlists $rootScope.$broadcast 'playlists-feteched', playlists playlistPages[page] = playlistDef.promise() fetch: (id, force) -> force = force || false return playlists[id] if !force && playlists[id] def = new $.Deferred() $http.get('/api/web/playlists/' + id + '?log=true').success (playlist) -> def.resolve playlist playlists[id] = def.promise() isPlaylistPinned: (id) -> _.find(self.pinnedPlaylists, (p) -> `p.id == id`) != undefined refreshOwned: (force = false, slug = window.pfm.auth.user.slug) -> return playlistDef if !force && playlistDef playlistDef = new $.Deferred() if auth.data.isLogged $http.get("/api/web/users/#{slug}/playlists").success (playlists) -> playlistDef.resolve playlists else playlistDef.resolve [] playlistDef addTrackToPlaylist: (playlistId, trackId) -> def = new $.Deferred() $http.post('/api/web/playlists/' + playlistId + '/add-track', {track_id: trackId}).success (res) -> def.resolve(res) def removeTrackFromPlaylist: (playlistId, trackId) -> def = new $.Deferred() $http.post('/api/web/playlists/' + playlistId + '/remove-track', {track_id: trackId}).success (res) -> def.resolve(res) def refresh: () -> if auth.data.isLogged $.getJSON('/api/web/playlists/pinned') .done (playlists) -> $rootScope.$apply -> self.pinnedPlaylists.length = 0 self.pinnedPlaylists.push playlist for playlist in playlists deletePlaylist: (playlist) -> def = new $.Deferred() $.post('/api/web/playlists/delete/' + playlist.id) .then -> $rootScope.$apply -> if _.some(self.pinnedPlaylists, (p) -> p.id == playlist.id) currentIndex = _.indexOf(self.pinnedPlaylists, (t) -> t.id == playlist.id) self.pinnedPlaylists.splice currentIndex, 1 if $state.is('playlist') && $state.params.id == playlist.id $state.transitionTo 'home' def.resolve() def editPlaylist: (playlist) -> def = new $.Deferred() $.post('/api/web/playlists/edit/' + playlist.id, playlist) .done (res) -> $rootScope.$apply -> currentIndex = _.indexOf(self.pinnedPlaylists, (t) -> t.id == playlist.id) isPinned = _.some(self.pinnedPlaylists, (p) -> p.id == playlist.id) if res.is_pinned && !isPinned self.pinnedPlaylists.push res self.pinnedPlaylists.sort (left, right) -> left.title.localeCompare right.title currentIndex = _.indexOf(self.pinnedPlaylists, (t) -> t.id == playlist.id) else if !res.is_pinned && isPinned self.pinnedPlaylists.splice currentIndex, 1 currentIndex = _.indexOf(self.pinnedPlaylists, (t) -> t.id == playlist.id) if res.is_pinned current = self.pinnedPlaylists[currentIndex] _.forEach res, (value, name) -> current[name] = value self.pinnedPlaylists.sort (left, right) -> left.title.localeCompare right.title def.resolve res $rootScope.$broadcast 'playlist-updated', res .fail (res)-> $rootScope.$apply -> errors = {} _.each res.responseJSON.errors, (value, key) -> errors[key] = value.join ', ' def.reject errors def createPlaylist: (playlist) -> def = new $.Deferred() $.post('/api/web/playlists/create', playlist) .done (res) -> $rootScope.$apply -> if res.is_pinned self.pinnedPlaylists.push res self.pinnedPlaylists.sort (left, right) -> left.title.localeCompare right.title def.resolve res .fail (res)-> $rootScope.$apply -> errors = {} _.each res.responseJSON.errors, (value, key) -> errors[key] = value.join ', ' def.reject errors def self.refresh() self ])