1
2
3
4
5
6
7
8 package com.buckosoft.BuckoVidLib.web;
9
10 import java.awt.Graphics2D;
11 import java.awt.Image;
12 import java.awt.image.BufferedImage;
13 import java.io.IOException;
14 import java.io.OutputStream;
15 import java.net.URL;
16 import java.util.Iterator;
17
18 import javax.imageio.ImageIO;
19 import javax.imageio.ImageWriter;
20 import javax.imageio.stream.ImageOutputStream;
21 import javax.servlet.http.HttpServletRequest;
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.springframework.beans.factory.annotation.Autowired;
26 import org.springframework.stereotype.Controller;
27 import org.springframework.web.bind.annotation.PathVariable;
28 import org.springframework.web.bind.annotation.RequestMapping;
29
30 import com.buckosoft.BuckoVidLib.business.BuckoVidLib;
31 import com.buckosoft.BuckoVidLib.domain.TVSeason;
32 import com.buckosoft.BuckoVidLib.domain.VideoBase;
33 import com.buckosoft.BuckoVidLib.util.DomainConverter;
34
35
36
37
38
39 @Controller(value="poster")
40 @RequestMapping("/poster")
41 public class PosterController {
42 private final Log log = LogFactory.getLog(getClass());
43
44 @Autowired
45 private BuckoVidLib bvl;
46
47 private int defaultWidth = 150;
48 private int defaultHeight = 225;
49
50 @RequestMapping("/{key}")
51 public void handleRequest(@PathVariable("key") String key,
52 HttpServletRequest request,
53 OutputStream outputStream) throws Exception {
54 handleRequest(key, defaultWidth, defaultHeight, request, outputStream);
55 }
56
57 @RequestMapping("/{key}/{width}/{height}")
58 public void handleRequest(@PathVariable("key") String key,
59 @PathVariable("width") Integer w, @PathVariable("height") Integer h,
60 HttpServletRequest request,
61 OutputStream outputStream) {
62
63 VideoBase v;
64 TVSeason tvs;
65 String printedTitle = null;
66 String vurl;
67 String s;
68 boolean b = false;
69 if (request == null)
70 b = true;
71 else
72 b = bvl.isAllowRestricted(request);
73 v = bvl.getVideoBaseFromKey(DomainConverter.keyToInt(key), b);
74 if (v == null) {
75 tvs = bvl.getTVSeasonFromHashKey(DomainConverter.keyToInt(key));
76 if (tvs == null) {
77 s = "Video not found for key: " + key;
78 log.warn(s);
79 if (request == null)
80 throw new RuntimeException(s);
81 return;
82 } else {
83 printedTitle = tvs.getTitle();
84 vurl = bvl.getPlexUrl() + getPosterUrl(tvs.getPlexKey());
85 }
86 } else {
87 printedTitle = v.getTitle() + " (" + v.getYear() + ")";
88 vurl = bvl.getPlexUrl() + getPosterUrl(v.getPlexKey());
89 }
90 BufferedImage img;
91 try {
92 URL url = new URL(vurl);
93 img = ImageIO.read(url);
94 } catch (IOException e1) {
95 s = "Failed to read image for '" + printedTitle + "'";
96 log.warn(s);
97 log.warn("url was '" + vurl + "'");
98 if (request == null)
99 throw new RuntimeException(s, e1);
100 return;
101 }
102 log.info("Fetch poster for: " + printedTitle);
103 log.debug("original w/h: " + img.getWidth() + "/" + img.getHeight());
104
105 if (w > 1 && h > 1) {
106
107 int targetw;
108 int targeth;
109 double wp = (double)img.getWidth() / (double)w;
110 double hp = (double)img.getHeight() / (double)h;
111 log.debug("wp/hp: " + wp + " / " + hp);
112 if (hp < wp) {
113 targetw = (int)((double)img.getWidth() / hp);
114 if (targetw < w)
115 targetw = w;
116 targeth = h;
117 } else {
118 targeth = (int)((double)img.getHeight() / wp);
119 if (targeth < h)
120 targeth = h;
121 targetw = w;
122 }
123 log.debug("target w/h: " + targetw + "/" + targeth);
124 BufferedImage scaled = new BufferedImage(targetw, targeth, BufferedImage.TYPE_INT_BGR);
125 Graphics2D g;
126 g = scaled.createGraphics();
127 g.drawImage(img.getScaledInstance(targetw, targeth, Image.SCALE_SMOOTH), null, null);
128
129 img = scaled;
130 g.dispose();
131
132 int overw = img.getWidth() - w;
133 int overh = img.getHeight() - h;
134 int shiftw = overw/2;
135 int shifth = overh/2;
136 log.debug("final: over: " + overw + "/" + overh + " shift: " + shiftw + "/" + shifth);
137 img = img.getSubimage(shiftw, shifth, w-0, h-0);
138 }
139
140
141
142 ImageOutputStream ios;
143 try {
144 ios = ImageIO.createImageOutputStream(outputStream);
145 } catch (IOException e) {
146 s = "Failed to create image for writing from " + vurl + " : " + e.getMessage();
147 log.warn(s);
148 if (request == null)
149 throw new RuntimeException(s);
150 return;
151 }
152 Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
153 ImageWriter writer = (ImageWriter)writers.next();
154 writer.setOutput(ios);
155 try {
156 writer.write(img);
157 } catch (IOException e) {
158 s = "Failed to write image from " + vurl + " : " + e.getMessage();
159 log.warn(s);
160 log.warn("Try alternate...");
161 BufferedImage bi = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_BGR);
162 for (int y=0; y<img.getHeight(); y++) {
163 for (int x=0; x<img.getWidth(); x++) {
164 bi.setRGB(x, y, img.getRGB(x, y));
165 }
166 }
167 try {
168 writer.write(bi);
169 } catch (IOException e1) {
170 log.warn("That failed too", e1);
171 writers = ImageIO.getImageWritersByFormatName("png");
172 writer = (ImageWriter)writers.next();
173 writer.setOutput(ios);
174 try {
175 log.warn("Try png");
176 writer.write(img);
177 ios.close();
178 ios = null;
179
180 log.warn("png writing successful");
181 return;
182 } catch (IOException e2) {
183 log.warn("Writing as png failed too", e2);
184 if (request == null)
185 throw new RuntimeException(s);
186 return;
187 }
188 }
189 log.warn("Alternate jpg passed");
190 return;
191 } finally {
192 try {
193 if (ios != null)
194 ios.close();
195 } catch (IOException e) {
196 log.warn("finally tipped", e);
197 }
198 }
199 }
200
201 private String getPosterUrl(int plexKey) {
202 return(String.format("library/metadata/%d/thumb", plexKey));
203 }
204
205
206 }