├── README.md ├── cron_releases.sh ├── digitalreleases.py └── digitalreleases2.py /README.md: -------------------------------------------------------------------------------- 1 | # torrentReleases 2 | Следим за качественными цифровыми релизами фильмов без суеты 3 | 4 | Полное описание с подробностями читайте по ссылке: 5 | https://habr.com/ru/post/443584/ 6 | -------------------------------------------------------------------------------- /cron_releases.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | for i in $(seq 1 5); do 4 | /opt/bin/python3 /opt/etc/movies/digitalreleases2.py > /opt/etc/movies/log.txt 5 | ret=$? 6 | if [ $ret -eq 0 ]; then 7 | logger -t "digitalreleases.py" "Загрузка завершена успешно." 8 | break 9 | else 10 | logger -t "digitalreleases.py" "Ошибка загрузки." 11 | fi 12 | done -------------------------------------------------------------------------------- /digitalreleases.py: -------------------------------------------------------------------------------- 1 | ### DAYS — за сколько последних дней загружать цифровые релизы. По умолчанию 60. 2 | ### SOCKS_IP и SOCKS_PORT — IP-адрес и порт SOCKS Proxy. Если они указаны, то будет импортирована библиотека (PySocks), а в функции rutorLinks запросы будет обрабатываться через указанный прокси-сервер. В digitalReleases и filmDetail запросы всегда идут без прокси. 3 | ### SORT_TYPE — тип финальной сортировки. rating — сортировка по рейтингу, releaseDate — сортировка по дате цифрового релиза, torrentsDate — сортировка по дате появления торрента, comboDate — сортировка по комбинированное дате (наибольшая из releaseDate и torrentsDate). 4 | ### USE_MAGNET — использование Magnet-ссылок вместо ссылок на торрент-файлы. 5 | 6 | 7 | ### digitalReleases(days) возвращает массив со словарями {filmID, releaseDate}, цифровые релизы за количество дней days. 8 | ### filmDetail(filmID) возвращает словарь с информацией по фильму, соответствующему filmID. 9 | ### rutorLinks(filmID) возвращает словарь с раздачами, соответствующими filmID. 10 | ### saveHTML(movies, filePath) формирует HTML-файл по пути filePath из массива movies. 11 | ### main объединяет всё вместе digitalReleases > rutorLinks + filmDetail > saveHTML. 12 | 13 | DAYS = 60 14 | USE_MAGNET = False 15 | SORT_TYPE = "rating" 16 | SOCKS_IP = "" 17 | SOCKS_PORT = 0 18 | HTML_SAVE_PATH = "/opt/share/www/releases.html" 19 | #HTML_SAVE_PATH = r"C:\Users\Yuri\releases.html" 20 | 21 | 22 | KINOPOISK_UUID = "6730382b7a236cd964264b49413ed00f" ### Генерируется автоматически в main, но можно в случае необходимости использовать константные значения. 23 | KINOPOISK_CLIENTID = "56decdcf6d4ad1bcaa1b3856" ### Генерируется автоматически в main, но можно в случае необходимости использовать константные значения. 24 | KINOPOISK_API_SALT = "IDATevHDS7" 25 | KINOPOISK_BASE_URL = "https://ma.kinopoisk.ru" 26 | KINOPOISK_API_RELEAESES = "/k/v1/films/releases/digital?digitalReleaseMonth={}&limit=1000&offset=0&uuid={}" 27 | KINOPOISK_BASE_URL2 = "https://ma.kinopoisk.ru/ios/5.0.0/" 28 | KINOPOISK_API_FILMDETAIL = "getKPFilmDetailView?still_limit=9&filmID={}&uuid={}" 29 | POSTER_URL = "https://st.kp.yandex.net/images/{}{}width=360" 30 | RUTOR_BASE_URL = "http://rutor.info/search/0/0/010/0/film%20" 31 | 32 | import hashlib 33 | import datetime 34 | import urllib.request 35 | from urllib.parse import urljoin 36 | import time 37 | import gzip 38 | import json 39 | import html 40 | import re 41 | import operator 42 | import os 43 | import binascii 44 | if SOCKS_IP: 45 | import socks 46 | import socket 47 | 48 | def digitalReleases(days): 49 | rDict = {} 50 | result = [] 51 | 52 | currentDateReal = datetime.date.today() 53 | currentDate = currentDateReal + datetime.timedelta(days=7) 54 | 55 | print("Текущая дата (с запасом 7 дней): " + currentDate.strftime("%d.%m.%Y")) 56 | downloadDates =[currentDate] 57 | targetDate = datetime.date.today() - datetime.timedelta(days=days) 58 | print("Целевая дата: " + targetDate.strftime("%d.%m.%Y")) 59 | iterationDate = datetime.date.today() + datetime.timedelta(days=7) 60 | 61 | while (targetDate.year != iterationDate.year) or (targetDate.month != iterationDate.month): 62 | iterationDate = iterationDate.replace(day=1) - datetime.timedelta(days=1) 63 | downloadDates.append(iterationDate) 64 | 65 | print("Количество месяцев для загрузки: " + str(len(downloadDates))) 66 | 67 | for downloadDate in downloadDates: 68 | print("Загрузка релизов за " + downloadDate.strftime("%m.%Y") + ".") 69 | 70 | requestMethod = KINOPOISK_API_RELEAESES.format(downloadDate.strftime("%m.%Y"), KINOPOISK_UUID) 71 | timestamp = str(int(round(time.time() * 1000))) 72 | hashString = requestMethod + timestamp + KINOPOISK_API_SALT 73 | 74 | request = urllib.request.Request(KINOPOISK_BASE_URL + requestMethod) 75 | request.add_header("Accept-encoding", "gzip") 76 | request.add_header("Accept", "application/json") 77 | request.add_header("User-Agent", "Android client (6.0.1 / api23), ru.kinopoisk/4.6.5 (86)") 78 | request.add_header("Image-Scale", "3") 79 | request.add_header("device", "android") 80 | request.add_header("ClientId", KINOPOISK_CLIENTID) 81 | request.add_header("countryID", "2") 82 | request.add_header("cityID", "1") 83 | request.add_header("Android-Api-Version", "23") 84 | request.add_header("clientDate", datetime.date.today().strftime("%H:%M %d.%m.%Y")) 85 | request.add_header("X-TIMESTAMP", timestamp) 86 | request.add_header("X-SIGNATURE", hashlib.md5(hashString.encode('utf-8')).hexdigest()) 87 | 88 | try: 89 | response = urllib.request.urlopen(request) 90 | except Exception: 91 | print("Ошибка соединения при загрузке релизов за " + downloadDate.strftime("%m.%Y") + ". Даём второй шанс.") 92 | response = urllib.request.urlopen(request) 93 | 94 | if response.info().get('Content-Encoding') == 'gzip': 95 | gzipFile = gzip.GzipFile(fileobj=response) 96 | content = gzipFile.read().decode("utf-8") 97 | else: 98 | content = response.read().decode("utf-8") 99 | 100 | if content: 101 | tmpDict = json.loads(content) 102 | if not tmpDict: 103 | raise ValueError("Ошибка загрузки релизов за " + downloadDate.strftime("%m.%Y") + ". Ответ не соответствует JSON.") 104 | if tmpDict.get("success") != True: 105 | raise ValueError("Ошибка загрузки релизов за " + downloadDate.strftime("%m.%Y") + ". В ответе нет значения success или оно равно False.") 106 | items = tmpDict.get("data") 107 | if items == None or not isinstance(items, dict): 108 | raise ValueError("Ошибка загрузки релизов за " + downloadDate.strftime("%m.%Y") + ". Проблемы со значением data.") 109 | items = items.get("items") 110 | if items == None or not isinstance(items, list): 111 | raise ValueError("Ошибка загрузки релизов за " + downloadDate.strftime("%m.%Y") + ". Проблемы со значением items.") 112 | 113 | for item in items: 114 | if not isinstance(item, dict): 115 | raise ValueError("Ошибка загрузки релизов за " + downloadDate.strftime("%m.%Y") + ". Проблемы с одним из элементов items.") 116 | filmID = item.get("id") 117 | if not isinstance(filmID, int): 118 | raise ValueError("Ошибка загрузки релизов за " + downloadDate.strftime("%m.%Y") + ". Проблемы с id в одном из элементов items.") 119 | contextData = item.get("contextData") 120 | if not isinstance(contextData, dict): 121 | raise ValueError("Ошибка загрузки релизов за " + downloadDate.strftime("%m.%Y") + ". Проблемы с contextData в одном из элементов items.") 122 | releaseDateStr = contextData.get("releaseDate") 123 | if not isinstance(releaseDateStr, str): 124 | raise ValueError("Ошибка загрузки релизов за " + downloadDate.strftime("%m.%Y") + ". Проблемы с releaseDate в одном из элементов items.") 125 | releaseDate = datetime.datetime.strptime(releaseDateStr, "%Y-%m-%d").date() 126 | 127 | if (targetDate <= releaseDate) and (releaseDate <= currentDate): 128 | rDict[str(filmID)] = releaseDate 129 | else: 130 | raise ValueError("Ошибка загрузки релизов за " + downloadDate.strftime("%m.%Y") + ".") 131 | 132 | print("Загружены ID от {} релизов.".format(len(rDict))) 133 | 134 | for key, value in rDict.items(): 135 | temp = {"filmID": key, "releaseDate":value} 136 | result.append(temp) 137 | 138 | return result 139 | 140 | def filmDetail(filmID): 141 | print("Загрузка данных для filmID " + filmID + ".") 142 | 143 | result = {} 144 | 145 | requestMethod = KINOPOISK_API_FILMDETAIL.format(filmID, KINOPOISK_UUID) 146 | timestamp = str(int(round(time.time() * 1000))) 147 | hashString = requestMethod + timestamp + KINOPOISK_API_SALT 148 | 149 | request = urllib.request.Request(KINOPOISK_BASE_URL2 + requestMethod) 150 | request.add_header("Accept-encoding", "gzip") 151 | request.add_header("Accept", "application/json") 152 | request.add_header("User-Agent", "Android client (6.0.1 / api23), ru.kinopoisk/4.6.5 (86)") 153 | request.add_header("Image-Scale", "3") 154 | request.add_header("device", "android") 155 | request.add_header("ClientId", KINOPOISK_CLIENTID) 156 | request.add_header("countryID", "2") 157 | request.add_header("cityID", "1") 158 | request.add_header("Android-Api-Version", "23") 159 | request.add_header("clientDate", datetime.date.today().strftime("%H:%M %d.%m.%Y")) 160 | request.add_header("X-TIMESTAMP", timestamp) 161 | request.add_header("X-SIGNATURE", hashlib.md5(hashString.encode('utf-8')).hexdigest()) 162 | 163 | try: 164 | response = urllib.request.urlopen(request) 165 | except Exception: 166 | print("Ошибка соединения при загрузке данных для filmID " + filmID + ". Даём второй шанс.") 167 | response = urllib.request.urlopen(request) 168 | 169 | if response.info().get('Content-Encoding') == 'gzip': 170 | gzipFile = gzip.GzipFile(fileobj=response) 171 | content = gzipFile.read().decode("utf-8") 172 | else: 173 | content = response.read().decode("utf-8") 174 | 175 | if content: 176 | tmpDict = json.loads(content) 177 | #print(tmpDict) 178 | 179 | if not tmpDict: 180 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Ответ не соответствует JSON.") 181 | if tmpDict.get("resultCode") != 0: 182 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". В ответе нет значения resultCode или оно не равно 0.") 183 | itemData = tmpDict.get("data") 184 | if itemData == None or not isinstance(itemData, dict): 185 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением data.") 186 | nameRU = itemData.get("nameRU") 187 | if nameRU == None or not isinstance(nameRU, str): 188 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением nameRU.") 189 | nameEN = itemData.get("nameEN") 190 | if nameEN == None or not isinstance(nameEN, str): 191 | nameEN = "" 192 | year = itemData.get("year") 193 | if year == None or not isinstance(year, str): 194 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением year.") 195 | country = itemData.get("country") 196 | if country == None or not isinstance(country, str): 197 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением country.") 198 | genre = itemData.get("genre") 199 | if genre == None or not isinstance(genre, str): 200 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением genre.") 201 | description = itemData.get("description") 202 | if description == None or not isinstance(description, str): 203 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением description.") 204 | ratingAgeLimits = itemData.get("ratingAgeLimits") 205 | if ratingAgeLimits == None or not isinstance(ratingAgeLimits, str): 206 | ratingAgeLimits = "" 207 | posterURL = itemData.get("posterURL") 208 | if posterURL == None or not isinstance(posterURL, str): 209 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением posterURL.") 210 | if "?" in posterURL: 211 | posterURL = POSTER_URL.format(posterURL, "&") 212 | else: 213 | posterURL = POSTER_URL.format(posterURL, "?") 214 | filmLength = itemData.get("filmLength") 215 | if filmLength == None or not isinstance(filmLength, str): 216 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением filmLength.") 217 | ratingData = itemData.get("ratingData") 218 | if ratingData == None or not isinstance(ratingData, dict): 219 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением ratingData.") 220 | ratingKP = ratingData.get("rating") 221 | if ratingKP == None or not isinstance(ratingKP, str): 222 | ratingKP = "" 223 | ratingIMDb = ratingData.get("ratingIMDb") 224 | if ratingIMDb == None or not isinstance(ratingIMDb, str): 225 | ratingIMDb = "" 226 | webURL = itemData.get("webURL") 227 | if webURL == None or not isinstance(webURL, str): 228 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением webURL.") 229 | 230 | 231 | directors = [] 232 | actors = [] 233 | 234 | creators = itemData.get("creators") 235 | if creators == None or not isinstance(creators, list): 236 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением creators.") 237 | for personsGroup in creators: 238 | if not isinstance(personsGroup, list): 239 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением creators > personsGroup.") 240 | for person in personsGroup: 241 | if not isinstance(person, dict): 242 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением creators > personsGroup > person.") 243 | if person.get("professionKey") == "director": 244 | if person.get("nameRU"): 245 | directors.append(person.get("nameRU")) 246 | if person.get("professionKey") == "actor": 247 | if person.get("nameRU"): 248 | actors.append(person.get("nameRU")) 249 | else: 250 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ".") 251 | 252 | if ratingIMDb and ratingKP: 253 | rating = "{0:.1f}".format((float(ratingKP) + float(ratingIMDb)) / 2.0 + 0.001) 254 | elif ratingKP: 255 | rating = ratingKP 256 | elif ratingIMDb: 257 | rating = ratingIMDb 258 | else: 259 | rating = "0" 260 | 261 | directorsResult = "" 262 | if len(directors) > 0: 263 | for director in directors: 264 | directorsResult += director 265 | directorsResult += ", " 266 | if directorsResult.endswith(", "): 267 | directorsResult = directorsResult[:-2] 268 | 269 | actorsResult = "" 270 | if len(actors) > 0: 271 | for actor in actors: 272 | actorsResult += actor 273 | actorsResult += ", " 274 | if actorsResult.endswith(", "): 275 | actorsResult = actorsResult[:-2] 276 | 277 | result["filmID"] = filmID 278 | result["nameRU"] = nameRU 279 | result["nameOriginal"] = nameEN 280 | result["description"] = description 281 | result["year"] = year 282 | result["country"] = country 283 | result["genre"] = genre 284 | result["ratingAgeLimits"] = ratingAgeLimits 285 | result["posterURL"] = posterURL 286 | result["filmLength"] = filmLength 287 | result["ratingKP"] = ratingKP 288 | result["ratingIMDb"] = ratingIMDb 289 | result["rating"] = rating 290 | result["ratingFloat"] = float(rating) 291 | result["directors"] = directorsResult 292 | result["actors"] = actorsResult 293 | result["webURL"] = webURL 294 | 295 | 296 | #print(result) 297 | 298 | return result 299 | 300 | def rutorLinks(filmID): 301 | print("Загрузка торрент-ссылок для filmID " + filmID + ".") 302 | 303 | if SOCKS_IP: 304 | default_socket = socket.socket 305 | socks.set_default_proxy(socks.SOCKS5, SOCKS_IP, SOCKS_PORT) 306 | socket.socket = socks.socksocket 307 | 308 | request = urllib.request.Request(RUTOR_BASE_URL + filmID) 309 | request.add_header("Accept-encoding", "gzip") 310 | request.add_header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0") 311 | 312 | try: 313 | response = urllib.request.urlopen(request) 314 | except Exception: 315 | print("Ошибка соединения при загрузке торрент-ссылок для filmID " + filmID + ". Даём второй шанс.") 316 | response = urllib.request.urlopen(request) 317 | if response.info().get('Content-Encoding') == 'gzip': 318 | gzipFile = gzip.GzipFile(fileobj=response) 319 | content = gzipFile.read().decode("utf-8") 320 | else: 321 | content = response.read().decode("utf-8") 322 | 323 | if SOCKS_IP: 324 | socket.socket = default_socket 325 | 326 | strIndex = content.find("
") 327 | if strIndex != -1: 328 | content = content[strIndex:] 329 | else: 330 | raise IndexError("Ошибка загрузки торрент-ссылок для filmID " + filmID + ". Не найден блок с торрентами. Возможно, сайт rutor заблокирован.") 331 | 332 | strIndex = content.find("
") 333 | if strIndex != -1: 334 | content = content[:-(len(content) - strIndex)] 335 | else: 336 | raise IndexError("Ошибка загрузки торрент-ссылок для filmID " + filmID + ". Не найден блок с торрентами. Возможно, сайт rutor заблокирован.") 337 | 338 | patternLink = re.compile("") 339 | matches1 = re.findall(patternLink, content) 340 | patternName = re.compile("(.*?)") 341 | matches2 = re.findall(patternName, content) 342 | patternSeeders = re.compile("alt=\"S\" />(.*?)") 343 | matches3 = re.findall(patternSeeders, content) 344 | patternMagnet = re.compile("") 345 | matches4 = re.findall(patternMagnet, content) 346 | patternDate = re.compile("(.*?) result["UHD BDRemux HDR"]["seeders"]: 393 | result["UHD BDRemux HDR"] = item #{"link": item["link"], "magnet": item["magnet"], "seeders": item["seeders"]} 394 | else: 395 | result["UHD BDRemux HDR"] = item 396 | #print("!UHD BDRemux HDR: " + tmpParts[0]) 397 | else: 398 | if result.get("UHD BDRemux SDR") != None: 399 | if item["seeders"] > result["UHD BDRemux SDR"]["seeders"]: 400 | result["UHD BDRemux SDR"] = item 401 | else: 402 | result["UHD BDRemux SDR"] = item 403 | #print("!UHD BDRemux SDR: " + tmpParts[0]) 404 | elif "BDREMUX" in realName: 405 | if result.get("BDRemux") != None: 406 | if item["seeders"] > result["BDRemux"]["seeders"]: 407 | result["BDRemux"] = item 408 | else: 409 | result["BDRemux"] = item 410 | #print("!BDRemux: " + tmpParts[0]) 411 | elif "BDRIP-HEVC 1080" in realName: 412 | if result.get("BDRip-HEVC 1080p") != None: 413 | if item["seeders"] > result["BDRip-HEVC 1080p"]["seeders"]: 414 | result["BDRip-HEVC 1080p"] = item 415 | else: 416 | result["BDRip-HEVC 1080p"] = item 417 | #print("!BDRip-HEVC 1080p: " + tmpParts[0]) 418 | elif "BDRIP 1080" in realName: 419 | if result.get("BDRip 1080p") != None: 420 | if item["seeders"] > result["BDRip 1080p"]["seeders"]: 421 | result["BDRip 1080p"] = item 422 | else: 423 | result["BDRip 1080p"] = item 424 | #print("!BDRip 1080p: " + tmpParts[0]) 425 | elif "WEB-DL 2160" in realName: 426 | if "HDR" in tags: 427 | if result.get("WEB-DL 2160p HDR") != None: 428 | if item["seeders"] > result["WEB-DL 2160p HDR"]["seeders"]: 429 | result["WEB-DL 2160p HDR"] = item 430 | else: 431 | result["WEB-DL 2160p HDR"] = item 432 | #print("!WEB-DL 2160p HDR: " + tmpParts[0]) 433 | else: 434 | if result.get("WEB-DL 2160p SDR") != None: 435 | if item["seeders"] > result["WEB-DL 2160p SDR"]["seeders"]: 436 | result["WEB-DL 2160p SDR"] = item 437 | else: 438 | result["WEB-DL 2160p SDR"] = item 439 | #print("!WEB-DL 2160p SDR: " + tmpParts[0]) 440 | elif "WEB-DL 1080" in realName: 441 | if result.get("WEB-DL 1080p") != None: 442 | if item["seeders"] > result["WEB-DL 1080p"]["seeders"]: 443 | result["WEB-DL 1080p"] = item 444 | else: 445 | result["WEB-DL 1080p"] = item 446 | #print("!WEB-DL 1080p: " + tmpParts[0]) 447 | 448 | if result.get("UHD BDRemux HDR") or result.get("UHD BDRemux SDR") or result.get("BDRip-HEVC 1080p") or result.get("BDRip 1080p"): 449 | result.pop("WEB-DL 2160p HDR", None) 450 | result.pop("WEB-DL 2160p SDR", None) 451 | result.pop("WEB-DL 1080p", None) 452 | 453 | finalResult = [] 454 | 455 | if result.get("WEB-DL 1080p"): 456 | finalResult.append({"link": result["WEB-DL 1080p"]["link"], "magnet": result["WEB-DL 1080p"]["magnet"], "date": result["WEB-DL 1080p"]["date"], "type": "WEB-DL 1080p"}) 457 | if result.get("WEB-DL 2160p HDR"): 458 | finalResult.append({"link": result["WEB-DL 2160p HDR"]["link"], "magnet": result["WEB-DL 2160p HDR"]["magnet"], "date": result["WEB-DL 2160p HDR"]["date"], "type": "WEB-DL 2160p HDR"}) 459 | elif result.get("WEB-DL 2160p SDR"): 460 | finalResult.append({"link": result["WEB-DL 2160p SDR"]["link"], "magnet": result["WEB-DL 2160p SDR"]["magnet"], "date": result["WEB-DL 2160p SDR"]["date"], "type": "WEB-DL 2160p SDR"}) 461 | if result.get("BDRip 1080p"): 462 | finalResult.append({"link": result["BDRip 1080p"]["link"], "magnet": result["BDRip 1080p"]["magnet"], "date": result["BDRip 1080p"]["date"], "type": "BDRip 1080p"}) 463 | if result.get("BDRip-HEVC 1080p"): 464 | finalResult.append({"link": result["BDRip-HEVC 1080p"]["link"], "magnet": result["BDRip-HEVC 1080p"]["magnet"], "date": result["BDRip-HEVC 1080p"]["date"], "type": "BDRip-HEVC 1080p"}) 465 | if result.get("BDRemux"): 466 | finalResult.append({"link": result["BDRemux"]["link"], "magnet": result["BDRemux"]["magnet"], "date": result["BDRemux"]["date"], "type": "BDRemux"}) 467 | if result.get("UHD BDRemux HDR"): 468 | finalResult.append({"link": result["UHD BDRemux HDR"]["link"], "magnet": result["UHD BDRemux HDR"]["magnet"], "date": result["UHD BDRemux HDR"]["date"], "type": "UHD BDRemux HDR"}) 469 | elif result.get("UHD BDRemux SDR"): 470 | finalResult.append({"link": result["UHD BDRemux SDR"]["link"], "magnet": result["UHD BDRemux SDR"]["magnet"], "date": result["UHD BDRemux SDR"]["date"], "type": "UHD BDRemux SDR"}) 471 | 472 | #print(finalResult) 473 | 474 | return finalResult 475 | 476 | def saveHTML(movies, filePath): 477 | f = open(filePath,'w', encoding='utf-8') 478 | html = """ 479 | 480 | 481 | 482 | 483 | Новые цифровые релизы 484 | 737 | 808 | 809 | 810 |
811 |
812 | 813 | 814 | 815 | 816 |
817 |
""" 818 | descriptionTemplate = """ 819 | 820 | {} 821 | 822 |
823 | {} 824 |
825 | 826 | """ 827 | buttonsTemplate = """ """ 828 | movieTemplate = """
829 |
830 |
831 |

{}

832 | {} 833 |
834 |
835 |
836 |
{}
837 | {} 838 |
839 |
840 |
841 | 842 | 843 | {} 844 | 845 |
846 |
847 |
848 |
849 | {} 850 |
851 |
852 | """ 853 | for movie in movies: 854 | #print(movie["nameRU"]) 855 | #print(movie["torrentsDate"]) 856 | #print(movie["releaseDate"]) 857 | 858 | descriptionBlock = "" 859 | descriptionBlock += descriptionTemplate.format("год", movie["year"]) 860 | descriptionBlock += descriptionTemplate.format("страна", movie["country"]) 861 | descriptionBlock += descriptionTemplate.format("режиссёр", movie["directors"]) 862 | descriptionBlock += descriptionTemplate.format("актёры", movie["actors"]) 863 | descriptionBlock += descriptionTemplate.format("жанр", movie["genre"]) 864 | if len(movie["ratingAgeLimits"]) > 0: 865 | if int(movie["ratingAgeLimits"]) <= 6: 866 | descriptionBlock += descriptionTemplate.format("возраст", "от 6 лет") 867 | elif int(movie["ratingAgeLimits"]) <= 12: 868 | descriptionBlock += descriptionTemplate.format("возраст", "от 12 лет") 869 | elif int(movie["ratingAgeLimits"]) <= 16: 870 | descriptionBlock += descriptionTemplate.format("возраст", "от 16 лет") 871 | elif int(movie["ratingAgeLimits"]) <= 18: 872 | descriptionBlock += descriptionTemplate.format("возраст", "от 18 лет") 873 | #descriptionBlock += descriptionTemplate.format("возраст", movie["ratingAgeLimits"] + " и старше") 874 | descriptionBlock += descriptionTemplate.format("продолжительность", movie["filmLength"]) 875 | if len(movie["ratingKP"]) > 0: 876 | rKP = movie["ratingKP"] 877 | else: 878 | rKP = "отсутствует" 879 | descriptionBlock += descriptionTemplate.format("рейтинг КиноПоиск", "
{}".format(movie["webURL"], rKP)) 880 | if len(movie["ratingIMDb"]) > 0: 881 | descriptionBlock += descriptionTemplate.format("рейтинг IMDb", movie["ratingIMDb"]) 882 | descriptionBlock += descriptionTemplate.format("цифровой релиз", movie["releaseDate"].strftime("%d.%m.%Y")) 883 | 884 | descriptionBlock += descriptionTemplate.format("торрент-релиз", "{}".format(RUTOR_BASE_URL + movie["filmID"], movie["torrentsDate"].strftime("%d.%m.%Y"))) 885 | descriptionBlock += descriptionTemplate.format("описание", movie["description"]) 886 | 887 | 888 | torrents = movie["torrents"] 889 | buttonsBlock = "" 890 | for torrent in torrents: 891 | if USE_MAGNET: 892 | buttonsBlock += buttonsTemplate.format(torrent["magnet"], torrent["type"]) 893 | else: 894 | buttonsBlock += buttonsTemplate.format(torrent["link"], torrent["type"]) 895 | 896 | displayOrigName = "display: none;" 897 | if len(movie["nameOriginal"]) > 0: 898 | displayOrigName = "" 899 | 900 | ratingColor = "#aaa" 901 | if movie["ratingFloat"] >= 7: 902 | ratingColor = "#3bb33b" 903 | elif movie["ratingFloat"] < 5.5: 904 | ratingColor = "#b43c3c" 905 | 906 | html += movieTemplate.format(movie["releaseDate"].strftime("%Y-%m-%d"), movie["torrentsDate"].strftime("%Y-%m-%d"), movie["rating"], movie["comboDate"].strftime("%Y-%m-%d"), movie["nameRU"], displayOrigName, movie["nameOriginal"], ratingColor, movie["rating"], movie["posterURL"], movie["nameRU"], descriptionBlock, buttonsBlock) 907 | 908 | html += """
909 |
910 | 911 | """ 912 | f.write(html) 913 | f.close() 914 | return 915 | 916 | def main(): 917 | KINOPOISK_UUID = binascii.b2a_hex(os.urandom(16)) 918 | KINOPOISK_CLIENTID = binascii.b2a_hex(os.urandom(12)) 919 | 920 | releases = digitalReleases(DAYS) 921 | movies = [] 922 | 923 | for release in releases: 924 | torrents = rutorLinks(release["filmID"]) 925 | if len(torrents) == 0: 926 | continue 927 | 928 | dates = [] 929 | for torrent in torrents: 930 | dates.append(torrent["date"]) 931 | dates.sort() 932 | 933 | detail = filmDetail(release["filmID"]) 934 | detail["releaseDate"] = release["releaseDate"] 935 | detail["torrents"] = torrents 936 | detail["torrentsDate"] = dates[0] 937 | detail["comboDate"] = max(release["releaseDate"], dates[0]) 938 | #print(detail["comboDate"]) 939 | movies.append(detail) 940 | 941 | if (SORT_TYPE == "releaseDate"): 942 | movies.sort(key = operator.itemgetter("releaseDate"), reverse = True) 943 | elif (SORT_TYPE == "torrentsDate"): 944 | movies.sort(key = operator.itemgetter("torrentsDate"), reverse = True) 945 | elif (SORT_TYPE == "comboDate"): 946 | movies.sort(key = operator.itemgetter("comboDate"), reverse = True) 947 | else: 948 | movies.sort(key = operator.itemgetter("ratingFloat"), reverse = True) 949 | 950 | saveHTML(movies, HTML_SAVE_PATH) 951 | 952 | main() -------------------------------------------------------------------------------- /digitalreleases2.py: -------------------------------------------------------------------------------- 1 | from bs4 import BeautifulSoup 2 | import hashlib 3 | import datetime 4 | import urllib.request 5 | from urllib.parse import urljoin 6 | from urllib.parse import quote 7 | import time 8 | import gzip 9 | import json 10 | import html 11 | import re 12 | import operator 13 | import os 14 | import binascii 15 | import urllib.parse 16 | import http.cookiejar 17 | import sys 18 | 19 | LOAD_DAYS = 60 20 | USE_MAGNET = True 21 | SORT_TYPE = "torrentsDate" #rating #torrentsDate 22 | MIN_VOTES_KP = 500 23 | MIN_VOTES_IMDB = 1500 24 | HTML_SAVE_PATH = "/opt/share/www/releases.html" 25 | 26 | SOCKS5_IP = "" 27 | SOCKS5_PORT = 9050 28 | if SOCKS5_IP: 29 | import socks 30 | from sockshandler import SocksiPyHandler 31 | 32 | CONNECTION_ATTEMPTS = 3 33 | 34 | RUTOR_BASE_URL = "http://rutor.info" 35 | #RUTOR_BASE_URL = "http://www.rutorc6mqdinc4cz.onion" 36 | RUTOR_MONTHS = {"Янв": 1, "Фев": 2, "Мар": 3, "Апр": 4, "Май": 5, "Июн": 6, "Июл": 7, "Авг": 8, "Сен": 9, "Окт": 10, "Ноя": 11, "Дек": 12} 37 | RUTOR_SEARCH_MAIN = "http://rutor.info/search/{}/{}/300/0/BDRemux|BDRip|(WEB%20DL)%201080p|2160p|1080%D1%80%7C2160%D1%80%7C1080i%20{}" 38 | #RUTOR_SEARCH_MAIN = "http://www.rutorc6mqdinc4cz.onion/search/{}/{}/300/0/BDRemux|BDRip|(WEB%20DL)%201080p|2160p|1080%D1%80%7C2160%D1%80%7C1080i%20{}" 39 | 40 | KINOPOISK_API_IOS_BASE_URL = "https://ma.kinopoisk.ru/ios/5.0.0/" 41 | KINOPOISK_API_V1_BASE_URL = "https://ma.kinopoisk.ru" 42 | KINOPOISK_API_IOS_FILMDETAIL = "getKPFilmDetailView?still_limit=9&filmID={}&uuid={}" 43 | KINOPOISK_API_SALT = "IDATevHDS7" 44 | KINOPOISK_CLIENTID = binascii.b2a_hex(os.urandom(12)).decode('ascii') 45 | KINOPOISK_UUID = binascii.b2a_hex(os.urandom(16)).decode('ascii') 46 | KINOPOISK_POSTER_URL = "https://st.kp.yandex.net/images/{}{}width=360" 47 | 48 | KINOZAL_SEARCH_BDREMUX = "http://kinozal.tv/browse.php?s=%5E{}&g=3&c=0&v=4&d=0&w=0&t=0&f=0" 49 | KINOZAL_SEARCH_BDRIP = "http://kinozal.tv/browse.php?s=%5E{}&g=3&c=0&v=3&d=0&w=0&t=0&f=0" 50 | KINOZAL_USERNAME = "" 51 | KINOZAL_PASSWORD = "" 52 | 53 | def main(): 54 | print("Дата и время запуска программы: " + str(datetime.datetime.now()) + ".") 55 | print("Количество попыток при ошибках соединения: " + str(CONNECTION_ATTEMPTS) + ".") 56 | 57 | if SOCKS5_IP: 58 | print("Для rutor.info и kinozal.tv будет использоваться прокси-сервер SOCKS5: " + SOCKS5_IP + ":" + str(SOCKS5_PORT) + ".") 59 | 60 | print("Проверка доступности rutor.info...") 61 | try: 62 | content = loadRutorContent(RUTOR_SEARCH_MAIN.format(0, 0, ""), useProxy=True) 63 | count = rutorPagesCountForResults(content) 64 | except: 65 | print("Сайт rutor.info недоступен, или изменился его формат данных.") 66 | print("Работа программы принудительно завершена.") 67 | return 1 68 | else: 69 | print("Сайт rutor.info доступен.") 70 | 71 | print("Анализ раздач...") 72 | results = rutorResultsForDays(LOAD_DAYS) 73 | movies = convertRutorResults(results) 74 | movies.sort(key = operator.itemgetter(SORT_TYPE), reverse = True) 75 | saveHTML(movies, HTML_SAVE_PATH) 76 | 77 | if "HTML_SAVE_PATH_LINKS" in globals(): 78 | saveHTML(movies, HTML_SAVE_PATH_LINKS, useMagnet=False) 79 | 80 | print("Работа программы завершена успешно.") 81 | 82 | return 0 83 | 84 | def rutorResultsForDays(days): 85 | targetDate = datetime.date.today() - datetime.timedelta(days=days) 86 | groups = [1, 5, 7, 10] 87 | tmpSet = set() 88 | tmpResults = {} 89 | 90 | for group in groups: 91 | try: 92 | print("Загрузка списка предварительно подходящих раздач...") 93 | content = loadRutorContent(RUTOR_SEARCH_MAIN.format(0, group, ""), useProxy=True) 94 | count = rutorPagesCountForResults(content) 95 | except: 96 | raise ConnectionError ("Ошибка. Не удалось загрузить страницу с результатами поиска или формат данных rutor.info изменился.") 97 | 98 | i = 0 99 | needMore = True 100 | 101 | while needMore: 102 | pageResults = rutorResultsOnPage(content) 103 | for result in pageResults: 104 | #if ("Патрик" in result["name"]): 105 | #print(result["name"]) 106 | if result["date"] >= targetDate: 107 | #print(result["name"]) 108 | #if not ("Шутки в сторону" in result["name"]): 109 | #continue 110 | element = parseRutorElement(result) 111 | if not element: 112 | continue 113 | if (element["compareName"] in tmpSet): 114 | continue 115 | print("Обработка раздачи: {} ({})...".format(element["nameRU"], element["year"])) 116 | try: 117 | elements = rutorSearchSimilarElements(element, group) 118 | elements = rutorFilmIDForElements(elements) 119 | #if len(newElements) == 0: 120 | #pass 121 | except: 122 | raise ConnectionError ("Ошибка. Не удалось загрузить данные похожих раздач или загрузить страницу с описанием.") 123 | tmpSet.add(element["compareName"]) 124 | if len(elements) > 0: 125 | if (tmpResults.get(elements[0]["filmID"])): 126 | tmpResults[elements[0]["filmID"]].extend(elements) 127 | else: 128 | tmpResults[elements[0]["filmID"]] = elements 129 | else: 130 | needMore = False 131 | break 132 | i = i + 1 133 | if (i >= count): 134 | needMore = False 135 | if needMore: 136 | print("Загрузка списка предварительно подходящих раздач...") 137 | try: 138 | content = loadRutorContent(RUTOR_SEARCH_MAIN.format(i, group, ""), useProxy=True) 139 | except: 140 | raise ConnectionError ("Ошибка. Не удалось загрузить страницу с результатами поиска или формат данных rutor.info изменился.") 141 | 142 | return tmpResults 143 | 144 | def convertRutorResults(rutorResults): 145 | targetDate = datetime.date.today() - datetime.timedelta(days=LOAD_DAYS) 146 | #targetDate = datetime.date.today() - datetime.timedelta(days=65) 147 | minPremierDate = datetime.date.today() - datetime.timedelta(days=365) 148 | 149 | movies = [] 150 | 151 | try: 152 | if KINOZAL_USERNAME: 153 | opener = kinozalAuth(KINOZAL_USERNAME, KINOZAL_PASSWORD) 154 | else: 155 | opener = None 156 | except: 157 | opener = None 158 | 159 | for key, values in rutorResults.items(): 160 | BDDate = None 161 | BDDateLicense = None 162 | WBDate = None 163 | for value in values: 164 | if "BD" in value["type"]: 165 | if value["license"]: 166 | if not BDDateLicense: 167 | BDDateLicense = value["date"] 168 | else: 169 | BDDateLicense = min(BDDateLicense, value["date"]) 170 | else: 171 | if not BDDate: 172 | BDDate = value["date"] 173 | else: 174 | BDDate = min(BDDate, value["date"]) 175 | else: 176 | if not WBDate: 177 | WBDate = value["date"] 178 | else: 179 | WBDate = min(WBDate, value["date"]) 180 | if BDDateLicense: 181 | if BDDateLicense < targetDate: 182 | continue 183 | elif BDDate: 184 | if BDDate < targetDate: 185 | continue 186 | else: 187 | if WBDate < targetDate: 188 | continue 189 | 190 | tr = {} 191 | 192 | for value in values: 193 | if value["type"] == "UHD BDRemux": 194 | if value["hdr"]: 195 | if tr.get("UHD BDRemux HDR") != None: 196 | if ((not tr["UHD BDRemux HDR"]["license"]) and value["license"]): 197 | tr["UHD BDRemux HDR"] = value 198 | elif (tr["UHD BDRemux HDR"]["license"] == False and value["license"] == False) or (tr["UHD BDRemux HDR"]["license"] == True and value["license"] == True): 199 | if value["seeders"] > tr["UHD BDRemux HDR"]["seeders"]: 200 | tr["UHD BDRemux HDR"] = value 201 | else: 202 | tr["UHD BDRemux HDR"] = value 203 | else: 204 | if tr.get("UHD BDRemux SDR") != None: 205 | if ((not tr["UHD BDRemux SDR"]["license"]) and value["license"]): 206 | tr["UHD BDRemux SDR"] = value 207 | elif (tr["UHD BDRemux SDR"]["license"] == False and value["license"] == False) or (tr["UHD BDRemux SDR"]["license"] == True and value["license"] == True): 208 | if value["seeders"] > tr["UHD BDRemux SDR"]["seeders"]: 209 | tr["UHD BDRemux SDR"] = value 210 | else: 211 | tr["UHD BDRemux SDR"] = value 212 | elif value["type"] == "BDRemux": 213 | if tr.get("BDRemux") != None: 214 | if ((not tr["BDRemux"]["license"]) and value["license"]): 215 | tr["BDRemux"] = value 216 | elif (tr["BDRemux"]["license"] == False and value["license"] == False) or (tr["BDRemux"]["license"] == True and value["license"] == True): 217 | if value["seeders"] > tr["BDRemux"]["seeders"]: 218 | tr["BDRemux"] = value 219 | else: 220 | tr["BDRemux"] = value 221 | elif value["type"] == "BDRip-HEVC": 222 | if tr.get("BDRip-HEVC 1080p") != None: 223 | if ((not tr["BDRip-HEVC 1080p"]["license"]) and value["license"]): 224 | tr["BDRip-HEVC 1080p"] = value 225 | elif (tr["BDRip-HEVC 1080p"]["license"] == False and value["license"] == False) or (tr["BDRip-HEVC 1080p"]["license"] == True and value["license"] == True): 226 | if value["seeders"] > tr["BDRip-HEVC 1080p"]["seeders"]: 227 | tr["BDRip-HEVC 1080p"] = value 228 | else: 229 | tr["BDRip-HEVC 1080p"] = value 230 | elif value["type"] == "BDRip": 231 | if tr.get("BDRip 1080p") != None: 232 | if ((not tr["BDRip 1080p"]["license"]) and value["license"]): 233 | tr["BDRip 1080p"] = value 234 | elif (tr["BDRip 1080p"]["license"] == False and value["license"] == False) or (tr["BDRip 1080p"]["license"] == True and value["license"] == True): 235 | if value["seeders"] > tr["BDRip 1080p"]["seeders"]: 236 | tr["BDRip 1080p"] = value 237 | else: 238 | tr["BDRip 1080p"] = value 239 | elif value["type"] == "WEB-DL": 240 | if value["resolution"] == "2160p": 241 | if value["hdr"]: 242 | if tr.get("WEB-DL 2160p HDR") != None: 243 | if ((not tr["WEB-DL 2160p HDR"]["license"]) and value["license"]): 244 | tr["WEB-DL 2160p HDR"] = value 245 | elif (tr["WEB-DL 2160p HDR"]["license"] == False and value["license"] == False) or (tr["WEB-DL 2160p HDR"]["license"] == True and value["license"] == True): 246 | if value["seeders"] > tr["WEB-DL 2160p HDR"]["seeders"]: 247 | tr["WEB-DL 2160p HDR"] = value 248 | else: 249 | tr["WEB-DL 2160p HDR"] = value 250 | else: 251 | if tr.get("WEB-DL 2160p SDR") != None: 252 | if ((not tr["WEB-DL 2160p SDR"]["license"]) and value["license"]): 253 | tr["WEB-DL 2160p SDR"] = value 254 | elif (tr["WEB-DL 2160p SDR"]["license"] == False and value["license"] == False) or (tr["WEB-DL 2160p SDR"]["license"] == True and value["license"] == True): 255 | if value["seeders"] > tr["WEB-DL 2160p SDR"]["seeders"]: 256 | tr["WEB-DL 2160p SDR"] = value 257 | else: 258 | tr["WEB-DL 2160p SDR"] = value 259 | else: 260 | if tr.get("WEB-DL 1080p") != None: 261 | if ((not tr["WEB-DL 1080p"]["license"]) and value["license"]): 262 | tr["WEB-DL 1080p"] = value 263 | elif (tr["WEB-DL 1080p"]["license"] == False and value["license"] == False) or (tr["WEB-DL 1080p"]["license"] == True and value["license"] == True): 264 | if value["seeders"] > tr["WEB-DL 1080p"]["seeders"]: 265 | tr["WEB-DL 1080p"] = value 266 | else: 267 | tr["WEB-DL 1080p"] = value 268 | 269 | if tr.get("UHD BDRemux HDR") or tr.get("UHD BDRemux SDR") or tr.get("BDRip-HEVC 1080p") or tr.get("BDRip 1080p") or tr.get("BDRemux"): 270 | tr.pop("WEB-DL 2160p HDR", None) 271 | tr.pop("WEB-DL 2160p SDR", None) 272 | tr.pop("WEB-DL 1080p", None) 273 | 274 | if tr.get("UHD BDRemux HDR"): 275 | tr.pop("UHD BDRemux SDR", None) 276 | 277 | print("Загрузка данных для фильма с ID " + values[0]["filmID"] + "...") 278 | try: 279 | detail = filmDetail(values[0]["filmID"]) 280 | except: 281 | print("Загрузка не удалась. Пропуск фильма с ID " + values[0]["filmID"] + ".") 282 | 283 | print("Загружены данные для фильма: " + detail["nameRU"] + ".") 284 | 285 | if not detail.get("premierDate"): 286 | print("У фильма \"" + detail["nameRU"] + "\" нет даты премьеры. Пропуск фильма.") 287 | continue 288 | if detail["premierDate"] < minPremierDate: 289 | print("Фильм \"" + detail["nameRU"] + "\" слишком старый. Пропуск фильма.") 290 | continue 291 | 292 | finalResult = [] 293 | 294 | if (tr.get("WEB-DL 1080p") or tr.get("WEB-DL 2160p HDR") or tr.get("WEB-DL 2160p SDR")) and opener: 295 | print("Пробуем найти отсутствующий BDRip 1080p на kinozal.tv...") 296 | kName = detail["nameRU"] 297 | kNameOriginal = detail["nameOriginal"] 298 | if not kNameOriginal: 299 | kNameOriginal = kName 300 | try: 301 | kRes = kinozalSearch({"nameRU" : kName, "nameOriginal":kNameOriginal, "year": detail["year"]}, opener, "BDRip 1080p") 302 | if kRes: 303 | print("Отсутствующий BDRip 1080p найден на kinozal.tv.") 304 | finalResult.append(kRes) 305 | tr.pop("WEB-DL 2160p HDR", None) 306 | tr.pop("WEB-DL 2160p SDR", None) 307 | tr.pop("WEB-DL 1080p", None) 308 | if kRes["license"]: 309 | BDDateLicense = kRes["date"] 310 | else: 311 | BDDate = kRes["date"] 312 | except: 313 | print("Какая-то ошибка при работе с kinozal.tv. Подробная информация о проблемах ещё не добавлена в функцию.") 314 | if tr.get("WEB-DL 1080p"): 315 | finalResult.append({"link": tr["WEB-DL 1080p"]["fileLink"], "magnet": tr["WEB-DL 1080p"]["magnetLink"], "date": tr["WEB-DL 1080p"]["date"], "type": "WEB-DL 1080p", "license": tr["WEB-DL 1080p"]["license"]}) 316 | if tr.get("WEB-DL 2160p HDR"): 317 | finalResult.append({"link": tr["WEB-DL 2160p HDR"]["fileLink"], "magnet": tr["WEB-DL 2160p HDR"]["magnetLink"], "date": tr["WEB-DL 2160p HDR"]["date"], "type": "WEB-DL 2160p HDR", "license": tr["WEB-DL 2160p HDR"]["license"]}) 318 | elif tr.get("WEB-DL 2160p SDR"): 319 | finalResult.append({"link": tr["WEB-DL 2160p SDR"]["fileLink"], "magnet": tr["WEB-DL 2160p SDR"]["magnetLink"], "date": tr["WEB-DL 2160p SDR"]["date"], "type": "WEB-DL 2160p SDR", "license": tr["WEB-DL 2160p SDR"]["license"]}) 320 | if tr.get("BDRip 1080p"): 321 | finalResult.append({"link": tr["BDRip 1080p"]["fileLink"], "magnet": tr["BDRip 1080p"]["magnetLink"], "date": tr["BDRip 1080p"]["date"], "type": "BDRip 1080p", "license": tr["BDRip 1080p"]["license"]}) 322 | elif (tr.get("BDRip-HEVC 1080p") or tr.get("BDRemux")) and opener: 323 | print("Пробуем найти отсутствующий BDRip 1080p на kinozal.tv...") 324 | kName = detail["nameRU"] 325 | kNameOriginal = detail["nameOriginal"] 326 | if not kNameOriginal: 327 | kNameOriginal = kName 328 | try: 329 | kRes = kinozalSearch({"nameRU" : kName, "nameOriginal":kNameOriginal, "year": detail["year"]}, opener, "BDRip 1080p") 330 | if kRes: 331 | print("Отсутствующий BDRip 1080p найден на kinozal.tv.") 332 | finalResult.append(kRes) 333 | except: 334 | print("Какая-то ошибка при работе с kinozal.tv. Подробная информация о проблемах ещё не добавлена в функцию.") 335 | if tr.get("BDRip-HEVC 1080p"): 336 | 337 | found = False 338 | 339 | try: 340 | if (not tr["BDRip-HEVC 1080p"]["license"]) and tr["BDRip 1080p"]["license"]: 341 | kName = detail["nameRU"] 342 | kNameOriginal = detail["nameOriginal"] 343 | if not kNameOriginal: 344 | kNameOriginal = kName 345 | kRes = kinozalSearch({"nameRU" : kName, "nameOriginal":kNameOriginal, "year": detail["year"]}, opener, "BDRip-HEVC 1080p", licenseOnly = True) 346 | if kRes: 347 | found = True 348 | finalResult.append(kRes) 349 | except: 350 | pass 351 | 352 | if not found: 353 | finalResult.append({"link": tr["BDRip-HEVC 1080p"]["fileLink"], "magnet": tr["BDRip-HEVC 1080p"]["magnetLink"], "date": tr["BDRip-HEVC 1080p"]["date"], "type": "BDRip-HEVC 1080p", "license": tr["BDRip-HEVC 1080p"]["license"]}) 354 | elif (tr.get("BDRip 1080p") or tr.get("BDRemux")) and opener: 355 | print("Пробуем найти отсутствующий BDRip-HEVC 1080p на kinozal.tv...") 356 | kName = detail["nameRU"] 357 | kNameOriginal = detail["nameOriginal"] 358 | if not kNameOriginal: 359 | kNameOriginal = kName 360 | try: 361 | kRes = kinozalSearch({"nameRU" : kName, "nameOriginal":kNameOriginal, "year": detail["year"]}, opener, "BDRip-HEVC 1080p") 362 | if kRes: 363 | print("Отсутствующий BDRip-HEVC 1080p найден на kinozal.tv.") 364 | finalResult.append(kRes) 365 | except: 366 | print("Какая-то ошибка при работе с kinozal.tv. Подробная информация о проблемах ещё не добавлена в функцию.") 367 | if tr.get("BDRemux"): 368 | found = False 369 | 370 | try: 371 | if (not tr["BDRemux"]["license"]) and tr["BDRip 1080p"]["license"]: 372 | kName = detail["nameRU"] 373 | kNameOriginal = detail["nameOriginal"] 374 | if not kNameOriginal: 375 | kNameOriginal = kName 376 | kRes = kinozalSearch({"nameRU" : kName, "nameOriginal":kNameOriginal, "year": detail["year"]}, opener, "BDRemux", licenseOnly = True) 377 | if kRes: 378 | found = True 379 | finalResult.append(kRes) 380 | except: 381 | pass 382 | 383 | if not found: 384 | finalResult.append({"link": tr["BDRemux"]["fileLink"], "magnet": tr["BDRemux"]["magnetLink"], "date": tr["BDRemux"]["date"], "type": "BDRemux", "license": tr["BDRemux"]["license"]}) 385 | elif (tr.get("BDRip-HEVC 1080p") or tr.get("BDRip 1080p")) and opener: 386 | print("Пробуем найти отсутствующий BDRemux на kinozal.tv...") 387 | kName = detail["nameRU"] 388 | kNameOriginal = detail["nameOriginal"] 389 | if not kNameOriginal: 390 | kNameOriginal = kName 391 | try: 392 | kRes = kinozalSearch({"nameRU" : kName, "nameOriginal":kNameOriginal, "year": detail["year"]}, opener, "BDRemux") 393 | if kRes: 394 | print("Отсутствующий BDRemux найден на kinozal.tv.") 395 | finalResult.append(kRes) 396 | except: 397 | print("Какая-то ошибка при работе с kinozal.tv. Подробная информация о проблемах ещё не добавлена в функцию.") 398 | if tr.get("UHD BDRemux HDR"): 399 | finalResult.append({"link": tr["UHD BDRemux HDR"]["fileLink"], "magnet": tr["UHD BDRemux HDR"]["magnetLink"], "date": tr["UHD BDRemux HDR"]["date"], "type": "UHD BDRemux HDR", "license": tr["UHD BDRemux HDR"]["license"]}) 400 | elif tr.get("UHD BDRemux SDR"): 401 | finalResult.append({"link": tr["UHD BDRemux SDR"]["fileLink"], "magnet": tr["UHD BDRemux SDR"]["magnetLink"], "date": tr["UHD BDRemux SDR"]["date"], "type": "UHD BDRemux SDR", "license": tr["UHD BDRemux SDR"]["license"]}) 402 | 403 | dates = [] 404 | for torrent in finalResult: 405 | dates.append(torrent["date"]) 406 | dates.sort() 407 | 408 | detail["torrents"] = finalResult 409 | detail["torrentsDate"] = dates[0] 410 | if BDDateLicense: 411 | detail["torrentsDate"] = BDDateLicense 412 | detail["torrentsDateType"] = "Blu-ray с официальным русским озвучиванием ★" 413 | elif BDDate: 414 | detail["torrentsDate"] = BDDate 415 | detail["torrentsDateType"] = "Blu-ray с официальным русским озвучиванием из VoD" 416 | else: 417 | detail["torrentsDate"] = WBDate 418 | detail["torrentsDateType"] = "VoD с официальным русским озвучиванием" 419 | movies.append(detail) 420 | 421 | return movies 422 | 423 | def loadRutorContent(URL, attempts=CONNECTION_ATTEMPTS, useProxy=False): 424 | headers = {} 425 | headers["Accept-encoding"] = "gzip" 426 | headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0" 427 | 428 | return loadURLContent(URL, headers=headers, attempts=attempts, useProxy=useProxy) 429 | 430 | def rutorPagesCountForResults(content): 431 | soup = BeautifulSoup(content, 'html.parser') 432 | 433 | if (soup == None): 434 | raise ValueError("Ошибка. Невозможно инициализировать HTML-парсер, что-то не так с контентом.") 435 | 436 | try: 437 | resultsGroup = soup.find("div", id="index") 438 | except: 439 | raise ValueError("Ошибка. Нет блока с торрентами.") 440 | if resultsGroup == None: 441 | raise ValueError("Ошибка. Нет блока с торрентами.") 442 | 443 | try: 444 | indexes = [text for text in resultsGroup.b.stripped_strings] 445 | except: 446 | raise ValueError("Ошибка. Нет блока со страницами результатов.") 447 | if len(indexes) == 0: 448 | raise ValueError("Ошибка. Нет блока со страницами результатов.") 449 | 450 | lastIndexStr = indexes[-1] 451 | if lastIndexStr.startswith("Страницы"): 452 | return 1 453 | 454 | lastIndex = int(lastIndexStr) 455 | 456 | if lastIndex <= 0: 457 | raise ValueError("Ошибка. Неверное значение индекса страницы.") 458 | 459 | return lastIndex 460 | 461 | def loadURLContent(url, headers={}, attempts=CONNECTION_ATTEMPTS, useProxy=False): 462 | if useProxy and SOCKS5_IP: 463 | proxyHandler = SocksiPyHandler(socks.PROXY_TYPE_SOCKS5, SOCKS5_IP, SOCKS5_PORT) 464 | opener = urllib.request.build_opener(proxyHandler) 465 | else: 466 | opener = urllib.request.build_opener() 467 | 468 | request = urllib.request.Request(url, headers=headers) 469 | response=None 470 | n = attempts 471 | while n > 0: 472 | try: 473 | response = opener.open(request) 474 | break 475 | except: 476 | n = n - 1 477 | if (n <= 0): 478 | raise ConnectionError("Ошибка соединения. Все попытки соединения израсходованы.") 479 | 480 | if response.info().get("Content-Encoding") == "gzip": 481 | gzipFile = gzip.GzipFile(fileobj=response) 482 | content = gzipFile.read().decode("utf-8") 483 | else: 484 | content = response.read().decode("utf-8") 485 | 486 | return content 487 | 488 | def kinopoiskRating(filmID, useProxy = False): 489 | result = {} 490 | 491 | headers = {} 492 | headers["Accept-encoding"] = "gzip" 493 | headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0" 494 | 495 | if useProxy and SOCKS5_IP: 496 | proxyHandler = SocksiPyHandler(socks.PROXY_TYPE_SOCKS5, SOCKS5_IP, SOCKS5_PORT) 497 | opener = urllib.request.build_opener(proxyHandler) 498 | else: 499 | opener = urllib.request.build_opener() 500 | 501 | request = urllib.request.Request("https://rating.kinopoisk.ru/{}.xml".format(filmID), headers=headers) 502 | response = opener.open(request) 503 | if response.info().get("Content-Encoding") == "gzip": 504 | gzipFile = gzip.GzipFile(fileobj=response) 505 | content = gzipFile.read().decode(response.info().get_content_charset()) 506 | else: 507 | content = response.read().decode(response.info().get_content_charset()) 508 | 509 | patternKP = re.compile("([0-9]*\.[0-9]*)") 510 | matches = re.findall(patternKP, content) 511 | 512 | if len(matches) == 1: 513 | result["rating"] = matches[0][1] 514 | result["ratingVoteCount"] = matches[0][0] 515 | 516 | patternIMDb = re.compile("([0-9]*\.[0-9]*)") 517 | matches = re.findall(patternIMDb, content) 518 | 519 | if len(matches) == 1: 520 | result["ratingIMDb"] = matches[0][1] 521 | result["ratingIMDbVoteCount"] = matches[0][0] 522 | 523 | return result 524 | 525 | def filmDetail(filmID): 526 | result = {} 527 | content = None 528 | 529 | try: 530 | content = loadKinopoiskContent(KINOPOISK_API_IOS_BASE_URL, KINOPOISK_API_IOS_FILMDETAIL.format(filmID, KINOPOISK_UUID)) 531 | except: 532 | pass 533 | 534 | if content: 535 | tmpDict = json.loads(content) 536 | 537 | if tmpDict == None or not isinstance(tmpDict, dict): 538 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Ответ не соответствует JSON.") 539 | if tmpDict.get("resultCode") != 0: 540 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". В ответе нет значения resultCode или оно не равно 0.") 541 | itemData = tmpDict.get("data") 542 | if itemData == None or not isinstance(itemData, dict): 543 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением data.") 544 | nameRU = itemData.get("nameRU") 545 | if nameRU == None or not isinstance(nameRU, str): 546 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением nameRU.") 547 | nameEN = itemData.get("nameEN") 548 | if nameEN == None or not isinstance(nameEN, str): 549 | nameEN = "" 550 | year = itemData.get("year") 551 | if year == None or not isinstance(year, str): 552 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением year.") 553 | country = itemData.get("country") 554 | if country == None or not isinstance(country, str): 555 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением country.") 556 | genre = itemData.get("genre") 557 | if genre == None or not isinstance(genre, str): 558 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением genre.") 559 | description = itemData.get("description") 560 | if description == None or not isinstance(description, str): 561 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением description.") 562 | ratingAgeLimits = itemData.get("ratingAgeLimits") 563 | if ratingAgeLimits == None or not isinstance(ratingAgeLimits, str): 564 | ratingAgeLimits = "" 565 | ratingMPAA = itemData.get("ratingMPAA") 566 | if ratingMPAA == None or not isinstance(ratingMPAA, str): 567 | ratingMPAA = "" 568 | posterURL = itemData.get("posterURL") 569 | if posterURL == None or not isinstance(posterURL, str): 570 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением posterURL.") 571 | if "?" in posterURL: 572 | posterURL = KINOPOISK_POSTER_URL.format(posterURL, "&") 573 | else: 574 | posterURL = KINOPOISK_POSTER_URL.format(posterURL, "?") 575 | filmLength = itemData.get("filmLength") 576 | if filmLength == None or not isinstance(filmLength, str): 577 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением filmLength.") 578 | ratingData = itemData.get("ratingData") 579 | if ratingData == None or not isinstance(ratingData, dict): 580 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением ratingData.") 581 | ratingKP = ratingData.get("rating") 582 | if ratingKP == None or not isinstance(ratingKP, str): 583 | ratingKP = "" 584 | ratingKPCount = ratingData.get("ratingVoteCount") 585 | if ratingKPCount == None or not isinstance(ratingKPCount, str): 586 | ratingKPCount = "0" 587 | ratingKPCount = ratingKPCount.replace(" ", "") 588 | try: 589 | ratingKPCount = int(ratingKPCount) 590 | except: 591 | ratingKPCount = 0 592 | if ratingKPCount < MIN_VOTES_KP: 593 | ratingKP = "" 594 | ratingIMDb = ratingData.get("ratingIMDb") 595 | if ratingIMDb == None or not isinstance(ratingIMDb, str): 596 | ratingIMDb = "" 597 | ratingIMDbCount = ratingData.get("ratingIMDbVoteCount") 598 | if ratingIMDbCount == None or not isinstance(ratingIMDbCount, str): 599 | ratingIMDbCount = "0" 600 | ratingIMDbCount = ratingIMDbCount.replace(" ", "") 601 | try: 602 | ratingIMDbCount = int(ratingIMDbCount) 603 | except: 604 | ratingIMDbCount = 0 605 | if ratingIMDbCount < MIN_VOTES_IMDB: 606 | ratingIMDb = "" 607 | webURL = itemData.get("webURL") 608 | if webURL == None or not isinstance(webURL, str): 609 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением webURL.") 610 | rentData = itemData.get("rentData") 611 | if rentData == None or not isinstance(rentData, dict): 612 | rentData = {} 613 | premiereRU = rentData.get("premiereRU") 614 | if not isinstance(premiereRU, str): 615 | premiereRU = None 616 | premiereWorld = rentData.get("premiereWorld") 617 | if not isinstance(premiereWorld, str): 618 | premiereWorld = None 619 | premiereDigital = rentData.get("premiereDigital") 620 | if not isinstance(premiereDigital, str): 621 | premiereDigital = None 622 | premierDate = None 623 | premierType = None 624 | if (not premierDate) and premiereRU: 625 | premierDate = datetime.datetime.strptime(premiereRU, "%d.%m.%Y").date() 626 | premierType = "ru" 627 | if (not premierDate) and premiereWorld: 628 | premierDate = datetime.datetime.strptime(premiereWorld, "%d.%m.%Y").date() 629 | premierType = "world" 630 | if (not premierDate) and premiereDigital: 631 | premierDate = datetime.datetime.strptime(premiereDigital, "%d.%m.%Y").date() 632 | premierType = "digital" 633 | videoURL = itemData.get("videoURL") 634 | if videoURL == None or not isinstance(videoURL, dict): 635 | videoURL == "" 636 | else: 637 | hdLink = videoURL.get("hd") 638 | if hdLink == None or not isinstance(hdLink, str): 639 | videoURL == "" 640 | else: 641 | videoURL = hdLink 642 | 643 | directors = [] 644 | actors = [] 645 | 646 | creators = itemData.get("creators") 647 | if creators == None or not isinstance(creators, list): 648 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением creators.") 649 | for personsGroup in creators: 650 | if not isinstance(personsGroup, list): 651 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением creators > personsGroup.") 652 | for person in personsGroup: 653 | if not isinstance(person, dict): 654 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ". Проблемы со значением creators > personsGroup > person.") 655 | if person.get("professionKey") == "director": 656 | if person.get("nameRU"): 657 | directors.append(person.get("nameRU")) 658 | if person.get("professionKey") == "actor": 659 | if person.get("nameRU"): 660 | actors.append(person.get("nameRU")) 661 | else: 662 | raise ValueError("Ошибка загрузки данных для filmID " + filmID + ".") 663 | 664 | freshRating = {} 665 | try: 666 | freshRating = kinopoiskRating(filmID) 667 | except: 668 | pass 669 | 670 | if freshRating.get("rating") and freshRating.get("ratingVoteCount"): 671 | ratingKP = freshRating.get("rating") 672 | ratingKPCount = freshRating.get("ratingVoteCount") 673 | try: 674 | ratingKP = "{0:.1f}".format(float(ratingKP)) 675 | ratingKPCount = int(ratingKPCount) 676 | except: 677 | ratingKPCount = 0 678 | if ratingKPCount < MIN_VOTES_KP: 679 | ratingKP = "" 680 | 681 | if freshRating.get("ratingIMDb") and freshRating.get("ratingIMDbVoteCount"): 682 | ratingIMDb = freshRating.get("ratingIMDb") 683 | ratingIMDbCount = freshRating.get("ratingIMDbVoteCount") 684 | try: 685 | ratingIMDb = "{0:.1f}".format(float(ratingIMDb)) 686 | ratingIMDbCount = int(ratingIMDbCount) 687 | except: 688 | ratingIMDbCount = 0 689 | if ratingIMDbCount < MIN_VOTES_IMDB: 690 | ratingIMDb = "" 691 | 692 | if ratingIMDb and ratingKP: 693 | rating = "{0:.1f}".format((float(ratingKP) + float(ratingIMDb)) / 2.0 + 0.001) 694 | elif ratingKP: 695 | rating = ratingKP 696 | elif ratingIMDb: 697 | rating = ratingIMDb 698 | else: 699 | rating = "0" 700 | 701 | directorsResult = "" 702 | if len(directors) > 0: 703 | for director in directors: 704 | directorsResult += director 705 | directorsResult += ", " 706 | if directorsResult.endswith(", "): 707 | directorsResult = directorsResult[:-2] 708 | 709 | actorsResult = "" 710 | if len(actors) > 0: 711 | for actor in actors: 712 | actorsResult += actor 713 | actorsResult += ", " 714 | if actorsResult.endswith(", "): 715 | actorsResult = actorsResult[:-2] 716 | 717 | result["filmID"] = filmID 718 | result["nameRU"] = nameRU 719 | result["nameOriginal"] = nameEN 720 | result["description"] = description 721 | result["year"] = year 722 | result["country"] = country 723 | result["genre"] = genre 724 | result["ratingAgeLimits"] = ratingAgeLimits 725 | result["ratingMPAA"] = ratingMPAA 726 | result["posterURL"] = posterURL 727 | result["filmLength"] = filmLength 728 | result["ratingKP"] = ratingKP 729 | result["ratingKPCount"] = ratingKPCount 730 | result["ratingIMDb"] = ratingIMDb 731 | result["ratingIMDbCount"] = ratingIMDbCount 732 | result["rating"] = rating 733 | result["ratingFloat"] = float(rating) 734 | result["directors"] = directorsResult 735 | result["actors"] = actorsResult 736 | result["webURL"] = webURL 737 | result["trailerURL"] = videoURL 738 | if premierDate: 739 | result["premierDate"] = premierDate 740 | result["premierType"] = premierType 741 | 742 | return result 743 | 744 | def convertToAlfaNum(str): 745 | tmpStr = str.upper() 746 | tmpList = [] 747 | for c in tmpStr: 748 | if c.isalnum(): 749 | tmpList.append(c) 750 | else: 751 | tmpList.append(" ") 752 | 753 | return " ".join("".join(tmpList).split()) 754 | 755 | def replaceSimilarChars(str): 756 | tmpStr = str.upper() 757 | tmpStr = tmpStr.replace("A", "А") 758 | tmpStr = tmpStr.replace("B", "В") 759 | tmpStr = tmpStr.replace("C", "С") 760 | tmpStr = tmpStr.replace("E", "Е") 761 | tmpStr = tmpStr.replace("H", "Н") 762 | tmpStr = tmpStr.replace("K", "К") 763 | tmpStr = tmpStr.replace("M", "М") 764 | tmpStr = tmpStr.replace("O", "О") 765 | tmpStr = tmpStr.replace("P", "Р") 766 | tmpStr = tmpStr.replace("T", "Т") 767 | tmpStr = tmpStr.replace("X", "Х") 768 | tmpStr = tmpStr.replace("Y", "У") 769 | tmpStr = tmpStr.replace("Ё", "Е") 770 | 771 | return tmpStr 772 | 773 | def parseRutorElement(dict): 774 | tmpParts = dict["name"].split("|") 775 | 776 | fullName = tmpParts[0].strip().upper() 777 | tags = set() 778 | tagsStr = "" 779 | 780 | if len(tmpParts) > 1: 781 | for i in range(1, len(tmpParts)): 782 | moreParts = tmpParts[i].split(",") 783 | for tmpPart in moreParts: 784 | tags.add(tmpPart.strip().upper()) 785 | tagsStr = tagsStr + tmpPart.strip().upper() + " " 786 | 787 | if ("LINE" in tags) or ("UKR" in tags) or ("3D-VIDEO" in tags) or ("60 FPS" in tags) or (("1080" in fullName) and ("HDR" in tags)) or ("UHD BDRIP" in fullName) or ("[" in fullName) or ("]" in fullName): 788 | return None 789 | 790 | patternYear = re.compile("\((\d{4})\)") 791 | match = re.search(patternYear, tmpParts[0]) 792 | 793 | if not match: 794 | return None 795 | 796 | year = match[1] 797 | targetYear = (datetime.date.today() - datetime.timedelta(days=365)).year 798 | if int(year) < targetYear: 799 | return None 800 | 801 | namesPart = (tmpParts[0][:match.start()]).strip() 802 | typePart = (tmpParts[0][match.end():]).strip().upper() 803 | names = namesPart.split("/") 804 | RU = True if len(names) == 1 else False 805 | nameRU = names[0].strip() 806 | names.pop(0) 807 | if len(names) > 0: 808 | nameOriginal = names[-1] 809 | else: 810 | nameOriginal = nameRU 811 | 812 | if not RU: 813 | if not (("ЛИЦЕНЗИЯ" in tags) or ("ITUNES" in tags) or ("D" in tags) or ("D1" in tags) or ("D2" in tags) or ("НЕВАФИЛЬМ" in tags) or ("ПИФАГОР" in tags) or ("AMEDIA" in tags) or ("МОСФИЛЬМ-МАСТЕР" in tags) or ("СВ-ДУБЛЬ" in tags) or ("КИРИЛЛИЦА" in tags) or ("АРК-ТВ" in tagsStr) or ("APK-ТВ" in tagsStr) or ("APK-TB" in tagsStr)): 814 | return None 815 | 816 | license = True if ("ЛИЦЕНЗИЯ" in tags) else False 817 | 818 | if "UHD BDREMUX" in typePart: 819 | type = "UHD BDRemux" 820 | elif "BDREMUX" in typePart: 821 | type = "BDRemux" 822 | elif "BDRIP-HEVC" in typePart: 823 | type = "BDRip-HEVC" 824 | elif "BDRIP" in typePart: 825 | type = "BDRip" 826 | elif "WEB-DL " in typePart: 827 | type = "WEB-DL" 828 | elif "WEB-DL-HEVC" in typePart: 829 | #type = "WEB-DL-HEVC" 830 | type = "WEB-DL" 831 | else: 832 | return None 833 | 834 | hdr = False 835 | 836 | if "2160" in typePart: 837 | resolution = "2160p" 838 | hdr = True if ("HDR" in tags) else False 839 | elif "1080I" in typePart: 840 | resolution = "1080i" 841 | elif ("1080P" in typePart) or ("1080Р" in typePart): 842 | resolution = "1080p" 843 | else: 844 | return None 845 | 846 | IMAX = True if (("IMAX" in tags) or ("IMAX EDITION" in tags)) else False 847 | OpenMatte = True if ("OPEN MATTE" in tags) else False 848 | 849 | if RU: 850 | compareName = replaceSimilarChars(convertToAlfaNum(nameRU)) + " " + year 851 | searchPattern = "(^" + convertToAlfaNum(nameRU) + " " + year + ")|(^" + compareName + ")" 852 | else: 853 | compareName = replaceSimilarChars(convertToAlfaNum(nameRU)) + " " + convertToAlfaNum(nameOriginal) + " " + year 854 | searchPattern = "(^" + convertToAlfaNum(nameRU) + " " + convertToAlfaNum(nameOriginal) + " " + year + ")|(^" + compareName + ")" 855 | if len(searchPattern) > 130: 856 | searchPattern = "(^" + convertToAlfaNum(nameRU) + " " + convertToAlfaNum(nameOriginal) + " " + year + ")" 857 | searchPattern = searchPattern.replace("AND", "and") 858 | searchPattern = searchPattern.replace("OR", "or") 859 | 860 | result = {"date": dict["date"], "torrentName": dict["name"], "fileLink": dict["fileLink"], "magnetLink": dict["magnetLink"], "descriptionLink": dict["descriptionLink"], "size": dict["size"], "seeders": dict["seeders"], "leechers": dict["leechers"], "nameOriginal": nameOriginal, "nameRU": nameRU, "compareName": compareName, "searchPattern": searchPattern, "year": year, "type": type, "resolution": resolution, "hdr": hdr, "IMAX": IMAX, "OpenMatte": OpenMatte, "license": license} 861 | 862 | return result 863 | 864 | def rutorSearchSimilarElements(element, group): 865 | results = [] 866 | #print(RUTOR_SEARCH_MAIN.format(0, group, quote(element["searchPattern"]))) 867 | content = loadRutorContent(RUTOR_SEARCH_MAIN.format(0, group, quote(element["searchPattern"])), useProxy=True) 868 | try: 869 | pageResults = rutorResultsOnPage(content) 870 | except: 871 | #print(RUTOR_SEARCH_MAIN.format(0, group, quote(element["searchPattern"]))) 872 | return results 873 | 874 | for result in pageResults: 875 | tmpElement = parseRutorElement(result) 876 | if not tmpElement: 877 | continue 878 | if tmpElement["compareName"] == element["compareName"]: 879 | results.append(tmpElement) 880 | 881 | return results 882 | 883 | def rutorResultsOnPage(content): 884 | soup = BeautifulSoup(content, 'html.parser') 885 | 886 | if (soup == None): 887 | raise ValueError("{} {}".format(datetime.datetime.now(), "Невозможно инициализировать HTML-парсер, что-то не так с контентом.")) 888 | 889 | result = [] 890 | 891 | try: 892 | resultsGroup = soup.find("div", id="index") 893 | except Exception as e: 894 | raise ValueError("{} {}".format(datetime.datetime.now(), "Нет блока с торрентами.")) 895 | if resultsGroup == None: 896 | raise ValueError("{} {}".format(datetime.datetime.now(), "Нет блока с торрентами.")) 897 | 898 | elements = resultsGroup.find_all("tr", class_=["gai", "tum"]) 899 | 900 | if len(elements) == 0: 901 | return result 902 | 903 | for element in elements: 904 | allTDinElement = element.find_all("td", recursive=False) 905 | 906 | if len(allTDinElement) == 4: 907 | dateElement = allTDinElement[0] 908 | mainElement = allTDinElement[1] 909 | sizeElement = allTDinElement[2] 910 | peersElement = allTDinElement[3] 911 | elif len(allTDinElement) == 5: 912 | dateElement = allTDinElement[0] 913 | mainElement = allTDinElement[1] 914 | sizeElement = allTDinElement[3] 915 | peersElement = allTDinElement[4] 916 | else: 917 | raise ValueError("{} {}".format(datetime.datetime.now(), "Неверный формат блока торрента.")) 918 | 919 | try: 920 | components = dateElement.string.split(u"\xa0") 921 | torrentDate = datetime.date((int(components[2]) + 2000) if int(components[2]) < 2000 else int(components[2]), RUTOR_MONTHS[components[1]], int(components[0])) 922 | except Exception as e: 923 | raise ValueError("{} {}".format(datetime.datetime.now(), "Неверный формат блока даты.")) 924 | 925 | try: 926 | seeders = int(peersElement.find("span", class_="green").get_text(strip=True)) 927 | leechers = int(peersElement.find("span", class_="red").get_text(strip=True)) 928 | except Exception as e: 929 | raise ValueError("{} {}".format(datetime.datetime.now(), "Неверный формат блока пиров.")) 930 | 931 | try: 932 | sizeStr = sizeElement.get_text(strip=True) 933 | 934 | if sizeStr.endswith("GB"): 935 | multiplier = 1024 * 1024 * 1024 936 | elif sizeStr.endswith("MB"): 937 | multiplier = 1024 * 1024 938 | elif sizeStr.endswith("KB"): 939 | multiplier = 1024 940 | else: 941 | multiplier = 1 942 | 943 | components = sizeStr.split(u"\xa0") 944 | torrentSize = int(float(components[0]) * multiplier) 945 | except Exception as e: 946 | raise ValueError("{} {}".format(datetime.datetime.now(), "Неверный формат блока размера.")) 947 | continue 948 | 949 | try: 950 | mainElements = mainElement.find_all("a") 951 | torrentFileLink = mainElements[0].get("href").strip() 952 | if not torrentFileLink.startswith("http"): 953 | torrentFileLink = urljoin("http://d.rutor.info", torrentFileLink) 954 | magnetLink = mainElements[1].get("href").strip() 955 | 956 | if not magnetLink.startswith("magnet"): 957 | raise ValueError("Magnet") 958 | 959 | torrentLink = quote(mainElements[2].get("href").strip()) 960 | if not torrentLink.startswith("http"): 961 | torrentLink = urljoin(RUTOR_BASE_URL, torrentLink) 962 | 963 | torrentName = mainElements[2].get_text(strip=True) 964 | except Exception as e: 965 | raise ValueError("{} {}".format(datetime.datetime.now(), "Неверный формат основного блока в блоке торрента.")) 966 | 967 | result.append({"date": torrentDate, "name": torrentName, "fileLink": torrentFileLink, "magnetLink": magnetLink, "descriptionLink": torrentLink, "size": torrentSize, "seeders": seeders, "leechers": leechers}) 968 | 969 | return result 970 | 971 | def rutorFilmIDForElements(elements, deep = True): 972 | kID = None 973 | for element in elements: 974 | content = loadRutorContent(element["descriptionLink"], useProxy=True) 975 | 976 | patternLink = re.compile("\"http://www.kinopoisk.ru/film/(.*?)/\"") 977 | matches = re.findall(patternLink, content) 978 | if len(matches) == 1: 979 | kID = matches[0] 980 | break 981 | elif len(matches) > 1: 982 | return [] 983 | 984 | if not kID: 985 | patternLink = re.compile("\"http://www.kinopoisk.ru/level/1/film/(.*?)/\"") 986 | matches = re.findall(patternLink, content) 987 | if len(matches) == 1: 988 | kID = matches[0] 989 | break 990 | elif len(matches) > 1: 991 | return [] 992 | 993 | if kID: 994 | for element in elements: 995 | element["filmID"] = kID 996 | return elements 997 | else: 998 | if not deep: 999 | return [] 1000 | 1001 | try: 1002 | for element in elements: 1003 | content = loadRutorContent(element["descriptionLink"], useProxy=True) 1004 | pageResults = rutorResultsOnPage(content) 1005 | newElements = rutorFilmIDForElements(pageResults, deep = False) 1006 | if len(newElements) > 0: 1007 | kID = newElements[0]["filmID"] 1008 | break 1009 | except: 1010 | return [] 1011 | 1012 | if kID: 1013 | for element in elements: 1014 | element["filmID"] = kID 1015 | return elements 1016 | else: 1017 | return [] 1018 | 1019 | return elements 1020 | 1021 | def loadKinopoiskContent(baseURL, requestMethod, CLIENTID=KINOPOISK_CLIENTID, API_SALT=KINOPOISK_API_SALT, attempts=CONNECTION_ATTEMPTS, useProxy=False): 1022 | timestamp = str(int(round(time.time() * 1000))) 1023 | hashString = requestMethod + timestamp + API_SALT 1024 | 1025 | headers = {} 1026 | headers["Accept-encoding"] = "gzip" 1027 | headers["Accept"] = "application/json" 1028 | headers["User-Agent"] = "Android client (6.0.1 / api23), ru.kinopoisk/4.6.5 (86)" 1029 | headers["Image-Scale"] = "3" 1030 | headers["device"] = "android" 1031 | headers["ClientId"] = CLIENTID 1032 | headers["countryID"] = "2" 1033 | headers["cityID"] = "1" 1034 | headers["Android-Api-Version"] = "23" 1035 | headers["clientDate"] = datetime.date.today().strftime("%H:%M %d.%m.%Y") 1036 | headers["device"] = "android" 1037 | headers["X-TIMESTAMP"] = timestamp 1038 | headers["X-SIGNATURE"] = hashlib.md5(hashString.encode('utf-8')).hexdigest() 1039 | 1040 | return loadURLContent(baseURL + requestMethod, headers=headers, attempts=attempts, useProxy=useProxy) 1041 | 1042 | def kinozalAuth(username, password, useProxy = True): 1043 | headers = {} 1044 | headers["Accept-encoding"] = "gzip" 1045 | headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0" 1046 | 1047 | cookiejar = http.cookiejar.CookieJar() 1048 | 1049 | if useProxy and SOCKS5_IP: 1050 | proxyHandler = SocksiPyHandler(socks.PROXY_TYPE_SOCKS5, SOCKS5_IP, SOCKS5_PORT) 1051 | opener = urllib.request.build_opener(proxyHandler) 1052 | opener.add_handler(urllib.request.HTTPCookieProcessor(cookiejar)) 1053 | else: 1054 | opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookiejar)) 1055 | 1056 | values = {"username":username, "password":password} 1057 | data = urllib.parse.urlencode(values).encode() 1058 | 1059 | request = urllib.request.Request("http://kinozal.tv/takelogin.php", data=data, headers=headers) 1060 | try: 1061 | response = opener.open(request) 1062 | except: 1063 | response = opener.open(request) 1064 | 1065 | cookieSet = set() 1066 | 1067 | for cookie in cookiejar: 1068 | cookieSet.add(cookie.name) 1069 | 1070 | if ("pass" in cookieSet) and ("uid" in cookieSet): 1071 | return opener 1072 | 1073 | return None 1074 | 1075 | def kinozalSearch(filmDetail, opener, type, licenseOnly = False): 1076 | targetDate = datetime.date.today() - datetime.timedelta(days=LOAD_DAYS) 1077 | headers = {} 1078 | headers["Accept-encoding"] = "gzip" 1079 | headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0" 1080 | 1081 | result = {} 1082 | DBResults = [] 1083 | PMResults = [] 1084 | 1085 | if type == "BDRip 1080p" or type == "BDRip-HEVC 1080p": 1086 | request = urllib.request.Request(KINOZAL_SEARCH_BDRIP.format(quote(filmDetail["nameRU"])), headers=headers) 1087 | elif type == "BDRemux": 1088 | request = urllib.request.Request(KINOZAL_SEARCH_BDREMUX.format(quote(filmDetail["nameRU"])), headers=headers) 1089 | else: 1090 | return None 1091 | 1092 | try: 1093 | response = opener.open(request) 1094 | except: 1095 | response = opener.open(request) 1096 | 1097 | if response.info().get("Content-Encoding") == "gzip": 1098 | gzipFile = gzip.GzipFile(fileobj=response) 1099 | content = gzipFile.read().decode(response.info().get_content_charset()) 1100 | else: 1101 | content = response.read().decode(response.info().get_content_charset()) 1102 | 1103 | content = content.replace("\n", "") 1104 | soup = BeautifulSoup(content, 'html.parser') 1105 | 1106 | elements = soup.find_all("td", class_=["nam"]) 1107 | 1108 | if len(elements) == 0: 1109 | return None 1110 | 1111 | for element in elements: 1112 | contents = element.contents 1113 | if len(contents) != 7: 1114 | continue 1115 | 1116 | fullName = contents[0].get_text(strip=True) 1117 | torrentLink = contents[0].get("href").strip() 1118 | seeders = int(contents[3].get_text(strip=True)) 1119 | leechers = int(contents[4].get_text(strip=True)) 1120 | dateStr = contents[5].get_text(strip=True) 1121 | 1122 | if "сегодня" in dateStr: 1123 | torrentDate = datetime.date.today() 1124 | elif "вчера" in dateStr: 1125 | torrentDate = datetime.date.today() - datetime.timedelta(days=1) 1126 | else: 1127 | patternDate = re.compile("\d{2}.\d{2}.\d{4}") 1128 | matches = re.findall(patternDate, dateStr) 1129 | if len(matches) != 1: 1130 | continue 1131 | torrentDate = datetime.datetime.strptime(matches[0], "%d.%m.%Y").date() 1132 | 1133 | if torrentDate <= targetDate: 1134 | continue 1135 | 1136 | patternID = re.compile("id=(\d+)") 1137 | matches = re.findall(patternID, torrentLink) 1138 | if len(matches) != 1: 1139 | continue 1140 | kinozalID = matches[0] 1141 | 1142 | patternYear = re.compile("/ \d{4} /") 1143 | match = re.search(patternYear, fullName) 1144 | 1145 | if not match: 1146 | continue 1147 | 1148 | 1149 | namesPart = (fullName[:match.end()]).strip().upper().replace("Ё", "Е") 1150 | typePart = (fullName[match.end():]).strip().upper() 1151 | 1152 | year = int(filmDetail["year"]) 1153 | nameRU = filmDetail["nameRU"].upper().replace("Ё", "Е") 1154 | nameOriginal = filmDetail["nameOriginal"].upper().replace("Ё", "Е") 1155 | 1156 | if type == "BDRip 1080p": 1157 | if not ((nameRU in namesPart) and (nameOriginal in namesPart) and ((str(year) in namesPart) or (str(year - 1) in namesPart) or (str(year + 1) in namesPart)) and ("BDRIP" in typePart) and ("1080P" in typePart)): 1158 | continue 1159 | if ("HEVC" in typePart): 1160 | continue 1161 | elif type == "BDRemux": 1162 | if not ((nameRU in namesPart) and (nameOriginal in namesPart) and ((str(year) in namesPart) or (str(year - 1) in namesPart) or (str(year + 1) in namesPart)) and ("REMUX" in typePart) and (("1080P" in typePart) or ("1080I" in typePart))): 1163 | continue 1164 | elif type == "BDRip-HEVC 1080p": 1165 | if not ((nameRU in namesPart) and (nameOriginal in namesPart) and ((str(year) in namesPart) or (str(year - 1) in namesPart) or (str(year + 1) in namesPart)) and ("BDRIP" in typePart) and ("HEVC" in typePart) and ("1080P" in typePart)): 1166 | continue 1167 | else: 1168 | return None 1169 | 1170 | if ("3D" in typePart) or ("TS" in typePart) or ("LINE" in typePart): 1171 | continue 1172 | 1173 | request = urllib.request.Request("http://kinozal.tv/details.php?id={}".format(kinozalID), headers=headers) 1174 | 1175 | try: 1176 | response = opener.open(request) 1177 | except: 1178 | response = opener.open(request) 1179 | 1180 | if response.info().get("Content-Encoding") == "gzip": 1181 | gzipFile = gzip.GzipFile(fileobj=response) 1182 | content = gzipFile.read().decode(response.info().get_content_charset()) 1183 | else: 1184 | content = response.read().decode(response.info().get_content_charset()) 1185 | patternTabID = re.compile("Релиз".format(kinozalID)) 1186 | matches = re.findall(patternTabID, content) 1187 | if len(matches) != 1: 1188 | continue 1189 | 1190 | request = urllib.request.Request("http://kinozal.tv/get_srv_details.php?id={}&pagesd={}".format(kinozalID, matches[0]), headers=headers) 1191 | try: 1192 | response = opener.open(request) 1193 | except: 1194 | response = opener.open(request) 1195 | if response.info().get("Content-Encoding") == "gzip": 1196 | gzipFile = gzip.GzipFile(fileobj=response) 1197 | content = gzipFile.read().decode(response.info().get_content_charset()) 1198 | else: 1199 | content = response.read().decode(response.info().get_content_charset()) 1200 | 1201 | content = content.upper() 1202 | pmAudioOK = False 1203 | 1204 | if ("ЛИЦЕНЗИЯ" in content) or ("ITUNES" in content) or ("НЕВАФИЛЬМ" in content) or ("ПИФАГОР" in content) or ("AMEDIA" in content) or ("МОСФИЛЬМ-МАСТЕР" in content) or ("СВ-ДУБЛЬ" in content) or ("АРК-ТВ" in content) or ("APK-ТВ" in content) or ("APK-TB" in content) or ("КИРИЛЛИЦА" in content): 1205 | pmAudioOK = True 1206 | 1207 | license = False 1208 | if ("ЛИЦЕНЗИЯ" in content): 1209 | license = True 1210 | 1211 | if ("RUS TRANSFER" in typePart) or ("РУ" in typePart): 1212 | license = True 1213 | 1214 | if ("ДБ" in typePart) or ("РУ" in typePart): 1215 | if licenseOnly: 1216 | if license: 1217 | DBResults.append({"fullName": fullName, "kinozalID": kinozalID, "torrentDate": torrentDate, "seeders":seeders, "leechers": leechers, "license": license}) 1218 | else: 1219 | #print(content) 1220 | #print(license) 1221 | DBResults.append({"fullName": fullName, "kinozalID": kinozalID, "torrentDate": torrentDate, "seeders":seeders, "leechers": leechers, "license": license}) 1222 | 1223 | if ("ПМ" in typePart) and pmAudioOK and not (("ДБ" in typePart) or ("РУ" in typePart)): 1224 | if licenseOnly: 1225 | if license: 1226 | PMResults.append({"fullName": fullName, "kinozalID": kinozalID, "torrentDate": torrentDate, "seeders":seeders, "leechers": leechers, "license": license}) 1227 | else: 1228 | PMResults.append({"fullName": fullName, "kinozalID": kinozalID, "torrentDate": torrentDate, "seeders":seeders, "leechers": leechers, "license": license}) 1229 | 1230 | if len(DBResults) > 0: 1231 | DBResults.sort(key = operator.itemgetter("license", "seeders"), reverse = True) 1232 | if DBResults[0]["seeders"] == 0: 1233 | #return None 1234 | DBResults.sort(key = operator.itemgetter("license", "torrentDate"), reverse = True) 1235 | request = urllib.request.Request("http://kinozal.tv/get_srv_details.php?id={}&action=2".format(DBResults[0]["kinozalID"]), headers=headers) 1236 | try: 1237 | response = opener.open(request) 1238 | except: 1239 | response = opener.open(request) 1240 | if response.info().get("Content-Encoding") == "gzip": 1241 | gzipFile = gzip.GzipFile(fileobj=response) 1242 | content = gzipFile.read().decode(response.info().get_content_charset()) 1243 | else: 1244 | content = response.read().decode(response.info().get_content_charset()) 1245 | 1246 | patternHash = re.compile("[A-F0-9]{40}") 1247 | match = re.search(patternHash, content) 1248 | 1249 | if not match: 1250 | return None 1251 | 1252 | return {"link": "http://dl.kinozal.tv/download.php?id={}".format(DBResults[0]["kinozalID"]), "magnet": "magnet:?xt=urn:btih:{}&dn=kinozal.tv".format(match[0]), "date": DBResults[0]["torrentDate"], "type": type, "license": DBResults[0]["license"]} 1253 | elif len(PMResults) > 0: 1254 | PMResults.sort(key = operator.itemgetter("license", "seeders"), reverse = True) 1255 | if PMResults[0]["seeders"] == 0: 1256 | #return None 1257 | PMResults.sort(key = operator.itemgetter("license", "torrentDate"), reverse = True) 1258 | request = urllib.request.Request("http://kinozal.tv/get_srv_details.php?id={}&action=2".format(PMResults[0]["kinozalID"]), headers=headers) 1259 | try: 1260 | response = opener.open(request) 1261 | except: 1262 | response = opener.open(request) 1263 | if response.info().get("Content-Encoding") == "gzip": 1264 | gzipFile = gzip.GzipFile(fileobj=response) 1265 | content = gzipFile.read().decode(response.info().get_content_charset()) 1266 | else: 1267 | content = response.read().decode(response.info().get_content_charset()) 1268 | 1269 | patternHash = re.compile("[A-F0-9]{40}") 1270 | match = re.search(patternHash, content) 1271 | 1272 | if not match: 1273 | return None 1274 | 1275 | return {"link": "http://dl.kinozal.tv/download.php?id={}".format(PMResults[0]["kinozalID"]), "magnet": "magnet:?xt=urn:btih:{}&dn=kinozal.tv".format(match[0]), "date": PMResults[0]["torrentDate"], "type": type, "license": PMResults[0]["license"]} 1276 | return None 1277 | 1278 | def saveHTML(movies, filePath, useMagnet=USE_MAGNET): 1279 | f = open(filePath,'w', encoding='utf-8') 1280 | html = """ 1281 | 1282 | 1283 | 1284 | 1285 | 1286 | Новые цифровые релизы 1287 | 1584 | 1634 | 1635 | 1636 |
1637 |
1638 | 1639 | 1640 |
1641 |
""" 1642 | descriptionTemplate = """ 1643 | 1644 | {} 1645 | 1646 |
1647 | {} 1648 |
1649 | 1650 | """ 1651 | buttonsTemplate = """ """ 1652 | buttonsTemplateS = """ """ 1653 | movieTemplate = """
1654 |
1655 |
1656 |

{}

1657 | {} 1658 |
1659 |
1660 |
1661 |
{}
1662 | {} 1663 |
1664 |
1665 | 1666 |
1667 |
1668 |
1669 | 1670 | 1671 | {} 1672 | 1673 |
1674 |
{}
1675 |
1676 |
1677 |
1678 | {} 1679 |
1680 |
1681 | """ 1682 | for movie in movies: 1683 | 1684 | descriptionBlock = "" 1685 | descriptionBlock += descriptionTemplate.format("год", movie["year"]) 1686 | descriptionBlock += descriptionTemplate.format("страна", movie["country"]) 1687 | descriptionBlock += descriptionTemplate.format("режиссёр", movie["directors"]) 1688 | descriptionBlock += descriptionTemplate.format("актёры", movie["actors"]) 1689 | descriptionBlock += descriptionTemplate.format("жанр", movie["genre"]) 1690 | if len(movie["ratingAgeLimits"]) > 0: 1691 | try: 1692 | if int(movie["ratingAgeLimits"]) < 6: 1693 | descriptionBlock += descriptionTemplate.format("возраст", "любой") 1694 | elif int(movie["ratingAgeLimits"]) < 12: 1695 | descriptionBlock += descriptionTemplate.format("возраст", "от 6 лет") 1696 | elif int(movie["ratingAgeLimits"]) < 16: 1697 | descriptionBlock += descriptionTemplate.format("возраст", "от 12 лет") 1698 | elif int(movie["ratingAgeLimits"]) < 18: 1699 | descriptionBlock += descriptionTemplate.format("возраст", "от 16 лет") 1700 | else: 1701 | descriptionBlock += descriptionTemplate.format("возраст", "от 18 лет") 1702 | except: 1703 | pass 1704 | elif len(movie["ratingMPAA"]) > 0: 1705 | if movie["ratingMPAA"] == "G": 1706 | descriptionBlock += descriptionTemplate.format("возраст", "любой") 1707 | elif movie["ratingMPAA"] == "PG": 1708 | descriptionBlock += descriptionTemplate.format("возраст", "от 6 лет") 1709 | elif movie["ratingMPAA"] == "PG-13": 1710 | descriptionBlock += descriptionTemplate.format("возраст", "от 12 лет") 1711 | elif movie["ratingMPAA"] == "R": 1712 | descriptionBlock += descriptionTemplate.format("возраст", "от 16 лет") 1713 | else: 1714 | descriptionBlock += descriptionTemplate.format("возраст", "от 18 лет") 1715 | descriptionBlock += descriptionTemplate.format("продолжительность", movie["filmLength"]) 1716 | 1717 | if len(movie["ratingKP"]) > 0: 1718 | rKP = movie["ratingKP"] 1719 | else: 1720 | if movie["ratingKPCount"] == 0: 1721 | rKP = "нет" 1722 | elif movie["ratingKPCount"] < MIN_VOTES_KP: 1723 | rKP = "мало голосов" 1724 | else: 1725 | rKP = "нет" 1726 | 1727 | descriptionBlock += descriptionTemplate.format("рейтинг КиноПоиск", "{}".format(movie["webURL"], rKP)) 1728 | 1729 | if len(movie["ratingIMDb"]) > 0: 1730 | rIMDb = movie["ratingIMDb"] 1731 | else: 1732 | if movie["ratingIMDbCount"] == 0: 1733 | rIMDb = "нет" 1734 | elif movie["ratingIMDbCount"] < MIN_VOTES_IMDB: 1735 | rIMDb = "мало голосов" 1736 | else: 1737 | rIMDb = "нет" 1738 | 1739 | descriptionBlock += descriptionTemplate.format("рейтинг IMDb", rIMDb) 1740 | 1741 | # if len(movie["ratingIMDb"]) > 0: 1742 | # descriptionBlock += descriptionTemplate.format("рейтинг IMDb", movie["ratingIMDb"]) 1743 | # else: 1744 | # descriptionBlock += descriptionTemplate.format("рейтинг IMDb", "нет (возможно, мало голосов)") 1745 | 1746 | prHeader = "премьера" 1747 | if movie["premierType"] == "digital": 1748 | prHeader = "цифровая премьера" 1749 | elif movie["premierType"] == "ru": 1750 | prHeader = "премьера в России" 1751 | descriptionBlock += descriptionTemplate.format(prHeader, movie["premierDate"].strftime("%d.%m.%Y")) 1752 | #descriptionBlock += descriptionTemplate.format("торрент-релиз", "{} ({})".format("http://rutor.info/search/0/0/010/0/film%20" + movie["filmID"], movie["torrentsDate"].strftime("%d.%m.%Y"), movie["torrentsDateType"])) 1753 | descriptionBlock += descriptionTemplate.format("торрент-релиз", "{}".format(movie["torrentsDate"].strftime("%d.%m.%Y"))) 1754 | #descriptionBlock += descriptionTemplate.format("описание", movie["description"]) 1755 | descriptionBlock += descriptionTemplate.format("тип торрент-релиза", movie["torrentsDateType"]) 1756 | 1757 | 1758 | torrents = movie["torrents"] 1759 | buttonsBlock = "" 1760 | for torrent in torrents: 1761 | if torrent["license"]: 1762 | if useMagnet: 1763 | buttonsBlock += buttonsTemplateS.format(torrent["magnet"], torrent["type"]) 1764 | else: 1765 | buttonsBlock += buttonsTemplateS.format(torrent["link"], torrent["type"]) 1766 | else: 1767 | if useMagnet: 1768 | buttonsBlock += buttonsTemplate.format(torrent["magnet"], torrent["type"]) 1769 | else: 1770 | buttonsBlock += buttonsTemplate.format(torrent["link"], torrent["type"]) 1771 | 1772 | displayOrigName = "display: none;" 1773 | if len(movie["nameOriginal"]) > 0: 1774 | displayOrigName = "" 1775 | 1776 | ratingStyle = "background-color: #aaa;" 1777 | if movie["ratingFloat"] >= 7: 1778 | ratingStyle = "background-color: #3bb33b;" 1779 | elif movie["ratingFloat"] < 5.5: 1780 | ratingStyle = "background-color: #b43c3c;" 1781 | 1782 | rating = movie["rating"] 1783 | if movie["ratingFloat"] < 1: 1784 | ratingStyle = "display: none;" 1785 | rating = "—" 1786 | 1787 | html += movieTemplate.format(movie["torrentsDate"].strftime("%Y-%m-%d"), movie["torrentsDate"].strftime("%Y-%m-%d"), movie["rating"], movie["torrentsDate"].strftime("%Y-%m-%d"), movie["nameRU"], displayOrigName, movie["nameOriginal"], ratingStyle, rating, movie["posterURL"], movie["nameRU"], "https://www.kinopoisk.ru/film/{}/video/".format(movie["filmID"]), descriptionBlock, movie["description"], buttonsBlock) 1788 | 1789 | #html += movieTemplate.format(movie["torrentsDate"].strftime("%Y-%m-%d"), movie["torrentsDate"].strftime("%Y-%m-%d"), movie["rating"], movie["torrentsDate"].strftime("%Y-%m-%d"), movie["nameRU"], displayOrigName, movie["nameOriginal"], ratingStyle, rating, movie["posterURL"], movie["nameRU"], movie["trailerURL"], descriptionBlock, movie["description"], buttonsBlock) 1790 | html += """
1791 |
1792 | 1793 | """ 1794 | f.write(html) 1795 | f.close() 1796 | return 1797 | 1798 | try: 1799 | exitCode = main() 1800 | except: 1801 | exitCode = 1 1802 | 1803 | sys.exit(exitCode) --------------------------------------------------------------------------------