示例#1
0
    def _findLineZero(self):
        lineNb = 0
        # Flag to stop the search for 0:00
        isLineAtTimeZero = False

        logPrint.printLog("Parsing the description field")

        for line in self.descriptionLinesList:
            if (not isLineAtTimeZero):
                # Not find yet: perform the search
                idxReturnedFromFind = line.find("0:00")
                if idxReturnedFromFind != -1:
                    # "0:00" found. We store the line number and the character index
                    if idxReturnedFromFind > 0:
                        # Consolidate: check again if idxReturnedFromFind>0, i.e. if it is really 00:00 and not for example 10:00
                        isLineAtTimeZero = self._checkIfDetectedZeroIsReallyZero(
                            line, idxReturnedFromFind)
                    else:
                        # 0:00 at index 0 is for sure a time zero
                        isLineAtTimeZero = True
                    if isLineAtTimeZero:
                        # self.idxCharZeroZero = idxReturnedFromFind
                        self.lineNbZeroZero = lineNb
                lineNb = lineNb+1
        if not isLineAtTimeZero:
            logPrint.printError("0:00 not found.")

        return isLineAtTimeZero
示例#2
0
def main(outputFilePath, argv):
    prefix = ""

    youtubeApiInst = youtubeApiWrapper(sys.argv[1])
    descrFromYoutubeApi = youtubeApiInst.getDescriptionField()
    # descriptionParser accepts only list of str
    descrListFromYoutubeApi = descrFromYoutubeApi.splitlines()

    # First attempt of chapter parsing using what Youtube API returned
    descriptionParserInstFromYoutube = descriptionParser(
        descrListFromYoutubeApi)
    succesfullParsing = descriptionParserInstFromYoutube.parse()
    if (not succesfullParsing):
        logPrint.printInfo(
            "Another attempt can be given using pasted chapter list.")
        # Another parsing is attempted using stdin
        logPrint.printInfo(
            "Copy/paste the description list you want, then hit Ctrl+Z")
        # returns a list of str
        descrListFromCopyPaste = sys.stdin.readlines()
        # strip this line from "\n"
        strippedDescrListFromCopyPaste = [
            "" for idx in range(len(descrListFromCopyPaste))
        ]
        for idx in range(len(descrListFromCopyPaste)):
            strippedDescrListFromCopyPaste[idx] = descrListFromCopyPaste[
                idx].strip(" \n")
        # Create a new descriptionParser with the pasted list stripped from the final \n
        descriptionParserInstFromCopyPaste = descriptionParser(
            strippedDescrListFromCopyPaste)
        succesfullParsing = descriptionParserInstFromCopyPaste.parse()
        if (not succesfullParsing):
            logPrint.printError("Second attempt failed. Exiting.")
            exit(-5)
        else:
            chaptersMatrix = descriptionParserInstFromCopyPaste.getChaptersMatrix(
            )
    else:
        chaptersMatrix = descriptionParserInstFromYoutube.getChaptersMatrix()

    if len(sys.argv) == 3:
        prefix = sys.argv[2]
        logPrint.printLog(
            "The prefix \"" + prefix +
            "\" read from the program's arguments, will be added before each title."
        )
    else:
        prefix = ""
        logPrint.printLog("No prefix read from the program's arguments.")

    # Instantiate musicDisplayer to launch a timer and print the correct music name
    musicDisplayerInst = musicDisplayer(outputFilePath, chaptersMatrix, prefix)

    # Launch the timer
    musicDisplayerInst.start()
示例#3
0
    def __init__(self):
        logPrint.printLog("Parsing the config file config.ini")
        self.config = configparser.ConfigParser()
        self.config.read('config.ini')

        self.outputFilePath = self.config['timeSnip']['outputFilePath']
        readVerbosityLevel = self.config['timeSnip']['verbosityLevel']

        # outputFilePath
        if self.outputFilePath == "":
            print("[ERR] In internalConfig.py, outputFilePath is not defined")
            exit(-7)
        outputFile = Path(self.outputFilePath)
        outputFileParent = outputFile.parent
        if not outputFileParent.is_dir():
            print(
                "[ERR] In internalConfig.py, outputFilePath is bad defined: its parent directory does not exist"
            )
            exit(-8)

        # verbosityLevel
        if readVerbosityLevel == "":
            print(
                "[ERR] In internalConfig.py, readVerbosityLevel is not defined"
            )
            exit(-7)
        if readVerbosityLevel == "debug":
            self.verbosityLevel = 0
        elif readVerbosityLevel == "log":
            self.verbosityLevel = 1
        elif readVerbosityLevel == "error":
            self.verbosityLevel = 2
        else:
            print(
                "[ERR] In internalConfig.py, verbosityLevel is not/bad defined"
            )
            exit(-9)
示例#4
0
    def getDescriptionField(self):
        logPrint.printLog(
            "Calling Youtube API to get the video description list")

        # Disable OAuthlib's HTTPS verification when running locally.
        # *DO NOT* leave this option enabled in production.
        os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"

        api_service_name = "youtube"
        api_version = "v3"

        # This file is secret
        client_secrets_file = os.getcwd(
        ) + "\\_credentials\\google-api-key.json"

        # Get credentials and create an API client
        flow = google_auth_oauthlib.flow.InstalledAppFlow.from_client_secrets_file(
            client_secrets_file, self.scopes)
        # Calls OAUTH2 services on a Browser
        credentials = flow.run_local_server(
            success_message="Twitch: @LukkoLuigi")
        youtube = googleapiclient.discovery.build(api_service_name,
                                                  api_version,
                                                  credentials=credentials)

        request = youtube.videos().list(part="snippet", id=self.videoId)
        response = request.execute()
        #description = response.items[0].snippet.description
        items = response["items"]
        snippet = items[0]["snippet"]
        description = snippet["description"]

        # logPrint.printDebug("description: ")
        # logPrint.printDebug(description)

        return description
