/**
  * Render core video thumbnail HTML
  * @requestParam MediaTransformOutput thumb
  * @requestParam array options - See ThumbnailHelper class for more detail
  * @responseParam string width
  * @responseParam string height
  * @responseParam string linkHref
  * @responseParam array linkClasses
  * @responseParam string linkId
  * @responseParam array linkAttrs
  * @responseParam string imgSrc
  * @responseParam string mediaKey
  * @responseParam string mediaName
  * @responseParam array imgClass
  * @responseParam array extraImgAttrs
  * @responseParam string dataSrc - data-src attribute for image lazy loading
  * @responseParam string duration (HH:MM:SS)
  * @responseParam array durationISO
  * @responseParam string mediaType - 'image' | 'video'
  */
 public function video()
 {
     wfProfileIn(__METHOD__);
     $thumb = $this->getVal('thumb');
     $options = $this->getVal('options', []);
     ThumbnailHelper::setVideoLinkClasses($this, $thumb, $options);
     ThumbnailHelper::setVideoLinkAttribs($this, $thumb, $options);
     ThumbnailHelper::setVideoImgAttribs($this, $thumb, $options);
     ThumbnailHelper::setExtraImgAttribs($this, $options);
     ThumbnailHelper::setExtraLinkAttribs($this, $options);
     // Set duration
     // The file is not always an instance of a class with magic getters implemented. see VID-1753
     $file = $thumb->file;
     if (is_callable([$file, 'getMetadataDuration'])) {
         $duration = $file->getMetadataDuration();
     } else {
         $duration = null;
     }
     $this->response->setVal('duration', WikiaFileHelper::formatDuration($duration));
     $this->response->setVal('mediaType', 'video');
     $lazyLoaded = ThumbnailHelper::setLazyLoad($this, $options);
     if (!$lazyLoaded) {
         // Only add RDF metadata when the thumb is not lazy loaded
         $this->response->setVal('rdf', true);
         if (!empty($duration)) {
             $this->response->setVal('durationISO', WikiaFileHelper::formatDurationISO8601($duration));
         }
     }
     wfProfileOut(__METHOD__);
 }
Example #2
0
 /**
  * @dataProvider durationDataProvider
  */
 public function testDuration($sec, $expResult)
 {
     // setup
     $this->setUpMock();
     // test
     $responseData = WikiaFileHelper::formatDuration($sec);
     $this->assertEquals($expResult, $responseData);
 }
