[
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  push:\n    branches:\n      - '*'\n\nenv:\n  sourceBranch: ${{ github.ref }}\n  isNightly: ${{ contains(github.ref, 'dev') }}\n  isFinalRelease: ${{ contains(github.ref, 'master') }}\n\njobs:\n  build:\n    runs-on: ubuntu-18.04\n    steps:\n    - name: Check out source code\n      uses: actions/checkout@v2\n\n    # - name: Build\n    #   uses: dawidd6/action-ansible-playbook@v2\n    #   with:\n    #     playbook: build.yml\n    #     directory: ./\n    #     options: |\n    #       --extra-vars branch=${{ github.ref }}\n\n    - name: Build latest\n      if: ${{ env.isNightly == 'true' }}\n      env:\n        THAT_HASH: ${{ secrets.THAT_HASH }}\n      run: chmod +x build && ./build dev\n\n    - name: Build stable\n      if: ${{ env.isFinalRelease == 'true' }}\n      env:\n        THAT_HASH: ${{ secrets.THAT_HASH }}\n      run: chmod +x build && ./build final\n\n    - name: Release latest\n      uses: marvinpinto/action-automatic-releases@latest\n      if: env.isNightly == 'true'\n      with:\n        automatic_release_tag: latest-rc\n        files: dist/sdcard.zip\n        prerelease: true\n        repo_token: \"${{ secrets.GITHUB_TOKEN }}\"\n        title: latest-rc\n\n    - name: Release stable\n      uses: marvinpinto/action-automatic-releases@latest\n      if: env.isFinalRelease == 'true'\n      with:\n        automatic_release_tag: stable\n        files: dist/sdcard.zip\n        prerelease: false\n        repo_token: \"${{ secrets.GITHUB_TOKEN }}\"\n        title: stable\n"
  },
  {
    "path": ".gitignore",
    "content": "*.ini\n*.xcf\ndist"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"submodules/x360h1080p-rtsp-server\"]\n\tpath = submodules/x360h1080p-rtsp-server\n\turl = https://github.com/telmomarques/x360h1080p-rtsp-server.git\n[submodule \"submodules/mija-framegrabber\"]\n\tpath = submodules/mija-framegrabber\n\turl = https://github.com/crckmc/mija-framegrabber.git\n[submodule \"submodules/x360h1080p-websocket-stream-server\"]\n\tpath = submodules/x360h1080p-websocket-stream-server\n\turl = https://github.com/telmomarques/x360h1080p-websocket-stream-server.git\n[submodule \"submodules/x360h1080p-web-config-client\"]\n\tpath = submodules/x360h1080p-web-config-client\n\turl = https://github.com/telmomarques/x360h1080p-web-config-client\n[submodule \"submodules/x360h1080p-web-config-server\"]\n\tpath = submodules/x360h1080p-web-config-server\n\turl = https://github.com/telmomarques/x360h1080p-web-config-server\n"
  },
  {
    "path": "README.md",
    "content": "[![discord](https://img.shields.io/discord/713125176971231233?label=discord)](http://discord.gg/qggupzu)\n\nStable: ![CI](https://github.com/cmiguelcabral/mjsxj05cm-hacks/workflows/CI/badge.svg?branch=master)\n\nLatest: ![CI](https://github.com/cmiguelcabral/mjsxj05cm-hacks/workflows/CI/badge.svg?tag=latest-rc)\n\n# Mi Camera Hacks (MJSXJ05CM)\n\n- [Supported Cameras](#supported-cameras)\n- [Features](#features)\n- [Install Instructions](#install-instructions)\n- [FAQ](#faq)\n- [These Guys are Awesome](#these-guys-are-awesome)\n\n\nKeep calm and follow the procedure!\n\nSeriously now: it's still in beta, please read everything before continuing.\n\n## Supported Cameras\nFor now this is it, I'm working on supporting more cameras.\n\nModel Name(s) | Picture\n--- | ---\nMJSXJ05CM|![MJSXJ05CM](images/MJSXJ02CM.jpg)\n\n\n## Features\nFeature | Latest | Stable\n--- | --- | ---\nMotor Control | ![C/C++ CI](https://github.com/cmiguelcabral/mjsxj05cm-motor-control/workflows/C/C++%20CI/badge.svg?tag=latest-rc) | ![C/C++ CI](https://github.com/cmiguelcabral/mjsxj05cm-motor-control/workflows/C/C++%20CI/badge.svg?branch=master)\nOnvif Server | ![C/C++ CI](https://github.com/cmiguelcabral/mjsxj05cm-onvif_srvd/workflows/C/C++%20CI/badge.svg?tag=latest-rc) | ![C/C++ CI](https://github.com/cmiguelcabral/mjsxj05cm-onvif_srvd/workflows/C/C++%20CI/badge.svg?branch=master)\nRTSP Server | ![C/C++ CI](https://github.com/cmiguelcabral/mjsxj05cm-rtsp-server/workflows/C/C++%20CI/badge.svg?tag=latest-rc)| ![C/C++ CI](https://github.com/cmiguelcabral/mjsxj05cm-rtsp-server/workflows/C/C++%20CI/badge.svg?branch=master)\nRunit | ![C/C++ CI](https://github.com/telmomarques/runit/workflows/C/C++%20CI/badge.svg?tag=latest-rc) | ![C/C++ CI](https://github.com/telmomarques/runit/workflows/C/C++%20CI/badge.svg?branch=master)\nSFTP Server | ![C/C++ CI](https://github.com/telmomarques/openssh-portable/workflows/C/C++%20CI/badge.svg?tag=latest-rc) | ![C/C++ CI](https://github.com/telmomarques/openssh-portable/workflows/C/C++%20CI/badge.svg?branch=master)\nSSH Server |![C/C++ CI](https://github.com/telmomarques/dropbear/workflows/C/C++%20CI/badge.svg?tag=latest-rc)|![C/C++ CI](https://github.com/telmomarques/dropbear/workflows/C/C++%20CI/badge.svg?branch=master)\nWeb Configuration Client | ![Node.js CI](https://github.com/cmiguelcabral/mjsxj05cm-web-client/workflows/Node.js%20CI/badge.svg?tag=latest-rc) | ![Node.js CI](https://github.com/cmiguelcabral/mjsxj05cm-web-client/workflows/Node.js%20CI/badge.svg?branch=master)\nWeb Configuration Server | ![Go](https://github.com/cmiguelcabral/mjsxj05cm-web-server/workflows/Go/badge.svg?tag=latest-rc)| ![Go](https://github.com/cmiguelcabral/mjsxj05cm-web-server/workflows/Go/badge.svg?branch=master)\nWebsocker Stream Server | ![Go](https://github.com/cmiguelcabral/mjsxj05cm-websocket-stream-server/workflows/Go/badge.svg?tag=latest-rc)| ![Go](https://github.com/cmiguelcabral/mjsxj05cm-websocket-stream-server/workflows/Go/badge.svg?branch=master)\n\n## Install Instructions\nThe hacks exploits a flaw in firmware version 3.4.2_0062, **please read the instructions very carefully!!**\n\n- First [Check your camera firmware version](#view-camera-firmware-version)\n\n- If you have firmware version 3.4.2_0062, go to [Install the hacks](#install-the-hacks)\n\n- If you have another firmware version, nothing can be done unfortunately.\n\n### View camera firmware version\n1. Configure the camera using the Mi Home app\n2. Open the camera in the app and touch the 3 dots in the upper right corner\n3. Select the option \"General Settings\", and then \"Check for firmware upgrades\"\n4. The current firmware version is presented on the screen\n\n### Downgrade the Firmware\n\n\n⚠️ It is not possible to downgrade the frimware to 3.4.2_0062 on the MJSXJ05CM\n\nIf you have try to use an firmware and you camera is stuck on amber light try [this firmware](https://drive.google.com/file/d/1ve6XlBEiZebJV6ukJ0Oiu7DePw2JCsWj/view)\n\n### Install the hacks\n1. Configure the camera using the Mi Home app\n2. Download the latest release from [releases](https://github.com/telmomarques/xiaomi-360-1080p-hacks/releases)\n3. Copy the **contents** of \"sdcard\" folder to the root of your SD Card\n4. Power off the camera and insert the SD Card\n5. Power on the camera\n6. Find the IP address of your camera\n7. Open the web config interface o the camrea on your browser: [http://<your-camera-ip/](http://<your-camera-ip/)\n\n## FAQ\n\n### I can't downgrade the firmware, I follow the instructions but nothing happens.\nThy another SD Card. This actually happens a lot, trying a different SD Card usually solves it.\n\n### The RTSP stream is corrupted / stops working after a while.\nThe RTSP server is still in alpha stage.\n\nYou may see some corrupted frames here and there, and the server may stop working after a few hours (restarting the camera solves it). We're working on it, but if a 100% stable video stream is **critical** for you, then it's still not ready.\n\n### I'm worried about security, can I create/modify the [hack] password?\n\nSecurity is in the roadmap, but still not the primary focus. Right now you'll have to secure the camera by making sure it's only accessible on your private network, and that your network is secure.\n\n## These Guys are Awesome\nHuge thanks to everyone who contributed!\n\n[@aslafy-z](https://github.com/aslafy-z)\n[@crckmc](https://github.com/crckmc)\n[@thewh1teagle](https://github.com/thewh1teagle)\n[@telmomarques](https://github.com/telmomarques)\n"
  },
  {
    "path": "build",
    "content": "#!/bin/bash\n\ngithub_download_release_asset() {\n  local owner=$1\n  local repository=$2\n  local tagName=$3\n  local assetName=$4\n\n  is_200_ok=$(wget -q --show-progress --server-response https://github.com/${owner}/${repository}/releases/download/${tagName}/${assetName} 2>&1 | grep -c 'HTTP/1.1 200 OK')\n  if [ $is_200_ok != \"1\" ]; then\n    echo \"Failed to get ${assetName}\"\n    exit 1\n  fi\n}\n\ndownload_from_url() {\n  local assetName=$1\n  is_200_ok=$(wget -q --show-progress --server-response ${1} 2>&1 | grep -c 'HTTP/1.1 200 OK')\n  if [ $is_200_ok != \"1\" ]; then\n    echo \"Failed to get ${assetName}\"\n    exit 1\n  fi\n}\n\nprocess_external_download() {\n  local url=$1\n  local filename=$2\n\n  echo Downloading \\\"${url}\\\"\n\n  download_from_url ${url}\n}\n\nprocess_github_release_asset_download() {\n  local owner=$1\n  local repository=$2\n  local assetName=$3\n\n  if [ $releaseType == \"dev\" ]; then\n    tagName=\"latest-rc\"\n  fi\n\n  if [ $releaseType == \"final\" ]; then\n    tagName=\"latest\"\n  fi\n\n  echo Downloading \\\"${owner}/${repository}@${tagName}/${assetName}\\\"\n\n  github_download_release_asset ${owner} ${repository} ${tagName} ${assetName}\n}\n\nextract() {\n  local fileName=${1}\n  case \"$fileName\" in\n  *.zip)\n    echo Extracting ${fileName}\n    extract_zip ${fileName}\n    rm -f ${assetFilename}\n    ;;\n  *.tar)\n    echo Extracting ${fileName}\n    extract_tar ${fileName}\n    rm -f ${assetFilename}\n    ;;\n  esac\n}\n\nextract_zip() {\n  unzip -qq ${1}\n}\n\nextract_tar() {\n  tar -xf ${1}\n}\n\nprocess_build_file() {\n  local buildType=$1\n  local buildFilePath=.build\n  local source=$(cat ${buildFilePath} | jq -r \".source\")\n  local assetFilename=\"\"\n\n  if [ \"${source}\" == \"external\" ]; then\n    local url=$(cat ${buildFilePath} | jq -r \".url\")\n    assetFilename=$(cat ${buildFilePath} | jq -r \".filename\")\n    process_external_download ${url} ${assetFilename}\n\n  elif [ \"${source}\" == \"github-release-asset\" ]; then\n    local owner=$(cat ${buildFilePath} | jq -r \".owner\")\n    local repository=$(cat ${buildFilePath} | jq -r \".repository\")\n    assetFilename=$(cat ${buildFilePath} | jq -r \".assetName\")\n    process_github_release_asset_download ${owner} ${repository} ${assetFilename}\n  fi\n\n  rm $buildFilePath\n\n  if [[ ! -z ${assetFilename} ]]; then\n    extract ${assetFilename}\n  fi\n\n  if [ -d \"uclibc\" ]; then\n    cp uclibc/* .\n    rm -rf libc uclibc\n  fi\n}\n\nclean() {\n  echo \"Cleaning...\"\n  rm -rf dist\n}\n\nbuild() {\n  echo \"Building...\"\n  test -d dist || mkdir dist\n  cp -r sdcard/* dist/\n  shopt -s globstar\n  for buildFile in dist/**/.build; do\n    pushd $(dirname ${buildFile})\n    process_build_file ${1}\n    popd\n  done\n}\n\npackage() {\n  pushd dist\n  zip -r sdcard.zip * -x hacks/**/libc -x hacks/**/uclibc\n  popd\n}\n\nmain() {\n  local target=$1\n\n  case ${target} in\n  clean)\n    clean\n    ;;\n\n  dev | rc | final)\n    releaseType=$1\n\n    clean\n    build\n    package\n    ;;\n\n  *)\n    echo \"Invalid target '${1}'\"\n    ;;\n  esac\n}\n\nmain $1\n"
  },
  {
    "path": "sdcard/hacks/framegrabber/bin/.build",
    "content": "{\n  \"source\": \"github-release-asset\",\n  \"owner\": \"telmomarques\",\n  \"repository\": \"mija-framegrabber\",\n  \"assetName\": \"framegrabber.zip\",\n  \"clean\":\n  [\n    \"ipc009\"\n  ]\n}"
  },
  {
    "path": "sdcard/hacks/framegrabber/bin/framegrabber",
    "content": "#!/bin/sh\nCAMERA_MODEL=`factory get model | cut -d '.' -f3`\n\nif [ -z \"$CAMERA_MODEL\" ]; then\n  echo \"Can't get camera model, exiting.\"\n  exit 1\nfi\n\nBINARY_PATH=${CAMERA_MODEL}/framegrabber\n\nif [ ! -f \"$BINARY_PATH\" ]; then\n  echo \"Camera model '${CAMERA_MODEL}' not supported, exiting.\"\n  exit 1\nfi\n\ncp -f ${BINARY_PATH} /mnt/data/bin\nexec /mnt/data/bin/framegrabber \"$@\""
  },
  {
    "path": "sdcard/hacks/motor-control/bin/.build",
    "content": "{\n  \"source\": \"github-release-asset\",\n  \"owner\": \"cmiguelcabral\",\n  \"repository\": \"mjsxj05cm-motor-control\",\n  \"assetName\": \"motord\"\n}"
  },
  {
    "path": "sdcard/hacks/motor-control/meta/service/.enable",
    "content": ""
  },
  {
    "path": "sdcard/hacks/motor-control/meta/service/motor-control",
    "content": "#!/bin/sh\ncd /mnt/sdcard/hacks/motor-control/bin\nexec ./motord"
  },
  {
    "path": "sdcard/hacks/onvif-server/bin/.build",
    "content": "{\n  \"source\": \"github-release-asset\",\n  \"owner\": \"cmiguelcabral\",\n  \"repository\": \"mjsxj05cm-onvif_srvd\",\n  \"assetName\": \"onvif_srvd\"\n}"
  },
  {
    "path": "sdcard/hacks/onvif-server/meta/service/.enable",
    "content": ""
  },
  {
    "path": "sdcard/hacks/onvif-server/meta/service/onvif-server",
    "content": "#!/bin/sh\ncd /mnt/sdcard/hacks/onvif-server/bin\n\nsource /mnt/data/etc/os-release\n\nSTEPS=5\nMOTOR_CONTROL=\"/mnt/sdcard/hacks/motor-control/bin\"\nEVENT_FILE=\"$MOTOR_CONTROL/event\"\n\nLEFT=\"echo pan forward $STEPS > $EVENT_FILE\"\nRIGHT=\"echo pan reverse $STEPS > $EVENT_FILE\"\nUP=\"echo tilt forward $STEPS > $EVENT_FILE\"\nDOWN=\"echo tilt reverse $STEPS > $EVENT_FILE\"\n\n\nIP_ADDR=$(ip -4 addr show wlan0 | grep inet | awk '{print $2}' | cut -d'/' -f1)\nwhile [[ -z $IP_ADDR ]]; do\n    IP_ADDR=$(ip -4 addr show wlan0 | grep inet | awk '{print $2}' | cut -d'/' -f1)\ndone\necho $IP_ADDR\n\nONVIF_PROFILE_0=\"--name HD --width 1920 --height 1080 --url rtsp://$IP_ADDR:8554/mainstream --type H264\"\nONVID_PROFILE_1=\"--name SD --width 640 --height 360 --url rtsp://$IP_ADDR:8554/substream --type H264\"\necho $ONVIF_PROFILE_0\necho $ONVIF_PROFILE_1\n\nexec ./onvif_srvd --no_fork --pid_file /var/run/onvif_srvd.pid --model \"MJSXJ05CM\" --manufacturer \"Xiaomi\" --ifs wlan0 --port 5000 --scope onvif://www.onvif.org/Profile/S $ONVIF_PROFILE_0 $ONVIF_PROFILE_1 \\\n        --ptz \\\n        --move_left \"eval $LEFT\" \\\n        --move_right \"eval $RIGHT\" \\\n        --move_up \"eval $UP\" \\\n        --move_down \"eval $DOWN\""
  },
  {
    "path": "sdcard/hacks/rtsp-server/bin/.build",
    "content": "{\n  \"source\": \"github-release-asset\",\n  \"owner\": \"cmiguelcabral\",\n  \"repository\": \"mjsxj05cm-rtsp-server\",\n  \"assetName\": \"rtspserver\"\n}"
  },
  {
    "path": "sdcard/hacks/rtsp-server/config/config.json",
    "content": "{\n  \"encodingType\": \"h265\"\n}\n"
  },
  {
    "path": "sdcard/hacks/rtsp-server/meta/config/config.json",
    "content": "{\n  \"enable\": false,\n  \"encodingType\": \"h265\"\n}"
  },
  {
    "path": "sdcard/hacks/rtsp-server/meta/config/config.json.template",
    "content": "{\n  \"encodingType\": \"{{.EncodingType}}\"\n}\n"
  },
  {
    "path": "sdcard/hacks/rtsp-server/meta/service/framegrabber-mainstream",
    "content": "#!/bin/sh\n\nETCDIR=/mnt/data/etc/framegrabber/\nRTSP_MAINSTREAM_PIPE=\"${ETCDIR}rtsp_mainstream\"\n\nmkdir -p $ETCDIR\nmkfifo $RTSP_MAINSTREAM_PIPE\n\ncd /mnt/sdcard/hacks/framegrabber/bin\nexec ./framegrabber -f $RTSP_MAINSTREAM_PIPE -c 0"
  },
  {
    "path": "sdcard/hacks/rtsp-server/meta/service/framegrabber-substream",
    "content": "#!/bin/sh\n\nETCDIR=/mnt/data/etc/framegrabber/\nRTSP_SUBSTREAM_PIPE=\"${ETCDIR}rtsp_substream\"\n\nmkdir -p $ETCDIR\nmkfifo $RTSP_SUBSTREAM_PIPE\n\ncd /mnt/sdcard/hacks/framegrabber/bin\nexec ./framegrabber -f $RTSP_SUBSTREAM_PIPE -c 1"
  },
  {
    "path": "sdcard/hacks/rtsp-server/meta/service/rtsp-server",
    "content": "#!/bin/sh\ncd /mnt/sdcard/hacks/rtsp-server/bin\ncp -f rtspserver /mnt/data/bin\nexec /mnt/data/bin/rtspserver -c ../config/config.json -m /mnt/data/etc/framegrabber/rtsp_mainstream -s /mnt/data/etc/framegrabber/rtsp_substream\n"
  },
  {
    "path": "sdcard/hacks/runit/bin/.build",
    "content": "{\n  \"source\": \"github-release-asset\",\n  \"owner\": \"cmiguelcabral\",\n  \"repository\": \"mjsxj05cm-runit\",\n  \"assetName\": \"runit.tar\",\n  \"clean\":\n  [\n    \"*\"\n  ]\n}"
  },
  {
    "path": "sdcard/hacks/sftp-server/bin/.build",
    "content": "{\n  \"source\": \"github-release-asset\",\n  \"owner\": \"telmomarques\",\n  \"repository\": \"openssh-portable\",\n  \"assetName\": \"sftp-server.tar\"\n}"
  },
  {
    "path": "sdcard/hacks/ssh-server/bin/.build",
    "content": "{\n  \"source\": \"github-release-asset\",\n  \"owner\": \"telmomarques\",\n  \"repository\": \"dropbear\",\n  \"assetName\": \"dropbear.tar\"\n}"
  },
  {
    "path": "sdcard/hacks/ssh-server/config/config.json",
    "content": "{\n    \"users\":\n    [\n    ]\n}"
  },
  {
    "path": "sdcard/hacks/ssh-server/meta/config/config.json",
    "content": "{\n  \"enable\": false,\n  \"users\": []\n}"
  },
  {
    "path": "sdcard/hacks/ssh-server/meta/config/config.json.template",
    "content": "{\n  \"users\":\n  [\n  {{range $i, $u := .Users}}\n    {{if $i}}, {{end}}\n    {\"systemUsername\": \"{{.SystemUsername}}\", \"username\": \"{{.Username}}\", \"password\": \"{{.Password}}\"}\n  {{end}}\n  ]\n}"
  },
  {
    "path": "sdcard/hacks/ssh-server/meta/service/ssh-server",
    "content": "#!/bin/sh\nmkdir -p /mnt/data/etc/dropbear\ncd /mnt/sdcard/hacks/ssh-server/bin\nexec ./dropbear -FERB"
  },
  {
    "path": "sdcard/hacks/web-config/bin/.build",
    "content": "{\n  \"source\": \"github-release-asset\",\n  \"owner\": \"cmiguelcabral\",\n  \"repository\": \"mjsxj05cm-web-server\",\n  \"assetName\": \"web-config-server\"\n}"
  },
  {
    "path": "sdcard/hacks/web-config/meta/service/.enable",
    "content": ""
  },
  {
    "path": "sdcard/hacks/web-config/meta/service/web-config",
    "content": "#!/bin/sh\ncd /mnt/sdcard/hacks/web-config/bin\nexec ./web-config-server\n"
  },
  {
    "path": "sdcard/hacks/web-config/www/.build",
    "content": "{\n  \"source\": \"github-release-asset\",\n  \"owner\": \"cmiguelcabral\",\n  \"repository\": \"mjsxj05cm-web-client\",\n  \"assetName\": \"web-config-client.zip\",\n  \"clean\":\n  [\n    \"*\"\n  ]\n}"
  },
  {
    "path": "sdcard/hacks/websocket-stream-server/bin/.build",
    "content": "{\n  \"source\": \"github-release-asset\",\n  \"owner\": \"telmomarques\",\n  \"repository\": \"x360h1080p-websocket-stream-server\",\n  \"assetName\": \"websocket-stream-server\"\n}"
  },
  {
    "path": "sdcard/hacks/websocket-stream-server/meta/config/config.json",
    "content": "{\n  \"enable\": false\n}"
  },
  {
    "path": "sdcard/hacks/websocket-stream-server/meta/service/framegrabber-mainstream",
    "content": "#!/bin/sh\n\nETCDIR=/mnt/data/etc/framegrabber/\nWEBSOCKET_MAINSTREAM_PIPE=\"${ETCDIR}websocket_mainstream\"\n\nmkdir -p $ETCDIR\nmkfifo $WEBSOCKET_MAINSTREAM_PIPE\n\ncd /mnt/sdcard/hacks/framegrabber/bin\nexec ./framegrabber -f $WEBSOCKET_MAINSTREAM_PIPE -c 0"
  },
  {
    "path": "sdcard/hacks/websocket-stream-server/meta/service/framegrabber-substream",
    "content": "#!/bin/sh\n\nETCDIR=/mnt/data/etc/framegrabber/\nWEBSOCKET_SUBSTREAM_PIPE=\"${ETCDIR}websocket_substream\"\n\nmkdir -p $ETCDIR\nmkfifo $WEBSOCKET_SUBSTREAM_PIPE\n\ncd /mnt/sdcard/hacks/framegrabber/bin\nexec ./framegrabber -f $WEBSOCKET_SUBSTREAM_PIPE -c 1"
  },
  {
    "path": "sdcard/hacks/websocket-stream-server/meta/service/websocket-stream-server",
    "content": "#!/bin/sh\ncd /mnt/sdcard/hacks/websocket-stream-server/bin/\nexec ./websocket-stream-server -m=/mnt/data/etc/framegrabber/websocket_mainstream -s=/mnt/data/etc/framegrabber/websocket_substream\n"
  },
  {
    "path": "sdcard/manu_test/configure_services.sh",
    "content": "#!/bin/sh\n\nHACKS_DIR=/mnt/sdcard/hacks\nSERVICES_DIR=/mnt/data/etc/runit\n\ninstall_service() {\n\thackName=$1\n\tserviceDir=${HACKS_DIR}/${hackName}/meta/service\n\n\tif [ -d ${serviceDir} ] && [ -f ${serviceDir}/.enable ]; then\n\t\tcd ${serviceDir}\n\t\t\n\t\tfor service in ${serviceDir}/* ; do\n\t\t\tserviceName=`basename ${service}`\n\t\t\thackServiceDir=${SERVICES_DIR}/${hackName}-${serviceName}\n\t\t\tmkdir -p ${hackServiceDir}\n\t\t\tcp ${service} ${hackServiceDir}/run\n\t\tdone\n\tfi\n}\n\ninstall_services() {\n\trm -rf ${SERVICES_DIR}\n\n\tfor hack in ${HACKS_DIR}/* ; do\n\t\tif [ -d ${hack} ]; then\n\t\t\thackName=`basename $hack`\n\t\t\tinstall_service ${hackName}\n\t\tfi\n\tdone;\n\n\texport PATH=$PATH:${HACKS_DIR}/runit/bin\n\trunsvdir ${SERVICES_DIR} &\n}\n\nif [ -z $1 ]; then\n\tinstall_services\nelse\n\tinstall_service $1\nfi"
  },
  {
    "path": "sdcard/manu_test/disable_factory_mode.sh",
    "content": "#!/bin/sh\nif [ -f \"/tmp/factory_mode\" ]; then\n  rm -f /tmp/factory_mode\nelse\n  echo '#!/bin/sh\n  rm -- \"$0\"' > /mnt/data/bin/touch\n  chmod +x /mnt/data/bin/touch\nfi"
  },
  {
    "path": "sdcard/manu_test/entrypoint.sh",
    "content": "#!/bin/sh\necho \"Xiaomi Hacks enabled\"\n\n/mnt/sdcard/manu_test/disable_factory_mode.sh\n/mnt/sdcard/manu_test/configure_services.sh &\n"
  },
  {
    "path": "sdcard/manu_test/manu.sh",
    "content": "#!/bin/sh\n/mnt/sdcard/manu_test/entrypoint.sh"
  }
]