Search code examples
c#asp.netrepeaterflickr

FlickrNet API - Get set name from PhotosSearch


I'm using the FlickrNet c# library that so far is proving a massive hit.

However, I've got one problem. I can get all photos for a user id but I can't get the set name that a specific photo belongs to without doing another api call. This separate call is giving me massive performance issues. The homepage takes 30 seconds to load 40 images. This will only increase.

I need to get the set name for each photo as I'm using isotope to display the images.

I'm simply grabbing the images from the api and binding them to a repeater.

Here's my code.

C#

Flickr f = FlickrManager.GetAuthInstance();
    protected void Page_Load(object sender, EventArgs e)
    {
        string userID = f.PeopleFindByEmail("me@yahoo.com").UserId;

        PhotoSearchOptions options = new PhotoSearchOptions
                                         {
                                             UserId = userID,
                                             Extras = PhotoSearchExtras.AllUrls | PhotoSearchExtras.Description | PhotoSearchExtras.Tags,
                                             SortOrder = PhotoSearchSortOrder.Relevance,
                                         };

        var photos = f.PhotosSearch(options);

        rptPhotos.DataSource = photos;
        rptPhotos.DataBind();
    }

    protected string GetSetNameForImageID(string imageID)
    {
        var sets = f.PhotosGetAllContexts(imageID).Sets;
        return sets[0].Title.ToLower().Replace(" ", "-");            
    }

HTML

<asp:Repeater runat="server" ID="rptPhotos">
    <ItemTemplate>
        <section class="<%# GetSetNameForImageID( Convert.ToString( Eval("PhotoID") ) ) %> item">
        <%--<a href="@Url.Action("Image", "Home", new {id = item.PhotoId})">--%>
        <a href="/View.aspx?pid=<%# DataBinder.Eval(Container.DataItem, "PhotoID") %>">
            <div>
                <div class="item_hover">
                    <header>         
                        <span>D</span>
                        <%--<p title="@item.Description" class="tiptip">_</p>  --%>
                        <p title="<%# DataBinder.Eval(Container.DataItem, "Description") %>" class="tiptip">_</p>  
                        <hgroup>
                            <%--<h2>@item.Title</h2>
                            <h3>@item.Tags[0]</h3>--%>

                            <h2><%# DataBinder.Eval(Container.DataItem, "Title") %></h2>
                            <h3><%# DataBinder.Eval(Container.DataItem, "Tags[0]") %></h3>
                        </hgroup>
                    </header>
                </div>
                <%--<img src="@item.Small320Url" alt="Video sit amet consectetur" />--%>
                <img src="<%# DataBinder.Eval(Container.DataItem, "Small320Url") %>" alt="Video sit amet consectetur" />
            </div>
        </a>
    </section>
    </ItemTemplate>
</asp:Repeater>

Is there a quicker way of getting the set name for each image without the GetSetNameForImageID and subsequent api call?


Solution

  • One thing I noticed about the PhotosGetAllContexts is that the Sets property you are using is a collection of ContextSet objects, which in turn store a PhotoSetId and a Title.

    What about combining the PhotosetsGetList and PhotosetsGetPhotos methods? I think you could use these two to avoid the overhead you are currently experiencing with the PhotosGetAllContexts method.

    Disclaimer: not tested code.

    var photoSets = f.PhotosetsGetList(userId);
    Dictionary<string, List<Photo>> photoSetPhotoMap = new Dictionary<string, List<Photo>>();
    
    foreach (var photoSet in photoSets)
    {
        var photoSetPhotos = f.PhotosetsGetPhotos(photoSet.PhotosetId,
            PhotoSearchExtras.AllUrls | PhotoSearchExtras.Description | PhotoSearchExtras.Tags);
    
        photoSetPhotoMap.Add(photoSet.PhotosetId, photoSetPhotos.ToList());
    }
    
    var photos =
        from kvp in photoSetPhotoMap
        from photo in kvp.Value
        select new
        {
            SetTitle = kvp.Key, PhotoId = photo.PhotoId, Description = photo.Description,
            PhotoTitle = photo.Title, Tags = photo.Tags[0], Small320Url = photo.Small320Url
        };
    
    rptPhotos.DataSource = photos;
    rptPhotos.DataBind();
    

    I think the main difficulty you will have with this approach is implementing paging effectively - depending on the size of a photoset (you can determine this by the NumberOfPhotos property) you will likely run across scenarios where a page cuts off halfway through a photoset.

    To solve this I would suggest using the NumberOfPhotos property to calculate the total number of photos and then using your page size multiplied by the page number to figure out how many and which PhotoSets you need to get to fulfill the request.