GithubHelp home page GithubHelp logo

nolovenodie / emby-crx Goto Github PK

View Code? Open in Web Editor NEW
715.0 7.0 72.0 1.05 MB

Emby 增强/美化 插件 (适用于 Chrome 内核浏览器 / EmbyServer)

Home Page: https://t.me/FreeEmbyChannel/454

License: MIT License

JavaScript 55.23% CSS 37.15% Shell 7.63%
emby misty

emby-crx's Introduction

Emby Crx

Emby 增强/美化 插件 (适用于 Chrome 内核浏览器)

警告: 媒体库封面为原创设计, 未经授权请勿模仿使用!


动画预览 (因 LOGO 入场动画过于优先, 效果可能略差, 最新版已更改, 视频等待更新, 具体效果可以自行尝试)

Preview.mp4

使用须知

如不需要 媒体库 鼠标悬浮 后居中显示库名, 请更改 static\css\style.css 文件内 第 37 行

使用方法

两种方法 只需部署一种即可

插件版

需要用户装载插件

Chrome 扩展设置 > 开发者模式 > 加载已解压的扩展程序 > 直接选择源码即可

服务器版

无需使用插件, 直接部署至服务端, 用户无缝使用

# Docker 版 (如遇脚本更新, 重新执行即可)
# 注意: 需要能访问的上Github的环境, 如果不懂 请在群内@我留言
# EmbyServer 为容器名, 如果你的容器名不是这个 请改成正确的!
# 参考教程(非官方): https://mj.tk/2023/07/Emby
docker exec EmbyServer /bin/sh -c 'cd /system/dashboard-ui && wget -O - https://tinyurl.com/2p97xcpd | sh'

# 正常版
# 参考教程(非官方): https://cangshui.net/5167.html

TODO

  • 封装为单 JS/CSS, 供客户端使用
  • 内封装进 Misty Media 客户端
  • 播放跳转第三方播放器功能
  • 版本在线检测更新

效果预览

警告: 媒体库封面为原创设计, 未经授权请勿模仿使用!

1 2 3 4

emby-crx's People

Contributors

jackloves111 avatar mobclix avatar nolovenodie avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

emby-crx's Issues

1.0.4点击主页再返回就一直转圈

很棒的插件,v1.0.4,先点击侧边栏的主页按钮后,再点击浏览器返回按钮,就一直转圈出不来了。
希望作者修复
emby版本:4.17.13
_20240114034401

经常首页点进去刷不出资源画面

经常点进去没有资源,反复三四次才能正常一次
其次,怎么正常删除这个美化插件
docker安装下怎么关闭悬停按钮显示媒体库名称?

新装emby首页无法加载

我今天刚使用docker 安装emby,然后安装插件,影片内容三部

// 只判断第一张海报加载完毕, 优化加载速度
await new Promise((resolve, reject) => {
let waitLoading = setInterval(() => {

			if (document.querySelector(".misty-banner-cover").complete) {
				clearInterval(waitLoading);
				resolve();
			}
		}, 16);
	});

