33using System . Linq ;
44using System . Runtime . InteropServices ;
55using System . Text . Json ;
6+ using System . Text . RegularExpressions ;
67using NLog ;
78using NzbDrone . Common . Cloud ;
89using NzbDrone . Common . EnvironmentInfo ;
910using NzbDrone . Common . Http ;
1011using NzbDrone . Core . Analytics ;
1112using NzbDrone . Core . Configuration ;
1213using NzbDrone . Core . Datastore ;
14+ using Semver ;
1315
1416namespace NzbDrone . Core . Update
1517{
@@ -54,11 +56,15 @@ public UpdatePackage GetLatestUpdate(string branch, Version currentVersion)
5456 if ( latest != null )
5557 {
5658 _logger . Info ( "Update found: {0} ({1})" , latest . Version , latest . FileName ) ;
57- if ( Semver . SemVersion . ComparePrecedence ( Semver . SemVersion . Parse ( currentVersion . ToString ( ) ) , latest . Version ) >= 0 )
59+
60+ // Convert latest.Version (SemVersion) to .NET Version for comparison
61+ var latestDotNetVersion = releaseVersionAsAssemblyVersion ( latest . Version . ToString ( ) ) ;
62+
63+ if ( currentVersion >= latestDotNetVersion )
5864 {
5965 _logger . Info ( "Current version '{0}' is up-to-date or newer than the latest available update '{1}'." ,
6066 currentVersion ,
61- latest . Version ) ;
67+ latestDotNetVersion ) ;
6268 return null ;
6369 }
6470
@@ -88,7 +94,7 @@ public List<UpdatePackage> GetRecentUpdates(string branch, Version currentVersio
8894
8995 var builder = _cloudRequestBuilder . GithubReleases . Create ( ) ;
9096 builder . SetSegment ( "githubownerrepo" , ownerRepo ) ;
91- builder . AddQueryParam ( "per_page" , "5 " ) ;
97+ builder . AddQueryParam ( "per_page" , "25 " ) ;
9298
9399 var request = builder . Build ( ) ;
94100 _logger . Debug ( $ "Requesting: { request . Url } ") ;
@@ -104,16 +110,58 @@ public List<UpdatePackage> GetRecentUpdates(string branch, Version currentVersio
104110 var packages = new List < UpdatePackage > ( ) ;
105111 foreach ( var release in releases )
106112 {
113+ // Filter out releases that do not match the requested branch
114+ // For example, if branch is 'eros-develop', skip tags like 'v3.2.0-release.27'
115+ // You may need to adjust this logic if your tag naming changes
116+ if ( ! string . IsNullOrEmpty ( branch ) )
117+ {
118+ var tagLower = release . tag_name . ToLowerInvariant ( ) ;
119+ var branchLower = branch . ToLowerInvariant ( ) ;
120+
121+ // If branch is exactly 'eros', skip prerelease tags
122+ if ( branchLower == "eros" && tagLower . Contains ( "develop" ) )
123+ {
124+ _logger . Debug ( $ "Skipping prerelease { release . tag_name } for stable branch { branch } .") ;
125+ continue ;
126+ }
127+
128+ // If branch contains 'develop', skip tags with 'release' and vice versa
129+ if ( branchLower . Contains ( "develop" ) && ! tagLower . Contains ( "develop" ) )
130+ {
131+ _logger . Debug ( $ "Skipping release { release . tag_name } because it is a release tag and branch is { branch } .") ;
132+ continue ;
133+ }
134+ }
135+
107136 if ( release . assets == null )
108137 {
109138 _logger . Debug ( $ "Release { release . tag_name } has no package assets, skipping.") ;
110139 continue ;
111140 }
112141
113- // Filter release assets by mapped OS asset string and architecture
114- var asset = release . assets . FirstOrDefault ( a =>
115- a . name . Contains ( osAssetString , StringComparison . OrdinalIgnoreCase ) &&
116- a . name . Contains ( arch , StringComparison . OrdinalIgnoreCase ) ) ;
142+ // Prefer .tar.gz for Osx, fallback to .zip/.app
143+ GithubAsset asset = null ;
144+ if ( OsInfo . Os == Os . Osx )
145+ {
146+ asset = release . assets . FirstOrDefault ( a =>
147+ a . name . Contains ( osAssetString , StringComparison . OrdinalIgnoreCase ) &&
148+ a . name . Contains ( arch , StringComparison . OrdinalIgnoreCase ) &&
149+ a . name . EndsWith ( ".tar.gz" , StringComparison . OrdinalIgnoreCase ) ) ;
150+ if ( asset == null )
151+ {
152+ asset = release . assets . FirstOrDefault ( a =>
153+ a . name . Contains ( osAssetString , StringComparison . OrdinalIgnoreCase ) &&
154+ a . name . Contains ( arch , StringComparison . OrdinalIgnoreCase ) &&
155+ ( a . name . EndsWith ( ".zip" , StringComparison . OrdinalIgnoreCase ) || a . name . EndsWith ( ".app" , StringComparison . OrdinalIgnoreCase ) ) ) ;
156+ }
157+ }
158+ else
159+ {
160+ asset = release . assets . FirstOrDefault ( a =>
161+ a . name . Contains ( osAssetString , StringComparison . OrdinalIgnoreCase ) &&
162+ a . name . Contains ( arch , StringComparison . OrdinalIgnoreCase ) ) ;
163+ }
164+
117165 if ( asset == null )
118166 {
119167 _logger . Debug ( "No asset found for release {0} matching OS asset string '{1}' and arch '{2}'" ,
@@ -125,7 +173,12 @@ public List<UpdatePackage> GetRecentUpdates(string branch, Version currentVersio
125173
126174 _logger . Debug ( $ "Found update: { release . tag_name } - { asset . name } ") ;
127175 var tag = release . tag_name . TrimStart ( 'v' ) ;
128- var version = Semver . SemVersion . Parse ( tag ) ;
176+
177+ // Attempt to strip "what's new", as it's repetitive in our UI
178+ var body = release ? . body != null
179+ ? Regex . Replace ( release . body , @"^## What's Changed\s*\r?\n" , "" , RegexOptions . Multiline )
180+ : string . Empty ;
181+ var version = SemVersion . Parse ( tag ) ;
129182 if ( version == null )
130183 {
131184 _logger . Warn ( "Could not parse semver from tag '{0}' (parsed: '{1}'). Skipping this release." ,
@@ -141,8 +194,8 @@ public List<UpdatePackage> GetRecentUpdates(string branch, Version currentVersio
141194 ReleaseDate = release . published_at ,
142195 FileName = asset . name ,
143196 Url = asset . browser_download_url ,
144- Changes = new UpdateChanges { New = new List < string > { release . body } } ,
145- Hash = asset . digest ,
197+ Changes = new UpdateChanges { New = new List < string > { body } } ,
198+ Hash = asset . digest . Replace ( "sha256:" , "" , StringComparison . OrdinalIgnoreCase ) ,
146199 Branch = branch
147200 } ) ;
148201 }
@@ -151,6 +204,37 @@ public List<UpdatePackage> GetRecentUpdates(string branch, Version currentVersio
151204 return packages ;
152205 }
153206
207+ /// <summary> Converts a GitHub release version string to a .NET Version object.</summary>
208+ /// <param name="releaseTag">The release version string (e.g., "v3.2.0-develop.23").</param>
209+ /// <returns>The corresponding .NET Assembly Version object.(e.e., 3.2.0.27)</returns>
210+ private static Version releaseVersionAsAssemblyVersion ( string releaseTag )
211+ {
212+ var semver = SemVersion . Parse ( releaseTag . TrimStart ( 'v' ) ) ;
213+ if ( semver == null )
214+ {
215+ throw new ArgumentException ( $ "Invalid semver: { releaseTag } ", nameof ( releaseTag ) ) ;
216+ }
217+
218+ // Use major, minor, patch, and if available, the last numeric part of prerelease as revision
219+ var major = ( int ) semver . Major ;
220+ var minor = ( int ) semver . Minor ;
221+ var build = ( int ) semver . Patch ;
222+
223+ // Try to extract revision from prerelease (e.g., 3.2.0-develop.23)
224+ var revision = 0 ;
225+
226+ if ( ! string . IsNullOrEmpty ( semver . Prerelease ) )
227+ {
228+ var parts = semver . Prerelease . Split ( '.' ) ;
229+ if ( parts . Length > 0 && int . TryParse ( parts . Last ( ) , out var rev ) )
230+ {
231+ revision = rev ;
232+ }
233+ }
234+
235+ return new Version ( major , minor , build , revision ) ;
236+ }
237+
154238 /// <summary>
155239 /// Maps the OsInfo.Os enum to the asset string prefix used in GitHub release asset names.
156240 /// </summary>
@@ -175,7 +259,7 @@ private static string GetOsAssetString(Os os)
175259 }
176260 }
177261
178- private class GithubRelease
262+ internal class GithubRelease
179263 {
180264 /// <summary>The tag name of the release.</summary>
181265 public string tag_name { get ; set ; }
@@ -191,12 +275,12 @@ private class GithubRelease
191275 }
192276
193277 /// <summary>Represents an asset in a GitHub release.</summary>
194- private class GithubAsset
278+ internal class GithubAsset
195279 {
196280 /// <summary>The name of the asset file.</summary>
197281 public string name { get ; set ; }
198282
199- /// <summary>The digest (sha: hash) of the asset.</summary>
283+ /// <summary>The digest (sha256 hash) of the asset.</summary>
200284 public string digest { get ; set ; }
201285
202286 /// <summary>The download URL of the asset.</summary>
0 commit comments