Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement #1

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 79 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,83 @@
# Kodi Addon: Autoload subtitles from `Subs` folder
# Kodi Addon: Autoload Subtitles from `Subs` Folder

### Description and configuration
Auto-loads subtitles from location `Subs/[number]_[language].srt`(Movies) or `Subs/Name.of.the.video/[number]_[language].srt`(Series) on video playback.
## Overview

`[language]` is first language used from kodi settings(`Player > Subtitles > Preferred Subtitle Language`).
This Kodi addon automatically loads subtitles from a `Subs` folder when video playback begins. It supports both movies and TV series, using a folder structure common in most media libraries.

`Subs` subtitle folder structure is mostly used in torrent releases(eg. RARBG).
- **Movies:** `Subs/[number]_[language].srt`
- **Series:** `Subs/Name.of.the.video/[number]_[language].srt`

This addon is designed to enhance your viewing experience by seamlessly loading subtitles according to your preferred language settings in Kodi.

## Features

- **Auto-Subtitle Loading:** Automatically loads subtitles for movies and TV series from the `Subs` folder, based on the Kodi preferred subtitle language setting.
- **Multi-Subtitle Support:** Supports loading multiple subtitle files directly from the `Subs` folder or from other configured directories.
- **Configurable Languages:** Ability to configure additional preferred languages using the addon settings, allowing for greater flexibility in subtitle selection.
- **Configurable Default Subs Folder:** Ability to configure the default `Subs` folder using the addon settings.
- **Common Structure Support:** Supports subtitle folder structures commonly used across different media types.

## Configuration

### Folder Structure

- **Movies:** The subtitles should be placed in the `Subs` folder, following this naming convention:
```
Subs/[number]_[language].srt
```
Example: `Subs/01_english.srt`

- **TV Series:** Subtitles for episodes should be placed within the corresponding video folder, like this:
```
Subs/Name.of.the.video/[number]_[language].srt
```
Example: `Subs/Name.of.the.show.S01E01/01_english.srt`

### Language Settings

The `[language]` placeholder refers to the first language configured in Kodi's settings (`Player > Subtitles > Preferred Subtitle Language`). You can also set additional languages within the addon configuration.

## Installation and Usage

### Step 1: Download the Addon

