images: download: Add support for factory images and OTAs
This commit is contained in:
parent
a1d82d9806
commit
cd86042e75
1 changed files with 57 additions and 16 deletions
|
@ -3,32 +3,73 @@ import cliProgress from 'cli-progress'
|
||||||
import fetch from 'node-fetch'
|
import fetch from 'node-fetch'
|
||||||
import { promises as stream } from 'stream'
|
import { promises as stream } from 'stream'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
const VENDOR_INDEX_URL = 'https://developers.google.com/android/drivers'
|
const DEV_INDEX_URL = 'https://developers.google.com/android'
|
||||||
const VENDOR_URL_PREFIX = 'https://dl.google.com/dl/android/aosp/google_devices'
|
const DL_URL_PREFIX = 'https://dl.google.com/dl/android/aosp/'
|
||||||
|
|
||||||
async function getUrl(type: string, buildId: string, device: string) {
|
interface ImageTypeInfo {
|
||||||
if (type == 'vendor') {
|
indexPath: string
|
||||||
let resp = await fetch(VENDOR_INDEX_URL)
|
filePattern: string
|
||||||
|
cookie?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ImageType {
|
||||||
|
Ota = 'ota',
|
||||||
|
Factory = 'factory',
|
||||||
|
Vendor = 'vendor',
|
||||||
|
}
|
||||||
|
|
||||||
|
const IMAGE_TYPES: Record<ImageType, ImageTypeInfo> = {
|
||||||
|
[ImageType.Factory]: {
|
||||||
|
indexPath: 'images',
|
||||||
|
filePattern: 'DEVICE-BUILDID',
|
||||||
|
cookie: 'devsite_wall_acks=nexus-image-tos',
|
||||||
|
},
|
||||||
|
[ImageType.Ota]: {
|
||||||
|
indexPath: 'ota',
|
||||||
|
filePattern: 'DEVICE-ota-BUILDID',
|
||||||
|
cookie: 'devsite_wall_acks=nexus-ota-tos',
|
||||||
|
},
|
||||||
|
[ImageType.Vendor]: {
|
||||||
|
indexPath: 'drivers',
|
||||||
|
filePattern: 'google_devices-DEVICE-BUILDID',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getUrl(type: ImageType, buildId: string, device: string) {
|
||||||
|
let { indexPath, filePattern, cookie } = IMAGE_TYPES[type]
|
||||||
|
|
||||||
|
let resp = await fetch(`${DEV_INDEX_URL}/${indexPath}`, cookie != undefined ? {
|
||||||
|
headers: {
|
||||||
|
Cookie: cookie,
|
||||||
|
},
|
||||||
|
} : undefined)
|
||||||
let index = await resp.text()
|
let index = await resp.text()
|
||||||
|
|
||||||
// TODO: parse HTML properly
|
let filePrefix = filePattern.replace('DEVICE', device)
|
||||||
let pattern = new RegExp(`"(${VENDOR_URL_PREFIX}-${device}-${buildId.toLowerCase()}-[a-z9-9.-_]+)">`)
|
.replace('BUILDID', buildId == 'latest' ? '' : buildId.toLowerCase() + '-')
|
||||||
let match = index.match(pattern)
|
let urlPrefix = DL_URL_PREFIX + filePrefix
|
||||||
if (match == null) {
|
|
||||||
|
let pattern = new RegExp(`"(${_.escapeRegExp(urlPrefix)}.+?)"`, 'g')
|
||||||
|
let matches = Array.from(index.matchAll(pattern))
|
||||||
|
if (matches.length == 0) {
|
||||||
throw new Error(`Image not found: ${type}, ${buildId}, ${device}`)
|
throw new Error(`Image not found: ${type}, ${buildId}, ${device}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return match[1]
|
if (buildId == 'latest') {
|
||||||
|
return matches
|
||||||
|
.map(m => m[1])
|
||||||
|
.sort((a, b) => b.localeCompare(a))[0]
|
||||||
} else {
|
} else {
|
||||||
// TODO: implement factory and ota
|
return matches[0][1]
|
||||||
throw new Error(`Unsupported type ${type}`)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function downloadFile(type: string, buildId: string, device: string, outDir: string) {
|
export async function downloadFile(type: ImageType, buildId: string, device: string, outDir: string) {
|
||||||
let url = await getUrl(type, buildId, device)
|
let url = await getUrl(type, buildId, device)
|
||||||
|
|
||||||
|
console.log(` ${url}`)
|
||||||
let resp = await fetch(url)
|
let resp = await fetch(url)
|
||||||
let name = path.basename(url)
|
let name = path.basename(url)
|
||||||
if (!resp.ok) {
|
if (!resp.ok) {
|
||||||
|
|
Loading…
Reference in a new issue