atcoder-gui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +149 -0
- package/dist/browser.d.ts +59 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +130 -0
- package/dist/browser.js.map +1 -0
- package/dist/config.d.ts +53 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +103 -0
- package/dist/config.js.map +1 -0
- package/dist/config.json5 +15 -0
- package/dist/cookie-export.d.ts +43 -0
- package/dist/cookie-export.d.ts.map +1 -0
- package/dist/cookie-export.js +151 -0
- package/dist/cookie-export.js.map +1 -0
- package/dist/main.d.ts +39 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +206 -0
- package/dist/main.js.map +1 -0
- package/dist/session.d.ts +53 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +73 -0
- package/dist/session.js.map +1 -0
- package/dist/submit.d.ts +22 -0
- package/dist/submit.d.ts.map +1 -0
- package/dist/submit.js +94 -0
- package/dist/submit.js.map +1 -0
- package/dist/utils.d.ts +10 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +18 -0
- package/dist/utils.js.map +1 -0
- package/package.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 firewood <174658+firewood@users.noreply.github.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# AtCoder GUI
|
|
2
|
+
|
|
3
|
+
A browser automation tool for AtCoder with CLI interface built with Node.js, TypeScript, and Playwright.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Browser Automation**: Launch a browser with UI using Playwright
|
|
8
|
+
- **Session Management**: Persistent browser sessions with automatic restoration
|
|
9
|
+
- **CLI Commands**: Interactive command line interface
|
|
10
|
+
- **Configuration Management**: Persistent settings using the conf module
|
|
11
|
+
- **URL Opening**: Open URLs with the `open URL` command
|
|
12
|
+
- **Automatic Startup**: Opens default URL on application launch
|
|
13
|
+
|
|
14
|
+
## Project Structure
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
atcoder-gui/
|
|
18
|
+
├── src/
|
|
19
|
+
│ ├── main.ts # CLI application entry point and command handling
|
|
20
|
+
│ ├── browser.ts # Playwright browser management and automation
|
|
21
|
+
│ ├── config.ts # Configuration management using conf module
|
|
22
|
+
│ ├── session.ts # Session persistence and restoration
|
|
23
|
+
│ └── *.test.ts # Test files
|
|
24
|
+
├── dist/ # Compiled JavaScript output
|
|
25
|
+
├── eslint.config.js # ESLint configuration
|
|
26
|
+
└── package.json # Project configuration
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
1. Clone the repository
|
|
32
|
+
2. Install dependencies:
|
|
33
|
+
```bash
|
|
34
|
+
npm install
|
|
35
|
+
```
|
|
36
|
+
3. Install Playwright browsers:
|
|
37
|
+
```bash
|
|
38
|
+
npx playwright install chromium
|
|
39
|
+
```
|
|
40
|
+
4. Build the project:
|
|
41
|
+
```bash
|
|
42
|
+
npm run build
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
### Interactive CLI
|
|
48
|
+
|
|
49
|
+
Start the interactive command prompt:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm run start
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
This will start an interactive CLI with a command prompt where you can enter commands:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
AtCoder GUI Interactive CLI
|
|
59
|
+
Type "help" for available commands or "exit" to quit
|
|
60
|
+
command> open https://atcoder.jp
|
|
61
|
+
command> config
|
|
62
|
+
command> help
|
|
63
|
+
command> exit
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Available Commands
|
|
67
|
+
|
|
68
|
+
- `open <URL>` - Open a URL in the browser
|
|
69
|
+
- `config` - Show current configuration
|
|
70
|
+
- `help` - Show available commands
|
|
71
|
+
- `exit` - Exit the application
|
|
72
|
+
|
|
73
|
+
### Configuration
|
|
74
|
+
|
|
75
|
+
Configuration is automatically managed using the `conf` module (similar to atcoder-cli). Settings are stored in the standard configuration directory for your operating system:
|
|
76
|
+
|
|
77
|
+
- **Windows**: `%APPDATA%\atcoder-gui\config.json`
|
|
78
|
+
- **macOS**: `~/Library/Preferences/atcoder-gui/config.json`
|
|
79
|
+
- **Linux**: `~/.config/atcoder-gui/config.json`
|
|
80
|
+
|
|
81
|
+
Default configuration values:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
{
|
|
85
|
+
theme: 'light',
|
|
86
|
+
autoStart: false,
|
|
87
|
+
defaultUrl: 'https://atcoder.jp',
|
|
88
|
+
windowSize: {
|
|
89
|
+
width: 1200,
|
|
90
|
+
height: 800
|
|
91
|
+
},
|
|
92
|
+
headless: false,
|
|
93
|
+
devtools: true
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
You can modify settings programmatically through the configuration API, and they will be automatically persisted.
|
|
98
|
+
|
|
99
|
+
### Session Management
|
|
100
|
+
|
|
101
|
+
The application automatically saves and restores browser sessions, including:
|
|
102
|
+
- Cookies
|
|
103
|
+
- Local storage data
|
|
104
|
+
- Login states
|
|
105
|
+
|
|
106
|
+
Session data is stored separately from configuration and is automatically restored when the browser launches.
|
|
107
|
+
|
|
108
|
+
## Development
|
|
109
|
+
|
|
110
|
+
### Available Scripts
|
|
111
|
+
|
|
112
|
+
- `npm run build` - Compile TypeScript to JavaScript
|
|
113
|
+
- `npm run dev` - Watch mode compilation
|
|
114
|
+
- `npm run test` - Run tests in watch mode
|
|
115
|
+
- `npm run test:run` - Run tests once
|
|
116
|
+
- `npm run lint` - Run ESLint
|
|
117
|
+
- `npm run lint:fix` - Fix ESLint issues automatically
|
|
118
|
+
- `npm run start` - Run the compiled CLI application
|
|
119
|
+
- `npm run clean` - Remove compiled output
|
|
120
|
+
|
|
121
|
+
### Testing
|
|
122
|
+
|
|
123
|
+
Run tests with Vitest:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npm run test
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Code Quality
|
|
130
|
+
|
|
131
|
+
The project uses ESLint with TypeScript-specific rules for code quality:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
npm run lint # Check code quality
|
|
135
|
+
npm run lint:fix # Auto-fix issues where possible
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Technology Stack
|
|
139
|
+
|
|
140
|
+
- **Node.js** - Runtime environment
|
|
141
|
+
- **TypeScript** - Programming language
|
|
142
|
+
- **Playwright** - Browser automation
|
|
143
|
+
- **Vitest** - Testing framework
|
|
144
|
+
- **ESLint** - Code linting
|
|
145
|
+
- **conf** - Configuration management library
|
|
146
|
+
|
|
147
|
+
## License
|
|
148
|
+
|
|
149
|
+
MIT
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Browser, Page } from 'playwright';
|
|
2
|
+
import { SessionManager } from './session.js';
|
|
3
|
+
export declare class BrowserManager {
|
|
4
|
+
private browser;
|
|
5
|
+
private context;
|
|
6
|
+
private page;
|
|
7
|
+
private sessionManager;
|
|
8
|
+
private onPageClose;
|
|
9
|
+
constructor();
|
|
10
|
+
/**
|
|
11
|
+
* Set the callback function to be called when the browser page closes
|
|
12
|
+
*/
|
|
13
|
+
setOnPageClose(callback: (() => void) | null): void;
|
|
14
|
+
/**
|
|
15
|
+
* Launch a new browser instance with UI
|
|
16
|
+
*/
|
|
17
|
+
launch(): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Open a URL in the browser
|
|
20
|
+
*/
|
|
21
|
+
openUrl(url: string): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Get the current page instance
|
|
24
|
+
*/
|
|
25
|
+
getCurrentPage(): Page | null;
|
|
26
|
+
/**
|
|
27
|
+
* Get the current browser instance
|
|
28
|
+
*/
|
|
29
|
+
getBrowser(): Browser | null;
|
|
30
|
+
/**
|
|
31
|
+
* Close the browser
|
|
32
|
+
*/
|
|
33
|
+
close(): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Check if browser is running
|
|
36
|
+
*/
|
|
37
|
+
isRunning(): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Get session manager for manual session operations
|
|
40
|
+
*/
|
|
41
|
+
getSessionManager(): SessionManager;
|
|
42
|
+
/**
|
|
43
|
+
* Manually save the current session state
|
|
44
|
+
*/
|
|
45
|
+
saveSession(): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Clear the stored session data
|
|
48
|
+
*/
|
|
49
|
+
clearSession(): void;
|
|
50
|
+
/**
|
|
51
|
+
* Get session information
|
|
52
|
+
*/
|
|
53
|
+
getSessionInfo(): {
|
|
54
|
+
hasSession: boolean;
|
|
55
|
+
cookieCount: number;
|
|
56
|
+
originCount: number;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAY,IAAI,EAAkB,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,WAAW,CAA6B;;IAMhD;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI;IAYnD;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IA6B7B;;OAEG;IACG,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzC;;OAEG;IACH,cAAc,IAAI,IAAI,GAAG,IAAI;IAI7B;;OAEG;IACH,UAAU,IAAI,OAAO,GAAG,IAAI;IAI5B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB5B;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,iBAAiB,IAAI,cAAc;IAInC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAQlC;;OAEG;IACH,YAAY,IAAI,IAAI;IAIpB;;OAEG;IACH,cAAc,IAAI;QAAE,UAAU,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE;CAGpF"}
|
package/dist/browser.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { chromium } from 'playwright';
|
|
2
|
+
import { SessionManager } from './session.js';
|
|
3
|
+
export class BrowserManager {
|
|
4
|
+
browser = null;
|
|
5
|
+
context = null;
|
|
6
|
+
page = null;
|
|
7
|
+
sessionManager;
|
|
8
|
+
onPageClose = null;
|
|
9
|
+
constructor() {
|
|
10
|
+
this.sessionManager = new SessionManager();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Set the callback function to be called when the browser page closes
|
|
14
|
+
*/
|
|
15
|
+
setOnPageClose(callback) {
|
|
16
|
+
if (this.page) {
|
|
17
|
+
if (this.onPageClose) {
|
|
18
|
+
this.page.off('close', this.onPageClose);
|
|
19
|
+
}
|
|
20
|
+
this.onPageClose = callback;
|
|
21
|
+
if (callback) {
|
|
22
|
+
this.page.on('close', callback);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Launch a new browser instance with UI
|
|
28
|
+
*/
|
|
29
|
+
async launch() {
|
|
30
|
+
if (this.browser) {
|
|
31
|
+
await this.close();
|
|
32
|
+
}
|
|
33
|
+
this.browser = await chromium.launch({
|
|
34
|
+
headless: false, // UI mode
|
|
35
|
+
args: [
|
|
36
|
+
'--disable-blink-features=AutomationControlled',
|
|
37
|
+
],
|
|
38
|
+
});
|
|
39
|
+
// Create context with existing storage state if available
|
|
40
|
+
const storageState = this.sessionManager.getStorageState();
|
|
41
|
+
this.context = await this.browser.newContext({
|
|
42
|
+
storageState: storageState
|
|
43
|
+
});
|
|
44
|
+
this.page = await this.context.newPage();
|
|
45
|
+
// Log session restoration status
|
|
46
|
+
const sessionInfo = this.sessionManager.getSessionInfo();
|
|
47
|
+
if (sessionInfo.hasSession) {
|
|
48
|
+
console.log(`Session restored: ${sessionInfo.cookieCount} cookies, ${sessionInfo.originCount} origins`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
console.log('Starting with fresh session');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Open a URL in the browser
|
|
56
|
+
*/
|
|
57
|
+
async openUrl(url) {
|
|
58
|
+
if (!this.page) {
|
|
59
|
+
throw new Error('Browser not launched. Call launch() first.');
|
|
60
|
+
}
|
|
61
|
+
await this.page.goto(url);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get the current page instance
|
|
65
|
+
*/
|
|
66
|
+
getCurrentPage() {
|
|
67
|
+
return this.page;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get the current browser instance
|
|
71
|
+
*/
|
|
72
|
+
getBrowser() {
|
|
73
|
+
return this.browser;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Close the browser
|
|
77
|
+
*/
|
|
78
|
+
async close() {
|
|
79
|
+
if (this.page) {
|
|
80
|
+
this.setOnPageClose(null);
|
|
81
|
+
await this.saveSession();
|
|
82
|
+
await this.page.close();
|
|
83
|
+
this.page = null;
|
|
84
|
+
}
|
|
85
|
+
if (this.context) {
|
|
86
|
+
await this.context.close();
|
|
87
|
+
this.context = null;
|
|
88
|
+
}
|
|
89
|
+
if (this.browser) {
|
|
90
|
+
await this.browser.close();
|
|
91
|
+
this.browser = null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Check if browser is running
|
|
96
|
+
*/
|
|
97
|
+
isRunning() {
|
|
98
|
+
return this.browser !== null && this.page !== null;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get session manager for manual session operations
|
|
102
|
+
*/
|
|
103
|
+
getSessionManager() {
|
|
104
|
+
return this.sessionManager;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Manually save the current session state
|
|
108
|
+
*/
|
|
109
|
+
async saveSession() {
|
|
110
|
+
if (this.context) {
|
|
111
|
+
await this.sessionManager.saveStorageState(this.context);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
console.log('No browser context available to save');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Clear the stored session data
|
|
119
|
+
*/
|
|
120
|
+
clearSession() {
|
|
121
|
+
this.sessionManager.clearSession();
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get session information
|
|
125
|
+
*/
|
|
126
|
+
getSessionInfo() {
|
|
127
|
+
return this.sessionManager.getSessionInfo();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export interface AppConfig {
|
|
2
|
+
theme?: 'light' | 'dark';
|
|
3
|
+
defaultUrl?: string;
|
|
4
|
+
windowSize?: {
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export declare class ConfigManager {
|
|
10
|
+
private conf;
|
|
11
|
+
constructor();
|
|
12
|
+
/**
|
|
13
|
+
* Initialize user config file with default template if it doesn't exist
|
|
14
|
+
*/
|
|
15
|
+
private initializeUserConfigIfNeeded;
|
|
16
|
+
/**
|
|
17
|
+
* Get the entire configuration object
|
|
18
|
+
*/
|
|
19
|
+
getConfig(): AppConfig;
|
|
20
|
+
/**
|
|
21
|
+
* Get a specific configuration value
|
|
22
|
+
*/
|
|
23
|
+
get<K extends keyof AppConfig>(key: K): AppConfig[K];
|
|
24
|
+
/**
|
|
25
|
+
* Set a specific configuration value
|
|
26
|
+
*/
|
|
27
|
+
set<K extends keyof AppConfig>(key: K, value: AppConfig[K]): void;
|
|
28
|
+
/**
|
|
29
|
+
* Set multiple configuration values
|
|
30
|
+
*/
|
|
31
|
+
setMultiple(config: Partial<AppConfig>): void;
|
|
32
|
+
/**
|
|
33
|
+
* Delete a configuration value (revert to default)
|
|
34
|
+
*/
|
|
35
|
+
delete<K extends keyof AppConfig>(key: K): void;
|
|
36
|
+
/**
|
|
37
|
+
* Clear all configuration (revert to defaults)
|
|
38
|
+
*/
|
|
39
|
+
clear(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Check if a configuration key exists
|
|
42
|
+
*/
|
|
43
|
+
has<K extends keyof AppConfig>(key: K): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Get the path to the configuration file
|
|
46
|
+
*/
|
|
47
|
+
getConfigPath(): string;
|
|
48
|
+
/**
|
|
49
|
+
* Get the configuration file size
|
|
50
|
+
*/
|
|
51
|
+
getSize(): number;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE;QACX,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,IAAI,CAAkB;;IAiB9B;;OAEG;IACH,OAAO,CAAC,4BAA4B;IAyBpC;;OAEG;IACH,SAAS,IAAI,SAAS;IAItB;;OAEG;IACH,GAAG,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;IAIpD;;OAEG;IACH,GAAG,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI;IAIjE;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI;IAM7C;;OAEG;IACH,MAAM,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI;IAI/C;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,GAAG,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,OAAO;IAI/C;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,OAAO,IAAI,MAAM;CAGlB"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import Conf from 'conf';
|
|
2
|
+
import JSON5 from 'json5';
|
|
3
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
4
|
+
import { join, dirname } from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
export class ConfigManager {
|
|
7
|
+
conf;
|
|
8
|
+
constructor() {
|
|
9
|
+
this.conf = new Conf({
|
|
10
|
+
projectName: 'atcoder-gui',
|
|
11
|
+
projectVersion: '0.1.0',
|
|
12
|
+
configName: 'config',
|
|
13
|
+
fileExtension: 'json5',
|
|
14
|
+
serialize: (value) => JSON5.stringify(value, null, 2),
|
|
15
|
+
deserialize: (text) => JSON5.parse(text),
|
|
16
|
+
defaults: {}
|
|
17
|
+
});
|
|
18
|
+
// Initialize user config with default template on first launch
|
|
19
|
+
this.initializeUserConfigIfNeeded();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Initialize user config file with default template if it doesn't exist
|
|
23
|
+
*/
|
|
24
|
+
initializeUserConfigIfNeeded() {
|
|
25
|
+
try {
|
|
26
|
+
// Check if user config file already exists
|
|
27
|
+
if (!existsSync(this.conf.path)) {
|
|
28
|
+
console.log('First launch detected, creating config file with default template...');
|
|
29
|
+
// Ensure config directory exists
|
|
30
|
+
const configDir = dirname(this.conf.path);
|
|
31
|
+
if (!existsSync(configDir)) {
|
|
32
|
+
mkdirSync(configDir, { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
// Read default config.json5 template
|
|
35
|
+
const defaultConfigPath = dirname(fileURLToPath(import.meta.url));
|
|
36
|
+
const defaultTemplate = readFileSync(join(defaultConfigPath, 'config.json5'), 'utf-8');
|
|
37
|
+
// Write the template directly to user config path using fs
|
|
38
|
+
writeFileSync(this.conf.path, defaultTemplate, 'utf-8');
|
|
39
|
+
console.log(`Config file created at: ${this.conf.path}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
console.warn('Failed to initialize user config file:', error);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get the entire configuration object
|
|
48
|
+
*/
|
|
49
|
+
getConfig() {
|
|
50
|
+
return this.conf.store;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get a specific configuration value
|
|
54
|
+
*/
|
|
55
|
+
get(key) {
|
|
56
|
+
return this.conf.get(key);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Set a specific configuration value
|
|
60
|
+
*/
|
|
61
|
+
set(key, value) {
|
|
62
|
+
this.conf.set(key, value);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Set multiple configuration values
|
|
66
|
+
*/
|
|
67
|
+
setMultiple(config) {
|
|
68
|
+
for (const [key, value] of Object.entries(config)) {
|
|
69
|
+
this.conf.set(key, value);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Delete a configuration value (revert to default)
|
|
74
|
+
*/
|
|
75
|
+
delete(key) {
|
|
76
|
+
this.conf.delete(key);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Clear all configuration (revert to defaults)
|
|
80
|
+
*/
|
|
81
|
+
clear() {
|
|
82
|
+
this.conf.clear();
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Check if a configuration key exists
|
|
86
|
+
*/
|
|
87
|
+
has(key) {
|
|
88
|
+
return this.conf.has(key);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Get the path to the configuration file
|
|
92
|
+
*/
|
|
93
|
+
getConfigPath() {
|
|
94
|
+
return this.conf.path;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Get the configuration file size
|
|
98
|
+
*/
|
|
99
|
+
getSize() {
|
|
100
|
+
return this.conf.size;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { BrowserManager } from './browser.js';
|
|
2
|
+
export declare class CookieExporter {
|
|
3
|
+
private browserManager;
|
|
4
|
+
constructor(browserManager: BrowserManager);
|
|
5
|
+
/**
|
|
6
|
+
* Get the oj (online-judge-tools) cookie path by running oj command
|
|
7
|
+
*/
|
|
8
|
+
private static getOjCookiePath;
|
|
9
|
+
/**
|
|
10
|
+
* Get AtCoder cookies from current browser session
|
|
11
|
+
*/
|
|
12
|
+
private getAtCoderCookies;
|
|
13
|
+
/**
|
|
14
|
+
* Export cookies to atcoder-tools cookie.txt file
|
|
15
|
+
*/
|
|
16
|
+
exportCookiesForAtCoderTools(): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Export cookies to oj (online-judge-tools) cookie.jar file
|
|
19
|
+
*/
|
|
20
|
+
exportCookiesForOj(): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Export cookies to oj (online-judge-tools) cookie.jar file
|
|
23
|
+
*/
|
|
24
|
+
exportCookies(cookiePath: string): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Generate LWP-Cookies-2.0 format content from Playwright cookies
|
|
27
|
+
*/
|
|
28
|
+
private generateLWPCookiesContent;
|
|
29
|
+
/**
|
|
30
|
+
* Convert Playwright cookie to LWP-Cookies-2.0 Set-Cookie3 format
|
|
31
|
+
*/
|
|
32
|
+
private convertToLWPFormat;
|
|
33
|
+
/**
|
|
34
|
+
* Write cookie content to atcoder-tools cookie.txt file
|
|
35
|
+
* Only overwrites existing cookie.txt files
|
|
36
|
+
*/
|
|
37
|
+
private writeCookieFile;
|
|
38
|
+
/**
|
|
39
|
+
* Get the path to atcoder-tools cookie.txt file
|
|
40
|
+
*/
|
|
41
|
+
static getAtCoderToolsCookiePath(): string;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=cookie-export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookie-export.d.ts","sourceRoot":"","sources":["../src/cookie-export.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAc9C,qBAAa,cAAc;IACzB,OAAO,CAAC,cAAc,CAAiB;gBAE3B,cAAc,EAAE,cAAc;IAI1C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IAiB9B;;OAEG;YACW,iBAAiB;IA8B/B;;OAEG;IACG,4BAA4B,IAAI,OAAO,CAAC,IAAI,CAAC;IAKnD;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAKzC;;OAEG;IACG,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IActD;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAYjC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAwC1B;;;OAGG;YACW,eAAe;IAe7B;;OAEG;IACH,MAAM,CAAC,yBAAyB,IAAI,MAAM;CAG3C"}
|