@@ -4,132 +4,113 @@ var profile = require('./template');
44var axios = require ( 'axios' ) ;
55
66module . exports = function papertemplate ( name ) {
7- const lowername = name . toLowerCase ( ) ;
8- const titlename = name . charAt ( 0 ) . toUpperCase ( ) + lowername . substr ( 1 ) ;
7+ const lowername = String ( name || 'paper' ) . toLowerCase ( ) ; // esperado: "paper"
8+ const titlename = lowername . charAt ( 0 ) . toUpperCase ( ) + lowername . substr ( 1 ) ;
9+
10+ const USER_AGENT = `${ titlename } -MineOS/1.0 (+admin@example.com)` ;
11+
12+ const AXIOS_OPTS = {
13+ headers : {
14+ 'User-Agent' : USER_AGENT ,
15+ 'Accept' : 'application/json'
16+ } ,
17+ timeout : 20000 ,
18+ validateStatus : ( s ) => s >= 200 && s < 300
19+ } ;
920
1021 return {
1122 name : titlename ,
23+
1224 request_args : {
1325 url : `https://fill.papermc.io/v3/projects/${ lowername } ` ,
14- json : true
26+ json : true ,
27+ headers : {
28+ 'User-Agent' : USER_AGENT ,
29+ 'Accept' : 'application/json'
30+ }
1531 } ,
16- handler : function ( profile_dir , body , callback ) {
17- var p = [ ] ;
18- var weight = 0 ;
19-
20- try {
21- const allVersions = [ ] ;
22-
23- if ( body . versions && typeof body . versions === 'object' ) {
24- Object . values ( body . versions ) . forEach ( groupVersions => {
25- if ( Array . isArray ( groupVersions ) ) {
26- allVersions . push ( ...groupVersions ) ;
27- }
28- } ) ;
29- }
3032
31- // ✅ 1. ÚLTIMA build estable (build más alto de latest)
32- p . push ( axios ( {
33- url : `https://fill.papermc.io/v3/projects/${ lowername } /versions/latest` ,
34- json : true
35- } ) . catch ( ( ) => null ) ) ;
36-
37- // ✅ 2. Builds más recientes por versión específica (top 8)
38- if ( allVersions . length > 0 ) {
39- allVersions . sort ( ( a , b ) => {
40- const va = a . split ( '.' ) . map ( Number ) ;
41- const vb = b . split ( '.' ) . map ( Number ) ;
42- for ( let i = 0 ; i < Math . max ( va . length , vb . length ) ; i ++ ) {
43- const vaPart = va [ i ] || 0 ;
44- const vbPart = vb [ i ] || 0 ;
45- if ( vaPart !== vbPart ) return vbPart - vaPart ;
46- }
47- return 0 ;
33+ handler : function ( profile_dir , body , callback ) {
34+ ( async ( ) => {
35+ try {
36+
37+ let projectData = body ;
38+ if ( ! projectData || ! projectData . versions || typeof projectData . versions !== 'object' ) {
39+ const projResp = await axios . get (
40+ `https://fill.papermc.io/v3/projects/${ lowername } ` ,
41+ AXIOS_OPTS
42+ ) ;
43+ projectData = projResp . data ;
44+ }
45+
46+ if ( ! projectData || ! projectData . versions || typeof projectData . versions !== 'object' ) {
47+ return callback ( new Error ( 'Respuesta inválida de Fill: faltan versiones.' ) , [ ] ) ;
48+ }
49+
50+ const allVersions = [ ] ;
51+ Object . values ( projectData . versions ) . forEach ( ( groupVersions ) => {
52+ if ( Array . isArray ( groupVersions ) ) allVersions . push ( ...groupVersions ) ;
4853 } ) ;
4954
50- allVersions . slice ( 0 , 8 ) . forEach ( version => {
51- p . push ( axios ( {
52- url : `https://fill.papermc.io/v3/projects/${ lowername } /versions/${ version } ` ,
53- json : true
54- } ) . catch ( ( ) => null ) ) ;
55- } ) ;
56- }
55+ if ( allVersions . length === 0 ) {
56+ return callback ( new Error ( 'No se encontraron versiones en Fill.' ) , [ ] ) ;
57+ }
5758
58- Promise . all ( p ) . then ( responses => {
59- var items = [ ] ;
60-
61- responses . forEach ( ( response , index ) => {
62- if ( ! response || response === null ) return ;
59+ let selectedVersion = null ;
60+ let selectedStableBuild = null ;
6361
64- const data = response . data ;
62+ for ( const ver of allVersions ) {
63+ try {
64+ const buildsResp = await axios . get (
65+ `https://fill.papermc.io/v3/projects/${ lowername } /versions/${ encodeURIComponent ( ver ) } /builds` ,
66+ AXIOS_OPTS
67+ ) ;
6568
66- if ( ! data || data . ok === false || ! data . builds || ! Array . isArray ( data . builds ) ) {
67- return ;
68- }
69+ const builds = buildsResp . data ;
70+ if ( ! Array . isArray ( builds ) || builds . length === 0 ) continue ;
6971
70- // ✅ ORDENAR BUILDS por número (más alto = más reciente)
71- const builds = [ ...data . builds ] . sort ( ( a , b ) => {
72- const buildA = a . build || a ;
73- const buildB = b . build || b ;
74- return buildB - buildA ; // DESCENDENTE: mayor build primero
75- } ) ;
76-
77- if ( builds . length === 0 ) return ;
78-
79- const latestBuildObj = builds [ 0 ] ; // PRIMERA = MÁS RECIENTE
80- const buildNumber = latestBuildObj . build || latestBuildObj ;
81-
82- // Extraer versión correctamente
83- let version ;
84- if ( index === 0 ) { // latest
85- version = data . version ?. id || data . version_name || data . version || 'latest' ;
86- if ( typeof version === 'object' ) {
87- version = version . id || version . name || version . version || 'latest' ;
88- }
89- } else {
90- version = allVersions [ index - 1 ] ;
91- }
72+ const stable = builds . find ( ( b ) => b && b . channel === 'STABLE' && b . downloads ) ;
73+ if ( ! stable ) continue ;
9274
93- const isLatest = index === 0 ;
94- const item = new profile ( ) ;
95-
96- item [ 'id' ] = `${ titlename } -${ version } -${ buildNumber } ` ;
97- item [ 'group' ] = lowername ;
98- item [ 'webui_desc' ] = isLatest
99- ? `LATEST ${ titlename } (${ version } ) build #${ buildNumber } `
100- : `${ titlename } ${ version } latest build #${ buildNumber } ` ;
101- item [ 'weight' ] = weight ;
102- item [ 'filename' ] = `${ lowername } -${ version } -${ buildNumber } .jar` ;
103-
104- let downloadUrl = '' ;
105- if ( latestBuildObj . downloads ?. application ?. url ) {
106- downloadUrl = latestBuildObj . downloads . application . url ;
107- } else {
108- const verForUrl = isLatest ? version : allVersions [ index - 1 ] ;
109- downloadUrl = `https://fill.papermc.io/v3/projects/${ lowername } /versions/${ verForUrl } /builds/${ buildNumber } /downloads/${ lowername } -${ verForUrl } -${ buildNumber } .jar` ;
75+ selectedVersion = ver ;
76+ selectedStableBuild = stable ;
77+ break ;
78+ } catch ( _ ) {
79+ continue ;
11080 }
81+ }
11182
112- item [ 'url' ] = downloadUrl ;
113- item [ 'downloaded' ] = fs . existsSync ( path . join ( profile_dir , item . id , item . filename ) ) ;
114- item [ 'version' ] = version ;
115- item [ 'release_version' ] = version ;
116- item [ 'type' ] = 'release' ;
83+ if ( ! selectedVersion || ! selectedStableBuild ) {
84+ return callback ( new Error ( 'No se encontró ninguna versión con build STABLE.' ) , [ ] ) ;
85+ }
11786
118- items . push ( item ) ;
119- weight ++ ;
120- } ) ;
87+ const buildId = selectedStableBuild . id ;
88+ const downloadUrl = selectedStableBuild . downloads ?. [ 'server:default' ] ?. url ;
12189
122- console . log ( `Generated ${ items . length } Paper endpoints (latest builds)` ) ;
123- callback ( null , items ) ;
124- } ) . catch ( err => {
125- console . error ( 'Error:' , err ) ;
126- callback ( err , [ ] ) ;
127- } ) ;
90+ if ( ! downloadUrl ) {
91+ return callback ( new Error ( 'Build STABLE encontrado pero sin URL de descarga.' ) , [ ] ) ;
92+ }
12893
129- } catch ( e ) {
130- console . error ( 'Error:' , e ) ;
131- callback ( e , [ ] ) ;
132- }
94+ // 4) Crear el item MineOS
95+ const item = new profile ( ) ;
96+ item [ 'id' ] = `${ titlename } -${ selectedVersion } -${ buildId } ` ;
97+ item [ 'group' ] = lowername ;
98+ item [ 'webui_desc' ] = `LATEST STABLE ${ titlename } (${ selectedVersion } ) build #${ buildId } ` ;
99+ item [ 'weight' ] = 0 ;
100+
101+ item [ 'filename' ] = `${ lowername } -${ selectedVersion } -${ buildId } .jar` ;
102+ item [ 'url' ] = downloadUrl ;
103+
104+ item [ 'downloaded' ] = fs . existsSync ( path . join ( profile_dir , item . id , item . filename ) ) ;
105+ item [ 'version' ] = selectedVersion ;
106+ item [ 'release_version' ] = selectedVersion ;
107+ item [ 'type' ] = 'release' ;
108+
109+ return callback ( null , [ item ] ) ;
110+ } catch ( err ) {
111+ return callback ( err , [ ] ) ;
112+ }
113+ } ) ( ) ;
133114 }
134115 } ;
135116} ;
0 commit comments