Example #3
0
 /**
  * Numbers given by Exif user agents are often magical, that is they
  * should be replaced by a detailed explanation depending on their
  * value which most of the time are plain integers. This function
  * formats Exif (and other metadata) values into human readable form.
  *
  * @param $tags Array: the Exif data to format ( as returned by
  *                    Exif::getFilteredData() or BitmapMetadataHandler )
  * @return array
  */
 public static function getFormattedData($tags)
 {
     global $wgLang;
     $resolutionunit = !isset($tags['ResolutionUnit']) || $tags['ResolutionUnit'] == 2 ? 2 : 3;
     unset($tags['ResolutionUnit']);
     foreach ($tags as $tag => &$vals) {
         // This seems ugly to wrap non-array's in an array just to unwrap again,
         // especially when most of the time it is not an array
         if (!is_array($tags[$tag])) {
             $vals = array($vals);
         }
         // _type is a special value to say what array type
         if (isset($tags[$tag]['_type'])) {
             $type = $tags[$tag]['_type'];
             unset($vals['_type']);
         } else {
             $type = 'ul';
             // default unordered list.
         }
         //This is done differently as the tag is an array.
         if ($tag == 'GPSTimeStamp' && count($vals) === 3) {
             //hour min sec array
             $h = explode('/', $vals[0]);
             $m = explode('/', $vals[1]);
             $s = explode('/', $vals[2]);
             // this should already be validated
             // when loaded from file, but it could
             // come from a foreign repo, so be
             // paranoid.
             if (!isset($h[1]) || !isset($m[1]) || !isset($s[1]) || $h[1] == 0 || $m[1] == 0 || $s[1] == 0) {
                 continue;
             }
             $tags[$tag] = intval($h[0] / $h[1]) . ':' . str_pad(intval($m[0] / $m[1]), 2, '0', STR_PAD_LEFT) . ':' . str_pad(intval($s[0] / $s[1]), 2, '0', STR_PAD_LEFT);
             $time = wfTimestamp(TS_MW, '1971:01:01 ' . $tags[$tag]);
             // the 1971:01:01 is just a placeholder, and not shown to user.
             if ($time && intval($time) > 0) {
                 $tags[$tag] = $wgLang->time($time);
             }
             continue;
         }
         // The contact info is a multi-valued field
         // instead of the other props which are single
         // valued (mostly) so handle as a special case.
         if ($tag === 'Contact') {
             $vals = self::collapseContactInfo($vals);
             continue;
         }
         foreach ($vals as &$val) {
             switch ($tag) {
                 case 'Compression':
                     switch ($val) {
                         case 1:
                         case 2:
                         case 3:
                         case 4:
                         case 5:
                         case 6:
                         case 7:
                         case 8:
                         case 32773:
                         case 32946:
                         case 34712:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'PhotometricInterpretation':
                     switch ($val) {
                         case 2:
                         case 6:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'Orientation':
                     switch ($val) {
                         case 1:
                         case 2:
                         case 3:
                         case 4:
                         case 5:
                         case 6:
                         case 7:
                         case 8:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'PlanarConfiguration':
                     switch ($val) {
                         case 1:
                         case 2:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                     // TODO: YCbCrSubSampling
                 // TODO: YCbCrSubSampling
                 case 'YCbCrPositioning':
                     switch ($val) {
                         case 1:
                         case 2:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'XResolution':
                 case 'YResolution':
                     switch ($resolutionunit) {
                         case 2:
                             $val = self::msg('XYResolution', 'i', self::formatNum($val));
                             break;
                         case 3:
                             $val = self::msg('XYResolution', 'c', self::formatNum($val));
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                     // TODO: YCbCrCoefficients  #p27 (see annex E)
                 // TODO: YCbCrCoefficients  #p27 (see annex E)
                 case 'ExifVersion':
                 case 'FlashpixVersion':
                     $val = "{$val}" / 100;
                     break;
                 case 'ColorSpace':
                     switch ($val) {
                         case 1:
                         case 65535:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'ComponentsConfiguration':
                     switch ($val) {
                         case 0:
                         case 1:
                         case 2:
                         case 3:
                         case 4:
                         case 5:
                         case 6:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'DateTime':
                 case 'DateTimeOriginal':
                 case 'DateTimeDigitized':
                 case 'DateTimeReleased':
                 case 'DateTimeExpires':
                 case 'GPSDateStamp':
                 case 'dc-date':
                 case 'DateTimeMetadata':
                     if ($val == '0000:00:00 00:00:00' || $val == '    :  :     :  :  ') {
                         $val = wfMsg('exif-unknowndate');
                     } elseif (preg_match('/^(?:\\d{4}):(?:\\d\\d):(?:\\d\\d) (?:\\d\\d):(?:\\d\\d):(?:\\d\\d)$/D', $val)) {
                         // Full date.
                         $time = wfTimestamp(TS_MW, $val);
                         if ($time && intval($time) > 0) {
                             $val = $wgLang->timeanddate($time);
                         }
                     } elseif (preg_match('/^(?:\\d{4}):(?:\\d\\d):(?:\\d\\d) (?:\\d\\d):(?:\\d\\d)$/D', $val)) {
                         // No second field. Still format the same
                         // since timeanddate doesn't include seconds anyways,
                         // but second still available in api
                         $time = wfTimestamp(TS_MW, $val . ':00');
                         if ($time && intval($time) > 0) {
                             $val = $wgLang->timeanddate($time);
                         }
                     } elseif (preg_match('/^(?:\\d{4}):(?:\\d\\d):(?:\\d\\d)$/D', $val)) {
                         // If only the date but not the time is filled in.
                         $time = wfTimestamp(TS_MW, substr($val, 0, 4) . substr($val, 5, 2) . substr($val, 8, 2) . '000000');
                         if ($time && intval($time) > 0) {
                             $val = $wgLang->date($time);
                         }
                     }
                     // else it will just output $val without formatting it.
                     break;
                     /** Wikia change start */
                 /** Wikia change start */
                 case 'duration':
                     $val = WikiaFileHelper::formatDuration($val);
                     break;
                 case 'published':
                     global $wgContLang;
                     $val = $wgContLang->date($val);
                     break;
                     /** Wikia change end */
                 /** Wikia change end */
                 case 'ExposureProgram':
                     switch ($val) {
                         case 0:
                         case 1:
                         case 2:
                         case 3:
                         case 4:
                         case 5:
                         case 6:
                         case 7:
                         case 8:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'SubjectDistance':
                     $val = self::msg($tag, '', self::formatNum($val));
                     break;
                 case 'MeteringMode':
                     switch ($val) {
                         case 0:
                         case 1:
                         case 2:
                         case 3:
                         case 4:
                         case 5:
                         case 6:
                         case 7:
                         case 255:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'LightSource':
                     switch ($val) {
                         case 0:
                         case 1:
                         case 2:
                         case 3:
                         case 4:
                         case 9:
                         case 10:
                         case 11:
                         case 12:
                         case 13:
                         case 14:
                         case 15:
                         case 17:
                         case 18:
                         case 19:
                         case 20:
                         case 21:
                         case 22:
                         case 23:
                         case 24:
                         case 255:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'Flash':
                     $flashDecode = array('fired' => $val & bindec('00000001'), 'return' => ($val & bindec('00000110')) >> 1, 'mode' => ($val & bindec('00011000')) >> 3, 'function' => ($val & bindec('00100000')) >> 5, 'redeye' => ($val & bindec('01000000')) >> 6);
                     # We do not need to handle unknown values since all are used.
                     foreach ($flashDecode as $subTag => $subValue) {
                         # We do not need any message for zeroed values.
                         if ($subTag != 'fired' && $subValue == 0) {
                             continue;
                         }
                         $fullTag = $tag . '-' . $subTag;
                         $flashMsgs[] = self::msg($fullTag, $subValue);
                     }
                     $val = $wgLang->commaList($flashMsgs);
                     break;
                 case 'FocalPlaneResolutionUnit':
                     switch ($val) {
                         case 2:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'SensingMethod':
                     switch ($val) {
                         case 1:
                         case 2:
                         case 3:
                         case 4:
                         case 5:
                         case 7:
                         case 8:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'FileSource':
                     switch ($val) {
                         case 3:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'SceneType':
                     switch ($val) {
                         case 1:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'CustomRendered':
                     switch ($val) {
                         case 0:
                         case 1:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'ExposureMode':
                     switch ($val) {
                         case 0:
                         case 1:
                         case 2:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'WhiteBalance':
                     switch ($val) {
                         case 0:
                         case 1:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'SceneCaptureType':
                     switch ($val) {
                         case 0:
                         case 1:
                         case 2:
                         case 3:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'GainControl':
                     switch ($val) {
                         case 0:
                         case 1:
                         case 2:
                         case 3:
                         case 4:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'Contrast':
                     switch ($val) {
                         case 0:
                         case 1:
                         case 2:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'Saturation':
                     switch ($val) {
                         case 0:
                         case 1:
                         case 2:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'Sharpness':
                     switch ($val) {
                         case 0:
                         case 1:
                         case 2:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'SubjectDistanceRange':
                     switch ($val) {
                         case 0:
                         case 1:
                         case 2:
                         case 3:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                     //The GPS...Ref values are kept for compatibility, probably won't be reached.
                 //The GPS...Ref values are kept for compatibility, probably won't be reached.
                 case 'GPSLatitudeRef':
                 case 'GPSDestLatitudeRef':
                     switch ($val) {
                         case 'N':
                         case 'S':
                             $val = self::msg('GPSLatitude', $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'GPSLongitudeRef':
                 case 'GPSDestLongitudeRef':
                     switch ($val) {
                         case 'E':
                         case 'W':
                             $val = self::msg('GPSLongitude', $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'GPSAltitude':
                     if ($val < 0) {
                         $val = self::msg('GPSAltitude', 'below-sealevel', self::formatNum(-$val, 3));
                     } else {
                         $val = self::msg('GPSAltitude', 'above-sealevel', self::formatNum($val, 3));
                     }
                     break;
                 case 'GPSStatus':
                     switch ($val) {
                         case 'A':
                         case 'V':
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'GPSMeasureMode':
                     switch ($val) {
                         case 2:
                         case 3:
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'GPSTrackRef':
                 case 'GPSImgDirectionRef':
                 case 'GPSDestBearingRef':
                     switch ($val) {
                         case 'T':
                         case 'M':
                             $val = self::msg('GPSDirection', $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'GPSLatitude':
                 case 'GPSDestLatitude':
                     $val = self::formatCoords($val, 'latitude');
                     break;
                 case 'GPSLongitude':
                 case 'GPSDestLongitude':
                     $val = self::formatCoords($val, 'longitude');
                     break;
                 case 'GPSSpeedRef':
                     switch ($val) {
                         case 'K':
                         case 'M':
                         case 'N':
                             $val = self::msg('GPSSpeed', $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'GPSDestDistanceRef':
                     switch ($val) {
                         case 'K':
                         case 'M':
                         case 'N':
                             $val = self::msg('GPSDestDistance', $val);
                             break;
                         default:
                             /* If not recognized, display as is. */
                             break;
                     }
                     break;
                 case 'GPSDOP':
                     // See http://en.wikipedia.org/wiki/Dilution_of_precision_(GPS)
                     if ($val <= 2) {
                         $val = self::msg($tag, 'excellent', self::formatNum($val));
                     } elseif ($val <= 5) {
                         $val = self::msg($tag, 'good', self::formatNum($val));
                     } elseif ($val <= 10) {
                         $val = self::msg($tag, 'moderate', self::formatNum($val));
                     } elseif ($val <= 20) {
                         $val = self::msg($tag, 'fair', self::formatNum($val));
                     } else {
                         $val = self::msg($tag, 'poor', self::formatNum($val));
                     }
                     break;
                     // This is not in the Exif standard, just a special
                     // case for our purposes which enables wikis to wikify
                     // the make, model and software name to link to their articles.
                 // This is not in the Exif standard, just a special
                 // case for our purposes which enables wikis to wikify
                 // the make, model and software name to link to their articles.
                 case 'Make':
                 case 'Model':
                     $val = self::msg($tag, '', $val);
                     break;
                 case 'Software':
                     if (is_array($val)) {
                         //if its a software, version array.
                         $val = wfMsg('exif-software-version-value', $val[0], $val[1]);
                     } else {
                         $val = self::msg($tag, '', $val);
                     }
                     break;
                 case 'ExposureTime':
                     // Show the pretty fraction as well as decimal version
                     $val = wfMsg('exif-exposuretime-format', self::formatFraction($val), self::formatNum($val));
                     break;
                 case 'ISOSpeedRatings':
                     // If its = 65535 that means its at the
                     // limit of the size of Exif::short and
                     // is really higher.
                     if ($val == '65535') {
                         $val = self::msg($tag, 'overflow');
                     } else {
                         $val = self::formatNum($val);
                     }
                     break;
                 case 'FNumber':
                     $val = wfMsg('exif-fnumber-format', self::formatNum($val));
                     break;
                 case 'FocalLength':
                 case 'FocalLengthIn35mmFilm':
                     $val = wfMsg('exif-focallength-format', self::formatNum($val));
                     break;
                 case 'MaxApertureValue':
                     if (strpos($val, '/') !== false) {
                         // need to expand this earlier to calculate fNumber
                         list($n, $d) = explode('/', $val);
                         if (is_numeric($n) && is_numeric($d)) {
                             $val = $n / $d;
                         }
                     }
                     if (is_numeric($val)) {
                         $fNumber = pow(2, $val / 2);
                         if ($fNumber !== false) {
                             $val = wfMsg('exif-maxaperturevalue-value', self::formatNum($val), self::formatNum($fNumber, 2));
                         }
                     }
                     break;
                 case 'iimCategory':
                     switch (strtolower($val)) {
                         // See pg 29 of IPTC photo
                         // metadata standard.
                         case 'ace':
                         case 'clj':
                         case 'dis':
                         case 'fin':
                         case 'edu':
                         case 'evn':
                         case 'hth':
                         case 'hum':
                         case 'lab':
                         case 'lif':
                         case 'pol':
                         case 'rel':
                         case 'sci':
                         case 'soi':
                         case 'spo':
                         case 'war':
                         case 'wea':
                             $val = self::msg('iimcategory', $val);
                     }
                     break;
                 case 'SubjectNewsCode':
                     // Essentially like iimCategory.
                     // 8 (numeric) digit hierarchical
                     // classification. We decode the
                     // first 2 digits, which provide
                     // a broad category.
                     $val = self::convertNewsCode($val);
                     break;
                 case 'Urgency':
                     // 1-8 with 1 being highest, 5 normal
                     // 0 is reserved, and 9 is 'user-defined'.
                     $urgency = '';
                     if ($val == 0 || $val == 9) {
                         $urgency = 'other';
                     } elseif ($val < 5 && $val > 1) {
                         $urgency = 'high';
                     } elseif ($val == 5) {
                         $urgency = 'normal';
                     } elseif ($val <= 8 && $val > 5) {
                         $urgency = 'low';
                     }
                     if ($urgency !== '') {
                         $val = self::msg('urgency', $urgency, $val);
                     }
                     break;
                     // Things that have a unit of pixels.
                 // Things that have a unit of pixels.
                 case 'OriginalImageHeight':
                 case 'OriginalImageWidth':
                 case 'PixelXDimension':
                 case 'PixelYDimension':
                 case 'ImageWidth':
                 case 'ImageLength':
                     $val = self::formatNum($val) . ' ' . wfMsg('unit-pixel');
                     break;
                     // Do not transform fields with pure text.
                     // For some languages the formatNum()
                     // conversion results to wrong output like
                     // foo,bar@example,com or foo٫bar@example٫com.
                     // Also some 'numeric' things like Scene codes
                     // are included here as we really don't want
                     // commas inserted.
                 // Do not transform fields with pure text.
                 // For some languages the formatNum()
                 // conversion results to wrong output like
                 // foo,bar@example,com or foo٫bar@example٫com.
                 // Also some 'numeric' things like Scene codes
                 // are included here as we really don't want
                 // commas inserted.
                 case 'ImageDescription':
                 case 'Artist':
                 case 'Copyright':
                 case 'RelatedSoundFile':
                 case 'ImageUniqueID':
                 case 'SpectralSensitivity':
                 case 'GPSSatellites':
                 case 'GPSVersionID':
                 case 'GPSMapDatum':
                 case 'Keywords':
                 case 'WorldRegionDest':
                 case 'CountryDest':
                 case 'CountryCodeDest':
                 case 'ProvinceOrStateDest':
                 case 'CityDest':
                 case 'SublocationDest':
                 case 'WorldRegionCreated':
                 case 'CountryCreated':
                 case 'CountryCodeCreated':
                 case 'ProvinceOrStateCreated':
                 case 'CityCreated':
                 case 'SublocationCreated':
                 case 'ObjectName':
                 case 'SpecialInstructions':
                 case 'Headline':
                 case 'Credit':
                 case 'Source':
                 case 'EditStatus':
                 case 'FixtureIdentifier':
                 case 'LocationDest':
                 case 'LocationDestCode':
                 case 'Writer':
                 case 'JPEGFileComment':
                 case 'iimSupplementalCategory':
                 case 'OriginalTransmissionRef':
                 case 'Identifier':
                 case 'dc-contributor':
                 case 'dc-coverage':
                 case 'dc-publisher':
                 case 'dc-relation':
                 case 'dc-rights':
                 case 'dc-source':
                 case 'dc-type':
                 case 'Lens':
                 case 'SerialNumber':
                 case 'CameraOwnerName':
                 case 'Label':
                 case 'Nickname':
                 case 'RightsCertificate':
                 case 'CopyrightOwner':
                 case 'UsageTerms':
                 case 'WebStatement':
                 case 'OriginalDocumentID':
                 case 'LicenseUrl':
                 case 'MorePermissionsUrl':
                 case 'AttributionUrl':
                 case 'PreferredAttributionName':
                 case 'PNGFileComment':
                 case 'Disclaimer':
                 case 'ContentWarning':
                 case 'GIFFileComment':
                 case 'SceneCode':
                 case 'IntellectualGenre':
                 case 'Event':
                 case 'OrginisationInImage':
                 case 'PersonInImage':
                     $val = htmlspecialchars($val);
                     break;
                 case 'ObjectCycle':
                     switch ($val) {
                         case 'a':
                         case 'p':
                         case 'b':
                             $val = self::msg($tag, $val);
                             break;
                         default:
                             $val = htmlspecialchars($val);
                             break;
                     }
                     break;
                 case 'Copyrighted':
                     switch ($val) {
                         case 'True':
                         case 'False':
                             $val = self::msg($tag, $val);
                             break;
                     }
                     break;
                 case 'Rating':
                     if ($val == '-1') {
                         $val = self::msg($tag, 'rejected');
                     } else {
                         $val = self::formatNum($val);
                     }
                     break;
                 case 'LanguageCode':
                     $lang = $wgLang->getLanguageName(strtolower($val));
                     if ($lang) {
                         $val = htmlspecialchars($lang);
                     } else {
                         $val = htmlspecialchars($val);
                     }
                     break;
                 default:
                     $val = self::formatNum($val);
                     break;
             }
         }
         // End formatting values, start flattening arrays.
         $vals = self::flattenArray($vals, $type);
     }
     return $tags;
 }
 /**
  * Return a HTML representation of the image gallery
  *
  * The new gallery disables the old perrow control, and automatically fit the gallery to the available space in the browser.
  */
 private function renderGallery()
 {
     wfProfileIn(__METHOD__);
     // do not render empty gallery
     if (empty($this->mFiles)) {
         wfProfileOut(__METHOD__);
         return '';
     }
     // Route to the mobile gallery or the new MediaGallery
     if (F::app()->checkSkin('wikiamobile')) {
         $html = $this->renderWikiaMobileMediaGroup();
         wfProfileOut(__METHOD__);
         return $html;
     } elseif ($this->canRenderMediaGallery()) {
         $html = $this->renderMediaGallery();
         // remove spaces from html produced by mustache template
         $html = trim(preg_replace('/\\n+/', ' ', $html));
         wfProfileOut(__METHOD__);
         return $html;
     }
     /** @var Skin|Linker $skin The skin object falls back to Linker methods via __call */
     $skin = RequestContext::getMain()->getSkin();
     $thumbSize = $this->mWidths;
     $orientation = $this->getParam('orientation');
     $ratio = WikiaPhotoGalleryHelper::getRatioFromOption($orientation);
     $crop = $this->mCrop;
     //calculate height of the biggest image
     $maxHeight = 0;
     $fileObjectsCache = array();
     $heights = array();
     $widths = array();
     $thumbParams = array();
     // loop through the images and get height of the tallest one
     foreach ($this->mFiles as $imageData) {
         $img = $this->getImage($imageData[0]);
         $fileObjectsCache[] = $img;
         if (!empty($img)) {
             // get thumbnail limited only by given width
             if ($img->width > $thumbSize) {
                 $imageHeight = round($img->height * ($thumbSize / $img->width));
                 $imageWidth = $thumbSize;
             } else {
                 $imageHeight = $img->height;
                 $imageWidth = $img->width;
             }
             $heights[] = $imageHeight;
             $widths[] = $imageWidth;
             if ($imageHeight > $maxHeight) {
                 $maxHeight = $imageHeight;
             }
         }
     }
     // calculate height based on gallery width
     $height = round($thumbSize / $ratio);
     if ($orientation == 'none') {
         $this->enableCropping($crop = false);
         // use the biggest height found
         if ($maxHeight > 0) {
             $height = $maxHeight;
         }
         // limit height (RT #59355)
         $height = min($height, $thumbSize);
         // recalculate dimensions (RT #59355)
         foreach ($this->mFiles as $index => $image) {
             if (!empty($heights[$index]) && !empty($widths[$index])) {
                 //fix #59355, min() added to let borders wrap images with smaller width
                 //fix #63886, round ( $tmpFloat ) != floor ( $tmpFloat ) added to check if thumbnail will be generated from proper width
                 $tmpFloat = $widths[$index] * $height / $heights[$index];
                 $widths[$index] = min($widths[$index], floor($tmpFloat));
                 $heights[$index] = min($height, $heights[$index]);
                 if (round($tmpFloat) != floor($tmpFloat)) {
                     $heights[$index]--;
                 }
             } else {
                 $widths[$index] = $thumbSize;
                 $heights[$index] = $height;
             }
         }
     }
     $useBuckets = $this->getParam('buckets');
     $useRowDivider = $this->getParam('rowdivider');
     $captionColor = $this->getParam('captiontextcolor');
     $borderColor = $this->getParam('bordercolor');
     $perRow = $this->mPerRow > 0 ? $this->mPerRow : 'dynamic';
     $position = $this->getParam('position');
     $captionsPosition = $this->getParam('captionposition', 'below');
     $captionsAlign = $this->getParam('captionalign');
     $captionsSize = $this->getParam('captionsize');
     $captionsColor = !empty($captionColor) ? $captionColor : null;
     $spacing = $this->getParam('spacing');
     $borderSize = $this->getParam('bordersize');
     $borderColor = !empty($borderColor) ? $borderColor : 'accent';
     $isTemplate = isset($this->mData['params']['source']) && $this->mData['params']['source'] == "template";
     $hash = $this->mData['hash'];
     $id = 'gallery-' . $this->mData['id'];
     $showAddButton = $this->mShowAddButton == true;
     $hideOverflow = $this->getParam('hideoverflow');
     if (in_array($borderColor, array('accent', 'color1'))) {
         $borderColorClass = " {$borderColor}";
     } else {
         $borderColorCSS = " border-color: {$borderColor};";
         if ($captionsPosition == 'within') {
             $captionsBackgroundColor = $borderColor;
         }
     }
     $html = Xml::openElement('div', array('id' => $id, 'hash' => $hash, 'class' => 'wikia-gallery' . ($isTemplate ? ' template' : null) . " wikia-gallery-caption-{$captionsPosition}" . " wikia-gallery-position-{$position}" . " wikia-gallery-spacing-{$spacing}" . " wikia-gallery-border-{$borderSize}" . " wikia-gallery-captions-{$captionsAlign}" . " wikia-gallery-caption-size-{$captionsSize}"));
     // render gallery caption (RT #59241)
     if ($this->mCaption !== false) {
         $html .= Xml::openElement('div', array('class' => 'wikia-gallery-caption')) . $this->mCaption . Xml::closeElement('div');
     }
     $itemWrapperWidth = $thumbSize;
     $thumbWrapperHeight = $height;
     //compensate image wrapper width depending on the border size
     switch ($borderSize) {
         case 'large':
             $itemWrapperWidth += 10;
             //5px * 2
             $thumbWrapperHeight += 10;
             break;
         case 'medium':
             $itemWrapperWidth += 4;
             //2px * 2
             $thumbWrapperHeight += 4;
             break;
         case 'small':
             $itemWrapperWidth += 2;
             //1px * 2
             $thumbWrapperHeight += 2;
             break;
     }
     //adding more width for the padding
     $outeritemWrapperWidth = $itemWrapperWidth + 20;
     $rowDividerCSS = '';
     if ($useRowDivider) {
         $rowDividerCSS = "height: " . ($thumbWrapperHeight + 100) . "px; padding: 30px 15px 20px 15px; margin: 0px; border-bottom: solid 1px #CCCCCC;";
     }
     if ($useBuckets) {
         $itemSpanStyle = "width:{$outeritemWrapperWidth}px; " . ($useRowDivider ? $rowDividerCSS : 'margin: 4px;');
         $itemDivStyle = "background-color: #f9f9f9; height:{$thumbWrapperHeight}px; text-align: center; border: solid 1px #CCCCCC; padding: " . ($outeritemWrapperWidth - $thumbWrapperHeight) / 2 . "px 5px;";
     } else {
         $itemSpanStyle = "width:{$itemWrapperWidth}px; {$rowDividerCSS}";
         $itemDivStyle = "height:{$thumbWrapperHeight}px;";
     }
     foreach ($this->mFiles as $index => $imageData) {
         if ($perRow != 'dynamic' && $index % $perRow == 0) {
             $html .= Xml::openElement('div', array('class' => 'wikia-gallery-row'));
         }
         $html .= Xml::openElement('div', array('class' => 'wikia-gallery-item', 'style' => $itemSpanStyle));
         $html .= Xml::openElement('div', array('class' => 'thumb', 'style' => $itemDivStyle));
         $image = array();
         // let's properly scale image (don't make it bigger than original size)
         /**
          * @var $imageTitle Title
          * @var $fileObject LocalFile
          */
         $imageTitle = $imageData[0];
         $fileObject = $fileObjectsCache[$index];
         $imageTitleText = $imageTitle->getText();
         $image['height'] = $height;
         $image['width'] = $thumbSize;
         $image['caption'] = $imageData[1];
         if (!is_object($fileObject) || $imageTitle->getNamespace() != NS_FILE) {
             $image['linkTitle'] = $image['titleText'] = $imageTitleText;
             $image['thumbnail'] = false;
             $image['link'] = Skin::makeSpecialUrl("Upload", array('wpDestFile' => $image['linkTitle']));
             $image['classes'] = 'image broken-image accent new';
         } else {
             $thumbParams = WikiaPhotoGalleryHelper::getThumbnailDimensions($fileObject, $thumbSize, $height, $crop);
             $image['thumbnail'] = $fileObject->createThumb($thumbParams['width'], $thumbParams['height']);
             $image['DBKey'] = $fileObject->getTitle()->getDBKey();
             $image['fileTitle'] = $fileObject->getTitle()->getText();
             $image['height'] = $orientation == 'none' ? $heights[$index] : min($thumbParams['height'], $height);
             $imgHeightCompensation = ($height - $image['height']) / 2;
             if ($imgHeightCompensation > 0) {
                 $image['heightCompensation'] = $imgHeightCompensation;
             }
             $image['width'] = min($widths[$index], $thumbSize);
             //Fix #59914, shared.css has auto-alignment rules
             /*$imgWidthCompensation = ($thumbSize - $image['width']) / 2;
             		if ($imgHeightCompensation > 0) $image['widthCompensation'] = $imgWidthCompensation;*/
             $image['link'] = $imageData[2];
             $linkAttribs = $this->parseLink($imageTitle->getLocalUrl(), $imageTitleText, $image['link']);
             $image['link'] = $linkAttribs['href'];
             $image['linkTitle'] = $linkAttribs['title'];
             $image['classes'] = $linkAttribs['class'];
             $image['bytes'] = $fileObject->getSize();
             if ($this->mParser && $fileObject->getHandler()) {
                 $fileObject->getHandler()->parserTransformHook($this->mParser, $fileObject);
             }
         }
         wfRunHooks('GalleryBeforeRenderImage', array(&$image));
         //see Image SEO project
         $wrapperId = preg_replace('/[^a-z0-9_]/i', '-', Sanitizer::escapeId($image['linkTitle']));
         $html .= Xml::openElement('div', array('class' => 'gallery-image-wrapper' . (!$useBuckets && !empty($borderColorClass) ? $borderColorClass : null), 'id' => $wrapperId, 'style' => 'position: relative;' . ($useBuckets ? " width: {$itemWrapperWidth}px; border-style: none;" : " height:{$image['height']}px; width:{$image['width']}px;") . (!empty($image['heightCompensation']) ? " top:{$image['heightCompensation']}px;" : null) . (!empty($borderColorCSS) ? $borderColorCSS : null)));
         $imgStyle = null;
         $isVideo = WikiaFileHelper::isFileTypeVideo($fileObject);
         # Fix 59913 - thumbnail goes as <img /> not as <a> background.
         if ($orientation != 'none') {
             # margin calculation for image positioning
             if ($thumbParams['height'] > $image['height']) {
                 $tempTopMargin = -1 * ($thumbParams['height'] - $image['height']) / 2;
             } else {
                 unset($tempTopMargin);
             }
             if ($thumbParams['width'] > $image['width']) {
                 $tempLeftMargin = -1 * ($thumbParams['width'] - $image['width']) / 2;
             } else {
                 unset($tempLeftMargin);
             }
             $imgStyle = (!empty($tempTopMargin) ? " margin-top:" . $tempTopMargin . "px;" : null) . (!empty($tempLeftMargin) ? " margin-left:" . $tempLeftMargin . "px;" : null);
             if ($isVideo) {
                 $image['classes'] .= ' force-lightbox';
             }
         }
         $linkAttribs = array('class' => empty($image['thumbnail']) ? 'image-no-lightbox' : $image['classes'], 'href' => $image['link'], 'title' => $image['linkTitle'] . (isset($image['bytes']) ? ' (' . $skin->formatSize($image['bytes']) . ')' : ""), 'style' => "height:{$image['height']}px; width:{$image['width']}px;");
         if (!empty($image['thumbnail'])) {
             if ($isVideo) {
                 $thumbHtml = '';
                 $duration = $fileObject->getMetadataDuration();
                 if (!empty($duration)) {
                     $duration = WikiaFileHelper::formatDuration($duration);
                     $thumbHtml .= '<span class="duration">' . $duration . '</span>';
                 }
                 $playButtonSize = ThumbnailHelper::getThumbnailSize($image['width']);
                 $thumbHtml .= $this->videoPlayButton;
                 $linkAttribs['class'] .= ' video video-thumbnail ' . $playButtonSize;
             } else {
                 $thumbHtml = '';
             }
             $imgAttribs = array('style' => (!empty($image['titleText']) ? " line-height:{$image['height']}px;" : null) . $imgStyle, 'src' => $image['thumbnail'] ? $image['thumbnail'] : null, 'title' => $image['linkTitle'] . (isset($image['bytes']) ? ' (' . $skin->formatSize($image['bytes']) . ')' : ""), 'class' => 'thumbimage', 'alt' => preg_replace('/\\.[^\\.]+$/', '', $image['linkTitle']));
             if ($isVideo) {
                 $imgAttribs['data-video-name'] = htmlspecialchars($image['fileTitle']);
                 $imgAttribs['data-video-key'] = urlencode(htmlspecialchars($image['DBKey']));
             } else {
                 $imgAttribs['data-image-name'] = htmlspecialchars($image['fileTitle']);
                 $imgAttribs['data-image-key'] = urlencode(htmlspecialchars($image['DBKey']));
             }
             if (!empty($image['data-caption'])) {
                 $imgAttribs['data-caption'] = $image['data-caption'];
             }
             if (isset($image['thumbnail-classes']) && isset($image['thumbnail-src']) && isset($image['thumbnail-onload'])) {
                 $thumbHtml .= '<noscript>' . Xml::openElement('img', $imgAttribs) . '</noscript>';
                 $imgAttribs['class'] .= ' ' . $image['thumbnail-classes'];
                 $imgAttribs['data-src'] = $imgAttribs['src'];
                 $imgAttribs['src'] = $image['thumbnail-src'];
                 $imgAttribs['onload'] = $image['thumbnail-onload'];
             }
             $thumbHtml .= Xml::openElement('img', $imgAttribs);
         } else {
             $thumbHtml = $image['linkTitle'];
         }
         $html .= Xml::openElement('a', $linkAttribs);
         $html .= $thumbHtml;
         $html .= Xml::closeElement('a');
         if ($captionsPosition == 'below') {
             $html .= Xml::closeElement('div');
             $html .= Xml::closeElement('div');
         }
         // Insert video titles here
         if ($isVideo) {
             $html .= '<div class="title">' . $imageTitleText . '</div>';
         }
         if (!empty($image['caption'])) {
             $html .= Xml::openElement('div', array('class' => 'lightbox-caption' . (!empty($borderColorClass) && $captionsPosition == 'within' ? $borderColorClass : null), 'style' => ($captionsPosition == 'below' ? "width:{$thumbSize}px;" : null) . (!empty($captionsColor) ? " color:{$captionsColor};" : null) . (!empty($captionsBackgroundColor) ? " background-color:{$captionsBackgroundColor}" : null) . ($useBuckets ? " margin-top: 0px;" : '') . (!empty($hideOverflow) ? " overflow: hidden" : null)));
             $html .= $image['caption'];
             $html .= Xml::closeElement('div');
         }
         if ($captionsPosition == 'within') {
             $html .= Xml::closeElement('div');
             $html .= Xml::closeElement('div');
         }
         $html .= Xml::closeElement('div');
         // /div.wikia-gallery-item
         if ($perRow != 'dynamic' && ($index % $perRow == $perRow - 1 || $index == count($this->mFiles) - 1)) {
             $html .= Xml::closeElement('div');
         }
     }
     // "Add image to this gallery" button (this button is shown by JS only in Monaco)
     if ($showAddButton) {
         if ($perRow == 'dynamic') {
             $html .= Xml::element('br');
         }
         // add button for Oasis
         $html .= Xml::openElement('a', array('class' => 'wikia-photogallery-add wikia-button noprint', 'style' => 'display: none'));
         $html .= Xml::element('img', array('src' => F::app()->wg->BlankImgUrl, 'class' => 'sprite photo', 'width' => 26, 'height' => 16));
         $html .= wfMessage('wikiaPhotoGallery-viewmode-addphoto')->inContentLanguage()->text();
         $html .= Xml::closeElement('a');
     }
     $html .= Xml::closeElement('div');
     wfProfileOut(__METHOD__);
     return $html;
 }
Example #5
0
 /**
  * get formatted duration
  * @return string
  */
 public function getFormattedDuration()
 {
     $metadata = $this->getVideoMetadata(true);
     if (!empty($metadata['duration'])) {
         $sec = $metadata['duration'];
         if (is_numeric($sec)) {
             $formattedDuration = WikiaFileHelper::formatDuration($sec);
             return $formattedDuration;
         } else {
             return $metadata['duration'];
         }
     }
     return '';
 }
 /**
  * @param array $options
  * @return mixed|string
  * @throws MWException
  */
 function toHtml($options = array())
 {
     $app = F::app();
     if (count(func_get_args()) == 2) {
         throw new MWException(__METHOD__ . ' called in the old style');
     }
     // Check if the editor is requesting, if so, render image thumbnail instead
     if (!empty($app->wg->RTEParserEnabled)) {
         return $this->renderAsThumbnailImage($options);
     }
     wfProfileIn(__METHOD__);
     // All non-WikiaMobile skins use Nirvana to render HTML now. WikiaMobile is slowly migrating with 'useTemplate'
     if (!F::app()->checkSkin('wikiamobile') || !empty($options['useTemplate'])) {
         $html = $this->renderView($options);
         wfProfileOut(__METHOD__);
         return $html;
     }
     // Only WikiaMobile beyond this point
     WikiaLogger::instance()->debug('Media method ' . __METHOD__ . ' called', array_merge($options, ['url' => $this->url, 'method' => __METHOD__, 'page' => $this->page, 'mediaType' => $this->mediaType(), 'fileType' => get_class($this->file)]));
     $alt = empty($options['alt']) ? '' : $options['alt'];
     $videoTitle = $this->file->getTitle();
     $useRDFData = !empty($options['disableRDF']) && $options['disableRDF'] == true ? false : true;
     $linkAttribs = array('href' => $videoTitle->getLocalURL());
     if (!empty($options['id'])) {
         $linkAttribs['id'] = $options['id'];
     }
     if ($useRDFData) {
         // bugId: #46621
         $linkAttribs['itemprop'] = 'video';
         $linkAttribs['itemscope'] = '';
         $linkAttribs['itemtype'] = 'http://schema.org/VideoObject';
     }
     // let extension override any link attributes
     if (isset($options['linkAttribs']) && is_array($options['linkAttribs'])) {
         $linkAttribs = array_merge($linkAttribs, $options['linkAttribs']);
     }
     $extraClasses = 'video';
     if (empty($options['noLightbox'])) {
         $extraClasses .= ' image lightbox';
     }
     $linkAttribs['class'] = empty($linkAttribs['class']) ? $extraClasses : $linkAttribs['class'] . ' ' . $extraClasses;
     if (!empty($options['fixedHeight'])) {
         $this->height = $options['fixedHeight'];
     }
     $attribs = array('alt' => $alt, 'src' => empty($options['src']) ? $this->url : $options['src'], 'width' => $this->width, 'height' => $this->height, 'data-video-name' => htmlspecialchars($videoTitle->getText()), 'data-video-key' => htmlspecialchars(urlencode($videoTitle->getDBKey())));
     if ($useRDFData) {
         $attribs['itemprop'] = 'thumbnail';
     }
     // lazy loading
     if (!empty($options['usePreloading'])) {
         $attribs['data-src'] = $this->url;
     }
     // this is used for video thumbnails on file page history tables to insure you see the older version of a file when thumbnail is clicked.
     if ($this->file instanceof OldLocalFile) {
         $archive_name = $this->file->getArchiveName();
         if (!empty($archive_name)) {
             $linkAttribs['href'] .= '?t=' . $this->file->getTimestamp();
             $linkAttribs['data-timestamp'] = $this->file->getTimestamp();
         }
     }
     if (!empty($options['valign'])) {
         $attribs['style'] = "vertical-align: {$options['valign']}";
     }
     $attribs['class'] = 'Wikia-video-thumb';
     if (!empty($options['img-class'])) {
         $attribs['class'] .= ' ' . $options['img-class'];
     }
     if (isset($options['imgExtraStyle'])) {
         if (!isset($attribs['style'])) {
             $attribs['style'] = '';
         }
         $attribs['style'] .= $options['imgExtraStyle'];
     }
     if (isset($options['duration']) && $options['duration'] == true) {
         $duration = WikiaFileHelper::formatDuration($this->file->getMetadataDuration());
     }
     if (!empty($duration)) {
         $timerProp = array('class' => 'timer');
         if ($useRDFData) {
             $timerProp['itemprop'] = 'duration';
         }
     }
     // WikiaMobile completely reconstructs the html
     $html = '';
     //give extensions a chance to modify the markup
     wfRunHooks('ThumbnailVideoHTML', array($options, $linkAttribs, $attribs, $this->file, &$html));
     wfProfileOut(__METHOD__);
     return $html;
 }
 public function save()
 {
     if (!$this->wg->User->isAllowed('gameguidessponsored')) {
         $this->displayRestrictionError();
         return false;
         // skip rendering
     }
     $this->response->setFormat('json');
     $languages = $this->request->getArray('languages');
     $err = [];
     if (!empty($languages)) {
         foreach ($languages as $lang => $videos) {
             foreach ($videos as $key => $video) {
                 $wikiId = (int) WikiFactory::DomainToID($video['wiki_domain']);
                 $video['wiki_id'] = $wikiId;
                 $wiki = WikiFactory::getWikiByID($wikiId);
                 $video['wiki_name'] = $wiki->city_title;
                 $video['wiki_lang'] = $wiki->city_lang;
                 $title = Title::newFromText($video['video_name'], NS_FILE);
                 if (!empty($title) && $title->exists()) {
                     $vid = wfFindFile($title);
                     if (!empty($vid) && $vid instanceof WikiaLocalFile) {
                         $handler = $vid->getHandler();
                         if ($handler instanceof OoyalaVideoHandler) {
                             $metadata = $handler->getVideoMetadata(true);
                             $video['video_id'] = $metadata['videoId'];
                             $video['duration'] = WikiaFileHelper::formatDuration($metadata['duration']);
                             $video['video_thumb'] = WikiaFileHelper::getMediaDetail($title)['imageUrl'];
                         } else {
                             $err[$video['video_name']] = self::VIDEO_IS_NOT_PROVIDED_BY_OOYALA;
                         }
                     } else {
                         $err[$video['video_name']] = self::VIDEO_DOES_NOT_EXIST;
                     }
                 } else {
                     $err[$video['video_name']] = self::VIDEO_DOES_NOT_EXIST;
                 }
                 $videos[$key] = $video;
             }
             $languages[$lang] = $videos;
         }
     }
     if (!empty($err)) {
         $this->response->setVal('error', $err);
     } else {
         $status = WikiFactory::setVarByName('wgWikiaGameGuidesSponsoredVideos', $this->wg->CityId, $languages);
         $this->response->setVal('status', $status);
         if ($status) {
             wfRunHooks('GameGuidesSponsoredVideosSave');
         }
     }
     return true;
 }