Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
- [TheBosZ](https://github.com/thebosz)
- [qm3jp](https://github.com/qm3jp)
- [johnnyg](https://github.com/johnnyg)
- [klaki892](https://github.com/klaki892)

## Emby Contributors

Expand Down
19 changes: 19 additions & 0 deletions src/apps/stable/routes/user/settings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,25 @@ const UserSettingsPage: FC = () => {
</LinkButton>
)}

<LinkButton
onClick={Dashboard.switchUser}
className='btnSwitchUser listItem-border'
style={{
display: 'block',
margin: 0,
padding: 0
}}
>
<div className='listItem'>
<span className='material-icons listItemIcon listItemIcon-transparent switch_account' aria-hidden='true' />
<div className='listItemBody'>
<div className='listItemBodyText'>
{globalize.translate('ButtonSwitchUser')}
</div>
</div>
</div>
</LinkButton>

<LinkButton
onClick={Dashboard.logout}
className='btnLogout listItem-border'
Expand Down
17 changes: 17 additions & 0 deletions src/components/toolbar/AppUserMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Download from '@mui/icons-material/Download';
import Edit from '@mui/icons-material/Edit';
import Logout from '@mui/icons-material/Logout';
import PhonelinkLock from '@mui/icons-material/PhonelinkLock';
import SwitchAccount from '@mui/icons-material/SwitchAccount';
import Settings from '@mui/icons-material/Settings';
import Storage from '@mui/icons-material/Storage';
import Divider from '@mui/material/Divider';
Expand Down Expand Up @@ -63,6 +64,11 @@ const AppUserMenu: FC<AppUserMenuProps> = ({
onMenuClose();
}, [ onMenuClose ]);

const onSwitchUserClick = useCallback(() => {
Dashboard.switchUser();
onMenuClose();
}, [ onMenuClose ]);

return (
<Menu
anchorEl={anchorEl}
Expand Down Expand Up @@ -191,6 +197,17 @@ const AppUserMenu: FC<AppUserMenuProps> = ({
</MenuItem>
)}

<MenuItem
onClick={onSwitchUserClick}
>
<ListItemIcon>
<SwitchAccount />
</ListItemIcon>
<ListItemText>
{globalize.translate('ButtonSwitchUser')}
</ListItemText>
</MenuItem>

<MenuItem
onClick={onLogoutClick}
>
Expand Down
2 changes: 1 addition & 1 deletion src/controllers/session/addServer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function submitServer(page) {
// eslint-disable-next-line sonarjs/slow-regex
const host = page.querySelector('#txtServerHost').value.replace(/\/+$/, '');
ServerConnections.connectToAddress(host, {
enableAutoLogin: appSettings.enableAutoLogin()
enableAutoLogin: appSettings.enableRememberMe()
}).then(function(result) {
handleConnectionResult(page, result);
}, function() {
Expand Down
5 changes: 5 additions & 0 deletions src/controllers/session/login/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ <h1 class="sectionTitle">${HeaderPleaseSignIn}</h1>
<span>${RememberMe}</span>
</label>

<label class="checkboxContainer">
<input is="emby-checkbox" type="checkbox" class="chkAutoSignIn" />
<span>${LabelAutomaticallySignIn}</span>
</label>

<button is="emby-button" type="submit" class="raised button-submit block">
<span>${ButtonSignIn}</span>
</button>
Expand Down
72 changes: 62 additions & 10 deletions src/controllers/session/login/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ import './login.scss';

const enableFocusTransform = !browser.slow && !browser.edge;

function authenticateUserByName(page, apiClient, url, username, password) {
function authenticateUserByName(page, apiClient, url, username, password, enableAutoSignIn) {
loading.show();
apiClient.authenticateUserByName(username, password).then(function (result) {
const user = result.User;
loading.hide();

onLoginSuccessful(user.Id, result.AccessToken, apiClient, url);
onLoginSuccessful(user.Id, result.AccessToken, apiClient, url, enableAutoSignIn);
}, function (response) {
page.querySelector('#txtManualPassword').value = '';
loading.hide();
Expand Down Expand Up @@ -112,13 +112,29 @@ function authenticateQuickConnect(apiClient, targetUrl) {
});
}

function onLoginSuccessful(id, accessToken, apiClient, url) {
function onLoginSuccessful(id, accessToken, apiClient, url, enableAutoSignIn) {
// Multi-account auto-login logic
const serverId = apiClient.serverInfo().Id;
if (enableAutoSignIn) {
ServerConnections.setAutoLoginUser(serverId, id);
} else {
const currentAutoLoginUser = ServerConnections.getAutoLoginUser(serverId);
if (currentAutoLoginUser === id) {
ServerConnections.setAutoLoginUser(serverId, null);
}
}

Dashboard.onServerChanged(id, accessToken, apiClient);
Dashboard.navigate(url || 'home');
}

function showManualForm(context, showCancel, focusPassword) {
context.querySelector('.chkRememberLogin').checked = appSettings.enableAutoLogin();
const rememberMe = appSettings.enableRememberMe();
context.querySelector('.chkRememberLogin').checked = rememberMe;
const autoSignIn = context.querySelector('.chkAutoSignIn');
if (!rememberMe) {
autoSignIn.checked = false;
}
context.querySelector('.manualLoginForm').classList.remove('hide');
context.querySelector('.visualLoginForm').classList.add('hide');
context.querySelector('.btnManual').classList.add('hide');
Expand Down Expand Up @@ -193,7 +209,7 @@ export default function (view, params) {
return ServerConnections.getOrCreateApiClient(serverId);
}

return ApiClient;
return ServerConnections.currentApiClient();
}

function getTargetUrl() {
Expand Down Expand Up @@ -234,18 +250,48 @@ export default function (view, params) {
} else if (haspw == 'false') {
authenticateUserByName(context, getApiClient(), getTargetUrl(), name, '');
} else {
context.querySelector('#txtManualName').value = name;
context.querySelector('#txtManualPassword').value = '';
showManualForm(context, true, true);
const apiClient = getApiClient();
const serverId = apiClient.serverInfo().Id;

loading.show();
ServerConnections.loginWithSavedCredentials(serverId, id).then(function (result) {
loading.hide();
if (result.ApiClient && result.ApiClient.accessToken()) {
onLoginSuccessful(id, result.ApiClient.accessToken(), result.ApiClient, getTargetUrl(), false);
} else {
context.querySelector('#txtManualName').value = name;
context.querySelector('#txtManualPassword').value = '';
showManualForm(context, true, true);
}
});
}
}
});
view.querySelector('.manualLoginForm').addEventListener('submit', function (e) {
appSettings.enableAutoLogin(view.querySelector('.chkRememberLogin').checked);
authenticateUserByName(view, getApiClient(), getTargetUrl(), view.querySelector('#txtManualName').value, view.querySelector('#txtManualPassword').value);
appSettings.enableRememberMe(view.querySelector('.chkRememberLogin').checked);
authenticateUserByName(
view,
getApiClient(),
getTargetUrl(),
view.querySelector('#txtManualName').value,
view.querySelector('#txtManualPassword').value,
view.querySelector('.chkAutoSignIn').checked
);
e.preventDefault();
return false;
});

view.querySelector('.chkRememberLogin').addEventListener('change', function () {
if (!this.checked) {
view.querySelector('.chkAutoSignIn').checked = false;
}
});

view.querySelector('.chkAutoSignIn').addEventListener('change', function () {
if (this.checked) {
view.querySelector('.chkRememberLogin').checked = true;
}
});
view.querySelector('.btnForgotPassword').addEventListener('click', function () {
Dashboard.navigate('forgotpassword');
});
Expand All @@ -272,6 +318,12 @@ export default function (view, params) {

const apiClient = getApiClient();

if (!apiClient) {
loading.hide();
Dashboard.selectServer();
return;
}

apiClient.getQuickConnect('Enabled')
.then(enabled => {
if (enabled === true) {
Expand Down
13 changes: 11 additions & 2 deletions src/controllers/session/selectServer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import loading from '../../../components/loading/loading';
import { appRouter } from '../../../components/router/appRouter';
import layoutManager from '../../../components/layoutManager';
import libraryMenu from '../../../scripts/libraryMenu';
import appSettings from '../../../scripts/settings/appSettings';
import focusManager from '../../../components/focusManager';
import globalize from '../../../lib/globalize';
import actionSheet from '../../../components/actionSheet/actionSheet';
Expand Down Expand Up @@ -104,9 +103,19 @@ function showServerConnectionFailure() {

export default function (view, params) {
function connectToServer(server) {
let enableAutoLogin = false;
if (server.AutoLoginUserId && server.Users) {
const user = server.Users.find(u => u.UserId === server.AutoLoginUserId);
if (user && user.AccessToken) {
server.UserId = user.UserId;
server.AccessToken = user.AccessToken;
enableAutoLogin = true;
}
}

loading.show();
ServerConnections.connectToServer(server, {
enableAutoLogin: appSettings.enableAutoLogin()
enableAutoLogin: enableAutoLogin
}).then(function (result) {
loading.hide();
const apiClient = result.ApiClient;
Expand Down
4 changes: 3 additions & 1 deletion src/lib/jellyfin-apiclient/ServerConnections.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class ServerConnections extends ConnectionManager {
setUserInfo(null, null);
// Ensure the updated credentials are persisted to storage
credentialProvider.credentials(credentialProvider.credentials());
localStorage.removeItem('enableRememberMe');

if (window.NativeShell && typeof window.NativeShell.onLocalUserSignedOut === 'function') {
window.NativeShell.onLocalUserSignedOut(logoutInfo);
Expand All @@ -52,6 +53,7 @@ class ServerConnections extends ConnectionManager {
apiClient.getMaxBandwidth = getMaxBandwidth;
apiClient.normalizeImageOptions = normalizeImageOptions;
});
this.shouldSaveCredentials = () => appSettings.enableRememberMe();
}

initApiClient(server) {
Expand All @@ -77,7 +79,7 @@ class ServerConnections extends ConnectionManager {

connect(options) {
return super.connect({
enableAutoLogin: appSettings.enableAutoLogin(),
enableAutoLogin: appSettings.enableRememberMe(),
...options
});
}
Expand Down
Loading
Loading