Add favorites list navbar component

This commit is contained in:
the1812 2020-01-31 11:09:46 +08:00
parent b22060fdaa
commit 02e2b4539e
21 changed files with 468 additions and 101 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -30,13 +30,14 @@
"compact-layout.min.js": "B20609A7CBBDB1845FA0156FB5BE6B1E1A1B8B069EA85F65D16241DD2C12D738",
"custom-control-background.min.css": "1981FD2BF3B17ECF33F98D5DEDAF0D32ACBE9532A51FDB70822286991AB98EF3",
"custom-control-background.min.js": "2A439B045A51D24F5115DD25995ED37E3D0371A074199FE6C727F2235F39C4D9",
"custom-navbar.min.css": "BC8741D8949DEEBD3A745292A139B639A54C43E8015D348649EF09228A1A568A",
"custom-navbar.min.css": "B6EF1AF22222A5F10B648D57494B4148B3E264B7D3F1EE5B0047BEBB51DFC2FB",
"custom-navbar.min.html": "17FD1B1727E8D62E7997F10002FE7BF23472F390042D44DE3376A7A5A5FF2FDF",
"custom-navbar.min.js": "10A4390317FA65E016F29953B0FF9FD70C7E39AAB4E883A563B3EE21B33B7249",
"custom-navbar.min.js": "3CBF688BE1F0FD3AEFFB6268328FEEC5B1BB189EC0F53C6B86E4D9353AE67DE7",
"custom-navbar-activities.min.js": "7CCA4AF4555CF9E9D338FE7285879C9F1396112F1FCD7293AD92EEE965E656C3",
"custom-navbar-blank.min.js": "DC2B75D5760EECD3A257785FDFBB7E5DEBF61CD9083C68DD5BCE468B093F54F3",
"custom-navbar-category.min.js": "4CF38ACE1D0501217266D1E35DFCBF9D5C1D9A3838C54D53C614878BB8CF55E2",
"custom-navbar-component.min.js": "D1B98EDF5C32D19E4A009D2303F69207B35ED35DD06E0F161E7D0BBB313F3C37",
"custom-navbar-favorites-list.min.js": "8F4387F2E99B6D25DF5325EAFB158E159217FAFC586EAA3D2C055E862DB459A7",
"custom-navbar-iframe.min.js": "C4EE469EC09655F9FF535ACBBD2A5F7C332DA2081936F8F485F5FB015EBD794B",
"custom-navbar-logo.min.js": "236CCC887A3917A6D4840889B7380B648197765B8CDA27CB233F3F1E3215F7BB",
"custom-navbar-messages.min.js": "D7B315A4D8FD9E2EF9C1E40C1F3CA7EC18C5A87AC7A9410049061A0D851868DE",
@ -47,7 +48,7 @@
"custom-navbar-upload.min.js": "0CDEEA46DCF0D6187C86BB12DE8CD36737116EF171AA1F63AB20C5DC7549C976",
"custom-navbar-user-info.min.js": "F0C8D9FC280BA0A69746EC36079FA97AD9F0B69EB7D8FB56C6ED815C46791321",
"custom-navbar-video-list.min.js": "08D6713144E910C1303CB610A5890A5663B92BE82630BDA3C8E6299FB4A429E2",
"custom-navbar-watchlater-list.min.js": "CFE0290F6F87551FF04C5D079A63FB7A0680A2706FC9CD9E034F97975703D045",
"custom-navbar-watchlater-list.min.js": "2742EAFAA8C716A9E937F70DE1D222DAA97A83EA6323B56DA001F609757240DE",
"danmaku-converter.min.js": "FDAB4DB2E3C79730A39CDA7C5FD193693621FED206C6549E9B8F13778080CC12",
"dark.min.css": "9C8701C1C5947D7579022E3198CA2C7290C2ACC1D9E84D2BD4133F91C80F27DC",
"dark-important.min.css": "8453644F7FC8BB0E9DA401DC161815E2AC198E9B4D7A5A19C29934B672F277B1",
@ -66,7 +67,7 @@
"download-danmaku.min.js": "87BC2B39D99E029BB602AB2F59A387FC960D5779791524F8C26FBC0278CD8F8E",
"download-subtitle.min.js": "4B99A00FEEA40C6D577AC8BD8DFFD34D91B75E150C7848B965D58B0096DF762C",
"download-video.min.css": "9B7FFAC852999B11DB62B6467CDBA1AEE53B7F3FA6C592185281542B25AF527A",
"download-video.min.html": "D662FBB3C6899E75A52D15C59C53FD6966DA6E4CE463BCEFF0008D5BD3796C7F",
"download-video.min.html": "B7EC01DF01DBA78A7B009BDA78865891A974F84A1D72964B7393A07E50D5E5F5",
"download-video.min.js": "6A43BC28D28CCB2B047E3E7AAF75314F0DB5B2004F75D1414D282FC3A0129888",
"download-video-package.min.js": "B10FF11DE7DFBACEC38F195B8E836511E527215B5E177CB1D223D14F30EB1435",
"dpi-img.vue.min.js": "905DD5D8071437FE1C04C3E156E61E594C676BF3928241CC52BCAFAAA0FFA089",
@ -196,7 +197,7 @@
"tweets.min.css": "9015C1F165C91B9205ABBE4E8A3B5FA83DB1EB4B5CF2442846AF61E44FF178A8",
"url-params-clean.min.js": "1B9818B2CF9405C0CC97553594BC8F190C04032D2205CFE6FAD5F93F3F62C0FF",
"v-checkbox.vue.min.js": "A23C35D5627009A29FD396A024442A19E37DEE70674BF3CE0FA377D781ED2231",
"v-dropdown.vue.min.js": "22D3C9C4FE98D522D5E9F3BC91E0EF3F228A8C36486CC0572A5F7770DC27A20D",
"v-dropdown.vue.min.js": "7E9837B89A8275F4CDFE239B06B2DD065C657EC8F9117CC41A854304C1C93B32",
"video-card.vue.min.js": "D622CD3A5123F605A46D1CFD80B09A42B4391A6C6C9B60062A247CA3F7B33538",
"video-card-info.min.js": "13B755C0EE0CA018AE65251E168BAF3395FEA2EB4FAD6949AADD752F61B8819B",
"video-dash.min.js": "E0345C36E793F8C05E5FC83DDAB88751CD6BA28FB0A1AA63BC20FBCE330F037B",

Binary file not shown.

View File

