Home Page
  • May 05, 2024, 08:56:03 pm *
  • Welcome, Guest
Please login or register.

Login with username, password and session length
Advanced search  

News:

Official site launch very soon, hurrah!


Pages: 1 ... 4 5 [6] 7 8 ... 10
 51 
 on: July 26, 2016, 08:12:09 pm 
Started by Dakusan - Last post by Dakusan
You mean a separate Plex pass user, correct? One in which you would have had to of shared your libraries with via Libraries->...->Share ? (Or shares visible via plex.tv->launch->settings->users->friends)

 52 
 on: July 14, 2016, 08:27:22 pm 
Started by Dakusan - Last post by Dakusan
Original update for Plex Playlist Importer v1.1 can be found at https://www.castledragmire.com/Updates/Plex_Playlist_Importer_v1.1.
Originally posted on: 07/14/16
Regarding: Plex Playlist Importer

Plex Playlist Importer v1.1 (source). Current updates spanning 2017:
     
  • Fixed absolute path logic for Linux (partial credit to Matt Spitz)
  •  
  • Bypasses UTF8 BOM
  •  
  • Program now works off of argument flags.
         
    • Added parameters: Playlist encoding, override type, force list
    •    
    • Created special BulletHelpFormatter class for parameters
    •  
  •  
  • Playlist names can now conflict with other item/list names in Plex
  •  
  • Console column width passthrough in the .sh file
  •  
  • Updated READMEs regarding:
         
    • Unicode compliance
    •    
    • The “no such module : FTS4” error
    •    
    • Running the script from a computer external to the server running Plex
    •    
    • The “The program can’t start because MSVCR100.dll is missing” error
    •    
    • All updates
    •  
  •  
  • Added the ability to compile to a windows executable (via setup.py py2exe)
  •  
  • The Playlist Name is now an optional argument which can be entered after the program is ran. This allows directly dragging playlists onto the executable
  •  
  • Added shebang to main script
  •  
  • M3U files now ignore lines that are empty or have only whitespace

 53 
 on: July 05, 2016, 04:42:39 pm 
Started by chemsed - Last post by Dakusan
Sure. If you needed the latest executable, it is available in this thread.

 54 
 on: July 05, 2016, 01:53:02 am 
Started by Dakusan - Last post by Dakusan
Yikes. It feels like on a lot of this you are going to way more trouble than should be needed :-\

Quote
I've not found a good way to execute ListImporter from a folder not containing both the .exe and all its .dll files. This would be useful but is not essential. I do have to manage Acronis' insistence on restarting one of its supposedly unneeded services that uses a different sqlite3.dll. The sqlite3.dll used by the latest version of PMS no longer conflicts.
I think I might actually have been providing a bad sqlite3.dll with my previous releases, which could have been the problem. That is fixed in the new archive I had sent you. I don't really see an easier way to do distribute this without the dlls as separate files in the archive. I'm not big on installers.
Quote
The first of two small issues is that ListImporter is intolerant of blank lines in the m3u (e.g., at the end).
I have updated the code to ignore lines that are blank or only have whitespace. It is up on github and I will included it on my next executable install.
Quote
The second small issue is that any error in one track reference causes the entire import to abort with Errorlevel set to 1.  [...]
This is always something I haven't really been sure how to handle. Do you have any suggestions? I guess I could include a batch error mode that would be the default...
Quote
(a) execution message output appears to go to stderr vs. stdout, which can interfere with batch file output piping for logging/analysis purposes
I believe throwing errors to stderr is the proper behavior. Would it help if I included a parameter flag that instead pushed everything through stdout? In bash shell environments, it's as simple as adding "2>&1" after your command. Not sure about windows.
I think that covers everything you mentioned, minus track length. I just looked in the DB, and from a quick glance, I'm not actually sure where the track durations are stored for items on a playlist. I think I skipped that since I wanted to make a minimum number of modifications to the database and knew it would auto correct.

[Edit] P.S. The latest version (have not compiled into exe yet) allows dragging playlists onto the executable.

 55 
 on: July 04, 2016, 03:15:18 pm 
Started by Dakusan - Last post by Skipper42
The latest ListImporter version for Windows works like a champ - thanks!I've successfully tested with:
  • Both relative and absolute paths to track files in the m3u
  • With m3u's exported from MediaMonkey (aka MM; ver 4.1.12.1798; I'll let you know if this changes with the latest version, 4.1.13.1801)
  • With m3u's exported from Mp3tag, and
  • With m3u's exported from my iBasso DX90.
