152 lines
8.1 KiB
JavaScript
152 lines
8.1 KiB
JavaScript
let host = 'https://emby.bangumi.ca';/*"Emby服务器URL (例如 http://localhost:8096): "*/
|
|
let Token = "8b0b16aae7e8403cb3d19969b82c3902";
|
|
let Users = "80e861cbff1343bfa0bedcea78895b91";
|
|
let headers = {
|
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
|
|
"Referer": host + "/",
|
|
"Accept-Language": "zh-CN,zh;q=0.9"
|
|
};
|
|
const init = async () => {};
|
|
const extractVideos = jsonData => {
|
|
if (!jsonData || !jsonData.Items) return [];
|
|
return jsonData.Items.map(it => {
|
|
return {
|
|
vod_id: it.Id,
|
|
vod_name: it.Name || "",
|
|
vod_pic: it.ImageTags?.Primary ? `${host}/emby/Items/${it.Id}/Images/Primary?maxWidth=400&tag=${it.ImageTags.Primary}&quality=90` : "",
|
|
vod_remarks: it.ProductionYear ? it.ProductionYear.toString() : ""
|
|
};
|
|
});
|
|
};
|
|
|
|
const homeVod = async () => {
|
|
const url = `${host}/emby/Users/${Users}/Views?X-Emby-Client=Emby+Web&X-Emby-Device-Name=Android+WebView+Android&X-Emby-Device-Id=ea27caf7-9a51-4209-b1a5-374bf30c2ffd&X-Emby-Client-Version=4.9.0.31&X-Emby-Token=${Token}&X-Emby-Language=zh-cn`;
|
|
const resp = await req(url, { headers });
|
|
if (!resp?.content) return JSON.stringify({ list: [] });
|
|
const json = JSON.parse(resp.content);
|
|
return JSON.stringify({ list: extractVideos(json) });
|
|
};
|
|
const home = async () => {
|
|
const url = `${host}/emby/Users/${Users}/Views?X-Emby-Client=Emby+Web&X-Emby-Device-Name=Android+WebView+Android&X-Emby-Device-Id=ea27caf7-9a51-4209-b1a5-374bf30c2ffd&X-Emby-Client-Version=4.9.0.31&X-Emby-Token=${Token}&X-Emby-Language=zh-cn`;
|
|
const resp = await req(url, { headers });
|
|
if (!resp?.content) return JSON.stringify({ class: [], filters: {}, list: [] });
|
|
const json = JSON.parse(resp.content);
|
|
const classList = json.Items
|
|
.filter(it => !it.Name.includes("播放列表") && !it.Name.includes("相机"))
|
|
.map(it => ({
|
|
type_id: it.Id,
|
|
type_name: it.Name
|
|
}));
|
|
const list = [];
|
|
return JSON.stringify({
|
|
class: classList,
|
|
filters: {},
|
|
list
|
|
});
|
|
};
|
|
const category = async (tid, pg, _, extend) => {
|
|
const startIndex = (pg - 1) * 30;
|
|
const url = `${host}/emby/Users/${Users}/Items?SortBy=DateLastContentAdded%2CSortName&SortOrder=Descending&IncludeItemTypes=Movie%2CSeries&Recursive=true&Fields=BasicSyncInfo%2CCanDelete%2CContainer%2CPrimaryImageAspectRatio%2CProductionYear%2CCommunityRating%2CStatus%2CCriticRating%2CEndDate%2CPath&StartIndex=${startIndex}&ParentId=${tid}&EnableImageTypes=Primary%2CBackdrop%2CThumb%2CBanner&ImageTypeLimit=1&Limit=30&EnableUserData=true&X-Emby-Token=${Token}`;
|
|
const resp = await req(url, { headers });
|
|
if (!resp?.content) return JSON.stringify({ list: [], page: +pg, pagecount: 1, limit: 30 });
|
|
const json = JSON.parse(resp.content);
|
|
const list = extractVideos(json);
|
|
const total = json.TotalRecordCount || 0;
|
|
const pagecount = pg * 30 < total ? +pg + 1 : +pg;
|
|
return JSON.stringify({ list, page: +pg, pagecount, limit: 30, total });
|
|
};
|
|
const detail = async id => {
|
|
const url = `${host}/emby/Users/${Users}/Items/${id}?X-Emby-Token=${Token}`;
|
|
const resp = await req(url, { headers });
|
|
if (!resp?.content) return JSON.stringify({ list: [] });
|
|
const info = JSON.parse(resp.content);
|
|
let playFrom = "EMBY";
|
|
let playUrl = "";
|
|
if (!info.IsFolder) {
|
|
playUrl += `${info.Name.trim()}$${info.Id}#`;
|
|
} else {
|
|
if (info.Type === "Series") {
|
|
const seasonsUrl = `${host}/emby/Shows/${id}/Seasons?UserId=${Users}&Fields=BasicSyncInfo%2CCanDelete%2CContainer%2CPrimaryImageAspectRatio%2CProductionYear%2CCommunityRating&EnableImages=true&EnableUserData=true&X-Emby-Token=${Token}`;
|
|
const seasonsResp = await req(seasonsUrl, { headers });
|
|
if (seasonsResp?.content) {
|
|
const seasons = JSON.parse(seasonsResp.content);
|
|
for (const season of seasons.Items) {
|
|
const episodesUrl = `${host}/emby/Shows/${id}/Episodes?SeasonId=${season.Id}&Fields=BasicSyncInfo%2CCanDelete%2CCommunityRating%2CPrimaryImageAspectRatio%2CProductionYear%2COverview&UserId=${Users}&Limit=1000&X-Emby-Token=${Token}`;
|
|
const episodesResp = await req(episodesUrl, { headers });
|
|
if (episodesResp?.content) {
|
|
const episodes = JSON.parse(episodesResp.content);
|
|
for (const episode of episodes.Items) {
|
|
const seasonName = season.Name.replace('#', '-').replace('$', '|').trim();
|
|
const episodeName = episode.Name.trim();
|
|
playUrl += `${seasonName}|${episodeName}$${episode.Id}#`;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
const itemsUrl = `${host}/emby/Users/${Users}/Items?ParentId=${id}&Fields=BasicSyncInfo%2CCanDelete%2CContainer%2CPrimaryImageAspectRatio%2CProductionYear%2CCommunityRating%2CCriticRating&ImageTypeLimit=1&StartIndex=0&EnableUserData=true&X-Emby-Token=${Token}`;
|
|
const itemsResp = await req(itemsUrl, { headers });
|
|
if (itemsResp?.content) {
|
|
const items = JSON.parse(itemsResp.content);
|
|
for (const item of items.Items) {
|
|
playUrl += `${item.Name.replace('#', '-').replace('$', '|').trim()}$${item.Id}#`;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
playUrl = playUrl.slice(0, -1);
|
|
return JSON.stringify({
|
|
list: [{
|
|
vod_id: id,
|
|
vod_name: info.Name || "",
|
|
vod_pic: info.ImageTags?.Primary ? `${host}/emby/Items/${id}/Images/Primary?maxWidth=400&tag=${info.ImageTags.Primary}&quality=90` : "",
|
|
vod_content: info.Overview ? info.Overview.replace(/\xa0/g, ' ').replace(/\n\n/g, '\n').trim() : "暂无简介",
|
|
vod_year: info.ProductionYear ? info.ProductionYear.toString() : "",
|
|
vod_director: "",
|
|
vod_actor: "",
|
|
vod_type: info.Genres ? info.Genres.join(" / ") : "",
|
|
vod_play_from: playFrom,
|
|
vod_play_url: playUrl
|
|
}]
|
|
});
|
|
};
|
|
|
|
const search = async (wd, _, pg = 1) => {
|
|
const url = `${host}/emby/Users/${Users}/Items?SortBy=SortName&SortOrder=Ascending&Fields=BasicSyncInfo%2CCanDelete%2CContainer%2CPrimaryImageAspectRatio%2CProductionYear%2CStatus%2CEndDate&StartIndex=0&EnableImageTypes=Primary%2CBackdrop%2CThumb&ImageTypeLimit=1&Recursive=true&SearchTerm=${encodeURIComponent(wd)}&GroupProgramsBySeries=true&Limit=50&X-Emby-Token=${Token}`;
|
|
const resp = await req(url, { headers });
|
|
if (!resp?.content) return JSON.stringify({ list: [] });
|
|
const json = JSON.parse(resp.content);
|
|
return JSON.stringify({ list: extractVideos(json) });
|
|
};
|
|
|
|
const play = async (_, id) => {
|
|
const playbackUrl = `${host}/emby/Items/${id}/PlaybackInfo?UserId=${Users}&IsPlayback=false&AutoOpenLiveStream=false&StartTimeTicks=0&MaxStreamingBitrate=7000000&X-Emby-Token=${Token}`;
|
|
const resp = await req(playbackUrl, {
|
|
method: "POST",
|
|
headers: {
|
|
...headers,
|
|
"Content-Type": "application/json"
|
|
},
|
|
body: JSON.stringify({
|
|
"DeviceProfile": {
|
|
"DirectPlayProfiles": [{"Container": "mp4,m4v,mkv,hls,webm", "Type": "Video"}],
|
|
"TranscodingProfiles": [{"Container": "ts", "Type": "Video", "Protocol": "hls"}]
|
|
}
|
|
})
|
|
});
|
|
if (!resp?.content) return JSON.stringify({ parse: 1, url: playbackUrl, header: headers });
|
|
const json = JSON.parse(resp.content);
|
|
const mediaSources = json.MediaSources;
|
|
if (!mediaSources || mediaSources.length === 0) {
|
|
return JSON.stringify({ parse: 1, url: playbackUrl, header: headers });
|
|
}
|
|
const mediaSource = mediaSources[0];
|
|
if (mediaSource.DirectStreamUrl) {
|
|
return JSON.stringify({ parse: 0, url: host + mediaSource.DirectStreamUrl, header: headers });
|
|
} else if (mediaSource.Protocol === "Http") {
|
|
return JSON.stringify({ parse: 0, url: mediaSource.Path, header: headers });
|
|
}
|
|
return JSON.stringify({ parse: 1, url: playbackUrl, header: headers });
|
|
};
|
|
export default { init, home, homeVod, category, detail, search, play };
|