add kodi api web interface

This commit is contained in:
Jurgis Sakalauskas
2023-01-04 09:13:06 +02:00
parent 9cf70326af
commit 8c900a774e
8 changed files with 555 additions and 8 deletions
+230
View File
@@ -33,6 +33,7 @@
"@types/supertest": "^2.0.11", "@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0", "@typescript-eslint/parser": "^5.0.0",
"copyfiles": "^2.4.1",
"eslint": "^8.0.1", "eslint": "^8.0.1",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
@@ -3664,6 +3665,75 @@
"integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==", "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==",
"dev": true "dev": true
}, },
"node_modules/copyfiles": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz",
"integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==",
"dev": true,
"dependencies": {
"glob": "^7.0.5",
"minimatch": "^3.0.3",
"mkdirp": "^1.0.4",
"noms": "0.0.0",
"through2": "^2.0.1",
"untildify": "^4.0.0",
"yargs": "^16.1.0"
},
"bin": {
"copyfiles": "copyfiles",
"copyup": "copyfiles"
}
},
"node_modules/copyfiles/node_modules/cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
"dev": true,
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^7.0.0"
}
},
"node_modules/copyfiles/node_modules/mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"dev": true,
"bin": {
"mkdirp": "bin/cmd.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/copyfiles/node_modules/yargs": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"dev": true,
"dependencies": {
"cliui": "^7.0.2",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
},
"engines": {
"node": ">=10"
}
},
"node_modules/copyfiles/node_modules/yargs-parser": {
"version": "20.2.9",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"dev": true,
"engines": {
"node": ">=10"
}
},
"node_modules/core-util-is": { "node_modules/core-util-is": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
@@ -7012,6 +7082,40 @@
"integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
"dev": true "dev": true
}, },
"node_modules/noms": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz",
"integrity": "sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==",
"dev": true,
"dependencies": {
"inherits": "^2.0.1",
"readable-stream": "~1.0.31"
}
},
"node_modules/noms/node_modules/isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==",
"dev": true
},
"node_modules/noms/node_modules/readable-stream": {
"version": "1.0.34",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==",
"dev": true,
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
}
},
"node_modules/noms/node_modules/string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==",
"dev": true
},
"node_modules/nopt": { "node_modules/nopt": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
@@ -8648,6 +8752,16 @@
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
"dev": true "dev": true
}, },
"node_modules/through2": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
"integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
"dev": true,
"dependencies": {
"readable-stream": "~2.3.6",
"xtend": "~4.0.1"
}
},
"node_modules/tmp": { "node_modules/tmp": {
"version": "0.0.33", "version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -9171,6 +9285,15 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/untildify": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
"integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/update-browserslist-db": { "node_modules/update-browserslist-db": {
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
@@ -12361,6 +12484,61 @@
"integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==", "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==",
"dev": true "dev": true
}, },
"copyfiles": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz",
"integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==",
"dev": true,
"requires": {
"glob": "^7.0.5",
"minimatch": "^3.0.3",
"mkdirp": "^1.0.4",
"noms": "0.0.0",
"through2": "^2.0.1",
"untildify": "^4.0.0",
"yargs": "^16.1.0"
},
"dependencies": {
"cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
"dev": true,
"requires": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^7.0.0"
}
},
"mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"dev": true
},
"yargs": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"dev": true,
"requires": {
"cliui": "^7.0.2",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
}
},
"yargs-parser": {
"version": "20.2.9",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"dev": true
}
}
},
"core-util-is": { "core-util-is": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
@@ -14888,6 +15066,42 @@
"integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
"dev": true "dev": true
}, },
"noms": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz",
"integrity": "sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==",
"dev": true,
"requires": {
"inherits": "^2.0.1",
"readable-stream": "~1.0.31"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==",
"dev": true
},
"readable-stream": {
"version": "1.0.34",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
}
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==",
"dev": true
}
}
},
"nopt": { "nopt": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
@@ -16082,6 +16296,16 @@
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
"dev": true "dev": true
}, },
"through2": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
"integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
"dev": true,
"requires": {
"readable-stream": "~2.3.6",
"xtend": "~4.0.1"
}
},
"tmp": { "tmp": {
"version": "0.0.33", "version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -16377,6 +16601,12 @@
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
}, },
"untildify": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
"integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==",
"dev": true
},
"update-browserslist-db": { "update-browserslist-db": {
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
+4 -2
View File
@@ -7,7 +7,7 @@
"license": "UNLICENSED", "license": "UNLICENSED",
"scripts": { "scripts": {
"prebuild": "rimraf dist", "prebuild": "rimraf dist",
"build": "nest build", "build": "nest build && npm run copy-files",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start", "start": "nest start",
"start:dev": "nest start --watch", "start:dev": "nest start --watch",
@@ -23,7 +23,8 @@
"typeorm:run-migrations": "npm run typeorm migration:run -- -d ./src/config/type-orm-migrations.config.ts", "typeorm:run-migrations": "npm run typeorm migration:run -- -d ./src/config/type-orm-migrations.config.ts",
"typeorm:generate-migration": "npm run typeorm -- -d ./src/config/type-orm-migrations.config.ts migration:generate ./migrations/$npm_config_name", "typeorm:generate-migration": "npm run typeorm -- -d ./src/config/type-orm-migrations.config.ts migration:generate ./migrations/$npm_config_name",
"typeorm:create-migration": "npm run typeorm -- migration:create ./migrations/$npm_config_name", "typeorm:create-migration": "npm run typeorm -- migration:create ./migrations/$npm_config_name",
"typeorm:revert-migration": "npm run typeorm -- -d ./src/config/type-orm-migrations.config.ts migration:revert" "typeorm:revert-migration": "npm run typeorm -- -d ./src/config/type-orm-migrations.config.ts migration:revert",
"copy-files": "copyfiles -u 1 src/**/*.html dist/src/"
}, },
"dependencies": { "dependencies": {
"@nestjs/axios": "^1.0.0", "@nestjs/axios": "^1.0.0",
@@ -50,6 +51,7 @@
"@types/supertest": "^2.0.11", "@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0", "@typescript-eslint/parser": "^5.0.0",
"copyfiles": "^2.4.1",
"eslint": "^8.0.1", "eslint": "^8.0.1",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
@@ -24,7 +24,6 @@ export class LrtApiSearchClient {
const resp = await firstValueFrom(this.httpService.get(url)); const resp = await firstValueFrom(this.httpService.get(url));
const searchResponse: SearchResponseInterface = resp.data; const searchResponse: SearchResponseInterface = resp.data;
const cats = [];
const loadedCategories = new Set(); const loadedCategories = new Set();
//todo - move to mapper //todo - move to mapper
@@ -34,9 +33,6 @@ export class LrtApiSearchClient {
); );
for (const searchItem of searchResponse.items) { for (const searchItem of searchResponse.items) {
if (cats.indexOf(searchItem.category_title) > -1) {
continue;
}
if (loadedCategories.has(searchItem.category_title)) { if (loadedCategories.has(searchItem.category_title)) {
continue; continue;
} }
@@ -49,7 +45,6 @@ export class LrtApiSearchClient {
searchItem.img_path_postfix; searchItem.img_path_postfix;
itemDto.categoryId = await this.findCategoryId(searchItem.category_url); itemDto.categoryId = await this.findCategoryId(searchItem.category_url);
cats.push(searchItem.category_title);
loadedCategories.add(searchItem.category_title); loadedCategories.add(searchItem.category_title);
responseDto.addItem(itemDto); responseDto.addItem(itemDto);
} }
@@ -69,7 +64,7 @@ export class LrtApiSearchClient {
const cat = new LrtCategory(); const cat = new LrtCategory();
cat.categoryUrl = categoryUrl; cat.categoryUrl = categoryUrl;
cat.categoryId = catId; cat.categoryId = catId;
this.lrtCategoriesRepository.save(cat); this.lrtCategoriesRepository.save(cat).then();
} }
private async findCategoryIdInDb( private async findCategoryIdInDb(
+291
View File
@@ -0,0 +1,291 @@
<html lang="lt">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css">
<title>kodi api test interface</title>
</head>
<body>
<!-- Modal -->
<div class="modal fade" id="modal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalLabel">OK</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div id="modalBody" class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">OK</button>
</div>
</div>
</div>
</div>
<div class="container">
<h2>Welcome</h2>
<input class="form-check-input" type="checkbox" value="" id="chkDebug">
<label class="form-check-label" for="chkDebug">
Debug
</label>
<div class="input-group mb-3">
<label for="endpoint"></label><input type="text" class="form-control" value="/../api" id="endpoint">
<button class="btn btn-outline-secondary" type="button" id="ok" onClick="okClicked()">OK</button>
</div>
<label for="path"></label><input type="text" class="form-control" id="path">
</div>
<div class="container">
<strong>Category:</strong> <span id="cat"></span>
<strong>Content:</strong> <span id="cont"></span>
</div>
<div class="container" id="content">
<div class="list-group" id="list">
<button type="button" class="list-group-item list-group-item-action" disabled>Nothing here</button>
</div>
<div id="video"></div>
</div>
<div id="debug">
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
crossorigin="anonymous"></script>
<script>
let paths = [""];
function okClicked() {
let path = document.getElementById("endpoint").value;
paths = [""];
loadApiPath(path);
}
function loadApiPath(path) {
$.ajax({
url: path,
success: function(result) {
$("#path").val(path);
if ($("#chkDebug")[0].checked) {
$("#debug").html("<pre>" + JSON.stringify(result, null, " ") + "</pre>");
} else {
$("#debug").html("");
}
processApiResult(result);
}
});
}
function processApiResult(result) {
if (!result) return; //todo error
if (result.msgBoxOK) {
$("#modalBody").text(result.msgBoxOK);
$("#modal").modal("show");
}
if (result.notification) {
$("#modalBody").text(result.notification);
$("#modal").modal("show");
}
if (result.play) {
//play
console.log("play, got from api " + result.play);
genPlayer(result.play);
$("#path").val(result.play);
return;
}
if (result.updateList) {
updateList(result);
return;
}
if (result.content) {
$("#cont").text(result.content);
}
if (result.category) {
$("#cat").text(result.category);
}
}
function updateList(result) {
let contentElement = $("#cont");
contentElement.text("");
if (result.content) {
contentElement.text(result.content);
}
let titleElement = $("#cat");
titleElement.text("");
if (result.category) {
titleElement.text(result.category);
}
if (result.items) {
if (!result.nosort) {
result.items.sort(function(a, b) {
let lbA = a.label;
let lbB = b.label;
let the1 = new RegExp("(the.)", "gi");
let the2 = new RegExp("(the)", "gi");
lbA = lbA.replace(the1, "");
lbA = lbA.replace(the2, "");
lbB = lbB.replace(the1, "");
lbB = lbB.replace(the2, "");
return lbA > lbB ? 1 : -1;
});
}
let itemsHtml = "<div class=\"list-group\" id=\"list\">";
let itemIcon = "";
if (paths.length > 1) {
let itemHtml = "<button type=\"button\" class=\"list-group-item list-group-item-action\"";
itemHtml = itemHtml + " data-path=\"..\"";
itemHtml = itemHtml + " data-folder=\"true\"";
itemHtml = itemHtml + ">";
itemIcon = "<i class=\"bi-folder\"></i>";
itemHtml = itemHtml + itemIcon + " ..</button>";
itemsHtml = itemsHtml + itemHtml;
}
for (let i = 0; i < result.items.length; i++) {
let item = result.items[i];
let itemHtml = "<button type=\"button\" class=\"list-group-item list-group-item-action\"";
itemHtml = itemHtml + " data-path=\"" + item.path + "\"";
if (item.searchFor) {
itemHtml = itemHtml + " data-searchfor=\"" + item.searchFor + "\"";
}
itemHtml = itemHtml + " data-playable=\"" + (item.IsPlayable || item.mediatype === "video") + "\"";
itemHtml = itemHtml + " data-folder=\"" + (item.isFolder) + "\"";
itemIcon = item.isFolder ? "<i class=\"bi-folder\"></i>" : "<i class=\"bi-film\"></i>";
if (item.action) {
if (!item.IsPlayable) {
itemIcon = item.action === "search" ? "<i class=\"bi-search\"></i>" : "<i class=\"bi-gear\"></i>";
}
itemHtml = itemHtml + " data-action=\"" + item.action + "\"";
}
itemHtml = itemHtml + ">";
itemHtml = itemHtml + itemIcon + " " + item.label + (item.plot ? "<div class=\"fw-lighter\">" + item.plot + "</div>" : "") + "</button>";
itemsHtml = itemsHtml + itemHtml;
}
itemsHtml = itemsHtml + "</div>";
$("#content").html(itemsHtml);
}
}
$(document).click("button", function(e) {
//todo - disable navigation after click
let path = $(e.target).data("path");
let folder = $(e.target).data("folder");
let playable = $(e.target).data("playable");
let action = $(e.target).data("action");
let searchFor = $(e.target).data("searchfor");
let endpoint = document.getElementById("endpoint").value;
if (folder && path) {
//navigate?
if (path === ".." || path === ".") {
if (paths.length > 1 && path === "..") {
paths.pop();
}
path = paths[paths.length - 1];
} else {
paths.push(path);
}
loadApiPath(endpoint + "?path=" + path);
return;
}
if (playable && path) {
if (action && action === "query") {
//get path from api
console.log("play, get path from api " + path);
loadApiPath(endpoint + "?path=" + path);
return;
}
//if http included - play directly, if not - play from server
console.log("play " + path);
genPlayer(path);
return;
}
if (action && action === "search") {
let iSearchFor = searchFor ? searchFor : "";
let searchText = prompt("What are you searching for?", iSearchFor);
if (searchText) {
paths.push(path + "&search=" + searchText);
loadApiPath(endpoint + "?path=" + path + "&search=" + searchText);
}
}
});
let videoPlayer;
function genPlayer(urlPath) {
let itemsHtml = "<div class=\"list-group\" id=\"list\">";
let itemHtml = "<button type=\"button\" class=\"list-group-item list-group-item-action\"";
itemHtml = itemHtml + " data-path=\".\"";
itemHtml = itemHtml + " data-folder=\"true\"";
itemHtml = itemHtml + ">";
let itemIcon = "<i class=\"bi-folder\"></i>";
itemHtml = itemHtml + itemIcon + " Back</button>";
itemsHtml = itemsHtml + itemHtml;
itemsHtml = itemsHtml + "</div>";
$("#path").val("http://sklk.lt:8181" + urlPath);
let contentElement = $("#content");
// if (type) {
// contentElement.html(itemsHtml + "<video width=\"100%\" controls><source src=\"" + urlPath + "\" type=\"" + type + "\"></video>");
// return;
// }
//
contentElement.html(itemsHtml + "<video width=\"100%\" controls><source src=\"" + urlPath + "\"></video>");
// $.ajax(urlPath, {
// method: 'HEAD',
// success: (a, b, c) => {
// let contentType = c.getResponseHeader('content-type')
// if (contentType) {
// let videoElementHtml = "<video width=\"100%\" controls><source src=\"" + urlPath + "\" type=\"" + contentType + "\"></video>";
// contentElement.html(itemsHtml + videoElementHtml);
// } else {
// contentElement.html(itemsHtml + "<video width=\"100%\" controls><source src=\"" + urlPath + "\"></video>");
// }
// }
// })
}
</script>
</body>
</html>
@@ -0,0 +1,14 @@
import { Controller, Get, Header, Res } from '@nestjs/common';
import { join } from 'path';
import { createReadStream } from 'fs';
import { Response } from 'express';
@Controller('if')
export class KodiApiInterfaceController {
@Get()
@Header('content-type', 'text/html')
async main(@Res() res: Response) {
const readable = createReadStream(join(__dirname, './View/if.html'));
readable.pipe(res);
}
}
@@ -0,0 +1,12 @@
import { Module } from '@nestjs/common';
import { KodiApiInterfaceController } from './kodi-api-interface.controller';
/**
* Playground module for playing around
*/
@Module({
imports: [],
controllers: [KodiApiInterfaceController],
providers: [],
})
export class KodiApiInterfaceModule {}
@@ -15,6 +15,7 @@ export class StreamerService {
private readonly responseHeadersService: ResponseHeadersService, private readonly responseHeadersService: ResponseHeadersService,
private readonly responseSender: ResponseSenderService, private readonly responseSender: ResponseSenderService,
) {} ) {}
stream( stream(
req: Request, req: Request,
res: Response, res: Response,
+2
View File
@@ -10,11 +10,13 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { RequestLogMiddleware } from './RequestLog/request-log.middleware'; import { RequestLogMiddleware } from './RequestLog/request-log.middleware';
import { TryModule } from './TryOutModule/try.module'; import { TryModule } from './TryOutModule/try.module';
import { configService } from './config/config.service'; import { configService } from './config/config.service';
import { KodiApiInterfaceModule } from './KodiApiInterface/kodi-api-interface.module';
@Module({ @Module({
imports: [ imports: [
TryModule, TryModule,
KodiApiModule, KodiApiModule,
KodiApiInterfaceModule,
StaticModule, StaticModule,
TypeOrmModule.forRoot(configService.getTypeOrmConfig()), TypeOrmModule.forRoot(configService.getTypeOrmConfig()),
], ],