Azure

Present Latest Weblog Posts In GitHub ReadMe Utilizing An Azure Perform

Introduction

 

 

 

 

GitHub lately launched an choice to customise our profile by giving a separate magical repository. This repository identify must be the identical as your username, for instance, right here. That is how yow will discover this secret repository.

 

Show Recent Blog Posts In GitHub ReadMe Using Azure Function 

 

GitHub secret repository

 

This opens countless alternatives for what you are able to do to your GitHub residence web page. For instance, I’m displaying the picture of the titles of my current 5 weblog posts on my residence web page routinely. I did it utilizing the Azure Perform which is able to return the picture, and all I needed to do on this repository was to make use of it. Total it was enjoyable.

 

Show Recent Blog Posts In GitHub ReadMe Using Azure Function 

 

Customized GitHub residence web page

 

Right here on this submit, we’ll see how we are able to develop an Azure Perform resolution that returns the above-mentioned picture.

 

Develop an Azure operate

 

The very first thing that you should do is to create a brand new Azure Perform. Go to your Azure portal, and seek for Azure Perform. The creation course of is similar as we’d create some other Azure useful resource.

 

When you create the Azure operate, you’re good to go and develop an Azure operate utility in Visual Studio. Right here, I’m utilizing Visual Studio 2019.

 

Show Recent Blog Posts In GitHub ReadMe Using Azure Function

 

Create Azure operate utilizing Visual Studio

 

We’re going to create an HttpTrigger Azure operate, so be sure you choose that choice on the subsequent display. If you happen to want a primary introduction concerning the HttpTrigger Azure operate. I named my operate as GetLatestPosts, and be happy to present any identify you want. This Azure operate has the previous jobs to do.

  1. Get the most recent posts particulars from the feed of my weblog
  2. Create a picture with the feed knowledge
  3. Ship again the picture as a stream

Get the most recent posts particulars from the feed

 

You possibly can often get the feed knowledge by going to {yoursitelink}/feed. For instance, I can get my feed knowledge by going to https://sibeeshpassion.com/feed/. So in our operate, we’ll get this knowledge utilizing an XmlReader and Deserialize it utilizing SyndicationFeed. Please be famous that the Syndication namespace is a part of the System.ServiceModel and it is best to set up the Nuget bundle System.ServiceModel.Syndication. Beneath is the operate used to retrieve the most recent 5 weblog posts’ particulars.

  1. public static IEnumerable < SyndicationItem > GetLatestFeeds() {  
  2.     var reader = XmlReader.Create(Configuration.BlogLink);  
  3.     var feed = SyndicationFeed.Load(reader);  
  4.     reader.Shut();  
  5.     return feed.Gadgets.Take(5);  
  6. }  

Create a picture with titles

 

Now we want a operate to generate a picture and write the weblog posts title to that picture dynamically. To do that, we’re utilizing the Nuget bundle known as SixLabors.ImageSharp. Be happy to make use of any packages you want, the one factor that issues is that we want a picture with the weblog posts titles. The SixLabors.ImageSharp is certainly a tremendous library, I can suggest you to present it a strive. That is how your Nuget bundle put in window ought to look now:

 

Show Recent Blog Posts In GitHub ReadMe Using Azure Function 

 

Required Nuget packages

 

Now we are able to write the operate as proven beneath.

  1. personal static string WriteOnImage(IEnumerable < SyndicationItem > feedItems) {  
  2.     var titles = string.Be a part of(“, “, feedItems.Choose(s => s.Title.Textual content).ToList());  
  3.     utilizing  
  4.     var img = new Picture < Rgba32 > (Configuration.ImageWidth, Configuration.ImageHeight);  
  5.     var font = System Fonts.CreateFont(Configuration.Font, Configuration.FontSize);  
  6.     img.Mutate(ctx => ctx.ApplyScalingWaterMark(font, titles, Shade.Black, 5, true));  
  7.     return img.ToBase64String(PngFormat.Occasion);  
  8. }  

