((resolve, reject) => {
+ // // @ts-ignore
+ // websocketServer.on("json", (userJson) => {
+ // try {
+ // expect(userJson).toEqual({ user: "iliekcomputers" });
+ // receivedUserNameMessage = true;
+ // resolve();
+ // } catch (error) {
+ // reject(error);
+ // }
+ // });
+ // });
+ // await act(async () => {
+ // renderWithProviders( );
+ // });
+ // await websocketServer.connected;
+ // await returnPromise; // See at the beginning of this test
+
+ // const websocketClients = websocketServer.server.clients();
+ // expect(websocketClients.length).toBeGreaterThanOrEqual(1);
+ // expect(receivedUserNameMessage).toBeTruthy();
+ // });
+
+ // it('calls correct handler for "listen" event', async () => {
+ // await act(async () => {
+ // renderWithProviders( );
+ // });
+ // await websocketServer.connected;
+
+ // expect(screen.queryByTestId("webSocketListens")).not.toBeInTheDocument();
+ // expect(screen.queryAllByTestId("listen")).toHaveLength(26);
+ // // send the message to the client
+
+ // await act(async () => {
+ // websocketServer.server.emit("listen", JSON.stringify(mockListen));
+ // });
+ // const websocketListensContainer = await screen.findByTestId(
+ // "webSocketListens",
+ // {}
+ // );
+ // const wsListens = within(websocketListensContainer).queryAllByTestId(
+ // "listen"
+ // );
+ // expect(wsListens).toHaveLength(1);
+ // expect(screen.queryAllByTestId("listen")).toHaveLength(27);
+ // });
+
+ // it('calls correct event for "playing_now" event', async () => {
+ // await act(async () => {
+ // renderWithProviders( );
+ // });
+ // await websocketServer.connected;
+ // expect(screen.queryAllByTestId("listen")).toHaveLength(26);
+
+ // const playingNowListen: Listen = {
+ // ...mockListen,
+ // listened_at: Date.now(),
+ // playing_now: true,
+ // };
+
+ // await act(async () => {
+ // websocketServer.server.emit(
+ // "playing_now",
+ // JSON.stringify(playingNowListen)
+ // );
+ // });
+ // const listenCards = screen.queryAllByTestId("listen");
+ // expect(listenCards).toHaveLength(27);
+ // await screen.findByTitle(playingNowListen.track_metadata.track_name, {});
+ // });
+
+ // it("crops the websocket listens array to a maximum of 7", async () => {
+ // await act(async () => {
+ // renderWithProviders( );
+ // });
+ // await websocketServer.connected;
+
+ // // Add 7 new listens
+ // await act(async () => {
+ // for (let index = 0; index < 8; index += 1) {
+ // // Prevent the "Encountered two children with the same key" warning message
+ // // by having a different timestamp for each listen
+ // websocketServer.server.emit(
+ // "listen",
+ // JSON.stringify({ ...mockListen, listened_at: Date.now() + index })
+ // );
+ // }
+ // });
+
+ // const websocketListensContainer = await screen.findByTestId(
+ // "webSocketListens"
+ // );
+ // const wsListens = within(websocketListensContainer).queryAllByTestId(
+ // "listen"
+ // );
+ // expect(wsListens).toHaveLength(7);
+
+ // // Add a few more, the process should crop to 7 max
+ // await act(async () => {
+ // websocketServer.server.emit(
+ // "listen",
+ // JSON.stringify({ ...mockListen, listened_at: Date.now() })
+ // );
+ // });
+ // await act(async () => {
+ // websocketServer.server.emit(
+ // "listen",
+ // JSON.stringify({ ...mockListen, listened_at: Date.now() })
+ // );
+ // });
+ // await act(async () => {
+ // websocketServer.server.emit(
+ // "listen",
+ // JSON.stringify({ ...mockListen, listened_at: Date.now() })
+ // );
+ // });
+
+ // // Should still have 7 listens
+ // expect(wsListens).toHaveLength(7);
+ // });
+ // });
+
+ // describe("deleteListen", () => {
+ // it("calls API and removeListenFromListenList correctly, and updates the state", async () => {
+ // const spy = jest
+ // .spyOn(APIService, "deleteListen")
+ // .mockImplementation(() => Promise.resolve(200));
+
+ // await act(async () => {
+ // renderWithProviders( , {
+ // APIService,
+ // currentUser,
+ // });
+ // });
+
+ // expect(await screen.findAllByTestId("listen")).toHaveLength(26);
+
+ // const listensContainer = await screen.findByTestId("listens");
+ // const listenCards = await within(listensContainer).findAllByTestId(
+ // "listen"
+ // );
+ // const listenToDelete = listenCards[0];
+
+ // const deleteButton = within(listenToDelete).getByRole("menuitem", {
+ // name: "Delete Listen",
+ // });
+ // await userEvent.click(deleteButton);
+
+ // await waitForElementToBeRemoved(
+ // within(listenToDelete!).queryByRole("menuitem", {
+ // name: "Delete Listen",
+ // })
+ // );
+
+ // expect(spy).toHaveBeenCalledTimes(1);
+ // expect(spy).toHaveBeenCalledWith(
+ // "fnord",
+ // "973e5620-829d-46dd-89a8-760d87076287",
+ // 1586523524
+ // );
+ // expect(await screen.findAllByTestId("listen")).toHaveLength(25);
+ // });
+
+ // it("does not render delete button if user is not logged in", async () => {
+ // await act(async () => {
+ // renderWithProviders( , {
+ // currentUser: undefined,
+ // });
+ // });
+
+ // const deleteButton = screen.queryAllByRole("menuitem", {
+ // name: "Delete Listen",
+ // });
+ // expect(deleteButton).toHaveLength(0);
+ // });
+
+ // it("does nothing if the user has no auth token", async () => {
+ // const spy = jest
+ // .spyOn(APIService, "deleteListen")
+ // .mockImplementation(() => Promise.resolve(200));
+
+ // await act(async () => {
+ // renderWithProviders( , {
+ // APIService,
+ // currentUser: { auth_token: undefined, name: "iliekcomputers" },
+ // });
+ // });
+
+ // const listensContainer = await screen.findByTestId("listens");
+ // const listenCards = await within(listensContainer).findAllByTestId(
+ // "listen"
+ // );
+ // expect(listenCards).toHaveLength(25);
+ // const listenToDelete = listenCards[0];
+
+ // const deleteButton = within(listenToDelete).getByRole("menuitem", {
+ // name: "Delete Listen",
+ // });
+ // await userEvent.click(deleteButton);
+
+ // expect(listenCards).toHaveLength(25);
+
+ // expect(spy).not.toHaveBeenCalled();
+ // });
+
+ // it("doesn't call removeListenFromListenList or update state if status code is not 200", async () => {
+ // const spy = jest.spyOn(APIService, "deleteListen");
+ // spy.mockImplementation(() => Promise.resolve(500));
+
+ // await act(async () => {
+ // renderWithProviders( , {
+ // APIService,
+ // currentUser,
+ // });
+ // });
+
+ // const listensContainer = await screen.findByTestId("listens");
+ // const listenCards = await within(listensContainer).findAllByTestId(
+ // "listen"
+ // );
+ // expect(listenCards).toHaveLength(25);
+ // const listenToDelete = listenCards[0];
+
+ // const deleteButton = within(listenToDelete).getByRole("menuitem", {
+ // name: "Delete Listen",
+ // });
+ // await userEvent.click(deleteButton);
+
+ // expect(listenCards).toHaveLength(25);
+
+ // expect(spy).toHaveBeenCalledTimes(1);
+ // expect(spy).toHaveBeenCalledWith(
+ // "fnord",
+ // "973e5620-829d-46dd-89a8-760d87076287",
+ // 1586523524
+ // );
+
+ // await waitFor(
+ // () => {
+ // expect(listenCards).toHaveLength(25);
+ // },
+ // { timeout: 1000 }
+ // );
+ // });
+
+ // it("handles error for delete listen", async () => {
+ // const spy = jest
+ // .spyOn(APIService, "deleteListen")
+ // .mockImplementation(() => {
+ // throw new Error("My error message");
+ // });
+
+ // await act(async () => {
+ // renderWithProviders( , {
+ // APIService,
+ // currentUser,
+ // });
+ // });
+ // const listensContainer = await screen.findByTestId("listens");
+ // const listenCards = await within(listensContainer).findAllByTestId(
+ // "listen"
+ // );
+ // expect(listenCards).toHaveLength(25);
+ // const listenToDelete = listenCards[0];
+ // const deleteButton = within(listenToDelete).getByRole("menuitem", {
+ // name: "Delete Listen",
+ // });
+ // await userEvent.click(deleteButton);
+ // expect(spy).toHaveBeenCalledTimes(1);
+ // expect(spy).toHaveBeenCalledWith(
+ // "fnord",
+ // "973e5620-829d-46dd-89a8-760d87076287",
+ // 1586523524
+ // );
+ // expect(
+ // screen.getByText("Error while deleting listen")
+ // ).toBeInTheDocument();
+ // expect(screen.getByText("My error message")).toBeInTheDocument();
+
+ // await waitFor(
+ // () => {
+ // expect(listenCards).toHaveLength(25);
+ // },
+ // { timeout: 1000 }
+ // );
+ // });
+ // });
+
+ // describe("Pagination", () => {
+ // const pushStateSpy = jest.spyOn(window.history, "pushState");
+ // const getListensForUserSpy = jest
+ // .spyOn(APIService, "getListensForUser")
+ // .mockImplementation(() => Promise.resolve([]));
+
+ // const mockListen: Listen = {
+ // track_metadata: {
+ // artist_name: "FNORD",
+ // track_name: "Have you seen the FNORDs?",
+ // additional_info: {
+ // recording_msid: "a6a089da-475b-45cb-a5a8-087caa1a121a",
+ // },
+ // },
+ // listened_at: 1586440100,
+ // user_name: "mr_monkey",
+ // };
+ // afterEach(() => {
+ // jest.clearAllMocks();
+ // });
+
+ // describe("handleClickOlder", () => {
+ // it("does nothing if there is no older listens timestamp", async () => {
+ // await act(async () => {
+ // renderWithProviders(
+ // ,
+ // { APIService }
+ // );
+ // });
+
+ // // button should be disabled if last listen's listened_at <= oldestListenTs
+ // const olderButton = await screen.findByLabelText(
+ // "Navigate to older listens"
+ // );
+ // expect(olderButton).toHaveAttribute("aria-disabled", "true");
+ // expect(olderButton).not.toHaveAttribute("href");
+ // await userEventSession.click(olderButton);
+
+ // expect(getListensForUserSpy).not.toHaveBeenCalled();
+ // });
+
+ // it("calls the API to get older listens", async () => {
+ // const expectedListensArray = [
+ // {
+ // track_metadata: {
+ // artist_name: "You mom",
+ // track_name: "A unique track name",
+ // release_name: "You mom's best of",
+ // },
+ // listened_at: 1586450001,
+ // },
+ // ];
+ // getListensForUserSpy.mockImplementation(() =>
+ // Promise.resolve(expectedListensArray)
+ // );
+
+ // await act(async () => {
+ // renderWithProviders( , { APIService });
+ // });
+ // const expectedNextListenTimestamp =
+ // listens[listens.length - 1].listened_at;
+
+ // const olderButton = await screen.findByLabelText(
+ // "Navigate to older listens"
+ // );
+ // await userEventSession.click(olderButton);
+
+ // expect(getListensForUserSpy).toHaveBeenCalledWith(
+ // user.name,
+ // undefined,
+ // expectedNextListenTimestamp
+ // );
+ // await screen.findByText("A unique track name");
+ // });
+
+ // it("prevents further navigation if it receives not enough listens from API", async () => {
+ // getListensForUserSpy.mockImplementationOnce(() =>
+ // Promise.resolve([mockListen])
+ // );
+ // await act(async () => {
+ // renderWithProviders( , { APIService });
+ // });
+
+ // const olderButton = await screen.findByLabelText(
+ // "Navigate to older listens"
+ // );
+ // expect(olderButton).toHaveAttribute("aria-disabled", "false");
+ // await userEventSession.click(olderButton);
+
+ // expect(getListensForUserSpy).toHaveBeenCalledWith(
+ // user.name,
+ // undefined,
+ // 1586440536
+ // );
+
+ // expect(olderButton).toHaveAttribute("aria-disabled", "true");
+ // expect(olderButton).not.toHaveAttribute("href");
+ // });
+
+ // it("updates the browser history", async () => {
+ // getListensForUserSpy.mockImplementationOnce(
+ // (username, minTs, maxTs) => {
+ // return Promise.resolve([...listens, mockListen]);
+ // }
+ // );
+
+ // await act(async () => {
+ // renderWithProviders( , { APIService });
+ // });
+
+ // const olderButton = await screen.findByLabelText(
+ // "Navigate to older listens"
+ // );
+ // expect(olderButton).toHaveAttribute("aria-disabled", "false");
+
+ // await userEventSession.click(olderButton);
+
+ // expect(getListensForUserSpy).toHaveBeenCalledWith(
+ // user.name,
+ // undefined,
+ // 1586440536
+ // );
+ // expect(pushStateSpy).toHaveBeenCalledWith(
+ // null,
+ // "",
+ // "?max_ts=1586440536"
+ // );
+
+ // expect(olderButton).toHaveAttribute("href", "?max_ts=1586440100");
+ // expect(olderButton).toHaveAttribute("aria-disabled", "false");
+ // });
+ // });
+
+ // describe("handleClickNewer", () => {
+ // it("does nothing if there is no newer listens timestamp", async () => {
+ // await act(async () => {
+ // renderWithProviders(
+ // ,
+ // { APIService }
+ // );
+ // });
+
+ // // button should be disabled if last previousListenTs >= earliest timestamp
+ // const newerButton = await screen.findByLabelText(
+ // "Navigate to more recent listens"
+ // );
+ // expect(newerButton).toHaveAttribute("aria-disabled", "true");
+ // expect(newerButton).not.toHaveAttribute("href");
+ // await userEventSession.click(newerButton);
+
+ // expect(getListensForUserSpy).not.toHaveBeenCalled();
+ // });
+
+ // it("calls the API to get newer listens", async () => {
+ // const expectedListensArray = [
+ // {
+ // track_metadata: {
+ // artist_name: "You mom",
+ // track_name: "Another unique track name",
+ // release_name: "You mom's best of",
+ // },
+ // listened_at: Date.now(),
+ // },
+ // ];
+ // getListensForUserSpy.mockImplementation(() =>
+ // Promise.resolve(expectedListensArray)
+ // );
+
+ // await act(async () => {
+ // renderWithProviders(
+ // ,
+ // { APIService }
+ // );
+ // });
+ // const expectedPreviousListenTimestamp = listens[0].listened_at;
+
+ // const newerButton = await screen.findByLabelText(
+ // "Navigate to more recent listens"
+ // );
+ // await userEventSession.click(newerButton);
+
+ // expect(getListensForUserSpy).toHaveBeenCalledWith(
+ // user.name,
+ // expectedPreviousListenTimestamp,
+ // undefined
+ // );
+ // await screen.findByText("Another unique track name");
+ // });
+
+ // it("prevents further navigation if it receives not enough listens from API", async () => {
+ // getListensForUserSpy.mockImplementationOnce(() =>
+ // Promise.resolve([mockListen])
+ // );
+ // await act(async () => {
+ // renderWithProviders(
+ // ,
+ // { APIService }
+ // );
+ // });
+
+ // const newerButton = await screen.findByLabelText(
+ // "Navigate to more recent listens"
+ // );
+ // expect(newerButton).toHaveAttribute("aria-disabled", "false");
+ // await userEventSession.click(newerButton);
+
+ // expect(getListensForUserSpy).toHaveBeenCalledWith(
+ // user.name,
+ // listens[0].listened_at,
+ // undefined
+ // );
+
+ // expect(newerButton).toHaveAttribute("aria-disabled", "true");
+ // expect(newerButton).not.toHaveAttribute("href");
+ // });
+
+ // it("updates the browser history", async () => {
+ // const mostRecentListenTs = listens[0].listened_at;
+ // const timestamp = Date.now();
+ // getListensForUserSpy.mockImplementationOnce(
+ // (username, minTs, maxTs) => {
+ // return Promise.resolve([
+ // { ...mockListen, listened_at: timestamp },
+ // ...listens,
+ // ]);
+ // }
+ // );
+
+ // await act(async () => {
+ // renderWithProviders(
+ // ,
+ // { APIService }
+ // );
+ // });
+
+ // const newerButton = await screen.findByLabelText(
+ // "Navigate to more recent listens"
+ // );
+ // expect(newerButton).toHaveAttribute("aria-disabled", "false");
+ // expect(newerButton).toHaveAttribute(
+ // "href",
+ // `?min_ts=${mostRecentListenTs}`
+ // );
+
+ // await userEventSession.click(newerButton);
+
+ // expect(getListensForUserSpy).toHaveBeenCalledWith(
+ // user.name,
+ // mostRecentListenTs,
+ // undefined
+ // );
+ // expect(pushStateSpy).toHaveBeenCalledWith(
+ // null,
+ // "",
+ // `?min_ts=${mostRecentListenTs}`
+ // );
+
+ // expect(newerButton).toHaveAttribute("href", `?min_ts=${timestamp}`);
+ // expect(newerButton).toHaveAttribute("aria-disabled", "false");
+ // });
+ // });
+
+ // describe("handleClickOldest", () => {
+ // it("does nothing if there is no older listens timestamp", async () => {
+ // await act(async () => {
+ // renderWithProviders(
+ // ,
+ // { APIService }
+ // );
+ // });
+
+ // // button should be disabled if last listen's listened_at <= oldestListenTs
+ // const oldestButton = await screen.findByLabelText(
+ // "Navigate to oldest listens"
+ // );
+ // expect(oldestButton).toHaveAttribute("aria-disabled", "true");
+ // expect(oldestButton).not.toHaveAttribute("href");
+ // await userEventSession.click(oldestButton);
+
+ // expect(getListensForUserSpy).not.toHaveBeenCalled();
+ // });
+
+ // it("updates the browser history and disables navigation to oldest", async () => {
+ // getListensForUserSpy.mockImplementationOnce(
+ // (username, minTs, maxTs) => {
+ // return Promise.resolve([
+ // ...listens,
+ // {
+ // ...mockListen,
+ // listened_at: oldestListenTs,
+ // },
+ // ]);
+ // }
+ // );
+
+ // await act(async () => {
+ // renderWithProviders( , { APIService });
+ // });
+
+ // const oldestButton = await screen.findByLabelText(
+ // "Navigate to oldest listens"
+ // );
+ // expect(oldestButton).toHaveAttribute("aria-disabled", "false");
+
+ // await userEventSession.click(oldestButton);
+
+ // expect(getListensForUserSpy).toHaveBeenCalledWith(
+ // user.name,
+ // oldestListenTs - 1
+ // );
+ // expect(pushStateSpy).toHaveBeenCalledWith(
+ // null,
+ // "",
+ // `?min_ts=${oldestListenTs - 1}`
+ // );
+
+ // expect(oldestButton).not.toHaveAttribute("href");
+ // expect(oldestButton).toHaveAttribute("aria-disabled", "true");
+ // });
+ // });
+ // describe("handleClickNewest", () => {
+ // it("does nothing if there is no more recent listens timestamp", async () => {
+ // await act(async () => {
+ // renderWithProviders(
+ // ,
+ // { APIService }
+ // );
+ // });
+
+ // // button should be disabled if last listen's listened_at <= oldestListenTs
+ // const newestButton = await screen.findByLabelText(
+ // "Navigate to most recent listens"
+ // );
+ // expect(newestButton).toHaveAttribute("aria-disabled", "true");
+ // expect(newestButton).toHaveAttribute("href", "/");
+ // await userEventSession.click(newestButton);
+
+ // expect(getListensForUserSpy).not.toHaveBeenCalled();
+ // });
+
+ // it("updates the browser history and disables navigation to newest listens", async () => {
+ // const timestamp = Math.round(Date.now() / 1000);
+ // await act(async () => {
+ // renderWithProviders(
+ // ,
+ // { APIService }
+ // );
+ // });
+
+ // getListensForUserSpy.mockResolvedValueOnce([
+ // { ...mockListen, listened_at: timestamp },
+ // ...listens,
+ // ]);
+
+ // const newestButton = await screen.findByLabelText(
+ // "Navigate to most recent listens"
+ // );
+
+ // expect(newestButton).toHaveAttribute("href", "/");
+ // expect(newestButton).toHaveAttribute("aria-disabled", "false");
+
+ // await userEventSession.click(newestButton);
+
+ // expect(getListensForUserSpy).toHaveBeenCalledWith(user.name);
+
+ // expect(pushStateSpy).toHaveBeenCalledWith(null, "", "");
+
+ // expect(newestButton).toHaveAttribute("href", "/");
+ // expect(newestButton).toHaveAttribute("aria-disabled", "true");
+ // });
+ // });
+ // });
});
diff --git a/frontend/js/tests/user/missing-data/MissingMBData.test.tsx b/frontend/js/tests/user/missing-data/MissingMBData.test.tsx
index 2ca5b8dc51..4892a01a94 100644
--- a/frontend/js/tests/user/missing-data/MissingMBData.test.tsx
+++ b/frontend/js/tests/user/missing-data/MissingMBData.test.tsx
@@ -16,6 +16,7 @@ import GlobalAppContext, {
import APIService from "../../../src/utils/APIService";
import { waitForComponentToPaint } from "../../test-utils";
import RecordingFeedbackManager from "../../../src/utils/RecordingFeedbackManager";
+import { BrowserRouter } from "react-router-dom";
// Font Awesome generates a random hash ID for each icon everytime.
// // Mocking Math.random() fixes this
@@ -47,7 +48,9 @@ describe("MissingMBDataPage", () => {
-
+
+
+
);
expect(wrapper.find("#missingMBData")).toHaveLength(1);
diff --git a/listenbrainz/tests/integration/test_api_compat.py b/listenbrainz/tests/integration/test_api_compat.py
index 68b275988f..3aaf02078d 100644
--- a/listenbrainz/tests/integration/test_api_compat.py
+++ b/listenbrainz/tests/integration/test_api_compat.py
@@ -62,10 +62,14 @@ def test_complete_workflow_json(self):
self.assert200(r)
token = r.json['token']
+ data = {
+ "token": token,
+ }
+
r = self.client.post(
self.custom_url_for('api_compat.api_auth_approve'),
- data=f"token={token}",
- headers={'Content-Type': 'application/x-www-form-urlencoded'}
+ data=json.dumps(data),
+ content_type="application/json"
)
self.assert200(r)
diff --git a/listenbrainz/webserver/__init__.py b/listenbrainz/webserver/__init__.py
index 637e0b204f..3fd59791e2 100644
--- a/listenbrainz/webserver/__init__.py
+++ b/listenbrainz/webserver/__init__.py
@@ -246,7 +246,8 @@ def before_request_gdpr_check():
or request.path == url_for('settings.index', path='export') \
or request.path == url_for('login.logout') \
or request.path.startswith('/static') \
- or request.path.startswith('/1'):
+ or request.path.startswith('/1') \
+ or request.method in ['OPTIONS', 'POST']:
return
# otherwise if user is logged in and hasn't agreed to gdpr,
# redirect them to agree to terms page.
@@ -265,6 +266,16 @@ def create_api_compat_app(debug=None):
app = create_app(debug=debug)
+ import listenbrainz.webserver.static_manager as static_manager
+ static_manager.read_manifest()
+ app.static_folder = '/static'
+
+ from listenbrainz.webserver.utils import get_global_props
+ app.context_processor(lambda: dict(
+ get_static_path=static_manager.get_static_path,
+ global_props=get_global_props()
+ ))
+
from listenbrainz.webserver.views.api_compat import api_bp as api_compat_bp
from listenbrainz.webserver.views.api_compat_deprecated import api_compat_old_bp
app.register_blueprint(api_compat_bp)
diff --git a/listenbrainz/webserver/admin/test_admin.py b/listenbrainz/webserver/admin/test_admin.py
index 9fc13b740d..ef7dce426e 100644
--- a/listenbrainz/webserver/admin/test_admin.py
+++ b/listenbrainz/webserver/admin/test_admin.py
@@ -15,7 +15,8 @@ def test_admin_views_when_not_logged_in(self):
r = self.client.get('/admin', follow_redirects=True)
self.assert200(r)
self.assertNotIn('BDFL Zone', r.data.decode('utf-8'))
- self.assertIn('You are not authorized', r.data.decode('utf-8'))
+ # Check if the user is redirected to the login page
+ self.assertEqual(r.request.path, self.custom_url_for('login.index'))
def test_admin_views_when_authorized_logged_in(self):
self.app.config['ADMINS'] = [self.authorized_user['musicbrainz_id']]
@@ -32,4 +33,5 @@ def test_admin_views_when_unauthorized_logged_in(self):
r = self.client.get('/admin', follow_redirects=True)
self.assert200(r)
self.assertNotIn('BDFL Zone', r.data.decode('utf-8'))
- self.assertIn('You are not authorized', r.data.decode('utf-8'))
+ # Check if the user is redirected to the their dashboard
+ self.assertEqual(r.request.path, self.custom_url_for('index.index_pages', path=""))
diff --git a/listenbrainz/webserver/decorators.py b/listenbrainz/webserver/decorators.py
index 3bdde81eba..fadabd9e3f 100644
--- a/listenbrainz/webserver/decorators.py
+++ b/listenbrainz/webserver/decorators.py
@@ -53,7 +53,7 @@ def web_listenstore_needed(func):
@wraps(func)
def decorator(*args, **kwargs):
if timescale_connection._ts is None:
- return redirect(url_for("index.listens_offline"))
+ return redirect(url_for("index.index_pages", page="listens-offline"))
return func(*args, **kwargs)
return decorator
@@ -70,6 +70,6 @@ def decorator(*args, **kwargs):
# if config item is missing, consider the database to be up (useful for local development)
is_musicbrainz_up = current_app.config.get("IS_MUSICBRAINZ_UP", True)
if not is_musicbrainz_up:
- return redirect(url_for("index.musicbrainz_offline"))
+ return redirect(url_for("index.index_pages", page="musicbrainz-offline"))
return func(*args, **kwargs)
return decorator
diff --git a/listenbrainz/webserver/login/__init__.py b/listenbrainz/webserver/login/__init__.py
index 5fb21870ea..60d5955021 100644
--- a/listenbrainz/webserver/login/__init__.py
+++ b/listenbrainz/webserver/login/__init__.py
@@ -63,7 +63,7 @@ def login_forbidden(f):
@wraps(f)
def decorated(*args, **kwargs):
if not current_user.is_anonymous:
- return redirect(url_for('index.index'))
+ return redirect(url_for('index.index_pages', path=''))
return f(*args, **kwargs)
return decorated
diff --git a/listenbrainz/webserver/templates/base-react.html b/listenbrainz/webserver/templates/base-react.html
deleted file mode 100644
index 8e5f9c8083..0000000000
--- a/listenbrainz/webserver/templates/base-react.html
+++ /dev/null
@@ -1,12 +0,0 @@
-{% extends 'base.html' %}
-
-{% block content %}
-
-
-{% endblock %}
-
-{% block scripts %}
- {{ super() }}
-
-
-{% endblock %}
diff --git a/listenbrainz/webserver/templates/entities/album.html b/listenbrainz/webserver/templates/entities/album.html
deleted file mode 100644
index 750bcd02e7..0000000000
--- a/listenbrainz/webserver/templates/entities/album.html
+++ /dev/null
@@ -1,22 +0,0 @@
-{%- extends 'base-react.html' -%}
-
-{% block title %}
- {{ title }} — ListenBrainz
-{% endblock %}
-
-{% block content %}
-
-
-
- {{ super() }}
-
-{% endblock %}
-
-{% block scripts %}
- {{ super() }}
-
-{% endblock %}
diff --git a/listenbrainz/webserver/templates/entities/artist.html b/listenbrainz/webserver/templates/entities/artist.html
deleted file mode 100644
index 37238169cc..0000000000
--- a/listenbrainz/webserver/templates/entities/artist.html
+++ /dev/null
@@ -1,22 +0,0 @@
-{%- extends 'base-react.html' -%}
-
-{% block title %}
- {{ title }} — ListenBrainz
-{% endblock %}
-
-{% block content %}
-
-
-
- {{ super() }}
-
-{% endblock %}
-
-{% block scripts %}
- {{ super() }}
-
-{% endblock %}
diff --git a/listenbrainz/webserver/templates/explore/ai-brainz.html b/listenbrainz/webserver/templates/explore/ai-brainz.html
deleted file mode 100644
index 9dbd8ae6dc..0000000000
--- a/listenbrainz/webserver/templates/explore/ai-brainz.html
+++ /dev/null
@@ -1,150 +0,0 @@
-{%- extends 'base-react.html' -%}
-
-{% block title %}
-AIBrainz
-{% endblock %}
-
-{% block head %}
- {{ super() }}
-
-
-{% endblock %}
-
-
-
-{% block content %}
-
- {{ super() }}
-{% endblock %}
-
-{% block scripts %}
- {{ super() }}
-
-
-
-
-{% endblock %}
diff --git a/listenbrainz/webserver/templates/index.html b/listenbrainz/webserver/templates/index.html
index 9a8bb35df9..e9f1c38865 100644
--- a/listenbrainz/webserver/templates/index.html
+++ b/listenbrainz/webserver/templates/index.html
@@ -1,13 +1,30 @@
-{%- extends 'base-react.html' -%}
+
+
+
+ {%- block head -%}
+
+ {% block title %}ListenBrainz{% endblock %}
+
+
+
+
+
-{% block content %}
- {{ super() }}
+ {# The css file has a .less extension in the manifest file entry (due to its original name in Webpack entry) #}
+
+ {%- endblock -%}
+
-{% endblock %}
+
+
+
-{% block scripts %}
- {{ super() }}
-
-{% endblock %}
+
+
+
+
+
+
+
diff --git a/listenbrainz/webserver/templates/index/about.html b/listenbrainz/webserver/templates/index/about.html
deleted file mode 100644
index 1b0e2b7789..0000000000
--- a/listenbrainz/webserver/templates/index/about.html
+++ /dev/null
@@ -1,99 +0,0 @@
-{%- extends 'index/base-about.html' -%}
-{%- block about_content -%}
-Goals
-
-The ListenBrainz project has a number of goals:
-
-
- A public store of your listen history. We feel that a listen history has a tremendous
- amount of personal value and in aggregate has a huge amount of value for developers who wish
- to create better music technologies, like recommendation systems.
-
-
- A permanent store of your listen history. MetaBrainz, the non-profit that runs
- MusicBrainz and ListenBrainz has a long
- history of curating and making data available to the public in a useful and meaningful manner. We promise
- to safeguard your listen history permanently.
-
-
- To make data dumps of this listen history available for download. We want everyone who is interested
- in this data to have access to the data and to use it in any manner they wish.
-
-
- To share listen histories in a distributed fashion. We plan to allow anyone to connect to ListenBrainz
- and to tap into a live feed of listen data as we receive it. We hope that Last.fm will work with us
- to make an interconnection with Last.fm possible. We welcome anyone scrobbling to us and we plan to share the listens
- shared with us to anyone else who wants them. We envision smaller music communities with a specific focus
- to install their own ListenBrainz server to collect listen data for their specific focus. We hope that
- these smaller communities will also share their data in the same manner in which we share our data.
-
-
-
-Anti-goals
-
-The project also has a number of anti-goals (things it doesn't try to be):
-
-
- A store for people's private listen history. The point of this project is to build a public, shareable
- store of listen data. As we build out our sharing features, building a private listen store will become
- possible, but that is not part of our goals.
-
-
- A closed platform. We aim to make everything open and to encourage a community of sharing and participation.
-
-
-Roadmap
-
-We've put together a very rough roadmap for this project:
-
-Short term
-
-
-
- Work to improve and extend the user data graphing features.
-
-
-
-Medium term
-
-
-
- Start working on an open source recommendation engine using data from ListenBrainz,
- AcousticBrainz and MusicBrainz .
-
-
-
-Long term
-
-
- Total world domination. What other goals are open source projects allowed to have?
-
-
-
-
-
-
- If you have any ideas that should be on our roadmap, please let us know !
-
-Contributing to ListenBrainz
-
-Donating
-
- Listenbrainz is a free open source project that is not run for profit. If you would like to help the project out
- financially, consider donating to the MetaBrainz Foundation.
-
-
-Developers
-
- ListenBrainz is in its infancy and we need a lot of help to implement more features and to debug the existing
- features. If you feel like helping out and have experience with Python, Postgres and Redis,
- we'd love some help.
-
-
- Have a look at the GitHub repository for this
- project to get started. You may also consider heading to our IRC channel #metabrainz on irc.libera.chat and
- asking people there what should be worked on next. Finally, we also have a bug tracker that keeps track of our
- current issues .
-
-
-{%- endblock -%}
diff --git a/listenbrainz/webserver/templates/index/add-data.html b/listenbrainz/webserver/templates/index/add-data.html
deleted file mode 100644
index 2cdfbe9481..0000000000
--- a/listenbrainz/webserver/templates/index/add-data.html
+++ /dev/null
@@ -1,95 +0,0 @@
-{%- extends 'index/base-about.html' -%}
-{%- block title -%}Adding Data - ListenBrainz{%- endblock -%}
-{%- block about_content -%}
- Adding your data to Listenbrainz
- {# Listen submission information #}
- Submitting Listens
-
- There are many ways to submit your listening history to ListenBrainz:
-
- Music players
-
- VLC , cross-platform multimedia player: VLC Listenbrainz plugin
- mpd , cross-platform server-side application for playing music: listenbrainz-mpd
, wylt
- Strawberry , a cross-platform music player
- Foobar2000 , full-fledged audio player for Windows: foo_listenbrainz2
- MusicBee , a music manager and player for Windows: ScrobblerBrainz plugin
- Rhythmbox , a music playing application for GNOME
- Lollypop , a modern music player for GNOME
- cmus , a console-based music player for Unix-like operating systems: cmus-status-scrobbler
- Longplay , an album-based music player for iOS
- Poweramp , a music player for Android: plugin
- Tauon Music Box , a music player for Linux, Arch Linux, and Windows
- Quod Libet , a cross-platform audio player
- Musium , an album-centered music player
- Ampcast , a player, scrobbler and visualiser for personal media servers and streaming services.
- TIDAL Hi-Fi , the web version of Tidal running in electron with Hi-Fi (High & Max) support.
-
-
- Standalone programs/streaming servers
-
- Rescrobbled , a universal Linux scrobbler for MPRIS enabled players
- mpris-scrobbler , a minimalistic unix scrobbler for MPRIS enabled players
- Multi-scrobbler , a powerful javascript server application for all platforms, with support for many sources
- SmashTunes , a Mac menu bar utility for displaying the current track. Submits Apple Music and Spotify listens
- applescript-listenbrainz , an applescript service to submit Apple Music listens
- Eavesdrop.FM , submits Plex music listening data to ListenBrainz
- AudioStreamerScrobbler , submit listens from hardware audiostreamers (Bluesound/BluOS, MusicCast, HEOS)
- Funkwhale , a decentralized music sharing and listening platform with built-in support for ListenBrainz
- Jellyfin , a free software media streaming system: jellyfin-plugin-listenbrainz
- gonic , a free software Subsonic-compatible music server, has built-in support for ListenBrainz
- Navidrome , a free software music server compatible with Subsonic/Airsonic
- Kodi , a free and open source media center: ListenBrainz add-on
- Airsonic-Advanced , a free, web-based media streamer
- AMWin-RP , a Discord Rich Presence client for Apple Music's native Windows app.
- OngakuKiroku , a ListenBrainz scrobbler for Swinsian and Music.app on macOS devices.
-
-
- Browser extensions
-
- Web Scrobbler , an extension for Firefox and Chrome/Chromium-based browsers
-
-
- Mobile devices
-
-
- Scripts
-
-
- Submitting via Spotify
-
- ListenBrainz can automatically record listens from Spotify.
-
-
- Importing the same listens from two different sources such as Last.FM and Spotify may cause the creation
- of duplicates in your listen history. If you opt into our automatic Spotify import, you may notice duplications in
- the last 50 listens on Spotify.This is a temporary issue while we find better ways to deduplicate listens.
-
-
- Connect your Spotify account to ListenBrainz.
-
-
- Playlist submissions and tools
-
- Playlists can also be submitted and stored on your ListenBrainz account.
-
- Tools
-
- listenbrainz-playlist-uploader , a CLI tool for submitting local M3U playlists to ListenBrainz, as well as submitting feedback on tracks
- ListenBrainz-SMP , a Foobar2000 plugin for submitting and retrieving playlists from ListenBrainz (+ Spotify), as well as retrieving recommendations or submitting feedback on tracks.
- Playlist-Manager-SMP , a Foobar2000 plugin for syncing local playlists (in multiple formats) with ListenBrainz (+ Spotify). Tracks playlists changes and also allows to resolve tracks with local content and YouTube links.
- Wrapped-SMP , a Foobar2000 plugin for creating reports based on user listens similar to the one found at Spotify. Suggested playlists use ListenBrainz recommendations (without requiring listens upload to the server).
-
-
- For advanced users
-
- Developers are able to submit their listens to Listenbrainz using the Listenbrainz API. Information on how to do this
- can be found in the API docs
-
-{%- endblock -%}
diff --git a/listenbrainz/webserver/templates/index/base-about.html b/listenbrainz/webserver/templates/index/base-about.html
deleted file mode 100644
index 203d48b9a5..0000000000
--- a/listenbrainz/webserver/templates/index/base-about.html
+++ /dev/null
@@ -1,47 +0,0 @@
-{% extends 'base-react.html' %}
-{%- block title -%}
- About ListenBrainz
-{%- endblock-%}
-{%- block content -%}
-
-
-
- About
- {% if not active_about_section == 'about' %}
- {{ active_about_section|replace("-", " ")|capitalize }}
- {% endif %}
-
-
-
-
-
-
-
- {% block about_content %}
- {% endblock %}
-
-
-
-{% endblock %}
-
-{% block scripts %}
- {{ super() }}
-{% endblock %}
diff --git a/listenbrainz/webserver/templates/index/current-status.html b/listenbrainz/webserver/templates/index/current-status.html
deleted file mode 100644
index b23617610e..0000000000
--- a/listenbrainz/webserver/templates/index/current-status.html
+++ /dev/null
@@ -1,84 +0,0 @@
-{%- extends 'index/base-about.html' -%}
-{%- block title -%}Status - ListenBrainz{%- endblock -%}
-{%- block about_content -%}
-
- Current status
-
-
-
-
-
ListenBrainz Stats
-
-
-
- Description
- Number
-
-
-
- {% if user_count %}
-
- Number of users
- {{ user_count }}
-
- {% endif %}
- {% if listen_count %}
-
- Number of listens
- {{ listen_count }}
-
- {% endif %}
- {% if listen_counts_per_day %}
- {% for data in listen_counts_per_day %}
-
- Number of listens submitted {{ data['label'] }} ({{ data['date'] }})
- {{ data['listen_count'] }}
-
- {% endfor %}
- {% endif %}
-
-
-
-
- If you are curious about the state of our Listen ingestion pipelines, you can
- create yourself a free account on our infrastructure
- statistics site . In particular,
- the
-
- RabbitMQ ListenBrainz view shows how many listens we are currently processing, and the number of incoming listens currently queued for processing.
-
-
-
- Something isn't updating? Stay calm and check the Expected Data Update Intervals doc.
-
-
-
load average
-
-
- Current server load average
-
-
- {{ load }}
-
-
-
-
-
-
-
-
-
-
-
- Our server doesn't have a selfie. :(
- Have a monkey selfie instead!
-
-
-
-
-
-
-
-{%- endblock -%}
diff --git a/listenbrainz/webserver/templates/index/data.html b/listenbrainz/webserver/templates/index/data.html
deleted file mode 100644
index 9a2efa6bc8..0000000000
--- a/listenbrainz/webserver/templates/index/data.html
+++ /dev/null
@@ -1,24 +0,0 @@
-{%- extends 'index/base-about.html' -%}
-{%- block title -%}Downloads - ListenBrainz{%- endblock -%}
-{%- block about_content -%}
-
- Data Downloads
-
- You can download the ListenBrainz data snapshots from the following sites:
-
-
- Available dump types
-
- fullexport: Dumps of the full ListenBrainz database, updated every two weeks on or about the 1st and the 15th of each month.
- incremental: Daily incremental dumps based on the most recent fullexport dump.
- spark: A version of the fullexport dump suitable for importing directly into
- our spark infrastructure .
-
-
-
-{%- endblock -%}
diff --git a/listenbrainz/webserver/templates/index/gdpr.html b/listenbrainz/webserver/templates/index/gdpr.html
deleted file mode 100644
index f98fe9f239..0000000000
--- a/listenbrainz/webserver/templates/index/gdpr.html
+++ /dev/null
@@ -1,44 +0,0 @@
-{% extends 'base.html' %}
-
-{% block title %}Agree to Terms - ListenBrainz{% endblock %}
-
-{% block content %}
-
-
-
Agree to General Data Protection Regulations
-
-
-
Important!
-
- By signing into ListenBrainz, you grant the MetaBrainz Foundation permission to include your listening history
- in data dumps we make publicly available under the
- CC0 license . None of your private information
- from your user profile will be included in these data dumps.
-
-
- Furthermore, you grant the MetaBrainz Foundation permission to process your listening history and include it
- in new open source tools such as recommendation engines that the ListenBrainz project is building. For details
- on processing your listening history, please see our GDPR compliance
- statement .
-
-
- If you change your mind about processing your listening history, you will need to
-
delete your ListenBrainz account .
-
-
-
-
-
- Submit choice!
-
-
-
-{% endblock %}
diff --git a/listenbrainz/webserver/templates/index/import-data.html b/listenbrainz/webserver/templates/index/import-data.html
deleted file mode 100644
index bef3adc4a6..0000000000
--- a/listenbrainz/webserver/templates/index/import-data.html
+++ /dev/null
@@ -1,18 +0,0 @@
-{%- extends 'base.html' -%}
-{%- block title -%}Importing Data - ListenBrainz{%- endblock -%}
-{%- block content -%}
- Importing your data to Listenbrainz
- {# Last.fm import information #}
- Importing data from Last.fm
-
-
- We encourage Last.fm users to save their listen histories to ListenBrainz.
-
-
- To help us test this service, please import your listen history from Last.fm. To proceed, you will need a
- MusicBrainz account.
-
-
-{%- endblock -%}
diff --git a/listenbrainz/webserver/templates/index/index.html b/listenbrainz/webserver/templates/index/index.html
deleted file mode 100644
index 431a5b4600..0000000000
--- a/listenbrainz/webserver/templates/index/index.html
+++ /dev/null
@@ -1,28 +0,0 @@
-{%- extends 'base-react.html' -%}
-
-{% block head %}
- {{ super() }}
-
-{%- endblock -%}
-
-{%- block content -%}
-
- {{ super() }}
-{%- endblock -%}
-
-{%- block footer -%}
-
-{%- endblock -%}
-
-{% block scripts %}
-{{ super() }}
-
-{% endblock %}
diff --git a/listenbrainz/webserver/templates/index/lastfm-proxy.html b/listenbrainz/webserver/templates/index/lastfm-proxy.html
deleted file mode 100644
index af8bac0643..0000000000
--- a/listenbrainz/webserver/templates/index/lastfm-proxy.html
+++ /dev/null
@@ -1,38 +0,0 @@
-{%- extends 'base.html' -%}
-{%- block title -%}Proxy Last.FM APIs - ListenBrainz{%- endblock -%}
-{%- block content -%}
- Proxy Last.FM APIs
-
- ListenBrainz supports the Last.FM API and v1.2 of the AudioScrobbler API (used by clients like VLC and Spotify). Existing Last.FM
- clients can be pointed to the ListenBrainz proxy URL and they should submit listens to
- ListenBrainz instead of Last.FM.
-
-
-
- Instructions
-
- Last.FM API
-
- Clients supporting the current Last.FM API (such as Audacious) should be able to submit listens to ListenBrainz after some
- configuration as instructed in the API Compatible README .
-
-
- AudioScrobbler API v1.2
-
-
- Clients supporting the old version of the
- AudioScrobbler API (such as VLC and Spotify) can be configured to work with ListenBrainz by making the client point
- to http://proxy.listenbrainz.org and using MusicBrainz ID as username and the
- LB auth token as password.
-
-
-
- If the software you are using doesn't support changing where the client submits info (like Spotify), you can edit your
- /etc/hosts file as follows:
-
-
- 138.201.169.196 post.audioscrobbler.com
- 138.201.169.196 post2.audioscrobbler.com
-
-
-{%- endblock -%}
diff --git a/listenbrainz/webserver/templates/index/listens_offline.html b/listenbrainz/webserver/templates/index/listens_offline.html
deleted file mode 100644
index dc675b39a4..0000000000
--- a/listenbrainz/webserver/templates/index/listens_offline.html
+++ /dev/null
@@ -1,22 +0,0 @@
-{%- extends 'base.html' -%}
-{%- block title -%}Listens currently unavailable - ListenBrainz{%- endblock -%}
-{%- block content -%}
- Listens currently unavailable
-
-
- The database that contains listens for our users is currently offline
- for maintenance. Please try again in a few minutes.
-
-
-
- Please note: You may continue to submit listens during this time. We'll
- save them once our database is available again.
-
-
-
- You may find out more about the current status of our services by
- checking our Twitter
- feed .
-
-
-{%- endblock -%}
diff --git a/listenbrainz/webserver/templates/index/messybrainz.html b/listenbrainz/webserver/templates/index/messybrainz.html
deleted file mode 100644
index 8310dcda09..0000000000
--- a/listenbrainz/webserver/templates/index/messybrainz.html
+++ /dev/null
@@ -1,18 +0,0 @@
-{%- extends 'base.html' -%}
-{%- block title -%}MessyBrainz - ListenBrainz{%- endblock -%}
-{%- block content -%}
-
- MessyBrainz
-
- MessyBrainz is a MetaBrainz project to support unclean metadata. While
- MusicBrainz is designed to link clean metadata to stable identifiers,
- there is a need to identify unclean or misspelled data as well. MessyBrainz provides identifiers to unclean
- metadata, and where possible, links it to stable MusicBrainz identifiers.
-
-
- MessyBrainz is currently used in support of ListenBrainz. Submission to MessyBrainz is restricted, however the
- resulting data will be made freely available.
-
-{%- endblock -%}
diff --git a/listenbrainz/webserver/templates/index/musicbrainz-offline.html b/listenbrainz/webserver/templates/index/musicbrainz-offline.html
deleted file mode 100644
index ba7494a2b4..0000000000
--- a/listenbrainz/webserver/templates/index/musicbrainz-offline.html
+++ /dev/null
@@ -1,21 +0,0 @@
-{%- extends 'base.html' -%}
-{%- block title -%}Login currently unavailable - ListenBrainz{%- endblock -%}
-{%- block content -%}
- Login currently unavailable
-
-
- ListenBrainz login and sign up is currently unavailable due to database maintenance.
- Please try again in a few minutes.
-
-
-
- Please note: You may continue to submit listens during this time.
-
-
-
- You may find out more about the current status of our services by
- checking our Twitter
- feed .
-
-
-{%- endblock -%}
diff --git a/listenbrainz/webserver/templates/index/player.html b/listenbrainz/webserver/templates/index/player.html
deleted file mode 100644
index 563540afda..0000000000
--- a/listenbrainz/webserver/templates/index/player.html
+++ /dev/null
@@ -1,19 +0,0 @@
-{%- extends 'base-react.html' -%}
-
-{%- block title -%}BrainzPlayer{%- endblock -%}
-
-
-{% block content %}
- {{ super() }}
- {% if error_msg %}
-
-
Error
-
{{ error_msg }}
-
- {% endif %}
-{% endblock %}
-
-{% block scripts %}
- {{ super() }}
-
-{% endblock %}
diff --git a/listenbrainz/webserver/templates/index/search-users.html b/listenbrainz/webserver/templates/index/search-users.html
deleted file mode 100644
index f1f00a3a66..0000000000
--- a/listenbrainz/webserver/templates/index/search-users.html
+++ /dev/null
@@ -1,51 +0,0 @@
-{%- extends "base.html" -%}
-{%- block title -%}Username Search Results{%- endblock -%}
-{%- block content -%}
-
-
-
-
- User
- {% if current_user.is_authenticated %}
- Similarity to you
-
-
-
- {% endif %}
-
- {% for row in users %}
-
- {{ loop.index }}
- {{ row[0] }}
- {% if current_user.is_authenticated %}
-
- {% if current_user.musicbrainz_id == row[0] %}
- 100%, we hope!
- {% elif row[2] %}
- {{ "{:.1f}".format(row[2] * 10) }}
- {% else %}
- Similarity score not available
- {% endif %}
-
- {% endif %}
-
- {% else %}
-
- No search results found.
-
- {% endfor %}
-
-{%- endblock -%}
diff --git a/listenbrainz/webserver/templates/index/terms-of-service.html b/listenbrainz/webserver/templates/index/terms-of-service.html
deleted file mode 100644
index de1727cc1d..0000000000
--- a/listenbrainz/webserver/templates/index/terms-of-service.html
+++ /dev/null
@@ -1,38 +0,0 @@
-{%- extends 'index/base-about.html' -%}
-{%- block title -%}Terms of Service - ListenBrainz{%- endblock -%}
-{%- block about_content -%}
-Terms of Service
-
-As one of the projects of the MetaBrainz Foundation ,
- ListenBrainz' terms of service are defined by the social contract and privacy policies of the Foundation.
- You will find these detailed on the MetaBrainz website:
-
-
-
-Third party resources
-
- Additionally, we use the following third party resources to enable you to play music on ListenBrainz:
-
-
-
- We use the YouTube API Services to search for and play music directly on ListenBrainz.
- By using ListenBrainz to play music, you agree to be bound by the YouTube Terms of Service.
- See their ToS and privacy policy below:
-
-
-
-{%- endblock -%}
diff --git a/listenbrainz/webserver/templates/login/login.html b/listenbrainz/webserver/templates/login/login.html
deleted file mode 100644
index 6d053136c1..0000000000
--- a/listenbrainz/webserver/templates/login/login.html
+++ /dev/null
@@ -1,40 +0,0 @@
-{% extends 'base.html' %}
-
-{% block title %}Sign in - ListenBrainz{% endblock %}
-
-{% block content %}
-
-
Sign in
-
-
To sign in, use your MusicBrainz account, and authorize ListenBrainz to access your profile data.
-
-
-
Important!
-
- By signing into ListenBrainz, you grant the MetaBrainz Foundation permission to include your listening history
- in data dumps we make publicly available under the
- CC0 license . None of your private information
- from your user profile will be included in these data dumps.
-
-
- Furthermore, you grant the MetaBrainz Foundation permission to process your listening history and include it
- in new open source tools such as recommendation engines that the ListenBrainz project is building. For details
- on processing your listening history, please see our GDPR compliance
- statement .
-
-
- In order to combat spammers and to be able to contact our users in case something goes wrong with the listen
- submission process, we now require an email address when creating a ListenBrainz account.
-
-
- If after creating an account you change your mind about processing your listening history, you will need to
- delete your ListenBrainz account .
-
-
-
-
-
-{% endblock %}
diff --git a/listenbrainz/webserver/templates/navbar.html b/listenbrainz/webserver/templates/navbar.html
index 641ed7a0b1..e5a8a471a5 100644
--- a/listenbrainz/webserver/templates/navbar.html
+++ b/listenbrainz/webserver/templates/navbar.html
@@ -21,11 +21,11 @@
{% if current_user.is_authenticated %}
-
Feed
+
Feed
Dashboard
{% else %}
-
Feed
-
Dashboard
+
Feed
+
Dashboard
{% endif %}
Explore
@@ -33,14 +33,14 @@