Compare commits
27 Commits
b392c80b25
...
f0b3df0485
Author | SHA1 | Date |
---|---|---|
Charles-Henri BERNARD | f0b3df0485 | |
Buster Neece | a1cd71922f | |
Buster Neece | 1a68f34452 | |
Buster Neece | b1662a4757 | |
Buster Neece | da51ec823c | |
Buster Neece | 3078f4f686 | |
Buster Neece | 66df8f7850 | |
Buster Neece | 3f9c21b63c | |
Buster Neece | ac7dd73fd8 | |
Buster Neece | bcb4443b4d | |
Buster Neece | 6feae35d81 | |
Buster Neece | f12b3c0da2 | |
Buster Neece | d03dc1f277 | |
Buster Neece | ba4a71cd98 | |
Buster Neece | 820cc7ad03 | |
Buster Neece | d438be0a72 | |
Buster Neece | 1871b7a0cd | |
Buster Neece | 17e83547f7 | |
Buster Neece | c881a28be4 | |
Buster Neece | c84522105d | |
Charles-Henri BERNARD | fd2a0896c0 | |
Charles-Henri BERNARD | 7ba5e5a437 | |
Charles-Henri BERNARD | 9aef2cf2d2 | |
Charles-Henri BERNARD | e49db10137 | |
Charles-Henri BERNARD | 99c288a072 | |
Charles-Henri BERNARD | 460c49b01d | |
Charles-Henri BERNARD | 61db6e5735 |
|
@ -52,7 +52,6 @@
|
|||
"league/oauth2-client": "^2.6",
|
||||
"league/plates": "^3.1",
|
||||
"lstrojny/fxmlrpc": "dev-master",
|
||||
"marcw/rss-writer": "^0.4.0",
|
||||
"matomo/device-detector": "^6",
|
||||
"mezzio/mezzio-session": "^1.3",
|
||||
"mezzio/mezzio-session-cache": "^1.7",
|
||||
|
@ -114,7 +113,7 @@
|
|||
"codeception/codeception": "^5.0.0-RC1",
|
||||
"codeception/module-asserts": "^3",
|
||||
"codeception/module-cli": "^2",
|
||||
"codeception/module-doctrine2": "^3",
|
||||
"codeception/module-doctrine": "^3.1",
|
||||
"codeception/module-phpbrowser": "dev-master",
|
||||
"codeception/module-rest": "^3",
|
||||
"filp/whoops": "^2",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,6 +8,7 @@
|
|||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"@codemirror/lang-css": "^6.0.1",
|
||||
"@codemirror/lang-html": "^6.4.9",
|
||||
"@codemirror/lang-javascript": "^6.1.2",
|
||||
"@flowjs/flow.js": "^2.14.1",
|
||||
"@fullcalendar/bootstrap5": "^6.1.8",
|
||||
|
@ -209,9 +210,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@codemirror/commands": {
|
||||
"version": "6.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.3.3.tgz",
|
||||
"integrity": "sha512-dO4hcF0fGT9tu1Pj1D2PvGvxjeGkbC6RGcZw6Qs74TH+Ed1gw98jmUgd2axWvIZEqTeTuFrg1lEB1KV6cK9h1A==",
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.5.0.tgz",
|
||||
"integrity": "sha512-rK+sj4fCAN/QfcY9BEzYMgp4wwL/q5aj/VfNSoH1RWPF9XS/dUwBkvlL3hpWgEjOqlpdN1uLC9UkjJ4tmyjJYg==",
|
||||
"dependencies": {
|
||||
"@codemirror/language": "^6.0.0",
|
||||
"@codemirror/state": "^6.4.0",
|
||||
|
@ -231,6 +232,22 @@
|
|||
"@lezer/css": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/lang-html": {
|
||||
"version": "6.4.9",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.9.tgz",
|
||||
"integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==",
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.0.0",
|
||||
"@codemirror/lang-css": "^6.0.0",
|
||||
"@codemirror/lang-javascript": "^6.0.0",
|
||||
"@codemirror/language": "^6.4.0",
|
||||
"@codemirror/state": "^6.0.0",
|
||||
"@codemirror/view": "^6.17.0",
|
||||
"@lezer/common": "^1.0.0",
|
||||
"@lezer/css": "^1.1.0",
|
||||
"@lezer/html": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/lang-javascript": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.2.tgz",
|
||||
|
@ -932,6 +949,16 @@
|
|||
"@lezer/common": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@lezer/html": {
|
||||
"version": "1.3.9",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.9.tgz",
|
||||
"integrity": "sha512-MXxeCMPyrcemSLGaTQEZx0dBUH0i+RPl8RN5GwMAzo53nTsd/Unc/t5ZxACeQoyPUM5/GkPLRUs2WliOImzkRA==",
|
||||
"dependencies": {
|
||||
"@lezer/common": "^1.2.0",
|
||||
"@lezer/highlight": "^1.0.0",
|
||||
"@lezer/lr": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@lezer/javascript": {
|
||||
"version": "1.4.14",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.14.tgz",
|
||||
|
@ -1017,9 +1044,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.3.tgz",
|
||||
"integrity": "sha512-X9alQ3XM6I9IlSlmC8ddAvMSyG1WuHk5oUnXGw+yUBs3BFoTizmG1La/Gr8fVJvDWAq+zlYTZ9DBgrlKRVY06g==",
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.16.1.tgz",
|
||||
"integrity": "sha512-92/y0TqNLRYOTXpm6Z7mnpvKAG9P7qmK7yJeRJSdzElNCUnsgbpAsGqerUboYRIQKzgfq4pWu9xVkgpWLfmNsw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
@ -1030,9 +1057,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.3.tgz",
|
||||
"integrity": "sha512-eQK5JIi+POhFpzk+LnjKIy4Ks+pwJ+NXmPxOCSvOKSNRPONzKuUvWE+P9JxGZVxrtzm6BAYMaL50FFuPe0oWMQ==",
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.16.1.tgz",
|
||||
"integrity": "sha512-ttWB6ZCfRLuDIUiE0yiu5gcqOsYjA5F7kEV1ggHMj20FwLZ8A1FMeahZJFl/pnOmcnD2QL0z4AcDuo27utGU8A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -1043,9 +1070,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.3.tgz",
|
||||
"integrity": "sha512-Od4vE6f6CTT53yM1jgcLqNfItTsLt5zE46fdPaEmeFHvPs5SjZYlLpHrSiHEKR1+HdRfxuzXHjDOIxQyC3ptBA==",
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.16.1.tgz",
|
||||
"integrity": "sha512-QLDvPLetbqjHojTGFw9+nuSP3YY/iz2k1cep6crYlr97sS+ZJ0W43b8Z0zC00+lnFZj6JSNxiA4DjboNQMuh1A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -1056,9 +1083,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.3.tgz",
|
||||
"integrity": "sha512-0IMAO21axJeNIrvS9lSe/PGthc8ZUS+zC53O0VhF5gMxfmcKAP4ESkKOCwEi6u2asUrt4mQv2rjY8QseIEb1aw==",
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.16.1.tgz",
|
||||
"integrity": "sha512-TAUK/D8khRrRIa1KwRzo8JNKk3tcqaeXWdtsiLgA8zmACWwlWLjPCJ4DULGHQrMkeBjp1Cd3Yuwx04lZgFx5Vg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -1069,9 +1096,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.3.tgz",
|
||||
"integrity": "sha512-ge2DC7tHRHa3caVEoSbPRJpq7azhG+xYsd6u2MEnJ6XzPSzQsTKyXvh6iWjXRf7Rt9ykIUWHtl0Uz3T6yXPpKw==",
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.16.1.tgz",
|
||||
"integrity": "sha512-KO+WGZjrh6zyFTD1alIFkfdtxf8B4BC+hqd3kBZHscPLvE5FR/6QKsyuCT0JlERxxYBSUKNUQ/UHyX5uwO1x2A==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
@ -1082,9 +1109,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.14.3.tgz",
|
||||
"integrity": "sha512-ljcuiDI4V3ySuc7eSk4lQ9wU8J8r8KrOUvB2U+TtK0TiW6OFDmJ+DdIjjwZHIw9CNxzbmXY39wwpzYuFDwNXuw==",
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.16.1.tgz",
|
||||
"integrity": "sha512-NqxbllzIB1WoAo4ThUXVtd21iiM5IHMTTXmXySKBLVcZvkU0HIZmatlP7hLzb5yQubcmdIeWmncd2NdsjocEiw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
@ -1095,9 +1122,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.3.tgz",
|
||||
"integrity": "sha512-Eci2us9VTHm1eSyn5/eEpaC7eP/mp5n46gTRB3Aar3BgSvDQGJZuicyq6TsH4HngNBgVqC5sDYxOzTExSU+NjA==",
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.16.1.tgz",
|
||||
"integrity": "sha512-snma5NvV8y7IECQ5rq0sr0f3UUu+92NVmG/913JXJMcXo84h9ak9TA5UI9Cl2XRM9j3m37QwDBtEYnJzRkSmxA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -1108,9 +1135,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.3.tgz",
|
||||
"integrity": "sha512-UrBoMLCq4E92/LCqlh+blpqMz5h1tJttPIniwUgOFJyjWI1qrtrDhhpHPuFxULlUmjFHfloWdixtDhSxJt5iKw==",
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.16.1.tgz",
|
||||
"integrity": "sha512-KOvqGprlD84ueivhCi2flvcUwDRD20mAsE3vxQNVEI2Di9tnPGAfEu6UcrSPZbM+jG2w1oSr43hrPo0RNg6GGg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -1121,9 +1148,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||
"version": "4.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.3.tgz",
|
||||
"integrity": "sha512-5aRjvsS8q1nWN8AoRfrq5+9IflC3P1leMoy4r2WjXyFqf3qcqsxRCfxtZIV58tCxd+Yv7WELPcO9mY9aeQyAmw==",
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.16.1.tgz",
|
||||
"integrity": "sha512-/gsNwtiGLqYwN4vP+EIdUC6Q6LTlpupWqokqIndvZcjn9ig/5P01WyaYCU2wvfL/2Z82jp5kX8c1mDBOvCP3zg==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
|
@ -1134,9 +1161,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.3.tgz",
|
||||
"integrity": "sha512-sk/Qh1j2/RJSX7FhEpJn8n0ndxy/uf0kI/9Zc4b1ELhqULVdTfN6HL31CDaTChiBAOgLcsJ1sgVZjWv8XNEsAQ==",
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.16.1.tgz",
|
||||
"integrity": "sha512-uU8zuGkQfGqfD9w6VRJZI4IuG4JIfNxxJgEmLMAmPVHREKGsxFVfgHy5c6CexQF2vOfgjB33OsET3Vdn2lln9A==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
|
@ -1147,9 +1174,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.3.tgz",
|
||||
"integrity": "sha512-jOO/PEaDitOmY9TgkxF/TQIjXySQe5KVYB57H/8LRP/ux0ZoO8cSHCX17asMSv3ruwslXW/TLBcxyaUzGRHcqg==",
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.16.1.tgz",
|
||||
"integrity": "sha512-lsjLtDgtcGFEuBP6yrXwkRN5/wKlvUZtfbKZZu0yaoNpiBL4epgnO21osAALIspVRnl4qZgyLFd8xjCYYWgwfw==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
|
@ -1160,9 +1187,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.3.tgz",
|
||||
"integrity": "sha512-8ybV4Xjy59xLMyWo3GCfEGqtKV5M5gCSrZlxkPGvEPCGDLNla7v48S662HSGwRd6/2cSneMQWiv+QzcttLrrOA==",
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.16.1.tgz",
|
||||
"integrity": "sha512-N2ZizKhUryqqrMfdCnjhJhZRgv61C6gK+hwVtCIKC8ts8J+go+vqENnGexwg21nHIOvLN5mBM8a7DI2vlyIOPg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -1173,9 +1200,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.3.tgz",
|
||||
"integrity": "sha512-s+xf1I46trOY10OqAtZ5Rm6lzHre/UiLA1J2uOhCFXWkbZrJRkYBPO6FhvGfHmdtQ3Bx793MNa7LvoWFAm93bg==",
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.16.1.tgz",
|
||||
"integrity": "sha512-5ICeMxqg66FrOA2AbnBQ2TJVxfvZsKLxmof0ibvPLaYtbsJqnTUtJOofgWb46Gjd4uZcA4rdsp4JCxegzQPqCg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -1186,9 +1213,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.3.tgz",
|
||||
"integrity": "sha512-+4h2WrGOYsOumDQ5S2sYNyhVfrue+9tc9XcLWLh+Kw3UOxAvrfOrSMFon60KspcDdytkNDh7K2Vs6eMaYImAZg==",
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.16.1.tgz",
|
||||
"integrity": "sha512-1vIP6Ce02L+qWD7uZYRiFiuAJo3m9kARatWmFSnss0gZnVj2Id7OPUU9gm49JPGasgcR3xMqiH3fqBJ8t00yVg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -1199,9 +1226,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.3.tgz",
|
||||
"integrity": "sha512-T1l7y/bCeL/kUwh9OD4PQT4aM7Bq43vX05htPJJ46RTI4r5KNt6qJRzAfNfM+OYMNEVBWQzR2Gyk+FXLZfogGw==",
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.16.1.tgz",
|
||||
"integrity": "sha512-Y3M92DcVsT6LoP+wrKpoUWPaazaP1fzbNkp0a0ZSj5Y//+pQVfVe/tQdsYQQy7dwXR30ZfALUIc9PCh9Izir6w==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
|
@ -1212,9 +1239,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.3.tgz",
|
||||
"integrity": "sha512-/BypzV0H1y1HzgYpxqRaXGBRqfodgoBBCcsrujT6QRcakDQdfU+Lq9PENPh5jB4I44YWq+0C2eHsHya+nZY1sA==",
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.16.1.tgz",
|
||||
"integrity": "sha512-x0fvpHMuF7fK5r8oZxSi8VYXkrVmRgubXpO/wcf15Lk3xZ4Jvvh5oG+u7Su1776A7XzVKZhD2eRc4t7H50gL3w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -1246,9 +1273,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/eslint": {
|
||||
"version": "8.56.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.9.tgz",
|
||||
"integrity": "sha512-W4W3KcqzjJ0sHg2vAq9vfml6OhsJ53TcUjUqfzzZf/EChUtwspszj/S0pzMxnfRcO55/iGq47dscXw71Fxc4Zg==",
|
||||
"version": "8.56.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz",
|
||||
"integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "*",
|
||||
|
@ -1283,9 +1310,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@types/leaflet": {
|
||||
"version": "1.9.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.11.tgz",
|
||||
"integrity": "sha512-Cwqw9h+1LVnsuOutOSNHlIE1DBQ9U/0CCLfAkwtkgggrYRwf7SUlyZM0LQzngpwKyvFQbPLCf6hNMzly56pGZw==",
|
||||
"version": "1.9.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.12.tgz",
|
||||
"integrity": "sha512-BK7XS+NyRI291HIo0HCfE18Lp8oA30H1gpi1tf0mF3TgiCEzanQjOqNZ4x126SXzzi2oNSZhZ5axJp1k0iM6jg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/geojson": "*"
|
||||
|
@ -1348,16 +1375,16 @@
|
|||
"integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow=="
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.6.0.tgz",
|
||||
"integrity": "sha512-gKmTNwZnblUdnTIJu3e9kmeRRzV2j1a/LUO27KNNAnIC5zjy1aSvXSRp4rVNlmAoHlQ7HzX42NbKpcSr4jF80A==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.0.tgz",
|
||||
"integrity": "sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "7.6.0",
|
||||
"@typescript-eslint/type-utils": "7.6.0",
|
||||
"@typescript-eslint/utils": "7.6.0",
|
||||
"@typescript-eslint/visitor-keys": "7.6.0",
|
||||
"@typescript-eslint/scope-manager": "7.7.0",
|
||||
"@typescript-eslint/type-utils": "7.7.0",
|
||||
"@typescript-eslint/utils": "7.7.0",
|
||||
"@typescript-eslint/visitor-keys": "7.7.0",
|
||||
"debug": "^4.3.4",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
|
@ -1383,15 +1410,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.6.0.tgz",
|
||||
"integrity": "sha512-usPMPHcwX3ZoPWnBnhhorc14NJw9J4HpSXQX4urF2TPKG0au0XhJoZyX62fmvdHONUkmyUe74Hzm1//XA+BoYg==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.0.tgz",
|
||||
"integrity": "sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "7.6.0",
|
||||
"@typescript-eslint/types": "7.6.0",
|
||||
"@typescript-eslint/typescript-estree": "7.6.0",
|
||||
"@typescript-eslint/visitor-keys": "7.6.0",
|
||||
"@typescript-eslint/scope-manager": "7.7.0",
|
||||
"@typescript-eslint/types": "7.7.0",
|
||||
"@typescript-eslint/typescript-estree": "7.7.0",
|
||||
"@typescript-eslint/visitor-keys": "7.7.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -1411,13 +1438,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.6.0.tgz",
|
||||
"integrity": "sha512-ngttyfExA5PsHSx0rdFgnADMYQi+Zkeiv4/ZxGYUWd0nLs63Ha0ksmp8VMxAIC0wtCFxMos7Lt3PszJssG/E6w==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz",
|
||||
"integrity": "sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.6.0",
|
||||
"@typescript-eslint/visitor-keys": "7.6.0"
|
||||
"@typescript-eslint/types": "7.7.0",
|
||||
"@typescript-eslint/visitor-keys": "7.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
|
@ -1428,13 +1455,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.6.0.tgz",
|
||||
"integrity": "sha512-NxAfqAPNLG6LTmy7uZgpK8KcuiS2NZD/HlThPXQRGwz6u7MDBWRVliEEl1Gj6U7++kVJTpehkhZzCJLMK66Scw==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.0.tgz",
|
||||
"integrity": "sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "7.6.0",
|
||||
"@typescript-eslint/utils": "7.6.0",
|
||||
"@typescript-eslint/typescript-estree": "7.7.0",
|
||||
"@typescript-eslint/utils": "7.7.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
|
@ -1455,9 +1482,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.6.0.tgz",
|
||||
"integrity": "sha512-h02rYQn8J+MureCvHVVzhl69/GAfQGPQZmOMjG1KfCl7o3HtMSlPaPUAPu6lLctXI5ySRGIYk94clD/AUMCUgQ==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.0.tgz",
|
||||
"integrity": "sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
|
@ -1468,13 +1495,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.6.0.tgz",
|
||||
"integrity": "sha512-+7Y/GP9VuYibecrCQWSKgl3GvUM5cILRttpWtnAu8GNL9j11e4tbuGZmZjJ8ejnKYyBRb2ddGQ3rEFCq3QjMJw==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz",
|
||||
"integrity": "sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.6.0",
|
||||
"@typescript-eslint/visitor-keys": "7.6.0",
|
||||
"@typescript-eslint/types": "7.7.0",
|
||||
"@typescript-eslint/visitor-keys": "7.7.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
|
@ -1496,17 +1523,17 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.6.0.tgz",
|
||||
"integrity": "sha512-x54gaSsRRI+Nwz59TXpCsr6harB98qjXYzsRxGqvA5Ue3kQH+FxS7FYU81g/omn22ML2pZJkisy6Q+ElK8pBCA==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.0.tgz",
|
||||
"integrity": "sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@typescript-eslint/scope-manager": "7.6.0",
|
||||
"@typescript-eslint/types": "7.6.0",
|
||||
"@typescript-eslint/typescript-estree": "7.6.0",
|
||||
"@typescript-eslint/scope-manager": "7.7.0",
|
||||
"@typescript-eslint/types": "7.7.0",
|
||||
"@typescript-eslint/typescript-estree": "7.7.0",
|
||||
"semver": "^7.6.0"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -1521,12 +1548,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.6.0.tgz",
|
||||
"integrity": "sha512-4eLB7t+LlNUmXzfOu1VAIAdkjbu5xNSerURS9X/S5TUKWFRpXRQZbmtPqgKmYx8bj3J0irtQXSiWAOY82v+cgw==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz",
|
||||
"integrity": "sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.6.0",
|
||||
"@typescript-eslint/types": "7.7.0",
|
||||
"eslint-visitor-keys": "^3.4.3"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -1557,77 +1584,77 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@volar/language-core": {
|
||||
"version": "2.2.0-alpha.8",
|
||||
"resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.2.0-alpha.8.tgz",
|
||||
"integrity": "sha512-Ew1Iw7/RIRNuDLn60fWJdOLApAlfTVPxbPiSLzc434PReC9kleYtaa//Wo2WlN1oiRqneW0pWQQV0CwYqaimLQ==",
|
||||
"version": "2.2.0-alpha.10",
|
||||
"resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.2.0-alpha.10.tgz",
|
||||
"integrity": "sha512-njVJLtpu0zMvDaEk7K5q4BRpOgbyEUljU++un9TfJoJNhxG0z/hWwpwgTRImO42EKvwIxF3XUzeMk+qatAFy7Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/source-map": "2.2.0-alpha.8"
|
||||
"@volar/source-map": "2.2.0-alpha.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@volar/source-map": {
|
||||
"version": "2.2.0-alpha.8",
|
||||
"resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.2.0-alpha.8.tgz",
|
||||
"integrity": "sha512-E1ZVmXFJ5DU4fWDcWHzi8OLqqReqIDwhXvIMhVdk6+VipfMVv4SkryXu7/rs4GA/GsebcRyJdaSkKBB3OAkIcA==",
|
||||
"version": "2.2.0-alpha.10",
|
||||
"resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.2.0-alpha.10.tgz",
|
||||
"integrity": "sha512-nrdWApVkP5cksAnDEyy1JD9rKdwOJsEq1B+seWO4vNXmZNcxQQCx4DULLBvKt7AzRUAQiAuw5aQkb9RBaSqdVA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"muggle-string": "^0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@volar/typescript": {
|
||||
"version": "2.2.0-alpha.8",
|
||||
"resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.2.0-alpha.8.tgz",
|
||||
"integrity": "sha512-RLbRDI+17CiayHZs9HhSzlH0FhLl/+XK6o2qoiw2o2GGKcyD1aDoY6AcMd44acYncTOrqoTNoY6LuCiRyiJiGg==",
|
||||
"version": "2.2.0-alpha.10",
|
||||
"resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.2.0-alpha.10.tgz",
|
||||
"integrity": "sha512-GCa0vTVVdA9ULUsu2Rx7jwsIuyZQPvPVT9o3NrANTbYv+523Ao1gv3glC5vzNSDPM6bUl37r94HbCj7KINQr+g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/language-core": "2.2.0-alpha.8",
|
||||
"@volar/language-core": "2.2.0-alpha.10",
|
||||
"path-browserify": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.21.tgz",
|
||||
"integrity": "sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==",
|
||||
"version": "3.4.23",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.23.tgz",
|
||||
"integrity": "sha512-HAFmuVEwNqNdmk+w4VCQ2pkLk1Vw4XYiiyxEp3z/xvl14aLTUBw2OfVH3vBcx+FtGsynQLkkhK410Nah1N2yyQ==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.23.9",
|
||||
"@vue/shared": "3.4.21",
|
||||
"@babel/parser": "^7.24.1",
|
||||
"@vue/shared": "3.4.23",
|
||||
"entities": "^4.5.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map-js": "^1.0.2"
|
||||
"source-map-js": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-dom": {
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.21.tgz",
|
||||
"integrity": "sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==",
|
||||
"version": "3.4.23",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.23.tgz",
|
||||
"integrity": "sha512-t0b9WSTnCRrzsBGrDd1LNR5HGzYTr7LX3z6nNBG+KGvZLqrT0mY6NsMzOqlVMBKKXKVuusbbB5aOOFgTY+senw==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-core": "3.4.21",
|
||||
"@vue/shared": "3.4.21"
|
||||
"@vue/compiler-core": "3.4.23",
|
||||
"@vue/shared": "3.4.23"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc": {
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.21.tgz",
|
||||
"integrity": "sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==",
|
||||
"version": "3.4.23",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.23.tgz",
|
||||
"integrity": "sha512-fSDTKTfzaRX1kNAUiaj8JB4AokikzStWgHooMhaxyjZerw624L+IAP/fvI4ZwMpwIh8f08PVzEnu4rg8/Npssw==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.23.9",
|
||||
"@vue/compiler-core": "3.4.21",
|
||||
"@vue/compiler-dom": "3.4.21",
|
||||
"@vue/compiler-ssr": "3.4.21",
|
||||
"@vue/shared": "3.4.21",
|
||||
"@babel/parser": "^7.24.1",
|
||||
"@vue/compiler-core": "3.4.23",
|
||||
"@vue/compiler-dom": "3.4.23",
|
||||
"@vue/compiler-ssr": "3.4.23",
|
||||
"@vue/shared": "3.4.23",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.30.7",
|
||||
"postcss": "^8.4.35",
|
||||
"source-map-js": "^1.0.2"
|
||||
"magic-string": "^0.30.8",
|
||||
"postcss": "^8.4.38",
|
||||
"source-map-js": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-ssr": {
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.21.tgz",
|
||||
"integrity": "sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==",
|
||||
"version": "3.4.23",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.23.tgz",
|
||||
"integrity": "sha512-hb6Uj2cYs+tfqz71Wj6h3E5t6OKvb4MVcM2Nl5i/z1nv1gjEhw+zYaNOV+Xwn+SSN/VZM0DgANw5TuJfxfezPg==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.4.21",
|
||||
"@vue/shared": "3.4.21"
|
||||
"@vue/compiler-dom": "3.4.23",
|
||||
"@vue/shared": "3.4.23"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/devtools-api": {
|
||||
|
@ -1660,12 +1687,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vue/language-core": {
|
||||
"version": "2.0.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.13.tgz",
|
||||
"integrity": "sha512-oQgM+BM66SU5GKtUMLQSQN0bxHFkFpLSSAiY87wVziPaiNQZuKVDt/3yA7GB9PiQw0y/bTNL0bOc0jM/siYjKg==",
|
||||
"version": "2.0.14",
|
||||
"resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.14.tgz",
|
||||
"integrity": "sha512-3q8mHSNcGTR7sfp2X6jZdcb4yt8AjBXAfKk0qkZIh7GAJxOnoZ10h5HToZglw4ToFvAnq+xu/Z2FFbglh9Icag==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/language-core": "2.2.0-alpha.8",
|
||||
"@volar/language-core": "2.2.0-alpha.10",
|
||||
"@vue/compiler-dom": "^3.4.0",
|
||||
"@vue/shared": "^3.4.0",
|
||||
"computeds": "^0.0.1",
|
||||
|
@ -1683,48 +1710,48 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity": {
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.21.tgz",
|
||||
"integrity": "sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==",
|
||||
"version": "3.4.23",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.23.tgz",
|
||||
"integrity": "sha512-GlXR9PL+23fQ3IqnbSQ8OQKLodjqCyoCrmdLKZk3BP7jN6prWheAfU7a3mrltewTkoBm+N7qMEb372VHIkQRMQ==",
|
||||
"dependencies": {
|
||||
"@vue/shared": "3.4.21"
|
||||
"@vue/shared": "3.4.23"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-core": {
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.21.tgz",
|
||||
"integrity": "sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==",
|
||||
"version": "3.4.23",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.23.tgz",
|
||||
"integrity": "sha512-FeQ9MZEXoFzFkFiw9MQQ/FWs3srvrP+SjDKSeRIiQHIhtkzoj0X4rWQlRNHbGuSwLra6pMyjAttwixNMjc/xLw==",
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.4.21",
|
||||
"@vue/shared": "3.4.21"
|
||||
"@vue/reactivity": "3.4.23",
|
||||
"@vue/shared": "3.4.23"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-dom": {
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.21.tgz",
|
||||
"integrity": "sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==",
|
||||
"version": "3.4.23",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.23.tgz",
|
||||
"integrity": "sha512-RXJFwwykZWBkMiTPSLEWU3kgVLNAfActBfWFlZd0y79FTUxexogd0PLG4HH2LfOktjRxV47Nulygh0JFXe5f9A==",
|
||||
"dependencies": {
|
||||
"@vue/runtime-core": "3.4.21",
|
||||
"@vue/shared": "3.4.21",
|
||||
"@vue/runtime-core": "3.4.23",
|
||||
"@vue/shared": "3.4.23",
|
||||
"csstype": "^3.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/server-renderer": {
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.21.tgz",
|
||||
"integrity": "sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==",
|
||||
"version": "3.4.23",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.23.tgz",
|
||||
"integrity": "sha512-LDwGHtnIzvKFNS8dPJ1SSU5Gvm36p2ck8wCZc52fc3k/IfjKcwCyrWEf0Yag/2wTFUBXrqizfhK9c/mC367dXQ==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-ssr": "3.4.21",
|
||||
"@vue/shared": "3.4.21"
|
||||
"@vue/compiler-ssr": "3.4.23",
|
||||
"@vue/shared": "3.4.23"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "3.4.21"
|
||||
"vue": "3.4.23"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/shared": {
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.21.tgz",
|
||||
"integrity": "sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g=="
|
||||
"version": "3.4.23",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.23.tgz",
|
||||
"integrity": "sha512-wBQ0gvf+SMwsCQOyusNw/GoXPV47WGd1xB5A1Pgzy0sQ3Bi5r5xm3n+92y3gCnB3MWqnRDdvfkRGxhKtbBRNgg=="
|
||||
},
|
||||
"node_modules/@vuelidate/core": {
|
||||
"version": "2.0.3",
|
||||
|
@ -1811,9 +1838,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vuepic/vue-datepicker": {
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@vuepic/vue-datepicker/-/vue-datepicker-8.4.0.tgz",
|
||||
"integrity": "sha512-Twgvqwd5GrQf3JT2DvAQ/Ku0+sM51zsH1OkQKoRwYqJyF+EugItS8I0CveYmcI3Gbu92RZ9C3DMutvkaiuDzAQ==",
|
||||
"version": "8.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@vuepic/vue-datepicker/-/vue-datepicker-8.5.0.tgz",
|
||||
"integrity": "sha512-p8CHPJYJ1nQgrKzVBaDi1ZO9G9syuvOacPDNMF4uViHsXGdUyGLZbgrvvcmDTd0xYtyCUswiH6S27gb1E7qQ2Q==",
|
||||
"dependencies": {
|
||||
"date-fns": "^3.6.0"
|
||||
},
|
||||
|
@ -3705,14 +3732,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.9",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz",
|
||||
"integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==",
|
||||
"version": "0.30.10",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz",
|
||||
"integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir": {
|
||||
|
@ -3933,9 +3957,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/nwsapi": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz",
|
||||
"integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==",
|
||||
"version": "2.2.9",
|
||||
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz",
|
||||
"integrity": "sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/oas-kit-common": {
|
||||
|
@ -4567,9 +4591,9 @@
|
|||
"integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g=="
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.14.3",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.3.tgz",
|
||||
"integrity": "sha512-ag5tTQKYsj1bhrFC9+OEWqb5O6VYgtQDO9hPDBMmIbePwhfSr+ExlcU741t8Dhw5DkPCQf6noz0jb36D6W9/hw==",
|
||||
"version": "4.16.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.16.1.tgz",
|
||||
"integrity": "sha512-5CaD3MPDlPKfhqzRvWXK96G6ELJfPZNb3LHiZxTHgDdC6jvwfGz2E8nY+9g1ONk4ttHsK1WaFP19Js4PSr1E3g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.5"
|
||||
|
@ -4582,22 +4606,22 @@
|
|||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.14.3",
|
||||
"@rollup/rollup-android-arm64": "4.14.3",
|
||||
"@rollup/rollup-darwin-arm64": "4.14.3",
|
||||
"@rollup/rollup-darwin-x64": "4.14.3",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.14.3",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.14.3",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.14.3",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.14.3",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.14.3",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.14.3",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.14.3",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.14.3",
|
||||
"@rollup/rollup-linux-x64-musl": "4.14.3",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.14.3",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.14.3",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.14.3",
|
||||
"@rollup/rollup-android-arm-eabi": "4.16.1",
|
||||
"@rollup/rollup-android-arm64": "4.16.1",
|
||||
"@rollup/rollup-darwin-arm64": "4.16.1",
|
||||
"@rollup/rollup-darwin-x64": "4.16.1",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.16.1",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.16.1",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.16.1",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.16.1",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.16.1",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.16.1",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.16.1",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.16.1",
|
||||
"@rollup/rollup-linux-x64-musl": "4.16.1",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.16.1",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.16.1",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.16.1",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
|
@ -5324,9 +5348,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.2.8",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz",
|
||||
"integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==",
|
||||
"version": "5.2.10",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.10.tgz",
|
||||
"integrity": "sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.20.1",
|
||||
|
@ -5409,15 +5433,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.4.21.tgz",
|
||||
"integrity": "sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==",
|
||||
"version": "3.4.23",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.4.23.tgz",
|
||||
"integrity": "sha512-X1y6yyGJ28LMUBJ0k/qIeKHstGd+BlWQEOT40x3auJFTmpIhpbKLgN7EFsqalnJXq1Km5ybDEsp6BhuWKciUDg==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.4.21",
|
||||
"@vue/compiler-sfc": "3.4.21",
|
||||
"@vue/runtime-dom": "3.4.21",
|
||||
"@vue/server-renderer": "3.4.21",
|
||||
"@vue/shared": "3.4.21"
|
||||
"@vue/compiler-dom": "3.4.23",
|
||||
"@vue/compiler-sfc": "3.4.23",
|
||||
"@vue/runtime-dom": "3.4.23",
|
||||
"@vue/server-renderer": "3.4.23",
|
||||
"@vue/shared": "3.4.23"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
|
@ -5513,9 +5537,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vue-router": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.3.0.tgz",
|
||||
"integrity": "sha512-dqUcs8tUeG+ssgWhcPbjHvazML16Oga5w34uCUmsk7i0BcnskoLGwjpa15fqMr2Fa5JgVBrdL2MEgqz6XZ/6IQ==",
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.3.2.tgz",
|
||||
"integrity": "sha512-hKQJ1vDAZ5LVkKEnHhmm1f9pMiWIBNGF5AwU67PdH7TyXCj/a4hTccuUuYCAMgJK6rO/NVYtQIEN3yL8CECa7Q==",
|
||||
"dependencies": {
|
||||
"@vue/devtools-api": "^6.5.1"
|
||||
},
|
||||
|
@ -5537,13 +5561,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vue-tsc": {
|
||||
"version": "2.0.13",
|
||||
"resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.0.13.tgz",
|
||||
"integrity": "sha512-a3nL3FvguCWVJUQW/jFrUxdeUtiEkbZoQjidqvMeBK//tuE2w6NWQAbdrEpY2+6nSa4kZoKZp8TZUMtHpjt4mQ==",
|
||||
"version": "2.0.14",
|
||||
"resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.0.14.tgz",
|
||||
"integrity": "sha512-DgAO3U1cnCHOUO7yB35LENbkapeRsBZ7Ugq5hGz/QOHny0+1VQN8eSwSBjYbjLVPfvfw6EY7sNPjbuHHUhckcg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/typescript": "2.2.0-alpha.8",
|
||||
"@vue/language-core": "2.0.13",
|
||||
"@volar/typescript": "2.2.0-alpha.10",
|
||||
"@vue/language-core": "2.0.14",
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"bin": {
|
||||
|
@ -5687,9 +5711,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/wavesurfer.js": {
|
||||
"version": "7.7.10",
|
||||
"resolved": "https://registry.npmjs.org/wavesurfer.js/-/wavesurfer.js-7.7.10.tgz",
|
||||
"integrity": "sha512-fpQ/OiHGkFxD6cJRuU/VQ+iuYM4ipMvMyD5fp0ENPPHYwiZeb01nqXYdXPemK70vAxNDHkVqAsFqLZEchxySJg=="
|
||||
"version": "7.7.11",
|
||||
"resolved": "https://registry.npmjs.org/wavesurfer.js/-/wavesurfer.js-7.7.11.tgz",
|
||||
"integrity": "sha512-27otJlDBcUSbMh/YkxEZN0yXTHINQNYSOl5aJplYlIaHw2u3BrABUzOmUZV3dKIy8udOLJXS/67y5pOIzgAg+w=="
|
||||
},
|
||||
"node_modules/web-streams-polyfill": {
|
||||
"version": "3.3.3",
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@codemirror/lang-css": "^6.0.1",
|
||||
"@codemirror/lang-html": "^6.4.9",
|
||||
"@codemirror/lang-javascript": "^6.1.2",
|
||||
"@flowjs/flow.js": "^2.14.1",
|
||||
"@fullcalendar/bootstrap5": "^6.1.8",
|
||||
|
|
|
@ -90,6 +90,27 @@
|
|||
</template>
|
||||
</form-group-field>
|
||||
|
||||
<form-group-field
|
||||
v-if="enableAdvancedFeatures"
|
||||
id="edit_form_backend_dj_port_secondary"
|
||||
class="col-md-6"
|
||||
:field="v$.backend_config.dj_port_secondary"
|
||||
input-type="number"
|
||||
:input-attrs="{ min: '0' }"
|
||||
advanced
|
||||
:label="$gettext('Customize DJ/Streamer Port Secondary')"
|
||||
>
|
||||
<template #description>
|
||||
{{
|
||||
$gettext('No other program can be using this port. Leave blank to automatically assign a port.')
|
||||
}}
|
||||
<br>
|
||||
{{
|
||||
$gettext('Note: the port after this one will automatically be used for legacy connections.')
|
||||
}}
|
||||
</template>
|
||||
</form-group-field>
|
||||
|
||||
<form-group-field
|
||||
id="edit_form_backend_dj_buffer"
|
||||
class="col-md-6"
|
||||
|
|
|
@ -13,6 +13,7 @@ import {useVModel} from "@vueuse/core";
|
|||
import {computed} from "vue";
|
||||
import {css} from "@codemirror/lang-css";
|
||||
import {javascript} from "@codemirror/lang-javascript";
|
||||
import {html} from "@codemirror/lang-html";
|
||||
import {liquidsoap} from "codemirror-lang-liquidsoap";
|
||||
import useTheme from "~/functions/theme";
|
||||
|
||||
|
@ -31,6 +32,8 @@ const lang = computed(() => {
|
|||
return css();
|
||||
case 'javascript':
|
||||
return javascript();
|
||||
case 'html':
|
||||
return html();
|
||||
case 'liquidsoap':
|
||||
return liquidsoap();
|
||||
default:
|
||||
|
|
|
@ -205,6 +205,20 @@ const fields: DataTableField[] = [
|
|||
sortable: true,
|
||||
selectable: true
|
||||
},
|
||||
{
|
||||
key: 'season_number',
|
||||
label: $gettext('Season Number'),
|
||||
visible: false,
|
||||
sortable: true,
|
||||
selectable: true
|
||||
},
|
||||
{
|
||||
key: 'episode_number',
|
||||
label: $gettext('Episode Number'),
|
||||
visible: false,
|
||||
sortable: true,
|
||||
selectable: true
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
label: $gettext('Actions'),
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
<h5 class="m-0">
|
||||
{{ item.title }}
|
||||
</h5>
|
||||
<div v-if="item.is_published">
|
||||
<div v-if="item.is_published && item.is_enabled">
|
||||
<a
|
||||
:href="item.links.public_episodes"
|
||||
target="_blank"
|
||||
|
@ -59,6 +59,12 @@
|
|||
>
|
||||
{{ $gettext('Unpublished') }}
|
||||
</span>
|
||||
<span
|
||||
v-if="!item.is_enabled"
|
||||
class="badge text-bg-danger"
|
||||
>
|
||||
{{ $gettext('Disabled') }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #cell(actions)="{item}">
|
||||
|
|
|
@ -53,6 +53,28 @@
|
|||
:label="$gettext('Contains explicit content')"
|
||||
:description="$gettext('Indicates the presence of explicit content (explicit language or adult content). Apple Podcasts displays an Explicit parental advisory graphic for your episode if turned on. Episodes containing explicit material aren\'t available in some Apple Podcasts territories.')"
|
||||
/>
|
||||
|
||||
<form-group-field
|
||||
id="form_edit_season_number"
|
||||
class="col-md-6"
|
||||
:field="v$.season_number"
|
||||
input-type="number"
|
||||
:input-attrs="{ step: '1' }"
|
||||
:label="$gettext('Season Number')"
|
||||
:description="$gettext('Optionally list this episode as part of a season in some podcast aggregators.')"
|
||||
clearable
|
||||
/>
|
||||
|
||||
<form-group-field
|
||||
id="form_edit_episode_number"
|
||||
class="col-md-6"
|
||||
:field="v$.episode_number"
|
||||
input-type="number"
|
||||
:input-attrs="{ step: '1' }"
|
||||
:label="$gettext('Episode Number')"
|
||||
:description="$gettext('Optionally set a specific episode number in some podcast aggregators.')"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</tab>
|
||||
</template>
|
||||
|
@ -83,6 +105,8 @@ const {v$, tabClass} = useVuelidateOnFormTab(
|
|||
publish_date: {},
|
||||
publish_time: {},
|
||||
explicit: {},
|
||||
season_number: {},
|
||||
episode_number: {}
|
||||
},
|
||||
form,
|
||||
{
|
||||
|
@ -91,7 +115,9 @@ const {v$, tabClass} = useVuelidateOnFormTab(
|
|||
description: '',
|
||||
publish_date: '',
|
||||
publish_time: '',
|
||||
explicit: false
|
||||
explicit: false,
|
||||
season_number: null,
|
||||
episode_number: null
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
|
|
@ -10,13 +10,13 @@
|
|||
>
|
||||
<tabs>
|
||||
<podcast-form-basic-info
|
||||
:form="form"
|
||||
v-model:form="form"
|
||||
:categories-options="categoriesOptions"
|
||||
:language-options="languageOptions"
|
||||
/>
|
||||
|
||||
<podcast-form-source
|
||||
:form="form"
|
||||
v-model:form="form"
|
||||
/>
|
||||
|
||||
<podcast-common-artwork
|
||||
|
@ -24,6 +24,10 @@
|
|||
:artwork-src="record.links.art"
|
||||
:new-art-url="newArtUrl"
|
||||
/>
|
||||
|
||||
<podcast-form-branding
|
||||
v-model:form="form"
|
||||
/>
|
||||
</tabs>
|
||||
</modal-form>
|
||||
</template>
|
||||
|
@ -31,6 +35,7 @@
|
|||
<script setup lang="ts">
|
||||
import PodcastFormBasicInfo from './PodcastForm/BasicInfo.vue';
|
||||
import PodcastFormSource from './PodcastForm/Source.vue';
|
||||
import PodcastFormBranding from './PodcastForm/Branding.vue';
|
||||
import PodcastCommonArtwork from './Common/Artwork.vue';
|
||||
import mergeExisting from "~/functions/mergeExisting";
|
||||
import {baseEditModalProps, ModalFormTemplateRef, useBaseEditModal} from "~/functions/useBaseEditModal";
|
||||
|
@ -99,8 +104,11 @@ const {
|
|||
(row) => row.category
|
||||
);
|
||||
|
||||
|
||||
record.value = data;
|
||||
formRef.value = mergeExisting(formRef.value, data);
|
||||
|
||||
console.log(formRef.value);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
|
|
@ -63,6 +63,14 @@
|
|||
:label="$gettext('Categories')"
|
||||
:description="$gettext('Select the category/categories that best reflects the content of your podcast.')"
|
||||
/>
|
||||
|
||||
<form-group-checkbox
|
||||
id="edit_form_is_enabled"
|
||||
class="col-md-12"
|
||||
:field="v$.is_enabled"
|
||||
:label="$gettext('Enable on Public Pages')"
|
||||
:description="$gettext('If disabled, the station will not be visible on public-facing pages or APIs.')"
|
||||
/>
|
||||
</div>
|
||||
</tab>
|
||||
</template>
|
||||
|
@ -74,6 +82,7 @@ import {useVModel} from "@vueuse/core";
|
|||
import {useVuelidateOnFormTab} from "~/functions/useVuelidateOnFormTab";
|
||||
import {required} from "@vuelidate/validators";
|
||||
import Tab from "~/components/Common/Tab.vue";
|
||||
import FormGroupCheckbox from "~/components/Form/FormGroupCheckbox.vue";
|
||||
|
||||
const props = defineProps({
|
||||
form: {
|
||||
|
@ -102,6 +111,7 @@ const {v$, tabClass} = useVuelidateOnFormTab(
|
|||
author: {},
|
||||
email: {},
|
||||
categories: {required},
|
||||
is_enabled: {},
|
||||
},
|
||||
form,
|
||||
{
|
||||
|
@ -112,6 +122,7 @@ const {v$, tabClass} = useVuelidateOnFormTab(
|
|||
author: '',
|
||||
email: '',
|
||||
categories: [],
|
||||
is_enabled: true
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<tab
|
||||
:label="$gettext('Branding')"
|
||||
:item-header-class="tabClass"
|
||||
>
|
||||
<div class="row g-3">
|
||||
<form-group-field
|
||||
id="edit_form_public_custom_html"
|
||||
class="col-md-12"
|
||||
:field="v$.branding_config.public_custom_html"
|
||||
:label="$gettext('Custom HTML for Public Pages')"
|
||||
>
|
||||
<template #default="slotProps">
|
||||
<codemirror-textarea
|
||||
:id="slotProps.id"
|
||||
v-model="slotProps.field.$model"
|
||||
mode="html"
|
||||
/>
|
||||
</template>
|
||||
</form-group-field>
|
||||
</div>
|
||||
</tab>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {useVModel} from "@vueuse/core";
|
||||
import {useVuelidateOnFormTab} from "~/functions/useVuelidateOnFormTab";
|
||||
import Tab from "~/components/Common/Tab.vue";
|
||||
import CodemirrorTextarea from "~/components/Common/CodemirrorTextarea.vue";
|
||||
import FormGroupField from "~/components/Form/FormGroupField.vue";
|
||||
|
||||
const props = defineProps({
|
||||
form: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:form']);
|
||||
const form = useVModel(props, 'form', emit);
|
||||
|
||||
const {v$, tabClass} = useVuelidateOnFormTab(
|
||||
{
|
||||
branding_config: {
|
||||
public_custom_html: {}
|
||||
},
|
||||
},
|
||||
form,
|
||||
{
|
||||
branding_config: {
|
||||
public_custom_html: ''
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
|
@ -611,6 +611,8 @@ export type ApiPodcast = HasLinks & {
|
|||
link?: string | null;
|
||||
description?: string;
|
||||
description_short?: string;
|
||||
/** An array containing podcast-specific branding configuration */
|
||||
branding_config?: any[];
|
||||
language?: string;
|
||||
language_name?: string;
|
||||
author?: string;
|
||||
|
@ -633,12 +635,15 @@ export interface ApiPodcastCategory {
|
|||
export type ApiPodcastEpisode = HasLinks & {
|
||||
id?: string;
|
||||
title?: string;
|
||||
link?: string | null;
|
||||
description?: string;
|
||||
description_short?: string;
|
||||
explicit?: boolean;
|
||||
season_number?: number | null;
|
||||
episode_number?: number | null;
|
||||
created_at?: number;
|
||||
publish_at?: number;
|
||||
is_published?: boolean;
|
||||
publish_at?: number | null;
|
||||
has_media?: boolean;
|
||||
playlist_media_id?: string | null;
|
||||
playlist_media?: ApiSong | null;
|
||||
|
@ -1501,6 +1506,8 @@ export type StationPlaylist = HasAutoIncrementId & {
|
|||
avoid_duplicates?: boolean;
|
||||
/** StationSchedule> */
|
||||
schedule_items?: any[];
|
||||
/** Podcast> */
|
||||
podcasts?: any[];
|
||||
};
|
||||
|
||||
export type StationSchedule = HasAutoIncrementId & {
|
||||
|
|
|
@ -35,6 +35,7 @@ final class ListPodcastsAction implements SingleActionInterface
|
|||
->from(Podcast::class, 'p')
|
||||
->leftJoin('p.categories', 'pc')
|
||||
->where('p.storage_location = :storageLocation')
|
||||
->andWhere('p.is_enabled = 1')
|
||||
->setParameter('storageLocation', $station->getPodcastsStorageLocation())
|
||||
->andWhere('p.id IN (:podcastIds)')
|
||||
->setParameter('podcastIds', $this->podcastRepo->getPodcastIdsWithPublishedEpisodes($station))
|
||||
|
|
|
@ -7,36 +7,20 @@ namespace App\Controller\Frontend\PublicPages;
|
|||
use App\Controller\SingleActionInterface;
|
||||
use App\Entity\ApiGenerator\PodcastApiGenerator;
|
||||
use App\Entity\ApiGenerator\PodcastEpisodeApiGenerator;
|
||||
use App\Entity\Podcast;
|
||||
use App\Entity\PodcastCategory;
|
||||
use App\Entity\PodcastEpisode;
|
||||
use App\Exception\NotFoundException;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Rss\PodcastNamespaceWriter;
|
||||
use DateTime;
|
||||
use MarcW\RssWriter\Extension\Atom\AtomLink;
|
||||
use MarcW\RssWriter\Extension\Atom\AtomWriter;
|
||||
use MarcW\RssWriter\Extension\Core\Category as RssCategory;
|
||||
use MarcW\RssWriter\Extension\Core\Channel as RssChannel;
|
||||
use MarcW\RssWriter\Extension\Core\CoreWriter;
|
||||
use MarcW\RssWriter\Extension\Core\Enclosure as RssEnclosure;
|
||||
use MarcW\RssWriter\Extension\Core\Guid as RssGuid;
|
||||
use MarcW\RssWriter\Extension\Core\Image as RssImage;
|
||||
use MarcW\RssWriter\Extension\Core\Item as RssItem;
|
||||
use MarcW\RssWriter\Extension\Itunes\ItunesChannel;
|
||||
use MarcW\RssWriter\Extension\Itunes\ItunesItem;
|
||||
use MarcW\RssWriter\Extension\Itunes\ItunesOwner;
|
||||
use MarcW\RssWriter\Extension\Itunes\ItunesWriter;
|
||||
use MarcW\RssWriter\Extension\Slash\Slash;
|
||||
use MarcW\RssWriter\Extension\Slash\SlashWriter;
|
||||
use MarcW\RssWriter\Extension\Sy\Sy;
|
||||
use MarcW\RssWriter\Extension\Sy\SyWriter;
|
||||
use MarcW\RssWriter\RssWriter;
|
||||
use App\Xml\Writer;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
|
||||
final class PodcastFeedAction implements SingleActionInterface
|
||||
{
|
||||
public const string PODCAST_NAMESPACE = 'ead4c236-bf58-58c6-a2c6-a6b28d128cb6';
|
||||
|
||||
public function __construct(
|
||||
private readonly PodcastApiGenerator $podcastApiGenerator,
|
||||
private readonly PodcastEpisodeApiGenerator $episodeApiGenerator
|
||||
|
@ -55,40 +39,78 @@ final class PodcastFeedAction implements SingleActionInterface
|
|||
|
||||
$podcast = $request->getPodcast();
|
||||
|
||||
$channel = new RssChannel();
|
||||
$channel->setTtl(5);
|
||||
$channel->setLastBuildDate(new DateTime());
|
||||
|
||||
// Fetch podcast API feed.
|
||||
$podcastApi = $this->podcastApiGenerator->__invoke($podcast, $request);
|
||||
|
||||
$channel->setTitle($podcastApi->title);
|
||||
$channel->setDescription($podcastApi->description);
|
||||
$channel->setLink($podcastApi->link ?? $podcastApi->links['self']);
|
||||
$channel->setLanguage($podcastApi->language);
|
||||
$now = CarbonImmutable::now($station->getTimezoneObject());
|
||||
|
||||
$channel->setCategories(
|
||||
$podcast->getCategories()->map(
|
||||
$rss = [
|
||||
'@xmlns:itunes' => 'http://www.itunes.com/dtds/podcast-1.0.dtd',
|
||||
'@xmlns:sy' => 'http://purl.org/rss/1.0/modules/syndication/',
|
||||
'@xmlns:slash' => 'http://purl.org/rss/1.0/modules/slash/',
|
||||
'@xmlns:atom' => 'http://www.w3.org/2005/Atom',
|
||||
'@xmlns:podcast' => 'https://podcastindex.org/namespace/1.0',
|
||||
'@version' => '2.0',
|
||||
];
|
||||
|
||||
$channel = [
|
||||
'title' => $podcastApi->title,
|
||||
'link' => $podcastApi->link ?? $podcastApi->links['public_episodes'],
|
||||
'description' => $podcastApi->description,
|
||||
'language' => $podcastApi->language,
|
||||
'lastBuildDate' => $now->toRssString(),
|
||||
'category' => $podcast->getCategories()->map(
|
||||
function (PodcastCategory $podcastCategory) {
|
||||
$rssCategory = new RssCategory();
|
||||
if (null === $podcastCategory->getSubTitle()) {
|
||||
$rssCategory->setTitle($podcastCategory->getTitle());
|
||||
} else {
|
||||
$rssCategory->setTitle($podcastCategory->getSubTitle());
|
||||
}
|
||||
return $rssCategory;
|
||||
return (null === $podcastCategory->getSubTitle())
|
||||
? $podcastCategory->getTitle()
|
||||
: $podcastCategory->getSubTitle();
|
||||
}
|
||||
)->getValues()
|
||||
);
|
||||
)->getValues(),
|
||||
'ttl' => 5,
|
||||
'image' => [
|
||||
'url' => $podcastApi->art,
|
||||
'title' => $podcastApi->title,
|
||||
],
|
||||
'itunes:author' => $podcastApi->author,
|
||||
'itunes:owner' => [],
|
||||
'itunes:image' => [
|
||||
'@href' => $podcastApi->art,
|
||||
],
|
||||
'itunes:explicit' => 'false',
|
||||
'itunes:category' => $podcast->getCategories()->map(
|
||||
function (PodcastCategory $podcastCategory) {
|
||||
return (null === $podcastCategory->getSubTitle())
|
||||
? [
|
||||
'@text' => $podcastCategory->getTitle(),
|
||||
] : [
|
||||
'@text' => $podcastCategory->getTitle(),
|
||||
'itunes:category' => [
|
||||
'@text' => $podcastCategory->getSubTitle(),
|
||||
],
|
||||
];
|
||||
}
|
||||
)->getValues(),
|
||||
'atom:link' => [
|
||||
'@rel' => 'self',
|
||||
'@type' => 'application/rss+xml',
|
||||
'@href' => (string)$request->getUri(),
|
||||
],
|
||||
'podcast:guid' => $this->buildPodcastGuid($podcastApi->links['public_feed']),
|
||||
'item' => [],
|
||||
];
|
||||
|
||||
$rssImage = new RssImage();
|
||||
$rssImage->setTitle($podcastApi->title);
|
||||
$rssImage->setUrl($podcastApi->art);
|
||||
if (null !== $podcastApi->link) {
|
||||
$rssImage->setLink($podcastApi->link);
|
||||
$channel['image']['link'] = $podcastApi->link;
|
||||
}
|
||||
|
||||
$channel->setImage($rssImage);
|
||||
if (empty($podcastApi->author) && empty($podcastApi->email)) {
|
||||
unset($channel['itunes:owner']);
|
||||
} else {
|
||||
$channel['itunes:owner'] = [
|
||||
'itunes:name' => $podcastApi->author,
|
||||
'itunes:email' => $podcastApi->email,
|
||||
];
|
||||
}
|
||||
|
||||
// Iterate through episodes.
|
||||
$hasPublishedEpisode = false;
|
||||
|
@ -105,53 +127,21 @@ final class PodcastFeedAction implements SingleActionInterface
|
|||
$hasExplicitEpisode = true;
|
||||
}
|
||||
|
||||
$channel->addItem($this->buildItemForEpisode($episode, $request));
|
||||
$channel['item'][] = $this->buildItemForEpisode($episode, $request);
|
||||
}
|
||||
|
||||
if (!$hasPublishedEpisode) {
|
||||
throw NotFoundException::podcast();
|
||||
}
|
||||
|
||||
$itunesChannel = new ItunesChannel();
|
||||
$itunesChannel->setExplicit($hasExplicitEpisode);
|
||||
$itunesChannel->setImage($rssImage->getUrl());
|
||||
$itunesChannel->setCategories(
|
||||
$podcast->getCategories()->map(
|
||||
function (PodcastCategory $podcastCategory) {
|
||||
return (null === $podcastCategory->getSubTitle())
|
||||
? $podcastCategory->getTitle()
|
||||
: [
|
||||
$podcastCategory->getTitle(),
|
||||
$podcastCategory->getSubTitle(),
|
||||
];
|
||||
}
|
||||
)->getValues()
|
||||
);
|
||||
if ($hasExplicitEpisode) {
|
||||
$channel['itunes:explicit'] = 'true';
|
||||
}
|
||||
|
||||
$itunesChannel->setOwner($this->buildItunesOwner($podcast));
|
||||
$itunesChannel->setAuthor($podcast->getAuthor());
|
||||
|
||||
$channel->addExtension($itunesChannel);
|
||||
$channel->addExtension(new Sy());
|
||||
$channel->addExtension(new Slash());
|
||||
$channel->addExtension(
|
||||
(new AtomLink())
|
||||
->setRel('self')
|
||||
->setHref((string)$request->getUri())
|
||||
->setType('application/rss+xml')
|
||||
);
|
||||
|
||||
$rssWriter = new RssWriter(null, [
|
||||
new CoreWriter(),
|
||||
new ItunesWriter(),
|
||||
new SyWriter(),
|
||||
new SlashWriter(),
|
||||
new AtomWriter(),
|
||||
new PodcastNamespaceWriter(),
|
||||
], true);
|
||||
$rss['channel'] = $channel;
|
||||
|
||||
$response->getBody()->write(
|
||||
$rssWriter->writeChannel($channel)
|
||||
Writer::toString($rss, 'rss')
|
||||
);
|
||||
|
||||
return $response
|
||||
|
@ -159,48 +149,58 @@ final class PodcastFeedAction implements SingleActionInterface
|
|||
->withHeader('X-Robots-Tag', 'index, nofollow');
|
||||
}
|
||||
|
||||
private function buildItemForEpisode(PodcastEpisode $episode, ServerRequest $request): RssItem
|
||||
private function buildItemForEpisode(PodcastEpisode $episode, ServerRequest $request): array
|
||||
{
|
||||
$station = $request->getStation();
|
||||
|
||||
$episodeApi = $this->episodeApiGenerator->__invoke($episode, $request);
|
||||
|
||||
$rssItem = new RssItem();
|
||||
$publishedAt = CarbonImmutable::createFromTimestamp($episodeApi->publish_at, $station->getTimezoneObject());
|
||||
|
||||
$rssItem->setGuid((new RssGuid())->setGuid($episodeApi->id));
|
||||
$rssItem->setTitle($episodeApi->title);
|
||||
$rssItem->setDescription($episodeApi->description);
|
||||
$rssItem->setLink($episodeApi->link ?? $episodeApi->links['self']);
|
||||
|
||||
$rssItem->setPubDate((new DateTime())->setTimestamp($episode->getPublishAt()));
|
||||
|
||||
$rssEnclosure = new RssEnclosure();
|
||||
$rssEnclosure->setUrl($episodeApi->links['download']);
|
||||
$item = [
|
||||
'title' => $episodeApi->title,
|
||||
'link' => $episodeApi->link ?? $episodeApi->links['public'],
|
||||
'description' => $episodeApi->description,
|
||||
'enclosure' => [
|
||||
'@url' => $episodeApi->links['download'],
|
||||
],
|
||||
'guid' => [
|
||||
'@isPermaLink' => 'false',
|
||||
'_' => $episodeApi->id,
|
||||
],
|
||||
'pubDate' => $publishedAt->toRssString(),
|
||||
'itunes:image' => [
|
||||
'@href' => $episodeApi->art,
|
||||
],
|
||||
'itunes:explicit' => $episodeApi->explicit ? 'true' : 'false',
|
||||
];
|
||||
|
||||
$podcastMedia = $episode->getMedia();
|
||||
if (null !== $podcastMedia) {
|
||||
$rssEnclosure->setType($podcastMedia->getMimeType());
|
||||
$rssEnclosure->setLength($podcastMedia->getLength());
|
||||
$item['enclosure']['@length'] = $podcastMedia->getLength();
|
||||
$item['enclosure']['@type'] = $podcastMedia->getMimeType();
|
||||
}
|
||||
$rssItem->setEnclosure($rssEnclosure);
|
||||
|
||||
$rssItem->addExtension(
|
||||
(new ItunesItem())
|
||||
->setExplicit($episode->getExplicit())
|
||||
->setImage($episodeApi->art)
|
||||
if (null !== $episodeApi->season_number) {
|
||||
$item['itunes:season'] = (string)$episodeApi->season_number;
|
||||
}
|
||||
if (null !== $episodeApi->episode_number) {
|
||||
$item['itunes:episode'] = (string)$episodeApi->episode_number;
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function buildPodcastGuid(string $uri): string
|
||||
{
|
||||
$baseUri = rtrim(
|
||||
str_replace(['https://', 'http://'], '', $uri),
|
||||
'/'
|
||||
);
|
||||
|
||||
return $rssItem;
|
||||
}
|
||||
|
||||
private function buildItunesOwner(Podcast $podcast): ?ItunesOwner
|
||||
{
|
||||
if (empty($podcast->getAuthor()) && empty($podcast->getEmail())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$itunesOwner = new ItunesOwner();
|
||||
$itunesOwner->setName($podcast->getAuthor());
|
||||
$itunesOwner->setEmail($podcast->getEmail());
|
||||
|
||||
return $itunesOwner;
|
||||
return (string)Uuid::uuid5(
|
||||
self::PODCAST_NAMESPACE,
|
||||
$baseUri
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,9 +29,13 @@ abstract class AbstractStationConfiguration implements JsonSerializable
|
|||
return $return;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
public function jsonSerialize(): array|object
|
||||
{
|
||||
return $this->toArray();
|
||||
$result = $this->toArray();
|
||||
|
||||
return (0 !== count($result))
|
||||
? $result
|
||||
: (object)[];
|
||||
}
|
||||
|
||||
protected function get(string $key, mixed $default = null): mixed
|
||||
|
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace App\Entity\Api;
|
||||
|
||||
use App\Entity\Api\Traits\HasLinks;
|
||||
use App\Entity\PodcastBrandingConfiguration;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
#[OA\Schema(
|
||||
|
@ -42,6 +43,16 @@ final class Podcast
|
|||
#[OA\Property]
|
||||
public string $description_short;
|
||||
|
||||
#[OA\Property]
|
||||
public bool $is_enabled = true;
|
||||
|
||||
#[OA\Property(
|
||||
description: "An array containing podcast-specific branding configuration",
|
||||
type: "array",
|
||||
items: new OA\Items()
|
||||
)]
|
||||
public PodcastBrandingConfiguration $branding_config;
|
||||
|
||||
#[OA\Property]
|
||||
public string $language;
|
||||
|
||||
|
|
|
@ -33,6 +33,12 @@ final class PodcastEpisode
|
|||
#[OA\Property]
|
||||
public bool $explicit = false;
|
||||
|
||||
#[OA\Property]
|
||||
public ?int $season_number = null;
|
||||
|
||||
#[OA\Property]
|
||||
public ?int $episode_number = null;
|
||||
|
||||
#[OA\Property]
|
||||
public int $created_at;
|
||||
|
||||
|
|
|
@ -48,6 +48,10 @@ final class PodcastApiGenerator
|
|||
$return->description = $record->getDescription();
|
||||
$return->description_short = Strings::truncateText($return->description, 200);
|
||||
|
||||
$return->is_enabled = $record->isEnabled();
|
||||
|
||||
$return->branding_config = $record->getBrandingConfig();
|
||||
|
||||
$return->language = $record->getLanguage();
|
||||
try {
|
||||
$locale = $request->getCustomization()->getLocale();
|
||||
|
|
|
@ -41,6 +41,9 @@ final class PodcastEpisodeApiGenerator
|
|||
$return->description_short = Strings::truncateText($return->description, 100);
|
||||
|
||||
$return->explicit = $record->getExplicit();
|
||||
$return->season_number = $record->getSeasonNumber();
|
||||
$return->episode_number = $record->getEpisodeNumber();
|
||||
|
||||
$return->created_at = $record->getCreatedAt();
|
||||
$return->publish_at = $record->getPublishAt();
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity\Migration;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
|
||||
final class Version20240421094525 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Expand podcast database fields.';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE podcast ADD branding_config JSON DEFAULT NULL');
|
||||
$this->addSql(
|
||||
'ALTER TABLE podcast_episode ADD season_number INT DEFAULT NULL, ADD episode_number INT DEFAULT NULL'
|
||||
);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE podcast DROP branding_config');
|
||||
$this->addSql('ALTER TABLE podcast_episode DROP season_number, DROP episode_number');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity\Migration;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
|
||||
final class Version20240425151151 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add is_enabled flag for podcasts.';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE podcast ADD is_enabled TINYINT(1) NOT NULL AFTER description');
|
||||
|
||||
$this->addSql(<<<'SQL'
|
||||
UPDATE podcast
|
||||
SET is_enabled=1
|
||||
SQL);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE podcast DROP is_enabled');
|
||||
}
|
||||
}
|
|
@ -52,6 +52,12 @@ class Podcast implements Interfaces\IdentifiableEntityInterface
|
|||
#[Assert\NotBlank]
|
||||
protected string $description;
|
||||
|
||||
#[ORM\Column]
|
||||
protected bool $is_enabled = true;
|
||||
|
||||
#[ORM\Column(type: 'json', nullable: true)]
|
||||
protected ?array $branding_config = null;
|
||||
|
||||
#[ORM\Column(length: 2)]
|
||||
#[Assert\NotBlank]
|
||||
protected string $language;
|
||||
|
@ -147,6 +153,34 @@ class Podcast implements Interfaces\IdentifiableEntityInterface
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return $this->is_enabled;
|
||||
}
|
||||
|
||||
public function setIsEnabled(bool $is_enabled): void
|
||||
{
|
||||
$this->is_enabled = $is_enabled;
|
||||
}
|
||||
|
||||
public function getBrandingConfig(): PodcastBrandingConfiguration
|
||||
{
|
||||
return new PodcastBrandingConfiguration((array)$this->branding_config);
|
||||
}
|
||||
|
||||
public function setBrandingConfig(
|
||||
PodcastBrandingConfiguration|array $brandingConfig,
|
||||
bool $forceOverwrite = false
|
||||
): void {
|
||||
if (is_array($brandingConfig)) {
|
||||
$brandingConfig = new PodcastBrandingConfiguration(
|
||||
$forceOverwrite ? $brandingConfig : array_merge((array)$this->branding_config, $brandingConfig)
|
||||
);
|
||||
}
|
||||
|
||||
$this->branding_config = $brandingConfig->toArray();
|
||||
}
|
||||
|
||||
public function getLanguage(): string
|
||||
{
|
||||
return $this->language;
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Utilities\Types;
|
||||
|
||||
class PodcastBrandingConfiguration extends AbstractStationConfiguration
|
||||
{
|
||||
public const PUBLIC_CUSTOM_HTML = 'public_custom_html';
|
||||
|
||||
public function getPublicCustomHtml(): ?string
|
||||
{
|
||||
return Types::stringOrNull($this->get(self::PUBLIC_CUSTOM_HTML), true);
|
||||
}
|
||||
|
||||
public function setPublicCustomHtml(?string $html): void
|
||||
{
|
||||
$this->set(self::PUBLIC_CUSTOM_HTML, $html);
|
||||
}
|
||||
}
|
|
@ -52,6 +52,12 @@ class PodcastEpisode implements IdentifiableEntityInterface
|
|||
#[ORM\Column]
|
||||
protected bool $explicit;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
protected ?int $season_number;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
protected ?int $episode_number;
|
||||
|
||||
#[ORM\Column]
|
||||
protected int $created_at;
|
||||
|
||||
|
@ -151,6 +157,30 @@ class PodcastEpisode implements IdentifiableEntityInterface
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getSeasonNumber(): ?int
|
||||
{
|
||||
return $this->season_number;
|
||||
}
|
||||
|
||||
public function setSeasonNumber(?int $season_number): self
|
||||
{
|
||||
$this->season_number = $season_number;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEpisodeNumber(): ?int
|
||||
{
|
||||
return $this->episode_number;
|
||||
}
|
||||
|
||||
public function setEpisodeNumber(?int $episode_number): self
|
||||
{
|
||||
$this->episode_number = $episode_number;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): int
|
||||
{
|
||||
return $this->created_at;
|
||||
|
|
|
@ -39,6 +39,18 @@ class StationBackendConfiguration extends AbstractStationConfiguration
|
|||
$this->set(self::DJ_PORT, $port);
|
||||
}
|
||||
|
||||
public const DJ_PORT_SECONDARY = 'dj_port_decondary';
|
||||
|
||||
public function getDjPortSecondary(): ?int
|
||||
{
|
||||
return Types::intOrNull($this->get(self::DJ_PORT_SECONDARY));
|
||||
}
|
||||
|
||||
public function setDjPortSecondary(?int $port): void
|
||||
{
|
||||
$this->set(self::DJ_PORT_SECONDARY, $port);
|
||||
}
|
||||
|
||||
public const TELNET_PORT = 'telnet_port';
|
||||
|
||||
public function getTelnetPort(): ?int
|
||||
|
|
|
@ -27,7 +27,8 @@ final class RequirePublishedPodcastEpisodeMiddleware extends AbstractMiddleware
|
|||
$publishedPodcastIds = $this->podcastRepository->getPodcastIdsWithPublishedEpisodes($station);
|
||||
|
||||
$podcast = $request->getPodcast();
|
||||
if (!in_array($podcast->getIdRequired(), $publishedPodcastIds, true)) {
|
||||
|
||||
if (!$podcast->isEnabled() || !in_array($podcast->getIdRequired(), $publishedPodcastIds, true)) {
|
||||
throw NotFoundException::podcast();
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,27 @@ final class Liquidsoap extends AbstractLocalAdapter
|
|||
return $frontendPort + 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the port used for a second DJs/Streamers to connect to LiquidSoap for broadcasting.
|
||||
*
|
||||
* @param Station $station
|
||||
*
|
||||
* @return int The port number to use for this station.
|
||||
*/
|
||||
public function getStreamPortSecondary(Station $station): int
|
||||
{
|
||||
$djPortSecondary = $station->getBackendConfig()->getDjPortSecondary();
|
||||
if (null !== $djPortSecondary) {
|
||||
return $djPortSecondary;
|
||||
}
|
||||
|
||||
// Default to frontend port + 7
|
||||
$frontendConfig = $station->getFrontendConfig();
|
||||
$frontendPort = $frontendConfig->getPort() ?? (8000 + (($station->getId() - 1) * 10));
|
||||
|
||||
return $frontendPort + 7;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the specified remote command on LiquidSoap via the telnet API.
|
||||
*
|
||||
|
|
|
@ -1030,7 +1030,41 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
|
||||
# Live Broadcasting
|
||||
live = input.harbor({$harborParams})
|
||||
LIQ
|
||||
);
|
||||
|
||||
|
||||
// Live Secondary Port
|
||||
$streamPortSecondary = $this->liquidsoap->getStreamPortSecondary($station);
|
||||
// Paramètres pour live Secondary
|
||||
$harborSecondary_params = [
|
||||
'"' . self::cleanUpString($dj_mount) . '"', // Assurez-vous que $dj_mount est défini correctement
|
||||
'id = "input_streamer_live_secondary"', // ID unique pour live1
|
||||
'port = ' . $streamPortSecondary, // Utilisation de getStreamPort1 pour le port
|
||||
'auth = dj_auth', // Authentification, assurez-vous que 'dj_auth' est correctement défini
|
||||
'icy = true', // Paramètres ICY
|
||||
'icy_metadata_charset = "' . $charset . '"', // Charset pour les métadonnées ICY, assurez-vous que $charset est défini
|
||||
'metadata_charset = "' . $charset . '"', // Charset pour les métadonnées, assurez-vous que $charset est défini
|
||||
'on_connect = live_connected', // Action à la connexion
|
||||
'on_disconnect = live_disconnected', // Action à la déconnexion
|
||||
];
|
||||
|
||||
// Ajouter des paramètres de buffer si nécessaire
|
||||
$djBuffer = $settings->getDjBuffer(); // Assurez-vous que $settings est défini et a une méthode getDjBuffer
|
||||
if (0 !== $djBuffer) {
|
||||
$harborSecondary_params[] = 'buffer = ' . self::toFloat($djBuffer);
|
||||
$harborSecondary_params[] = 'max = ' . self::toFloat(max($djBuffer + 5, 10));
|
||||
}
|
||||
|
||||
// Concaténer les paramètres pour former la chaîne de configuration live1
|
||||
$harborSecondaryParams = implode(', ', $harborSecondary_params);
|
||||
|
||||
// Ajout de la configuration live1 au fichier de configuration LiquidSoap
|
||||
// Assurez-vous que cette ligne est placée au bon endroit dans votre script pour écrire dans le fichier de configuration
|
||||
$event->appendBlock("live1 = input.harbor({$harbor1Params})\n");
|
||||
|
||||
$event->appendBlock(
|
||||
<<<LIQ
|
||||
def insert_missing(m) =
|
||||
if m == [] then
|
||||
[("title", "{$liveBroadcastText}"), ("is_live", "true")]
|
||||
|
@ -1039,8 +1073,9 @@ final class ConfigWriter implements EventSubscriberInterface
|
|||
end
|
||||
end
|
||||
live = metadata.map(insert_missing, live)
|
||||
live1 = metadata.map(insert_missing, live1)
|
||||
|
||||
radio = fallback(id="live_fallback", track_sensitive=false, replay_metadata=true, [live, radio])
|
||||
radio = fallback(id="live_fallback", track_sensitive=false, replay_metadata=true, [live, live1, radio])
|
||||
|
||||
# Skip non-live track when live DJ goes live.
|
||||
def check_live() =
|
||||
|
|
|
@ -289,6 +289,12 @@ final class Configuration
|
|||
$station->setBackendConfig($backendConfig);
|
||||
}
|
||||
|
||||
$djPortSecondary = $backendConfig->getDjPortSecondary();
|
||||
if ($force || null === $djPortSecondary) {
|
||||
$backendConfig->setDjPortSecondary($basePort + 7);
|
||||
$station->setBackendConfig($backendConfig);
|
||||
}
|
||||
|
||||
$telnetPort = $backendConfig->getTelnetPort();
|
||||
if ($force || null === $telnetPort) {
|
||||
$backendConfig->setTelnetPort($basePort + 4);
|
||||
|
@ -374,6 +380,11 @@ final class Configuration
|
|||
$usedPorts[$port] = $stationReference;
|
||||
$usedPorts[$port + 1] = $stationReference;
|
||||
}
|
||||
if (!empty($backendConfig['dj_port_secondary'])) {
|
||||
$port = (int)$backendConfig['dj_port_secondary'];
|
||||
$usedPorts[$port] = $stationReference;
|
||||
$usedPorts[$port + 1] = $stationReference;
|
||||
}
|
||||
if (!empty($backendConfig['telnet_port'])) {
|
||||
$port = (int)$backendConfig['telnet_port'];
|
||||
$usedPorts[$port] = $stationReference;
|
||||
|
|
|
@ -292,10 +292,7 @@ final class Icecast extends AbstractFrontend
|
|||
}
|
||||
}
|
||||
|
||||
$configString = Writer::toString($config, 'icecast');
|
||||
|
||||
// Strip the first line (the XML charset)
|
||||
return substr($configString, strpos($configString, "\n") + 1);
|
||||
return Writer::toString($config, 'icecast', false);
|
||||
}
|
||||
|
||||
public function getCommand(Station $station): ?string
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Rss;
|
||||
|
||||
use MarcW\RssWriter\WriterRegistererInterface;
|
||||
|
||||
/**
|
||||
* Placeholder class to write the Podcast namespace for PSP-1 compliance.
|
||||
*/
|
||||
class PodcastNamespaceWriter implements WriterRegistererInterface
|
||||
{
|
||||
public function getRegisteredWriters(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getRegisteredNamespaces(): array
|
||||
{
|
||||
return [
|
||||
'podcast' => 'https://podcastindex.org/namespace/1.0',
|
||||
];
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ final class StationPortCheckerValidator extends ConstraintValidator
|
|||
$portsToCheck = [
|
||||
'frontend_config_port' => $frontendConfig->getPort(),
|
||||
'backend_config_dj_port' => $backendConfig->getDjPort(),
|
||||
'backend_config_dj_port_secondary' => $backendConfig->getDjPortSecondary(),
|
||||
'backend_config_telnet_port' => $backendConfig->getTelnetPort(),
|
||||
];
|
||||
|
||||
|
|
|
@ -8,32 +8,25 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Xml;
|
||||
|
||||
use RuntimeException;
|
||||
use XMLWriter;
|
||||
|
||||
final class Writer
|
||||
{
|
||||
public static function toString(
|
||||
array $config,
|
||||
string $baseElement = 'xml-config'
|
||||
): string {
|
||||
return self::processConfig($config, $baseElement);
|
||||
}
|
||||
|
||||
private static function processConfig(
|
||||
array $config,
|
||||
string $baseElement = 'xml-config'
|
||||
string $baseElement = 'xml-config',
|
||||
bool $includeOpeningTag = true
|
||||
): string {
|
||||
$writer = new XMLWriter();
|
||||
$writer->openMemory();
|
||||
$writer->setIndent(true);
|
||||
$writer->setIndentString(str_repeat(' ', 4));
|
||||
|
||||
$writer->startDocument('1.0', 'UTF-8');
|
||||
$writer->startElement($baseElement);
|
||||
if ($includeOpeningTag) {
|
||||
$writer->startDocument('1.0', 'UTF-8');
|
||||
}
|
||||
|
||||
// Make sure attributes come first
|
||||
uksort($config, [self::class, 'attributesFirst']);
|
||||
$writer->startElement($baseElement);
|
||||
|
||||
foreach ($config as $sectionName => $data) {
|
||||
if (!is_array($data)) {
|
||||
|
@ -58,54 +51,50 @@ final class Writer
|
|||
array $config,
|
||||
XMLWriter $writer
|
||||
): void {
|
||||
$branchType = null;
|
||||
|
||||
// Ensure attributes come first.
|
||||
uksort($config, [self::class, 'attributesFirst']);
|
||||
$attributes = [];
|
||||
$innerText = null;
|
||||
|
||||
foreach ($config as $key => $value) {
|
||||
if ($branchType === null) {
|
||||
if (is_numeric($key)) {
|
||||
$branchType = 'numeric';
|
||||
} else {
|
||||
$writer->startElement($branchName);
|
||||
$branchType = 'string';
|
||||
if (str_starts_with((string)$key, '@')) {
|
||||
$attributes[substr($key, 1)] = (string)$value;
|
||||
unset($config[$key]);
|
||||
} else {
|
||||
if ('_' === $key) {
|
||||
$innerText = (string)$value;
|
||||
unset($config[$key]);
|
||||
}
|
||||
} elseif ($branchType !== (is_numeric($key) ? 'numeric' : 'string')) {
|
||||
throw new RuntimeException('Mixing of string and numeric keys is not allowed');
|
||||
}
|
||||
}
|
||||
|
||||
if ($branchType === 'numeric') {
|
||||
if (0 !== count($config) && array_is_list($config)) {
|
||||
foreach ($config as $value) {
|
||||
if (is_array($value)) {
|
||||
self::addBranch($branchName, $value, $writer);
|
||||
} else {
|
||||
$writer->writeElement($branchName, (string)$value);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
$writer->startElement($branchName);
|
||||
|
||||
foreach ($attributes as $attrKey => $attrVal) {
|
||||
$writer->writeAttribute($attrKey, $attrVal);
|
||||
}
|
||||
|
||||
if (null !== $innerText) {
|
||||
$writer->text($innerText);
|
||||
}
|
||||
|
||||
foreach ($config as $key => $value) {
|
||||
/** @var string $key */
|
||||
if (is_array($value)) {
|
||||
self::addBranch($key, $value, $writer);
|
||||
} elseif (str_starts_with($key, '@')) {
|
||||
$writer->writeAttribute(substr($key, 1), (string)$value);
|
||||
} else {
|
||||
$writer->writeElement($key, (string)$value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($branchType === 'string') {
|
||||
$writer->endElement();
|
||||
}
|
||||
}
|
||||
|
||||
private static function attributesFirst(mixed $a, mixed $b): int
|
||||
{
|
||||
if (str_starts_with((string)$a, '@')) {
|
||||
return -1;
|
||||
}
|
||||
if (str_starts_with((string)$b, '@')) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||
namespace <namespace>;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use App\Entity\Migrations\AbstractMigration;
|
||||
|
||||
final class <className> extends AbstractMigration
|
||||
{
|
||||
|
@ -16,12 +15,12 @@ final class <className> extends AbstractMigration
|
|||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
<up>
|
||||
<up>
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
<down>
|
||||
<down>
|
||||
}
|
||||
<override>
|
||||
<override>
|
||||
}
|
||||
|
|
|
@ -3944,6 +3944,13 @@ components:
|
|||
type: string
|
||||
storage_location_id:
|
||||
type: integer
|
||||
source:
|
||||
type: string
|
||||
playlist_id:
|
||||
type: integer
|
||||
nullable: true
|
||||
playlist_auto_publish:
|
||||
type: boolean
|
||||
title:
|
||||
type: string
|
||||
link:
|
||||
|
@ -3953,6 +3960,10 @@ components:
|
|||
type: string
|
||||
description_short:
|
||||
type: string
|
||||
branding_config:
|
||||
description: 'An array containing podcast-specific branding configuration'
|
||||
type: array
|
||||
items: { }
|
||||
language:
|
||||
type: string
|
||||
language_name:
|
||||
|
@ -3999,23 +4010,42 @@ components:
|
|||
type: string
|
||||
title:
|
||||
type: string
|
||||
link:
|
||||
type: string
|
||||
nullable: true
|
||||
description:
|
||||
type: string
|
||||
description_short:
|
||||
type: string
|
||||
explicit:
|
||||
type: boolean
|
||||
season_number:
|
||||
type: integer
|
||||
nullable: true
|
||||
episode_number:
|
||||
type: integer
|
||||
nullable: true
|
||||
created_at:
|
||||
type: integer
|
||||
publish_at:
|
||||
type: integer
|
||||
is_published:
|
||||
type: boolean
|
||||
publish_at:
|
||||
type: integer
|
||||
nullable: true
|
||||
has_media:
|
||||
type: boolean
|
||||
playlist_media_id:
|
||||
type: string
|
||||
nullable: true
|
||||
playlist_media:
|
||||
nullable: true
|
||||
oneOf:
|
||||
-
|
||||
$ref: '#/components/schemas/Api_Song'
|
||||
media:
|
||||
$ref: '#/components/schemas/Api_PodcastMedia'
|
||||
nullable: true
|
||||
oneOf:
|
||||
-
|
||||
$ref: '#/components/schemas/Api_PodcastMedia'
|
||||
has_custom_art:
|
||||
type: boolean
|
||||
art:
|
||||
|
@ -5012,6 +5042,10 @@ components:
|
|||
description: StationSchedule>
|
||||
type: array
|
||||
items: { }
|
||||
podcasts:
|
||||
description: Podcast>
|
||||
type: array
|
||||
items: { }
|
||||
type: object
|
||||
StationSchedule:
|
||||
type: object
|
||||
|
|
Loading…
Reference in New Issue