As you’ll be able to see that there’s a Configuration class, from the place we take all of the configurations. Let’ write that now. You may also use Surroundings variables right here, I could replace my repository within the coming days.

  1. namespace GitHub Funcs {  
  2.     public static class Configuration {  
  3.         public static string BlogLink {  
  4.             get;  
  5.             set;  
  6.         } = “https://sibeeshpassion.com/feed”;  
  7.         public static int ImageWidth {  
  8.             get;  
  9.             set;  
  10.         } = 850;  
  11.         public static int ImageHeight {  
  12.             get;  
  13.             set;  
  14.         } = 100;  
  15.         public static string ContentType {  
  16.             get;  
  17.             set;  
  18.         } = “picture/png”;  
  19.         public static string Font {  
  20.             get;  
  21.             set;  
  22.         } = “Arial”;  
  23.         public static int FontSize {  
  24.             get;  
  25.             set;  
  26.         } = 5;  
  27.     }  
  28. }  

The SixLabors.ImageSharp has an inbuilt extension operate known as ToBase64String, which is able to return the picture as base64 string. Did you discover that we’re utilizing one other extension technique right here, “ApplyScalingWaterMark”? Let’s create a category for our Extension strategies in order that it will likely be useful sooner or later.

  1. utilizing SixLabors.Fonts;  
  2. utilizing SixLabors.ImageSharp;  
  3. utilizing SixLabors.ImageSharp.Drawing.Processing;  
  4. utilizing SixLabors.ImageSharp.Processing;  
  5. utilizing System;  
  6. namespace GitHub Funcs.ExtensionMethods {  
  7.     public static class ImageSharpExtensions {  
  8.         public static IImageProcessingContextApplyScalingWaterMark(thisIImageProcessingContextprocessingContext, Font font, string textual content, Shade colour, float padding, bool wordwrap) {  
  9.             if (wordwrap) {  
  10.                 return processing Context.ApplyScalingWaterMarkWordWrap(font, textual content, colour, padding);  
  11.             } else {  
  12.                 return processing Context.ApplyScalingWaterMarkSimple(font, textual content, colour, padding);  
  13.             }  
  14.         }  
  15.         personal static IImage Processing Context Apply Scaling WaterMarkSimple(thisIImageProcessingContextprocessingContext, Font font, string textual content, Shade colour, float padding) {  
  16.             Dimension imgSize = processingContext.GetCurrentSize();  
  17.             float goal Width = img Dimension.Width – (padding * 2);  
  18.             float goal Top = img Dimension.Top – (padding * 2);  
  19.               
  20.             Font Rectangle dimension = Textual content Measurer.Measure(textual content, newRendererOptions(font));  
  21.               
  22.             float scaling Issue = Math.Min(imgSize.Width / dimension.Width, imgSize.Top / dimension.Top);  
  23.               
  24.             Fonts caled Font = new Font(font, scalingFactor * font.Dimension);  
  25.             var heart = new PointF(imgSize.Width / 2, imgSize.Top / 2);  
  26.             var textGraphicOptions = new TextGraphicsOptions() {  
  27.                 Textual content Choices = {  
  28.                     Horizontal Alignment = Horizontal Alignment.Middle,  
  29.                     Vertical Alignment = Vertical Alignment.Middle  
  30.                 }  
  31.             };  
  32.             return processing Context.DrawText(textGraphicOptions, textual content, scaledFont, colour, heart);  
  33.         }  
  34.         personal static IImageProcessing ContextApply ScalingWaterMark WordWrap(thisIImageProcessingContextprocessingContext, Font font, string textual content, Shade colour, float padding) {  
  35.             Dimension imgSize = processing Context.GetCurrentSize();  
  36.             floattar get Width = img Dimension.Width – (padding * 2);  
  37.             floattar get Top = imgSize.Top – (padding * 2);  
  38.             float goal Min Top = imgSize.Top – (padding * 3);   
  39.               
  40.               
  41.             var scaled Font = font;  
  42.             Font Rectangles = new FontRectangle(0, 0, float.MaxValue, float.MaxValue);  
  43.             float scale Issue = (scaledFont.Dimension / 2);   
  44.             int lure Depend = (int) scaledFont.Dimension * 2;  
  45.             if (lure Depend < 10) {  
  46.                 lure Depend = 10;  
  47.             }  
  48.             bool is TooSmall = false;  
  49.             whereas ((s.Top > targetHeight || s.Top < targetMinHeight) && trapCount > 0) {  
  50.                 if (s.Top > goal Top) {  
  51.                     if (isTooSmall) {  
  52.                         scale Issue = scale Issue / 2;  
  53.                     }  
  54.                     scaled Font = new Font(scaledFont, scaledFont.Dimension – scaleFactor);  
  55.                     isTooSmall = false;  
  56.                 }  
  57.                 if (s.Top < targetMinHeight) {  
  58.                     if (!isTooSmall) {  
  59.                         scale Issue = scale Issue / 2;  
  60.                     }  
  61.                     scaled Font = new Font(scaledFont, scaledFont.Dimension + scaleFactor);  
  62.                     isTooSmall = true;  
  63.                 }  
  64.                 trapCount–;  
  65.                 s = TextMeasurer.Measure(textual content, newRendererOptions(scaledFont) {  
  66.                     Wrapping Width = goal Width  
  67.                 });  
  68.             }  
  69.             var heart = new PointF(padding, imgSize.Top / 2);  
  70.             var textGraphicOptions = new TextGraphicsOptions() {  
  71.                 Textual content Choices = {  
  72.                     Horizontal Alignment = Horizontal Alignment.Left,  
  73.                     Vertical Alignment = Vertical Alignment.Middle,  
  74.                     WrapText Width = goal Width  
  75.                 }  
  76.             };  
  77.             return processing Context.DrawText(textGraphicOptions, textual content, scaledFont, colour, heart);  
  78.         }  
  79.     }  
  80. }  