Head over to the [Releases](#) section of this repository and download the latest release of the addon as a `.zip` file.

### Step 2: Install the Addon

Once downloaded, follow the official [Kodi guide to install the addon from a zip file](https://kodi.wiki/view/Archive:Install_add-ons_from_zip_files).

### Step 3: Enjoy Subtitles Autoload

After installation, the subtitle autoload feature should work immediately upon video playback. No additional setup is required for basic functionality.

## Customization

### Multi-Subtitle Loading

If you need to load multiple subtitle files, you can configure this within the addon settings. This allows you to select and load multiple subtitle tracks from either the default `Subs` folder or from other directories that you configure.

### Preferred Languages

The addon lets you configure additional preferred subtitle languages through its settings. This feature is useful for multilingual viewers who prefer subtitles in different languages for various content.

## Troubleshooting

If the addon is not working as expected:
- Ensure that the subtitle files are named and structured correctly.
- Double-check the configured language settings in Kodi (`Player > Subtitles > Preferred Subtitle Language`).
- Automatic scan for `Subs` folder and other possible folders = {`'Subs', 'Sub', 'Subtitles', 'subs', 'sub', 'subtitles'`} placed correctly in relation to your media files.

## Contributing

Contributions are welcome! If you would like to contribute to the development of this addon:
- Fork this repository.
- Make your changes in a new branch.
- Submit a pull request with a detailed description of your changes.

Please ensure that your code adheres to the project's coding standards and that you test your changes thoroughly before submitting.

## License

This project is licensed under the Apache License. See the [LICENSE](LICENSE) file for more details.

### Installation and Usage
Download latest release from [releases](https://github.com/recrof/kodi.service.subsautoloader/releases/), then [Use kodi guide to install the addon zip file](https://kodi.wiki/view/Archive:Install_add-ons_from_zip_files). Subs autoloader should work right after installation.
22 changes: 11 additions & 11 deletions service.subsautoloader/addon.xml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="service.subsautoloader" name="Subs Autoloader" version="1.0.1" provider-name="recrof">
<requires>
<import addon="xbmc.python" version="3.0.0"/>
</requires>
<extension point="xbmc.service" library="service.py"></extension>
<extension point="xbmc.addon.metadata">
<summary lang="en_GB">AutoLoad subtitles from Subs dir</summary>
<description lang="en_GB">Automatically load subtitles from Subs folder when video starts playing</description>
<platform>all</platform>
<license>Apache License 2.0</license>
</extension>
<addon id="service.subsautoloader" name="Subs Autoloader" version="1.0.2" provider-name="mussonero" origin-author="recrof" origin-url="https://github.com/recrof/kodi.service.subsautoloader" provider-url="https://github.com/mussonero/kodi.service.subsautoloader">
<requires>
<import addon="xbmc.python" version="3.0.0"/>
</requires>
<extension point="xbmc.service" library="service.py"></extension>
<extension point="xbmc.addon.metadata">
<summary lang="en_GB">Auto-load subtitles from Subs folder</summary>
<description lang="en_GB">Automatically loads subtitles from the Subs folder when video starts playing. Supports movie and series subtitle structures, with multi-subtitle and language configuration options.</description>
<platform>all</platform>
<license>MIT License</license>
</extension>
</addon>
30 changes: 30 additions & 0 deletions service.subsautoloader/resources/settings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<settings>
<category label="Subtitle Configuration">
<setting id="language1" type="labelenum" label="Language 1" values="English|Italian|Spanish|French|German|Other" default="0" />
<setting id="langcode1" type="text" label="Language Code 1" default="eng" />

<setting id="language2" type="labelenum" label="Language 2" values="English|Italian|Spanish|French|German|Other" default="1" />
<setting id="langcode2" type="text" label="Language Code 2" default="ita" />

<setting id="language3" type="labelenum" label="Language 3" values="English|Italian|Spanish|French|German|Other" default="2" />
<setting id="langcode3" type="text" label="Language Code 3" default="spa" />

<setting id="language4" type="labelenum" label="Language 4" values="English|Italian|Spanish|French|German|Other" default="3" />
<setting id="langcode4" type="text" label="Language Code 4" default="fra" />

<setting id="language5" type="labelenum" label="Language 5" values="English|Italian|Spanish|French|German|Other" default="4" />
<setting id="langcode5" type="text" label="Language Code 5" default="deu" />

<!-- Additional slots for custom languages -->
<setting id="language6" type="text" label="Language 6" default="" />
<setting id="langcode6" type="text" label="Language Code 6" default="" />

<setting id="language7" type="text" label="Language 7" default="" />
<setting id="langcode7" type="text" label="Language Code 7" default="" />

<!-- Add as many slots as you deem necessary -->
</category>
<category label="Default Subs Folder">
<setting id="defaultsubsdir" type="text" label="Default Subs Folder" default="Subs" />
</category>
</settings>
173 changes: 128 additions & 45 deletions service.subsautoloader/service.py
Original file line number Diff line number Diff line change
@@ -1,62 +1,145 @@
import xbmc, xbmcvfs, os, json
import xbmc, xbmcvfs, os, json, xbmcgui, xbmcaddon

addon = xbmcaddon.Addon()

def debug(msg):
xbmc.log('[service.subsautoloader] ' + msg, xbmc.LOGINFO)
xbmc.log('[service.subsautoloader] ' + msg, xbmc.LOGINFO)

def execRPC(method, params):
rpcCallObject = {
'jsonrpc': '2.0',
'method': method,
'params': params,
'id': 1
}

resObject = json.loads(xbmc.executeJSONRPC(json.dumps(rpcCallObject)))

return resObject['result']
rpcCallObject = {
'jsonrpc': '2.0',
'method': method,
'params': params,
'id': 1
}
resObject = json.loads(xbmc.executeJSONRPC(json.dumps(rpcCallObject)))
return resObject['result']

def findSub(path, language):
dirs, files = xbmcvfs.listdir(path)
# Load user-configured language mappings
language_mapping = {}

if len(files) == 0:
return ''
# Loop through possible language slots in settings.xml
for i in range(1, 8): # Assuming you have 7 slots, adjust as needed
lang = addon.getSetting(f'language{i}').lower()
lang_code = addon.getSetting(f'langcode{i}').lower()
if lang and lang_code: # Only add if both fields are not empty
language_mapping[lang] = [lang_code]

for subFile in files[::-1]:
if language.lower() in subFile.lower():
return subFile
return ''
debug(f'Loaded language mapping from settings: {language_mapping}')

def getSubFilePath(videoPath):
videoFile = os.path.basename(videoPath)
rootPath = os.path.dirname(videoPath)
subVideoName = '.'.join(videoFile.split('.')[0:-1])
subPath = rootPath + '/Subs'
def find_subs_folder(rootPath):
# Check default folder first
defaultsubsdir = addon.getSetting('defaultsubsdir')
debug(f'Checking for default subs folder: {defaultsubsdir}')
if defaultsubsdir and xbmcvfs.exists(os.path.join(rootPath, defaultsubsdir)):
return os.path.join(rootPath, defaultsubsdir)
# Check other possible folders
possible_folders = {'Subs', 'Sub', 'Subtitles', 'subs', 'sub', 'subtitles'}
for folder in xbmcvfs.listdir(rootPath)[0]:
if folder in possible_folders:
return os.path.join(rootPath, folder)
# Return None if none of the folders exist
return None

def getSubFilePaths(videoPath):
# Extract the video file name from the video path
videoFile = os.path.basename(videoPath)
# Extract the root path from the video path
rootPath = os.path.dirname(videoPath)
# Construct the subtitle path using the root path
subPath = find_subs_folder(rootPath)
if subPath is None:
return None
debug(f'Checking for subtitles in: {subPath}')
# Get the user-configured subtitle language from Kodi settings
subLanguage = execRPC('Settings.GetSettingValue', {'setting': 'subtitles.languages'})['value'][0].lower()
# Print the subtitle language used
debug(f'Using subtitle language: {subLanguage}')
# Get the possible subtitle codes for the language
possible_sub_codes = language_mapping.get(subLanguage, [subLanguage])
# Initialize lists to store main and other subtitles
main_subs, other_subs = [], []

subLanguages = execRPC('Settings.GetSettingValue', { 'setting': 'subtitles.languages' })['value']
debug('using subtitle language: ' + subLanguages[0])
# Loop through two possible subtitle paths
for path in [subPath, os.path.join(subPath, os.path.splitext(videoFile)[0])]:
try:
# List the files in the subtitle path
for subFile in xbmcvfs.listdir(path)[1]:
# Convert the subtitle file name to lowercase
subFileLower = subFile.lower()
# Check if the subtitle file name contains any of the possible subtitle codes
if any(subCode.lower() in subFileLower for subCode in possible_sub_codes):
# If it does, add it to the main subtitle list
main_subs.append(os.path.join(path, subFile))
else:
# Loop through the language mappings
for lang, codes in language_mapping.items():
# Skip the language that was already checked
if lang == subLanguage:
continue
# Check if the subtitle file name contains any of the codes for the language
if any(subCode.lower() in subFileLower for subCode in codes):
# If it does, add it to the other subtitle list and break the loop
other_subs.append(os.path.join(path, subFile))
break
# If an error occurs while listing the files or searching for subtitles, print the error
except Exception as e:
debug(f"Error while searching for subtitles: {str(e)}")
pass

for path in [subPath, subPath + '/' + subVideoName]:
foundSub = findSub(path, subLanguages[0])
if foundSub:
return path + '/' + foundSub

return ''
# Return the concatenated lists of main and other subtitles
return main_subs + other_subs

class Player(xbmc.Player):
def onAVStarted(self):
if not self.isPlayingVideo():
return
subtitles = self.getAvailableSubtitleStreams()
if subtitles:
return

subFilePath = getSubFilePath(self.getPlayingFile())
if subFilePath:
debug('loading subtitle: ' + subFilePath)
self.setSubtitles(subFilePath)

# def onPlayBackStarted(self):
# """Called when playback starts."""
def onAVStarted(self):
"""
Called when video is ready for playback.
Checks if subtitles are already available.
If not, it retrieves the video path and searches for subtitles.
If subtitles are found, it creates a new ListItem with the video path and sets the subtitles.
Then it restarts playback with the new ListItem and video path.
"""
# Check if the current playback is for a video
if not self.isPlayingVideo():
return

# Check if subtitles are already available
subtitles = self.getAvailableSubtitleStreams()
if subtitles:
# Print the available subtitles
debug(f'Subtitle streams already available: {subtitles}')
return

# Get the path of the currently playing video
video_path = self.getPlayingFile()

# Search for subtitles based on the video path
subFilePaths = getSubFilePaths(video_path)

if subFilePaths:
# Print the found subtitles
debug('Found subtitles: ' + ', '.join(subFilePaths))

# Create a new ListItem with the video path
list_item = xbmcgui.ListItem(path=video_path)

# Set the subtitles for the ListItem
list_item.setSubtitles(subFilePaths)

# Print the subtitles set for the ListItem
debug(f'Subtitles set for ListItem before playback: {subFilePaths}')

# Restart playback with the new ListItem and video path
self.play(video_path, list_item)
else:
# Print if no matching subtitles were found
debug('No matching subtitles found.')

player = Player()
monitor = xbmc.Monitor()

while not monitor.abortRequested():
monitor.waitForAbort(10)
monitor.waitForAbort(10)