diff --git a/package-lock.json b/package-lock.json index 6889abf..7cb11f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "oblecto", - "version": "0.2.4", + "version": "0.2.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1736,6 +1736,16 @@ } } }, + "access-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/access-control/-/access-control-1.0.1.tgz", + "integrity": "sha512-H5aqjkogmFxfaOrfn/e42vyspHVXuJ8er63KuljJXpOyJ1ZO/U5CrHfO8BLKIy2w7mBM02L5quL0vbfQqrGQbA==", + "requires": { + "millisecond": "~0.1.2", + "setheader": "~1.0.0", + "vary": "~1.1.0" + } + }, "acorn": { "version": "7.4.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", @@ -1966,6 +1976,11 @@ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" }, + "asyncemit": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/asyncemit/-/asyncemit-3.0.1.tgz", + "integrity": "sha1-zD4P4No5tTzBXls6qGFupqcr1Zk=" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -2627,6 +2642,31 @@ "simple-swizzle": "^0.2.2" } }, + "colornames": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", + "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=" + }, + "colorspace": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", + "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "requires": { + "color": "3.0.x", + "text-hex": "1.0.x" + }, + "dependencies": { + "color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + } + } + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -2716,6 +2756,11 @@ } } }, + "connected": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/connected/-/connected-0.0.2.tgz", + "integrity": "sha1-e1dVshbOMf+rzMOOn04d/Bw7fG0=" + }, "console-browserify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", @@ -2794,6 +2839,14 @@ "underscore": ">1.4.4" } }, + "create-server": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/create-server/-/create-server-1.0.2.tgz", + "integrity": "sha512-hie+Kyero+jxt6dwKhLKtN23qSNiMn8mNIEjTjwzaZwH2y4tr4nYloeFrpadqV+ZqV9jQ15t3AKotaK8dOo45w==", + "requires": { + "connected": "~0.0.2" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -3069,6 +3122,29 @@ "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==" }, + "diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-gvnlQHwkWTOeSM1iRNEwPcUuUwlhovzbuQzalKrTbcJhI5cvhtkRVZZqomwZt4pCl2dvbsugD6yyu+66rtMy3Q==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0", + "storage-engine": "3.0.x" + }, + "dependencies": { + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + } + } + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -3189,12 +3265,25 @@ "integrity": "sha512-fNaYN3EtKQWLQsrKXui8mzcryJXuA0LbCLoizeX6oayG2emBaS5MauKjCPAvc29NEY4FpLHIUWiP+Y0Bfrs5dg==", "dev": true }, + "emits": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emits/-/emits-3.0.0.tgz", + "integrity": "sha1-MnUrupXhcHshlWI4Srm7ix/WL3A=" + }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, + "enabled": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", + "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", + "requires": { + "env-variable": "0.0.x" + } + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -3300,10 +3389,15 @@ }, "entities": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/entities/-/entities-1.0.0.tgz", "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", "dev": true }, + "env-variable": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.6.tgz", + "integrity": "sha512-bHz59NlBbtS0NhftmR8+ExBEekE7br0e01jw+kk0NDro7TtZzBYZ5ScGPs3OmwnpyfHTHOtr1Y6uedCdrIldtg==" + }, "epinfer": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/epinfer/-/epinfer-1.1.4.tgz", @@ -3627,6 +3721,11 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, "ewma": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ewma/-/ewma-2.0.1.tgz", @@ -3717,6 +3816,11 @@ } } }, + "extendible": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/extendible/-/extendible-0.1.1.tgz", + "integrity": "sha1-4qN+2HEp+0+VM+io11BiMKU5yQU=" + }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", @@ -3836,6 +3940,13 @@ "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -4031,6 +4142,11 @@ } } }, + "forwarded-for": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/forwarded-for/-/forwarded-for-1.1.0.tgz", + "integrity": "sha512-1Yam9ht7GyMXMBvuwJfUYqpdtLVodtT5ee5JMBzGiSwVVeh37ZN8LuOWkNHd6ho2zUxpSZCHuQrt1Vjl2AxDNA==" + }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -4086,7 +4202,10 @@ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "dev": true, - "optional": true + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } } } }, @@ -4102,6 +4221,15 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "fusing": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fusing/-/fusing-1.0.0.tgz", + "integrity": "sha1-VQwV12r5Jld4qgUezkTUAAoJjUU=", + "requires": { + "emits": "3.0.x", + "predefine": "0.1.x" + } + }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -4467,7 +4595,7 @@ }, "htmlparser2": { "version": "3.8.3", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "resolved": "http://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", "dev": true, "requires": { @@ -4486,7 +4614,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -4498,7 +4626,7 @@ }, "string_decoder": { "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true } @@ -4633,7 +4761,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "optional": true, @@ -4692,7 +4820,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "optional": true, @@ -5091,6 +5219,14 @@ "dev": true, "optional": true }, + "kuler": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", + "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", + "requires": { + "colornames": "^1.1.1" + } + }, "latest-version": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", @@ -5290,6 +5426,11 @@ "to-regex": "^3.0.2" } }, + "millisecond": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/millisecond/-/millisecond-0.1.2.tgz", + "integrity": "sha1-bMWtOGJByrjniv+WT4cCjuyS2sU=" + }, "mime": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", @@ -5573,6 +5714,11 @@ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==" }, + "nanoid": { + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz", + "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==" + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -6441,6 +6587,14 @@ } } }, + "predefine": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/predefine/-/predefine-0.1.2.tgz", + "integrity": "sha1-KqkrRJa8H4VU5DpF92v75Q0z038=", + "requires": { + "extendible": "0.1.x" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -6453,6 +6607,23 @@ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", "dev": true }, + "primus": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/primus/-/primus-7.3.5.tgz", + "integrity": "sha512-Jo2iKfCRWmXTMupgUzuZtzVtfXWwKQdiV6OrPRCm+nJfPn1tLOhi/wyUh/HlEXivpW7YirAG83ou/Fm+ktKm7A==", + "requires": { + "access-control": "~1.0.0", + "asyncemit": "~3.0.1", + "create-server": "~1.0.1", + "diagnostics": "~2.0.0", + "eventemitter3": "~4.0.0", + "forwarded-for": "~1.1.0", + "fusing": "~1.0.0", + "nanoid": "~3.1.10", + "setheader": "~1.0.2", + "ultron": "~1.1.0" + } + }, "process": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", @@ -6929,7 +7100,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "optional": true, @@ -7117,6 +7288,26 @@ } } }, + "setheader": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/setheader/-/setheader-1.0.2.tgz", + "integrity": "sha512-A704nIwzqGed0CnJZIqDE+0udMPS839ocgf1R9OJ8aq8vw4U980HWeNaD9ec8VnmBni9lyGEWDedOWXT/C5kxA==", + "requires": { + "diagnostics": "1.x.x" + }, + "dependencies": { + "diagnostics": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", + "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", + "requires": { + "colorspace": "1.1.x", + "enabled": "1.0.x", + "kuler": "1.0.x" + } + } + } + }, "setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", @@ -7215,7 +7406,7 @@ }, "shelljs": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "resolved": "http://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", "dev": true }, @@ -7771,6 +7962,22 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" }, + "storage-engine": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/storage-engine/-/storage-engine-3.0.7.tgz", + "integrity": "sha512-V/jJykpPdsyDImLwu19syIAWn/Tb41tBDikQS+aQPH2h2OgqdLxwOg7wI9nPH3Y0Mh1ce566JZl2u+4eH1nAsg==", + "requires": { + "enabled": "^2.0.0", + "eventemitter3": "^4.0.0" + }, + "dependencies": { + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + } + } + }, "stream-transform": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-2.0.2.tgz", @@ -8026,6 +8233,11 @@ "integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==", "dev": true }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -8180,6 +8392,11 @@ "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==" }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, "unbzip2-stream": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", @@ -8446,6 +8663,11 @@ "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, "vasync": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/vasync/-/vasync-2.2.0.tgz", diff --git a/package.json b/package.json index c295905..d5ed3dc 100755 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "node-rsa": "^1.1.1", "node-tvdb": "^4.1.0", "node-uuid": "^1.4.8", + "primus": "^7.3.5", "recursive-readdir": "^2.2.2", "restify": "^8.5.1", "restify-cors-middleware": "^1.1.1", diff --git a/src/lib/embyEmulation/ServerAPI/index.js b/src/lib/embyEmulation/ServerAPI/index.js new file mode 100644 index 0000000..3c9864e --- /dev/null +++ b/src/lib/embyEmulation/ServerAPI/index.js @@ -0,0 +1,64 @@ +import restify from 'restify'; +import routes from './routes'; +import corsMiddleware from 'restify-cors-middleware'; + +export default class EmbyServerAPI { + /** + * @param {EmbyEmulation} embyEmulation + */ + constructor(embyEmulation) { + this.embyEmulation = embyEmulation; + + // Initialize REST based server + this.server = restify.createServer(); + + // Allow remote clients to connect to the backend + const cors = corsMiddleware({ + preflightMaxAge: 5, //Optional + origins: ['*'], + allowHeaders: ['API-Token', 'authorization'], + exposeHeaders: ['API-Token-Expiry'] + }); + + this.server.pre(cors.preflight); + this.server.use(cors.actual); + this.server.use(restify.plugins.authorizationParser()); + this.server.use(restify.plugins.queryParser({ mapParams: true })); + this.server.use(restify.plugins.bodyParser({ mapParams: true })); + + this.server.pre(function(req, res, next) { + req.url = req.url.toLowerCase(); + next(); + }); + + this.server.pre(function(req, res, next) { + if (!req.headers['x-emby-authorization']) return next(); + + req.headers['emby'] = req.headers['x-emby-authorization'].split(', '); + + let auth = {}; + + for (let i in req.headers['emby']) { + let item = req.headers['emby'][i].split('='); + auth[item[0]] = item[1].replace(/"/g, ''); + } + + req.headers['emby'] = auth; + + next(); + }); + + this.server.pre(function (request, response, next) { + console.log(request.url, request.params, request.method); + next(); + }); + + // Add routes routes + routes(this.server, this.embyEmulation); + + // Start restify server + this.server.listen(8096, () => { + console.log('Jellyfin emulation server listening at %s', this.server.url); + }); + } +} diff --git a/src/lib/embyEmulation/ServerAPI/routes/branding/index.js b/src/lib/embyEmulation/ServerAPI/routes/branding/index.js new file mode 100644 index 0000000..dfb42d7 --- /dev/null +++ b/src/lib/embyEmulation/ServerAPI/routes/branding/index.js @@ -0,0 +1,16 @@ +export default (server, embyEmulation) => { + server.get('/branding/configuration', async (req, res, next) => { + res.send({ + LoginDisclaimer: 'This is an Oblecto Media server', + CustomCss: '' + }); + + next(); + }); + + server.get('/branding/css', async (req, res, next) => { + res.send(); + + next(); + }); +}; diff --git a/src/lib/embyEmulation/ServerAPI/routes/displaypreferences/index.js b/src/lib/embyEmulation/ServerAPI/routes/displaypreferences/index.js new file mode 100644 index 0000000..e72a508 --- /dev/null +++ b/src/lib/embyEmulation/ServerAPI/routes/displaypreferences/index.js @@ -0,0 +1,22 @@ +/** + * @param {*} server + * @param {EmbyEmulation} embyEmulation + */ +export default (server, embyEmulation) => { + server.get('/displaypreferences/usersettings', async (req, res, next) => { + res.send({ + //'Id': '3ce5b65de116d73165d1efc4a30ec35c', + 'RememberIndexing': false, + 'PrimaryImageHeight': 250, + 'PrimaryImageWidth': 250, + 'ScrollDirection': 'Horizontal', + 'ShowBackdrop': true, + 'RememberSorting': false, + 'SortOrder': 'Ascending', + 'ShowSidebar': false, + 'Client': 'emby' + }); + + next(); + }); +}; diff --git a/src/lib/embyEmulation/ServerAPI/routes/index.js b/src/lib/embyEmulation/ServerAPI/routes/index.js new file mode 100644 index 0000000..2938fde --- /dev/null +++ b/src/lib/embyEmulation/ServerAPI/routes/index.js @@ -0,0 +1,23 @@ +import system from './system'; +import users from './users'; +import sessions from './sessions'; +import displaypreferences from './displaypreferences'; +import branding from './branding'; +import shows from './shows'; +import items from './items'; + +/** + * + * @param server + * @param {EmbyEmulation} embyEmulation + */ +export default (server, embyEmulation) => { + system(server, embyEmulation); + users(server, embyEmulation); + sessions(server, embyEmulation); + displaypreferences(server, embyEmulation); + branding(server, embyEmulation); + shows(server, embyEmulation); + items(server, embyEmulation); + +}; diff --git a/src/lib/embyEmulation/ServerAPI/routes/items/index.js b/src/lib/embyEmulation/ServerAPI/routes/items/index.js new file mode 100644 index 0000000..0d8171f --- /dev/null +++ b/src/lib/embyEmulation/ServerAPI/routes/items/index.js @@ -0,0 +1,253 @@ +import {Movie} from '../../../../../models/movie'; +import {File} from '../../../../../models/file'; +import fs from 'fs'; +import errors from 'restify-errors'; + +/** + * + * @param server + * @param {EmbyEmulation} embyEmulation + */ +export default (server, embyEmulation) => { + server.get('/items', async (req, res, next) => { + if (req.params.includeitemtypes === 'movie') { + let count = await Movie.count(); + + let offset = parseInt(req.params.startindex) | 0; + + let results = await Movie.findAll({ + limit: parseInt(req.params.limit) || 100, + offset + }); + + let items = []; + + for (let movie of results) { + items.push({ + 'Name': movie.movieName, + 'ServerId': embyEmulation.serverId, + 'Id': 'movie' + movie.id, + 'HasSubtitles': true, + 'Container': 'mkv,webm', + 'PremiereDate': movie.releaseDate, + 'CriticRating': 82, + 'OfficialRating': 'PG-13', + 'CommunityRating': 2.6, + 'RunTimeTicks': 69087043584, + 'ProductionYear': movie.releaseDate.substring(0, 4), + 'IsFolder': false, + 'Type': 'Movie', + 'PrimaryImageAspectRatio': 0.6666666666666666, + 'VideoType': 'VideoFile', + 'LocationType': 'FileSystem', + 'MediaType': 'Video', + 'UserData': { + 'PlaybackPositionTicks': 0, + 'PlayCount': 0, + 'IsFavorite': true, + 'Played': false, + 'Key': '337401' + }, + 'ImageTags': { + 'Primary': 'eaaa9ab0189f4166db1012ec5230c7db' + } + }); + } + + res.send({ + 'Items': items, 'TotalRecordCount': count, 'StartIndex': offset + }); + } else { + res.send({ + Items: [], + TotalRecordCount: 0, + StartIndex: 0 + }); + } + + next(); + }); + + + server.get('/items/:mediaid/similar', async (req, res, next) => { + res.send({ + Items: [], + TotalRecordCount: 0, + StartIndex: 0 + }); + + next(); + }); + + server.get('/items/:mediaid/thememedia', async (req, res, next) => { + res.send({ + 'ThemeVideosResult': { + //'OwnerId': 'f27caa37e5142225cceded48f6553502', + 'Items': [], + 'TotalRecordCount': 0, + 'StartIndex': 0 + }, + 'ThemeSongsResult': { + //'OwnerId': 'f27caa37e5142225cceded48f6553502', + 'Items': [], + 'TotalRecordCount': 0, + 'StartIndex': 0 + }, + 'SoundtrackSongsResult': {'Items': [], 'TotalRecordCount': 0, 'StartIndex': 0} + }); + + next(); + }); + + server.get('/items/:mediaid/images/primary', async (req, res, next) => { + let mediaid = req.params.mediaid; + + if (mediaid.includes('movie')) { + let movie = await Movie.findByPk(mediaid.replace('movie', ''), { + include: [File] + }); + + let posterPath = embyEmulation.oblecto.artworkUtils.moviePosterPath(movie, 'medium'); + + fs.createReadStream(posterPath) + .on('error', () => { + return next(new errors.NotFoundError('Poster for movie does not exist')); + }) + .pipe(res); + + } + + next(); + }); + + server.get('/items/:mediaid/images/backdrop/:artworkid', async (req, res, next) => { + let mediaid = req.params.mediaid; + + if (mediaid.includes('movie')) { + let movie = await Movie.findByPk(mediaid.replace('movie', ''), { + include: [File] + }); + + let posterPath = embyEmulation.oblecto.artworkUtils.movieFanartPath(movie, 'large'); + + fs.createReadStream(posterPath) + .on('error', () => { + return next(new errors.NotFoundError('Poster for movie does not exist')); + }) + .pipe(res); + + } + + next(); + }); + + server.post('/items/:mediaid/playbackinfo', async (req, res, next) => { + let mediaid = req.params.mediaid; + + let files = []; + + if (mediaid.includes('movie')) { + let movie = await Movie.findByPk(mediaid.replace('movie', ''), { + include: [File] + }); + + files = movie.Files; + + } + + let MediaSources = []; + + for (let file of files) { + MediaSources.push({ + 'Protocol': 'File', + 'Id': file.id, + 'Path': file.path, + 'Type': 'Default', + 'Container': 'mp4', + 'Size': 7990969856, + 'Name': file.name, + 'IsRemote': false, + 'ETag': '313f5f26c5f6636a77c630468b6920f7', + 'RunTimeTicks': file.duration * 10000000, + 'ReadAtNativeFramerate': true, + 'IgnoreDts': false, + 'IgnoreIndex': false, + 'GenPtsInput': false, + 'SupportsTranscoding': false, + 'SupportsDirectStream': true, + 'SupportsDirectPlay': true, + 'IsInfiniteStream': false, + 'RequiresOpening': false, + 'RequiresClosing': false, + 'RequiresLooping': false, + 'SupportsProbing': true, + 'VideoType': 'VideoFile', + 'MediaStreams': [{ + 'Codec': 'h264', + 'Language': 'eng', + 'ColorTransfer': 'bt709', + 'ColorPrimaries': 'bt709', + 'TimeBase': '1/1000', + 'CodecTimeBase': '1001/48000', + 'VideoRange': 'SDR', + 'DisplayTitle': '1080p H264', + 'NalLengthSize': '0', + 'IsInterlaced': false, + 'IsAVC': false, + 'BitRate': 9253220, + 'BitDepth': 8, + 'RefFrames': 1, + 'IsDefault': true, + 'IsForced': false, + 'Height': 1080, + 'Width': 1920, + 'AverageFrameRate': 23.976025, + 'RealFrameRate': 23.976025, + 'Profile': 'High', + 'Type': 'Video', + 'AspectRatio': '16:9', + 'Index': 0, + 'IsExternal': false, + 'IsTextSubtitleStream': false, + 'SupportsExternalStream': false, + 'PixelFormat': 'yuv420p', + 'Level': 40 + }, { + 'Codec': 'aac', + 'Language': 'eng', + 'TimeBase': '1/1000', + 'CodecTimeBase': '1/48000', + 'Title': 'English', + 'DisplayTitle': 'Eng Dolby Digital+ 6 ch Default', + 'IsInterlaced': false, + 'Channels': 6, + 'SampleRate': 48000, + 'IsDefault': true, + 'IsForced': false, + 'Type': 'Audio', + 'Index': 1, + 'IsExternal': false, + 'IsTextSubtitleStream': false, + 'SupportsExternalStream': false, + 'Level': 0 + }], + 'MediaAttachments': [], + 'Formats': [], + 'Bitrate': 9253220, + 'RequiredHttpHeaders': {}, + //'TranscodingUrl': '/videos/c042cd5e-c05a-5397-5b85-3b127bea567b/master.m3u8?DeviceId=TW96aWxsYS81LjAgKFgxMTsgTGludXggeDg2XzY0OyBydjo4Mi4wKSBHZWNrby8yMDEwMDEwMSBGaXJlZm94LzgyLjB8MTU5OTg2NDM5ODY2Mg11&MediaSourceId=c042cd5ec05a53975b853b127bea567b&VideoCodec=h264&AudioCodec=mp3,aac&AudioStreamIndex=1&VideoBitrate=139616000&AudioBitrate=384000&PlaySessionId=c89d3c1e027b4463b59bcd06e183679f&api_key=28eece16e48a4bb997e2137297d36321&TranscodingMaxAudioChannels=2&RequireAvc=false&Tag=313f5f26c5f6636a77c630468b6920f7&SegmentContainer=ts&MinSegments=1&BreakOnNonKeyFrames=True&h264-profile=high,main,baseline,constrainedbaseline&h264-level=51&h264-deinterlace=true&TranscodeReasons=VideoCodecNotSupported', + //'TranscodingSubProtocol': 'hls', + //'TranscodingContainer': 'ts', + 'DefaultAudioStreamIndex': 1, + 'DefaultSubtitleStreamIndex': 2 + }); + } + + res.send({ + MediaSources, 'PlaySessionId': req.headers.emby.Token + }); + + next(); + }); + +}; diff --git a/src/lib/embyEmulation/ServerAPI/routes/sessions/index.js b/src/lib/embyEmulation/ServerAPI/routes/sessions/index.js new file mode 100644 index 0000000..6be570b --- /dev/null +++ b/src/lib/embyEmulation/ServerAPI/routes/sessions/index.js @@ -0,0 +1,28 @@ +/** + * @param {*} server + * @param {EmbyEmulation} embyEmulation + */ +export default (server, embyEmulation) => { + server.post('/sessions/capabilities/:type', async (req, res, next) => { + embyEmulation.sessions[req.headers.emby.Token] = req.params; + + res.send(); + + next(); + }); + + server.post('/sessions/playing', async (req, res, next) => { + embyEmulation.sessions[req.headers.emby.Token].playSession = req.params; + + console.log(req.params); + + embyEmulation.websocketSessions[req.headers.emby.Token].write({ + MessageType: 'Play', + Data: req.params + }); + + res.send(); + + next(); + }); +}; diff --git a/src/lib/embyEmulation/ServerAPI/routes/shows/index.js b/src/lib/embyEmulation/ServerAPI/routes/shows/index.js new file mode 100644 index 0000000..8848342 --- /dev/null +++ b/src/lib/embyEmulation/ServerAPI/routes/shows/index.js @@ -0,0 +1,15 @@ +/** + * @param {*} server + * @param {EmbyEmulation} embyEmulation + */ +export default (server, embyEmulation) => { + server.get('/shows/nextup', async (req, res, next) => { + res.send({'Items':[],'TotalRecordCount':0,'StartIndex':0}); + next(); + }); + + server.get('/shows/:seriesid/episodes', async (req, res, next) => { + res.send({'Items':[],'TotalRecordCount':0,'StartIndex':0}); + next(); + }); +}; diff --git a/src/lib/embyEmulation/ServerAPI/routes/system/index.js b/src/lib/embyEmulation/ServerAPI/routes/system/index.js new file mode 100644 index 0000000..f70f4fb --- /dev/null +++ b/src/lib/embyEmulation/ServerAPI/routes/system/index.js @@ -0,0 +1,16 @@ +import ping from './ping'; +import info from './info'; + +export default (server, embyEmulation) => { + ping(server, embyEmulation); + info(server, embyEmulation); + + server.get('/system/endpoint', async (req, res, next) => { + res.send({ + IsLocal: true, + IsInNetwork: true + }); + + next(); + }); +}; diff --git a/src/lib/embyEmulation/ServerAPI/routes/system/info.js b/src/lib/embyEmulation/ServerAPI/routes/system/info.js new file mode 100644 index 0000000..4d9bbed --- /dev/null +++ b/src/lib/embyEmulation/ServerAPI/routes/system/info.js @@ -0,0 +1,44 @@ +export default (server, embyEmulation) => { + server.get('/system/info/public', async (req, res, next) => { + res.send({ + 'LocalAddress': 'http://oblecto:8096', + 'ServerName': embyEmulation.serverName, + 'Version': '10.6.4', + 'ProductName': 'Oblecto Server', + 'OperatingSystem': 'Linux', + 'Id': embyEmulation.serverId + }); + + next(); + }); + + server.get('/system/info', async (req, res, next) => { + res.send({ + 'OperatingSystemDisplayName': 'Linux', + 'HasPendingRestart': false, + 'IsShuttingDown': false, + 'SupportsLibraryMonitor': true, + 'WebSocketPortNumber': 8096, + 'CompletedInstallations': [], + 'CanSelfRestart': false, + 'CanLaunchWebBrowser': false, + 'ProgramDataPath': '/config/data', + 'WebPath': '/usr/share/jellyfin/web', + 'ItemsByNamePath': '/config/data/metadata', + 'CachePath': '/config/cache', + 'LogPath': '/config/log', + 'InternalMetadataPath': '/config/data/metadata', + 'TranscodingTempPath': '/config/data/transcodes', + 'HasUpdateAvailable': false, + 'EncoderLocation': 'Custom', + 'SystemArchitecture': 'X64', + 'LocalAddress': 'http://192.168.178.84:8096', + 'ServerName': embyEmulation.serverName, + 'Version': embyEmulation.version, + 'OperatingSystem': 'Linux', + 'Id': '79d44cdaf63d4e0ab91fca60b8e4b6d6' + }); + + next(); + }); +}; diff --git a/src/lib/embyEmulation/ServerAPI/routes/system/ping.js b/src/lib/embyEmulation/ServerAPI/routes/system/ping.js new file mode 100644 index 0000000..3eb8604 --- /dev/null +++ b/src/lib/embyEmulation/ServerAPI/routes/system/ping.js @@ -0,0 +1,13 @@ +export default (server, embyEmulation) => { + server.get('/system/ping', async (req, res, next) => { + res.send(); + + next(); + }); + + server.post('/system/ping', async (req, res, next) => { + res.send(); + + next(); + }); +}; diff --git a/src/lib/embyEmulation/ServerAPI/routes/users/index.js b/src/lib/embyEmulation/ServerAPI/routes/users/index.js new file mode 100644 index 0000000..323fb9c --- /dev/null +++ b/src/lib/embyEmulation/ServerAPI/routes/users/index.js @@ -0,0 +1,1013 @@ +import {Movie} from '../../../../../models/movie'; +import {TrackMovie} from '../../../../../models/trackMovie'; +import {File} from '../../../../../models/file'; +import {User} from '../../../../../models/user'; + +/** + * @param {*} server + * @param {EmbyEmulation} embyEmulation + */ +export default (server, embyEmulation) => { + server.get('/users/public', async (req, res, next) => { + res.send([]); + + next(); + }); + + server.post('/users/authenticatebyname', async (req, res, next) => { + let sessionId = await embyEmulation.handleLogin(req.params.Username, req.params.Pw); + + res.send({ + User: embyEmulation.sessions[sessionId], + SessionInfo: {}, + AccessToken: sessionId, + ServerId: embyEmulation.serverId + }); + + next(); + }); + + server.get('/users/:userid', async (req, res, next) => { + let user = await User.findByPk(req.params.userid); + + let HasPassword = user.password !== ''; + + res.send({ + Name: user.name, + ServerId: embyEmulation.serverId, + Id: user.id, + HasPassword, + HasConfiguredPassword: HasPassword, + HasConfiguredEasyPassword: false, + EnableAutoLogin: false, + LastLoginDate: '2020-09-11T23:37:27.3042432Z', + LastActivityDate: '2020-09-11T23:37:27.3042432Z', + 'Policy': { + 'IsAdministrator': false, + 'IsHidden': true, + 'IsDisabled': false, + 'BlockedTags': [], + 'EnableUserPreferenceAccess': true, + 'AccessSchedules': [], + 'BlockUnratedItems': [], + 'EnableRemoteControlOfOtherUsers': false, + 'EnableSharedDeviceControl': true, + 'EnableRemoteAccess': true, + 'EnableLiveTvManagement': true, + 'EnableLiveTvAccess': true, + 'EnableMediaPlayback': true, + 'EnableAudioPlaybackTranscoding': true, + 'EnableVideoPlaybackTranscoding': true, + 'EnablePlaybackRemuxing': true, + 'ForceRemoteSourceTranscoding': false, + 'EnableContentDeletion': false, + 'EnableContentDeletionFromFolders': [], + 'EnableContentDownloading': true, + 'EnableSyncTranscoding': true, + 'EnableMediaConversion': true, + 'EnabledDevices': [], + 'EnableAllDevices': true, + 'EnabledChannels': [], + 'EnableAllChannels': false, + 'EnabledFolders': [], + 'EnableAllFolders': true, + 'InvalidLoginAttemptCount': 0, + 'LoginAttemptsBeforeLockout': -1, + 'EnablePublicSharing': true, + 'BlockedMediaFolders': [], + 'BlockedChannels': [], + 'RemoteClientBitrateLimit': 0, + 'AuthenticationProviderId': 'Jellyfin.Server.Implementations.Users.DefaultAuthenticationProvider', + 'PasswordResetProviderId': 'Jellyfin.Server.Implementations.Users.DefaultPasswordResetProvider', + 'SyncPlayAccess': 'CreateAndJoinGroups' + }, + 'Configuration': { + 'PlayDefaultAudioTrack': true, + 'SubtitleLanguagePreference': '', + 'DisplayMissingEpisodes': false, + 'GroupedFolders': [], + 'SubtitleMode': 'Default', + 'DisplayCollectionsView': false, + 'EnableLocalPassword': false, + 'OrderedViews': [], + 'LatestItemsExcludes': [], + 'MyMediaExcludes': [], + 'HidePlayedInLatest': true, + 'RememberAudioSelections': true, + 'RememberSubtitleSelections': true, + 'EnableNextEpisodeAutoPlay': true + } + }); + + next(); + }); + + server.get('/users/:userid/views', async (req, res, next) => { + res.send({ + 'Items': [{ + 'Name': 'Movies', + 'ServerId': embyEmulation.serverId, + 'Id': 'f137a2dd21bbc1b99aa5c0f6bf02a805', + 'Etag': 'cf36c1cd9bcd03c80bd92c9570ec620b', + 'DateCreated': '2020-08-31T16:25:53.2124461Z', + 'CanDelete': false, + 'CanDownload': false, + 'SortName': 'movies', + 'ExternalUrls': [], + 'Path': '/config/data/root/default/Movies', + 'EnableMediaSourceDisplay': true, + 'Taglines': [], + 'Genres': [], + 'PlayAccess': 'Full', + 'RemoteTrailers': [], + 'ProviderIds': {}, + 'IsFolder': true, + 'ParentId': 'e9d5075a555c1cbc394eec4cef295274', + 'Type': 'CollectionFolder', + 'People': [], + 'Studios': [], + 'GenreItems': [], + 'LocalTrailerCount': 0, + 'UserData': { + 'PlaybackPositionTicks': 0, + 'PlayCount': 0, + 'IsFavorite': false, + 'Played': false, + 'Key': 'f137a2dd-21bb-c1b9-9aa5-c0f6bf02a805' + }, + 'ChildCount': 2, + 'SpecialFeatureCount': 0, + 'DisplayPreferencesId': 'f137a2dd21bbc1b99aa5c0f6bf02a805', + 'Tags': [], + 'PrimaryImageAspectRatio': 1, + 'CollectionType': 'movies', + //'ImageTags': {'Primary': '8d5abf60711bc8af6ef4063baf6b67e4'}, + 'BackdropImageTags': [], + 'ScreenshotImageTags': [], + //'ImageBlurHashes': {'Primary': {'8d5abf60711bc8af6ef4063baf6b67e4': 'WvIE5t05-gs,RVt6a%s,axa#fRodETt0WGa#fha$Rot3WBj[oLaf'}}, + 'LocationType': 'FileSystem', + 'LockedFields': [], + 'LockData': false + }, { + 'Name': 'TV Shows', + 'ServerId': embyEmulation.serverId, + 'Id': '767bffe4f11c93ef34b805451a696a4e', + 'Etag': '838cbe93f5d829a9df3df680e4d14065', + 'DateCreated': '2020-08-31T04:36:37.8321784Z', + 'CanDelete': false, + 'CanDownload': false, + 'SortName': 'tv shows', + 'ExternalUrls': [], + 'Path': '/config/data/root/default/TV Shows', + 'EnableMediaSourceDisplay': true, + 'Taglines': [], + 'Genres': [], + 'PlayAccess': 'Full', + 'RemoteTrailers': [], + 'ProviderIds': {}, + 'IsFolder': true, + 'ParentId': 'e9d5075a555c1cbc394eec4cef295274', + 'Type': 'CollectionFolder', + 'People': [], + 'Studios': [], + 'GenreItems': [], + 'LocalTrailerCount': 0, + 'UserData': { + 'PlaybackPositionTicks': 0, + 'PlayCount': 0, + 'IsFavorite': false, + 'Played': false, + 'Key': '767bffe4-f11c-93ef-34b8-05451a696a4e' + }, + 'ChildCount': 9, + 'SpecialFeatureCount': 0, + 'DisplayPreferencesId': '767bffe4f11c93ef34b805451a696a4e', + 'Tags': [], + 'PrimaryImageAspectRatio': 1, + 'CollectionType': 'tvshows', + //'ImageTags': {'Primary': '12c129f756f9ae7ca28c3d87ac4aa3b5'}, + 'BackdropImageTags': [], + 'ScreenshotImageTags': [], + //'ImageBlurHashes': {'Primary': {'12c129f756f9ae7ca28c3d87ac4aa3b5': 'WrHeF9~X%gt7e-Rjs.WBoft7xutRR,t7s:aebHofoft7WBWBRjRj'}}, + 'LocationType': 'FileSystem', + 'LockedFields': [], + 'LockData': false + }], 'TotalRecordCount': 2, 'StartIndex': 0 + }); + + next(); + }); + + server.get('/users/:userid/items', async (req, res, next) => { + if (req.params.includeitemtypes === 'movie') { + let count = await Movie.count(); + + let offset = parseInt(req.params.startindex) | 0; + + let results = await Movie.findAll({ + limit: parseInt(req.params.limit) || 100, + offset + }); + + let items = []; + + for (let movie of results) { + items.push({ + 'Name': movie.movieName, + 'ServerId': embyEmulation.serverId, + 'Id': 'movie' + movie.id, + 'HasSubtitles': true, + 'Container': 'mkv,webm', + 'PremiereDate': movie.releaseDate, + 'CriticRating': 82, + 'OfficialRating': 'PG-13', + 'CommunityRating': 2.6, + 'RunTimeTicks': 69087043584, + 'ProductionYear': movie.releaseDate.substring(0, 4), + 'IsFolder': false, + 'Type': 'Movie', + 'PrimaryImageAspectRatio': 0.6666666666666666, + 'VideoType': 'VideoFile', + 'LocationType': 'FileSystem', + 'MediaType': 'Video', + 'UserData': { + 'PlaybackPositionTicks': 0, + 'PlayCount': 0, + 'IsFavorite': true, + 'Played': false, + 'Key': '337401' + }, + 'ImageTags': { + 'Primary': 'WhyIsThisEvenNeeded' + } + + }); + } + + res.send({ + 'Items': items, 'TotalRecordCount': count, 'StartIndex': offset + }); + } else { + res.send({ + Items: [], + TotalRecordCount: 0, + StartIndex: 0 + }); + } + + next(); + }); + + server.get('/users/:userid/items/:mediaid', async (req, res, next) => { + if (req.params.mediaid.includes('movie')) { + let movie = await Movie.findByPk(req.params.mediaid.replace('movie', ''), { + include: [ + File + ] + }); + + let MediaSources = []; + + for (let file of movie.Files) { + MediaSources.push({ + 'Protocol': 'File', + 'Id': file.id, + 'Path': file.path, + 'Type': 'Default', + 'Container': file.container, + 'Size': 7990969856, + 'Name': file.name, + 'IsRemote': false, + 'ETag': '313f5f26c5f6636a77c630468b6920f7', + 'RunTimeTicks': file.duration * 10000000, + 'ReadAtNativeFramerate': false, + 'IgnoreDts': false, + 'IgnoreIndex': false, + 'GenPtsInput': false, + 'SupportsTranscoding': true, + 'SupportsDirectStream': true, + 'SupportsDirectPlay': true, + 'IsInfiniteStream': false, + 'RequiresOpening': false, + 'RequiresClosing': false, + 'RequiresLooping': false, + 'SupportsProbing': true, + 'VideoType': 'VideoFile', + 'MediaStreams': [ + { + 'Codec': 'h264', + 'Language': 'eng', + 'ColorTransfer': 'bt709', + 'ColorPrimaries': 'bt709', + 'TimeBase': '1/1000', + 'CodecTimeBase': '1001/48000', + 'VideoRange': 'SDR', + 'DisplayTitle': '1080p H264', + 'NalLengthSize': '0', + 'IsInterlaced': false, + 'IsAVC': false, + 'BitRate': 9253220, + 'BitDepth': 8, + 'RefFrames': 1, + 'IsDefault': true, + 'IsForced': false, + 'Height': 1080, + 'Width': 1920, + 'AverageFrameRate': 23.976025, + 'RealFrameRate': 23.976025, + 'Profile': 'High', + 'Type': 'Video', + 'AspectRatio': '16:9', + 'Index': 0, + 'IsExternal': false, + 'IsTextSubtitleStream': false, + 'SupportsExternalStream': false, + 'PixelFormat': 'yuv420p', + 'Level': 40 + }, + { + 'Codec': 'eac3', + 'Language': 'eng', + 'TimeBase': '1/1000', + 'CodecTimeBase': '1/48000', + 'Title': 'English', + 'DisplayTitle': 'Eng Dolby Digital+ 6 ch Default', + 'IsInterlaced': false, + 'Channels': 6, + 'SampleRate': 48000, + 'IsDefault': true, + 'IsForced': false, + 'Type': 'Audio', + 'Index': 1, + 'IsExternal': false, + 'IsTextSubtitleStream': false, + 'SupportsExternalStream': false, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'eng', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'English', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'English - Default', + 'IsInterlaced': false, + 'IsDefault': true, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 2, + 'Score': 112221, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'dan', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'Danish', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'Danish', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 3, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'ger', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'German', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'German', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 4, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'ger', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'German', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'German', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 5, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'spa', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'Spanish', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'Spanish', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 6, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'spa', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'Spanish', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'Spanish', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 7, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'spa', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'Spanish', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'Spanish', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 8, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'spa', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'Spanish', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'Spanish', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 9, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'fin', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'Finnish', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'Finnish', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 10, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'fre', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'French', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'French', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 11, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'fre', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'French', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'French', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 12, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'fre', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'French', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'French', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 13, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'fre', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'French', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'French', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 14, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'ita', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'Italian', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'Italian', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 15, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'ita', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'Italian', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'Italian', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 16, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'dut', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'Dutch', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'Dutch', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 17, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'nor', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'Norwegian', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'Norwegian', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 18, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'por', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'Portuguese', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'Portuguese', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 19, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'por', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'Portuguese', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'Portuguese', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 20, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'por', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'Portuguese', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'Portuguese', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 21, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'por', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'Portuguese', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'Portuguese', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 22, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + }, + { + 'Codec': 'subrip', + 'Language': 'swe', + 'TimeBase': '1/1000', + 'CodecTimeBase': '0/1', + 'Title': 'Swedish', + 'localizedUndefined': 'Undefined', + 'localizedDefault': 'Default', + 'localizedForced': 'Forced', + 'DisplayTitle': 'Swedish', + 'IsInterlaced': false, + 'IsDefault': false, + 'IsForced': false, + 'Type': 'Subtitle', + 'Index': 23, + 'IsExternal': false, + 'IsTextSubtitleStream': true, + 'SupportsExternalStream': true, + 'Level': 0 + } + ], + 'MediaAttachments': [], + 'Formats': [], + 'Bitrate': 9253220, + 'RequiredHttpHeaders': {}, + 'DefaultAudioStreamIndex': 1, + 'DefaultSubtitleStreamIndex': 2, + }); + } + + res.send({ + 'Name': movie.movieName, + 'OriginalTitle': movie.originalName, + 'ServerId': embyEmulation.serverId, + 'Id': 'movie' + movie.id, + 'Etag': '6448f9c5d2678db5ffa4de1c283f6e6a', + 'DateCreated': movie.createdAt, + 'CanDelete': false, + 'CanDownload': true, + 'HasSubtitles': true, + 'Container': 'mkv,webm', + 'SortName': movie.movieName, + 'PremiereDate': movie.releaseDate, + 'ExternalUrls': [ + {'Name': 'IMDb', 'Url': 'https://www.imdb.com/title/tt4566758'}, + {'Name': 'TheMovieDb', 'Url': 'https://www.themoviedb.org/movie/337401'}, + {'Name': 'Trakt', 'Url': 'https://trakt.tv/movies/tt4566758'}], + 'MediaSources': MediaSources, + 'CriticRating': 82, + 'ProductionLocations': ['China', 'United States of America'], + 'Path': movie.Files[0].path, + 'EnableMediaSourceDisplay': true, + 'OfficialRating': 'PG-13', + 'Overview': movie.overview, + 'Taglines': [movie.tagline], + 'Genres': ['Drama', 'Action', 'War', 'Fantasy', 'Adventure'], + 'CommunityRating': 2.6, + 'RunTimeTicks': movie.Files[0].duration * 10000000, + 'PlayAccess': 'Full', + 'ProductionYear': movie.releaseDate.substring(0, 4), + 'RemoteTrailers': [], + 'ProviderIds': { + 'Tmdb': movie.tmdbid, 'Imdb': movie.imdbid + }, + 'IsHD': true, + 'IsFolder': false, + 'ParentId': 'e675012a1892a87530d2c0b0d14a9026', + 'Type': 'Movie', + 'People': [], + 'Studios': [], + 'LocalTrailerCount': 0, + 'UserData': { + 'PlaybackPositionTicks': 0, + 'PlayCount': 0, + 'IsFavorite': true, + 'Played': false, + 'Key': '337401' + }, + 'SpecialFeatureCount': 0, + 'DisplayPreferencesId': 'dbf7709c41faaa746463d67978eb863d', + 'Tags': [], + 'PrimaryImageAspectRatio': 0.6666666666666666, + 'ImageTags': { + 'Primary': 'ThisIDisfairlyuseless' + }, + 'BackdropImageTags': [ + 'be04a5eac7bc48ea3f5834aa816a03f0' + ], + 'VideoType': 'VideoFile', + //'ImageTags': {'Primary': 'eaaa9ab0189f4166db1012ec5230c7db'}, + //'BackdropImageTags': ['be04a5eac7bc48ea3f5834aa816a03f0'], + 'ScreenshotImageTags': [], + //'ImageBlurHashes': { + // 'Backdrop': {'be04a5eac7bc48ea3f5834aa816a03f0': 'W7D78hkBL};OCl}E}G,rI:65KOSxITWVx^K39tjG+]sBs;Sgadwd'}, + // 'Primary': {'eaaa9ab0189f4166db1012ec5230c7db': 'ddHoON-V.S%g~qxuxuniRPRjMxM{-;M{Rjoz%#Nasoxa'} + //}, + 'Chapters': [ + { + 'StartPositionTicks': 0, + 'Name': 'Chapter 1', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 3000000000, + 'Name': 'Chapter 2', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 6000000000, + 'Name': 'Chapter 3', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 9000000000, + 'Name': 'Chapter 4', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 12000000000, + 'Name': 'Chapter 5', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 15000000000, + 'Name': 'Chapter 6', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 18000000000, + 'Name': 'Chapter 7', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 21000000000, + 'Name': 'Chapter 8', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 24000000000, + 'Name': 'Chapter 9', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 27000000000, + 'Name': 'Chapter 10', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 30000000000, + 'Name': 'Chapter 11', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 33000000000, + 'Name': 'Chapter 12', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 36000000000, + 'Name': 'Chapter 13', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 39000000000, + 'Name': 'Chapter 14', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 42000000000, + 'Name': 'Chapter 15', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 45000000000, + 'Name': 'Chapter 16', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 48000000000, + 'Name': 'Chapter 17', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 51000000000, + 'Name': 'Chapter 18', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 54000000000, + 'Name': 'Chapter 19', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 57000000000, + 'Name': 'Chapter 20', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 60000000000, + 'Name': 'Chapter 21', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 63000000000, + 'Name': 'Chapter 22', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + }, + { + 'StartPositionTicks': 66000000000, + 'Name': 'Chapter 23', + 'ImageDateModified': '0001-01-01T00:00:00.0000000Z' + } + ], + 'LocationType': 'FileSystem', + 'MediaType': 'Video', + 'LockedFields': [], + 'LockData': false, + 'Width': 1920, + 'Height': 1080, + }); + } else { + res.send({ + Items: [], + TotalRecordCount: 0, + StartIndex: 0 + }); + } + + next(); + }); + + server.get('/users/:userid/items/:mediaid/intros', async (req, res, next) => { + res.send({'Items': [], 'TotalRecordCount': 0, 'StartIndex': 0}); + next(); + }); + + server.get('/users/:userid/items/resume', async (req, res, next) => { + res.send({'Items': [], 'TotalRecordCount': 0, 'StartIndex': 0}); + next(); + }); + + server.get('/users/:userid/items/latest', async (req, res, next) => { + res.send({'Items': [], 'TotalRecordCount': 0, 'StartIndex': 0}); + next(); + }); +}; diff --git a/src/lib/embyEmulation/index.js b/src/lib/embyEmulation/index.js new file mode 100644 index 0000000..f306dd6 --- /dev/null +++ b/src/lib/embyEmulation/index.js @@ -0,0 +1,118 @@ +import EmbyServerAPI from './ServerAPI'; + +import { v4 as uuidv4 } from 'uuid'; +import {User} from '../../models/user'; +import errors from 'restify-errors'; +import bcrypt from 'bcrypt'; +import Primus from 'primus'; +import {timeout} from 'async'; + +export default class EmbyEmulation { + /** + * + * @param {Oblecto} oblecto + */ + constructor(oblecto) { + this.oblecto = oblecto; + + this.sessions = {}; + + this.websocketSessions = {}; + + this.serverId = 'cadda85fd4f447b9ad3ccc3c83cf1cf6'; + this.version = '10.6.4'; + + this.serverName = 'Oblecto'; + + this.serverAPI = new EmbyServerAPI(this); + + this.primus = new Primus(this.serverAPI.server, { + pathname: '/socket', + authorization: function (req, done) { + + if (!req.query || !req.query.api_key) + return done({ statusCode: 403, message: '' }); + + this.auth = 'test'; + + done(); + } + }); + + this.primus.on('connection', (spark) => { + let req = spark.request; + + if (!req.query || !req.query.api_key) + return spark.disconnect(); + + this.websocketSessions[req.query.api_key] = spark; + + console.log('test'); + + timeout(() => { + console.log('sending'); + spark.write({ + MessageType: 'Play', + Data: { + VolumeLevel: 100, + IsMuted: false, + IsPaused: false, + RepeatMode: 'RepeatNone', + ShuffleMode: 'Sorted', + MaxStreamingBitrate: 140000000, + PositionTicks: 0, + PlaybackStartTimeTicks: 15999190139560000, + SubtitleStreamIndex: 2, + AudioStreamIndex: 1, + BufferedRanges: [], + PlayMethod: 'DirectStream', + PlaySessionId: 'Thisisafuckingtest', + PlaylistItemId: 'playlistItem1', + MediaSourceId: 2725, + CanSeek: true, + ItemId: 'movie16', + NowPlayingQueue: [ { Id: 'movie16', PlaylistItemId: 'playlistItem1' } ] + } + }); + }, 2000); + + + spark.on('data', function message(data) { + + console.log(data); + }); + }); + } + + async handleLogin(username, password) { + let user = await User.findOne({ + where: { + username: username + }, + attributes: ['username', 'name', 'email', 'password', 'id'] + }); + + if (!user) throw Error('Incorrect username'); + + if (!await bcrypt.compare(password, user.password)) + throw Error('Password incorrect'); + + let HasPassword = user.password !== ''; + + let sessionId = uuidv4(); + + this.sessions[sessionId] = { + Name: user.name, + ServerId: this.serverId, + Id: user.id, + HasPassword, + HasConfiguredPassword: HasPassword, + HasConfiguredEasyPassword: false, + EnableAutoLogin: false, + LastLoginDate: '2020-09-11T23:37:27.3042432Z', + LastActivityDate: '2020-09-11T23:37:27.3042432Z' + }; + + return sessionId; + } +} diff --git a/src/lib/oblecto/index.js b/src/lib/oblecto/index.js index ba73301..094f959 100644 --- a/src/lib/oblecto/index.js +++ b/src/lib/oblecto/index.js @@ -41,6 +41,7 @@ import FileCleaner from '../cleaners/FileCleaner'; import FileIndexer from '../indexers/files/FileIndexer'; import {initDatabes} from '../../submodules/database'; +import EmbyEmulation from '../embyEmulation'; export default class Oblecto { constructor(config) { @@ -94,5 +95,8 @@ export default class Oblecto { this.federationClientController.addAllSyncMasters(); } + + // Emby Server emulation + this.embyServer = new EmbyEmulation(this); } } diff --git a/src/lib/updaters/movies/informationRetrievers/TmdbMovieRetriever.js b/src/lib/updaters/movies/informationRetrievers/TmdbMovieRetriever.js index 5930e9e..042be86 100644 --- a/src/lib/updaters/movies/informationRetrievers/TmdbMovieRetriever.js +++ b/src/lib/updaters/movies/informationRetrievers/TmdbMovieRetriever.js @@ -11,7 +11,19 @@ export default class TmdbMovieRetriever { let movieInfo = await this.oblecto.tmdb.movieInfo({ id: movie.tmdbid }); let data = { + imdbid: movieInfo.imdb_id, + movieName: movieInfo.title, + originalName: movieInfo.original_title, + tagline: movieInfo.tagline, + + originalLanguage: movieInfo.original_language, + + budget: movieInfo.budget, + revenue: movieInfo.revenue, + + runtime: movieInfo.runtime, + overview: movieInfo.overview, popularity: movieInfo.popularity, releaseDate: movieInfo.release_date diff --git a/src/models/movie.js b/src/models/movie.js index dc92bce..1c3ca07 100644 --- a/src/models/movie.js +++ b/src/models/movie.js @@ -4,8 +4,18 @@ export class Movie extends Model {} export const movieColumns = { tmdbid: { type: DataTypes.INTEGER, allowNull: true, unique: true }, + imdbid: { type: DataTypes.STRING, allowNull: true, unique: true }, movieName: DataTypes.STRING, + originalName: DataTypes.STRING, + tagline: DataTypes.STRING, + + originalLanguage: DataTypes.STRING, + + budget: DataTypes.INTEGER, + revenue: DataTypes.INTEGER, + + runtime: DataTypes.INTEGER, popularity: DataTypes.FLOAT,