Azure operate to return a stream

 

As all of the supporting strategies are prepared, let’s write our important operate. The final word job of this operate is to transform the bottom64 string to a stream and return the stream. It is so simple as that.

  1. [FunctionName(“GetLatestPosts”)]  
  2. public static FileStreamResultRun([HttpTrigger(AuthorizationLevel.Function, “get”, Route = null)] HttpRequestrequest, ILoggerlog) {  
  3.     strive {  
  4.         varbase String = WriteOnImage(GetLatestFeeds());  
  5.           
  6.         string convert = baseString.Exchange(“knowledge:picture/png;base64,”, String.Empty);  
  7.         var bytes = Convert.FromBase64String(convert);  
  8.         var outcome = new FileStreamResult(newMemoryStream(bytes), Configuration.ContentType);  
  9.         log.LogInformation(“Returning stream now!”);  
  10.         request.HttpContext.Response.Headers.Add(“Cache-Management”“s-maxage=1, stale-while-revalidate”);  
  11.         return outcome;;  
  12.     } catch (System.Exceptionex) {  
  13.         log.LogError($ “One thing went improper: {ex}”);  
  14.         throwex;  
  15.     }  
  16. }  

As soon as your Azure operate is prepared, please keep in mind to publish the identical to Azure. To publish your Azure Perform app, good click on in your mission and click on Publish after which arrange your publish goal by selecting the prevailing Azure Perform App, keep in mind we’ve created one earlier?

 

Develop secret GitHub readme repository

 

Right here, I’m assuming that you just already created your secret repository. And if sure, you’ll be able to replace the “readme” content material as follows. Please keep in mind that that is only a pattern, you’ll be able to replace it as you want.

 

Hello there ?, be happy to take a look at my weblog and youtube channel!

 

 

Beneath are the titles of the most recent 5 posts from my weblog (That is an automatic message utilizing Azure Perform. Azure is Love!)

  • ? I’m at the moment engaged on Azure IoT Hub, IoT Central, Raspberry Pi
  • ? I’m at the moment studying numerous new IoT matters
  • ? I’m seeking to collaborate on any MVP product in IoT
  • ⚡ Enjoyable reality: Nicely, this readme file won’t be sufficient!

Increase!. We did it. Now go to your GitHub residence web page, and I’m certain that you’ll love your new stunning, detailed residence web page.

 

Replace

 

