Commit 076cd507 authored by Mathieu Delestre's avatar Mathieu Delestre

Merge branch '339-frontend-ui-for-download' into 300-kara-line

parents ff64d33f 95973631
......@@ -20,65 +20,6 @@ var mouseDown; // Boolean : capture if the mouse is pressed
document.documentElement.scrollTop = 0; // For IE and Firefox
});
$('#volume').on('mouseleave', () => {
$('#volume').click();
});
$('button[action="command"], a[action="command"]').click(function (e) {
var name = $(this).attr('name');
var dataAjax = { command: name };
if ($(this).val() != '') dataAjax['options'] = $(this).val();
if (e.target.name == 'setVolume') {
var btn = $(e.target);
var val = parseInt(btn.val()), base = 100, pow = .76;
val = Math.pow(val, pow) / Math.pow(base, pow);
val = val * base;
dataAjax = { command: btn.attr('name'), options: val };
}
// ask for the kara list from given playlist
if (ajaxSearch[name]) ajaxSearch[name].abort();
ajaxSearch[name] = $.ajax({
url: 'admin/player',
type: 'PUT',
data: dataAjax
});
});
$('.btn[action="account"]').click(function () {
showProfil();
});
$('.btn[action="poweroff"]').click(function () {
$.ajax({
url: 'admin/shutdown',
type: 'POST',
}).done(function () {
DEBUG && console.log('Shutdown');
stopUpdate = true;
});
});
$('#adminMessage').click(function () {
displayModal('custom', 'Message indispensable',
'<select class="form-control" name="destination"><option value="screen">' + i18n.__('CL_SCREEN') + '</option>'
+ '<option value="users">' + i18n.__('CL_USERS') + '</option><option value="all">' + i18n.__('CL_ALL') + '</option></select>'
+ '<input type="text"name="duration" placeholder="5000 (ms)"/>'
+ '<input type="text" placeholder="Message" class="form-control" id="message" name="message">', function (data)
{
var defaultDuration = 5000;
var msgData = {
message: data.message,
destination: data.destination,
duration: !data.duration || isNaN(data.duration) ? defaultDuration : data.duration
};
ajx('POST', 'admin/player/message', msgData);
}
);
});
$('[name="searchPlaylist"]').keypress(function (e) { // allow pressing enter to validate a setting
if (e.which == 13) {
......@@ -359,10 +300,6 @@ var mouseDown; // Boolean : capture if the mouse is pressed
setStopUpdate = function (stop) {
stopUpdate = stop;
};
$('select[name="Player.Screen"] > option').each(function (i) {
$(this).text(i + 1 + ' - ' + $(this).text());
});
});
/*** INITIALISATION ***/
......@@ -371,16 +308,10 @@ var mouseDown; // Boolean : capture if the mouse is pressed
mouseDown = false;
panel1Default = -1;
// nameExclude = input not being updated (most likely user is on it)
getSettings = function (nameExclude) {
getSettings = function () {
var promise = $.Deferred();
$.ajax({ url: 'admin/settings' }).done(function (data) {
settings = data;
if(settings.Online.Stats === undefined) {
window.callOnlineStatsModal();
}
playlistToAdd = data.Karaoke.Private ? 'current' : 'public';
$.ajax({ url: 'public/playlists/' + playlistToAdd, }).done(function (data) {
......
......@@ -183,7 +183,7 @@ var plData;
$('.changePseudo').click( function() {
if(logInfos.token && !showedLoginAfter401) {
showProfil();
window.callProfileModal();
} else {
window.callLoginModal(scope);
}
......@@ -645,13 +645,6 @@ var plData;
});
/* login stuff END */
/* profil stuff */
showProfil = function() {
window.callProfileModal();
};
/* profil stuff END */
/* prevent the virtual keyboard popup when on touchscreen by not focusing the search input */
if(isTouchScreen) {
$('#progressBarColor').addClass('cssTransition');
......@@ -1219,10 +1212,8 @@ var plData;
/**
* refresh the player infos
* @param {Function} callback - function to call at the end of the refresh
* @param {anything} param1 - param to give to this function
*/
refreshPlayerInfos = function (data, callback, param1) {
refreshPlayerInfos = function (data) {
if (oldState != data && logInfos.username) {
var newWidth = $('#karaInfo').width() * parseInt(10000 * ( data.timePosition + refreshTime/1000) / $('#karaInfo').attr('length')) / 10000 + 'px';
......@@ -1234,15 +1225,12 @@ var plData;
status = data.status === 'stop' ? 'stop' : data.playerStatus;
switch (status) {
case 'play':
$('#status').attr('name','pause');
$('#progressBarColor').addClass('cssTransform');
break;
case 'pause':
$('#status').attr('name', 'play');
$('#progressBarColor').removeClass('cssTransform');
break;
case 'stop':
$('#status').attr('name', 'play');
$('#progressBarColor').removeClass('cssTransform');
break;
default:
......@@ -1291,38 +1279,8 @@ var plData;
});
}
}
if (data.showSubs != oldState.showSubs) {
if (data.showSubs) {
$('#showSubs').attr('name','hideSubs');
} else {
$('#showSubs').attr('name','showSubs');
}
}
if (data.muteStatus != oldState.muteStatus) {
if (!data.muteStatus) {
$('#mutestatus').attr('name','mute');
} else {
$('#mutestatus').attr('name','unmute');
}
}
if (data.onTop != oldState.onTop) {
$('input[name="Player.StayOnTop"]').bootstrapSwitch('state', data.onTop, true);
}
if (data.fullscreen != oldState.fullscreen) {
$('input[name="Player.FullScreen"]').bootstrapSwitch('state', data.fullscreen, true);
}
if (data.volume != oldState.volume) {
var val = data.volume, base = 100, pow = .76;
val = val / base;
val = base * Math.pow(val, 1/pow);
val = parseInt(val);
$('input[name="setVolume"]').val(val);
}
oldState = data;
if (callback && typeof callback === 'function' && typeof param1 != 'undefined') {
callback(param1);
}
}
};
......@@ -1623,13 +1581,13 @@ var plData;
* Init bootstrapSwitchs
*/
initSwitchs = function () {
$('input[switch="onoff"],[name="Karaoke.Private"],[name="kara_panel"],[name="lyrics"]').bootstrapSwitch('destroy', true);
$('input[switch="onoff"],[name="kara_panel"],[name="lyrics"]').bootstrapSwitch('destroy', true);
$('input[switch="onoff"]').bootstrapSwitch({
wrapperClass: 'btn btn-default',
'data-size': 'normal'
});
$('[name="Karaoke.Private"],[name="kara_panel"],[name="lyrics"]').bootstrapSwitch({
$('[name="kara_panel"],[name="lyrics"]').bootstrapSwitch({
'wrapperClass': 'btn',
'data-size': 'large',
'labelWidth': '15',
......@@ -1644,36 +1602,7 @@ var plData;
$container.attr('introLabel', introLabel).attr('introStep', introStep);
}
});
/* init selects & switchs */
if(scope === 'admin') {
$('[name="kara_panel"]').on('switchChange.bootstrapSwitch', function (event, state) {
if (state) {
$('#playlist').show();
$('#manage').hide();
} else {
$('#playlist').hide();
$('#manage').show();
if(introManager && introManager._currentStep) {
introManager.nextStep();
}
}
});
$('input[name="Karaoke.Private"]').on('switchChange.bootstrapSwitch', function () {
const value = $(this).val() === 'on' ? true : false;
$.ajax({
type: 'PUT',
url: 'admin/settings',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify({ 'setting': {'Karaoke': {'Private': value}} })
});
});
}
/* set the right value for switchs */
$('input[type="checkbox"],[switch="onoff"]').on('switchChange.bootstrapSwitch', function () {
$(this).val($(this).is(':checked') ? 'true' : 'false');
......
<div id="header" class="header" introStep="6" introLabel="lecteur" introTooltipClass="_introBottom">
<div class="dropdown btn btn-default btn-dark pull-right" id="manageButton">
<button class="btn btn-dark pull-right dropdown-toggle klogo" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li title="{{i18n "ACCOUNT"}}" action="account" class="btn btn-default btn-dark">
<i class="glyphicon glyphicon-user"></i></li>
<li title="{{i18n "LOGOUT"}}" action="logout" class="btn btn-default btn-dark">
<i class="glyphicon glyphicon-log-out"></i></li>
<li title="{{i18n "SHUTDOWN"}}" action="poweroff" class="btn btn-default btn-dark">
<i class="glyphicon glyphicon-off"></i></li>
</ul>
</div>
<a title="{{i18n "MUTE_UNMUTE"}}" action="command" id="mutestatus" name="mute" class="btn btn-default btn-dark pull-right">
<i class="glyphicon glyphicon-volume-up unmute"></i>
<i class="glyphicon glyphicon-volume-off mute"></i>
<input title='{{i18n "VOLUME_LEVEL"}}' action="command" name="setVolume" id="volume" value="100" type="range" />
</a>
<button title="{{i18n "SHOW_HIDE_SUBS"}}" action="command" id="showSubs" name="hideSubs" class="btn btn-default btn-dark pull-right">
<i class="glyphicon glyphicon-subtitles hideSubs"></i>
<i class="glyphicon glyphicon glyphicon-question-sign showSubs"></i>
</button>
<button title="{{i18n "MESSAGE"}}" id="adminMessage" class="btn btn-dark pull-right" style="border-left-width: 0px"><i class="glyphicon glyphicon-comment"></i></button>
<div class="pull-left btn-group switchs" style="width: 129px; max-width: 12.4vw;">
<input title='{{i18n "SWITCH_PRIVATE"}}' data-introStep="7" data-introLabel="mode" type="checkbox" checked name="Karaoke.Private" class="btn pull-left" data-on-text="<i class='glyphicon glyphicon-eye-close'></i> {{i18n "PRIVATE"}}"
data-off-text="<i class='glyphicon glyphicon-eye-open'></i> {{i18n "PUBLIC"}}" data-size="large"/>
<input title='{{i18n "SWITCH_OPTIONS"}}' data-introStep="13" data-introLabel="settings" type="checkbox" checked name="kara_panel" class="btn pull-left" data-off-text="<i class='glyphicon glyphicon-cog'></i> {{i18n "OPTIONS"}}"
data-on-text="<i class='glyphicon glyphicon glyphicon-music'></i> {{i18n "CL_PLAYLISTS"}}" data-size="large"/>
</div>
<div class="pull-left btn-group">
<button title="{{i18n "STOP_AFTER"}}" action="command" id="stopAfter" name="stopAfter" class="btn btn-danger-low" style="width: 50px;">
<i class="glyphicon glyphicon-stop"></i><i class="glyphicon glyphicon-time secondaryIcon"></i></button>
<button title="{{i18n "STOP_NOW"}}" action="command" id="stopNow" name="stopNow" class="btn btn-danger"> <i class="glyphicon glyphicon-stop"></i></button>
<button title="{{i18n "REWIND"}}" action="command" id="goTo" name="goTo" value="0" class="btn btn-dark"><i class="glyphicon glyphicon-fast-backward"></i></button>
</div>
<div class="btn-group centerBtns">
<button title="{{i18n "REWIND"}}" action="command" id="prev" name="prev" class="btn btn-default"><i class="glyphicon glyphicon-chevron-left"></i></button>
<button title="{{i18n "PLAY_PAUSE"}}" action="command" id="status" name="play" class="btn btn-primary"><i class="glyphicon glyphicon-play play"></i><i class="glyphicon glyphicon-pause pause"></i></button>
<button title="{{i18n "NEXT_SONG"}}" action="command" id="skip" name="skip" class="btn btn-default"><i class="glyphicon glyphicon-chevron-right"></i></button>
<button class="btn btn-default hidden"></button>
</div>
</div>
<div id="progressBar" class="underHeader">
<div id="karaInfo" idKara="-1" ondragstart="return false" draggable="false"><span>{{i18n "KARA_PAUSED_WAITING"}}<span></div>
<div id="progressBarColor" class="cssTransform"></div>
......
......@@ -17,6 +17,7 @@
<body scope="admin">
<div id="root"></div>
<div id="adminHeader"></div>
{{{ body }}}
<a id="downloadAnchorElem"></a>
</body>
......@@ -45,4 +46,5 @@
<script src="/ressources/js/karaokemugen.js"></script>
<script src="/ressources/js/tools.js"></script>
<script src="/ressources/js/admin.js"></script>
<script>window.adminHeader();</script>
</html>
\ No newline at end of file
......@@ -21,5 +21,32 @@
<a id="downloadAnchorElem"></a>
<div class="toastMessageContainer"></div>
</body>
<script>
var query = {{{ query }}};
var scope = 'welcome';
var appFirstRun = {{ appFirstRun }} == true;
var webappMode = 2;
welcomeScreen = true;
</script>
<script src="/ressources/vendors/js/jquery-3.2.1.min.js"></script>
<script src="/ressources/vendors/js/select2.min.js"></script>
<script src="/ressources/vendors/js/bootstrap.min.js"></script>
<script src="/ressources/vendors/js/i18n.js"></script>
<script src="/ressources/vendors/js/assignIE.js"></script>
<script src="/ressources/vendors/js/bootstrap-switch.min.js"></script>
<script src="/ressources/vendors/js/jquery-ui.min.js"></script>
<script src="/ressources/vendors/js/jquery.ui.touch-punch.min.js"></script>
<script src="/ressources/vendors/js/hammer.min.js"></script>
<script src="/ressources/vendors/js/hammer-time.min.js"></script>
<script src="/ressources/vendors/js/velocity.min.js"></script>
<script src="/ressources/vendors/js/perfect-scrollbar.jquery.min.js"></script>
<script src="/ressources/vendors/js/intro.js"></script>
<script src="/ressources/vendors/js/sprintf.min.js"></script>
<script src="/build/app.js"></script>
<script src="/ressources/js/karaokemugen.js"></script>
<script src="/ressources/js/admin.js"></script>
<script src="/ressources/js/tools.js"></script>
<script>window.welcomePage();</script>
</html>
\ No newline at end of file
<!-- Js -->
<script>
var query = {{{ query }}};
var scope = 'welcome';
var appFirstRun = {{ appFirstRun }} == true;
var webappMode = 2;
welcomeScreen = true;
</script>
<script src="/ressources/vendors/js/jquery-3.2.1.min.js"></script>
<script src="/ressources/vendors/js/select2.min.js"></script>
<script src="/ressources/vendors/js/bootstrap.min.js"></script>
<script src="/ressources/vendors/js/i18n.js"></script>
<script src="/ressources/vendors/js/assignIE.js"></script>
<script src="/ressources/vendors/js/bootstrap-switch.min.js"></script>
<script src="/ressources/vendors/js/jquery-ui.min.js"></script>
<script src="/ressources/vendors/js/jquery.ui.touch-punch.min.js"></script>
<script src="/ressources/vendors/js/hammer.min.js"></script>
<script src="/ressources/vendors/js/hammer-time.min.js"></script>
<script src="/ressources/vendors/js/velocity.min.js"></script>
<script src="/ressources/vendors/js/perfect-scrollbar.jquery.min.js"></script>
<script src="/ressources/vendors/js/intro.js"></script>
<script src="/ressources/vendors/js/sprintf.min.js"></script>
<script src="/build/app.js"></script>
<script src="/ressources/js/karaokemugen.js"></script>
<script src="/ressources/js/admin.js"></script>
<script src="/ressources/js/tools.js"></script>
<script>window.welcomePage();</script>
\ No newline at end of file
......@@ -14,5 +14,4 @@
@import './styles/admin.scss';
@import './styles/main.scss';
@import './styles/public.scss';
@import './styles/Switch.scss';
@import './styles/Autocomplete.scss';
\ No newline at end of file
......@@ -15,6 +15,7 @@ import axios from 'axios';
import WelcomePage from './components/WelcomePage';
import KaraDetail from './components/karas/KaraDetail';
import KaraList from './components/karas/KaraList';
import AdminHeader from './components/AdminHeader';
const Loader = () => (
<div>loading...</div>
......@@ -77,3 +78,7 @@ window.buildKaraList = (data, scope, idPlaylist, flagPublic, filter, side) => {
<KaraList data={data} scope={scope} idPlaylist={idPlaylist} flagPublic={flagPublic} filter={filter} gitlabEnabled={settings.config.Gitlab.Enabled} side={side}/>
</Suspense>, document.getElementById('playlist' + side));
}
window.adminHeader = () => {
ReactDOM.render(<Suspense fallback={<Loader />}><AdminHeader config={settings.config} profileModal={callProfileModal} callModal={callModal}/></Suspense>, document.getElementById('adminHeader'));
}
\ No newline at end of file
This diff is collapsed.
import React, { Component } from "react";
import '../styles/RadioButton.scss';
class RadioButton extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="radiobutton-ui">
{
this.props.buttons.map(function(item,i){
var style = {};
if(item.active && item.activeColor)
style.backgroundColor = item.activeColor;
return (
<button
key={i}
type="button"
className={item.active ? 'active':''}
style={style}
onClick={item.onClick}
>
{item.label}
</button>
)
})
}
</div>
);
}
}
export default RadioButton;
\ No newline at end of file
import React, { Component } from "react";
import '../styles/Switch.scss';
class Switch extends Component {
constructor(props) {
......
......@@ -10,7 +10,7 @@ class KaraLine extends Component {
}
getActionsDiv() {
var addKaraButton = (<button title={this.props.t('TOOLTIP_ADDKARA') + (scope == 'admin' ? ' - ' + t('TOOLTIP_ADDKARA_ADMIN') : '')}
var addKaraButton = (<button title={this.props.t('TOOLTIP_ADDKARA') + (scope == 'admin' ? ' - ' + this.props.t('TOOLTIP_ADDKARA_ADMIN') : '')}
name="addKara" className="btn btn-sm btn-action"></button>);
if (this.props.scope === 'admin' && (this.props.idPlaylist >= 0 || this.props.idPlaylist === -3)) {
// Admin et playlist standard ou Whitelist
......
import React, { Component } from "react";
import { withTranslation } from "react-i18next";
import KaraLine from "./KaraLine";
class KaraList extends Component {
......@@ -7,6 +8,7 @@ class KaraList extends Component {
}
render() {
const t = this.props.t;
var data = this.props.data;
var count = this.props.data.infos ? this.props.data.infos.count : 0;
var container = $('#panel' + this.props.side + ' .playlistContainer');
......@@ -30,4 +32,5 @@ class KaraList extends Component {
}
}
export default KaraList;
export default withTranslation()(KaraList);
\ No newline at end of file
import React, { Component } from "react";
import { withTranslation } from 'react-i18next';
import axios from 'axios';
import {expand} from '../toolsReact';
class OnlineStatsModal extends Component {
constructor(props) {
......@@ -8,14 +9,8 @@ class OnlineStatsModal extends Component {
this.onClick = this.onClick.bind(this);
}
expand(str, val) {
return str.split('.').reduceRight((acc, currentValue) => {
return { [currentValue]: acc };
}, val);
};
onClick(e) {
var data = this.expand("Online.Stats", eval(e.target.value));
var data = expand("Online.Stats", eval(e.target.value));
axios.put('/api/admin/settings', {
setting: JSON.stringify(data)
});
......
......@@ -4,6 +4,7 @@ import PlayerOptions from './PlayerOptions';
import KaraokeOptions from './KaraokeOptions';
import InterfaceOptions from './InterfaceOptions';
import axios from 'axios';
import {expand} from '../toolsReact';
require('babel-polyfill');
axios.defaults.headers.common['authorization'] = document.cookie.replace(/(?:(?:^|.*;\s*)mugenToken\s*\=\s*([^;]*).*$)|^.*$/, "$1");
......@@ -19,15 +20,9 @@ class Options extends Component {
this.saveSettings = this.saveSettings.bind(this);
}
expand (str, val) {
return str.split('.').reduceRight((acc, currentValue) => {
return { [currentValue]: acc };
}, val);
};
async saveSettings(event) {
const value = event.target.type === 'checkbox' ? event.target.checked : event.target.value;
var data = this.expand(event.target.id, eval(value));
var data = expand(event.target.id, eval(value));
const res = await axios.put('/api/admin/settings', {
setting: JSON.stringify(data)
});
......@@ -118,4 +113,4 @@ class Options extends Component {
};
}
export default withTranslation()(Options);
export default withTranslation()(Options);
\ No newline at end of file
......@@ -37,7 +37,7 @@ class PlayerOptions extends Component {
? this.state.displays.map((display, index) => (
<option key={index} value={index} >
{" "}
({display.resolutionx}x{display.resolutiony}) {display.model}
{index+1} - ({display.resolutionx}x{display.resolutiony}) {display.model}
</option>
))
: null;
......
......@@ -47,6 +47,14 @@ export function is_touch_device() {
};
export function expand (str, val) {
return str.split('.').reduceRight((acc, currentValue) => {
return { [currentValue]: acc };
}, val);
};
/* format seconds to Hour Minute Second */
export function secondsTimeSpanToHMS (s, format) {
var d = Math.floor(s/(3600 * 24));
......
.radiobutton-ui {
display: flex;
flex-direction: row;
button {
display: block;
flex:1;
padding: 0;
margin: 1px;
border: none;
background: #575757;
color: #aaa;
outline:none;
transition: color ease .5s, background ease .5s;
&.active {
background: #37679a;
color: #FFF;
}
}
}
\ No newline at end of file
......@@ -40,6 +40,12 @@ body[scope="admin"] {
}
.header > .btn-group.switchs {
height: calc(100% - 0px);
width: 10em;
display: flex;
flex-direction: column;
> * {
flex:1;
}
}
.header, .header .btn, #manageButton li, .header input[type=range] {
max-height: 7.4vw;
......@@ -164,6 +170,13 @@ body[scope="admin"] {
display: none;
}
.btn-left {
height: 2em;
background-color: #f4f4f4;
color: #1E2124;
border-color: #9e9e9e;
}
.btn-stop {
height: 100%;
}
......
export const KARAS_LOAD_LOCAL = 'KARAS_LOAD_LOCAL';
export const KARAS_FILTER_LOCAL = 'KARAS_FILTER_LOCAL';
export const KARAS_DELETE_KARA = 'KARAS_DELETE_KARA';
export const KARAS_FILTER_ONLINE = 'KARAS_FILTER_ONLINE';
export const KARAS_LOAD_ONLINE = 'KARAS_LOAD_RECENT_ONLINE';
export const KARAS_LOAD_DOWNLOAD_QUEUE = 'KARAS_LOAD_DOWNLOAD_QUEUE';
export const KARAS_SET_IS_SEARCHING = 'KARAS_SET_IS_SEARCHING';
export const KARAS_DOWNLOAD_ADD_TO_QUEUE = 'KARAS_DOWNLOAD_ADD_TO_QUEUE';
export const KARAS_DOWNLOAD_PROGRESS_UPDATE = 'KARAS_DOWNLOAD_PROGRESS_UPDATE';
export const KARAS_DOWNLOAD_START = 'KARAS_DOWNLOAD_START';
export const KARAS_DOWNLOAD_PAUSE = 'KARAS_DOWNLOAD_PAUSE';
// Runs a filter against the karas, {} || null will get all karas
export function filterLocalKaras(filter) {
return {
type: KARAS_FILTER_LOCAL,
payload: filter
};
}
// Action to put the localKaras into the redux store
export function loadLocalKaras(localKaras) {
return {
type: KARAS_LOAD_LOCAL,
payload: localKaras
};
}
export function deleteKara(kid) {
return {
type: KARAS_DELETE_KARA,
payload: kid
};
}
// Fetch recent karas from kara.moe. Defaults to recent if no filter is applied (for now)
export function filterOnlineKaras(filter) {
return {
type: KARAS_FILTER_ONLINE,
payload: filter
};
}
// Action to put the onlineKaras into the redux store
export function loadOnlineKaras(onlineKaras) {
return {
type: KARAS_LOAD_ONLINE,
payload: onlineKaras
};
}
export function setIsSearching(isSearching) {
return {
type: KARAS_SET_IS_SEARCHING,
payload: isSearching
};
}
export function downloadSong(kid) {
return {
type: KARAS_DOWNLOAD_ADD_TO_QUEUE,
payload: kid
};
}
export function downloadStart() {
return {
type: KARAS_DOWNLOAD_START,
payload: null
};
}
export function downloadPause() {
return {
type: KARAS_DOWNLOAD_PAUSE,
payload: null
};
}
\ No newline at end of file
import axios from 'axios';
/**
* I'll be naming api requests with the first word being the http method.
* ex. getSomeThing || postSomething || ...etc
*/
// GET karas with/without filter.
export async function getLocalKaras() {
try {
const res = await axios.get('/api/system/karas');
return res.data.content;
} catch (e) {
console.log('Error from /api/local.js:getLocalKaras()');
throw e;
}
}
// START karas download queue
export async function putToDownloadQueueStart() {
try {
const res = await axios.put('/api/system/downloads/start');
return res.data;
} catch (e) {
console.log('Error from /api/local.js:putToDownloadQueueStart');