I confirmed that byte order no longer matters; I no longer have to go thru the extra pass through EditPad Lite to drop the BOM.If an actual file cannot be found from its m3u reference, I've confirmed that ListImporter correctly notifies the user of the path and filename of the file it cannot find (with one exception; please see below).If errors are encountered, ListImporter correctly sets Errorlevel so it can be checked in a batch file. Thus, I can use this to avoid prematurely archiving failed import playlists until the issues are resolved.I've not found a good way to execute ListImporter from a folder not containing both the .exe and all its .dll files. This would be useful but is not essential. I do have to manage Acronis' insistence on restarting one of its supposedly unneeded services that uses a different sqlite3.dll. The sqlite3.dll used by the latest version of PMS no longer conflicts.I did find a couple of small residual issues plus a couple of what you're free to view as extremely minor quibbles.The first of two small issues is that ListImporter is intolerant of blank lines in the m3u (e.g., at the end). This leads to the mysterious error message that the track file must be located relative to the playlist, but since the reference line is a blank, there's no file reported. Took some lengthy trial and error to find what was causing the glitch. I'll note that part of my confusion was that the same error message ("relative to") appeared irrespective of whether I was using dot notation relative paths or absolute paths for the track references (I suspect this is a holdover from versions prior to those permitting absolute path references).The second small issue is that any error in one track reference causes the entire import to abort with Errorlevel set to 1. That meant the original m3u with one or more blank lines would abort, while trying to identify the problem track reference by successive runs each with a new reference added from the original always was successful. That's actually how I tumbled to the blank line intolerance.My benchmark for whether the m3u had valid references has been Florian Heidenreich's excellent freeware Mp3tag (http://www.mp3tag.de/en/). In sum, if Mp3tag can import all the rows successfully, then I can safely assume the m3u is valid; it reports any track files it cannot find. That means anyone should be able to debug issues with ListImporter using Mp3tag to test the m3u's track file references for validity (plus verifying that the track files can be played independently in Plex).I also use Mp3tag to convert relative paths in m3u's to absolute or relative paths matching the location of the m3u file to be imported to Plex. MM's relative paths are relative to where the m3u is originally stored). MM is a far richer playlist editor/maker than Plex, so combining your tool with my methods gives me the best of both worlds.The .mte export configuration file I use in Mp3tag is:$filename(<path>\to_import\Plex.m3u,utf-8)$loop(%_counter%)%_folderpath%%_filename_ext%$loopend()...with care to have the file end after the $loopend() statement so as not to generate the blank line that ListImporter thinks is an invalid track reference. In my case, E:\Users\Public\Music\My Playlists\! Plex Playlists\ is the folder also containing the ListImporter .exe, .dll's and ppibatch.bat file.Once exported, I rename Plex.m3u to whatever I want the playlist name to be. Note: to export with relative vs. absolute paths, change %_folderpath% to %_folderpath_rel%, tho ListImporter always worked irrespective of which was used.The two minor quibbles are (a) execution message output appears to go to stderr vs. stdout, which can interfere with batch file output piping for logging/analysis purposes, and (b) delays/problems updating the track length once the playlist has been imported into Plex (an issue I noted in a previous post).The batch file I use (ppibatch.bat, attached) presumes the m3u playlists to be imported are in a particular 'to_import' folder, and if the import of each is successful, the m3u file is moved to an 'imported' folder in the same hierarchy.In the batch file, I used UTF-8 encoding, but set it explicitly in the command line vs. relying on the default. Ditto the file type setting (explicitly 'mp3' vs. default). These were more for self-documentation than any requirement to do so; worked fine with the defaults. Ditto the location of the Plex database.When piped to a log file, each execution in my batch file generates an entry of the following form:Sat 07/02/2016 14:38:28.48PlexPlaylistImporter.exe -f -e utf-8 -t m3u "<path>\to_import\5hr Playlist.m3u" "5hr Playlist"73 items imported        1 file(s) moved....showing there could be value in having error messages, etc. in the consolidated app+OS output also.The track length update problem seems to be avoidable if one turns on frequent Library updating and updating of the Library with any change to the Library, prior to importing the m3u. If that's not done, the track lengths of some tracks remain at 0:00 after import. This also means the overall playlist length will be misreported until each of the 0:00 tracks is launched and another track launched afterward, at which point Plex updates the playlist track length entry and overall playlist length. Even forcing Library updates failed to update the track and playlist lengths.I cannot tell from info available to me here whether the track length update problem is a Plex bug/feature (they clearly have yet to envision importing m3u playlists, and thus without your tool would have no way to test for this bug!) or whether there's some other additional Plex database field references that need updating in your update query SQL (e.g., possibley a field in a different table from the main Playlist records). Regardless, once I turned on frequent Library updating/updating after every change, the problem seemed to disappear.With all that in mind, and given the general end-to-end utility now available, I recommend you post an update to the Plex Forum that details these working methods. Please feel free to share my Mp3tag export .mte above and batch import method's .bat file attached in your post.Thanks again very much for all your efforts here. This has now made Plex finally usable for me!

 56 
 on: July 03, 2016, 02:39:06 pm 
Started by chemsed - Last post by chemsed
Thank you. I will check it out.

 57 
 on: July 02, 2016, 03:52:11 am 
Started by Dakusan - Last post by Dakusan

The PHP MySQL extension is being deprecated in favor of the MySQLi extension in PHP 5.5, and removed as of PHP 7.0. MySQLi was first referenced in PHP v5.0.0 beta 4 on 2004-02-12, with the first stable release in PHP 5.0.0 on 2004-07-13[1]. Before that, the PHP MySQL extension was by far the most popular way of interacting with MySQL on PHP, and still was for a very long time after. This website was opened only 2 years after the first stable release!


With the deprecation, problems from some websites I help host have popped up, many of these sites being very, very old. I needed a quick and dirty solution to monkey-patch these websites to use MySQLi without rewriting all their code. The obvious answer is to overwrite the functions with wrappers for MySQLi. The generally known way of doing this is with the Advanced PHP Debugger (APD). However, using this extension has a lot of requirements that are not appropriate for a production web server. Fortunately, another extension I recently learned of offers the renaming functionality; runkit. It was a super simple install for me.

  1. From the command line, run “pecl install runkit”
  2. Add “extension=runkit.so” and “runkit.internal_override=On” to the php.ini

Besides the ability to override these functions with wrappers, I also needed a way to make sure this file was always loaded before all other PHP files. The simple solution for that is adding “auto_prepend_file=/PATH/TO/FILE” to the “.user.ini” in the user’s root web directory.

The code for this script is as follows. It only contains a limited set of the MySQL functions, including some very esoteric ones that the web site used. This is not a foolproof script, but it gets the job done.


//Override the MySQL functions
foreach(Array(
   'connect', 'error', 'fetch_array', 'fetch_row', 'insert_id', 'num_fields', 'num_rows',
   'query', 'select_db', 'field_len', 'field_name', 'field_type', 'list_dbs', 'list_fields',
   'list_tables', 'tablename'
) as $FuncName)
   runkit_function_redefine("mysql_$FuncName", '',
       'return call_user_func_array("mysql_'.$FuncName.'_OVERRIDE", func_get_args());');

//If a connection is not explicitely passed to a mysql_ function, use the last created connection
global $SQLLink; //The remembered SQL Link
function GetConn($PassedConn)
{
   if(isset($PassedConn))
       return $PassedConn;
   global $SQLLink;
   return $SQLLink;
}

//Override functions
function mysql_connect_OVERRIDE($Host, $Username, $Password) {
   global $SQLLink;
   return $SQLLink=mysqli_connect($Host, $Username, $Password);
}
function mysql_error_OVERRIDE($SQLConn=NULL) {
   return mysqli_error(GetConn($SQLConn));
}
function mysql_fetch_array_OVERRIDE($Result, $ResultType=MYSQL_BOTH) {
   return mysqli_fetch_array($Result, $ResultType);
}
function mysql_fetch_row_OVERRIDE($Result) {
   return mysqli_fetch_row($Result);
}
function mysql_insert_id_OVERRIDE($SQLConn=NULL) {
   return mysqli_insert_id(GetConn($SQLConn));
}
function mysql_num_fields_OVERRIDE($Result) {
   return mysqli_num_fields($Result);
}
function mysql_num_rows_OVERRIDE($Result) {
   return mysqli_num_rows($Result);
}
function mysql_query_OVERRIDE($Query, $SQLConn=NULL) {
   return mysqli_query(GetConn($SQLConn), $Query);
}
function mysql_select_db_OVERRIDE($DBName, $SQLConn=NULL) {
   return mysqli_select_db(GetConn($SQLConn), $DBName);
}
function mysql_field_len_OVERRIDE($Result, $Offset) {
   $Fields=$Result->fetch_fields();
   return $Fields[$Offset]->length;
}
function mysql_field_name_OVERRIDE($Result, $Offset) {
   $Fields=$Result->fetch_fields();
   return $Fields[$Offset]->name;
}
function mysql_field_type_OVERRIDE($Result, $Offset) {
   $Fields=$Result->fetch_fields();
   return $Fields[$Offset]->type;
}
function mysql_list_dbs_OVERRIDE($SQLConn=NULL) {
   $Result=mysql_query('SHOW DATABASES', GetConn($SQLConn));
   $Tables=Array();
   while($Row=mysqli_fetch_assoc($Result))
       $Tables[]=$Row['Database'];
   return $Tables;
}
function mysql_list_fields_OVERRIDE($DBName, $TableName, $SQLConn=NULL) {
   $SQLConn=GetConn($SQLConn);
   $CurDB=mysql_fetch_array(mysql_query('SELECT Database()', $SQLConn));
   $CurDB=$CurDB[0];
   mysql_select_db($DBName, $SQLConn);
   $Result=mysql_query("SHOW COLUMNS FROM $TableName", $SQLConn);
   mysql_select_db($CurDB, $SQLConn);
   if(!$Result) {
       print 'Could not run query: '.mysql_error($SQLConn);
       return Array();
   }
   $Fields=Array();
   while($Row=mysqli_fetch_assoc($Result))
       $Fields[]=$Row['Field'];
   return $Fields;
}
function mysql_list_tables_OVERRIDE($DBName, $SQLConn=NULL) {
   $SQLConn=GetConn($SQLConn);
   $CurDB=mysql_fetch_array(mysql_query('SELECT Database()', $SQLConn));
   $CurDB=$CurDB[0];
   mysql_select_db($DBName, $SQLConn);
   $Result=mysql_query("SHOW TABLES", $SQLConn);
   mysql_select_db($CurDB, $SQLConn);
   if(!$Result) {
       print 'Could not run query: '.mysql_error($SQLConn);
       return Array();
   }
   $Tables=Array();
   while($Row=mysql_fetch_row($Result))
       $Tables[]=$Row[0];
   return $Tables;
}
function mysql_tablename_OVERRIDE($Result) {
   $Fields=$Result->fetch_fields();
   return $Fields[0]->table;
}

And here is some test code to confirm functionality:
global $MyConn, $TEST_Table;
$TEST_Server='localhost';
$TEST_UserName='...';
$TEST_Password='...';
$TEST_DB='...';
$TEST_Table='...';
function GetResult() {
   global $MyConn, $TEST_Table;
   return mysql_query('SELECT * FROM '.$TEST_Table.' LIMIT 1', $MyConn);
}
var_dump($MyConn=mysql_connect($TEST_Server, $TEST_UserName, $TEST_Password));
//Set $MyConn to NULL here if you want to test global $SQLLink functionality
var_dump(mysql_select_db($TEST_DB, $MyConn));
var_dump(mysql_query('SELECT * FROM INVALIDTABLE LIMIT 1', $MyConn));
var_dump(mysql_error($MyConn));
var_dump($Result=GetResult());
var_dump(mysql_fetch_array($Result));
$Result=GetResult(); var_dump(mysql_fetch_row($Result));
$Result=GetResult(); var_dump(mysql_num_fields($Result));
var_dump(mysql_num_rows($Result));
var_dump(mysql_field_len($Result, 0));
var_dump(mysql_field_name($Result, 0));
var_dump(mysql_field_type($Result, 0));
var_dump(mysql_tablename($Result));
var_dump(mysql_list_dbs($MyConn));
var_dump(mysql_list_fields($TEST_DB, $TEST_Table, $MyConn));
var_dump(mysql_list_tables($TEST_DB, $MyConn));
mysql_query('CREATE TEMPORARY TABLE mysqltest (i int auto_increment, primary key (i))', $MyConn);
mysql_query('INSERT INTO mysqltest VALUES ()', $MyConn);
mysql_query('INSERT INTO mysqltest VALUES ()', $MyConn);
var_dump(mysql_insert_id($MyConn));
mysql_query('DROP TEMPORARY TABLE mysqltest', $MyConn);

 58 
 on: July 02, 2016, 02:55:20 am 
Started by Dakusan - Last post by Dakusan
Original post for Bullet Help Formatter for Python’s argparse can be found at https://www.castledragmire.com/Posts/Bullet_Help_Formatter_for_Python’s_argparse.
Originally posted on: 07/02/16

This is a HelpFormatter for Python’s argparse class which:
  • Takes raw input and wraps long lines to indent against the current line start.
  • When an indented/list line is encountered, which starts with spaces followed by a star "*", wrapped line’s indents will start 2 spaces after the star.
  • Lines attempt to split at words of 10 characters or less (see .MinCharsInSplitWord).
  • If a line needs to split along a word longer than this, a hyphen is inserted at the end of the line.

import argparse
import re
class BulletHelpFormatter(argparse.HelpFormatter):
   def __init__(self, *args, **kwargs):
       super(BulletHelpFormatter, self).__init__(*args, **kwargs)
       self.MinCharsInSplitWord=10

   def _split_lines(self, text, width):
       #Split lines around line breaks and then modify each line
       Lines=[]
       for Line in text.splitlines():
           #Get the number of spaces to put at subsequent lines
           #0 if not a list item, oherwise, 2+list item start
           ListEl=re.match(r'^ *\*', Line)
           NumBeginningSpace=(0 if ListEl==None else ListEl.end()+1)

           #Add extra spaces at the beginning of each line to match the start of the current line, and go to a maxium of $width
           IsFirstPass=True
           SpacesToAdd=''
           NumSpacesToAdd=0
           while(True):
               #Get the word break points before and after where the line would end
               MaxLineLen=max(min(width-NumSpacesToAdd, len(Line)), 1)
               PrevWordBreak=CurWordBreak=0
               for WordBreak in re.finditer(r'(?<=\W).|\W|$', Line):
                   PrevWordBreak=CurWordBreak
                   CurWordBreak=WordBreak.start()
                   if CurWordBreak>=MaxLineLen:
                       if CurWordBreak==MaxLineLen:
                           PrevWordBreak=CurWordBreak
                       break

               #If previous wordbreak is more than MinCharsInSplitWord away from MaxLineLen, then split at the end of the line
               IsSplit=(PrevWordBreak<1 or CurWordBreak-PrevWordBreak>self.MinCharsInSplitWord)
               SplitPos=(MaxLineLen if IsSplit else PrevWordBreak)

               #Append the new line to the list of lines
               Lines.append(SpacesToAdd+Line[0:SplitPos]+('-' if IsSplit else ''))
               Line=Line[SplitPos:]

               #If this is the end, nothing left to do
               if len(Line)==0:
                   break

               #If this is the first pass, update line creation variables
               if IsFirstPass:
                   IsFirstPass=False
                   NumSpacesToAdd=NumBeginningSpace
                   SpacesToAdd=(' ' * NumSpacesToAdd)

       return Lines

 59 
 on: July 01, 2016, 04:16:31 am 
Started by Dakusan - Last post by Dakusan
I have made multiple updates to the software and recompiled it. I have attached it to this post if you want to check it out. I confirmed that it worked fine in command prompt with your m3u file. Update log is on github.

P.S. If possible, please let me know within the next few days if all is well now. Would like to get the confirmed updates and compilation up on my website.

 60 
 on: June 29, 2016, 01:41:47 am 
Started by chemsed - Last post by Dakusan
Quote
I guess that french characters is the cause of that error:"List Importer  'Winamp playlist':'utf-8' codec can't decode byte 0xe9 in position  323:invalid continuarion byte
I have added a command line flag that lets you set the encoding of the file. You will want to set it to ISO-8859-1.
Quote
I chose an full English playlist. I have that:"Playlist name has already been taken by a non-playlist"
This has been fixed.
Quote
It seem that my plex playlist name can't be the same as the artist that  is already in my plex library, so I change the playlist name to  "paramorelist":DB Error: no such module fts4
I have added the following to the README file:
Quote
If running this mentions something about “no such module : FTS4”, you may need to replace the sqlite3.dll or sqlite3.so for your Python, which can be found at https://www.sqlite.org/download.html .
For a Python for Windows install, the DLL location will most likely be located at C:\Users\%USERNAME%\AppData\Local\Programs\Python\Python%PYTHON_VERSION%\DLLs.

The new version is available on github. Will be uploading a new windows executable within the next few days.

Pages: 1 ... 4 5 [6] 7 8 ... 10