diff --git a/TODO.md b/TODO.md index 118a23c..987dd0d 100644 --- a/TODO.md +++ b/TODO.md @@ -14,16 +14,20 @@ - [x] pause/unpause - [x] remove including from disk - [ ] DHT - - [ ] for torrents with a few seeds might be cool to re-query DHT once in a while + - [ ] for torrents with a few seeds might be cool to re-query DHT once in a while. - [x] it's sending many requests now way too fast, locks up Mac OS UI annoyingly someday: -- [ ] cancellation from the client-side for the lib (i.e. stop the torrent manager) +- [x] cancellation from the client-side for the lib (i.e. stop the torrent manager) refactor: - [x] where are peers stored - [x] http api pause/unpause etc -- [ ] when a live torrent fails writing to disk, it should transition to error state -- [ ] something is wrong when unpausing - can't finish. Recalculate needed/have from chunk tracker. -- [ ] silence this: WARN torrent{id=0}:external_peer_adder: librqbit::spawn_utils: finished with error: no longer live +- [x] when a live torrent fails writing to disk, it should transition to error state +- [x] something is wrong when unpausing - can't finish. Recalculate needed/have from chunk tracker. +- [x] silence this: WARN torrent{id=0}:external_peer_adder: librqbit::spawn_utils: finished with error: no longer live + +- [x] start from error state should be possible from UI +- [ ] if the torrent was completed, not need to re-check it +- [ ] checking is very slow on raspberry \ No newline at end of file diff --git a/crates/librqbit/src/torrent_state/mod.rs b/crates/librqbit/src/torrent_state/mod.rs index 31b9ca5..cd9f01d 100644 --- a/crates/librqbit/src/torrent_state/mod.rs +++ b/crates/librqbit/src/torrent_state/mod.rs @@ -192,7 +192,11 @@ impl ManagedTorrent { ); }; - let spawn_peer_adder = |live: &Arc| { + fn spawn_peer_adder( + live: &Arc, + initial_peers: Vec, + peer_rx: Option + Unpin + Send + Sync + 'static>, + ) { let span = live.meta().span.clone(); let live = Arc::downgrade(live); spawn( @@ -209,10 +213,11 @@ impl ManagedTorrent { if let Some(mut peer_rx) = peer_rx { while let Some(peer) = peer_rx.next().await { - live.upgrade() - .context("no longer live")? - .add_peer_if_not_seen(peer) - .context("torrent closed")?; + let live = match live.upgrade() { + Some(live) => live, + None => return Ok(()), + }; + live.add_peer_if_not_seen(peer).context("torrent closed")?; } } else { error!("peer rx is not set"); @@ -221,7 +226,7 @@ impl ManagedTorrent { Ok(()) }, ); - }; + } match &g.state { ManagedTorrentState::Live(_) => { @@ -254,7 +259,7 @@ impl ManagedTorrent { g.state = ManagedTorrentState::Live(live.clone()); spawn_fatal_errors_receiver(&t, rx); - spawn_peer_adder(&live); + spawn_peer_adder(&live, initial_peers, peer_rx); Ok(()) } @@ -274,11 +279,19 @@ impl ManagedTorrent { let live = TorrentStateLive::new(paused, tx); g.state = ManagedTorrentState::Live(live.clone()); spawn_fatal_errors_receiver(self, rx); - spawn_peer_adder(&live); + spawn_peer_adder(&live, initial_peers, peer_rx); Ok(()) } ManagedTorrentState::Error(_) => { - bail!("starting torrents from error state not implemented") + let initializing = Arc::new(TorrentStateInitializing::new( + self.info.clone(), + self.only_files.clone(), + )); + g.state = ManagedTorrentState::Initializing(initializing.clone()); + drop(g); + + // Recurse. + self.start(initial_peers, peer_rx, start_paused) } ManagedTorrentState::None => bail!("bug: torrent is in empty state"), } diff --git a/crates/librqbit/webui/dist/app.js b/crates/librqbit/webui/dist/app.js index 765ee33..4330772 100644 --- a/crates/librqbit/webui/dist/app.js +++ b/crates/librqbit/webui/dist/app.js @@ -41,4 +41,4 @@ Error generating stack: `+o.message+` Copyright (c) 2018 Jed Watson. Licensed under the MIT License (MIT), see http://jedwatson.github.io/classnames -*/(function(e){(function(){var t={}.hasOwnProperty;function n(){for(var r=[],l=0;l=0)&&(n[l]=e[l]);return n}function ia(e){return"default"+e.charAt(0).toUpperCase()+e.substr(1)}function mh(e){var t=hh(e,"string");return typeof t=="symbol"?t:String(t)}function hh(e,t){if(typeof e!="object"||e===null)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||"default");if(typeof r!="object")return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return(t==="string"?String:Number)(e)}function vh(e,t,n){var r=y.useRef(e!==void 0),l=y.useState(t),o=l[0],i=l[1],u=e!==void 0,s=r.current;return r.current=u,!u&&s&&o!==t&&i(t),[u?e:o,y.useCallback(function(a){for(var d=arguments.length,m=new Array(d>1?d-1:0),p=1;p{o.target===e&&(l(),t(o))},n+r)}function Bh(e){e.offsetHeight}const aa=e=>!e||typeof e=="function"?e:t=>{e.current=t};function Uh(e,t){const n=aa(e),r=aa(t);return l=>{n&&n(l),r&&r(l)}}function mo(e,t){return y.useMemo(()=>Uh(e,t),[e,t])}function Hh(e){return e&&"setState"in e?Cn.findDOMNode(e):e??null}const Wh=Wt.forwardRef(({onEnter:e,onEntering:t,onEntered:n,onExit:r,onExiting:l,onExited:o,addEndListener:i,children:u,childRef:s,...a},d)=>{const m=y.useRef(null),p=mo(m,s),g=N=>{p(Hh(N))},w=N=>T=>{N&&m.current&&N(m.current,T)},k=y.useCallback(w(e),[e]),R=y.useCallback(w(t),[t]),f=y.useCallback(w(n),[n]),c=y.useCallback(w(r),[r]),h=y.useCallback(w(l),[l]),S=y.useCallback(w(o),[o]),C=y.useCallback(w(i),[i]);return v.jsx(zh,{ref:d,...a,onEnter:k,onEntered:f,onEntering:R,onExit:c,onExited:S,onExiting:h,addEndListener:C,nodeRef:m,children:typeof u=="function"?(N,T)=>u(N,{...T,ref:g}):Wt.cloneElement(u,{ref:g})})}),Vh=Wh;function Qh(e){const t=y.useRef(e);return y.useEffect(()=>{t.current=e},[e]),t}function Pe(e){const t=Qh(e);return y.useCallback(function(...n){return t.current&&t.current(...n)},[t])}const Qf=e=>y.forwardRef((t,n)=>v.jsx("div",{...t,ref:n,className:M(t.className,e)})),Kf=Qf("h4");Kf.displayName="DivStyledAsH4";const Gf=y.forwardRef(({className:e,bsPrefix:t,as:n=Kf,...r},l)=>(t=H(t,"alert-heading"),v.jsx(n,{ref:l,className:M(e,t),...r})));Gf.displayName="AlertHeading";const Kh=Gf;function Gh(){return y.useState(null)}function Yh(){const e=y.useRef(!0),t=y.useRef(()=>e.current);return y.useEffect(()=>(e.current=!0,()=>{e.current=!1}),[]),t.current}function Xh(e){const t=y.useRef(null);return y.useEffect(()=>{t.current=e}),t.current}const Zh=typeof global<"u"&&global.navigator&&global.navigator.product==="ReactNative",Jh=typeof document<"u",ca=Jh||Zh?y.useLayoutEffect:y.useEffect,qh=["as","disabled"];function bh(e,t){if(e==null)return{};var n={},r=Object.keys(e),l,o;for(o=0;o=0)&&(n[l]=e[l]);return n}function ev(e){return!e||e.trim()==="#"}function Hu({tagName:e,disabled:t,href:n,target:r,rel:l,role:o,onClick:i,tabIndex:u=0,type:s}){e||(n!=null||r!=null||l!=null?e="a":e="button");const a={tagName:e};if(e==="button")return[{type:s||"button",disabled:t},a];const d=p=>{if((t||e==="a"&&ev(n))&&p.preventDefault(),t){p.stopPropagation();return}i==null||i(p)},m=p=>{p.key===" "&&(p.preventDefault(),d(p))};return e==="a"&&(n||(n="#"),t&&(n=void 0)),[{role:o??"button",disabled:void 0,tabIndex:t?void 0:u,href:n,target:e==="a"?r:void 0,"aria-disabled":t||void 0,rel:e==="a"?l:void 0,onClick:d,onKeyDown:m},a]}const tv=y.forwardRef((e,t)=>{let{as:n,disabled:r}=e,l=bh(e,qh);const[o,{tagName:i}]=Hu(Object.assign({tagName:n,disabled:r},l));return v.jsx(i,Object.assign({},l,o,{ref:t}))});tv.displayName="Button";const nv=["onKeyDown"];function rv(e,t){if(e==null)return{};var n={},r=Object.keys(e),l,o;for(o=0;o=0)&&(n[l]=e[l]);return n}function lv(e){return!e||e.trim()==="#"}const Yf=y.forwardRef((e,t)=>{let{onKeyDown:n}=e,r=rv(e,nv);const[l]=Hu(Object.assign({tagName:"a"},r)),o=Pe(i=>{l.onKeyDown(i),n==null||n(i)});return lv(r.href)||r.role==="button"?v.jsx("a",Object.assign({ref:t},r,l,{onKeyDown:o})):v.jsx("a",Object.assign({ref:t},r,{onKeyDown:n}))});Yf.displayName="Anchor";const ov=Yf,Xf=y.forwardRef(({className:e,bsPrefix:t,as:n=ov,...r},l)=>(t=H(t,"alert-link"),v.jsx(n,{ref:l,className:M(e,t),...r})));Xf.displayName="AlertLink";const iv=Xf,uv={[St]:"show",[Ht]:"show"},Zf=y.forwardRef(({className:e,children:t,transitionClasses:n={},onEnter:r,...l},o)=>{const i={in:!1,timeout:300,mountOnEnter:!1,unmountOnExit:!1,appear:!1,...l},u=y.useCallback((s,a)=>{Bh(s),r==null||r(s,a)},[r]);return v.jsx(Vh,{ref:o,addEndListener:Ah,...i,onEnter:u,childRef:t.ref,children:(s,a)=>y.cloneElement(t,{...a,className:M("fade",e,t.props.className,uv[s],n[s])})})});Zf.displayName="Fade";const Kl=Zf,sv={"aria-label":ot.string,onClick:ot.func,variant:ot.oneOf(["white"])},Wu=y.forwardRef(({className:e,variant:t,"aria-label":n="Close",...r},l)=>v.jsx("button",{ref:l,type:"button",className:M("btn-close",t&&`btn-close-${t}`,e),"aria-label":n,...r}));Wu.displayName="CloseButton";Wu.propTypes=sv;const Jf=Wu,qf=y.forwardRef((e,t)=>{const{bsPrefix:n,show:r=!0,closeLabel:l="Close alert",closeVariant:o,className:i,children:u,variant:s="primary",onClose:a,dismissible:d,transition:m=Kl,...p}=yh(e,{show:"onClose"}),g=H(n,"alert"),w=Pe(f=>{a&&a(!1,f)}),k=m===!0?Kl:m,R=v.jsxs("div",{role:"alert",...k?void 0:p,ref:t,className:M(i,g,s&&`${g}-${s}`,d&&`${g}-dismissible`),children:[d&&v.jsx(Jf,{onClick:w,"aria-label":l,variant:o}),u]});return k?v.jsx(k,{unmountOnExit:!0,...p,ref:void 0,in:r,children:R}):r?R:null});qf.displayName="Alert";const fa=Object.assign(qf,{Link:iv,Heading:Kh}),bf=y.forwardRef(({as:e,bsPrefix:t,variant:n="primary",size:r,active:l=!1,disabled:o=!1,className:i,...u},s)=>{const a=H(t,"btn"),[d,{tagName:m}]=Hu({tagName:e,disabled:o,...u}),p=m;return v.jsx(p,{...d,...u,ref:s,disabled:o,className:M(i,a,l&&"active",n&&`${a}-${n}`,r&&`${a}-${r}`,u.href&&o&&"disabled")})});bf.displayName="Button";const Mr=bf;function av(e){const t=y.useRef(e);return t.current=e,t}function ed(e){const t=av(e);y.useEffect(()=>()=>t.current(),[])}function cv(e,t){let n=0;return y.Children.map(e,r=>y.isValidElement(r)?t(r,n++):r)}function fv(e,t){return y.Children.toArray(e).some(n=>y.isValidElement(n)&&n.type===t)}function dv({as:e,bsPrefix:t,className:n,...r}){t=H(t,"col");const l=Df(),o=If(),i=[],u=[];return l.forEach(s=>{const a=r[s];delete r[s];let d,m,p;typeof a=="object"&&a!=null?{span:d,offset:m,order:p}=a:d=a;const g=s!==o?`-${s}`:"";d&&i.push(d===!0?`${t}${g}`:`${t}${g}-${d}`),p!=null&&u.push(`order${g}-${p}`),m!=null&&u.push(`offset${g}-${m}`)}),[{...r,className:M(n,...i,...u)},{as:e,bsPrefix:t,spans:i}]}const td=y.forwardRef((e,t)=>{const[{className:n,...r},{as:l="div",bsPrefix:o,spans:i}]=dv(e);return v.jsx(l,{...r,ref:t,className:M(n,!i.length&&o)})});td.displayName="Col";const Vu=td,nd=y.forwardRef(({bsPrefix:e,fluid:t=!1,as:n="div",className:r,...l},o)=>{const i=H(e,"container"),u=typeof t=="string"?`-${t}`:"-fluid";return v.jsx(n,{ref:o,...l,className:M(r,t?`${i}${u}`:i)})});nd.displayName="Container";const pv=nd;var mv=Function.prototype.bind.call(Function.prototype.call,[].slice);function cn(e,t){return mv(e.querySelectorAll(t))}function da(e,t){if(e.contains)return e.contains(t);if(e.compareDocumentPosition)return e===t||!!(e.compareDocumentPosition(t)&16)}const hv="data-rr-ui-";function vv(e){return`${hv}${e}`}const rd=y.createContext(Wn?window:void 0);rd.Provider;function Qu(){return y.useContext(rd)}const yv={type:ot.string,tooltip:ot.bool,as:ot.elementType},Ku=y.forwardRef(({as:e="div",className:t,type:n="valid",tooltip:r=!1,...l},o)=>v.jsx(e,{...l,ref:o,className:M(t,`${n}-${r?"tooltip":"feedback"}`)}));Ku.displayName="Feedback";Ku.propTypes=yv;const ld=Ku,gv=y.createContext({}),ct=gv,od=y.forwardRef(({id:e,bsPrefix:t,className:n,type:r="checkbox",isValid:l=!1,isInvalid:o=!1,as:i="input",...u},s)=>{const{controlId:a}=y.useContext(ct);return t=H(t,"form-check-input"),v.jsx(i,{...u,ref:s,type:r,id:e||a,className:M(n,t,l&&"is-valid",o&&"is-invalid")})});od.displayName="FormCheckInput";const id=od,ud=y.forwardRef(({bsPrefix:e,className:t,htmlFor:n,...r},l)=>{const{controlId:o}=y.useContext(ct);return e=H(e,"form-check-label"),v.jsx("label",{...r,ref:l,htmlFor:n||o,className:M(t,e)})});ud.displayName="FormCheckLabel";const Gi=ud,sd=y.forwardRef(({id:e,bsPrefix:t,bsSwitchPrefix:n,inline:r=!1,reverse:l=!1,disabled:o=!1,isValid:i=!1,isInvalid:u=!1,feedbackTooltip:s=!1,feedback:a,feedbackType:d,className:m,style:p,title:g="",type:w="checkbox",label:k,children:R,as:f="input",...c},h)=>{t=H(t,"form-check"),n=H(n,"form-switch");const{controlId:S}=y.useContext(ct),C=y.useMemo(()=>({controlId:e||S}),[S,e]),N=!R&&k!=null&&k!==!1||fv(R,Gi),T=v.jsx(id,{...c,type:w==="switch"?"checkbox":w,ref:h,isValid:i,isInvalid:u,disabled:o,as:f});return v.jsx(ct.Provider,{value:C,children:v.jsx("div",{style:p,className:M(m,N&&t,r&&`${t}-inline`,l&&`${t}-reverse`,w==="switch"&&n),children:R||v.jsxs(v.Fragment,{children:[T,N&&v.jsx(Gi,{title:g,children:k}),a&&v.jsx(ld,{type:d,tooltip:s,children:a})]})})})});sd.displayName="FormCheck";const Gl=Object.assign(sd,{Input:id,Label:Gi}),ad=y.forwardRef(({bsPrefix:e,type:t,size:n,htmlSize:r,id:l,className:o,isValid:i=!1,isInvalid:u=!1,plaintext:s,readOnly:a,as:d="input",...m},p)=>{const{controlId:g}=y.useContext(ct);return e=H(e,"form-control"),v.jsx(d,{...m,type:t,size:r,ref:p,readOnly:a,id:l||g,className:M(o,s?`${e}-plaintext`:e,n&&`${e}-${n}`,t==="color"&&`${e}-color`,i&&"is-valid",u&&"is-invalid")})});ad.displayName="FormControl";const wv=Object.assign(ad,{Feedback:ld}),cd=y.forwardRef(({className:e,bsPrefix:t,as:n="div",...r},l)=>(t=H(t,"form-floating"),v.jsx(n,{ref:l,className:M(e,t),...r})));cd.displayName="FormFloating";const Sv=cd,fd=y.forwardRef(({controlId:e,as:t="div",...n},r)=>{const l=y.useMemo(()=>({controlId:e}),[e]);return v.jsx(ct.Provider,{value:l,children:v.jsx(t,{...n,ref:r})})});fd.displayName="FormGroup";const dd=fd,pd=y.forwardRef(({as:e="label",bsPrefix:t,column:n=!1,visuallyHidden:r=!1,className:l,htmlFor:o,...i},u)=>{const{controlId:s}=y.useContext(ct);t=H(t,"form-label");let a="col-form-label";typeof n=="string"&&(a=`${a} ${a}-${n}`);const d=M(l,t,r&&"visually-hidden",n&&a);return o=o||s,n?v.jsx(Vu,{ref:u,as:"label",className:d,htmlFor:o,...i}):v.jsx(e,{ref:u,className:d,htmlFor:o,...i})});pd.displayName="FormLabel";const kv=pd,md=y.forwardRef(({bsPrefix:e,className:t,id:n,...r},l)=>{const{controlId:o}=y.useContext(ct);return e=H(e,"form-range"),v.jsx("input",{...r,type:"range",ref:l,className:M(t,e),id:n||o})});md.displayName="FormRange";const Ev=md,hd=y.forwardRef(({bsPrefix:e,size:t,htmlSize:n,className:r,isValid:l=!1,isInvalid:o=!1,id:i,...u},s)=>{const{controlId:a}=y.useContext(ct);return e=H(e,"form-select"),v.jsx("select",{...u,size:n,ref:s,className:M(r,e,t&&`${e}-${t}`,l&&"is-valid",o&&"is-invalid"),id:i||a})});hd.displayName="FormSelect";const xv=hd,vd=y.forwardRef(({bsPrefix:e,className:t,as:n="small",muted:r,...l},o)=>(e=H(e,"form-text"),v.jsx(n,{...l,ref:o,className:M(t,e,r&&"text-muted")})));vd.displayName="FormText";const Cv=vd,yd=y.forwardRef((e,t)=>v.jsx(Gl,{...e,ref:t,type:"switch"}));yd.displayName="Switch";const Nv=Object.assign(yd,{Input:Gl.Input,Label:Gl.Label}),gd=y.forwardRef(({bsPrefix:e,className:t,children:n,controlId:r,label:l,...o},i)=>(e=H(e,"form-floating"),v.jsxs(dd,{ref:i,className:M(t,e),controlId:r,...o,children:[n,v.jsx("label",{htmlFor:r,children:l})]})));gd.displayName="FloatingLabel";const Tv=gd,_v={_ref:ot.any,validated:ot.bool,as:ot.elementType},Gu=y.forwardRef(({className:e,validated:t,as:n="form",...r},l)=>v.jsx(n,{...r,ref:l,className:M(e,t&&"was-validated")}));Gu.displayName="Form";Gu.propTypes=_v;const On=Object.assign(Gu,{Group:dd,Control:wv,Floating:Sv,Check:Gl,Switch:Nv,Label:kv,Text:Cv,Range:Ev,Select:xv,FloatingLabel:Tv});var ul;function pa(e){if((!ul&&ul!==0||e)&&Wn){var t=document.createElement("div");t.style.position="absolute",t.style.top="-9999px",t.style.width="50px",t.style.height="50px",t.style.overflow="scroll",document.body.appendChild(t),ul=t.offsetWidth-t.clientWidth,document.body.removeChild(t)}return ul}function Wo(e){e===void 0&&(e=po());try{var t=e.activeElement;return!t||!t.nodeName?null:t}catch{return e.body}}function jv(e=document){const t=e.defaultView;return Math.abs(t.innerWidth-e.documentElement.clientWidth)}const ma=vv("modal-open");class Rv{constructor({ownerDocument:t,handleContainerOverflow:n=!0,isRTL:r=!1}={}){this.handleContainerOverflow=n,this.isRTL=r,this.modals=[],this.ownerDocument=t}getScrollbarWidth(){return jv(this.ownerDocument)}getElement(){return(this.ownerDocument||document).body}setModalAttributes(t){}removeModalAttributes(t){}setContainerStyle(t){const n={overflow:"hidden"},r=this.isRTL?"paddingLeft":"paddingRight",l=this.getElement();t.style={overflow:l.style.overflow,[r]:l.style[r]},t.scrollBarWidth&&(n[r]=`${parseInt(Xt(l,r)||"0",10)+t.scrollBarWidth}px`),l.setAttribute(ma,""),Xt(l,n)}reset(){[...this.modals].forEach(t=>this.remove(t))}removeContainerStyle(t){const n=this.getElement();n.removeAttribute(ma),Object.assign(n.style,t.style)}add(t){let n=this.modals.indexOf(t);return n!==-1||(n=this.modals.length,this.modals.push(t),this.setModalAttributes(t),n!==0)||(this.state={scrollBarWidth:this.getScrollbarWidth(),style:{}},this.handleContainerOverflow&&this.setContainerStyle(this.state)),n}remove(t){const n=this.modals.indexOf(t);n!==-1&&(this.modals.splice(n,1),!this.modals.length&&this.handleContainerOverflow&&this.removeContainerStyle(this.state),this.removeModalAttributes(t))}isTopModal(t){return!!this.modals.length&&this.modals[this.modals.length-1]===t}}const Yu=Rv,Vo=(e,t)=>Wn?e==null?(t||po()).body:(typeof e=="function"&&(e=e()),e&&"current"in e&&(e=e.current),e&&("nodeType"in e||e.getBoundingClientRect)?e:null):null;function Lv(e,t){const n=Qu(),[r,l]=y.useState(()=>Vo(e,n==null?void 0:n.document));if(!r){const o=Vo(e);o&&l(o)}return y.useEffect(()=>{t&&r&&t(r)},[t,r]),y.useEffect(()=>{const o=Vo(e);o!==r&&l(o)},[e,r]),r}function Ov({children:e,in:t,onExited:n,mountOnEnter:r,unmountOnExit:l}){const o=y.useRef(null),i=y.useRef(t),u=Pe(n);y.useEffect(()=>{t?i.current=!0:u(o.current)},[t,u]);const s=mo(o,e.ref),a=y.cloneElement(e,{ref:s});return t?a:l||!i.current&&r?null:a}function Pv({in:e,onTransition:t}){const n=y.useRef(null),r=y.useRef(!0),l=Pe(t);return ca(()=>{if(!n.current)return;let o=!1;return l({in:e,element:n.current,initial:r.current,isStale:()=>o}),()=>{o=!0}},[e,l]),ca(()=>(r.current=!1,()=>{r.current=!0}),[]),n}function Fv({children:e,in:t,onExited:n,onEntered:r,transition:l}){const[o,i]=y.useState(!t);t&&o&&i(!1);const u=Pv({in:!!t,onTransition:a=>{const d=()=>{a.isStale()||(a.in?r==null||r(a.element,a.initial):(i(!0),n==null||n(a.element)))};Promise.resolve(l(a)).then(d,m=>{throw a.in||i(!0),m})}}),s=mo(u,e.ref);return o&&!t?null:y.cloneElement(e,{ref:s})}function ha(e,t,n){return e?v.jsx(e,Object.assign({},n)):t?v.jsx(Fv,Object.assign({},n,{transition:t})):v.jsx(Ov,Object.assign({},n))}function Mv(e){return e.code==="Escape"||e.keyCode===27}const zv=["show","role","className","style","children","backdrop","keyboard","onBackdropClick","onEscapeKeyDown","transition","runTransition","backdropTransition","runBackdropTransition","autoFocus","enforceFocus","restoreFocus","restoreFocusOptions","renderDialog","renderBackdrop","manager","container","onShow","onHide","onExit","onExited","onExiting","onEnter","onEntering","onEntered"];function $v(e,t){if(e==null)return{};var n={},r=Object.keys(e),l,o;for(o=0;o=0)&&(n[l]=e[l]);return n}let Qo;function Dv(e){return Qo||(Qo=new Yu({ownerDocument:e==null?void 0:e.document})),Qo}function Iv(e){const t=Qu(),n=e||Dv(t),r=y.useRef({dialog:null,backdrop:null});return Object.assign(r.current,{add:()=>n.add(r.current),remove:()=>n.remove(r.current),isTopModal:()=>n.isTopModal(r.current),setDialogRef:y.useCallback(l=>{r.current.dialog=l},[]),setBackdropRef:y.useCallback(l=>{r.current.backdrop=l},[])})}const wd=y.forwardRef((e,t)=>{let{show:n=!1,role:r="dialog",className:l,style:o,children:i,backdrop:u=!0,keyboard:s=!0,onBackdropClick:a,onEscapeKeyDown:d,transition:m,runTransition:p,backdropTransition:g,runBackdropTransition:w,autoFocus:k=!0,enforceFocus:R=!0,restoreFocus:f=!0,restoreFocusOptions:c,renderDialog:h,renderBackdrop:S=K=>v.jsx("div",Object.assign({},K)),manager:C,container:N,onShow:T,onHide:j=()=>{},onExit:B,onExited:P,onExiting:ie,onEnter:Ve,onEntering:Qe,onEntered:rn}=e,Qn=$v(e,zv);const _e=Qu(),Ke=Lv(N),x=Iv(C),L=Yh(),O=Xh(n),[D,A]=y.useState(!n),fe=y.useRef(null);y.useImperativeHandle(t,()=>x,[x]),Wn&&!O&&n&&(fe.current=Wo(_e==null?void 0:_e.document)),n&&D&&A(!1);const je=Pe(()=>{if(x.add(),on.current=Ql(document,"keydown",ho),ln.current=Ql(document,"focus",()=>setTimeout(Re),!0),T&&T(),k){var K,Hr;const Yn=Wo((K=(Hr=x.dialog)==null?void 0:Hr.ownerDocument)!=null?K:_e==null?void 0:_e.document);x.dialog&&Yn&&!da(x.dialog,Yn)&&(fe.current=Yn,x.dialog.focus())}}),qe=Pe(()=>{if(x.remove(),on.current==null||on.current(),ln.current==null||ln.current(),f){var K;(K=fe.current)==null||K.focus==null||K.focus(c),fe.current=null}});y.useEffect(()=>{!n||!Ke||je()},[n,Ke,je]),y.useEffect(()=>{D&&qe()},[D,qe]),ed(()=>{qe()});const Re=Pe(()=>{if(!R||!L()||!x.isTopModal())return;const K=Wo(_e==null?void 0:_e.document);x.dialog&&K&&!da(x.dialog,K)&&x.dialog.focus()}),mt=Pe(K=>{K.target===K.currentTarget&&(a==null||a(K),u===!0&&j())}),ho=Pe(K=>{s&&Mv(K)&&x.isTopModal()&&(d==null||d(K),K.defaultPrevented||j())}),ln=y.useRef(),on=y.useRef(),Kn=(...K)=>{A(!0),P==null||P(...K)};if(!Ke)return null;const Ur=Object.assign({role:r,ref:x.setDialogRef,"aria-modal":r==="dialog"?!0:void 0},Qn,{style:o,className:l,tabIndex:-1});let Gn=h?h(Ur):v.jsx("div",Object.assign({},Ur,{children:y.cloneElement(i,{role:"document"})}));Gn=ha(m,p,{unmountOnExit:!0,mountOnEnter:!0,appear:!0,in:!!n,onExit:B,onExiting:ie,onExited:Kn,onEnter:Ve,onEntering:Qe,onEntered:rn,children:Gn});let It=null;return u&&(It=S({ref:x.setBackdropRef,onClick:mt}),It=ha(g,w,{in:!!n,appear:!0,mountOnEnter:!0,unmountOnExit:!0,children:It})),v.jsx(v.Fragment,{children:Cn.createPortal(v.jsxs(v.Fragment,{children:[It,Gn]}),Ke)})});wd.displayName="Modal";const Av=Object.assign(wd,{Manager:Yu});function Bv(e,t){return e.classList?!!t&&e.classList.contains(t):(" "+(e.className.baseVal||e.className)+" ").indexOf(" "+t+" ")!==-1}function Uv(e,t){e.classList?e.classList.add(t):Bv(e,t)||(typeof e.className=="string"?e.className=e.className+" "+t:e.setAttribute("class",(e.className&&e.className.baseVal||"")+" "+t))}function va(e,t){return e.replace(new RegExp("(^|\\s)"+t+"(?:\\s|$)","g"),"$1").replace(/\s+/g," ").replace(/^\s*|\s*$/g,"")}function Hv(e,t){e.classList?e.classList.remove(t):typeof e.className=="string"?e.className=va(e.className,t):e.setAttribute("class",va(e.className&&e.className.baseVal||"",t))}const fn={FIXED_CONTENT:".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",STICKY_CONTENT:".sticky-top",NAVBAR_TOGGLER:".navbar-toggler"};class Wv extends Yu{adjustAndStore(t,n,r){const l=n.style[t];n.dataset[t]=l,Xt(n,{[t]:`${parseFloat(Xt(n,t))+r}px`})}restore(t,n){const r=n.dataset[t];r!==void 0&&(delete n.dataset[t],Xt(n,{[t]:r}))}setContainerStyle(t){super.setContainerStyle(t);const n=this.getElement();if(Uv(n,"modal-open"),!t.scrollBarWidth)return;const r=this.isRTL?"paddingLeft":"paddingRight",l=this.isRTL?"marginLeft":"marginRight";cn(n,fn.FIXED_CONTENT).forEach(o=>this.adjustAndStore(r,o,t.scrollBarWidth)),cn(n,fn.STICKY_CONTENT).forEach(o=>this.adjustAndStore(l,o,-t.scrollBarWidth)),cn(n,fn.NAVBAR_TOGGLER).forEach(o=>this.adjustAndStore(l,o,t.scrollBarWidth))}removeContainerStyle(t){super.removeContainerStyle(t);const n=this.getElement();Hv(n,"modal-open");const r=this.isRTL?"paddingLeft":"paddingRight",l=this.isRTL?"marginLeft":"marginRight";cn(n,fn.FIXED_CONTENT).forEach(o=>this.restore(r,o)),cn(n,fn.STICKY_CONTENT).forEach(o=>this.restore(l,o)),cn(n,fn.NAVBAR_TOGGLER).forEach(o=>this.restore(l,o))}}let Ko;function Vv(e){return Ko||(Ko=new Wv(e)),Ko}const Sd=y.forwardRef(({className:e,bsPrefix:t,as:n="div",...r},l)=>(t=H(t,"modal-body"),v.jsx(n,{ref:l,className:M(e,t),...r})));Sd.displayName="ModalBody";const Qv=Sd,Kv=y.createContext({onHide(){}}),kd=Kv,Ed=y.forwardRef(({bsPrefix:e,className:t,contentClassName:n,centered:r,size:l,fullscreen:o,children:i,scrollable:u,...s},a)=>{e=H(e,"modal");const d=`${e}-dialog`,m=typeof o=="string"?`${e}-fullscreen-${o}`:`${e}-fullscreen`;return v.jsx("div",{...s,ref:a,className:M(d,t,l&&`${e}-${l}`,r&&`${d}-centered`,u&&`${d}-scrollable`,o&&m),children:v.jsx("div",{className:M(`${e}-content`,n),children:i})})});Ed.displayName="ModalDialog";const xd=Ed,Cd=y.forwardRef(({className:e,bsPrefix:t,as:n="div",...r},l)=>(t=H(t,"modal-footer"),v.jsx(n,{ref:l,className:M(e,t),...r})));Cd.displayName="ModalFooter";const Gv=Cd,Yv=y.forwardRef(({closeLabel:e="Close",closeVariant:t,closeButton:n=!1,onHide:r,children:l,...o},i)=>{const u=y.useContext(kd),s=Pe(()=>{u==null||u.onHide(),r==null||r()});return v.jsxs("div",{ref:i,...o,children:[l,n&&v.jsx(Jf,{"aria-label":e,variant:t,onClick:s})]})}),Xv=Yv,Nd=y.forwardRef(({bsPrefix:e,className:t,closeLabel:n="Close",closeButton:r=!1,...l},o)=>(e=H(e,"modal-header"),v.jsx(Xv,{ref:o,...l,className:M(t,e),closeLabel:n,closeButton:r})));Nd.displayName="ModalHeader";const Zv=Nd,Jv=Qf("h4"),Td=y.forwardRef(({className:e,bsPrefix:t,as:n=Jv,...r},l)=>(t=H(t,"modal-title"),v.jsx(n,{ref:l,className:M(e,t),...r})));Td.displayName="ModalTitle";const qv=Td;function bv(e){return v.jsx(Kl,{...e,timeout:null})}function ey(e){return v.jsx(Kl,{...e,timeout:null})}const _d=y.forwardRef(({bsPrefix:e,className:t,style:n,dialogClassName:r,contentClassName:l,children:o,dialogAs:i=xd,"aria-labelledby":u,"aria-describedby":s,"aria-label":a,show:d=!1,animation:m=!0,backdrop:p=!0,keyboard:g=!0,onEscapeKeyDown:w,onShow:k,onHide:R,container:f,autoFocus:c=!0,enforceFocus:h=!0,restoreFocus:S=!0,restoreFocusOptions:C,onEntered:N,onExit:T,onExiting:j,onEnter:B,onEntering:P,onExited:ie,backdropClassName:Ve,manager:Qe,...rn},Qn)=>{const[_e,Ke]=y.useState({}),[x,L]=y.useState(!1),O=y.useRef(!1),D=y.useRef(!1),A=y.useRef(null),[fe,je]=Gh(),qe=mo(Qn,je),Re=Pe(R),mt=kh();e=H(e,"modal");const ho=y.useMemo(()=>({onHide:Re}),[Re]);function ln(){return Qe||Vv({isRTL:mt})}function on($){if(!Wn)return;const un=ln().getScrollbarWidth()>0,Zu=$.scrollHeight>po($).documentElement.clientHeight;Ke({paddingRight:un&&!Zu?pa():void 0,paddingLeft:!un&&Zu?pa():void 0})}const Kn=Pe(()=>{fe&&on(fe.dialog)});ed(()=>{Ki(window,"resize",Kn),A.current==null||A.current()});const Ur=()=>{O.current=!0},Gn=$=>{O.current&&fe&&$.target===fe.dialog&&(D.current=!0),O.current=!1},It=()=>{L(!0),A.current=Vf(fe.dialog,()=>{L(!1)})},K=$=>{$.target===$.currentTarget&&It()},Hr=$=>{if(p==="static"){K($);return}if(D.current||$.target!==$.currentTarget){D.current=!1;return}R==null||R()},Yn=$=>{g?w==null||w($):($.preventDefault(),p==="static"&&It())},Dd=($,un)=>{$&&on($),B==null||B($,un)},Id=$=>{A.current==null||A.current(),T==null||T($)},Ad=($,un)=>{P==null||P($,un),Wf(window,"resize",Kn)},Bd=$=>{$&&($.style.display=""),ie==null||ie($),Ki(window,"resize",Kn)},Ud=y.useCallback($=>v.jsx("div",{...$,className:M(`${e}-backdrop`,Ve,!m&&"show")}),[m,Ve,e]),Xu={...n,..._e};Xu.display="block";const Hd=$=>v.jsx("div",{role:"dialog",...$,style:Xu,className:M(t,e,x&&`${e}-static`,!m&&"show"),onClick:p?Hr:void 0,onMouseUp:Gn,"aria-label":a,"aria-labelledby":u,"aria-describedby":s,children:v.jsx(i,{...rn,onMouseDown:Ur,className:r,contentClassName:l,children:o})});return v.jsx(kd.Provider,{value:ho,children:v.jsx(Av,{show:d,ref:qe,backdrop:p,container:f,keyboard:!0,autoFocus:c,enforceFocus:h,restoreFocus:S,restoreFocusOptions:C,onEscapeKeyDown:Yn,onShow:k,onHide:R,onEnter:Dd,onEntering:Ad,onEntered:N,onExit:Id,onExiting:j,onExited:Bd,manager:ln(),transition:m?bv:void 0,backdropTransition:m?ey:void 0,renderBackdrop:Ud,renderDialog:Hd})})});_d.displayName="Modal";const tt=Object.assign(_d,{Body:Qv,Header:Zv,Title:qv,Footer:Gv,Dialog:xd,TRANSITION_DURATION:300,BACKDROP_TRANSITION_DURATION:150}),ya=1e3;function ty(e,t,n){const r=(e-t)/(n-t)*100;return Math.round(r*ya)/ya}function ga({min:e,now:t,max:n,label:r,visuallyHidden:l,striped:o,animated:i,className:u,style:s,variant:a,bsPrefix:d,...m},p){return v.jsx("div",{ref:p,...m,role:"progressbar",className:M(u,`${d}-bar`,{[`bg-${a}`]:a,[`${d}-bar-animated`]:i,[`${d}-bar-striped`]:i||o}),style:{width:`${ty(t,e,n)}%`,...s},"aria-valuenow":t,"aria-valuemin":e,"aria-valuemax":n,children:l?v.jsx("span",{className:"visually-hidden",children:r}):r})}const jd=y.forwardRef(({isChild:e=!1,...t},n)=>{const r={min:0,max:100,animated:!1,visuallyHidden:!1,striped:!1,...t};if(r.bsPrefix=H(r.bsPrefix,"progress"),e)return ga(r,n);const{min:l,now:o,max:i,label:u,visuallyHidden:s,striped:a,animated:d,bsPrefix:m,variant:p,className:g,children:w,...k}=r;return v.jsx("div",{ref:n,...k,className:M(g,m),children:w?cv(w,R=>y.cloneElement(R,{isChild:!0})):ga({min:l,now:o,max:i,label:u,visuallyHidden:s,striped:a,animated:d,bsPrefix:m,variant:p},n)})});jd.displayName="ProgressBar";const ny=jd,Rd=y.forwardRef(({bsPrefix:e,className:t,as:n="div",...r},l)=>{const o=H(e,"row"),i=Df(),u=If(),s=`${o}-cols`,a=[];return i.forEach(d=>{const m=r[d];delete r[d];let p;m!=null&&typeof m=="object"?{cols:p}=m:p=m;const g=d!==u?`-${d}`:"";p!=null&&a.push(`${s}${g}-${p}`)}),v.jsx(n,{ref:l,...r,className:M(t,o,...a)})});Rd.displayName="Row";const Ld=Rd,Od=y.forwardRef(({bsPrefix:e,variant:t,animation:n="border",size:r,as:l="div",className:o,...i},u)=>{e=H(e,"spinner");const s=`${e}-${n}`;return v.jsx(l,{ref:u,...i,className:M(o,s,r&&`${s}-${r}`,t&&`text-${t}`)})});Od.displayName="Spinner";const An=Od,ry=window.origin==="null"||window.origin==="http://localhost:3031"?"http://localhost:3030":"",Sl="initializing",wa="paused",Pd="live",ly="error",vt=async(e,t,n)=>{console.log(e,t);const r=ry+t,l={method:e,headers:{Accept:"application/json"},body:n};let o={method:e,path:t,text:""},i;try{i=await fetch(r,l)}catch{return o.text="network error",Promise.reject(o)}if(o.status=i.status,o.statusText=i.statusText,!i.ok){const s=await i.text();try{const a=JSON.parse(s);o.text=a.human_readable!==void 0?a.human_readable:JSON.stringify(a,null,2)}catch{o.text=s}return Promise.reject(o)}return await i.json()},ft={listTorrents:()=>vt("GET","/torrents"),getTorrentDetails:e=>vt("GET",`/torrents/${e}`),getTorrentStats:e=>vt("GET",`/torrents/${e}/stats/v1`),uploadTorrent:(e,t)=>{t=t||{};let n="/torrents?&overwrite=true";return t.listOnly&&(n+="&list_only=true"),t.selectedFiles!=null&&(n+=`&only_files=${t.selectedFiles.join(",")}`),vt("POST",n,e)},pause:e=>vt("POST",`/torrents/${e}/pause`),start:e=>vt("POST",`/torrents/${e}/start`),forget:e=>vt("POST",`/torrents/${e}/forget`),delete:e=>vt("POST",`/torrents/${e}/delete`)},Vn=y.createContext(null),Fd=y.createContext(null),Go=({className:e,onClick:t,disabled:n,color:r})=>{const l=o=>{o.stopPropagation(),!n&&t()};return v.jsx("a",{className:`bi ${e} p-1`,onClick:l,href:"#"})},oy=({id:e,show:t,onHide:n})=>{if(!t)return null;const[r,l]=y.useState(!1),[o,i]=y.useState(null),[u,s]=y.useState(!1),a=y.useContext(Vn),d=()=>{l(!1),i(null),s(!1),n()},m=()=>{s(!0),(r?ft.delete:ft.forget)(e).then(()=>{a.refreshTorrents(),d()}).catch(g=>{i({text:`Error deleting torrent id=${e}`,details:g}),s(!1)})};return v.jsxs(tt,{show:t,onHide:d,children:[v.jsx(tt.Header,{closeButton:!0,children:"Delete torrent"}),v.jsxs(tt.Body,{children:[v.jsx(On,{children:v.jsx(On.Group,{controlId:"delete-torrent",children:v.jsx(On.Check,{type:"checkbox",label:"Also delete files",checked:r,onChange:()=>l(!r)})})}),o&&v.jsx(zr,{error:o})]}),v.jsxs(tt.Footer,{children:[u&&v.jsx(An,{}),v.jsx(Mr,{variant:"primary",onClick:m,disabled:u,children:"OK"}),v.jsx(Mr,{variant:"secondary",onClick:d,children:"Cancel"})]})]})},iy=({id:e,statsResponse:t})=>{let n=t.state,[r,l]=y.useState(!1),[o,i]=y.useState(!1),u=y.useContext(Fd);const s=n=="live",a=n=="paused",d=y.useContext(Vn),m=()=>{l(!0),ft.start(e).then(()=>{u.refresh()},k=>{d.setCloseableError({text:`Error starting torrent id=${e}`,details:k})}).finally(()=>l(!1))},p=()=>{l(!0),ft.pause(e).then(()=>{u.refresh()},k=>{d.setCloseableError({text:`Error pausing torrent id=${e}`,details:k})}).finally(()=>l(!1))},g=()=>{l(!0),i(!0)},w=()=>{l(!1),i(!1)};return v.jsx(Ld,{children:v.jsxs(Vu,{children:[a&&v.jsx(Go,{className:"bi-play-circle",onClick:m,disabled:r,color:"success"}),s&&v.jsx(Go,{className:"bi-pause-circle",onClick:p,disabled:r}),v.jsx(Go,{className:"bi-x-circle",onClick:g,disabled:r,color:"danger"}),v.jsx(oy,{id:e,show:o,onHide:w})]})})},uy=({id:e,detailsResponse:t,statsResponse:n})=>{const r=(n==null?void 0:n.state)??"",l=n==null?void 0:n.error,o=(n==null?void 0:n.total_bytes)??1,i=(n==null?void 0:n.progress_bytes)??0,u=(n==null?void 0:n.finished)||!1,s=l?100:i/o*100,a=(r==Sl||r==Pd)&&!u,d=l?"Error":`${s.toFixed(2)}%`,m=l?"danger":u?"success":r==Sl?"warning":"primary",p=()=>{var R;let k=(R=n==null?void 0:n.live)==null?void 0:R.snapshot.peer_stats;return k?`${k.live} / ${k.seen}`:""},g=()=>{var k;if(u)return"Completed";switch(r){case wa:return"Paused";case Sl:return"Checking files";case ly:return"Error"}return((k=n.live)==null?void 0:k.download_speed.human_readable)??"N/A"};let w=[];return l?w.push("bg-warning"):e%2==0&&w.push("bg-light"),v.jsxs(Ld,{className:w.join(" "),children:[v.jsx(yt,{size:3,label:"Name",children:t?v.jsxs(v.Fragment,{children:[v.jsx("div",{className:"text-truncate",children:yy(t)}),l&&v.jsxs("p",{className:"text-danger",children:[v.jsx("strong",{children:"Error:"})," ",l]})]}):v.jsx(An,{})}),n?v.jsxs(v.Fragment,{children:[v.jsx(yt,{label:"Size",children:`${zd(o)} `}),v.jsx(yt,{size:2,label:(r==wa,"Progress"),children:v.jsx(ny,{now:s,label:d,animated:a,variant:m})}),v.jsx(yt,{size:2,label:"Down Speed",children:g()}),v.jsx(yt,{label:"ETA",children:gy(n)}),v.jsx(yt,{size:2,label:"Peers",children:p()}),v.jsx(yt,{label:"Actions",children:v.jsx(iy,{id:e,statsResponse:n})})]}):v.jsx(yt,{label:"Loading stats",size:8,children:v.jsx(An,{})})]})},yt=({size:e,label:t,children:n})=>v.jsxs(Vu,{md:e||1,className:"py-3",children:[v.jsx("div",{className:"fw-bold",children:t}),n]}),sy=({id:e,torrent:t})=>{const[n,r]=y.useState(null),[l,o]=y.useState(null),[i,u]=y.useState(0),s=()=>{u(i+1)};return y.useEffect(()=>{if(n===null)return Sy(async()=>{await ft.getTorrentDetails(t.id).then(r)},1e3)},[n]),y.useEffect(()=>$d(async()=>ft.getTorrentStats(t.id).then(g=>(o(g),g)).then(g=>g.finished?1e4:g.state==Sl||g.state==Pd?1e3:1e4,g=>1e4),0),[i]),v.jsx(Fd.Provider,{value:{refresh:s},children:v.jsx(uy,{id:e,detailsResponse:n,statsResponse:l})})},ay=e=>{if(e.torrents===null&&e.loading)return v.jsx(An,{});if(e.torrents!==null)return e.torrents.length===0?v.jsx("div",{className:"text-center",children:v.jsx("p",{children:"No existing torrents found. Add them through buttons below."})}):v.jsx(v.Fragment,{children:e.torrents.map(t=>v.jsx(sy,{id:t.id,torrent:t},t.id))})},cy=()=>{const[e,t]=y.useState(null),[n,r]=y.useState(null),[l,o]=y.useState(null),[i,u]=y.useState(!1),s=async()=>{u(!0);let d=await ft.listTorrents().finally(()=>u(!1));o(d.torrents)};y.useEffect(()=>$d(async()=>s().then(()=>(r(null),5e3),d=>(r({text:"Error refreshing torrents",details:d}),console.error(d),5e3)),0),[]);const a={setCloseableError:t,refreshTorrents:s};return v.jsx(Vn.Provider,{value:a,children:v.jsxs("div",{className:"text-center",children:[v.jsx("h1",{className:"mt-3 mb-4",children:"rqbit web 0.0.1-alpha"}),v.jsx(vy,{closeableError:e,otherError:n,torrents:l,torrentsLoading:i})]})})},fy=e=>{let{details:t}=e;return t?v.jsxs(v.Fragment,{children:[t.status&&v.jsxs("strong",{children:[t.status," ",t.statusText,": "]}),t.text]}):null},zr=e=>{let{error:t,remove:n}=e;return t==null?null:v.jsxs(fa,{variant:"danger",onClose:n,dismissible:n!=null,children:[v.jsx(fa.Heading,{children:t.text}),v.jsx(fy,{details:t.details})]})},Md=({buttonText:e,onClick:t,data:n,resetData:r,variant:l})=>{const[o,i]=y.useState(!1),[u,s]=y.useState([]),[a,d]=y.useState(null);y.useContext(Vn);const m=n!==null||a!==null;y.useEffect(()=>{if(n===null)return;let g=setTimeout(async()=>{i(!0);try{const w=await ft.uploadTorrent(n,{listOnly:!0});s(w.details.files)}catch(w){d({text:"Error uploading torrent",details:w})}finally{i(!1)}},0);return()=>clearTimeout(g)},[n]);const p=()=>{r(),d(null),s([]),i(!1)};return v.jsxs(v.Fragment,{children:[v.jsx(Mr,{variant:l,onClick:t,className:"m-1",children:e}),v.jsx(my,{show:m,onHide:p,fileListError:a,fileList:u,data:n,fileListLoading:o})]})},dy=()=>{let[e,t]=y.useState(null);const n=()=>{const r=prompt("Enter magnet link or HTTP(s) URL");t(r===""?null:r)};return v.jsx(Md,{variant:"primary",buttonText:"Add Torrent from Magnet Link",onClick:n,data:e,resetData:()=>t(null)})},py=()=>{const e=y.useRef(),[t,n]=y.useState(null),r=async()=>{const i=e.current.files[0];n(i)},l=()=>{e.current.value="",n(null)},o=()=>{e.current.click()};return v.jsxs(v.Fragment,{children:[v.jsx("input",{type:"file",ref:e,accept:".torrent",onChange:r,className:"d-none"}),v.jsx(Md,{variant:"secondary",buttonText:"Upload .torrent File",onClick:o,data:t,resetData:l})]})},my=e=>{let{show:t,onHide:n,fileList:r,fileListError:l,fileListLoading:o,data:i}=e;const[u,s]=y.useState([]),[a,d]=y.useState(!1),[m,p]=y.useState(null),g=y.useContext(Vn);y.useEffect(()=>{s(r.map((f,c)=>c))},[r]);const w=()=>{n(),s([]),p(null),d(!1)},k=f=>{u.includes(f)?s(u.filter(c=>c!==f)):s([...u,f])},R=async()=>{d(!0),ft.uploadTorrent(i,{selectedFiles:u}).then(()=>{n(),g.refreshTorrents()},f=>{p({text:"Error starting torrent",details:f})}).finally(()=>d(!1))};return v.jsxs(tt,{show:t,onHide:w,size:"lg",children:[v.jsx(tt.Header,{closeButton:!0,children:!!l||v.jsx(tt.Title,{children:"Select Files"})}),v.jsxs(tt.Body,{children:[o?v.jsx(An,{}):l?v.jsx(zr,{error:l}):v.jsx(On,{children:r.map((f,c)=>v.jsx(On.Group,{controlId:`check-${c}`,children:v.jsx(On.Check,{type:"checkbox",label:`${f.name} (${zd(f.length)})`,checked:u.includes(c),onChange:()=>k(c)})},c))}),v.jsx(zr,{error:m})]}),v.jsxs(tt.Footer,{children:[a&&v.jsx(An,{}),v.jsx(Mr,{variant:"primary",onClick:R,disabled:o||a||u.length==0,children:"OK"}),v.jsx(Mr,{variant:"secondary",onClick:w,children:"Cancel"})]})]})},hy=()=>v.jsxs("div",{id:"buttons-container",className:"mt-3",children:[v.jsx(dy,{}),v.jsx(py,{})]}),vy=e=>{let t=y.useContext(Vn);return v.jsxs(pv,{children:[v.jsx(zr,{error:e.closeableError,remove:()=>t.setCloseableError(null)}),v.jsx(zr,{error:e.otherError}),v.jsx(ay,{torrents:e.torrents,loading:e.torrentsLoading}),v.jsx(hy,{})]})};function zd(e){if(e===0)return"0 Bytes";const t=1024,n=["Bytes","KB","MB","GB"],r=Math.floor(Math.log(e)/Math.log(t));return parseFloat((e/Math.pow(t,r)).toFixed(2))+" "+n[r]}function yy(e){return e.files.filter(n=>n.included).reduce((n,r)=>n.length>r.length?n:r).name}function gy(e){var n,r,l;let t=(l=(r=(n=e==null?void 0:e.live)==null?void 0:n.time_remaining)==null?void 0:r.duration)==null?void 0:l.secs;return t==null?"N/A":wy(t)}function wy(e){const t=Math.floor(e/3600),n=Math.floor(e%3600/60),r=e%60,l=(o,i)=>o>0?`${o}${i}`:"";return t>0?`${l(t,"h")} ${l(n,"m")}`.trim():n>0?`${l(n,"m")} ${l(r,"s")}`.trim():`${l(r,"s")}`.trim()}function $d(e,t){let n,r=t;const l=async()=>{if(r=await e(),r==null)throw"asyncCallback returned null or undefined";o()};let o=()=>{n=setTimeout(l,r)};return o(),()=>{clearTimeout(n)}}function Sy(e,t){let n;const r=async()=>{await e().then(()=>!1,()=>!0)&&l()};let l=o=>{n=setTimeout(r,o!==void 0?o:t)};return l(0),()=>clearTimeout(n)}async function ky(){const e=document.getElementById("app");Yo.createRoot(e).render(v.jsx(y.StrictMode,{children:v.jsx(cy,{})}))}document.addEventListener("DOMContentLoaded",ky); +*/(function(e){(function(){var t={}.hasOwnProperty;function n(){for(var r=[],l=0;l=0)&&(n[l]=e[l]);return n}function ia(e){return"default"+e.charAt(0).toUpperCase()+e.substr(1)}function mh(e){var t=hh(e,"string");return typeof t=="symbol"?t:String(t)}function hh(e,t){if(typeof e!="object"||e===null)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||"default");if(typeof r!="object")return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return(t==="string"?String:Number)(e)}function vh(e,t,n){var r=y.useRef(e!==void 0),l=y.useState(t),o=l[0],i=l[1],u=e!==void 0,s=r.current;return r.current=u,!u&&s&&o!==t&&i(t),[u?e:o,y.useCallback(function(a){for(var d=arguments.length,m=new Array(d>1?d-1:0),p=1;p{o.target===e&&(l(),t(o))},n+r)}function Bh(e){e.offsetHeight}const aa=e=>!e||typeof e=="function"?e:t=>{e.current=t};function Uh(e,t){const n=aa(e),r=aa(t);return l=>{n&&n(l),r&&r(l)}}function mo(e,t){return y.useMemo(()=>Uh(e,t),[e,t])}function Hh(e){return e&&"setState"in e?Cn.findDOMNode(e):e??null}const Wh=Wt.forwardRef(({onEnter:e,onEntering:t,onEntered:n,onExit:r,onExiting:l,onExited:o,addEndListener:i,children:u,childRef:s,...a},d)=>{const m=y.useRef(null),p=mo(m,s),g=N=>{p(Hh(N))},w=N=>T=>{N&&m.current&&N(m.current,T)},k=y.useCallback(w(e),[e]),R=y.useCallback(w(t),[t]),f=y.useCallback(w(n),[n]),c=y.useCallback(w(r),[r]),h=y.useCallback(w(l),[l]),S=y.useCallback(w(o),[o]),C=y.useCallback(w(i),[i]);return v.jsx(zh,{ref:d,...a,onEnter:k,onEntered:f,onEntering:R,onExit:c,onExited:S,onExiting:h,addEndListener:C,nodeRef:m,children:typeof u=="function"?(N,T)=>u(N,{...T,ref:g}):Wt.cloneElement(u,{ref:g})})}),Vh=Wh;function Qh(e){const t=y.useRef(e);return y.useEffect(()=>{t.current=e},[e]),t}function Pe(e){const t=Qh(e);return y.useCallback(function(...n){return t.current&&t.current(...n)},[t])}const Qf=e=>y.forwardRef((t,n)=>v.jsx("div",{...t,ref:n,className:M(t.className,e)})),Kf=Qf("h4");Kf.displayName="DivStyledAsH4";const Gf=y.forwardRef(({className:e,bsPrefix:t,as:n=Kf,...r},l)=>(t=H(t,"alert-heading"),v.jsx(n,{ref:l,className:M(e,t),...r})));Gf.displayName="AlertHeading";const Kh=Gf;function Gh(){return y.useState(null)}function Yh(){const e=y.useRef(!0),t=y.useRef(()=>e.current);return y.useEffect(()=>(e.current=!0,()=>{e.current=!1}),[]),t.current}function Xh(e){const t=y.useRef(null);return y.useEffect(()=>{t.current=e}),t.current}const Zh=typeof global<"u"&&global.navigator&&global.navigator.product==="ReactNative",Jh=typeof document<"u",ca=Jh||Zh?y.useLayoutEffect:y.useEffect,qh=["as","disabled"];function bh(e,t){if(e==null)return{};var n={},r=Object.keys(e),l,o;for(o=0;o=0)&&(n[l]=e[l]);return n}function ev(e){return!e||e.trim()==="#"}function Hu({tagName:e,disabled:t,href:n,target:r,rel:l,role:o,onClick:i,tabIndex:u=0,type:s}){e||(n!=null||r!=null||l!=null?e="a":e="button");const a={tagName:e};if(e==="button")return[{type:s||"button",disabled:t},a];const d=p=>{if((t||e==="a"&&ev(n))&&p.preventDefault(),t){p.stopPropagation();return}i==null||i(p)},m=p=>{p.key===" "&&(p.preventDefault(),d(p))};return e==="a"&&(n||(n="#"),t&&(n=void 0)),[{role:o??"button",disabled:void 0,tabIndex:t?void 0:u,href:n,target:e==="a"?r:void 0,"aria-disabled":t||void 0,rel:e==="a"?l:void 0,onClick:d,onKeyDown:m},a]}const tv=y.forwardRef((e,t)=>{let{as:n,disabled:r}=e,l=bh(e,qh);const[o,{tagName:i}]=Hu(Object.assign({tagName:n,disabled:r},l));return v.jsx(i,Object.assign({},l,o,{ref:t}))});tv.displayName="Button";const nv=["onKeyDown"];function rv(e,t){if(e==null)return{};var n={},r=Object.keys(e),l,o;for(o=0;o=0)&&(n[l]=e[l]);return n}function lv(e){return!e||e.trim()==="#"}const Yf=y.forwardRef((e,t)=>{let{onKeyDown:n}=e,r=rv(e,nv);const[l]=Hu(Object.assign({tagName:"a"},r)),o=Pe(i=>{l.onKeyDown(i),n==null||n(i)});return lv(r.href)||r.role==="button"?v.jsx("a",Object.assign({ref:t},r,l,{onKeyDown:o})):v.jsx("a",Object.assign({ref:t},r,{onKeyDown:n}))});Yf.displayName="Anchor";const ov=Yf,Xf=y.forwardRef(({className:e,bsPrefix:t,as:n=ov,...r},l)=>(t=H(t,"alert-link"),v.jsx(n,{ref:l,className:M(e,t),...r})));Xf.displayName="AlertLink";const iv=Xf,uv={[St]:"show",[Ht]:"show"},Zf=y.forwardRef(({className:e,children:t,transitionClasses:n={},onEnter:r,...l},o)=>{const i={in:!1,timeout:300,mountOnEnter:!1,unmountOnExit:!1,appear:!1,...l},u=y.useCallback((s,a)=>{Bh(s),r==null||r(s,a)},[r]);return v.jsx(Vh,{ref:o,addEndListener:Ah,...i,onEnter:u,childRef:t.ref,children:(s,a)=>y.cloneElement(t,{...a,className:M("fade",e,t.props.className,uv[s],n[s])})})});Zf.displayName="Fade";const Kl=Zf,sv={"aria-label":ot.string,onClick:ot.func,variant:ot.oneOf(["white"])},Wu=y.forwardRef(({className:e,variant:t,"aria-label":n="Close",...r},l)=>v.jsx("button",{ref:l,type:"button",className:M("btn-close",t&&`btn-close-${t}`,e),"aria-label":n,...r}));Wu.displayName="CloseButton";Wu.propTypes=sv;const Jf=Wu,qf=y.forwardRef((e,t)=>{const{bsPrefix:n,show:r=!0,closeLabel:l="Close alert",closeVariant:o,className:i,children:u,variant:s="primary",onClose:a,dismissible:d,transition:m=Kl,...p}=yh(e,{show:"onClose"}),g=H(n,"alert"),w=Pe(f=>{a&&a(!1,f)}),k=m===!0?Kl:m,R=v.jsxs("div",{role:"alert",...k?void 0:p,ref:t,className:M(i,g,s&&`${g}-${s}`,d&&`${g}-dismissible`),children:[d&&v.jsx(Jf,{onClick:w,"aria-label":l,variant:o}),u]});return k?v.jsx(k,{unmountOnExit:!0,...p,ref:void 0,in:r,children:R}):r?R:null});qf.displayName="Alert";const fa=Object.assign(qf,{Link:iv,Heading:Kh}),bf=y.forwardRef(({as:e,bsPrefix:t,variant:n="primary",size:r,active:l=!1,disabled:o=!1,className:i,...u},s)=>{const a=H(t,"btn"),[d,{tagName:m}]=Hu({tagName:e,disabled:o,...u}),p=m;return v.jsx(p,{...d,...u,ref:s,disabled:o,className:M(i,a,l&&"active",n&&`${a}-${n}`,r&&`${a}-${r}`,u.href&&o&&"disabled")})});bf.displayName="Button";const Mr=bf;function av(e){const t=y.useRef(e);return t.current=e,t}function ed(e){const t=av(e);y.useEffect(()=>()=>t.current(),[])}function cv(e,t){let n=0;return y.Children.map(e,r=>y.isValidElement(r)?t(r,n++):r)}function fv(e,t){return y.Children.toArray(e).some(n=>y.isValidElement(n)&&n.type===t)}function dv({as:e,bsPrefix:t,className:n,...r}){t=H(t,"col");const l=Df(),o=If(),i=[],u=[];return l.forEach(s=>{const a=r[s];delete r[s];let d,m,p;typeof a=="object"&&a!=null?{span:d,offset:m,order:p}=a:d=a;const g=s!==o?`-${s}`:"";d&&i.push(d===!0?`${t}${g}`:`${t}${g}-${d}`),p!=null&&u.push(`order${g}-${p}`),m!=null&&u.push(`offset${g}-${m}`)}),[{...r,className:M(n,...i,...u)},{as:e,bsPrefix:t,spans:i}]}const td=y.forwardRef((e,t)=>{const[{className:n,...r},{as:l="div",bsPrefix:o,spans:i}]=dv(e);return v.jsx(l,{...r,ref:t,className:M(n,!i.length&&o)})});td.displayName="Col";const Vu=td,nd=y.forwardRef(({bsPrefix:e,fluid:t=!1,as:n="div",className:r,...l},o)=>{const i=H(e,"container"),u=typeof t=="string"?`-${t}`:"-fluid";return v.jsx(n,{ref:o,...l,className:M(r,t?`${i}${u}`:i)})});nd.displayName="Container";const pv=nd;var mv=Function.prototype.bind.call(Function.prototype.call,[].slice);function cn(e,t){return mv(e.querySelectorAll(t))}function da(e,t){if(e.contains)return e.contains(t);if(e.compareDocumentPosition)return e===t||!!(e.compareDocumentPosition(t)&16)}const hv="data-rr-ui-";function vv(e){return`${hv}${e}`}const rd=y.createContext(Wn?window:void 0);rd.Provider;function Qu(){return y.useContext(rd)}const yv={type:ot.string,tooltip:ot.bool,as:ot.elementType},Ku=y.forwardRef(({as:e="div",className:t,type:n="valid",tooltip:r=!1,...l},o)=>v.jsx(e,{...l,ref:o,className:M(t,`${n}-${r?"tooltip":"feedback"}`)}));Ku.displayName="Feedback";Ku.propTypes=yv;const ld=Ku,gv=y.createContext({}),ct=gv,od=y.forwardRef(({id:e,bsPrefix:t,className:n,type:r="checkbox",isValid:l=!1,isInvalid:o=!1,as:i="input",...u},s)=>{const{controlId:a}=y.useContext(ct);return t=H(t,"form-check-input"),v.jsx(i,{...u,ref:s,type:r,id:e||a,className:M(n,t,l&&"is-valid",o&&"is-invalid")})});od.displayName="FormCheckInput";const id=od,ud=y.forwardRef(({bsPrefix:e,className:t,htmlFor:n,...r},l)=>{const{controlId:o}=y.useContext(ct);return e=H(e,"form-check-label"),v.jsx("label",{...r,ref:l,htmlFor:n||o,className:M(t,e)})});ud.displayName="FormCheckLabel";const Gi=ud,sd=y.forwardRef(({id:e,bsPrefix:t,bsSwitchPrefix:n,inline:r=!1,reverse:l=!1,disabled:o=!1,isValid:i=!1,isInvalid:u=!1,feedbackTooltip:s=!1,feedback:a,feedbackType:d,className:m,style:p,title:g="",type:w="checkbox",label:k,children:R,as:f="input",...c},h)=>{t=H(t,"form-check"),n=H(n,"form-switch");const{controlId:S}=y.useContext(ct),C=y.useMemo(()=>({controlId:e||S}),[S,e]),N=!R&&k!=null&&k!==!1||fv(R,Gi),T=v.jsx(id,{...c,type:w==="switch"?"checkbox":w,ref:h,isValid:i,isInvalid:u,disabled:o,as:f});return v.jsx(ct.Provider,{value:C,children:v.jsx("div",{style:p,className:M(m,N&&t,r&&`${t}-inline`,l&&`${t}-reverse`,w==="switch"&&n),children:R||v.jsxs(v.Fragment,{children:[T,N&&v.jsx(Gi,{title:g,children:k}),a&&v.jsx(ld,{type:d,tooltip:s,children:a})]})})})});sd.displayName="FormCheck";const Gl=Object.assign(sd,{Input:id,Label:Gi}),ad=y.forwardRef(({bsPrefix:e,type:t,size:n,htmlSize:r,id:l,className:o,isValid:i=!1,isInvalid:u=!1,plaintext:s,readOnly:a,as:d="input",...m},p)=>{const{controlId:g}=y.useContext(ct);return e=H(e,"form-control"),v.jsx(d,{...m,type:t,size:r,ref:p,readOnly:a,id:l||g,className:M(o,s?`${e}-plaintext`:e,n&&`${e}-${n}`,t==="color"&&`${e}-color`,i&&"is-valid",u&&"is-invalid")})});ad.displayName="FormControl";const wv=Object.assign(ad,{Feedback:ld}),cd=y.forwardRef(({className:e,bsPrefix:t,as:n="div",...r},l)=>(t=H(t,"form-floating"),v.jsx(n,{ref:l,className:M(e,t),...r})));cd.displayName="FormFloating";const Sv=cd,fd=y.forwardRef(({controlId:e,as:t="div",...n},r)=>{const l=y.useMemo(()=>({controlId:e}),[e]);return v.jsx(ct.Provider,{value:l,children:v.jsx(t,{...n,ref:r})})});fd.displayName="FormGroup";const dd=fd,pd=y.forwardRef(({as:e="label",bsPrefix:t,column:n=!1,visuallyHidden:r=!1,className:l,htmlFor:o,...i},u)=>{const{controlId:s}=y.useContext(ct);t=H(t,"form-label");let a="col-form-label";typeof n=="string"&&(a=`${a} ${a}-${n}`);const d=M(l,t,r&&"visually-hidden",n&&a);return o=o||s,n?v.jsx(Vu,{ref:u,as:"label",className:d,htmlFor:o,...i}):v.jsx(e,{ref:u,className:d,htmlFor:o,...i})});pd.displayName="FormLabel";const kv=pd,md=y.forwardRef(({bsPrefix:e,className:t,id:n,...r},l)=>{const{controlId:o}=y.useContext(ct);return e=H(e,"form-range"),v.jsx("input",{...r,type:"range",ref:l,className:M(t,e),id:n||o})});md.displayName="FormRange";const Ev=md,hd=y.forwardRef(({bsPrefix:e,size:t,htmlSize:n,className:r,isValid:l=!1,isInvalid:o=!1,id:i,...u},s)=>{const{controlId:a}=y.useContext(ct);return e=H(e,"form-select"),v.jsx("select",{...u,size:n,ref:s,className:M(r,e,t&&`${e}-${t}`,l&&"is-valid",o&&"is-invalid"),id:i||a})});hd.displayName="FormSelect";const xv=hd,vd=y.forwardRef(({bsPrefix:e,className:t,as:n="small",muted:r,...l},o)=>(e=H(e,"form-text"),v.jsx(n,{...l,ref:o,className:M(t,e,r&&"text-muted")})));vd.displayName="FormText";const Cv=vd,yd=y.forwardRef((e,t)=>v.jsx(Gl,{...e,ref:t,type:"switch"}));yd.displayName="Switch";const Nv=Object.assign(yd,{Input:Gl.Input,Label:Gl.Label}),gd=y.forwardRef(({bsPrefix:e,className:t,children:n,controlId:r,label:l,...o},i)=>(e=H(e,"form-floating"),v.jsxs(dd,{ref:i,className:M(t,e),controlId:r,...o,children:[n,v.jsx("label",{htmlFor:r,children:l})]})));gd.displayName="FloatingLabel";const Tv=gd,_v={_ref:ot.any,validated:ot.bool,as:ot.elementType},Gu=y.forwardRef(({className:e,validated:t,as:n="form",...r},l)=>v.jsx(n,{...r,ref:l,className:M(e,t&&"was-validated")}));Gu.displayName="Form";Gu.propTypes=_v;const On=Object.assign(Gu,{Group:dd,Control:wv,Floating:Sv,Check:Gl,Switch:Nv,Label:kv,Text:Cv,Range:Ev,Select:xv,FloatingLabel:Tv});var ul;function pa(e){if((!ul&&ul!==0||e)&&Wn){var t=document.createElement("div");t.style.position="absolute",t.style.top="-9999px",t.style.width="50px",t.style.height="50px",t.style.overflow="scroll",document.body.appendChild(t),ul=t.offsetWidth-t.clientWidth,document.body.removeChild(t)}return ul}function Wo(e){e===void 0&&(e=po());try{var t=e.activeElement;return!t||!t.nodeName?null:t}catch{return e.body}}function jv(e=document){const t=e.defaultView;return Math.abs(t.innerWidth-e.documentElement.clientWidth)}const ma=vv("modal-open");class Rv{constructor({ownerDocument:t,handleContainerOverflow:n=!0,isRTL:r=!1}={}){this.handleContainerOverflow=n,this.isRTL=r,this.modals=[],this.ownerDocument=t}getScrollbarWidth(){return jv(this.ownerDocument)}getElement(){return(this.ownerDocument||document).body}setModalAttributes(t){}removeModalAttributes(t){}setContainerStyle(t){const n={overflow:"hidden"},r=this.isRTL?"paddingLeft":"paddingRight",l=this.getElement();t.style={overflow:l.style.overflow,[r]:l.style[r]},t.scrollBarWidth&&(n[r]=`${parseInt(Xt(l,r)||"0",10)+t.scrollBarWidth}px`),l.setAttribute(ma,""),Xt(l,n)}reset(){[...this.modals].forEach(t=>this.remove(t))}removeContainerStyle(t){const n=this.getElement();n.removeAttribute(ma),Object.assign(n.style,t.style)}add(t){let n=this.modals.indexOf(t);return n!==-1||(n=this.modals.length,this.modals.push(t),this.setModalAttributes(t),n!==0)||(this.state={scrollBarWidth:this.getScrollbarWidth(),style:{}},this.handleContainerOverflow&&this.setContainerStyle(this.state)),n}remove(t){const n=this.modals.indexOf(t);n!==-1&&(this.modals.splice(n,1),!this.modals.length&&this.handleContainerOverflow&&this.removeContainerStyle(this.state),this.removeModalAttributes(t))}isTopModal(t){return!!this.modals.length&&this.modals[this.modals.length-1]===t}}const Yu=Rv,Vo=(e,t)=>Wn?e==null?(t||po()).body:(typeof e=="function"&&(e=e()),e&&"current"in e&&(e=e.current),e&&("nodeType"in e||e.getBoundingClientRect)?e:null):null;function Lv(e,t){const n=Qu(),[r,l]=y.useState(()=>Vo(e,n==null?void 0:n.document));if(!r){const o=Vo(e);o&&l(o)}return y.useEffect(()=>{t&&r&&t(r)},[t,r]),y.useEffect(()=>{const o=Vo(e);o!==r&&l(o)},[e,r]),r}function Ov({children:e,in:t,onExited:n,mountOnEnter:r,unmountOnExit:l}){const o=y.useRef(null),i=y.useRef(t),u=Pe(n);y.useEffect(()=>{t?i.current=!0:u(o.current)},[t,u]);const s=mo(o,e.ref),a=y.cloneElement(e,{ref:s});return t?a:l||!i.current&&r?null:a}function Pv({in:e,onTransition:t}){const n=y.useRef(null),r=y.useRef(!0),l=Pe(t);return ca(()=>{if(!n.current)return;let o=!1;return l({in:e,element:n.current,initial:r.current,isStale:()=>o}),()=>{o=!0}},[e,l]),ca(()=>(r.current=!1,()=>{r.current=!0}),[]),n}function Fv({children:e,in:t,onExited:n,onEntered:r,transition:l}){const[o,i]=y.useState(!t);t&&o&&i(!1);const u=Pv({in:!!t,onTransition:a=>{const d=()=>{a.isStale()||(a.in?r==null||r(a.element,a.initial):(i(!0),n==null||n(a.element)))};Promise.resolve(l(a)).then(d,m=>{throw a.in||i(!0),m})}}),s=mo(u,e.ref);return o&&!t?null:y.cloneElement(e,{ref:s})}function ha(e,t,n){return e?v.jsx(e,Object.assign({},n)):t?v.jsx(Fv,Object.assign({},n,{transition:t})):v.jsx(Ov,Object.assign({},n))}function Mv(e){return e.code==="Escape"||e.keyCode===27}const zv=["show","role","className","style","children","backdrop","keyboard","onBackdropClick","onEscapeKeyDown","transition","runTransition","backdropTransition","runBackdropTransition","autoFocus","enforceFocus","restoreFocus","restoreFocusOptions","renderDialog","renderBackdrop","manager","container","onShow","onHide","onExit","onExited","onExiting","onEnter","onEntering","onEntered"];function $v(e,t){if(e==null)return{};var n={},r=Object.keys(e),l,o;for(o=0;o=0)&&(n[l]=e[l]);return n}let Qo;function Dv(e){return Qo||(Qo=new Yu({ownerDocument:e==null?void 0:e.document})),Qo}function Iv(e){const t=Qu(),n=e||Dv(t),r=y.useRef({dialog:null,backdrop:null});return Object.assign(r.current,{add:()=>n.add(r.current),remove:()=>n.remove(r.current),isTopModal:()=>n.isTopModal(r.current),setDialogRef:y.useCallback(l=>{r.current.dialog=l},[]),setBackdropRef:y.useCallback(l=>{r.current.backdrop=l},[])})}const wd=y.forwardRef((e,t)=>{let{show:n=!1,role:r="dialog",className:l,style:o,children:i,backdrop:u=!0,keyboard:s=!0,onBackdropClick:a,onEscapeKeyDown:d,transition:m,runTransition:p,backdropTransition:g,runBackdropTransition:w,autoFocus:k=!0,enforceFocus:R=!0,restoreFocus:f=!0,restoreFocusOptions:c,renderDialog:h,renderBackdrop:S=K=>v.jsx("div",Object.assign({},K)),manager:C,container:N,onShow:T,onHide:j=()=>{},onExit:B,onExited:P,onExiting:ie,onEnter:Ve,onEntering:Qe,onEntered:rn}=e,Qn=$v(e,zv);const _e=Qu(),Ke=Lv(N),x=Iv(C),L=Yh(),O=Xh(n),[D,A]=y.useState(!n),fe=y.useRef(null);y.useImperativeHandle(t,()=>x,[x]),Wn&&!O&&n&&(fe.current=Wo(_e==null?void 0:_e.document)),n&&D&&A(!1);const je=Pe(()=>{if(x.add(),on.current=Ql(document,"keydown",ho),ln.current=Ql(document,"focus",()=>setTimeout(Re),!0),T&&T(),k){var K,Hr;const Yn=Wo((K=(Hr=x.dialog)==null?void 0:Hr.ownerDocument)!=null?K:_e==null?void 0:_e.document);x.dialog&&Yn&&!da(x.dialog,Yn)&&(fe.current=Yn,x.dialog.focus())}}),qe=Pe(()=>{if(x.remove(),on.current==null||on.current(),ln.current==null||ln.current(),f){var K;(K=fe.current)==null||K.focus==null||K.focus(c),fe.current=null}});y.useEffect(()=>{!n||!Ke||je()},[n,Ke,je]),y.useEffect(()=>{D&&qe()},[D,qe]),ed(()=>{qe()});const Re=Pe(()=>{if(!R||!L()||!x.isTopModal())return;const K=Wo(_e==null?void 0:_e.document);x.dialog&&K&&!da(x.dialog,K)&&x.dialog.focus()}),mt=Pe(K=>{K.target===K.currentTarget&&(a==null||a(K),u===!0&&j())}),ho=Pe(K=>{s&&Mv(K)&&x.isTopModal()&&(d==null||d(K),K.defaultPrevented||j())}),ln=y.useRef(),on=y.useRef(),Kn=(...K)=>{A(!0),P==null||P(...K)};if(!Ke)return null;const Ur=Object.assign({role:r,ref:x.setDialogRef,"aria-modal":r==="dialog"?!0:void 0},Qn,{style:o,className:l,tabIndex:-1});let Gn=h?h(Ur):v.jsx("div",Object.assign({},Ur,{children:y.cloneElement(i,{role:"document"})}));Gn=ha(m,p,{unmountOnExit:!0,mountOnEnter:!0,appear:!0,in:!!n,onExit:B,onExiting:ie,onExited:Kn,onEnter:Ve,onEntering:Qe,onEntered:rn,children:Gn});let It=null;return u&&(It=S({ref:x.setBackdropRef,onClick:mt}),It=ha(g,w,{in:!!n,appear:!0,mountOnEnter:!0,unmountOnExit:!0,children:It})),v.jsx(v.Fragment,{children:Cn.createPortal(v.jsxs(v.Fragment,{children:[It,Gn]}),Ke)})});wd.displayName="Modal";const Av=Object.assign(wd,{Manager:Yu});function Bv(e,t){return e.classList?!!t&&e.classList.contains(t):(" "+(e.className.baseVal||e.className)+" ").indexOf(" "+t+" ")!==-1}function Uv(e,t){e.classList?e.classList.add(t):Bv(e,t)||(typeof e.className=="string"?e.className=e.className+" "+t:e.setAttribute("class",(e.className&&e.className.baseVal||"")+" "+t))}function va(e,t){return e.replace(new RegExp("(^|\\s)"+t+"(?:\\s|$)","g"),"$1").replace(/\s+/g," ").replace(/^\s*|\s*$/g,"")}function Hv(e,t){e.classList?e.classList.remove(t):typeof e.className=="string"?e.className=va(e.className,t):e.setAttribute("class",va(e.className&&e.className.baseVal||"",t))}const fn={FIXED_CONTENT:".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",STICKY_CONTENT:".sticky-top",NAVBAR_TOGGLER:".navbar-toggler"};class Wv extends Yu{adjustAndStore(t,n,r){const l=n.style[t];n.dataset[t]=l,Xt(n,{[t]:`${parseFloat(Xt(n,t))+r}px`})}restore(t,n){const r=n.dataset[t];r!==void 0&&(delete n.dataset[t],Xt(n,{[t]:r}))}setContainerStyle(t){super.setContainerStyle(t);const n=this.getElement();if(Uv(n,"modal-open"),!t.scrollBarWidth)return;const r=this.isRTL?"paddingLeft":"paddingRight",l=this.isRTL?"marginLeft":"marginRight";cn(n,fn.FIXED_CONTENT).forEach(o=>this.adjustAndStore(r,o,t.scrollBarWidth)),cn(n,fn.STICKY_CONTENT).forEach(o=>this.adjustAndStore(l,o,-t.scrollBarWidth)),cn(n,fn.NAVBAR_TOGGLER).forEach(o=>this.adjustAndStore(l,o,t.scrollBarWidth))}removeContainerStyle(t){super.removeContainerStyle(t);const n=this.getElement();Hv(n,"modal-open");const r=this.isRTL?"paddingLeft":"paddingRight",l=this.isRTL?"marginLeft":"marginRight";cn(n,fn.FIXED_CONTENT).forEach(o=>this.restore(r,o)),cn(n,fn.STICKY_CONTENT).forEach(o=>this.restore(l,o)),cn(n,fn.NAVBAR_TOGGLER).forEach(o=>this.restore(l,o))}}let Ko;function Vv(e){return Ko||(Ko=new Wv(e)),Ko}const Sd=y.forwardRef(({className:e,bsPrefix:t,as:n="div",...r},l)=>(t=H(t,"modal-body"),v.jsx(n,{ref:l,className:M(e,t),...r})));Sd.displayName="ModalBody";const Qv=Sd,Kv=y.createContext({onHide(){}}),kd=Kv,Ed=y.forwardRef(({bsPrefix:e,className:t,contentClassName:n,centered:r,size:l,fullscreen:o,children:i,scrollable:u,...s},a)=>{e=H(e,"modal");const d=`${e}-dialog`,m=typeof o=="string"?`${e}-fullscreen-${o}`:`${e}-fullscreen`;return v.jsx("div",{...s,ref:a,className:M(d,t,l&&`${e}-${l}`,r&&`${d}-centered`,u&&`${d}-scrollable`,o&&m),children:v.jsx("div",{className:M(`${e}-content`,n),children:i})})});Ed.displayName="ModalDialog";const xd=Ed,Cd=y.forwardRef(({className:e,bsPrefix:t,as:n="div",...r},l)=>(t=H(t,"modal-footer"),v.jsx(n,{ref:l,className:M(e,t),...r})));Cd.displayName="ModalFooter";const Gv=Cd,Yv=y.forwardRef(({closeLabel:e="Close",closeVariant:t,closeButton:n=!1,onHide:r,children:l,...o},i)=>{const u=y.useContext(kd),s=Pe(()=>{u==null||u.onHide(),r==null||r()});return v.jsxs("div",{ref:i,...o,children:[l,n&&v.jsx(Jf,{"aria-label":e,variant:t,onClick:s})]})}),Xv=Yv,Nd=y.forwardRef(({bsPrefix:e,className:t,closeLabel:n="Close",closeButton:r=!1,...l},o)=>(e=H(e,"modal-header"),v.jsx(Xv,{ref:o,...l,className:M(t,e),closeLabel:n,closeButton:r})));Nd.displayName="ModalHeader";const Zv=Nd,Jv=Qf("h4"),Td=y.forwardRef(({className:e,bsPrefix:t,as:n=Jv,...r},l)=>(t=H(t,"modal-title"),v.jsx(n,{ref:l,className:M(e,t),...r})));Td.displayName="ModalTitle";const qv=Td;function bv(e){return v.jsx(Kl,{...e,timeout:null})}function ey(e){return v.jsx(Kl,{...e,timeout:null})}const _d=y.forwardRef(({bsPrefix:e,className:t,style:n,dialogClassName:r,contentClassName:l,children:o,dialogAs:i=xd,"aria-labelledby":u,"aria-describedby":s,"aria-label":a,show:d=!1,animation:m=!0,backdrop:p=!0,keyboard:g=!0,onEscapeKeyDown:w,onShow:k,onHide:R,container:f,autoFocus:c=!0,enforceFocus:h=!0,restoreFocus:S=!0,restoreFocusOptions:C,onEntered:N,onExit:T,onExiting:j,onEnter:B,onEntering:P,onExited:ie,backdropClassName:Ve,manager:Qe,...rn},Qn)=>{const[_e,Ke]=y.useState({}),[x,L]=y.useState(!1),O=y.useRef(!1),D=y.useRef(!1),A=y.useRef(null),[fe,je]=Gh(),qe=mo(Qn,je),Re=Pe(R),mt=kh();e=H(e,"modal");const ho=y.useMemo(()=>({onHide:Re}),[Re]);function ln(){return Qe||Vv({isRTL:mt})}function on($){if(!Wn)return;const un=ln().getScrollbarWidth()>0,Zu=$.scrollHeight>po($).documentElement.clientHeight;Ke({paddingRight:un&&!Zu?pa():void 0,paddingLeft:!un&&Zu?pa():void 0})}const Kn=Pe(()=>{fe&&on(fe.dialog)});ed(()=>{Ki(window,"resize",Kn),A.current==null||A.current()});const Ur=()=>{O.current=!0},Gn=$=>{O.current&&fe&&$.target===fe.dialog&&(D.current=!0),O.current=!1},It=()=>{L(!0),A.current=Vf(fe.dialog,()=>{L(!1)})},K=$=>{$.target===$.currentTarget&&It()},Hr=$=>{if(p==="static"){K($);return}if(D.current||$.target!==$.currentTarget){D.current=!1;return}R==null||R()},Yn=$=>{g?w==null||w($):($.preventDefault(),p==="static"&&It())},Dd=($,un)=>{$&&on($),B==null||B($,un)},Id=$=>{A.current==null||A.current(),T==null||T($)},Ad=($,un)=>{P==null||P($,un),Wf(window,"resize",Kn)},Bd=$=>{$&&($.style.display=""),ie==null||ie($),Ki(window,"resize",Kn)},Ud=y.useCallback($=>v.jsx("div",{...$,className:M(`${e}-backdrop`,Ve,!m&&"show")}),[m,Ve,e]),Xu={...n,..._e};Xu.display="block";const Hd=$=>v.jsx("div",{role:"dialog",...$,style:Xu,className:M(t,e,x&&`${e}-static`,!m&&"show"),onClick:p?Hr:void 0,onMouseUp:Gn,"aria-label":a,"aria-labelledby":u,"aria-describedby":s,children:v.jsx(i,{...rn,onMouseDown:Ur,className:r,contentClassName:l,children:o})});return v.jsx(kd.Provider,{value:ho,children:v.jsx(Av,{show:d,ref:qe,backdrop:p,container:f,keyboard:!0,autoFocus:c,enforceFocus:h,restoreFocus:S,restoreFocusOptions:C,onEscapeKeyDown:Yn,onShow:k,onHide:R,onEnter:Dd,onEntering:Ad,onEntered:N,onExit:Id,onExiting:j,onExited:Bd,manager:ln(),transition:m?bv:void 0,backdropTransition:m?ey:void 0,renderBackdrop:Ud,renderDialog:Hd})})});_d.displayName="Modal";const tt=Object.assign(_d,{Body:Qv,Header:Zv,Title:qv,Footer:Gv,Dialog:xd,TRANSITION_DURATION:300,BACKDROP_TRANSITION_DURATION:150}),ya=1e3;function ty(e,t,n){const r=(e-t)/(n-t)*100;return Math.round(r*ya)/ya}function ga({min:e,now:t,max:n,label:r,visuallyHidden:l,striped:o,animated:i,className:u,style:s,variant:a,bsPrefix:d,...m},p){return v.jsx("div",{ref:p,...m,role:"progressbar",className:M(u,`${d}-bar`,{[`bg-${a}`]:a,[`${d}-bar-animated`]:i,[`${d}-bar-striped`]:i||o}),style:{width:`${ty(t,e,n)}%`,...s},"aria-valuenow":t,"aria-valuemin":e,"aria-valuemax":n,children:l?v.jsx("span",{className:"visually-hidden",children:r}):r})}const jd=y.forwardRef(({isChild:e=!1,...t},n)=>{const r={min:0,max:100,animated:!1,visuallyHidden:!1,striped:!1,...t};if(r.bsPrefix=H(r.bsPrefix,"progress"),e)return ga(r,n);const{min:l,now:o,max:i,label:u,visuallyHidden:s,striped:a,animated:d,bsPrefix:m,variant:p,className:g,children:w,...k}=r;return v.jsx("div",{ref:n,...k,className:M(g,m),children:w?cv(w,R=>y.cloneElement(R,{isChild:!0})):ga({min:l,now:o,max:i,label:u,visuallyHidden:s,striped:a,animated:d,bsPrefix:m,variant:p},n)})});jd.displayName="ProgressBar";const ny=jd,Rd=y.forwardRef(({bsPrefix:e,className:t,as:n="div",...r},l)=>{const o=H(e,"row"),i=Df(),u=If(),s=`${o}-cols`,a=[];return i.forEach(d=>{const m=r[d];delete r[d];let p;m!=null&&typeof m=="object"?{cols:p}=m:p=m;const g=d!==u?`-${d}`:"";p!=null&&a.push(`${s}${g}-${p}`)}),v.jsx(n,{ref:l,...r,className:M(t,o,...a)})});Rd.displayName="Row";const Ld=Rd,Od=y.forwardRef(({bsPrefix:e,variant:t,animation:n="border",size:r,as:l="div",className:o,...i},u)=>{e=H(e,"spinner");const s=`${e}-${n}`;return v.jsx(l,{ref:u,...i,className:M(o,s,r&&`${s}-${r}`,t&&`text-${t}`)})});Od.displayName="Spinner";const An=Od,ry=window.origin==="null"||window.origin==="http://localhost:3031"?"http://localhost:3030":"",Sl="initializing",wa="paused",Pd="live",ly="error",vt=async(e,t,n)=>{console.log(e,t);const r=ry+t,l={method:e,headers:{Accept:"application/json"},body:n};let o={method:e,path:t,text:""},i;try{i=await fetch(r,l)}catch{return o.text="network error",Promise.reject(o)}if(o.status=i.status,o.statusText=i.statusText,!i.ok){const s=await i.text();try{const a=JSON.parse(s);o.text=a.human_readable!==void 0?a.human_readable:JSON.stringify(a,null,2)}catch{o.text=s}return Promise.reject(o)}return await i.json()},ft={listTorrents:()=>vt("GET","/torrents"),getTorrentDetails:e=>vt("GET",`/torrents/${e}`),getTorrentStats:e=>vt("GET",`/torrents/${e}/stats/v1`),uploadTorrent:(e,t)=>{t=t||{};let n="/torrents?&overwrite=true";return t.listOnly&&(n+="&list_only=true"),t.selectedFiles!=null&&(n+=`&only_files=${t.selectedFiles.join(",")}`),vt("POST",n,e)},pause:e=>vt("POST",`/torrents/${e}/pause`),start:e=>vt("POST",`/torrents/${e}/start`),forget:e=>vt("POST",`/torrents/${e}/forget`),delete:e=>vt("POST",`/torrents/${e}/delete`)},Vn=y.createContext(null),Fd=y.createContext(null),Go=({className:e,onClick:t,disabled:n,color:r})=>{const l=o=>{o.stopPropagation(),!n&&t()};return v.jsx("a",{className:`bi ${e} p-1`,onClick:l,href:"#"})},oy=({id:e,show:t,onHide:n})=>{if(!t)return null;const[r,l]=y.useState(!1),[o,i]=y.useState(null),[u,s]=y.useState(!1),a=y.useContext(Vn),d=()=>{l(!1),i(null),s(!1),n()},m=()=>{s(!0),(r?ft.delete:ft.forget)(e).then(()=>{a.refreshTorrents(),d()}).catch(g=>{i({text:`Error deleting torrent id=${e}`,details:g}),s(!1)})};return v.jsxs(tt,{show:t,onHide:d,children:[v.jsx(tt.Header,{closeButton:!0,children:"Delete torrent"}),v.jsxs(tt.Body,{children:[v.jsx(On,{children:v.jsx(On.Group,{controlId:"delete-torrent",children:v.jsx(On.Check,{type:"checkbox",label:"Also delete files",checked:r,onChange:()=>l(!r)})})}),o&&v.jsx(zr,{error:o})]}),v.jsxs(tt.Footer,{children:[u&&v.jsx(An,{}),v.jsx(Mr,{variant:"primary",onClick:m,disabled:u,children:"OK"}),v.jsx(Mr,{variant:"secondary",onClick:d,children:"Cancel"})]})]})},iy=({id:e,statsResponse:t})=>{let n=t.state,[r,l]=y.useState(!1),[o,i]=y.useState(!1),u=y.useContext(Fd);const s=n=="live",a=n=="paused"||n=="error",d=y.useContext(Vn),m=()=>{l(!0),ft.start(e).then(()=>{u.refresh()},k=>{d.setCloseableError({text:`Error starting torrent id=${e}`,details:k})}).finally(()=>l(!1))},p=()=>{l(!0),ft.pause(e).then(()=>{u.refresh()},k=>{d.setCloseableError({text:`Error pausing torrent id=${e}`,details:k})}).finally(()=>l(!1))},g=()=>{l(!0),i(!0)},w=()=>{l(!1),i(!1)};return v.jsx(Ld,{children:v.jsxs(Vu,{children:[a&&v.jsx(Go,{className:"bi-play-circle",onClick:m,disabled:r,color:"success"}),s&&v.jsx(Go,{className:"bi-pause-circle",onClick:p,disabled:r}),v.jsx(Go,{className:"bi-x-circle",onClick:g,disabled:r,color:"danger"}),v.jsx(oy,{id:e,show:o,onHide:w})]})})},uy=({id:e,detailsResponse:t,statsResponse:n})=>{const r=(n==null?void 0:n.state)??"",l=n==null?void 0:n.error,o=(n==null?void 0:n.total_bytes)??1,i=(n==null?void 0:n.progress_bytes)??0,u=(n==null?void 0:n.finished)||!1,s=l?100:i/o*100,a=(r==Sl||r==Pd)&&!u,d=l?"Error":`${s.toFixed(2)}%`,m=l?"danger":u?"success":r==Sl?"warning":"primary",p=()=>{var R;let k=(R=n==null?void 0:n.live)==null?void 0:R.snapshot.peer_stats;return k?`${k.live} / ${k.seen}`:""},g=()=>{var k;if(u)return"Completed";switch(r){case wa:return"Paused";case Sl:return"Checking files";case ly:return"Error"}return((k=n.live)==null?void 0:k.download_speed.human_readable)??"N/A"};let w=[];return l?w.push("bg-warning"):e%2==0&&w.push("bg-light"),v.jsxs(Ld,{className:w.join(" "),children:[v.jsx(yt,{size:3,label:"Name",children:t?v.jsxs(v.Fragment,{children:[v.jsx("div",{className:"text-truncate",children:yy(t)}),l&&v.jsxs("p",{className:"text-danger",children:[v.jsx("strong",{children:"Error:"})," ",l]})]}):v.jsx(An,{})}),n?v.jsxs(v.Fragment,{children:[v.jsx(yt,{label:"Size",children:`${zd(o)} `}),v.jsx(yt,{size:2,label:(r==wa,"Progress"),children:v.jsx(ny,{now:s,label:d,animated:a,variant:m})}),v.jsx(yt,{size:2,label:"Down Speed",children:g()}),v.jsx(yt,{label:"ETA",children:gy(n)}),v.jsx(yt,{size:2,label:"Peers",children:p()}),v.jsx(yt,{label:"Actions",children:v.jsx(iy,{id:e,statsResponse:n})})]}):v.jsx(yt,{label:"Loading stats",size:8,children:v.jsx(An,{})})]})},yt=({size:e,label:t,children:n})=>v.jsxs(Vu,{md:e||1,className:"py-3",children:[v.jsx("div",{className:"fw-bold",children:t}),n]}),sy=({id:e,torrent:t})=>{const[n,r]=y.useState(null),[l,o]=y.useState(null),[i,u]=y.useState(0),s=()=>{u(i+1)};return y.useEffect(()=>{if(n===null)return Sy(async()=>{await ft.getTorrentDetails(t.id).then(r)},1e3)},[n]),y.useEffect(()=>$d(async()=>ft.getTorrentStats(t.id).then(g=>(o(g),g)).then(g=>g.finished?1e4:g.state==Sl||g.state==Pd?1e3:1e4,g=>1e4),0),[i]),v.jsx(Fd.Provider,{value:{refresh:s},children:v.jsx(uy,{id:e,detailsResponse:n,statsResponse:l})})},ay=e=>{if(e.torrents===null&&e.loading)return v.jsx(An,{});if(e.torrents!==null)return e.torrents.length===0?v.jsx("div",{className:"text-center",children:v.jsx("p",{children:"No existing torrents found. Add them through buttons below."})}):v.jsx(v.Fragment,{children:e.torrents.map(t=>v.jsx(sy,{id:t.id,torrent:t},t.id))})},cy=()=>{const[e,t]=y.useState(null),[n,r]=y.useState(null),[l,o]=y.useState(null),[i,u]=y.useState(!1),s=async()=>{u(!0);let d=await ft.listTorrents().finally(()=>u(!1));o(d.torrents)};y.useEffect(()=>$d(async()=>s().then(()=>(r(null),5e3),d=>(r({text:"Error refreshing torrents",details:d}),console.error(d),5e3)),0),[]);const a={setCloseableError:t,refreshTorrents:s};return v.jsx(Vn.Provider,{value:a,children:v.jsxs("div",{className:"text-center",children:[v.jsx("h1",{className:"mt-3 mb-4",children:"rqbit web 0.0.1-alpha"}),v.jsx(vy,{closeableError:e,otherError:n,torrents:l,torrentsLoading:i})]})})},fy=e=>{let{details:t}=e;return t?v.jsxs(v.Fragment,{children:[t.status&&v.jsxs("strong",{children:[t.status," ",t.statusText,": "]}),t.text]}):null},zr=e=>{let{error:t,remove:n}=e;return t==null?null:v.jsxs(fa,{variant:"danger",onClose:n,dismissible:n!=null,children:[v.jsx(fa.Heading,{children:t.text}),v.jsx(fy,{details:t.details})]})},Md=({buttonText:e,onClick:t,data:n,resetData:r,variant:l})=>{const[o,i]=y.useState(!1),[u,s]=y.useState([]),[a,d]=y.useState(null);y.useContext(Vn);const m=n!==null||a!==null;y.useEffect(()=>{if(n===null)return;let g=setTimeout(async()=>{i(!0);try{const w=await ft.uploadTorrent(n,{listOnly:!0});s(w.details.files)}catch(w){d({text:"Error uploading torrent",details:w})}finally{i(!1)}},0);return()=>clearTimeout(g)},[n]);const p=()=>{r(),d(null),s([]),i(!1)};return v.jsxs(v.Fragment,{children:[v.jsx(Mr,{variant:l,onClick:t,className:"m-1",children:e}),v.jsx(my,{show:m,onHide:p,fileListError:a,fileList:u,data:n,fileListLoading:o})]})},dy=()=>{let[e,t]=y.useState(null);const n=()=>{const r=prompt("Enter magnet link or HTTP(s) URL");t(r===""?null:r)};return v.jsx(Md,{variant:"primary",buttonText:"Add Torrent from Magnet Link",onClick:n,data:e,resetData:()=>t(null)})},py=()=>{const e=y.useRef(),[t,n]=y.useState(null),r=async()=>{const i=e.current.files[0];n(i)},l=()=>{e.current.value="",n(null)},o=()=>{e.current.click()};return v.jsxs(v.Fragment,{children:[v.jsx("input",{type:"file",ref:e,accept:".torrent",onChange:r,className:"d-none"}),v.jsx(Md,{variant:"secondary",buttonText:"Upload .torrent File",onClick:o,data:t,resetData:l})]})},my=e=>{let{show:t,onHide:n,fileList:r,fileListError:l,fileListLoading:o,data:i}=e;const[u,s]=y.useState([]),[a,d]=y.useState(!1),[m,p]=y.useState(null),g=y.useContext(Vn);y.useEffect(()=>{s(r.map((f,c)=>c))},[r]);const w=()=>{n(),s([]),p(null),d(!1)},k=f=>{u.includes(f)?s(u.filter(c=>c!==f)):s([...u,f])},R=async()=>{d(!0),ft.uploadTorrent(i,{selectedFiles:u}).then(()=>{n(),g.refreshTorrents()},f=>{p({text:"Error starting torrent",details:f})}).finally(()=>d(!1))};return v.jsxs(tt,{show:t,onHide:w,size:"lg",children:[v.jsx(tt.Header,{closeButton:!0,children:!!l||v.jsx(tt.Title,{children:"Select Files"})}),v.jsxs(tt.Body,{children:[o?v.jsx(An,{}):l?v.jsx(zr,{error:l}):v.jsx(On,{children:r.map((f,c)=>v.jsx(On.Group,{controlId:`check-${c}`,children:v.jsx(On.Check,{type:"checkbox",label:`${f.name} (${zd(f.length)})`,checked:u.includes(c),onChange:()=>k(c)})},c))}),v.jsx(zr,{error:m})]}),v.jsxs(tt.Footer,{children:[a&&v.jsx(An,{}),v.jsx(Mr,{variant:"primary",onClick:R,disabled:o||a||u.length==0,children:"OK"}),v.jsx(Mr,{variant:"secondary",onClick:w,children:"Cancel"})]})]})},hy=()=>v.jsxs("div",{id:"buttons-container",className:"mt-3",children:[v.jsx(dy,{}),v.jsx(py,{})]}),vy=e=>{let t=y.useContext(Vn);return v.jsxs(pv,{children:[v.jsx(zr,{error:e.closeableError,remove:()=>t.setCloseableError(null)}),v.jsx(zr,{error:e.otherError}),v.jsx(ay,{torrents:e.torrents,loading:e.torrentsLoading}),v.jsx(hy,{})]})};function zd(e){if(e===0)return"0 Bytes";const t=1024,n=["Bytes","KB","MB","GB"],r=Math.floor(Math.log(e)/Math.log(t));return parseFloat((e/Math.pow(t,r)).toFixed(2))+" "+n[r]}function yy(e){return e.files.filter(n=>n.included).reduce((n,r)=>n.length>r.length?n:r).name}function gy(e){var n,r,l;let t=(l=(r=(n=e==null?void 0:e.live)==null?void 0:n.time_remaining)==null?void 0:r.duration)==null?void 0:l.secs;return t==null?"N/A":wy(t)}function wy(e){const t=Math.floor(e/3600),n=Math.floor(e%3600/60),r=e%60,l=(o,i)=>o>0?`${o}${i}`:"";return t>0?`${l(t,"h")} ${l(n,"m")}`.trim():n>0?`${l(n,"m")} ${l(r,"s")}`.trim():`${l(r,"s")}`.trim()}function $d(e,t){let n,r=t;const l=async()=>{if(r=await e(),r==null)throw"asyncCallback returned null or undefined";o()};let o=()=>{n=setTimeout(l,r)};return o(),()=>{clearTimeout(n)}}function Sy(e,t){let n;const r=async()=>{await e().then(()=>!1,()=>!0)&&l()};let l=o=>{n=setTimeout(r,o!==void 0?o:t)};return l(0),()=>clearTimeout(n)}async function ky(){const e=document.getElementById("app");Yo.createRoot(e).render(v.jsx(y.StrictMode,{children:v.jsx(cy,{})}))}document.addEventListener("DOMContentLoaded",ky); diff --git a/crates/librqbit/webui/src/index.tsx b/crates/librqbit/webui/src/index.tsx index 9462266..1d4a3ec 100644 --- a/crates/librqbit/webui/src/index.tsx +++ b/crates/librqbit/webui/src/index.tsx @@ -106,7 +106,7 @@ const TorrentActions: React.FC<{ let refreshCtx = useContext(RefreshTorrentStatsContext); const canPause = state == 'live'; - const canUnpause = state == 'paused'; + const canUnpause = state == 'paused' || state == 'error'; const ctx = useContext(AppContext);