Fix grid + begin play buttons
This commit is contained in:
parent
2b3207ec44
commit
d5da4e4818
@ -143,7 +143,7 @@ export function loginUser(username, passwordOrToken, endpoint, rememberMe, redir
|
|||||||
loginUserRequest,
|
loginUserRequest,
|
||||||
jsonData => dispatch => {
|
jsonData => dispatch => {
|
||||||
if (!jsonData.auth || !jsonData.sessionExpire) {
|
if (!jsonData.auth || !jsonData.sessionExpire) {
|
||||||
return Promise.reject(new i18nRecord({ id: "app.api.error", values: {} }));
|
return dispatch(loginUserFailure(new i18nRecord({ id: "app.api.error", values: {} })));
|
||||||
}
|
}
|
||||||
const token = {
|
const token = {
|
||||||
token: jsonData.auth,
|
token: jsonData.auth,
|
||||||
|
@ -1,15 +1,26 @@
|
|||||||
import React, { Component, PropTypes } from "react";
|
import React, { Component, PropTypes } from "react";
|
||||||
import CSSModules from "react-css-modules";
|
import CSSModules from "react-css-modules";
|
||||||
|
import { defineMessages, FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import { formatLength } from "../utils";
|
import { formatLength, messagesMap } from "../utils";
|
||||||
|
|
||||||
|
import commonMessages from "../locales/messagesDescriptors/common";
|
||||||
|
|
||||||
import css from "../styles/Album.scss";
|
import css from "../styles/Album.scss";
|
||||||
|
|
||||||
|
const albumMessages = defineMessages(messagesMap(commonMessages));
|
||||||
|
|
||||||
export class AlbumTrackRow extends Component {
|
export class AlbumTrackRow extends Component {
|
||||||
render () {
|
render () {
|
||||||
const length = formatLength(this.props.track.length);
|
const length = formatLength(this.props.track.length);
|
||||||
return (
|
return (
|
||||||
<tr>
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span className="sr-only">
|
||||||
|
<FormattedMessage {...albumMessages["app.common.play"]} />
|
||||||
|
</span>
|
||||||
|
<span className="glyphicon glyphicon-play-circle" aria-hidden="true"></span>
|
||||||
|
</td>
|
||||||
<td>{this.props.track.track}</td>
|
<td>{this.props.track.track}</td>
|
||||||
<td>{this.props.track.name}</td>
|
<td>{this.props.track.name}</td>
|
||||||
<td>{length}</td>
|
<td>{length}</td>
|
||||||
|
@ -8,6 +8,7 @@ export default class Albums extends Component {
|
|||||||
const grid = {
|
const grid = {
|
||||||
isFetching: this.props.isFetching,
|
isFetching: this.props.isFetching,
|
||||||
items: this.props.albums,
|
items: this.props.albums,
|
||||||
|
itemsType: "album",
|
||||||
itemsLabel: "app.common.album",
|
itemsLabel: "app.common.album",
|
||||||
subItemsType: "tracks",
|
subItemsType: "tracks",
|
||||||
subItemsLabel: "app.common.track"
|
subItemsLabel: "app.common.track"
|
||||||
|
@ -8,6 +8,7 @@ class Artists extends Component {
|
|||||||
const grid = {
|
const grid = {
|
||||||
isFetching: this.props.isFetching,
|
isFetching: this.props.isFetching,
|
||||||
items: this.props.artists,
|
items: this.props.artists,
|
||||||
|
itemsType: "artist",
|
||||||
itemsLabel: "app.common.artist",
|
itemsLabel: "app.common.artist",
|
||||||
subItemsType: "albums",
|
subItemsType: "albums",
|
||||||
subItemsLabel: "app.common.album"
|
subItemsLabel: "app.common.album"
|
||||||
|
@ -175,8 +175,8 @@ Login.propTypes = {
|
|||||||
rememberMe: PropTypes.bool,
|
rememberMe: PropTypes.bool,
|
||||||
onSubmit: PropTypes.func.isRequired,
|
onSubmit: PropTypes.func.isRequired,
|
||||||
isAuthenticating: PropTypes.bool,
|
isAuthenticating: PropTypes.bool,
|
||||||
error: PropTypes.string,
|
info: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||||
info: PropTypes.oneOfType([PropTypes.string, PropTypes.object])
|
error: PropTypes.oneOfType([PropTypes.string, PropTypes.object])
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CSSModules(Login, css);
|
export default CSSModules(Login, css);
|
||||||
|
@ -18,12 +18,17 @@ const songsMessages = defineMessages(messagesMap(Array.concat([], commonMessages
|
|||||||
|
|
||||||
export class SongsTableRow extends Component {
|
export class SongsTableRow extends Component {
|
||||||
render () {
|
render () {
|
||||||
const length = formatLength(this.props.song.length);
|
const length = formatLength(this.props.song.time);
|
||||||
const linkToArtist = "/artist/" + this.props.song.artist.id;
|
const linkToArtist = "/artist/" + this.props.song.artist.id;
|
||||||
const linkToAlbum = "/album/" + this.props.song.album.id;
|
const linkToAlbum = "/album/" + this.props.song.album.id;
|
||||||
return (
|
return (
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td>
|
||||||
|
<span className="sr-only">
|
||||||
|
<FormattedMessage {...songsMessages["app.common.play"]} />
|
||||||
|
</span>
|
||||||
|
<span className="glyphicon glyphicon-play-circle" aria-hidden="true"></span>
|
||||||
|
</td>
|
||||||
<td className="title">{this.props.song.name}</td>
|
<td className="title">{this.props.song.name}</td>
|
||||||
<td className="artist"><Link to={linkToArtist}>{this.props.song.artist.name}</Link></td>
|
<td className="artist"><Link to={linkToArtist}>{this.props.song.artist.name}</Link></td>
|
||||||
<td className="album"><Link to={linkToAlbum}>{this.props.song.album.name}</Link></td>
|
<td className="album"><Link to={linkToAlbum}>{this.props.song.album.name}</Link></td>
|
||||||
@ -45,7 +50,7 @@ class SongsTableCSS extends Component {
|
|||||||
if (this.props.filterText) {
|
if (this.props.filterText) {
|
||||||
// Use Fuse for the filter
|
// Use Fuse for the filter
|
||||||
displayedSongs = new Fuse(
|
displayedSongs = new Fuse(
|
||||||
this.props.songs,
|
this.props.songs.toArray(),
|
||||||
{
|
{
|
||||||
"keys": ["name"],
|
"keys": ["name"],
|
||||||
"threshold": 0.4,
|
"threshold": 0.4,
|
||||||
|
@ -29,7 +29,7 @@ class FilterBarCSSIntl extends Component {
|
|||||||
<FormattedMessage {...filterMessages["app.filter.whatAreWeListeningToToday"]} />
|
<FormattedMessage {...filterMessages["app.filter.whatAreWeListeningToToday"]} />
|
||||||
</p>
|
</p>
|
||||||
<div className="col-xs-12 col-sm-6 col-md-4 input-group">
|
<div className="col-xs-12 col-sm-6 col-md-4 input-group">
|
||||||
<form className="form-inline" onSubmit={this.handleChange} aria-describedby="filterInputDescription" role="search">
|
<form className="form-inline" onSubmit={this.handleChange} aria-describedby="filterInputDescription" role="search" aria-label={formatMessage(filterMessages["app.filter.filter"])}>
|
||||||
<div className="form-group" styleName="form-group">
|
<div className="form-group" styleName="form-group">
|
||||||
<input type="text" className="form-control" placeholder={formatMessage(filterMessages["app.filter.filter"])} aria-label={formatMessage(filterMessages["app.filter.filter"])} value={this.props.filterText} onChange={this.handleChange} ref="filterTextInput" />
|
<input type="text" className="form-control" placeholder={formatMessage(filterMessages["app.filter.filter"])} aria-label={formatMessage(filterMessages["app.filter.filter"])} value={this.props.filterText} onChange={this.handleChange} ref="filterTextInput" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -30,10 +30,10 @@ class GridItemCSSIntl extends Component {
|
|||||||
|
|
||||||
var subItemsLabel = formatMessage(gridMessages[this.props.subItemsLabel], { itemCount: nSubItems });
|
var subItemsLabel = formatMessage(gridMessages[this.props.subItemsLabel], { itemCount: nSubItems });
|
||||||
|
|
||||||
const to = "/" + this.props.item.type + "/" + this.props.item.id;
|
const to = "/" + this.props.itemsType + "/" + this.props.item.id;
|
||||||
const id = "grid-item-" + this.props.item.type + "/" + this.props.item.id;
|
const id = "grid-item-" + this.props.itemsType + "/" + this.props.item.id;
|
||||||
|
|
||||||
const title = formatMessage(gridMessages["app.grid.goTo" + this.props.item.type.capitalize() + "Page"]);
|
const title = formatMessage(gridMessages["app.grid.goTo" + this.props.itemsType.capitalize() + "Page"]);
|
||||||
return (
|
return (
|
||||||
<div className="grid-item col-xs-6 col-sm-3" styleName="placeholders" id={id}>
|
<div className="grid-item col-xs-6 col-sm-3" styleName="placeholders" id={id}>
|
||||||
<div className="grid-item-content text-center">
|
<div className="grid-item-content text-center">
|
||||||
@ -48,6 +48,7 @@ class GridItemCSSIntl extends Component {
|
|||||||
|
|
||||||
GridItemCSSIntl.propTypes = {
|
GridItemCSSIntl.propTypes = {
|
||||||
item: PropTypes.object.isRequired,
|
item: PropTypes.object.isRequired,
|
||||||
|
itemsType: PropTypes.string.isRequired,
|
||||||
itemsLabel: PropTypes.string.isRequired,
|
itemsLabel: PropTypes.string.isRequired,
|
||||||
subItemsType: PropTypes.string.isRequired,
|
subItemsType: PropTypes.string.isRequired,
|
||||||
subItemsLabel: PropTypes.string.isRequired,
|
subItemsLabel: PropTypes.string.isRequired,
|
||||||
@ -96,7 +97,7 @@ export class Grid extends Component {
|
|||||||
}
|
}
|
||||||
// Use Fuse for the filter
|
// Use Fuse for the filter
|
||||||
var result = new Fuse(
|
var result = new Fuse(
|
||||||
props.items,
|
props.items.toArray(),
|
||||||
{
|
{
|
||||||
"keys": ["name"],
|
"keys": ["name"],
|
||||||
"threshold": 0.4,
|
"threshold": 0.4,
|
||||||
@ -150,11 +151,12 @@ export class Grid extends Component {
|
|||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
// The list of keys seen in the previous render
|
// The list of keys seen in the previous render
|
||||||
let currentKeys = prevProps.items.map(
|
let currentKeys = prevProps.items.map(
|
||||||
(n) => "grid-item-" + n.type + "/" + n.id);
|
(n) => "grid-item-" + prevProps.itemsType + "/" + n.id);
|
||||||
|
|
||||||
// The latest list of keys that have been rendered
|
// The latest list of keys that have been rendered
|
||||||
|
const {itemsType} = this.props;
|
||||||
let newKeys = this.props.items.map(
|
let newKeys = this.props.items.map(
|
||||||
(n) => "grid-item-" + n.type + "/" + n.id);
|
(n) => "grid-item-" + itemsType + "/" + n.id);
|
||||||
|
|
||||||
// Find which keys are new between the current set of keys and any new children passed to this component
|
// Find which keys are new between the current set of keys and any new children passed to this component
|
||||||
let addKeys = immutableDiff(newKeys, currentKeys);
|
let addKeys = immutableDiff(newKeys, currentKeys);
|
||||||
@ -162,17 +164,17 @@ export class Grid extends Component {
|
|||||||
// Find which keys have been removed between the current set of keys and any new children passed to this component
|
// Find which keys have been removed between the current set of keys and any new children passed to this component
|
||||||
let removeKeys = immutableDiff(currentKeys, newKeys);
|
let removeKeys = immutableDiff(currentKeys, newKeys);
|
||||||
|
|
||||||
|
var iso = this.iso;
|
||||||
if (removeKeys.count() > 0) {
|
if (removeKeys.count() > 0) {
|
||||||
removeKeys.forEach(removeKey => this.iso.remove(document.getElementById(removeKey)));
|
removeKeys.forEach(removeKey => iso.remove(document.getElementById(removeKey)));
|
||||||
this.iso.arrange();
|
iso.arrange();
|
||||||
}
|
}
|
||||||
if (addKeys.count() > 0) {
|
if (addKeys.count() > 0) {
|
||||||
const itemsToAdd = addKeys.map((addKey) => document.getElementById(addKey)).toArray();
|
const itemsToAdd = addKeys.map((addKey) => document.getElementById(addKey)).toArray();
|
||||||
this.iso.addItems(itemsToAdd);
|
iso.addItems(itemsToAdd);
|
||||||
this.iso.arrange();
|
iso.arrange();
|
||||||
}
|
}
|
||||||
|
|
||||||
var iso = this.iso;
|
|
||||||
// Layout again after images are loaded
|
// Layout again after images are loaded
|
||||||
imagesLoaded(this.refs.grid).on("progress", function() {
|
imagesLoaded(this.refs.grid).on("progress", function() {
|
||||||
// Layout after each image load, fix for responsive grid
|
// Layout after each image load, fix for responsive grid
|
||||||
@ -185,11 +187,9 @@ export class Grid extends Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
var gridItems = [];
|
var gridItems = [];
|
||||||
const itemsLabel = this.props.itemsLabel;
|
const { itemsType, itemsLabel, subItemsType, subItemsLabel } = this.props;
|
||||||
const subItemsType = this.props.subItemsType;
|
|
||||||
const subItemsLabel = this.props.subItemsLabel;
|
|
||||||
this.props.items.forEach(function (item) {
|
this.props.items.forEach(function (item) {
|
||||||
gridItems.push(<GridItem item={item} itemsLabel={itemsLabel} subItemsType={subItemsType} subItemsLabel={subItemsLabel} key={item.id} />);
|
gridItems.push(<GridItem item={item} itemsType={itemsType} itemsLabel={itemsLabel} subItemsType={subItemsType} subItemsLabel={subItemsLabel} key={item.id} />);
|
||||||
});
|
});
|
||||||
var loading = null;
|
var loading = null;
|
||||||
if (gridItems.length == 0 && this.props.isFetching) {
|
if (gridItems.length == 0 && this.props.isFetching) {
|
||||||
@ -220,8 +220,10 @@ export class Grid extends Component {
|
|||||||
Grid.propTypes = {
|
Grid.propTypes = {
|
||||||
isFetching: PropTypes.bool.isRequired,
|
isFetching: PropTypes.bool.isRequired,
|
||||||
items: PropTypes.instanceOf(Immutable.List).isRequired,
|
items: PropTypes.instanceOf(Immutable.List).isRequired,
|
||||||
|
itemsType: PropTypes.string.isRequired,
|
||||||
itemsLabel: PropTypes.string.isRequired,
|
itemsLabel: PropTypes.string.isRequired,
|
||||||
subItemsType: PropTypes.string.isRequired,
|
subItemsType: PropTypes.string.isRequired,
|
||||||
|
subItemsLabel: PropTypes.string.isRequired,
|
||||||
filterText: PropTypes.string
|
filterText: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ class PaginationCSSIntl extends Component {
|
|||||||
// Push first page
|
// Push first page
|
||||||
pagesButton.push(
|
pagesButton.push(
|
||||||
<li className="page-item" key={key}>
|
<li className="page-item" key={key}>
|
||||||
<Link role="button" className="page-link" title={formatMessage(paginationMessages["app.pagination.goToPageWithoutMarkup"], { pageNumber: 1})} to={this.props.buildLinkToPage(1)}>
|
<Link className="page-link" title={formatMessage(paginationMessages["app.pagination.goToPageWithoutMarkup"], { pageNumber: 1})} to={this.props.buildLinkToPage(1)}>
|
||||||
<FormattedHTMLMessage {...paginationMessages["app.pagination.goToPage"]} values={{ pageNumber: 1 }} />
|
<FormattedHTMLMessage {...paginationMessages["app.pagination.goToPage"]} values={{ pageNumber: 1 }} />
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
@ -95,7 +95,7 @@ class PaginationCSSIntl extends Component {
|
|||||||
const title = formatMessage(paginationMessages["app.pagination.goToPageWithoutMarkup"], { pageNumber: i });
|
const title = formatMessage(paginationMessages["app.pagination.goToPageWithoutMarkup"], { pageNumber: i });
|
||||||
pagesButton.push(
|
pagesButton.push(
|
||||||
<li className={className} key={key}>
|
<li className={className} key={key}>
|
||||||
<Link role="button" className="page-link" title={title} to={this.props.buildLinkToPage(i)}>
|
<Link className="page-link" title={title} to={this.props.buildLinkToPage(i)}>
|
||||||
<FormattedHTMLMessage {...paginationMessages["app.pagination.goToPage"]} values={{ pageNumber: i }} />
|
<FormattedHTMLMessage {...paginationMessages["app.pagination.goToPage"]} values={{ pageNumber: i }} />
|
||||||
{currentSpan}
|
{currentSpan}
|
||||||
</Link>
|
</Link>
|
||||||
@ -117,7 +117,7 @@ class PaginationCSSIntl extends Component {
|
|||||||
// Push last page
|
// Push last page
|
||||||
pagesButton.push(
|
pagesButton.push(
|
||||||
<li className="page-item" key={key}>
|
<li className="page-item" key={key}>
|
||||||
<Link role="button" className="page-link" title={title} to={this.props.buildLinkToPage(this.props.nPages)}>
|
<Link className="page-link" title={title} to={this.props.buildLinkToPage(this.props.nPages)}>
|
||||||
<FormattedHTMLMessage {...paginationMessages["app.pagination.goToPage"]} values={{ pageNumber: this.props.nPages }} />
|
<FormattedHTMLMessage {...paginationMessages["app.pagination.goToPage"]} values={{ pageNumber: this.props.nPages }} />
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
|
2
app/dist/fix.ie9.js.map
vendored
2
app/dist/fix.ie9.js.map
vendored
File diff suppressed because one or more lines are too long
44
app/dist/index.js
vendored
44
app/dist/index.js
vendored
File diff suppressed because one or more lines are too long
2
app/dist/index.js.map
vendored
2
app/dist/index.js.map
vendored
File diff suppressed because one or more lines are too long
@ -8,6 +8,7 @@ module.exports = {
|
|||||||
"app.common.close": "Close", // Close
|
"app.common.close": "Close", // Close
|
||||||
"app.common.go": "Go", // Go
|
"app.common.go": "Go", // Go
|
||||||
"app.common.loading": "Loading…", // Loading indicator
|
"app.common.loading": "Loading…", // Loading indicator
|
||||||
|
"app.common.play": "Play", // PLay icon description
|
||||||
"app.common.track": "{itemCount, plural, one {track} other {tracks}}", // Track
|
"app.common.track": "{itemCount, plural, one {track} other {tracks}}", // Track
|
||||||
"app.filter.filter": "Filter…", // Filtering input placeholder
|
"app.filter.filter": "Filter…", // Filtering input placeholder
|
||||||
"app.filter.whatAreWeListeningToToday": "What are we listening to today?", // Description for the filter bar
|
"app.filter.whatAreWeListeningToToday": "What are we listening to today?", // Description for the filter bar
|
||||||
|
@ -8,6 +8,7 @@ module.exports = {
|
|||||||
"app.common.close": "Fermer", // Close
|
"app.common.close": "Fermer", // Close
|
||||||
"app.common.go": "Aller", // Go
|
"app.common.go": "Aller", // Go
|
||||||
"app.common.loading": "Chargement…", // Loading indicator
|
"app.common.loading": "Chargement…", // Loading indicator
|
||||||
|
"app.common.play": "Jouer", // PLay icon description
|
||||||
"app.common.track": "{itemCount, plural, one {piste} other {pistes}}", // Track
|
"app.common.track": "{itemCount, plural, one {piste} other {pistes}}", // Track
|
||||||
"app.filter.filter": "Filtrer…", // Filtering input placeholder
|
"app.filter.filter": "Filtrer…", // Filtering input placeholder
|
||||||
"app.filter.whatAreWeListeningToToday": "Que voulez-vous écouter aujourd'hui\u00a0?", // Description for the filter bar
|
"app.filter.whatAreWeListeningToToday": "Que voulez-vous écouter aujourd'hui\u00a0?", // Description for the filter bar
|
||||||
|
@ -34,6 +34,11 @@ const messages = [
|
|||||||
description: "Loading indicator",
|
description: "Loading indicator",
|
||||||
defaultMessage: "Loading…"
|
defaultMessage: "Loading…"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "app.common.play",
|
||||||
|
description: "PLay icon description",
|
||||||
|
defaultMessage: "Play"
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default messages;
|
export default messages;
|
||||||
|
@ -46,7 +46,7 @@ function _checkAPIErrors (jsonData) {
|
|||||||
return jsonData;
|
return jsonData;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _uglyFixes (endpoint, token) {
|
function _uglyFixes () {
|
||||||
if (typeof _uglyFixes.artistsCount === "undefined" ) {
|
if (typeof _uglyFixes.artistsCount === "undefined" ) {
|
||||||
_uglyFixes.artistsCount = 0;
|
_uglyFixes.artistsCount = 0;
|
||||||
}
|
}
|
||||||
@ -58,51 +58,70 @@ function _uglyFixes (endpoint, token) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var _uglyFixesSongs = function (songs) {
|
var _uglyFixesSongs = function (songs) {
|
||||||
for (var i = 0; i < songs.length; i++) {
|
return songs.map(function (song) {
|
||||||
// Add song type
|
|
||||||
songs[i].type = "track";
|
|
||||||
// Fix for name becoming title in songs objects
|
|
||||||
songs[i].name = songs[i].title;
|
|
||||||
// Fix for length being time in songs objects
|
|
||||||
songs[i].length = songs[i].time;
|
|
||||||
|
|
||||||
// Fix for cdata left in artist and album
|
// Fix for cdata left in artist and album
|
||||||
songs[i].artist.name = songs[i].artist.cdata;
|
song.artist.name = song.artist.cdata;
|
||||||
songs[i].album.name = songs[i].album.cdata;
|
song.album.name = song.album.cdata;
|
||||||
}
|
return song;
|
||||||
return songs;
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var _uglyFixesAlbums = function (albums) {
|
var _uglyFixesAlbums = function (albums) {
|
||||||
for (var i = 0; i < albums.length; i++) {
|
return albums.map(function (album) {
|
||||||
// Add album type
|
// TODO
|
||||||
albums[i].type = "album";
|
|
||||||
|
|
||||||
// Fix for absence of distinction between disks in the same album
|
// Fix for absence of distinction between disks in the same album
|
||||||
if (albums[i].disk > 1) {
|
if (album.disk > 1) {
|
||||||
albums[i].name = albums[i].name + " [Disk " + albums[i].disk + "]";
|
album.name = album.name + " [Disk " + album.disk + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move songs one node top
|
// Move songs one node top
|
||||||
if (albums[i].tracks.song) {
|
if (album.tracks.song) {
|
||||||
albums[i].tracks = albums[i].tracks.song;
|
album.tracks = album.tracks.song;
|
||||||
|
|
||||||
// Ensure tracks is an array
|
// Ensure tracks is an array
|
||||||
if (!Array.isArray(albums[i].tracks)) {
|
if (!Array.isArray(album.tracks)) {
|
||||||
albums[i].tracks = [albums[i].tracks];
|
album.tracks = [album.tracks];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix tracks
|
// Fix tracks
|
||||||
albums[i].tracks = _uglyFixesSongs(albums[i].tracks);
|
album.tracks = _uglyFixesSongs(album.tracks);
|
||||||
}
|
}
|
||||||
|
return album;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var _uglyFixesArtists = function (artists) {
|
||||||
|
return artists.map(function (artist) {
|
||||||
|
// Move albums one node top
|
||||||
|
if (artist.albums.album) {
|
||||||
|
artist.albums = artist.albums.album;
|
||||||
|
|
||||||
|
// Ensure albums are an array
|
||||||
|
if (!Array.isArray(artist.albums)) {
|
||||||
|
artist.albums = [artist.albums];
|
||||||
}
|
}
|
||||||
return albums;
|
|
||||||
|
// Fix albums
|
||||||
|
artist.albums = _uglyFixesAlbums(artist.albums);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move songs one node top
|
||||||
|
if (artist.songs.song) {
|
||||||
|
artist.songs = artist.songs.song;
|
||||||
|
|
||||||
|
// Ensure songs are an array
|
||||||
|
if (!Array.isArray(artist.songs)) {
|
||||||
|
artist.songs = [artist.songs];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix songs
|
||||||
|
artist.songs = _uglyFixesSongs(artist.songs);
|
||||||
|
}
|
||||||
|
return artist;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return jsonData => {
|
return jsonData => {
|
||||||
// Camelize
|
|
||||||
jsonData = humps.camelizeKeys(jsonData);
|
|
||||||
|
|
||||||
// Ensure items are always wrapped in an array
|
// Ensure items are always wrapped in an array
|
||||||
if (jsonData.artist && !Array.isArray(jsonData.artist)) {
|
if (jsonData.artist && !Array.isArray(jsonData.artist)) {
|
||||||
jsonData.artist = [jsonData.artist];
|
jsonData.artist = [jsonData.artist];
|
||||||
@ -114,6 +133,7 @@ function _uglyFixes (endpoint, token) {
|
|||||||
jsonData.song = [jsonData.song];
|
jsonData.song = [jsonData.song];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
// Keep track of artists count
|
// Keep track of artists count
|
||||||
if (jsonData.artists) {
|
if (jsonData.artists) {
|
||||||
_uglyFixes.artistsCount = parseInt(jsonData.artists);
|
_uglyFixes.artistsCount = parseInt(jsonData.artists);
|
||||||
@ -127,49 +147,22 @@ function _uglyFixes (endpoint, token) {
|
|||||||
_uglyFixes.songsCount = parseInt(jsonData.songs);
|
_uglyFixes.songsCount = parseInt(jsonData.songs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fix artists
|
||||||
if (jsonData.artist) {
|
if (jsonData.artist) {
|
||||||
for (var i = 0; i < jsonData.artist.length; i++) {
|
jsonData.artist = _uglyFixesArtists(jsonData.artist);
|
||||||
// Add artist type
|
|
||||||
jsonData.artist[i].type = "artist";
|
|
||||||
|
|
||||||
// Fix for artists art not included
|
|
||||||
jsonData.artist[i].art = endpoint.replace("/server/xml.server.php", "") + "/image.php?object_id=" + jsonData.artist[i].id + "&object_type=artist&auth=" + token;
|
|
||||||
|
|
||||||
// Move albums one node top
|
|
||||||
if (jsonData.artist[i].albums.album) {
|
|
||||||
jsonData.artist[i].albums = jsonData.artist[i].albums.album;
|
|
||||||
|
|
||||||
// Ensure albums are an array
|
|
||||||
if (!Array.isArray(jsonData.artist[i].albums)) {
|
|
||||||
jsonData.artist[i].albums = [jsonData.artist[i].albums];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix albums
|
|
||||||
jsonData.artist[i].albums = _uglyFixesAlbums(jsonData.artist[i].albums);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move songs one node top
|
|
||||||
if (jsonData.artist[i].songs.song) {
|
|
||||||
jsonData.artist[i].songs = jsonData.artist[i].songs.song;
|
|
||||||
|
|
||||||
// Ensure songs are an array
|
|
||||||
if (!Array.isArray(jsonData.artist[i].songs)) {
|
|
||||||
jsonData.artist[i].songs = [jsonData.artist[i].songs];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix songs
|
|
||||||
jsonData.artist[i].songs = _uglyFixesSongs(jsonData.artist[i].songs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Store the total number of items
|
// Store the total number of items
|
||||||
jsonData.artists = _uglyFixes.artistsCount;
|
jsonData.artists = _uglyFixes.artistsCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fix albums
|
||||||
if (jsonData.album) {
|
if (jsonData.album) {
|
||||||
// Fix albums
|
// Fix albums
|
||||||
jsonData.album = _uglyFixesAlbums(jsonData.album);
|
jsonData.album = _uglyFixesAlbums(jsonData.album);
|
||||||
// Store the total number of items
|
// Store the total number of items
|
||||||
jsonData.albums = _uglyFixes.albumsCount;
|
jsonData.albums = _uglyFixes.albumsCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fix songs
|
||||||
if (jsonData.song) {
|
if (jsonData.song) {
|
||||||
// Fix songs
|
// Fix songs
|
||||||
jsonData.song = _uglyFixesSongs(jsonData.song);
|
jsonData.song = _uglyFixesSongs(jsonData.song);
|
||||||
@ -177,6 +170,8 @@ function _uglyFixes (endpoint, token) {
|
|||||||
jsonData.songs = _uglyFixes.songsCount;
|
jsonData.songs = _uglyFixes.songsCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// Add sessionExpire information
|
||||||
if (!jsonData.sessionExpire) {
|
if (!jsonData.sessionExpire) {
|
||||||
// Fix for Ampache not returning updated sessionExpire
|
// Fix for Ampache not returning updated sessionExpire
|
||||||
jsonData.sessionExpire = (new Date(Date.now() + 3600 * 1000)).toJSON();
|
jsonData.sessionExpire = (new Date(Date.now() + 3600 * 1000)).toJSON();
|
||||||
@ -186,6 +181,11 @@ function _uglyFixes (endpoint, token) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _normalizeResponse(jsonData) {
|
||||||
|
// TODO
|
||||||
|
return jsonData;
|
||||||
|
}
|
||||||
|
|
||||||
// Fetches an API response and normalizes the result JSON according to schema.
|
// Fetches an API response and normalizes the result JSON according to schema.
|
||||||
// This makes every API response have the same shape, regardless of how nested it was.
|
// This makes every API response have the same shape, regardless of how nested it was.
|
||||||
function doAPICall (endpoint, action, auth, username, extraParams) {
|
function doAPICall (endpoint, action, auth, username, extraParams) {
|
||||||
@ -206,7 +206,9 @@ function doAPICall (endpoint, action, auth, username, extraParams) {
|
|||||||
.then (response => response.text())
|
.then (response => response.text())
|
||||||
.then(_parseToJSON)
|
.then(_parseToJSON)
|
||||||
.then(_checkAPIErrors)
|
.then(_checkAPIErrors)
|
||||||
.then(_uglyFixes(endpoint, auth));
|
.then(jsonData => humps.camelizeKeys(jsonData)) // Camelize
|
||||||
|
.then(_uglyFixes())
|
||||||
|
.then(_normalizeResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Action key that carries API call info interpreted by this Redux middleware.
|
// Action key that carries API call info interpreted by this Redux middleware.
|
||||||
|
Loading…
Reference in New Issue
Block a user