initial commit
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
# FIX CRLF always when developer has not set
|
||||
# Linux/Mac: git config --global core.autocrlf input
|
||||
# Windows: git config --global core.autocrlf true
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
* eol=lf
|
||||
@@ -0,0 +1,29 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
**/node_modules/**
|
||||
/.pnp
|
||||
.pnp.js
|
||||
.pnp.cjs
|
||||
.pnp.loader.mjs
|
||||
.yarn
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.vscode
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
/junit.xml
|
||||
/.nyc_output/
|
||||
/coverage/
|
||||
/dist/
|
||||
.idea
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"loader": "ts-node/esm",
|
||||
"spec": "src/**/*.test.ts"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Francisco Hodge
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,176 @@
|
||||
# Meta Interface
|
||||
|
||||
Shared TypeScript interfaces and types for the Meta Orbit ecosystem, providing type definitions used across all packages.
|
||||
|
||||
## Overview
|
||||
|
||||
Meta Interface is the foundational package that defines common TypeScript interfaces, types, and constants shared across the entire Meta Orbit monorepo. It has no dependencies and serves as the base layer for type safety.
|
||||
|
||||
## Features
|
||||
|
||||
- **Zero Dependencies**: Foundation package with no external dependencies
|
||||
- **Type Definitions**: Comprehensive TypeScript interfaces for metadata structures
|
||||
- **Shared Constants**: Common enums and constant values
|
||||
- **Platform Agnostic**: Works in both Node.js and browser environments
|
||||
- **Strict Typing**: Enables type safety across all packages
|
||||
|
||||
## Installation
|
||||
|
||||
This package is automatically available in the monorepo workspace:
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@metazla/meta-interface": "workspace:*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```typescript
|
||||
import type {
|
||||
HashMeta,
|
||||
FileMetadata,
|
||||
VideoType,
|
||||
MediaType
|
||||
} from '@metazla/meta-interface';
|
||||
|
||||
// Use interfaces for type safety
|
||||
const metadata: HashMeta = {
|
||||
cid_sha256: 'baejbei...',
|
||||
fileName: 'episode.mkv',
|
||||
sizeByte: '1024000',
|
||||
videoType: 'tvshow',
|
||||
season: '1',
|
||||
episode: '1',
|
||||
titles: { eng: 'Show Name' }
|
||||
};
|
||||
```
|
||||
|
||||
## Key Interfaces
|
||||
|
||||
### HashMeta
|
||||
Complete metadata structure for media files:
|
||||
```typescript
|
||||
interface HashMeta {
|
||||
// Content identifiers
|
||||
cid_sha1?: string;
|
||||
cid_sha256?: string;
|
||||
cid_md5?: string;
|
||||
cid_sha3_256?: string;
|
||||
cid_sha3_384?: string;
|
||||
cid_crc32?: string;
|
||||
|
||||
// File information
|
||||
fileName: string;
|
||||
extension?: string;
|
||||
sizeByte: string;
|
||||
fileType?: MediaType;
|
||||
|
||||
// Video metadata
|
||||
videoType?: VideoType;
|
||||
season?: string;
|
||||
episode?: string;
|
||||
originalTitle?: string;
|
||||
titles?: Record<string, string>;
|
||||
|
||||
// Classification
|
||||
anime?: string;
|
||||
genres?: string[];
|
||||
languages?: string[];
|
||||
tags?: string[];
|
||||
|
||||
// Paths
|
||||
privateFilePath?: string;
|
||||
publicFilePath?: string;
|
||||
}
|
||||
```
|
||||
|
||||
### VideoType
|
||||
```typescript
|
||||
type VideoType = 'movie' | 'tvshow' | 'anime' | 'documentary' | 'unknown';
|
||||
```
|
||||
|
||||
### MediaType
|
||||
```typescript
|
||||
type MediaType = 'video' | 'audio' | 'image' | 'document' | 'unknown';
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
### Build Configuration
|
||||
Built with `tsup` for dual output:
|
||||
- **ESM**: `dist/index.js`
|
||||
- **CommonJS**: `dist/index.cjs`
|
||||
|
||||
### Package Structure
|
||||
```
|
||||
meta-interface/
|
||||
├── src/
|
||||
│ └── lib/
|
||||
│ ├── interfaces.ts # Core interface definitions
|
||||
│ ├── types.ts # Type aliases and unions
|
||||
│ ├── constants.ts # Shared constants
|
||||
│ └── index.ts # Public exports
|
||||
├── package.json
|
||||
└── tsconfig.json
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Building
|
||||
|
||||
```bash
|
||||
# From monorepo root
|
||||
pnpm run build
|
||||
|
||||
# From package directory
|
||||
cd packages/meta-interface
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
```bash
|
||||
cd packages/meta-interface
|
||||
pnpm test
|
||||
```
|
||||
|
||||
Uses Mocha for type validation and interface tests.
|
||||
|
||||
## Used By
|
||||
|
||||
All packages in the monorepo depend on meta-interface:
|
||||
- **meta-hash**: Hash metadata structures
|
||||
- **meta-db**: Database record types
|
||||
- **meta-mesh**: File processing interfaces
|
||||
- **meta-orbit**: Network message types
|
||||
- **meta-ui**: UI component prop types
|
||||
- **filename-tool**: Parsing result types
|
||||
|
||||
## Dependency Flow
|
||||
|
||||
```
|
||||
meta-interface (foundation, no deps)
|
||||
↓
|
||||
All other packages depend on it
|
||||
```
|
||||
|
||||
This ensures:
|
||||
- Consistent types across the entire codebase
|
||||
- Single source of truth for interfaces
|
||||
- Type safety in all inter-package communication
|
||||
|
||||
## Contributing
|
||||
|
||||
When adding new interfaces:
|
||||
1. Add to appropriate file in `src/lib/`
|
||||
2. Export from `src/lib/index.ts`
|
||||
3. Document with JSDoc comments
|
||||
4. Ensure backward compatibility
|
||||
|
||||
This package is part of the Meta Orbit monorepo. See the root README for contribution guidelines.
|
||||
|
||||
## License
|
||||
|
||||
MIT - Same as Meta Orbit monorepo
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "@metazla/meta-interface",
|
||||
"version": "1.0.0",
|
||||
"description": "List of interfaces for the Meta project",
|
||||
"type": "module",
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"dist/index.d.ts": [
|
||||
"dist/index.d.ts"
|
||||
],
|
||||
"*": [
|
||||
"dist/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.js",
|
||||
"require": "./dist/index.cjs"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "cross-env tsc && tsup",
|
||||
"test": "mocha"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.3.11",
|
||||
"@types/mocha": "^10.0.6",
|
||||
"@types/node": "^20.12.2",
|
||||
"chai": "^5.0.3",
|
||||
"cross-env": "^7.0.3",
|
||||
"mocha": "^10.2.0",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsup": "^8.0.2",
|
||||
"typescript": "^5.4.3"
|
||||
}
|
||||
}
|
||||
+1637
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,50 @@
|
||||
import {describe, beforeEach, it} from 'mocha';
|
||||
import {expect} from 'chai';
|
||||
import {from, MetadataNode} from './MetaDataAPI.js';
|
||||
import {VideoMeta} from "./metadata-type/VideoMeta";
|
||||
import {GenreMeta} from "./metadata-type/GenreMeta";
|
||||
|
||||
type TypedMetaData = VideoMeta & GenreMeta;
|
||||
|
||||
describe('MetaData', () => {
|
||||
let root: MetadataNode<TypedMetaData>;
|
||||
let meta = {};
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset meta for each test to ensure no test pollution
|
||||
meta = {};
|
||||
root = from<TypedMetaData>(meta);
|
||||
});
|
||||
|
||||
it('should set and get a simple key-value pair', () => {
|
||||
root.at('originalTitle').set("Star Wars");
|
||||
expect(root.at('originalTitle').get()).to.equal("Star Wars");
|
||||
});
|
||||
|
||||
it('should set and get nested metadata using nested keys', () => {
|
||||
root.at('titles').at('eng').set("Star Wars");
|
||||
root.at('titles').at('jpn').set("Staru Warsu");
|
||||
expect(root.at('titles').at('eng').get()).to.equal("Star Wars");
|
||||
expect(root.at('titles').at('jpn').get()).to.equal("Staru Warsu");
|
||||
expect(root.at('titles').get()).to.deep.equal({eng: "Star Wars", jpn: "Staru Warsu"});
|
||||
expect(root.get()).to.deep.equal({
|
||||
titles: {eng: "Star Wars", jpn: "Staru Warsu"}
|
||||
});
|
||||
});
|
||||
|
||||
it('should return undefined for non-existent keys', () => {
|
||||
expect(root.at<any>('nonexistent').at<any>('nonexistent2').get()).to.equal(undefined);
|
||||
});
|
||||
|
||||
it('should handle overriding existing keys with new values', () => {
|
||||
root.at('genres').add("Sci-fi");
|
||||
expect(root.at('genres').getKeysAsSet()).to.deep.equal(new Set(["Sci-fi"]));
|
||||
// Override the value
|
||||
root.at('genres').add("Adventure");
|
||||
expect(root.at('genres').getKeysAsSet()).to.deep.equal(new Set(['Sci-fi', 'Adventure']));
|
||||
root.at('genres').add("Sci-fi");
|
||||
expect(root.at('genres').getKeysAsSet()).to.deep.equal(new Set(['Sci-fi', 'Adventure']));
|
||||
//root.at('genres').remove('Sci-fi');
|
||||
//expect(root.at('genres').getKeys()).to.deep.equal(new Set(['Adventure']));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,115 @@
|
||||
export function from<T>(metadata: T): MetadataNode<T> {
|
||||
return new MetadataNode<T>([], metadata);
|
||||
}
|
||||
|
||||
export class MetadataNode<T> {
|
||||
constructor(private path: string[], private rootData: any, private replacementRule?: (oldValue: T, newValue: T) => T) {
|
||||
this.replacementRule = replacementRule || ((oldValue: T, newValue: T) => {
|
||||
console.warn(`Key ${path.join('.')} already exists and no replacement rule defined (default to taking the new one).
|
||||
Current value: ${oldValue}
|
||||
New value: ${newValue}`);
|
||||
return newValue;
|
||||
});
|
||||
}
|
||||
|
||||
// Navigate to a subnode without ensuring it exists for further operations
|
||||
at<K extends keyof T>(key: K): MetadataNode<T[K]> {
|
||||
if (!key) {
|
||||
throw new Error('Key is required');
|
||||
}
|
||||
const newPath = [...this.path, key as string];
|
||||
return new MetadataNode<T[K]>(newPath, this.rootData);
|
||||
}
|
||||
|
||||
// Set the value at the current node, ensuring the path exists
|
||||
set(value: T): void {
|
||||
if (value === undefined || value === null) {
|
||||
//we don't want to set undefined or null values
|
||||
return;
|
||||
}
|
||||
const current = this.ensurePath(true);
|
||||
if (this.path.length > 0) {
|
||||
const lastKey = this.path[this.path.length - 1];
|
||||
if (current[lastKey]) {
|
||||
if (current[lastKey] === value) {
|
||||
return;
|
||||
}
|
||||
current[lastKey] = this.replacementRule(current[lastKey], value);
|
||||
} else {
|
||||
current[lastKey] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the value at the current node
|
||||
get(defaultValue?: T): T {
|
||||
const current = this.ensurePath(false);
|
||||
return current === undefined ? defaultValue : current;
|
||||
}
|
||||
|
||||
// this is used to define set of values
|
||||
add(key: string): void {
|
||||
if (key === undefined || key === null) {
|
||||
//we don't want to set undefined or null values
|
||||
return;
|
||||
}
|
||||
let node = this.get();
|
||||
if (node && node instanceof Set) {
|
||||
const set = node as Set<string>;
|
||||
if (set.has(key)) {
|
||||
return;
|
||||
} else {
|
||||
set.add(key);
|
||||
}
|
||||
} else {
|
||||
this.set(new Set([key]) as any);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove a key from the node
|
||||
/*remove<K extends keyof T>(key: K|string): void {
|
||||
const current = this.ensurePath(false);
|
||||
if (current && current[key] !== undefined) {
|
||||
delete current[key];
|
||||
}
|
||||
}*/
|
||||
|
||||
// Get all keys at the current node
|
||||
getKeysAsSet(): Set<string> {
|
||||
const current = this.ensurePath(false);
|
||||
if(current instanceof Set){
|
||||
return current as Set<string>;
|
||||
}else {
|
||||
return new Set(current ? Object.keys(current) as Array<string> : []);
|
||||
}
|
||||
}
|
||||
|
||||
getKeysAsArray(): string[] {
|
||||
const current = this.ensurePath(false);
|
||||
if(!current){
|
||||
return [];
|
||||
}
|
||||
if(current instanceof Set){
|
||||
return Array.from(current as Set<string>);
|
||||
}else {
|
||||
return Object.keys(current);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private ensurePath(createPath: boolean): any {
|
||||
let current = this.rootData;
|
||||
const path = createPath ? this.path.slice(0, -1) : this.path;
|
||||
for (const segment of path) {
|
||||
if (current[segment] === undefined) {
|
||||
if (createPath) {
|
||||
current[segment] = {};
|
||||
} else {
|
||||
return undefined; // Return undefined early if the path segment doesn't exist and we're not creating it
|
||||
}
|
||||
}
|
||||
current = current[segment];
|
||||
}
|
||||
return current;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
export const FileMetaDataName = [
|
||||
"fileType",
|
||||
"mimeType",
|
||||
"byteSize",
|
||||
]
|
||||
|
||||
export const hashMetaDataName = [
|
||||
"cid_crc32",
|
||||
"cid_md5",
|
||||
"cid_sha1",
|
||||
"cid_sha2-256",
|
||||
"cid_sha3-256",
|
||||
"cid_sha3_384",
|
||||
];
|
||||
|
||||
export const AnimeMetaData = [
|
||||
"anime"
|
||||
];
|
||||
|
||||
export const FFMpegMetaData = [
|
||||
"fileinfo"
|
||||
];
|
||||
|
||||
export const FileNameMetaData = [
|
||||
"fileName",
|
||||
"extension",
|
||||
"videoType",
|
||||
"extra",
|
||||
"season",
|
||||
"episode",
|
||||
"increment",
|
||||
"movieYear",
|
||||
"title",
|
||||
"titles",
|
||||
];
|
||||
|
||||
export const TorrentMetaData = [
|
||||
"trakers"
|
||||
];
|
||||
|
||||
export const VideoMetaData = [
|
||||
"subtitles"
|
||||
];
|
||||
|
||||
export const JellyfinMetaData = [
|
||||
"videoType", // Noted as optional and with specific types in your comment, but listed as a simple string here
|
||||
"episode",
|
||||
"season",
|
||||
"title",
|
||||
"year",
|
||||
"originaltitle",
|
||||
"imdbid",
|
||||
"tmdbid",
|
||||
"anidbid",
|
||||
"premiered",
|
||||
"genre",
|
||||
"releasedate",
|
||||
"plot",
|
||||
"director",
|
||||
"rating",
|
||||
"runtime",
|
||||
"studio",
|
||||
"art",
|
||||
"actor",
|
||||
"showtitle",
|
||||
"aired",
|
||||
"customrating",
|
||||
"dateadded",
|
||||
"sorttitle",
|
||||
"mpaa",
|
||||
"aspectratio",
|
||||
"collectionnumber",
|
||||
"criticrating",
|
||||
];
|
||||
@@ -0,0 +1 @@
|
||||
create a lib for that
|
||||
@@ -0,0 +1,26 @@
|
||||
export * from './MetaDataAPI';
|
||||
export * from './MetaDataName';
|
||||
|
||||
export * from './metadata-type/basic/FileRef';
|
||||
export * from './metadata-type/basic/LanguageData';
|
||||
export * from './metadata-type/basic/RecordSet';
|
||||
export * from './metadata-type/basic/SimpleFileType';
|
||||
export * from './metadata-type/basic/StringBoolean';
|
||||
export * from './metadata-type/basic/VideoType';
|
||||
export * from "./metadata-type/basic/ArrayKey";
|
||||
|
||||
export * from './metadata-type/AnimeMeta';
|
||||
export * from './metadata-type/DebugMeta';
|
||||
export * from './metadata-type/FileNameMeta';
|
||||
export * from './metadata-type/FileStatMeta';
|
||||
export * from './metadata-type/GenreMeta';
|
||||
export * from './metadata-type/HashMeta';
|
||||
export * from './metadata-type/JellyfinMeta';
|
||||
export * from './metadata-type/LanguagesMeta';
|
||||
export * from './metadata-type/MediaStreamMeta';
|
||||
export * from './metadata-type/SubtitleMeta';
|
||||
export * from './metadata-type/TagsMeta';
|
||||
export * from './metadata-type/TorrentMeta';
|
||||
export * from './metadata-type/VideoMeta';
|
||||
export * from './metadata-type/VersionMeta';
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import {StringBoolean} from "./basic/StringBoolean.js";
|
||||
|
||||
export interface AnimeMeta {
|
||||
anime?: StringBoolean;
|
||||
}
|
||||
|
||||
export const AnimeMetaFields = [
|
||||
"anime",
|
||||
];
|
||||
@@ -0,0 +1,7 @@
|
||||
export interface DebugMeta {
|
||||
privateFilePath?: string;
|
||||
}
|
||||
|
||||
export const DebugMetaFields = [
|
||||
"privateFilePath",
|
||||
];
|
||||
@@ -0,0 +1,9 @@
|
||||
export interface FileNameMeta {
|
||||
fileName?: string;
|
||||
extension?: string;
|
||||
}
|
||||
|
||||
export const FileNameMetaFields = [
|
||||
"fileName",
|
||||
"extension",
|
||||
];
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
export interface FileStatMeta {
|
||||
fileType?:string;
|
||||
mimeType?:string;
|
||||
sizeByte?:string;
|
||||
}
|
||||
|
||||
export const FileStatMetaFields = [
|
||||
"fileType",
|
||||
"mimeType",
|
||||
"sizeByte",
|
||||
];
|
||||
@@ -0,0 +1,9 @@
|
||||
import {RecordSet} from "./basic/RecordSet.js";
|
||||
|
||||
export interface GenreMeta{
|
||||
genres?: RecordSet;
|
||||
}
|
||||
|
||||
export const GenreMetaFields = [
|
||||
"genres",
|
||||
];
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* HashMeta - Content identification hashes
|
||||
*
|
||||
* Primary Global ID: cid_midhash256 (SHA-256 hash of middle 1MB + file size)
|
||||
* - Format: CID v1 with custom multicodec 0x1000
|
||||
* - Example: bafkr4ih5kapbjzqvmj7jxr... (base32 CID encoding)
|
||||
*
|
||||
* Legacy IDs: cid_sha2-256, cid_sha1 (computed optionally for compatibility)
|
||||
*
|
||||
* Migration Note: cid_midhash256 is the new primary identifier replacing full SHA-256.
|
||||
* Old hashes remain for backward compatibility and external system integration.
|
||||
* All CIDs now use proper CID v1 format (IPFS-compatible structure).
|
||||
*/
|
||||
export interface HashMeta {
|
||||
cid_crc32?: string; //0x0132 CRC32 (SFV)
|
||||
cid_md5?: string; // 0xd5 md5
|
||||
cid_sha1?: string; // 0x11 sha1
|
||||
"cid_sha2-256"?: string;//0x12 sha2-256
|
||||
"cid_sha3-256"?: string; // 0x16 sha3-256
|
||||
"cid_sha3_384"?: string; // 0x16 sha3-256
|
||||
cid_midhash256?: string; // 0x1000 midhash256 (CID v1 format with custom multicodec)
|
||||
}
|
||||
|
||||
export const HashMetaFields = [
|
||||
"cid_crc32",
|
||||
"cid_md5",
|
||||
"cid_sha1",
|
||||
"cid_sha2-256",
|
||||
"cid_sha3-256",
|
||||
"cid_sha3_384",
|
||||
"cid_midhash256",
|
||||
];
|
||||
@@ -0,0 +1,64 @@
|
||||
import {LanguageData} from "./basic/LanguageData.js";
|
||||
import {RecordSet} from "./basic/RecordSet.js";
|
||||
import {VideoMeta} from "./VideoMeta.js";
|
||||
import {TagsMeta} from "./TagsMeta.js";
|
||||
import {LanguagesMeta} from "./LanguagesMeta.js";
|
||||
import {GenreMeta} from "./GenreMeta.js";
|
||||
import {FileRef} from "./basic/FileRef";
|
||||
|
||||
export interface IMDBMeta{
|
||||
imdbid?: string;
|
||||
criticrating?: string;
|
||||
}
|
||||
|
||||
export interface TMDBMeta{
|
||||
tmdbid?: string;
|
||||
}
|
||||
|
||||
export interface AnidbMeta{
|
||||
anidbid?: string;
|
||||
}
|
||||
|
||||
export interface JellyfinMeta extends
|
||||
IMDBMeta,
|
||||
TMDBMeta,
|
||||
AnidbMeta,
|
||||
VideoMeta,
|
||||
TagsMeta,
|
||||
LanguagesMeta,
|
||||
GenreMeta
|
||||
{
|
||||
releasedate?: string;
|
||||
plot?: LanguageData<string>;//key is language ISO 639-1 code
|
||||
rating?: string;
|
||||
studio?: RecordSet;
|
||||
art?:{
|
||||
poster?: FileRef;
|
||||
fanart?: FileRef;
|
||||
};
|
||||
mpaa?: string;
|
||||
//TODO add more fields in the future
|
||||
}
|
||||
|
||||
export const JellyfinMetaFields = [
|
||||
"imdbid",
|
||||
"tmdbid",
|
||||
"anidbid",
|
||||
"extra",
|
||||
"season",
|
||||
"episode",
|
||||
"increment",
|
||||
"movieYear",
|
||||
"videoType",
|
||||
"originalTitle",
|
||||
"titles",
|
||||
"tags",
|
||||
"languages",
|
||||
"genre",
|
||||
"releasedate",
|
||||
"plot",
|
||||
"rating",
|
||||
"studio",
|
||||
"art",
|
||||
"mpaa",
|
||||
];
|
||||
@@ -0,0 +1,10 @@
|
||||
import {TypedRecordSet} from "./basic/RecordSet.js";
|
||||
import {ISO639_1_CODE} from "./basic/LanguageData.js";
|
||||
|
||||
export interface LanguagesMeta{
|
||||
languages?: TypedRecordSet<ISO639_1_CODE>;
|
||||
}
|
||||
|
||||
export const LanguagesMetaFields = [
|
||||
"languages",
|
||||
];
|
||||
@@ -0,0 +1,59 @@
|
||||
import {StringBoolean} from "./basic/StringBoolean.js";
|
||||
import {ArrayKey} from "./basic/ArrayKey";
|
||||
|
||||
export interface VideoStream {
|
||||
width?: string;
|
||||
height?: string;
|
||||
bitrate?: string;
|
||||
frameRate?: string;
|
||||
rotation?: string;
|
||||
language?: string;
|
||||
}
|
||||
|
||||
export interface SubtitleStream {
|
||||
language?: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export interface AudioStream {
|
||||
sampleRate?: string;
|
||||
bitrate?: string;
|
||||
language?: string;
|
||||
channelLayout?: string;
|
||||
}
|
||||
|
||||
export interface CommonStream {
|
||||
index?: string;
|
||||
duration?: string;
|
||||
codecType?: string;
|
||||
codec?: string;
|
||||
language?: string;
|
||||
title?: string;
|
||||
default?: StringBoolean;
|
||||
forced?: StringBoolean;
|
||||
}
|
||||
|
||||
export type Stream = VideoStream & SubtitleStream & AudioStream & CommonStream;
|
||||
|
||||
/**
|
||||
* StreamList is a list of streams
|
||||
* key is stream index in string "0","1","2" etc
|
||||
*/
|
||||
export type StreamList = Record<ArrayKey,Stream>;
|
||||
|
||||
export interface MediaStreamMeta {
|
||||
fileinfo?: {
|
||||
duration?: string;
|
||||
formatName?: string;
|
||||
streamdetails?: {
|
||||
video: StreamList;
|
||||
audio: StreamList;
|
||||
subtitle: StreamList;
|
||||
embeddedimage: StreamList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const MediaStreamMetaFields = [
|
||||
"fileinfo",
|
||||
];
|
||||
@@ -0,0 +1,23 @@
|
||||
import {LanguageData} from "./basic/LanguageData.js";
|
||||
import {TypedRecordSet} from "./basic/RecordSet.js";
|
||||
import {FileRef} from "./basic/FileRef.js";
|
||||
|
||||
//used by video files to store the subtitle files
|
||||
export interface SubtitleMeta {
|
||||
subtitles?:LanguageData<TypedRecordSet<FileRef>>;//key is the language code, value is a set of ipfs hash of the subtitle file
|
||||
}
|
||||
|
||||
//used by subtitle files to store the video files
|
||||
export interface SubtitleFileMeta {
|
||||
videos?:TypedRecordSet<FileRef>;//a set of ipfs hash of the video file
|
||||
subtitleLanguage?:string;//the language of the subtitle file
|
||||
}
|
||||
|
||||
export const SubtitleMetaFields = [
|
||||
"subtitles",
|
||||
];
|
||||
|
||||
export const SubtitleFileMetaFields = [
|
||||
"videos",
|
||||
"subtitleLanguage",
|
||||
];
|
||||
@@ -0,0 +1,9 @@
|
||||
import {RecordSet} from "./basic/RecordSet.js";
|
||||
|
||||
export interface TagsMeta {
|
||||
tags?: RecordSet;
|
||||
}
|
||||
|
||||
export const TagsMetaFields = [
|
||||
"tags",
|
||||
];
|
||||
@@ -0,0 +1,25 @@
|
||||
import {RecordSet} from "./basic/RecordSet.js";
|
||||
|
||||
export interface TorrentMeta {
|
||||
announce?: string;
|
||||
announceList?: RecordSet;
|
||||
comment?: string;
|
||||
createdBy?: string;
|
||||
creationDate?: number;
|
||||
info: {
|
||||
files: Record<string, {
|
||||
length: number;
|
||||
path: string;
|
||||
}>;// key is the "0" "1" "2" etc
|
||||
name: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const TorrentMetaFields = [
|
||||
"announce",
|
||||
"announceList",
|
||||
"comment",
|
||||
"createdBy",
|
||||
"creationDate",
|
||||
"info",
|
||||
];
|
||||
@@ -0,0 +1,7 @@
|
||||
export interface VersionMeta {
|
||||
version: string; //usually a V1 V2 V3 etc..
|
||||
}
|
||||
|
||||
export const VersionMetaFields = [
|
||||
"version"
|
||||
];
|
||||
@@ -0,0 +1,24 @@
|
||||
import {LanguageData} from "./basic/LanguageData.js";
|
||||
import {VideoType} from "./basic/VideoType";
|
||||
|
||||
export interface VideoMeta {
|
||||
extra?: string;
|
||||
season?: string;
|
||||
episode?: string;
|
||||
increment?: string;
|
||||
movieYear?: string;
|
||||
videoType?: VideoType;
|
||||
originalTitle?: string;//title in original language
|
||||
titles?: LanguageData<string>;// <ISO 639-3 lang codes, title>
|
||||
}
|
||||
|
||||
export const VideoMetaFields = [
|
||||
"extra",
|
||||
"season",
|
||||
"episode",
|
||||
"increment",
|
||||
"movieYear",
|
||||
"videoType",
|
||||
"originalTitle",
|
||||
"titles",
|
||||
];
|
||||
@@ -0,0 +1,6 @@
|
||||
// used to simulate array using map and object
|
||||
export type ArrayKey = "id_0" | "id_1" | "id_2" | "id_3" | "id_4" | "id_5" | "id_6" | "id_7" | "id_8" | "id_9";
|
||||
|
||||
export function createArrayKey (index: number): ArrayKey {
|
||||
return `id_${index}` as ArrayKey;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export type FileRef = URLString | FilePathString | CIDString;
|
||||
export type URLString = string;
|
||||
export type FilePathString = string;
|
||||
export type CIDString = string;
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* key is language ISO 639-3 code
|
||||
* https://en.wikipedia.org/wiki/List_of_ISO_639-3_codes
|
||||
*/
|
||||
export type LanguageData<T> = Record<string, T>;
|
||||
export type ISO639_1_CODE = string;
|
||||
|
||||
/**
|
||||
* jpn, jpr and jpa already exist. Creating jpl is for japan-latin. Used for japanese romaji NON ISO 639-3 standard.
|
||||
* */
|
||||
export const romajiIsoCode = "jpl";
|
||||
export const englishIsoCode = "eng";
|
||||
@@ -0,0 +1,2 @@
|
||||
export type RecordSet = Set<string>;
|
||||
export type TypedRecordSet<T extends string> = Set<T>;
|
||||
@@ -0,0 +1,2 @@
|
||||
export type SimpleFileType = 'audio' | 'video' | 'document' | 'archive' | 'other' | 'undefined';
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export type StringBoolean = "true" | "false";
|
||||
@@ -0,0 +1 @@
|
||||
export type VideoType = "movie" | "tvshow";
|
||||
@@ -0,0 +1,14 @@
|
||||
<!-- Example XSD: mediaFileSchema.xsd -->
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.com/schema" xmlns="http://www.example.com/schema" elementFormDefault="qualified">
|
||||
|
||||
<xs:element name="root">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="fileType" type="xs:string"/>
|
||||
<xs:element name="mimeType" type="xs:string"/>
|
||||
<xs:element name="byteSize" type="xs:long"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
</xs:schema>
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noImplicitAny": false,
|
||||
"module": "esnext",
|
||||
"target": "esnext",
|
||||
"allowJs": true,
|
||||
"sourceMap": true,
|
||||
"esModuleInterop":true,
|
||||
"skipLibCheck": true,
|
||||
"noEmit": true,
|
||||
"moduleResolution": "node",
|
||||
"baseUrl": "./",
|
||||
},
|
||||
"include": [
|
||||
"src/lib"
|
||||
],
|
||||
"exclude": ["node_modules/**"]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import {defineConfig} from 'tsup'
|
||||
|
||||
export default defineConfig({
|
||||
entry: {
|
||||
'index': 'src/lib/index.ts',
|
||||
},
|
||||
outDir: 'dist',
|
||||
splitting: true,
|
||||
treeshake: true,
|
||||
sourcemap: true,
|
||||
clean: true,
|
||||
dts:true,
|
||||
minify:false,
|
||||
format: ['cjs', 'esm'],
|
||||
})
|
||||
Reference in New Issue
Block a user