diff --git a/bun.lockb b/bun.lockb
index f4c7ad9..b1b5288 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/protos/player.proto b/protos/player.proto
index e86cd47..c4c5813 100644
--- a/protos/player.proto
+++ b/protos/player.proto
@@ -15,6 +15,7 @@ service Player {
rpc SetVolume(SetVolumeRequest) returns (SetVolumeResponse);
rpc PlayTrackNext(TrackRequest) returns (Queue);
rpc AddTrackToQueue(TrackRequest) returns (Queue);
+ rpc SwapQueueIndices(SwapQueueIndicesRequest) returns (Queue);
rpc SkipTrack(google.protobuf.Empty) returns (PlayerStatus);
rpc SkipToQueueIndex(SkipToQueueIndexRequest) returns (PlayerStatus);
}
@@ -63,3 +64,8 @@ message SetVolumeResponse {
message SkipToQueueIndexRequest {
uint32 index = 1;
}
+
+message SwapQueueIndicesRequest {
+ uint32 a = 1;
+ uint32 b = 2;
+}
diff --git a/src/app.css b/src/app.css
index 81f02c7..c682e5a 100644
--- a/src/app.css
+++ b/src/app.css
@@ -77,5 +77,5 @@
}
* {
- -webkit-user-drag: none !important;
+ /* -webkit-user-drag: none !important; */
}
diff --git a/src/lib/components/groove/Footer.svelte b/src/lib/components/groove/Footer.svelte
index 4abdaf0..319dedd 100644
--- a/src/lib/components/groove/Footer.svelte
+++ b/src/lib/components/groove/Footer.svelte
@@ -11,6 +11,7 @@
import { getCoverUrl } from '$lib/covers';
import VolumeSlider from '$lib/components/groove/VolumeSlider.svelte';
import type { SubmitFunction } from '../../../routes/player/$types';
+ import Queue from './Queue.svelte';
dayjs.extend(duration);
@@ -133,35 +134,7 @@
-
+
diff --git a/src/lib/components/groove/Queue.svelte b/src/lib/components/groove/Queue.svelte
new file mode 100644
index 0000000..f2a0bc5
--- /dev/null
+++ b/src/lib/components/groove/Queue.svelte
@@ -0,0 +1,108 @@
+
+
+
+
+
diff --git a/src/lib/proto/player.client.ts b/src/lib/proto/player.client.ts
index 76cf2ae..a0c529c 100644
--- a/src/lib/proto/player.client.ts
+++ b/src/lib/proto/player.client.ts
@@ -5,6 +5,7 @@ import type { RpcTransport } from "@protobuf-ts/runtime-rpc";
import type { ServiceInfo } from "@protobuf-ts/runtime-rpc";
import { Player } from "./player";
import type { SkipToQueueIndexRequest } from "./player";
+import type { SwapQueueIndicesRequest } from "./player";
import type { Queue } from "./player";
import type { SetVolumeResponse } from "./player";
import type { SetVolumeRequest } from "./player";
@@ -59,6 +60,10 @@ export interface IPlayerClient {
* @generated from protobuf rpc: AddTrackToQueue(player.TrackRequest) returns (player.Queue);
*/
addTrackToQueue(input: TrackRequest, options?: RpcOptions): UnaryCall;
+ /**
+ * @generated from protobuf rpc: SwapQueueIndices(player.SwapQueueIndicesRequest) returns (player.Queue);
+ */
+ swapQueueIndices(input: SwapQueueIndicesRequest, options?: RpcOptions): UnaryCall;
/**
* @generated from protobuf rpc: SkipTrack(google.protobuf.Empty) returns (player.PlayerStatus);
*/
@@ -140,18 +145,25 @@ export class PlayerClient implements IPlayerClient, ServiceInfo {
const method = this.methods[8], opt = this._transport.mergeOptions(options);
return stackIntercept("unary", this._transport, method, opt, input);
}
+ /**
+ * @generated from protobuf rpc: SwapQueueIndices(player.SwapQueueIndicesRequest) returns (player.Queue);
+ */
+ swapQueueIndices(input: SwapQueueIndicesRequest, options?: RpcOptions): UnaryCall {
+ const method = this.methods[9], opt = this._transport.mergeOptions(options);
+ return stackIntercept("unary", this._transport, method, opt, input);
+ }
/**
* @generated from protobuf rpc: SkipTrack(google.protobuf.Empty) returns (player.PlayerStatus);
*/
skipTrack(input: Empty, options?: RpcOptions): UnaryCall {
- const method = this.methods[9], opt = this._transport.mergeOptions(options);
+ const method = this.methods[10], opt = this._transport.mergeOptions(options);
return stackIntercept("unary", this._transport, method, opt, input);
}
/**
* @generated from protobuf rpc: SkipToQueueIndex(player.SkipToQueueIndexRequest) returns (player.PlayerStatus);
*/
skipToQueueIndex(input: SkipToQueueIndexRequest, options?: RpcOptions): UnaryCall {
- const method = this.methods[10], opt = this._transport.mergeOptions(options);
+ const method = this.methods[11], opt = this._transport.mergeOptions(options);
return stackIntercept("unary", this._transport, method, opt, input);
}
}
diff --git a/src/lib/proto/player.ts b/src/lib/proto/player.ts
index dea54e2..07d147d 100644
--- a/src/lib/proto/player.ts
+++ b/src/lib/proto/player.ts
@@ -123,6 +123,19 @@ export interface SkipToQueueIndexRequest {
*/
index: number;
}
+/**
+ * @generated from protobuf message player.SwapQueueIndicesRequest
+ */
+export interface SwapQueueIndicesRequest {
+ /**
+ * @generated from protobuf field: uint32 a = 1;
+ */
+ a: number;
+ /**
+ * @generated from protobuf field: uint32 b = 2;
+ */
+ b: number;
+}
// @generated message type with reflection information, may provide speed optimized methods
class TrackRequest$Type extends MessageType {
constructor() {
@@ -631,6 +644,61 @@ class SkipToQueueIndexRequest$Type extends MessageType
* @generated MessageType for protobuf message player.SkipToQueueIndexRequest
*/
export const SkipToQueueIndexRequest = new SkipToQueueIndexRequest$Type();
+// @generated message type with reflection information, may provide speed optimized methods
+class SwapQueueIndicesRequest$Type extends MessageType {
+ constructor() {
+ super("player.SwapQueueIndicesRequest", [
+ { no: 1, name: "a", kind: "scalar", T: 13 /*ScalarType.UINT32*/ },
+ { no: 2, name: "b", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }
+ ]);
+ }
+ create(value?: PartialMessage): SwapQueueIndicesRequest {
+ const message = globalThis.Object.create((this.messagePrototype!));
+ message.a = 0;
+ message.b = 0;
+ if (value !== undefined)
+ reflectionMergePartial(this, message, value);
+ return message;
+ }
+ internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: SwapQueueIndicesRequest): SwapQueueIndicesRequest {
+ let message = target ?? this.create(), end = reader.pos + length;
+ while (reader.pos < end) {
+ let [fieldNo, wireType] = reader.tag();
+ switch (fieldNo) {
+ case /* uint32 a */ 1:
+ message.a = reader.uint32();
+ break;
+ case /* uint32 b */ 2:
+ message.b = reader.uint32();
+ break;
+ default:
+ let u = options.readUnknownField;
+ if (u === "throw")
+ throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
+ let d = reader.skip(wireType);
+ if (u !== false)
+ (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
+ }
+ }
+ return message;
+ }
+ internalBinaryWrite(message: SwapQueueIndicesRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
+ /* uint32 a = 1; */
+ if (message.a !== 0)
+ writer.tag(1, WireType.Varint).uint32(message.a);
+ /* uint32 b = 2; */
+ if (message.b !== 0)
+ writer.tag(2, WireType.Varint).uint32(message.b);
+ let u = options.writeUnknownFields;
+ if (u !== false)
+ (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
+ return writer;
+ }
+}
+/**
+ * @generated MessageType for protobuf message player.SwapQueueIndicesRequest
+ */
+export const SwapQueueIndicesRequest = new SwapQueueIndicesRequest$Type();
/**
* @generated ServiceType for protobuf service player.Player
*/
@@ -644,6 +712,7 @@ export const Player = new ServiceType("player.Player", [
{ name: "SetVolume", options: {}, I: SetVolumeRequest, O: SetVolumeResponse },
{ name: "PlayTrackNext", options: {}, I: TrackRequest, O: Queue },
{ name: "AddTrackToQueue", options: {}, I: TrackRequest, O: Queue },
+ { name: "SwapQueueIndices", options: {}, I: SwapQueueIndicesRequest, O: Queue },
{ name: "SkipTrack", options: {}, I: Empty, O: PlayerStatus },
{ name: "SkipToQueueIndex", options: {}, I: SkipToQueueIndexRequest, O: PlayerStatus }
]);
diff --git a/src/routes/player/+page.server.ts b/src/routes/player/+page.server.ts
index 5c69d45..d68104b 100644
--- a/src/routes/player/+page.server.ts
+++ b/src/routes/player/+page.server.ts
@@ -3,7 +3,7 @@ import { fail } from '@sveltejs/kit';
import { protoTransport } from '../../hooks.server';
import type { Actions } from './$types';
import { serializable } from '$lib/proto';
-import type { PlayerStatus } from '$lib/proto/player';
+import { PlayerStatus } from '$lib/proto/player';
export const actions = {
skip: async () => {
@@ -26,6 +26,23 @@ export const actions = {
return serializable(response.response);
},
+ 'swap-queue-indices': async ({ request }) => {
+ const formData = await request.formData();
+ const [a, b] = [formData.get('a')?.toString(), formData.get('b')?.toString()];
+
+ if (!a || !b) {
+ return fail(400);
+ }
+
+ const client = new PlayerClient(protoTransport);
+
+ const response = await client.swapQueueIndices({
+ a: parseInt(a),
+ b: parseInt(b)
+ });
+
+ return serializable(response.response);
+ },
resume: async () => {
const client = new PlayerClient(protoTransport);