Skip to content

Commit

Permalink
Merge pull request #162 from Superjo149/discover
Browse files Browse the repository at this point in the history
Add discover
  • Loading branch information
sneljo1 authored Dec 13, 2018
2 parents 407efe0 + d758755 commit 6baf137
Show file tree
Hide file tree
Showing 32 changed files with 925 additions and 57 deletions.
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"repository": "Superjo149/auryo",
"homepage": "http://auryo.com",
"productName": "Auryo",
"version": "2.2.3",
"version": "2.3.0",
"author": {
"name": "Jonas Snellinckx",
"email": "[email protected]"
Expand Down Expand Up @@ -92,7 +92,7 @@
"css-loader": "^0.28.11",
"devtron": "^1.4.0",
"dotenv": "^6.0.0",
"electron": "^3.0.10",
"electron": "^3.0.11",
"electron-builder": "^20.34.0",
"electron-devtools-installer": "^2.2.4",
"electron-download": "^4.1.1",
Expand Down Expand Up @@ -152,6 +152,7 @@
"bootstrap": "^4.1.3",
"boxicons": "^1.7.1",
"classnames": "^2.2.5",
"color-hash": "^1.0.3",
"connected-react-router": "^4.5.0",
"electron-debug": "^2.0.0",
"electron-dl": "^1.12.0",
Expand All @@ -163,6 +164,7 @@
"history": "^4.7.2",
"jquery": "1.9.1",
"lodash": "^4.16.6",
"mac-accessibility-features-check": "^1.0.2",
"moment": "^2.17.0",
"normalizr": "^3.2.2",
"popper.js": "^1.12.9",
Expand Down Expand Up @@ -204,6 +206,7 @@
"@nodert-win10/windows.media.playback": "^0.2.95",
"@nodert-win10/windows.storage.streams": "^0.2.95",
"electron-media-service": "^0.2.2",
"mac-accessibility-features-check": "^1.0.2",
"mpris-service": "GPMDP/mpris-service",
"dbus": "GPMDP/node-dbus#linux-only"
},
Expand Down
48 changes: 48 additions & 0 deletions src/common/api/fetchPersonalised.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { normalize, schema } from 'normalizr';
import { NormalizedEntities, NormalizedPersonalizedItem, SoundCloud } from '../../types';
import { playlistSchema } from '../schemas';
import fetchToJson from './helpers/fetchToJson';

interface JsonResponse {
collection: Array<PersonalisedCollectionItem>;
next_href?: string;
query_urn: string;
}

export interface PersonalisedCollectionItem {
urn: string;
query_urn: string;
title: string;
description: string;
tracking_feature_name: string;
last_updated: string;
style: string;
social_proof: SoundCloud.CompactUser;
system_playlists: Array<SoundCloud.SystemPlaylist>;
}


export default async function fetchPersonalised(url: string): Promise<{
json: JsonResponse,
normalized: {
entities: NormalizedEntities;
result: Array<NormalizedPersonalizedItem>;
}
}> {
try {
const json = await fetchToJson<JsonResponse>(url);

const collection = json.collection.filter((t) => t.urn.indexOf('chart') === -1);

return ({
normalized: normalize(collection, new schema.Array(new schema.Object({
system_playlists: new schema.Array(playlistSchema),
playlists: new schema.Array(playlistSchema)
}))),
json
});

} catch (err) {
throw err;
}
}
45 changes: 44 additions & 1 deletion src/common/store/auth/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import { AuthActionTypes } from './types';
import { ObjectTypes, PlaylistTypes } from '../objects';
import fetchPlaylists from '../../api/fetchPlaylists';
import { replace } from 'connected-react-router';
import { getPlaylistObjectSelector } from '../objects/selectors';
import { getPlaylistObjectSelector, getPlaylistName } from '../objects/selectors';
import fetchPersonalised from '../../api/fetchPersonalised';

export function logout(): ThunkResult<void> {
return (dispatch) => {
Expand Down Expand Up @@ -207,3 +208,45 @@ export function getAuthPlaylists(): ThunkResult<any> {
}
});
}

export function fetchPersonalizedPlaylistsIfNeeded(): ThunkResult<void> {
return (dispatch, getState) => {
const { auth: { personalizedPlaylists } } = getState();

if (!personalizedPlaylists.items && !personalizedPlaylists.loading) {
dispatch<Promise<any>>({
type: AuthActionTypes.SET_PERSONALIZED_PLAYLISTS,
payload: {
promise: fetchPersonalised(SC.getPersonalizedurl())
.then(({ normalized, json }) => {

normalized.result.forEach((playlistResult) => {

(playlistResult.system_playlists || []).forEach((playlistId) => {
if (normalized.entities.playlistEntities && normalized.entities.playlistEntities[playlistId]) {
const playlist = normalized.entities.playlistEntities[playlistId];

dispatch(setObject(
playlistId.toString(),
ObjectTypes.PLAYLISTS,
{},
playlist.tracks,
null,
null,
0
));
}
});

});

return {
entities: normalized.entities,
items: normalized.result
};
})
}
} as any);
}
};
}
30 changes: 29 additions & 1 deletion src/common/store/auth/reducer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Reducer } from 'redux';
import { onSuccess } from '../../utils/reduxUtils';
import { onSuccess, isLoading, onError } from '../../utils/reduxUtils';
import { AppActionTypes } from '../app';
import { ConfigActionTypes } from '../config';
import { AuthActionTypes, AuthState } from './types';
Expand All @@ -19,6 +19,10 @@ const initialState = {
authentication: {
loading: false,
error: null
},
personalizedPlaylists: {
loading: false,
items: null
}
};

