From 14ec0cc12d68e7f15fe3f3bb03c1ecfd06d0e6c3 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Tue, 3 Mar 2026 17:47:50 +0100 Subject: [PATCH 01/16] Fix for player timer. --- src/wolnelektury/static/js/contrib/jplayer/jquery.jplayer.js | 2 +- .../static/js/contrib/jplayer/jquery.jplayer.min.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wolnelektury/static/js/contrib/jplayer/jquery.jplayer.js b/src/wolnelektury/static/js/contrib/jplayer/jquery.jplayer.js index 2bd9316b5..0ab3569ea 100644 --- a/src/wolnelektury/static/js/contrib/jplayer/jquery.jplayer.js +++ b/src/wolnelektury/static/js/contrib/jplayer/jquery.jplayer.js @@ -212,7 +212,7 @@ s = (s && typeof s === 'number') ? s : 0; var myTime = new Date(s * 1000), - hour = myTime.getUTCHours() + (myTime.getDate() - 1) * 24, + hour = myTime.getUTCHours() + (myTime.getUTCDate() - 1) * 24, min = this.options.timeFormat.showHour ? myTime.getUTCMinutes() : myTime.getUTCMinutes() + hour * 60, sec = this.options.timeFormat.showMin ? myTime.getUTCSeconds() : myTime.getUTCSeconds() + min * 60, strHour = (this.options.timeFormat.padHour && hour < 10) ? "0" + hour : hour, diff --git a/src/wolnelektury/static/js/contrib/jplayer/jquery.jplayer.min.js b/src/wolnelektury/static/js/contrib/jplayer/jquery.jplayer.min.js index 6f1536a35..4390d8cd4 100644 --- a/src/wolnelektury/static/js/contrib/jplayer/jquery.jplayer.min.js +++ b/src/wolnelektury/static/js/contrib/jplayer/jquery.jplayer.min.js @@ -1,3 +1,3 @@ /*! jPlayer 2.9.2 for jQuery ~ (c) 2009-2014 Happyworm Ltd ~ MIT License */ -!function(a,b){"function"==typeof define&&define.amd?define(["jquery"],b):b("object"==typeof exports?require("jquery"):a.jQuery?a.jQuery:a.Zepto)}(this,function(a,b){a.fn.jPlayer=function(c){var d="jPlayer",e="string"==typeof c,f=Array.prototype.slice.call(arguments,1),g=this;return c=!e&&f.length?a.extend.apply(null,[!0,c].concat(f)):c,e&&"_"===c.charAt(0)?g:(this.each(e?function(){var e=a(this).data(d),h=e&&a.isFunction(e[c])?e[c].apply(e,f):e;return h!==e&&h!==b?(g=h,!1):void 0}:function(){var b=a(this).data(d);b?b.option(c||{}):a(this).data(d,new a.jPlayer(c,this))}),g)},a.jPlayer=function(b,c){if(arguments.length){this.element=a(c),this.options=a.extend(!0,{},this.options,b);var d=this;this.element.bind("remove.jPlayer",function(){d.destroy()}),this._init()}},"function"!=typeof a.fn.stop&&(a.fn.stop=function(){}),a.jPlayer.emulateMethods="load play pause",a.jPlayer.emulateStatus="src readyState networkState currentTime duration paused ended playbackRate",a.jPlayer.emulateOptions="muted volume",a.jPlayer.reservedEvent="ready flashreset resize repeat error warning",a.jPlayer.event={},a.each(["ready","setmedia","flashreset","resize","repeat","click","error","warning","loadstart","progress","suspend","abort","emptied","stalled","play","pause","loadedmetadata","loadeddata","waiting","playing","canplay","canplaythrough","seeking","seeked","timeupdate","ended","ratechange","durationchange","volumechange"],function(){a.jPlayer.event[this]="jPlayer_"+this}),a.jPlayer.htmlEvent=["loadstart","abort","emptied","stalled","loadedmetadata","canplay","canplaythrough"],a.jPlayer.pause=function(){a.jPlayer.prototype.destroyRemoved(),a.each(a.jPlayer.prototype.instances,function(a,b){b.data("jPlayer").status.srcSet&&b.jPlayer("pause")})},a.jPlayer.timeFormat={showHour:!1,showMin:!0,showSec:!0,padHour:!1,padMin:!0,padSec:!0,sepHour:":",sepMin:":",sepSec:""};var c=function(){this.init()};c.prototype={init:function(){this.options={timeFormat:a.jPlayer.timeFormat}},time:function(a){a=a&&"number"==typeof a?a:0;var b=new Date(1e3*a),c=b.getUTCHours()+(b.getDate()-1)*24,d=this.options.timeFormat.showHour?b.getUTCMinutes():b.getUTCMinutes()+60*c,e=this.options.timeFormat.showMin?b.getUTCSeconds():b.getUTCSeconds()+60*d,f=this.options.timeFormat.padHour&&10>c?"0"+c:c,g=this.options.timeFormat.padMin&&10>d?"0"+d:d,h=this.options.timeFormat.padSec&&10>e?"0"+e:e,i="";return i+=this.options.timeFormat.showHour?f+this.options.timeFormat.sepHour:"",i+=this.options.timeFormat.showMin?g+this.options.timeFormat.sepMin:"",i+=this.options.timeFormat.showSec?h+this.options.timeFormat.sepSec:""}};var d=new c;a.jPlayer.convertTime=function(a){return d.time(a)},a.jPlayer.uaBrowser=function(a){var b=a.toLowerCase(),c=/(webkit)[ \/]([\w.]+)/,d=/(opera)(?:.*version)?[ \/]([\w.]+)/,e=/(msie) ([\w.]+)/,f=/(mozilla)(?:.*? rv:([\w.]+))?/,g=c.exec(b)||d.exec(b)||e.exec(b)||b.indexOf("compatible")<0&&f.exec(b)||[];return{browser:g[1]||"",version:g[2]||"0"}},a.jPlayer.uaPlatform=function(a){var b=a.toLowerCase(),c=/(ipad|iphone|ipod|android|blackberry|playbook|windows ce|webos)/,d=/(ipad|playbook)/,e=/(android)/,f=/(mobile)/,g=c.exec(b)||[],h=d.exec(b)||!f.exec(b)&&e.exec(b)||[];return g[1]&&(g[1]=g[1].replace(/\s/g,"_")),{platform:g[1]||"",tablet:h[1]||""}},a.jPlayer.browser={},a.jPlayer.platform={};var e=a.jPlayer.uaBrowser(navigator.userAgent);e.browser&&(a.jPlayer.browser[e.browser]=!0,a.jPlayer.browser.version=e.version);var f=a.jPlayer.uaPlatform(navigator.userAgent);f.platform&&(a.jPlayer.platform[f.platform]=!0,a.jPlayer.platform.mobile=!f.tablet,a.jPlayer.platform.tablet=!!f.tablet),a.jPlayer.getDocMode=function(){var b;return a.jPlayer.browser.msie&&(document.documentMode?b=document.documentMode:(b=5,document.compatMode&&"CSS1Compat"===document.compatMode&&(b=7))),b},a.jPlayer.browser.documentMode=a.jPlayer.getDocMode(),a.jPlayer.nativeFeatures={init:function(){var a,b,c,d=document,e=d.createElement("video"),f={w3c:["fullscreenEnabled","fullscreenElement","requestFullscreen","exitFullscreen","fullscreenchange","fullscreenerror"],moz:["mozFullScreenEnabled","mozFullScreenElement","mozRequestFullScreen","mozCancelFullScreen","mozfullscreenchange","mozfullscreenerror"],webkit:["","webkitCurrentFullScreenElement","webkitRequestFullScreen","webkitCancelFullScreen","webkitfullscreenchange",""],webkitVideo:["webkitSupportsFullscreen","webkitDisplayingFullscreen","webkitEnterFullscreen","webkitExitFullscreen","",""],ms:["","msFullscreenElement","msRequestFullscreen","msExitFullscreen","MSFullscreenChange","MSFullscreenError"]},g=["w3c","moz","webkit","webkitVideo","ms"];for(this.fullscreen=a={support:{w3c:!!d[f.w3c[0]],moz:!!d[f.moz[0]],webkit:"function"==typeof d[f.webkit[3]],webkitVideo:"function"==typeof e[f.webkitVideo[2]],ms:"function"==typeof e[f.ms[2]]},used:{}},b=0,c=g.length;c>b;b++){var h=g[b];if(a.support[h]){a.spec=h,a.used[h]=!0;break}}if(a.spec){var i=f[a.spec];a.api={fullscreenEnabled:!0,fullscreenElement:function(a){return a=a?a:d,a[i[1]]},requestFullscreen:function(a){return a[i[2]]()},exitFullscreen:function(a){return a=a?a:d,a[i[3]]()}},a.event={fullscreenchange:i[4],fullscreenerror:i[5]}}else a.api={fullscreenEnabled:!1,fullscreenElement:function(){return null},requestFullscreen:function(){},exitFullscreen:function(){}},a.event={}}},a.jPlayer.nativeFeatures.init(),a.jPlayer.focus=null,a.jPlayer.keyIgnoreElementNames="A INPUT TEXTAREA SELECT BUTTON";var g=function(b){var c,d=a.jPlayer.focus;d&&(a.each(a.jPlayer.keyIgnoreElementNames.split(/\s+/g),function(a,d){return b.target.nodeName.toUpperCase()===d.toUpperCase()?(c=!0,!1):void 0}),c||a.each(d.options.keyBindings,function(c,e){return e&&a.isFunction(e.fn)&&("number"==typeof e.key&&b.which===e.key||"string"==typeof e.key&&b.key===e.key)?(b.preventDefault(),e.fn(d),!1):void 0}))};a.jPlayer.keys=function(b){var c="keydown.jPlayer";a(document.documentElement).unbind(c),b&&a(document.documentElement).bind(c,g)},a.jPlayer.keys(!0),a.jPlayer.prototype={count:0,version:{script:"2.9.2",needFlash:"2.9.0",flash:"unknown"},options:{swfPath:"js",solution:"html, flash",supplied:"mp3",auroraFormats:"wav",preload:"metadata",volume:.8,muted:!1,remainingDuration:!1,toggleDuration:!1,captureDuration:!0,playbackRate:1,defaultPlaybackRate:1,minPlaybackRate:.5,maxPlaybackRate:4,wmode:"opaque",backgroundColor:"#000000",cssSelectorAncestor:"#jp_container_1",cssSelector:{videoPlay:".jp-video-play",play:".jp-play",pause:".jp-pause",stop:".jp-stop",seekBar:".jp-seek-bar",playBar:".jp-play-bar",mute:".jp-mute",unmute:".jp-unmute",volumeBar:".jp-volume-bar",volumeBarValue:".jp-volume-bar-value",volumeMax:".jp-volume-max",playbackRateBar:".jp-playback-rate-bar",playbackRateBarValue:".jp-playback-rate-bar-value",currentTime:".jp-current-time",duration:".jp-duration",title:".jp-title",fullScreen:".jp-full-screen",restoreScreen:".jp-restore-screen",repeat:".jp-repeat",repeatOff:".jp-repeat-off",gui:".jp-gui",noSolution:".jp-no-solution"},stateClass:{playing:"jp-state-playing",seeking:"jp-state-seeking",muted:"jp-state-muted",looped:"jp-state-looped",fullScreen:"jp-state-full-screen",noVolume:"jp-state-no-volume"},useStateClassSkin:!1,autoBlur:!0,smoothPlayBar:!1,fullScreen:!1,fullWindow:!1,autohide:{restored:!1,full:!0,fadeIn:200,fadeOut:600,hold:1e3},loop:!1,repeat:function(b){b.jPlayer.options.loop?a(this).unbind(".jPlayerRepeat").bind(a.jPlayer.event.ended+".jPlayer.jPlayerRepeat",function(){a(this).jPlayer("play")}):a(this).unbind(".jPlayerRepeat")},nativeVideoControls:{},noFullWindow:{msie:/msie [0-6]\./,ipad:/ipad.*?os [0-4]\./,iphone:/iphone/,ipod:/ipod/,android_pad:/android [0-3]\.(?!.*?mobile)/,android_phone:/(?=.*android)(?!.*chrome)(?=.*mobile)/,blackberry:/blackberry/,windows_ce:/windows ce/,iemobile:/iemobile/,webos:/webos/},noVolume:{ipad:/ipad/,iphone:/iphone/,ipod:/ipod/,android_pad:/android(?!.*?mobile)/,android_phone:/android.*?mobile/,blackberry:/blackberry/,windows_ce:/windows ce/,iemobile:/iemobile/,webos:/webos/,playbook:/playbook/},timeFormat:{},keyEnabled:!1,audioFullScreen:!1,keyBindings:{play:{key:80,fn:function(a){a.status.paused?a.play():a.pause()}},fullScreen:{key:70,fn:function(a){(a.status.video||a.options.audioFullScreen)&&a._setOption("fullScreen",!a.options.fullScreen)}},muted:{key:77,fn:function(a){a._muted(!a.options.muted)}},volumeUp:{key:190,fn:function(a){a.volume(a.options.volume+.1)}},volumeDown:{key:188,fn:function(a){a.volume(a.options.volume-.1)}},loop:{key:76,fn:function(a){a._loop(!a.options.loop)}}},verticalVolume:!1,verticalPlaybackRate:!1,globalVolume:!1,idPrefix:"jp",noConflict:"jQuery",emulateHtml:!1,consoleAlerts:!0,errorAlerts:!1,warningAlerts:!1},optionsAudio:{size:{width:"0px",height:"0px",cssClass:""},sizeFull:{width:"0px",height:"0px",cssClass:""}},optionsVideo:{size:{width:"480px",height:"270px",cssClass:"jp-video-270p"},sizeFull:{width:"100%",height:"100%",cssClass:"jp-video-full"}},instances:{},status:{src:"",media:{},paused:!0,format:{},formatType:"",waitForPlay:!0,waitForLoad:!0,srcSet:!1,video:!1,seekPercent:0,currentPercentRelative:0,currentPercentAbsolute:0,currentTime:0,duration:0,remaining:0,videoWidth:0,videoHeight:0,readyState:0,networkState:0,playbackRate:1,ended:0},internal:{ready:!1},solution:{html:!0,aurora:!0,flash:!0},format:{mp3:{codec:"audio/mpeg",flashCanPlay:!0,media:"audio"},m4a:{codec:'audio/mp4; codecs="mp4a.40.2"',flashCanPlay:!0,media:"audio"},m3u8a:{codec:'application/vnd.apple.mpegurl; codecs="mp4a.40.2"',flashCanPlay:!1,media:"audio"},m3ua:{codec:"audio/mpegurl",flashCanPlay:!1,media:"audio"},oga:{codec:'audio/ogg; codecs="vorbis, opus"',flashCanPlay:!1,media:"audio"},flac:{codec:"audio/x-flac",flashCanPlay:!1,media:"audio"},wav:{codec:'audio/wav; codecs="1"',flashCanPlay:!1,media:"audio"},webma:{codec:'audio/webm; codecs="vorbis"',flashCanPlay:!1,media:"audio"},fla:{codec:"audio/x-flv",flashCanPlay:!0,media:"audio"},rtmpa:{codec:'audio/rtmp; codecs="rtmp"',flashCanPlay:!0,media:"audio"},m4v:{codec:'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',flashCanPlay:!0,media:"video"},m3u8v:{codec:'application/vnd.apple.mpegurl; codecs="avc1.42E01E, mp4a.40.2"',flashCanPlay:!1,media:"video"},m3uv:{codec:"audio/mpegurl",flashCanPlay:!1,media:"video"},ogv:{codec:'video/ogg; codecs="theora, vorbis"',flashCanPlay:!1,media:"video"},webmv:{codec:'video/webm; codecs="vorbis, vp8"',flashCanPlay:!1,media:"video"},flv:{codec:"video/x-flv",flashCanPlay:!0,media:"video"},rtmpv:{codec:'video/rtmp; codecs="rtmp"',flashCanPlay:!0,media:"video"}},_init:function(){var c=this;if(this.element.empty(),this.status=a.extend({},this.status),this.internal=a.extend({},this.internal),this.options.timeFormat=a.extend({},a.jPlayer.timeFormat,this.options.timeFormat),this.internal.cmdsIgnored=a.jPlayer.platform.ipad||a.jPlayer.platform.iphone||a.jPlayer.platform.ipod,this.internal.domNode=this.element.get(0),this.options.keyEnabled&&!a.jPlayer.focus&&(a.jPlayer.focus=this),this.androidFix={setMedia:!1,play:!1,pause:!1,time:0/0},a.jPlayer.platform.android&&(this.options.preload="auto"!==this.options.preload?"metadata":"auto"),this.formats=[],this.solutions=[],this.require={},this.htmlElement={},this.html={},this.html.audio={},this.html.video={},this.aurora={},this.aurora.formats=[],this.aurora.properties=[],this.flash={},this.css={},this.css.cs={},this.css.jq={},this.ancestorJq=[],this.options.volume=this._limitValue(this.options.volume,0,1),a.each(this.options.supplied.toLowerCase().split(","),function(b,d){var e=d.replace(/^\s+|\s+$/g,"");if(c.format[e]){var f=!1;a.each(c.formats,function(a,b){return e===b?(f=!0,!1):void 0}),f||c.formats.push(e)}}),a.each(this.options.solution.toLowerCase().split(","),function(b,d){var e=d.replace(/^\s+|\s+$/g,"");if(c.solution[e]){var f=!1;a.each(c.solutions,function(a,b){return e===b?(f=!0,!1):void 0}),f||c.solutions.push(e)}}),a.each(this.options.auroraFormats.toLowerCase().split(","),function(b,d){var e=d.replace(/^\s+|\s+$/g,"");if(c.format[e]){var f=!1;a.each(c.aurora.formats,function(a,b){return e===b?(f=!0,!1):void 0}),f||c.aurora.formats.push(e)}}),this.internal.instance="jp_"+this.count,this.instances[this.internal.instance]=this.element,this.element.attr("id")||this.element.attr("id",this.options.idPrefix+"_jplayer_"+this.count),this.internal.self=a.extend({},{id:this.element.attr("id"),jq:this.element}),this.internal.audio=a.extend({},{id:this.options.idPrefix+"_audio_"+this.count,jq:b}),this.internal.video=a.extend({},{id:this.options.idPrefix+"_video_"+this.count,jq:b}),this.internal.flash=a.extend({},{id:this.options.idPrefix+"_flash_"+this.count,jq:b,swf:this.options.swfPath+(".swf"!==this.options.swfPath.toLowerCase().slice(-4)?(this.options.swfPath&&"/"!==this.options.swfPath.slice(-1)?"/":"")+"jquery.jplayer.swf":"")}),this.internal.poster=a.extend({},{id:this.options.idPrefix+"_poster_"+this.count,jq:b}),a.each(a.jPlayer.event,function(a,d){c.options[a]!==b&&(c.element.bind(d+".jPlayer",c.options[a]),c.options[a]=b)}),this.require.audio=!1,this.require.video=!1,a.each(this.formats,function(a,b){c.require[c.format[b].media]=!0}),this.options=this.require.video?a.extend(!0,{},this.optionsVideo,this.options):a.extend(!0,{},this.optionsAudio,this.options),this._setSize(),this.status.nativeVideoControls=this._uaBlocklist(this.options.nativeVideoControls),this.status.noFullWindow=this._uaBlocklist(this.options.noFullWindow),this.status.noVolume=this._uaBlocklist(this.options.noVolume),a.jPlayer.nativeFeatures.fullscreen.api.fullscreenEnabled&&this._fullscreenAddEventListeners(),this._restrictNativeVideoControls(),this.htmlElement.poster=document.createElement("img"),this.htmlElement.poster.id=this.internal.poster.id,this.htmlElement.poster.onload=function(){(!c.status.video||c.status.waitForPlay)&&c.internal.poster.jq.show()},this.element.append(this.htmlElement.poster),this.internal.poster.jq=a("#"+this.internal.poster.id),this.internal.poster.jq.css({width:this.status.width,height:this.status.height}),this.internal.poster.jq.hide(),this.internal.poster.jq.bind("click.jPlayer",function(){c._trigger(a.jPlayer.event.click)}),this.html.audio.available=!1,this.require.audio&&(this.htmlElement.audio=document.createElement("audio"),this.htmlElement.audio.id=this.internal.audio.id,this.html.audio.available=!!this.htmlElement.audio.canPlayType&&this._testCanPlayType(this.htmlElement.audio)),this.html.video.available=!1,this.require.video&&(this.htmlElement.video=document.createElement("video"),this.htmlElement.video.id=this.internal.video.id,this.html.video.available=!!this.htmlElement.video.canPlayType&&this._testCanPlayType(this.htmlElement.video)),this.flash.available=this._checkForFlash(10.1),this.html.canPlay={},this.aurora.canPlay={},this.flash.canPlay={},a.each(this.formats,function(b,d){c.html.canPlay[d]=c.html[c.format[d].media].available&&""!==c.htmlElement[c.format[d].media].canPlayType(c.format[d].codec),c.aurora.canPlay[d]=a.inArray(d,c.aurora.formats)>-1,c.flash.canPlay[d]=c.format[d].flashCanPlay&&c.flash.available}),this.html.desired=!1,this.aurora.desired=!1,this.flash.desired=!1,a.each(this.solutions,function(b,d){if(0===b)c[d].desired=!0;else{var e=!1,f=!1;a.each(c.formats,function(a,b){c[c.solutions[0]].canPlay[b]&&("video"===c.format[b].media?f=!0:e=!0)}),c[d].desired=c.require.audio&&!e||c.require.video&&!f}}),this.html.support={},this.aurora.support={},this.flash.support={},a.each(this.formats,function(a,b){c.html.support[b]=c.html.canPlay[b]&&c.html.desired,c.aurora.support[b]=c.aurora.canPlay[b]&&c.aurora.desired,c.flash.support[b]=c.flash.canPlay[b]&&c.flash.desired}),this.html.used=!1,this.aurora.used=!1,this.flash.used=!1,a.each(this.solutions,function(b,d){a.each(c.formats,function(a,b){return c[d].support[b]?(c[d].used=!0,!1):void 0})}),this._resetActive(),this._resetGate(),this._cssSelectorAncestor(this.options.cssSelectorAncestor),this.html.used||this.aurora.used||this.flash.used?this.css.jq.noSolution.length&&this.css.jq.noSolution.hide():(this._error({type:a.jPlayer.error.NO_SOLUTION,context:"{solution:'"+this.options.solution+"', supplied:'"+this.options.supplied+"'}",message:a.jPlayer.errorMsg.NO_SOLUTION,hint:a.jPlayer.errorHint.NO_SOLUTION}),this.css.jq.noSolution.length&&this.css.jq.noSolution.show()),this.flash.used){var d,e="jQuery="+encodeURI(this.options.noConflict)+"&id="+encodeURI(this.internal.self.id)+"&vol="+this.options.volume+"&muted="+this.options.muted;if(a.jPlayer.browser.msie&&(Number(a.jPlayer.browser.version)<9||a.jPlayer.browser.documentMode<9)){var f='',g=['','','','',''];d=document.createElement(f);for(var h=0;h0&&(d.internal.cmdsIgnored=!1),d._getHtmlStatus(b),d._updateInterface(),d._trigger(a.jPlayer.event.progress))},!1),b.addEventListener("loadeddata",function(){c.gate&&(d.androidFix.setMedia=!1,d.androidFix.play&&(d.androidFix.play=!1,d.play(d.androidFix.time)),d.androidFix.pause&&(d.androidFix.pause=!1,d.pause(d.androidFix.time)),d._trigger(a.jPlayer.event.loadeddata))},!1),b.addEventListener("timeupdate",function(){c.gate&&(d._getHtmlStatus(b),d._updateInterface(),d._trigger(a.jPlayer.event.timeupdate))},!1),b.addEventListener("durationchange",function(){c.gate&&(d._getHtmlStatus(b),d._updateInterface(),d._trigger(a.jPlayer.event.durationchange))},!1),b.addEventListener("play",function(){c.gate&&(d._updateButtons(!0),d._html_checkWaitForPlay(),d._trigger(a.jPlayer.event.play))},!1),b.addEventListener("playing",function(){c.gate&&(d._updateButtons(!0),d._seeked(),d._trigger(a.jPlayer.event.playing))},!1),b.addEventListener("pause",function(){c.gate&&(d._updateButtons(!1),d._trigger(a.jPlayer.event.pause))},!1),b.addEventListener("waiting",function(){c.gate&&(d._seeking(),d._trigger(a.jPlayer.event.waiting))},!1),b.addEventListener("seeking",function(){c.gate&&(d._seeking(),d._trigger(a.jPlayer.event.seeking))},!1),b.addEventListener("seeked",function(){c.gate&&(d._seeked(),d._trigger(a.jPlayer.event.seeked))},!1),b.addEventListener("volumechange",function(){c.gate&&(d.options.volume=b.volume,d.options.muted=b.muted,d._updateMute(),d._updateVolume(),d._trigger(a.jPlayer.event.volumechange))},!1),b.addEventListener("ratechange",function(){c.gate&&(d.options.defaultPlaybackRate=b.defaultPlaybackRate,d.options.playbackRate=b.playbackRate,d._updatePlaybackRate(),d._trigger(a.jPlayer.event.ratechange))},!1),b.addEventListener("suspend",function(){c.gate&&(d._seeked(),d._trigger(a.jPlayer.event.suspend))},!1),b.addEventListener("ended",function(){c.gate&&(a.jPlayer.browser.webkit||(d.htmlElement.media.currentTime=0),d.htmlElement.media.pause(),d._updateButtons(!1),d._getHtmlStatus(b,!0),d._updateInterface(),d._trigger(a.jPlayer.event.ended))},!1),b.addEventListener("error",function(){c.gate&&(d._updateButtons(!1),d._seeked(),d.status.srcSet&&(clearTimeout(d.internal.htmlDlyCmdId),d.status.waitForLoad=!0,d.status.waitForPlay=!0,d.status.video&&!d.status.nativeVideoControls&&d.internal.video.jq.css({width:"0px",height:"0px"}),d._validString(d.status.media.poster)&&!d.status.nativeVideoControls&&d.internal.poster.jq.show(),d.css.jq.videoPlay.length&&d.css.jq.videoPlay.show(),d._error({type:a.jPlayer.error.URL,context:d.status.src,message:a.jPlayer.errorMsg.URL,hint:a.jPlayer.errorHint.URL})))},!1),a.each(a.jPlayer.htmlEvent,function(e,f){b.addEventListener(this,function(){c.gate&&d._trigger(a.jPlayer.event[f])},!1)})},_addAuroraEventListeners:function(b,c){var d=this;b.volume=100*this.options.volume,b.on("progress",function(){c.gate&&(d.internal.cmdsIgnored&&this.readyState>0&&(d.internal.cmdsIgnored=!1),d._getAuroraStatus(b),d._updateInterface(),d._trigger(a.jPlayer.event.progress),b.duration>0&&d._trigger(a.jPlayer.event.timeupdate))},!1),b.on("ready",function(){c.gate&&d._trigger(a.jPlayer.event.loadeddata)},!1),b.on("duration",function(){c.gate&&(d._getAuroraStatus(b),d._updateInterface(),d._trigger(a.jPlayer.event.durationchange))},!1),b.on("end",function(){c.gate&&(d._updateButtons(!1),d._getAuroraStatus(b,!0),d._updateInterface(),d._trigger(a.jPlayer.event.ended))},!1),b.on("error",function(){c.gate&&(d._updateButtons(!1),d._seeked(),d.status.srcSet&&(d.status.waitForLoad=!0,d.status.waitForPlay=!0,d.status.video&&!d.status.nativeVideoControls&&d.internal.video.jq.css({width:"0px",height:"0px"}),d._validString(d.status.media.poster)&&!d.status.nativeVideoControls&&d.internal.poster.jq.show(),d.css.jq.videoPlay.length&&d.css.jq.videoPlay.show(),d._error({type:a.jPlayer.error.URL,context:d.status.src,message:a.jPlayer.errorMsg.URL,hint:a.jPlayer.errorHint.URL})))},!1)},_getHtmlStatus:function(a,b){var c=0,d=0,e=0,f=0;isFinite(a.duration)&&(this.status.duration=a.duration),c=a.currentTime,d=this.status.duration>0?100*c/this.status.duration:0,"object"==typeof a.seekable&&a.seekable.length>0?(e=this.status.duration>0?100*a.seekable.end(a.seekable.length-1)/this.status.duration:100,f=this.status.duration>0?100*a.currentTime/a.seekable.end(a.seekable.length-1):0):(e=100,f=d),b&&(c=0,f=0,d=0),this.status.seekPercent=e,this.status.currentPercentRelative=f,this.status.currentPercentAbsolute=d,this.status.currentTime=c,this.status.remaining=this.status.duration-this.status.currentTime,this.status.videoWidth=a.videoWidth,this.status.videoHeight=a.videoHeight,this.status.readyState=a.readyState,this.status.networkState=a.networkState,this.status.playbackRate=a.playbackRate,this.status.ended=a.ended},_getAuroraStatus:function(a,b){var c=0,d=0,e=0,f=0;this.status.duration=a.duration/1e3,c=a.currentTime/1e3,d=this.status.duration>0?100*c/this.status.duration:0,a.buffered>0?(e=this.status.duration>0?a.buffered*this.status.duration/this.status.duration:100,f=this.status.duration>0?c/(a.buffered*this.status.duration):0):(e=100,f=d),b&&(c=0,f=0,d=0),this.status.seekPercent=e,this.status.currentPercentRelative=f,this.status.currentPercentAbsolute=d,this.status.currentTime=c,this.status.remaining=this.status.duration-this.status.currentTime,this.status.readyState=4,this.status.networkState=0,this.status.playbackRate=1,this.status.ended=!1},_resetStatus:function(){this.status=a.extend({},this.status,a.jPlayer.prototype.status)},_trigger:function(b,c,d){var e=a.Event(b);e.jPlayer={},e.jPlayer.version=a.extend({},this.version),e.jPlayer.options=a.extend(!0,{},this.options),e.jPlayer.status=a.extend(!0,{},this.status),e.jPlayer.html=a.extend(!0,{},this.html),e.jPlayer.aurora=a.extend(!0,{},this.aurora),e.jPlayer.flash=a.extend(!0,{},this.flash),c&&(e.jPlayer.error=a.extend({},c)),d&&(e.jPlayer.warning=a.extend({},d)),this.element.trigger(e)},jPlayerFlashEvent:function(b,c){if(b===a.jPlayer.event.ready)if(this.internal.ready){if(this.flash.gate){if(this.status.srcSet){var d=this.status.currentTime,e=this.status.paused;this.setMedia(this.status.media),this.volumeWorker(this.options.volume),d>0&&(e?this.pause(d):this.play(d))}this._trigger(a.jPlayer.event.flashreset)}}else this.internal.ready=!0,this.internal.flash.jq.css({width:"0px",height:"0px"}),this.version.flash=c.version,this.version.needFlash!==this.version.flash&&this._error({type:a.jPlayer.error.VERSION,context:this.version.flash,message:a.jPlayer.errorMsg.VERSION+this.version.flash,hint:a.jPlayer.errorHint.VERSION}),this._trigger(a.jPlayer.event.repeat),this._trigger(b);if(this.flash.gate)switch(b){case a.jPlayer.event.progress:this._getFlashStatus(c),this._updateInterface(),this._trigger(b);break;case a.jPlayer.event.timeupdate:this._getFlashStatus(c),this._updateInterface(),this._trigger(b);break;case a.jPlayer.event.play:this._seeked(),this._updateButtons(!0),this._trigger(b);break;case a.jPlayer.event.pause:this._updateButtons(!1),this._trigger(b);break;case a.jPlayer.event.ended:this._updateButtons(!1),this._trigger(b);break;case a.jPlayer.event.click:this._trigger(b);break;case a.jPlayer.event.error:this.status.waitForLoad=!0,this.status.waitForPlay=!0,this.status.video&&this.internal.flash.jq.css({width:"0px",height:"0px"}),this._validString(this.status.media.poster)&&this.internal.poster.jq.show(),this.css.jq.videoPlay.length&&this.status.video&&this.css.jq.videoPlay.show(),this.status.video?this._flash_setVideo(this.status.media):this._flash_setAudio(this.status.media),this._updateButtons(!1),this._error({type:a.jPlayer.error.URL,context:c.src,message:a.jPlayer.errorMsg.URL,hint:a.jPlayer.errorHint.URL});break;case a.jPlayer.event.seeking:this._seeking(),this._trigger(b);break;case a.jPlayer.event.seeked:this._seeked(),this._trigger(b);break;case a.jPlayer.event.ready:break;default:this._trigger(b)}return!1},_getFlashStatus:function(a){this.status.seekPercent=a.seekPercent,this.status.currentPercentRelative=a.currentPercentRelative,this.status.currentPercentAbsolute=a.currentPercentAbsolute,this.status.currentTime=a.currentTime,this.status.duration=a.duration,this.status.remaining=a.duration-a.currentTime,this.status.videoWidth=a.videoWidth,this.status.videoHeight=a.videoHeight,this.status.readyState=4,this.status.networkState=0,this.status.playbackRate=1,this.status.ended=!1},_updateButtons:function(a){a===b?a=!this.status.paused:this.status.paused=!a,a?this.addStateClass("playing"):this.removeStateClass("playing"),!this.status.noFullWindow&&this.options.fullWindow?this.addStateClass("fullScreen"):this.removeStateClass("fullScreen"),this.options.loop?this.addStateClass("looped"):this.removeStateClass("looped"),this.css.jq.play.length&&this.css.jq.pause.length&&(a?(this.css.jq.play.hide(),this.css.jq.pause.show()):(this.css.jq.play.show(),this.css.jq.pause.hide())),this.css.jq.restoreScreen.length&&this.css.jq.fullScreen.length&&(this.status.noFullWindow?(this.css.jq.fullScreen.hide(),this.css.jq.restoreScreen.hide()):this.options.fullWindow?(this.css.jq.fullScreen.hide(),this.css.jq.restoreScreen.show()):(this.css.jq.fullScreen.show(),this.css.jq.restoreScreen.hide())),this.css.jq.repeat.length&&this.css.jq.repeatOff.length&&(this.options.loop?(this.css.jq.repeat.hide(),this.css.jq.repeatOff.show()):(this.css.jq.repeat.show(),this.css.jq.repeatOff.hide()))},_updateInterface:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.width(this.status.seekPercent+"%"),this.css.jq.playBar.length&&(this.options.smoothPlayBar?this.css.jq.playBar.stop().animate({width:this.status.currentPercentAbsolute+"%"},250,"linear"):this.css.jq.playBar.width(this.status.currentPercentRelative+"%"));var a="";this.css.jq.currentTime.length&&(a=this._convertTime(this.status.currentTime),a!==this.css.jq.currentTime.text()&&this.css.jq.currentTime.text(this._convertTime(this.status.currentTime)));var b="",c=this.status.duration,d=this.status.remaining;this.css.jq.duration.length&&("string"==typeof this.status.media.duration?b=this.status.media.duration:("number"==typeof this.status.media.duration&&(c=this.status.media.duration,d=c-this.status.currentTime),b=this.options.remainingDuration?(d>0?"-":"")+this._convertTime(d):this._convertTime(c)),b!==this.css.jq.duration.text()&&this.css.jq.duration.text(b))},_convertTime:c.prototype.time,_seeking:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.addClass("jp-seeking-bg"),this.addStateClass("seeking")},_seeked:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.removeClass("jp-seeking-bg"),this.removeStateClass("seeking")},_resetGate:function(){this.html.audio.gate=!1,this.html.video.gate=!1,this.aurora.gate=!1,this.flash.gate=!1},_resetActive:function(){this.html.active=!1,this.aurora.active=!1,this.flash.active=!1},_escapeHtml:function(a){return a.split("&").join("&").split("<").join("<").split(">").join(">").split('"').join(""")},_qualifyURL:function(a){var b=document.createElement("div"); +!function(a,b){"function"==typeof define&&define.amd?define(["jquery"],b):b("object"==typeof exports?require("jquery"):a.jQuery?a.jQuery:a.Zepto)}(this,function(a,b){a.fn.jPlayer=function(c){var d="jPlayer",e="string"==typeof c,f=Array.prototype.slice.call(arguments,1),g=this;return c=!e&&f.length?a.extend.apply(null,[!0,c].concat(f)):c,e&&"_"===c.charAt(0)?g:(this.each(e?function(){var e=a(this).data(d),h=e&&a.isFunction(e[c])?e[c].apply(e,f):e;return h!==e&&h!==b?(g=h,!1):void 0}:function(){var b=a(this).data(d);b?b.option(c||{}):a(this).data(d,new a.jPlayer(c,this))}),g)},a.jPlayer=function(b,c){if(arguments.length){this.element=a(c),this.options=a.extend(!0,{},this.options,b);var d=this;this.element.bind("remove.jPlayer",function(){d.destroy()}),this._init()}},"function"!=typeof a.fn.stop&&(a.fn.stop=function(){}),a.jPlayer.emulateMethods="load play pause",a.jPlayer.emulateStatus="src readyState networkState currentTime duration paused ended playbackRate",a.jPlayer.emulateOptions="muted volume",a.jPlayer.reservedEvent="ready flashreset resize repeat error warning",a.jPlayer.event={},a.each(["ready","setmedia","flashreset","resize","repeat","click","error","warning","loadstart","progress","suspend","abort","emptied","stalled","play","pause","loadedmetadata","loadeddata","waiting","playing","canplay","canplaythrough","seeking","seeked","timeupdate","ended","ratechange","durationchange","volumechange"],function(){a.jPlayer.event[this]="jPlayer_"+this}),a.jPlayer.htmlEvent=["loadstart","abort","emptied","stalled","loadedmetadata","canplay","canplaythrough"],a.jPlayer.pause=function(){a.jPlayer.prototype.destroyRemoved(),a.each(a.jPlayer.prototype.instances,function(a,b){b.data("jPlayer").status.srcSet&&b.jPlayer("pause")})},a.jPlayer.timeFormat={showHour:!1,showMin:!0,showSec:!0,padHour:!1,padMin:!0,padSec:!0,sepHour:":",sepMin:":",sepSec:""};var c=function(){this.init()};c.prototype={init:function(){this.options={timeFormat:a.jPlayer.timeFormat}},time:function(a){a=a&&"number"==typeof a?a:0;var b=new Date(1e3*a),c=b.getUTCHours()+(b.getUTCDate()-1)*24,d=this.options.timeFormat.showHour?b.getUTCMinutes():b.getUTCMinutes()+60*c,e=this.options.timeFormat.showMin?b.getUTCSeconds():b.getUTCSeconds()+60*d,f=this.options.timeFormat.padHour&&10>c?"0"+c:c,g=this.options.timeFormat.padMin&&10>d?"0"+d:d,h=this.options.timeFormat.padSec&&10>e?"0"+e:e,i="";return i+=this.options.timeFormat.showHour?f+this.options.timeFormat.sepHour:"",i+=this.options.timeFormat.showMin?g+this.options.timeFormat.sepMin:"",i+=this.options.timeFormat.showSec?h+this.options.timeFormat.sepSec:""}};var d=new c;a.jPlayer.convertTime=function(a){return d.time(a)},a.jPlayer.uaBrowser=function(a){var b=a.toLowerCase(),c=/(webkit)[ \/]([\w.]+)/,d=/(opera)(?:.*version)?[ \/]([\w.]+)/,e=/(msie) ([\w.]+)/,f=/(mozilla)(?:.*? rv:([\w.]+))?/,g=c.exec(b)||d.exec(b)||e.exec(b)||b.indexOf("compatible")<0&&f.exec(b)||[];return{browser:g[1]||"",version:g[2]||"0"}},a.jPlayer.uaPlatform=function(a){var b=a.toLowerCase(),c=/(ipad|iphone|ipod|android|blackberry|playbook|windows ce|webos)/,d=/(ipad|playbook)/,e=/(android)/,f=/(mobile)/,g=c.exec(b)||[],h=d.exec(b)||!f.exec(b)&&e.exec(b)||[];return g[1]&&(g[1]=g[1].replace(/\s/g,"_")),{platform:g[1]||"",tablet:h[1]||""}},a.jPlayer.browser={},a.jPlayer.platform={};var e=a.jPlayer.uaBrowser(navigator.userAgent);e.browser&&(a.jPlayer.browser[e.browser]=!0,a.jPlayer.browser.version=e.version);var f=a.jPlayer.uaPlatform(navigator.userAgent);f.platform&&(a.jPlayer.platform[f.platform]=!0,a.jPlayer.platform.mobile=!f.tablet,a.jPlayer.platform.tablet=!!f.tablet),a.jPlayer.getDocMode=function(){var b;return a.jPlayer.browser.msie&&(document.documentMode?b=document.documentMode:(b=5,document.compatMode&&"CSS1Compat"===document.compatMode&&(b=7))),b},a.jPlayer.browser.documentMode=a.jPlayer.getDocMode(),a.jPlayer.nativeFeatures={init:function(){var a,b,c,d=document,e=d.createElement("video"),f={w3c:["fullscreenEnabled","fullscreenElement","requestFullscreen","exitFullscreen","fullscreenchange","fullscreenerror"],moz:["mozFullScreenEnabled","mozFullScreenElement","mozRequestFullScreen","mozCancelFullScreen","mozfullscreenchange","mozfullscreenerror"],webkit:["","webkitCurrentFullScreenElement","webkitRequestFullScreen","webkitCancelFullScreen","webkitfullscreenchange",""],webkitVideo:["webkitSupportsFullscreen","webkitDisplayingFullscreen","webkitEnterFullscreen","webkitExitFullscreen","",""],ms:["","msFullscreenElement","msRequestFullscreen","msExitFullscreen","MSFullscreenChange","MSFullscreenError"]},g=["w3c","moz","webkit","webkitVideo","ms"];for(this.fullscreen=a={support:{w3c:!!d[f.w3c[0]],moz:!!d[f.moz[0]],webkit:"function"==typeof d[f.webkit[3]],webkitVideo:"function"==typeof e[f.webkitVideo[2]],ms:"function"==typeof e[f.ms[2]]},used:{}},b=0,c=g.length;c>b;b++){var h=g[b];if(a.support[h]){a.spec=h,a.used[h]=!0;break}}if(a.spec){var i=f[a.spec];a.api={fullscreenEnabled:!0,fullscreenElement:function(a){return a=a?a:d,a[i[1]]},requestFullscreen:function(a){return a[i[2]]()},exitFullscreen:function(a){return a=a?a:d,a[i[3]]()}},a.event={fullscreenchange:i[4],fullscreenerror:i[5]}}else a.api={fullscreenEnabled:!1,fullscreenElement:function(){return null},requestFullscreen:function(){},exitFullscreen:function(){}},a.event={}}},a.jPlayer.nativeFeatures.init(),a.jPlayer.focus=null,a.jPlayer.keyIgnoreElementNames="A INPUT TEXTAREA SELECT BUTTON";var g=function(b){var c,d=a.jPlayer.focus;d&&(a.each(a.jPlayer.keyIgnoreElementNames.split(/\s+/g),function(a,d){return b.target.nodeName.toUpperCase()===d.toUpperCase()?(c=!0,!1):void 0}),c||a.each(d.options.keyBindings,function(c,e){return e&&a.isFunction(e.fn)&&("number"==typeof e.key&&b.which===e.key||"string"==typeof e.key&&b.key===e.key)?(b.preventDefault(),e.fn(d),!1):void 0}))};a.jPlayer.keys=function(b){var c="keydown.jPlayer";a(document.documentElement).unbind(c),b&&a(document.documentElement).bind(c,g)},a.jPlayer.keys(!0),a.jPlayer.prototype={count:0,version:{script:"2.9.2",needFlash:"2.9.0",flash:"unknown"},options:{swfPath:"js",solution:"html, flash",supplied:"mp3",auroraFormats:"wav",preload:"metadata",volume:.8,muted:!1,remainingDuration:!1,toggleDuration:!1,captureDuration:!0,playbackRate:1,defaultPlaybackRate:1,minPlaybackRate:.5,maxPlaybackRate:4,wmode:"opaque",backgroundColor:"#000000",cssSelectorAncestor:"#jp_container_1",cssSelector:{videoPlay:".jp-video-play",play:".jp-play",pause:".jp-pause",stop:".jp-stop",seekBar:".jp-seek-bar",playBar:".jp-play-bar",mute:".jp-mute",unmute:".jp-unmute",volumeBar:".jp-volume-bar",volumeBarValue:".jp-volume-bar-value",volumeMax:".jp-volume-max",playbackRateBar:".jp-playback-rate-bar",playbackRateBarValue:".jp-playback-rate-bar-value",currentTime:".jp-current-time",duration:".jp-duration",title:".jp-title",fullScreen:".jp-full-screen",restoreScreen:".jp-restore-screen",repeat:".jp-repeat",repeatOff:".jp-repeat-off",gui:".jp-gui",noSolution:".jp-no-solution"},stateClass:{playing:"jp-state-playing",seeking:"jp-state-seeking",muted:"jp-state-muted",looped:"jp-state-looped",fullScreen:"jp-state-full-screen",noVolume:"jp-state-no-volume"},useStateClassSkin:!1,autoBlur:!0,smoothPlayBar:!1,fullScreen:!1,fullWindow:!1,autohide:{restored:!1,full:!0,fadeIn:200,fadeOut:600,hold:1e3},loop:!1,repeat:function(b){b.jPlayer.options.loop?a(this).unbind(".jPlayerRepeat").bind(a.jPlayer.event.ended+".jPlayer.jPlayerRepeat",function(){a(this).jPlayer("play")}):a(this).unbind(".jPlayerRepeat")},nativeVideoControls:{},noFullWindow:{msie:/msie [0-6]\./,ipad:/ipad.*?os [0-4]\./,iphone:/iphone/,ipod:/ipod/,android_pad:/android [0-3]\.(?!.*?mobile)/,android_phone:/(?=.*android)(?!.*chrome)(?=.*mobile)/,blackberry:/blackberry/,windows_ce:/windows ce/,iemobile:/iemobile/,webos:/webos/},noVolume:{ipad:/ipad/,iphone:/iphone/,ipod:/ipod/,android_pad:/android(?!.*?mobile)/,android_phone:/android.*?mobile/,blackberry:/blackberry/,windows_ce:/windows ce/,iemobile:/iemobile/,webos:/webos/,playbook:/playbook/},timeFormat:{},keyEnabled:!1,audioFullScreen:!1,keyBindings:{play:{key:80,fn:function(a){a.status.paused?a.play():a.pause()}},fullScreen:{key:70,fn:function(a){(a.status.video||a.options.audioFullScreen)&&a._setOption("fullScreen",!a.options.fullScreen)}},muted:{key:77,fn:function(a){a._muted(!a.options.muted)}},volumeUp:{key:190,fn:function(a){a.volume(a.options.volume+.1)}},volumeDown:{key:188,fn:function(a){a.volume(a.options.volume-.1)}},loop:{key:76,fn:function(a){a._loop(!a.options.loop)}}},verticalVolume:!1,verticalPlaybackRate:!1,globalVolume:!1,idPrefix:"jp",noConflict:"jQuery",emulateHtml:!1,consoleAlerts:!0,errorAlerts:!1,warningAlerts:!1},optionsAudio:{size:{width:"0px",height:"0px",cssClass:""},sizeFull:{width:"0px",height:"0px",cssClass:""}},optionsVideo:{size:{width:"480px",height:"270px",cssClass:"jp-video-270p"},sizeFull:{width:"100%",height:"100%",cssClass:"jp-video-full"}},instances:{},status:{src:"",media:{},paused:!0,format:{},formatType:"",waitForPlay:!0,waitForLoad:!0,srcSet:!1,video:!1,seekPercent:0,currentPercentRelative:0,currentPercentAbsolute:0,currentTime:0,duration:0,remaining:0,videoWidth:0,videoHeight:0,readyState:0,networkState:0,playbackRate:1,ended:0},internal:{ready:!1},solution:{html:!0,aurora:!0,flash:!0},format:{mp3:{codec:"audio/mpeg",flashCanPlay:!0,media:"audio"},m4a:{codec:'audio/mp4; codecs="mp4a.40.2"',flashCanPlay:!0,media:"audio"},m3u8a:{codec:'application/vnd.apple.mpegurl; codecs="mp4a.40.2"',flashCanPlay:!1,media:"audio"},m3ua:{codec:"audio/mpegurl",flashCanPlay:!1,media:"audio"},oga:{codec:'audio/ogg; codecs="vorbis, opus"',flashCanPlay:!1,media:"audio"},flac:{codec:"audio/x-flac",flashCanPlay:!1,media:"audio"},wav:{codec:'audio/wav; codecs="1"',flashCanPlay:!1,media:"audio"},webma:{codec:'audio/webm; codecs="vorbis"',flashCanPlay:!1,media:"audio"},fla:{codec:"audio/x-flv",flashCanPlay:!0,media:"audio"},rtmpa:{codec:'audio/rtmp; codecs="rtmp"',flashCanPlay:!0,media:"audio"},m4v:{codec:'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',flashCanPlay:!0,media:"video"},m3u8v:{codec:'application/vnd.apple.mpegurl; codecs="avc1.42E01E, mp4a.40.2"',flashCanPlay:!1,media:"video"},m3uv:{codec:"audio/mpegurl",flashCanPlay:!1,media:"video"},ogv:{codec:'video/ogg; codecs="theora, vorbis"',flashCanPlay:!1,media:"video"},webmv:{codec:'video/webm; codecs="vorbis, vp8"',flashCanPlay:!1,media:"video"},flv:{codec:"video/x-flv",flashCanPlay:!0,media:"video"},rtmpv:{codec:'video/rtmp; codecs="rtmp"',flashCanPlay:!0,media:"video"}},_init:function(){var c=this;if(this.element.empty(),this.status=a.extend({},this.status),this.internal=a.extend({},this.internal),this.options.timeFormat=a.extend({},a.jPlayer.timeFormat,this.options.timeFormat),this.internal.cmdsIgnored=a.jPlayer.platform.ipad||a.jPlayer.platform.iphone||a.jPlayer.platform.ipod,this.internal.domNode=this.element.get(0),this.options.keyEnabled&&!a.jPlayer.focus&&(a.jPlayer.focus=this),this.androidFix={setMedia:!1,play:!1,pause:!1,time:0/0},a.jPlayer.platform.android&&(this.options.preload="auto"!==this.options.preload?"metadata":"auto"),this.formats=[],this.solutions=[],this.require={},this.htmlElement={},this.html={},this.html.audio={},this.html.video={},this.aurora={},this.aurora.formats=[],this.aurora.properties=[],this.flash={},this.css={},this.css.cs={},this.css.jq={},this.ancestorJq=[],this.options.volume=this._limitValue(this.options.volume,0,1),a.each(this.options.supplied.toLowerCase().split(","),function(b,d){var e=d.replace(/^\s+|\s+$/g,"");if(c.format[e]){var f=!1;a.each(c.formats,function(a,b){return e===b?(f=!0,!1):void 0}),f||c.formats.push(e)}}),a.each(this.options.solution.toLowerCase().split(","),function(b,d){var e=d.replace(/^\s+|\s+$/g,"");if(c.solution[e]){var f=!1;a.each(c.solutions,function(a,b){return e===b?(f=!0,!1):void 0}),f||c.solutions.push(e)}}),a.each(this.options.auroraFormats.toLowerCase().split(","),function(b,d){var e=d.replace(/^\s+|\s+$/g,"");if(c.format[e]){var f=!1;a.each(c.aurora.formats,function(a,b){return e===b?(f=!0,!1):void 0}),f||c.aurora.formats.push(e)}}),this.internal.instance="jp_"+this.count,this.instances[this.internal.instance]=this.element,this.element.attr("id")||this.element.attr("id",this.options.idPrefix+"_jplayer_"+this.count),this.internal.self=a.extend({},{id:this.element.attr("id"),jq:this.element}),this.internal.audio=a.extend({},{id:this.options.idPrefix+"_audio_"+this.count,jq:b}),this.internal.video=a.extend({},{id:this.options.idPrefix+"_video_"+this.count,jq:b}),this.internal.flash=a.extend({},{id:this.options.idPrefix+"_flash_"+this.count,jq:b,swf:this.options.swfPath+(".swf"!==this.options.swfPath.toLowerCase().slice(-4)?(this.options.swfPath&&"/"!==this.options.swfPath.slice(-1)?"/":"")+"jquery.jplayer.swf":"")}),this.internal.poster=a.extend({},{id:this.options.idPrefix+"_poster_"+this.count,jq:b}),a.each(a.jPlayer.event,function(a,d){c.options[a]!==b&&(c.element.bind(d+".jPlayer",c.options[a]),c.options[a]=b)}),this.require.audio=!1,this.require.video=!1,a.each(this.formats,function(a,b){c.require[c.format[b].media]=!0}),this.options=this.require.video?a.extend(!0,{},this.optionsVideo,this.options):a.extend(!0,{},this.optionsAudio,this.options),this._setSize(),this.status.nativeVideoControls=this._uaBlocklist(this.options.nativeVideoControls),this.status.noFullWindow=this._uaBlocklist(this.options.noFullWindow),this.status.noVolume=this._uaBlocklist(this.options.noVolume),a.jPlayer.nativeFeatures.fullscreen.api.fullscreenEnabled&&this._fullscreenAddEventListeners(),this._restrictNativeVideoControls(),this.htmlElement.poster=document.createElement("img"),this.htmlElement.poster.id=this.internal.poster.id,this.htmlElement.poster.onload=function(){(!c.status.video||c.status.waitForPlay)&&c.internal.poster.jq.show()},this.element.append(this.htmlElement.poster),this.internal.poster.jq=a("#"+this.internal.poster.id),this.internal.poster.jq.css({width:this.status.width,height:this.status.height}),this.internal.poster.jq.hide(),this.internal.poster.jq.bind("click.jPlayer",function(){c._trigger(a.jPlayer.event.click)}),this.html.audio.available=!1,this.require.audio&&(this.htmlElement.audio=document.createElement("audio"),this.htmlElement.audio.id=this.internal.audio.id,this.html.audio.available=!!this.htmlElement.audio.canPlayType&&this._testCanPlayType(this.htmlElement.audio)),this.html.video.available=!1,this.require.video&&(this.htmlElement.video=document.createElement("video"),this.htmlElement.video.id=this.internal.video.id,this.html.video.available=!!this.htmlElement.video.canPlayType&&this._testCanPlayType(this.htmlElement.video)),this.flash.available=this._checkForFlash(10.1),this.html.canPlay={},this.aurora.canPlay={},this.flash.canPlay={},a.each(this.formats,function(b,d){c.html.canPlay[d]=c.html[c.format[d].media].available&&""!==c.htmlElement[c.format[d].media].canPlayType(c.format[d].codec),c.aurora.canPlay[d]=a.inArray(d,c.aurora.formats)>-1,c.flash.canPlay[d]=c.format[d].flashCanPlay&&c.flash.available}),this.html.desired=!1,this.aurora.desired=!1,this.flash.desired=!1,a.each(this.solutions,function(b,d){if(0===b)c[d].desired=!0;else{var e=!1,f=!1;a.each(c.formats,function(a,b){c[c.solutions[0]].canPlay[b]&&("video"===c.format[b].media?f=!0:e=!0)}),c[d].desired=c.require.audio&&!e||c.require.video&&!f}}),this.html.support={},this.aurora.support={},this.flash.support={},a.each(this.formats,function(a,b){c.html.support[b]=c.html.canPlay[b]&&c.html.desired,c.aurora.support[b]=c.aurora.canPlay[b]&&c.aurora.desired,c.flash.support[b]=c.flash.canPlay[b]&&c.flash.desired}),this.html.used=!1,this.aurora.used=!1,this.flash.used=!1,a.each(this.solutions,function(b,d){a.each(c.formats,function(a,b){return c[d].support[b]?(c[d].used=!0,!1):void 0})}),this._resetActive(),this._resetGate(),this._cssSelectorAncestor(this.options.cssSelectorAncestor),this.html.used||this.aurora.used||this.flash.used?this.css.jq.noSolution.length&&this.css.jq.noSolution.hide():(this._error({type:a.jPlayer.error.NO_SOLUTION,context:"{solution:'"+this.options.solution+"', supplied:'"+this.options.supplied+"'}",message:a.jPlayer.errorMsg.NO_SOLUTION,hint:a.jPlayer.errorHint.NO_SOLUTION}),this.css.jq.noSolution.length&&this.css.jq.noSolution.show()),this.flash.used){var d,e="jQuery="+encodeURI(this.options.noConflict)+"&id="+encodeURI(this.internal.self.id)+"&vol="+this.options.volume+"&muted="+this.options.muted;if(a.jPlayer.browser.msie&&(Number(a.jPlayer.browser.version)<9||a.jPlayer.browser.documentMode<9)){var f='',g=['','','','',''];d=document.createElement(f);for(var h=0;h0&&(d.internal.cmdsIgnored=!1),d._getHtmlStatus(b),d._updateInterface(),d._trigger(a.jPlayer.event.progress))},!1),b.addEventListener("loadeddata",function(){c.gate&&(d.androidFix.setMedia=!1,d.androidFix.play&&(d.androidFix.play=!1,d.play(d.androidFix.time)),d.androidFix.pause&&(d.androidFix.pause=!1,d.pause(d.androidFix.time)),d._trigger(a.jPlayer.event.loadeddata))},!1),b.addEventListener("timeupdate",function(){c.gate&&(d._getHtmlStatus(b),d._updateInterface(),d._trigger(a.jPlayer.event.timeupdate))},!1),b.addEventListener("durationchange",function(){c.gate&&(d._getHtmlStatus(b),d._updateInterface(),d._trigger(a.jPlayer.event.durationchange))},!1),b.addEventListener("play",function(){c.gate&&(d._updateButtons(!0),d._html_checkWaitForPlay(),d._trigger(a.jPlayer.event.play))},!1),b.addEventListener("playing",function(){c.gate&&(d._updateButtons(!0),d._seeked(),d._trigger(a.jPlayer.event.playing))},!1),b.addEventListener("pause",function(){c.gate&&(d._updateButtons(!1),d._trigger(a.jPlayer.event.pause))},!1),b.addEventListener("waiting",function(){c.gate&&(d._seeking(),d._trigger(a.jPlayer.event.waiting))},!1),b.addEventListener("seeking",function(){c.gate&&(d._seeking(),d._trigger(a.jPlayer.event.seeking))},!1),b.addEventListener("seeked",function(){c.gate&&(d._seeked(),d._trigger(a.jPlayer.event.seeked))},!1),b.addEventListener("volumechange",function(){c.gate&&(d.options.volume=b.volume,d.options.muted=b.muted,d._updateMute(),d._updateVolume(),d._trigger(a.jPlayer.event.volumechange))},!1),b.addEventListener("ratechange",function(){c.gate&&(d.options.defaultPlaybackRate=b.defaultPlaybackRate,d.options.playbackRate=b.playbackRate,d._updatePlaybackRate(),d._trigger(a.jPlayer.event.ratechange))},!1),b.addEventListener("suspend",function(){c.gate&&(d._seeked(),d._trigger(a.jPlayer.event.suspend))},!1),b.addEventListener("ended",function(){c.gate&&(a.jPlayer.browser.webkit||(d.htmlElement.media.currentTime=0),d.htmlElement.media.pause(),d._updateButtons(!1),d._getHtmlStatus(b,!0),d._updateInterface(),d._trigger(a.jPlayer.event.ended))},!1),b.addEventListener("error",function(){c.gate&&(d._updateButtons(!1),d._seeked(),d.status.srcSet&&(clearTimeout(d.internal.htmlDlyCmdId),d.status.waitForLoad=!0,d.status.waitForPlay=!0,d.status.video&&!d.status.nativeVideoControls&&d.internal.video.jq.css({width:"0px",height:"0px"}),d._validString(d.status.media.poster)&&!d.status.nativeVideoControls&&d.internal.poster.jq.show(),d.css.jq.videoPlay.length&&d.css.jq.videoPlay.show(),d._error({type:a.jPlayer.error.URL,context:d.status.src,message:a.jPlayer.errorMsg.URL,hint:a.jPlayer.errorHint.URL})))},!1),a.each(a.jPlayer.htmlEvent,function(e,f){b.addEventListener(this,function(){c.gate&&d._trigger(a.jPlayer.event[f])},!1)})},_addAuroraEventListeners:function(b,c){var d=this;b.volume=100*this.options.volume,b.on("progress",function(){c.gate&&(d.internal.cmdsIgnored&&this.readyState>0&&(d.internal.cmdsIgnored=!1),d._getAuroraStatus(b),d._updateInterface(),d._trigger(a.jPlayer.event.progress),b.duration>0&&d._trigger(a.jPlayer.event.timeupdate))},!1),b.on("ready",function(){c.gate&&d._trigger(a.jPlayer.event.loadeddata)},!1),b.on("duration",function(){c.gate&&(d._getAuroraStatus(b),d._updateInterface(),d._trigger(a.jPlayer.event.durationchange))},!1),b.on("end",function(){c.gate&&(d._updateButtons(!1),d._getAuroraStatus(b,!0),d._updateInterface(),d._trigger(a.jPlayer.event.ended))},!1),b.on("error",function(){c.gate&&(d._updateButtons(!1),d._seeked(),d.status.srcSet&&(d.status.waitForLoad=!0,d.status.waitForPlay=!0,d.status.video&&!d.status.nativeVideoControls&&d.internal.video.jq.css({width:"0px",height:"0px"}),d._validString(d.status.media.poster)&&!d.status.nativeVideoControls&&d.internal.poster.jq.show(),d.css.jq.videoPlay.length&&d.css.jq.videoPlay.show(),d._error({type:a.jPlayer.error.URL,context:d.status.src,message:a.jPlayer.errorMsg.URL,hint:a.jPlayer.errorHint.URL})))},!1)},_getHtmlStatus:function(a,b){var c=0,d=0,e=0,f=0;isFinite(a.duration)&&(this.status.duration=a.duration),c=a.currentTime,d=this.status.duration>0?100*c/this.status.duration:0,"object"==typeof a.seekable&&a.seekable.length>0?(e=this.status.duration>0?100*a.seekable.end(a.seekable.length-1)/this.status.duration:100,f=this.status.duration>0?100*a.currentTime/a.seekable.end(a.seekable.length-1):0):(e=100,f=d),b&&(c=0,f=0,d=0),this.status.seekPercent=e,this.status.currentPercentRelative=f,this.status.currentPercentAbsolute=d,this.status.currentTime=c,this.status.remaining=this.status.duration-this.status.currentTime,this.status.videoWidth=a.videoWidth,this.status.videoHeight=a.videoHeight,this.status.readyState=a.readyState,this.status.networkState=a.networkState,this.status.playbackRate=a.playbackRate,this.status.ended=a.ended},_getAuroraStatus:function(a,b){var c=0,d=0,e=0,f=0;this.status.duration=a.duration/1e3,c=a.currentTime/1e3,d=this.status.duration>0?100*c/this.status.duration:0,a.buffered>0?(e=this.status.duration>0?a.buffered*this.status.duration/this.status.duration:100,f=this.status.duration>0?c/(a.buffered*this.status.duration):0):(e=100,f=d),b&&(c=0,f=0,d=0),this.status.seekPercent=e,this.status.currentPercentRelative=f,this.status.currentPercentAbsolute=d,this.status.currentTime=c,this.status.remaining=this.status.duration-this.status.currentTime,this.status.readyState=4,this.status.networkState=0,this.status.playbackRate=1,this.status.ended=!1},_resetStatus:function(){this.status=a.extend({},this.status,a.jPlayer.prototype.status)},_trigger:function(b,c,d){var e=a.Event(b);e.jPlayer={},e.jPlayer.version=a.extend({},this.version),e.jPlayer.options=a.extend(!0,{},this.options),e.jPlayer.status=a.extend(!0,{},this.status),e.jPlayer.html=a.extend(!0,{},this.html),e.jPlayer.aurora=a.extend(!0,{},this.aurora),e.jPlayer.flash=a.extend(!0,{},this.flash),c&&(e.jPlayer.error=a.extend({},c)),d&&(e.jPlayer.warning=a.extend({},d)),this.element.trigger(e)},jPlayerFlashEvent:function(b,c){if(b===a.jPlayer.event.ready)if(this.internal.ready){if(this.flash.gate){if(this.status.srcSet){var d=this.status.currentTime,e=this.status.paused;this.setMedia(this.status.media),this.volumeWorker(this.options.volume),d>0&&(e?this.pause(d):this.play(d))}this._trigger(a.jPlayer.event.flashreset)}}else this.internal.ready=!0,this.internal.flash.jq.css({width:"0px",height:"0px"}),this.version.flash=c.version,this.version.needFlash!==this.version.flash&&this._error({type:a.jPlayer.error.VERSION,context:this.version.flash,message:a.jPlayer.errorMsg.VERSION+this.version.flash,hint:a.jPlayer.errorHint.VERSION}),this._trigger(a.jPlayer.event.repeat),this._trigger(b);if(this.flash.gate)switch(b){case a.jPlayer.event.progress:this._getFlashStatus(c),this._updateInterface(),this._trigger(b);break;case a.jPlayer.event.timeupdate:this._getFlashStatus(c),this._updateInterface(),this._trigger(b);break;case a.jPlayer.event.play:this._seeked(),this._updateButtons(!0),this._trigger(b);break;case a.jPlayer.event.pause:this._updateButtons(!1),this._trigger(b);break;case a.jPlayer.event.ended:this._updateButtons(!1),this._trigger(b);break;case a.jPlayer.event.click:this._trigger(b);break;case a.jPlayer.event.error:this.status.waitForLoad=!0,this.status.waitForPlay=!0,this.status.video&&this.internal.flash.jq.css({width:"0px",height:"0px"}),this._validString(this.status.media.poster)&&this.internal.poster.jq.show(),this.css.jq.videoPlay.length&&this.status.video&&this.css.jq.videoPlay.show(),this.status.video?this._flash_setVideo(this.status.media):this._flash_setAudio(this.status.media),this._updateButtons(!1),this._error({type:a.jPlayer.error.URL,context:c.src,message:a.jPlayer.errorMsg.URL,hint:a.jPlayer.errorHint.URL});break;case a.jPlayer.event.seeking:this._seeking(),this._trigger(b);break;case a.jPlayer.event.seeked:this._seeked(),this._trigger(b);break;case a.jPlayer.event.ready:break;default:this._trigger(b)}return!1},_getFlashStatus:function(a){this.status.seekPercent=a.seekPercent,this.status.currentPercentRelative=a.currentPercentRelative,this.status.currentPercentAbsolute=a.currentPercentAbsolute,this.status.currentTime=a.currentTime,this.status.duration=a.duration,this.status.remaining=a.duration-a.currentTime,this.status.videoWidth=a.videoWidth,this.status.videoHeight=a.videoHeight,this.status.readyState=4,this.status.networkState=0,this.status.playbackRate=1,this.status.ended=!1},_updateButtons:function(a){a===b?a=!this.status.paused:this.status.paused=!a,a?this.addStateClass("playing"):this.removeStateClass("playing"),!this.status.noFullWindow&&this.options.fullWindow?this.addStateClass("fullScreen"):this.removeStateClass("fullScreen"),this.options.loop?this.addStateClass("looped"):this.removeStateClass("looped"),this.css.jq.play.length&&this.css.jq.pause.length&&(a?(this.css.jq.play.hide(),this.css.jq.pause.show()):(this.css.jq.play.show(),this.css.jq.pause.hide())),this.css.jq.restoreScreen.length&&this.css.jq.fullScreen.length&&(this.status.noFullWindow?(this.css.jq.fullScreen.hide(),this.css.jq.restoreScreen.hide()):this.options.fullWindow?(this.css.jq.fullScreen.hide(),this.css.jq.restoreScreen.show()):(this.css.jq.fullScreen.show(),this.css.jq.restoreScreen.hide())),this.css.jq.repeat.length&&this.css.jq.repeatOff.length&&(this.options.loop?(this.css.jq.repeat.hide(),this.css.jq.repeatOff.show()):(this.css.jq.repeat.show(),this.css.jq.repeatOff.hide()))},_updateInterface:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.width(this.status.seekPercent+"%"),this.css.jq.playBar.length&&(this.options.smoothPlayBar?this.css.jq.playBar.stop().animate({width:this.status.currentPercentAbsolute+"%"},250,"linear"):this.css.jq.playBar.width(this.status.currentPercentRelative+"%"));var a="";this.css.jq.currentTime.length&&(a=this._convertTime(this.status.currentTime),a!==this.css.jq.currentTime.text()&&this.css.jq.currentTime.text(this._convertTime(this.status.currentTime)));var b="",c=this.status.duration,d=this.status.remaining;this.css.jq.duration.length&&("string"==typeof this.status.media.duration?b=this.status.media.duration:("number"==typeof this.status.media.duration&&(c=this.status.media.duration,d=c-this.status.currentTime),b=this.options.remainingDuration?(d>0?"-":"")+this._convertTime(d):this._convertTime(c)),b!==this.css.jq.duration.text()&&this.css.jq.duration.text(b))},_convertTime:c.prototype.time,_seeking:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.addClass("jp-seeking-bg"),this.addStateClass("seeking")},_seeked:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.removeClass("jp-seeking-bg"),this.removeStateClass("seeking")},_resetGate:function(){this.html.audio.gate=!1,this.html.video.gate=!1,this.aurora.gate=!1,this.flash.gate=!1},_resetActive:function(){this.html.active=!1,this.aurora.active=!1,this.flash.active=!1},_escapeHtml:function(a){return a.split("&").join("&").split("<").join("<").split(">").join(">").split('"').join(""")},_qualifyURL:function(a){var b=document.createElement("div"); return b.innerHTML='x',b.firstChild.href},_absoluteMediaUrls:function(b){var c=this;return a.each(b,function(a,d){d&&c.format[a]&&"data:"!==d.substr(0,5)&&(b[a]=c._qualifyURL(d))}),b},addStateClass:function(a){this.ancestorJq.length&&this.ancestorJq.addClass(this.options.stateClass[a])},removeStateClass:function(a){this.ancestorJq.length&&this.ancestorJq.removeClass(this.options.stateClass[a])},setMedia:function(b){var c=this,d=!1,e=this.status.media.poster!==b.poster;this._resetMedia(),this._resetGate(),this._resetActive(),this.androidFix.setMedia=!1,this.androidFix.play=!1,this.androidFix.pause=!1,b=this._absoluteMediaUrls(b),a.each(this.formats,function(e,f){var g="video"===c.format[f].media;return a.each(c.solutions,function(e,h){if(c[h].support[f]&&c._validString(b[f])){var i="html"===h,j="aurora"===h;return g?(i?(c.html.video.gate=!0,c._html_setVideo(b),c.html.active=!0):(c.flash.gate=!0,c._flash_setVideo(b),c.flash.active=!0),c.css.jq.videoPlay.length&&c.css.jq.videoPlay.show(),c.status.video=!0):(i?(c.html.audio.gate=!0,c._html_setAudio(b),c.html.active=!0,a.jPlayer.platform.android&&(c.androidFix.setMedia=!0)):j?(c.aurora.gate=!0,c._aurora_setAudio(b),c.aurora.active=!0):(c.flash.gate=!0,c._flash_setAudio(b),c.flash.active=!0),c.css.jq.videoPlay.length&&c.css.jq.videoPlay.hide(),c.status.video=!1),d=!0,!1}}),d?!1:void 0}),d?(this.status.nativeVideoControls&&this.html.video.gate||this._validString(b.poster)&&(e?this.htmlElement.poster.src=b.poster:this.internal.poster.jq.show()),"string"==typeof b.title&&(this.css.jq.title.length&&this.css.jq.title.html(b.title),this.htmlElement.audio&&this.htmlElement.audio.setAttribute("title",b.title),this.htmlElement.video&&this.htmlElement.video.setAttribute("title",b.title)),this.status.srcSet=!0,this.status.media=a.extend({},b),this._updateButtons(!1),this._updateInterface(),this._trigger(a.jPlayer.event.setmedia)):this._error({type:a.jPlayer.error.NO_SUPPORT,context:"{supplied:'"+this.options.supplied+"'}",message:a.jPlayer.errorMsg.NO_SUPPORT,hint:a.jPlayer.errorHint.NO_SUPPORT})},_resetMedia:function(){this._resetStatus(),this._updateButtons(!1),this._updateInterface(),this._seeked(),this.internal.poster.jq.hide(),clearTimeout(this.internal.htmlDlyCmdId),this.html.active?this._html_resetMedia():this.aurora.active?this._aurora_resetMedia():this.flash.active&&this._flash_resetMedia()},clearMedia:function(){this._resetMedia(),this.html.active?this._html_clearMedia():this.aurora.active?this._aurora_clearMedia():this.flash.active&&this._flash_clearMedia(),this._resetGate(),this._resetActive()},load:function(){this.status.srcSet?this.html.active?this._html_load():this.aurora.active?this._aurora_load():this.flash.active&&this._flash_load():this._urlNotSetError("load")},focus:function(){this.options.keyEnabled&&(a.jPlayer.focus=this)},play:function(a){var b="object"==typeof a;b&&this.options.useStateClassSkin&&!this.status.paused?this.pause(a):(a="number"==typeof a?a:0/0,this.status.srcSet?(this.focus(),this.html.active?this._html_play(a):this.aurora.active?this._aurora_play(a):this.flash.active&&this._flash_play(a)):this._urlNotSetError("play"))},videoPlay:function(){this.play()},pause:function(a){a="number"==typeof a?a:0/0,this.status.srcSet?this.html.active?this._html_pause(a):this.aurora.active?this._aurora_pause(a):this.flash.active&&this._flash_pause(a):this._urlNotSetError("pause")},tellOthers:function(b,c){var d=this,e="function"==typeof c,f=Array.prototype.slice.call(arguments);"string"==typeof b&&(e&&f.splice(1,1),a.jPlayer.prototype.destroyRemoved(),a.each(this.instances,function(){d.element!==this&&(!e||c.call(this.data("jPlayer"),d))&&this.jPlayer.apply(this,f)}))},pauseOthers:function(a){this.tellOthers("pause",function(){return this.status.srcSet},a)},stop:function(){this.status.srcSet?this.html.active?this._html_pause(0):this.aurora.active?this._aurora_pause(0):this.flash.active&&this._flash_pause(0):this._urlNotSetError("stop")},playHead:function(a){a=this._limitValue(a,0,100),this.status.srcSet?this.html.active?this._html_playHead(a):this.aurora.active?this._aurora_playHead(a):this.flash.active&&this._flash_playHead(a):this._urlNotSetError("playHead")},_muted:function(a){this.mutedWorker(a),this.options.globalVolume&&this.tellOthers("mutedWorker",function(){return this.options.globalVolume},a)},mutedWorker:function(b){this.options.muted=b,this.html.used&&this._html_setProperty("muted",b),this.aurora.used&&this._aurora_mute(b),this.flash.used&&this._flash_mute(b),this.html.video.gate||this.html.audio.gate||(this._updateMute(b),this._updateVolume(this.options.volume),this._trigger(a.jPlayer.event.volumechange))},mute:function(a){var c="object"==typeof a;c&&this.options.useStateClassSkin&&this.options.muted?this._muted(!1):(a=a===b?!0:!!a,this._muted(a))},unmute:function(a){a=a===b?!0:!!a,this._muted(!a)},_updateMute:function(a){a===b&&(a=this.options.muted),a?this.addStateClass("muted"):this.removeStateClass("muted"),this.css.jq.mute.length&&this.css.jq.unmute.length&&(this.status.noVolume?(this.css.jq.mute.hide(),this.css.jq.unmute.hide()):a?(this.css.jq.mute.hide(),this.css.jq.unmute.show()):(this.css.jq.mute.show(),this.css.jq.unmute.hide()))},volume:function(a){this.volumeWorker(a),this.options.globalVolume&&this.tellOthers("volumeWorker",function(){return this.options.globalVolume},a)},volumeWorker:function(b){b=this._limitValue(b,0,1),this.options.volume=b,this.html.used&&this._html_setProperty("volume",b),this.aurora.used&&this._aurora_volume(b),this.flash.used&&this._flash_volume(b),this.html.video.gate||this.html.audio.gate||(this._updateVolume(b),this._trigger(a.jPlayer.event.volumechange))},volumeBar:function(b){if(this.css.jq.volumeBar.length){var c=a(b.currentTarget),d=c.offset(),e=b.pageX-d.left,f=c.width(),g=c.height()-b.pageY+d.top,h=c.height();this.volume(this.options.verticalVolume?g/h:e/f)}this.options.muted&&this._muted(!1)},_updateVolume:function(a){a===b&&(a=this.options.volume),a=this.options.muted?0:a,this.status.noVolume?(this.addStateClass("noVolume"),this.css.jq.volumeBar.length&&this.css.jq.volumeBar.hide(),this.css.jq.volumeBarValue.length&&this.css.jq.volumeBarValue.hide(),this.css.jq.volumeMax.length&&this.css.jq.volumeMax.hide()):(this.removeStateClass("noVolume"),this.css.jq.volumeBar.length&&this.css.jq.volumeBar.show(),this.css.jq.volumeBarValue.length&&(this.css.jq.volumeBarValue.show(),this.css.jq.volumeBarValue[this.options.verticalVolume?"height":"width"](100*a+"%")),this.css.jq.volumeMax.length&&this.css.jq.volumeMax.show())},volumeMax:function(){this.volume(1),this.options.muted&&this._muted(!1)},_cssSelectorAncestor:function(b){var c=this;this.options.cssSelectorAncestor=b,this._removeUiClass(),this.ancestorJq=b?a(b):[],b&&1!==this.ancestorJq.length&&this._warning({type:a.jPlayer.warning.CSS_SELECTOR_COUNT,context:b,message:a.jPlayer.warningMsg.CSS_SELECTOR_COUNT+this.ancestorJq.length+" found for cssSelectorAncestor.",hint:a.jPlayer.warningHint.CSS_SELECTOR_COUNT}),this._addUiClass(),a.each(this.options.cssSelector,function(a,b){c._cssSelector(a,b)}),this._updateInterface(),this._updateButtons(),this._updateAutohide(),this._updateVolume(),this._updateMute()},_cssSelector:function(b,c){var d=this;if("string"==typeof c)if(a.jPlayer.prototype.options.cssSelector[b]){if(this.css.jq[b]&&this.css.jq[b].length&&this.css.jq[b].unbind(".jPlayer"),this.options.cssSelector[b]=c,this.css.cs[b]=this.options.cssSelectorAncestor+" "+c,this.css.jq[b]=c?a(this.css.cs[b]):[],this.css.jq[b].length&&this[b]){var e=function(c){c.preventDefault(),d[b](c),d.options.autoBlur?a(this).blur():a(this).focus()};this.css.jq[b].bind("click.jPlayer",e)}c&&1!==this.css.jq[b].length&&this._warning({type:a.jPlayer.warning.CSS_SELECTOR_COUNT,context:this.css.cs[b],message:a.jPlayer.warningMsg.CSS_SELECTOR_COUNT+this.css.jq[b].length+" found for "+b+" method.",hint:a.jPlayer.warningHint.CSS_SELECTOR_COUNT})}else this._warning({type:a.jPlayer.warning.CSS_SELECTOR_METHOD,context:b,message:a.jPlayer.warningMsg.CSS_SELECTOR_METHOD,hint:a.jPlayer.warningHint.CSS_SELECTOR_METHOD});else this._warning({type:a.jPlayer.warning.CSS_SELECTOR_STRING,context:c,message:a.jPlayer.warningMsg.CSS_SELECTOR_STRING,hint:a.jPlayer.warningHint.CSS_SELECTOR_STRING})},duration:function(a){this.options.toggleDuration&&(this.options.captureDuration&&a.stopPropagation(),this._setOption("remainingDuration",!this.options.remainingDuration))},seekBar:function(b){if(this.css.jq.seekBar.length){var c=a(b.currentTarget),d=c.offset(),e=b.pageX-d.left,f=c.width(),g=100*e/f;this.playHead(g)}},playbackRate:function(a){this._setOption("playbackRate",a)},playbackRateBar:function(b){if(this.css.jq.playbackRateBar.length){var c,d,e=a(b.currentTarget),f=e.offset(),g=b.pageX-f.left,h=e.width(),i=e.height()-b.pageY+f.top,j=e.height();c=this.options.verticalPlaybackRate?i/j:g/h,d=c*(this.options.maxPlaybackRate-this.options.minPlaybackRate)+this.options.minPlaybackRate,this.playbackRate(d)}},_updatePlaybackRate:function(){var a=this.options.playbackRate,b=(a-this.options.minPlaybackRate)/(this.options.maxPlaybackRate-this.options.minPlaybackRate);this.status.playbackRateEnabled?(this.css.jq.playbackRateBar.length&&this.css.jq.playbackRateBar.show(),this.css.jq.playbackRateBarValue.length&&(this.css.jq.playbackRateBarValue.show(),this.css.jq.playbackRateBarValue[this.options.verticalPlaybackRate?"height":"width"](100*b+"%"))):(this.css.jq.playbackRateBar.length&&this.css.jq.playbackRateBar.hide(),this.css.jq.playbackRateBarValue.length&&this.css.jq.playbackRateBarValue.hide())},repeat:function(a){var b="object"==typeof a;this._loop(b&&this.options.useStateClassSkin&&this.options.loop?!1:!0)},repeatOff:function(){this._loop(!1)},_loop:function(b){this.options.loop!==b&&(this.options.loop=b,this._updateButtons(),this._trigger(a.jPlayer.event.repeat))},option:function(c,d){var e=c;if(0===arguments.length)return a.extend(!0,{},this.options);if("string"==typeof c){var f=c.split(".");if(d===b){for(var g=a.extend(!0,{},this.options),h=0;h0||Math.floor(d)>0):e=!0,a.internal.mouse={x:b.pageX,y:b.pageY},e&&a.css.jq.gui.fadeIn(a.options.autohide.fadeIn,function(){clearTimeout(a.internal.autohideId),a.internal.autohideId=setTimeout(function(){a.css.jq.gui.fadeOut(a.options.autohide.fadeOut)},a.options.autohide.hold)})};this.css.jq.gui.length&&(this.css.jq.gui.stop(!0,!0),clearTimeout(this.internal.autohideId),delete this.internal.mouse,this.element.unbind(c),this.css.jq.gui.unbind(c),this.status.nativeVideoControls?this.css.jq.gui.hide():this.options.fullWindow&&this.options.autohide.full||!this.options.fullWindow&&this.options.autohide.restored?(this.element.bind(d,e),this.css.jq.gui.bind(d,e),this.css.jq.gui.hide()):this.css.jq.gui.show())},fullScreen:function(a){var b="object"==typeof a;b&&this.options.useStateClassSkin&&this.options.fullScreen?this._setOption("fullScreen",!1):this._setOption("fullScreen",!0)},restoreScreen:function(){this._setOption("fullScreen",!1)},_fullscreenAddEventListeners:function(){var b=this,c=a.jPlayer.nativeFeatures.fullscreen;c.api.fullscreenEnabled&&c.event.fullscreenchange&&("function"!=typeof this.internal.fullscreenchangeHandler&&(this.internal.fullscreenchangeHandler=function(){b._fullscreenchange()}),document.addEventListener(c.event.fullscreenchange,this.internal.fullscreenchangeHandler,!1))},_fullscreenRemoveEventListeners:function(){var b=a.jPlayer.nativeFeatures.fullscreen;this.internal.fullscreenchangeHandler&&document.removeEventListener(b.event.fullscreenchange,this.internal.fullscreenchangeHandler,!1)},_fullscreenchange:function(){this.options.fullScreen&&!a.jPlayer.nativeFeatures.fullscreen.api.fullscreenElement()&&this._setOption("fullScreen",!1)},_requestFullscreen:function(){var b=this.ancestorJq.length?this.ancestorJq[0]:this.element[0],c=a.jPlayer.nativeFeatures.fullscreen;c.used.webkitVideo&&(b=this.htmlElement.video),c.api.fullscreenEnabled&&c.api.requestFullscreen(b)},_exitFullscreen:function(){var b,c=a.jPlayer.nativeFeatures.fullscreen;c.used.webkitVideo&&(b=this.htmlElement.video),c.api.fullscreenEnabled&&c.api.exitFullscreen(b)},_html_initMedia:function(b){var c=a(this.htmlElement.media).empty();a.each(b.track||[],function(a,b){var d=document.createElement("track");d.setAttribute("kind",b.kind?b.kind:""),d.setAttribute("src",b.src?b.src:""),d.setAttribute("srclang",b.srclang?b.srclang:""),d.setAttribute("label",b.label?b.label:""),b.def&&d.setAttribute("default",b.def),c.append(d)}),this.htmlElement.media.src=this.status.src,"none"!==this.options.preload&&this._html_load(),this._trigger(a.jPlayer.event.timeupdate)},_html_setFormat:function(b){var c=this;a.each(this.formats,function(a,d){return c.html.support[d]&&b[d]?(c.status.src=b[d],c.status.format[d]=!0,c.status.formatType=d,!1):void 0})},_html_setAudio:function(a){this._html_setFormat(a),this.htmlElement.media=this.htmlElement.audio,this._html_initMedia(a)},_html_setVideo:function(a){this._html_setFormat(a),this.status.nativeVideoControls&&(this.htmlElement.video.poster=this._validString(a.poster)?a.poster:""),this.htmlElement.media=this.htmlElement.video,this._html_initMedia(a)},_html_resetMedia:function(){this.htmlElement.media&&(this.htmlElement.media.id!==this.internal.video.id||this.status.nativeVideoControls||this.internal.video.jq.css({width:"0px",height:"0px"}),this.htmlElement.media.pause())},_html_clearMedia:function(){this.htmlElement.media&&(this.htmlElement.media.src="about:blank",this.htmlElement.media.load())},_html_load:function(){this.status.waitForLoad&&(this.status.waitForLoad=!1,this.htmlElement.media.load()),clearTimeout(this.internal.htmlDlyCmdId)},_html_play:function(a){var b=this,c=this.htmlElement.media;if(this.androidFix.pause=!1,this._html_load(),this.androidFix.setMedia)this.androidFix.play=!0,this.androidFix.time=a;else if(isNaN(a))c.play();else{this.internal.cmdsIgnored&&c.play();try{if(c.seekable&&!("object"==typeof c.seekable&&c.seekable.length>0))throw 1;c.currentTime=a,c.play()}catch(d){return void(this.internal.htmlDlyCmdId=setTimeout(function(){b.play(a)},250))}}this._html_checkWaitForPlay()},_html_pause:function(a){var b=this,c=this.htmlElement.media;if(this.androidFix.play=!1,a>0?this._html_load():clearTimeout(this.internal.htmlDlyCmdId),c.pause(),this.androidFix.setMedia)this.androidFix.pause=!0,this.androidFix.time=a;else if(!isNaN(a))try{if(c.seekable&&!("object"==typeof c.seekable&&c.seekable.length>0))throw 1;c.currentTime=a}catch(d){return void(this.internal.htmlDlyCmdId=setTimeout(function(){b.pause(a)},250))}a>0&&this._html_checkWaitForPlay()},_html_playHead:function(a){var b=this,c=this.htmlElement.media;this._html_load();try{if("object"==typeof c.seekable&&c.seekable.length>0)c.currentTime=a*c.seekable.end(c.seekable.length-1)/100;else{if(!(c.duration>0)||isNaN(c.duration))throw"e";c.currentTime=a*c.duration/100}}catch(d){return void(this.internal.htmlDlyCmdId=setTimeout(function(){b.playHead(a)},250))}this.status.waitForLoad||this._html_checkWaitForPlay()},_html_checkWaitForPlay:function(){this.status.waitForPlay&&(this.status.waitForPlay=!1,this.css.jq.videoPlay.length&&this.css.jq.videoPlay.hide(),this.status.video&&(this.internal.poster.jq.hide(),this.internal.video.jq.css({width:this.status.width,height:this.status.height})))},_html_setProperty:function(a,b){this.html.audio.available&&(this.htmlElement.audio[a]=b),this.html.video.available&&(this.htmlElement.video[a]=b)},_aurora_setAudio:function(b){var c=this;a.each(this.formats,function(a,d){return c.aurora.support[d]&&b[d]?(c.status.src=b[d],c.status.format[d]=!0,c.status.formatType=d,!1):void 0}),this.aurora.player=new AV.Player.fromURL(this.status.src),this._addAuroraEventListeners(this.aurora.player,this.aurora),"auto"===this.options.preload&&(this._aurora_load(),this.status.waitForLoad=!1)},_aurora_resetMedia:function(){this.aurora.player&&this.aurora.player.stop()},_aurora_clearMedia:function(){},_aurora_load:function(){this.status.waitForLoad&&(this.status.waitForLoad=!1,this.aurora.player.preload())},_aurora_play:function(b){this.status.waitForLoad||isNaN(b)||this.aurora.player.seek(b),this.aurora.player.playing||this.aurora.player.play(),this.status.waitForLoad=!1,this._aurora_checkWaitForPlay(),this._updateButtons(!0),this._trigger(a.jPlayer.event.play)},_aurora_pause:function(b){isNaN(b)||this.aurora.player.seek(1e3*b),this.aurora.player.pause(),b>0&&this._aurora_checkWaitForPlay(),this._updateButtons(!1),this._trigger(a.jPlayer.event.pause)},_aurora_playHead:function(a){this.aurora.player.duration>0&&this.aurora.player.seek(a*this.aurora.player.duration/100),this.status.waitForLoad||this._aurora_checkWaitForPlay()},_aurora_checkWaitForPlay:function(){this.status.waitForPlay&&(this.status.waitForPlay=!1)},_aurora_volume:function(a){this.aurora.player.volume=100*a},_aurora_mute:function(a){a?(this.aurora.properties.lastvolume=this.aurora.player.volume,this.aurora.player.volume=0):this.aurora.player.volume=this.aurora.properties.lastvolume,this.aurora.properties.muted=a},_flash_setAudio:function(b){var c=this;try{a.each(this.formats,function(a,d){if(c.flash.support[d]&&b[d]){switch(d){case"m4a":case"fla":c._getMovie().fl_setAudio_m4a(b[d]);break;case"mp3":c._getMovie().fl_setAudio_mp3(b[d]);break;case"rtmpa":c._getMovie().fl_setAudio_rtmp(b[d])}return c.status.src=b[d],c.status.format[d]=!0,c.status.formatType=d,!1}}),"auto"===this.options.preload&&(this._flash_load(),this.status.waitForLoad=!1)}catch(d){this._flashError(d)}},_flash_setVideo:function(b){var c=this;try{a.each(this.formats,function(a,d){if(c.flash.support[d]&&b[d]){switch(d){case"m4v":case"flv":c._getMovie().fl_setVideo_m4v(b[d]);break;case"rtmpv":c._getMovie().fl_setVideo_rtmp(b[d])}return c.status.src=b[d],c.status.format[d]=!0,c.status.formatType=d,!1}}),"auto"===this.options.preload&&(this._flash_load(),this.status.waitForLoad=!1)}catch(d){this._flashError(d)}},_flash_resetMedia:function(){this.internal.flash.jq.css({width:"0px",height:"0px"}),this._flash_pause(0/0)},_flash_clearMedia:function(){try{this._getMovie().fl_clearMedia()}catch(a){this._flashError(a)}},_flash_load:function(){try{this._getMovie().fl_load()}catch(a){this._flashError(a)}this.status.waitForLoad=!1},_flash_play:function(a){try{this._getMovie().fl_play(a)}catch(b){this._flashError(b)}this.status.waitForLoad=!1,this._flash_checkWaitForPlay()},_flash_pause:function(a){try{this._getMovie().fl_pause(a)}catch(b){this._flashError(b)}a>0&&(this.status.waitForLoad=!1,this._flash_checkWaitForPlay())},_flash_playHead:function(a){try{this._getMovie().fl_play_head(a)}catch(b){this._flashError(b)}this.status.waitForLoad||this._flash_checkWaitForPlay()},_flash_checkWaitForPlay:function(){this.status.waitForPlay&&(this.status.waitForPlay=!1,this.css.jq.videoPlay.length&&this.css.jq.videoPlay.hide(),this.status.video&&(this.internal.poster.jq.hide(),this.internal.flash.jq.css({width:this.status.width,height:this.status.height})))},_flash_volume:function(a){try{this._getMovie().fl_volume(a)}catch(b){this._flashError(b)}},_flash_mute:function(a){try{this._getMovie().fl_mute(a)}catch(b){this._flashError(b)}},_getMovie:function(){return document[this.internal.flash.id]},_getFlashPluginVersion:function(){var a,b=0;if(window.ActiveXObject)try{if(a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash")){var c=a.GetVariable("$version");c&&(c=c.split(" ")[1].split(","),b=parseInt(c[0],10)+"."+parseInt(c[1],10))}}catch(d){}else navigator.plugins&&navigator.mimeTypes.length>0&&(a=navigator.plugins["Shockwave Flash"],a&&(b=navigator.plugins["Shockwave Flash"].description.replace(/.*\s(\d+\.\d+).*/,"$1")));return 1*b},_checkForFlash:function(a){var b=!1;return this._getFlashPluginVersion()>=a&&(b=!0),b},_validString:function(a){return a&&"string"==typeof a},_limitValue:function(a,b,c){return b>a?b:a>c?c:a},_urlNotSetError:function(b){this._error({type:a.jPlayer.error.URL_NOT_SET,context:b,message:a.jPlayer.errorMsg.URL_NOT_SET,hint:a.jPlayer.errorHint.URL_NOT_SET})},_flashError:function(b){var c;c=this.internal.ready?"FLASH_DISABLED":"FLASH",this._error({type:a.jPlayer.error[c],context:this.internal.flash.swf,message:a.jPlayer.errorMsg[c]+b.message,hint:a.jPlayer.errorHint[c]}),this.internal.flash.jq.css({width:"1px",height:"1px"})},_error:function(b){this._trigger(a.jPlayer.event.error,b),this.options.errorAlerts&&this._alert("Error!"+(b.message?"\n"+b.message:"")+(b.hint?"\n"+b.hint:"")+"\nContext: "+b.context)},_warning:function(c){this._trigger(a.jPlayer.event.warning,b,c),this.options.warningAlerts&&this._alert("Warning!"+(c.message?"\n"+c.message:"")+(c.hint?"\n"+c.hint:"")+"\nContext: "+c.context)},_alert:function(a){var b="jPlayer "+this.version.script+" : id='"+this.internal.self.id+"' : "+a;this.options.consoleAlerts?window.console&&window.console.log&&window.console.log(b):alert(b)},_emulateHtmlBridge:function(){var b=this;a.each(a.jPlayer.emulateMethods.split(/\s+/g),function(a,c){b.internal.domNode[c]=function(a){b[c](a)}}),a.each(a.jPlayer.event,function(c,d){var e=!0;a.each(a.jPlayer.reservedEvent.split(/\s+/g),function(a,b){return b===c?(e=!1,!1):void 0}),e&&b.element.bind(d+".jPlayer.jPlayerHtml",function(){b._emulateHtmlUpdate();var a=document.createEvent("Event");a.initEvent(c,!1,!0),b.internal.domNode.dispatchEvent(a)})})},_emulateHtmlUpdate:function(){var b=this;a.each(a.jPlayer.emulateStatus.split(/\s+/g),function(a,c){b.internal.domNode[c]=b.status[c]}),a.each(a.jPlayer.emulateOptions.split(/\s+/g),function(a,c){b.internal.domNode[c]=b.options[c]})},_destroyHtmlBridge:function(){var b=this;this.element.unbind(".jPlayerHtml");var c=a.jPlayer.emulateMethods+" "+a.jPlayer.emulateStatus+" "+a.jPlayer.emulateOptions;a.each(c.split(/\s+/g),function(a,c){delete b.internal.domNode[c]})}},a.jPlayer.error={FLASH:"e_flash",FLASH_DISABLED:"e_flash_disabled",NO_SOLUTION:"e_no_solution",NO_SUPPORT:"e_no_support",URL:"e_url",URL_NOT_SET:"e_url_not_set",VERSION:"e_version"},a.jPlayer.errorMsg={FLASH:"jPlayer's Flash fallback is not configured correctly, or a command was issued before the jPlayer Ready event. Details: ",FLASH_DISABLED:"jPlayer's Flash fallback has been disabled by the browser due to the CSS rules you have used. Details: ",NO_SOLUTION:"No solution can be found by jPlayer in this browser. Neither HTML nor Flash can be used.",NO_SUPPORT:"It is not possible to play any media format provided in setMedia() on this browser using your current options.",URL:"Media URL could not be loaded.",URL_NOT_SET:"Attempt to issue media playback commands, while no media url is set.",VERSION:"jPlayer "+a.jPlayer.prototype.version.script+" needs Jplayer.swf version "+a.jPlayer.prototype.version.needFlash+" but found "},a.jPlayer.errorHint={FLASH:"Check your swfPath option and that Jplayer.swf is there.",FLASH_DISABLED:"Check that you have not display:none; the jPlayer entity or any ancestor.",NO_SOLUTION:"Review the jPlayer options: support and supplied.",NO_SUPPORT:"Video or audio formats defined in the supplied option are missing.",URL:"Check media URL is valid.",URL_NOT_SET:"Use setMedia() to set the media URL.",VERSION:"Update jPlayer files."},a.jPlayer.warning={CSS_SELECTOR_COUNT:"e_css_selector_count",CSS_SELECTOR_METHOD:"e_css_selector_method",CSS_SELECTOR_STRING:"e_css_selector_string",OPTION_KEY:"e_option_key"},a.jPlayer.warningMsg={CSS_SELECTOR_COUNT:"The number of css selectors found did not equal one: ",CSS_SELECTOR_METHOD:"The methodName given in jPlayer('cssSelector') is not a valid jPlayer method.",CSS_SELECTOR_STRING:"The methodCssSelector given in jPlayer('cssSelector') is not a String or is empty.",OPTION_KEY:"The option requested in jPlayer('option') is undefined."},a.jPlayer.warningHint={CSS_SELECTOR_COUNT:"Check your css selector and the ancestor.",CSS_SELECTOR_METHOD:"Check your method name.",CSS_SELECTOR_STRING:"Check your css selector is a string.",OPTION_KEY:"Check your option name."}}); -- 2.20.1 From 1b9cdd6220596c93a73c180249a10e6d6f9bd3e4 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Fri, 6 Mar 2026 14:11:37 +0100 Subject: [PATCH 02/16] Add can_sell --- src/catalogue/api/views.py | 2 +- src/catalogue/forms.py | 2 ++ src/catalogue/migrations/0055_book_can_sell.py | 18 ++++++++++++++++++ src/catalogue/models/book.py | 5 ++++- src/wolnelektury/settings/contrib.py | 2 +- 5 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 src/catalogue/migrations/0055_book_can_sell.py diff --git a/src/catalogue/api/views.py b/src/catalogue/api/views.py index a4c0173e7..3449339e5 100644 --- a/src/catalogue/api/views.py +++ b/src/catalogue/api/views.py @@ -190,7 +190,7 @@ class BookFilter(dfilters.FilterSet): sort = dfilters.OrderingFilter( fields=( ('sort_key_author', 'alpha'), - ('popularity', 'popularity'), + ('popularity__count', 'popularity'), ) ) tag = dfilters.ModelMultipleChoiceFilter( diff --git a/src/catalogue/forms.py b/src/catalogue/forms.py index 919ff3a62..7e543df29 100644 --- a/src/catalogue/forms.py +++ b/src/catalogue/forms.py @@ -20,6 +20,7 @@ class BookImportForm(forms.Form): logo = forms.CharField(required=False) logo_mono = forms.CharField(required=False) logo_alt = forms.CharField(required=False) + can_sell = forms.BooleanField(required=False) def clean(self): from django.core.files.base import ContentFile @@ -40,6 +41,7 @@ class BookImportForm(forms.Form): logo=self.cleaned_data['logo'], logo_mono=self.cleaned_data['logo_mono'], logo_alt=self.cleaned_data['logo_alt'], + can_sell=self.cleaned_data['can_sell'], **kwargs) diff --git a/src/catalogue/migrations/0055_book_can_sell.py b/src/catalogue/migrations/0055_book_can_sell.py new file mode 100644 index 000000000..3f3df552e --- /dev/null +++ b/src/catalogue/migrations/0055_book_can_sell.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.8 on 2026-03-06 13:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('catalogue', '0054_alter_book_sort_key_alter_book_sort_key_author_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='book', + name='can_sell', + field=models.BooleanField(default=True, verbose_name='do sprzedaży'), + ), + ] diff --git a/src/catalogue/models/book.py b/src/catalogue/models/book.py index 375c79a8e..8597eac75 100644 --- a/src/catalogue/models/book.py +++ b/src/catalogue/models/book.py @@ -61,6 +61,7 @@ class Book(models.Model): preview_until = models.DateField('prapremiera do', blank=True, null=True) preview_key = models.CharField(max_length=32, blank=True, null=True) findable = models.BooleanField('wyszukiwalna', default=True, db_index=True) + can_sell = models.BooleanField('do sprzedaży', default=True) # files generated during publication xml_file = fields.XmlField(storage=bofh_storage, with_etag=False) @@ -683,7 +684,7 @@ class Book(models.Model): @classmethod def from_text_and_meta(cls, raw_file, book_info, overwrite=False, dont_build=None, search_index=True, - remote_gallery_url=None, days=0, findable=True, logo=None, logo_mono=None, logo_alt=None): + remote_gallery_url=None, days=0, findable=True, logo=None, logo_mono=None, logo_alt=None, can_sell=None): from catalogue import tasks if dont_build is None: @@ -738,6 +739,8 @@ class Book(models.Model): extra['logo_mono'] = logo_mono if logo_alt: extra['logo_alt'] = logo_alt + if can_sell is not None: + book.can_sell = can_sell book.extra_info = json.dumps(extra) book.load_abstract() book.load_toc() diff --git a/src/wolnelektury/settings/contrib.py b/src/wolnelektury/settings/contrib.py index 465286bbb..1e74dbf43 100644 --- a/src/wolnelektury/settings/contrib.py +++ b/src/wolnelektury/settings/contrib.py @@ -24,7 +24,7 @@ PAYPAL_ENABLED = True REST_FRAMEWORK = { "DEFAULT_RENDERER_CLASSES": ( 'rest_framework.renderers.JSONRenderer', - 'rest_framework.renderers.BrowsableAPIRenderer', + #'rest_framework.renderers.BrowsableAPIRenderer', 'api.renderers.LegacyXMLRenderer', ), 'DEFAULT_AUTHENTICATION_CLASSES': ( -- 2.20.1 From 68be98c55bfd8af8acbf9490d7db5f3f0c528d60 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Fri, 6 Mar 2026 14:53:44 +0100 Subject: [PATCH 03/16] Partners --- src/api/urls.py | 2 ++ src/partners/__init__.py | 0 src/partners/admin.py | 15 +++++++++++ src/partners/api/urls.py | 11 ++++++++ src/partners/api/views.py | 36 +++++++++++++++++++++++++ src/partners/apps.py | 6 +++++ src/partners/migrations/0001_initial.py | 35 ++++++++++++++++++++++++ src/partners/migrations/__init__.py | 0 src/partners/models.py | 26 ++++++++++++++++++ src/partners/tests.py | 3 +++ src/partners/views.py | 3 +++ src/wolnelektury/settings/apps.py | 1 + 12 files changed, 138 insertions(+) create mode 100644 src/partners/__init__.py create mode 100644 src/partners/admin.py create mode 100644 src/partners/api/urls.py create mode 100644 src/partners/api/views.py create mode 100644 src/partners/apps.py create mode 100644 src/partners/migrations/0001_initial.py create mode 100644 src/partners/migrations/__init__.py create mode 100644 src/partners/models.py create mode 100644 src/partners/tests.py create mode 100644 src/partners/views.py diff --git a/src/api/urls.py b/src/api/urls.py index 182e0dd6f..1a1b4f337 100644 --- a/src/api/urls.py +++ b/src/api/urls.py @@ -26,6 +26,8 @@ urlpatterns1 = [ path('', include('bookmarks.api.urls')), path('', include('search.api.urls')), path('', include('push.api.urls')), + + path('partners/', include('partners.api.urls')), ] diff --git a/src/partners/__init__.py b/src/partners/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/partners/admin.py b/src/partners/admin.py new file mode 100644 index 000000000..3ad6775ce --- /dev/null +++ b/src/partners/admin.py @@ -0,0 +1,15 @@ +from django.contrib import admin +from . import models + + +class PriceLevelInline(admin.TabularInline): + model = models.PriceLevel + extra = 0 + + +@admin.register(models.Partner) +class PartnerAdmin(admin.ModelAdmin): + inlines = [ + PriceLevelInline, + ] + diff --git a/src/partners/api/urls.py b/src/partners/api/urls.py new file mode 100644 index 000000000..df250fdd6 --- /dev/null +++ b/src/partners/api/urls.py @@ -0,0 +1,11 @@ +# This file is part of Wolne Lektury, licensed under GNU Affero GPLv3 or later. +# Copyright © Fundacja Wolne Lektury. See NOTICE for more information. +# +from django.urls import path +from . import views + + +urlpatterns = [ + path('/books/', + views.PartnerBooksView.as_view()), +] diff --git a/src/partners/api/views.py b/src/partners/api/views.py new file mode 100644 index 000000000..f8aaa0568 --- /dev/null +++ b/src/partners/api/views.py @@ -0,0 +1,36 @@ +from django.utils.decorators import method_decorator +from django.views.decorators.cache import never_cache +from rest_framework.generics import (ListAPIView, get_object_or_404) +from rest_framework import serializers +from api.fields import AbsoluteURLField +from catalogue.models import Book +from partners import models + + + + +class PartnerBookSerializer(serializers.ModelSerializer): + url = AbsoluteURLField(view_name='catalogue_api_book', view_args=['slug']) + price = serializers.SerializerMethodField() + + class Meta: + model = Book + fields = ['url', 'epub_url', 'price'] + + def get_price(self, obj): + if obj.pages is None: + return None + return self.context['partner'].get_price(obj.pages) + + +@method_decorator(never_cache, name='dispatch') +class PartnerBooksView(ListAPIView): + serializer_class = PartnerBookSerializer + + def get_serializer_context(self): + ctx = super().get_serializer_context() + ctx['partner'] = get_object_or_404(models.Partner, key=self.kwargs['key']) + return ctx + + def get_queryset(self): + return Book.objects.filter(parent=None).filter(can_sell=True).exclude(pages=None) diff --git a/src/partners/apps.py b/src/partners/apps.py new file mode 100644 index 000000000..07969c76d --- /dev/null +++ b/src/partners/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class PartnersConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'partners' diff --git a/src/partners/migrations/0001_initial.py b/src/partners/migrations/0001_initial.py new file mode 100644 index 000000000..10d88f75e --- /dev/null +++ b/src/partners/migrations/0001_initial.py @@ -0,0 +1,35 @@ +# Generated by Django 4.0.8 on 2026-03-06 13:32 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Partner', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('key', models.CharField(max_length=255)), + ], + ), + migrations.CreateModel( + name='PriceLevel', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('min_pages', models.IntegerField(blank=True, null=True)), + ('price', models.IntegerField()), + ('partner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='partners.partner')), + ], + options={ + 'ordering': ('price',), + }, + ), + ] diff --git a/src/partners/migrations/__init__.py b/src/partners/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/partners/models.py b/src/partners/models.py new file mode 100644 index 000000000..9e58e2a88 --- /dev/null +++ b/src/partners/models.py @@ -0,0 +1,26 @@ +from django.db import models + + +class Partner(models.Model): + name = models.CharField(max_length=255) + key = models.CharField(max_length=255) + + def __str__(self): + return self.name + + def get_price(self, pages): + price_obj = self.pricelevel_set.exclude( + min_pages__gt=pages + ).order_by('-price').first() + if price_obj is None: + return None + return price_obj.price + + +class PriceLevel(models.Model): + partner = models.ForeignKey(Partner, models.CASCADE) + min_pages = models.IntegerField(null=True, blank=True) + price = models.IntegerField() + + class Meta: + ordering = ('price',) diff --git a/src/partners/tests.py b/src/partners/tests.py new file mode 100644 index 000000000..7ce503c2d --- /dev/null +++ b/src/partners/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/src/partners/views.py b/src/partners/views.py new file mode 100644 index 000000000..91ea44a21 --- /dev/null +++ b/src/partners/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/src/wolnelektury/settings/apps.py b/src/wolnelektury/settings/apps.py index b9d507e86..c90152cde 100644 --- a/src/wolnelektury/settings/apps.py +++ b/src/wolnelektury/settings/apps.py @@ -41,6 +41,7 @@ INSTALLED_APPS_OUR = [ 'push', 'club', 'redirects', + 'partners', ] INSTALLED_APPS_CONTRIB = [ -- 2.20.1 From 0bcc7528161ce32c08247cf87c6096b888cfb153 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Fri, 6 Mar 2026 15:05:26 +0100 Subject: [PATCH 04/16] decimal prices --- .../migrations/0002_alter_pricelevel_price.py | 18 ++++++++++++++++++ src/partners/models.py | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 src/partners/migrations/0002_alter_pricelevel_price.py diff --git a/src/partners/migrations/0002_alter_pricelevel_price.py b/src/partners/migrations/0002_alter_pricelevel_price.py new file mode 100644 index 000000000..c7a405593 --- /dev/null +++ b/src/partners/migrations/0002_alter_pricelevel_price.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.8 on 2026-03-06 14:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('partners', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='pricelevel', + name='price', + field=models.DecimalField(decimal_places=2, max_digits=10), + ), + ] diff --git a/src/partners/models.py b/src/partners/models.py index 9e58e2a88..32e8a1bb2 100644 --- a/src/partners/models.py +++ b/src/partners/models.py @@ -20,7 +20,7 @@ class Partner(models.Model): class PriceLevel(models.Model): partner = models.ForeignKey(Partner, models.CASCADE) min_pages = models.IntegerField(null=True, blank=True) - price = models.IntegerField() + price = models.DecimalField(max_digits=10, decimal_places=2) class Meta: ordering = ('price',) -- 2.20.1 From 61ff9348beb56e3623378f25713bf382e3c2078c Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Fri, 6 Mar 2026 15:14:27 +0100 Subject: [PATCH 05/16] partner api --- src/partners/api/views.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/partners/api/views.py b/src/partners/api/views.py index f8aaa0568..ccae25ebd 100644 --- a/src/partners/api/views.py +++ b/src/partners/api/views.py @@ -4,18 +4,34 @@ from rest_framework.generics import (ListAPIView, get_object_or_404) from rest_framework import serializers from api.fields import AbsoluteURLField from catalogue.models import Book +from catalogue.api.fields import EmbargoURLField +from catalogue.api.serializers import BookSerializer2 from partners import models -class PartnerBookSerializer(serializers.ModelSerializer): - url = AbsoluteURLField(view_name='catalogue_api_book', view_args=['slug']) +class PartnerBookSerializer(BookSerializer2): price = serializers.SerializerMethodField() class Meta: model = Book - fields = ['url', 'epub_url', 'price'] + fields = [ + 'slug', 'title', 'full_sort_key', + 'href', 'url', 'language', + 'authors', 'translators', + 'epochs', 'genres', 'kinds', + 'children', + 'parent', 'preview', + 'epub', 'mobi', 'pdf', 'html', 'txt', 'fb2', 'xml', + 'cover_thumb', 'cover', + 'isbn_pdf', 'isbn_epub', 'isbn_mobi', + 'abstract', + 'has_mp3_file', 'has_sync_file', + 'elevenreader_link', 'content_warnings', 'audiences', + 'changed_at', 'read_time', 'pages', 'redakcja', + 'price', + ] def get_price(self, obj): if obj.pages is None: -- 2.20.1 From 37c0f94336f330a8660a46b8b3052a24f4c9d5b5 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Fri, 13 Mar 2026 10:39:51 +0100 Subject: [PATCH 06/16] maint: move code --- src/social/api/serializers.py | 163 ++++++++++++++++++++++++++++++ src/social/api/views.py | 181 +++------------------------------- 2 files changed, 175 insertions(+), 169 deletions(-) create mode 100644 src/social/api/serializers.py diff --git a/src/social/api/serializers.py b/src/social/api/serializers.py new file mode 100644 index 000000000..7a596d261 --- /dev/null +++ b/src/social/api/serializers.py @@ -0,0 +1,163 @@ +# This file is part of Wolne Lektury, licensed under GNU Affero GPLv3 or later. +# Copyright © Fundacja Wolne Lektury. See NOTICE for more information. +# +from rest_framework import serializers +import catalogue.models +from social import models + + +class SettingsSerializer(serializers.ModelSerializer): + class Meta: + model = models.UserProfile + fields = ['notifications'] + + +class UserListItemsField(serializers.Field): + def to_representation(self, value): + return value.userlistitem_set.exclude(deleted=True).exclude(book=None).values_list('book__slug', flat=True) + + def to_internal_value(self, value): + return {'books': catalogue.models.Book.objects.filter(slug__in=value)} + + +class UserListSerializer(serializers.ModelSerializer): + client_id = serializers.CharField(write_only=True, required=False) + books = UserListItemsField(source='*', required=False) + timestamp = serializers.IntegerField(required=False) + + class Meta: + model = models.UserList + fields = [ + 'timestamp', + 'client_id', + 'name', + 'slug', + 'favorites', + 'deleted', + 'books', + ] + read_only_fields = [ + 'favorites', + 'slug', + ] + extra_kwargs = { + 'slug': { + 'required': False + } + } + + def create(self, validated_data): + instance = models.UserList.get_by_name( + validated_data['user'], + validated_data['name'], + create=True + ) + if 'books' in validated_data: + instance.userlistitem_set.all().delete() + for book in validated_data['books']: + instance.append(book) + return instance + + def update(self, instance, validated_data): + super().update(instance, validated_data) + if 'books' in validated_data: + instance.userlistitem_set.all().delete() + for book in validated_data['books']: + instance.append(instance) + return instance + + +class UserListBooksSerializer(UserListSerializer): + class Meta: + model = models.UserList + fields = ['books'] + + +class UserListItemSerializer(serializers.ModelSerializer): + client_id = serializers.CharField(write_only=True, required=False) + favorites = serializers.BooleanField(required=False) + list_slug = serializers.SlugRelatedField( + queryset=models.UserList.objects.all(), + source='list', + slug_field='slug', + required=False, + ) + timestamp = serializers.IntegerField(required=False) + book_slug = serializers.SlugRelatedField( + queryset=catalogue.models.Book.objects.all(), + source='book', + slug_field='slug', + required=False + ) + + class Meta: + model = models.UserListItem + fields = [ + 'client_id', + 'uuid', + 'order', + 'list_slug', + 'timestamp', + 'favorites', + 'deleted', + + 'book_slug', + 'fragment', + 'quote', + 'bookmark', + 'note', + ] + extra_kwargs = { + 'order': { + 'required': False + } + } + + +class ProgressSerializer(serializers.ModelSerializer): + book = serializers.HyperlinkedRelatedField( + read_only=True, + view_name='catalogue_api_book', + lookup_field='slug' + ) + book_slug = serializers.SlugRelatedField( + queryset=catalogue.models.Book.objects.all(), + source='book', + slug_field='slug') + timestamp = serializers.IntegerField(required=False) + + class Meta: + model = models.Progress + fields = [ + 'timestamp', + 'book', 'book_slug', 'last_mode', 'text_percent', + 'text_anchor', + 'audio_percent', + 'audio_timestamp', + 'implicit_text_percent', + 'implicit_text_anchor', + 'implicit_audio_percent', + 'implicit_audio_timestamp', + ] + extra_kwargs = { + 'last_mode': { + 'required': False, + 'default': 'text', + } + } + + +class TextProgressSerializer(serializers.ModelSerializer): + class Meta: + model = models.Progress + fields = [ + 'text_percent', + 'text_anchor', + ] + read_only_fields = ['text_percent'] + +class AudioProgressSerializer(serializers.ModelSerializer): + class Meta: + model = models.Progress + fields = ['audio_percent', 'audio_timestamp'] + read_only_fields = ['audio_percent'] diff --git a/src/social/api/views.py b/src/social/api/views.py index f89de2704..a43bec277 100644 --- a/src/social/api/views.py +++ b/src/social/api/views.py @@ -8,7 +8,6 @@ from django.utils.timezone import now, utc from rest_framework.generics import ListAPIView, ListCreateAPIView, RetrieveAPIView, RetrieveUpdateAPIView, RetrieveUpdateDestroyAPIView, get_object_or_404 from rest_framework.permissions import SAFE_METHODS, IsAuthenticated, IsAuthenticatedOrReadOnly from rest_framework.response import Response -from rest_framework import serializers from rest_framework.views import APIView from api.models import BookUserData from api.utils import vary_on_auth, never_cache @@ -20,18 +19,14 @@ from social.views import get_sets_for_book_ids from social.utils import likes from social import models import bookmarks.models +from . import serializers from bookmarks.api.views import BookmarkSerializer -class SettingsSerializer(serializers.ModelSerializer): - class Meta: - model = models.UserProfile - fields = ['notifications'] - class SettingsView(RetrieveUpdateAPIView): permission_classes = [IsAuthenticated] - serializer_class = SettingsSerializer + serializer_class = serializers.SettingsSerializer def get_object(self): return models.UserProfile.get_for(self.request.user) @@ -102,113 +97,11 @@ class MyLikesView(APIView): ) -class UserListItemsField(serializers.Field): - def to_representation(self, value): - return value.userlistitem_set.exclude(deleted=True).exclude(book=None).values_list('book__slug', flat=True) - - def to_internal_value(self, value): - return {'books': catalogue.models.Book.objects.filter(slug__in=value)} - - -class UserListSerializer(serializers.ModelSerializer): - client_id = serializers.CharField(write_only=True, required=False) - books = UserListItemsField(source='*', required=False) - timestamp = serializers.IntegerField(required=False) - - class Meta: - model = models.UserList - fields = [ - 'timestamp', - 'client_id', - 'name', - 'slug', - 'favorites', - 'deleted', - 'books', - ] - read_only_fields = [ - 'favorites', - 'slug', - ] - extra_kwargs = { - 'slug': { - 'required': False - } - } - - def create(self, validated_data): - instance = models.UserList.get_by_name( - validated_data['user'], - validated_data['name'], - create=True - ) - if 'books' in validated_data: - instance.userlistitem_set.all().delete() - for book in validated_data['books']: - instance.append(book) - return instance - - def update(self, instance, validated_data): - super().update(instance, validated_data) - if 'books' in validated_data: - instance.userlistitem_set.all().delete() - for book in validated_data['books']: - instance.append(instance) - return instance - - -class UserListBooksSerializer(UserListSerializer): - class Meta: - model = models.UserList - fields = ['books'] - - -class UserListItemSerializer(serializers.ModelSerializer): - client_id = serializers.CharField(write_only=True, required=False) - favorites = serializers.BooleanField(required=False) - list_slug = serializers.SlugRelatedField( - queryset=models.UserList.objects.all(), - source='list', - slug_field='slug', - required=False, - ) - timestamp = serializers.IntegerField(required=False) - book_slug = serializers.SlugRelatedField( - queryset=Book.objects.all(), - source='book', - slug_field='slug', - required=False - ) - - class Meta: - model = models.UserListItem - fields = [ - 'client_id', - 'uuid', - 'order', - 'list_slug', - 'timestamp', - 'favorites', - 'deleted', - - 'book_slug', - 'fragment', - 'quote', - 'bookmark', - 'note', - ] - extra_kwargs = { - 'order': { - 'required': False - } - } - - @never_cache class ListsView(ListCreateAPIView): permission_classes = [IsAuthenticated] #pagination_class = None - serializer_class = UserListSerializer + serializer_class = serializers.UserListSerializer def get_queryset(self): return models.UserList.objects.filter( @@ -225,7 +118,7 @@ class ListsView(ListCreateAPIView): class ListView(RetrieveUpdateDestroyAPIView): # TODO: check if can modify permission_classes = [IsAuthenticatedOrReadOnly] - serializer_class = UserListSerializer + serializer_class = serializers.UserListSerializer def get_object(self): if self.request.method in SAFE_METHODS: @@ -247,7 +140,7 @@ class ListView(RetrieveUpdateDestroyAPIView): serializer.save(user=self.request.user) def post(self, request, slug): - serializer = UserListBooksSerializer(data=request.data) + serializer = serializers.UserListBooksSerializer(data=request.data) serializer.is_valid(raise_exception=True) instance = self.get_object() for book in serializer.validated_data['books']: @@ -300,60 +193,10 @@ class ShelfView(ListAPIView): return books - -class ProgressSerializer(serializers.ModelSerializer): - book = serializers.HyperlinkedRelatedField( - read_only=True, - view_name='catalogue_api_book', - lookup_field='slug' - ) - book_slug = serializers.SlugRelatedField( - queryset=Book.objects.all(), - source='book', - slug_field='slug') - timestamp = serializers.IntegerField(required=False) - - class Meta: - model = models.Progress - fields = [ - 'timestamp', - 'book', 'book_slug', 'last_mode', 'text_percent', - 'text_anchor', - 'audio_percent', - 'audio_timestamp', - 'implicit_text_percent', - 'implicit_text_anchor', - 'implicit_audio_percent', - 'implicit_audio_timestamp', - ] - extra_kwargs = { - 'last_mode': { - 'required': False, - 'default': 'text', - } - } - - -class TextProgressSerializer(serializers.ModelSerializer): - class Meta: - model = models.Progress - fields = [ - 'text_percent', - 'text_anchor', - ] - read_only_fields = ['text_percent'] - -class AudioProgressSerializer(serializers.ModelSerializer): - class Meta: - model = models.Progress - fields = ['audio_percent', 'audio_timestamp'] - read_only_fields = ['audio_percent'] - - @never_cache class ProgressListView(ListAPIView): permission_classes = [IsAuthenticated] - serializer_class = ProgressSerializer + serializer_class = serializers.ProgressSerializer def get_queryset(self): return models.Progress.objects.filter(user=self.request.user).order_by('-updated_at') @@ -372,13 +215,13 @@ class ProgressMixin: @never_cache class ProgressView(ProgressMixin, RetrieveAPIView): permission_classes = [IsAuthenticated] - serializer_class = ProgressSerializer + serializer_class = serializers.ProgressSerializer @never_cache class TextProgressView(ProgressMixin, RetrieveUpdateAPIView): permission_classes = [IsAuthenticated] - serializer_class = TextProgressSerializer + serializer_class = serializers.TextProgressSerializer def perform_update(self, serializer): serializer.instance.last_mode = 'text' @@ -388,7 +231,7 @@ class TextProgressView(ProgressMixin, RetrieveUpdateAPIView): @never_cache class AudioProgressView(ProgressMixin, RetrieveUpdateAPIView): permission_classes = [IsAuthenticated] - serializer_class = AudioProgressSerializer + serializer_class = serializers.AudioProgressSerializer def perform_update(self, serializer): serializer.instance.last_mode = 'audio' @@ -458,7 +301,7 @@ class SyncView(ListAPIView): class ProgressSyncView(SyncView): model = models.Progress - serializer_class = ProgressSerializer + serializer_class = serializers.ProgressSerializer sync_id_field = 'book__slug' sync_id_serializer_field = 'book_slug' @@ -466,12 +309,12 @@ class ProgressSyncView(SyncView): class UserListSyncView(SyncView): model = models.UserList - serializer_class = UserListSerializer + serializer_class = serializers.UserListSerializer class UserListItemSyncView(SyncView): model = models.UserListItem - serializer_class = UserListItemSerializer + serializer_class = serializers.UserListItemSerializer sync_id_field = 'uuid' sync_id_serializer_field = 'uuid' -- 2.20.1 From 93e3e1f84811affff7f6ba0ad808c813904da42b Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Fri, 13 Mar 2026 12:33:48 +0100 Subject: [PATCH 07/16] v3: User lists --- src/api/urls.py | 2 + src/api/views.py | 6 +++ src/social/api/serializers.py | 41 +++++++++++++-- src/social/api/urls2.py | 4 +- src/social/api/views.py | 95 ++++++++++++++++++++++++++--------- 5 files changed, 118 insertions(+), 30 deletions(-) diff --git a/src/api/urls.py b/src/api/urls.py index 1a1b4f337..867e1fd09 100644 --- a/src/api/urls.py +++ b/src/api/urls.py @@ -33,6 +33,8 @@ urlpatterns1 = [ urlpatterns = [ path('2/', include((urlpatterns1, 'api'), namespace="v2")), + path('3/', include((urlpatterns1, 'api'), namespace="v3")), + path('1/', views.Unsupported.as_view()), path('oauth/request_token/', csrf_exempt(views.OAuth1RequestTokenView.as_view())), path('oauth/authorize/', views.oauth_user_auth, name='oauth_user_auth'), diff --git a/src/api/views.py b/src/api/views.py index 5d526780a..290dc93fe 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -426,3 +426,9 @@ class ConsumeSessionTransferTokenView(View): login(request, ott.user) return redirect(next_url) + + +class Unsupported(APIView): + get = post = put = delete = lambda self, request, path: Response({ + "error": "unsupported-api", + }, status=410) diff --git a/src/social/api/serializers.py b/src/social/api/serializers.py index 7a596d261..dadf24935 100644 --- a/src/social/api/serializers.py +++ b/src/social/api/serializers.py @@ -12,7 +12,7 @@ class SettingsSerializer(serializers.ModelSerializer): fields = ['notifications'] -class UserListItemsField(serializers.Field): +class UserListBooksField(serializers.Field): def to_representation(self, value): return value.userlistitem_set.exclude(deleted=True).exclude(book=None).values_list('book__slug', flat=True) @@ -20,9 +20,9 @@ class UserListItemsField(serializers.Field): return {'books': catalogue.models.Book.objects.filter(slug__in=value)} -class UserListSerializer(serializers.ModelSerializer): +class UserListSerializerV2(serializers.ModelSerializer): client_id = serializers.CharField(write_only=True, required=False) - books = UserListItemsField(source='*', required=False) + books = UserListBooksField(source='*', required=False) timestamp = serializers.IntegerField(required=False) class Meta: @@ -67,7 +67,7 @@ class UserListSerializer(serializers.ModelSerializer): return instance -class UserListBooksSerializer(UserListSerializer): +class UserListBooksSerializer(UserListSerializerV2): class Meta: model = models.UserList fields = ['books'] @@ -114,6 +114,39 @@ class UserListItemSerializer(serializers.ModelSerializer): } +class UserListSerializerV3(serializers.ModelSerializer): + client_id = serializers.CharField(write_only=True, required=False) + timestamp = serializers.IntegerField(required=False) + + class Meta: + model = models.UserList + fields = [ + 'timestamp', + 'client_id', + 'name', + 'slug', + 'favorites', + 'deleted', + ] + read_only_fields = [ + 'favorites', + 'slug', + ] + extra_kwargs = { + 'slug': { + 'required': False + } + } + + def create(self, validated_data): + instance = models.UserList.get_by_name( + validated_data['user'], + validated_data['name'], + create=True + ) + return instance + + class ProgressSerializer(serializers.ModelSerializer): book = serializers.HyperlinkedRelatedField( read_only=True, diff --git a/src/social/api/urls2.py b/src/social/api/urls2.py index 3863ec622..7f6ab6542 100644 --- a/src/social/api/urls2.py +++ b/src/social/api/urls2.py @@ -17,7 +17,9 @@ urlpatterns = [ path('lists/', views.ListsView.as_view()), path('lists//', views.ListView.as_view()), - path('lists///', views.ListItemView.as_view()), + path('lists//items/', views.ListItemListViewV3.as_view()), + path('list-items//', views.ListItemViewV3.as_view()), + path('lists///', views.ListItemViewV2.as_view()), path('progress/', views.ProgressListView.as_view()), path('progress//', views.ProgressView.as_view()), diff --git a/src/social/api/views.py b/src/social/api/views.py index a43bec277..41268084e 100644 --- a/src/social/api/views.py +++ b/src/social/api/views.py @@ -5,6 +5,7 @@ from datetime import datetime from django.db.models import Q from django.http import Http404 from django.utils.timezone import now, utc +from rest_framework.exceptions import MethodNotAllowed from rest_framework.generics import ListAPIView, ListCreateAPIView, RetrieveAPIView, RetrieveUpdateAPIView, RetrieveUpdateDestroyAPIView, get_object_or_404 from rest_framework.permissions import SAFE_METHODS, IsAuthenticated, IsAuthenticatedOrReadOnly from rest_framework.response import Response @@ -101,7 +102,11 @@ class MyLikesView(APIView): class ListsView(ListCreateAPIView): permission_classes = [IsAuthenticated] #pagination_class = None - serializer_class = serializers.UserListSerializer + + def get_serializer_class(self): + if self.request.version == 'v2': + return serializers.UserListSerializerV2 + return serializers.UserListSerializerV3 def get_queryset(self): return models.UserList.objects.filter( @@ -114,38 +119,51 @@ class ListsView(ListCreateAPIView): serializer.save(user=self.request.user) +def get_userlist(slug, request): + if request.method in SAFE_METHODS: + q = Q(deleted=False) + if request.user.is_authenticated: + q |= Q(user=request.user) + return get_object_or_404( + models.UserList, + q, + slug=slug, + ) + else: + return get_object_or_404( + models.UserList.all_objects.all(), + slug=slug, + user=request.user + ) + + @never_cache class ListView(RetrieveUpdateDestroyAPIView): # TODO: check if can modify permission_classes = [IsAuthenticatedOrReadOnly] - serializer_class = serializers.UserListSerializer + + def get_serializer_class(self): + if self.request.version == 'v2': + return serializers.UserListSerializerV2 + return serializers.UserListSerializerV3 def get_object(self): - if self.request.method in SAFE_METHODS: - q = Q(deleted=False) - if self.request.user.is_authenticated: - q |= Q(user=self.request.user) - return get_object_or_404( - models.UserList, - q, - slug=self.kwargs['slug'], - ) - else: - return get_object_or_404( - models.UserList.all_objects.all(), - slug=self.kwargs['slug'], - user=self.request.user) + return get_userlist(self.kwargs['slug'], self.request) def perform_update(self, serializer): serializer.save(user=self.request.user) def post(self, request, slug): - serializer = serializers.UserListBooksSerializer(data=request.data) - serializer.is_valid(raise_exception=True) - instance = self.get_object() - for book in serializer.validated_data['books']: - instance.append(book) - return Response(self.get_serializer(instance).data) + if request.version == 'v2': + # Accept posting a list of books here. + serializer = serializers.UserListBooksSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + instance = self.get_object() + for book in serializer.validated_data['books']: + instance.append(book) + return Response(self.get_serializer(instance).data) + else: + raise MethodNotAllowed(method=request.method) def perform_destroy(self, instance): instance.deleted = True @@ -154,7 +172,8 @@ class ListView(RetrieveUpdateDestroyAPIView): @never_cache -class ListItemView(APIView): +class ListItemViewV2(APIView): + """v2 only""" permission_classes = [IsAuthenticated] def delete(self, request, slug, book): @@ -162,7 +181,29 @@ class ListItemView(APIView): models.UserList, slug=slug, user=self.request.user) book = get_object_or_404(catalogue.models.Book, slug=book) instance.remove(book=book) - return Response(UserListSerializer(instance).data) + return Response(serializers.UserListSerializerV2(instance).data) + + +@never_cache +class ListItemListViewV3(ListCreateAPIView): + permission_classes = [IsAuthenticatedOrReadOnly] + serializer_class = serializers.UserListItemSerializer + + def get_queryset(self): + lst = get_userlist(self.kwargs['slug'], self.request) + return lst.userlistitem_set.all() + + +@never_cache +class ListItemViewV3(RetrieveUpdateDestroyAPIView): + permission_classes = [IsAuthenticated] + serializer_class = serializers.UserListItemSerializer + lookup_field = 'uuid' + + def get_queryset(self): + return models.UserListItem.objects.filter( + list__user=self.request.user + ) @vary_on_auth @@ -309,7 +350,11 @@ class ProgressSyncView(SyncView): class UserListSyncView(SyncView): model = models.UserList - serializer_class = serializers.UserListSerializer + + def get_serializer_class(self): + if self.request.version == 'v2': + return serializers.UserListSerializerV2 + return serializers.UserListSerializerV3 class UserListItemSyncView(SyncView): -- 2.20.1 From 5b24dd5b8f3f1a8be1c4c38f0afe500135b6d432 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Fri, 13 Mar 2026 12:35:06 +0100 Subject: [PATCH 08/16] fix for xml --- src/social/api/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/social/api/serializers.py b/src/social/api/serializers.py index dadf24935..ff20aad8d 100644 --- a/src/social/api/serializers.py +++ b/src/social/api/serializers.py @@ -14,7 +14,7 @@ class SettingsSerializer(serializers.ModelSerializer): class UserListBooksField(serializers.Field): def to_representation(self, value): - return value.userlistitem_set.exclude(deleted=True).exclude(book=None).values_list('book__slug', flat=True) + return list(value.userlistitem_set.exclude(deleted=True).exclude(book=None).values_list('book__slug', flat=True)) def to_internal_value(self, value): return {'books': catalogue.models.Book.objects.filter(slug__in=value)} -- 2.20.1 From 3ee9313de5b723b2b8d90933d546964edfa4a7f4 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Fri, 13 Mar 2026 12:35:28 +0100 Subject: [PATCH 09/16] add a robots line --- src/wolnelektury/static/root/robots.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wolnelektury/static/root/robots.txt b/src/wolnelektury/static/root/robots.txt index 98751b194..913cfaae8 100644 --- a/src/wolnelektury/static/root/robots.txt +++ b/src/wolnelektury/static/root/robots.txt @@ -6,4 +6,5 @@ Disallow: /lesmianator/wiersz/$ Disallow: /szukaj/ Disallow: /uzytkownik/ Disallow: /zegar/ +Disallow: /katalog/custompdf/ -- 2.20.1 From 200882c4c84192160b63b054b94220989c86aec2 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Fri, 13 Mar 2026 14:31:20 +0100 Subject: [PATCH 10/16] fix progress --- src/social/api/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/social/api/views.py b/src/social/api/views.py index 41268084e..2ac1c930f 100644 --- a/src/social/api/views.py +++ b/src/social/api/views.py @@ -265,6 +265,7 @@ class TextProgressView(ProgressMixin, RetrieveUpdateAPIView): serializer_class = serializers.TextProgressSerializer def perform_update(self, serializer): + serializer.instance.reported_timestamp = now() serializer.instance.last_mode = 'text' serializer.save() @@ -275,6 +276,7 @@ class AudioProgressView(ProgressMixin, RetrieveUpdateAPIView): serializer_class = serializers.AudioProgressSerializer def perform_update(self, serializer): + serializer.instance.reported_timestamp = now() serializer.instance.last_mode = 'audio' serializer.save() -- 2.20.1 From 475a7f55a8d6fd4168b33bbf7d216d961c0d6d54 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Tue, 17 Mar 2026 12:35:30 +0100 Subject: [PATCH 11/16] Allow posting lists --- src/social/api/views.py | 15 +++++++++++- .../0027_alter_userlistitem_order_and_more.py | 24 +++++++++++++++++++ src/social/models.py | 9 +++++-- 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 src/social/migrations/0027_alter_userlistitem_order_and_more.py diff --git a/src/social/api/views.py b/src/social/api/views.py index 2ac1c930f..2c2383591 100644 --- a/src/social/api/views.py +++ b/src/social/api/views.py @@ -191,7 +191,20 @@ class ListItemListViewV3(ListCreateAPIView): def get_queryset(self): lst = get_userlist(self.kwargs['slug'], self.request) - return lst.userlistitem_set.all() + return lst.userlistitem_set.all().order_by('order') + + def get_serializer(self, *args, **kwargs): + serializer_class = self.get_serializer_class() + kwargs.setdefault('context', self.get_serializer_context()) + + if isinstance(self.request.data, list): + kwargs['many'] = True + + return serializer_class(*args, **kwargs) + + def perform_create(self, serializer): + lst = get_userlist(self.kwargs['slug'], self.request) + serializer.save(list=lst) @never_cache diff --git a/src/social/migrations/0027_alter_userlistitem_order_and_more.py b/src/social/migrations/0027_alter_userlistitem_order_and_more.py new file mode 100644 index 000000000..08a4413cc --- /dev/null +++ b/src/social/migrations/0027_alter_userlistitem_order_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.0.8 on 2026-03-17 11:18 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('social', '0026_userprofile'), + ] + + operations = [ + migrations.AlterField( + model_name='userlistitem', + name='order', + field=models.IntegerField(default=0), + ), + migrations.AlterField( + model_name='userlistitem', + name='reported_timestamp', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + ] diff --git a/src/social/models.py b/src/social/models.py index c8d0d1023..45ee0f4a6 100644 --- a/src/social/models.py +++ b/src/social/models.py @@ -418,11 +418,11 @@ class UserList(Syncable, models.Model): class UserListItem(Syncable, models.Model): list = models.ForeignKey(UserList, models.CASCADE) uuid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False, blank=True) - order = models.IntegerField() + order = models.IntegerField(default=0) deleted = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) - reported_timestamp = models.DateTimeField() + reported_timestamp = models.DateTimeField(default=now) book = models.ForeignKey('catalogue.Book', models.SET_NULL, null=True, blank=True) fragment = models.ForeignKey('catalogue.Fragment', models.SET_NULL, null=True, blank=True) @@ -436,6 +436,11 @@ class UserListItem(Syncable, models.Model): objects = ActiveManager() all_objects = models.Manager() + def save(self, *args, **kwargs): + if not self.order: + self.order = self.list.userlistitem_set.all().count() + 1 + super().save(*args, **kwargs) + @classmethod def create_from_data(cls, user, data): if data.get('favorites'): -- 2.20.1 From d7b89d3f41ba44a7f327652014e6baff6999f70e Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Tue, 17 Mar 2026 12:36:42 +0100 Subject: [PATCH 12/16] fix --- src/social/api/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/social/api/serializers.py b/src/social/api/serializers.py index ff20aad8d..085783f8a 100644 --- a/src/social/api/serializers.py +++ b/src/social/api/serializers.py @@ -75,7 +75,7 @@ class UserListBooksSerializer(UserListSerializerV2): class UserListItemSerializer(serializers.ModelSerializer): client_id = serializers.CharField(write_only=True, required=False) - favorites = serializers.BooleanField(required=False) + favorites = serializers.BooleanField(read_only=True) list_slug = serializers.SlugRelatedField( queryset=models.UserList.objects.all(), source='list', -- 2.20.1 From f59de09387c7ceb7d6ab2ccf6ea25cb4be8dacb5 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Mon, 23 Mar 2026 12:32:32 +0100 Subject: [PATCH 13/16] Simpler payments and introduce seasonal banner. --- src/annoy/models.py | 20 ++++-- src/annoy/places.py | 1 + .../templates/annoy/banner_seasonal.html | 71 +++++++++++++++++++ src/annoy/templatetags/annoy.py | 8 +++ src/club/forms.py | 16 ++--- src/club/models.py | 14 ++++ src/club/templates/club/donation_step1.html | 8 +++ src/club/templates/club/donation_step2.html | 60 +++++----------- .../templates/club/donation_step_base.html | 3 +- .../static/2022/styles/layout/_annoy.scss | 57 +++++++++++++++ .../static/2022/styles/layout/_checkout.scss | 12 ++-- .../static/js/book_text/references.js | 9 +-- src/wolnelektury/static/js/main.js | 12 ++-- src/wolnelektury/templates/base.html | 5 +- 14 files changed, 217 insertions(+), 79 deletions(-) create mode 100644 src/annoy/templates/annoy/banner_seasonal.html diff --git a/src/annoy/models.py b/src/annoy/models.py index 6af1cc045..638da5e86 100644 --- a/src/annoy/models.py +++ b/src/annoy/models.py @@ -120,20 +120,26 @@ class Banner(models.Model): return int(self.progress_percent) def update_progress(self): - # Total of new payments during the action. - # This definition will need to change for longer timespans. if not self.since or not self.until or not self.target: return Schedule = apps.get_model('club', 'Schedule') - self.progress = Schedule.objects.filter( - payed_at__gte=self.since, - payed_at__lte=self.until, - ).aggregate(c=models.Sum('amount'))['c'] + PayUOrder = apps.get_model('club', 'PayUOrder') + progress = PayUOrder.objects.filter( + completed_at__gte=self.since, + completed_at__lte=self.until, + ).aggregate(c=models.Sum('schedule__amount'))['c'] + + for schedule in Schedule.objects.filter( + method='paypal', + expires_at__gt=self.since + ): + progress += schedule.n_paypal_payments(self.since, self.until) * schedule.amount + self.progress = progress self.save(update_fields=['progress']) @classmethod def update_all_progress(cls): - for obj in cls.objects.exclude(target=None): + for obj in cls.objects.exclude(target=None).exclude(until__lt=now()): obj.update_progress() diff --git a/src/annoy/places.py b/src/annoy/places.py index 0de0483b9..2fbd34ca3 100644 --- a/src/annoy/places.py +++ b/src/annoy/places.py @@ -13,6 +13,7 @@ PLACE_DEFINITIONS = [ ('quiet', 'Spokojny'), ('loud', 'Ostry'), )), + ('seasonal', 'Sezonowa', False), ] PLACE_CHOICES = [p[:2] for p in PLACE_DEFINITIONS] diff --git a/src/annoy/templates/annoy/banner_seasonal.html b/src/annoy/templates/annoy/banner_seasonal.html new file mode 100644 index 000000000..a3a8a1aae --- /dev/null +++ b/src/annoy/templates/annoy/banner_seasonal.html @@ -0,0 +1,71 @@ +{% load l10n %} +{% load time_tags %} + +{% if banner %} +
+
+ {% if not banner.action_label %} + + {% endif %} + + {% if not banner.action_label %} + + {% endif %} + +
+
+
+
+ +
+
+
+
+
+   +
+ {% if banner.target %} + {{ banner.target }} zł + {% endif %} +
+
+ + +
+
+{% endif %} diff --git a/src/annoy/templatetags/annoy.py b/src/annoy/templatetags/annoy.py index cdf4dbc5d..602fb3cef 100644 --- a/src/annoy/templatetags/annoy.py +++ b/src/annoy/templatetags/annoy.py @@ -45,3 +45,11 @@ def annoy_banner_crisis(context): 'banner': banners.first(), 'closable': True, } + +@register.inclusion_tag('annoy/banner_seasonal.html', takes_context=True) +def annoy_banner_seasonal(context): + banners = Banner.choice('seasonal', request=context['request'], exemptions=False) + return { + 'banner': banners.first(), + 'closable': False, + } diff --git a/src/club/forms.py b/src/club/forms.py index e0963036a..ceda8d5b1 100644 --- a/src/club/forms.py +++ b/src/club/forms.py @@ -62,9 +62,7 @@ class DonationStep2Form(forms.ModelForm, NewsletterForm): model = models.Schedule fields = [ 'first_name', 'last_name', - 'email', 'phone', - 'postal', - 'postal_code', 'postal_town', 'postal_country', + 'email', ] widgets = { 'amount': forms.HiddenInput, @@ -74,16 +72,14 @@ class DonationStep2Form(forms.ModelForm, NewsletterForm): def __init__(self, **kwargs): super().__init__(**kwargs) - self.fields['first_name'].required = True - self.fields['last_name'].required = True - self.consent = [] for c in models.Consent.objects.filter(active=True).order_by('order'): key = f'consent{c.id}' - self.fields[key] = forms.BooleanField( - label=c.text, - required=c.required - ) + if not c.required: + self.fields[key] = forms.BooleanField( + label=c.text, + required=c.required + ) self.consent.append(( c, key, (lambda k: lambda: self[k])(key) )) diff --git a/src/club/models.py b/src/club/models.py index de2d3c62b..eb1439084 100644 --- a/src/club/models.py +++ b/src/club/models.py @@ -201,6 +201,20 @@ class Schedule(models.Model): def is_recurring(self): return self.monthly or self.yearly + def n_paypal_payments(self, since, until): + # TODO: pull BA payments. + t = self.payed_at + if t is None: return 0 + c = 0 + until = min(until, now()) + t += timedelta(days=1) + while t < until: + if t >= since: + c += 1 + m = datetime(t.year, t.month, 1) + t += ((m + timedelta(days=31)).replace(day=1)) - m + return c + def set_payed(self): since = self.expires_at n = now() diff --git a/src/club/templates/club/donation_step1.html b/src/club/templates/club/donation_step1.html index c9f5ed211..d01e69364 100644 --- a/src/club/templates/club/donation_step1.html +++ b/src/club/templates/club/donation_step1.html @@ -1,5 +1,13 @@ {% extends 'club/donation_step_base.html' %} +{% load chunks %} {% block donation-step-content %} {% include "club/donation_step1_form.html" %} {% endblock %} + +{% block donate-bottom %} + +
+ {% chunk "donate-bottom" %} +
+{% endblock %} diff --git a/src/club/templates/club/donation_step2.html b/src/club/templates/club/donation_step2.html index 5d602135d..0a4cba521 100644 --- a/src/club/templates/club/donation_step2.html +++ b/src/club/templates/club/donation_step2.html @@ -30,70 +30,46 @@ {% csrf_token %} {{ form.errors }}
-
-
- - {{ form.first_name }} - {{ form.first_name.errors }} -
-
- - {{ form.last_name }} - {{ form.last_name.errors }} -
-
-
-
+
+
{{ form.email }} {{ form.email.errors }}
-
- - {{ form.phone }} - {{ form.phone.errors }} -
-
-
-
- - {{ form.postal }} - {{ form.postal.errors }} -
- - {{ form.postal_code }} - {{ form.postal_code.errors }} -
-
- - {{ form.postal_town }} - {{ form.postal_town.errors }} + + {{ form.first_name }} + {{ form.first_name.errors }}
-
-
- - {{ form.postal_country }} - {{ form.postal_country.errors }} + + {{ form.last_name }} + {{ form.last_name.errors }}
+
{% for consent, key, field in form.consent %} - {{ field.errors }} + {% if not consent.required %} + {{ field.errors }} + {% endif %}
+ {% if consent.required %} + + {% else %} {{ field }} + {% endif %}
{% endfor %}
{{ form.agree_newsletter }}
diff --git a/src/club/templates/club/donation_step_base.html b/src/club/templates/club/donation_step_base.html index 388932488..0c99d3ca9 100644 --- a/src/club/templates/club/donation_step_base.html +++ b/src/club/templates/club/donation_step_base.html @@ -84,8 +84,9 @@