@ -0,0 +1 @@
(()=>{return(t,i)=>{const{NavbarComponent:a}=i.import("custom-navbar-component");class e extends a{constructor(){super();this.noPadding=true;this.href=`https://space.bilibili.com/${getUID()}/favlist`;this.html=`收藏`;this.active=document.URL.replace(/\?.*$/,"")===`https://space.bilibili.com/${getUID()}/favlist`;this.popupHtml=`\n<div class="favorites-list loading">\n<div class="loading-tip">\n 加载中...\n</div>\n<div class="content">\n<div class="header">\n<v-dropdown class="list-select" @change="changeList()" :round="true" :items="listNames" :value.sync="selectedListName">\n</v-dropdown>\n<a class="more-info" :href="moreLink" title="查看更多" target="_blank">\n 查看更多\n<i class="mdi mdi-dots-horizontal"></i>\n</a>\n</div>\n<transition-group name="cards" tag="div" class="cards">\n<div class="loading-tip" v-if="cardsLoading" key="loading-tip">\n 加载中...\n</div>\n<div class="empty-tip" v-if="!cardsLoading && cards.length === 0" key="empty-tip">\n 空空如也哦 = ̄ω ̄=\n</div>\n<div class="favorite-card" v-for="card of cards" :key="card.id">\n<a class="cover-container" target="_blank" :href="'https://www.bilibili.com/video/av' + card.aid">\n<dpi-img class="cover" :src="card.coverUrl" :size="{width: 130, height: 85}"></dpi-img>\n<div class="floating duration">{{card.durationText}}</div>\n<div class="floating favorite-time">{{card.favoriteTime | formatDate}}</div>\n</a>\n<a class="title" target="_blank" :href="'https://www.bilibili.com/video/av' + card.aid" :title="card.title">{{card.title}}</a>\n<a class="up" target="_blank" :href="'https://space.bilibili.com/' + card.upID" :title="card.upName">\n<dpi-img class="face" :src="card.upFaceUrl" :size="20"></dpi-img>\n<div class="name">{{card.upName}}</div>\n</a>\n</div>\n</transition-group>\n</div>\n</div>\n`;this.initialPopup=(()=>this.init())}get name(){return"favoritesList"}async init(){new Vue({el:await SpinQuery.select(`.custom-navbar [data-name="${this.name}"] .favorites-list`),store:store,filters:{formatDate(t){return`${t.getFullYear()}-${(t.getMonth()+1).toString().padEnd(2,"0")}-${t.getDate().toString().padEnd(2,"0")}`}},components:{DpiImg:()=>i.importAsync("dpi-img.vue"),VDropdown:()=>i.importAsync("v-dropdown.vue")},data:{list:[],cards:[],selectedListName:"",cardsLoading:true},computed:{listNames(){return this.list.map(t=>t.name)},selectedListId(){const t=this.list.find(t=>t.name===this.selectedListName);return t?t.id:0},moreLink(){const t=this.selectedListId;if(t===0){return`https://space.bilibili.com/${getUID()}/favlist`}return`https://space.bilibili.com/${getUID()}/favlist?fid=${t}`}},methods:{async changeList(){try{this.cards=[];this.cardsLoading=true;const t=`https://api.bilibili.com/medialist/gateway/base/spaceDetail?media_id=${this.selectedListId}&pn=1&ps=20`;const i=await Ajax.getJsonWithCredentials(t);if(i.code!==0){throw new Error(`加载收藏夹内容失败: ${i.message}`)}this.cards=i.data.medias.filter(t=>{return t.attr===0}).map(t=>{return{id:t.id,aid:t.id,coverUrl:t.cover.replace("http:","https:"),favoriteTimestamp:t.fav_time*1e3,favoriteTime:new Date(t.fav_time*1e3),title:t.title,description:t.intro,duration:t.duration,durationText:formatDuration(t.duration),playCount:t.cnt_info.play,danmakuCount:t.cnt_info.danmaku,upName:t.upper.name,upFaceUrl:t.upper.face.replace("http:","https:"),upID:t.upper.mid}})}catch(t){logError(t)}finally{this.cardsLoading=false}}},async mounted(){try{const t=`https://api.bilibili.com/medialist/gateway/base/created?pn=1&ps=100&up_mid=${getUID()}&is_space=0`;const i=await Ajax.getJsonWithCredentials(t);if(i.code!==0){throw new Error(`获取收藏夹列表失败: ${i.message}`)}this.list=i.data.list.map(t=>{return{id:t.id,name:t.title,count:t.media_count}});if(this.list.length>0){this.selectedListName=this.list[0].name;this.changeList()}}catch(t){logError(t)}finally{this.$el.classList.remove("loading")}}})}}return{export:{FavoritesList:e}}}})();

View File