Expand Down Expand Up @@ -151,6 +155,30 @@ export const authReducer: Reducer<AuthState> = (state = initialState, action) =>
[payload.userId]: payload.following
}
};
case isLoading(AuthActionTypes.SET_PERSONALIZED_PLAYLISTS):
return {
...state,
personalizedPlaylists: {
...state.personalizedPlaylists,
loading: true
}
};
case onError(AuthActionTypes.SET_PERSONALIZED_PLAYLISTS):
return {
...state,
personalizedPlaylists: {
...state.personalizedPlaylists,
loading: false
}
};
case onSuccess(AuthActionTypes.SET_PERSONALIZED_PLAYLISTS):
return {
...state,
personalizedPlaylists: {
loading: false,
items: payload.items
}
};
case AppActionTypes.RESET_STORE:
return initialState;
default:
Expand Down
2 changes: 0 additions & 2 deletions src/common/store/auth/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import { ObjectGroup, ObjectState } from '../objects';
import { getPlaylistsObjects } from '../objects/selectors';
import { AuthReposts } from './types';

// SC.hasID(item.id, followings);

export const getAuth = (state: StoreState) => state.auth;

export const getFollowings = createSelector<StoreState, AuthState, AuthFollowing>(
Expand Down
7 changes: 6 additions & 1 deletion src/common/store/auth/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SoundCloud, NormalizedResult } from '../../../types';
import { SoundCloud, NormalizedResult, NormalizedPersonalizedItem } from '../../../types';

// TYPES

Expand All @@ -9,6 +9,10 @@ export interface AuthState extends Readonly<{
reposts: AuthReposts,
playlists: Array<NormalizedResult>;
authentication: AuthStatus
personalizedPlaylists: {
loading: boolean;
items: Array<NormalizedPersonalizedItem> | null;
}
}> { }

