Skip to content

Commit

Permalink
Beta branches merge (#77)
Browse files Browse the repository at this point in the history
* Start work on v5.0

Simple rename and push to `beta-branch`

* Fixed minor bug that would cause searches to fail for cached media.

* Fixed the plugin script

* Quick save while switching laptops. New cloud-like layout.

* Quick back-up, DO NOT USE.

* Update to v4.2 (BETA).

Moved and restructured code to be cloud based.

Added several new options.

Added Developer options.

* Fix "hide web to plex" icon. Make code easier to use

* Updated document.furnish, and class Prompt

* Crap ton of fixes and changes...

* Added Vumoo support. Dropped GoStream.

* The user can now disable default sites. Added the `configuration` var

* Removed restart requirement for disabling default sites

* Reenabled GoStream (updated script). Added `Notify` to helpers.js

* Added GoStream as a search provider (again)

* Added Medusa as a manager, added the testing suite (to be removed), etc.

* Update README.md

* Update README.md

* Match README layout of Wiki

* Update test page. Minor aesthetic error in background.js
  • Loading branch information
Ephellon authored Jul 11, 2019
1 parent 08e5d90 commit 5856c5e
Show file tree
Hide file tree
Showing 43 changed files with 3,420 additions and 1,917 deletions.
97 changes: 55 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,66 @@

# Web to Plex ![Icon](src/img/48.png)

![Examples](example.png)
![Examples](https://github.com/SpaceK33z/web-to-plex/blob/master/example.png)

This browser extension searches your [Plex Media Server (PMS)](https://www.plex.tv/downloads/) for matching media on sites like [IMDb](https://imdb.com), letting you immediately open the movie or TV show in Plex, if it is available. If the item isn't found on your PMS, then a download button is added instead.

----

## Features:

- Can save media directly from noted sites (file downloads/magnet URLs)
- Right-click | Web to Plex | Save as "Show/Movie (Year)"
- Can push requests to your chosen download manager
- [Radarr](https://radarr.video/)
- [Sonarr](https://sonarr.tv/)
- [CouchPotato](https://couchpota.to/)
- [Watcher 3](https://nosmokingbandit.github.io/)
- [Ombi](https://ombi.io/)
- Offers search options via right-click (context menu)
- Right-click | Web to Plex | Find "Show/Movie (Year)"
- Offers a Plex-like GUI
- Web to Plex button
- Settings page
- Pop-up page
- Offers a status via the browser badge and button
- Orange/Yellow: item is on Plex
- Blue (button): item isn't on Plex, but can be sent for
- Grey (badge)/Red (button): item is unavailable/not found
- Grey (button): item is loading
- Offers an easy login feature
- Offers an API login feature
- Offers a "Direct Plex URL" feature
- i.e. you can specify `localhost:32400` as your Plex URL to avoid bandwidth usage for Plex requests

# Download Managers

Optionally, you can configure your download manager(s) (see support table) in the extension's options. After that, you can immediately add a TV show or movie with one click, right from your favorite site.
# NZB Managers

Optionally, you can configure NZB Manager (see support table) in the extension's options. After that, you can immediately add a TV show or movie with one click, right from your favorite site.

## Supported Managers
| Manager | Movie Support | TV Show Support | Searchable
| ----------------------------------------------- | ------------- | --------------- | ----------
| [Watcher 3](https://nosmokingbandit.github.io/) | Yes | |
| [CouchPotato](https://couchpota.to/) | Yes | Yes |
| [Radarr](https://radarr.video/) | Yes | | Yes
| [Sonarr](https://sonarr.tv/) | | Yes | Yes
| [Ombi](https://ombi.io/) | Yes | Yes | Yes
| ----------------------------------------------- |:-------------:|:---------------:|:----------:
| [Watcher 3](https://nosmokingbandit.github.io/) | ✔ | ❌ | ❌
| [CouchPotato](https://couchpota.to/) | ✔ | ✔ | ❌
| [Radarr](https://radarr.video/) | ✔ | ❌ | ✔
| [Sonarr](https://sonarr.tv/) | ❌ | ✔ | ✔
| [Ombi](https://ombi.io/) | ❔ | ❔ | ✔
| [Medusa](https://pymedusa.com/) | ❌ | ✔ | ✔

### Key

||||
| - | - | - |
| yes | no | yes (with help) |

----

## Features
### Easy login
You can log into Plex using either an access token, your credentials, or Ombi (if setup).

### Download (![download icon](https://github.com/SpaceK33z/web-to-plex/blob/master/src/img/16.png))
On certain sites (denoted with the "download" icon), the user can choose to save/engage media directly, instead of waiting for their NZB manager to find the item.

### Plex It! (![plex it icon](https://github.com/SpaceK33z/web-to-plex/blob/master/src/img/plexit.16.png))
Click the icon to open **Plex It!** (left sidebar), click it again to add the current item(s) to your list.

If you don't feel like actually downloading the movie, or want a simple watchlist, you can also use the built-in "Plex It!" feature to bookmark the current page.
It's primary purpose is to provide a watchlist service on sites that don't support watchlists.

### Hide Web to Plex (![hide icon](https://github.com/SpaceK33z/web-to-plex/blob/master/src/img/hide.16.png))
Use this to hide the **Web to Plex** button. It changes the button's opacity to 10% to make it almost invisible so that it isn't as distracting on sites like Netflix.

### Reload Web to Plex (![reload icon](https://github.com/SpaceK33z/web-to-plex/blob/master/src/img/reload.16.png))
Use this to reload **Web to Plex** on the current page. This can sometimes fix loading issues or cache errors.

### Plex URL
This is a *moderately advance* setting, but is very useful to know. If you know your Plex server's URL (e.g. `https://localhost:32400`), then you can specify this and avoid bandwidth usage, as the extension will communicate with Plex on your device instead of `https://app.plex.tv/`.

### Find this | Right Click
If you aren't satisfied with a found item, or it is incorrect, you can right click the page and use the **Web to Plex | Find "XYZ"** feature to search for the item.

The sites used as search engines (IMDb, TMDb, and TVDb) will automatically create a cached version of the information (for "Local Search" results).

--------

## Supported sites

*Given in order of completion*

1. [Movieo](http://movieo.me/)
2. [IMDb](http://imdb.com/)
3. [Trakt.tv](https://trakt.tv/)
Expand All @@ -76,11 +87,13 @@ If you don't feel like actually downloading the movie, or want a simple watchlis
23. [Toloka](https://toloka.to/)<sup>6</sup>
24. [Shana Project](https://www.shanaproject.com/)<sup>6</sup>
25. [My Anime List](https://myanimelist.com/)<sup>6</sup>
26. [YouTube](https://youtube.com/)
27. [Flickmetrix (Cinesift)](https://flickmetrix.com/)
28. [Allociné](https://www.allocine.fr/)
29. [MovieMeter](https://www.moviemeter.nl/)
30. [JustWatch](https://justwatch.com/)
26. [My Shows](https://en.myshows.me/)
27. [YouTube](https://youtube.com/)
28. [Flickmetrix (Cinesift)](https://flickmetrix.com/)
29. [Allociné](https://www.allocine.fr/)
30. [MovieMeter](https://www.moviemeter.nl/)
31. [JustWatch](https://justwatch.com/)
32. [Vumoo](https://vumoo.to/)<sup>1</sup>

*Notes*

Expand Down
Binary file modified src.crx
Binary file not shown.
Binary file modified src.zip
Binary file not shown.
92 changes: 86 additions & 6 deletions src/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ function ChangeStatus({ ITEM_ID, ITEM_TITLE, ITEM_TYPE, ID_PROVIDER, ITEM_YEAR,

let FILE_TITLE = ITEM_TITLE.replace(/\-/g, ' ').replace(/[\s\:]{2,}/g, ' - ').replace(/[^\w\s\-\']+/g, ''),
// File friendly title
SEARCH_TITLE = ITEM_TITLE.replace(/[\-\s]+/g, '-').replace(/[^\w\-]+/g, ''),
SEARCH_TITLE = ITEM_TITLE.replace(/[\-\s]+/g, '-').replace(/\s*&\s*/g, ' and ').replace(/[^\w\-\'\*\#]+/g, ''),
// Search friendly title
SEARCH_PROVIDER = /[it]m/i.test(ID_PROVIDER)? 'GX': 'GG';
SEARCH_PROVIDER = /^im/i.test(ID_PROVIDER)? 'VO': /^tm/i.test(ID_PROVIDER)? 'GX': 'GG';

ITEM_ID = (ITEM_ID && !/^tt$/i.test(ITEM_ID)? ITEM_ID: '') + '';
ITEM_ID = ITEM_ID.replace(/^.*\b(tt\d+)\b.*$/, '$1').replace(/^.*\bid=(\d+)\b.*$/, '$1').replace(/^.*(?:movie|tv|(?:tv-?)?(?:shows?|series|episodes?))\/(\d+).*$/, '$1');
Expand Down Expand Up @@ -94,7 +94,7 @@ function ChangeStatus({ ITEM_ID, ITEM_TITLE, ITEM_TYPE, ID_PROVIDER, ITEM_YEAR,
});

chrome.contextMenus.update('W2P-XX', {
title: `Find on ${ (SEARCH_PROVIDER == 'GX'? 'GoStream': 'Google') }`,
title: `Find on ${ (SEARCH_PROVIDER == 'VO'? 'Vumoo': SEARCH_PROVIDER == 'GX'? 'GoStream': 'Google') }`,
checked: false
});
}
Expand Down Expand Up @@ -342,6 +342,80 @@ function addSonarr(request, sendResponse) {
});
}

/** Medusa - TV Shows **/
function addMedusa(request, sendResponse) {
let headers = {
'Content-Type': 'application/json',
'X-Api-Key': request.token,
...(new Headers(request.basicAuth))
},
id = request.tvdbId,
query = request.title.replace(/\s+/g, '+'),
debug = { headers, query, request };
// setup stack trace for debugging

fetch(debug.url = `${ request.root }internal/searchIndexersForShowName?api_key=${ request.token }&indexerId=0&query=${ query }`)
.then(response => response.json())
.catch(error => sendResponse({ error: 'TV Show not found', location: 'addMedusa => fetch.then.catch', silent: true }))
.then(data => {
data = data.results;

if (!data instanceof Array || !data.length)
throw new Error('TV Show not found');

// Monitor, search, and download series ASAP
let body = data[0].join('|');

terminal.group('Generated URL');
terminal.log('URL', request.url);
terminal.log('Head', headers);
terminal.log('Body', body);
terminal.groupEnd();

return debug.body = body;
})
.then(body => {
return fetch(`${ request.url }`, debug.requestHeaders = {
method: 'POST',
mode: cors(request.url),
body: JSON.stringify({ id: { tvdb: request.tvdbId } }),
headers
});
})
.then(response => response.text())
.then(data => {
let path = request.StoragePath.replace(/\\?$/, '\\');

debug.data =
data = JSON.parse(data || `{"path":"${ path }${ request.title } (${ request.year })"}`);

if (data && data.error) {
sendResponse({
error: data.error,
location: `addMedusa => fetch("${ request.url }", { headers }).then(data => { if })`,
debug
});
} else if (data && data.id) {
sendResponse({
success: `Added to ${ path }${ request.title }(${ request.year })`
});
} else {
sendResponse({
error: 'Unknown error',
location: `addMedusa => fetch("${ request.url }", { headers }).then(data => { else })`,
debug
});
}
})
.catch(error => {
sendResponse({
error: String(error),
location: `addMedusa => fetch("${ request.url }", { headers }).catch(error => { sendResponse })`,
debug
});
});
}

/** Ombi* - TV Shows/Movies **/
function addOmbi(request, sendResponse) {
let headers = {
Expand Down Expand Up @@ -536,20 +610,22 @@ chrome.contextMenus.onClicked.addListener(item => {
case 'im':
url = (qu && pv == 'im')?
`imdb.com/title/${ qu }/`:
`imdb.com/find?ref_=nv_sr_fn&s=all&q=${ tl }`;
`imdb.com/find?ref_=nv_sr_fn&s=all&q=${ tt }`;
break;
case 'tm':
url = (qu && pv == 'tm')?
`themoviedb.org/${ external.ITEM_TYPE == 'show'? 'tv': 'movie' }/${ qu }`:
`themoviedb.org/search?query=${ tl }`;
`themoviedb.org/search?query=${ tt }`;
break;
case 'tv':
url = (qu && pv == 'tv')?
`thetvdb.com/series/${ tl }#${ qu }`: // TVDb accepts either: a title, or a series number... but only one
`thetvdb.com/search?q=${ p(tl) }`;
break;
case 'xx':
url = external.SEARCH_PROVIDER == 'GX'?
url = external.SEARCH_PROVIDER == 'VO'?
`google.com/search?q=${ p(tl) }+site:vumoo.to`:
external.SEARCH_PROVIDER == 'GX'?
`gostream.site/?s=${ p(tl) }`:
`google.com/search?q="${ p(tl, ' ') } ${ yr }"+${ pv }db`;
break;
Expand Down Expand Up @@ -607,6 +683,9 @@ chrome.runtime.onMessage.addListener((request, sender, callback) => {
case 'ADD_SONARR':
addSonarr(request, callback);
return true;
case 'ADD_MEDUSA':
addMedusa(request, callback);
return true;
case 'ADD_WATCHER':
addWatcher(request, callback);
return true;
Expand Down Expand Up @@ -647,6 +726,7 @@ chrome.runtime.onMessage.addListener((request, sender, callback) => {
case 'PLUGIN':
case 'SCRIPT':
case '_INIT_':
case '$INIT$':
case 'FOUND':
/* These are meant to be handled by plugn.js */
return false;
Expand Down
2 changes: 1 addition & 1 deletion src/cloud/__layout__.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ let script = {
"ready": () => { /* return a boolean to describe if the page is ready */ },

// optional
"timeout": 1000, // if the script fails to complete, retry after ... milisecoonds
"timeout": 1000, // if the script fails to complete, retry after ... milliseconds

// required
"init": (ready) => {
Expand Down
37 changes: 37 additions & 0 deletions src/cloud/__test__.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
let script = {
// required
"url": "*://ephellon.github.io/web.to.plex/test/*",
// Example: *://*.amazon.com/*/video/(detail|buy)/*
// *:// - match any protocol (http, https, etc.)
// *.amazon.com - match any sub-domain (www, ww5, etc.)
// /* - match any path
// (detail|buy) - match one of the items

// optional
"ready": () => {
/* return a boolean to describe if the page is ready */
return true;
},

// optional
"timeout": 1000, // if the script fails to complete, retry after ... milliseconds

// required
"init": (ready) => {
let _title, _year, _image, R = RegExp;

let title = $('#title').first,
year = $('#year').first,
image = $('#poster').first,
type = script.getType(); // described below

title = title.textContent;
year = +year.textContent;
image = image.src || '';

return { type, title, year, image };
},

// optional | functioanlity only
"getType": () => $('#example').first.getAttribute('type'),
};
6 changes: 4 additions & 2 deletions src/cloud/fandango.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
let script = {
"url": "*://*.fandango.com/movie-overview/*",
"url": "*://*.fandango.com/[\\w\\-]+/movie-overview",

"init": (ready) => {
let _title, _year, _image, R = RegExp;
Expand All @@ -11,7 +11,9 @@ let script = {

title = title.textContent.trim().split(/\n+/)[0].trim();
year = year.textContent.replace(/.*(\d{4}).*/, '$1').trim();
image = image.empty? '': image.first.src;
image = image.empty? '': image.src;

title = title.replace(RegExp(`\\s*\\((${ year })\\)`), '');

return { type, title, year, image };
},
Expand Down
27 changes: 27 additions & 0 deletions src/cloud/google.play.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
let script = {
"url": "*://play.google.com/store/(movies|tv)/details/*",

"init": (ready) => {
let _title, _year, _image, R = RegExp;

let type = script.getType(),
title = $('h1').first,
year = $(`h1 ~ div span:${ type == 'movie'? 'first': 'last' }-of-type`).first,
image = $('img[alt="cover art" i]').first;

title = title.textContent.replace(/\s*\(\s*(\d{4})\s*\).*?$/, '').trim();
year = (year.textContent || R.$1).replace(/^.*?(\d{4})/, '$1').trim();
image = (image || {}).src;

return { type, title, year, image };
},

"getType": () => (
location.pathname.startsWith('/store/movies')?
'movie':
'show'
),
};

addEventListener('popstate', script.init);
addEventListener('pushstate-changed', script.init);
2 changes: 1 addition & 1 deletion src/cloud/gostream.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ let script = {
image = $('.hiddenz, [itemprop="image"]').first,
type = 'movie';

new Notification('update', 'Select the Openload (OL) server');
Notify('update', 'Select the Openload (OL) server');

title = title.textContent.trim();
year = (year? year.textContent.trim(): 0);
Expand Down
Loading

0 comments on commit 5856c5e

Please sign in to comment.