Exemple #1
0
    def _read_m3u_or_similar(file):
        item_to_remove = FileItem(file)
        item_list = [item_to_remove]
        # Try to read the file:
        try:
            item_to_remove.status = EncoderStatus.REMOVE
            with open(file, "r") as reader:
                for line in reader:
                    line = line.strip()
                    if not line.startswith("#"):
                        url = QUrl(line)
                        if url.isLocalFile() and os.path.exists(line):
                            # TODO: check with file_dir + line
                            item_list.append(FileItem(line))
                        elif url.authority() != "":
                            item_list.append(FileItem(file=file, url=line))
        except (UnicodeDecodeError, OSError):
            TransCoda.logger.warn(
                f"Could not open/read file:{file}. Transcoda will skip this file"
            )
            item_to_remove.status = EncoderStatus.ERROR
            item_list = [item_to_remove]
            return item_list

        return item_list
Exemple #2
0
def parse_javascript_url(url: QUrl) -> str:
    """Get JavaScript source from the given URL.

    See https://wiki.whatwg.org/wiki/URL_schemes#javascript:_URLs
    and https://github.com/whatwg/url/issues/385
    """
    ensure_valid(url)
    if url.scheme() != 'javascript':
        raise Error("Expected a javascript:... URL")
    if url.authority():
        raise Error("URL contains unexpected components: {}".format(
            url.authority()))

    urlstr = url.toString(QUrl.FullyEncoded)  # type: ignore[arg-type]
    urlstr = urllib.parse.unquote(urlstr)

    code = urlstr[len('javascript:'):]
    if not code:
        raise Error("Resulted in empty JavaScript code")

    return code
Exemple #3
0
def parse_javascript_url(url: QUrl) -> str:
    """Get JavaScript source from the given URL.

    See https://wiki.whatwg.org/wiki/URL_schemes#javascript:_URLs
    and https://github.com/whatwg/url/issues/385
    """
    ensure_valid(url)
    if url.scheme() != 'javascript':
        raise Error("Expected a javascript:... URL")
    if url.authority():
        raise Error("URL contains unexpected components: {}".format(
            url.authority()))

    code = url.path(QUrl.FullyDecoded)
    if url.hasQuery():
        code += '?' + url.query(QUrl.FullyDecoded)
    if url.hasFragment():
        code += '#' + url.fragment(QUrl.FullyDecoded)

    if not code:
        raise Error("Resulted in empty JavaScript code")

    return code
    def __stripUrl(self, url):
        """
        Private method to strip off all unneeded parts of a URL.
        
        @param url URL to be stripped (QUrl)
        @return stripped URL (QUrl)
        """
        cleanUrl = QUrl(url)
        cleanUrl.setQuery("")
        cleanUrl.setUserInfo("")

        authority = cleanUrl.authority()
        if authority.startswith("@"):
            authority = authority[1:]
        cleanUrl = QUrl("{0}://{1}{2}".format(cleanUrl.scheme(), authority,
                                              cleanUrl.path()))
        cleanUrl.setFragment("")
        return cleanUrl
Exemple #5
0
 def __stripUrl(self, url):
     """
     Private method to strip off all unneeded parts of a URL.
     
     @param url URL to be stripped (QUrl)
     @return stripped URL (QUrl)
     """
     cleanUrl = QUrl(url)
     if qVersion() >= "5.0.0":
         cleanUrl.setQuery("")
     else:
         cleanUrl.setQueryItems([])
     cleanUrl.setUserInfo("")
     
     authority = cleanUrl.authority()
     if authority.startswith("@"):
         authority = authority[1:]
     cleanUrl = QUrl("{0}://{1}{2}".format(
         cleanUrl.scheme(), authority, cleanUrl.path()))
     cleanUrl.setFragment("")
     return cleanUrl
