Comments (6)
thanks lot,it can be worked on mobile chrome now!
from emby-crx.
edit all in emby-crx/style.css
code:
::-webkit-scrollbar {
width: .3em !important;
}
.mdl-spinner {
zoom: .5;
}
.skinHeader-withBackground {
right: 0 !important;
background-image: linear-gradient(rgba(0,0,0,.5), transparent);
background-color: unset;
}
.view:not(.hide) .skinHeader, .skinHeader-withBackground.headroom-scrolling {
width: 100%;
background-image: linear-gradient(black, transparent) !important;
background-color: unset !important;
}
.view[data-type=home]:not(.hide) > div:nth-child(1) .scrollSlider.padded-top-page {
padding-top: 0 !important;
}
.view:not(.hide) .itemsContainer-finepointerwrap {
flex-wrap: initial !important;
-webkit-flex-wrap: initial !important;
}
.view:not(.hide) .section0 {
display: none;
z-index: 2;
}
.view:not(.hide) .section0 .cardText {
position: absolute;
top: 0;
display: flex; /* ????????????, ??flex??none */
width: 100%;
height: 100%;
padding: 0;
background-color: rgba(0, 0, 0, .5);
font-weight: bolder;
font-size: larger;
border-radius: 0.3em;
transition: .2s;
opacity: 0;
}
.view:not(.hide) .section0 .backdropCard:hover .cardText {
opacity: 1;
}
.view:not(.hide) .section0 .cardText button {
text-decoration: none;
}
.view:not(.hide) .section0 .cardOverlayContainer,
.view:not(.hide) .section0 .sectionTitleContainer {
display: none;
}
.view:not(.hide) .section0 .cardBox-touchzoom {
box-shadow: 0 8px 10px rgb(0 0 0 / 15%);
}
.view:not(.hide) .section0 .backdropCard {
transition: all 1.5s cubic-bezier(0, 1.75, .25, 1) 0s;
}
.view:not(.hide) .section0 .backdropCard:hover {
transform: scale(1.1) !important;
}
.view:not(.hide) .section0 .scrollbuttoncontainer {
top: 0;
bottom: calc(.8em - min(.72em, max(.48em, 1.78vw)) / 2);
background-color: rgba(0, 0, 0, 0);
overflow: visible;
}
.view:not(.hide) .section0 .scrollbuttoncontainer:hover > .emby-scrollbuttons-scrollbutton{
background-color: rgba(0, 0, 0, .5);
transform: scale(.85) !important;
}
.tabs-viewmenubar-backgroundcontainer:not(.tabs-viewmenubar-backgroundcontainer-tv) {
background: 0 0 !important;
-webkit-backdrop-filter: blur(10px) !important;
backdrop-filter: blur(10px) !important;
}
.misty-banner {
position: relative;
overflow: hidden;
}
.misty-banner-cover {
width: 100%;
max-height: 100vh;
user-select: none;
object-fit: cover;
}
.misty-banner-logo {
position: absolute;
user-select: none;
object-fit: contain;
height: clamp(2rem, -2.182rem + 10.91vw, 7rem);
width: fit-content;
transform: translateY(calc(-50% - clamp(-2rem, -3.455rem + 7.27vw, 2rem)));
right: calc(3.4% + min(0.72em, max(0.48em, 1.78vw)));
opacity: 0;
transition: 1s;
transition-delay: .8s;
}
.misty-banner-logo.active {
transform: translateY(calc(-100% - clamp(-2rem, -3.455rem + 7.27vw, 2rem)));
opacity: 1;
}
.misty-loading {
z-index: 99999999;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 1);
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.misty-loading h1 {
margin: 0;
margin-bottom: 3rem;
text-transform: uppercase;
transition: .8s;
transform: scale(1.15);
opacity: 0;
}
.misty-loading h1.active {
transform: scale(1);
opacity: 1;
}
.misty-loading .mdl-spinner {
margin: 0;
position: initial;
}
.misty-loading .mdl-spinner__layer-1 {
border-color: #fff;
}
.misty-banner-library {
position: absolute;
width: 100%;
height: 100%;
top: 0;
padding: clamp(0rem, -1.313rem + 3.75vw, 1.5rem) 0;
box-sizing: border-box;
display: flex;
justify-content: flex-end;
flex-direction: column;
background-image: linear-gradient(90deg, rgba(0, 0, 0, .6), transparent);
}
.misty-banner-body {
display: flex;
position: relative;
left: 0;
transition: all 1.5s cubic-bezier(0.15, 0.07, 0, 1) 0s;
}
.misty-banner-item {
min-width: 100%;
}
.misty-banner-info {
width: 100%;
margin: min(.72em, max(.48em, 1.78vw));
margin-top: 0;
position: absolute;
top: 0;
z-index: 1;
height: 100%;
height: -webkit-fill-available;
display: flex;
flex-direction: column;
justify-content: center
}
.misty-banner-info > * {
transition: all 2.5s cubic-bezier(0, 1.41, 0.36, 0.93) .4s;
transform: translateY(150%);
opacity: 0 !important;
}
.misty-banner-item.active .misty-banner-info > * {
transform: translateY(0);
opacity: 1 !important;
}
.misty-banner-info > div:nth-child(2) {
transition-delay: .6s;
}
.misty-banner-info > div:nth-child(3) {
transition-delay: .8s;
}
.misty-banner-info h1 {
color: #fff !important;
font-size: clamp(2rem, -.362rem + 6.75vw, 4.7rem);
font-weight: bolder;
margin: 0;
text-shadow: 0 4px 10px rgb(0 0 0 / 20%);
/* margin-bottom: clamp(0rem, -.545rem + 2.73vw, 1.5rem); */
max-width: 80%;
display: -webkit-box !important;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
}
.misty-banner-info p {
color: #fff !important;
font-size: clamp(.6rem, .4rem + 1vw, 1.6rem);
font-weight: bold;
max-width: 47%;
opacity: .7;
/* overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis; */
display: -webkit-box !important;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.misty-banner-info button {
cursor: pointer;
margin-top: clamp(0rem, -2.625rem + 7.5vw, 3rem);
width: 6em;
height: 2.8em;
background-color: #fff;
border: none;
font-size: clamp(0.6rem, 0.025rem + 3.5vw, 14.6rem);
border-radius: 10px;
font-weight: bold;
letter-spacing: 2px;
box-shadow: 0 2px 7px rgba(1, 1, 1, -.8);
font-family: system-ui;
transition: .2s;
}
.misty-banner-info button:hover{
transform: scale(.95);
}
@media screen and (max-width: 62.5em) {
.misty-banner-info button {
margin-top: 0;
}
}
@media screen and (max-width: 52em) {
.misty-banner-info button,
.misty-banner-info p {
}
}
@media screen and (max-width: 35em) {
.misty-banner-info,
.misty-banner-logo {
}
.misty-banner-body{
opacity: 100;
}
}
.misty-banner .backdropCard {
transition-duration: 0;
transform: translateY(80%);
opacity: 0;
}
.misty-banner-library-show {
transition-duration: 1.7s !important;
transform: translateY(0) !important;
opacity: 1 !important;
}
.misty-banner-library-overflow {
overflow: visible !important;
}
and main.js
code:
class Home {
static start() {
this.cache = {
items: undefined,
item: new Map(),
};
this.itemQuery = { ImageTypes: "Backdrop", EnableImageTypes: "Logo,Backdrop", IncludeItemTypes: "Movie,Series", SortBy: "ProductionYear, PremiereDate, SortName", Recursive: true, ImageTypeLimit: 1, Limit: 10, Fields: "ProductionYear", SortOrder: "Descending", EnableUserData: false, EnableTotalRecordCount: false };
this.coverOptions = { type: "Backdrop", maxWidth: 3000 };
this.logoOptions = { type: "Logo", maxWidth: 3000 };
if (this.IsPhone()) {
this.itemQuery.ImageTypes = "Primary";
this.coverOptions.type = "Primary";
}
setInterval(() => {
if (window.location.href.indexOf("!/home") != -1) {
if ($(".view:not(.hide) .misty-banner").length == 0 && $(".misty-loading").length == 0) {
this.initLoading();
}
if ($(".hide .misty-banner").length != 0) {
$(".hide .misty-banner").remove();
this.init();
}
if ($(".section0 .card").length != 0 && $(".view:not(.hide) .misty-banner").length == 0) {
this.init();
}
}
}, 100);
}
static IsPhone() {
const info = navigator.userAgent;
const isPhone = /mobile/i.test(info);
return isPhone;
}
static async init() {
// Beta
$(".view:not(.hide)").attr("data-type", "home");
// Loading
const serverName = await this.injectCall("serverName", "");
$(".misty-loading h1").text(serverName).addClass("active");
// Banner
await this.initBanner();
this.initEvent();
}
/* 插入Loading */
static initLoading() {
const load = `
<div class="misty-loading">
<h1></h1>
<div class="mdl-spinner"><div class="mdl-spinner__layer mdl-spinner__layer-1"><div class="mdl-spinner__circle-clipper mdl-spinner__left"><div class="mdl-spinner__circle mdl-spinner__circleLeft"></div></div><div class="mdl-spinner__circle-clipper mdl-spinner__right"><div class="mdl-spinner__circle mdl-spinner__circleRight"></div></div></div></div>
</div>
`;
$("body").append(load);
}
static injectCode(code) {
let hash = md5(code + Math.random().toString());
return new Promise((resolve, reject) => {
const channel = new BroadcastChannel(hash);
channel.addEventListener("message", (event) => resolve(event.data));
const script = `
<script class="I${hash}">
setTimeout(async ()=> {
async function R${hash}(){${code}};
const channel = new BroadcastChannel("${hash}");
channel.postMessage(await R${hash}());
document.querySelector("script.I${hash}").remove()
}, 16)
</script>
`;
$(document.head || document.documentElement).append(script);
});
}
static injectCall(func, arg) {
const script = `
// const client = (await window.require(["ApiClient"]))[0];
const client = await new Promise((resolve, reject) => {
setInterval(() => {
if (window.ApiClient != undefined) resolve(window.ApiClient);
}, 16);
});
return await client.${func}(${arg})
`;
return this.injectCode(script);
}
static getItems(query) {
if (this.cache.items == undefined) {
this.cache.items = this.injectCall("getItems", "client.getCurrentUserId(), " + JSON.stringify(query));
}
return this.cache.items;
}
static async getItem(itemId) {
// 双缓存 优先使用 WebStorage
if (typeof Storage !== "undefined" && !localStorage.getItem("CACHE|" + itemId) && !this.cache.item.has(itemId)) {
const data = JSON.stringify(await this.injectCall("getItem", `client.getCurrentUserId(), "${itemId}"`));
if (typeof Storage !== "undefined") localStorage.setItem("CACHE|" + itemId, data);
else this.cache.item.set(itemId, data);
}
return JSON.parse(typeof Storage !== "undefined" ? localStorage.getItem("CACHE|" + itemId) : this.cache.item.get(itemId));
}
static getImageUrl(itemId, options) {
return this.injectCall("getImageUrl", itemId + ", " + JSON.stringify(options));
}
/* 插入Banner */
static async initBanner() {
const banner = `
<div class="misty-banner">
<div class="misty-banner-body">
</div>
<div class="misty-banner-library">
<div class="misty-banner-logos"></div>
</div>
</div>
`;
$(".view:not(.hide) .homeSectionsContainer").prepend(banner);
$(".view:not(.hide) .section0").detach().appendTo(".view:not(.hide) .misty-banner-library");
// 插入数据
const data = await this.getItems(this.itemQuery);
console.log(data);
data.Items.forEach(async (item) => {
const detail = await this.getItem(item.Id),
itemHtml = `
<div class="misty-banner-item" id="${detail.Id}">
<img draggable="false" loading="eager" decoding="async" class="misty-banner-cover" src="${await this.getImageUrl(detail.Id, this.coverOptions)}" alt="Backdrop" style="">
<div class="misty-banner-info padded-left padded-right">
<h1>${detail.Name}</h1>
<div><p>${detail.Overview}</p></div>
<div><button onclick="appRouter.showItem('${detail.Id}')">MORE</button></div>
</div>
</div>
`,
logoHtml = `
<img id="${detail.Id}" draggable="false" loading="auto" decoding="lazy" class="misty-banner-logo" data-banner="img-title" alt="Logo" src="${await this.getImageUrl(detail.Id, this.logoOptions)}">
`;
if (detail.ImageTags && detail.ImageTags.Logo) {
$(".misty-banner-logos").append(logoHtml);
}
$(".misty-banner-body").append(itemHtml);
console.log(item.Id, detail);
});
let complete = 0;
let loading = setInterval(async () => {
// 判断图片加载完毕
$(".misty-banner-cover:not(.complete)").each((i, dom) => {
if (dom.complete) {
dom.classList.add("complete");
complete++;
}
});
if (complete == $(".misty-banner-item").length && $(".misty-banner-item").length != 0) {
clearInterval(loading);
$(".misty-loading").fadeOut(500, () => $(".misty-loading").remove());
await CommonUtils.sleep(150);
// 置入场动画
let delay = 80; // 动媒体库画间隔
let id = $(".misty-banner-item").eq(0).addClass("active").attr("id"); // 初次信息动画
$(`.misty-banner-logo[id=${id}]`).addClass("active");
await CommonUtils.sleep(200); // 间隔动画
$(".section0 > div").addClass("misty-banner-library-overflow"); // 关闭overflow 防止媒体库动画溢出
$(".misty-banner .card").each((i, dom) => setTimeout(() => $(dom).addClass("misty-banner-library-show"), i * delay)); // 媒体库动画
await CommonUtils.sleep(delay * 8 + 1000); // 等待媒体库动画完毕
$(".section0 > div").removeClass("misty-banner-library-overflow"); // 开启overflow 防止无法滚动
// 滚屏逻辑
var index = 0;
clearInterval(this.bannerInterval);
this.bannerInterval = setInterval(async () => {
// 背景切换
index += index + 1 == $(".misty-banner-item").length ? -index : 1;
$(".misty-banner-body").css("left", -(index * 100).toString() + "%");
// 信息切换
$(".misty-banner-item.active").removeClass("active");
let id = $(".misty-banner-item").eq(index).addClass("active").attr("id");
// LOGO切换
$(".misty-banner-logo.active").removeClass("active");
$(`.misty-banner-logo[id=${id}]`).addClass("active");
}, 8000);
}
}, 16);
}
/* 初始事件 */
static initEvent() {
// 通过注入方式, 方可调用appRouter函数, 以解决Content-Script window对象不同步问题
const script = `
// 挂载appRouter
if (!window.appRouter) window.appRouter = (await window.require(["appRouter"]))[0];
// 修复library事件参数
const serverId = ApiClient._serverInfo.Id,
librarys = document.querySelectorAll(".view:not(.hide) .section0 .card");
librarys.forEach(library => {
library.setAttribute("data-serverid", serverId);
library.setAttribute("data-type", "CollectionFolder");
});
`;
this.injectCode(script);
}
}
// 运行
if ($("meta[name=application-name]").attr("content") == "Emby" || $(".accent-emby") != undefined) {
Home.start();
}
from emby-crx.
谢谢你,可以了。
from emby-crx.
这个是否是一个BUG呢?
from emby-crx.
我也不知道是不是bug,现在正常了,请问你知道如果更改标题和简介的字体和颜色吗?其他地方的字体颜色不变就仅仅是标题和剧情简介,或者让媒体库的文字显示出来而不是把鼠标移动上去才显示?
from emby-crx.
这个是否是一个BUG呢?
不算,因为我压根没写适配手机端的 ;)
from emby-crx.
Related Issues (20)
- 插件版后续是否可以支持jellyfin? HOT 6
- 是否可以考虑增加tv版本的适配,太好看了 HOT 1
- 自建媒体问题 HOT 1
- 建议文档里不要走 tinyurl 中转了 HOT 2
- 能否指定/排除某个媒体库的封面图? HOT 1
- 是否有适配手机端Web HOT 1
- 内网穿透后卡在加载界面一直转
- 无法在Edge浏览器上使用 HOT 2
- 使用后无法正常显示详见下方
- 1.0.4依然会出现点击主页重复出现的问题,期待修复 HOT 1
- 1.0.4点击主页再返回就一直转圈 HOT 1
- 按返回或主頁後出現兩個背景 HOT 1
- [Bug] 主页音乐库跳转链接错误
- 库不显示图片和名称 HOT 3
- 4.8.0.80新版本前端菜单样式新增,有多了个碍眼的滑轮 HOT 2
- 4.8.0.80更新 导致前端默认显示侧边栏为打开状态 HOT 5
- 顶部盖住了 滚动条
- 4.7及以后版本,音乐库顶栏选项显示不全 HOT 1
- 插件使用的Manifest V2即将弃用
- 出bug了,变成竖屏列表 HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from emby-crx.