﻿#coding=utf-8
#!/usr/bin/python
import sys
import json
import time
import requests
from uuid import uuid4
from urllib.parse import quote

sys.path.append('..')
from base.spider import Spider

class Spider(Spider):
	def getName(self):
		return "EMBY"

	def init(self, extend):
		try:
			extendDict = json.loads(extend)
			self.baseUrl = extendDict['server'].strip('/')
			self.username = extendDict['username']
			self.password = extendDict['password']
			self.proxy = extendDict['proxy']
			self.thread = extendDict['thread'] if 'thread' in extendDict else 0
		except:
			self.baseUrl = ''
			self.username = ''
			self.password = ''
			self.proxy = ''
			self.thread = 0

	def destroy(self):
		pass

	def isVideoFormat(self, url):
		pass

	def manualVideoCheck(self):
		pass

	def homeContent(self, filter):
		try:
			embyInfos = self.getAccessToken()
		except:
			return {'msg': '获取Emby服务器信息出错'}

		header = self.header.copy()
		header['Content-Type'] = "application/json; charset=UTF-8"
		url = f"{self.baseUrl}/emby/Users/{embyInfos['User']['Id']}/Views"
		params = {
			"X-Emby-Client": embyInfos['SessionInfo']['Client'],
			"X-Emby-Device-Name": embyInfos['SessionInfo']['DeviceName'],
			"X-Emby-Device-Id": embyInfos['SessionInfo']['DeviceId'],
			"X-Emby-Client-Version": embyInfos['SessionInfo']['ApplicationVersion'],
			"X-Emby-Token": embyInfos['AccessToken']
		}
		r = requests.get(url, params=params, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy})
		typeInfos = r.json()["Items"]
		classList = []
		for typeInfo in typeInfos:
			if "播放列表" in typeInfo['Name'] or '相机' in typeInfo['Name']:
				continue
			classList.append({"type_name": typeInfo['Name'], "type_id": typeInfo['Id']})
		result = {'class': classList}
		return result

	def homeVideoContent(self):
		return {}

	def categoryContent(self, cid, page, filter, ext):
		try:
			embyInfos = self.getAccessToken()
		except:
			return {'list': [], 'msg': '获取Emby服务器信息出错'}

		result = {}
		page = int(page)
		header = self.header.copy()
		header['Content-Type'] = "application/json; charset=UTF-8"
		url = f"{self.baseUrl}/emby/Users/{embyInfos['User']['Id']}/Items"
		params = {
			"X-Emby-Client": embyInfos['SessionInfo']['Client'],
			"X-Emby-Device-Name": embyInfos['SessionInfo']['DeviceName'],
			"X-Emby-Device-Id": embyInfos['SessionInfo']['DeviceId'],
			"X-Emby-Client-Version": embyInfos['SessionInfo']['ApplicationVersion'],
			"X-Emby-Token": embyInfos['AccessToken'],
			"SortBy": "DateLastContentAdded,SortName",
			"IncludeItemTypes": "Movie,Series",
			"SortOrder": "Descending",
			"ParentId": cid,
			"Recursive": "true",
			"Limit": "30",
			"ImageTypeLimit": 1,
			"StartIndex": str((page - 1) * 30),
			"EnableImageTypes": "Primary,Backdrop,Thumb,Banner",
			"Fields": "BasicSyncInfo,CanDelete,Container,PrimaryImageAspectRatio,ProductionYear,CommunityRating,Status,CriticRating,EndDate,Path",
			"EnableUserData": "true"
		}
		r = requests.get(url, params=params, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy})
		videoList = r.json()['Items']
		videos = []
		for video in videoList:
			name = self.cleanText(video['Name'])
			videos.append({
				"vod_id": video['Id'],
				"vod_name": name,
				"vod_pic": f"{self.baseUrl}/emby/Items/{video['Id']}/Images/Primary?maxWidth=400&tag={video['ImageTags']['Primary']}&quality=90" if 'Primary' in video['ImageTags'] else '',
				"vod_remarks": video['ProductionYear'] if 'ProductionYear' in video else ''
			})
		result['list'] = videos
		result['page'] = page
		result['pagecount'] = page + 1 if page * 30 < int(r.json()['TotalRecordCount']) else page
		result['limit'] = len(videos)
		result['total'] = int(r.json()['TotalRecordCount']) if "TotalRecordCount" in r.json() else 0
		return result

	def detailContent(self, did):
		try:
			embyInfos = self.getAccessToken()
		except:
			return {'list': [], 'msg': '获取Emby服务器信息出错'}

		header = self.header.copy()
		header['Content-Type'] = "application/json; charset=UTF-8"
		url = f"{self.baseUrl}/emby/Users/{embyInfos['User']['Id']}/Items/{did[0]}"
		params = {
			"X-Emby-Client": embyInfos['SessionInfo']['Client'],
			"X-Emby-Device-Name": embyInfos['SessionInfo']['DeviceName'],
			"X-Emby-Device-Id": embyInfos['SessionInfo']['DeviceId'],
			"X-Emby-Client-Version": embyInfos['SessionInfo']['ApplicationVersion'],
			"X-Emby-Token": embyInfos['AccessToken']
		}
		r = requests.get(url, params=params, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy})
		videoInfos = r.json()
		vod = {
			"vod_id": did[0],
			"vod_name": videoInfos['Name'],
			"vod_pic": f'{self.baseUrl}/emby/Items/{did[0]}/Images/Primary?maxWidth=400&tag={videoInfos["ImageTags"]["Primary"]}&quality=90' if 'Primary' in videoInfos['ImageTags'] else '',
			"type_name": videoInfos['Genres'][0] if len(videoInfos['Genres']) > 0 else '',
			"vod_year": videoInfos['ProductionYear'] if 'ProductionYear' in videoInfos else '',
			"vod_content": videoInfos['Overview'].replace('\xa0', ' ').replace('\n\n', '\n').strip() if 'Overview' in videoInfos else '',
			"vod_play_from": "EMBY"
		}
		playUrl = ''
		if not videoInfos['IsFolder']:
			playUrl += f"{videoInfos['Name'].strip()}${videoInfos['Id']}#"
		else:
			url = f"{self.baseUrl}/emby/Shows/{did[0]}/Seasons"
			params.update(
				{
					"UserId": embyInfos['User']['Id'],
					"EnableImages": "true",
					"Fields": "BasicSyncInfo,CanDelete,Container,PrimaryImageAspectRatio,ProductionYear,CommunityRating",
					"EnableUserData": "true",
					"EnableTotalRecordCount": "false"
				}
			)
			r = requests.get(url, params=params, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy})
			if r.status_code == 200:
				playInfos = r.json()['Items']
				for playInfo in playInfos:
					url = f"{self.baseUrl}/emby/Shows/{playInfo['Id']}/Episodes"
					params.update(
						{
							"SeasonId": playInfo['Id'],
							"Fields": "BasicSyncInfo,CanDelete,CommunityRating,PrimaryImageAspectRatio,ProductionYear,Overview"
						}
					)
					r = requests.get(url, params=params, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy})
					videoList = r.json()['Items']
					for video in videoList:
						playUrl += f"{playInfo['Name'].replace('#', '-').replace('$', '|').strip()}|{video['Name'].strip()}${video['Id']}#"
			else:
				url = f"{self.baseUrl}/emby/Users/{embyInfos['User']['Id']}/Items"
				params = {
					"ParentId": did[0],
					"Fields": "BasicSyncInfo,CanDelete,Container,PrimaryImageAspectRatio,ProductionYear,CommunityRating,CriticRating",
					"ImageTypeLimit": "1",
					"StartIndex": "0",
					"EnableUserData": "true",
					"X-Emby-Client": embyInfos['SessionInfo']['Client'],
					"X-Emby-Device-Name": embyInfos['SessionInfo']['DeviceName'],
					"X-Emby-Device-Id": embyInfos['SessionInfo']['DeviceId'],
					"X-Emby-Client-Version": embyInfos['SessionInfo']['ApplicationVersion'],
					"X-Emby-Token": embyInfos['AccessToken']
				}
				r = requests.get(url, params=params, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy})
				videoList = r.json()['Items']
				for video in videoList:
					playUrl += f"{video['Name'].replace('#', '-').replace('$', '|').strip()}${video['Id']}#"
		vod['vod_play_url'] = playUrl.strip('#')
		result = {'list': [vod]}
		return result

	def searchContent(self, key, quick, pg="1"):
		return self.searchContentPage(key, quick, pg)

	def searchContentPage(self, keywords, quick, page):
		try:
			embyInfos = self.getAccessToken()
		except:
			return {'list': [], 'msg': '获取Emby服务器信息出错'}
		page = int(page)
		header = self.header.copy()
		header['Content-Type'] = "application/json; charset=UTF-8"
		url = f"{self.baseUrl}/emby/Users/{embyInfos['User']['Id']}/Items"
		params = {
			"X-Emby-Client": embyInfos['SessionInfo']['Client'],
			"X-Emby-Device-Name": embyInfos['SessionInfo']['DeviceName'],
			"X-Emby-Device-Id": embyInfos['SessionInfo']['DeviceId'],
			"X-Emby-Client-Version": embyInfos['SessionInfo']['ApplicationVersion'],
			"X-Emby-Token": embyInfos['AccessToken'],
			"SortBy": "SortName",
			"SortOrder": "Ascending",
			"Fields": "BasicSyncInfo,CanDelete,Container,PrimaryImageAspectRatio,ProductionYear,Status,EndDate",
			"StartIndex": str(((page-1)*50)),
			"EnableImageTypes": "Primary,Backdrop,Thumb",
			"ImageTypeLimit": "1",
			"Recursive": "true",
			"SearchTerm": keywords,
			"IncludeItemTypes": "Movie,Series,BoxSet",
			"GroupProgramsBySeries": "true",
			"Limit": "50",
			"EnableTotalRecordCount": "true"
		}
		r = requests.get(url, params=params, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy})

		videos = []
		vodList = r.json()['Items']
		for vod in vodList:
			sid = vod['Id']
			name = self.cleanText(vod['Name'])
			pic = f'{self.baseUrl}/emby/Items/{sid}/Images/Primary?maxWidth=400&tag={vod["ImageTags"]["Primary"]}&quality=90' if 'Primary' in vod["ImageTags"] else ''
			videos.append({
				"vod_id": sid,
				"vod_name": name,
				"vod_pic": pic,
				"vod_remarks": vod['ProductionYear'] if 'ProductionYear' in vod else ''
			})
		result = {'list': videos}
		return result

	def playerContent(self, flag, pid, vipFlags):
		try:
			embyInfos = self.getAccessToken()
		except:
			return {'list': [], 'msg': '获取Emby服务器信息出错'}

		header = self.header.copy()
		header['Content-Type'] = "application/json; charset=UTF-8"
		url = f"{self.baseUrl}/emby/Items/{pid}/PlaybackInfo"
		params = {
			"UserId": embyInfos['User']['Id'],
			"IsPlayback": "false",
			"AutoOpenLiveStream": "false",
			"StartTimeTicks": 0,
			"MaxStreamingBitrate": "2147483647",
			"X-Emby-Client": embyInfos['SessionInfo']['Client'],
			"X-Emby-Device-Name": embyInfos['SessionInfo']['DeviceName'],
			"X-Emby-Device-Id": embyInfos['SessionInfo']['DeviceId'],
			"X-Emby-Client-Version": embyInfos['SessionInfo']['ApplicationVersion'],
			"X-Emby-Token": embyInfos['AccessToken']
		}
		data = "{\"DeviceProfile\":{\"SubtitleProfiles\":[{\"Method\":\"Embed\",\"Format\":\"ass\"},{\"Format\":\"ssa\",\"Method\":\"Embed\"},{\"Format\":\"subrip\",\"Method\":\"Embed\"},{\"Format\":\"sub\",\"Method\":\"Embed\"},{\"Method\":\"Embed\",\"Format\":\"pgssub\"},{\"Format\":\"subrip\",\"Method\":\"External\"},{\"Method\":\"External\",\"Format\":\"sub\"},{\"Method\":\"External\",\"Format\":\"ass\"},{\"Format\":\"ssa\",\"Method\":\"External\"},{\"Method\":\"External\",\"Format\":\"vtt\"},{\"Method\":\"External\",\"Format\":\"ass\"},{\"Format\":\"ssa\",\"Method\":\"External\"}],\"CodecProfiles\":[{\"Codec\":\"h264\",\"Type\":\"Video\",\"ApplyConditions\":[{\"Property\":\"IsAnamorphic\",\"Value\":\"true\",\"Condition\":\"NotEquals\",\"IsRequired\":false},{\"IsRequired\":false,\"Value\":\"high|main|baseline|constrained baseline\",\"Condition\":\"EqualsAny\",\"Property\":\"VideoProfile\"},{\"IsRequired\":false,\"Value\":\"80\",\"Condition\":\"LessThanEqual\",\"Property\":\"VideoLevel\"},{\"IsRequired\":false,\"Value\":\"true\",\"Condition\":\"NotEquals\",\"Property\":\"IsInterlaced\"}]},{\"Codec\":\"hevc\",\"ApplyConditions\":[{\"Property\":\"IsAnamorphic\",\"Value\":\"true\",\"Condition\":\"NotEquals\",\"IsRequired\":false},{\"IsRequired\":false,\"Value\":\"high|main|main 10\",\"Condition\":\"EqualsAny\",\"Property\":\"VideoProfile\"},{\"Property\":\"VideoLevel\",\"Value\":\"175\",\"Condition\":\"LessThanEqual\",\"IsRequired\":false},{\"IsRequired\":false,\"Value\":\"true\",\"Condition\":\"NotEquals\",\"Property\":\"IsInterlaced\"}],\"Type\":\"Video\"}],\"MaxStreamingBitrate\":40000000,\"TranscodingProfiles\":[{\"Container\":\"ts\",\"AudioCodec\":\"aac,mp3,wav,ac3,eac3,flac,opus\",\"VideoCodec\":\"hevc,h264,mpeg4\",\"BreakOnNonKeyFrames\":true,\"Type\":\"Video\",\"MaxAudioChannels\":\"6\",\"Protocol\":\"hls\",\"Context\":\"Streaming\",\"MinSegments\":2}],\"DirectPlayProfiles\":[{\"Container\":\"mov,mp4,mkv,hls,webm\",\"Type\":\"Video\",\"VideoCodec\":\"h264,hevc,dvhe,dvh1,h264,hevc,hev1,mpeg4,vp9\",\"AudioCodec\":\"aac,mp3,wav,ac3,eac3,flac,truehd,dts,dca,opus,pcm,pcm_s24le\"}],\"ResponseProfiles\":[{\"MimeType\":\"video/mp4\",\"Type\":\"Video\",\"Container\":\"m4v\"}],\"ContainerProfiles\":[],\"MusicStreamingTranscodingBitrate\":40000000,\"MaxStaticBitrate\":40000000}}"
		r = requests.post(url, params=params, data=data, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy})
		url = self.baseUrl + r.json()['MediaSources'][0]['DirectStreamUrl']
		if int(self.thread) > 0:
			try:
				self.fetch('http://127.0.0.1:7777', timeout=120)
			except:
				self.fetch('http://127.0.0.1:9978/go')
			url = f'http://127.0.0.1:7777/?url={quote(url)}&thread={self.thread}'
		result = {
			"url": url,
			"header": self.header,
			"parse": 0
		}
		return result

	def localProxy(self, params):
		pass

	def getAccessToken(self):
		key = f"emby_{self.baseUrl}_{self.username}_{self.password }"
		embyInfos = self.getCache(key)
		if embyInfos:
			return embyInfos

		header = self.header.copy()
		header['Content-Type'] = "application/json; charset=UTF-8"
#		r = requests.post(f"{self.baseUrl}/emby/Users/AuthenticateByName", params={"Username": self.username, "Password": self.password , "Pw": self.password , "X-Emby-Client": "Yamby", "X-Emby-Device-Name": "Yamby", "X-Emby-Device-Id": str(uuid4()), "X-Emby-Client-Version": "1.0.2"}, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy}
		r = requests.post(f"{self.baseUrl}/emby/Users/AuthenticateByName", params={"Username": self.username, "Password": self.password , "Pw": self.password , "X-Emby-Client": "Emby Theater", "X-Emby-Device-Name": "DESKTOP-C25AFR6", "X-Emby-Device-Id": str(uuid4()), "X-Emby-Client-Version": "3.0.20-3.0"}, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy})
		embyInfos = r.json()
		self.setCache(key, embyInfos)
		return embyInfos
	#header = {"User-Agent": "Yamby/1.0.2(Android"}
	header = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) EmbyTheater/3.0.20-3.0 Chrome/100.0.4896.160 Electron/18.3.15 Safari/537.36"}