示例#5
0
 def __init__(self, youtubeUrl):
     logPrint.printLog("Initializing youtubeApiWrapper with " + youtubeUrl)
     logPrint.printDebug("youtubeUrl: " + youtubeUrl)
     self.videoId = self.extractIdFromUrl(youtubeUrl)
示例#6
0
    def _parseChapterList(self):
        idxSplitted = 0
        idxOfZeroInSplittedLine = -1
        line = self.descriptionLinesList[self.lineNbZeroZero]
        splittedLineList = re.split(r'([0-9:]+:[0-9:]+)', line)
        for splittedWord in splittedLineList:
            if re.search(r'[0-9:]+:[0-9:]+', splittedWord):
                idxOfZeroInSplittedLine = idxSplitted
            idxSplitted = idxSplitted+1

        # Analyze pattern
        self.patternId = self._analyzeChaptersPattern(
            splittedLineList, idxOfZeroInSplittedLine)
        logPrint.printLog("Pattern detected: "+str(self.patternId))

        idxMatrix = 0
        # To avoid false end-of-chapters due to problems of formatting in the description, another attempt is given to each non-match
        numberOfRemainingAttemptsToParseEachLine = self.MAX_ATTEMPTS_NB_TO_PARSE_TIME_AND_TITLE
        logPrint.printLog("While parsing the chapters, a maximum of "+str(
            self.MAX_ATTEMPTS_NB_TO_PARSE_TIME_AND_TITLE)+" not matching line(s) is accepted.")
        offsetForIdxMatrixBecauseOfFalseErrors = 0

        # Max length of the matrix
        while (idxMatrix < self.MAX_SIZE_OF_MATRIX):
            # Avoid overflow
            if((self.lineNbZeroZero + idxMatrix + offsetForIdxMatrixBecauseOfFalseErrors < len(self.descriptionLinesList)) and numberOfRemainingAttemptsToParseEachLine > 0):
                line = self.descriptionLinesList[self.lineNbZeroZero +
                                                 idxMatrix + offsetForIdxMatrixBecauseOfFalseErrors]
                if re.search('[0-9:]+:[0-9:]+', line):
                    # Reset for the next formatting error found
                    numberOfRemainingAttemptsToParseEachLine = self.MAX_ATTEMPTS_NB_TO_PARSE_TIME_AND_TITLE

                    # FIXME Does not work for "[2:20] the past inside the present"
                    splittedLine = re.split(r'([0-9:]+:[0-9:]+)', line)

                    # Too specific, commented and will be deleted after testing
                    # offsetForSplittedLineReading = 0
                    # if splittedLine[0] == "":
                    #     # re.split created an empty cell at the beginning, ignore it
                    #     offsetForSplittedLineReading = 1

                    # Pattern 0 could include the case where time is not the first word, the shift to do is idxOfZeroInSplittedLine
                    # We here take thy hypothesis that the shift of the 0:00 line is the same for every line
                    if self.patternId == 0:
                        time = splittedLine[0 + idxOfZeroInSplittedLine]
                        titleAndDelim = splittedLine[1 +
                                                     idxOfZeroInSplittedLine]
                    elif self.patternId == 1:
                        time = splittedLine[1]
                        titleAndDelim = splittedLine[0]
                    else:
                        logPrint.printError(
                            "Chapters pattern not found. Exiting.")
                        exit(-4)

                    logPrint.printLog("Matching line found, line "+str(self.lineNbZeroZero +
                                                                       idxMatrix + offsetForIdxMatrixBecauseOfFalseErrors)+", time "+time)
                    # The title is stripped to not store useless characters in the beginning and in the end
                    title = titleAndDelim.strip(" -_[]#:")

                    # Strip remaining parenthesis around timestamp e.g. "(25:32) title" without cutting the included parenthesis of one title
                    # e.g. "(25:32) title (featuring Pitbull)"
                    title = title.lstrip(") ")
                    title = title.rstrip("( ")

                    self.chaptersMatrix[idxMatrix, 0] = time
                    self.chaptersMatrix[idxMatrix, 1] = title

                    # Shift the index only if we have found something to avoid holes because of formatting errors
                    idxMatrix = idxMatrix+1
                else:
                    if numberOfRemainingAttemptsToParseEachLine > 0:
                        # Second chance
                        logPrint.printLog("Not matching line found, line "+str(self.lineNbZeroZero +
                                                                               idxMatrix + offsetForIdxMatrixBecauseOfFalseErrors)+", another chance is given.")
                        numberOfRemainingAttemptsToParseEachLine = numberOfRemainingAttemptsToParseEachLine - 1
                        offsetForIdxMatrixBecauseOfFalseErrors = offsetForIdxMatrixBecauseOfFalseErrors + 1
            else:
                # No more time is detected and the formatting error margin is consumed, the chapter list is over
                logPrint.printLog("No more matching line found, line "+str(self.lineNbZeroZero +
                                                                           idxMatrix + offsetForIdxMatrixBecauseOfFalseErrors)+", the chapter list parsing is over.")
                self.chaptersMatrixSize = idxMatrix
                # End the while loop
                idxMatrix = self.MAX_SIZE_OF_MATRIX

        logPrint.printDebug("chaptersMatrix, " +
                            str(self.chaptersMatrixSize)+" lines: ")
        for idxMatrix in range(self.chaptersMatrixSize):
            logPrint.printDebug("|" +
                                self.chaptersMatrix[idxMatrix, 0]+"|"+self.chaptersMatrix[idxMatrix, 1]+"|")