enhance image detection and proxy
This commit is contained in:
		
							parent
							
								
									059d8d68ac
								
							
						
					
					
						commit
						3c711b6083
					
				@ -1,5 +1,5 @@
 | 
				
			|||||||
import { createHmac } from 'node:crypto'
 | 
					import { createHmac } from 'node:crypto'
 | 
				
			||||||
import { extractUrls } from '../../lib/md'
 | 
					import { extractUrls } from '../../../lib/md'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const IMGPROXY_URL = process.env.NEXT_PUBLIC_IMGPROXY_URL
 | 
					const IMGPROXY_URL = process.env.NEXT_PUBLIC_IMGPROXY_URL
 | 
				
			||||||
const IMGPROXY_SALT = process.env.IMGPROXY_SALT
 | 
					const IMGPROXY_SALT = process.env.IMGPROXY_SALT
 | 
				
			||||||
@ -20,7 +20,7 @@ const createImageProxyUrl = url => {
 | 
				
			|||||||
  const b64Url = Buffer.from(url, 'utf-8').toString('base64url')
 | 
					  const b64Url = Buffer.from(url, 'utf-8').toString('base64url')
 | 
				
			||||||
  const target = `${processingOptions}/${b64Url}`
 | 
					  const target = `${processingOptions}/${b64Url}`
 | 
				
			||||||
  const signature = sign(target)
 | 
					  const signature = sign(target)
 | 
				
			||||||
  return `${IMGPROXY_URL}/${signature}${target}`
 | 
					  return `${IMGPROXY_URL}${signature}${target}`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const isImageURL = async url => {
 | 
					const isImageURL = async url => {
 | 
				
			||||||
@ -35,13 +35,13 @@ const isImageURL = async url => {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useImageProxy = async text => {
 | 
					export const proxyImages = async text => {
 | 
				
			||||||
  const urls = extractUrls(text)
 | 
					  const urls = extractUrls(text)
 | 
				
			||||||
  for (const url of urls) {
 | 
					  for (const url of urls) {
 | 
				
			||||||
    if (url.startsWith(IMGPROXY_URL)) continue
 | 
					    if (url.startsWith(IMGPROXY_URL)) continue
 | 
				
			||||||
    if (!(await isImageURL(url))) continue
 | 
					    if (!(await isImageURL(url))) continue
 | 
				
			||||||
    const proxyUrl = createImageProxyUrl(url)
 | 
					    const proxyUrl = createImageProxyUrl(url)
 | 
				
			||||||
    text = text.replace(new RegExp(url, 'g'), proxyUrl)
 | 
					    text = text.replaceAll(url, proxyUrl)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return text
 | 
					  return text
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -13,7 +13,7 @@ import { parse } from 'tldts'
 | 
				
			|||||||
import uu from 'url-unshort'
 | 
					import uu from 'url-unshort'
 | 
				
			||||||
import { amountSchema, bountySchema, commentSchema, discussionSchema, jobSchema, linkSchema, pollSchema, ssValidate } from '../../lib/validate'
 | 
					import { amountSchema, bountySchema, commentSchema, discussionSchema, jobSchema, linkSchema, pollSchema, ssValidate } from '../../lib/validate'
 | 
				
			||||||
import { sendUserNotification } from '../webPush'
 | 
					import { sendUserNotification } from '../webPush'
 | 
				
			||||||
import { useImageProxy } from '../imgproxy'
 | 
					import { proxyImages } from './imgproxy'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function comments (me, models, id, sort) {
 | 
					async function comments (me, models, id, sort) {
 | 
				
			||||||
  let orderBy
 | 
					  let orderBy
 | 
				
			||||||
@ -1251,8 +1251,8 @@ export const updateItem = async (parent, { id, data: { sub, title, url, text, bo
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  url = await useImageProxy(url)
 | 
					  url = await proxyImages(url)
 | 
				
			||||||
  text = await useImageProxy(text)
 | 
					  text = await proxyImages(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [item] = await serialize(models,
 | 
					  const [item] = await serialize(models,
 | 
				
			||||||
    models.$queryRaw(
 | 
					    models.$queryRaw(
 | 
				
			||||||
@ -1286,8 +1286,8 @@ const createItem = async (parent, { sub, title, url, text, boost, forward, bount
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  url = await useImageProxy(url)
 | 
					  url = await proxyImages(url)
 | 
				
			||||||
  text = await useImageProxy(text)
 | 
					  text = await proxyImages(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [item] = await serialize(
 | 
					  const [item] = await serialize(
 | 
				
			||||||
    models,
 | 
					    models,
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,7 @@ import PollIcon from '../svgs/bar-chart-horizontal-fill.svg'
 | 
				
			|||||||
import BountyIcon from '../svgs/bounty-bag.svg'
 | 
					import BountyIcon from '../svgs/bounty-bag.svg'
 | 
				
			||||||
import ActionTooltip from './action-tooltip'
 | 
					import ActionTooltip from './action-tooltip'
 | 
				
			||||||
import Flag from '../svgs/flag-fill.svg'
 | 
					import Flag from '../svgs/flag-fill.svg'
 | 
				
			||||||
 | 
					import ImageIcon from '../svgs/image-fill.svg'
 | 
				
			||||||
import { abbrNum } from '../lib/format'
 | 
					import { abbrNum } from '../lib/format'
 | 
				
			||||||
import ItemInfo from './item-info'
 | 
					import ItemInfo from './item-info'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -22,6 +23,8 @@ export default function Item ({ item, rank, belowTitle, right, full, children })
 | 
				
			|||||||
  const titleRef = useRef()
 | 
					  const titleRef = useRef()
 | 
				
			||||||
  const [pendingSats, setPendingSats] = useState(0)
 | 
					  const [pendingSats, setPendingSats] = useState(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const image = item.url && item.url.startsWith(process.env.NEXT_PUBLIC_IMGPROXY_URL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
      {rank
 | 
					      {rank
 | 
				
			||||||
@ -39,16 +42,17 @@ export default function Item ({ item, rank, belowTitle, right, full, children })
 | 
				
			|||||||
            <Link href={`/items/${item.id}`} passHref>
 | 
					            <Link href={`/items/${item.id}`} passHref>
 | 
				
			||||||
              <a ref={titleRef} className={`${styles.title} text-reset mr-2`}>
 | 
					              <a ref={titleRef} className={`${styles.title} text-reset mr-2`}>
 | 
				
			||||||
                {item.searchTitle ? <SearchTitle title={item.searchTitle} /> : item.title}
 | 
					                {item.searchTitle ? <SearchTitle title={item.searchTitle} /> : item.title}
 | 
				
			||||||
                {item.pollCost && <span> <PollIcon className='fill-grey vertical-align-baseline' height={14} width={14} /></span>}
 | 
					                {item.pollCost && <span> <PollIcon className='fill-grey ml-1' height={14} width={14} /></span>}
 | 
				
			||||||
                {item.bounty > 0 &&
 | 
					                {item.bounty > 0 &&
 | 
				
			||||||
                  <span>
 | 
					                  <span>
 | 
				
			||||||
                    <ActionTooltip notForm overlayText={`${abbrNum(item.bounty)} ${item.bountyPaidTo?.length ? 'sats paid' : 'sats bounty'}`}>
 | 
					                    <ActionTooltip notForm overlayText={`${abbrNum(item.bounty)} ${item.bountyPaidTo?.length ? 'sats paid' : 'sats bounty'}`}>
 | 
				
			||||||
                      <BountyIcon className={`${styles.bountyIcon} ${item.bountyPaidTo?.length ? 'fill-success vertical-align-middle' : 'fill-grey vertical-align-middle'}`} height={16} width={16} />
 | 
					                      <BountyIcon className={`${styles.bountyIcon} ${item.bountyPaidTo?.length ? 'fill-success' : 'fill-grey'}`} height={16} width={16} />
 | 
				
			||||||
                    </ActionTooltip>
 | 
					                    </ActionTooltip>
 | 
				
			||||||
                  </span>}
 | 
					                  </span>}
 | 
				
			||||||
 | 
					                {image && <span><ImageIcon className='fill-grey ml-2' height={16} width={16} /></span>}
 | 
				
			||||||
              </a>
 | 
					              </a>
 | 
				
			||||||
            </Link>
 | 
					            </Link>
 | 
				
			||||||
            {item.url &&
 | 
					            {item.url && !image &&
 | 
				
			||||||
              <>
 | 
					              <>
 | 
				
			||||||
                {/*  eslint-disable-next-line */}
 | 
					                {/*  eslint-disable-next-line */}
 | 
				
			||||||
                <a
 | 
					                <a
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,8 @@
 | 
				
			|||||||
    font-weight: 500;
 | 
					    font-weight: 500;
 | 
				
			||||||
    white-space: normal;
 | 
					    white-space: normal;
 | 
				
			||||||
    max-width: 100%;
 | 
					    max-width: 100%;
 | 
				
			||||||
 | 
					    display: inline-flex;
 | 
				
			||||||
 | 
					    align-items: center;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
a.title:visited {
 | 
					a.title:visited {
 | 
				
			||||||
 | 
				
			|||||||
@ -27,7 +27,7 @@ export function extractUrls (md) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  const urls = new Set()
 | 
					  const urls = new Set()
 | 
				
			||||||
  visit(tree, ({ type }) => {
 | 
					  visit(tree, ({ type }) => {
 | 
				
			||||||
    return type === 'link'
 | 
					    return type === 'link' || type === 'image'
 | 
				
			||||||
  }, ({ url }) => {
 | 
					  }, ({ url }) => {
 | 
				
			||||||
    urls.add(url)
 | 
					    urls.add(url)
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
				
			|||||||
@ -94,6 +94,10 @@
 | 
				
			|||||||
    margin-bottom: .5rem;
 | 
					    margin-bottom: .5rem;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.fullItemContainer img {
 | 
				
			||||||
 | 
					    border-radius: .4rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.fullItemContainer:empty {
 | 
					.fullItemContainer:empty {
 | 
				
			||||||
    margin: 0;
 | 
					    margin: 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								svgs/image-fill.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								svgs/image-fill.svg
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 5H4V19L13.2923 9.70649C13.6828 9.31595 14.3159 9.31591 14.7065 9.70641L20 15.0104V5ZM2 3.9934C2 3.44476 2.45531 3 2.9918 3H21.0082C21.556 3 22 3.44495 22 3.9934V20.0066C22 20.5552 21.5447 21 21.0082 21H2.9918C2.44405 21 2 20.5551 2 20.0066V3.9934ZM8 11C6.89543 11 6 10.1046 6 9C6 7.89543 6.89543 7 8 7C9.10457 7 10 7.89543 10 9C10 10.1046 9.10457 11 8 11Z"></path></svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 443 B  | 
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user