BCR.BCR.GetPageImage C# (CSharp) Method

GetPageImage() public static method

public static GetPageImage ( System.Guid id, int page, int width, int height, IResponseFormatter response ) : Response
id System.Guid
page int
width int
height int
response IResponseFormatter
return Nancy.Response
        public static Response GetPageImage(Guid id, int page, int width, int height, IResponseFormatter response)
        {
          // Restrict access to the FreeImage library to one thread at a time.
          lock(lockThis)
          {
            int max_width = 0;
            int max_height = 0;
            bool thumbnail = !(width == -1 && height == -1);
            bool processed = false;
            
            string filename = string.Format("{0}-p{1}-w{2}-h{3}.jpg", id, page, width, height);
            
            if (thumbnail)
            {
              MemoryStream cachestream = ImageCache.Instance.LoadFromCache(filename, true);
              // Cached thumbnails are assumed to be in the correct format and adhere to the size/format restrictions of the ipad.
              if (cachestream != null)
                return response.FromStream(cachestream, MimeTypes.GetMimeType(".jpg"));
            }
            else
            {
              // Check if a processed (rescaled and/or progressive) image is cached.
              string processed_filename = string.Format("{0}-p{1}-processed.jpg", id, page);
              MemoryStream cachestream = ImageCache.Instance.LoadFromCache(processed_filename, false);
              if (cachestream != null)
                return response.FromStream(cachestream, MimeTypes.GetMimeType(".jpg"));
            }

            MemoryStream stream = null;
            
            // Check if original image is in the cache.
            string org_filename = string.Format("{0}-p{1}.jpg", id, page);
            stream = ImageCache.Instance.LoadFromCache(org_filename, false);
              
            if (stream == null)
            {
              // Image is not in the cache, get it via ComicRack.
              var bytes = GetPageImageBytes(id, page);
              if (bytes == null)
              {
                return HttpStatusCode.NotFound;
              }
                
              stream = new MemoryStream(bytes);
                
              // Always save the original page to the cache
              ImageCache.Instance.SaveToCache(org_filename, stream, false);
            }
                        
            stream.Seek(0, SeekOrigin.Begin);

            #if USE_GDI
            
              Bitmap bitmap = new Bitmap(stream, false);
              int bitmap_width = (int)bitmap.Width;
              int bitmap_height = (int)bitmap.Height;
              
            #elif USE_DIB
            
              FIBITMAP dib = FreeImage.LoadFromStream(stream);
              if (dib == null)
              {
                Console.WriteLine("Loading bitmap failed. Aborting.");
                // Check whether there was an error message.
                return HttpStatusCode.InternalServerError;
              }
              int bitmap_width = (int)FreeImage.GetWidth(dib);
              int bitmap_height = (int)FreeImage.GetHeight(dib);
            
            #elif USE_FIB
            
              FreeImageBitmap fib = FreeImageBitmap.FromStream(stream, false);
              if (fib == null)
              {
                Console.WriteLine("Loading bitmap failed. Aborting.");
                // Check whether there was an error message.
                return HttpStatusCode.InternalServerError;
              }
                                      
              int bitmap_width = (int)fib.Width;
              int bitmap_height = (int)fib.Height;
            #endif
            
            if (ImageCache.Instance.use_max_dimension)
            {
              int mw, mh;
              
              if (bitmap_width >= bitmap_height)
              {
                mw = ImageCache.Instance.max_dimension_long;
                mh = ImageCache.Instance.max_dimension_short;
              }
              else
              {
                mw = ImageCache.Instance.max_dimension_short;
                mh = ImageCache.Instance.max_dimension_long;
              }
              
              if (bitmap_width > mw || bitmap_height > mh)
              {
                double scaleW = (double)mw / (double)bitmap_width;
                double scaleH = (double)mh / (double)bitmap_height;
                double scale = Math.Min(scaleW, scaleH);
                
                max_width = (int)Math.Floor(scale * bitmap_width);
                max_height = (int)Math.Floor(scale * bitmap_height);
              }
              else
              {
                max_width = bitmap_width;
                max_height = bitmap_height;
              }
            }
            else            
            // Check if the image dimensions exceeds the maximum image dimensions
            if ((bitmap_width * bitmap_height) > ImageCache.Instance.maximum_imagesize)
            {
              max_width = (int)Math.Floor(Math.Sqrt((double)bitmap_width / (double)bitmap_height * (double)ImageCache.Instance.maximum_imagesize));
              max_height = (int)Math.Floor((double)max_width * (double)bitmap_height / (double)bitmap_width);
            }
            else
            {
              max_width = bitmap_width;
              max_height = bitmap_height;
            }
                        
            // Calculate the dimensions of the returned image.
            int result_width = width;
            int result_height = height;
            
            if (result_width == -1 && result_height == -1)
            {
              result_width = max_width;
              result_height = max_height;
            }
            else
            {
              if (result_width == -1)
              {
                result_height = Math.Min(max_height, result_height);
                double ratio = (double)result_height / (double)max_height;
                result_width = (int)Math.Floor(((double)max_width * ratio));
              }
              else
              if (result_height == -1)
              {
                result_width = Math.Min(max_width, result_width);
                double ratio = (double)result_width / (double)max_width;
                result_height = (int)Math.Floor(((double)max_height * ratio));
              }
            }
            
            // TODO: do this per requesting target device instead of using one global setting.
            
            // Resize ?
            if (result_width != bitmap_width || result_height != bitmap_height)
            {
                processed = true;
                
              #if USE_DIB || USE_FIB
                //FREE_IMAGE_FILTER resizer = FREE_IMAGE_FILTER.FILTER_BICUBIC;
                FREE_IMAGE_FILTER resizer = FREE_IMAGE_FILTER.FILTER_LANCZOS3;
                
                #if USE_FIB
                  fib.Rescale(result_width, result_height, resizer);
                #else
                              
                  FIBITMAP newdib = FreeImage.Rescale(dib, result_width, result_height, resizer);
                  if (!newdib.IsNull)
                  {
                    FreeImage.Unload(dib);
                    dib.SetNull();
                    dib = newdib;
                  }
                #endif
              #elif USE_GDI
                Bitmap resizedBitmap = Resize(bitmap, result_width, result_height);
                bitmap.Dispose();
                bitmap = resizedBitmap;
                resizedBitmap = null;
              #endif
            }
            
            
            // Check if the image must be converted to progressive jpeg
            if (ImageCache.Instance.use_progressive_jpeg && (result_width * result_height) >= ImageCache.Instance.progressive_jpeg_size_threshold)
            {
              processed = true;
              
              // Convert image to progressive jpeg
              
              // FreeImage source code reveals that lower 7 bits of the FREE_IMAGE_SAVE_FLAGS enum are used for low-level quality control.
              FREE_IMAGE_SAVE_FLAGS quality = (FREE_IMAGE_SAVE_FLAGS)ImageCache.Instance.progressive_jpeg_quality;
              FREE_IMAGE_SAVE_FLAGS flags = FREE_IMAGE_SAVE_FLAGS.JPEG_SUBSAMPLING_444 | FREE_IMAGE_SAVE_FLAGS.JPEG_PROGRESSIVE | quality;

              #if USE_DIB || USE_FIB
                
                stream.Dispose();
                stream = new MemoryStream();
                
                #if USE_FIB
                
                  fib.Save(stream, FREE_IMAGE_FORMAT.FIF_JPEG, flags);
                  fib.Dispose();
                  
                #else
                
                  FreeImage.SaveToStream(dib, stream, FREE_IMAGE_FORMAT.FIF_JPEG, flags);
                  FreeImage.Unload(dib);
                  dib.SetNull();
                 
                #endif
                
              #else
                FIBITMAP dib = FreeImage.CreateFromBitmap(bitmap);
                bitmap.Dispose();
                bitmap = null;
                stream.Dispose();
                stream = new MemoryStream();
                
                FreeImage.SaveToStream(dib, stream, FREE_IMAGE_FORMAT.FIF_JPEG, flags);
                FreeImage.Unload(dib);
                dib.SetNull();
                
              #endif              
            }
            else
            if (processed) 
            {
              // image was rescaled, make new stream with rescaled bitmap
              
              #if USE_DIB || USE_FIB
              
                FREE_IMAGE_SAVE_FLAGS flags = FREE_IMAGE_SAVE_FLAGS.JPEG_SUBSAMPLING_444 | FREE_IMAGE_SAVE_FLAGS.JPEG_OPTIMIZE | FREE_IMAGE_SAVE_FLAGS.JPEG_QUALITYNORMAL;
                
                stream.Dispose();  
                stream = new MemoryStream();
                
                #if USE_FIB
                  fib.Save(stream, FREE_IMAGE_FORMAT.FIF_JPEG, flags);
                  fib.Dispose();
                #else
                  FreeImage.SaveToStream(dib, stream, FREE_IMAGE_FORMAT.FIF_JPEG, flags);
                  FreeImage.Unload(dib);
                  dib.SetNull();
                #endif
              #else
              
                stream = GetBytesFromImage(bitmap);
   
              #endif           
              // For now, images that were resized because they exceeded the maximum dimensions are not saved to the cache.
            }
            
            #if USE_DIB
              FreeImage.Unload(dib);
              dib.SetNull();
            #elif USE_FIB
              fib.Dispose();
            #elif USE_GDI

            if (bitmap != null)
            {
              bitmap.Dispose();
              bitmap = null;
            }

            #endif
            
            // Always save thumbnails to the cache
            if (thumbnail)
            {
              ImageCache.Instance.SaveToCache(filename, stream, true);
            }
            else
            if (processed)
            {
              // Store rescaled and/or progressive jpegs in the cache for now.
              string processed_filename = string.Format("{0}-p{1}-processed.jpg", id, page);
              ImageCache.Instance.SaveToCache(processed_filename, stream, false);
            }
            
            stream.Seek(0, SeekOrigin.Begin);
            return response.FromStream(stream, MimeTypes.GetMimeType(".jpg"));
          }
        }
        

