diff --git a/MSVC/make-daemon.bat b/MSVC/make-daemon.bat
deleted file mode 100644
index 166934e590359c36ed79d0144d18437f56f8d2c2..0000000000000000000000000000000000000000
--- a/MSVC/make-daemon.bat
+++ /dev/null
@@ -1,163 +0,0 @@
-:: Ring - native Windows fetch and build
-
-@echo off
-@setlocal
-
-if "%1" == "/?" goto Usage
-if "%~1" == "" goto Usage
-
-set doFetch=N
-set doBuildContrib=N
-set doBuildDaemon=N
-set targetContrib=""
-
-set SCRIPTNAME=%~nx0
-
-if "%1"=="fetch" (
-    set doFetch=Y
-) else if "%1"=="contrib" (
-    set doBuildContrib=Y
-) else if "%1"=="daemon" (
-    set doBuildDaemon=Y
-) else (
-    goto Usage
-)
-
-set BUILD.x86=N
-set BUILD.x64=Y
-set BUILD.uwp=N
-set BUILD.win32=Y
-
-shift
-:ParseArgs
-if "%1" == "" goto FinishedArgs
-if /I "%1"=="x86" (
-    set BUILD.x86=Y
-) else if /I "%1"=="x64" (
-    set BUILD.x64=Y
-) else if /I "%1"=="uwp" (
-    set BUILD.uwp=Y
-) else if /I "%1"=="win32" (
-    set BUILD.win32=Y
-) else if /I "%1" neq "" (
-    if "%doBuildContrib%" neq "N" (
-        set targetContrib=%1
-    ) else if "%doFetch%" neq "N" (
-        set targetContrib=%1
-    )
-) else (
-    goto Usage
-)
-shift
-goto ParseArgs
-
-:FinishedArgs
-set CONTRIB_DIR=%~dp0../contrib
-set platform=N
-set arch=N
-if "%BUILD.x86%"=="Y" (
-    set arch=x86
-) else if "%BUILD.x64%"=="Y" (
-    set arch=x64
-)
-if "%BUILD.uwp%"=="Y" (
-    set platform=uwp
-    if "%arch%"=="x86" (
-        set DAEMON_MSBUILD_ARGS=/nologo /p:useenv=true /p:Configuration=ReleaseLib /p:Platform=Win32 /verbosity:normal /maxcpucount:%NUMBER_OF_PROCESSORS%
-    ) else if "%arch%"=="x64" (
-        set DAEMON_MSBUILD_ARGS=/nologo /p:useenv=true /p:Configuration=ReleaseLib /p:Platform=x64 /verbosity:normal /maxcpucount:%NUMBER_OF_PROCESSORS%
-    )
-) else if "%BUILD.win32%"=="Y" (
-    set platform=win32
-    if "%arch%"=="x86" (
-        set DAEMON_MSBUILD_ARGS=/nologo /p:useenv=true /p:Configuration=ReleaseLib_win32 /p:Platform=Win32 /verbosity:normal /maxcpucount:%NUMBER_OF_PROCESSORS%
-    ) else if "%arch%"=="x64" (
-        set DAEMON_MSBUILD_ARGS=/nologo /p:useenv=true /p:Configuration=ReleaseLib_win32 /p:Platform=x64 /verbosity:normal /maxcpucount:%NUMBER_OF_PROCESSORS%
-    )
-)
-if "%arch%" neq "N" (
-    if "%platform%" neq "N" (
-        if "%doFetch%" neq "N" (
-            call %CONTRIB_DIR%\src\fetch_all.bat %platform% %arch% %targetContrib%
-        ) else if "%doBuildContrib%" neq "N" (
-			call %CONTRIB_DIR%\build_all.bat %platform% %arch% %targetContrib%
-        ) else if "%doBuildDaemon%" neq "N" (
-            goto buildDaemon
-        )
-        goto :eof
-    )
-)
-goto Usage
-
-:buildDaemon
-@setlocal
-
-set VSInstallerFolder="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer"
-if %PROCESSOR_ARCHITECTURE%==x86 set VSInstallerFolder="%ProgramFiles%\Microsoft Visual Studio\Installer"
-
-pushd %VSInstallerFolder%
-for /f "usebackq tokens=*" %%i in (`vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do (
-  set VSLATESTDIR=%%i
-)
-popd
-
-echo VS Installation folder: %VSLATESTDIR%
-
-if not exist "%VSLATESTDIR%\VC\Auxiliary\Build\vcvarsall.bat" (
-    echo:
-    echo VSInstallDir not found or not installed correctly.
-    goto cleanup
-)
-
-if %PROCESSOR_ARCHITECTURE%==x86 (
-    if "%platform%"=="uwp" (
-        set Comp_x86=x86 uwp 10.0.15063.0
-        set Comp_x64=x86_amd64 uwp 10.0.15063.0
-    ) else (
-        set Comp_x86=x86 10.0.15063.0
-        set Comp_x64=x86_amd64 10.0.15063.0
-    )
-) else (
-    if "%platform%"=="uwp" (
-        set Comp_x86=amd64_x86 uwp 10.0.15063.0
-        set Comp_x64=amd64 uwp 10.0.15063.0
-    ) else (
-        set Comp_x86=amd64_x86 10.0.15063.0
-        set Comp_x64=amd64 10.0.15063.0
-    )
-)
-
-set path=%path:"=%
-if "%arch%"=="x86" (
-    call "%VSLATESTDIR%"\\VC\\Auxiliary\\Build\\vcvarsall.bat %Comp_x86%
-) else if "%arch%"=="x64" (
-    call "%VSLATESTDIR%"\\VC\\Auxiliary\\Build\\vcvarsall.bat %Comp_x64%
-)
-
-::build the daemon
-echo "building daemon..."
-msbuild ring-daemon.vcxproj %DAEMON_MSBUILD_ARGS%
-goto :eof
-
-@endlocal
-
-:Usage
-echo:
-echo The correct usage is:
-echo:
-echo     %0 [action] [target platform] [architecture]
-echo:
-echo where
-echo:
-echo [action]           is: fetch ^| build
-echo [target platform]  is: uwp   ^| win32
-echo [architecture]     is: x86   ^| x64
-echo:
-echo For example:
-echo     %SCRIPTNAME% fetch win32 x86   - fetch contrib for a win32/x86 build
-echo     %SCRIPTNAME% contrib uwp x64   - build uwp(win10)/x64 contrib
-echo     %SCRIPTNAME% daemon uwp x64    - build uwp(win10)/x64 daemon
-echo:
-goto :eof
-
-@endlocal
\ No newline at end of file
diff --git a/MSVC/package.json b/MSVC/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..851eeba1fe6680edf6e6a37d499cdf8a85aa8c55
--- /dev/null
+++ b/MSVC/package.json
@@ -0,0 +1,16 @@
+{
+    "name": "daemon",
+    "deps": [
+        "asio",
+        "ffmpeg",
+        "natpmp",
+        "opendht",
+        "pjproject",
+        "portaudio",
+        "secp256k1",
+        "upnp",
+        "yaml-cpp"
+    ],
+    "configuration": "ReleaseLib_win32",
+    "project_paths": ["ring-daemon.vcxproj"]
+}
\ No newline at end of file
diff --git a/MSVC/ring-daemon.sln b/MSVC/ring-daemon.sln
deleted file mode 100644
index 76652c2cde2b07b54c7d7672b0b165db87011020..0000000000000000000000000000000000000000
--- a/MSVC/ring-daemon.sln
+++ /dev/null
@@ -1,54 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27703.2026
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ring-daemon", "ring-daemon.vcxproj", "{79F8DE42-595D-49D9-A66F-55244FD9DCC3}"
-EndProject
-Global
-	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|x64 = Debug|x64
-		Debug|x86 = Debug|x86
-		DebugLib_win32|x64 = DebugLib_win32|x64
-		DebugLib_win32|x86 = DebugLib_win32|x86
-		DebugLib|x64 = DebugLib|x64
-		DebugLib|x86 = DebugLib|x86
-		Release|x64 = Release|x64
-		Release|x86 = Release|x86
-		ReleaseLib_win32|x64 = ReleaseLib_win32|x64
-		ReleaseLib_win32|x86 = ReleaseLib_win32|x86
-		ReleaseLib|x64 = ReleaseLib|x64
-		ReleaseLib|x86 = ReleaseLib|x86
-	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.Debug|x64.ActiveCfg = Debug|x64
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.Debug|x64.Build.0 = Debug|x64
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.Debug|x86.ActiveCfg = Debug|Win32
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.Debug|x86.Build.0 = Debug|Win32
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.DebugLib_win32|x64.ActiveCfg = DebugLib_win32|x64
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.DebugLib_win32|x64.Build.0 = DebugLib_win32|x64
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.DebugLib_win32|x86.ActiveCfg = DebugLib_win32|Win32
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.DebugLib_win32|x86.Build.0 = DebugLib_win32|Win32
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.DebugLib|x64.ActiveCfg = DebugLib|x64
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.DebugLib|x64.Build.0 = DebugLib|x64
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.DebugLib|x86.ActiveCfg = DebugLib|Win32
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.DebugLib|x86.Build.0 = DebugLib|Win32
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.Release|x64.ActiveCfg = Release|x64
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.Release|x64.Build.0 = Release|x64
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.Release|x86.ActiveCfg = Release|Win32
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.Release|x86.Build.0 = Release|Win32
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.ReleaseLib_win32|x64.ActiveCfg = ReleaseLib_win32|x64
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.ReleaseLib_win32|x64.Build.0 = ReleaseLib_win32|x64
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.ReleaseLib_win32|x86.ActiveCfg = ReleaseLib_win32|Win32
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.ReleaseLib_win32|x86.Build.0 = ReleaseLib_win32|Win32
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.ReleaseLib|x64.ActiveCfg = ReleaseLib|x64
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.ReleaseLib|x64.Build.0 = ReleaseLib|x64
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.ReleaseLib|x86.ActiveCfg = ReleaseLib|Win32
-		{79F8DE42-595D-49D9-A66F-55244FD9DCC3}.ReleaseLib|x86.Build.0 = ReleaseLib|Win32
-	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
-	EndGlobalSection
-	GlobalSection(ExtensibilityGlobals) = postSolution
-		SolutionGuid = {7505C3ED-E07A-48C4-BE60-8BD5A00CC85C}
-	EndGlobalSection
-EndGlobal
diff --git a/MSVC/ring-daemon.vcxproj b/MSVC/ring-daemon.vcxproj
index 6647055f0b715ba3449f33acb5cb93d0539866a0..f36704a1e54bd90e71344c08e6d49c624b11a577 100644
--- a/MSVC/ring-daemon.vcxproj
+++ b/MSVC/ring-daemon.vcxproj
@@ -53,70 +53,70 @@
   <PropertyGroup Label="Globals">
     <ProjectGuid>{79F8DE42-595D-49D9-A66F-55244FD9DCC3}</ProjectGuid>
     <RootNamespace>ringdaemon</RootNamespace>
-    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
+<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
+<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugLib|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
+<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugLib_win32|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
+<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
+<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
     <WholeProgramOptimization>false</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLib|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
+<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
     <WholeProgramOptimization>false</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLib_win32|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
+<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
     <WholeProgramOptimization>false</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>DynamicLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
+<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugLib|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
+<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugLib_win32|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
+<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
+<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
     <WholeProgramOptimization>false</WholeProgramOptimization>
     <CharacterSet>Unicode</CharacterSet>
     <WindowsAppContainer>false</WindowsAppContainer>
@@ -124,14 +124,14 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLib|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
+<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
     <WholeProgramOptimization>false</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLib_win32|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
+<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
     <WholeProgramOptimization>false</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
diff --git a/MSVC/winmake.py b/MSVC/winmake.py
new file mode 100644
index 0000000000000000000000000000000000000000..62b214852c4c7ee46d8b62d0e0d676d97a7968d6
--- /dev/null
+++ b/MSVC/winmake.py
@@ -0,0 +1,750 @@
+import sys
+import os
+import subprocess
+import platform
+import argparse
+import json
+import re
+import zipfile
+import tarfile
+import multiprocessing
+import shutil
+import shlex
+import glob
+import time
+from datetime import timedelta
+import struct
+import importlib
+import logging
+import traceback
+import re
+import fileinput
+
+root_logger = logging.getLogger(__name__)
+log = None
+
+# project paths
+daemon_msvc_dir = os.path.dirname(os.path.realpath(__file__))
+daemon_dir = os.path.dirname(daemon_msvc_dir)
+contrib_src_dir = daemon_dir + r'\contrib\src'
+contrib_build_dir = daemon_dir + r'\contrib\build'
+contrib_tmp_dir = daemon_dir + r'\contrib\tarballs'
+
+# SCM
+wget_args = [
+    '--no-check-certificate', '--retry-connrefused',
+    '--waitretry=1', '--read-timeout=20',
+    '--timeout=15', '--tries=4']
+git_apply_args = ['apply', '--reject',
+                  '--ignore-whitespace', '--whitespace=fix']
+patch_args = ['-flp1', '-i']
+
+# vs help
+win_sdk_default = '10.0.16299.0'
+win_toolset_default = 'v141'
+
+vs_where_path = os.path.join(
+    os.environ['ProgramFiles(x86)'], 'Microsoft Visual Studio', 'Installer', 'vswhere.exe'
+)
+
+host_is_64bit = (False, True)[platform.machine().endswith('64')]
+python_is_64bit = (False, True)[8 * struct.calcsize("P") == 64]
+
+
+def shellquote(s, windows=False):
+    if not windows:
+        return "'" + s.replace("'", "'\''") + "'"
+    else:
+        return '\"' + s + '\"'
+
+
+def getLatestVSVersion():
+    args = [
+        '-latest',
+        '-products *',
+        '-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
+        '-property installationVersion'
+    ]
+    cmd = [vs_where_path] + args
+    output = subprocess.check_output(' '.join(cmd)).decode('utf-8')
+    if output:
+        return output.splitlines()[0].split('.')[0]
+    else:
+        return
+
+
+def findVSLatestDir():
+    args = [
+        '-latest',
+        '-products *',
+        '-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
+        '-property installationPath'
+    ]
+    cmd = [vs_where_path] + args
+    output = subprocess.check_output(' '.join(cmd)).decode('utf-8')
+    if output:
+        return output.splitlines()[0]
+    else:
+        return
+
+
+def findMSBuild():
+    filename = 'MSBuild.exe'
+    for root, _, files in os.walk(findVSLatestDir() + r'\\MSBuild'):
+        if filename in files:
+            return os.path.join(root, filename)
+
+
+def getVSEnv(arch='x64', platform='', version=''):
+    env_cmd = 'set path=%path:"=% && ' + \
+        getVSEnvCmd(arch, platform, version) + ' && set'
+    p = subprocess.Popen(env_cmd,
+                         shell=True,
+                         stdout=subprocess.PIPE)
+    stdout, _ = p.communicate()
+    out = stdout.decode('utf-8').split("\r\n")[5:-1]
+    return dict(s.split('=', 1) for s in out)
+
+
+def getCMakeGenerator(vs_version):
+    if vs_version == '15':
+        return '\"Visual Studio 15 2017 Win64\"'
+    else:
+        return '\"Visual Studio ' + vs_version + ' 2019\"'
+
+
+def getVSEnvCmd(arch='x64', platform='', version=''):
+    vcEnvInit = [findVSLatestDir() + r'\VC\Auxiliary\Build\"vcvarsall.bat']
+    if platform != '':
+        args = [arch, platform, version]
+    else:
+        args = [arch, version]
+    if args:
+        vcEnvInit.extend(args)
+    vcEnvInit = 'call \"' + ' '.join(vcEnvInit)
+    return vcEnvInit
+
+
+def make_daemon(pkg_info, force, sdk_version, toolset):
+    for dep in pkg_info.get('deps', []):
+        resolve(dep, False, sdk_version, toolset)
+    root_logger.warning(
+        "Building daemon with preferred sdk version %s and toolset %s", sdk_version, toolset)
+    env_set = 'false' if pkg_info.get('with_env', '') == '' else 'true'
+    sdk_to_use = sdk_version if env_set == 'false' else pkg_info.get('with_env', '')
+    build('daemon', daemon_msvc_dir,
+          pkg_info.get('project_paths', []),
+          pkg_info.get('custom_scripts', {}),
+          env_set,
+          sdk_to_use,
+          toolset,
+          conf=pkg_info.get('configuration', 'Release'))
+
+
+def make(pkg_info, force, sdk_version, toolset):
+    pkg_name = pkg_info.get('name')
+    if pkg_name == 'daemon':
+        return make_daemon(pkg_info, force, sdk_version, toolset)
+    version = pkg_info.get('version')
+    pkg_build_uptodate = False
+    pkg_ver_uptodate = False
+    # attempt to get the current built version
+    current_version = ''
+    # check build file for current version
+    build_file = contrib_build_dir + r'\\.' + pkg_name
+    if os.path.exists(build_file):
+        if force:
+            os.remove(build_file)
+        else:
+            pkg_build_uptodate = is_build_uptodate(pkg_name, build_file)
+            with open(build_file, 'r+') as f:
+                current_version = f.read()
+                if current_version == version:
+                    pkg_ver_uptodate = True
+    for dep in pkg_info.get('deps', []):
+        dep_build_dep = resolve(dep, False, sdk_version, toolset)
+        if dep_build_dep:
+            pkg_build_uptodate = False
+    pkg_up_to_date = pkg_build_uptodate & pkg_ver_uptodate
+    if not pkg_up_to_date or current_version is None or force:
+        if not current_version is '':
+            log.debug(pkg_name + ' currently @: ' + current_version)
+        if force:
+            log.debug('Forcing fetch/patch/build for ' + pkg_name)
+        should_fetch = not pkg_up_to_date
+        pkg_build_path = contrib_build_dir + '\\' + pkg_name
+        should_fetch &= not os.path.exists(pkg_build_path)
+        if not pkg_up_to_date or force:
+            if not force and not current_version is None:
+                log.warning(pkg_name + ' is not up to date')
+            if (should_fetch or force) and fetch_pkg(pkg_name, version, pkg_info['url'], force):
+                apply(pkg_name, pkg_info.get('patches', []),
+                      pkg_info.get('win_patches', []))
+        env_set = 'false' if pkg_info.get('with_env', '') != '' else 'true'
+        sdk_to_use = sdk_version if env_set == 'false' else pkg_info.get('with_env', '')
+        if build(pkg_name,
+                 contrib_build_dir + '\\' + pkg_name,
+                 pkg_info.get('project_paths', []),
+                 pkg_info.get('custom_scripts', {}),
+                 env_set,
+                 sdk_to_use,
+                 toolset):
+            track_build(pkg_name, version)
+        else:
+            log.error("Couldn't build contrib " + pkg_name)
+            exit(1)
+        log.info(pkg_name + ' up to date')
+        return True
+    # did not need build
+    log.info(pkg_name + ' already up to date')
+    return False
+
+
+def fetch_pkg(pkg_name, version, url, force):
+    version_replace = re.compile(re.escape('__VERSION__'))
+    full_url = version_replace.sub(version, url)
+    if not full_url:
+        log.error(pkg_name + ' missing url in package configuration')
+        return False
+    archive_name = full_url[full_url.rfind("/") + 1:]
+    archive_path = contrib_tmp_dir + '\\' + archive_name
+    if not os.path.exists(archive_path):
+        log.debug('Fetching ' + pkg_name + ' from: ' + full_url)
+        args = [full_url, '-P', contrib_tmp_dir]
+        args.extend(wget_args)
+        dl_result = getSHrunner().exec_batch('wget', args)
+        if dl_result[0] is not 0:
+            log.warning(
+                'wget failure. Using powershell Invoke-WebRequest instead')
+            args = ['-Uri', full_url, '-OutFile', archive_path]
+            dl_result = getSHrunner().exec_ps1('Invoke-WebRequest', args)
+        return extract_archive(pkg_name, archive_name, archive_path)
+    else:
+        log.warning(archive_name +
+                    ' already exists in the tarball/archive directory')
+        decomp_result = extract_archive(pkg_name, archive_name, archive_path)
+        if not decomp_result and force:
+            log.debug('Removing old tarball for ' + archive_name)
+            getSHrunner().exec_batch('del', ['/s', '/q', archive_name])
+            return fetch_pkg(pkg_name, version, url, False)
+        else:
+            return True
+    return False
+
+
+def remove_archive_if_needed(pkg_build_path, dirty_path):
+    if os.path.exists(pkg_build_path):
+        log.debug('Removing old package ' + pkg_build_path)
+        getSHrunner().exec_batch('rmdir', ['/s', '/q', pkg_build_path])
+    elif os.path.exists(dirty_path):
+        log.debug('Removing partial decompression ' + dirty_path)
+        getSHrunner().exec_batch('rmdir', ['/s', '/q', dirty_path])
+
+
+def extract_tar(pkg_build_path, name, path):
+    with tarfile.open(path, 'r') as tarball:
+        tar_common_prefix = os.path.commonprefix(tarball.getnames())
+        dirty_path = contrib_build_dir + '\\' + tar_common_prefix
+        remove_archive_if_needed(pkg_build_path, dirty_path)
+        log.debug('Decompressing ' + name + ' to ' + pkg_build_path)
+        tarball.extractall(contrib_build_dir)
+        os.rename(contrib_build_dir + '\\' + tar_common_prefix,
+                  pkg_build_path)
+        return True
+    return False
+
+
+def extract_zip(pkg_build_path, name, path):
+    with zipfile.ZipFile(path, 'r') as ziparchive:
+        zip_common_prefix = os.path.commonprefix(ziparchive.namelist())
+        dirty_path = contrib_build_dir + '\\' + zip_common_prefix
+        remove_archive_if_needed(pkg_build_path, dirty_path)
+        log.debug('Decompressing ' + name + ' to ' + pkg_build_path)
+        ziparchive.extractall(contrib_build_dir)
+        os.rename(contrib_build_dir + '\\' + zip_common_prefix,
+                  pkg_build_path)
+        return True
+    return False
+
+
+def extract_archive(pkg_name, name, path):
+    pkg_build_path = contrib_build_dir + '\\' + pkg_name
+    if tarfile.is_tarfile(path):
+        return extract_tar(pkg_build_path, name, path)
+    elif zipfile.is_zipfile(path):
+        return extract_zip(pkg_build_path, name, path)
+
+
+def apply_linux(patch_path):
+    log.debug('applying linux patch ' + patch_path)
+    args = []
+    args.extend(patch_args)
+    args.append(patch_path)
+    return getSHrunner().exec_sh('patch', args)
+
+
+def apply_windows(patch_path):
+    log.debug('applying windows patch ' + patch_path)
+    args = []
+    args.extend(git_apply_args)
+    args.append(patch_path)
+    return getSHrunner().exec_batch('git', args)
+
+
+def apply(pkg_name, patches, win_patches):
+    log.debug('patching ' + pkg_name + '...')
+    tmp_dir = os.getcwd()
+    pkg_build_path = contrib_build_dir + '\\' + pkg_name
+    if not os.path.exists(pkg_build_path):
+        os.makedirs(pkg_build_path)
+    os.chdir(pkg_build_path)
+    base_sh_src_path = get_sh_path(contrib_src_dir)
+    # 1. git patches (LF)
+    for p in patches:
+        patch_path = base_sh_src_path + '/' + pkg_name + '/' + p
+        result = apply_linux(patch_path)
+        if result[0]:
+            log.error('Couldn\'t apply patch: ' + patch_path)
+            exit(1)
+
+    # 2. windows git patches (CR/LF)
+    for wp in win_patches:
+        patch_path = contrib_src_dir + '\\' + pkg_name + '\\' + wp
+        result = apply_windows(patch_path)
+        if result[0]:
+            log.error('Couldn\'t apply patch: ' + patch_path)
+            exit(1)
+
+    os.chdir(tmp_dir)
+
+
+def get_pkg_file(pkg_name):
+    if pkg_name == 'daemon':
+        pkg_location = daemon_msvc_dir
+    else:
+        pkg_location = daemon_dir + r'\contrib\src\\' + pkg_name
+    pkg_json_file = pkg_location + r"\\package.json"
+    if not os.path.exists(pkg_json_file):
+        log.error("No package info for " + pkg_name)
+        sys.exit(1)
+    return pkg_json_file
+
+
+def resolve(pkg_name, force=False, sdk_version='', toolset=''):
+    pkg_json_file = get_pkg_file(pkg_name)
+    with open(pkg_json_file) as json_file:
+        log.info('Resolving: ' + pkg_name)
+        pkg_info = json.load(json_file)
+        try:
+            return make(pkg_info, force, sdk_version, toolset)
+        except Exception as e:
+            print(e)
+            log.error('Make ' + pkg_name + ' failed!')
+            sys.exit(1)
+
+
+def track_build(pkg_name, version):
+    build_file = contrib_build_dir + '\\.' + pkg_name
+    f = open(build_file, "w+")
+    f.write(version)
+    f.close()
+
+
+def build(pkg_name, pkg_dir, project_paths, custom_scripts, with_env, sdk,
+          toolset, arch='x64', conf='Release'):
+    getMSbuilder().set_msbuild_configuration(with_env, arch, conf, toolset)
+    getMSbuilder().setup_vs_env(sdk)
+
+    success = True
+    build_operations = 0
+    tmp_dir = os.getcwd()
+    os.chdir(pkg_dir)
+
+    # pre_build custom step (CMake...)
+    pre_build_scripts = custom_scripts.get("pre_build", [])
+    if pre_build_scripts:
+        log.debug('Pre_build phase')
+    for script in pre_build_scripts:
+        result = getSHrunner().exec_batch(script)
+        success &= not result[0]
+        build_operations += 1
+
+    # build custom step (nmake...)
+    build_scripts = custom_scripts.get("build", [])
+    if build_scripts:
+        log.debug('Custom Build phase')
+    for script in build_scripts:
+        result = getSHrunner().exec_batch(script)
+        success &= not result[0]
+        build_operations += 1
+
+    # vcxproj files
+    if project_paths:
+        log.debug('Msbuild phase')
+    for pp in project_paths:
+        project_full_path = pkg_dir + '\\' + pp
+        log.debug('Building: ' + pkg_name + " with sdk version " +
+                  sdk + " and toolset " + toolset)
+        getMSbuilder().build(pkg_name, project_full_path, sdk, toolset)
+        build_operations += 1
+
+    os.chdir(tmp_dir)
+
+    # should cover header only, no cmake, etc
+    ops = len(build_scripts) + len(project_paths) + len(pre_build_scripts)
+    return success and build_operations == ops
+
+
+class Singleton:
+    def __init__(self, decorated):
+        self._decorated = decorated
+
+    def instance(self):
+        try:
+            return self._instance
+        except AttributeError:
+            self._instance = self._decorated()
+            return self._instance
+
+    def __call__(self):
+        raise TypeError('Singletons must be accessed through `instance()`.')
+
+    def __instancecheck__(self, inst):
+        return isinstance(inst, self._decorated)
+
+
+class ScriptType:
+    ps1 = 1
+    cmd = 2
+    sh = 3
+
+
+@Singleton
+class SHrunner():
+    def __init__(self):
+        sys_path = (r'\Sysnative', r'\system32')[python_is_64bit]
+        full_sys_path = os.path.expandvars('%systemroot%') + sys_path
+
+        # powershell
+        self.ps_path = full_sys_path + r'\WindowsPowerShell\v1.0\powershell.exe'
+        if not os.path.exists(self.ps_path):
+            log.error('Powershell not found at %s.' % self.ps_path)
+            sys.exit(1)
+
+        # bash
+        if not os.environ.get('JENKINS_URL'):
+            self.sh_path = full_sys_path + r'\bash.exe'
+        else:
+            self.sh_path = '\"C:\Program Files\Git\git-bash.exe\"'
+
+        if not os.path.exists(self.sh_path):
+            log.warning('Bash not found at ' + self.sh_path)
+            self.sh_path = shutil.which('bash.exe')
+            if not os.path.exists(self.sh_path):
+                log.error('No bash found')
+                sys.exit(1)
+            else:
+                self.sh_path = shellquote(self.sh_path, windows=True)
+                log.debug('Using alternate bash found at ' + self.sh_path)
+
+        self.project_env_vars = {
+            'DAEMON_DIR': daemon_dir,
+            'CONTRIB_SRC_DIR': contrib_src_dir,
+            'CONTRIB_BUILD_DIR': contrib_build_dir,
+            'VCVARSALL_CMD': getVSEnvCmd(),
+            'CMAKE_GENERATOR': getCMakeGenerator(getLatestVSVersion())
+        }
+        self.base_env_vars = self.project_env_vars.copy()
+        self.base_env_vars.update(os.environ.copy())
+        self.vs_env_vars = {}
+
+    def set_vs_env_vars(self, env_target):
+        self.vs_env_vars = {}
+        self.vs_env_vars = self.project_env_vars.copy()
+        self.vs_env_vars.update(getVSEnv(version=env_target))
+
+    def exec_script(self, script_type=ScriptType.cmd, script=None, args=[]):
+        if script_type is ScriptType.cmd:
+            cmd = [script]
+            if not args:
+                cmd = shlex.split(script)
+        elif script_type is ScriptType.ps1:
+            cmd = [self.ps_path, '-ExecutionPolicy', 'ByPass', script]
+        elif script_type is ScriptType.sh:
+            cmd = [self.sh_path, '-c ', '\"' + script]
+        if args:
+            cmd.extend(args)
+        if script_type is ScriptType.sh:
+            cmd[-1] = cmd[-1] + '\"'
+            cmd = " ".join(cmd)
+        p = subprocess.Popen(cmd,
+                             shell=True,
+                             stderr=sys.stderr,
+                             stdout=sys.stdout,
+                             env=self.vs_env_vars if self.vs_env_vars else self.base_env_vars)
+        rtrn, perr = p.communicate()
+        rcode = p.returncode
+        data = None
+        if perr:
+            data = json.dumps(perr.decode('utf-8', 'ignore'))
+        else:
+            data = rtrn
+        return rcode, data
+
+    def exec_batch(self, script=None, args=[]):
+        return self.exec_script(ScriptType.cmd, script, args)
+
+    def exec_ps1(self, script=None, args=[]):
+        return self.exec_script(ScriptType.ps1, script, args)
+
+    def exec_sh(self, script=None, args=[]):
+        return self.exec_script(ScriptType.sh, script, args)
+
+
+def getSHrunner():
+    return SHrunner.instance()
+
+
+@Singleton
+class MSbuilder:
+    def __init__(self):
+        self.vsenv_done = False
+        self.msbuild = findMSBuild()
+        self.default_msbuild_args = [
+            '/nologo',
+            '/verbosity:normal',
+            '/maxcpucount:' + str(multiprocessing.cpu_count())]
+        self.set_msbuild_configuration()
+
+    def set_msbuild_configuration(self, with_env='false', arch='x64',
+                                  configuration='Release',
+                                  toolset=win_toolset_default):
+        self.extra_msbuild_args = [
+            '/p:Platform=' + arch,
+            '/p:Configuration=' + configuration,
+            '/p:PlatformToolset=' + toolset,
+            '/p:useenv=' + with_env
+        ]
+
+    @staticmethod
+    def replace_vs_prop(filename, prop, val):
+        p = re.compile(r'(?s)<' + prop + r'\s?.*?>(.*?)<\/' + prop + r'>')
+        val = r'<' + prop + r'>' + val + r'</' + prop + r'>'
+        with fileinput.FileInput(filename, inplace=True) as file:
+            for line in file:
+                print(re.sub(p, val, line), end='')
+
+    def build(self, pkg_name, proj_path, sdk_version, toolset):
+        if not os.path.isfile(self.msbuild):
+            raise IOError('msbuild.exe not found. path=' + self.msbuild)
+        # force chosen sdk
+        self.__class__.replace_vs_prop(proj_path,
+                                       'WindowsTargetPlatformVersion',
+                                       sdk_version)
+        # force chosen toolset
+        self.__class__.replace_vs_prop(proj_path,
+                                       'PlatformToolset',
+                                        toolset)
+        args = []
+        args.extend(self.default_msbuild_args)
+        args.extend(self.extra_msbuild_args)
+        args.append(proj_path)
+        result = getSHrunner().exec_batch(self.msbuild, args)
+        if result[0] == 1:
+            log.error("Build failed when building " + pkg_name)
+            sys.exit(1)
+
+    def setup_vs_env(self, env_target):
+        if self.vsenv_done:
+            log.debug('vs environment already initialized')
+            return
+        log.debug('Setting up vs environment')
+        getSHrunner().set_vs_env_vars(env_target)
+        self.vsenv_done = True
+
+
+def getMSbuilder():
+    return MSbuilder.instance()
+
+
+def parse_args():
+    ap = argparse.ArgumentParser(description="Windows Jami build tool")
+    ap.add_argument(
+        '-b', '--build',
+        help='Build latest contrib')
+    ap.add_argument(
+        '-f', '--force', action='store_true',
+        help='Force action')
+    ap.add_argument(
+        '-c', '--clean',
+        help='Cleans out build directory for a contrib')
+    ap.add_argument(
+        '-d', '--debug', default='DEBUG',
+        help='Sets the logging level')
+    ap.add_argument(
+        '-i', '--indent', action='store_true',
+        help='Sets whether the logs are indented to stack frames')
+    ap.add_argument(
+        '-v', '--verbose', action='store_true',
+        help='Sets whether the logs are verbose or not')
+    ap.add_argument(
+        '-p', '--purge', action='store_true',
+        help='Cleans out contrib tarball directory')
+    ap.add_argument(
+        '-s', '--sdk', default=win_sdk_default, type=str,
+        help='Use specified windows sdk version')
+    ap.add_argument(
+        '-t', '--toolset', default=win_toolset_default, type=str,
+        help='Use specified platform toolset version')
+
+    parsed_args = ap.parse_args()
+
+    return parsed_args
+
+
+def main():
+    start_time = time.time()
+
+    parsed_args = parse_args()
+
+    setup_logging(lvl=parsed_args.debug,
+                  verbose=parsed_args.verbose,
+                  do_indent=parsed_args.indent)
+
+    if not host_is_64bit:
+        log.error('These scripts will only run on a 64-bit Windows system for now!')
+        sys.exit(1)
+
+    if int(getLatestVSVersion()) < 15:
+        log.error('These scripts require at least Visual Studio v15 2017!')
+        sys.exit(1)
+
+    if parsed_args.purge:
+        if os.path.exists(contrib_tmp_dir):
+            log.warning('Removing contrib tarballs ' + contrib_tmp_dir)
+            getSHrunner().exec_batch(
+                'del', ['/s', '/f', '/q', contrib_tmp_dir + '\\*.tar.*'])
+            getSHrunner().exec_batch(
+                'del', ['/s', '/f', '/q', contrib_tmp_dir + '\\*.tgz.*'])
+            getSHrunner().exec_batch(
+                'del', ['/s', '/f', '/q', contrib_tmp_dir + '\\*.zip.*'])
+        else:
+            log.warning('No tarballs to remove')
+
+    if parsed_args.clean:
+        if os.path.exists(contrib_build_dir) and parsed_args.clean == 'all':
+            log.warning('Removing contrib builds ' + contrib_build_dir)
+            getSHrunner().exec_batch('rmdir', ['/s', '/q', contrib_build_dir])
+        else:
+            pkg_json_file = get_pkg_file(parsed_args.clean)
+            with open(pkg_json_file) as json_file:
+                pkg_info = json.load(json_file)
+                dir_to_clean = contrib_build_dir + '\\' + pkg_info['name']
+                file_to_clean = contrib_build_dir + '\\.' + pkg_info['name']
+                if os.path.exists(dir_to_clean) or os.path.exists(file_to_clean):
+                    log.warning('Removing contrib build ' + dir_to_clean)
+                    getSHrunner().exec_batch(
+                        'rmdir', ['/s', '/q', dir_to_clean])
+                    getSHrunner().exec_batch(
+                        'del', ['/s', '/f', '/q', file_to_clean])
+                else:
+                    log.warning('No builds to remove')
+
+    if parsed_args.build:
+        if not os.path.exists(contrib_build_dir):
+            os.makedirs(contrib_build_dir)
+        log.info('Making: ' + parsed_args.build)
+        resolve(parsed_args.build, parsed_args.force,
+                parsed_args.sdk, parsed_args.toolset)
+        log.info('Make done for: ' + parsed_args.build)
+
+    log.debug("--- %s ---" % secondsToStr(time.time() - start_time))
+
+
+def get_sh_path(path):
+    driveless_path = path.replace(os.path.sep, '/')[3:]
+    drive_letter = os.path.splitdrive(daemon_dir)[0][0].lower()
+    wsl_drive_path = '/mnt/' + drive_letter + '/'
+    no_echo = ' &> /dev/null'
+    result = getSHrunner().exec_sh('pwd | grep ' + wsl_drive_path + no_echo)
+    if result[0]:
+        # using git bash
+        return '/' + drive_letter + '/' + driveless_path
+        # using wsl
+    return wsl_drive_path + driveless_path
+
+
+def newest_file(root):
+    file_list = []
+    for path, _, files in os.walk(root):
+        for name in files:
+            file_list.append(os.path.join(path, name))
+    latest_file = max(file_list, key=os.path.getmtime)
+    return latest_file
+
+
+def is_build_uptodate(pkg_name, build_file):
+    root = contrib_build_dir + '\\' + pkg_name
+    file_list = []
+    for path, _, files in os.walk(root):
+        for name in files:
+            file_list.append(os.path.join(path, name))
+    if not file_list:
+        return False
+    latest_file = max(file_list, key=os.path.getmtime)
+    t_mod = os.path.getmtime(latest_file)
+    t_build = os.path.getmtime(build_file)
+    return t_mod < t_build
+
+
+def secondsToStr(elapsed=None):
+    return str(timedelta(seconds=elapsed))
+
+
+class CustomAdapter(logging.LoggerAdapter):
+    @staticmethod
+    def indent():
+        indentation_level = len(traceback.extract_stack())
+        return indentation_level - 4 - 2  # Remove logging infrastructure frames
+
+    def process(self, msg, kwargs):
+        return '{i}{m}'.format(i=' '*(self.indent()), m=msg), kwargs
+
+
+def setup_logging(lvl=logging.DEBUG, verbose=False, do_indent=False):
+    format = ''
+    if verbose:
+        format = '[ %(levelname)-8s %(created).6f %(funcName)10s:%(lineno)4s ] '
+    fmt = format + '%(message)s'
+    try:
+        import coloredlogs
+        coloredlogs.install(
+            level=lvl,
+            logger=root_logger,
+            fmt=fmt,
+            level_styles={
+                'debug': {'color': 'blue'},
+                'info': {'color': 'green'},
+                'warn': {'color': 'yellow'},
+                'error': {'color': 'red'},
+                'critical': {'color': 'red', 'bold': True}
+            },
+            field_styles={
+                'asctime': {'color': 'magenta'},
+                'created': {'color': 'magenta'},
+                'levelname': {'color': 'cyan'},
+                'funcName': {'color': 'black', 'bold': True},
+                'lineno': {'color': 'black', 'bold': True}
+            })
+    except ImportError:
+        root_logger.setLevel(logging.DEBUG)
+        logging.basicConfig(level=lvl, format=fmt)
+    if do_indent:
+        global log
+        log = CustomAdapter(logging.getLogger(__name__), {})
+    else:
+        log = logging.getLogger(__name__)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/contrib/build_all.bat b/contrib/build_all.bat
deleted file mode 100644
index 3a442832017d046a6a35ca03a9dbfe103eb41a5c..0000000000000000000000000000000000000000
--- a/contrib/build_all.bat
+++ /dev/null
@@ -1,281 +0,0 @@
-@echo off
-@setlocal EnableDelayedExpansion
-
-set CONTRIB_DIR=%~dp0
-
-set platform=win32
-set arch=x64
-if "%1"=="uwp" (
-    set platform=uwp
-    if "%2"=="x86" (
-        set arch=x86
-        goto arch_x86
-    ) else if "%2"=="x64" (
-        set arch=x64
-        goto arch_x64
-    ) else (
-        goto parameterError
-    )
-) else if "%1"=="win32" (
-    if "%2"=="x86" (
-        set arch=x86
-        goto arch_x86
-    ) else if "%2"=="x64" (
-        set arch=x64
-        goto arch_x64
-    ) else (
-        goto parameterError
-    )
-) else (
-    goto parameterError
-)
-
-:arch_x86
-set MSBUILD_ARGS=/nologo /p:useenv=true /p:Configuration=Release /p:Platform=Win32 /verbosity:normal /maxcpucount:%NUMBER_OF_PROCESSORS%
-if "%1"=="uwp" (
-    set DAEMON_MSBUILD_ARGS=/nologo /p:useenv=true /p:Configuration=ReleaseLib /p:Platform=Win32 /verbosity:normal /maxcpucount:%NUMBER_OF_PROCESSORS%
-    goto uwpProjs
-) else if "%1"=="win32" (
-    set DAEMON_MSBUILD_ARGS=/nologo /p:useenv=true /p:Configuration=ReleaseLib_win32 /p:Platform=Win32 /verbosity:normal /maxcpucount:%NUMBER_OF_PROCESSORS%
-    goto win32Projs
-)
-
-:arch_x64
-set MSBUILD_ARGS=/nologo /p:useenv=true /p:Configuration=Release /p:Platform=x64 /verbosity:normal /maxcpucount:%NUMBER_OF_PROCESSORS%
-if "%1"=="uwp" (
-    set DAEMON_MSBUILD_ARGS=/nologo /p:useenv=true /p:Configuration=ReleaseLib /p:Platform=x64 /verbosity:normal /maxcpucount:%NUMBER_OF_PROCESSORS%
-    goto uwpProjs
-) else if "%1"=="win32" (
-    set DAEMON_MSBUILD_ARGS=/nologo /p:useenv=true /p:Configuration=ReleaseLib_win32 /p:Platform=x64 /verbosity:normal /maxcpucount:%NUMBER_OF_PROCESSORS%
-    goto win32Projs
-)
-
-:uwpProjs
-set TOBUILD= ^
-x264=build\x264\SMP\libx264.vcxproj, ^
-opus=build\opus\SMP\libopus.vcxproj, ^
-media-sdk=build\media-sdk\api\mfx_dispatch\windows\libmfx_vs2015.vcxproj, ^
-ffmpeg=ffmpeg, ^
-openssl=openssl, ^
-asio=build\asio\asio\msvc\asio.vcxproj, ^
-fmt=build\fmt\msvc\fmt.vcxproj, ^
-http_parser=build\http_parser\http-parser.vcxproj, ^
-jsoncpp=build\jsoncpp\makefiles\vs2017\lib_json.vcxproj, ^
-argon2=build\argon2\vs2015\Argon2Ref\Argon2Ref.vcxproj, ^
-gmp=build\gmp\SMP\libgmp.vcxproj, ^
-iconv=build\iconv\SMP\libiconv.vcxproj, ^
-zlib=build\zlib\SMP\libzlib.vcxproj, ^
-nettle=build\nettle\SMP\libnettle.vcxproj, ^
-hogweed=build\nettle\SMP\libhogweed.vcxproj, ^
-gnutls=build\gnutls\SMP\libgnutls.vcxproj, ^
-msgpack=build\msgpack-c\vs2017\msgpackc-static.vcxproj, ^
-opendht=build\opendht\MSVC\opendht.vcxproj, ^
-pjproject=pjproject, ^
-pthreads=build\pthreads\MSVC\pthreads.vcxproj, ^
-xml=build\pupnp\build\vs2017\ixml.vcxproj, ^
-upnp=build\pupnp\build\vs2017\libupnp.vcxproj, ^
-secp256k1=build\secp256k1\MSVC\secp256k1.vcxproj, ^
-portaudio=build\portaudio\msvc\portaudio.vcxproj, ^
-yaml-cpp=build\yaml-cpp\msvc\yaml-cpp.vcxproj, ^
-goto startBuild
-
-:win32Projs
-set TOBUILD= ^
-vpx=build\vpx\SMP\libvpx.vcxproj, ^
-x264=build\x264\SMP\libx264.vcxproj, ^
-opus=build\opus\SMP\libopus.vcxproj, ^
-media-sdk=build\media-sdk\api\mfx_dispatch\windows\libmfx_vs2015.vcxproj, ^
-ffmpeg=ffmpeg, ^
-openssl=openssl, ^
-asio=build\asio\asio\msvc\asio.vcxproj, ^
-fmt=build\fmt\msvc\fmt.vcxproj, ^
-http_parser=build\http_parser\http-parser.vcxproj, ^
-jsoncpp=build\jsoncpp\makefiles\vs2017\lib_json.vcxproj, ^
-argon2=build\argon2\vs2015\Argon2Ref\Argon2Ref.vcxproj, ^
-iconv=build\iconv\SMP\libiconv.vcxproj, ^
-zlib=build\zlib\SMP\libzlib.vcxproj, ^
-gmp=build\gmp\SMP\libgmp.vcxproj, ^
-nettle=build\nettle\SMP\libnettle.vcxproj, ^
-hogweed=build\nettle\SMP\libhogweed.vcxproj, ^
-gnutls=build\gnutls\SMP\libgnutls.vcxproj, ^
-msgpack=build\msgpack-c\vs2017\msgpackc-static.vcxproj, ^
-opendht=build\opendht\MSVC\opendht.vcxproj, ^
-pjproject=pjproject, ^
-pthreads=build\pthreads\MSVC\pthreads.vcxproj, ^
-xml=build\pupnp\build\vs2017\ixml.vcxproj, ^
-upnp=build\pupnp\build\vs2017\libupnp.vcxproj, ^
-natpmp=build\natpmp\msvc\natpmp.vcxproj, ^
-secp256k1=build\secp256k1\MSVC\secp256k1.vcxproj, ^
-portaudio=build\portaudio\msvc\portaudio.vcxproj, ^
-yaml-cpp=build\yaml-cpp\msvc\yaml-cpp.vcxproj
-
-goto startBuild
-
-:startBuild
-
-set PJTOBUILD= ^
-pjlib_util=build\pjproject\pjlib-util\build\pjlib_util.vcxproj, ^
-pjmedia=build\pjproject\pjmedia\build\pjmedia.vcxproj, ^
-pjmedia_codec=build\pjproject\pjmedia\build\pjmedia_codec.vcxproj, ^
-pjlib=build\pjproject\pjlib\build\pjlib.vcxproj, ^
-pjsip_core=build\pjproject\pjsip\build\pjsip_core.vcxproj, ^
-pjsip_simple=build\pjproject\pjsip\build\pjsip_simple.vcxproj, ^
-pjsua_lib=build\pjproject\pjsip\build\pjsua_lib.vcxproj, ^
-pjsua2_lib=build\pjproject\pjsip\build\pjsua2_lib.vcxproj, ^
-pjsip_ua=build\pjproject\pjsip\build\pjsip_ua.vcxproj, ^
-pjnath=build\pjproject\pjnath\build\pjnath.vcxproj
-
-@setlocal
-
-set VSInstallerFolder="%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer"
-if %PROCESSOR_ARCHITECTURE%==x86 set VSInstallerFolder="%ProgramFiles%\\Microsoft Visual Studio\\Installer"
-
-pushd %VSInstallerFolder%
-for /f "usebackq tokens=*" %%i in (`vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do (
-  set VSLATESTDIR=%%i
-)
-popd
-
-echo VS Installation folder: %VSLATESTDIR%
-
-if not exist "%VSLATESTDIR%\\VC\\Auxiliary\\Build\\vcvarsall.bat" (
-    echo:
-    echo VSInstallDir not found or not installed correctly.
-    goto cleanup
-)
-
-if %PROCESSOR_ARCHITECTURE%==x86 (
-    if "%1"=="uwp" (
-        set Comp_x86=x86 uwp 10.0.15063.0
-        set Comp_x64=x86_amd64 uwp 10.0.15063.0
-    ) else (
-        set Comp_x86=x86 10.0.15063.0
-        set Comp_x64=x86_amd64 10.0.15063.0
-    )
-) else (
-    if "%1"=="uwp" (
-        set Comp_x86=amd64_x86 uwp 10.0.15063.0
-        set Comp_x64=amd64 uwp 10.0.15063.0
-    ) else (
-        set Comp_x86=amd64_x86 10.0.15063.0
-        set Comp_x64=amd64 10.0.15063.0
-    )
-)
-
-set path=%path:"=%
-if "%2"=="x86" (
-    call "%VSLATESTDIR%"\\VC\\Auxiliary\\Build\\vcvarsall.bat %Comp_x86%
-) else if "%2"=="x64" (
-    call "%VSLATESTDIR%"\\VC\\Auxiliary\\Build\\vcvarsall.bat %Comp_x64%
-)
-
-set MSYS2_PATH_TYPE=inherit
-
-if not defined MSYS2_BIN (
-    if exist C:\msys64\usr\bin\bash.exe set MSYS2_BIN="C:\msys64\usr\bin\bash.exe"
-)
-if not defined MSYS2_BIN (
-    if exist C:\msys\usr\bin\bash.exe set MSYS2_BIN="C:\msys\usr\bin\bash.exe"
-)
-
-if /I %3 equ "" (
-    goto build_all
-) else (
-    goto build_one
-)
-
-:build_all
-set "keyname="
-for %%I in (%TOBUILD%) do (
-    if not defined keyname (
-        set keyname=%%I
-    ) else (
-        echo building: !keyname!
-        call :build %%I %1 %2
-        set %%keyname%%=%%I
-        set "keyname="
-    )
-)
-goto cleanup
-
-:build_one
-set found="N"
-set "keyname="
-for %%I in (%TOBUILD%) do (
-    if not defined keyname (
-        set keyname=%%I
-    ) else (
-        if /I %3 equ !keyname! (
-            echo building: !keyname!
-            set found="Y"
-            call :build %%I %1 %2
-            goto cleanup
-        )
-        set %%keyname%%=%%I
-        set "keyname="
-    )
-)
-if %found%=="N" (
-    echo "%3" not in listed contrib
-)
-goto cleanup
-
-:parameterError
-echo "parameter error"
-goto cleanup
-
-:cleanup
-endlocal
-@endlocal
-if %ERRORLEVEL% geq 1 (
-    echo build_all failed
-    exit %ERRORLEVEL%
-) else (
-    echo build_all succeeded
-    exit /B %ERRORLEVEL%
-)
-
-:build
-if /I %1 equ ffmpeg (
-    %MSYS2_BIN% --login -x %CONTRIB_DIR%src/ffmpeg/windows-configure-make.sh %2 %3
-) else if /I %1 equ pjproject (
-    goto build_pjproject %2 %3
-) else if /I %1 equ openssl (
-    goto build_openssl %2 %3
-) else (
-    msbuild %CONTRIB_DIR%%1 %MSBUILD_ARGS%
-)
-if %ERRORLEVEL% geq 1 (
-    goto cleanup
-)
-goto :eof
-
-:build_openssl
-:: build openssl
-cd %CONTRIB_DIR%build\openssl
-if "%2"=="win32" (
-    call perl Configure VC-WIN64A
-    call ms\do_win64a
-) else if "%2"=="uwp" (
-    call perl Configure no-asm no-hw no-dso VC-WINUNIVERSAL
-    call ms\do_winuniversal
-    call ms\setVSvars universal10.0x64
-)
-call nmake -f ms\ntdll.mak
-set PATH=restbed\dependency\openssl\out32dll;%PATH%
-goto :eof
-
-:build_pjproject
-setlocal
-set "keyname="
-for %%I in (%PJTOBUILD%) do (
-    if not defined keyname (
-        set keyname=%%I
-    ) else (
-        echo building: !keyname!
-        call :build %%I %1 %2
-        set %%keyname%%=%%I
-        set "keyname="
-    )
-)
-endlocal
\ No newline at end of file
diff --git a/contrib/src/argon2/fetch_and_patch.bat b/contrib/src/argon2/fetch_and_patch.bat
deleted file mode 100644
index 6372b5edc1bf436140f8dd0c7b1695f02dbbe573..0000000000000000000000000000000000000000
--- a/contrib/src/argon2/fetch_and_patch.bat
+++ /dev/null
@@ -1,22 +0,0 @@
-set BUILD=%SRC%..\build
-
-set ARGON2_VERSION=670229c849b9fe882583688b74eb7dfdc846f9f6
-set ARGON2_URL=https://github.com/P-H-C/phc-winner-argon2/archive/%ARGON2_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%ARGON2_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %ARGON2_URL%
-)
-
-7z -y x %ARGON2_VERSION%.tar.gz && 7z -y x %ARGON2_VERSION%.tar -o%BUILD%
-del %ARGON2_VERSION%.tar && del %ARGON2_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\phc-winner-argon2-%ARGON2_VERSION% argon2
-
-cd %BUILD%\argon2
-
-%APPLY_CMD% %SRC%\argon2\argon2-vs2017.patch
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/argon2/package.json b/contrib/src/argon2/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..b16c8c95f797d9ff514306c24312e4be23987a9b
--- /dev/null
+++ b/contrib/src/argon2/package.json
@@ -0,0 +1,15 @@
+{
+    "name": "argon2",
+    "version": "670229c849b9fe882583688b74eb7dfdc846f9f6",
+    "url": "https://github.com/P-H-C/phc-winner-argon2/archive/__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": ["argon2-vs2017.patch"],
+    "project_paths": ["vs2015/Argon2Ref/Argon2Ref.vcxproj"],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/asio/fetch_and_patch.bat b/contrib/src/asio/fetch_and_patch.bat
deleted file mode 100644
index 8f761610247640da2822e04f8c72b14c6a1e501f..0000000000000000000000000000000000000000
--- a/contrib/src/asio/fetch_and_patch.bat
+++ /dev/null
@@ -1,22 +0,0 @@
-set BUILD=%SRC%..\build
-
-set ASIO_VERSION=asio-1-12-2
-set ASIO_URL=https://github.com/chriskohlhoff/asio/archive/%ASIO_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-%WGET_CMD% %ASIO_URL%
-
-7z -y x %ASIO_VERSION%.tar.gz && 7z -y x %ASIO_VERSION%.tar -o%BUILD%
-del %ASIO_VERSION%.tar && del %ASIO_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\asio-%ASIO_VERSION% asio
-
-cd %BUILD%\asio
-
-%APPLY_CMD% %SRC%asio\asio-vcxproj.patch
-
-if "%1"=="uwp" (
-    %APPLY_CMD% %SRC%asio\asio-uwp.patch
-)
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/asio/package.json b/contrib/src/asio/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..2f73b7d71d54145f4b60ded80adf00abfc8dfc21
--- /dev/null
+++ b/contrib/src/asio/package.json
@@ -0,0 +1,19 @@
+{
+    "name": "asio",
+    "version": "asio-1-12-2",
+    "url": "https://github.com/chriskohlhoff/asio/archive/__VERSION__.tar.gz",
+    "deps": ["openssl"],
+    "patches": [],
+    "win_patches": [
+        "asio-vcxproj.patch"
+    ],
+    "project_paths": [
+        "asio/msvc/asio.vcxproj"
+    ],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/fetch_all.bat b/contrib/src/fetch_all.bat
deleted file mode 100644
index dbb7831dd100f810fff5f440f9ed4f7a85b57dc6..0000000000000000000000000000000000000000
--- a/contrib/src/fetch_all.bat
+++ /dev/null
@@ -1,110 +0,0 @@
-@echo off
-@setlocal enabledelayedexpansion
-
-echo fetching and patching contrib for %1
-
-if "%USE_CACHE%"=="" (
-    set USE_CACHE=0
-)
-
-set SRC=%~dp0
-
-set WGET_CMD=wget --no-check-certificate --retry-connrefused --waitretry=1 --read-timeout=20 --timeout=15 --tries=4
-set PATCH_CMD=patch -flp1 -i
-set APPLY_CMD=git apply --reject --ignore-whitespace --whitespace=fix
-
-if "%1"=="uwp" (
-    goto uwpDeps
-) else if "%1"=="win32" (
-    goto win32Deps
-)
-
-:uwpDeps
-set DEPENDENCIES=( ^
-media-sdk, ^
-ffnvcodec, ^
-ffmpeg, ^
-argon2, ^
-zlib ^
-fmt, ^
-http_parser, ^
-restinio, ^
-gmp, ^
-iconv, ^
-jsoncpp, ^
-msgpack, ^
-nettle, ^
-gnutls, ^
-opendht, ^
-opus, ^
-pjproject, ^
-portaudio, ^
-pthreads, ^
-secp256k1, ^
-upnp, ^
-x264, ^
-yaml-cpp, ^
-)
-goto fetch
-
-:win32Deps
-set DEPENDENCIES=( ^
-media-sdk, ^
-ffnvcodec, ^
-ffmpeg, ^
-asio, ^
-argon2, ^
-zlib ^
-fmt, ^
-http_parser, ^
-restinio, ^
-gmp, ^
-iconv, ^
-jsoncpp, ^
-msgpack, ^
-nettle, ^
-gnutls, ^
-opendht, ^
-openssl, ^
-opus, ^
-pjproject, ^
-portaudio, ^
-pthreads, ^
-secp256k1, ^
-upnp, ^
-natpmp, ^
-vpx, ^
-x264, ^
-yaml-cpp, ^
-)
-
-if /I %3 equ "" (
-    goto fetch
-) else (
-    goto fetch_one
-)
-
-:fetch
-if exist %SRC%\..\build rd /S /Q %SRC%\..\build
-for %%I in %DEPENDENCIES% do (
-    echo fetching: %%I
-    call %SRC%\%%I\fetch_and_patch.bat %1 %2
-)
-goto cleanup
-
-:fetch_one
-set found="N"
-for %%I in %DEPENDENCIES% do (
-    if /I %3 equ %%I (
-        if exist %SRC%\..\build\%%I rd /S /Q %SRC%\..\build\%%I
-        echo fetching: %%I
-        set found="Y"
-        call %SRC%\%%I\fetch_and_patch.bat %1 %2
-    )
-)
-if %found%=="N" (
-    echo "%3" not in listed contrib
-)
-
-:cleanup
-@endlocal
\ No newline at end of file
diff --git a/contrib/src/ffmpeg/build_ffmpeg.bat b/contrib/src/ffmpeg/build_ffmpeg.bat
new file mode 100644
index 0000000000000000000000000000000000000000..d3189af153837126cb1259f6b1a85cb244b5fe12
--- /dev/null
+++ b/contrib/src/ffmpeg/build_ffmpeg.bat
@@ -0,0 +1,3 @@
+set MSYS2_PATH_TYPE=inherit
+IF exist C:\msys64\usr\bin ( set MSYS2_BIN="C:\msys64\usr\bin\bash.exe" ) ELSE ( set MSYS2_BIN="C:\tools\msys64\usr\bin\bash.exe" )
+%MSYS2_BIN% --login -x %CONTRIB_SRC_DIR%\ffmpeg\windows-configure-make.sh win32 x64
diff --git a/contrib/src/ffmpeg/fetch_and_patch.bat b/contrib/src/ffmpeg/fetch_and_patch.bat
deleted file mode 100644
index 7f9df0cae2373f350ec9fb26c8b8082bf370dd42..0000000000000000000000000000000000000000
--- a/contrib/src/ffmpeg/fetch_and_patch.bat
+++ /dev/null
@@ -1,38 +0,0 @@
-set BUILD=%SRC%..\build
-
-mkdir %BUILD%
-cd %BUILD%
-
-set FFMPEG_VERSION=59da9dcd7ef6277e4e04998ced71b05a6083c635
-set FFMPEG_URL=https://github.com/FFmpeg/FFmpeg/archive/%FFMPEG_VERSION%.tar.gz
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%FFMPEG_VERSION%.tar.gz %cd%
-) else (
-    wget --no-check-certificate %FFMPEG_URL%
-)
-
-7z -y x %FFMPEG_VERSION%.tar.gz && 7z -y x %FFMPEG_VERSION%.tar
-del %FFMPEG_VERSION%.tar && del %FFMPEG_VERSION%.tar.gz && del pax_global_header
-rename FFmpeg-%FFMPEG_VERSION% ffmpeg
-
-cd ffmpeg
-
-for /F "tokens=* usebackq" %%F in (`bash -c "pwd | grep /mnt/c/"`) do (
-    set NO_AUTO=%%F
-)
-if "%NO_AUTO%"=="" (
-    set ROOTPATH=/c/
-) else (
-    set ROOTPATH=/mnt/c/
-)
-set UNIXPATH=%SRC:\=/%
-set UNIXPATH=%ROOTPATH%%UNIXPATH:C:/=%
-bash -c "%PATCH_CMD% %UNIXPATH%ffmpeg/change-RTCP-ratio.patch"
-bash -c "%PATCH_CMD% %UNIXPATH%ffmpeg/rtp_ext_abs_send_time.patch"
-
-git apply --reject --whitespace=fix %SRC%\ffmpeg\windows-configure.patch
-git apply --reject --whitespace=fix %SRC%\ffmpeg\windows-configure-ffnvcodec.patch
-git apply --reject --whitespace=fix %SRC%\ffmpeg\windows-configure-libmfx.patch
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/ffmpeg/package.json b/contrib/src/ffmpeg/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..5d93d59deea6cc5b543e281771cb705b43b4a959
--- /dev/null
+++ b/contrib/src/ffmpeg/package.json
@@ -0,0 +1,27 @@
+{
+    "name": "ffmpeg",
+    "version": "59da9dcd7ef6277e4e04998ced71b05a6083c635",
+    "url": "https://github.com/FFmpeg/FFmpeg/archive/__VERSION__.tar.gz",
+    "deps": [
+        "vpx",
+        "x264",
+        "opus",
+        "ffnvcodec",
+        "media-sdk"
+    ],
+    "patches": ["change-RTCP-ratio.patch"],
+    "win_patches": [
+        "windows-configure.patch",
+        "windows-configure-ffnvcodec.patch",
+        "windows-configure-libmfx.patch"
+    ],
+    "project_paths": [],
+    "with_env" : "10.0.16299.0",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [
+            "call \"%CONTRIB_SRC_DIR%\\ffmpeg\\build_ffmpeg.bat\""
+        ],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/ffnvcodec/fetch_and_patch.bat b/contrib/src/ffnvcodec/fetch_and_patch.bat
deleted file mode 100644
index 6c4bcfb9c4b86d44644b132bba34915cd2cf86f7..0000000000000000000000000000000000000000
--- a/contrib/src/ffnvcodec/fetch_and_patch.bat
+++ /dev/null
@@ -1,28 +0,0 @@
-set BUILD=%SRC%..\build
-
-mkdir %BUILD%
-cd %BUILD%
-
-set FFNVCODEC_VERSION=5eeca8cc95267d55030e98a051effa47c45f13f3
-set FFNVCODEC_GITURL=https://github.com/FFmpeg/nv-codec-headers/archive/%FFNVCODEC_VERSION%.tar.gz
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%FFNVCODEC_VERSION%.tar.gz %cd%
-) else (
-    wget --no-check-certificate %FFNVCODEC_GITURL%
-)
-
-7z -y x %FFNVCODEC_VERSION%.tar.gz && 7z -y x %FFNVCODEC_VERSION%.tar
-del %FFNVCODEC_VERSION%.tar && del %FFNVCODEC_VERSION%.tar.gz && del pax_global_header
-rename nv-codec-headers-%FFNVCODEC_VERSION% ffnvcodec
-
-cd ffnvcodec\include\ffnvcodec
-
-mkdir ..\..\..\..\msvc\include
-
-mkdir ..\..\..\..\msvc\include\ffnvcodec
-
-xcopy /S /Y *.h ..\..\..\..\msvc\include\ffnvcodec
-
-cd %SRC%
-
diff --git a/contrib/src/ffnvcodec/package.json b/contrib/src/ffnvcodec/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..f6d08119168d767d53e1942d7418547a3bae9106
--- /dev/null
+++ b/contrib/src/ffnvcodec/package.json
@@ -0,0 +1,17 @@
+{
+    "name": "ffnvcodec",
+    "version": "5eeca8cc95267d55030e98a051effa47c45f13f3",
+    "url": "https://github.com/FFmpeg/nv-codec-headers/archive/__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": [],
+    "project_paths": [],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [
+            "mkdir \"%DAEMON_DIR%\\contrib\\msvc\\include\\ffnvcodec\" & cd include/ffnvcodec & xcopy /S /Y *.h \"%DAEMON_DIR%\\contrib\\msvc\\include\\ffnvcodec\""
+        ],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/fmt/fetch_and_patch.bat b/contrib/src/fmt/fetch_and_patch.bat
deleted file mode 100644
index 18103d14730a856b11bfcb8fc2caefe81e8151f0..0000000000000000000000000000000000000000
--- a/contrib/src/fmt/fetch_and_patch.bat
+++ /dev/null
@@ -1,26 +0,0 @@
-set BUILD=%SRC%..\build
-
-set FMT_VERSION=5.3.0
-set FMT_URL=https://github.com/fmtlib/fmt/archive/%FMT_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%FMT_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %FMT_URL%
-)
-
-7z -y x %FMT_VERSION%.tar.gz && 7z -y x %FMT_VERSION%.tar -o%BUILD%
-del %FMT_VERSION%.tar && del %FMT_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\fmt-%FMT_VERSION% fmt
-
-cd %BUILD%\fmt
-
-mkdir msvc && cd msvc
-setlocal
-set PATH=C:\\Program Files\\CMake\\bin\\;%PATH%
-cmake .. -G "Visual Studio 15 2017 Win64" -DBUILD_SHARED_LIBS=Off -DFMT_USE_USER_DEFINED_LITERALS=0
-endlocal
-
-cd %SRC%
diff --git a/contrib/src/fmt/package.json b/contrib/src/fmt/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..f8b0efc94d0a99dbafae6a2d7005eddbd1d23c0e
--- /dev/null
+++ b/contrib/src/fmt/package.json
@@ -0,0 +1,17 @@
+{
+    "name": "fmt",
+    "version": "5.3.0",
+    "url": "https://github.com/fmtlib/fmt/archive/__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": [],
+    "project_paths": ["msvc/fmt.vcxproj"],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [
+            "mkdir msvc & cd msvc & cmake .. -G %CMAKE_GENERATOR% -DBUILD_SHARED_LIBS=Off -DFMT_USE_USER_DEFINED_LITERALS=0"
+        ],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/gmp/fetch_and_patch.bat b/contrib/src/gmp/fetch_and_patch.bat
deleted file mode 100644
index c711240666e54ff5066dded830376172aaa25836..0000000000000000000000000000000000000000
--- a/contrib/src/gmp/fetch_and_patch.bat
+++ /dev/null
@@ -1,22 +0,0 @@
-set BUILD=%SRC%..\build
-
-set GMP_VERSION=eb35fdadc072ecae2b262fd6e6709c308cadc07a
-set GMP_URL=https://github.com/ShiftMediaProject/gmp/archive/%GMP_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%GMP_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %GMP_URL%
-)
-
-7z -y x %GMP_VERSION%.tar.gz && 7z -y x %GMP_VERSION%.tar -o%BUILD%
-del %GMP_VERSION%.tar && del %GMP_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\gmp-%GMP_VERSION% gmp
-
-cd %BUILD%\gmp
-
-%APPLY_CMD% %SRC%\gmp\gmp_addaddmul_1msb0.patch
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/gmp/package.json b/contrib/src/gmp/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..6a897fb551124a1efd12ad146db44cff15d78f0e
--- /dev/null
+++ b/contrib/src/gmp/package.json
@@ -0,0 +1,17 @@
+{
+    "name": "gmp",
+    "version": "eb35fdadc072ecae2b262fd6e6709c308cadc07a",
+    "url": "https://github.com/ShiftMediaProject/gmp/archive/__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": ["gmp_addaddmul_1msb0.patch"],
+    "project_paths": [
+        "SMP/libgmp.vcxproj"
+    ],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/gnutls/fetch_and_patch.bat b/contrib/src/gnutls/fetch_and_patch.bat
deleted file mode 100644
index 116bcad91946dfa74767a773d4a0361b8f3efa77..0000000000000000000000000000000000000000
--- a/contrib/src/gnutls/fetch_and_patch.bat
+++ /dev/null
@@ -1,35 +0,0 @@
-set BUILD=%SRC%..\build
-
-set GNUTLS_VERSION=3.6.7
-set GNUTLS_URL=https://www.gnupg.org/ftp/gcrypt/gnutls/v3.6/gnutls-%GNUTLS_VERSION%.tar.xz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\gnutls-%GNUTLS_VERSION%.tar.xz %cd%
-) else (
-    %WGET_CMD% %GNUTLS_URL%
-)
-
-7z -y x gnutls-%GNUTLS_VERSION%.tar.xz && 7z -y x gnutls-%GNUTLS_VERSION%.tar -o%BUILD%
-del gnutls-%GNUTLS_VERSION%.tar && del gnutls-%GNUTLS_VERSION%.tar.xz
-rename %BUILD%\gnutls-%GNUTLS_VERSION% gnutls
-
-cd %BUILD%\gnutls
-
-for /F "tokens=* usebackq" %%F in (`bash -c "pwd | grep /mnt/c/"`) do (
-    set NO_AUTO=%%F
-)
-if "%NO_AUTO%"=="" (
-    set ROOTPATH=/c/
-) else (
-    set ROOTPATH=/mnt/c/
-)
-set UNIXPATH=%SRC:\=/%
-set UNIXPATH=%ROOTPATH%%UNIXPATH:C:/=%
-
-bash -c "%PATCH_CMD% %UNIXPATH%gnutls/gnutls-3.6.7-win32-compat.patch"
-bash -c "%PATCH_CMD% %UNIXPATH%gnutls/gnutls-3.6.7-win32-vs-support.patch"
-bash -c "%PATCH_CMD% %UNIXPATH%gnutls/read-file-limits.h.patch"
-
-cd %SRC%
diff --git a/contrib/src/gnutls/package.json b/contrib/src/gnutls/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..4b706dd4ae1cb89802ca264c7a898eef0b677b9b
--- /dev/null
+++ b/contrib/src/gnutls/package.json
@@ -0,0 +1,26 @@
+{
+    "name": "gnutls",
+    "version": "3.6.7",
+    "url": "https://www.gnupg.org/ftp/gcrypt/gnutls/v3.6/gnutls-__VERSION__.tar.xz",
+    "deps": [
+        "iconv",
+        "nettle",
+        "zlib",
+        "gmp"
+    ],
+    "patches": [
+        "gnutls-3.6.7-win32-compat.patch",
+        "gnutls-3.6.7-win32-vs-support.patch",
+        "read-file-limits.h.patch"
+    ],
+    "win_patches": [],
+    "project_paths": [
+        "SMP/libgnutls.vcxproj"
+    ],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/http_parser/fetch_and_patch.bat b/contrib/src/http_parser/fetch_and_patch.bat
deleted file mode 100644
index 328c66d23180de7a04beadc342f1ba2811723047..0000000000000000000000000000000000000000
--- a/contrib/src/http_parser/fetch_and_patch.bat
+++ /dev/null
@@ -1,22 +0,0 @@
-set BUILD=%SRC%..\build
-
-set HTTP_PARSER_VERSION=2.9.3
-set HTTP_PARSER_URL=https://github.com/binarytrails/http_parser/archive/v%HTTP_PARSER_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%HTTP_PARSER_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %HTTP_PARSER_URL%
-)
-
-7z -y x v%HTTP_PARSER_VERSION%.tar.gz && 7z -y x v%HTTP_PARSER_VERSION%.tar -o%BUILD%
-del v%HTTP_PARSER_VERSION%.tar && del v%HTTP_PARSER_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\http_parser-%HTTP_PARSER_VERSION% http_parser
-
-cd %BUILD%\http_parser
-
-%APPLY_CMD% %SRC%http_parser\http_parser-vs.patch
-
-cd %SRC%
diff --git a/contrib/src/http_parser/package.json b/contrib/src/http_parser/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..17491af1a7af2be4944b56bbffea22c97f0fb399
--- /dev/null
+++ b/contrib/src/http_parser/package.json
@@ -0,0 +1,15 @@
+{
+    "name": "http_parser",
+    "version": "2.9.3",
+    "url": "https://github.com/binarytrails/http_parser/archive/v__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": ["http_parser-vs.patch"],
+    "project_paths": ["http-parser.vcxproj"],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/iconv/fetch_and_patch.bat b/contrib/src/iconv/fetch_and_patch.bat
deleted file mode 100644
index 5f5b2e1989eeb1879778242edbf29dea863af2f9..0000000000000000000000000000000000000000
--- a/contrib/src/iconv/fetch_and_patch.bat
+++ /dev/null
@@ -1,18 +0,0 @@
-set BUILD=%SRC%..\build
-
-set ICONV_VERSION=a4d13b43f8bfc328a9d1d326b0d748d5236613be
-set ICONV_URL=https://github.com/ShiftMediaProject/libiconv/archive/%ICONV_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%ICONV_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %ICONV_URL%
-)
-
-7z -y x %ICONV_VERSION%.tar.gz && 7z -y x %ICONV_VERSION%.tar -o%BUILD%
-del %ICONV_VERSION%.tar && del %ICONV_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\libiconv-%ICONV_VERSION% iconv
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/iconv/package.json b/contrib/src/iconv/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..f6fba284e47bed53fd97a2c4cf0ccf72bad33b9f
--- /dev/null
+++ b/contrib/src/iconv/package.json
@@ -0,0 +1,17 @@
+{
+    "name": "iconv",
+    "version": "a4d13b43f8bfc328a9d1d326b0d748d5236613be",
+    "url": "https://github.com/ShiftMediaProject/libiconv/archive/__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": [],
+    "project_paths": [
+        "SMP/libiconv.vcxproj"
+    ],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/jsoncpp/fetch_and_patch.bat b/contrib/src/jsoncpp/fetch_and_patch.bat
deleted file mode 100644
index da411615c7256cd148c8c014879891dd2c6d6a8c..0000000000000000000000000000000000000000
--- a/contrib/src/jsoncpp/fetch_and_patch.bat
+++ /dev/null
@@ -1,22 +0,0 @@
-set BUILD=%SRC%..\build
-
-set JSONCPP_VERSION=81065748e315026017c633fca1bfc57cba5b246a
-set JSONCPP_URL=https://github.com/open-source-parsers/jsoncpp/archive/%JSONCPP_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%JSONCPP_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %JSONCPP_URL%
-)
-
-7z -y x %JSONCPP_VERSION%.tar.gz && 7z -y x %JSONCPP_VERSION%.tar -o%BUILD%
-del %JSONCPP_VERSION%.tar && del %JSONCPP_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\jsoncpp-%JSONCPP_VERSION% jsoncpp
-
-cd %BUILD%\jsoncpp
-
-%APPLY_CMD% %SRC%\jsoncpp\jsoncpp-vs2017.patch
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/jsoncpp/package.json b/contrib/src/jsoncpp/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..5304fa9e55b44f0ea221669fee1f85d547bf2190
--- /dev/null
+++ b/contrib/src/jsoncpp/package.json
@@ -0,0 +1,15 @@
+{
+    "name": "jsoncpp",
+    "version": "81065748e315026017c633fca1bfc57cba5b246a",
+    "url": "https://github.com/open-source-parsers/jsoncpp/archive/__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": ["jsoncpp-vs2017.patch"],
+    "project_paths": ["makefiles/vs2017/lib_json.vcxproj"],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/media-sdk/fetch_and_patch.bat b/contrib/src/media-sdk/fetch_and_patch.bat
deleted file mode 100644
index c37e86716eb1bb0cde080a34ddaf8ec84f0773ec..0000000000000000000000000000000000000000
--- a/contrib/src/media-sdk/fetch_and_patch.bat
+++ /dev/null
@@ -1,22 +0,0 @@
-set BUILD=%SRC%..\build
-
-set MEDIA_SDK_HASH=intel-mediasdk-19.2.0
-set MEDIA_SDK_URL=https://github.com/Intel-Media-SDK/MediaSDK/archive/%MEDIA_SDK_HASH%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%MEDIA_SDK_HASH%.tar.gz %cd%
-) else (
-    %WGET_CMD% %MEDIA_SDK_URL%
-)
-
-7z -y x %MEDIA_SDK_HASH%.tar.gz && 7z -y x %MEDIA_SDK_HASH%.tar -o%BUILD%
-del %MEDIA_SDK_HASH%.tar && del %MEDIA_SDK_HASH%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\MediaSDK-%MEDIA_SDK_HASH% media-sdk
-
-cd %BUILD%\media-sdk
-
-%APPLY_CMD% %SRC%\media-sdk\windows-static-lib-build.patch
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/media-sdk/package.json b/contrib/src/media-sdk/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..a238fa5996513b24dd33601dfbe3b43af4f1ac3e
--- /dev/null
+++ b/contrib/src/media-sdk/package.json
@@ -0,0 +1,15 @@
+{
+    "name": "media-sdk",
+    "version": "intel-mediasdk-19.2.0",
+    "url": "https://github.com/Intel-Media-SDK/MediaSDK/archive/__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": ["windows-static-lib-build.patch"],
+    "project_paths": ["api/mfx_dispatch/windows/libmfx_vs2015.vcxproj"],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/msgpack/fetch_and_patch.bat b/contrib/src/msgpack/fetch_and_patch.bat
deleted file mode 100644
index 44eccf1d152cfe7ce590e094c4943231bfa41af4..0000000000000000000000000000000000000000
--- a/contrib/src/msgpack/fetch_and_patch.bat
+++ /dev/null
@@ -1,24 +0,0 @@
-set BUILD=%SRC%..\build
-
-set MSGPACK_VERSION=cpp-3.2.0
-set MSGPACK_URL=https://github.com/msgpack/msgpack-c/archive/%MSGPACK_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%MSGPACK_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %MSGPACK_URL%
-)
-
-7z -y x %MSGPACK_VERSION%.tar.gz && 7z -y x %MSGPACK_VERSION%.tar -o%BUILD%
-del %MSGPACK_VERSION%.tar && del %MSGPACK_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\msgpack-c-%MSGPACK_VERSION% msgpack-c
-
-cd %BUILD%\msgpack-c
-
-mkdir vs2017
-cd vs2017
-cmake .. -DMSGPACK_CXX11=ON -G "Visual Studio 15 2017 Win64"
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/msgpack/package.json b/contrib/src/msgpack/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..17c4c40e52e953af8bc5408d59412dc67eb83fcb
--- /dev/null
+++ b/contrib/src/msgpack/package.json
@@ -0,0 +1,17 @@
+{
+    "name": "msgpack-c",
+    "version": "cpp-3.2.0",
+    "url": "https://github.com/msgpack/msgpack-c/archive/__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": [],
+    "project_paths": ["vs2017/msgpackc.vcxproj"],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [
+            "mkdir vs2017 & cd vs2017 & cmake .. -DMSGPACK_CXX11=ON -G %CMAKE_GENERATOR%"
+        ],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/natpmp/fetch_and_patch.bat b/contrib/src/natpmp/fetch_and_patch.bat
deleted file mode 100644
index ae7105ab00b81807fcb823918929f5f3e89aa9ab..0000000000000000000000000000000000000000
--- a/contrib/src/natpmp/fetch_and_patch.bat
+++ /dev/null
@@ -1,29 +0,0 @@
-set BUILD=%SRC%..\build
-
-set NATPMP_VERSION=6d5c0db6a06036fcd97bdba10b474d5369582dba
-set NATPMP_URL=http://github.com/miniupnp/libnatpmp/archive/%NATPMP_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%NATPMP_VERSION%.zip %cd%
-) else (
-    %WGET_CMD% %NATPMP_URL%
-)
-
-7z -y x %NATPMP_VERSION%.tar.gz && 7z -y x %NATPMP_VERSION%.tar -o%BUILD%
-del %NATPMP_VERSION%.tar && del %NATPMP_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\libnatpmp-%NATPMP_VERSION% natpmp
-
-cd %BUILD%\natpmp
-
-%APPLY_CMD% %SRC%\natpmp\natpmp-win32-ssize_t.patch
-
-rmdir /s /q msvc
-mkdir msvc && cd msvc
-setlocal
-set PATH=C:\\Program Files\\CMake\\bin\\;%PATH%
-cmake .. -G "Visual Studio 15 2017 Win64"
-endlocal
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/natpmp/package.json b/contrib/src/natpmp/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..1d5b8f255e96dd1b8eb2ff3f5ecdc3ac0b624506
--- /dev/null
+++ b/contrib/src/natpmp/package.json
@@ -0,0 +1,17 @@
+{
+    "name": "natpmp",
+    "version": "6d5c0db6a06036fcd97bdba10b474d5369582dba",
+    "url": "http://github.com/miniupnp/libnatpmp/archive/__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": ["natpmp-win32-ssize_t.patch"],
+    "project_paths": ["msvc/natpmp.vcxproj"],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [
+            "rmdir /s /q msvc & mkdir msvc & cd msvc & cmake .. -G %CMAKE_GENERATOR%"
+        ],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/nettle/fetch_and_patch.bat b/contrib/src/nettle/fetch_and_patch.bat
deleted file mode 100644
index 459ebf77d5b9791627996c22615480070fc7f1f5..0000000000000000000000000000000000000000
--- a/contrib/src/nettle/fetch_and_patch.bat
+++ /dev/null
@@ -1,18 +0,0 @@
-set BUILD=%SRC%..\build
-
-set NETTLE_VERSION=c180b4d7afbda4049ad265d1366567f62a7a4a3a
-set NETTLE_URL=https://github.com/ShiftMediaProject/nettle/archive/%NETTLE_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%NETTLE_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %NETTLE_URL%
-)
-
-7z -y x %NETTLE_VERSION%.tar.gz && 7z -y x %NETTLE_VERSION%.tar -o%BUILD%
-del %NETTLE_VERSION%.tar && del %NETTLE_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\nettle-%NETTLE_VERSION% nettle
-
-cd %SRC%
diff --git a/contrib/src/nettle/package.json b/contrib/src/nettle/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..9bf61932a644de5103406cb2cb766e9085d81488
--- /dev/null
+++ b/contrib/src/nettle/package.json
@@ -0,0 +1,18 @@
+{
+    "name": "nettle",
+    "version": "c180b4d7afbda4049ad265d1366567f62a7a4a3a",
+    "url": "https://github.com/ShiftMediaProject/nettle/archive/__VERSION__.tar.gz",
+    "deps": ["gmp"],
+    "patches": [],
+    "win_patches": [],
+    "project_paths": [
+        "SMP/libnettle.vcxproj",
+        "SMP/libhogweed.vcxproj"
+    ],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/opendht/fetch_and_patch.bat b/contrib/src/opendht/fetch_and_patch.bat
deleted file mode 100644
index c64f86d04d89d1f4c8cce216dd1d3fc255423492..0000000000000000000000000000000000000000
--- a/contrib/src/opendht/fetch_and_patch.bat
+++ /dev/null
@@ -1,20 +0,0 @@
-set BUILD=%SRC%..\build
-
-set OPENDHT_VERSION=9c84e59bbf6d5cb4a67ebb01eac9a6f2aff8e131
-set OPENDHT_URL=https://github.com/savoirfairelinux/opendht/archive/%OPENDHT_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%OPENDHT_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %OPENDHT_URL%
-)
-
-7z -y x %OPENDHT_VERSION%.tar.gz && 7z -y x %OPENDHT_VERSION%.tar -o%BUILD%
-del %OPENDHT_VERSION%.tar && del %OPENDHT_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\opendht-%OPENDHT_VERSION% opendht
-
-cd %BUILD%\opendht
-
-cd %SRC%
diff --git a/contrib/src/opendht/package.json b/contrib/src/opendht/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..5f40b82e055ba5b7df89d111fd99c0101791a8a3
--- /dev/null
+++ b/contrib/src/opendht/package.json
@@ -0,0 +1,22 @@
+{
+    "name": "opendht",
+    "version": "9c84e59bbf6d5cb4a67ebb01eac9a6f2aff8e131",
+    "url": "https://github.com/savoirfairelinux/opendht/archive/__VERSION__.tar.gz",
+    "deps": [
+        "argon2",
+        "asio",
+        "gnutls",
+        "jsoncpp",
+        "msgpack",
+        "restinio"
+    ],
+    "patches": [],
+    "win_patches": [],
+    "project_paths": ["msvc/opendht.vcxproj"],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/openssl/fetch_and_patch.bat b/contrib/src/openssl/fetch_and_patch.bat
deleted file mode 100644
index f986ac8a4c5b8c3dcbaf8bddd58cd8583ef8b723..0000000000000000000000000000000000000000
--- a/contrib/src/openssl/fetch_and_patch.bat
+++ /dev/null
@@ -1,20 +0,0 @@
-set BUILD=%SRC%..\build
-
-set OPENSSL_VERSION=5cc1e25bc76bcf0db03bc37bd64b3290727963b6
-set OPENSSL_URL=https://github.com/Microsoft/openssl/archive/%OPENSSL_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-%WGET_CMD% %OPENSSL_URL%
-
-7z -y x %OPENSSL_VERSION%.tar.gz && 7z -y x %OPENSSL_VERSION%.tar -o%BUILD%
-del %OPENSSL_VERSION%.tar && del %OPENSSL_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\openssl-%OPENSSL_VERSION% openssl
-
-cd %BUILD%\openssl
-
-if "%1"=="uwp" (
-    %APPLY_CMD% %SRC%\openssl-uwp.patch
-)
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/openssl/package.json b/contrib/src/openssl/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..d1f6321365d9b750504955b4dfec22ec5fcf8679
--- /dev/null
+++ b/contrib/src/openssl/package.json
@@ -0,0 +1,19 @@
+{
+    "name": "openssl",
+    "version": "5cc1e25bc76bcf0db03bc37bd64b3290727963b6",
+    "url": "https://github.com/Microsoft/openssl/archive/__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": [],
+    "project_paths": [],
+    "with_env" : "10.0.16299.0",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [
+            "call perl Configure no-asm no-hw VC-WIN64A",
+            "call ms/do_win64a",
+            "set CL=/MP & call nmake -f ms/ntdll.mak"
+        ],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/opus/fetch_and_patch.bat b/contrib/src/opus/fetch_and_patch.bat
deleted file mode 100644
index 9befb1e177d163aeadce0817efa2407268312204..0000000000000000000000000000000000000000
--- a/contrib/src/opus/fetch_and_patch.bat
+++ /dev/null
@@ -1,18 +0,0 @@
-set BUILD=%SRC%..\build
-
-set OPUS_VERSION=be8b4fb30945c1ee239471d52e0350c78917ac94
-set OPUS_URL=https://github.com/ShiftMediaProject/opus/archive/%OPUS_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%OPUS_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %OPUS_URL%
-)
-
-7z -y x %OPUS_VERSION%.tar.gz && 7z -y x %OPUS_VERSION%.tar -o%BUILD%
-del %OPUS_VERSION%.tar && del %OPUS_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\opus-%OPUS_VERSION% opus
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/opus/package.json b/contrib/src/opus/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..18301bdf9c50ffa5a4fc45fc2b27524acced0c86
--- /dev/null
+++ b/contrib/src/opus/package.json
@@ -0,0 +1,15 @@
+{
+    "name": "opus",
+    "version": "be8b4fb30945c1ee239471d52e0350c78917ac94",
+    "url": "https://github.com/ShiftMediaProject/opus/archive/__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": [],
+    "project_paths": ["SMP/libopus.vcxproj"],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/pjproject/fetch_and_patch.bat b/contrib/src/pjproject/fetch_and_patch.bat
deleted file mode 100644
index e469ac31421bcf8a2ce3965f94b79442486ce0dc..0000000000000000000000000000000000000000
--- a/contrib/src/pjproject/fetch_and_patch.bat
+++ /dev/null
@@ -1,54 +0,0 @@
-set BUILD=%SRC%..\build
-
-set PJPROJECT_VERSION=5dfa75be7d69047387f9b0436dd9492bbbf03fe4
-set PJPROJECT_URL=https://github.com/pjsip/pjproject/archive/%PJPROJECT_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%PJPROJECT_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %PJPROJECT_URL%
-)
-
-7z -y x %PJPROJECT_VERSION%.tar.gz && 7z -y x %PJPROJECT_VERSION%.tar -o%BUILD%
-del %PJPROJECT_VERSION%.tar && del %PJPROJECT_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\pjproject-%PJPROJECT_VERSION% pjproject
-
-cd %BUILD%\pjproject
-
-for /F "tokens=* usebackq" %%F in (`bash -c "pwd | grep /mnt/c/"`) do (
-    set NO_AUTO=%%F
-)
-if "%NO_AUTO%"=="" (
-    set ROOTPATH=/c/
-) else (
-    set ROOTPATH=/mnt/c/
-)
-set UNIXPATH=%SRC:\=/%
-set UNIXPATH=%ROOTPATH%%UNIXPATH:C:/=%
-bash -c "%PATCH_CMD% %UNIXPATH%pjproject/fix_turn_alloc_failure.patch"
-bash -c "%PATCH_CMD% %UNIXPATH%pjproject/ipv6.patch"
-bash -c "%PATCH_CMD% %UNIXPATH%pjproject/multiple_listeners.patch"
-bash -c "%PATCH_CMD% %UNIXPATH%pjproject/pj_ice_sess.patch"
-bash -c "%PATCH_CMD% %UNIXPATH%pjproject/fix_turn_fallback.patch"
-bash -c "%PATCH_CMD% %UNIXPATH%pjproject/fix_ioqueue_ipv6_sendto.patch"
-bash -c "%PATCH_CMD% %UNIXPATH%pjproject/add_dtls_transport.patch"
-bash -c "%PATCH_CMD% %UNIXPATH%pjproject/rfc6544.patch"
-bash -c "%PATCH_CMD% %UNIXPATH%pjproject/ice_config.patch"
-bash -c "%PATCH_CMD% %UNIXPATH%pjproject/fix_first_packet_turn_tcp.patch"
-bash -c "%PATCH_CMD% %UNIXPATH%pjproject/fix_ebusy_turn.patch"
-bash -c "%PATCH_CMD% %UNIXPATH%pjproject/ignore_ipv6_on_transport_check.patch"
-bash -c "%PATCH_CMD% %UNIXPATH%pjproject/fix_turn_connection_failure.patch"
-bash -c "%PATCH_CMD% %UNIXPATH%pjproject/disable_local_resolution.patch"
-bash -c "%PATCH_CMD% %UNIXPATH%pjproject/fix_assert_on_connection_attempt.patch"
-
-%APPLY_CMD% %SRC%\pjproject\win32_vs_gnutls.patch
-%APPLY_CMD% %SRC%\pjproject\win_config.patch
-%APPLY_CMD% %SRC%\pjproject\win_vs2017_props.patch
-
-if "%1"=="uwp" (
-    %APPLY_CMD% %SRC%\pjproject\uwp_vs.patch
-)
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/pjproject/package.json b/contrib/src/pjproject/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..c198db9b183e6800c8f2e4b0226ae0f8d2a89bdb
--- /dev/null
+++ b/contrib/src/pjproject/package.json
@@ -0,0 +1,43 @@
+{
+    "name": "pjproject",
+    "version": "5dfa75be7d69047387f9b0436dd9492bbbf03fe4",
+    "url": "https://github.com/pjsip/pjproject/archive/__VERSION__.tar.gz",
+    "deps": ["gnutls"],
+    "patches": [
+        "fix_turn_alloc_failure.patch",
+        "ipv6.patch",
+        "multiple_listeners.patch",
+        "pj_ice_sess.patch",
+        "fix_turn_fallback.patch",
+        "fix_ioqueue_ipv6_sendto.patch",
+        "add_dtls_transport.patch",
+        "rfc6544.patch",
+        "ice_config.patch",
+        "fix_first_packet_turn_tcp.patch",
+        "fix_ebusy_turn.patch",
+        "ignore_ipv6_on_transport_check.patch"
+    ],
+    "win_patches": [
+        "win32_vs_gnutls.patch",
+        "win_config.patch",
+        "win_vs2017_props.patch"
+    ],
+    "project_paths": [
+        "pjlib-util/build/pjlib_util.vcxproj",
+        "pjmedia/build/pjmedia.vcxproj",
+        "pjmedia/build/pjmedia_codec.vcxproj",
+        "pjlib/build/pjlib.vcxproj",
+        "pjsip/build/pjsip_core.vcxproj",
+        "pjsip/build/pjsip_simple.vcxproj",
+        "pjsip/build/pjsua_lib.vcxproj",
+        "pjsip/build/pjsua2_lib.vcxproj",
+        "pjsip/build/pjsip_ua.vcxproj",
+        "pjnath/build/pjnath.vcxproj"
+    ],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/portaudio/fetch_and_patch.bat b/contrib/src/portaudio/fetch_and_patch.bat
deleted file mode 100644
index 108e029a7313484e01d56f44a591528246f6713d..0000000000000000000000000000000000000000
--- a/contrib/src/portaudio/fetch_and_patch.bat
+++ /dev/null
@@ -1,28 +0,0 @@
-set BUILD=%SRC%..\build
-
-set PA_VERSION=v190600_20161030
-set PA_URL="http://www.portaudio.com/archives/pa_stable_%PA_VERSION%.tgz"
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\pa_stable_%PA_VERSION%.tgz %cd%
-) else (
-    %WGET_CMD% %PA_URL%
-)
-
-7z -y e pa_stable_%PA_VERSION%.tgz && 7z -y x pa_stable_%PA_VERSION%.tar -o%BUILD%
-del pa_stable_%PA_VERSION%.tgz && del pa_stable_%PA_VERSION%.tar
-
-cd %BUILD%\portaudio
-
-%APPLY_CMD% %SRC%\portaudio\pa-vs2017.patch
-
-if "%1"=="uwp" (
-    %APPLY_CMD% %SRC%\portaudio\pa-uwp.patch
-) else (
-    %APPLY_CMD% %SRC%\portaudio\pa-dsound-aecns.patch
-    %APPLY_CMD% %SRC%\portaudio\pa-dsound.patch
-)
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/portaudio/package.json b/contrib/src/portaudio/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..66b794b067d02dfaf9785ede19f112771f8f8792
--- /dev/null
+++ b/contrib/src/portaudio/package.json
@@ -0,0 +1,19 @@
+{
+    "name": "portaudio",
+    "version": "v190600_20161030",
+    "url": "http://www.portaudio.com/archives/pa_stable___VERSION__.tgz",
+    "deps": [],
+    "patches": [],
+    "win_patches": [
+        "pa-vs2017.patch",
+        "pa-dsound-aecns.patch",
+        "pa-dsound.patch"
+    ],
+    "project_paths": ["MSVC/portaudio.vcxproj"],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/pthreads/fetch_and_patch.bat b/contrib/src/pthreads/fetch_and_patch.bat
deleted file mode 100644
index 127d45f2a06e408f5ab056217325766848fd04af..0000000000000000000000000000000000000000
--- a/contrib/src/pthreads/fetch_and_patch.bat
+++ /dev/null
@@ -1,29 +0,0 @@
-set BUILD=%SRC%..\build
-
-set PTHREADS_VERSION="pthreads4w-code-v2.10.0-rc"
-set PTHREADS_VERSION2="pthreads4w-code-02fecc211d626f28e05ecbb0c10f739bd36d6442"
-set PTHREADS_URL="https://sourceforge.net/projects/pthreads4w/files/%PTHREADS_VERSION%.zip"
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%PTHREADS_VERSION%.zip %cd%
-) else (
-    %WGET_CMD% %PTHREADS_URL%
-)
-
-7z -y x %PTHREADS_VERSION%.zip -o%BUILD%
-del %PTHREADS_VERSION%.zip
-rename %BUILD%\%PTHREADS_VERSION2% pthreads
-
-cd %BUILD%\pthreads
-
-%APPLY_CMD% %SRC%\pthreads\pthreads-windows.patch
-
-if "%1"=="uwp" (
-    %APPLY_CMD% %SRC%\pthreads\pthreads-uwp.patch
-)
-
-%APPLY_CMD% %SRC%\pthreads\pthreads-vs2017.patch
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/pthreads/package.json b/contrib/src/pthreads/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..943ea3c6b30331fd84fa5600e496f1997efa8f1a
--- /dev/null
+++ b/contrib/src/pthreads/package.json
@@ -0,0 +1,20 @@
+{
+    "name": "pthreads",
+    "version": "pthreads4w-code-v2.10.0-rc",
+    "url": "https://sourceforge.net/projects/pthreads4w/files/__VERSION__.zip",
+    "deps": [],
+    "patches": [],
+    "win_patches": [
+        "pthreads-windows.patch",
+        "pthreads-vs2017.patch"
+    ],
+    "project_paths": [
+        "MSVC/pthreads.vcxproj"
+    ],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/restinio/fetch_and_patch.bat b/contrib/src/restinio/fetch_and_patch.bat
deleted file mode 100644
index 9bc3e4fc5a6c9f4ea7dd64e8c4c9cab2f1bfeb6c..0000000000000000000000000000000000000000
--- a/contrib/src/restinio/fetch_and_patch.bat
+++ /dev/null
@@ -1,20 +0,0 @@
-set BUILD=%SRC%..\build
-
-set RESTINIO_VERSION=8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59
-set RESTINIO_URL=https://github.com/Stiffstream/restinio/archive/%RESTINIO_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%RESTINIO_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %RESTINIO_URL%
-)
-
-7z -y x %RESTINIO_VERSION%.tar.gz && 7z -y x %RESTINIO_VERSION%.tar -o%BUILD%
-del %RESTINIO_VERSION%.tar && del %RESTINIO_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\restinio-%RESTINIO_VERSION% restinio
-
-cd %BUILD%\restinio
-
-cd %SRC%
diff --git a/contrib/src/restinio/package.json b/contrib/src/restinio/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..eca0f5487144561e710ccf96bde376c0a194409e
--- /dev/null
+++ b/contrib/src/restinio/package.json
@@ -0,0 +1,19 @@
+{
+    "name": "restinio",
+    "version": "8d5d3e8237e0947adb9ba1ffc8281f4ad7cb2a59",
+    "url": "https://github.com/Stiffstream/restinio/archive/__VERSION__.tar.gz",
+    "deps": [
+        "fmt",
+        "asio",
+        "http_parser"
+    ],
+    "patches": [],
+    "win_patches": [],
+    "project_paths": [],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/secp256k1/fetch_and_patch.bat b/contrib/src/secp256k1/fetch_and_patch.bat
deleted file mode 100644
index 33e5a0e9c92749f0397eab97d3c19d3c5c3e3364..0000000000000000000000000000000000000000
--- a/contrib/src/secp256k1/fetch_and_patch.bat
+++ /dev/null
@@ -1,22 +0,0 @@
-set BUILD=%SRC%..\build
-
-set SECP256K1_VERSION=0b7024185045a49a1a6a4c5615bf31c94f63d9c4
-set SECP256K1_URL="https://github.com/bitcoin-core/secp256k1/archive/%SECP256K1_VERSION%.tar.gz"
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\libsamplerate-%SECP256K1_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %SECP256K1_URL%
-)
-
-7z -y e %SECP256K1_VERSION%.tar.gz  && 7z -y x %SECP256K1_VERSION%.tar -o%BUILD%
-del %SECP256K1_VERSION%.tar && del %SECP256K1_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\secp256k1-%SECP256K1_VERSION% secp256k1
-
-cd %BUILD%\secp256k1
-
-%APPLY_CMD% %SRC%\secp256k1\secp256k1-vs2017.patch
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/secp256k1/package.json b/contrib/src/secp256k1/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..662c0888971c77787c8ae7e696c47f837f9f1523
--- /dev/null
+++ b/contrib/src/secp256k1/package.json
@@ -0,0 +1,15 @@
+{
+    "name": "secp256k1",
+    "version": "0b7024185045a49a1a6a4c5615bf31c94f63d9c4",
+    "url": "https://github.com/bitcoin-core/secp256k1/archive/__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": ["secp256k1-vs2017.patch"],
+    "project_paths": ["MSVC/secp256k1.vcxproj"],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/upnp/fetch_and_patch.bat b/contrib/src/upnp/fetch_and_patch.bat
deleted file mode 100644
index 219f6e19547f24b29adea55c006f2f8c2d103277..0000000000000000000000000000000000000000
--- a/contrib/src/upnp/fetch_and_patch.bat
+++ /dev/null
@@ -1,22 +0,0 @@
-set BUILD=%SRC%..\build
-
-set UPNP_VERSION=1.8.4
-set UPNP_URL=https://github.com/mrjimenez/pupnp/archive/release-%UPNP_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\release-%UPNP_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %UPNP_URL%
-)
-
-7z -y x release-%UPNP_VERSION%.tar.gz && 7z -y x release-%UPNP_VERSION%.tar -o%BUILD%
-del release-%UPNP_VERSION%.tar && del release-%UPNP_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\pupnp-release-%UPNP_VERSION% pupnp
-
-cd %BUILD%\pupnp
-
-%APPLY_CMD% %SRC%\upnp\libupnp-windows.patch
-
-cd %SRC%
diff --git a/contrib/src/upnp/libupnp-windows.patch b/contrib/src/upnp/libupnp-windows.patch
index 3c0de75dc5f5e2ab062662d50556fc6af840e1f7..9985763c7f833ebab508c395621f2def3b8b8ec0 100644
--- a/contrib/src/upnp/libupnp-windows.patch
+++ b/contrib/src/upnp/libupnp-windows.patch
@@ -50,50 +50,6 @@ Subject: [PATCH] Windows patch.
  delete mode 100644 upnp/src/inc/inet_pton.h
  delete mode 100644 upnp/src/inet_pton.c
 
---- a/.gitignore
-+++ b/.gitignore
-@@ -55,8 +55,6 @@ modules.builtin
- include/config
- include/linux/version.h
- include/generated
--build/inc/autoconfig.h
--build/inc/upnpconfig.h
- 
- # stgit generated dirs 
- patches-* 
-@@ -91,7 +89,6 @@ pupnp.includes
- Makefile
- Makefile.in
- aclocal.m4
--autoconfig.h
- autoconfig.h.in
- autom4te.cache/
- build-aux/
-@@ -107,7 +104,7 @@ m4/ltversion.m4
- m4/lt~obsolete.m4
- stamp-h1
- upnp/inc/stamp-h2
--upnp/inc/upnpconfig.h
-+
- upnp/sample/tv_combo
- upnp/sample/tv_combo-1.8
- upnp/sample/tv_ctrlpt
-@@ -135,7 +132,6 @@ upnp/test_url.trs
- /build/vc10/out.vc9.Win32/Debug
- /build/vc10/out.vc10.Win32
- /build/vc10/out.vc10.x64
--/pthreads
- /build/vc10/ipch
- /build/vc10/IUpnpErrFile.txt
- /build/vc10/IUpnpInfoFile.txt
---- /dev/null
-+++ b/build/vs2017/.gitignore
-@@ -0,0 +1,4 @@
-+
-+*.suo
-+*.user
-+*.sdf
-\ No newline at end of file
 --- /dev/null
 +++ b/build/vs2017/ixml.vcxproj
 @@ -0,0 +1,233 @@
diff --git a/contrib/src/upnp/package.json b/contrib/src/upnp/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..44f931129e44f9155216a4309e62499f87633a4c
--- /dev/null
+++ b/contrib/src/upnp/package.json
@@ -0,0 +1,18 @@
+{
+    "name": "upnp",
+    "version": "1.8.4",
+    "url": "https://github.com/mrjimenez/pupnp/archive/release-__VERSION__.tar.gz",
+    "deps": ["pthreads"],
+    "patches": [],
+    "win_patches": ["libupnp-windows.patch"],
+    "project_paths": [
+        "build/vs2017/ixml.vcxproj",
+        "build/vs2017/libupnp.vcxproj"
+    ],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/vpx/fetch_and_patch.bat b/contrib/src/vpx/fetch_and_patch.bat
deleted file mode 100644
index cd85cad21c2a78081f335fe4d4fd09442410c651..0000000000000000000000000000000000000000
--- a/contrib/src/vpx/fetch_and_patch.bat
+++ /dev/null
@@ -1,22 +0,0 @@
-set BUILD=%SRC%..\build
-
-set VPX_VERSION=c01b6dc8451f09745916c079e036364ab63b93cd
-set VPX_URL=https://github.com/ShiftMediaProject/libvpx/archive/%VPX_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%VPX_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %VPX_URL%
-)
-
-7z -y x %VPX_VERSION%.tar.gz && 7z -y x %VPX_VERSION%.tar -o%BUILD%
-del %VPX_VERSION%.tar && del %VPX_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\libvpx-%VPX_VERSION% vpx
-
-cd %BUILD%\vpx
-
-%APPLY_CMD% %SRC%\vpx\windows-vpx_config.patch
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/vpx/package.json b/contrib/src/vpx/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..39e16321344303644ee207d9e509401d7797e374
--- /dev/null
+++ b/contrib/src/vpx/package.json
@@ -0,0 +1,15 @@
+{
+    "name": "vpx",
+    "version": "c01b6dc8451f09745916c079e036364ab63b93cd",
+    "url": "https://github.com/ShiftMediaProject/libvpx/archive/__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": ["windows-vpx_config.patch"],
+    "project_paths": ["SMP/libvpx.vcxproj"],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/x264/fetch_and_patch.bat b/contrib/src/x264/fetch_and_patch.bat
deleted file mode 100644
index 12ad81dd4ddcda232f5e542f3b16cf26d07f74ff..0000000000000000000000000000000000000000
--- a/contrib/src/x264/fetch_and_patch.bat
+++ /dev/null
@@ -1,24 +0,0 @@
-set BUILD=%SRC%..\build
-
-set X264_VERSION=5fee86cae91cd7b726db7408a3ed1c4da71fb78c
-set X264_URL=https://github.com/ShiftMediaProject/x264/archive/%X264_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%X264_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %X264_URL%
-)
-
-7z -y x %X264_VERSION%.tar.gz && 7z -y x %X264_VERSION%.tar -o%BUILD%
-del %X264_VERSION%.tar && del %X264_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\x264-%X264_VERSION% x264
-
-cd %BUILD%\x264
-
-if "%1"=="uwp" (
-    %APPLY_CMD% %SRC%\x264\x264-uwp.patch
-)
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/x264/package.json b/contrib/src/x264/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..9c06135880d432a7dd73865e136c679808bd0242
--- /dev/null
+++ b/contrib/src/x264/package.json
@@ -0,0 +1,15 @@
+{
+    "name": "x264",
+    "version": "5fee86cae91cd7b726db7408a3ed1c4da71fb78c",
+    "url": "https://github.com/ShiftMediaProject/x264/archive/__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": [],
+    "project_paths": ["SMP/libx264.vcxproj"],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/yaml-cpp/fetch_and_patch.bat b/contrib/src/yaml-cpp/fetch_and_patch.bat
deleted file mode 100644
index 5b5aff8f6c8ab2116647121af79436ddc7605fdc..0000000000000000000000000000000000000000
--- a/contrib/src/yaml-cpp/fetch_and_patch.bat
+++ /dev/null
@@ -1,26 +0,0 @@
-set BUILD=%SRC%..\build
-
-set YAMLCPP_VERSION=24fa1b33805c9a91df0f32c46c28e314dd7ad96f
-set YAMLCPP_URL=https://github.com/jbeder/yaml-cpp/archive/%YAMLCPP_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%YAMLCPP_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %YAMLCPP_URL%
-)
-
-7z -y x %YAMLCPP_VERSION%.tar.gz && 7z -y x %YAMLCPP_VERSION%.tar -o%BUILD%
-del %YAMLCPP_VERSION%.tar && del %YAMLCPP_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\yaml-cpp-%YAMLCPP_VERSION% yaml-cpp
-
-cd %BUILD%\yaml-cpp
-
-mkdir msvc && cd msvc
-setlocal
-set PATH=C:\\Program Files\\CMake\\bin\\;%PATH%
-cmake .. -G "Visual Studio 15 2017 Win64"
-endlocal
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/yaml-cpp/package.json b/contrib/src/yaml-cpp/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..90f0d2ff0980b9ed3969fd5aba165f4f2c486f83
--- /dev/null
+++ b/contrib/src/yaml-cpp/package.json
@@ -0,0 +1,17 @@
+{
+    "name": "yaml-cpp",
+    "version": "24fa1b33805c9a91df0f32c46c28e314dd7ad96f",
+    "url": "https://github.com/jbeder/yaml-cpp/archive/__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": [],
+    "project_paths": ["msvc/yaml-cpp.vcxproj"],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [
+            "mkdir msvc & cd msvc & cmake .. -G %CMAKE_GENERATOR%"
+        ],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/src/zlib/fetch_and_patch.bat b/contrib/src/zlib/fetch_and_patch.bat
deleted file mode 100644
index 3482894de2a5875ab91d955b39cc8ab055e7a166..0000000000000000000000000000000000000000
--- a/contrib/src/zlib/fetch_and_patch.bat
+++ /dev/null
@@ -1,18 +0,0 @@
-set BUILD=%SRC%..\build
-
-set ZLIB_VERSION=8e4e3ead55cdd296130242d86b44b92fde3ea4d4
-set ZLIB_URL=https://github.com/ShiftMediaProject/zlib/archive/%ZLIB_VERSION%.tar.gz
-
-mkdir %BUILD%
-
-if %USE_CACHE%==1 (
-    copy %CACHE_DIR%\%ZLIB_VERSION%.tar.gz %cd%
-) else (
-    %WGET_CMD% %ZLIB_URL%
-)
-
-7z -y x %ZLIB_VERSION%.tar.gz && 7z -y x %ZLIB_VERSION%.tar -o%BUILD%
-del %ZLIB_VERSION%.tar && del %ZLIB_VERSION%.tar.gz && del %BUILD%\pax_global_header
-rename %BUILD%\zlib-%ZLIB_VERSION% zlib
-
-cd %SRC%
\ No newline at end of file
diff --git a/contrib/src/zlib/package.json b/contrib/src/zlib/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..b72c18c403c1ef1f8d59ec8923f6e5c726650ee8
--- /dev/null
+++ b/contrib/src/zlib/package.json
@@ -0,0 +1,17 @@
+{
+    "name": "zlib",
+    "version": "8e4e3ead55cdd296130242d86b44b92fde3ea4d4",
+    "url": "https://github.com/ShiftMediaProject/zlib/archive/__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": [],
+    "project_paths": [
+        "SMP/libzlib.vcxproj"
+    ],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/contrib/tarballs/.gitignore b/contrib/tarballs/.gitignore
index 7e4045957f870c852233ec8bd36be58657c3fe32..f7c13541d06f00ddf3ba0e5290edfb834110b021 100644
--- a/contrib/tarballs/.gitignore
+++ b/contrib/tarballs/.gitignore
@@ -3,3 +3,4 @@
 *.h
 *.tgz
 *-git/
+.wget-hsts
\ No newline at end of file