def getTagInCurJson(jsonTags, jsonDict): ret = "" try: if(isinstance(jsonTags[0][0], int)): if(jsonTags[0][0] > len(jsonDict)): str_tools.printMsg("JSON", "Source file sized differently from template (max: "+ jsonTags[0][0] +"). Parameter changed to max of json source: " + len(jsonDict) -1) jsonTags[0][0] = len(jsonDict) -1 except: pass for i in range(len(jsonTags[0])): r0 = jsonTags[0][i] if(i==0): #First ret = jsonDict[r0] elif (i == len(jsonTags[0]) - 1): #Last one if(isinstance(ret, list)): ret = ret[0][r0] else: ret = ret[r0] else: #n index in middle if(isinstance(ret, list)): ret = ret[0][r0] else: ret = ret[r0] return ret
def generateImg(content, filename, quality=50): driver = driverInit() driver.get("about:blank") driver.delete_all_cookies() encodedBytes = base64.b64encode(content.encode("utf-8")) encodedStr = str(encodedBytes, "utf-8") driver.get("data:text/html;charset=utf-8;base64," + encodedStr) delay = 5 try: waitLoading = WebDriverWait(driver, delay).until( EC.presence_of_element_located((By.TAG_NAME, 'end'))) except TimeoutException: str_tools.printMsg("Wdv ", "Timeout on slide generation") time.sleep(1) png = driver.get_screenshot_as_png() box = (0, 0, 320, 240) im = Image.open(BytesIO(png)) rgb_im = im.convert('RGB') region = rgb_im.crop(box) try: region.save(filename + ".jpg", 'JPEG', optimize=True, quality=quality) except Exception as ex: str_tools.printMsg("Wdv ", "WebDriver error : " + str(ex)) driver.quit()
def searchForJson(expr, d, parent=[], level=0): found = 0 if(isinstance(d, dict)): for k, v in d.items(): if(isinstance(v, dict)): parent.append(k) level = level+1 parent, level, found = searchForJson(expr, v, parent, level) if (found == 1): return parent, level, found parent.pop(len(parent)-1) elif(isinstance(v, list)): parent.append(k) level = level+1 parent, level, found = searchForJson(expr, v, parent, level) if (found == 1): return parent, level, found parent.pop(len(parent)-1) else: if (v == expr): parent.append(k) str_tools.printMsg ("JSON", "Tag '" + expr + "' found in : " + str(parent)) return parent, level, 1 if(isinstance(d, list)): idx = 0 for item in d: if(isinstance(item, list)): parent.append(item) level = level+1 parent, level, found = searchForJson(expr, item, parent, level) if (found == 1): return parent, level, found else: for k, v in item.items(): if(isinstance(v, dict)): parent.append(k) level = level+1 parent, level, found = searchForJson(expr, v, parent, level) if (found == 1): return parent, level, found parent.pop(len(parent)-1) else: if (v == expr): if(d.count != 1): parent.append(idx) parent.append(k) str_tools.printMsg ("JSON", "Tag '" + expr + "' found in : " + str(parent)) return parent, level, 1 idx = idx+1 return parent, level, found
def parseJson(file,tmpl): artist = "" title = "" cover = "" try: file = file.decode('utf-8') except: pass try: if (file.index("{") != 0): file = file[file.index("{"):] while (file[len(file)-1] != "}"): file = file[0:-1] if (tmpl.index("{") != 0): tmpl = tmpl[tmpl.index("{"):] while (tmpl[len(tmpl)-1] != "}"): tmpl = tmpl[0:-1] except: pass # Identification of where are the $artist, the $title and the $cover tags are in the tmpl file jsonDecoderTemplate = json.JSONDecoder() jsonTemplate = "" try: jsonTemplate = jsonDecoderTemplate.decode(tmpl) except: jsonTemplate = jsonDecoderTemplate.decode("[" + tmpl + "]") jsonNF = "" try: jsonNF = jsonDecoderTemplate.decode(file) except: jsonNF = jsonDecoderTemplate.decode("[" + file + "]") try: artist = getTagInCurJson(searchForJson("$artist", jsonTemplate, []),jsonNF) title = getTagInCurJson(searchForJson("$title", jsonTemplate, []),jsonNF) cover = getTagInCurJson(searchForJson("$cover", jsonTemplate, []),jsonNF) except: artist = "" title = "" cover = "" if(artist == "" or title == "" or cover == ""): str_tools.printMsg("JSON" ,"The following items aren't found in the json source file:") if(artist == ""): str_tools.printMsg("JSON", "$artist, ") if(title == ""): str_tools.printMsg("JSON", "$title, ") if(cover == ""): str_tools.printMsg("JSON", "$cover") return artist, title, cover
def dabctlExtSend(cfg, mode, fileToSend): hostname = cfg.get('dabctl-ext', 'hostname') port = cfg.get('dabctl-ext', 'port') pi = cfg.get('dabctl-ext', 'pi') try: passkey = cfg.get('dabctl-ext', 'passkey') except: passkey = "" url = "http://" + hostname + ":" + str(port) + "/_ext" try: if (mode == "DLS"): dls = "" with open(fileToSend, 'r') as f: dls = f.readlines()[-1] args = {'PI': pi, 'key': passkey, 'variable': 'DLS', 'value': dls} ret = requests.post(url, data=args) elif (mode == "SLS"): args = {'PI': pi, 'key': passkey, 'variable': 'SLS'} files = {'file': open(fileToSend, 'rb')} ret = requests.post(url, data=args, files=files) except Exception as ex: str_tools.printMsg("Ext ", "Error requesting DAB-CTL Server : " + ex)
def driverInit(): driver = None str_tools.printMsg ("Wdv ", "Initializing WebDriver...") try: #Formerly with PhantomJS until v0.8.0 #driver = webdriver.PhantomJS(service_args=["--disk-cache=false", "--ignore-ssl-errors=true", "--ssl-protocol=any"]) #Now with ChromeDriver since v0.9.0 options = webdriver.ChromeOptions() options.add_argument('headless') options.add_argument('no-sandbox') options.add_argument('disable-dev-shm-usage') options.add_argument('hide-scrollbars') options.add_argument('log-level=2') driver = webdriver.Chrome(options=options) driver.set_window_size(320, 240) str_tools.printMsg ("Wdv ", "WebDriver Initialized") except Exception as error: str_tools.printMsg ("Wdv ", "WebDriver initialization error : " + str(error)) sys.exit(2) return driver
def parseTxt(file, tmpl): artist = "" title = "" cover = "" try: file = file.decode("utf-8") file = file.split('\n') tmpl = tmpl.split('\n') except: file = str(file.decode("latin1")) file = file.split('\n') tmpl = tmpl.split('\n') idxArtistLine = -1 idxArtistIdx = -1 idxTitleLine = -1 idxTitleIdx = -1 idxCoverLine = -1 idxCoverIdx = -1 lenArtistTag = len("$artist") lenTitleTag = len("$title") lenCoverTag = len("$cover") count = 0 for line in tmpl: if ("$artist" in line): idxArtistLine = count idxArtistIdx = line.index("$artist") if ("$title" in line): idxTitleLine = count idxTitleIdx = line.index("title") if ("$cover" in line): idxCoverLine = count idxCoverIdx = line.index("cover") count = count + 1 if (idxArtistLine == idxTitleLine): file[idxArtistLine] = file[idxArtistLine].strip("\r") file[idxArtistLine] = file[idxArtistLine].strip("\n") #Case where the artist tag is located on the same line that the title tag offset = idxTitleIdx - idxArtistIdx separator = "" eol = "" if (offset > 0): #Case where the artist tag is located before the title tag separator = tmpl[idxArtistLine][idxArtistIdx + lenArtistTag:idxTitleIdx - 1] eol = tmpl[idxArtistLine][idxTitleIdx + lenTitleTag - 1:] elif (offset < 0): #Case where the title tag is located before the artist tag separator = tmpl[idxTitleLine][idxTitleIdx + lenTitleTag - 1:idxArtistIdx] eol = tmpl[idxTitleLine][idxArtistIdx + lenArtistTag:] lenSeparator = len(separator) lenEol = len(eol) idxFileSeparator = file[idxArtistLine].index(separator) if (offset > 0): artist = file[idxArtistLine][idxArtistIdx:idxFileSeparator] if (lenEol > 0): title = file[idxTitleLine][idxFileSeparator + lenSeparator:-lenEol] else: title = file[idxTitleLine][idxFileSeparator + lenSeparator:] elif (offset < 0): title = file[idxTitleLine][idxTitleIdx - 1:idxFileSeparator] if (lenEol > 0): artist = file[idxArtistLine][idxFileSeparator + lenSeparator:-lenEol] else: artist = file[idxArtistLine][idxFileSeparator + lenSeparator:] else: if (idxArtistLine != -1): if (len(tmpl[idxArtistLine]) != lenArtistTag): extraBe = tmpl[idxArtistLine].index("$artist") extraAf = len(tmpl[idxArtistLine]) - ( tmpl[idxArtistLine].index("$artist") + lenArtistTag) artist = file[idxArtistLine][extraBe:-extraAf] str_tools.printMsg("TXT ", "Artist value : '" + artist + "'") else: artist = file[idxArtistLine] str_tools.printMsg("TXT ", "Artist value : '" + artist + "'") if (idxTitleLine != -1): if (len(tmpl[idxTitleLine]) != lenTitleTag): extraBe = tmpl[idxTitleLine].index("$title") extraAf = len(tmpl[idxTitleLine]) - ( tmpl[idxTitleLine].index("$title") + lenTitleTag) title = file[idxTitleLine][extraBe:-extraAf] str_tools.printMsg("TXT ", "Title value : '" + title + "'") else: title = file[idxTitleLine] str_tools.printMsg("TXT ", "Title value : '" + title + "'") if (idxCoverLine != -1): if (len(tmpl[idxCoverLine]) != lenCoverTag): extraBe = tmpl[idxCoverLine].index("$cover") extraAf = len(tmpl[idxCoverLine]) - ( tmpl[idxCoverLine].index("$cover") + lenCoverTag) cover = file[idxCoverLine][extraBe:-extraAf] str_tools.printMsg("TXT ", "Cover value : '" + cover + "'") else: cover = file[idxCoverLine] str_tools.printMsg("TXT ", "Cover value : '" + cover + "'") if (artist == "" or title == "" or cover == ""): str_tools.printMsg("TXT ", "The following items aren't found :") if (artist == ""): str_tools.printMsg("TXT ", "$artist, ") if (title == ""): str_tools.printMsg("TXT ", "$title, ") if (cover == ""): str_tools.printMsg("TXT ", "$cover") return artist, title, cover
def generate(cfg=None, lastArtist="", lastTitle="", mode="standalone", artistFromServer="", titleFromServer="", coverFromServer=""): # Avoid SSL errors ssl._create_default_https_context = ssl._create_unverified_context # Parameters to generate SLS from the config file compAtc = -1 try: logo = cfg.get('general', 'logoUrl') color1 = cfg.get('general', 'color1') color2 = cfg.get('general', 'color2') backUrl = cfg.get('general', 'backUrl') theme = "themes/" + cfg.get('general', 'theme') radioName = cfg.get('general', 'radioName') slogan = cfg.get('general', 'slogan') outFolder = cfg.get('general', 'outFolder') try: compAtc = cfg.get('quality', 'atc') if(int(compAtc) < 0 or int(compAtc) > 100): str_tools.printMsg("ATC ", "The quality ratio setting is not correct. Provided " + str(compAtc) + "%. The value must be between 0-100%") compAtc = atcCompressionRatio except: str_tools.printMsg("ATC ", "No quality ratio setting defined for ATC slides. Using default value: " + str(atcCompressionRatio) +"%") compAtc = atcCompressionRatio except configparser.NoOptionError as error: str_tools.printMsg("ATC ", "Mandatory parameter is missing : " + str(error)) sys.exit(2) # Local Vars tempArtist = "" tempTitle = "" # Opening Template file = "" cptFails = 0 # Count connection failures, exits the app when not reached for 5 times. # Checking connecion failures while True: try: req = Request(cfg.get('source', 'url'), headers={'User-Agent': 'Mozilla/5.0'}) file = urlopen(req).read() cptFails = 0 break except Exception as ex: cptFails = cptFails + 1 if(cptFails < 5): str_tools.printMsg("ATC ", "[" + str(cptFails) + "/5] Failed to open source file ("+str(ex)+"). Retrying in 10secs...") time.sleep(10) else: str_tools.printMsg("ATC ", "[" + str(cptFails) + "/5] Failed 5 times to open source file. PadTool will exits...") sys.exit(2) # Parsing formalisms for $artist and $title tags artistForm = 0 titleForm = 0 try: artistForm = cfg.get('general','artistForm') if(artistForm == ""): artistForm = 0 except: artistForm = 0 try: titleForm = cfg.get('general','titleForm') if(titleForm == ""): titleForm = 0 except: titleForm = 0 tmpl = "" with open(cfg.get('source', 'template'), "r") as template: for line in template: tmpl = tmpl + line ret = [] if(mode == "server"): ret = [artistFromServer, titleFromServer, coverFromServer] else: if (cfg.get('source','format') == "json"): ret = json_file.parseJson(file, tmpl) elif (cfg.get('source','format') == "xml"): ret = xml_file.parseXml(file,tmpl) elif (cfg.get('source','format') == "txt"): ret = txt_file.parseTxt(file,tmpl) artist = str_tools.formString(str(html.unescape(str(ret[0]))), int(artistForm)).strip() title = str_tools.formString(str(html.unescape(str(ret[1]))), int(titleForm)).strip() cover = html.unescape(str(ret[2])) if(artist == lastArtist and title == lastTitle): str_tools.printMsg("ATC ", "SLS/DLS already generated, passing...") return artist, title # Filters management for artist tag filterFound = False try: filterArtist = json.loads(cfg.get('filter', 'artist')) str_tools.printMsg("ATC ", "Filters defined for artist tag") for fart in filterArtist: if (str(fart) == artist): filterFound = True str_tools.printMsg ("ATC ", "Filter '" + str(fart) +"' found in artist tag") if(mode == "dabctl"): try: tmpPath = "/tmp/PadTool-" + os.getpid() if(os.path.isfile(tmpPath + "/music.jpg")): str_tools.printMsg ("ATC " ,"Slide exists, deleting slide...") os.remove(tmpPath + "/music.jpg") except: str_tools.printMsg ("ATC ", "Slide removal error : " + str(ex)) else: if(os.path.isfile(outFolder + "/music.jpg")): os.remove(outFolder + "/music.jpg") str_tools.printMsg ("ATC ", "SLS exists, deleting slide...") # Create file REQUEST_SLIDES_DIR_REREAD f = open( outFolder + '/REQUEST_SLIDES_DIR_REREAD', 'w' ) f.write("") f.close() except configparser.NoOptionError as error: str_tools.printMsg("ATC ", "No filters defined for artist tag, ignoring...") except configparser.NoSectionError as error: str_tools.printMsg("ATC ", "No filters defined for artist tag, ignoring...") except json.decoder.JSONDecodeError as ex: str_tools.printMsg("ATC ", "No filters defined for artist tag (bad format or empty), ignoring...") # Filters management for title tag try: filterTitle = json.loads(cfg.get('filter', 'title')) str_tools.printMsg("ATC ", "Filters defined for title tag") for ftit in filterTitle: if (str(ftit) == title): filterFound = True str_tools.printMsg ("ATC ", "Filter '" + str(ftit) + "' found in title tag") if(os.path.isfile(outFolder + "/music.jpg")): str_tools.printMsg ("ATC ", "SLS exists, deleting slide...") os.remove(outFolder + "/music.jpg") # Create file REQUEST_SLIDES_DIR_REREAD f = open( outFolder + '/REQUEST_SLIDES_DIR_REREAD', 'w' ) f.write("") f.close() break except configparser.NoOptionError as error: str_tools.printMsg("ATC ", "No filters defined for title tag, ignoring...") except configparser.NoSectionError as error: str_tools.printMsg("ATC ", "No filters defined for title tag, ignoring...") except json.decoder.JSONDecodeError as ex: str_tools.printMsg("ATC ", "No filters defined for title tag (bad format or empty), ignoring...") try: if(cfg.get('slides', 'music') == "1"): # Find the cover on CoverPy or Sacad coverPyEnabled = "0" coverPyFound = False try: coverPyEnabled = cfg.get('source', 'researchCover') except: pass albumFromCpy = "" # Search a cover via CoverPy if enabled if not cover and coverPyEnabled == "1": cpy = coverpy.CoverPy() try: str_tools.printMsg ("ATC ", "No cover URL provided, using CoverPy to find one cover...") result = cpy.get_cover(artist + " - " + title, 1) cover = result.artwork(300) albumFromCpy = result.album coverPyFound = True str_tools.printMsg ("ATC ", "Cover found using CoverPy : " + cover) except coverpy.exceptions.NoResultsException: str_tools.printMsg ("ATC ", "No cover found using CoverPy") except: str_tools.printMsg ("ATC ", "Error with CoverPy") # If no cover found via CoverPy, then call to Sacad to find a cover if not cover and coverPyEnabled == "1": try: str_tools.printMsg ("ATC ", "Using Sacad to find a cover") if(albumFromCpy == ""): albumFromCpy = title os.system("sacad \"" + artist + "\" \"" + albumFromCpy + "\" " + " 300 PadTool-Art-" + str(os.getpid()) + ".jpg -a fr") with open("PadTool-Art-" + str(os.getpid()) + ".jpg", "rb") as image_file: cover = "data:image/jpg;base64," + str(base64.b64encode(image_file.read()).decode()) if (os.path.isdir("PadTool-Art-" + str(os.getpid()) + ".jpg", "rb")): shutil.rmtree("PadTool-Art-" + str(os.getpid()) + ".jpg", "rb") coverPyFound = True str_tools.printMsg("ATC ", "Cover found via Sacad") time.sleep(1) except: str_tools.printMsg ("ATC ", "Error with Sacad or cover not found") # Put default cover when no cover image provided (eg. logo of the radio station) if (not cover and coverPyFound == False) or filterFound == True: str_tools.printMsg ("ATC ", "Putting default cover as no URL has been provided or if a filter has been found") try: cover = cfg.get('source','defaultCover') except configparser.NoOptionError as error: str_tools.printMsg("ATC ", "Mandatory parameter is missing : " + str(error)) sys.exit(2) tempArtist = str(lastArtist).replace("...", "") tempTitle = str(lastTitle).replace("...", "") # Some APIs do not use http or https prefix, add http:// when it's the case if (len(cover) > 0): if("http" not in cover): cover = str(cfg.get('general', 'prefix')) + cover if(filterFound == True or (artist == "" and title == "")): try: contentDls = cfg.get('dls', 'defaultDls') except: contentDls = "$radioName, $slogan" if(os.path.isfile(outFolder + "/music.jpg")): os.remove(outFolder + "/music.jpg") else: contentDls = cfg.get('dls', 'text') # Data masking replacement with correct values content = "" with io.open(theme + '.html', 'r', encoding="utf-8") as f: content = f.read() except: pass if (cfg.get('dls','enabled') == "1"): if((artist not in tempArtist and title not in tempTitle) or (artist == "" or title == "")): str_tools.printMsg ("ATC ", "Generating DLS...") if(filterFound == True or (artist == "" or title == "")): try: contentDls = cfg.get('dls', 'defaultDls') except: contentDls = "$radioName, $slogan" if(os.path.isfile(outFolder + "/music.jpg")): os.remove(outFolder + "/music.jpg") else: contentDls = cfg.get('dls', 'text') lenDls = len(contentDls) lenArtist = len(str(artist)) lenTitle = len(str(title)) lenRadioName = len(radioName) contentDls = contentDls.replace("$artist", artist) contentDls = contentDls.replace("$title", title) contentDls = contentDls.replace("$radioName", radioName) contentDls = contentDls.replace("$slogan", slogan) idxArtist = -1 idxTitle = -1 idxRadioName = -1 if (artist in contentDls and artist != ""): idxArtist = contentDls.index(artist) if (title in contentDls and title != ""): idxTitle = contentDls.index(title) if (radioName in contentDls and radioName != ""): idxRadioName = contentDls.index(radioName) dlsPlusEnabled = "0" try: # Parsing option in the config file if the DLS+ is enabled or not. if(cfg.get('dls', 'dlsPlus') != "" and mode != "dabctl-ext"): dlsPlusEnabled = cfg.get('dls', 'dlsPlus') except: dlsPlusEnabled = "0" if(dlsPlusEnabled == "1"): dlPlus = "##### parameters { #####\nDL_PLUS=1\nDL_PLUS_ITEM_TOGGLE=0\nDL_PLUS_ITEM_RUNNING=1\n" if (idxRadioName != -1): dlPlus = dlPlus + "DL_PLUS_TAG=32 " + str(idxRadioName) + " " + str(lenRadioName -1) + "\n" if (idxTitle != -1): dlPlus = dlPlus + "DL_PLUS_TAG=1 " + str(idxTitle) + " " + str(lenTitle - 1) + "\n" if (idxArtist != -1): dlPlus = dlPlus + "DL_PLUS_TAG=4 " + str(idxArtist) + " " + str(lenArtist - 1) + "\n" dlPlus = dlPlus + "##### parameters } #####" outDls = outFolder + '/dls.txt' try: # Parsing option in the config file if the DLS file should be generated in an other path. if(cfg.get('dls', 'outFile') != ""): outDls = cfg.get('dls', 'outFile') except: pass f = "" if(mode == "dabctl"): f = open("/tmp/PadTool-" + str(os.getpid()) + "/dls.txt", "w") else: f = open(outDls, 'w') if(dlsPlusEnabled == "1"): f.write(dlPlus + "\n" + contentDls) else: f.write(contentDls) f.close() try: if(cfg.get('dls', 'outFile') != ""): if(dlsPlusEnabled == "1"): str_tools.printMsg ("ATC ", "DLS exported with DLS+ : '" + contentDls + "' at '" + outDls + "'") else: str_tools.printMsg ("ATC ", "DLS exported : '" + contentDls + "' at '" + outDls + "'") except: if(dlsPlusEnabled == "1"): str_tools.printMsg ("ATC ", "DLS exported with DLS+ : '" + contentDls + "' at '" + outFolder + "/dls.txt'") else: str_tools.printMsg ("ATC ", "DLS exported : '" + contentDls + "' at '" + outDls + "'") # If a filter has been found, we don't generate any artist, title slide if(filterFound == True): return artist, title # If a there is no artist nor title, we don't generate any artist, title slide if(artist == "" or title == ""): return artist, title # If title and/or artist are too long to be displayed on a slide, we reduce them if(len(str(artist)) > 35): artist = str(artist)[0:35] + "..." if(len(str(title)) > 35): title = str(title)[0:35] + "..." try: if(cfg.get('slides', 'music') == "1"): if(mode != "dabctl"): if(artist == lastArtist and title == lastTitle): str_tools.printMsg("ATC ", "SLS/DLS already generated, passing...") return artist, title str_tools.printMsg ("ATC ", "Generating Slide...") # content = content.replace("$artist", str(artist.encode("utf-8").decode('unicode_escape'))) # content = content.replace("$title", str(title.encode("utf-8").decode('unicode_escape'))) content = content.replace("$artist", str_tools.formString(str(artist), int(artistForm)).strip()) content = content.replace("$title", str_tools.formString(str(title), int(titleForm)).strip()) content = content.replace("$color1", color1) content = content.replace("$color2", color2) content = content.replace("$backurl", backUrl) content = content.replace("$logo", logo) try: # respCover = urlopen(cover).getcode() req = Request(cover, headers={'User-Agent': 'Mozilla/5.0'}) readCover = urlopen(req).read() except: cover = cfg.get('source','defaultCover') content = content.replace("$cover", cover) try: if(mode == "dabctl"): img_file.generateImg(content, "/tmp/PadTool-" + str(os.getpid()) + "/music", int(compAtc)) str_tools.printMsg ("ATC ", "Slide generated at : '" + "/tmp/PadTool-" + str(os.getpid()) + "/music.jpg' and will be copied to '" + outFolder + "/music.jpg'") else: img_file.generateImg(content, outFolder + "/music", int(compAtc)) str_tools.printMsg ("ATC ", "Slide generated at : '" + outFolder + "/music.jpg' (ratio: " + str(compAtc)+"%)") except Exception as ex: str_tools.printMsg ("ATC ", "Slide generation error : " + str(ex)) # Create file REQUEST_SLIDES_DIR_REREAD if(mode != "dabctl" or mode != "dabctl-ext"): f = open(outFolder + '/REQUEST_SLIDES_DIR_REREAD', 'w' ) f.write("") f.close() except: pass return artist, title
def generate(cfg): # Parameters to generate SLS from the config file compLogo = -1 try: logo = cfg.get('general', 'logoUrl') colorl = cfg.get('general', 'colorl') mode = cfg.get('general', 'mode') outFolder = cfg.get('general', 'outFolder') try: compLogo = cfg.get('quality', 'logo') if(int(compLogo) < 0 or int(compLogo) > 100): str_tools.printMsg("Logo", "The quality ratio setting is not correct. Provided " + str(compLogo) + "%. The value must be between 0-100%") compLogo = logoCompressionRatio except: str_tools.printMsg("Logo", "No quality ratio setting defined for Logo slides. Using default value: " + str(logoCompressionRatio) +"%") compLogo = logoCompressionRatio except configparser.NoOptionError as error: str_tools.printMsg("Logo", "Mandatory parameter is missing : " + str(error)) sys.exit(2) # Checking connection failures while True: try: req = Request(cfg.get('source', 'url'), headers={'User-Agent': 'Mozilla/5.0'}) file = urlopen(logo).read() cptFails = 0 break except Exception as ex: cptFails = cptFails + 1 if(cptFails < 5): str_tools.printMsg("Logo", "[" + str(cptFails) + "/5] Failed to open source file ("+str(ex)+"). Retrying in 10secs...") time.sleep(10) else: str_tools.printMsg("Logo", "[" + str(cptFails) + "/5] Failed 5 times to open source file. PadTool will exits...") sys.exit(2) str_tools.printMsg ("Logo", "Generating Slide...") # Data masking replacement with correct values content = """ <html> <head> <style type="text/css"> body { margin:auto; background-color:$colorl; background:$colorl;} .conteneur{ width: 315px; height: 235px; text-align: center; display: table-cell; vertical-align: middle; } img { max-width: 300px; max-height: 220px; } </style> </head> <body> <div class="conteneur"> <img src="$logo" /> </div> </body> <end></end> </html> """ content = content.replace("$logo", logo) content = content.replace("$colorl", colorl) try: if(mode == "dabctl"): img_file.generateImg(content, "/tmp/PadTool-" + str(os.getpid()) + "/logo", int(compLogo)) str_tools.printMsg ("Logo", "Slide generated at : '" + "/tmp/PadTool-" + str(os.getpid()) + "/logo.jpg' and will be copied to '" + outFolder + "/logo.jpg' (ratio: " + str(compAtc)+"%)") else: img_file.generateImg(content, outFolder + "/logo", int(compLogo)) str_tools.printMsg ("Logo", "Slide generated at : '" + outFolder + "/logo.jpg' (ratio: " + str(compLogo)+"%)") except Exception as ex: str_tools.printMsg ("Logo", "Slide generation error : " + str(ex))
def parseXml(file, tmpl): artist = "" title = "" cover = "" xmlf = ET.XML(file) xmlt = ET.XML(tmpl) # Init temporary work values for listing xml values idxLine = 0 idxArtist = idxTitle = idxCover = -1 # Identification of where are the $artist, the $title and the $cover tags are in the tmpl file for v in xmlt.iter(): if (v.text == "$artist"): idxArtist = idxLine elif (v.text == "$title"): idxTitle = idxLine elif (v.text == "$cover"): idxCover = idxLine if (idxArtist != -1 and idxTitle != -1 and idxCover != -1): break idxLine = idxLine + 1 # Retrieving info from the xml file with the help of the template file idxLine = 0 for v in xmlf.iter(): if (idxLine == idxArtist): artist = v.text str_tools.printMsg( "XML ", "Found artist tag, item nb '" + str(idxLine) + "' with value : '" + artist + "'") elif (idxLine == idxTitle): title = v.text str_tools.printMsg( "XML ", "Found title tag, item nb '" + str(idxLine) + "' with value : '" + title + "'") elif (idxLine == idxCover): cover = v.text str_tools.printMsg( "XML ", "Found cover tag, item nb '" + str(idxLine) + "' with value : '" + cover + "'") if (artist != "" and title != "" and cover != ""): break idxLine = idxLine + 1 if (artist == "" or title == "" or cover == ""): str_tools.printMsg("XML ", "The following items aren't found :") if (artist == ""): str_tools.printMsg("XML ", "$artist, ") if (title == ""): str_tools.printMsg("XML ", "$title, ") if (cover == ""): str_tools.printMsg("XML ", "$cover") return artist, title, cover
def initPlugins(pathCfg, cfg, mode, timer): title = None artist = None # Server Mode (or server enabled) try: port = cfg.get("server", "port") user = cfg.get("server", "user") password = cfg.get("server", "password") if (mode == "server" or port != ""): webServer = server.Server(cfg, port, user, password) webServer.start() str_tools.printMsg( "Web ", "PadTool HTTP Server enabled, listening on port " + str(port)) except: pass # Standalone Mode Management if (cfg.get('slides', 'logo') == "1"): templateLogo.generate(cfg) time.sleep(1) # Regular execution totalTime = 0 triggerHour = True triggerQuarterHour = True triggerHalfHour = True triggerTenMin = True triggerFiveMin = True listFilesDabCtlSls = [] listFilesDabCtlDls = [] indexSlsDabCtlLoop = 0 indexDlsDabCtlLoop = 0 while True: # Generating artist/title/cover slide (with DLS+ if selected) if mode is not "server" if (mode != "server"): artist, title = templateATC.generate(cfg, artist, title, mode) # Timer reset at 0 when we get to an a new hour / Trigger 1 hour if (datetime.datetime.now().minute == 0 and datetime.datetime.now().second <= int(timer) and triggerHour == False): totalTime = 0 triggerHour = True if (datetime.datetime.now().minute != 0): triggerHour = False # Trigger 30min if (datetime.datetime.now().minute == 30 and datetime.datetime.now().second <= int(timer) and triggerHalfHour == False): triggerHalfHour = True if (datetime.datetime.now().minute != 30): triggerHalfHour = False # Trigger 15min if (datetime.datetime.now().minute % 15 == 0 and datetime.datetime.now().second <= int(timer) and triggerQuarterHour == False): triggerQuarterHour = True if (datetime.datetime.now().minute % 15 != 0): triggerQuarterHour = False # Trigger 10min if (datetime.datetime.now().minute % 10 == 0 and datetime.datetime.now().second <= int(timer) and triggerTenMin == False): triggerTenMin = True if (datetime.datetime.now().minute % 10 != 0): triggerTenMin = False # Trigger 5min if (datetime.datetime.now().minute % 5 == 0 and datetime.datetime.now().second <= int(timer) and triggerFiveMin == False): triggerFiveMin = True if (datetime.datetime.now().minute % 5 != 0): triggerFiveMin = False if (totalTime == 0 or triggerHour == True): triggerHour = False try: # print("Trigger hour") _pluginsManagement1h.generate(os.path.abspath(pathCfg)) _pluginsManagement30min.generate(os.path.abspath(pathCfg)) except: pass if (totalTime == 0 or triggerHalfHour == True): triggerHalfHour = False try: # print("Trigger half hour") _pluginsManagement30min.generate(os.path.abspath(pathCfg)) except: pass if (totalTime == 0 or triggerQuarterHour == True): triggerQuarterHour = False try: # print("Trigger quarter hour") _pluginsManagement15min.generate(os.path.abspath(pathCfg)) except: pass if (totalTime == 0 or triggerTenMin == True): triggerTenMin = False try: # print("Trigger ten minutes") _pluginsManagement10min.generate(os.path.abspath(pathCfg)) except Exception as ex: pass if (totalTime == 0 or triggerFiveMin == True): triggerFiveMin = False try: # print("Trigger five minutes") _pluginsManagement5min.generate(os.path.abspath(pathCfg)) except: pass # DAB-CTL mode, call at first start when all slides are generated if ((mode == "dabctl" or mode == 'dabctl-ext') and totalTime == 0): try: outFolder = cfg.get('general', 'outFolder') except configparser.NoOptionError as error: str_tools.printMsg( "Ext ", "Mandatory parameter is missing : " + str(error)) sys.exit(2) if (mode == 'dabctl'): tempFolder = "/tmp/PadTool-" + str(os.getpid()) elif (mode == "dabctl-ext"): tempFolder = outFolder try: if (os.path.isdir(tempFolder)): listFilesDabCtlSls = [ os.path.basename(x) for x in glob.glob(tempFolder + '/*.jpg') ] listFilesDabCtlDls = [ os.path.basename(x) for x in glob.glob(tempFolder + '/*.txt') ] except: str_tools.printMsg( "Ext ", "Mandatory parameter is missing : " + str(error)) sys.exit(2) # DAB-CTL, call each time in loop if (mode == "dabctl" or mode == "dabctl-ext"): try: if (len(listFilesDabCtlSls) != len( glob.glob(tempFolder + '/*.jpg'))): listFilesDabCtlSls = [ os.path.basename(x) for x in glob.glob(tempFolder + '/*.jpg') ] except: pass try: if (len(listFilesDabCtlDls != len( glob.glob(tempFolder + '/*.txt')))): listFilesDabCtlDls = [ os.path.basename(x) for x in glob.glob(tempFolder + '/*.txt') ] except: pass # Copy SLS if (mode == "dabctl"): outFolderFilesCount = -1 timeoutCount = 0 while ( outFolderFilesCount != 0 ): # Is the folder empty of jpgs ? If then, we push an image. try: outFolderFilesCount = len( glob.glob(outFolder + '/*.jpg')) # print("SLS directory not empty, waiting...") except: outFolderFilesCount = 0 # print("SLS directory empty, copying...") time.sleep(1) timeoutCount = timeoutCount + 1 if (timeoutCount >= 30): # print("Timeout 30s !") outFolderFilesCount = 0 try: if (len(listFilesDabCtlSls) > 0): # print ("Copy SLS index " + str(indexSlsDabCtlLoop) + " on " + str(len(listFilesDabCtlSls))) if (mode == "dabctl"): shutil.copyfile( tempFolder + '/' + listFilesDabCtlSls[indexSlsDabCtlLoop], outFolder + '/' + os.path.basename( listFilesDabCtlSls[indexSlsDabCtlLoop])) elif (mode == "dabctl-ext"): dabctlExtSend( cfg, "SLS", outFolder + '/' + os.path.basename( listFilesDabCtlSls[indexSlsDabCtlLoop])) except Exception as ex: pass # Copy DLS try: if (len(listFilesDabCtlDls) > 0): # print ("Copy DLS index " + str(indexDlsDabCtlLoop) + " on " + str(len(listFilesDabCtlDls))) if (mode == "dabctl"): try: outFile = cfg.get('dls', 'outFile') except: str_tools.printMsg( "Ext ", "Mandatory parameter is missing : " + str(error)) sys.exit(2) shutil.copyfile( tempFolder + '/' + listFilesDabCtlDls[indexDlsDabCtlLoop], outFile) elif (mode == "dabctl-ext"): dabctlExtSend( cfg, "DLS", outFolder + '/' + os.path.basename( listFilesDabCtlDls[indexDlsDabCtlLoop])) except Exception as ex: pass indexSlsDabCtlLoop = indexSlsDabCtlLoop + 1 indexDlsDabCtlLoop = indexDlsDabCtlLoop + 1 if (indexSlsDabCtlLoop >= len(listFilesDabCtlSls)): indexSlsDabCtlLoop = 0 if (indexDlsDabCtlLoop >= len(listFilesDabCtlDls)): indexDlsDabCtlLoop = 0 totalTime = totalTime + int(timer) if (totalTime >= 3600): totalTime = 1 time.sleep(int(timer))