Greasy Fork

Douban-Info-for-PTP&HDB

在ptp和hdb电影详情页展示部分中文信息

当前为 2021-01-24 提交的版本,查看 最新版本

// ==UserScript==
// @name         Douban-Info-for-PTP&HDB
// @namespace    https://github.com/techmovie/Douban-Info-for-PTP
// @version      0.5.1
// @description  在ptp和hdb电影详情页展示部分中文信息
// @author       birdplane
// @match        https://passthepopcorn.me/torrents.php?id=*
// @match        https://hdbits.org/details.php?id=*
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @resource  emptyIcon  https://www.themoviedb.org/assets/2/v4/glyphicons/basic/glyphicons-basic-4-user-grey-d8fe957375e70239d6abdd549fd7568c89281b2179b5f4470e2e12895792dfa5.svg
// @note         2021-01-12 支持hdb剧集
// @note         2021-01-24 修改豆瓣评分样式
// ==/UserScript==

(function () {
  'use strict'
  const API_KEY = '054022eaeae0b00e0fc068c0c0a2102a'
  const DOUBAN_API_URL = 'https://frodo.douban.com/api/v2'
  const DOUBAN_SEARCH_API = 'https://movie.douban.com/j/subject_suggest'
  const isPTP = location.host.includes('passthepopcorn')
  const isHDB = location.host.includes('hdbits')
  const isHDBShow = isHDB && !!$j('.showlinks')[0]
  let imdbLink = null
  if (isPTP) {
    imdbLink = $('#imdb-title-link').attr('href')
  }
  if (isHDB && !isHDBShow) {
    imdbLink = $j('.contentlayout h1 a').attr('href')
  }
  if (isHDBShow) {
    imdbLink = $j('#details .showlinks li').eq(1).find('a').attr('href')
  }
  if (!imdbLink) {
    return
  }
  const imdbId = /tt\d+/.exec(imdbLink)[0]
  GM_xmlhttpRequest({
    method: 'GET',
    url: `${DOUBAN_SEARCH_API}?q=${imdbId}`,
    onload (res) {
      const data = JSON.parse(res.responseText)
      if (data.length > 0) {
        const doubanId = data[0].id
        if (isHDBShow) {
          getTvInfo(doubanId)
        } else {
          getMovieInfo(doubanId)
        }
      }
    }
  })
  const getTvInfo = (tvId) => {
    GM_xmlhttpRequest({
      url: `${DOUBAN_API_URL}/tv/${tvId}?apiKey=${API_KEY}`,
      onload (res) {
        const data = JSON.parse(res.responseText)
        addInfoToHdbPage(data)
      }
    })
  }
  const getMovieInfo = (movieId) => {
    GM_xmlhttpRequest({
      url: `${DOUBAN_API_URL}/movie/${movieId}?apiKey=${API_KEY}`,
      onload (res) {
        const data = JSON.parse(res.responseText)
        if (isPTP) {
          addInfoToPtpPage(data)
        }
        if (isHDB) {
          addInfoToHdbPage(data)
        }
      }
    })
  }
  const addInfoToHdbPage = (data) => {
    const infoContent = `
        <tr>
            <td>
                <div id="l7829483" class="label collapsable" onclick="showHideEl(7829483);(7829483)"><span class="plusminus">- </span>豆瓣信息</div>
                <div id="c7829483" class="hideablecontent" >
                    <div class="contentlayout  douban-info">
                        <div class="poster" style="margin-right: 10px;max-width: 300px;">
                            <image src="${data.pic.normal}" style="width: 100%;">
                        </div>
                        <div class="detail">
                            <div class="title">
                                <a  target='_blank' href="${data.url}">${data.title}  (${data.year}) </a>
                            </div>
                            <div style="font-size: 0;min-width: 105px;margin-bottom: 20px;">
                                <span class="icon-pt1" >豆</span>
                                <span class="icon-pt2">豆瓣评分</span>
                                <span style="font-size: 18px;font-weight:600;margin-left:10px;">${data.rating.value}</span>
                                <span style="font-size: 14px;">&nbsp;(${data.rating.count} votes)</span>
                            </div>
                            <div class="movie-detail">
                                <div class="synopsis">
                                    ${data.intro || '暂无简介'}
                                </div>
                                <div class="movieinfo">
                                    <div class="panel">
                                        <div class="panel__body">
                                            <div><strong>导演:</strong> ${data.directors.map(item => {
                                                return ` <a class="artist-info-link" href="${item.url}" target="_blank">${item.name}</a>  `
                                            })}
                                            </div>
                                            <div><strong>类型:</strong> ${data.genres.join('/')}</div>
                                            <div><strong>制片国家/地区:</strong> ${data.countries.join('/')}</div>
                                            <div><strong>语言:</strong> ${data.languages.join('/')}</div>
                                            <div><strong>时长:</strong> ${data.durations.join('/')}</div>
                                            <div><strong>又名:</strong>  ${data.aka.join('/')}</div
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="cast-info">
                            ${createCastDom(data)}
                        </div>
                    </div>
                </div>
            </td>
        </tr>`
    if (isHDBShow) {
      $j('#details>tbody>tr').eq(2).before(infoContent)
    } else {
      $j('#details>tbody>tr').eq(1).before(infoContent)
    }
  }
  const addInfoToPtpPage = (data) => {
    if (isChinese(data.title)) {
      $('.page__title').prepend(`<a  target='_blank' href="${data.url}">[${data.title}] </a>`)
    }
    if (data.intro) {
      $('#synopsis').html(data.intro)
    }
    $('#movieinfo').before(`
        <div class="panel">
        <div class="panel__heading"><span class="panel__heading__title">电影信息</span></div>
        <div class="panel__body">
          <div><strong>导演:</strong>
            ${data.directors.map(item => {
                return ` <a class="artist-info-link" href="${item.url}" target="_blank">${item.name}</a>  `
              })}
          </div>
          <div><strong>类型:</strong> ${data.genres.join('/')}</div>
          <div><strong>制片国家/地区:</strong> ${data.countries.join('/')}</div>
          <div><strong>语言:</strong> ${data.languages.join('/')}</div>
          <div><strong>时长:</strong> ${data.durations.join('/')}</div>
          <div><strong>又名:</strong>  ${data.aka.join('/')}</div
        </div>`)
    if (data.rating.value) {
      $('#movie-ratings-table tr').prepend(
            `<td colspan="1" style="width: 152px;">
            <center>
            <a target="_blank" class="rating" href="${data.url}" rel="noreferrer">
            <div style="font-size: 0;min-width: 105px;">
                <span class="icon-pt1">豆</span>
                <span class="icon-pt2">豆瓣评分</span>
            </div>
            </a>
            </center>
            </td>
            <td style="width: 153px;">
            <span class="rating">${data.rating.value}</span>
            <span class="mid">/</span>
            <span class="outof"> ${data.rating.max}</span>
            <br>(${data.rating.count} votes)</td>`)
    }
    const castEl = createCastDom(data)
    if (castEl) {
      const castPanelEl = `<div class="panel">
                <div class="panel__heading"><span class="panel__heading__title">主演</span></div>
                <div class="panel__body">
                    <ul style="width: 100%;overflow-x: auto;display: flex;padding-left:0;word-break: break-all;">
                        ${castEl}
                    </ul>
                </div>
                </div>`
      $('#synopsis-and-trailer').next('.panel').after(castPanelEl)
    }
  }
  const isChinese = (title) => {
    return /[\u4e00-\u9fa5]+/.test(title)
  }
  const createCastDom = (data) => {
    if (data.actors && data.actors.length) {
      const castsDom = data.actors.map(item => {
        const imageEl = item.cover_url
          ? ` <image style="width: 100%;"
                src="${item.cover_url}"></image>`
          : '<div class="cast-empty"></div>'
        return `
                <li class="cast-item">
                    <a target="_blank" href="${item.url}" class="cast-item-image">
                        ${imageEl}
                    </a>
                    <div class="actor-name">
                        <a target="_blank" style="color: #000;font-weight: bold" href="${item.url}">${item.name}</a>
                    </div>
                </li>`
      })
      return castsDom.join('')
    }
    return ''
  }
  GM_addStyle(`
    .contentlayout.douban-info {
        display: flex;
        justify-content: space-around;
    }
    .contentlayout.douban-info .detail{
        flex:1;
    }
    .detail .title{
        font-size: 26px;
        font-weight: 600;
        margin-bottom: 20px;
   }
    .detail .title a{
        text-decoration: none;
   }
    .movie-detail{
        display: flex;
        justify-content: space-between;
    }
    .movie-detail .synopsis {
        width: 60%;
    }
    .movie-detail .movieinfo {
        margin-right: 20px;
        max-width: 30%;
    }
    .icon-pt1{
        font-size: 14px;
        display: inline-block;
        text-align: center;
        border: 1px solid #41be57;
        background-color: #41be57;
        color: white;
        border-top-left-radius: 4px;
        border-bottom-left-radius: 4px;
        width: 24px;
        height: 24px;
        line-height: 24px;
    }

    .icon-pt2{
        display: inline-block;
        text-align: center;
        border: 1px solid #41be57;
        color: #3ba94d;
        background: #ffffff;
        border-top-right-radius: 4px;
        border-bottom-right-radius: 4px;
        width: 69px;
        height: 24px;
        line-height: 24px;
        font-size: 14px;
    }
    .cast-empty{
        background-image: url(GM.getResourceUrl("emptyIcon")); width: auto;
        display: flex;
        align-content: center;
        align-items: center;
        flex-wrap: wrap;
        overflow: hidden;
        height: 100%;
        background-position: center center;
        background-repeat: no-repeat;
        background-color: #dbdbdb;
        box-sizing: border-box;
        background-size: 50%;
        text-overflow: ellipsis;
    }
    .cast-item{
        margin-top: 10px;
        margin-bottom: 10px;
        flex-shrink: 0;
        display: inline-block;
        margin-left: 10px;
        margin-right: 4px;
        width: 138px;
        background-color: #fff;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
        padding-bottom: 10px;
        border-radius: 6px;
        overflow: hidden;
    }
    .cast-item-image{
        width: 138px;
        height: 175px;
        display:block;
        overflow: hidden;
    }
    .cast-item .actor-name{
        color: #000;
        font-weight: bold;
        padding: 10px 10px 0;
    }
`)
})()