implemented content check on ftp servers

This commit is contained in:
2026-09-09 14:59:30 +02:00
parent b91703f39d
commit 9283151f3b
7 changed files with 1018 additions and 69 deletions
+23 -17
View File
@@ -1,7 +1,13 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Python Debugger: Current File",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
},
{
"name": "Python Debugger: Tikmon",
"type": "debugpy",
@@ -9,10 +15,10 @@
"program": "${file}",
"console": "integratedTerminal",
"env": {
"INTERVAL" : "5",
"INFLUXDB_TOKEN":"apiv3_tbEpA8JmIRTfr8Wbw9npD79BcMlFsnV4_jhdt-CdUP53Mos61KBODGaggl2g5oKZZvZrZu3e6mpob6zorhEdbg",
"INFLUXDB_URL" : "http://edelweiss-srv:8181",
"INFLUXDB_DATABASE" : "edelweiss",
"INTERVAL": "5",
"INFLUXDB_TOKEN": "apiv3_tbEpA8JmIRTfr8Wbw9npD79BcMlFsnV4_jhdt-CdUP53Mos61KBODGaggl2g5oKZZvZrZu3e6mpob6zorhEdbg",
"INFLUXDB_URL": "http://edelweiss-srv:8181",
"INFLUXDB_DATABASE": "edelweiss",
"MIKROTIK_IP": "192.168.31.1",
"MIKROTIK_USER": "service",
"MIKROTIK_PASSWORD": "dataservice",
@@ -28,10 +34,10 @@
"program": "${file}",
"console": "integratedTerminal",
"env": {
"INTERVAL" : "5",
"INFLUXDB_TOKEN":"apiv3_tbEpA8JmIRTfr8Wbw9npD79BcMlFsnV4_jhdt-CdUP53Mos61KBODGaggl2g5oKZZvZrZu3e6mpob6zorhEdbg",
"INFLUXDB_URL" : "http://edelweiss-srv:8181",
"INFLUXDB_DATABASE" : "edelweiss",
"INTERVAL": "5",
"INFLUXDB_TOKEN": "apiv3_tbEpA8JmIRTfr8Wbw9npD79BcMlFsnV4_jhdt-CdUP53Mos61KBODGaggl2g5oKZZvZrZu3e6mpob6zorhEdbg",
"INFLUXDB_URL": "http://edelweiss-srv:8181",
"INFLUXDB_DATABASE": "edelweiss",
"PORT": "/dev/ttyS0",
"BAUD": "2400",
"LOG_FILE": "/tmp/upsmon.log",
@@ -48,17 +54,17 @@
"console": "integratedTerminal",
"env": {
"PYTHONPATH": "${workspaceFolder}",
"INTERVAL" : "15",
"INTERVAL": "15",
"LOG_FILE": "/tmp/upsmon.log",
"LOG_FILE_LVL": "WARNING",
"LOG_CLI_LVL": "DEBUG",
"PROJECTOR_IP":"192.168.31.10",
"PROJECTOR_USER":"alberto",
"PROJECTOR_PASSWORD":"alberto",
"MQTT_USER":"projmon",
"MQTT_PASSWORD":"projmon",
"MQTT_HOST":"192.168.31.26",
"MQTT_PORT":"1883"
"PROJECTOR_IP": "192.168.31.10",
"PROJECTOR_USER": "alberto",
"PROJECTOR_PASSWORD": "alberto",
"MQTT_USER": "projmon",
"MQTT_PASSWORD": "projmon",
"MQTT_HOST": "192.168.31.26",
"MQTT_PORT": "1883"
}
}
]
+629
View File
@@ -0,0 +1,629 @@
{
"servers": [
{
"name": "DELUXE",
"host": "192.168.31.16",
"port": 21,
"username": "dcpftp",
"password": "dcpftp",
"timeout": 15,
"dirs": [
{
"name": ".",
"modified_time": "2026-09-09T10:42:53",
"unique": "FD02UF00001"
},
{
"name": "..",
"modified_time": "2026-09-09T10:42:53",
"unique": "FD02UF00001"
},
{
"name": "1763910_CatInTheHat_TLR-F5_S_IT-XX_IT_51_2K_WR_20260607_DLX_SMPTE_OV",
"modified_time": "2026-07-13T13:02:16",
"unique": "FD02UF10012"
},
{
"name": "1763911_CatInTheHat_TLR-F5_F_IT-XX_IT_51_2K_WR_20260607_DLX_SMPTE_OV",
"modified_time": "2026-07-13T13:12:21",
"unique": "FD02UF1003A"
},
{
"name": "1785943_Gatto_TLR-A-2D_S_IT-XX_IT_51_2K_DI_20260609_DLX_IOP_",
"modified_time": "2026-08-28T14:14:01",
"unique": "FD02UF10024"
},
{
"name": "1785944_Gatto_TLR-A-2D_F_IT-XX_IT_51_2K_DI_20260609_DLX_IOP",
"modified_time": "2026-08-28T14:14:01",
"unique": "FD02UF10023"
},
{
"name": "1874853_LinkinParkU_TLR-Ext_F_EN-it_IT_51_4K_NXO_20260908_DLX_IOP_OV",
"modified_time": "2026-09-09T10:42:53",
"unique": "FD02UF10061"
},
{
"name": "1874873_QueenBudapest_TLR-Ext_F_IT-XX_IT_51_4K_NXO_20260908_DLX_IOP_OV",
"modified_time": "2026-09-09T10:42:53",
"unique": "FD02UF10062"
},
{
"name": "AndataCosi60No_TLR-1_F_IT-XX_IT_51_2K_VISI_20260908_SMPTE_OV",
"modified_time": "2026-09-09T10:04:56",
"unique": "FD02UF10032"
},
{
"name": "AndataCosi60No_TLR-1_S_IT-XX_IT_51_2K_VISI_20260908_SMPTE_OV",
"modified_time": "2026-09-09T10:04:56",
"unique": "FD02UF10033"
},
{
"name": "AndataCosiNo_TLR-1_F_IT-XX_IT_51_2K_VISI_20260908_SMPTE_OV",
"modified_time": "2026-09-09T10:21:45",
"unique": "FD02UF10036"
},
{
"name": "AndataCosiNo_TLR-1_S_IT-XX_IT_51_2K_VISI_20260908_SMPTE_OV",
"modified_time": "2026-09-09T10:21:45",
"unique": "FD02UF10037"
},
{
"name": "AssassinClass_TLR-OURTIME_F-177_IT-XX_IT-TD_51_2K_20260804_PZO_SMPTE_OV",
"modified_time": "2026-08-05T14:03:39",
"unique": "FD02UF1000C"
},
{
"name": "AssassinClass_TLR-OURTIME_S-177_IT-XX_IT-TD_51_2K_20260804_PZO_SMPTE_OV",
"modified_time": "2026-08-05T14:03:39",
"unique": "FD02UF1000B"
},
{
"name": "AvengEndGamEnc_TLR-A-2D-Tutti_F_IT-XX_IT_51_2K_DI_20260820_DDS_IOP",
"modified_time": "2026-08-28T15:11:50",
"unique": "FD02UF10026"
},
{
"name": "AvengEndGamEnc_TLR-A-2D-Tutti_S_IT-XX_IT_51_2K_DI_20260820_DDS_IOP",
"modified_time": "2026-08-28T15:11:49",
"unique": "FD02UF10025"
},
{
"name": "AvengersDoomsd_TLR-F-2D-Tutti_F_IT-XX_IT_51_2K_DI_20260720_DDS_IOP",
"modified_time": "2026-07-21T16:32:46",
"unique": "FD02UF10053"
},
{
"name": "AvengersDoomsd_TLR-F-2D-Tutti_S_IT-XX_IT_51_2K_DI_20260720_DDS_IOP",
"modified_time": "2026-07-21T16:32:46",
"unique": "FD02UF10052"
},
{
"name": "AvengersDoomsd_TLR-P-2D-Tutti_F_IT-XX_IT_51_2K_DI_20260821_DDS_IOP",
"modified_time": "2026-08-28T15:12:03",
"unique": "FD02UF10028"
},
{
"name": "AvengersDoomsd_TLR-P-2D-Tutti_S_IT-XX_IT_51_2K_DI_20260821_DDS_IOP",
"modified_time": "2026-08-28T15:11:58",
"unique": "FD02UF10027"
},
{
"name": "Behemoth_TLR-A-2D-Tutti_F_IT-XX_IT_51_2K_DI_20260716_DDS_IOP",
"modified_time": "2026-08-19T13:32:52",
"unique": "FD02UF1001A"
},
{
"name": "Behemoth_TLR-A-2D-Tutti_S_IT-XX_IT_51_2K_DI_20260716_DDS_IOP",
"modified_time": "2026-08-19T13:42:38",
"unique": "FD02UF1001E"
},
{
"name": "Cars20year_TLR-30A_S_IT-XX_IT_20_2K_DI_20260624_RL1_IOP_OV",
"modified_time": "2026-08-14T07:05:17",
"unique": "FD02UF10011"
},
{
"name": "Clayface_TLR-F2_F_IT-XX_IT_51_4K_WR_20260721_EKN_SMPTE_OV",
"modified_time": "2026-07-24T09:22:49",
"unique": "FD02UF1006B"
},
{
"name": "Clayface_TLR-F2_S_IT-XX_IT_51_4K_WR_20260721_EKN_SMPTE_OV",
"modified_time": "2026-07-24T09:22:48",
"unique": "FD02UF1006A"
},
{
"name": "Clayface_TLR-F3_F_IT-XX_IT_51_4K_WR_20260721_EKN_SMPTE_OV",
"modified_time": "2026-07-24T09:14:34",
"unique": "FD02UF10068"
},
{
"name": "Clayface_TLR-F3_S_IT-XX_IT_51_4K_WR_20260721_EKN_SMPTE_OV",
"modified_time": "2026-07-24T09:14:34",
"unique": "FD02UF10069"
},
{
"name": "DIORIDE_TLR60_F_IT-XX_IT_51_4K_ST_20260903_FLA_IOP_OV",
"modified_time": "2026-09-04T14:42:12",
"unique": "FD02UF1005C"
},
{
"name": "DIORIDE_TLR60_S_IT-XX_IT_51_4K_ST_20260904_FLA_IOP_OV",
"modified_time": "2026-09-04T14:42:12",
"unique": "FD02UF1005D"
},
{
"name": "DIORIDE_TLR90_F_IT-XX_IT_51_4K_ST_20260903_FLA_IOP_OV",
"modified_time": "2026-09-04T14:42:12",
"unique": "FD02UF1005B"
},
{
"name": "DIORIDE_TLR90_S_IT-XX_IT_51_4K_ST_20260904_FLA_IOP_OV",
"modified_time": "2026-09-04T14:42:12",
"unique": "FD02UF1005E"
},
{
"name": "DUELADRIFUGA60_TLR_F-185_IT-XX_IT_51_2K_EAG_20260907_PBC_IOP_OV",
"modified_time": "2026-09-09T08:34:09",
"unique": "FD02UF10030"
},
{
"name": "DUELADRIFUGA60_TLR_S-239_IT-XX_IT_51_2K_EAG_20260907_PBC_IOP_OV",
"modified_time": "2026-09-09T08:34:10",
"unique": "FD02UF10031"
},
{
"name": "Digger_TLR-F4_F_IT-XX_IT_51_4K_WR_20260712_EKN_SMPTE_OV",
"modified_time": "2026-07-13T15:41:56",
"unique": "FD02UF1003E"
},
{
"name": "Digger_TLR-F4_S_IT-XX_IT_51_4K_WR_20260712_EKN_SMPTE_OV",
"modified_time": "2026-07-13T15:41:51",
"unique": "FD02UF1003D"
},
{
"name": "Digger_TLR-F6-REV2_F_EN-XX_IT_51_4K_WR_20260727_EKN_SMPTE_OV",
"modified_time": "2026-07-28T11:24:12",
"unique": "FD02UF10001"
},
{
"name": "Digger_TLR-F6-REV2_S_EN-XX_IT_51_4K_WR_20260727_EKN_SMPTE_OV",
"modified_time": "2026-07-28T11:24:12",
"unique": "FD02UF10002"
},
{
"name": "Digger_TLR-F6-REV_F_EN-XX_IT_51_4K_WR_20260717_EKN_SMPTE_OV",
"modified_time": "2026-07-20T10:31:59",
"unique": "FD02UF1004A"
},
{
"name": "Digger_TLR-F6-REV_F_IT-XX_IT_51_4K_WR_20260717_EKN_SMPTE_OV",
"modified_time": "2026-07-20T10:31:59",
"unique": "FD02UF1004B"
},
{
"name": "Digger_TLR-F6-REV_S_EN-XX_IT_51_4K_WR_20260717_EKN_SMPTE_OV",
"modified_time": "2026-07-20T10:31:59",
"unique": "FD02UF1004D"
},
{
"name": "Digger_TLR-F6-REV_S_IT-XX_IT_51_4K_WR_20260717_EKN_SMPTE_OV",
"modified_time": "2026-07-20T10:31:59",
"unique": "FD02UF1004C"
},
{
"name": "Digger_TLR-F6_F_EN-XX_IT_51_4K_WR_20260711_EKN_SMPTE_OV",
"modified_time": "2026-07-13T15:34:07",
"unique": "FD02UF1003C"
},
{
"name": "Digger_TLR-F6_F_IT-XX_IT_51_4K_WR_20260713_EKN_SMPTE_OV",
"modified_time": "2026-07-14T14:43:14",
"unique": "FD02UF10046"
},
{
"name": "Digger_TLR-F6_S_EN-XX_IT_51_4K_WR_20260711_EKN_SMPTE_OV",
"modified_time": "2026-07-13T15:34:07",
"unique": "FD02UF1003B"
},
{
"name": "Digger_TLR-F6_S_IT-XX_IT_51_4K_WR_20260713_EKN_SMPTE_OV",
"modified_time": "2026-07-14T14:43:14",
"unique": "FD02UF10045"
},
{
"name": "DioRide_TLR-60_F_IT-XX_IT-6_51_4K_PIP_20260713_RL1_IOP_OV",
"modified_time": "2026-07-13T08:44:03",
"unique": "FD02UF10038"
},
{
"name": "DioRide_TLR-60_S_IT-XX_IT-6_51_4K_PIP_20260713_RL1_IOP_OV",
"modified_time": "2026-07-13T08:44:03",
"unique": "FD02UF10039"
},
{
"name": "DogStarsThe_TLR-J-2D-10Plus_F_IT-XX_IT_51_2K_DI_20260708_DDS_IOP",
"modified_time": "2026-07-23T15:22:28",
"unique": "FD02UF10057"
},
{
"name": "DogStarsThe_TLR-J-2D-10Plus_S_IT-XX_IT_51_2K_DI_20260708_DDS_IOP",
"modified_time": "2026-07-23T15:22:28",
"unique": "FD02UF10065"
},
{
"name": "DontLookBkAngr_TLR-A-2D-6Plus_F_EN-it_IT_51_2K_DI_20260813_DDS_IOP",
"modified_time": "2026-08-19T13:42:43",
"unique": "FD02UF10020"
},
{
"name": "DontLookBkAngr_TLR-A-2D-6Plus_S_EN-it_IT_51_2K_DI_20260813_DDS_IOP",
"modified_time": "2026-08-19T13:42:43",
"unique": "FD02UF1001F"
},
{
"name": "DontLookBkAngr_TLR-C-2D-6Plus_F_EN-it_IT_51_2K_DI_20260901_DDS_IOP",
"modified_time": "2026-09-02T15:31:47",
"unique": "FD02UF1002C"
},
{
"name": "DontLookBkAngr_TLR-C-2D-6Plus_S_EN-it_IT_51_2K_DI_20260901_DDS_IOP",
"modified_time": "2026-09-02T15:22:06",
"unique": "FD02UF1002B"
},
{
"name": "DoveLaFiesta_TRL-60_F_IT-XX_51_2K_VISION_20260811",
"modified_time": "2026-08-17T09:22:20",
"unique": "FD02UF10017"
},
{
"name": "DoveLaFiesta_TRL-60_S_IT-XX_51_2K_VISION_20260811",
"modified_time": "2026-08-17T09:22:20",
"unique": "FD02UF10016"
},
{
"name": "EndOakStreet_Greeting_TLR-F5_F_IT-XX_IT_51_4K_NXT_20260717_NXT_SMPTE_OV",
"modified_time": "2026-07-24T09:42:22",
"unique": "FD02UF1006D"
},
{
"name": "EndOakStreet_Greeting_TLR-F5_S_IT-XX_IT_51_4K_NXT_20260717_NXT_SMPTE_OV",
"modified_time": "2026-07-24T09:42:22",
"unique": "FD02UF1006C"
},
{
"name": "FIP60ANTEPRIMA_TLR_F-185_IT-IT_IT_51_2K_EAG_20260720_PBC_IOP_OV",
"modified_time": "2026-07-20T16:54:51",
"unique": "FD02UF1004E"
},
{
"name": "FIP60ANTEPRIMA_TLR_S-239_IT-IT_INT_51_2K_EAG_20260720_PBC_IOP_OV",
"modified_time": "2026-07-20T16:54:51",
"unique": "FD02UF1004F"
},
{
"name": "FIP60DATA_TLR_F-185_IT-XX_IT_51_2K_EAG_20260716_PBC_IOP_OV",
"modified_time": "2026-07-22T15:57:32",
"unique": "FD02UF10055"
},
{
"name": "FIP60DATA_TLR_S-239_IT-XX_IT_51_2K_EAG_20260716_PBC_IOP_OV",
"modified_time": "2026-07-22T15:57:32",
"unique": "FD02UF10054"
},
{
"name": "GeorgeMFaithTr_TLR-B_F_EN-it_IT_51_4K_UPI_20260908_LSF_SMPTE_OV",
"modified_time": "2026-09-09T09:34:17",
"unique": "FD02UF1002F"
},
{
"name": "GeorgeMFaithTr_TLR-B_S_EN-it_IT_51_4K_UPI_20260908_LSF_SMPTE_OV",
"modified_time": "2026-09-09T09:33:05",
"unique": "FD02UF1002E"
},
{
"name": "Ghost2Big_TLR-1_F_EN-it_51_2K_20260731_NXO_SMPTE_OV",
"modified_time": "2026-07-31T12:16:12",
"unique": "FD02UF10079"
},
{
"name": "JESOPAZZO_TLR-120_F_IT-XX_51_2K_01_20260730_MAF_IOP_OV",
"modified_time": "2026-08-03T14:32:41",
"unique": "FD02UF10006"
},
{
"name": "JESOPAZZO_TLR-120_S_IT-XX_51_2K_01_20260730_MAF_IOP_OV",
"modified_time": "2026-08-03T14:32:41",
"unique": "FD02UF10003"
},
{
"name": "JumanjiOpenWor_TLR-D_F_IT-XX_IT_51_2K_SPE_20260729_DMK_IOP_OV",
"modified_time": "2026-07-29T11:58:57",
"unique": "FD02UF10073"
},
{
"name": "JumanjiOpenWor_TLR-D_S_IT-XX_IT_51_2K_SPE_20260729_DMK_IOP_OV",
"modified_time": "2026-07-29T11:58:57",
"unique": "FD02UF10072"
},
{
"name": "KatyPerryTour_TLR_F_EN-it_IT_51_4K_TFR_20260727_MPS_IOP_OV",
"modified_time": "2026-07-30T14:12:50",
"unique": "FD02UF10078"
},
{
"name": "Kettice_TLR-60_F_IT-XX_IT-NR_51_4K_NULL_20260729_FBF_SMPTE_OV",
"modified_time": "2026-07-30T13:52:00",
"unique": "FD02UF10077"
},
{
"name": "Kettice_TLR-60_S_IT-XX_IT-NR_51_4K_NULL_20260729_FBF_SMPTE_OV",
"modified_time": "2026-07-30T13:52:00",
"unique": "FD02UF10076"
},
{
"name": "LEstranea_TLR-112sec_F_IT-XX_IT_51_4K_01D_20260804_IML_SMPTE_OV",
"modified_time": "2026-08-05T08:41:39",
"unique": "FD02UF1000A"
},
{
"name": "LEstranea_TLR-112sec_S_IT-XX_IT_51_4K_01D_20260804_IML_SMPTE_OV",
"modified_time": "2026-08-05T08:41:38",
"unique": "FD02UF10009"
},
{
"name": "LaCittaDeiVivi_TLR-B_F_IT-XX_51_4K_Eagle_20260828_LSF_IOP_OV",
"modified_time": "2026-08-31T07:52:54",
"unique": "FD02UF10029"
},
{
"name": "LaCittaDeiVivi_TLR-B_S_IT-XX_51_4K_Eagle_20260828_LSF_IOP_OV2",
"modified_time": "2026-08-31T07:52:54",
"unique": "FD02UF1002A"
},
{
"name": "LaCittaDeiVivi_TLR_F_IT_51_4K_20260807_AUG_IOP_OV",
"modified_time": "2026-08-11T07:52:46",
"unique": "FD02UF10004"
},
{
"name": "LaCittaDeiVivi_TLR_S_IT_51_4K_20260807_AUG_IOP_OV",
"modified_time": "2026-08-11T07:52:46",
"unique": "FD02UF10005"
},
{
"name": "LinkinParkU_TLR_F_EN-it_IT_51_4K_TFR_20260826_MPS_IOP_OV",
"modified_time": "2026-09-09T10:21:46",
"unique": "FD02UF1005F"
},
{
"name": "Malloppo_SPOT-30A_F_IT-XX_51_2K_VISION_20260713",
"modified_time": "2026-07-14T08:33:02",
"unique": "FD02UF10044"
},
{
"name": "Malloppo_SPOT-30A_S_IT-XX_51_2K_VISION_20260713",
"modified_time": "2026-07-14T08:23:49",
"unique": "FD02UF1003F"
},
{
"name": "Malloppo_SPOT-30B_F_IT-XX_51_2K_VISION_20260713",
"modified_time": "2026-07-14T08:23:49",
"unique": "FD02UF10040"
},
{
"name": "Malloppo_SPOT-30B_S_IT-XX_51_2K_VISION_20260713",
"modified_time": "2026-07-14T08:23:49",
"unique": "FD02UF10041"
},
{
"name": "Malloppo_TRL-60_F_IT-XX_51_2K_VISION_20260713",
"modified_time": "2026-07-14T08:32:48",
"unique": "FD02UF10042"
},
{
"name": "Malloppo_TRL-60_S_IT-XX_51_2K_VISION_20260713",
"modified_time": "2026-07-14T08:33:02",
"unique": "FD02UF10043"
},
{
"name": "NGioiaNDolore_TSR-24_F-185_IT_51_3996x2160_20260721_M74_IOP_OV",
"modified_time": "2026-07-21T16:13:27",
"unique": "FD02UF10050"
},
{
"name": "NGioiaNDolore_TSR-24_S-239_IT_51_4096x1716_20260721_M74_IOP_OV",
"modified_time": "2026-07-21T16:14:35",
"unique": "FD02UF10051"
},
{
"name": "NessunDolore_TLR-108sec_F_IT-XX_IT_51_2K_01D_20260730_IML_SMPTE_OV",
"modified_time": "2026-08-14T08:41:29",
"unique": "FD02UF10013"
},
{
"name": "NessunDolore_TLR-108sec_S_IT-XX_IT_51_2K_01D_20260730_IML_SMPTE_OV",
"modified_time": "2026-08-14T08:41:42",
"unique": "FD02UF1001C"
},
{
"name": "Nimrods_TLR_F_EN-it_IT_51_4K_TFR_20260708_MPS_IOP_OV",
"modified_time": "2026-07-15T10:24:05",
"unique": "FD02UF10047"
},
{
"name": "OBSESSIONTRLA_TLR-2_F-185_IT-XX_IT_51_2K_UP_20260903_PBC_IOP_OV",
"modified_time": "2026-09-04T09:08:00",
"unique": "FD02UF1005A"
},
{
"name": "OBSESSIONTRLA_TLR-2_S-239_IT-XX_IT_51_2K_UP_20260903_PBC_IOP_OV",
"modified_time": "2026-09-04T09:07:59",
"unique": "FD02UF10059"
},
{
"name": "PPTDM_PRO-LoveRev_F_IT-XX_IT_51_2K_PC_20260730_DMK_SMPTE_OV",
"modified_time": "2026-08-05T07:13:10",
"unique": "FD02UF10007"
},
{
"name": "PPTDM_PRO-LoveRev_S_IT-XX_IT_51_2K_PC_20260730_DMK_SMPTE_OV",
"modified_time": "2026-08-05T07:13:10",
"unique": "FD02UF10008"
},
{
"name": "PracticalMagic2_TLR-F4_F_IT-XX_IT_51_4K_WR_20260627_DLX_SMPTE_OV",
"modified_time": "2026-08-19T13:37:04",
"unique": "FD02UF1001D"
},
{
"name": "PracticalMagic2_TLR-F4_S_IT-XX_IT_51_4K_WR_20260627_DLX_SMPTE_OV",
"modified_time": "2026-08-19T13:37:03",
"unique": "FD02UF1001B"
},
{
"name": "QueenBudapest_TLR-1_F_IT-XX_51_4K_20260825_NXO_IOP_OV",
"modified_time": "2026-09-09T10:21:47",
"unique": "FD02UF10060"
},
{
"name": "ResidentEvil_TLR-H_F_IT-XX_IT_51_2K_SPE_20260723_DMK_IOP_OV",
"modified_time": "2026-07-23T16:13:15",
"unique": "FD02UF10066"
},
{
"name": "ResidentEvil_TLR-H_S_IT-XX_IT_51_2K_SPE_20260723_DMK_IOP_OV",
"modified_time": "2026-07-23T16:13:15",
"unique": "FD02UF10067"
},
{
"name": "SONY_SMBND_TOMHOLLANDGREETING_FTR_F_EN-IT_IT_51_2K_NXT_20260728_NXT_SMPTE_OV",
"modified_time": "2026-07-28T14:22:17",
"unique": "FD02UF1006E"
},
{
"name": "SONY_SMBND_TOMHOLLANDGREETING_FTR_S_EN-IT_IT_51_2K_NXT_20260728_NXT_SMPTE_OV",
"modified_time": "2026-07-28T14:22:17",
"unique": "FD02UF1006F"
},
{
"name": "SONY_SMBND_TOMHOLLANDGREETING_TLR_F_EN-IT_IT_51_2K_NXT_20260729_NXT_SMPTE_OV",
"modified_time": "2026-07-29T11:34:40",
"unique": "FD02UF10070"
},
{
"name": "SONY_SMBND_TOMHOLLANDGREETING_TLR_S_EN-IT_IT_51_2K_NXT_20260729_NXT_SMPTE_OV",
"modified_time": "2026-07-29T11:34:41",
"unique": "FD02UF10071"
},
{
"name": "Sacrifice_TLR-60_F_IT-XX_IT_51_4K_Eagle_20260728_LSF_SMPTE_OV3",
"modified_time": "2026-07-29T14:12:29",
"unique": "FD02UF10075"
},
{
"name": "Sacrifice_TLR-60_S_IT-XX_IT_51_4K_Eagle_20260728_LSF_SMPTE_OV3",
"modified_time": "2026-07-29T14:12:28",
"unique": "FD02UF10074"
},
{
"name": "SpiderManBrandNewDay_TLR-G_F_EN-it_IT_51_2K_SPE_20260716_DMK_IOP_OV",
"modified_time": "2026-07-16T10:52:01",
"unique": "FD02UF10048"
},
{
"name": "SpiderManBrandNewDay_TLR-G_S_EN-it_IT_51_2K_SPE_20260716_DMK_IOP_OV",
"modified_time": "2026-07-16T10:52:01",
"unique": "FD02UF10049"
},
{
"name": "TAD4_TLR-A_F_IT-XX_IT_51_2K_PC_20260616_PWL_SMPTE_OV",
"modified_time": "2026-09-03T13:52:11",
"unique": "FD02UF1002D"
},
{
"name": "TAD4_TLR-A_S_IT-XX_IT_51_2K_PC_20260616_PWL_SMPTE_OV",
"modified_time": "2026-09-03T13:52:11",
"unique": "FD02UF10058"
},
{
"name": "TheEchoChamber_TLR-110_F_IT-XX_51_2K_01_20260811_MAF_IOP_OV",
"modified_time": "2026-08-17T09:02:30",
"unique": "FD02UF10015"
},
{
"name": "TheEchoChamber_TLR-110_S_IT-XX_51_2K_01_20260811_MAF_IOP_OV",
"modified_time": "2026-08-17T09:02:30",
"unique": "FD02UF10014"
},
{
"name": "Ultimo_TSR-24_F-185_IT_51_1998x1080_20260722_M74_SMPTE_OV",
"modified_time": "2026-07-23T11:14:12",
"unique": "FD02UF10056"
},
{
"name": "UnTranquilloFunerale_TRL-90_25_F_IT-XX_51_4K_RAICINEMA_20260805",
"modified_time": "2026-08-06T08:41:58",
"unique": "FD02UF1000D"
},
{
"name": "UnTranquilloFunerale_TRL-90_25_S_IT-XX_51_4K_RAICINEMA_20260805",
"modified_time": "2026-08-06T08:41:59",
"unique": "FD02UF1000E"
},
{
"name": "Verity_TLR-J_F_IT-XX_IT_51_2K_SPE_20260811_DMK_IOP_OV",
"modified_time": "2026-08-12T09:12:38",
"unique": "FD02UF10010"
},
{
"name": "Verity_TLR-J_S_IT-XX_IT_51_2K_SPE_20260811_DMK_IOP_OV",
"modified_time": "2026-08-12T09:12:38",
"unique": "FD02UF1000F"
},
{
"name": "Whalefall_TLR-B-2D-6Plus_F_IT-XX_IT_51_2K_DI_20260601_DDS_IOP",
"modified_time": "2026-08-19T13:32:50",
"unique": "FD02UF10019"
},
{
"name": "Whalefall_TLR-B-2D-6Plus_S_IT-XX_IT_51_2K_DI_20260601_DDS_IOP",
"modified_time": "2026-08-19T13:23:20",
"unique": "FD02UF10018"
},
{
"name": "Whalefall_TLR-E-2D-6Plus_F_IT-XX_IT_51_2K_DI_20260824_DDS_IOP",
"modified_time": "2026-08-25T11:32:03",
"unique": "FD02UF10022"
},
{
"name": "Whalefall_TLR-E-2D-6Plus_S_IT-XX_IT_51_2K_DI_20260824_DDS_IOP",
"modified_time": "2026-08-25T11:32:02",
"unique": "FD02UF10021"
},
{
"name": "WildHorseNine_TLR-A-2D-10Plus_F_IT-XX_IT_51_2K_DI_20260511_DDS_IOP",
"modified_time": "2026-08-19T13:52:28",
"unique": "FD02UF10034"
},
{
"name": "WildHorseNine_TLR-A-2D-10Plus_S_IT-XX_IT_51_2K_DI_20260511_DDS_IOP",
"modified_time": "2026-08-19T13:52:28",
"unique": "FD02UF10035"
},
{
"name": "assets-folder",
"modified_time": "2025-08-30T16:32:48",
"unique": "FD02UF20013"
}
],
"notify_filters": [
"TLR",
"TRL",
"FTR"
]
}
]
}
+44 -19
View File
@@ -1,4 +1,4 @@
from datetime import datetime, time
from datetime import datetime, time, date
from typing import Dict, List, Any, ClassVar, Optional
from uuid import UUID
@@ -113,7 +113,7 @@ class JobProgress(BaseModel):
AggregatePercentValidated: int
State: str
ImportProgress: ImportProgressWrapper
ValidationProgressList: ValidationProgressWrapper | None
ValidationProgressList: Optional[ValidationProgressWrapper] = None
IngestedByFolder: bool
ContentsTransferType: str
@@ -123,7 +123,7 @@ class JobProgressWrapper(BaseModel):
class DCPImportJobList(SMSMessage):
IsPaused: bool
JobProgressList: JobProgressWrapper | None
JobProgressList: Optional[JobProgressWrapper] = None
path = ['content', 'dcp', 'command']
params = {'action': 'ListImportJobs'}
@@ -146,17 +146,17 @@ class StorageInfo(SMSMessage):
return data
class SPLLanguage(BaseModel):
Audio: str | None
Subtitle: str | None
Audio: Optional[str] = None
Subtitle: Optional[str] = None
class SPLMetadata(BaseModel):
Id: UUID = Field(alias='UUID')
Title: str
Type: str | None
Type: Optional[str] = None
Duration: time
DurationWithIntermission: time
RevisionDate: datetime
Version: str | None
Version: Optional[str] = None
Language: SPLLanguage
Has3DElement: bool
HasIntermission: bool
@@ -176,18 +176,18 @@ class SPLList(SMSMessage):
class PrjLampInformation(SMSMessage):
path = ['command', 'projector', 'maintenance', 'lamp', 'info', 'get']
ProjectorId: int | None
LampId: int | None
HoursOfUse: int | None
LampSerialNumber: str | None
LampMaximumWattage: int | None
LampWattage: int | None
LampLuminanceDecayRatio: int | None
LampPower: float | None
LampSelect: int | None
LuminanceShutterControl: int | None
LampOn: bool | None
LampStatus: str | None
ProjectorId: Optional[int] = None
LampId: Optional[int] = None
HoursOfUse: Optional[int] = None
LampSerialNumber: Optional[str] = None
LampMaximumWattage: Optional[int] = None
LampWattage: Optional[int] = None
LampLuminanceDecayRatio: Optional[int] = None
LampPower: Optional[float] = None
LampSelect: Optional[int] = None
LuminanceShutterControl: Optional[int] = None
LampOn: Optional[bool] = None
LampStatus: Optional[str] = None
class HDDStatusWrapper(BaseModel):
Name: str
@@ -199,3 +199,28 @@ class RAIDStatusDetail(SMSMessage):
RAIDStatus: str
HDDStatus: HDDStatusElem
class ShowScheduleWrapper(BaseModel):
ScheduleId: UUID
Id: UUID
Title: str
DurationMs: int
IsSplRegistered: bool
IsPlayable: bool
IsContentAvailable: bool
WaitForTrigger: bool
class RecurrenceWrapper(BaseModel):
BeginDate: date
EndDate: date
class ShowScheduleEvent(BaseModel):
PlayTime: datetime
ShowScheduleSummary: ShowScheduleWrapper
IsRecurringEvent: bool
RecurrenceRule: Optional[RecurrenceWrapper] = None
class ShowScheduleEventList(SMSMessage):
path = ['show', 'schedule', 'info', 'events', 'list']
ShowScheduleEventList: List[ShowScheduleEvent]
+121
View File
@@ -0,0 +1,121 @@
from ftplib import FTP
import os
import sys
from pydantic import BaseModel, Field
from typing import Optional, List
from datetime import datetime
from time import sleep
from paho.mqtt import client as mqtt_client
from paho.mqtt.enums import CallbackAPIVersion
from logging import Logger
class FTPDirInfo(BaseModel):
name: str
modified_time: datetime = Field(default_factory=datetime.now)
unique: str = Field(default_factory=lambda: str(datetime.now().timestamp()))
class FTPServer(BaseModel):
name: str
host: str
port: int = 21
username: Optional[str] = None
password: Optional[str] = None
timeout: int = 15
dirs: List[FTPDirInfo] = Field(default_factory=list)
notify_filters: List[str] = Field(default_factory=list)
def connect(self) -> FTP:
"""Establishes an FTP connection using the provided configuration."""
ftp = FTP()
ftp.connect(self.host, self.port, timeout=self.timeout)
if self.username and self.password:
ftp.login(self.username, self.password)
return ftp
class FTPServers(BaseModel):
servers: List[FTPServer] = Field(default_factory=list)
class NotificationMessage(BaseModel):
server: str
name: str
modified_time: datetime
def load_ftp_servers_from_json(file_path: str) -> FTPServers:
"""Loads FTP server configurations from a JSON file."""
with open(file_path, 'r') as f:
return FTPServers.model_validate_json(f.read())
def save_ftp_servers_to_json(ftp_servers: FTPServers, file_path: str) -> None:
"""Saves FTP server configurations to a JSON file."""
with open(file_path, 'w') as f:
f.write(ftp_servers.model_dump_json(indent=2))
def initialize_ftp_servers(file_path: str) -> FTPServers:
"""Initializes FTP server configurations."""
dcp_servers = FTPServers()
# dcp_servers.servers.append(FTPServer(
# name="MART",
# host="192.168.31.15",
# port=21)
# )
dcp_servers.servers.append(FTPServer(
name="DELUXE",
host="192.168.31.16",
port=21,
username="dcpftp",
password="dcpftp",
notify_filters=["TLR", "TRL", "FTR"])
)
save_ftp_servers_to_json(dcp_servers, file_path)
return dcp_servers
def list_new_directories(ftp_server: FTPServer) -> List[FTPDirInfo]:
"""Lists new directories on the FTP server that are not already known."""
with ftp_server.connect() as ftp_connection:
new_dirs: List[FTPDirInfo] = []
for d in ftp_connection.mlsd(): # List directory contents
dir_name: str = d[0]
dir_info: dict = d[1]
modified_time_str: str = dir_info.get('modify', '')
modified_time: datetime = datetime.strptime(modified_time_str, '%Y%m%d%H%M%S') if modified_time_str else datetime.now()
unique: str = dir_info.get('unique', str(datetime.now().timestamp()))
new_dirs.append(FTPDirInfo(name=dir_name, modified_time=modified_time, unique=unique))
new_dirs.sort(key=lambda x: x.name, reverse=False) # Sort directories by name
diff_dirs: List[FTPDirInfo] = list(filter(lambda x: x.name not in [d.name for d in ftp_server.dirs], new_dirs))
ftp_server.dirs = new_dirs # Update the server's directory list with the new directories
return diff_dirs # Return both new directories and the difference
def check_new_titles(mqtt: mqtt_client.Client, topic: str, file_path: str, logger: Logger) -> None:
dcp_servers = FTPServers()
first_run = False
if os.path.exists(file_path):
dcp_servers = load_ftp_servers_from_json(file_path)
else:
dcp_servers = initialize_ftp_servers(file_path)
first_run = True
for server in dcp_servers.servers:
with server.connect() as ftp_connection:
logger.debug("Connected to FTP server %s: %s", server.name, ftp_connection.getwelcome())
diff_dirs: List[FTPDirInfo] = list_new_directories(server)
# do not publish complete list with garbage
if first_run:
return
for d in diff_dirs:
logger.info(f"New DCP found on {server.name}: {d.name} (Modified: {d.modified_time}, Unique: {d.unique})")
for filter_str in server.notify_filters:
if filter_str in d.name:
topic = topic
notification = NotificationMessage(
server=server.name,
name=d.name,
modified_time=d.modified_time
)
mqtt.publish(topic, notification.model_dump_json())
sleep(1) # Small delay to ensure message is sent
save_ftp_servers_to_json(dcp_servers, file_path)
+36
View File
@@ -0,0 +1,36 @@
from typing import Any, Optional, Type, List, Callable
from pydantic import BaseModel, Field
from pydantic import BaseModel
from paho.mqtt import client as mqtt_client
class HAentity(BaseModel):
name: str
unique_id: str
device: Any
entity_type: str = Field(exclude=True, default="sensor")
class HAsensor(HAentity):
value_template: Optional[str] = None
unit_of_measurement: Optional[str] = None
state_topic: str
device_class: Optional[str] = None
state_class: Optional[str] = None
icon: Optional[str] = None
request: Type = Field(exclude=True)
class HAbutton(HAentity):
command_topic: str
payload_press: str = ""
device_class: Optional[str] = None
icon: Optional[str] = None
callback: Optional[Callable[[mqtt_client.Client, Any, mqtt_client.MQTTMessage], None]] = Field(exclude=True, default=None)
class HAdevice(BaseModel):
identifiers: List[str]
name: str
manufacturer: str
model: str
via_device: str | None = None
entities: List[HAentity] = Field(exclude=True, default_factory=list)
short_name: str = Field(exclude=True)
+12 -33
View File
@@ -2,7 +2,7 @@ import logging
import os
import sys
import time
from typing import List, Optional, Type, TypeVar, Set, Any, Callable
from typing import List, Type, TypeVar, Set, Any
from uuid import UUID
import projrequest
@@ -10,9 +10,10 @@ from commands import ShowStatus, SMSMessage, SPLList, SPLMetadata, StorageInfo,
from paho.mqtt import client as mqtt_client
from paho.mqtt.enums import CallbackAPIVersion
from pydantic import BaseModel, Field
from requests import Timeout, ConnectionError
from pyutils.utils import SignalHandler
from homeassistant import HAdevice, HAsensor, HAbutton
from ftpexplorer import check_new_titles
T = TypeVar("T", bound=SMSMessage)
@@ -22,37 +23,6 @@ LOGGER: logging.Logger
DISCOVERY_PREFIX = "homeassistant"
class HAentity(BaseModel):
name: str
unique_id: str
device: Any
entity_type: str = Field(exclude=True, default="sensor")
class HAsensor(HAentity):
value_template: Optional[str] = None
unit_of_measurement: Optional[str] = None
state_topic: str
device_class: Optional[str] = None
state_class: Optional[str] = None
icon: Optional[str] = None
request: Type = Field(exclude=True)
class HAbutton(HAentity):
command_topic: str
payload_press: str = ""
device_class: Optional[str] = None
icon: Optional[str] = None
callback: Optional[Callable[[mqtt_client.Client, Any, mqtt_client.MQTTMessage], None]] = Field(exclude=True, default=None)
class HAdevice(BaseModel):
identifiers: List[str]
name: str
manufacturer: str
model: str
via_device: str | None = None
entities: List[HAentity] = Field(exclude=True, default_factory=list)
short_name: str = Field(exclude=True)
def on_shutwown(client: mqtt_client.Client, userdata: Any, msg: mqtt_client.MQTTMessage) -> None:
LOGGER.info("Shutdown command received")
if msg and msg.payload.decode() == "shutdown":
@@ -84,6 +54,7 @@ def main() -> int:
########## MAIN LOOP #########
##############################
last: float = 0
last_title_check: float = 0
handler: SignalHandler = SignalHandler(LOGGER)
projector: projrequest.ProjectorConnection = projrequest.ProjectorConnection(
ip=env['PROJECTOR_IP'],
@@ -340,6 +311,14 @@ def main() -> int:
except Exception as e:
LOGGER.error("Unexpected exception: [%s]", e)
return 1
if now - last_title_check > 300:
try:
check_new_titles(mqtt, "projmon/ftp", "dcpservers.json", LOGGER)
last_title_check = now
except Exception as e:
LOGGER.error("Failed to check DCP on FTP servers")
last: float = time.time()
cycle_time: float = last - now
LOGGER.debug("Cycle Time: %4.3f", cycle_time)
+153
View File
@@ -0,0 +1,153 @@
<!--
{
"GET": {
"scheme": "https",
"host": "192.168.31.10",
"filename": "/show/schedule/info/events/list",
"query": {
"begin": "20260903",
"end": "20260904",
"omitPlayable": "true",
"omitDurationWithIntermission": "false",
"omitDetailEvent": "false"
},
"remote": {
"Indirizzo": "192.168.31.10:443"
}
}
}
-->
<?xml version="1.0" encoding="UTF-8"?>
<SMSMessage xmlns="http://xmlns.sony.net/d-cinema/sms/2007b">
<MessageHeader>
<Id>-1</Id>
<Type>ShowScheduleEventList</Type>
<Timestamp>1788533605013</Timestamp>
<Source>LSM-100v2</Source>
</MessageHeader>
<MessageBody>
<ShowScheduleEventList>
<ShowScheduleEvent>
<PlayTime>2026-09-05T07:00:00.000+02:00</PlayTime>
<ShowScheduleSummary>
<ScheduleId>urn:uuid:6e4b4a16-939a-498d-a16a-d7e0d823cf8c</ScheduleId>
<Id>urn:uuid:b90174cb-66f2-4af7-a66e-d9f0422c5678</Id>
<Title>%23+08+DVD%2FBLURAY%2FPC%2FALTRO+%28FLAT%29</Title>
<DurationMs>6000</DurationMs>
<IsSplRegistered>true</IsSplRegistered>
<IsPlayable>true</IsPlayable>
<IsContentAvailable>false</IsContentAvailable>
<WaitForTrigger>false</WaitForTrigger>
</ShowScheduleSummary>
<IsRecurringEvent>false</IsRecurringEvent>
</ShowScheduleEvent>
<ShowScheduleEvent>
<PlayTime>2026-09-05T16:00:00.000+02:00</PlayTime>
<ShowScheduleSummary>
<ScheduleId>urn:uuid:efe80f11-a2b2-495f-ae6e-b1cd6495d051</ScheduleId>
<Id>urn:uuid:66b84a42-3246-4514-b898-d41a2b43b5a8</Id>
<Title>%23+Giovani+Madri+-+CINEFORUM</Title>
<DurationMs>6532000</DurationMs>
<IsSplRegistered>true</IsSplRegistered>
<IsPlayable>false</IsPlayable>
<IsContentAvailable>false</IsContentAvailable>
<WaitForTrigger>false</WaitForTrigger>
</ShowScheduleSummary>
<IsRecurringEvent>true</IsRecurringEvent>
<RecurrenceRule>
<BeginDate>2026-09-05</BeginDate>
<EndDate>2026-09-07</EndDate>
</RecurrenceRule>
</ShowScheduleEvent>
</ShowScheduleEventList>
</MessageBody>
</SMSMessage>
<!--
ADD SCHEDULED RECURRENCE
{
"POST": {
"scheme": "https",
"host": "192.168.31.10",
"filename": "/show/schedule/manage/recurrence",
"remote": {
"Indirizzo": "192.168.31.10:443"
}
}
}
-->
<SMSMessage>
<MessageHeader>
<Id>-1</Id>
<Type>Command</Type>
<Timestamp>1788533759537</Timestamp>
<Source>LSM-100v2</Source>
</MessageHeader>
<MessageBody>
<Command>
<Operation>Add</Operation>
<ParameterList>
<Parameter>
<Name>Id</Name>
<Value>urn:uuid:d1753dfd-23f2-494a-b7ea-19c1c9e20c27</Value>
</Parameter>
<Parameter>
<Name>BeginDate</Name>
<Value>2026-09-05</Value>
</Parameter>
<Parameter>
<Name>EndDate</Name>
<Value>2026-09-17</Value>
</Parameter>
<Parameter>
<Name>StartTime</Name>
<Value>14:00:00</Value>
</Parameter>
<Parameter>
<Name>WaitForTrigger</Name>
<Value>false</Value>
</Parameter>
</ParameterList>
</Command>
</MessageBody>
</SMSMessage>
<!--
ADD SCHEDULED SINFLE EVENT
{
"POST": {
"scheme": "https",
"host": "192.168.31.10",
"filename": "/show/schedule/manage",
"remote": {
"Indirizzo": "192.168.31.10:443"
}
}
}
-->
<SMSMessage>
<MessageHeader>
<Id>-1</Id>
<Type>ShowScheduleUpdateList</Type>
<Timestamp>1788533904670</Timestamp>
<Source>LSM-100v2</Source>
</MessageHeader>
<MessageBody>
<ShowScheduleUpdateList>
<ShowScheduleUpdateItem>
<Action>Add</Action>
<Date>2026-09-05</Date>
<ShowScheduleDayItem>
<Time>05:00:00</Time>
<ShowId>urn:uuid:14e6cf10-0400-4f1e-a447-ee146dc8a0ff</ShowId>
<IsPlayable>false</IsPlayable>
<WaitForTrigger>false</WaitForTrigger>
</ShowScheduleDayItem>
</ShowScheduleUpdateItem>
</ShowScheduleUpdateList>
</MessageBody>
</SMSMessage>