Initial commit

This commit is contained in:
imeed166 2026-01-15 21:56:18 +01:00
commit 2af82cd4a9
11 changed files with 7031 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
node_modules/
.DS_Store
.idea/
.vscode/

19
README.md Normal file
View file

@ -0,0 +1,19 @@
# Cross Player
A media player plugin for Obsidian that watches a folder and plays media files.
## Features
- **Watched Folder**: configure a local folder to watch for media files.
- **Queue Management**: Automatically adds new media files to a queue.
- **Playback**: Plays video and audio files in the center pane.
- **Progress Tracking**: Remembers playback position and completion status.
- **Cleanup**: Command to delete consumed (completed) media files from disk.
## Usage
1. Enable the plugin.
2. Go to Settings > Cross Player and set the "Watched Folder" path (absolute path).
3. Open the "Cross Player Queue" view from the ribbon icon or command palette.
4. Click a media item to play it.
5. Use "Clean Consumed Media" command to remove finished files.

45
esbuild.config.mjs Normal file
View file

@ -0,0 +1,45 @@
import esbuild from "esbuild";
import process from "process";
import builtins from "builtin-modules";
const banner =
`/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
`;
const prod = (process.argv[2] === "production");
const context = await esbuild.context({
banner: {
js: banner,
},
entryPoints: ["src/main.ts"],
bundle: true,
external: [
"obsidian",
"electron",
"@codemirror/autocomplete",
"@codemirror/collab",
"@codemirror/commands",
"@codemirror/language",
"@codemirror/lint",
"@codemirror/search",
"@codemirror/state",
"@codemirror/view",
...builtins],
format: "cjs",
target: "es2018",
logLevel: "info",
sourcemap: prod ? false : "inline",
treeShaking: true,
outfile: "main.js",
});
if (prod) {
await context.rebuild();
process.exit(0);
} else {
await context.watch();
}

3257
main.js Normal file

File diff suppressed because it is too large Load diff

9
manifest.json Normal file
View file

@ -0,0 +1,9 @@
{
"id": "cross-player",
"name": "Cross Player",
"version": "1.0.0",
"minAppVersion": "0.15.0",
"description": "A media player plugin that watches a folder and plays media.",
"author": "Trae",
"authorUrl": "https://github.com/"
}

2249
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

27
package.json Normal file
View file

@ -0,0 +1,27 @@
{
"name": "cross-player",
"version": "1.0.0",
"description": "Media player plugin for Obsidian",
"main": "main.js",
"scripts": {
"dev": "node esbuild.config.mjs",
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production"
},
"keywords": [],
"author": "",
"license": "MIT",
"devDependencies": {
"@types/node": "^16.11.6",
"@typescript-eslint/eslint-plugin": "5.29.0",
"@typescript-eslint/parser": "5.29.0",
"builtin-modules": "3.3.0",
"esbuild": "0.17.3",
"obsidian": "latest",
"tslib": "2.4.0",
"typescript": "4.7.4"
},
"dependencies": {
"@types/sortablejs": "^1.15.9",
"sortablejs": "^1.15.6"
}
}

1300
src/main.ts Normal file

File diff suppressed because it is too large Load diff

38
src/types.ts Normal file
View file

@ -0,0 +1,38 @@
export interface MediaItem {
id: string;
path: string;
name: string;
status: 'pending' | 'playing' | 'completed';
position: number;
duration: number;
size?: number; // in bytes
}
export interface CrossPlayerSettings {
watchedFolder: string;
defaultPlaybackSpeed: number;
seekSecondsForward: number;
seekSecondsBackward: number;
// YouTube Download Settings
youtubeDlpPath: string;
downloadFolder: string;
defaultDownloadQuality: 'best' | '1080p' | '720p' | '480p' | 'audio';
defaultDownloadType: 'video' | 'audio';
maxStorageLimit: number; // in GB
}
export interface DownloadStatus {
id: string;
name: string;
progress: string;
speed: string;
eta: string;
status: 'downloading' | 'completed' | 'error';
error?: string;
}
export interface CrossPlayerData {
settings: CrossPlayerSettings;
queue: MediaItem[];
playbackSpeed: number;
}

66
styles.css Normal file
View file

@ -0,0 +1,66 @@
/* Styles for Cross Player */
.cross-player-list {
padding: 10px;
}
.cross-player-item {
display: flex;
align-items: center;
padding: 8px;
border-bottom: 1px solid var(--background-modifier-border);
transition: background-color 0.1s ease;
}
.cross-player-item:hover {
background-color: var(--background-modifier-hover);
}
.cross-player-status-icon {
margin-right: 10px;
display: flex;
align-items: center;
}
.cross-player-name {
flex-grow: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
font-size: 0.9em;
}
.cross-player-controls {
display: flex;
gap: 4px;
opacity: 0.5;
transition: opacity 0.2s;
}
.cross-player-item:hover .cross-player-controls {
opacity: 1;
}
.clickable-icon {
cursor: pointer;
padding: 2px;
}
.clickable-icon:hover {
color: var(--text-accent);
}
/* Drag and Drop Styles */
.sortable-ghost {
background-color: var(--interactive-accent);
opacity: 0.4;
}
.sortable-handle {
cursor: grab;
}
.sortable-handle:active {
cursor: grabbing;
}

17
tsconfig.json Normal file
View file

@ -0,0 +1,17 @@
{
"compilerOptions": {
"baseUrl": ".",
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "ES6",
"allowJs": true,
"noImplicitAny": true,
"moduleResolution": "node",
"importHelpers": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"lib": ["DOM", "ES5", "ES6", "ES7"]
},
"include": ["**/*.ts"]
}