@@ -4,6 +4,17 @@ import { feedToJSON } from './feedtojson';
44import { getRandomUserAgent } from './useragent' ;
55import { parse } from 'node-html-parser' ;
66
7+ // Convert cdn-images-1.medium.com URL to miro.medium.com format
8+ // Example: https://cdn-images-1.medium.com/max/1024/0*abc.png -> https://miro.medium.com/v2/resize:fit:150/0*abc.png
9+ function convertToMiroUrl ( cdnUrl : string ) : string {
10+ const match = cdnUrl . match ( / c d n - i m a g e s - \d \. m e d i u m \. c o m \/ m a x \/ \d + \/ ( .+ ) $ / ) ;
11+ if ( match ) {
12+ // Use smaller size (150px) for thumbnail to reduce payload
13+ return `https://miro.medium.com/v2/resize:fit:800/${ match [ 1 ] } ` ;
14+ }
15+ return cdnUrl ;
16+ }
17+
718export const getArticle = async ( index : string , username : string ) => {
819 const rssUrl = `https://medium.com/feed/${ username } `
920 const res = await feedToJSON ( rssUrl ) ;
@@ -24,19 +35,30 @@ export const getArticle = async (index: string, username: string) => {
2435 ] ;
2536
2637 const description = content || desc ;
27- const responseThumbnail = await axios ( thumbnail . src , {
28- responseType : 'arraybuffer' ,
29- headers : {
30- 'User-Agent' : getRandomUserAgent ( ) ,
31- }
32- } ) ;
33- const base64Img = Buffer . from ( responseThumbnail . data , 'binary' ) . toString ( 'base64' ) ;
3438
35- const imgTypeArr = thumbnail . src . split ( '.' ) ;
36- const imgType = imgTypeArr [ imgTypeArr . length - 1 ] ;
39+ // Medium placeholder SVG as fallback
40+ const placeholderSvg = `data:image/svg+xml;base64, ${ Buffer . from ( `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150"><rect fill="#12100E" width="150" height="150"/><path fill="#fff" d="M40 45h10l22 35 22-35h10v60h-10V65L75 95h-2L55 65v40H40V45z"/></svg>` ) . toString ( 'base64' ) } ` ;
3741
38- const convertedThumbnail = `data:image/ ${ imgType } ;base64, ${ base64Img } ` ;
42+ let convertedThumbnail = placeholderSvg ;
3943
44+ try {
45+ // Use miro.medium.com which doesn't have Cloudflare bot protection
46+ const miroUrl = convertToMiroUrl ( thumbnail . src ) ;
47+
48+ const responseThumbnail = await axios ( miroUrl , {
49+ responseType : 'arraybuffer' ,
50+ timeout : 10000 ,
51+ headers : {
52+ 'User-Agent' : getRandomUserAgent ( ) ,
53+ }
54+ } ) ;
55+ const base64Img = Buffer . from ( responseThumbnail . data , 'binary' ) . toString ( 'base64' ) ;
56+
57+ // miro.medium.com returns JPEG images
58+ convertedThumbnail = `data:image/jpeg;base64,${ base64Img } ` ;
59+ } catch ( error ) {
60+ console . log ( 'Failed to fetch thumbnail, using placeholder:' , error instanceof Error ? error . message : 'Unknown error' ) ;
61+ }
4062
4163 const cleanedDescription = stripHTML ( description ) ;
4264 return {
0 commit comments