updating dependencies & fixed tv.dir.bg
This commit is contained in:
1 parent
2a658185d3
commit
d6884090df
8 files changed
+2268
-644
No files matched your search
Generated
+2084
-537
File diff suppressed because it is too large.
Load diff
+11
-11
@@ -38,7 +38,7 @@
|
||||
"dependencies": {
|
||||
"@alex_neo/jest-expect-message": "^1.0.5",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "^9.31.0",
|
||||
"@eslint/js": "^9.32.0",
|
||||
"@freearhey/chronos": "^0.0.1",
|
||||
"@freearhey/core": "^0.10.2",
|
||||
"@freearhey/search-js": "^0.1.2",
|
||||
@@ -46,32 +46,32 @@
|
||||
"@octokit/core": "^7.0.3",
|
||||
"@octokit/plugin-paginate-rest": "^13.1.1",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^16.0.0",
|
||||
"@swc/core": "^1.13.0",
|
||||
"@swc/core": "^1.13.2",
|
||||
"@swc/jest": "^0.2.39",
|
||||
"@types/cli-progress": "^3.11.6",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/inquirer": "^9.0.8",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/langs": "^2.0.5",
|
||||
"@types/node": "^24.0.15",
|
||||
"@types/node": "^24.1.0",
|
||||
"@types/node-cleanup": "^2.1.5",
|
||||
"@types/numeral": "^2.0.5",
|
||||
"@typescript-eslint/eslint-plugin": "^8.37.0",
|
||||
"@typescript-eslint/parser": "^8.37.0",
|
||||
"axios": "^1.10.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.38.0",
|
||||
"@typescript-eslint/parser": "^8.38.0",
|
||||
"axios": "^1.11.0",
|
||||
"axios-cookiejar-support": "^6.0.4",
|
||||
"chalk": "^5.4.1",
|
||||
"cheerio": "^1.1.0",
|
||||
"cheerio": "^1.1.2",
|
||||
"cli-progress": "^3.12.0",
|
||||
"commander": "^14.0.0",
|
||||
"consola": "^3.4.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"cross-env": "^10.0.0",
|
||||
"csv-parser": "^3.2.0",
|
||||
"cwait": "^1.1.2",
|
||||
"dayjs": "^1.11.13",
|
||||
"epg-grabber": "^0.41.0",
|
||||
"epg-parser": "^0.3.1",
|
||||
"eslint": "^9.31.0",
|
||||
"eslint": "^9.32.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"form-data": "^4.0.4",
|
||||
"fs-extra": "^11.3.0",
|
||||
@@ -79,8 +79,8 @@
|
||||
"globals": "^16.3.0",
|
||||
"husky": "^9.1.7",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"inquirer": "^12.7.0",
|
||||
"jest": "^30.0.4",
|
||||
"inquirer": "^12.8.2",
|
||||
"jest": "^30.0.5",
|
||||
"jest-offline": "^1.0.1",
|
||||
"langs": "^2.0.0",
|
||||
"libxml2-wasm": "^0.5.0",
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<div class=\"panels\">\n <div class=\"panel\">\n <div class=\"day-broadcast-list\">\n <p class=\"broadcast-item-name\">\n \u0412\u0447\u0435\u0440\u0430\n <\/p>\n <div class=\"broadcasts-lists\">\n <div class=\"broadcast-item \">\n <div class=\"broadcast-image\">\n <img loading=\"lazy\" src=\"data:image\/jpg;base64,\/9j\/4AAQSkZJRgABAQEBLAEsAAD\/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj\/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj\/wAARCAFoAoADASIAAhEBAxEB\/8QAHAAAAgIDAQEAAAAAAAAAAAAAAgMBBAAFBgcI\/8QARRAAAgEDAgQEAggEBAUFAAEFAQIDAAQREiEFMUFRBhMiYXGBBxQyQlKRofAjscHRFTNi4QgkcoLxFkNTkqLCJXODstL\/xAAZAQEBAQEBAQAAAAAAAAAAAAAAAQIDBAX\/xAAkEQEBAQACAwACAgMBAQAAAAAAARECEgMhMUFRE2EEFHEiMv\/aAAwDAQACEQMRAD8A+dhTU50sCmRiurznJvRaaGMUwUA6ajy80wUaigQYj2odGKuAZFCY6CqFqdFM0dqnT7UUvRWBKaFoguaIr+XWaKs6Kjy6CtpogKcY6ExkUaCKkCs0kUQFEwOis0e1NWi0g1WcV9FTop+is00VX01gUdafoqNBoFhe1SFogMUQAIoFFM1gSnhaIJQV9FZoqxprNNBV8us0Yq1ozQFDmiwkLWYqwIj2ovKHagq49qjTVvyhWz8McDk45x204dCcNM+7YJwo3J29hQaIL2otFe7+Ifox8O2lnChM\/D55kLwSNKX83YkL1B2BzgA14zxCzW0vri3SZJ1ikZBKnJwDjIq2YksqgEqNFWVTvU+XkVFVNFRpq35VT5NFVVSj0VZEVF5dGdVNFSI6teVUiPFC1U8upEdWtFT5dGVTRUeXVvRUaKCtoqNFWtFZooaq+XWeXVnRWaKCt5dZ5dWdFDp9qBGis0VY0ZrPLoK\/l1nl1Z0VmigreXWeXVjy6IR1FVfLqdFWhHWaMU0xV8us0Va0ZrPLppisI6zy6teXioKUFbRU6BT9PasEZNTVxVK0JjzVsx1nlVNWKXl1giJq75YqQmKKpeTQmPFXXXApLITRFZtqU2elXBbk86IQAUXFARFudMWECrRUCsAzyFBQEdEqVf8Aq9SIN+VDFWNKIpV6O3z0oZICDyoYpaaJRTjER0qRGRzppgBWU4JtQlDQKwKLRmi096JVxWgryxWBMcqeBRKtZMIG3OiAFO0A0JQiroXpqClMFEBmqYR5dZ5dWVTIqRH3oir5dRoI5VdEe1QY8iporVIAomQgmoAxV0xAXNSY9qIVI2ppiuY9zQhSKtlc0OimqUozTVU1KpT403pqYToqRHVrRWaKaitoqPLFW\/LNT5e3Kmioq1hSrHlkdKMR5pqqgQ9K9D8LeDrq04dBx1eIKk8qqYoYgcgOxX1NnY7csH864XyypOK3\/C\/GHGuHW9vbRyxzWkCsiQTxK6YP6n232q8eUl9pZvx2vBmaPgHiHhpsUuZRAYo2eV2MS88orHuMgjHUGvI3iKSOp5qSPyNek+HOMTyxszRxzC3KSLBICY5Ai6WUhegUq23auKvLN2WW8jjVYGnZMrnBbOSfYdq3znrWeLWaO4qVQGrKJjmKYsQzyrlraqIs1PldxVwR+1SU2qaikI\/ap8s9qtYrMe1NFby6zyqsge1SFzV0xWEVR5dW9FZopqYp+VWeXVvRWaKaYqeXUeXVvT7VGimir5dZ5dWdHtUeXU1cVSlCU7CrhjqBHimioqHqKLy6teXWaB2ppisI6zy6sFMcqgjFNMJ8uo0gUTnFCFZqLIFjjlQBSaspD3pyw1NXFRU25UQQ1b8qs8uiYqeXWeV3q55dZoouKgiohHVgJmjERoYqGOllRV1ojioWADmKmmKQjJpqQbVbEdMSPamrI17QDtQGICr8q1XdCaaYptillGY8quiH2oxDTWlAQ96kREdKO7vbW0z5kgLfhXc1pLvjU0uRboI1\/EdzRltbO9trjZXAb8LbGtnHCGG1cYsWqtjw+8u7dgI31D8D7g\/Orhrq4bUHpQT2uDyouE8VilYJcxtE3fmp+dbSRUkyY2Vh3BrLcksc+bY77VAts9K3f1bsKxbbuKadWnW125UqS3IroPIwpwKqSQ89qunVozCcnas8ojpW2Nv7ULW23KmpjUsmDWKKvvb+1L8nFXUxXUbVhFOMRxyoStFJMfY0OkinY71mM0ClYinI2RvQ6KkJ2omGACp0dqBNQNOUHFEwopnnQmHtVoH8QoggP2cU1MUfKx0yKIJVzQDsaExZ5U1VbSKjRtVnyiOxovKyKuiooFPjUY3oDHpNMjwaGGogo9AoQvamIhxvUTAlAanRR6agChhboKFRT1XNQYyD7UXAhAe1C8YVGbB2BO1PVM8qfaorTxrKwVGYBiTjA6\/PGas90sdx4U8OGbhh4r50sbIVNquj0EjBcZbYrjVnGee\/Ko4tccEgZ7VuGyDg8shYPFK4Bk2yy52zueY69qrN4i4Z5\/CYPqckttwyMxQTXEpLKWG5K8tsk471tfEnEZ0js341ZzIsykecojcuinMZ7a8E5PwFei304yOI8R8JThXGJ7SKTzYQFeJzzZGUMucdcGtaIwK23H+If4pxOS4SAQRaVSOIHOlVGACep6n41rvavNb79O84\/sAQVBjBpoG21QaLhXljtQlOwp+\/QVOk4odVdYyelEI6fjAoSN6adS9FDp3pmCakKRRMK01mmmkVGM0MJwKzTTStZihhWnFRpp2msC7UMJ0+1YVFOxUaaGE6ajSaseXWaKhivooTHmreipCYoYpiAdaMRDtVrAFDtRcKEeBRKlHkVBftQxGkUBwKIktWCMmhgNulQFJqzHBmm+UB0qL1VY46fHCDzpgGKdEtFkVzCO1LMftV8pnpWeRq5UXGvCAUyOIt0q2LbHMVJntrbaSRc\/hG5NQxRkgOTtVeREjUtIwVR1JqnxXjkpLLaQ6R+N\/7VzN1LPcsTPI8h7HkPlVkYtn4bu843awZWAGZx+Hl+daG94rd3WQX8tPwp\/ekMgXnSHYDNakjOg2G+MnuaAkmpJJ5UJXvvVMXLaUg771u7BYbghWOh+ma5+IsDtW54Sks0qqqj5ioOv4PwuVZlDrqU8jjYihueGlLh5ImeAg8wcCt7wMC3tUSSYMzHAUcqpcdlS6ysMgLpsUP9Ky31mNZ\/ic9ptIi3I\/Euxq1acWtLptPmaHP3ZPSa5yRpI5CGyoB3HKrMMCXS7YJ7MMUScq7COMMhI7VVkh3xiqfDLa5gtpDBJIgA+y2601L+WLe+gwPxxn+ho3oxB2FEYMLuKbbXtpc7W8yM34Ts35GrZjJQ5FFjSyQjfakGD2raSR7mgEXtRMatrfbYVXeAjpW+MIIqu8I6UOrSGL2ofLrbNBvypbW+\/KiY1misC1da3I5ClmMiqmK4UijU4pmis8sdaGDQBqnyd\/SaAIRypsZYc6GI0MKlR3FPU5FYcVDCwgPKoMe1PC5qdHvVMUJUyMDnVfSUNbVo+4zVeWEtnANDCoXJG5qymCKp6GQnNOjkPU0MWQMUJAFCsgqS6kUEZGdjWMcc80Gpd8Vb4VZScTujbW2WuChMaDcyN0Ue5qybcS+vY+E2rX90sSnSDzY8ht+\/gK2lnweSS4EBPluWC5kTONixY9sKCcdyB3rp+G+E7m2jtohC2qWXyAz7KwGWc5J5YU\/LHenGRVsbmeTINvw+ScjG6NM+Ez3OP0NejjxkcLytMseFwy2VtPfWEWuTRpLHSTrMhAJ9lUZJ7irF6tqWjt04Tw\/y2iha3D5Ozp6AcEfeBU9iynlW34tIknCorW3tY42jjt4HYJ0aMjr3BHzrkTckQm1ktmDhfqrSKTyQllPscgbjtW0afj9vbG0t7yO0jszKf8ALjLYA6Egk4zhhz5qR0rSFMMVYb10l3b+dJcNdISsqrJI2rKprbBcnn6XKnH\/AFd652KOYC6S4TRLbtpK9RglWHyYEVy58PzHTx8\/eVGjbpQrGAc5zUh98YowO1cHowOkVAA6VLCh0mhjMUOPamhakpmhhOw6Vm1ZInvSHbBwNzRPhpK1lIUEnOTTUjHc1ETsBvUqM8t6kQZ509IwowKqyEFKjRVhhigAoYWF2qdNMPxxSXkC8t6GJ00LEDrSnkZvhSzk1EOaVRS2mPSgCk0YizQLLMe9SMnvThFRrEe1DCVjJpiQ1YjhPWrUUIouKaxY5CmJFV4we1QIt6LhUUWTRvAe1W4I9+VNfSgJcgAdTU1WsEGDyqxBBvQTcQtRkRN5rjom\/wCtU1vL2aTSirAvLuaJsXrlordS0rqijqTWnm8QQxki1jaZu42Fa7iLine truncated
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"status": true,
|
||||
"html": "<div class=\"panels\">\n <div class=\"panel\">\n <div class=\"day-broadcast-list\">\n <p class=\"broadcast-item-name\">\n 29.06\n </p>\n <div class=\"broadcasts-lists\">\n <div class=\"broadcast-item \">\n <div class=\"broadcast-image\">\n <img loading=\"lazy\" src=\"data:image/jpg;base64,/9j/4AAQSkZJRgABAQEBLAEsAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAFoAoADASIAAhEBAxEB/8QAHAAAAQUBAQEAAAAAAAAAAAAABAECAwUGAAcI/8QAURAAAgEDAwIEAgcFBAUJBwMFAQIDAAQRBRIhMUEGE1FhInEHFDKBkaGxI0JSwdEVYnLhFiQzQ/AlJjRTY4KSovFERXSTlLLSF1VkCDVUc4P/xAAbAQACAwEBAQAAAAAAAAAAAAABAgADBAUGB//EADURAAICAQQBBAAEBQMEAwEAAAABAhEDBBIhMUEFEyJRMmFxsRRCgZHRBqHhI1LB8BYzNGL/2gAMAwEAAhEDEQA/ANSidalVBzSKMVNAjSMqICzMcACrDhJDVQYrXaRomn/VI3ulaSRgM/EQMnsAKqP7JkgR5bhlWJBk46n5f1oqw1hDABM4tpclRuPwnHcGq5vbwzqaLSt3KUQvXfD0Edq1zYgpsGWTOQR7VmVgLHgEn2rYtePcW5hMsckjKVTy2GWOKM0+3/s2wjj2rvxukYetBS4LMukTnxwYeOzkLBVjcsTgDaasWt/LYRlSNowARitZHcKZMlvhXnJ9e1U+sypLdKUbcQuDjtVi65MmbAocp2VflDNSQW3myrGv2mOBTq6B5FlzBt805C7jgZ9/SgURSckmWI0eMR5eUlv7o4qvltvJkKnHHf1qW8uNUsQXlithGCPjEmQ33dR3rJeO/GEmnaXDKIhDeXC/Cobd5aDjOe5P9fSkWRNtHRzaWO1OBpAqhiCRmq+bVNOW/Wye8hW6ZdyxluTWb+ju21jXovrdxcG3s2PDFdzSfjWp1r6PNJvXWdJZ47pMFZVYZDDocVV7zb6LYenJxux9pJDdIr20qSIRwyMGB/Ctnb2Df2XGSh37dw5xyea+do5L/RLuTULS4CwvcvFcR4wIZQfT+FsZ9ia9Y8L+LzdaBdzpPJuhjBKgg7DyCfzB+6rYycuEVLCtO3fTN7pqlLNAwweT+dE5rxeXxfq0twQmqXSA8KdqqrfLjrTx4j13vqt1+I/pTThKDqSon8ZCPFM9W1e6mt4U8jaGY8swzj7vWgrm9u/7NjmiCrO4VWbbkKMt8QB9cD8a81/0k1tuDqlyR77f6U06/rDMxOpXOWwD8Q5/KkFeth+Z61pE001puuOWzgNjG4etG5rxhfEGs9Bqd1x/ep3+kGsYP/Kd1/46gVroLwz2WmtFG0iyMgLr0J7V40df1jvqd3n/AB03+3dYP/vO8/8AmGhQf46P0XP0ov5niG0j/wCrtv1Yn+VUnh6L/ly1bH2ct+VQtLNeTma7mkmlwBvkbJx86tvD0P8AygzY+xETRiuTFv8Acy39s0zyDqe1DIGmlLHpTidx21zPtTbFg9iRWqzoiyybfgTlv0qNG2528serGo2YKdi8ueTUsSqq7pDgdh60LISxR55xk1MYtskbtkqOD7UJ9eRHO4rjsB2om3vRMcCGQqe5HFCw0WMSjHFT9BQUUqKcBvuNMa5KsV5JqWFElxgg0BcRK9lKpGS5AA++iN+/7bY+6njyR1aksayut9OjGPgz86GvNOEFyY0z5bgMPbNaCOSMNhAWPypZYvrDLI6AHGOtGNiumAadaJHCUx70rRbnxVlHEE6DmuMPxEgUwVJIB8gGMqB0qE29W3kk014DjtUoO8qWtjglulPFsqxhsnFWTRfs8EjFIY18rHGKlAcwSGNRyDxRcC59MVHGilSBipIyUGFK/fTJiNWTeWrdOtRXcQ2gU5JmB/c/A1Bq10YY1dygB471LES5K28uBHGyR8tQsMTTqPNBxRSmNnyPL5+dFQR7jxtA9s0vY90Vlzp6JtEZO41DHbFT5DjJByK0K2ZaTcW6e1LaWQa5aQk5HqKKFbKS6jEFvKZ/tvwBVdpgMl4kcQwg64q/1WwW6mMhdgR0AGal0nT47eQscZPfGKJWX1jHttI1x0FThPavMdX8XalpHim9Ecyz2MBWMwFfhAIz16g+9Ud7431S6vnmLKgWVZIUXkRbfT1z3z1rRGE2rRhk4qTs9q2122vMx9JshvLErZqINg+tJ3LZ5KH0A9etelafdW9/bJcWUqTwuMh0Of8A0PtUkpQ7BHbLoXZSeXSvc26XaWrzRrcupZIi2GYDqQKnApd4fbB/LpPLonArgtHeL7YN5dJ5dFha7bR3i+0C+VXeUPSi9tKEqbye0CCL0FL5VFhK7y6G8PtAoi9qXyx6UUEpdlTeT2kCCKl8qixHXBKG8ntAoip3l0SEpdtDeFYgby6UR+1TkoOrKPvpyhSODn5UN43tA4jpwjqcL7U4AAHjP34pXMaOK2DiOni3ZuimphI4GEijB/xVzSTbeXUeyj+tV+430W+xGP4jxTTYZ7x44YlMkx4OBjocZ9q2Wk6XDpy75JFmnPBxwB7D1rM2mozaPo9y0umTq6lncFdrlc5xnOPupLTWPrERltfPtweQZ1JfP54pJ/GVJl2lwwit7Vs2N7At3auPLdMr8QJycVl7DT0Z7lL8ZQLsQ44YnoR7j+ddo/iAwyLb6hKv1qR/hG1lBHoC32j8qP1R44QxZgrnhf7vvRxpZV8uaNeTJLAt0eLIYGtbOYi3hhjl7EHBqw/tFmfY8hbjJDc1mxHBbftRvLuODtJHzzS2sgkn8qNW64Zv+Aau9pJUjD78m7kzSxWsjIZRM8oJ8wK3BA7Y7EUybULWQ+XEJ7i4Axi3jL5PucY/Oo7C7lW9jjcbUb7OWJwR861ct4saY5JxyqVU9Ot9vk04s7lCilt9Od7RHmWLzT1VJAfz6V4F4n8R+LtI1ry9Qe5sJUYtHGUCo654Ixww49a+h4rmHlo0AVyfmrDqCKpPGWg2PibRms70BXU7oZgMtC38Q9R6jvVnsbfwiSlCXLSPM5vpFn1DRPPmhEccB2yfFk78cBR7+p6V55r+qXOryRTXJC7/ALESnKovt+f50d4n8Pah4cuX0y/aJYXYTRyhvgkxkZB7HnoaAsbF5dTtYGXeSUT4SGBGecEcYxms07Tcpdl2NpxUY9HvXhm7h0bw/Y27xOdsSkhSo5Iyep5rTWWoQ3dt5qZRccgkZFUM/h6x1KaO5kG5goXBPAAPYdvnVtY2MUFnPFFnGQM56YrCrR1ocKmea+ObZo/7VubS1kayuYyZwCp8uQdHwDnB4rO/RPFJqGsSWG+QRTwOsm19pC9j6HBxwa9Tn8MWw+suC4aSKRG+LhgwxyO/rXmv0QRNp+t3806sBDE0LYXJySP6VowWnw+TFq3tptFl4tlvtB0+TStSihubYNutLwKVxzzjHf2/WiPDjSalpUE6q0jY2uQO4OKtfpN36h4UnUHazspjjJ4BU5z88cffTfAmnDR/D1qkL+a0uZJHHw5Y9vkOBVz1SyRqXdmDU4I8eERNalSQ6kH0I7U0Q5zxWjeEOdzDBwBTfqq+lCjluNPgz6QdeKUQcdPyrQparjpXfVU54qUDazOGD4gTmu8n1FaE2qZ6U36qhyMUKJTKWGLG44q88PxbVvZD2jArktF6YFWumwCO0usLuzxgd6MS7Tr/AKiBC5bOOBTIZNsjCIZU9fnRK2rBTJLkKThVP867y41cr9hvbvVtnVVA7BYVaR26ckmm26Sajt80bQrZVD3Hqabc2zSXShnLRqAQuMc1a2NuFZT3HSh2Fg0OnGZiIEZyvUIucUeIjbgLKjIccBlxQVvuKHbM8Lb3+JT1+I0S2843szEDqxpqM/uN9jyEbmuAjfhmxjviqy51KKElIyJH9AeB8zU9sxuos7ufapVheSgpwgO2Jt/qR0qSK339eKS2i2rjvRkCEH4jmmSSB7j8k0VuidMZx1qZIxtwx6UNJKEyBy1NUuw9KDkNG2FsYwM5FMaVAMgioFhJOBkk9qXyo04kYsf4VPT5n+lLuHHPMuPtAffUbOHi4cH5GkMMbRtkgnP2cdR86hESDIUAfLihuGRI7o0ezd8VIuFiYEjFQtDtUsOn51AyE+tDexkkSrKkZJzQlzcuxIjyPelCcnimtHSuTHTigTfMpyJGzUd7czTweVKQVBol4+elDyRjB4FLyNvj9FequjAqx4o+xvJkk+IkioH2r1xTrd08zgipG10JLJF9o1VndrIqg8E1ZRqvlNsIye9UlmiSwgZ5qYpLa/HGDKq87M4z7Vcm/Jmm0ugsRlXxjn3qK5G1eOAKga9kminmEbQsqkhSc9qlVmk06B3OXeMMT74pLine truncated
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"status": true,
|
||||
"html": "<div class=\"panels\">\n <div class=\"panel\">\n <div class=\"day-broadcast-list\">\n <p class=\"broadcast-item-name\">\n 29.07\n </p>\n <div class=\"broadcasts-lists\">\n </div>\n </div>\n </div>\n <div class=\"panel\">\n <div class=\"day-broadcast-list\">\n <p class=\"broadcast-item-name\">\n 30.07\n </p>\n <div class=\"broadcasts-lists\">\n </div>\n </div>\n </div>\n <div class=\"panel\">\n <div class=\"day-broadcast-list\">\n <p class=\"broadcast-item-name\">\n 31.07\n </p>\n <div class=\"broadcasts-lists\">\n </div>\n </div>\n </div>\n </div>"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<div class=\"panels\">\n <div class=\"panel\">\n <div class=\"day-broadcast-list\">\n <p class=\"broadcast-item-name\">\n 19.02\n </p>\n <div class=\"broadcasts-lists\">\n </div>\n </div>\n </div>\n <div class=\"panel\">\n <div class=\"day-broadcast-list\">\n <p class=\"broadcast-item-name\">\n 20.02\n </p>\n <div class=\"broadcasts-lists\">\n </div>\n </div>\n </div>\n <div class=\"panel\">\n <div class=\"day-broadcast-list\">\n <p class=\"broadcast-item-name\">\n 21.02\n </p>\n <div class=\"broadcasts-lists\">\n </div>\n </div>\n </div>\n </div>
|
||||
@@ -1,52 +1,134 @@
|
||||
const axios = require('axios')
|
||||
const cheerio = require('cheerio')
|
||||
const url = require('url')
|
||||
const { DateTime } = require('luxon')
|
||||
const dayjs = require('dayjs')
|
||||
const utc = require('dayjs/plugin/utc')
|
||||
const timezone = require('dayjs/plugin/timezone')
|
||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||
|
||||
let cachedToken = null
|
||||
let tokenExpiry = null
|
||||
dayjs.extend(utc)
|
||||
dayjs.extend(timezone)
|
||||
dayjs.extend(customParseFormat)
|
||||
|
||||
let sessionCache = null
|
||||
|
||||
async function getSession(forceRefresh = false) {
|
||||
if (sessionCache && !forceRefresh) {
|
||||
return sessionCache
|
||||
}
|
||||
|
||||
try {
|
||||
const initResponse = await axios.get('https://tv.dir.bg/init')
|
||||
|
||||
if (!initResponse.data) {
|
||||
throw new Error('No response data from init endpoint')
|
||||
}
|
||||
|
||||
// Extract cookies from response headers
|
||||
const setCookieHeader = initResponse.headers['set-cookie']
|
||||
let xsrfToken = null
|
||||
let dirSessionCookie = null
|
||||
|
||||
if (setCookieHeader) {
|
||||
setCookieHeader.forEach(cookie => {
|
||||
// Extract XSRF token from cookie
|
||||
const xsrfMatch = cookie.match(/XSRF-TOKEN=([^;]+)/)
|
||||
if (xsrfMatch) {
|
||||
xsrfToken = decodeURIComponent(xsrfMatch[1])
|
||||
}
|
||||
|
||||
// Extract dir_session cookie
|
||||
const sessionMatch = cookie.match(/dir_session=([^;]+)/)
|
||||
if (sessionMatch) {
|
||||
dirSessionCookie = sessionMatch[1]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const csrfToken = initResponse.data.csrfToken
|
||||
|
||||
if (!csrfToken) {
|
||||
throw new Error('No CSRF/XSRF token found in response')
|
||||
}
|
||||
|
||||
// Build cookie string
|
||||
let cookieString = ''
|
||||
if (xsrfToken) {
|
||||
cookieString += `XSRF-TOKEN=${encodeURIComponent(xsrfToken)}`
|
||||
}
|
||||
if (dirSessionCookie) {
|
||||
if (cookieString) cookieString += '; '
|
||||
cookieString += `dir_session=${dirSessionCookie}`
|
||||
}
|
||||
|
||||
sessionCache = {
|
||||
csrfToken,
|
||||
cookieString,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
|
||||
return sessionCache
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error getting session:', error.message)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
site: 'tv.dir.bg',
|
||||
days: 2,
|
||||
async url({ channel, date }) {
|
||||
const token = await getToken()
|
||||
if (!token) {
|
||||
throw new Error('Unable to retrieve CSRF token')
|
||||
}
|
||||
|
||||
const form = new url.URLSearchParams({
|
||||
_token: token,
|
||||
channel: channel.site_id,
|
||||
day: date.format('YYYY-MM-DD')
|
||||
})
|
||||
|
||||
return axios.post('https://tv.dir.bg/load/programs', form.toString(), {
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
url: 'https://tv.dir.bg/load/programs',
|
||||
request: {
|
||||
maxContentLength: 125000000, // 10 MB
|
||||
method: 'POST',
|
||||
async headers() {
|
||||
try {
|
||||
const session = await getSession()
|
||||
return {
|
||||
'Cookie': session.cookieString,
|
||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error getting headers:', error.message)
|
||||
throw error
|
||||
}
|
||||
})
|
||||
},
|
||||
async data({ channel, date }) {
|
||||
try {
|
||||
const session = await getSession()
|
||||
|
||||
const params = new URLSearchParams()
|
||||
params.append('_token', session.csrfToken)
|
||||
params.append('channel', channel.site_id)
|
||||
params.append('day', date.format('YYYY-MM-DD'))
|
||||
|
||||
return params
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error preparing request data:', error.message)
|
||||
throw error
|
||||
}
|
||||
},
|
||||
},
|
||||
parser({ content, date }) {
|
||||
const programs = []
|
||||
const items = parseItems(content)
|
||||
|
||||
|
||||
items.forEach(item => {
|
||||
const $item = cheerio.load(item)
|
||||
const prev = programs[programs.length - 1]
|
||||
const $item = cheerio.load(item)
|
||||
let start = parseStart($item, date)
|
||||
if (!start) return
|
||||
|
||||
if (prev) {
|
||||
if (start < prev.start) {
|
||||
start = start.plus({ days: 1 })
|
||||
date = date.plus({ days: 1 })
|
||||
if (start.isBefore(prev.start)) {
|
||||
start = start.add(1, 'd')
|
||||
}
|
||||
prev.stop = start
|
||||
}
|
||||
|
||||
const stop = start.plus({ minutes: 30 })
|
||||
const stop = start.add(30, 'm')
|
||||
programs.push({
|
||||
title: parseTitle($item),
|
||||
start,
|
||||
@@ -56,6 +138,7 @@ module.exports = {
|
||||
|
||||
return programs
|
||||
},
|
||||
|
||||
async channels() {
|
||||
try {
|
||||
const response = await axios.get('https://tv.dir.bg/channels')
|
||||
@@ -63,7 +146,7 @@ module.exports = {
|
||||
|
||||
const channels = []
|
||||
|
||||
$('.channel_cont').each((index, element) => {
|
||||
$('.channel_cont').each((_index, element) => {
|
||||
const $element = $(element)
|
||||
|
||||
const $link = $element.find('a.channel_link')
|
||||
@@ -79,63 +162,55 @@ module.exports = {
|
||||
channels.push({
|
||||
lang: 'bg',
|
||||
site_id: site_id,
|
||||
name: name,
|
||||
logo: logo
|
||||
name: name.trim(),
|
||||
logo: logo ? (logo.startsWith('http') ? logo : `https://tv.dir.bg${logo}`) : null
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return channels
|
||||
return channels
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching channels:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function getToken() {
|
||||
if (cachedToken && tokenExpiry && DateTime.now() < tokenExpiry) {
|
||||
return cachedToken
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.get('https://tv.dir.bg/init', { headers: {'X-Requested-With': 'XMLHttpRequest'} })
|
||||
|
||||
// Check different possible locations for the token
|
||||
let token = null
|
||||
if (response.data && response.data.csrfToken) {
|
||||
token = response.data.csrfToken
|
||||
} catch (error) {
|
||||
console.error('Error fetching channels:', error.message)
|
||||
return []
|
||||
}
|
||||
|
||||
if (token) {
|
||||
cachedToken = token
|
||||
tokenExpiry = DateTime.now().plus({ hours: 1 })
|
||||
return token
|
||||
} else {
|
||||
console.error('CSRF token not found in response structure:', Object.keys(response.data || {}))
|
||||
return null
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching token:', error.message)
|
||||
return null
|
||||
},
|
||||
|
||||
clearSession() {
|
||||
sessionCache = null
|
||||
}
|
||||
}
|
||||
|
||||
function parseStart($item, date) {
|
||||
const timeText = $item('.broadcast-time').text().trim()
|
||||
if (!timeText) return null
|
||||
const time = $item('.broadcast-time').text().trim()
|
||||
const dateString = `${date.format('YYYY-MM-DD')} ${time}`
|
||||
|
||||
const [hours, minutes] = timeText.split(':').map(Number)
|
||||
const dateTime = date.isValid ? date : DateTime.fromISO(date)
|
||||
return dateTime.set({ hour: hours, minute: minutes, second: 0, millisecond: 0 })
|
||||
return dayjs.tz(dateString, 'YYYY-MM-DD HH:mm', 'Europe/Sofia')
|
||||
}
|
||||
|
||||
|
||||
function parseTitle($item) {
|
||||
return $item('.broadcast-title').text().trim()
|
||||
return $item('.broadcast-title').text()
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim()
|
||||
}
|
||||
|
||||
function parseItems(content) {
|
||||
const $ = cheerio.load(content)
|
||||
return $('.broadcast-item').toArray()
|
||||
}
|
||||
try {
|
||||
const json = JSON.parse(content)
|
||||
|
||||
if (!json || json.status !== true) {
|
||||
return []
|
||||
}
|
||||
|
||||
const $ = cheerio.load(json.html)
|
||||
const items = $('.broadcast-item').toArray()
|
||||
|
||||
return items
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error parsing items:', error.message)
|
||||
console.error('Error stack:', error.stack)
|
||||
return []
|
||||
}
|
||||
}
|
||||
@@ -9,46 +9,42 @@ dayjs.extend(utc)
|
||||
|
||||
const date = dayjs.utc('2025-06-30', 'YYYY-MM-DD').startOf('d')
|
||||
const channel = {
|
||||
site_id: '12',
|
||||
site_id: '61',
|
||||
xmltv_id: 'BTV.bg'
|
||||
}
|
||||
|
||||
it('can generate valid url', () => {
|
||||
expect(url({ channel, date })).toBe('https://tv.dir.bg/programa/12')
|
||||
expect(url).toBe('https://tv.dir.bg/load/programs')
|
||||
})
|
||||
|
||||
it('can parse response', () => {
|
||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'))
|
||||
const result = parser({ content, date }).map(p => {
|
||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||
const results = parser({ content, date }).map(p => {
|
||||
p.start = p.start.toJSON()
|
||||
p.stop = p.stop.toJSON()
|
||||
return p
|
||||
})
|
||||
|
||||
expect(result).toMatchObject([
|
||||
{
|
||||
start: '2025-06-30T08:00:00.000Z',
|
||||
stop: '2025-06-30T10:00:00.000Z',
|
||||
title: 'Купа на Франция: Еспали - Пари Сен Жермен'
|
||||
},
|
||||
{
|
||||
start: '2025-06-30T10:00:00.000Z',
|
||||
stop: '2025-06-30T12:00:00.000Z',
|
||||
title: 'Ла Лига: Леганес - Реал Сосиедад'
|
||||
},
|
||||
{
|
||||
start: '2025-06-30T12:00:00.000Z',
|
||||
stop: '2025-06-30T13:00:00.000Z',
|
||||
title: 'Пред Стадиона" - спортно шоу'
|
||||
}
|
||||
])
|
||||
expect(results.length).toBe(63)
|
||||
|
||||
expect(results[0]).toMatchObject({
|
||||
start: '2025-06-30T03:00:00.000Z',
|
||||
stop: '2025-06-30T03:30:00.000Z',
|
||||
title: 'Светът на здравето'
|
||||
})
|
||||
|
||||
expect(results[62]).toMatchObject({
|
||||
start: '2025-07-01T02:00:00.000Z',
|
||||
stop: '2025-07-01T02:30:00.000Z',
|
||||
title: 'Убийства в Рая , сезон 1 , епизод 7'
|
||||
})
|
||||
})
|
||||
|
||||
it('can handle empty guide', () => {
|
||||
const result = parser({
|
||||
date,
|
||||
channel,
|
||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_data.html'))
|
||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||
})
|
||||
expect(result).toMatchObject([])
|
||||
})
|
||||
Reference in new issue
Block a user