As GitHub has a really low timeout, typically the picture created was not displaying in my profile. Thus, I needed to change the mechanism. I modified my Azure operate to a time set off operate that runs each hour and the principle performance of this operate now could be to generate the picture and add to the Azure blob storage. Now I can straight get the blob picture URL within the Readme file. No extra timeout points. Following are the codes of the brand new Azure operate. You may also see this within the Dev department of the repository.

  1. utilizing GitHubFuncs.ExtensionMethods;  
  2. utilizing Microsoft.AspNetCore.Mvc;  
  3. utilizing Microsoft.Azure.WebJobs;  
  4. utilizing Microsoft.Extensions.Logging;  
  5. utilizing Microsoft.WindowsAzure.Storage;  
  6. utilizing SixLabors.Fonts;  
  7. utilizing SixLabors.ImageSharp;  
  8. utilizing SixLabors.ImageSharp.Codecs.Png;  
  9. utilizing SixLabors.ImageSharp.PixelFormats;  
  10. utilizing SixLabors.ImageSharp.Processing;  
  11. utilizing System;  
  12. utilizing System.Collections.Generic;  
  13. utilizing System.IO;  
  14. utilizing System.Linq;  
  15. utilizing System.Web.Mime;  
  16. utilizing System.ServiceModel.Syndication;  
  17. utilizing System.Threading.Duties;  
  18. utilizing System.Xml;  
  19. namespace GitHubFuncs {  
  20.     public class GetLatestPosts {  
  21.         personal static ILogger_logger;  
  22.         personal  
  23.         const string_fileName = “latestpost.png”;  
  24.         personal  
  25.         const string_blobContainerName = “github”;  
  26.         [FunctionName(“GetLatestPosts”)]  
  27.         public async TaskRun([TimerTrigger(“0 0 */1 * * *”)] TimerInfomyTimer, ILoggerlog) {  
  28.             strive {  
  29.                 _logger = log;  
  30.                 await UplaodImageToStorage();  
  31.             } catch (System.Exceptionex) {  
  32.                 log.LogError($ “One thing went improper: {ex}”);  
  33.                 throwex;  
  34.             }  
  35.         }  
  36.         personal static async Job < bool > UplaodImageToStorage() {  
  37.             strive {  
  38.                 var base String = WriteOnImage(GetLatestFeeds());  
  39.                 string convert = baseString.Exchange(“knowledge:picture/png;base64,”, String.Empty);  
  40.                 var bytes = Convert.FromBase64String(convert);  
  41.                 var stream = newMemoryStream(bytes);  
  42.                 if (CloudStorageAccount.TryParse(Surroundings.GetEnvironmentVariable(“AzureWebJobsStorage”), outCloudStorageAccountcloudStorageAccount)) {  
  43.                     var cloud BlobClient = cloud StorageAccount.CreateCloudBlobClient();  
  44.                     var cloud BlobContainer = cloud BlobClient.GetContainerReference(_blobContainerName);  
  45.                     var cloud BlockBlob = cloud BlobContainer.GetBlockBlobReference(_fileName);  
  46.                     cloud BlockBlob.Properties.ContentType = “picture/png”;  
  47.                     await cloud BlockBlob.UploadFromStreamAsync(stream);  
  48.                     _logger.LogInformation(“Uploaded new picture”);  
  49.                 } else {  
  50.                     _logger.LogError(“Error in connection”);  
  51.                 }  
  52.             } catch (Exceptionex) {  
  53.                 _logger.LogError(ex.Message);  
  54.             }  
  55.             return false;  
  56.         }  
  57.         personal static string WriteOnImage(IEnumerable < SyndicationItem > feedItems) {  
  58.             var titles = string.Be a part of(“, “, feedItems.Choose(s => s.Title.Textual content).ToList());  
  59.             utilizing  
  60.             var img = new Picture < Rgba32 > (Configuration.ImageWidth, Configuration.ImageHeight);  
  61.             var font = SystemFonts.CreateFont(Configuration.Font, Configuration.FontSize);  
  62.             img.Mutate(ctx => ctx.ApplyScalingWaterMark(font, titles, Shade.Black, 5, true));  
  63.             return img.ToBase64String(PngFormat.Occasion);  
  64.         }  
  65.         public static IEnumerable < SyndicationItem > GetLatestFeeds() {  
  66.             var reader = XmlReader.Create(Configuration.BlogLink);  
  67.             var feed = SyndicationFeed.Load(reader);  
  68.             reader.Shut();  
  69.             return feed.Gadgets.Take(5);  
  70.         }  
  71.     }  
  72. }  

Supply Code

 

Please be happy to take a look at the repositories right here:

  • https://github.com/SibeeshVenu/GitHubFuncs
  • https://github.com/SibeeshVenu/sibeeshvenu

Your flip. What do you suppose?

 

Thanks so much for studying. Did I miss something that you could be suppose is required on this article? Did you discover this submit helpful? Please don’t forget to share your suggestions!

Show More

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button