@ -1 +1 @@
(()=>{return(t,i)=>{const{NavbarComponent:a}=i.import("custom-navbar-component");class e extends a{constructor(){super();this.noPadding=true;this.href="https://www.bilibili.com/watchlater/#/list";this.html="稍后再看";this.active=document.URL.startsWith("https://www.bilibili.com/watchlater/");this.popupHtml=`\n<div class="watchlater-list loading">\n<div class="loading-tip">\n 加载中...\n</div>\n<div class="empty-tip" v-if="filteredCards.length === 0">\n 空空如也哦 = ̄ω ̄=\n</div>\n<div class="header">\n \x3c!--<div class="operations">\n<div v-if="!redirect" class="round-button" title="播放全部"><i class="mdi mdi-play-circle-outline"></i></div>\n<div class="round-button" title="移除已观看"><i class="mdi mdi-eye-check-outline"></i></div>\n<div class="round-button" title="清空全部"><i class="mdi mdi-trash-can-outline"></i></div>\n</div>--\x3e\n<div class="search">\n<input type="text" placeholder="搜索" v-model="search">\n</div>\n<a class="more-info" href="https://www.bilibili.com/watchlater/#/list" title="查看更多" target="_blank">\n 查看更多\n<i class="mdi mdi-dots-horizontal"></i>\n</a>\n</div>\n<transition-group name="cards" tag="div" class="cards">\n<div class="watchlater-card" v-for="(card, index) of filteredCards" :key="card.aid">\n<a class="cover-container" target="_blank" :href="card.href">\n<dpi-img class="cover" :src="card.coverUrl" :size="{width: 130, height: 85}"></dpi-img>\n<div class="floating remove" title="移除" @click.prevent="remove(card.aid, index)"><i class="mdi mdi-close"></i></div>\n<div class="floating duration">{{card.durationText}}</div>\n<div class="floating viewed" v-if="card.complete">\n 已观看\n</div>\n</a>\n<a class="title" target="_blank" :href="card.href" :title="card.title">{{card.title}}</a>\n<a class="up" target="_blank" :href="'https://space.bilibili.com/' + card.upID" :title="card.upName">\n<dpi-img class="face" :src="card.upFaceUrl" :size="20"></dpi-img>\n<div class="name">{{card.upName}}</div>\n</a>\n</div>\n</transition-group>\n \x3c!--<div class="undo round-button">\n<i class="mdi mdi-undo-variant"></i>\n 撤销\n</div>--\x3e\n</div>\n`;this.initialPopup=(()=>{this.init()})}async init(){console.log(await SpinQuery.select(`.custom-navbar [data-name="${this.name}"] .watchlater-list`));new Vue({el:await SpinQuery.select(`.custom-navbar [data-name="${this.name}"] .watchlater-list`),store:store,components:{DpiImg:()=>i.importAsync("dpi-img.vue")},data:{cards:[],filteredCards:[],search:"",lastRemovedAid:0},computed:{...Vuex.mapState(["watchlaterList"])},watch:{watchlaterList(){this.updateList()},search(){this.updateFilteredCards()}},methods:{...Vuex.mapActions(["toggleWatchlater"]),async updateList(){const{getWatchlaterList:a}=await i.importAsync("watchlater-api");const e=await a(true);if(!e){this.cards=[];return}const s=e.map(i=>{const a=(()=>{if(i.pages===undefined){return t.watchLaterRedirect?`https://www.bilibili.com/video/av${i.aid}`:`https://www.bilibili.com/watchlater/#/av${i.aid}`}const a=i.pages.map(t=>t.cid);const e=i.cid===0?1:a.indexOf(i.cid)+1;return t.watchLaterRedirect?`https://www.bilibili.com/video/av${i.aid}?p=${e}`:`https://www.bilibili.com/watchlater/#/av${i.aid}/p${e}`})();const e=Math.round(1e3*i.progress/i.duration)/1e3;return{aid:i.aid,href:a,coverUrl:i.pic.replace("http:","https:"),durationText:formatDuration(i.duration),duration:i.duration,complete:i.progress<0||e>.95,title:i.title,upName:i.owner.name,upFaceUrl:i.owner.face.replace("http:","https:"),upID:i.owner.mid}});this.cards=s;if(this.search){this.updateFilteredCards()}else{this.filteredCards=s}},async remove(t,i){this.cards.splice(i,1);await this.toggleWatchlater(t);this.lastRemovedAid=t},async undo(){const t=this.lastRemovedAid;if(t!==0){await this.toggleWatchlater(t)}},updateFilteredCards:_.debounce(function(){const t=this.search.toLowerCase();const i=this.$el.querySelector(".cards");i.scrollTo(0,0);this.filteredCards=this.cards.filter(i=>{return i.title.toLowerCase().includes(t)||i.upName.toLowerCase().includes(t)})},200)},async mounted(){try{await this.updateList()}finally{this.$el.classList.remove("loading")}}})}get name(){return"watchlaterList"}}return{export:{WatchlaterList:e}}}})();
(()=>{return(t,i)=>{const{NavbarComponent:a}=i.import("custom-navbar-component");class e extends a{constructor(){super();this.noPadding=true;this.href="https://www.bilibili.com/watchlater/#/list";this.html="稍后再看";this.active=document.URL.startsWith("https://www.bilibili.com/watchlater/");this.popupHtml=`\n<div class="watchlater-list loading">\n<div class="loading-tip">\n 加载中...\n</div>\n<div class="empty-tip" v-if="filteredCards.length === 0">\n 空空如也哦 = ̄ω ̄=\n</div>\n<div class="header">\n \x3c!--<div class="operations">\n<div v-if="!redirect" class="round-button" title="播放全部"><i class="mdi mdi-play-circle-outline"></i></div>\n<div class="round-button" title="移除已观看"><i class="mdi mdi-eye-check-outline"></i></div>\n<div class="round-button" title="清空全部"><i class="mdi mdi-trash-can-outline"></i></div>\n</div>--\x3e\n<div class="search">\n<input type="text" placeholder="搜索" v-model="search">\n</div>\n<a class="more-info" href="https://www.bilibili.com/watchlater/#/list" title="查看更多" target="_blank">\n 查看更多\n<i class="mdi mdi-dots-horizontal"></i>\n</a>\n</div>\n<transition-group name="cards" tag="div" class="cards">\n<div class="watchlater-card" v-for="(card, index) of filteredCards" :key="card.aid">\n<a class="cover-container" target="_blank" :href="card.href">\n<dpi-img class="cover" :src="card.coverUrl" :size="{width: 130, height: 85}"></dpi-img>\n<div class="floating remove" title="移除" @click.prevent="remove(card.aid, index)"><i class="mdi mdi-close"></i></div>\n<div class="floating duration">{{card.durationText}}</div>\n<div class="floating viewed" v-if="card.complete">\n 已观看\n</div>\n</a>\n<a class="title" target="_blank" :href="card.href" :title="card.title">{{card.title}}</a>\n<a class="up" target="_blank" :href="'https://space.bilibili.com/' + card.upID" :title="card.upName">\n<dpi-img class="face" :src="card.upFaceUrl" :size="20"></dpi-img>\n<div class="name">{{card.upName}}</div>\n</a>\n</div>\n</transition-group>\n \x3c!--<div class="undo round-button">\n<i class="mdi mdi-undo-variant"></i>\n 撤销\n</div>--\x3e\n</div>\n`;this.initialPopup=(()=>{this.init()})}async init(){new Vue({el:await SpinQuery.select(`.custom-navbar [data-name="${this.name}"] .watchlater-list`),store:store,components:{DpiImg:()=>i.importAsync("dpi-img.vue")},data:{cards:[],filteredCards:[],search:"",lastRemovedAid:0},computed:{...Vuex.mapState(["watchlaterList"])},watch:{watchlaterList(){this.updateList()},search(){this.updateFilteredCards()}},methods:{...Vuex.mapActions(["toggleWatchlater"]),async updateList(){const{getWatchlaterList:a}=await i.importAsync("watchlater-api");const e=await a(true);if(!e){this.cards=[];return}const s=e.map(i=>{const a=(()=>{if(i.pages===undefined){return t.watchLaterRedirect?`https://www.bilibili.com/video/av${i.aid}`:`https://www.bilibili.com/watchlater/#/av${i.aid}`}const a=i.pages.map(t=>t.cid);const e=i.cid===0?1:a.indexOf(i.cid)+1;return t.watchLaterRedirect?`https://www.bilibili.com/video/av${i.aid}?p=${e}`:`https://www.bilibili.com/watchlater/#/av${i.aid}/p${e}`})();const e=Math.round(1e3*i.progress/i.duration)/1e3;return{aid:i.aid,href:a,coverUrl:i.pic.replace("http:","https:"),durationText:formatDuration(i.duration),duration:i.duration,complete:i.progress<0||e>.95,title:i.title,upName:i.owner.name,upFaceUrl:i.owner.face.replace("http:","https:"),upID:i.owner.mid}});this.cards=s;if(this.search){this.updateFilteredCards()}else{this.filteredCards=s}},async remove(t,i){this.cards.splice(i,1);await this.toggleWatchlater(t);this.lastRemovedAid=t},async undo(){const t=this.lastRemovedAid;if(t!==0){await this.toggleWatchlater(t)}},updateFilteredCards:_.debounce(function(){const t=this.search.toLowerCase();const i=this.$el.querySelector(".cards");i.scrollTo(0,0);this.filteredCards=this.cards.filter(i=>{return i.title.toLowerCase().includes(t)||i.upName.toLowerCase().includes(t)})},200)},async mounted(){try{await this.updateList()}finally{this.$el.classList.remove("loading")}}})}get name(){return"watchlaterList"}}return{export:{WatchlaterList:e}}}})();

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
(()=>{return(t,i)=>{const a=["//www.bilibili.com","//t.bilibili.com","//search.bilibili.com","//space.bilibili.com","//account.bilibili.com","//pay.bilibili.com","//member.bilibili.com","//big.bilibili.com","//message.bilibili.com","//app.bilibili.com","//passport.bilibili.com","//game.bilibili.com","//live.bilibili.com/blackboard/"];const s=["//t.bilibili.com/vote/h5/index/#/result","//t.bilibili.com/lottery/h5/index/#/result","//member.bilibili.com/video/upload","//space.bilibili.com/ajax/","//www.bilibili.com/h5/comment/","//www.bilibili.com/blackboard/"];const o=()=>{document.body.style.setProperty("--navbar-bounds-padding",`0 ${t.customNavbarBoundsPadding}%`);document.body.style.setProperty("--navbar-blur-opacity",(t.customNavbarBlurOpacity||.7).toString());addSettingsListener("customNavbarBlurOpacity",t=>{document.body.style.setProperty("--navbar-blur-opacity",t)})};const n=(t,i,a)=>{a.classList.toggle(t,i)};const e=t=>{dq(".custom-navbar").classList.toggle("dark",t);dq(".custom-navbar-settings").classList.toggle("dark",t)};return(()=>{if(isIframe()){return}o();const c=!(!a.some(t=>document.URL.includes(t))||s.some(t=>document.URL.includes(t)))||document.URL.includes("//www.bilibili.com/blackboard/bnj2020.html");if(c){document.body.classList.add("custom-navbar-loading");(async()=>{const a=await i.importAsync("customNavbarHtml");document.body.insertAdjacentHTML("beforeend",a);addSettingsListener("useDarkStyle",e,true);const s=()=>dq(".custom-navbar");["Fill","Shadow","Compact","Blur"].forEach(t=>{const i="customNavbar"+t;addSettingsListener(i,i=>n(t.toLowerCase(),i,s()),true)});SpinQuery.condition(()=>dq("#banner_link,.international-header .bili-banner"),t=>t===null?false:Boolean(t.style.backgroundImage),i=>{Observer.attributes(i,()=>{const a=dqa(".custom-navbar .blur-layer");a.forEach(t=>{t.style.backgroundImage=i.style.backgroundImage;t.setAttribute("data-image",i.style.backgroundImage)});addSettingsListener("customNavbarTransparent",i=>{if(!t.hideBanner){s().classList.toggle("transparent",i)}},true);addSettingsListener("hideBanner",i=>{if(t.customNavbarTransparent){s().classList.toggle("transparent",!i)}})})});const{Blank:o}=await i.importAsync("custom-navbar-blank");const{Logo:c}=await i.importAsync("custom-navbar-logo");const{Category:r}=await i.importAsync("custom-navbar-category");const{SimpleLink:l}=await i.importAsync("custom-navbar-simple-link");const{UserInfo:b}=await i.importAsync("custom-navbar-user-info");const{SearchBox:m}=await i.importAsync("custom-navbar-search-box");const{Iframe:u}=await i.importAsync("custom-navbar-iframe");const d=[new o(1),new c,new r,new l("排行","https://www.bilibili.com/ranking","ranking"),new l("相簿","https://h.bilibili.com","drawing"),new l("音频","https://www.bilibili.com/audio/home/","music"),new u("游戏中心","https://game.bilibili.com/",{src:`https://www.bilibili.com/page-proxy/game-nav.html`,width:`680px`,height:`260px`,lazy:true,iframeName:"games"}),new u("直播","https://live.bilibili.com",{src:`https://live.bilibili.com/blackboard/dropdown-menu.html`,width:`528px`,height:`266px`,lazy:true,iframeName:"lives"}),new l("会员购","https://show.bilibili.com","shop"),new l("漫画","https://manga.bilibili.com","manga"),new o(2),new m,new b];if(getUID()){const{WatchlaterList:t}=await i.importAsync("custom-navbar-watchlater-list");const{Messages:a}=await i.importAsync("custom-navbar-messages");const{Activities:s}=await i.importAsync("custom-navbar-activities");const{Subscriptions:o}=await i.importAsync("custom-navbar-subscriptions");const{FavoritesList:n,HistoryList:e}=await i.importAsync("custom-navbar-video-list");d.push(new a,new o,new s,new t,new n,new e)}const{Upload:p}=await i.importAsync("custom-navbar-upload");d.push(new p,new o(3));new Vue({el:".custom-navbar",data:{components:d},methods:{requestPopup(t){if(!t.requestedPopup&&!t.disabled&&!t.active){this.$set(t,`requestedPopup`,true);t.initialPopup&&t.initialPopup()}t.onPopup&&t.onPopup()}},mounted(){document.body.classList.remove("custom-navbar-loading")}})})()}return{widget:{content:`\n<div class="gui-settings-flat-button" id="custom-navbar-settings">\n<i class="mdi mdi-24px mdi-auto-fix"></i>\n<span>顶栏布局</span>\n</div>`,condition:()=>c,success:async()=>{const{initSettingsPanel:t}=await i.importAsync("custom-navbar-settings");await t()}},unload:()=>{const t=dqa(".custom-navbar,.custom-navbar-settings");t.forEach(t=>t.style.display="none");i.removeStyle("customNavbarStyle")},reload:()=>{const t=dqa(".custom-navbar,.custom-navbar-settings");t.forEach(t=>t.style.display="flex");i.applyImportantStyle("customNavbarStyle")}}})()}})();
(()=>{return(t,i)=>{const a=["//www.bilibili.com","//t.bilibili.com","//search.bilibili.com","//space.bilibili.com","//account.bilibili.com","//pay.bilibili.com","//member.bilibili.com","//big.bilibili.com","//message.bilibili.com","//app.bilibili.com","//passport.bilibili.com","//game.bilibili.com","//live.bilibili.com/blackboard/"];const s=["//t.bilibili.com/vote/h5/index/#/result","//t.bilibili.com/lottery/h5/index/#/result","//member.bilibili.com/video/upload","//space.bilibili.com/ajax/","//www.bilibili.com/h5/comment/","//www.bilibili.com/blackboard/"];const o=()=>{document.body.style.setProperty("--navbar-bounds-padding",`0 ${t.customNavbarBoundsPadding}%`);document.body.style.setProperty("--navbar-blur-opacity",(t.customNavbarBlurOpacity||.7).toString());addSettingsListener("customNavbarBlurOpacity",t=>{document.body.style.setProperty("--navbar-blur-opacity",t)})};const n=(t,i,a)=>{a.classList.toggle(t,i)};const e=t=>{dq(".custom-navbar").classList.toggle("dark",t);dq(".custom-navbar-settings").classList.toggle("dark",t)};return(()=>{if(isIframe()){return}o();const c=!(!a.some(t=>document.URL.includes(t))||s.some(t=>document.URL.includes(t)))||document.URL.includes("//www.bilibili.com/blackboard/bnj2020.html");if(c){document.body.classList.add("custom-navbar-loading");(async()=>{const a=await i.importAsync((()=>"customNavbarHtml")());document.body.insertAdjacentHTML("beforeend",a);addSettingsListener("useDarkStyle",e,true);const s=()=>dq(".custom-navbar");["Fill","Shadow","Compact","Blur"].forEach(t=>{const i="customNavbar"+t;addSettingsListener(i,i=>n(t.toLowerCase(),i,s()),true)});SpinQuery.condition(()=>dq("#banner_link,.international-header .bili-banner"),t=>t===null?false:Boolean(t.style.backgroundImage),i=>{Observer.attributes(i,()=>{const a=dqa(".custom-navbar .blur-layer");a.forEach(t=>{t.style.backgroundImage=i.style.backgroundImage;t.setAttribute("data-image",i.style.backgroundImage)});addSettingsListener("customNavbarTransparent",i=>{if(!t.hideBanner){s().classList.toggle("transparent",i)}},true);addSettingsListener("hideBanner",i=>{if(t.customNavbarTransparent){s().classList.toggle("transparent",!i)}})})});const{Blank:o}=await i.importAsync("custom-navbar-blank");const{Logo:c}=await i.importAsync("custom-navbar-logo");const{Category:r}=await i.importAsync("custom-navbar-category");const{SimpleLink:l}=await i.importAsync("custom-navbar-simple-link");const{UserInfo:m}=await i.importAsync("custom-navbar-user-info");const{SearchBox:b}=await i.importAsync("custom-navbar-search-box");const{Iframe:u}=await i.importAsync("custom-navbar-iframe");const d=[new o(1),new c,new r,new l("排行","https://www.bilibili.com/ranking","ranking"),new l("相簿","https://h.bilibili.com","drawing"),new l("音频","https://www.bilibili.com/audio/home/","music"),new u("游戏中心","https://game.bilibili.com/",{src:`https://www.bilibili.com/page-proxy/game-nav.html`,width:`680px`,height:`260px`,lazy:true,iframeName:"games"}),new u("直播","https://live.bilibili.com",{src:`https://live.bilibili.com/blackboard/dropdown-menu.html`,width:`528px`,height:`266px`,lazy:true,iframeName:"lives"}),new l("会员购","https://show.bilibili.com","shop"),new l("漫画","https://manga.bilibili.com","manga"),new o(2),new b,new m];if(getUID()){const{WatchlaterList:t}=await i.importAsync("custom-navbar-watchlater-list");const{Messages:a}=await i.importAsync("custom-navbar-messages");const{Activities:s}=await i.importAsync("custom-navbar-activities");const{Subscriptions:o}=await i.importAsync("custom-navbar-subscriptions");const{FavoritesList:n}=await i.importAsync("custom-navbar-favorites-list");const{HistoryList:e}=await i.importAsync("custom-navbar-video-list");d.push(new a,new o,new s,new t,new n,new e)}const{Upload:p}=await i.importAsync("custom-navbar-upload");d.push(new p,new o(3));new Vue({el:".custom-navbar",data:{components:d},methods:{requestPopup(t){if(!t.requestedPopup&&!t.disabled&&!t.active){this.$set(t,`requestedPopup`,true);t.initialPopup&&t.initialPopup()}t.onPopup&&t.onPopup()}},mounted(){document.body.classList.remove("custom-navbar-loading")}})})()}return{widget:{content:`\n<div class="gui-settings-flat-button" id="custom-navbar-settings">\n<i class="mdi mdi-24px mdi-auto-fix"></i>\n<span>顶栏布局</span>\n</div>`,condition:()=>c,success:async()=>{const{initSettingsPanel:t}=await i.importAsync("custom-navbar-settings");await t()}},unload:()=>{const t=dqa(".custom-navbar,.custom-navbar-settings");t.forEach(t=>t.style.display="none");i.removeStyle("customNavbarStyle")},reload:()=>{const t=dqa(".custom-navbar,.custom-navbar-settings");t.forEach(t=>t.style.display="flex");i.applyImportantStyle("customNavbarStyle")}}})()}})();

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
(()=>{return(o,e)=>{const n=`<div class=v-dropdown @click=toggleDropdown()><span class=selected>{{ value }}</span><ul class=dropdown-menu :class="{ opened: dropdownOpen }"><li v-for="item in items":key=item :data-value=item @click=select(item)>{{ item }}</li></ul><i class="mdi mdi-chevron-down"></i></div>`;e.applyStyleFromText(`.v-dropdown{--background-color:#eee;position:relative;background-color:var(--background-color);cursor:pointer;display:flex;align-items:center;justify-content:space-between;min-width:100px}body.dark .v-dropdown{--background-color:#333}.v-dropdown .dropdown-menu{transform-origin:top;transform:translateY(-4px) translateX(-50%);pointer-events:none;opacity:0;position:absolute;top:calc(100% + 2px);left:50%;background-color:var(--background-color);z-index:1;transition:.2s ease-out;box-shadow:rgba(0,0,0,.2) 0 4px 8px 0}.v-dropdown .dropdown-menu.opened{transform:translateY(0) translateX(-50%);pointer-events:initial;opacity:1}.v-dropdown .dropdown-menu li{padding:4px 16px;box-sizing:content-box;white-space:nowrap;min-width:64px;text-align:center;cursor:pointer;color:inherit;background-color:transparent}.v-dropdown .dropdown-menu li:hover{background-color:rgba(0,0,0,.16)}.v-dropdown .mdi-chevron-down{font-size:16pt;line-height:1;transform:rotate(0)}.v-dropdown .dropdown-menu.opened~.mdi-chevron-down{transform:rotate(180deg)}.v-dropdown .selected{user-select:none;padding:4px 8px}.round-corner .v-dropdown,.round-corner .v-dropdown .dropdown-menu,.round-corner .v-dropdown .dropdown-menu li{border-radius:var(--corner-radius)}`,"v-dropdown-style");return{export:Object.assign({template:n},{props:["items","value"],data(){return{dropdownOpen:false}},methods:{toggleDropdown(){this.dropdownOpen=!this.dropdownOpen;if(this.dropdownOpen){document.addEventListener("click",o=>{const e=o.target;if(e===this.$el||this.$el.contains(e)){return}this.dropdownOpen=false},{once:true,capture:true})}},select(o){this.$emit("update:value",o);this.$emit("change",o)}}})}}})();
(()=>{return(o,e)=>{const r=`<div class=v-dropdown @click=toggleDropdown() :class={round}><span class=selected>{{ value }}</span><ul class=dropdown-menu :class="{ opened: dropdownOpen }"><li v-for="item in items":key=item :data-value=item @click=select(item)>{{ item }}</li></ul><i class="mdi mdi-chevron-down"></i></div>`;e.applyStyleFromText(`.v-dropdown{--background-color:#eee;position:relative;background-color:var(--background-color);cursor:pointer;display:flex;align-items:center;justify-content:space-between;min-width:100px;border-radius:var(--corner-radius)}body.dark .v-dropdown{--background-color:#333}.v-dropdown.round{border-radius:14px;padding:0 4px}.v-dropdown .dropdown-menu{transform-origin:top;transform:translateY(-4px) translateX(-50%);pointer-events:none;opacity:0;position:absolute;top:calc(100% + 2px);left:50%;background-color:var(--background-color);z-index:1;transition:.2s ease-out;box-shadow:rgba(0,0,0,.2) 0 4px 8px 0;border-radius:var(--corner-radius)}.v-dropdown .dropdown-menu.opened{transform:translateY(0) translateX(-50%);pointer-events:initial;opacity:1}.v-dropdown .dropdown-menu li{padding:4px 16px;box-sizing:content-box;white-space:nowrap;min-width:64px;text-align:center;cursor:pointer;color:inherit;background-color:transparent;border-radius:var(--corner-radius)}.v-dropdown .dropdown-menu li:hover{background-color:rgba(0,0,0,.16)}.v-dropdown .mdi-chevron-down{font-size:16pt;line-height:1;transform:rotate(0)}.v-dropdown .dropdown-menu.opened~.mdi-chevron-down{transform:rotate(180deg)}.v-dropdown .selected{user-select:none;padding:4px 8px}`,"v-dropdown-style");return{export:Object.assign({template:r},{props:["items","value","round"],data(){return{dropdownOpen:false}},methods:{toggleDropdown(){this.dropdownOpen=!this.dropdownOpen;if(this.dropdownOpen){document.addEventListener("click",o=>{const e=o.target;if(e===this.$el||this.$el.contains(e)){return}this.dropdownOpen=false},{once:true,capture:true})}},select(o){if(o!==this.value){this.$emit("update:value",o);this.$emit("change",o)}}}})}}})();