Exemple #6
0
class NetworkMJPGImage(QQuickPaintedItem):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)

        self._stream_buffer = QByteArray()
        self._stream_buffer_start_index = -1
        self._network_manager = None  # type: QNetworkAccessManager
        self._image_request = None  # type: QNetworkRequest
        self._image_reply = None  # type: QNetworkReply
        self._image = QImage()
        self._image_rect = QRect()

        self._source_url = QUrl()
        self._started = False

        self._mirror = False

        self.setAntialiasing(True)

    ##  Ensure that close gets called when object is destroyed
    def __del__(self) -> None:
        self.stop()

    def paint(self, painter: "QPainter") -> None:
        if self._mirror:
            painter.drawImage(self.contentsBoundingRect(),
                              self._image.mirrored())
            return

        painter.drawImage(self.contentsBoundingRect(), self._image)

    def setSourceURL(self, source_url: "QUrl") -> None:
        self._source_url = source_url
        self.sourceURLChanged.emit()
        if self._started:
            self.start()

    def getSourceURL(self) -> "QUrl":
        return self._source_url

    sourceURLChanged = pyqtSignal()
    source = pyqtProperty(QUrl,
                          fget=getSourceURL,
                          fset=setSourceURL,
                          notify=sourceURLChanged)

    def setMirror(self, mirror: bool) -> None:
        if mirror == self._mirror:
            return
        self._mirror = mirror
        self.mirrorChanged.emit()
        self.update()

    def getMirror(self) -> bool:
        return self._mirror

    mirrorChanged = pyqtSignal()
    mirror = pyqtProperty(bool,
                          fget=getMirror,
                          fset=setMirror,
                          notify=mirrorChanged)

    imageSizeChanged = pyqtSignal()

    @pyqtProperty(int, notify=imageSizeChanged)
    def imageWidth(self) -> int:
        return self._image.width()

    @pyqtProperty(int, notify=imageSizeChanged)
    def imageHeight(self) -> int:
        return self._image.height()

    @pyqtSlot()
    def start(self) -> None:
        self.stop()  # Ensure that previous requests (if any) are stopped.

        if not self._source_url:
            Logger.log("w", "Unable to start camera stream without target!")
            return

        auth_data = ""
        if self._source_url.userInfo():
            # move auth data to basic authorization header
            auth_data = base64.b64encode(
                self._source_url.userInfo().encode()).decode("utf-8")
            authority = self._source_url.authority()
            self._source_url.setAuthority(authority.rsplit("@", 1)[1])

        self._image_request = QNetworkRequest(self._source_url)
        self._image_request.setAttribute(
            QNetworkRequest.FollowRedirectsAttribute, True)

        if auth_data:
            self._image_request.setRawHeader(b"Authorization",
                                             ("basic %s" % auth_data).encode())

        if self._source_url.scheme().lower() == "https":
            # ignore SSL errors (eg for self-signed certificates)
            ssl_configuration = QSslConfiguration.defaultConfiguration()
            ssl_configuration.setPeerVerifyMode(QSslSocket.VerifyNone)
            self._image_request.setSslConfiguration(ssl_configuration)

        if self._network_manager is None:
            self._network_manager = QNetworkAccessManager()

        self._image_reply = self._network_manager.get(self._image_request)
        self._image_reply.downloadProgress.connect(
            self._onStreamDownloadProgress)

        self._started = True

    @pyqtSlot()
    def stop(self) -> None:
        self._stream_buffer = QByteArray()
        self._stream_buffer_start_index = -1

        if self._image_reply:
            try:
                try:
                    self._image_reply.downloadProgress.disconnect(
                        self._onStreamDownloadProgress)
                except Exception:
                    pass

                if not self._image_reply.isFinished():
                    self._image_reply.close()
            except Exception as e:  # RuntimeError
                pass  # It can happen that the wrapped c++ object is already deleted.

            self._image_reply = None
            self._image_request = None

        self._network_manager = None

        self._started = False

    def _onStreamDownloadProgress(self, bytes_received: int,
                                  bytes_total: int) -> None:
        # An MJPG stream is (for our purpose) a stream of concatenated JPG images.
        # JPG images start with the marker 0xFFD8, and end with 0xFFD9
        if self._image_reply is None:
            return
        self._stream_buffer += self._image_reply.readAll()

        if (len(self._stream_buffer) >
                5000000):  # No single camera frame should be 5 MB or larger
            Logger.log(
                "w",
                "MJPEG buffer exceeds reasonable size. Restarting stream...")
            self.stop()  # resets stream buffer and start index
            self.start()
            return

        if self._stream_buffer_start_index == -1:
            self._stream_buffer_start_index = self._stream_buffer.indexOf(
                b"\xff\xd8")
        stream_buffer_end_index = self._stream_buffer.lastIndexOf(b"\xff\xd9")
        # If this happens to be more than a single frame, then so be it; the JPG decoder will
        # ignore the extra data. We do it like this in order not to get a buildup of frames

        if self._stream_buffer_start_index != -1 and stream_buffer_end_index != -1:
            jpg_data = self._stream_buffer[
                self._stream_buffer_start_index:stream_buffer_end_index + 2]
            self._stream_buffer = self._stream_buffer[stream_buffer_end_index +
                                                      2:]
            self._stream_buffer_start_index = -1
            self._image.loadFromData(jpg_data)

            if self._image.rect() != self._image_rect:
                self.imageSizeChanged.emit()

            self.update()