Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Able to save and load replays with a static connect code. #4

Closed
wants to merge 1 commit into from
Closed
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
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,9 @@
"vite": "^2.7.10",
"zx": "^4.2.0"
},
"packageManager": "yarn@3.1.1"
}
"packageManager": "yarn@3.1.1",
"dependencies": {
"@spectrum-web-components/textfield": "^0.11.4",
"axios": "^0.26.1"
}
}
61 changes: 61 additions & 0 deletions packages/slippilab/src/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import axios from 'axios';

export interface SlpReplay {
id: string;
connectCode: string;
fileName: string;
fileData: string;
contentType: string;
createdAt: Date;
};

export interface GetReplaysResponse {
data: SlpReplay[];
}


export class Api {

public async getSlpReplays() {
try {
// 👇️ const data: GetUsersResponse
const { data, status } = await axios.get<GetReplaysResponse>(
'http://localhost:8080/replays-by-connect-code?connectCode=KVLR%23653',
{
headers: {
'Access-Control-Allow-Origin': '*',
Accept: 'application/json',
},
},
);

console.log(JSON.stringify(data, null, 4));

// 👇️ "response status is: 200"
console.log('response status is: ', status);

return data;
} catch (error) {
if (axios.isAxiosError(error)) {
console.log('error message: ', error.message);
return error.message;
} else {
console.log('unexpected error: ', error);
return 'An unexpected error occurred';
}
}
}

public async postSlpReplays(file: File) {
const formData = new FormData();
formData.append("file", file, file.name);
formData.append("connectCode", "KVLR#653")
axios.post('http://localhost:8080/add-replay', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
}
}

export const api = new Api()
9 changes: 9 additions & 0 deletions packages/slippilab/src/app-root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { model } from './model';
import type { Replay } from './model';
import { fetchAnimation } from '@slippilab/viewer';
import './replay-select';
import './replay-store-select';
import './file-list';
import './highlight-list';
import './sl-settings';
Expand Down Expand Up @@ -85,6 +86,11 @@ export class AppRoot extends LitElement {
flex-direction: column;
justify-content: space-between;
}
.middle {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.bottom {
display: flex;
flex-direction: row;
Expand Down Expand Up @@ -162,6 +168,9 @@ export class AppRoot extends LitElement {
<sl-settings></sl-settings>
</sp-tab-panel>
</sp-tabs>
<div class="middle">
<replay-store-select></replay-store-select>
</div>
<div class="bottom">
<sp-link
size="xl"
Expand Down
25 changes: 24 additions & 1 deletion packages/slippilab/src/model.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { parseReplay } from '@slippilab/parser';
import { Subject } from 'rxjs';
import { BlobReader, BlobWriter, ZipReader } from '@zip.js/zip.js';
import { BlobReader, BlobWriter, ZipReader, ZipWriter } from '@zip.js/zip.js';
import { run } from '@slippilab/search';
import type { Highlight, Query } from '@slippilab/search';
import { supportedStagesById } from '@slippilab/viewer';
Expand Down Expand Up @@ -259,6 +259,29 @@ export class Model {
),
);
}

async zip(octetFile: File): Promise<File> {
if (octetFile.type == "application/zip") {
console.log("Found a zip file. don't zip further")
return octetFile;
}
// use a BlobWriter to store with a ZipWriter the zip into a Blob object
const blobWriter = new BlobWriter("application/zip");
const writer = new ZipWriter(blobWriter);

// use a BlobReader to read the Blob to add
await writer.add(octetFile.name, new BlobReader(octetFile));

// close the ZipReader
await writer.close();

// get the zip file as a Blob
const blob = blobWriter.getData();

var zipFile = new File([blob], octetFile.name + ".zip", { type: 'application/zip' });

return zipFile;
}
}

export const model = new Model();
Expand Down
133 changes: 133 additions & 0 deletions packages/slippilab/src/replay-store-select.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { css, html, LitElement } from 'lit';
import { customElement, query, queryAll } from 'lit/decorators.js';
import '@spectrum-web-components/action-button/sp-action-button';
import '@spectrum-web-components/textfield/sp-textfield';
import type { ActionButton } from '@spectrum-web-components/action-button';
import { model } from './model';
import { api } from './api';


@customElement('replay-store-select')
export class ReplayStoreSelect extends LitElement {
static get styles() {
return css`
input {
display: none;
}
.container {
display: flex;
justify-content: center;
}
`;
}

@query('#replay-input-files')
private filesInput?: HTMLInputElement;

@query('#replay-input-dir')
private dirInput?: HTMLInputElement;

@queryAll('sp-action-button')
private actionButtons?: NodeListOf<ActionButton>;

private async uploadToReplayStore() {
this.selectFiles(this.filesInput);
}

private async selectFiles(input?: HTMLInputElement) {
if (!input?.files) {
return;
}
if (input.files.length > 0) {
var allFiles = Array.from(input.files);

model.setFiles(allFiles);

allFiles.forEach(async function (slpFile) {
var fileNameComponents = slpFile.name.split(".");
var fileExtension = fileNameComponents[fileNameComponents.length - 1];
if (fileExtension == "slp") {
console.log("Got the slp file. Trying to zip and upload");
var zipFile = await model.zip(slpFile);
api.postSlpReplays(zipFile);
} else {
api.postSlpReplays(slpFile);
}
})

}
this.actionButtons?.forEach((actionButton) => actionButton.blur());

}


private async openFromReplayStore() {
const slpReplays = await api.getSlpReplays()

if (Array.isArray(slpReplays)) {
var files: File[] = [];

slpReplays.forEach(async function (slpReplay) {
console.log("Here is the srsReplay: ", slpReplay);
var file = blobToFile(slpReplay);

files.push(file);

});
model.setFiles(Array.from(files))
}
else {
console.log("Error fetching replays");
}
}

private openFile() {
this.filesInput?.click();
}


render() {
return html`
<div class="container">
<sp-field-label for="connect-code">Connect Code</sp-field-label>
<sp-textfield id="connect-code" placeholder="Enter your connect code"></sp-textfield>
</div>
<div class="container">
<sp-action-button class="label" @click=${this.openFromReplayStore}>
Open Replay Store
</sp-action-button>
<sp-action-button class="label" @click=${this.openFile}>
Save Replay Store
</sp-action-button>
<input
id="replay-input-files"
name="replay-input-files"
type="file"
accept=".slp,.zip"
multiple
@change=${this.uploadToReplayStore}
/>
</div>
`;
}
}

function blobToFile(slpReplay: any) {
const byteCharacters = atob(slpReplay.fileData);

const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}

const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: slpReplay.contentType });

console.log("Here is the blob: ", blob);

console.log("here is the blob content type: ", blob.type);

var file = new File([blob], slpReplay.fileName);
return file;
}

Loading