打开控制台发现 (document.querySelector(".misty-banner-cover").complete ,这个块返回的是null

添加了一些可配置项

添加了一些可配置项:

  1. 可选择展示的媒体库
  2. 可选择展示的最大数量
  3. 可选择是否随机展示

因为写的比较丑陋所以就不pr了,有需要的自取,当然作者要是能帮忙重构那就太感谢了!
顺便推荐一个桌面壁纸软件lively-wallpaper,可以把网页设为桌面,和这个项目可以说是绝配

index.html中在<script src="main.js"></script>前添加

<script src="config.js"></script>

config.js

class Config{
	constructor() {
		//媒体库id,用逗号分隔。进入媒体库后url里的parentId
		//this.parentId = "5,21463";
                this.parentId = "";
		//滚屏间隔 ms
		this.interval = 8000;
		//是否开启随机
		this.random = true;
		this.itemQuery={
			//返回横幅的最大数量,注意每10个为一轮,一轮不足10个的会被舍弃。例如27则只显示两轮20个
			Limit : 20,//(integer) Optional. The maximum number of records to return
			
			//一般只需要关注上面几个配置,下面不了解的不需要修改
			/*-------------------------------------------------------------------------------------------------------------------------------*/
			Recursive : true,//(boolean) When searching within folders, this determines whether or not the search will be recursive. true/false
			SortOrder : "Descending",//(string) Sort Order - Ascending,Descending
			Fields : "ProductionYear",//(string) Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines
			EnableUserData : false,//(boolean) Optional, include user data
			ImageTypeLimit : 1,//(integer) Optional, the max number of images to return, per image type
			Fields : "ProductionYear",//(string) Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines
			IncludeItemTypes : "Movie,Series",//(string) Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.
			ImageTypes : "Backdrop",//(string) Optional. If specified, results will be filtered based on those containing image types. This allows multiple, comma delimited.
			EnableImageTypes : "Logo,Backdrop",//(string) Optional. The image types to include in the output.
			SortBy : "ProductionYear, PremiereDate, SortName",//(string) Optional. Specify one or more sort orders, comma delimeted. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime
			ArtistType : "",//(string) Artist or AlbumArtist
			MaxOfficialRating : "",//(string) Optional filter by maximum official rating (PG, PG-13, TV-MA, etc).
			HasThemeSong : "",//(boolean) Optional filter by items with theme songs.
			HasThemeVideo : "",//(boolean) Optional filter by items with theme videos.
			HasSubtitles : "",//(boolean) Optional filter by items with subtitles.
			HasSpecialFeature : "",//(boolean) Optional filter by items with special features.
			HasTrailer : "",//(boolean) Optional filter by items with trailers.
			AdjacentTo : "",//(string) Optional. Return items that are siblings of a supplied item.
			MinIndexNumber : "",//(integer) Optional filter by minimum index number.
			MaxPlayers : "",//(integer) Optional filter by minimum number of game players.
			ParentIndexNumber : "",//(integer) Optional filter by parent index number.
			HasParentalRating : "",//(integer) Optional filter by items that have or do not have a parental rating
			IsHD : "",//(boolean) Optional filter by items that are HD or not.
			LocationTypes : "",//(string) Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimeted.
			ExcludeLocationTypes : "",//(string) Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimeted.
			IsMissing : "",//(boolean) Optional filter by items that are missing episodes or not.
			IsUnaired : "",//(boolean) Optional filter by items that are unaired episodes or not.
			MinCommunityRating : "",//(number) Optional filter by minimum community rating.
			MinCriticRating : "",//(number) Optional filter by minimum critic rating.
			AiredDuringSeason : "",//(integer) Gets all episodes that aired during a season, including specials.
			MinPremiereDate : "",//(string) Optional. The minimum premiere date. Format = ISO
			MinDateLastSaved : "",//(string) Optional. The minimum premiere date. Format = ISO
			MinDateLastSavedForUser : "",//(string) Optional. The minimum premiere date. Format = ISO
			MaxPremiereDate : "",//(string) Optional. The maximum premiere date. Format = ISO
			HasOverview : "",//(boolean) Optional filter by items that have an overview or not.
			HasImdbId : "",//(boolean) Optional filter by items that have an imdb id or not.
			HasTmdbId : "",//(boolean) Optional filter by items that have a tmdb id or not.
			HasTvdbId : "",//(boolean) Optional filter by items that have a tvdb id or not.
			ExcludeItemIds : "",//(string) Optional. If specified, results will be filtered by exxcluding item ids. This allows multiple, comma delimeted.
			StartIndex : "",//(integer) Optional. The record index to start at. All items with a lower index will be dropped from the results.
			ExcludeItemTypes : "",//(string) Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.
			AnyProviderIdEquals : "",//(string) Optional. If specified, result will be filtered to contain only items which match at least one of the specified IDs. Each provider ID must be in the form 'prov.id', e.g. 'imdb.tt123456'. This allows multiple, comma delimeted value pairs.
			Filters : "",//(string) Optional. Specify additional filters to apply. This allows multiple, comma delimeted. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes
			IsFavorite : "",//(boolean) Optional filter by items that are marked as favorite, or not.
			IsMovie : "",//(boolean) Optional filter for movies.
			IsSeries : "",//(boolean) Optional filter for movies.
			IsNews : "",//(boolean) Optional filter for news.
			IsKids : "",//(boolean) Optional filter for kids.
			IsSports : "",//(boolean) Optional filter for sports.
			MediaTypes : "",//(string) Optional filter by MediaType. Allows multiple, comma delimited.
			IsPlayed : "",//(string) Optional filter by items that are played, or not.
			Genres : "",//(string) Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimeted.
			OfficialRatings : "",//(string) Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimeted.
			Tags : "",//(string) Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimeted.
			Years : "",//(string) Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimeted.
			EnableImages : "",//(boolean) Optional, include image information in output
			Person : "",//(string) Optional. If specified, results will be filtered to include only those containing the specified person.
			PersonIds : "",//(string) Optional. If specified, results will be filtered to include only those containing the specified person.
			PersonTypes : "",//(string) Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited
			Studios : "",//(string) Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimeted.
			StudioIds : "",//(string) Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimeted.
			Artists : "",//(string) Optional. If specified, results will be filtered based on artist. This allows multiple, pipe delimeted.
			ArtistIds : "",//(string) Optional. If specified, results will be filtered based on artist. This allows multiple, pipe delimeted.
			Albums : "",//(string) Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimeted.
			Ids : "",//(string) Optional. If specific items are needed, specify a list of item id's to retrieve. This allows multiple, comma delimited.
			VideoTypes : "",//(string) Optional filter by VideoType (videofile, dvd, bluray, iso). Allows multiple, comma delimeted.
			Containers : "",//(string) Optional filter by Container. Allows multiple, comma delimeted.
			AudioCodecs : "",//(string) Optional filter by AudioCodec. Allows multiple, comma delimeted.
			VideoCodecs : "",//(string) Optional filter by VideoCodec. Allows multiple, comma delimeted.
			SubtitleCodecs : "",//(string) Optional filter by SubtitleCodec. Allows multiple, comma delimeted.
			Path : "",//(string) Optional filter by Path.
			UserId  : "",//(string) User Id
			MinOfficialRating : "",//(string) Optional filter by minimum official rating (PG, PG-13, TV-MA, etc).
			IsLocked : "",//(string) Optional filter by items that are locked.
			IsPlaceHolder : "",//(boolean) Optional filter by items that are placeholders
			HasOfficialRating : "",//(boolean) Optional filter by items that have official ratings
			GroupItemsIntoCollections : "",//(boolean) Whether or not to hide items behind their boxsets.
			Is3D : "",//(boolean) Whether or not to hide items behind their boxsets.
			SeriesStatus : "",//(string) Optional filter by Series Status. Allows multiple, comma delimeted.
			NameStartsWithOrGreater : "",//(string) Optional filter by items whose name is sorted equally or greater than a given input string.
			NameStartsWith : "",//(string) Optional filter by items whose name is sorted equally than a given input string.
			NameLessThan : ""//(string) Optional filter by items whose name is equally or lesser than a given input string.
		}
		
		Object.getOwnPropertyNames(this.itemQuery).forEach(key => {
			if(this.itemQuery[key]==""){
				delete this.itemQuery[key];
			}
		})
		
		this.parentIds = this.parentId.split(',');
	}
}

main.js

class Home {
	static start() {
		this.cache = {
			items: undefined,
			item: new Map(),
		};
		this.config = new Config();
		console.log(this.config.itemQuery);
		this.itemQuery = this.config.itemQuery;
		this.coverOptions = { type: "Backdrop", maxWidth: 3000 };
		this.logoOptions = { type: "Logo", maxWidth: 3000 };

		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();
				}
				if ($(".section0 .card").length != 0 && $(".view:not(.hide) .misty-banner").length == 0) {
					this.init();
				}
			}
		}, 100);
	}

	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) {
		//由于要合并多个媒体库所以放弃做缓存
		return this.injectCall("getItems", "client.getCurrentUserId(), " + JSON.stringify(query));

	}
	
	static itemsRandom(array){
		let res = [], random;
		while(array.length>0){
			random = Math.floor(Math.random()*array.length);
			res.push(array[random]);
			array.splice(random, 1);
		}
		return res;
	}
	
	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));
	}

	static async appendItem(i){
		const detail = await this.getItem(this.data.Items[i].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);
	}
	
	//总数小于10
	static bannerRollOnce(){
		this.index += this.index + 1 == $(".misty-banner-item").length ? -this.index : 1;
		$(".misty-banner-body").css("left", -(this.index * 100).toString() + "%");
		// 信息切换
		$(".misty-banner-item.active").removeClass("active");
		let id = $(".misty-banner-item").eq(this.index).addClass("active").attr("id");
		// LOGO切换
		$(".misty-banner-logo.active").removeClass("active");
		$(`.misty-banner-logo[id=${id}]`).addClass("active");
	}
	
	//总数大于10
	static async bannerRoll(){
		// 背景切换
		this.index += this.index + 1 == $(".misty-banner-item").length ? -this.index : 1;
		//正常切换
		if(this.index != 0){
			$(".misty-banner-body").css("left", -(this.index * 100).toString() + "%");
			// 信息切换
			$(".misty-banner-item.active").removeClass("active");
			let id = $(".misty-banner-item").eq(this.index).addClass("active").attr("id");
			// LOGO切换
			$(".misty-banner-logo.active").removeClass("active");
			$(`.misty-banner-logo[id=${id}]`).addClass("active");
		}
		//已经切换到最后
		if(this.index == 0){
			clearInterval(this.bannerInterval);
			let l = $(".misty-banner-item").length;
			//剩余小于10张直接舍弃,从头开始
			if(this.count+1==this.data.Items.length||this.data.Items.length-this.count-1<10)
				this.count=-1;
			//向后添加,剩余10张以上添加10张
			for(let i=this.count+1;i<this.count+1+(this.data.Items.length-this.count-1<10?this.data.Items.length-this.count-1:10);i++){
				await this.appendItem(i)
			}
			//切换到第一张
			$(".misty-banner-body").css("left", "0%");
			$(".misty-banner-item.active").removeClass("active");
			let id = $(".misty-banner-item").eq(l).addClass("active").attr("id");
			$(".misty-banner-logo.active").removeClass("active");
			$(`.misty-banner-logo[id=${id}]`).addClass("active");
			//从dom中移除上一轮次的横幅
			for(let i=0;i<l;i++){
				$(".misty-banner-item").eq(0).remove();
			}
			this.bannerInterval = setInterval(this.bannerRoll.bind(this), this.config.interval);
		}
		this.count++;
	}
	/* 插入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");

		// 插入数据
		this.data = {Items:[]}
		//配置的媒体库不为空
		if(this.config.parentIds[0] != ""){
			//合并所有配置的媒体库的结果
			for(let parentId of this.config.parentIds){
				this.itemQuery.ParentId = parentId;
				let res = await this.getItems(this.itemQuery);
				this.data.Items = this.data.Items.concat(res.Items);
			}
		} else {
			//查询所有媒体库
			this.data = await this.getItems(this.itemQuery);
		}
		
		if(this.config.random==true){
			this.data.Items = this.itemsRandom(this.data.Items);
		}
		//大于10时添加10张				   
		for(let i=0;i<(this.data.Items.length<10?this.data.Items.length:10);i++){
			await this.appendItem(i)
			//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 防止无法滚动

				// 滚屏逻辑
				clearInterval(this.bannerInterval);
				this.index = 0;this.count = 0;
				this.bannerInterval = this.data.Items.length<10?setInterval(this.bannerRollOnce.bind(this), this.config.interval):setInterval(this.bannerRoll.bind(this), this.config.interval);
			}
		}, 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();
}

能否适配竖屏

目前是竖屏直接把上面的轮播图隐去了,能否让其保持在上面,媒体库下移?

使用后无法正常显示详见下方

  • 平台:macOS
  • edge版本:版本 120.0.2210.121 (正式版本) (x86_64)
  • emby-crx版本:v1.0.4
  • Emby版本:4.7.14.0

错误

错误描述:上下显示两个第一页

image

使用后,板块菜单进入内容发生变化,而且内容加载慢

rt
使用的是 docker 版本,使用后,点击板块菜单,加载很慢很慢,而且内容很少,不如主页旁的面包屑板块进入的内容多。比如音乐进入加载慢,而且没有“歌曲”栏。应该是这个板块进入不是原版的吧。如何像原版的?
感谢大佬的开发!

手机黑屏 pc端正常

PC端正常

F12控制台选手机模式也正常

就是直接手机端打不开一直黑屏 换了几个浏览器都不行

大佬知道是什么原因吗?

[Bug] 主页音乐库跳转链接错误

在主页轮播图处选择进入音乐库的时候,跳转的链接为 /web/index.html#!/videos?serverId=***&parentId=***,事实上音乐库应该跳转 /web/index.html#!/music?serverId=***&parentId=***

我的媒体鼠标移动上去时,没有选项了.

本来是可以直接在我的媒体封面上鼠标移动上去即可显示右下角的三个小圆点的.点击后出现菜单.开启这个以后我的媒体这几个版块只提供了点击进入的选项了.

BUG反馈-顶部导航下滑显示问题

如果左侧栏打开的状态下,顶部导航栏下滑再上滑出现,会被遮盖,检查代码发现是这个CSS的问题

.view:not(.hide) .skinHeader, .skinHeader-withBackground.headroom-scrolling {
    width: 100%;
}

将这个宽度100%注释掉后,可以恢复!
c5db1036-5419-447f-98d8-1ab6b868843a

自建媒体问题

如果切换用户之后,用户的媒体库里都没有影视,只有自己添加没有刮削的文件,能不能不显示海报墙,其他的样式不变。
因为这个用户的所有媒体库没有刮削过的影视,现在卡住了进不去主页

功能请求: 标签页后台禁用轮播

目前版本中, 即使标签页处于后台也会自动轮播, 这样当切换到该标签页时, 会快速切换多个封面图, 有点“鬼畜”, 有碍美观.
哪位佬能给加个“后台禁用轮播”或者“后台冻结”的类似功能?
或者稍微指点一下如何修改, 我自己琢磨一下?

建议文档里不要走 tinyurl 中转了

docker exec emby_unlockd /bin/sh -c 'cd /system/dashboard-ui && wget -O - https://tinyurl.com/2p97xcpd | sh'
Connecting to tinyurl.com (172.67.1.225:443)
wget: note: TLS certificate validation not implemented
wget: got bad TLS record (len:0) while expecting handshake record
wget: error getting response: Connection reset by peer

发现一个bug

版本:bata4.8版本
使用docker脚本安装在服务器端,会有重叠的首页
image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.