@@ -17,13 +17,30 @@ public static class GetUnityUpdates
17
17
private const string CacheFileName = "UnityVersionCache.json" ;
18
18
private static readonly HttpClient Client = new HttpClient ( ) ;
19
19
20
+ static Dictionary < string , string > unofficialReleaseURLs = new Dictionary < string , string > ( ) ;
21
+
20
22
public static async Task < List < UnityVersion > > FetchAll ( )
21
23
{
22
24
var cachedVersions = LoadCachedVersions ( ) ;
23
25
var newVersions = await FetchNewVersions ( cachedVersions ) ;
24
26
25
- var allVersions = newVersions . Concat ( cachedVersions ) . ToList ( ) ;
27
+ var unofficialVersions = await FetchUnofficialVersions ( cachedVersions ) ;
28
+
29
+ unofficialReleaseURLs . Clear ( ) ;
30
+ // TODO modify FetchUnofficialVersions to put items in this dictionary directly
31
+ foreach ( var version in unofficialVersions )
32
+ {
33
+ //Console.WriteLine("unofficial: " + version.Version + " , " + version.directURL);
34
+ if ( unofficialReleaseURLs . ContainsKey ( version . Version ) == false )
35
+ {
36
+ unofficialReleaseURLs . Add ( version . Version , version . directURL ) ;
37
+ }
38
+ }
39
+
40
+ var allVersions = newVersions . Concat ( unofficialVersions ) . Concat ( cachedVersions ) . ToList ( ) ;
41
+ //var allVersions = newVersions.Concat(cachedVersions).ToList();
26
42
43
+ // TODO save unofficial versions to cache also? or maybe not, they will appear in official list later
27
44
if ( newVersions . Count > 0 )
28
45
{
29
46
SaveCachedVersions ( allVersions ) ;
@@ -32,13 +49,89 @@ public static async Task<List<UnityVersion>> FetchAll()
32
49
return allVersions ;
33
50
}
34
51
52
+ public static async Task < List < UnityVersion > > FetchUnofficialVersions ( List < UnityVersion > cachedVersions )
53
+ {
54
+ var unofficialVersions = new List < UnityVersion > ( ) ;
55
+ var existingVersions = new HashSet < string > ( cachedVersions . Select ( v => v . Version ) ) ;
56
+
57
+ try
58
+ {
59
+ string url = "https://raw.githubusercontent.com/unitycoder/UnofficialUnityReleasesWatcher/refs/heads/main/unity-releases.md" ;
60
+
61
+ var content = await Client . GetStringAsync ( url ) ;
62
+
63
+ // Parse the Markdown content
64
+ var lines = content . Split ( new [ ] { '\n ' , '\r ' } , StringSplitOptions . RemoveEmptyEntries ) ;
65
+ foreach ( var line in lines )
66
+ {
67
+ if ( line . StartsWith ( "- " ) ) // Identify Markdown list items
68
+ {
69
+ var urlPart = line . Substring ( 2 ) . Trim ( ) ;
70
+ var version = ExtractVersionFromUrl ( urlPart ) ;
71
+
72
+ if ( ! string . IsNullOrEmpty ( version ) && ! existingVersions . Contains ( version ) )
73
+ {
74
+ var stream = InferStreamFromVersion ( version ) ;
75
+
76
+ unofficialVersions . Add ( new UnityVersion
77
+ {
78
+ Version = version ,
79
+ Stream = stream ,
80
+ ReleaseDate = DateTime . Now , // NOTE not correct, but we don't have known release date for unofficial versions (its only when they are found..)
81
+ //ReleaseDate = DateTime.MinValue // Release date is unavailable in the MD format, TODO add to md as #2021-01-01 ?
82
+ directURL = urlPart , // this is available only for unofficial releases
83
+ } ) ;
84
+ }
85
+ }
86
+ }
87
+ }
88
+ catch ( Exception ex )
89
+ {
90
+ Console . WriteLine ( $ "Error fetching unofficial versions: { ex . Message } ") ;
91
+ }
92
+
93
+ return unofficialVersions ;
94
+ }
95
+
96
+ // TODO fixme, f is not always LTS
97
+ private static UnityVersionStream InferStreamFromVersion ( string version )
98
+ {
99
+ if ( Tools . IsAlpha ( version ) ) return UnityVersionStream . Alpha ;
100
+ if ( Tools . IsBeta ( version ) ) return UnityVersionStream . Beta ;
101
+ if ( Tools . IsLTS ( version ) ) return UnityVersionStream . LTS ;
102
+
103
+ //if (version.Contains("a")) return UnityVersionStream.Alpha;
104
+ //if (version.Contains("b")) return UnityVersionStream.Beta;
105
+ //if (version.Contains("f")) return UnityVersionStream.LTS;
106
+ return UnityVersionStream . Tech ; // Default to Tech if no identifier is found
107
+ }
108
+
109
+ /// <summary>
110
+ /// Extracts the Unity version from the given URL.
111
+ /// </summary>
112
+ /// <param name="url">The URL to parse.</param>
113
+ /// <returns>The Unity version string.</returns>
114
+ private static string ExtractVersionFromUrl ( string url )
115
+ {
116
+ try
117
+ {
118
+ var versionStart = url . LastIndexOf ( '#' ) + 1 ;
119
+ return versionStart > 0 && versionStart < url . Length ? url . Substring ( versionStart ) : null ;
120
+ }
121
+ catch
122
+ {
123
+ return null ;
124
+ }
125
+ }
126
+
35
127
public static async Task < string > FetchDownloadUrl ( string unityVersion )
36
128
{
37
129
if ( string . IsNullOrEmpty ( unityVersion ) )
38
130
{
39
131
return null ;
40
132
}
41
133
134
+ // unity release api
42
135
string apiUrl = $ "{ BaseApiUrl } ?limit=1&version={ unityVersion } &architecture=X86_64&platform=WINDOWS";
43
136
44
137
try
@@ -53,8 +146,37 @@ public static async Task<string> FetchDownloadUrl(string unityVersion)
53
146
}
54
147
}
55
148
149
+ static string ParseHashCodeFromURL ( string url )
150
+ {
151
+ // https://beta.unity3d.com/download/330fbefc18b7/download.html#6000.1.0a8 > 330fbefc18b7
152
+
153
+ int hashStart = url . IndexOf ( "download/" ) + 9 ;
154
+ int hashEnd = url . IndexOf ( "/download.html" , hashStart ) ;
155
+ return url . Substring ( hashStart , hashEnd - hashStart ) ;
156
+ }
157
+
56
158
private static async Task < string > ExtractDownloadUrlAsync ( string json , string unityVersion )
57
159
{
160
+ //Console.WriteLine("json: " + json + " vers: " + unityVersion);
161
+
162
+ if ( json . Contains ( "\" results\" :[]" ) )
163
+ {
164
+ Console . WriteLine ( "No results found from releases API, checking unofficial list (if enabled)" ) ;
165
+
166
+ if ( unofficialReleaseURLs . ContainsKey ( unityVersion ) )
167
+ {
168
+ Console . WriteLine ( "Unofficial release found in the list." ) ;
169
+
170
+ string unityHash = ParseHashCodeFromURL ( unofficialReleaseURLs [ unityVersion ] ) ;
171
+ // Console.WriteLine(unityHash);
172
+ string downloadURL = Tools . ParseDownloadURLFromWebpage ( unityVersion , unityHash , false , true ) ;
173
+ // Console.WriteLine("direct download url: "+downloadURL);
174
+ return downloadURL ;
175
+ }
176
+
177
+ return null ;
178
+ }
179
+
58
180
int resultsIndex = json . IndexOf ( "\" results\" :" ) ;
59
181
if ( resultsIndex == - 1 ) return null ;
60
182
@@ -84,7 +206,7 @@ private static async Task<string> ExtractDownloadUrlAsync(string json, string un
84
206
85
207
if ( await CheckAssistantUrl ( assistantUrl ) )
86
208
{
87
- Console . WriteLine ( "Assistant download URL found." ) ;
209
+ // Console.WriteLine("ExtractDownloadUrlAsync: Assistant download URL found.");
88
210
return assistantUrl ;
89
211
}
90
212
else
@@ -279,6 +401,7 @@ private static void SaveCachedVersions(List<UnityVersion> versions)
279
401
if ( configDirectory == null ) return ;
280
402
281
403
string cacheFilePath = Path . Combine ( configDirectory , CacheFileName ) ;
404
+ //Console.WriteLine("Saving cachedrelease: " + cacheFilePath);
282
405
File . WriteAllText ( cacheFilePath , json ) ;
283
406
}
284
407
}
0 commit comments