Skip to content

Instantly share code, notes, and snippets.

@mono0926
Last active September 18, 2025 03:38
Show Gist options
  • Select an option

  • Save mono0926/788546d3a5e93069b7a832c82b6b6359 to your computer and use it in GitHub Desktop.

Select an option

Save mono0926/788546d3a5e93069b7a832c82b6b6359 to your computer and use it in GitHub Desktop.

Revisions

  1. mono0926 revised this gist Sep 18, 2025. No changes.
  2. mono0926 revised this gist Mar 10, 2025. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.ts
    Original file line number Diff line number Diff line change
    @@ -130,7 +130,7 @@ export const convertMap = onRequest(
    }
    const placeId = await fetchGooglePlaceId(coordinate, place)
    return placeId
    ? `${commonUrl}${place}&query_place_id=${placeId}`
    ? `${commonUrl}${encodeURIComponent(place)}&query_place_id=${placeId}`
    : coordinateUrl
    })()

  3. mono0926 revised this gist Mar 10, 2025. 1 changed file with 3 additions and 2 deletions.
    5 changes: 3 additions & 2 deletions index.ts
    Original file line number Diff line number Diff line change
    @@ -123,13 +123,14 @@ export const convertMap = onRequest(
    if (url.includes('maps.apple.com')) {
    const { place, coordinate, invalidPlace } = extractAppleMapInfo(url)
    const googleMapUrl = await (async () => {
    const coordinateUrl = `https://www.google.com/maps/search/?api=1&query=${coordinate}`
    const commonUrl = 'https://www.google.com/maps/search/?api=1&query='
    const coordinateUrl = ${commonUrl}${coordinate}`
    if (invalidPlace) {
    return coordinateUrl
    }
    const placeId = await fetchGooglePlaceId(coordinate, place)
    return placeId
    ? `https://www.google.com/maps/place/?q=place_id:${placeId}`
    ? `${commonUrl}${place}&query_place_id=${placeId}`
    : coordinateUrl
    })()

  4. mono0926 revised this gist Mar 10, 2025. 1 changed file with 33 additions and 1 deletion.
    34 changes: 33 additions & 1 deletion index.ts
    Original file line number Diff line number Diff line change
    @@ -47,6 +47,29 @@ async function getPlaceInfoFromFtid(
    return { place, coordinate, invalidPlace: !plusCode }
    }

    async function fetchGooglePlaceId(
    coordinate: string,
    keyword: string,
    ): Promise<string | null> {
    const radius = 1000 // 検索半径(メートル)
    const apiUrl = `https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=${coordinate}&radius=${radius}&keyword=${encodeURIComponent(keyword)}&language=ja&key=${googleMapsApiKey.value()}`

    const response = await fetch(apiUrl)
    const data = (await response.json()) as any

    if (data.status !== 'OK') {
    logger.warn(
    `Places API error: ${data.status} - ${data.error_message || 'Unknown error'}`,
    )
    return null
    }

    const placeId = data.results[0].place_id
    logger.info('Found place:', { name: data.results[0].name, placeId })

    return placeId
    }

    function extractAppleMapInfo(url: string): {
    place: string
    coordinate: string
    @@ -99,7 +122,16 @@ export const convertMap = onRequest(

    if (url.includes('maps.apple.com')) {
    const { place, coordinate, invalidPlace } = extractAppleMapInfo(url)
    const googleMapUrl = `https://www.google.com/maps/search/?api=1&query=${invalidPlace ? '' : encodeURIComponent(`${place} `)}${coordinate}`
    const googleMapUrl = await (async () => {
    const coordinateUrl = `https://www.google.com/maps/search/?api=1&query=${coordinate}`
    if (invalidPlace) {
    return coordinateUrl
    }
    const placeId = await fetchGooglePlaceId(coordinate, place)
    return placeId
    ? `https://www.google.com/maps/place/?q=place_id:${placeId}`
    : coordinateUrl
    })()

    res.status(200).json({
    place,
  5. mono0926 revised this gist Mar 6, 2025. No changes.
  6. mono0926 revised this gist Mar 6, 2025. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions index.ts
    Original file line number Diff line number Diff line change
    @@ -28,7 +28,7 @@ async function getFtidFromShortUrl(shortUrl: string): Promise<string> {
    async function getPlaceInfoFromFtid(
    ftid: string,
    ): Promise<{ place: string; coordinate: string; invalidPlace: boolean }> {
    const apiUrl = `https://maps.googleapis.com/maps/api/place/details/json?ftid=${ftid}&fields=name,geometry,place_id,plus_code&language=ja&key=${googleMapsApiKey.value()}`
    const apiUrl = `https://maps.googleapis.com/maps/api/place/details/json?ftid=${ftid}&fields=name,geometry,plus_code&language=ja&key=${googleMapsApiKey.value()}`
    const response = await fetch(apiUrl)
    const data = (await response.json()) as any

    @@ -84,10 +84,10 @@ export const convertMap = onRequest(
    const ftid = await getFtidFromShortUrl(url)
    const { place, coordinate, invalidPlace } =
    await getPlaceInfoFromFtid(ftid)
    const baseUrl = 'https://maps.apple.com'
    const baseUrl = 'https://maps.apple.com/search'
    const appleMapUrl = invalidPlace
    ? `${baseUrl}/?ll=${coordinate}&q=Marked%20Location`
    : `${baseUrl}/?q=${encodeURIComponent(place)}`
    ? `${baseUrl}?coordinate=${coordinate}`
    : `${baseUrl}?query=${encodeURIComponent(place)}&center=${coordinate}&span=0.0001,0.0001`

    res.status(200).json({
    place,
    @@ -99,7 +99,7 @@ export const convertMap = onRequest(

    if (url.includes('maps.apple.com')) {
    const { place, coordinate, invalidPlace } = extractAppleMapInfo(url)
    const googleMapUrl = `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(invalidPlace ? coordinate : place)}`
    const googleMapUrl = `https://www.google.com/maps/search/?api=1&query=${invalidPlace ? '' : encodeURIComponent(`${place} `)}${coordinate}`

    res.status(200).json({
    place,
  7. mono0926 revised this gist Mar 5, 2025. 1 changed file with 15 additions and 9 deletions.
    24 changes: 15 additions & 9 deletions index.ts
    Original file line number Diff line number Diff line change
    @@ -27,8 +27,8 @@ async function getFtidFromShortUrl(shortUrl: string): Promise<string> {

    async function getPlaceInfoFromFtid(
    ftid: string,
    ): Promise<{ place: string; coordinate: string }> {
    const apiUrl = `https://maps.googleapis.com/maps/api/place/details/json?ftid=${ftid}&fields=name,geometry&language=ja&key=${googleMapsApiKey.value()}`
    ): Promise<{ place: string; coordinate: string; invalidPlace: boolean }> {
    const apiUrl = `https://maps.googleapis.com/maps/api/place/details/json?ftid=${ftid}&fields=name,geometry,place_id,plus_code&language=ja&key=${googleMapsApiKey.value()}`
    const response = await fetch(apiUrl)
    const data = (await response.json()) as any

    @@ -40,15 +40,17 @@ async function getPlaceInfoFromFtid(
    }

    const place = data.result.name
    const plusCode = data.result.plus_code
    const location = data.result.geometry.location
    const coordinate = `${location.lat},${location.lng}`

    return { place, coordinate }
    return { place, coordinate, invalidPlace: !plusCode }
    }

    function extractAppleMapInfo(url: string): {
    place: string
    coordinate: string
    invalidPlace: boolean
    } {
    const urlParams = new URLSearchParams(url.split('?')[1])
    const place = urlParams.get('name')
    @@ -58,11 +60,11 @@ function extractAppleMapInfo(url: string): {
    throw new HttpsError('invalid-argument', 'Invalid Apple Maps URL')
    }

    return { place, coordinate }
    return { place, coordinate, invalidPlace: place == 'Marked Location' }
    }

    export const convertMap = onRequest(
    { secrets: [googleMapsApiKey, secretKey] },
    { secrets: [googleMapsApiKey, secretKey], region: 'asia-northeast1' },
    async (req, res) => {
    try {
    const secretHeader = req.get('X-Secret-String')
    @@ -80,8 +82,12 @@ export const convertMap = onRequest(

    if (url.includes('maps.app.goo.gl')) {
    const ftid = await getFtidFromShortUrl(url)
    const { place, coordinate } = await getPlaceInfoFromFtid(ftid)
    const appleMapUrl = `http://maps.apple.com/?q=${encodeURIComponent(place)}`
    const { place, coordinate, invalidPlace } =
    await getPlaceInfoFromFtid(ftid)
    const baseUrl = 'https://maps.apple.com'
    const appleMapUrl = invalidPlace
    ? `${baseUrl}/?ll=${coordinate}&q=Marked%20Location`
    : `${baseUrl}/?q=${encodeURIComponent(place)}`

    res.status(200).json({
    place,
    @@ -92,8 +98,8 @@ export const convertMap = onRequest(
    }

    if (url.includes('maps.apple.com')) {
    const { place, coordinate } = extractAppleMapInfo(url)
    const googleMapUrl = `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(place)}`
    const { place, coordinate, invalidPlace } = extractAppleMapInfo(url)
    const googleMapUrl = `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(invalidPlace ? coordinate : place)}`

    res.status(200).json({
    place,
  8. mono0926 created this gist Mar 5, 2025.
    126 changes: 126 additions & 0 deletions index.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,126 @@
    import * as logger from 'firebase-functions/logger'
    import { defineSecret } from 'firebase-functions/params'
    import { HttpsError, onRequest } from 'firebase-functions/v2/https'

    const secretKey = defineSecret('convertMapSecretKey')
    const googleMapsApiKey = defineSecret('convertMapGoogleMapsApiKey')

    async function getFtidFromShortUrl(shortUrl: string): Promise<string> {
    const response = await fetch(shortUrl, {
    method: 'GET',
    redirect: 'manual',
    })

    const redirectUrl = response.headers.get('location')
    if (!redirectUrl) {
    throw new HttpsError('not-found', 'Failed to get redirect URL')
    }
    logger.info('Redirect URL:', redirectUrl)

    const urlParams = new URLSearchParams(redirectUrl.split('?')[1])
    const ftid = urlParams.get('ftid')
    if (!ftid) {
    throw new HttpsError('invalid-argument', 'No ftid found in redirect URL')
    }
    return ftid
    }

    async function getPlaceInfoFromFtid(
    ftid: string,
    ): Promise<{ place: string; coordinate: string }> {
    const apiUrl = `https://maps.googleapis.com/maps/api/place/details/json?ftid=${ftid}&fields=name,geometry&language=ja&key=${googleMapsApiKey.value()}`
    const response = await fetch(apiUrl)
    const data = (await response.json()) as any

    if (data.status !== 'OK') {
    throw new HttpsError(
    'not-found',
    `Places API error: ${data.status} - ${data.error_message || 'Unknown error'}`,
    )
    }

    const place = data.result.name
    const location = data.result.geometry.location
    const coordinate = `${location.lat},${location.lng}`

    return { place, coordinate }
    }

    function extractAppleMapInfo(url: string): {
    place: string
    coordinate: string
    } {
    const urlParams = new URLSearchParams(url.split('?')[1])
    const place = urlParams.get('name')
    const coordinate = urlParams.get('coordinate')

    if (!place || !coordinate) {
    throw new HttpsError('invalid-argument', 'Invalid Apple Maps URL')
    }

    return { place, coordinate }
    }

    export const convertMap = onRequest(
    { secrets: [googleMapsApiKey, secretKey] },
    async (req, res) => {
    try {
    const secretHeader = req.get('X-Secret-String')
    if (!secretHeader || secretHeader !== secretKey.value()) {
    throw new HttpsError(
    'permission-denied',
    'Forbidden: Invalid or missing secret string',
    )
    }

    const { url } = req.body
    if (!url || typeof url !== 'string') {
    throw new HttpsError('invalid-argument', 'URL is required')
    }

    if (url.includes('maps.app.goo.gl')) {
    const ftid = await getFtidFromShortUrl(url)
    const { place, coordinate } = await getPlaceInfoFromFtid(ftid)
    const appleMapUrl = `http://maps.apple.com/?q=${encodeURIComponent(place)}`

    res.status(200).json({
    place,
    appleMapUrl,
    coordinate,
    })
    return
    }

    if (url.includes('maps.apple.com')) {
    const { place, coordinate } = extractAppleMapInfo(url)
    const googleMapUrl = `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(place)}`

    res.status(200).json({
    place,
    googleMapUrl,
    coordinate,
    })
    return
    }

    throw new HttpsError('invalid-argument', 'Unsupported URL format')
    } catch (error) {
    if (error instanceof HttpsError) {
    res.status(error.httpErrorCode.status).json({
    error: {
    code: error.code,
    message: error.message,
    },
    })
    } else {
    logger.error('Unexpected error:', error)
    res.status(500).json({
    error: {
    code: 'internal',
    message: 'Internal server error',
    },
    })
    }
    }
    },
    )