updating latest plexposters
This commit is contained in:
78
plex-posters/__dev/create-config.txt
Normal file
78
plex-posters/__dev/create-config.txt
Normal file
@@ -0,0 +1,78 @@
|
||||
Creating a config class
|
||||
|
||||
can have a toml/ini in ~/.config/module/config.toml to read the values in
|
||||
|
||||
os.path.expanduser('~') - expands the tilde to the home directory
|
||||
|
||||
suggestion: save configs in ~/.config/module
|
||||
|
||||
os.environ.get('VIRTUAL_ENVs', expand) - will get the env variable and fall back to the default afterwards if its not specified.
|
||||
|
||||
Method to read from an os env, and then fall back on another way if it doesnt exist:
|
||||
|
||||
def get(self, key, default=None, cast=None):
|
||||
""" Returns the specified configuration value or <default> if not found.
|
||||
Parameters:
|
||||
key (str): Configuration variable to load in the format '<section>.<variable>'.
|
||||
default: Default value to use if key not found.
|
||||
cast (func): Cast the value to the specified type before returning.
|
||||
"""
|
||||
try:
|
||||
# First: check environment variable is set
|
||||
envkey = 'PLEXAPI_%s' % key.upper().replace('.', '_')
|
||||
value = os.environ.get(envkey)
|
||||
if value is None:
|
||||
# Second: check the config file has attr
|
||||
section, name = key.lower().split('.')
|
||||
value = self.data.get(section, {}).get(name, default)
|
||||
return cast(value) if cast else value
|
||||
except: # noqa: E722
|
||||
return default
|
||||
|
||||
|
||||
- To open a config .toml:
|
||||
toml.load(file) where file has a default value of the ~/.config/module/module.toml
|
||||
If the toml file doesn't exist, nor has a path been passed in, pass and fall back to other methods (os envs, cli)
|
||||
|
||||
- Have a get method, that checks the config file for the result, and then tries the env variable.
|
||||
|
||||
|
||||
|
||||
-- set the path to the toml in the __init__.py, check for a config file override path and fall back to default if not
|
||||
|
||||
# Load User Defined Config
|
||||
DEFAULT_CONFIG_PATH = os.path.expanduser('~/.config/plexapi/config.ini')
|
||||
CONFIG_PATH = os.environ.get('PLEXAPI_CONFIG_PATH', DEFAULT_CONFIG_PATH)
|
||||
CONFIG = PlexConfig(CONFIG_PATH)
|
||||
|
||||
- each module/submodule should have the header set to the section it corresponds to in the .toml file.
|
||||
|
||||
e.g a reddit module that needs access to the reddit options should have
|
||||
__section__ = 'reddit'
|
||||
|
||||
this would correspond to
|
||||
[reddit]
|
||||
PLEXPOSTERS_REDDIT_ env var
|
||||
|
||||
|
||||
-- the __init__ of the module should instantiate this config class:
|
||||
|
||||
# Load User Defined Config
|
||||
DEFAULT_CONFIG_PATH = os.path.expanduser('~/.config/plexapi/config.ini')
|
||||
CONFIG_PATH = os.environ.get('PLEXAPI_CONFIG_PATH', DEFAULT_CONFIG_PATH)
|
||||
CONFIG = PlexConfig(CONFIG_PATH)
|
||||
|
||||
other modules can import this instantiated class
|
||||
|
||||
the __init__ of the module should also set all the default values as capital vars e.g.
|
||||
|
||||
PLEX_USERNAME = plexPosterConfig.get(f'{__section__}.username')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
28
plex-posters/__dev/toml-layout.txt
Normal file
28
plex-posters/__dev/toml-layout.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
[name]
|
||||
|
||||
[name.module]
|
||||
anything generic to the module
|
||||
|
||||
[name.header]
|
||||
specific values for different sections
|
||||
|
||||
[name.logging]
|
||||
logging configurations
|
||||
|
||||
|
||||
|
||||
|
||||
[plexapi]
|
||||
|
||||
[plexapi.reddit]
|
||||
client_id =
|
||||
client_secret =
|
||||
user_agent =
|
||||
|
||||
[plexapi.logging]
|
||||
backup_count = 3
|
||||
format = "%(asctime)s %(module)12s:%(lineno)-4s %(levelname)-9s %(message)s"
|
||||
level = "INFO"
|
||||
path = ~/.config/plexapi/plexapi.log
|
||||
rotate_bytes = 512000
|
||||
secrets = false
|
||||
294
plex-posters/html/plex_posters/config/index.html
Normal file
294
plex-posters/html/plex_posters/config/index.html
Normal file
@@ -0,0 +1,294 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.7.2" />
|
||||
<title>plex_posters.config API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css' rel='stylesheet'>
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/8.0.0/sanitize.min.css' rel='stylesheet'>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" rel="stylesheet">
|
||||
<style>.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{font-weight:bold}#index h4 + ul{margin-bottom:.6em}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>plex_posters.config</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">from plex_posters.lib import export
|
||||
import toml
|
||||
import os
|
||||
from typing import Union
|
||||
|
||||
__all__ = []
|
||||
|
||||
|
||||
@export
|
||||
class plexPosterConfig:
|
||||
|
||||
"""Handles the config options for the module
|
||||
|
||||
Attributes
|
||||
----------
|
||||
config_file : dict
|
||||
Contains the config options. See `plexPosterConfig.read_config()`
|
||||
for the data structure.
|
||||
"""
|
||||
|
||||
def __init__(self, path: str) -> None:
|
||||
self.config_file = self.read_config(path)
|
||||
|
||||
@staticmethod
|
||||
def read_config(path: str) -> Union[dict, None]:
|
||||
|
||||
"""Reads the toml config file from `path` if it exists.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : str
|
||||
Path to config file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Union[dict, None]
|
||||
Returns a dict if the file is found else returns nothing.
|
||||
|
||||
The dict contains a key for each header. Each key contains a
|
||||
dictionary containing a key, value pair for each config under
|
||||
that header.
|
||||
|
||||
Example:
|
||||
|
||||
[plex_posters]
|
||||
foo = bar
|
||||
|
||||
Returns a dict: {'plex_posters' : {'foo': 'bar'}}
|
||||
"""
|
||||
|
||||
path += 'config.toml' if path[-1] == '/' else '/config.toml'
|
||||
|
||||
try:
|
||||
with open(path, 'r+') as config_file:
|
||||
config_file = toml.load(config_file)
|
||||
return config_file
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
def get(self, key: str, default: str = None, cast: callable = None):
|
||||
pass
|
||||
|
||||
|
||||
inst = plexPosterConfig(
|
||||
os.path.expanduser('~/.config/plex-posters/')
|
||||
)
|
||||
|
||||
print(inst.config_file)</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="plex_posters.config.plexPosterConfig"><code class="flex name class">
|
||||
<span>class <span class="ident">plexPosterConfig</span></span>
|
||||
<span>(</span><span>path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"><p>Handles the config options for the module</p>
|
||||
<h2 id="attributes">Attributes</h2>
|
||||
<dl>
|
||||
<dt><strong><code>config_file</code></strong> : <code>dict</code></dt>
|
||||
<dd>Contains the config options. See <a title="plex_posters.config.plexPosterConfig.read_config" href="#plex_posters.config.plexPosterConfig.read_config"><code>plexPosterConfig.read_config()</code></a>
|
||||
for the data structure.</dd>
|
||||
</dl></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class plexPosterConfig:
|
||||
|
||||
"""Handles the config options for the module
|
||||
|
||||
Attributes
|
||||
----------
|
||||
config_file : dict
|
||||
Contains the config options. See `plexPosterConfig.read_config()`
|
||||
for the data structure.
|
||||
"""
|
||||
|
||||
def __init__(self, path: str) -> None:
|
||||
self.config_file = self.read_config(path)
|
||||
|
||||
@staticmethod
|
||||
def read_config(path: str) -> Union[dict, None]:
|
||||
|
||||
"""Reads the toml config file from `path` if it exists.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : str
|
||||
Path to config file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Union[dict, None]
|
||||
Returns a dict if the file is found else returns nothing.
|
||||
|
||||
The dict contains a key for each header. Each key contains a
|
||||
dictionary containing a key, value pair for each config under
|
||||
that header.
|
||||
|
||||
Example:
|
||||
|
||||
[plex_posters]
|
||||
foo = bar
|
||||
|
||||
Returns a dict: {'plex_posters' : {'foo': 'bar'}}
|
||||
"""
|
||||
|
||||
path += 'config.toml' if path[-1] == '/' else '/config.toml'
|
||||
|
||||
try:
|
||||
with open(path, 'r+') as config_file:
|
||||
config_file = toml.load(config_file)
|
||||
return config_file
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
def get(self, key: str, default: str = None, cast: callable = None):
|
||||
pass</code></pre>
|
||||
</details>
|
||||
<h3>Static methods</h3>
|
||||
<dl>
|
||||
<dt id="plex_posters.config.plexPosterConfig.read_config"><code class="name flex">
|
||||
<span>def <span class="ident">read_config</span></span>(<span>path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"><p>Reads the toml config file from <code>path</code> if it exists.</p>
|
||||
<h2 id="parameters">Parameters</h2>
|
||||
<dl>
|
||||
<dt><strong><code>path</code></strong> : <code>str</code></dt>
|
||||
<dd>Path to config file.</dd>
|
||||
</dl>
|
||||
<h2 id="returns">Returns</h2>
|
||||
<dl>
|
||||
<dt><code>Union</code>[<code>dict</code>, <code>None</code>]</dt>
|
||||
<dd>
|
||||
<p>Returns a dict if the file is found else returns nothing.</p>
|
||||
<p>The dict contains a key for each header. Each key contains a
|
||||
dictionary containing a key, value pair for each config under
|
||||
that header.</p>
|
||||
<p>Example:</p>
|
||||
<p>[plex_posters]
|
||||
foo = bar</p>
|
||||
<p>Returns a dict: {'plex_posters' : {'foo': 'bar'}}</p>
|
||||
</dd>
|
||||
</dl></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@staticmethod
|
||||
def read_config(path: str) -> Union[dict, None]:
|
||||
|
||||
"""Reads the toml config file from `path` if it exists.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : str
|
||||
Path to config file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Union[dict, None]
|
||||
Returns a dict if the file is found else returns nothing.
|
||||
|
||||
The dict contains a key for each header. Each key contains a
|
||||
dictionary containing a key, value pair for each config under
|
||||
that header.
|
||||
|
||||
Example:
|
||||
|
||||
[plex_posters]
|
||||
foo = bar
|
||||
|
||||
Returns a dict: {'plex_posters' : {'foo': 'bar'}}
|
||||
"""
|
||||
|
||||
path += 'config.toml' if path[-1] == '/' else '/config.toml'
|
||||
|
||||
try:
|
||||
with open(path, 'r+') as config_file:
|
||||
config_file = toml.load(config_file)
|
||||
return config_file
|
||||
except FileNotFoundError:
|
||||
pass</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="plex_posters.config.plexPosterConfig.get"><code class="name flex">
|
||||
<span>def <span class="ident">get</span></span>(<span>self, key, default=None, cast=None)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def get(self, key: str, default: str = None, cast: callable = None):
|
||||
pass</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="plex_posters" href="../index.html">plex_posters</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="plex_posters.config.plexPosterConfig" href="#plex_posters.config.plexPosterConfig">plexPosterConfig</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="plex_posters.config.plexPosterConfig.get" href="#plex_posters.config.plexPosterConfig.get">get</a></code></li>
|
||||
<li><code><a title="plex_posters.config.plexPosterConfig.read_config" href="#plex_posters.config.plexPosterConfig.read_config">read_config</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.7.2</a>.</p>
|
||||
</footer>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
|
||||
<script>hljs.initHighlightingOnLoad()</script>
|
||||
</body>
|
||||
</html>
|
||||
379
plex-posters/html/plex_posters/index.html
Normal file
379
plex-posters/html/plex_posters/index.html
Normal file
@@ -0,0 +1,379 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.7.2" />
|
||||
<title>plex_posters API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css' rel='stylesheet'>
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/8.0.0/sanitize.min.css' rel='stylesheet'>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" rel="stylesheet">
|
||||
<style>.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{font-weight:bold}#index h4 + ul{margin-bottom:.6em}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>plex_posters</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">from __future__ import annotations
|
||||
from .__version__ import __version__ # noqa
|
||||
from .lib import export
|
||||
from typing import Type, TypeVar, List, Dict
|
||||
import praw # type: ignore
|
||||
import requests
|
||||
|
||||
__all__ = [] # type: List
|
||||
|
||||
|
||||
T_movie_poster_porn_scraper = TypeVar(
|
||||
'T_movie_poster_porn_scraper', bound="movie_poster_porn_scraper"
|
||||
)
|
||||
|
||||
|
||||
@export
|
||||
class movie_poster_porn_scraper(object):
|
||||
|
||||
"""Poster scraper
|
||||
|
||||
Attributes
|
||||
----------
|
||||
reddit_instance : praw.Reddit
|
||||
A praw instance connected to Reddit
|
||||
"""
|
||||
|
||||
def __init__(self, instance: praw.Reddit) -> None:
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
instance : praw.Reddit
|
||||
A praw instance connected to Reddit
|
||||
"""
|
||||
super().__init__()
|
||||
self.reddit_instance = instance
|
||||
|
||||
@classmethod
|
||||
def create_instance(
|
||||
cls: Type[T_movie_poster_porn_scraper],
|
||||
client_id: str,
|
||||
client_secret: str,
|
||||
user_agent: str,
|
||||
) -> T_movie_poster_porn_scraper:
|
||||
"""`classmethod` to connect to reddit using the api.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
client_id : str
|
||||
a valid client id
|
||||
client_secret : str
|
||||
the secret key for the client
|
||||
user_agent : str
|
||||
a user agent
|
||||
"""
|
||||
reddit_instance = praw.Reddit(
|
||||
client_id=client_id,
|
||||
client_secret=client_secret,
|
||||
user_agent=user_agent,
|
||||
)
|
||||
|
||||
return cls(reddit_instance)
|
||||
|
||||
def get_hot_posters(
|
||||
self,
|
||||
) -> T_movie_poster_porn_scraper:
|
||||
"""
|
||||
"""
|
||||
self._poster_urls: Dict = {}
|
||||
for post in self.reddit_instance.subreddit('MoviePosterPorn').hot(
|
||||
limit=10
|
||||
):
|
||||
print(post.title)
|
||||
print(post.url)
|
||||
# print(dir(post))
|
||||
# self._poster_urls.append(post.url)
|
||||
self._poster_urls[post.title] = post.url
|
||||
print(self._poster_urls)
|
||||
return self
|
||||
|
||||
def get_posters(self):
|
||||
"""download the posters
|
||||
|
||||
Returns
|
||||
-------
|
||||
self
|
||||
"""
|
||||
for title, url in self._poster_urls.items():
|
||||
r = requests.get(url)
|
||||
with open('posters/' + title + '.jpg', 'wb') as p:
|
||||
p.write(r.content)
|
||||
return self</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-submodules">Sub-modules</h2>
|
||||
<dl>
|
||||
<dt><code class="name"><a title="plex_posters.config" href="config/index.html">plex_posters.config</a></code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="plex_posters.lib" href="lib/index.html">plex_posters.lib</a></code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="plex_posters.movie_poster_porn_scraper"><code class="flex name class">
|
||||
<span>class <span class="ident">movie_poster_porn_scraper</span></span>
|
||||
<span>(</span><span>instance)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"><p>Poster scraper</p>
|
||||
<h2 id="attributes">Attributes</h2>
|
||||
<dl>
|
||||
<dt><strong><code>reddit_instance</code></strong> : <code>praw.Reddit</code></dt>
|
||||
<dd>A praw instance connected to Reddit</dd>
|
||||
</dl>
|
||||
<h2 id="parameters">Parameters</h2>
|
||||
<dl>
|
||||
<dt><strong><code>instance</code></strong> : <code>praw.Reddit</code></dt>
|
||||
<dd>A praw instance connected to Reddit</dd>
|
||||
</dl></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class movie_poster_porn_scraper(object):
|
||||
|
||||
"""Poster scraper
|
||||
|
||||
Attributes
|
||||
----------
|
||||
reddit_instance : praw.Reddit
|
||||
A praw instance connected to Reddit
|
||||
"""
|
||||
|
||||
def __init__(self, instance: praw.Reddit) -> None:
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
instance : praw.Reddit
|
||||
A praw instance connected to Reddit
|
||||
"""
|
||||
super().__init__()
|
||||
self.reddit_instance = instance
|
||||
|
||||
@classmethod
|
||||
def create_instance(
|
||||
cls: Type[T_movie_poster_porn_scraper],
|
||||
client_id: str,
|
||||
client_secret: str,
|
||||
user_agent: str,
|
||||
) -> T_movie_poster_porn_scraper:
|
||||
"""`classmethod` to connect to reddit using the api.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
client_id : str
|
||||
a valid client id
|
||||
client_secret : str
|
||||
the secret key for the client
|
||||
user_agent : str
|
||||
a user agent
|
||||
"""
|
||||
reddit_instance = praw.Reddit(
|
||||
client_id=client_id,
|
||||
client_secret=client_secret,
|
||||
user_agent=user_agent,
|
||||
)
|
||||
|
||||
return cls(reddit_instance)
|
||||
|
||||
def get_hot_posters(
|
||||
self,
|
||||
) -> T_movie_poster_porn_scraper:
|
||||
"""
|
||||
"""
|
||||
self._poster_urls: Dict = {}
|
||||
for post in self.reddit_instance.subreddit('MoviePosterPorn').hot(
|
||||
limit=10
|
||||
):
|
||||
print(post.title)
|
||||
print(post.url)
|
||||
# print(dir(post))
|
||||
# self._poster_urls.append(post.url)
|
||||
self._poster_urls[post.title] = post.url
|
||||
print(self._poster_urls)
|
||||
return self
|
||||
|
||||
def get_posters(self):
|
||||
"""download the posters
|
||||
|
||||
Returns
|
||||
-------
|
||||
self
|
||||
"""
|
||||
for title, url in self._poster_urls.items():
|
||||
r = requests.get(url)
|
||||
with open('posters/' + title + '.jpg', 'wb') as p:
|
||||
p.write(r.content)
|
||||
return self</code></pre>
|
||||
</details>
|
||||
<h3>Static methods</h3>
|
||||
<dl>
|
||||
<dt id="plex_posters.movie_poster_porn_scraper.create_instance"><code class="name flex">
|
||||
<span>def <span class="ident">create_instance</span></span>(<span>client_id, client_secret, user_agent)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"><p><code>classmethod</code> to connect to reddit using the api.</p>
|
||||
<h2 id="parameters">Parameters</h2>
|
||||
<dl>
|
||||
<dt><strong><code>client_id</code></strong> : <code>str</code></dt>
|
||||
<dd>a valid client id</dd>
|
||||
<dt><strong><code>client_secret</code></strong> : <code>str</code></dt>
|
||||
<dd>the secret key for the client</dd>
|
||||
<dt><strong><code>user_agent</code></strong> : <code>str</code></dt>
|
||||
<dd>a user agent</dd>
|
||||
</dl></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@classmethod
|
||||
def create_instance(
|
||||
cls: Type[T_movie_poster_porn_scraper],
|
||||
client_id: str,
|
||||
client_secret: str,
|
||||
user_agent: str,
|
||||
) -> T_movie_poster_porn_scraper:
|
||||
"""`classmethod` to connect to reddit using the api.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
client_id : str
|
||||
a valid client id
|
||||
client_secret : str
|
||||
the secret key for the client
|
||||
user_agent : str
|
||||
a user agent
|
||||
"""
|
||||
reddit_instance = praw.Reddit(
|
||||
client_id=client_id,
|
||||
client_secret=client_secret,
|
||||
user_agent=user_agent,
|
||||
)
|
||||
|
||||
return cls(reddit_instance)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="plex_posters.movie_poster_porn_scraper.get_hot_posters"><code class="name flex">
|
||||
<span>def <span class="ident">get_hot_posters</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def get_hot_posters(
|
||||
self,
|
||||
) -> T_movie_poster_porn_scraper:
|
||||
"""
|
||||
"""
|
||||
self._poster_urls: Dict = {}
|
||||
for post in self.reddit_instance.subreddit('MoviePosterPorn').hot(
|
||||
limit=10
|
||||
):
|
||||
print(post.title)
|
||||
print(post.url)
|
||||
# print(dir(post))
|
||||
# self._poster_urls.append(post.url)
|
||||
self._poster_urls[post.title] = post.url
|
||||
print(self._poster_urls)
|
||||
return self</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="plex_posters.movie_poster_porn_scraper.get_posters"><code class="name flex">
|
||||
<span>def <span class="ident">get_posters</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"><p>download the posters</p>
|
||||
<h2 id="returns">Returns</h2>
|
||||
<dl>
|
||||
<dt><code>self</code></dt>
|
||||
<dd> </dd>
|
||||
</dl></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def get_posters(self):
|
||||
"""download the posters
|
||||
|
||||
Returns
|
||||
-------
|
||||
self
|
||||
"""
|
||||
for title, url in self._poster_urls.items():
|
||||
r = requests.get(url)
|
||||
with open('posters/' + title + '.jpg', 'wb') as p:
|
||||
p.write(r.content)
|
||||
return self</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3><a href="#header-submodules">Sub-modules</a></h3>
|
||||
<ul>
|
||||
<li><code><a title="plex_posters.config" href="config/index.html">plex_posters.config</a></code></li>
|
||||
<li><code><a title="plex_posters.lib" href="lib/index.html">plex_posters.lib</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="plex_posters.movie_poster_porn_scraper" href="#plex_posters.movie_poster_porn_scraper">movie_poster_porn_scraper</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="plex_posters.movie_poster_porn_scraper.create_instance" href="#plex_posters.movie_poster_porn_scraper.create_instance">create_instance</a></code></li>
|
||||
<li><code><a title="plex_posters.movie_poster_porn_scraper.get_hot_posters" href="#plex_posters.movie_poster_porn_scraper.get_hot_posters">get_hot_posters</a></code></li>
|
||||
<li><code><a title="plex_posters.movie_poster_porn_scraper.get_posters" href="#plex_posters.movie_poster_porn_scraper.get_posters">get_posters</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.7.2</a>.</p>
|
||||
</footer>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
|
||||
<script>hljs.initHighlightingOnLoad()</script>
|
||||
</body>
|
||||
</html>
|
||||
35
plex-posters/poetry.lock
generated
35
plex-posters/poetry.lock
generated
@@ -14,6 +14,12 @@ optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "19.3.0"
|
||||
|
||||
[package.extras]
|
||||
azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"]
|
||||
dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"]
|
||||
docs = ["sphinx", "zope.interface"]
|
||||
tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
@@ -68,6 +74,9 @@ mypy-extensions = ">=0.4.0,<0.5.0"
|
||||
typed-ast = ">=1.4.0,<1.5.0"
|
||||
typing-extensions = ">=3.7.4"
|
||||
|
||||
[package.extras]
|
||||
dmypy = ["psutil (>=4.0)"]
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Experimental type system extensions for programs checked with the mypy typechecker."
|
||||
@@ -84,6 +93,9 @@ optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "0.13.1"
|
||||
|
||||
[package.extras]
|
||||
dev = ["pre-commit", "tox"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "PRAW, an acronym for `Python Reddit API Wrapper`, is a python package that allows for simple access to reddit's API."
|
||||
@@ -97,6 +109,9 @@ prawcore = ">=1.0.1,<2.0"
|
||||
update-checker = ">=0.16"
|
||||
websocket-client = ">=0.54.0"
|
||||
|
||||
[package.extras]
|
||||
dev = ["pre-commit"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Low-level communication layer for PRAW 4+."
|
||||
@@ -168,6 +183,10 @@ chardet = ">=3.0.2,<3.1.0"
|
||||
idna = ">=2.5,<2.9"
|
||||
urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26"
|
||||
|
||||
[package.extras]
|
||||
security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)"]
|
||||
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python 2 and 3 compatibility utilities"
|
||||
@@ -176,6 +195,14 @@ optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*"
|
||||
version = "1.13.0"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python Library for Tom's Obvious, Minimal Language"
|
||||
name = "toml"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.10.0"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "a fork of Python 2 and 3 ast modules with type comment support"
|
||||
@@ -211,6 +238,11 @@ optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4"
|
||||
version = "1.25.7"
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotlipy (>=0.6.0)"]
|
||||
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
|
||||
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "A full-featured console (xterm et al.) user interface library"
|
||||
@@ -231,7 +263,7 @@ version = "0.56.0"
|
||||
six = "*"
|
||||
|
||||
[metadata]
|
||||
content-hash = "3fb939a7e78632a796efbfa0c358369ccd78a148d5649cd2894380f6e82d5409"
|
||||
content-hash = "535a624cacbbf26a39bef9870a9f37106b05293cfd93a0b05be181cab1f57628"
|
||||
python-versions = "^3.8"
|
||||
|
||||
[metadata.hashes]
|
||||
@@ -253,6 +285,7 @@ pygments = ["71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127",
|
||||
pytest = ["3f193df1cfe1d1609d4c583838bea3d532b18d6160fd3f55c9447fdca30848ec", "e246cf173c01169b9617fc07264b7b1316e78d7a650055235d6d897bc80d9660"]
|
||||
requests = ["11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", "9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"]
|
||||
six = ["1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd", "30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"]
|
||||
toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"]
|
||||
typed-ast = ["1170afa46a3799e18b4c977777ce137bb53c7485379d9706af8a59f2ea1aa161", "18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", "262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", "2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", "354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", "48e5b1e71f25cfdef98b013263a88d7145879fbb2d5185f2a0c79fa7ebbeae47", "4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", "630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", "66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", "71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", "7954560051331d003b4e2b3eb822d9dd2e376fa4f6d98fee32f452f52dd6ebb2", "838997f4310012cf2e1ad3803bce2f3402e9ffb71ded61b5ee22617b3a7f6b6e", "95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", "bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", "cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", "d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", "d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", "d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", "fdc1c9bbf79510b76408840e009ed65958feba92a88833cdceecff93ae8fff66", "ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12"]
|
||||
typing-extensions = ["091ecc894d5e908ac75209f10d5b4f118fbdb2eb1ede6a63544054bb1edb41f2", "910f4656f54de5993ad9304959ce9bb903f90aadc7c67a0bef07e678014e892d", "cf8b63fedea4d89bab840ecbb93e75578af28f76f66c35889bd7065f5af88575"]
|
||||
update-checker = ["59cfad7f9a0ee99f95f1dfc60f55bf184937bcab46a7270341c2c33695572453", "70e39446fccf77b21192cf7a8214051fa93a636dc3b5c8b602b589d100a168b8"]
|
||||
|
||||
@@ -7,6 +7,7 @@ authors = ["dtomlinson <dtomlinson@panaetius.co.uk>"]
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
praw = "^6.4"
|
||||
toml = "^0.10.0"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pytest = "^3.0"
|
||||
|
||||
93
plex-posters/src/plex_posters/__dev/__init__.py
Normal file
93
plex-posters/src/plex_posters/__dev/__init__.py
Normal file
@@ -0,0 +1,93 @@
|
||||
from __future__ import annotations
|
||||
from .__version__ import __version__ # noqa
|
||||
from .lib import export
|
||||
from typing import Type, TypeVar, List, Dict
|
||||
import praw # type: ignore
|
||||
import requests
|
||||
|
||||
__all__ = [] # type: List
|
||||
|
||||
__header__ = 'plex_posters'
|
||||
# __section__ = 'module'
|
||||
|
||||
T_movie_poster_porn_scraper = TypeVar(
|
||||
'T_movie_poster_porn_scraper', bound="movie_poster_porn_scraper"
|
||||
)
|
||||
|
||||
|
||||
@export
|
||||
class movie_poster_porn_scraper(object):
|
||||
|
||||
"""Poster scraper
|
||||
|
||||
Attributes
|
||||
----------
|
||||
reddit_instance : praw.Reddit
|
||||
A praw instance connected to Reddit
|
||||
"""
|
||||
|
||||
def __init__(self, instance: praw.Reddit) -> None:
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
instance : praw.Reddit
|
||||
A praw instance connected to Reddit
|
||||
"""
|
||||
super().__init__()
|
||||
self.reddit_instance = instance
|
||||
|
||||
@classmethod
|
||||
def create_instance(
|
||||
cls: Type[T_movie_poster_porn_scraper],
|
||||
client_id: str,
|
||||
client_secret: str,
|
||||
user_agent: str,
|
||||
) -> T_movie_poster_porn_scraper:
|
||||
"""`classmethod` to connect to reddit using the api.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
client_id : str
|
||||
a valid client id
|
||||
client_secret : str
|
||||
the secret key for the client
|
||||
user_agent : str
|
||||
a user agent
|
||||
"""
|
||||
reddit_instance = praw.Reddit(
|
||||
client_id=client_id,
|
||||
client_secret=client_secret,
|
||||
user_agent=user_agent,
|
||||
)
|
||||
|
||||
return cls(reddit_instance)
|
||||
|
||||
def get_hot_posters(
|
||||
self,
|
||||
) -> T_movie_poster_porn_scraper:
|
||||
"""
|
||||
"""
|
||||
self._poster_urls: Dict = {}
|
||||
for post in self.reddit_instance.subreddit('MoviePosterPorn').hot(
|
||||
limit=10
|
||||
):
|
||||
print(post.title)
|
||||
print(post.url)
|
||||
# print(dir(post))
|
||||
# self._poster_urls.append(post.url)
|
||||
self._poster_urls[post.title] = post.url
|
||||
print(self._poster_urls)
|
||||
return self
|
||||
|
||||
def get_posters(self):
|
||||
"""download the posters
|
||||
|
||||
Returns
|
||||
-------
|
||||
self
|
||||
"""
|
||||
for title, url in self._poster_urls.items():
|
||||
r = requests.get(url)
|
||||
with open('posters/' + title + '.jpg', 'wb') as p:
|
||||
p.write(r.content)
|
||||
return self
|
||||
@@ -1,88 +1,35 @@
|
||||
from __future__ import annotations
|
||||
from .__version__ import __version__ # noqa
|
||||
from .lib import export
|
||||
from typing import Type, TypeVar, List, Dict
|
||||
import praw # type: ignore
|
||||
import requests
|
||||
from plex_posters.config import plexPosterConfig
|
||||
import logging
|
||||
|
||||
__all__ = [] # type: List
|
||||
__header__ = 'plex_posters'
|
||||
|
||||
|
||||
T_movie_poster_porn_scraper = TypeVar(
|
||||
'T_movie_poster_porn_scraper', bound="movie_poster_porn_scraper"
|
||||
# Load User Defined Config
|
||||
DEFAULT_CONFIG_PATH = os.path.expanduser('~/.config/plexapi/config.ini')
|
||||
CONFIG_PATH = os.environ.get('PLEXAPI_CONFIG_PATH', DEFAULT_CONFIG_PATH)
|
||||
_config = plexPosterConfig(CONFIG_PATH)
|
||||
|
||||
|
||||
# Logging Configuration
|
||||
log = logging.getLogger(__header__)
|
||||
logfile = CONFIG.get('log.path')
|
||||
logformat = CONFIG.get(
|
||||
'log.format',
|
||||
'%(asctime)s %(module)12s:%(lineno)-4s %(levelname)-9s %(message)s',
|
||||
)
|
||||
loglevel = CONFIG.get('log.level', 'INFO').upper()
|
||||
loghandler = logging.NullHandler()
|
||||
|
||||
if logfile: # pragma: no cover
|
||||
logbackups = CONFIG.get('log.backup_count', 3, int)
|
||||
logbytes = CONFIG.get('log.rotate_bytes', 512000, int)
|
||||
loghandler = RotatingFileHandler(
|
||||
os.path.expanduser(logfile), 'a', logbytes, logbackups
|
||||
)
|
||||
|
||||
@export
|
||||
class movie_poster_porn_scraper(object):
|
||||
|
||||
"""Poster scraper
|
||||
Attributes
|
||||
----------
|
||||
reddit_instance : praw.Reddit
|
||||
A praw instance connected to Reddit
|
||||
"""
|
||||
|
||||
def __init__(self, instance: praw.Reddit) -> None:
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
instance : praw.Reddit
|
||||
A praw instance connected to Reddit
|
||||
"""
|
||||
super().__init__()
|
||||
self.reddit_instance = instance
|
||||
|
||||
@classmethod
|
||||
def create_instance(
|
||||
cls: Type[T_movie_poster_porn_scraper],
|
||||
client_id: str,
|
||||
client_secret: str,
|
||||
user_agent: str,
|
||||
) -> T_movie_poster_porn_scraper:
|
||||
"""Connect to reddit
|
||||
Parameters
|
||||
----------
|
||||
client_id : str
|
||||
a valid client id
|
||||
client_secret : str
|
||||
the secret key for the client
|
||||
user_agent : str
|
||||
a user agent
|
||||
"""
|
||||
reddit_instance = praw.Reddit(
|
||||
client_id=client_id,
|
||||
client_secret=client_secret,
|
||||
user_agent=user_agent,
|
||||
)
|
||||
|
||||
return cls(reddit_instance)
|
||||
|
||||
def get_hot_posters(
|
||||
self: T_movie_poster_porn_scraper,
|
||||
) -> T_movie_poster_porn_scraper:
|
||||
"""
|
||||
"""
|
||||
self._poster_urls: Dict = {}
|
||||
for post in self.reddit_instance.subreddit('MoviePosterPorn').hot(
|
||||
limit=10
|
||||
):
|
||||
print(post.title)
|
||||
print(post.url)
|
||||
# print(dir(post))
|
||||
# self._poster_urls.append(post.url)
|
||||
self._poster_urls[post.title] = post.url
|
||||
print(self._poster_urls)
|
||||
return self
|
||||
|
||||
def get_posters(self: T_movie_poster_porn_scraper):
|
||||
"""download the posters
|
||||
Returns
|
||||
-------
|
||||
self
|
||||
"""
|
||||
for title, url in self._poster_urls.items():
|
||||
r = requests.get(url)
|
||||
with open('posters/' + title + '.jpg', 'wb') as p:
|
||||
p.write(r.content)
|
||||
return self
|
||||
loghandler.setFormatter(logging.Formatter(logformat))
|
||||
log.addHandler(loghandler)
|
||||
log.setLevel(loglevel)
|
||||
logfilter = SecretsFilter()
|
||||
if CONFIG.get('log.show_secrets', '').lower() != 'true':
|
||||
log.addFilter(logfilter)
|
||||
|
||||
Binary file not shown.
95
plex-posters/src/plex_posters/config/__init__.py
Normal file
95
plex-posters/src/plex_posters/config/__init__.py
Normal file
@@ -0,0 +1,95 @@
|
||||
from plex_posters.lib import export
|
||||
from plex_posters import __header__ as header
|
||||
from typing import Union
|
||||
import os
|
||||
import toml
|
||||
|
||||
__all__ = []
|
||||
__section__ = 'CONFIG'
|
||||
|
||||
|
||||
@export
|
||||
class plexPosterConfig:
|
||||
|
||||
"""Handles the config options for the module
|
||||
|
||||
Attributes
|
||||
----------
|
||||
config_file : dict
|
||||
Contains the config options. See `plexPosterConfig.read_config()`
|
||||
for the data structure.
|
||||
"""
|
||||
|
||||
def __init__(self, path: str) -> None:
|
||||
self.config_file = self.read_config(path)
|
||||
self.module_name = header.lower()
|
||||
|
||||
@staticmethod
|
||||
def read_config(path: str) -> Union[dict, None]:
|
||||
|
||||
"""Reads the toml config file from `path` if it exists.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : str
|
||||
Path to config file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Union[dict, None]
|
||||
Returns a dict if the file is found else returns nothing.
|
||||
|
||||
The dict contains a key for each header. Each key contains a
|
||||
dictionary containing a key, value pair for each config under
|
||||
that header.
|
||||
|
||||
Example:
|
||||
|
||||
[plexposters]
|
||||
|
||||
[plexposters.foo]
|
||||
foo = bar
|
||||
|
||||
Returns a dict: {'plexposters' : {foo: {'foo': 'bar'}}}
|
||||
"""
|
||||
|
||||
path += 'config.toml' if path[-1] == '/' else '/config.toml'
|
||||
|
||||
try:
|
||||
with open(path, 'r+') as config_file:
|
||||
config_file = toml.load(config_file)
|
||||
return config_file
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
def get(self, key: str, default: str = None, cast: callable = None):
|
||||
env_key = f"{header}_{key.upper().replace('.', '_')}"
|
||||
print(self.config_file)
|
||||
try:
|
||||
section, name = key.lower().split('.')
|
||||
value = self.config_file[self.module_name][section][name]
|
||||
print(f'{env_key} found in config.toml')
|
||||
return cast(value) if cast else value
|
||||
except KeyError:
|
||||
print(f'{env_key} not found in config.toml')
|
||||
value = os.environ.get(env_key)
|
||||
if value is not None:
|
||||
print(f'{env_key} found in an environment variable')
|
||||
else:
|
||||
print(f'{env_key} not found in an environment variable.')
|
||||
value = default
|
||||
print(f'{env_key} set to default {default}')
|
||||
return cast(value) if cast else value
|
||||
|
||||
|
||||
inst = plexPosterConfig(
|
||||
os.path.expanduser('~/.config/plex-posters/')
|
||||
)
|
||||
|
||||
# print(inst.config_file, '\n')
|
||||
|
||||
# print(f"{os.environ.get('VIRTUAL_ENV')=}")
|
||||
|
||||
PLEX_USERNAME = inst.get(f'plex.password', 'smile')
|
||||
|
||||
print(f'{PLEX_USERNAME=}')
|
||||
@@ -1,7 +1,7 @@
|
||||
import sys
|
||||
|
||||
|
||||
def export(fn):
|
||||
def export(fn: callable) -> callable:
|
||||
mod = sys.modules[fn.__module__]
|
||||
if hasattr(mod, '__all__'):
|
||||
mod.__all__.append(fn.__name__)
|
||||
|
||||
Binary file not shown.
BIN
plex-posters/tests/testimport/.DS_Store
vendored
BIN
plex-posters/tests/testimport/.DS_Store
vendored
Binary file not shown.
Reference in New Issue
Block a user