30
src/style/_common.scss Normal file
View File

@ -0,0 +1,30 @@
@mixin h-center {
display: flex;
align-items: center;
}
@mixin v-center {
display: flex;
align-items: center;
flex-direction: column;
}
@mixin h-stretch {
display: flex;
align-items: stretch;
}
@mixin v-stretch {
display: flex;
align-items: stretch;
flex-direction: column;
}
@mixin round-bar($height) {
box-sizing: border-box;
height: #{$height}px;
border-radius: #{$height / 2}px;
}
@mixin no-scrollbar {
scrollbar-width: none !important;
&::-webkit-scrollbar {
height: 0 !important;
width: 0 !important;
}
}

View File

@ -851,7 +851,7 @@ li.nav-item[report-id="playpage_dynamic"] .i-frame,
}
}
@import "./activities/activities", "./subscriptions/subscriptions", "_round-corner", "./settings/settings",
"./category/category", "./watchlater-list/watchlater-list";
"./category/category", "./watchlater-list/watchlater-list", "./favorites-list/favorites-list";
.custom-navbar > ul > li:not(.disabled):hover > .popup,
#custom-navbar-home-popup .category-item:hover .popup,

View File

@ -119,7 +119,8 @@ export default (() => {
const { Messages } = await import('./simple/custom-navbar-messages')
const { Activities } = await import('./activities/custom-navbar-activities')
const { Subscriptions } = await import('./subscriptions/custom-navbar-subscriptions')
const { FavoritesList, HistoryList } = await import('./simple/custom-navbar-video-list')
const { FavoritesList } = await import('./favorites-list/custom-navbar-favorites-list')
const { HistoryList } = await import('./simple/custom-navbar-video-list')
components.push(
new Messages(),
new Subscriptions(),

View File

@ -0,0 +1,179 @@
@import "../../common";
.custom-navbar .favorites-list {
width: 380px;
height: 600px;
font-size: 12px;
@include v-stretch();
justify-content: center;
.empty-tip,
.loading-tip {
display: flex;
justify-content: center;
width: 100%;
}
& > .loading-tip {
display: none;
}
.mdi {
line-height: 1;
font-size: 18px;
}
&.loading {
& > .loading-tip {
display: flex;
}
& > :not(.loading-tip) {
display: none;
}
}
.content {
@include v-stretch();
@include no-scrollbar();
justify-content: space-between;
flex-grow: 1;
overflow: auto;
.floating {
@include round-bar(20);
@include h-center();
background-color: #000c;
color: white;
justify-content: center;
cursor: pointer;
}
.header {
@include h-center();
justify-content: space-between;
margin: 16px 12px;
.list-select {
height: 26px;
}
.more-info {
@include h-center();
@include round-bar(26);
padding: 4px 6px 4px 10px;
background-color: #8882;
&:hover {
background-color: #8884;
}
.mdi {
margin-left: 8px;
}
}
}
.cards {
flex: 1;
overflow: auto;
overscroll-behavior: contain;
scroll-behavior: smooth;
position: relative;
@include no-scrollbar();
margin: 0 12px;
padding-bottom: 12px;
&-enter,
&-leave-to {
opacity: 0;
transform: translateY(-16px) scale(0.9);
}
&-leave-active {
transition: 0.24s cubic-bezier(0.22, 0.61, 0.36, 1);
position: absolute;
}
.favorite-card {
cursor: pointer;
flex-shrink: 0;
border-radius: 8px;
box-shadow: 0 4px 8px 0 #0001;
color: black;
background-color: #fff;
display: grid;
grid-template:
"cover title" 2fr
"cover info" 1fr / 130px 1fr;
height: 85px;
body.dark & {
background-color: #282828;
color: #eee;
}
&:not(:last-child) {
margin-bottom: 12px;
}
.cover-container {
grid-area: cover;
overflow: hidden;
border-radius: 8px 0 0 8px;
position: relative;
$padding: 6px;
.favorite-time{
top: $padding;
left: $padding;
padding: 0 6px;
}
.duration {
left: $padding;
bottom: $padding;
padding: 0 6px;
}
.floating {
position: absolute;
opacity: 0;
font-size: 11px;
}
.cover {
object-fit: cover;
}
}
&:hover {
.floating {
opacity: 1;
}
}
.title {
grid-area: title;
font-size: 13px;
font-weight: bold;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
max-height: 3em;
word-break: break-all;
line-height: 1.5;
overflow: hidden;
margin-top: 8px;
padding: 0 10px;
&:hover {
color: var(--theme-color) !important;
}
}
.up {
flex: 0 1 auto;
padding: 2px 10px 2px 2px;
margin: 0 8px 6px;
justify-self: start;
align-self: center;
max-width: calc(100% - 16px);
@include h-center();
@include round-bar(24);
background-color: #8882;
&:hover {
background-color: #8884;
}
.face {
border-radius: 50%;
margin-right: 6px;
height: 20px;
width: 20px;
}
.name {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 11px;
}
&:hover .name {
color: var(--theme-color);
}
}
}
}
}
}

View File

@ -0,0 +1,164 @@
import { NavbarComponent } from '../custom-navbar-component'
import { VideoCardInfo } from '../../simplify-home/video-card-info'
interface ListInfo {
id: number
name: string
count: number
}
interface FavoritesItemInfo extends VideoCardInfo {
favoriteTimestamp: number
favoriteTime: Date
}
export class FavoritesList extends NavbarComponent {
constructor() {
super()
this.noPadding = true
this.href = `https://space.bilibili.com/${getUID()}/favlist`
this.html = `收藏`
this.active = document.URL.replace(/\?.*$/, "") === `https://space.bilibili.com/${getUID()}/favlist`
this.popupHtml = /*html*/`
<div class="favorites-list loading">
<div class="loading-tip">
...
</div>
<div class="content">
<div class="header">
<v-dropdown class="list-select" @change="changeList()" :round="true" :items="listNames" :value.sync="selectedListName">
</v-dropdown>
<a class="more-info" :href="moreLink" title="查看更多" target="_blank">
<i class="mdi mdi-dots-horizontal"></i>
</a>
</div>
<transition-group name="cards" tag="div" class="cards">
<div class="loading-tip" v-if="cardsLoading" key="loading-tip">
...
</div>
<div class="empty-tip" v-if="!cardsLoading && cards.length === 0" key="empty-tip">
=ω=
</div>
<div class="favorite-card" v-for="card of cards" :key="card.id">
<a class="cover-container" target="_blank" :href="'https://www.bilibili.com/video/av' + card.aid">
<dpi-img class="cover" :src="card.coverUrl" :size="{width: 130, height: 85}"></dpi-img>
<div class="floating duration">{{card.durationText}}</div>
<div class="floating favorite-time">{{card.favoriteTime | formatDate}}</div>
</a>
<a class="title" target="_blank" :href="'https://www.bilibili.com/video/av' + card.aid" :title="card.title">{{card.title}}</a>
<a class="up" target="_blank" :href="'https://space.bilibili.com/' + card.upID" :title="card.upName">
<dpi-img class="face" :src="card.upFaceUrl" :size="20"></dpi-img>
<div class="name">{{card.upName}}</div>
</a>
</div>
</transition-group>
</div>
</div>
`
this.initialPopup = () => this.init()
}
get name(): keyof CustomNavbarOrders {
return 'favoritesList'
}
async init() {
new Vue({
el: await SpinQuery.select(`.custom-navbar [data-name="${this.name}"] .favorites-list`) as HTMLElement,
store,
filters: {
formatDate(value: Date) {
return `${value.getFullYear()}-${(value.getMonth() + 1).toString().padEnd(2, '0')}-${(value.getDate()).toString().padEnd(2, '0')}`
}
},
components: {
DpiImg: () => import('../dpi-img.vue'),
VDropdown: () => import('../../../video/download-video/v-dropdown.vue'),
},
data: {
list: [],
cards: [],
selectedListName: '',
cardsLoading: true,
},
computed: {
listNames() {
return this.list.map((item: ListInfo) => item.name)
},
selectedListId() {
const item = (this.list as ListInfo[]).find(item => item.name === this.selectedListName)!
return item ? item.id : 0
},
moreLink() {
const id = this.selectedListId
if (id === 0) {
return `https://space.bilibili.com/${getUID()}/favlist`
}
return `https://space.bilibili.com/${getUID()}/favlist?fid=${id}`
},
},
methods: {
async changeList() {
try {
this.cards = []
this.cardsLoading = true
const url = `https://api.bilibili.com/medialist/gateway/base/spaceDetail?media_id=${this.selectedListId}&pn=1&ps=20`
const json = await Ajax.getJsonWithCredentials(url)
if (json.code !== 0) {
throw new Error(`加载收藏夹内容失败: ${json.message}`)
}
this.cards = json.data.medias.filter((item: any) => {
return item.attr === 0 // 过滤掉已失效视频
}).map((item: any) => {
return {
id: item.id,
aid: item.id,
coverUrl: item.cover.replace('http:', 'https:'),
favoriteTimestamp: item.fav_time * 1000,
favoriteTime: new Date(item.fav_time * 1000),
title: item.title,
description: item.intro,
duration: item.duration,
durationText: formatDuration(item.duration),
playCount: item.cnt_info.play,
danmakuCount: item.cnt_info.danmaku,
upName: item.upper.name,
upFaceUrl: item.upper.face.replace('http:', 'https:'),
upID: item.upper.mid,
} as FavoritesItemInfo
})
} catch (error) {
logError(error)
} finally {
this.cardsLoading = false
}
}
},
async mounted() {
try {
const url = `https://api.bilibili.com/medialist/gateway/base/created?pn=1&ps=100&up_mid=${getUID()}&is_space=0`
const json = await Ajax.getJsonWithCredentials(url)
if (json.code !== 0) {
throw new Error(`获取收藏夹列表失败: ${json.message}`)
}
this.list = json.data.list.map((item: any) => {
return {
id: item.id,
name: item.title,
count: item.media_count
} as ListInfo
})
if (this.list.length > 0) {
this.selectedListName = this.list[0].name
this.changeList()
}
} catch (error) {
logError(error)
} finally {
this.$el.classList.remove('loading')
}
},
})
}
}
export default {
export: {
FavoritesList,
}
}

View File

@ -1,20 +1,5 @@
@import "../../common";
.custom-navbar {
@mixin h-center {
display: flex;
align-items: center;
}
@mixin round-bar($height) {
box-sizing: border-box;
height: #{$height}px;
border-radius: #{$height / 2}px;
}
@mixin no-scrollbar {
scrollbar-width: none !important;
&::-webkit-scrollbar {
height: 0 !important;
width: 0 !important;
}
}
@mixin button-background {
background-color: #8882;
&:hover {
@ -136,8 +121,6 @@
scroll-behavior: smooth;
position: relative;
@include no-scrollbar();
// display: flex;
// flex-flow: column nowrap;
margin: 0 12px;
padding-bottom: 12px;
&-enter,

View File

@ -68,7 +68,7 @@ export class WatchlaterList extends NavbarComponent {
}
}
async init() {
console.log(await SpinQuery.select(`.custom-navbar [data-name="${this.name}"] .watchlater-list`))
// console.log(await SpinQuery.select(`.custom-navbar [data-name="${this.name}"] .watchlater-list`))
new Vue({
el: await SpinQuery.select(`.custom-navbar [data-name="${this.name}"] .watchlater-list`) as HTMLElement,
store,

View File

@ -1,21 +1,21 @@
<div class="download-video">
<a v-bind:href="blobUrl" id="video-complete" style="display: none"></a>
<a :href="blobUrl" id="video-complete" style="display: none"></a>
<div class="header">
<i class="mdi mdi-download"></i>
<h1>下载视频</h1>
<div class="grow"></div>
<i class="mdi mdi-close" v-on:click="close()"></i>
<i class="mdi mdi-close" @click="close()"></i>
</div>
<div v-if="batch" class="tabs">
<div class="tab download-single" v-bind:class="{active: downloadSingle}" v-on:click="downloadSingle = true">单个视频
<div class="tab download-single" :class="{active: downloadSingle}" @click="downloadSingle = true">单个视频
</div>
<div class="tab download-batch" v-bind:class="{active: !downloadSingle}" v-on:click="downloadSingle = false">批量导出
<div class="tab download-batch" :class="{active: !downloadSingle}" @click="downloadSingle = false">批量导出
</div>
</div>
<div v-show="downloadSingle" class="info">
<img v-bind:src="coverUrl" class="cover">
<img :src="coverUrl" class="cover">
<div class="title">
<!-- <span class="bold" v-bind:title="'av' + aid + ' / cid' + cid">av{{aid}} / cid{{cid}}</span> -->
<!-- <span class="bold" :title="'av' + aid + ' / cid' + cid">av{{aid}} / cid{{cid}}</span> -->
<span class="size">
<div v-if="sizeWarning" class="size-warning">
<i class="mdi mdi-alert-circle"></i>
@ -31,27 +31,29 @@
<div class="options">
<div class="option-item" v-if="enableDash">
格式
<v-dropdown style="text-transform: uppercase;" v-on:change="dashChange()" v-bind:items="dashModel.items"
v-bind:value.sync="dashModel.value">
<v-dropdown style="text-transform: uppercase;" @change="dashChange()" :items="dashModel.items"
:value.sync="dashModel.value">
</v-dropdown>
</div>
<div class="option-item">
清晰度
<v-dropdown v-on:change="formatChange(true)" v-bind:items="qualityModel.items" v-bind:value.sync="qualityModel.value"></v-dropdown>
<v-dropdown @change="formatChange(true)" :items="qualityModel.items" :value.sync="qualityModel.value">
</v-dropdown>
</div>
<div class="option-item">
弹幕
<v-dropdown v-on:change="danmakuOptionChange()" v-bind:items="danmakuModel.items" v-bind:value.sync="danmakuModel.value"></v-dropdown>
<v-dropdown @change="danmakuOptionChange()" :items="danmakuModel.items" :value.sync="danmakuModel.value">
</v-dropdown>
</div>
<div class="option-item" v-if="enableDash && dashModel.value === 'dash'">
首选编码
<v-dropdown v-on:change="codecChange()" v-bind:items="codecModel.items" v-bind:value.sync="codecModel.value">
<v-dropdown @change="codecChange()" :items="codecModel.items" :value.sync="codecModel.value">
</v-dropdown>
</div>
<!-- <div class="option-item" v-if="enableDash">
ffmpeg支持
<v-dropdown v-on:change="ffmpegChange()" v-bind:items="ffmpegModel.items"
v-bind:value.sync="ffmpegModel.value"></v-dropdown>
<v-dropdown @change="ffmpegChange()" :items="ffmpegModel.items"
:value.sync="ffmpegModel.value"></v-dropdown>
</div> -->
</div>
<div class="separator"></div>
@ -60,11 +62,11 @@
<h2>直接下载</h2>
<span class="download-speed">{{speed}}</span>
</div>
<button v-if="!downloading" class="primary start-download" v-on:click="startDownload()">开始</button>
<button v-else class="primary cancel-download" v-on:click="cancelDownload()">取消</button>
<button v-if="!downloading" class="primary start-download" @click="startDownload()">开始</button>
<button v-else class="primary cancel-download" @click="cancelDownload()">取消</button>
<div class="progress">
<div class="background">
<div class="foreground" v-bind:style="{width: progressPercent + '%'}"></div>
<div class="foreground" :style="{width: progressPercent + '%'}"></div>
</div>
<span class="percent">{{progressPercent}}%</span>
</div>
@ -72,38 +74,40 @@
<div v-show="!downloadSingle" class="batch-download">
<div class="episode-header">
<h2>选集</h2>
<button class="list-tool" title="全选" v-on:click="selectAllEpisodes()">
<button class="list-tool" title="全选" @click="selectAllEpisodes()">
<i class="mdi mdi-checkbox-multiple-marked-circle"></i>
</button>
<button class="list-tool" title="全不选" v-on:click="unselectAllEpisodes()">
<button class="list-tool" title="全不选" @click="unselectAllEpisodes()">
<i class="mdi mdi-checkbox-multiple-blank-circle-outline"></i>
</button>
<button class="list-tool" title="反选" v-on:click="inverseAllEpisodes()">
<button class="list-tool" title="反选" @click="inverseAllEpisodes()">
<i class="mdi mdi-circle-slice-4"></i>
</button>
<span class="selected-count">{{selectedEpisodeCount}}/{{episodeList.length}}</span>
</div>
<div class="episode-list">
<v-checkbox v-for="ep of episodeList" v-bind:key="ep.index" v-bind:title="ep.title" v-bind:checked.sync="ep.checked"></v-checkbox>
<v-checkbox v-for="ep of episodeList" :key="ep.index" :title="ep.title" :checked.sync="ep.checked"></v-checkbox>
</div>
</div>
<div class="separator"></div>
<div class="exports">
<h2>导出</h2>
<div class="actions" v-bind:class="{busy: busy}">
<!-- <button class="copy-link" v-bind:disabled="downloadSingle ? null : 'disabled'" v-on:click="exportData('copyLink')">复制链接</button> -->
<button class="show-link" v-bind:disabled="downloadSingle ? null : 'disabled'"
v-on:click="exportData('showLink')">显示链接</button>
<div class="actions" :class="{busy: busy}">
<!-- <button class="copy-link" :disabled="downloadSingle ? null : 'disabled'" @click="exportData('copyLink')">复制链接</button> -->
<button class="show-link" :disabled="downloadSingle ? null : 'disabled'"
@click="exportData('showLink')">显示链接</button>
<!-- <button class="idm-export" disabled title="暂不支持导出IDM, 详见 GitHub issue #149">IDM</button> -->
<button class="aria2-file" v-on:click="exportData('aria2')">aria2</button>
<button class="ffmpeg-fragments" v-if="!dash" v-on:click="exportData('ffmpegFragments')">ffmpeg - 分段列表</button>
<button class="ffmpeg-episodes" v-if="!dash" v-bind:disabled="downloadSingle ? 'disabled' : null" v-on:click="exportData('ffmpegEpisodes')">ffmpeg - 分P列表</button>
<!-- <button class="vld-copy" v-on:click="exportData('copyVLD')">复制vld数据</button>
<button class="vld-export" v-on:click="exportData('exportVLD')">导出vld数据</button> -->
<div class="button aria2-rpc" v-on:click.self="toggleRpcSettings()">
<button class="aria2-file" @click="exportData('aria2')">aria2</button>
<button class="ffmpeg-fragments" v-if="!dash" @click="exportData('ffmpegFragments')">ffmpeg - 分段列表</button>
<button class="ffmpeg-episodes" v-if="!dash" :disabled="downloadSingle ? 'disabled' : null"
@click="exportData('ffmpegEpisodes')">ffmpeg - 分P列表</button>
<!-- <button class="vld-copy" @click="exportData('copyVLD')">复制vld数据</button>
<button class="vld-export" @click="exportData('exportVLD')">导出vld数据</button> -->
<div class="button aria2-rpc" @click.self="toggleRpcSettings()">
{{showRpcSettings ? '取消' : 'aria2 RPC'}}
<i :class="{'mdi-close': showRpcSettings, 'mdi-chevron-right': !showRpcSettings}" class="mdi" v-on:click.self="toggleRpcSettings()"></i>
<div class="rpc-settings" v-bind:class="{show: showRpcSettings}">
<i :class="{'mdi-close': showRpcSettings, 'mdi-chevron-right': !showRpcSettings}" class="mdi"
@click.self="toggleRpcSettings()"></i>
<div class="rpc-settings" :class="{show: showRpcSettings}">
<h1>aria2 RPC</h1>
<rpc-profiles @profile-change="updateProfile"></rpc-profiles>
<h2>配置</h2>
@ -129,11 +133,11 @@
最终路径: {{rpcSettings.baseDir + rpcSettings.dir}}
</div>
<div class="rpc-settings-item">
方法<v-dropdown style="text-transform: uppercase;" v-bind:items="['get', 'post']" v-bind:value.sync="rpcSettings.method">
方法<v-dropdown style="text-transform: uppercase;" :items="['get', 'post']" :value.sync="rpcSettings.method">
</div>
<div class="operations">
<div class="primary button" v-on:click="saveRpcSettings();toggleRpcSettings();exportData('aria2RPC')">开始下载</div>
<div class="button" v-on:click="saveRpcSettings()">{{saveRpcSettingsText}}</div>
<div class="primary button" @click="saveRpcSettings();toggleRpcSettings();exportData('aria2RPC')">开始下载</div>
<div class="button" @click="saveRpcSettings()">{{saveRpcSettingsText}}</div>
</div>
</div>
</div>

View File

@ -1,5 +1,5 @@
<template>
<div class="v-dropdown" @click="toggleDropdown()">
<div class="v-dropdown" @click="toggleDropdown()" :class="{round}">
<span class="selected">{{ value }}</span>
<ul class="dropdown-menu" :class="{ opened: dropdownOpen }">
<li v-for="item in items" :key="item" :data-value="item" @click="select(item)">{{ item }}</li>
@ -9,7 +9,7 @@
</template>
<script lang="ts">
export default {
props: ['items', 'value'],
props: ['items', 'value', 'round'],
data() {
return {
dropdownOpen: false
@ -33,8 +33,10 @@ export default {
}
},
select(item: string) {
this.$emit('update:value', item)
this.$emit('change', item)
if (item !== this.value) {
this.$emit('update:value', item)
this.$emit('change', item)
}
}
}
}
@ -49,10 +51,15 @@ export default {
align-items: center;
justify-content: space-between;
min-width: 100px;
border-radius: var(--corner-radius);
body.dark & {
--background-color: #333;
}
&.round {
border-radius: 14px;
padding: 0 4px;
}
.dropdown-menu {
transform-origin: top;
transform: translateY(-4px) translateX(-50%);
@ -65,6 +72,7 @@ export default {
z-index: 1;
transition: 0.2s ease-out;
box-shadow: rgba(0, 0, 0, 0.2) 0 4px 8px 0px;
border-radius: var(--corner-radius);
&.opened {
transform: translateY(0) translateX(-50%);
pointer-events: initial;
@ -79,6 +87,7 @@ export default {
cursor: pointer;
color: inherit;
background-color: transparent;
border-radius: var(--corner-radius);
&:hover {
background-color: rgba(0, 0, 0, 0.16);
}
@ -96,14 +105,5 @@ export default {
user-select: none;
padding: 4px 8px;
}
.round-corner & {
border-radius: var(--corner-radius);
.dropdown-menu,
.dropdown-menu li {
border-radius: var(--corner-radius);
}
}
}
</style>