├── README.md ├── main.lua ├── requirements.txt └── submpv.py /README.md: -------------------------------------------------------------------------------- 1 | # Submpv 2 | 3 | # Note 4 | 5 | This project is no longer supported nor working due to Subscene being closed. 6 | 7 | ## Overview 8 | 9 | **submpv** is a python script to automate downloading and loading subtitle from subscence. 10 | 11 | ## Dependencies 12 | 13 | This lua script depend on python3 been already installed. 14 | 15 | ```bash 16 | # for windows go to the official python website. 17 | apt install python3 -y 18 | ``` 19 | 20 | ## Setup 21 | 22 | ### Windows 23 | 24 | Install the zip file from github and extract the folder in **[Drive]:\Users\\[User]\AppData\Roaming\mpv\scripts\\**. 25 | 26 | ```bash 27 | # to get python path run the following command: 28 | where python 29 | # open cmd in the directory of this script and run: 30 | pip install -r requirements.txt 31 | ``` 32 | 33 | ### Linux 34 | ```bash 35 | git clone https://github.com/yassin-l/submpv.git 36 | mv ./submpv ~/.config/mpv/scripts/ 37 | cd ~/.config/mpv/scripts/submpv 38 | pip install -r requirements.txt 39 | ``` 40 | 41 | ### Note 42 | 43 | > change the /bin/python path inside [[]] in the main.lua file to your python path. 44 | 45 | > add this line to your input.conf **[key] script-binding "submpv"**, where key is your key. 46 | 47 | > you can use submpv.py as sperated script to download subtitle from subscence. 48 | 49 | ### Usage of submpv.py 50 | 51 | ```bash 52 | python3 submpv.lua "Tv.show.name.S01E07" 53 | ``` 54 | 55 | ## Todo List 56 | - [x] support for movies 57 | - [ ] renaming subtitle as the target name ( by [ayghub](https://github.com/ayghub/) ). 58 | - [ ] config file 59 | -------------------------------------------------------------------------------- /main.lua: -------------------------------------------------------------------------------- 1 | -- submpv lua script 2 | -- ===================| 3 | 4 | local python_path = [[/bin/python]] -- path to python3 bin 5 | local script_dir = mp.get_script_directory() 6 | local utils = require 'mp.utils' 7 | 8 | -- Log function: log to both terminal and MPV OSD (On-Screen Display) 9 | function log(level,string,secs) 10 | secs = secs or 2.5 11 | mp.msg.log(level,string) 12 | mp.osd_message(string,secs) 13 | end 14 | 15 | -- download/load function 16 | function submpv() 17 | log('info','searching for arabic subtitle!') 18 | --get directory and filename 19 | local directory,filename = utils.split_path(mp.get_property('path')) 20 | local table = { name = "subprocess", 21 | capture_stdout = true, 22 | args = { python_path } 23 | } 24 | local a = table.args 25 | 26 | a[#a + 1] = string.format("%s/submpv.py",script_dir) 27 | a[#a + 1] = '-d' 28 | a[#a + 1] = directory 29 | a[#a + 1] = filename --> submpv command ends with the movie/tvshow name/filename 30 | 31 | -- run command and capture stdout 32 | local result = mp.command_native(table) 33 | 34 | if result.status == 0 then 35 | if string.find(result.stdout, 'done') then 36 | log('info','Arabic subtitle ready!') 37 | -- to make sure all downloaded subtitle loaded 38 | mp.set_property('sub-auto', 'all') 39 | mp.commandv('rescan_external_files','reselect') 40 | else 41 | log('error','Arabic subtitles wasn\'t found!') 42 | end 43 | end 44 | end 45 | mp.add_key_binding(nil,'submpv',submpv) 46 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | bs4 3 | guessit -------------------------------------------------------------------------------- /submpv.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # standard library 4 | import argparse 5 | import zipfile 6 | from re import search 7 | from os import remove,chdir 8 | from sys import argv,exit as sys_exit 9 | from difflib import SequenceMatcher,get_close_matches 10 | # third party library 11 | from guessit import guessit 12 | import requests 13 | from bs4 import BeautifulSoup as bs 14 | 15 | # help 16 | parser = argparse.ArgumentParser( 17 | description="submpv is a download/add subtitle from subscence", 18 | epilog="Author:yassin-l", 19 | ) 20 | parser.add_argument('name',help='the show name to download sub for should be in \"\" with no spaces like:"name.sxex" or the movie name with in \"\" with year of release like this:"movie (year)"') 21 | parser.add_argument('-d','--directory',metavar="",type=str,help='choose where to download sub by default:current directory') 22 | parser.add_argument('-l','--lang',metavar="",choices=['ar','en'],help='select which language to filter with',default='ar') 23 | args = parser.parse_args() 24 | 25 | # var 26 | url = 'https://subscene.com' 27 | headers = { 28 | "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36" 29 | } 30 | 31 | # scrap func 32 | def scrape(url:str=None,name:str=None): 33 | if name: 34 | url = 'https://subscene.com/subtitles/searchbytitle' 35 | request = requests.get(url,params={'query':name},headers=headers) 36 | 37 | else: 38 | request = requests.get(url,headers=headers) 39 | 40 | if request.status_code == 200: 41 | return bs(request.content,'html.parser') 42 | 43 | print('connection error try again') 44 | sys_exit() 45 | 46 | # get query url 47 | def get_query_url(soup,name): 48 | if name.get('type',None) == 'episode': 49 | seasons = {1:'first-season',2:'second-season',3:'third-season',4:'fourth-season',5:'fifth-season',6:'sixth-Season',7:'seventh-season',8:'eighth-season'} 50 | urls = [i for i in soup.find_all('a',href=True,limit=16) if str(i.get('href')).startswith('/subtitles')] 51 | matches = [SequenceMatcher(None,i.get('href'),f"{name['title']}-{seasons[name['season']]}").ratio() for i in urls] 52 | return urls[matches.index(max(matches))].get('href') 53 | 54 | else: 55 | urls = [i for i in soup.find_all('a',href=True,limit=16) if str(i.get('href')).startswith('/subtitles')] 56 | if name.get('year',None): 57 | matches = [SequenceMatcher(None,i.text,f"{name['title']} - ({name['year']})").ratio() for i in urls] 58 | else: 59 | matches = [SequenceMatcher(None,i.text,f"{name['title']})").ratio() for i in urls] 60 | return urls[matches.index(max(matches))].get('href') 61 | 62 | print('not found') 63 | sys_exit(0) 64 | 65 | ## get episode url 66 | def ep_url(url:str,soup,name): 67 | if name.get('type',None) == 'episode': 68 | langs = {'ar':'arabic','en':'english','fr':'french'} 69 | urls = [i for i in soup.find_all('a',href=True) if str(i.get('href')).startswith(f'{url}/{langs.get("args.lang","ar")}')] 70 | num = f"0{name['episode']}" if len(str(name['episode'])) < 2 else name['episode'] 71 | for i in urls: 72 | _name = search(r'e?{n}'.format(n=num),i.span.find_next_sibling('span').text.lower()) 73 | if _name: 74 | return i.get('href') 75 | else: 76 | urls = [i for i in soup.find_all('a',href=True) if str(i.get('href')).startswith(f'{url}/{args.lang}')] 77 | _url = [] 78 | # filter based on edition and source using a dic 79 | #for i in urls: 80 | # if search(r'{}'.format(name['title']).lower(),i.span.find_next_sibling('span').text.lower()): 81 | # _name.append(i.get('href')) 82 | if name.get('source',None): 83 | for i in urls: 84 | _name = search(r'{}'.format(name['title']).lower(),i.span.find_next_sibling('span').text.lower()) 85 | _source = search(r'{}'.format(name['source']).lower(),i.span.find_next_sibling('span').text.lower()) 86 | if _name and _source: 87 | return i.get('href') 88 | for i in urls: 89 | _name = search(r'{}'.format(name['title']).lower(),i.span.find_next_sibling('span').text.lower()) 90 | if _name: 91 | return i.get('href') 92 | print('not found!') 93 | sys_exit(0) 94 | 95 | ## download subtitle 96 | def dw_sub(soup): 97 | div = soup.find("div", {"class": "download"}) 98 | down_link = url + div.find("a").get("href") 99 | down_sub = requests.get(down_link,headers=headers, stream=True).content 100 | if args.directory: 101 | chdir(args.directory) 102 | with open('sub.zip','wb') as f: 103 | f.write(down_sub) 104 | with zipfile.ZipFile('sub.zip', "r") as f: 105 | f.extractall() 106 | remove('sub.zip') 107 | print('done') 108 | 109 | def main(): 110 | # parsing giving name 111 | name = guessit(args.name) 112 | 113 | # get sub first page 114 | first_url = get_query_url(scrape(name=name['title']),name) 115 | 116 | # getting episode url 117 | episode_url = ep_url(first_url,scrape(url+first_url),name) 118 | 119 | # downloading subtitle 120 | dw_sub(scrape(url+episode_url)) 121 | 122 | 123 | if __name__ == "__main__": 124 | main() 125 | --------------------------------------------------------------------------------