/* * PS3 Media Server, for streaming any medias to your PS3. * Copyright (C) 2008 A.Brochard * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; version 2 * of the License only. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package net.pms.network; import net.pms.PMS; import net.pms.configuration.RendererConfiguration; import net.pms.dlna.DLNAResource; import net.pms.formats.Format; import net.pms.util.PropertiesUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.net.Authenticator; import java.net.URL; import java.net.URLConnection; import static net.pms.util.StringUtil.convertURLToFileName; /** * Implements any item that can be transfered through the HTTP pipes. * In the PMS case, this item represents media files. * @see DLNAResource */ public class HTTPResource { private static final Logger logger = LoggerFactory.getLogger(HTTPResource.class); public static final String UNKNOWN_VIDEO_TYPEMIME = "video/mpeg"; public static final String UNKNOWN_IMAGE_TYPEMIME = "image/jpeg"; public static final String UNKNOWN_AUDIO_TYPEMIME = "audio/mpeg"; public static final String AUDIO_MP3_TYPEMIME = "audio/mpeg"; public static final String AUDIO_MP4_TYPEMIME = "audio/x-m4a"; public static final String AUDIO_WAV_TYPEMIME = "audio/wav"; public static final String AUDIO_WMA_TYPEMIME = "audio/x-ms-wma"; public static final String AUDIO_FLAC_TYPEMIME = "audio/x-flac"; public static final String AUDIO_OGG_TYPEMIME = "audio/x-ogg"; public static final String AUDIO_LPCM_TYPEMIME = "audio/L16"; public static final String MPEG_TYPEMIME = "video/mpeg"; public static final String MP4_TYPEMIME = "video/mp4"; public static final String AVI_TYPEMIME = "video/avi"; public static final String WMV_TYPEMIME = "video/x-ms-wmv"; public static final String ASF_TYPEMIME = "video/x-ms-asf"; public static final String MATROSKA_TYPEMIME = "video/x-matroska"; public static final String VIDEO_TRANSCODE = "video/transcode"; public static final String AUDIO_TRANSCODE = "audio/transcode"; public static final String PNG_TYPEMIME = "image/png"; public static final String JPEG_TYPEMIME = "image/jpeg"; public static final String TIFF_TYPEMIME = "image/tiff"; public static final String GIF_TYPEMIME = "image/gif"; public static final String BMP_TYPEMIME = "image/bmp"; public HTTPResource() { } /** * Returns for a given item type the default MIME type associated. This is used in the HTTP transfers * as in the client might do different things for different MIME types. * @param type Type for which the default MIME type is needed. * @return Default MIME associated with the file type. */ public static String getDefaultMimeType(int type) { String mimeType = HTTPResource.UNKNOWN_VIDEO_TYPEMIME; if (type == Format.VIDEO) { mimeType = HTTPResource.UNKNOWN_VIDEO_TYPEMIME; } else if (type == Format.IMAGE) { mimeType = HTTPResource.UNKNOWN_IMAGE_TYPEMIME; } else if (type == Format.AUDIO) { mimeType = HTTPResource.UNKNOWN_AUDIO_TYPEMIME; } return mimeType; } /** * Returns a InputStream associated with the fileName. * @param fileName TODO Absolute or relative file path. * @return If found, an InputStream associated with the fileName. null otherwise. */ protected InputStream getResourceInputStream(String fileName) { fileName = "/resources/" + fileName; ClassLoader cll = this.getClass().getClassLoader(); InputStream is = cll.getResourceAsStream(fileName.substring(1)); while (is == null && cll.getParent() != null) { cll = cll.getParent(); is = cll.getResourceAsStream(fileName.substring(1)); } return is; } /** * Creates an InputStream based on a URL. This is used while accessing external resources * like online radio stations. * @param u URL. * @param saveOnDisk If true, the file is first downloaded to the temporary folder. * @return InputStream that can be used for sending to the media renderer. * @throws IOException * @see #downloadAndSendBinary(String) */ protected static InputStream downloadAndSend(String u, boolean saveOnDisk) throws IOException { URL url = new URL(u); File f = null; if (saveOnDisk) { String host = url.getHost(); String hostName = convertURLToFileName(host); String fileName = url.getFile(); fileName = convertURLToFileName(fileName); File hostDir = new File(PMS.getConfiguration().getTempFolder(), hostName); if (!hostDir.isDirectory()) { if (!hostDir.mkdir()) { logger.debug("Cannot create directory: {}", hostDir.getAbsolutePath()); } } f = new File(hostDir, fileName); if (f.exists()) { return new FileInputStream(f); } } byte[] content = downloadAndSendBinary(u, saveOnDisk, f); return new ByteArrayInputStream(content); } /** * Overloaded method for {@link #downloadAndSendBinary(String, boolean, File)}, without storing a file on the filesystem. * @param u URL to retrieve. * @return byte array. * @throws IOException */ protected static byte[] downloadAndSendBinary(String u) throws IOException { return downloadAndSendBinary(u, false, null); } /** * Returns a byte array representation of the file given by the URL. The file is downloaded and optionally stored on the filesystem. * @param u URL to retrieve. * @param saveOnDisk If true, store the file on the filesystem. * @param f If saveOnDisk is true, then store the contents of the file represented by u in the associated File. f needs to be opened before * calling this function. * @return The byte array * @throws IOException */ protected static byte[] downloadAndSendBinary(String u, boolean saveOnDisk, File f) throws IOException { URL url = new URL(u); // The URL may contain user authentication information Authenticator.setDefault(new HTTPResourceAuthenticator()); HTTPResourceAuthenticator.addURL(url); logger.debug("Retrieving " + url.toString()); ByteArrayOutputStream bytes = new ByteArrayOutputStream(); URLConnection conn = url.openConnection(); // GameTrailers blocks user-agents that identify themselves as "Java" conn.setRequestProperty("User-agent", PropertiesUtil.getProjectProperties().get("project.name") + " " + PMS.getVersion()); InputStream in = conn.getInputStream(); FileOutputStream fOUT = null; if (saveOnDisk && f != null) { // fileName = convertURLToFileName(fileName); fOUT = new FileOutputStream(f); } byte[] buf = new byte[4096]; int n = -1; while ((n = in.read(buf)) > -1) { bytes.write(buf, 0, n); if (fOUT != null) { fOUT.write(buf, 0, n); } } in.close(); if (fOUT != null) { fOUT.close(); } return bytes.toByteArray(); } /** * Returns the supplied MIME type customized for the supplied media renderer according to the renderer's aliasing rules. * @param mimetype MIME type to customize. * @param renderer media renderer to customize the MIME type for. * @return The MIME type */ public String getRendererMimeType(String mimetype, RendererConfiguration renderer) { return renderer.getMimeType(mimetype); } public int getDLNALocalesCount() { return 3; } public final String getMPEG_PS_PALLocalizedValue(int index) { if (index == 1 || index == 2) { return "MPEG_PS_NTSC"; } return "MPEG_PS_PAL"; } public final String getMPEG_TS_SD_EU_ISOLocalizedValue(int index) { if (index == 1) { return "MPEG_TS_SD_NA_ISO"; } if (index == 2) { return "MPEG_TS_SD_JP_ISO"; } return "MPEG_TS_SD_EU_ISO"; } public final String getMPEG_TS_SD_EULocalizedValue(int index) { if (index == 1) { return "MPEG_TS_SD_NA"; } if (index == 2) { return "MPEG_TS_SD_JP"; } return "MPEG_TS_SD_EU"; } }