Usage Example

Ejemplo n.º 1
0
        public BCRModule()
            : base(Database.Instance.GlobalSettings.url_base + "/BCR")
        {
            // The user must be authenticated in order to use the BCR API.
            this.RequiresAuthentication();

            Get["/"] = x => { return(Response.AsText("Authentication OK")); };


            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Retrieve a list of all (smart)lists.
            Get["/Lists"] = x => {
                try
                {
                    //var user = (BCRUser)this.Context.CurrentUser;
                    //Gui guid = user.GetHomeList();
                    //ComicListItem item = Program.Database.ComicLists.GetItems<ComicListItem>(false).FirstOrDefault((ComicListItem cli) => cli.Id == s);

                    int depth = Request.Query.depth.HasValue ? int.Parse(Request.Query.depth) : -1;
                    return(Response.AsOData(Program.Database.ComicLists.Select(c => c.ToComicList(depth))));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };


            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Retrieve the contents of the specified list.
            Get["/Lists/{id}"] = x => {
                try
                {
                    int depth = Request.Query.depth.HasValue ? int.Parse(Request.Query.depth) : -1;
                    IEnumerable <ComicList> list = Program.Database.ComicLists.Where(c => c.Id == new Guid(x.id)).Select(c => c.ToComicList(depth));
                    if (list.Count() == 0)
                    {
                        return(Response.AsError(HttpStatusCode.NotFound, "List not found", Request));
                    }

                    return(Response.AsOData(list));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };


            ///////////////////////////////////////////////////////////////////////////////////////////////
            // For OData compatibility, count should be $count, but I don't know how to parse the $ with Nancy....
            Get["/Lists/{id}/Comics/count"] = x => {
                try
                {
                    BCRUser user       = (BCRUser)this.Context.CurrentUser;
                    int     totalCount = 0;
                    return(Response.AsText(Context.ApplyODataUriFilter(BCR.GetComicsForList(user, new Guid(x.id)), ref totalCount).Count().ToString()));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };


            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Return the comics of the specified list using OData to filter the comic properties and the list paging.
            Get["/Lists/{id}/Comics"] = x => {
                try
                {
                    BCRUser user = (BCRUser)this.Context.CurrentUser;

                    var rawcomics = BCR.GetComicsForList(user, new Guid(x.id));
                    int propCount = rawcomics.Count();
                    var result    = new { totalCount = propCount, items = rawcomics };
                    return(Response.AsJson(result, HttpStatusCode.OK));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };

            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Return the Library Totals.
            Get["/Totals"] = x => {
                try
                {
                    BCRUser user            = (BCRUser)this.Context.CurrentUser;
                    var     comics          = BCR.GetComics().Select(c => c.ToComic(user));
                    var     series          = BCR.GetSeries();
                    var     publishers      = BCR.GetPublishers();
                    int     issuesCount     = comics.Count();
                    int     seriesCount     = series.Count();
                    int     publishersCount = publishers.Count();
                    var     result          = new { issues = issuesCount, series = seriesCount, publishers = publishersCount };
                    return(Response.AsJson(result, HttpStatusCode.OK));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };

            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Returns a list of all the comics as comic excerpts
            Get["/Comics"] = x => {
                try
                {
                    BCRUser user      = (BCRUser)this.Context.CurrentUser;
                    var     comics    = BCR.GetComics().Select(c => c.ToComic(user));
                    int     propCount = comics.Count();
                    var     result    = new { totalCount = propCount, items = comics };
                    return(Response.AsJson(result, HttpStatusCode.OK));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };


            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Return the comicbook info as an OData filtered bag of properties.
            Get["/Comics/{id}"] = x => {
                try
                {
                    BCRUser user  = (BCRUser)this.Context.CurrentUser;
                    Comic   comic = BCR.GetComic(user, new Guid(x.id));
                    if (comic == null)
                    {
                        return(Response.AsError(HttpStatusCode.NotFound, "Comic not found", Request));
                    }

                    return(Response.AsOData(new List <Comic> {
                        comic
                    }));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };


            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Retrieve the specified page as a jpg file with the specified dimensions.
            Get["/Comics/{id}/Pages/{page}"] = x => {
                try
                {
                    int width  = Request.Query.width.HasValue ? int.Parse(Request.Query.width) : -1;
                    int height = Request.Query.height.HasValue ? int.Parse(Request.Query.height) : -1;

                    int maxWidth  = Request.Query.maxWidth.HasValue ? int.Parse(Request.Query.maxWidth) : -1;
                    int maxHeight = Request.Query.maxHeight.HasValue ? int.Parse(Request.Query.maxHeight) : -1;

                    return(BCR.GetPageImage(new Guid(x.id), int.Parse(x.page), width, height, Response));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };


            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Retrieve the original size (in pixels) of the requested page.
            Get["/Comics/{id}/Pages/{page}/size"] = x => {
                try
                {
                    int width  = 0;
                    int height = 0;
                    BCR.GetPageImageSize(new Guid(x.id), int.Parse(x.page), ref width, ref height);
                    return(Response.AsJson(new { width = width, height = height }, HttpStatusCode.OK));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };

            Get["/Comics/{id}/pagesizes"] = x => {
                try
                {
                    //   int width = 0;
                    //     int height = 0;
                    //  int pageCnt = 0;
                    //      List<PageSizes> pagesizes = new List<PageSizes>();
                    //    BCRUser user = (BCRUser)this.Context.CurrentUser;
                    //      Comic comic = BCR.GetComic(user, new Guid(x.id));
                    var pages = BCR.GetPagesInfo(new Guid(x.id));
                    if (pages == null)
                    {
                        return(Response.AsError(HttpStatusCode.NotFound, "Comic not found", Request));
                    }

                    // pageCnt = comic.PageCount;
                    //  for (int i = 0; i < pageCnt; i++)
                    // {
                    //BCR.GetPageImageSize(new Guid(x.id), i, ref width, ref height);
                    //pagesizes.Add(new PageSizes { pageNbr = i, height = height, width = width, ratio = width / height });
                    // }

                    return(Response.AsJson(pages, HttpStatusCode.OK));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };

            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Get one property.

            /*
             * Get["/Comics/{id}/{property}"] = x => {
             * try
             * {
             * Comic comic = BCR.GetComic(new Guid(x.id));
             * if (comic == null)
             * {
             *  return Response.AsError(HttpStatusCode.NotFound, "Comic not found", Request);
             * }
             *
             * PropertyInfo property = comic.GetType().GetProperty(x.property);
             * object value = property.GetValue(comic, null);
             *
             * return Response.AsJson(value);
             * }
             * catch(Exception e)
             * {
             *  return Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request);
             * }
             * };
             */


            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Update properties of the specified comicbook.

            /*
             * Put["/Comics/{id}"] = x => {
             * try
             * {
             * // Get the ComicBook entry from the library, so we can change it.
             * ComicBook book = BCR.GetComicBook(new Guid(x.id));
             * if (book == null)
             * {
             *  return Response.AsError(HttpStatusCode.NotFound, "Comic not found", Request);
             * }
             *
             * // Convert form values to temporary ComicBook object.
             * ComicBook info = this.Bind<ComicBook>();
             *
             * IEnumerable<string> keys = Request.Form.GetDynamicMemberNames();
             *
             * // This also triggers the update of the ComicRack application.
             * book.CopyDataFrom(info, keys);
             *
             * return HttpStatusCode.OK;
             * }
             * catch(Exception e)
             * {
             *  return Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request);
             * }
             * };
             */

            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Update properties of the specified comicbook for the current user
            Post["/Comics/{id}/Progress"] = x => {
                try
                {
                    // Check if the comic exists.


                    Guid      comicId = new Guid(x.id);
                    ComicBook book    = BCR.GetComics().FirstOrDefault(comic => comic.Id == comicId);
                    if (book == null)
                    {
                        return(Response.AsError(HttpStatusCode.NotFound, "Comic not found", Request));
                    }

                    BCRUser user = (BCRUser)this.Context.CurrentUser;
                    user.UpdateComicProgress(book, int.Parse(this.Request.Form.CurrentPage));
                    //if using multiple users do we update the master file with a users progress?
                    //book.SetValue("CurrentPage", int.Parse(this.Request.Form.CurrentPage));
                    return(HttpStatusCode.OK);
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };

            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Update one property

            /*
             * Put["/Comics/{id}/{property}"] = x => {
             * try
             * {
             * // Convert form values to temporary Comic object.
             * string info = this.Bind<string>();
             *
             *
             * // Now get the ComicBook entry from the library, so we can change it.
             * ComicBook book = BCR.GetComicBook(x.id);
             * if (book == null)
             * {
             *  return Response.AsError(HttpStatusCode.NotFound, "Comic not found", Request);
             * }
             *
             * // Setting one of these values also triggers the update of the ComicRack application.
             * book.SetValue(x.property, info);
             *
             *
             * return HttpStatusCode.OK;
             * }
             * catch(Exception e)
             * {
             *  return Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request);
             * }
             * };
             */


            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Get the BCR settings.
            Get["/Settings"] = x => {
                try
                {
                    var user = (BCRUser)this.Context.CurrentUser;
                    return(Response.AsJson(user.GetSettings(), HttpStatusCode.OK));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };


            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Update the BCR settings.
            Put["/Settings"] = x => {
                try
                {
                    var user = (BCRUser)this.Context.CurrentUser;
                    user.UpdateSettings(this.Bind <UserSettings>());

                    return(HttpStatusCode.OK);
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };

            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Get a list of series
            Get["/Series"] = x => {
                try
                {
                    var user      = (BCRUser)this.Context.CurrentUser;
                    var series    = BCR.GetSeriesList();
                    int propCount = series.Count();
                    var result    = new { totalCount = propCount, items = series };
                    return(Response.AsJson(result, HttpStatusCode.OK));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };
            // Get a list of series added in the last 2 days
            Get["/Series/Recent/{days}"] = x => {
                try
                {
                    var user      = (BCRUser)this.Context.CurrentUser;
                    int days      = x.days;
                    var series    = BCR.GetMostRecentlyAdded(user, days);
                    int propCount = series.Count();
                    var result    = new { totalCount = propCount, items = series };
                    return(Response.AsJson(result, HttpStatusCode.OK));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };
            // Get a list of series Read in the last 2 days
            Get["/Series/RecentlyRead/{days}"] = x => {
                try
                {
                    var user      = (BCRUser)this.Context.CurrentUser;
                    int days      = x.days;
                    var series    = BCR.GetMostRecentlyRead(user, days);
                    int propCount = series.Count();
                    var result    = new { totalCount = propCount, items = series };
                    return(Response.AsJson(result, HttpStatusCode.OK));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };
            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Retrieve a list of all comics in the specified list
            Get["/Series/{id}"] = x => {
                try
                {
                    var user      = (BCRUser)this.Context.CurrentUser;
                    var series    = BCR.GetComicsFromSeries(user, new Guid(x.id));
                    int propCount = series.Count();
                    var result    = new { totalCount = propCount, items = series };
                    return(Response.AsJson(result, HttpStatusCode.OK));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };


            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Retrieve the number of comics in the specified list
            Get["/Series/{id}/count"] = x => {
                try
                {
                    var user       = (BCRUser)this.Context.CurrentUser;
                    int totalCount = 0;
                    return(Response.AsText(Context.ApplyODataUriFilter(BCR.GetComicsFromSeries(user, new Guid(x.id)), ref totalCount).Count().ToString()));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };


            ///////////////////////////////////////////////////////////////////////////////////////////////
            //
            Get["/Series/{id}/Volumes"] = x => {
                try
                {
                    return(Response.AsOData(BCR.GetVolumesFromSeries(new Guid(x.id)), HttpStatusCode.OK));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };


            ///////////////////////////////////////////////////////////////////////////////////////////////
            //
            Get["/Series/{id}/Volumes/{volume}"] = x => {
                try
                {
                    BCRUser user   = (BCRUser)this.Context.CurrentUser;
                    int     volume = int.Parse(x.volume);
                    var     comics = BCR.GetComicsFromSeriesVolume(user, new Guid(x.id), volume);
                    return(Response.AsOData(comics, HttpStatusCode.OK));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };


            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Get a list of publishers
            Get["/Publishers"] = x => {
                try
                {
                    var publishers = BCR.GetPublishers();
                    int propCount  = publishers.Count();
                    var result     = new { totalCount = propCount, items = publishers };
                    return(Response.AsJson(result, HttpStatusCode.OK));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };

            Get["/Publishers/{publisher}/Imprint/{imprint}/"] = x => {
                try
                {
                    var user    = (BCRUser)this.Context.CurrentUser;
                    var pub     = x.publisher;
                    var imprint = x.imprint;
                    if (string.IsNullOrEmpty(imprint))
                    {
                        imprint = "";
                    }
                    var series = BCR.GetSeries(pub, imprint);
                    // int propCount = series.Count();
                    var result = new { items = series };
                    return(Response.AsJson(result, HttpStatusCode.OK));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };


            Get["/Ratings"] = x => {
                try
                {
                    var series    = BCR.GetAgeRatings();
                    int propCount = series.Count();
                    var result    = new { totalCount = propCount, items = series };
                    return(Response.AsJson(result, HttpStatusCode.OK));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };

            Get["/Rating/{rating}/"] = x => {
                try
                {
                    var    user   = (BCRUser)this.Context.CurrentUser;
                    string rating = x.rating;
                    // replace ~ with +
                    rating = rating.Replace('~', '+');
                    if (string.IsNullOrEmpty(rating))
                    {
                        rating = "";
                    }
                    var series    = BCR.GetSeriesByAgeRating(rating);
                    int propCount = series.Count();
                    var result    = new { totalCount = propCount, items = series };
                    return(Response.AsJson(result, HttpStatusCode.OK));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };

            ///////////////////////////////////////////////////////////////////////////////////////////////
            //
            Get["/Log"] = x => {
                try
                {
                    string severity = Request.Query.sev.HasValue ? Request.Query.sev : "";
                    string message  = Request.Query.msg.HasValue ? Request.Query.msg : "";

                    // TODO: write log entry to a file.

                    return(Response.AsRedirect("/tablet/resources/images/empty_1x1.png", RedirectResponse.RedirectType.Permanent));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };


            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Get the list of watched folders.
            Get["/WatchFolder"] = x => {
                try
                {
                    //return Response.AsOData(BCR.GetPublishers(), HttpStatusCode.OK);

                    var folders = Program.Database.WatchFolders as cYo.Projects.ComicRack.Engine.Database.WatchFolderCollection;

                    List <string> books = BCRExtensions.GetFolderBookList2(folders.Folders.First(), true);
                    return(Response.AsJson(books, HttpStatusCode.OK));

                    //return Response.AsRedirect("/tablet/resources/images/empty_1x1.png", RedirectResponse.RedirectType.Permanent);
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };


            ///////////////////////////////////////////////////////////////////////////////////////////////
            // Get list of all files in the folder
            Get["/WatchFolder/{folder}"] = x => {
                try
                {
                    return(Response.AsRedirect("/tablet/resources/images/empty_1x1.png", RedirectResponse.RedirectType.Permanent));
                }
                catch (Exception e)
                {
                    return(Response.AsError(HttpStatusCode.InternalServerError, e.ToString(), Request));
                }
            };
        }