export interface AuthFollowing {
Expand Down Expand Up @@ -46,6 +50,7 @@ export interface AuthStatus {
export const enum AuthActionTypes {
SET = '@@auth/SET',
SET_PLAYLISTS = '@@auth/SET_PLAYLISTS',
SET_PERSONALIZED_PLAYLISTS = '@@auth/SET_PERSONALIZED_PLAYLISTS',
SET_FOLLOWINGS = '@@auth/SET_FOLLOWINGS',
SET_LIKES = '@@auth/SET_LIKES',
SET_PLAYLIST_LIKES = '@@auth/SET_PLAYLIST_LIKES',
Expand Down
4 changes: 2 additions & 2 deletions src/common/store/entities/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { playlistSchema, trackSchema, userSchema, commentSchema } from '../../sc

export const getEntities = (state: StoreState) => state.entities;

const deNormSchema = new schema.Array({
export const normalizeSchema = new schema.Array({
tracks: trackSchema,
playlists: playlistSchema,
users: userSchema,
Expand All @@ -16,7 +16,7 @@ const deNormSchema = new schema.Array({

export const getDenormalizedEntities = <T>(result: Array<NormalizedResult>) => createSelector<StoreState, EntitiesState, Array<T>>(
getEntities,
(entities) => denormalize(result, deNormSchema, entities)
(entities) => denormalize(result, normalizeSchema, entities)
);

export const getDenormalizedEntity = <T>(result: NormalizedResult) => createSelector<StoreState, Array<T>, T | null>(
Expand Down
29 changes: 19 additions & 10 deletions src/common/store/objects/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import { trackSchema } from '../../schemas';
import { SC } from '../../utils';
import { PlayerActionTypes, ProcessedQueueItems, processQueueItems } from '../player';
import { SortTypes } from '../playlist/types';
import { ObjectsActionTypes, ObjectState, ObjectTypes } from './types';
import { getPlaylistObjectSelector } from './selectors';
import { ObjectsActionTypes, ObjectState, ObjectTypes, PlaylistTypes } from './types';
import { getPlaylistObjectSelector, getPlaylistName } from './selectors';
import fetchPersonalised from '../../api/fetchPersonalised';

const canFetch = (current: ObjectState<any>): boolean => !current || (!!current && !current.isFetching);
const canFetchMore = (current: ObjectState<any>): boolean => canFetch(current) && (current && current.nextUrl !== null);
Expand Down Expand Up @@ -155,15 +156,17 @@ export const setObject = (
entities: NormalizedEntities,
result: Array<NormalizedResult>,
nextUrl = null,
futureUrl = null
futureUrl = null,
fetchedItems = 0
) => {
return action(ObjectsActionTypes.SET, {
objectId,
objectType,
entities,
result,
nextUrl: (nextUrl) ? SC.appendToken(nextUrl) : null,
futureUrl: (futureUrl) ? SC.appendToken(futureUrl) : null
futureUrl: (futureUrl) ? SC.appendToken(futureUrl) : null,
fetchedItems
});
};

Expand All @@ -175,6 +178,10 @@ export function fetchPlaylistIfNeeded(playlistId: number): ThunkResult<Promise<a

const playlist_object = getPlaylistObjectSelector(playlistId.toString())(getState());

if (playlist_object && !playlist_object.fetchedItems) {
dispatch<Promise<any>>(fetchPlaylistTracks(playlistId));
}

if (!playlist_object || (playlist_object && playlist_object.fetchedItems === 0)) {
await dispatch<Promise<any>>({
type: ObjectsActionTypes.SET,
Expand Down Expand Up @@ -231,10 +238,8 @@ export function fetchPlaylistIfNeeded(playlistId: number): ThunkResult<Promise<a
*/
export function fetchChartsIfNeeded(objectId: string, sortType: SortTypes = SortTypes.TOP): ThunkResult<void> {
return (dispatch, getState) => {
const { objects } = getState();

const playlist_objects = objects[ObjectTypes.PLAYLISTS];
const playlist_object = playlist_objects[objectId];
const playlist_object = getPlaylistObjectSelector(objectId)(getState());

if (!playlist_object) {
dispatch(getPlaylist(SC.getChartsUrl(objectId.split('_')[0], sortType, 25), objectId));
Expand Down Expand Up @@ -281,13 +286,15 @@ export function fetchPlaylistTracks(playlistId: number, size: number = 20, ids?:
}

if (!ids) {
let new_count = playlist_object.fetchedItems + size;
const fetched = playlist_object.fetchedItems || 0;

let new_count = fetched + size;

if (new_count > playlist_object.items.length) {
new_count = playlist_object.items.length;
}

ids = playlist_object.items.slice(playlist_object.fetchedItems, new_count);
ids = playlist_object.items.slice(fetched, new_count);

}

Expand All @@ -306,7 +313,9 @@ export function fetchPlaylistTracks(playlistId: number, size: number = 20, ids?:
objectId: playlistId,
objectType: ObjectTypes.PLAYLISTS,
entities: normalized.entities,
fetchedItems: size
fetchedItems: size,
fetchedIds: normalized.result,
shouldFetchedIds: ids,
};
}),
data: {
Expand Down
10 changes: 10 additions & 0 deletions src/common/store/objects/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { isLoading, onError, onSuccess } from '../../utils/reduxUtils';
import { AppActionTypes } from '../app';
import { AuthActionTypes } from '../auth';
import { ObjectGroup, ObjectsActionTypes, ObjectsState, ObjectState, ObjectTypes, PlaylistTypes } from './types';
import _ = require('lodash');
import { NormalizedResult } from '../../../types';

const initialObjectsState = {
isFetching: false,
Expand Down Expand Up @@ -64,9 +66,17 @@ const objectState: Reducer<ObjectState<any>> = (state = initialObjectsState, act
items: [...payload.items]
};
case onSuccess(ObjectsActionTypes.SET_TRACKS):
const unableToFetch = _.difference(
payload.shouldFetchedIds.map((t: NormalizedResult) => t.id),
payload.fetchedIds.map((t: NormalizedResult) => t.id)
);

const filtered = state.items.filter((t) => unableToFetch.indexOf(t.id) === -1);

return {
...state,
isFetching: false,
items: [...filtered],
fetchedItems: state.fetchedItems + payload.fetchedItems
};
case onSuccess(AuthActionTypes.SET_LIKE):
Expand Down
1 change: 1 addition & 0 deletions src/common/store/objects/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export enum PlaylistTypes {
// Without ids
LIKES = 'LIKES',
STREAM = 'STREAM',
DISCOVER = 'DISCOVER',
MYTRACKS = 'MYTRACKS',
PLAYLIST = 'PLAYLIST',
PLAYLISTS = 'PLAYLISTS',
Expand Down
1 change: 1 addition & 0 deletions src/common/store/ui/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const getPreviousScrollTop = createSelector(
getUi,
getRouter,
(ui, router) => {
console.log(router.location.pathname);
return router.action === 'POP' ? ui.scrollPosition[router.location.pathname] : undefined;
}
);
5 changes: 5 additions & 0 deletions src/common/utils/soundcloudUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ export function getUserTracksUrl(artistID, limit = 50) {
limit,
});
}
export function getPersonalizedurl() {
return makeUrl(`selections`, {
oauth_token: true,
}, true);
}

export function getUserWebProfilesUrl(artistID) {
return makeUrl(`users/${artistID}/web-profiles`, {
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/_shared/PageHeader/PageHeader.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
}
.subtitle {
margin: 0;
color: $blue;
color: #767c89;
font-weight: 600;
font-size: 1rem;
}
Expand Down
Loading

0 comments on commit 6baf137

Please sign in to comment.